gecoder 0.8.3 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (142) hide show
  1. data/CHANGES +15 -0
  2. data/README +6 -2
  3. data/example/equation_system.rb +15 -0
  4. data/example/magic_sequence.rb +7 -7
  5. data/example/money.rb +36 -0
  6. data/example/queens.rb +7 -8
  7. data/example/send_most_money.rb +1 -1
  8. data/example/square_tiling.rb +2 -2
  9. data/example/sudoku-set.rb +11 -12
  10. data/example/sudoku.rb +40 -45
  11. data/ext/extconf.rb +0 -0
  12. data/lib/gecoder/bindings.rb +42 -0
  13. data/lib/gecoder/bindings/bindings.rb +16 -0
  14. data/lib/gecoder/interface.rb +2 -1
  15. data/lib/gecoder/interface/branch.rb +16 -9
  16. data/lib/gecoder/interface/constraints.rb +410 -451
  17. data/lib/gecoder/interface/constraints/bool/boolean.rb +205 -213
  18. data/lib/gecoder/interface/constraints/bool/channel.rb +4 -5
  19. data/lib/gecoder/interface/constraints/bool/linear.rb +192 -21
  20. data/lib/gecoder/interface/constraints/bool_enum/channel.rb +43 -39
  21. data/lib/gecoder/interface/constraints/bool_enum/extensional.rb +43 -49
  22. data/lib/gecoder/interface/constraints/bool_enum/relation.rb +38 -71
  23. data/lib/gecoder/interface/constraints/bool_enum_constraints.rb +73 -22
  24. data/lib/gecoder/interface/constraints/bool_var_constraints.rb +140 -61
  25. data/lib/gecoder/interface/constraints/extensional_regexp.rb +4 -4
  26. data/lib/gecoder/interface/constraints/fixnum_enum/element.rb +63 -0
  27. data/lib/gecoder/interface/constraints/fixnum_enum/operation.rb +65 -0
  28. data/lib/gecoder/interface/constraints/fixnum_enum_constraints.rb +42 -0
  29. data/lib/gecoder/interface/constraints/int/arithmetic.rb +131 -130
  30. data/lib/gecoder/interface/constraints/int/channel.rb +21 -31
  31. data/lib/gecoder/interface/constraints/int/domain.rb +45 -42
  32. data/lib/gecoder/interface/constraints/int/linear.rb +85 -239
  33. data/lib/gecoder/interface/constraints/int/relation.rb +141 -0
  34. data/lib/gecoder/interface/constraints/int_enum/arithmetic.rb +55 -64
  35. data/lib/gecoder/interface/constraints/int_enum/channel.rb +35 -37
  36. data/lib/gecoder/interface/constraints/int_enum/count.rb +53 -78
  37. data/lib/gecoder/interface/constraints/int_enum/distinct.rb +36 -46
  38. data/lib/gecoder/interface/constraints/int_enum/element.rb +39 -57
  39. data/lib/gecoder/interface/constraints/int_enum/equality.rb +15 -19
  40. data/lib/gecoder/interface/constraints/int_enum/extensional.rb +65 -72
  41. data/lib/gecoder/interface/constraints/int_enum/sort.rb +42 -45
  42. data/lib/gecoder/interface/constraints/int_enum_constraints.rb +79 -22
  43. data/lib/gecoder/interface/constraints/int_var_constraints.rb +215 -44
  44. data/lib/gecoder/interface/constraints/reifiable_constraints.rb +14 -14
  45. data/lib/gecoder/interface/constraints/selected_set/select.rb +120 -0
  46. data/lib/gecoder/interface/constraints/selected_set_constraints.rb +75 -0
  47. data/lib/gecoder/interface/constraints/set/cardinality.rb +43 -53
  48. data/lib/gecoder/interface/constraints/set/channel.rb +26 -29
  49. data/lib/gecoder/interface/constraints/set/connection.rb +89 -152
  50. data/lib/gecoder/interface/constraints/set/domain.rb +112 -65
  51. data/lib/gecoder/interface/constraints/set/include.rb +36 -0
  52. data/lib/gecoder/interface/constraints/set/operation.rb +96 -110
  53. data/lib/gecoder/interface/constraints/set/relation.rb +114 -137
  54. data/lib/gecoder/interface/constraints/set_elements/relation.rb +116 -0
  55. data/lib/gecoder/interface/constraints/set_elements_constraints.rb +97 -0
  56. data/lib/gecoder/interface/constraints/set_enum/channel.rb +23 -27
  57. data/lib/gecoder/interface/constraints/set_enum/distinct.rb +18 -19
  58. data/lib/gecoder/interface/constraints/set_enum/operation.rb +62 -53
  59. data/lib/gecoder/interface/constraints/set_enum/select.rb +79 -0
  60. data/lib/gecoder/interface/constraints/set_enum_constraints.rb +73 -23
  61. data/lib/gecoder/interface/constraints/set_var_constraints.rb +222 -57
  62. data/lib/gecoder/interface/enum_matrix.rb +4 -4
  63. data/lib/gecoder/interface/enum_wrapper.rb +71 -22
  64. data/lib/gecoder/interface/model.rb +167 -12
  65. data/lib/gecoder/interface/model_sugar.rb +84 -0
  66. data/lib/gecoder/interface/search.rb +30 -18
  67. data/lib/gecoder/interface/variables.rb +103 -33
  68. data/lib/gecoder/version.rb +2 -2
  69. data/specs/bool_var.rb +19 -12
  70. data/specs/constraints/{boolean.rb → bool/boolean.rb} +103 -28
  71. data/specs/constraints/bool/boolean_properties.rb +51 -0
  72. data/specs/constraints/bool/linear.rb +213 -0
  73. data/specs/constraints/bool_enum/bool_enum_relation.rb +117 -0
  74. data/specs/constraints/bool_enum/channel.rb +102 -0
  75. data/specs/constraints/{extensional.rb → bool_enum/extensional.rb} +32 -101
  76. data/specs/constraints/constraint_helper.rb +149 -179
  77. data/specs/constraints/constraint_receivers.rb +103 -0
  78. data/specs/constraints/constraints.rb +6 -63
  79. data/specs/constraints/fixnum_enum/element.rb +58 -0
  80. data/specs/constraints/fixnum_enum/operation.rb +67 -0
  81. data/specs/constraints/int/arithmetic.rb +149 -0
  82. data/specs/constraints/int/channel.rb +101 -0
  83. data/specs/constraints/int/domain.rb +106 -0
  84. data/specs/constraints/int/linear.rb +183 -0
  85. data/specs/constraints/int/linear_properties.rb +97 -0
  86. data/specs/constraints/int/relation.rb +84 -0
  87. data/specs/constraints/int_enum/arithmetic.rb +72 -0
  88. data/specs/constraints/int_enum/channel.rb +57 -0
  89. data/specs/constraints/int_enum/count.rb +72 -0
  90. data/specs/constraints/int_enum/distinct.rb +80 -0
  91. data/specs/constraints/int_enum/element.rb +61 -0
  92. data/specs/constraints/int_enum/equality.rb +29 -0
  93. data/specs/constraints/int_enum/extensional.rb +224 -0
  94. data/specs/constraints/int_enum/sort.rb +167 -0
  95. data/specs/constraints/operands.rb +264 -0
  96. data/specs/constraints/property_helper.rb +443 -0
  97. data/specs/constraints/reification_sugar.rb +4 -5
  98. data/specs/constraints/selected_set/select.rb +56 -0
  99. data/specs/constraints/selected_set/select_properties.rb +157 -0
  100. data/specs/constraints/set/cardinality.rb +58 -0
  101. data/specs/constraints/set/cardinality_properties.rb +46 -0
  102. data/specs/constraints/set/channel.rb +77 -0
  103. data/specs/constraints/set/connection.rb +176 -0
  104. data/specs/constraints/set/domain.rb +197 -0
  105. data/specs/constraints/set/include.rb +36 -0
  106. data/specs/constraints/set/operation.rb +132 -0
  107. data/specs/constraints/set/relation.rb +117 -0
  108. data/specs/constraints/set_elements/relation.rb +84 -0
  109. data/specs/constraints/set_enum/channel.rb +80 -0
  110. data/specs/constraints/set_enum/distinct.rb +59 -0
  111. data/specs/constraints/set_enum/operation.rb +111 -0
  112. data/specs/constraints/set_enum/select.rb +73 -0
  113. data/specs/enum_wrapper.rb +53 -3
  114. data/specs/int_var.rb +44 -25
  115. data/specs/model.rb +58 -1
  116. data/specs/model_sugar.rb +30 -0
  117. data/specs/search.rb +24 -5
  118. data/specs/selected_set.rb +39 -0
  119. data/specs/set_elements.rb +34 -0
  120. data/specs/set_var.rb +22 -8
  121. data/specs/spec_helper.rb +206 -6
  122. data/tasks/distribution.rake +22 -7
  123. data/tasks/svn.rake +3 -1
  124. metadata +218 -134
  125. data/lib/gecoder/interface/constraints/set_enum/selection.rb +0 -217
  126. data/specs/constraints/arithmetic.rb +0 -351
  127. data/specs/constraints/bool_enum_relation.rb +0 -160
  128. data/specs/constraints/cardinality.rb +0 -157
  129. data/specs/constraints/channel.rb +0 -454
  130. data/specs/constraints/connection.rb +0 -369
  131. data/specs/constraints/count.rb +0 -146
  132. data/specs/constraints/distinct.rb +0 -164
  133. data/specs/constraints/element.rb +0 -108
  134. data/specs/constraints/equality.rb +0 -31
  135. data/specs/constraints/int_domain.rb +0 -70
  136. data/specs/constraints/int_relation.rb +0 -82
  137. data/specs/constraints/linear.rb +0 -340
  138. data/specs/constraints/selection.rb +0 -292
  139. data/specs/constraints/set_domain.rb +0 -185
  140. data/specs/constraints/set_operation.rb +0 -285
  141. data/specs/constraints/set_relation.rb +0 -197
  142. data/specs/constraints/sort.rb +0 -179
