gecoder 0.8.3 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +15 -0
- data/README +6 -2
- data/example/equation_system.rb +15 -0
- data/example/magic_sequence.rb +7 -7
- data/example/money.rb +36 -0
- data/example/queens.rb +7 -8
- data/example/send_most_money.rb +1 -1
- data/example/square_tiling.rb +2 -2
- data/example/sudoku-set.rb +11 -12
- data/example/sudoku.rb +40 -45
- data/ext/extconf.rb +0 -0
- data/lib/gecoder/bindings.rb +42 -0
- data/lib/gecoder/bindings/bindings.rb +16 -0
- data/lib/gecoder/interface.rb +2 -1
- data/lib/gecoder/interface/branch.rb +16 -9
- data/lib/gecoder/interface/constraints.rb +410 -451
- data/lib/gecoder/interface/constraints/bool/boolean.rb +205 -213
- data/lib/gecoder/interface/constraints/bool/channel.rb +4 -5
- data/lib/gecoder/interface/constraints/bool/linear.rb +192 -21
- data/lib/gecoder/interface/constraints/bool_enum/channel.rb +43 -39
- data/lib/gecoder/interface/constraints/bool_enum/extensional.rb +43 -49
- data/lib/gecoder/interface/constraints/bool_enum/relation.rb +38 -71
- data/lib/gecoder/interface/constraints/bool_enum_constraints.rb +73 -22
- data/lib/gecoder/interface/constraints/bool_var_constraints.rb +140 -61
- data/lib/gecoder/interface/constraints/extensional_regexp.rb +4 -4
- data/lib/gecoder/interface/constraints/fixnum_enum/element.rb +63 -0
- data/lib/gecoder/interface/constraints/fixnum_enum/operation.rb +65 -0
- data/lib/gecoder/interface/constraints/fixnum_enum_constraints.rb +42 -0
- data/lib/gecoder/interface/constraints/int/arithmetic.rb +131 -130
- data/lib/gecoder/interface/constraints/int/channel.rb +21 -31
- data/lib/gecoder/interface/constraints/int/domain.rb +45 -42
- data/lib/gecoder/interface/constraints/int/linear.rb +85 -239
- data/lib/gecoder/interface/constraints/int/relation.rb +141 -0
- data/lib/gecoder/interface/constraints/int_enum/arithmetic.rb +55 -64
- data/lib/gecoder/interface/constraints/int_enum/channel.rb +35 -37
- data/lib/gecoder/interface/constraints/int_enum/count.rb +53 -78
- data/lib/gecoder/interface/constraints/int_enum/distinct.rb +36 -46
- data/lib/gecoder/interface/constraints/int_enum/element.rb +39 -57
- data/lib/gecoder/interface/constraints/int_enum/equality.rb +15 -19
- data/lib/gecoder/interface/constraints/int_enum/extensional.rb +65 -72
- data/lib/gecoder/interface/constraints/int_enum/sort.rb +42 -45
- data/lib/gecoder/interface/constraints/int_enum_constraints.rb +79 -22
- data/lib/gecoder/interface/constraints/int_var_constraints.rb +215 -44
- data/lib/gecoder/interface/constraints/reifiable_constraints.rb +14 -14
- data/lib/gecoder/interface/constraints/selected_set/select.rb +120 -0
- data/lib/gecoder/interface/constraints/selected_set_constraints.rb +75 -0
- data/lib/gecoder/interface/constraints/set/cardinality.rb +43 -53
- data/lib/gecoder/interface/constraints/set/channel.rb +26 -29
- data/lib/gecoder/interface/constraints/set/connection.rb +89 -152
- data/lib/gecoder/interface/constraints/set/domain.rb +112 -65
- data/lib/gecoder/interface/constraints/set/include.rb +36 -0
- data/lib/gecoder/interface/constraints/set/operation.rb +96 -110
- data/lib/gecoder/interface/constraints/set/relation.rb +114 -137
- data/lib/gecoder/interface/constraints/set_elements/relation.rb +116 -0
- data/lib/gecoder/interface/constraints/set_elements_constraints.rb +97 -0
- data/lib/gecoder/interface/constraints/set_enum/channel.rb +23 -27
- data/lib/gecoder/interface/constraints/set_enum/distinct.rb +18 -19
- data/lib/gecoder/interface/constraints/set_enum/operation.rb +62 -53
- data/lib/gecoder/interface/constraints/set_enum/select.rb +79 -0
- data/lib/gecoder/interface/constraints/set_enum_constraints.rb +73 -23
- data/lib/gecoder/interface/constraints/set_var_constraints.rb +222 -57
- data/lib/gecoder/interface/enum_matrix.rb +4 -4
- data/lib/gecoder/interface/enum_wrapper.rb +71 -22
- data/lib/gecoder/interface/model.rb +167 -12
- data/lib/gecoder/interface/model_sugar.rb +84 -0
- data/lib/gecoder/interface/search.rb +30 -18
- data/lib/gecoder/interface/variables.rb +103 -33
- data/lib/gecoder/version.rb +2 -2
- data/specs/bool_var.rb +19 -12
- data/specs/constraints/{boolean.rb → bool/boolean.rb} +103 -28
- data/specs/constraints/bool/boolean_properties.rb +51 -0
- data/specs/constraints/bool/linear.rb +213 -0
- data/specs/constraints/bool_enum/bool_enum_relation.rb +117 -0
- data/specs/constraints/bool_enum/channel.rb +102 -0
- data/specs/constraints/{extensional.rb → bool_enum/extensional.rb} +32 -101
- data/specs/constraints/constraint_helper.rb +149 -179
- data/specs/constraints/constraint_receivers.rb +103 -0
- data/specs/constraints/constraints.rb +6 -63
- data/specs/constraints/fixnum_enum/element.rb +58 -0
- data/specs/constraints/fixnum_enum/operation.rb +67 -0
- data/specs/constraints/int/arithmetic.rb +149 -0
- data/specs/constraints/int/channel.rb +101 -0
- data/specs/constraints/int/domain.rb +106 -0
- data/specs/constraints/int/linear.rb +183 -0
- data/specs/constraints/int/linear_properties.rb +97 -0
- data/specs/constraints/int/relation.rb +84 -0
- data/specs/constraints/int_enum/arithmetic.rb +72 -0
- data/specs/constraints/int_enum/channel.rb +57 -0
- data/specs/constraints/int_enum/count.rb +72 -0
- data/specs/constraints/int_enum/distinct.rb +80 -0
- data/specs/constraints/int_enum/element.rb +61 -0
- data/specs/constraints/int_enum/equality.rb +29 -0
- data/specs/constraints/int_enum/extensional.rb +224 -0
- data/specs/constraints/int_enum/sort.rb +167 -0
- data/specs/constraints/operands.rb +264 -0
- data/specs/constraints/property_helper.rb +443 -0
- data/specs/constraints/reification_sugar.rb +4 -5
- data/specs/constraints/selected_set/select.rb +56 -0
- data/specs/constraints/selected_set/select_properties.rb +157 -0
- data/specs/constraints/set/cardinality.rb +58 -0
- data/specs/constraints/set/cardinality_properties.rb +46 -0
- data/specs/constraints/set/channel.rb +77 -0
- data/specs/constraints/set/connection.rb +176 -0
- data/specs/constraints/set/domain.rb +197 -0
- data/specs/constraints/set/include.rb +36 -0
- data/specs/constraints/set/operation.rb +132 -0
- data/specs/constraints/set/relation.rb +117 -0
- data/specs/constraints/set_elements/relation.rb +84 -0
- data/specs/constraints/set_enum/channel.rb +80 -0
- data/specs/constraints/set_enum/distinct.rb +59 -0
- data/specs/constraints/set_enum/operation.rb +111 -0
- data/specs/constraints/set_enum/select.rb +73 -0
- data/specs/enum_wrapper.rb +53 -3
- data/specs/int_var.rb +44 -25
- data/specs/model.rb +58 -1
- data/specs/model_sugar.rb +30 -0
- data/specs/search.rb +24 -5
- data/specs/selected_set.rb +39 -0
- data/specs/set_elements.rb +34 -0
- data/specs/set_var.rb +22 -8
- data/specs/spec_helper.rb +206 -6
- data/tasks/distribution.rake +22 -7
- data/tasks/svn.rake +3 -1
- metadata +218 -134
- data/lib/gecoder/interface/constraints/set_enum/selection.rb +0 -217
- data/specs/constraints/arithmetic.rb +0 -351
- data/specs/constraints/bool_enum_relation.rb +0 -160
- data/specs/constraints/cardinality.rb +0 -157
- data/specs/constraints/channel.rb +0 -454
- data/specs/constraints/connection.rb +0 -369
- data/specs/constraints/count.rb +0 -146
- data/specs/constraints/distinct.rb +0 -164
- data/specs/constraints/element.rb +0 -108
- data/specs/constraints/equality.rb +0 -31
- data/specs/constraints/int_domain.rb +0 -70
- data/specs/constraints/int_relation.rb +0 -82
- data/specs/constraints/linear.rb +0 -340
- data/specs/constraints/selection.rb +0 -292
- data/specs/constraints/set_domain.rb +0 -185
- data/specs/constraints/set_operation.rb +0 -285
- data/specs/constraints/set_relation.rb +0 -197
- 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
|
-
|
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
|
-
|
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(' ')
|
data/example/magic_sequence.rb
CHANGED
@@ -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
|
-
|
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|
|
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
|
-
|
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
|
-
|
26
|
+
sequence.zip((-1...n).to_a).map{ |element, c| element*c }.sum.must == 0
|
27
27
|
|
28
|
-
branch_on
|
28
|
+
branch_on sequence, :variable => :smallest_degree, :value => :split_max
|
29
29
|
end
|
30
30
|
|
31
31
|
def to_s
|
32
|
-
|
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
|
43
|
+
puts MagicSequence.new(500).solve!.to_s
|
data/example/money.rb
ADDED
@@ -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(' ')
|
data/example/queens.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
16
|
+
queen_rows.must_be.distinct(:offsets => (0...n).to_a)
|
17
17
|
# Queens must not be in the same diagonal (positive slope).
|
18
|
-
|
18
|
+
queen_rows.must_be.distinct(:offsets => (0...n).to_a.reverse)
|
19
19
|
# Queens must not be in the same row.
|
20
|
-
|
20
|
+
queen_rows.must_be.distinct
|
21
21
|
|
22
22
|
# Branching, we use first-fail heuristic.
|
23
|
-
branch_on
|
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 =
|
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(
|
43
|
-
|
42
|
+
puts NQueens.new((ARGV[0] || 8).to_i).solve!.to_s
|
data/example/send_most_money.rb
CHANGED
data/example/square_tiling.rb
CHANGED
@@ -74,11 +74,11 @@ class SquareTiling < Gecode::Model
|
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
77
|
-
# Displays the
|
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
|
84
|
+
puts SquareTiling.new(65, 47, [25, 24, 23, 22, 19, 17, 11, 6, 5, 3]).solve!.to_s
|
data/example/sudoku-set.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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.
|
68
|
-
|
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 ==
|
70
|
+
set.intersection(row).size.must == 1
|
72
71
|
end
|
73
72
|
columns.each do |column|
|
74
|
-
set.intersection(column).must ==
|
73
|
+
set.intersection(column).size.must == 1
|
75
74
|
end
|
76
75
|
blocks.each do |block|
|
77
|
-
set.intersection(block).must ==
|
76
|
+
set.intersection(block).size.must == 1
|
78
77
|
end
|
79
78
|
end
|
80
79
|
|
81
80
|
# Branching.
|
82
|
-
branch_on
|
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
|
-
|
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
|
106
|
+
puts SudokuSet.new(predefined_squares).solve!.to_s
|
data/example/sudoku.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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($/)
|
data/ext/extconf.rb
CHANGED
File without changes
|
data/lib/gecoder/bindings.rb
CHANGED
@@ -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"
|
data/lib/gecoder/interface.rb
CHANGED
@@ -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'
|