gecoder-with-gecode 0.9.0-x86-mswin32-60
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGES +137 -0
- data/COPYING +17 -0
- data/LGPL-LICENSE +458 -0
- data/README +58 -0
- data/Rakefile +14 -0
- data/example/equation_system.rb +15 -0
- data/example/example_helper.rb +1 -0
- data/example/magic_sequence.rb +43 -0
- data/example/money.rb +36 -0
- data/example/queens.rb +42 -0
- data/example/send_more_money.rb +43 -0
- data/example/send_most_money.rb +58 -0
- data/example/square_tiling.rb +84 -0
- data/example/sudoku-set.rb +106 -0
- data/example/sudoku.rb +56 -0
- data/lib/gecode.dll +0 -0
- data/lib/gecoder.rb +5 -0
- data/lib/gecoder/bindings.rb +96 -0
- data/lib/gecoder/bindings/bindings.rb +2029 -0
- data/lib/gecoder/interface.rb +9 -0
- data/lib/gecoder/interface/binding_changes.rb +9 -0
- data/lib/gecoder/interface/branch.rb +163 -0
- data/lib/gecoder/interface/constraints.rb +471 -0
- data/lib/gecoder/interface/constraints/bool/boolean.rb +251 -0
- data/lib/gecoder/interface/constraints/bool/channel.rb +7 -0
- data/lib/gecoder/interface/constraints/bool/linear.rb +200 -0
- data/lib/gecoder/interface/constraints/bool_enum/channel.rb +68 -0
- data/lib/gecoder/interface/constraints/bool_enum/extensional.rb +106 -0
- data/lib/gecoder/interface/constraints/bool_enum/relation.rb +55 -0
- data/lib/gecoder/interface/constraints/bool_enum_constraints.rb +84 -0
- data/lib/gecoder/interface/constraints/bool_var_constraints.rb +155 -0
- data/lib/gecoder/interface/constraints/extensional_regexp.rb +101 -0
- 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 +150 -0
- data/lib/gecoder/interface/constraints/int/channel.rb +51 -0
- data/lib/gecoder/interface/constraints/int/domain.rb +80 -0
- data/lib/gecoder/interface/constraints/int/linear.rb +143 -0
- data/lib/gecoder/interface/constraints/int/relation.rb +141 -0
- data/lib/gecoder/interface/constraints/int_enum/arithmetic.rb +63 -0
- data/lib/gecoder/interface/constraints/int_enum/channel.rb +86 -0
- data/lib/gecoder/interface/constraints/int_enum/count.rb +66 -0
- data/lib/gecoder/interface/constraints/int_enum/distinct.rb +64 -0
- data/lib/gecoder/interface/constraints/int_enum/element.rb +64 -0
- data/lib/gecoder/interface/constraints/int_enum/equality.rb +37 -0
- data/lib/gecoder/interface/constraints/int_enum/extensional.rb +187 -0
- data/lib/gecoder/interface/constraints/int_enum/sort.rb +135 -0
- data/lib/gecoder/interface/constraints/int_enum_constraints.rb +95 -0
- data/lib/gecoder/interface/constraints/int_var_constraints.rb +230 -0
- data/lib/gecoder/interface/constraints/reifiable_constraints.rb +78 -0
- 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 +65 -0
- data/lib/gecoder/interface/constraints/set/channel.rb +51 -0
- data/lib/gecoder/interface/constraints/set/connection.rb +130 -0
- data/lib/gecoder/interface/constraints/set/domain.rb +156 -0
- data/lib/gecoder/interface/constraints/set/include.rb +36 -0
- data/lib/gecoder/interface/constraints/set/operation.rb +118 -0
- data/lib/gecoder/interface/constraints/set/relation.rb +155 -0
- 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 +45 -0
- data/lib/gecoder/interface/constraints/set_enum/distinct.rb +43 -0
- data/lib/gecoder/interface/constraints/set_enum/operation.rb +69 -0
- data/lib/gecoder/interface/constraints/set_enum/select.rb +79 -0
- data/lib/gecoder/interface/constraints/set_enum_constraints.rb +84 -0
- data/lib/gecoder/interface/constraints/set_var_constraints.rb +243 -0
- data/lib/gecoder/interface/enum_matrix.rb +64 -0
- data/lib/gecoder/interface/enum_wrapper.rb +205 -0
- data/lib/gecoder/interface/model.rb +453 -0
- data/lib/gecoder/interface/model_sugar.rb +84 -0
- data/lib/gecoder/interface/search.rb +197 -0
- data/lib/gecoder/interface/variables.rb +306 -0
- data/lib/gecoder/version.rb +4 -0
- data/specs/bool_var.rb +81 -0
- data/specs/branch.rb +185 -0
- data/specs/constraints/bool/boolean.rb +317 -0
- 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/bool_enum/extensional.rb +225 -0
- data/specs/constraints/constraint_helper.rb +234 -0
- data/specs/constraints/constraint_receivers.rb +103 -0
- data/specs/constraints/constraints.rb +26 -0
- 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 +69 -0
- 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/distribution.rb +14 -0
- data/specs/enum_matrix.rb +43 -0
- data/specs/enum_wrapper.rb +179 -0
- data/specs/examples.rb +17 -0
- data/specs/int_var.rb +163 -0
- data/specs/logging.rb +24 -0
- data/specs/model.rb +325 -0
- data/specs/model_sugar.rb +30 -0
- data/specs/search.rb +383 -0
- data/specs/selected_set.rb +39 -0
- data/specs/set_elements.rb +34 -0
- data/specs/set_var.rb +82 -0
- data/specs/spec_helper.rb +265 -0
- data/tasks/all_tasks.rb +1 -0
- data/tasks/dependencies.txt +22 -0
- data/tasks/distribution.rake +194 -0
- data/tasks/rcov.rake +18 -0
- data/tasks/specs.rake +21 -0
- data/tasks/svn.rake +16 -0
- data/tasks/website.rake +51 -0
- data/vendor/gecode/win32/lib/libgecodeint.dll +0 -0
- data/vendor/gecode/win32/lib/libgecodekernel.dll +0 -0
- data/vendor/gecode/win32/lib/libgecodeminimodel.dll +0 -0
- data/vendor/gecode/win32/lib/libgecodesearch.dll +0 -0
- data/vendor/gecode/win32/lib/libgecodeset.dll +0 -0
- data/vendor/gecode/win32/lib/libgecodesupport.dll +0 -0
- data/vendor/rust/README +28 -0
- data/vendor/rust/bin/cxxgenerator.rb +93 -0
- data/vendor/rust/include/rust_checks.hh +116 -0
- data/vendor/rust/include/rust_conversions.hh +102 -0
- data/vendor/rust/rust.rb +67 -0
- data/vendor/rust/rust/attribute.rb +51 -0
- data/vendor/rust/rust/bindings.rb +172 -0
- data/vendor/rust/rust/class.rb +337 -0
- data/vendor/rust/rust/constants.rb +48 -0
- data/vendor/rust/rust/container.rb +110 -0
- data/vendor/rust/rust/cppifaceparser.rb +129 -0
- data/vendor/rust/rust/cwrapper.rb +72 -0
- data/vendor/rust/rust/cxxclass.rb +96 -0
- data/vendor/rust/rust/element.rb +81 -0
- data/vendor/rust/rust/enum.rb +63 -0
- data/vendor/rust/rust/function.rb +407 -0
- data/vendor/rust/rust/namespace.rb +61 -0
- data/vendor/rust/rust/templates/AttributeDefinition.rusttpl +17 -0
- data/vendor/rust/rust/templates/AttributeInitBinding.rusttpl +9 -0
- data/vendor/rust/rust/templates/BindingsHeader.rusttpl +24 -0
- data/vendor/rust/rust/templates/BindingsUnit.rusttpl +46 -0
- data/vendor/rust/rust/templates/CWrapperClassDefinitions.rusttpl +64 -0
- data/vendor/rust/rust/templates/ClassDeclarations.rusttpl +7 -0
- data/vendor/rust/rust/templates/ClassInitialize.rusttpl +6 -0
- data/vendor/rust/rust/templates/ConstructorStub.rusttpl +21 -0
- data/vendor/rust/rust/templates/CxxClassDefinitions.rusttpl +100 -0
- data/vendor/rust/rust/templates/CxxMethodStub.rusttpl +12 -0
- data/vendor/rust/rust/templates/CxxStandaloneClassDefinitions.rusttpl +26 -0
- data/vendor/rust/rust/templates/EnumDeclarations.rusttpl +3 -0
- data/vendor/rust/rust/templates/EnumDefinitions.rusttpl +29 -0
- data/vendor/rust/rust/templates/FunctionDefinition.rusttpl +9 -0
- data/vendor/rust/rust/templates/FunctionInitAlias.rusttpl +5 -0
- data/vendor/rust/rust/templates/FunctionInitBinding.rusttpl +9 -0
- data/vendor/rust/rust/templates/MethodInitBinding.rusttpl +9 -0
- data/vendor/rust/rust/templates/ModuleDeclarations.rusttpl +3 -0
- data/vendor/rust/rust/templates/ModuleDefinitions.rusttpl +3 -0
- data/vendor/rust/rust/templates/StandaloneClassDeclarations.rusttpl +7 -0
- data/vendor/rust/rust/templates/VariableFunctionCall.rusttpl +14 -0
- data/vendor/rust/rust/type.rb +98 -0
- data/vendor/rust/test/Makefile +4 -0
- data/vendor/rust/test/constants.rb +36 -0
- data/vendor/rust/test/cppclass.cc +45 -0
- data/vendor/rust/test/cppclass.hh +67 -0
- data/vendor/rust/test/cppclass.rb +59 -0
- data/vendor/rust/test/cwrapper.c +74 -0
- data/vendor/rust/test/cwrapper.h +41 -0
- data/vendor/rust/test/cwrapper.rb +56 -0
- data/vendor/rust/test/dummyclass.hh +31 -0
- data/vendor/rust/test/lib/extension-test.rb +98 -0
- data/vendor/rust/test/operators.cc +41 -0
- data/vendor/rust/test/operators.hh +39 -0
- data/vendor/rust/test/operators.rb +39 -0
- data/vendor/rust/test/test-constants.rb +43 -0
- data/vendor/rust/test/test-cppclass.rb +82 -0
- data/vendor/rust/test/test-cwrapper.rb +80 -0
- data/vendor/rust/test/test-operators.rb +42 -0
- metadata +393 -0
data/README
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
= Gecode/R
|
2
|
+
|
3
|
+
Website: http://gecoder.org
|
4
|
+
|
5
|
+
Gecode/R is a Ruby interface to the Gecode constraint programming library.
|
6
|
+
Gecode/R is intended for people with no previous experience of constraint
|
7
|
+
programming, aiming to be easy to pick up and use.
|
8
|
+
|
9
|
+
See Gecode::Model to get started.
|
10
|
+
|
11
|
+
== Warning
|
12
|
+
|
13
|
+
Gecode/R is still in a development stage, the syntax is by no means final
|
14
|
+
and backwards compatibility will be broken time and time again. Don't use
|
15
|
+
Gecode/R in production-code yet, it's merely available at this point to allow
|
16
|
+
people to play with it and give feedback.
|
17
|
+
|
18
|
+
== Installation
|
19
|
+
|
20
|
+
Gecode/R requires Gecode 2.1.1, which can be downloaded from
|
21
|
+
http://www.gecode.org/download.html . See
|
22
|
+
http://www.gecode.org/gecode-doc-latest/PageComp.html for the installation
|
23
|
+
instructions.
|
24
|
+
|
25
|
+
=== Installing from gem
|
26
|
+
|
27
|
+
There are two gems. The first includes only Gecode/R, and assumes that you have
|
28
|
+
installed Gecode yourself. The second includes both Gecode/R and Gecode. If you
|
29
|
+
use Windows then you're recommended to use the second one, even though you
|
30
|
+
already have Gecode, as the other one does not come in a pre-compiled variant.
|
31
|
+
|
32
|
+
Gecode/R only:
|
33
|
+
gem install gecoder
|
34
|
+
|
35
|
+
Gecode/R and Gecode:
|
36
|
+
gem install gecoder-with-gecode
|
37
|
+
|
38
|
+
=== Installing from source using gem
|
39
|
+
|
40
|
+
rake gem
|
41
|
+
gem install pkg/gecoder-0.x.x.gem
|
42
|
+
|
43
|
+
=== Installing from source without using gem
|
44
|
+
|
45
|
+
"gecode.so" might have another extension depending on which platform it's
|
46
|
+
generated on (replace the extension in the following commands with whatever
|
47
|
+
extension it's given).
|
48
|
+
|
49
|
+
cd ext
|
50
|
+
ruby extconf.rb
|
51
|
+
make
|
52
|
+
mv gecode.so ../lib/
|
53
|
+
|
54
|
+
=== Running the tests
|
55
|
+
|
56
|
+
rake specs
|
57
|
+
|
58
|
+
Requires RSpec (1.0.5, but other version should hopefully work).
|
data/Rakefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
require 'rake/gempackagetask'
|
5
|
+
|
6
|
+
require 'tasks/all_tasks'
|
7
|
+
task :default => [:verify_rcov, :example_specs]
|
8
|
+
|
9
|
+
desc 'Performs the tasks necessary when releasing'
|
10
|
+
task :release => [:clobber, :verify_rcov, :example_specs, :publish_website,
|
11
|
+
:publish_packages, :tag]
|
12
|
+
|
13
|
+
desc 'Runs all the tests'
|
14
|
+
task :test => :specs
|
@@ -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(' ')
|
@@ -0,0 +1 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../lib/gecoder'
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/example_helper'
|
2
|
+
|
3
|
+
# Solves the magic sequence problem.
|
4
|
+
class MagicSequence < Gecode::Model
|
5
|
+
# n is the length of the sequence.
|
6
|
+
def initialize(n)
|
7
|
+
# The i:th variable represents the value of the i:th element in the
|
8
|
+
# sequence.
|
9
|
+
sequence_is_an int_var_array(n, 0...n)
|
10
|
+
|
11
|
+
# The basic requirement to qualify as a magic sequence.
|
12
|
+
n.times{ |i| sequence.count(i).must == sequence[i] }
|
13
|
+
|
14
|
+
# The following are implied constraints. They do not affect which
|
15
|
+
# assignments are solutions, but they do help prune the search space
|
16
|
+
# quicker.
|
17
|
+
|
18
|
+
# The sum must be n. This follows from that there are exactly n elements and
|
19
|
+
# that the sum of all elements are the number of occurrences in total, i.e.
|
20
|
+
# the number of elements.
|
21
|
+
sequence.sum.must == n
|
22
|
+
|
23
|
+
# sum(seq[i] * (i-1)) must equal 0 because sum(seq[i]) = n as seen above
|
24
|
+
# and sum(i*seq[i]) is just another way to compute sum(seq[i]). So we get
|
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
|
27
|
+
|
28
|
+
branch_on sequence, :variable => :smallest_degree, :value => :split_max
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_s
|
32
|
+
sequence.values.join(', ')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class Array
|
37
|
+
# Sums all the elements in the array using #+ .
|
38
|
+
def sum
|
39
|
+
inject{ |sum, element| sum + element }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
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
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/example_helper'
|
2
|
+
|
3
|
+
# Solves the n-queens problem: http://en.wikipedia.org/wiki/Nqueens . No attempt
|
4
|
+
# to break the involved symmetries is made.
|
5
|
+
class NQueens < Gecode::Model
|
6
|
+
def initialize(n)
|
7
|
+
@size = n
|
8
|
+
|
9
|
+
# The row number that the queen in the i:th column has. By using this as
|
10
|
+
# our variables we already make sure that no two queens are in the same
|
11
|
+
# column.
|
12
|
+
queen_rows_is_an int_var_array(n, 0...n)
|
13
|
+
|
14
|
+
# Set up the constraints
|
15
|
+
# Queens must not be in the same diagonal (negative slope).
|
16
|
+
queen_rows.must_be.distinct(:offsets => (0...n).to_a)
|
17
|
+
# Queens must not be in the same diagonal (positive slope).
|
18
|
+
queen_rows.must_be.distinct(:offsets => (0...n).to_a.reverse)
|
19
|
+
# Queens must not be in the same row.
|
20
|
+
queen_rows.must_be.distinct
|
21
|
+
|
22
|
+
# Branching, we use first-fail heuristic.
|
23
|
+
branch_on queen_rows, :variable => :smallest_size, :value => :min
|
24
|
+
end
|
25
|
+
|
26
|
+
# Displays the assignment as a chessboard with queens denoted by 'x'.
|
27
|
+
def to_s
|
28
|
+
rows = queen_rows.values
|
29
|
+
|
30
|
+
separator = '+' << '-' * (3 * @size + (@size - 1)) << "+\n"
|
31
|
+
res = (0...@size).inject(separator) do |s, i|
|
32
|
+
(0...@size).inject(s + '|') do |s, j|
|
33
|
+
s << " #{rows[j] == i ? 'x' : ' '} |"
|
34
|
+
end << "\n" << separator
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Print the first solution. Note that there are 92 solutions, but only 12
|
40
|
+
# are rotationally distinct. For any serious use one should place additional
|
41
|
+
# constraints to eliminate those symmetries.
|
42
|
+
puts NQueens.new((ARGV[0] || 8).to_i).solve!.to_s
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/example_helper'
|
2
|
+
|
3
|
+
# Solves the send+more=money problem:
|
4
|
+
# http://en.wikipedia.org/wiki/Send%2Bmore%3Dmoney
|
5
|
+
class SendMoreMoney < Gecode::Model
|
6
|
+
def initialize
|
7
|
+
# Set up the variables, 8 letters with domain 0..9.
|
8
|
+
s,e,n,d,m,o,r,y = @letters = int_var_array(8, 0..9)
|
9
|
+
|
10
|
+
# Set up the constraints.
|
11
|
+
# The equation must hold.
|
12
|
+
(equation_row(s, e, n, d) + equation_row(m, o, r, e)).must ==
|
13
|
+
equation_row(m, o, n, e, y)
|
14
|
+
|
15
|
+
# The initial letters may not be 0.
|
16
|
+
s.must_not == 0
|
17
|
+
m.must_not == 0
|
18
|
+
|
19
|
+
# All letters must be assigned different digits.
|
20
|
+
@letters.must_be.distinct
|
21
|
+
|
22
|
+
# Set the branching.
|
23
|
+
branch_on @letters, :variable => :smallest_size, :value => :min
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_s
|
27
|
+
%w{s e n d m o r y}.zip(@letters).map do |text, letter|
|
28
|
+
"#{text}: #{letter.value}"
|
29
|
+
end.join(', ')
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
# A helper to make the linear equation a bit tidier. Takes a number of
|
35
|
+
# variables and computes the linear combination as if the variable
|
36
|
+
# were digits in a base 10 number. E.g. x,y,z becomes
|
37
|
+
# 100*x + 10*y + z .
|
38
|
+
def equation_row(*variables)
|
39
|
+
variables.inject{ |result, variable| variable + result*10 }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
puts SendMoreMoney.new.solve!.to_s
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/example_helper'
|
2
|
+
|
3
|
+
# Solves the cryptarithmetic send+most=money problem while maximizing the value
|
4
|
+
# of "money".
|
5
|
+
class SendMoreMoney < Gecode::Model
|
6
|
+
attr :money
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
# Set up the variables, 9 letters with domain 0..9.
|
10
|
+
s,e,n,d,m,o,s,t,y = @letters = int_var_array(9, 0..9)
|
11
|
+
@money = wrap_enum([m,o,n,e,y])
|
12
|
+
|
13
|
+
# Set up the constraints.
|
14
|
+
# The equation must hold.
|
15
|
+
(equation_row(s, e, n, d) + equation_row(m, o, s, t)).must ==
|
16
|
+
equation_row(m,o,n,e,y)
|
17
|
+
|
18
|
+
# The initial letters may not be 0.
|
19
|
+
s.must_not == 0
|
20
|
+
m.must_not == 0
|
21
|
+
|
22
|
+
# All letters must be assigned different digits.
|
23
|
+
@letters.must_be.distinct
|
24
|
+
|
25
|
+
# Set the branching.
|
26
|
+
branch_on @letters, :variable => :smallest_size, :value => :min
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_s
|
30
|
+
%w{s e n d m o s t y}.zip(@letters).map do |text, letter|
|
31
|
+
"#{text}: #{letter.value}"
|
32
|
+
end.join(', ')
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
# A helper to make the linear equation a bit tidier. Takes a number of
|
38
|
+
# variables and computes the linear combination as if the variable
|
39
|
+
# were digits in a base 10 number. E.g. x,y,z becomes
|
40
|
+
# 100*x + 10*y + z .
|
41
|
+
def equation_row(*variables)
|
42
|
+
variables.to_number
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class Array
|
47
|
+
# Computes a number of the specified base using the array's elements as
|
48
|
+
# digits.
|
49
|
+
def to_number(base = 10)
|
50
|
+
inject{ |result, variable| variable + result * base }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
solution = SendMoreMoney.new.optimize! do |model, best_so_far|
|
55
|
+
model.money.to_number.must > best_so_far.money.values.to_number
|
56
|
+
end
|
57
|
+
puts solution.to_s
|
58
|
+
puts "money: #{solution.money.values.to_number}"
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/example_helper'
|
2
|
+
|
3
|
+
# Solves the square tiling problem. The objective is to pack supplied squares
|
4
|
+
# into a bigger rectangle so that there is no overlap.
|
5
|
+
class SquareTiling < Gecode::Model
|
6
|
+
# Takes the width and height of the rectangle to pack the squares into. Then
|
7
|
+
# the sizes of the squares that should be packed into the rectangle. The sizes
|
8
|
+
# must be sorted.
|
9
|
+
def initialize(width, height, square_sizes)
|
10
|
+
@sizes = square_sizes
|
11
|
+
@square_count = @sizes.size
|
12
|
+
|
13
|
+
# The coordinates of the placed squares.
|
14
|
+
@xs = int_var_array(@square_count, 0..(width - @sizes.min))
|
15
|
+
@ys = int_var_array(@square_count, 0..(height - @sizes.min))
|
16
|
+
|
17
|
+
# The essential constraints of the problem.
|
18
|
+
@square_count.times do |i|
|
19
|
+
# Each square must be placed within the bounds
|
20
|
+
@xs[i].must <= width - @sizes[i]
|
21
|
+
@ys[i].must <= height - @sizes[i]
|
22
|
+
|
23
|
+
# Pairwise conditions, no pair of squares may overlap.
|
24
|
+
0.upto(i - 1) do |j|
|
25
|
+
# That the two squares don't overlap means that i is left of j,
|
26
|
+
# or j is left of i, or i is above j, or j is above i.
|
27
|
+
((@xs[j] - @xs[i]).must >= @sizes[i]) |
|
28
|
+
((@xs[i] - @xs[j]).must >= @sizes[j]) |
|
29
|
+
((@ys[j] - @ys[i]).must >= @sizes[i]) |
|
30
|
+
((@ys[i] - @ys[j]).must >= @sizes[j])
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# A couple of implied constraints that only serve to make the solving
|
35
|
+
# faster:
|
36
|
+
|
37
|
+
# The combined size of all squares occupying a column must be equal to the
|
38
|
+
# total height.
|
39
|
+
occupied_length_must_equal_total_length(height, width, @xs)
|
40
|
+
# The combined size of all squares occupying a row must be equal to the
|
41
|
+
# total width.
|
42
|
+
occupied_length_must_equal_total_length(width, height, @ys)
|
43
|
+
|
44
|
+
# Symmetry-breaking constraint: Order squares of the same size.
|
45
|
+
@square_count.times do |i|
|
46
|
+
@xs[i].must <= @xs[i+1] if @sizes[i] == @sizes[i+1]
|
47
|
+
end
|
48
|
+
|
49
|
+
# Place the squares left to right on the x-axis first, then the y-axis.
|
50
|
+
branch_on @xs, :variable => :smallest_min, :value => :min
|
51
|
+
branch_on @ys, :variable => :smallest_min, :value => :min
|
52
|
+
end
|
53
|
+
|
54
|
+
# Constrains the combined length of the squares in the same row or column to
|
55
|
+
# equal +total_length+ in the axis of the specified coordinates +coords+,
|
56
|
+
# which is +axist_length+ long.
|
57
|
+
def occupied_length_must_equal_total_length(total_length, axis_length, coords)
|
58
|
+
axis_length.times do |i|
|
59
|
+
# We create an array of boolean variables and constrain it so that element
|
60
|
+
# +j+ is true iff square +j+ occupies +i+ (+i+ being a row or column).
|
61
|
+
occupied = bool_var_array(@square_count)
|
62
|
+
occupied.each_with_index do |is_occupying, j|
|
63
|
+
coords[j].must_be.in((i - @sizes[j] + 1)..i, :reify => is_occupying)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Constrain the combined length of squares that are occupying +i+ to equal
|
67
|
+
# the total length. We multiply the sizes with the boolean variables
|
68
|
+
# since a boolean in linear equation is 0 if assigned false and 1 if
|
69
|
+
# assigned true. Hence we will mask out the sizes of any squares not in
|
70
|
+
# +i+.
|
71
|
+
occupied_sizes = occupied.zip(@sizes).map{ |bool, size| bool*size }
|
72
|
+
occupied_sizes.inject(0){ |sum, x| x + sum }.must.equal(total_length,
|
73
|
+
:strength => :domain)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Displays the coordinates of the squares.
|
78
|
+
# TODO: Something more impressive.
|
79
|
+
def to_s
|
80
|
+
@xs.values.zip(@ys.values).map{ |x,y| "(#{x}, #{y})"}.join(', ')
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
puts SquareTiling.new(65, 47, [25, 24, 23, 22, 19, 17, 11, 6, 5, 3]).solve!.to_s
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/example_helper'
|
2
|
+
require 'enumerator'
|
3
|
+
|
4
|
+
# Solves the sudoku problem using sets. The model used is a fairly direct
|
5
|
+
# translation of the corresponding Gecode example:
|
6
|
+
# http://www.gecode.org/gecode-doc-latest/sudoku-set_8cc-source.html .
|
7
|
+
class SudokuSet < Gecode::Model
|
8
|
+
# Takes a 9x9 matrix of values in the initial sudoku, 0 if the square is
|
9
|
+
# empty.
|
10
|
+
def initialize(predefined_values)
|
11
|
+
# Verify that the input is of a valid size.
|
12
|
+
@size = n = predefined_values.row_size
|
13
|
+
block_size = Math.sqrt(n).round
|
14
|
+
unless predefined_values.square? and block_size**2 == n
|
15
|
+
raise ArgumentError, 'Incorrect value matrix size.'
|
16
|
+
end
|
17
|
+
sub_count = block_size
|
18
|
+
|
19
|
+
# Create one set per assignable number (i.e. 1..9). Each set contains the
|
20
|
+
# position of all squares that the number is located in. The squares are
|
21
|
+
# given numbers from 1 to 81. Each set therefore has an empty lower bound
|
22
|
+
# (since we have no guarantees where a number will end up) and 1..81 as
|
23
|
+
# upper bound (as it may potentially occurr in any square). We know that
|
24
|
+
# each assignable number must occurr 9 times in a solved sudoku, so we
|
25
|
+
# set the cardinality to 9..9 .
|
26
|
+
sets_is_an set_var_array(n, [], 1..n*n, n..n)
|
27
|
+
predefined_values.row_size.times do |i|
|
28
|
+
predefined_values.column_size.times do |j|
|
29
|
+
unless predefined_values[i,j].zero?
|
30
|
+
# We add the constraint that the square position must occurr in the
|
31
|
+
# set corresponding to the predefined value.
|
32
|
+
sets[predefined_values[i,j] - 1].must_be.superset_of [i*n + j+1]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Build arrays containing the square positions of each row and column.
|
38
|
+
rows = []
|
39
|
+
columns = []
|
40
|
+
n.times do |i|
|
41
|
+
rows << ((i*n + 1)..(i*n + n))
|
42
|
+
columns << (0...n).map{ |e| e*n + 1 + i }
|
43
|
+
end
|
44
|
+
|
45
|
+
# Build arrays containing the square positions of each block.
|
46
|
+
blocks = []
|
47
|
+
# The square numbers of the first block.
|
48
|
+
first_block = (0...block_size).map do |e|
|
49
|
+
((n*e+1)..(n*e+block_size)).to_a
|
50
|
+
end.flatten
|
51
|
+
block_size.times do |i|
|
52
|
+
block_size.times do |j|
|
53
|
+
blocks << first_block.map{ |e| e + (j*n*block_size)+(i*block_size) }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# All sets must be pairwise disjoint since two numbers can't be assigned to
|
58
|
+
# the same square.
|
59
|
+
n.times do |i|
|
60
|
+
(i + 1).upto(n - 1) do |j|
|
61
|
+
sets[i].must_be.disjoint_with sets[j]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# The sets must intersect in exactly one element with each row column and
|
66
|
+
# block. I.e. an assignable number must be assigned exactly once in each
|
67
|
+
# row, column and block.
|
68
|
+
sets.each do |set|
|
69
|
+
rows.each do |row|
|
70
|
+
set.intersection(row).size.must == 1
|
71
|
+
end
|
72
|
+
columns.each do |column|
|
73
|
+
set.intersection(column).size.must == 1
|
74
|
+
end
|
75
|
+
blocks.each do |block|
|
76
|
+
set.intersection(block).size.must == 1
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Branching.
|
81
|
+
branch_on sets, :variable => :none, :value => :min
|
82
|
+
end
|
83
|
+
|
84
|
+
# Outputs the assigned numbers in a grid.
|
85
|
+
def to_s
|
86
|
+
squares = []
|
87
|
+
sets.values.each_with_index do |positions, i|
|
88
|
+
positions.each{ |square_position| squares[square_position - 1] = i + 1 }
|
89
|
+
end
|
90
|
+
squares.enum_slice(@size).map{ |slice| slice.join(' ') }.join("\n")
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
predefined_squares = Matrix[
|
95
|
+
[0,0,0, 2,0,5, 0,0,0],
|
96
|
+
[0,9,0, 0,0,0, 7,3,0],
|
97
|
+
[0,0,2, 0,0,9, 0,6,0],
|
98
|
+
|
99
|
+
[2,0,0, 0,0,0, 4,0,9],
|
100
|
+
[0,0,0, 0,7,0, 0,0,0],
|
101
|
+
[6,0,9, 0,0,0, 0,0,1],
|
102
|
+
|
103
|
+
[0,8,0, 4,0,0, 1,0,0],
|
104
|
+
[0,6,3, 0,0,0, 0,8,0],
|
105
|
+
[0,0,0, 6,0,8, 0,0,0]]
|
106
|
+
puts SudokuSet.new(predefined_squares).solve!.to_s
|