data/CHANGES CHANGED
@@ -1,3 +1,18 @@
1
+ == Version 0.9.0
2
+ This release adds a generous amount of sugar designed to cut down on often
3
+ repeated code. It also adds the ability to freely combine constraints
4
+ without needing temporary variables.
5
+
6
+ * Variables that should be accessible from outside the model can now easily be created by calling "<variable_name>_is_a <variable>" where "<variable_name>" is the desired name of the variable and "<variable>" is the variable (e.g. "int_var(17)"). Take a look at the examples to see it in action.
7
+ * Gecode.solve, Gecode.maximize and Gecode.minimize can now be used to solve a problem without first having to explicitly create a class for the model.
8
+ * An exception (Gecode::NoSolutionError) is now thrown if a solution can not be found when using Model#solve!, Model#minimize!, Model#maximize! and Model#optimize! (rather than returning nil). This change breaks backwards compatibility. If you feel that this is a bad change then please tell the mailing list.
9
+ * The offset option to the distinct constraint is now given as "int_enum.must_be.distinct(:offset => offsets)" rather than the previous "int_enum.with_offsets(offsets).must_be.distinct".
10
+ * Complex combinations of several constraints such as "(set1.size + set2.size).must > int.abs - 3" can now be used. The underlying code has been changed quite a bit, but it should remain backwards compatible except for above mentioned exception. The change also brings about some changed terminology, which mostly aims to remove the concept of "composite constraints" and replace them with the more general "operands" (see the documentation for further details).
11
+ * [#21578] Fixed a bug that caused options given to the boolean "false" domain constraint to not be processed.
12
+ * [#21579] Fixed a bug that caused the integer enumeration equality constraint to not work at all (threw an exception).
13
+ * [#21580] Fixed a bug that caused ranges that use three dots to not be correctly interpreted by the negated integer domain constraint.
14
+ * [#21581] Fixed a bug that caused the abs constraint to prune away valid solutions in some cases.
15
+
1
16
  == Version 0.8.3
2
17
  This release adds regular expression constraints, the last channel
3
18
  constraint and various minor convenience improvements. It also fixes a
data/README CHANGED
@@ -1,9 +1,13 @@
1
- == Gecode/R
1
+ = Gecode/R
2
+
3
+ Website: http://gecoder.org
2
4
 
3
5
  Gecode/R is a Ruby interface to the Gecode constraint programming library.
4
6
  Gecode/R is intended for people with no previous experience of constraint
5
7
  programming, aiming to be easy to pick up and use.
6
8
 
9
+ See Gecode::Model to get started.
10
+
7
11
  == Warning
8
12
 
9
13
  Gecode/R is still in a development stage, the syntax is by no means final
@@ -47,7 +51,7 @@ extension it's given).
47
51
  make
48
52
  mv gecode.so ../lib/
49
53
 
50
- == Running the tests
54
+ === Running the tests
51
55
 
52
56
  rake specs
53
57
 
@@ -0,0 +1,15 @@
1
+ require File.dirname(__FILE__) + '/example_helper'
2
+
3
+ class EquationProblem < Gecode::Model
4
+ def initialize
5
+ x, y, z = vars_is_an int_var_array(3, 0..9)
6
+
7
+ (x + y).must == z
8
+ x.must == y - 3
9
+
10
+ branch_on vars
11
+ end
12
+ end
13
+
14
+ puts 'x y z'
15
+ puts EquationProblem.new.solve!.vars.values.join(' ')
@@ -6,10 +6,10 @@ class MagicSequence < Gecode::Model
6
6
  def initialize(n)
7
7
  # The i:th variable represents the value of the i:th element in the
8
8
  # sequence.
9
- @sequence = int_var_array(n, 0...n)
9
+ sequence_is_an int_var_array(n, 0...n)
10
10
 
11
11
  # The basic requirement to qualify as a magic sequence.
12
- n.times{ |i| @sequence.count(i).must == @sequence[i] }
12
+ n.times{ |i| sequence.count(i).must == sequence[i] }
13
13
 
14
14
  # The following are implied constraints. They do not affect which
15
15
  # assignments are solutions, but they do help prune the search space
@@ -18,18 +18,18 @@ class MagicSequence < Gecode::Model
18
18
  # The sum must be n. This follows from that there are exactly n elements and
19
19
  # that the sum of all elements are the number of occurrences in total, i.e.
20
20
  # the number of elements.
21
- @sequence.sum.must == n
21
+ sequence.sum.must == n
22
22
 
23
23
  # sum(seq[i] * (i-1)) must equal 0 because sum(seq[i]) = n as seen above
24
24
  # and sum(i*seq[i]) is just another way to compute sum(seq[i]). So we get
25
25
  # sum(seq[i] * (i-1)) = sum(seq[i]) - sum(i*seq[i]) = n - n = 0
26
- @sequence.zip((-1...n).to_a).map{ |element, c| element*c }.sum.must == 0
26
+ sequence.zip((-1...n).to_a).map{ |element, c| element*c }.sum.must == 0
27
27
 
28
- branch_on @sequence, :variable => :smallest_degree, :value => :split_max
28
+ branch_on sequence, :variable => :smallest_degree, :value => :split_max
29
29
  end
30
30
 
31
31
  def to_s
32
- @sequence.values.join(', ')
32
+ sequence.values.join(', ')
33
33
  end
34
34
  end
35
35
 
@@ -40,4 +40,4 @@ class Array
40
40
  end
41
41
  end
42
42
 
43
- puts((MagicSequence.new(500).solve! || 'Failed').to_s)
43
+ puts MagicSequence.new(500).solve!.to_s
@@ -0,0 +1,36 @@
1
+ require 'rubygems'
2
+ require 'gecoder'
3
+
4
+ solution = Gecode.solve do
5
+ # A helper to make the linear equation a bit tidier. Takes a number of
6
+ # variables and computes the linear combination as if the variable
7
+ # were digits in a base 10 number. E.g. x,y,z becomes
8
+ # 100*x + 10*y + z .
9
+ def equation_row(*variables)
10
+ variables.inject{ |result, variable| variable + result*10 }
11
+ end
12
+
13
+ # Set up the variables.
14
+ # Let "letters" be an array of 8 integer variables with domain 0..9.
15
+ # The elements represents the letters s, e, n, d, m, o, r and y.
16
+ letters_is_an int_var_array(8, 0..9)
17
+ s,e,n,d,m,o,r,y = letters
18
+
19
+ # Set up the constraints.
20
+ # The equation must hold.
21
+ (equation_row(s, e, n, d) + equation_row(m, o, r, e)).must ==
22
+ equation_row(m, o, n, e, y)
23
+
24
+ # The initial letters may not be 0.
25
+ s.must_not == 0
26
+ m.must_not == 0
27
+
28
+ # All letters must be assigned different digits.
29
+ letters.must_be.distinct
30
+
31
+ # Tell Gecode what variables we want to know the values of.
32
+ branch_on letters, :variable => :smallest_size, :value => :min
33
+ end
34
+
35
+ puts 's e n d m o r y'
36
+ puts solution.letters.values.join(' ')
@@ -9,23 +9,23 @@ class NQueens < Gecode::Model
9
9
  # The row number that the queen in the i:th column has. By using this as
10
10
  # our variables we already make sure that no two queens are in the same
11
11
  # column.
12
- @queen_rows = int_var_array(n, 0...n)
12
+ queen_rows_is_an int_var_array(n, 0...n)
13
13
 
14
14
  # Set up the constraints
15
15
  # Queens must not be in the same diagonal (negative slope).
16
- @queen_rows.with_offsets((0...n).to_a).must_be.distinct
16
+ queen_rows.must_be.distinct(:offsets => (0...n).to_a)
17
17
  # Queens must not be in the same diagonal (positive slope).
18
- @queen_rows.with_offsets((0...n).to_a.reverse).must_be.distinct
18
+ queen_rows.must_be.distinct(:offsets => (0...n).to_a.reverse)
19
19
  # Queens must not be in the same row.
20
- @queen_rows.must_be.distinct
20
+ queen_rows.must_be.distinct
21
21
 
22
22
  # Branching, we use first-fail heuristic.
23
- branch_on @queen_rows, :variable => :smallest_size, :value => :min
23
+ branch_on queen_rows, :variable => :smallest_size, :value => :min
24
24
  end
25
25
 
26
26
  # Displays the assignment as a chessboard with queens denoted by 'x'.
27
27
  def to_s
28
- rows = @queen_rows.values
28
+ rows = queen_rows.values
29
29
 
30
30
  separator = '+' << '-' * (3 * @size + (@size - 1)) << "+\n"
31
31
  res = (0...@size).inject(separator) do |s, i|
@@ -39,5 +39,4 @@ end
39
39
  # Print the first solution. Note that there are 92 solutions, but only 12
40
40
  # are rotationally distinct. For any serious use one should place additional
41
41
  # constraints to eliminate those symmetries.
42
- NQueens.new( (ARGV[0] || 8).to_i ).solution{ |sol| puts sol.to_s }
43
-
42
+ puts NQueens.new((ARGV[0] || 8).to_i).solve!.to_s
@@ -55,4 +55,4 @@ solution = SendMoreMoney.new.optimize! do |model, best_so_far|
55
55
  model.money.to_number.must > best_so_far.money.values.to_number
56
56
  end
57
57
  puts solution.to_s
58
- puts "money: #{solution.money.values.to_number}"
58
+ puts "money: #{solution.money.values.to_number}"
@@ -74,11 +74,11 @@ class SquareTiling < Gecode::Model
74
74
  end
75
75
  end
76
76
 
77
- # Displays the corrdinates of the squares.
77
+ # Displays the coordinates of the squares.
78
78
  # TODO: Something more impressive.
79
79
  def to_s
80
80
  @xs.values.zip(@ys.values).map{ |x,y| "(#{x}, #{y})"}.join(', ')
81
81
  end
82
82
  end
83
83
 
84
- puts(SquareTiling.new(65, 47, [25, 24, 23, 22, 19, 17, 11, 6, 5, 3]).solve! || 'Failed').to_s
84
+ puts SquareTiling.new(65, 47, [25, 24, 23, 22, 19, 17, 11, 6, 5, 3]).solve!.to_s
@@ -23,13 +23,13 @@ class SudokuSet < Gecode::Model
23
23
  # upper bound (as it may potentially occurr in any square). We know that
24
24
  # each assignable number must occurr 9 times in a solved sudoku, so we
25
25
  # set the cardinality to 9..9 .
26
- @sets = set_var_array(n, [], 1..n*n, n..n)
26
+ sets_is_an set_var_array(n, [], 1..n*n, n..n)
27
27
  predefined_values.row_size.times do |i|
28
28
  predefined_values.column_size.times do |j|
29
29
  unless predefined_values[i,j].zero?
30
30
  # We add the constraint that the square position must occurr in the
31
31
  # set corresponding to the predefined value.
32
- @sets[predefined_values[i,j] - 1].must_be.superset_of [i*n + j+1]
32
+ sets[predefined_values[i,j] - 1].must_be.superset_of [i*n + j+1]
33
33
  end
34
34
  end
35
35
  end
@@ -58,34 +58,33 @@ class SudokuSet < Gecode::Model
58
58
  # the same square.
59
59
  n.times do |i|
60
60
  (i + 1).upto(n - 1) do |j|
61
- @sets[i].must_be.disjoint_with @sets[j]
61
+ sets[i].must_be.disjoint_with sets[j]
62
62
  end
63
63
  end
64
64
 
65
65
  # The sets must intersect in exactly one element with each row column and
66
66
  # block. I.e. an assignable number must be assigned exactly once in each
67
- # row, column and block. We specify the constraint by expressing that the
68
- # intersection must be equal with a set variable with cardinality 1.
69
- @sets.each do |set|
67
+ # row, column and block.
68
+ sets.each do |set|
70
69
  rows.each do |row|
71
- set.intersection(row).must == set_var([], 1..n*n, 1..1)
70
+ set.intersection(row).size.must == 1
72
71
  end
73
72
  columns.each do |column|
74
- set.intersection(column).must == set_var([], 1..n*n, 1..1)
73
+ set.intersection(column).size.must == 1
75
74
  end
76
75
  blocks.each do |block|
77
- set.intersection(block).must == set_var([], 1..n*n, 1..1)
76
+ set.intersection(block).size.must == 1
78
77
  end
79
78
  end
80
79
 
81
80
  # Branching.
82
- branch_on @sets, :variable => :none, :value => :min
81
+ branch_on sets, :variable => :none, :value => :min
83
82
  end
84
83
 
85
84
  # Outputs the assigned numbers in a grid.
86
85
  def to_s
87
86
  squares = []
88
- @sets.values.each_with_index do |positions, i|
87
+ sets.values.each_with_index do |positions, i|
89
88
  positions.each{ |square_position| squares[square_position - 1] = i + 1 }
90
89
  end
91
90
  squares.enum_slice(@size).map{ |slice| slice.join(' ') }.join("\n")
@@ -104,4 +103,4 @@ predefined_squares = Matrix[
104
103
  [0,8,0, 4,0,0, 1,0,0],
105
104
  [0,6,3, 0,0,0, 0,8,0],
106
105
  [0,0,0, 6,0,8, 0,0,0]]
107
- puts(SudokuSet.new(predefined_squares).solve! || 'Failed').to_s
106
+ puts SudokuSet.new(predefined_squares).solve!.to_s
@@ -2,51 +2,9 @@ require File.dirname(__FILE__) + '/example_helper'
2
2
  require 'enumerator'
3
3
 
4
4
  # Solves the sudoku problem: http://en.wikipedia.org/wiki/Soduko
5
- class Sudoku < Gecode::Model
6
- # Takes a matrix of values in the initial sudoku, 0 if the square is empty.
7
- # The matrix must be square with a square size.
8
- def initialize(values)
9
- # Verify that the input is of a valid size.
10
- @size = n = values.row_size
11
- sub_matrix_size = Math.sqrt(n).round
12
- unless values.square? and sub_matrix_size**2 == n
13
- raise ArgumentError, 'Incorrect value matrix size.'
14
- end
15
- sub_count = sub_matrix_size
16
-
17
- # Create the squares and initialize them.
18
- @squares = int_var_matrix(n, n, 1..n)
19
- values.row_size.times do |i|
20
- values.column_size.times do |j|
21
- @squares[i,j].must == values[i,j] unless values[i,j] == 0
22
- end
23
- end
24
-
25
- # Constraints.
26
- n.times do |i|
27
- # All rows must contain distinct numbers.
28
- @squares.row(i).must_be.distinct(:strength => :domain)
29
- # All columns must contain distinct numbers.
30
- @squares.column(i).must_be.distinct(:strength => :domain)
31
- # All sub-matrices must contain distinct numbers.
32
- @squares.minor(
33
- (i % sub_count) * sub_matrix_size,
34
- sub_matrix_size,
35
- (i / sub_count) * sub_matrix_size,
36
- sub_matrix_size).must_be.distinct(:strength => :domain)
37
- end
38
-
39
- # Branching, we use first-fail heuristic.
40
- branch_on @squares, :variable => :smallest_size, :value => :min
41
- end
42
-
43
- # Display the solved sudoku in a grid.
44
- def to_s
45
- @squares.values.enum_slice(@size).map{ |slice| slice.join(' ') }.join("\n")
46
- end
47
- end
48
5
 
49
- given_squares = Matrix[
6
+ # The sudoku we want to solve (0 represents that the square is empty).
7
+ sudoku = Matrix[
50
8
  [0,0,0, 2,0,5, 0,0,0],
51
9
  [0,9,0, 0,0,0, 7,3,0],
52
10
  [0,0,2, 0,0,9, 0,6,0],
@@ -58,4 +16,41 @@ given_squares = Matrix[
58
16
  [0,8,0, 4,0,0, 1,0,0],
59
17
  [0,6,3, 0,0,0, 0,8,0],
60
18
  [0,0,0, 6,0,8, 0,0,0]]
61
- puts Sudoku.new(given_squares).solve!.to_s
19
+
20
+ solution = Gecode.solve do
21
+ # Verify that the input is of a valid size.
22
+ @size = n = sudoku.row_size
23
+ sub_matrix_size = Math.sqrt(n).round
24
+ unless sudoku.square? and sub_matrix_size**2 == n
25
+ raise ArgumentError, 'Incorrect value matrix size.'
26
+ end
27
+ sub_count = sub_matrix_size
28
+
29
+ # Create the squares and initialize them.
30
+ squares_is_an int_var_matrix(n, n, 1..n)
31
+ sudoku.row_size.times do |i|
32
+ sudoku.column_size.times do |j|
33
+ squares[i,j].must == sudoku[i,j] unless sudoku[i,j] == 0
34
+ end
35
+ end
36
+
37
+ # Constraints.
38
+ n.times do |i|
39
+ # All rows must contain distinct numbers.
40
+ squares.row(i).must_be.distinct(:strength => :domain)
41
+ # All columns must contain distinct numbers.
42
+ squares.column(i).must_be.distinct(:strength => :domain)
43
+ # All sub-matrices must contain distinct numbers.
44
+ squares.minor(
45
+ (i % sub_count) * sub_matrix_size,
46
+ sub_matrix_size,
47
+ (i / sub_count) * sub_matrix_size,
48
+ sub_matrix_size).must_be.distinct(:strength => :domain)
49
+ end
50
+
51
+ # Branching, we use first-fail heuristic.
52
+ branch_on squares, :variable => :smallest_size, :value => :min
53
+ end.squares.values
54
+
55
+ # Output the solved sudoku in a grid.
56
+ puts solution.enum_slice(sudoku.row_size).map{ |slice| slice.join(' ') }.join($/)
File without changes
@@ -1,3 +1,45 @@
1
+ # Problems can be formulated and solved either through defining a new
2
+ # class that inherits from Gecode::Model or by using Gecode#solve et al.
3
+ # Gecode::Model describes how to formulate problems.
4
+ #
5
+ # ==== Examples
6
+ #
7
+ # The following two examples show how to solve the following equation
8
+ # system, using both ways to define and solve a problem.
9
+ #
10
+ # Equation system:
11
+ # x + y = z
12
+ # x = y - 3
13
+ # 0 <= x,y,z <= 9
14
+ #
15
+ # === Inheriting from Gecode::Model
16
+ #
17
+ # class EquationProblem < Gecode::Model
18
+ # def initialize
19
+ # variables_is_an int_var_array(3, 0..9)
20
+ # x, y, z = variables
21
+ #
22
+ # (x + y).must == z
23
+ # x.must == y - 3
24
+ #
25
+ # branch_on variables
26
+ # end
27
+ # end
28
+ # puts EquationProblem.new.solve!.variables.join(' ')
29
+ #
30
+ # === Using Gecode#solve
31
+ #
32
+ # solution = Gecode.solve do
33
+ # variables_is_an int_var_array(3, 0..9)
34
+ # x, y, z = variables
35
+ #
36
+ # (x + y).must == z
37
+ # x.must == y - 3
38
+ #
39
+ # branch_on variables
40
+ # end
41
+ # puts solution.variables.values.join(' ')
42
+ #
1
43
  module Gecode
2
44
  # Loads the binding libraries. This is done as a method in order to be easier
3
45
  # to test.
@@ -735,6 +735,11 @@ Rust::Bindings::create_bindings Rust::Bindings::LangCxx, "gecode" do |b|
735
735
  ['Gecode::IntVar', 'Gecode::BoolVar'].each do |template_type|
736
736
  minimodelns.add_cxx_class "LinExpr<#{template_type}>" do |klass|
737
737
  klass.add_constructor
738
+
739
+ klass.add_constructor do |method|
740
+ method.add_parameter "#{template_type}&", "x"
741
+ method.add_parameter "int", "a", true
742
+ end
738
743
 
739
744
  klass.add_method "post" do |method|
740
745
  method.add_parameter "Gecode::MSpace *", "home"
@@ -1175,6 +1180,7 @@ Rust::Bindings::create_bindings Rust::Bindings::LangCxx, "gecode" do |b|
1175
1180
  func.add_parameter "Gecode::IntVar", "y0"
1176
1181
  func.add_parameter "Gecode::IntVar", "y1"
1177
1182
  func.add_parameter "Gecode::IntConLevel", "icl"
1183
+ func.add_parameter "Gecode::PropKind", "pk"
1178
1184
  end
1179
1185
 
1180
1186
  ns.add_function "linear", "void" do |func|
@@ -1377,6 +1383,16 @@ Rust::Bindings::create_bindings Rust::Bindings::LangCxx, "gecode" do |b|
1377
1383
  func.add_parameter "Gecode::IntConLevel", "icl"
1378
1384
  func.add_parameter "Gecode::PropKind", "pk"
1379
1385
  end
1386
+
1387
+ ns.add_function "rel" do |func|
1388
+ func.add_parameter "Gecode::MSpace*", "home"
1389
+ func.add_parameter "Gecode::MIntVarArray *", "x" do |param|
1390
+ param.custom_conversion = "*ruby2Gecode_MIntVarArrayPtr(argv[1], 2)->ptr()"
1391
+ end
1392
+ func.add_parameter "Gecode::IntRelType", "r"
1393
+ func.add_parameter "Gecode::IntConLevel", "icl"
1394
+ func.add_parameter "Gecode::PropKind", "pk"
1395
+ end
1380
1396
 
1381
1397
  ns.add_function "rel" do |func|
1382
1398
  func.add_parameter "Gecode::MSpace*", "home"
@@ -1,8 +1,9 @@
1
1
  require 'gecoder/interface/binding_changes'
2
- require 'gecoder/interface/variables'
3
2
  require 'gecoder/interface/enum_matrix'
4
3
  require 'gecoder/interface/model'
5
4
  require 'gecoder/interface/search'
6
5
  require 'gecoder/interface/constraints'
6
+ require 'gecoder/interface/variables'
7
7
  require 'gecoder/interface/enum_wrapper'
8
8
  require 'gecoder/interface/branch'
9
+ require 'gecoder/interface/model_sugar'