gecoder-with-gecode 0.7.1-mswin32
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 +81 -0
- data/COPYING +17 -0
- data/LGPL-LICENSE +458 -0
- data/README +45 -0
- data/Rakefile +13 -0
- data/example/example_helper.rb +1 -0
- data/example/magic_sequence.rb +43 -0
- data/example/queens.rb +43 -0
- data/example/raw_bindings.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 +110 -0
- data/example/sudoku.rb +61 -0
- data/lib/gecode.dll +0 -0
- data/lib/gecoder.rb +5 -0
- data/lib/gecoder/bindings.rb +54 -0
- data/lib/gecoder/bindings/bindings.rb +2210 -0
- data/lib/gecoder/interface.rb +8 -0
- data/lib/gecoder/interface/binding_changes.rb +313 -0
- data/lib/gecoder/interface/branch.rb +152 -0
- data/lib/gecoder/interface/constraints.rb +397 -0
- data/lib/gecoder/interface/constraints/bool/boolean.rb +246 -0
- data/lib/gecoder/interface/constraints/bool/linear.rb +29 -0
- data/lib/gecoder/interface/constraints/bool_enum/boolean.rb +84 -0
- data/lib/gecoder/interface/constraints/bool_enum_constraints.rb +8 -0
- data/lib/gecoder/interface/constraints/bool_var_constraints.rb +75 -0
- data/lib/gecoder/interface/constraints/int/arithmetic.rb +71 -0
- data/lib/gecoder/interface/constraints/int/domain.rb +78 -0
- data/lib/gecoder/interface/constraints/int/linear.rb +295 -0
- data/lib/gecoder/interface/constraints/int_enum/arithmetic.rb +72 -0
- data/lib/gecoder/interface/constraints/int_enum/channel.rb +100 -0
- data/lib/gecoder/interface/constraints/int_enum/count.rb +92 -0
- data/lib/gecoder/interface/constraints/int_enum/distinct.rb +69 -0
- data/lib/gecoder/interface/constraints/int_enum/element.rb +82 -0
- data/lib/gecoder/interface/constraints/int_enum/equality.rb +38 -0
- data/lib/gecoder/interface/constraints/int_enum/sort.rb +126 -0
- data/lib/gecoder/interface/constraints/int_enum_constraints.rb +37 -0
- data/lib/gecoder/interface/constraints/int_var_constraints.rb +58 -0
- data/lib/gecoder/interface/constraints/reifiable_constraints.rb +78 -0
- data/lib/gecoder/interface/constraints/set/cardinality.rb +75 -0
- data/lib/gecoder/interface/constraints/set/connection.rb +193 -0
- data/lib/gecoder/interface/constraints/set/domain.rb +109 -0
- data/lib/gecoder/interface/constraints/set/operation.rb +132 -0
- data/lib/gecoder/interface/constraints/set/relation.rb +178 -0
- data/lib/gecoder/interface/constraints/set_enum/channel.rb +18 -0
- data/lib/gecoder/interface/constraints/set_enum/distinct.rb +80 -0
- data/lib/gecoder/interface/constraints/set_enum/operation.rb +60 -0
- data/lib/gecoder/interface/constraints/set_enum/selection.rb +217 -0
- data/lib/gecoder/interface/constraints/set_enum_constraints.rb +34 -0
- data/lib/gecoder/interface/constraints/set_var_constraints.rb +72 -0
- data/lib/gecoder/interface/enum_matrix.rb +64 -0
- data/lib/gecoder/interface/enum_wrapper.rb +153 -0
- data/lib/gecoder/interface/model.rb +251 -0
- data/lib/gecoder/interface/search.rb +123 -0
- data/lib/gecoder/interface/variables.rb +254 -0
- data/lib/gecoder/version.rb +4 -0
- data/specs/binding_changes.rb +76 -0
- data/specs/bool_var.rb +74 -0
- data/specs/branch.rb +170 -0
- data/specs/constraints/arithmetic.rb +266 -0
- data/specs/constraints/bool_enum.rb +140 -0
- data/specs/constraints/boolean.rb +232 -0
- data/specs/constraints/cardinality.rb +154 -0
- data/specs/constraints/channel.rb +126 -0
- data/specs/constraints/connection.rb +373 -0
- data/specs/constraints/constraint_helper.rb +180 -0
- data/specs/constraints/constraints.rb +74 -0
- data/specs/constraints/count.rb +139 -0
- data/specs/constraints/distinct.rb +218 -0
- data/specs/constraints/element.rb +106 -0
- data/specs/constraints/equality.rb +31 -0
- data/specs/constraints/int_domain.rb +69 -0
- data/specs/constraints/int_relation.rb +78 -0
- data/specs/constraints/linear.rb +332 -0
- data/specs/constraints/reification_sugar.rb +96 -0
- data/specs/constraints/selection.rb +292 -0
- data/specs/constraints/set_domain.rb +181 -0
- data/specs/constraints/set_operation.rb +285 -0
- data/specs/constraints/set_relation.rb +201 -0
- data/specs/constraints/sort.rb +175 -0
- data/specs/distribution.rb +14 -0
- data/specs/enum_matrix.rb +43 -0
- data/specs/enum_wrapper.rb +122 -0
- data/specs/int_var.rb +144 -0
- data/specs/logging.rb +24 -0
- data/specs/model.rb +190 -0
- data/specs/search.rb +246 -0
- data/specs/set_var.rb +68 -0
- data/specs/spec_helper.rb +93 -0
- data/tasks/all_tasks.rb +1 -0
- data/tasks/building.howto +65 -0
- data/tasks/distribution.rake +156 -0
- data/tasks/rcov.rake +17 -0
- data/tasks/specs.rake +15 -0
- data/tasks/svn.rake +11 -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/rust/README +28 -0
- data/vendor/rust/bin/cxxgenerator.rb +93 -0
- data/vendor/rust/include/rust_checks.hh +115 -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 +339 -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 +98 -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 +91 -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 +293 -0
@@ -0,0 +1,153 @@
|
|
1
|
+
module Gecode
|
2
|
+
class Model
|
3
|
+
# Wraps a custom enumerable so that constraints can be specified using it.
|
4
|
+
# The argument is altered and returned.
|
5
|
+
def wrap_enum(enum)
|
6
|
+
unless enum.kind_of? Enumerable
|
7
|
+
raise TypeError, 'Only enumerables can be wrapped.'
|
8
|
+
end
|
9
|
+
elements = enum.to_a
|
10
|
+
if elements.empty?
|
11
|
+
raise ArgumentError, 'Enumerable must not be empty.'
|
12
|
+
end
|
13
|
+
|
14
|
+
if elements.all?{ |var| var.kind_of? FreeIntVar }
|
15
|
+
class <<enum
|
16
|
+
include Gecode::IntEnumMethods
|
17
|
+
end
|
18
|
+
elsif elements.all?{ |var| var.kind_of? FreeBoolVar }
|
19
|
+
class <<enum
|
20
|
+
include Gecode::BoolEnumMethods
|
21
|
+
end
|
22
|
+
elsif elements.all?{ |var| var.kind_of? FreeSetVar }
|
23
|
+
class <<enum
|
24
|
+
include Gecode::SetEnumMethods
|
25
|
+
end
|
26
|
+
elsif elements.all?{ |var| var.kind_of? Fixnum }
|
27
|
+
class <<enum
|
28
|
+
include Gecode::FixnumEnumMethods
|
29
|
+
end
|
30
|
+
else
|
31
|
+
raise TypeError, "Enumerable doesn't contain variables #{enum.inspect}."
|
32
|
+
end
|
33
|
+
|
34
|
+
enum.model = self
|
35
|
+
return enum
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# A module containing the methods needed by enumerations containing variables.
|
40
|
+
module EnumMethods
|
41
|
+
attr_accessor :model
|
42
|
+
# Gets the current space of the model the array is connected to.
|
43
|
+
def active_space
|
44
|
+
@model.active_space
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
module VariableEnumMethods
|
49
|
+
include EnumMethods
|
50
|
+
|
51
|
+
# Gets the values of all the variables in the enum.
|
52
|
+
def values
|
53
|
+
map{ |var| var.value }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# A module containing the methods needed by enumerations containing int
|
58
|
+
# variables. Requires that it's included in an enumerable.
|
59
|
+
module IntEnumMethods
|
60
|
+
include VariableEnumMethods
|
61
|
+
|
62
|
+
# Returns an int variable array with all the bound variables.
|
63
|
+
def to_int_var_array
|
64
|
+
space = @model.active_space
|
65
|
+
unless @bound_space == space
|
66
|
+
elements = to_a
|
67
|
+
@bound_arr = Gecode::Raw::IntVarArray.new(active_space, elements.size)
|
68
|
+
elements.each_with_index{ |var, index| @bound_arr[index] = var.bind }
|
69
|
+
@bound_space = space
|
70
|
+
end
|
71
|
+
return @bound_arr
|
72
|
+
end
|
73
|
+
alias_method :to_var_array, :to_int_var_array
|
74
|
+
|
75
|
+
# Returns the smallest range that contains the domains of all integer
|
76
|
+
# variables involved.
|
77
|
+
def domain_range
|
78
|
+
inject(nil) do |range, var|
|
79
|
+
min = var.min
|
80
|
+
max = var.max
|
81
|
+
next min..max if range.nil?
|
82
|
+
|
83
|
+
range = min..range.last if min < range.first
|
84
|
+
range = range.first..max if max > range.last
|
85
|
+
range
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# A module containing the methods needed by enumerations containing boolean
|
91
|
+
# variables. Requires that it's included in an enumerable.
|
92
|
+
module BoolEnumMethods
|
93
|
+
include VariableEnumMethods
|
94
|
+
|
95
|
+
# Returns a bool variable array with all the bound variables.
|
96
|
+
def to_bool_var_array
|
97
|
+
space = @model.active_space
|
98
|
+
unless @bound_space == space
|
99
|
+
elements = to_a
|
100
|
+
@bound_arr = Gecode::Raw::BoolVarArray.new(active_space, elements.size)
|
101
|
+
elements.each_with_index{ |var, index| @bound_arr[index] = var.bind }
|
102
|
+
@bound_space = space
|
103
|
+
end
|
104
|
+
return @bound_arr
|
105
|
+
end
|
106
|
+
alias_method :to_var_array, :to_bool_var_array
|
107
|
+
end
|
108
|
+
|
109
|
+
# A module containing the methods needed by enumerations containing set
|
110
|
+
# variables. Requires that it's included in an enumerable.
|
111
|
+
module SetEnumMethods
|
112
|
+
include VariableEnumMethods
|
113
|
+
|
114
|
+
# Returns a set variable array with all the bound variables.
|
115
|
+
def to_set_var_array
|
116
|
+
space = @model.active_space
|
117
|
+
unless @bound_space == space
|
118
|
+
elements = to_a
|
119
|
+
@bound_arr = Gecode::Raw::SetVarArray.new(active_space, elements.size)
|
120
|
+
elements.each_with_index{ |var, index| @bound_arr[index] = var.bind }
|
121
|
+
@bound_space = space
|
122
|
+
end
|
123
|
+
return @bound_arr
|
124
|
+
end
|
125
|
+
alias_method :to_var_array, :to_set_var_array
|
126
|
+
|
127
|
+
# Returns the range of the union of the contained sets' upper bounds.
|
128
|
+
def upper_bound_range
|
129
|
+
inject(nil) do |range, var|
|
130
|
+
upper_bound = var.upper_bound
|
131
|
+
min = upper_bound.min
|
132
|
+
max = upper_bound.max
|
133
|
+
next min..max if range.nil?
|
134
|
+
|
135
|
+
range = min..range.last if min < range.first
|
136
|
+
range = range.first..max if max > range.last
|
137
|
+
range
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# A module containing the methods needed by enumerations containing fixnums.
|
143
|
+
# Requires that it's included in an enumerable.
|
144
|
+
module FixnumEnumMethods
|
145
|
+
include EnumMethods
|
146
|
+
|
147
|
+
# Returns the smallest range that contains the domains of all integer
|
148
|
+
# variables involved.
|
149
|
+
def domain_range
|
150
|
+
min..max
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
@@ -0,0 +1,251 @@
|
|
1
|
+
module Gecode
|
2
|
+
# Model is the base class that all models must inherit from.
|
3
|
+
class Model
|
4
|
+
# Creates a new integer variable with the specified domain. The domain can
|
5
|
+
# either be a range, a single element, or an enumeration of elements. If no
|
6
|
+
# domain is specified then the largest possible domain is used.
|
7
|
+
def int_var(domain =
|
8
|
+
Gecode::Raw::Limits::Int::INT_MIN..Gecode::Raw::Limits::Int::INT_MAX)
|
9
|
+
enum = domain_enum(domain)
|
10
|
+
index = variable_creation_space.new_int_vars(enum).first
|
11
|
+
FreeIntVar.new(self, index)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Creates an array containing the specified number of integer variables
|
15
|
+
# with the specified domain. The domain can either be a range, a single
|
16
|
+
# element, or an enumeration of elements.
|
17
|
+
def int_var_array(count, domain)
|
18
|
+
enum = domain_enum(domain)
|
19
|
+
variables = []
|
20
|
+
variable_creation_space.new_int_vars(enum, count).each do |index|
|
21
|
+
variables << FreeIntVar.new(self, index)
|
22
|
+
end
|
23
|
+
return wrap_enum(variables)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Creates a matrix containing the specified number rows and columns of
|
27
|
+
# integer variables with the specified domain. The domain can either be a
|
28
|
+
# range, a single element, or an enumeration of elements.
|
29
|
+
def int_var_matrix(row_count, col_count, domain)
|
30
|
+
enum = domain_enum(domain)
|
31
|
+
indices = variable_creation_space.new_int_vars(enum, row_count*col_count)
|
32
|
+
rows = []
|
33
|
+
row_count.times do |i|
|
34
|
+
rows << indices[(i*col_count)...(i.succ*col_count)].map! do |index|
|
35
|
+
FreeIntVar.new(self, index)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
return wrap_enum(Util::EnumMatrix.rows(rows, false))
|
39
|
+
end
|
40
|
+
|
41
|
+
# Creates a new boolean variable.
|
42
|
+
def bool_var
|
43
|
+
index = variable_creation_space.new_bool_vars.first
|
44
|
+
FreeBoolVar.new(self, index)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Creates an array containing the specified number of boolean variables.
|
48
|
+
def bool_var_array(count)
|
49
|
+
variables = []
|
50
|
+
variable_creation_space.new_bool_vars(count).each do |index|
|
51
|
+
variables << FreeBoolVar.new(self, index)
|
52
|
+
end
|
53
|
+
return wrap_enum(variables)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Creates a matrix containing the specified number rows and columns of
|
57
|
+
# boolean variables.
|
58
|
+
def bool_var_matrix(row_count, col_count)
|
59
|
+
indices = variable_creation_space.new_bool_vars(row_count*col_count)
|
60
|
+
rows = []
|
61
|
+
row_count.times do |i|
|
62
|
+
rows << indices[(i*col_count)...(i.succ*col_count)].map! do |index|
|
63
|
+
FreeBoolVar.new(self, index)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
return wrap_enum(Util::EnumMatrix.rows(rows, false))
|
67
|
+
end
|
68
|
+
|
69
|
+
# Creates a set variable with the specified domain for greatest lower bound
|
70
|
+
# and least upper bound (specified as either a range or enum). If no bounds
|
71
|
+
# are specified then the empty set is used as greates lower bound and the
|
72
|
+
# universe as least upper bound. A range for the allowed cardinality of the
|
73
|
+
# set can also be specified, if none is specified, or nil is given, then the
|
74
|
+
# default range (anything) will be used. If only a single Fixnum is
|
75
|
+
# specified as cardinality_range then it's used as lower bound.
|
76
|
+
def set_var(glb_domain = [], lub_domain =
|
77
|
+
Gecode::Raw::Limits::Set::INT_MIN..Gecode::Raw::Limits::Set::INT_MAX,
|
78
|
+
cardinality_range = nil)
|
79
|
+
check_set_bounds(glb_domain, lub_domain)
|
80
|
+
|
81
|
+
index = variable_creation_space.new_set_vars(glb_domain, lub_domain,
|
82
|
+
to_set_cardinality_range(cardinality_range)).first
|
83
|
+
FreeSetVar.new(self, index)
|
84
|
+
end
|
85
|
+
|
86
|
+
# Creates an array containing the specified number of set variables. The
|
87
|
+
# parameters beyond count are the same as for #set_var .
|
88
|
+
def set_var_array(count, glb_domain, lub_domain, cardinality_range = nil)
|
89
|
+
check_set_bounds(glb_domain, lub_domain)
|
90
|
+
|
91
|
+
variables = []
|
92
|
+
variable_creation_space.new_set_vars(glb_domain, lub_domain,
|
93
|
+
to_set_cardinality_range(cardinality_range), count).each do |index|
|
94
|
+
variables << FreeSetVar.new(self, index)
|
95
|
+
end
|
96
|
+
return wrap_enum(variables)
|
97
|
+
end
|
98
|
+
|
99
|
+
# Creates a matrix containing the specified number of rows and columns
|
100
|
+
# filled with set variables. The parameters beyond row and column counts are
|
101
|
+
# the same as for #set_var .
|
102
|
+
def set_var_matrix(row_count, col_count, glb_domain, lub_domain,
|
103
|
+
cardinality_range = nil)
|
104
|
+
check_set_bounds(glb_domain, lub_domain)
|
105
|
+
|
106
|
+
indices = variable_creation_space.new_set_vars(glb_domain, lub_domain,
|
107
|
+
to_set_cardinality_range(cardinality_range), row_count*col_count)
|
108
|
+
rows = []
|
109
|
+
row_count.times do |i|
|
110
|
+
rows << indices[(i*col_count)...(i.succ*col_count)].map! do |index|
|
111
|
+
FreeSetVar.new(self, index)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
return wrap_enum(Util::EnumMatrix.rows(rows, false))
|
115
|
+
end
|
116
|
+
|
117
|
+
# Retrieves the currently used space. Calling this method is only allowed
|
118
|
+
# when sanctioned by the model beforehand, e.g. when the model asks a
|
119
|
+
# constraint to post itself. Otherwise an RuntimeError is raised.
|
120
|
+
#
|
121
|
+
# The space returned by this method should never be stored, it should be
|
122
|
+
# rerequested from the model every time that it's needed.
|
123
|
+
def active_space #:nodoc:
|
124
|
+
unless @allow_space_access
|
125
|
+
raise 'Space access is restricted and the permission to access the ' +
|
126
|
+
'space has not been given.'
|
127
|
+
end
|
128
|
+
selected_space
|
129
|
+
end
|
130
|
+
|
131
|
+
# Adds the specified constraint to the model. Returns the newly added
|
132
|
+
# constraint.
|
133
|
+
def add_constraint(constraint) #:nodoc:
|
134
|
+
add_interaction do
|
135
|
+
constraint.post
|
136
|
+
end
|
137
|
+
return constraint
|
138
|
+
end
|
139
|
+
|
140
|
+
# Adds a block containing something that interacts with Gecode to a queue
|
141
|
+
# where it is potentially executed.
|
142
|
+
def add_interaction(&block) #:nodoc:
|
143
|
+
gecode_interaction_queue << block
|
144
|
+
end
|
145
|
+
|
146
|
+
# Allows the model's active space to be accessed while the block is
|
147
|
+
# executed. Don't use this unless you know what you're doing. Anything that
|
148
|
+
# the space is used for (such as bound variables) must be released before
|
149
|
+
# the block ends.
|
150
|
+
#
|
151
|
+
# Returns the result of the block.
|
152
|
+
def allow_space_access(&block) #:nodoc:
|
153
|
+
# We store the old value so that nested calls don't become a problem, i.e.
|
154
|
+
# access is allowed as long as one call to this method is still on the
|
155
|
+
# stack.
|
156
|
+
old = @allow_space_access
|
157
|
+
@allow_space_access = true
|
158
|
+
res = yield
|
159
|
+
@allow_space_access = old
|
160
|
+
return res
|
161
|
+
end
|
162
|
+
|
163
|
+
# Starts tracking a variable that depends on the space. All variables
|
164
|
+
# created should call this method for their respective models.
|
165
|
+
def track_variable(variable) #:nodoc:
|
166
|
+
(@variables ||= []) << variable
|
167
|
+
end
|
168
|
+
|
169
|
+
protected
|
170
|
+
|
171
|
+
# Gets a queue of objects that can be posted to the model's active_space
|
172
|
+
# (by calling their post method).
|
173
|
+
def gecode_interaction_queue #:nodoc:
|
174
|
+
@gecode_interaction_queue ||= []
|
175
|
+
end
|
176
|
+
|
177
|
+
private
|
178
|
+
|
179
|
+
# Returns an enumeration of the specified domain arguments, which can
|
180
|
+
# either be given as a range, a single number, or an enumerable of elements.
|
181
|
+
def domain_enum(domain)
|
182
|
+
if domain.respond_to?(:first) and domain.respond_to?(:last) and
|
183
|
+
domain.respond_to?(:exclude_end?)
|
184
|
+
if domain.exclude_end?
|
185
|
+
return domain.first..(domain.last - 1)
|
186
|
+
else
|
187
|
+
return domain
|
188
|
+
end
|
189
|
+
elsif domain.kind_of? Enumerable
|
190
|
+
return domain
|
191
|
+
else
|
192
|
+
return domain..domain
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
# Transforms the argument to a set cardinality range, returns nil if the
|
197
|
+
# default range should be used. If arg is a range then that's used,
|
198
|
+
# otherwise if the argument is a fixnum it's used as lower bound.
|
199
|
+
def to_set_cardinality_range(arg)
|
200
|
+
if arg.kind_of? Fixnum
|
201
|
+
arg..Gecode::Raw::Limits::Set::CARD_MAX
|
202
|
+
else
|
203
|
+
arg
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
# Checks whether the specified greatest lower bound is a subset of least
|
208
|
+
# upper bound. Raises ArgumentError if that is not the case.
|
209
|
+
def check_set_bounds(glb, lub)
|
210
|
+
unless valid_set_bounds?(glb, lub)
|
211
|
+
raise ArgumentError,
|
212
|
+
"Invalid set bounds: #{glb} is not a subset of #{lub}."
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
# Returns whether the greatest lower bound is a subset of least upper
|
217
|
+
# bound.
|
218
|
+
def valid_set_bounds?(glb, lub)
|
219
|
+
return true if glb.respond_to?(:empty?) and glb.empty?
|
220
|
+
if glb.kind_of?(Range) and lub.kind_of?(Range)
|
221
|
+
glb.first >= lub.first and glb.last <= lub.last
|
222
|
+
else
|
223
|
+
(glb.to_a - lub.to_a).empty?
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
# Retrieves the base from which searches are made.
|
228
|
+
def base_space
|
229
|
+
@base_space ||= Gecode::Raw::Space.new
|
230
|
+
end
|
231
|
+
|
232
|
+
# Retrieves the currently selected space, the one which constraints and
|
233
|
+
# variables should be bound to.
|
234
|
+
def selected_space
|
235
|
+
@active_space ||= base_space
|
236
|
+
end
|
237
|
+
|
238
|
+
# Retrieves the space that should be used for variable creation.
|
239
|
+
def variable_creation_space
|
240
|
+
@variable_creation_space || selected_space
|
241
|
+
end
|
242
|
+
|
243
|
+
# Refreshes all cached variables. This should be called if the variables
|
244
|
+
# in an existing space were changed.
|
245
|
+
def refresh_variables
|
246
|
+
@variables.each do |variable|
|
247
|
+
variable.refresh if variable.cached?
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
module Gecode
|
2
|
+
class Model
|
3
|
+
# Finds the first solution to the modelled problem and updates the variables
|
4
|
+
# to that solution. Returns the model if a solution was found, nil
|
5
|
+
# otherwise.
|
6
|
+
def solve!
|
7
|
+
space = dfs_engine.next
|
8
|
+
return nil if space.nil?
|
9
|
+
@active_space = space
|
10
|
+
return self
|
11
|
+
end
|
12
|
+
|
13
|
+
# Returns to the original state, before any search was made (but propagation
|
14
|
+
# might have been performed). Returns the reset model.
|
15
|
+
def reset!
|
16
|
+
@active_space = base_space
|
17
|
+
return self
|
18
|
+
end
|
19
|
+
|
20
|
+
# Yields the first solution (if any) to the block. If no solution is found
|
21
|
+
# then the block is not used. Returns the result of the block (nil in case
|
22
|
+
# the block wasn't run).
|
23
|
+
def solution(&block)
|
24
|
+
solution = self.solve!
|
25
|
+
res = yield solution unless solution.nil?
|
26
|
+
self.reset!
|
27
|
+
return res
|
28
|
+
end
|
29
|
+
|
30
|
+
# Yields each solution that the model has.
|
31
|
+
def each_solution(&block)
|
32
|
+
dfs = dfs_engine
|
33
|
+
while not (@active_space = dfs.next).nil?
|
34
|
+
yield self
|
35
|
+
end
|
36
|
+
self.reset!
|
37
|
+
end
|
38
|
+
|
39
|
+
# Finds the optimal solution. Optimality is defined by the provided block
|
40
|
+
# which is given one parameter, a solution to the problem. The block should
|
41
|
+
# constrain the solution so that that only "better" solutions can be new
|
42
|
+
# solutions. For instance if one wants to optimize a variable named price
|
43
|
+
# (accessible from the model) to be as low as possible then one should write
|
44
|
+
# the following.
|
45
|
+
#
|
46
|
+
# model.optimize! do |model, best_so_far|
|
47
|
+
# model.price.must < best_so_far.price.val
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# Returns nil if there is no solution.
|
51
|
+
def optimize!(&block)
|
52
|
+
# Execute constraints.
|
53
|
+
perform_queued_gecode_interactions
|
54
|
+
|
55
|
+
# Set the method used for constrain calls by the BAB-search.
|
56
|
+
Model.constrain_proc = lambda do |home_space, best_space|
|
57
|
+
@active_space = best_space
|
58
|
+
@variable_creation_space = home_space
|
59
|
+
yield(self, self)
|
60
|
+
@active_space = home_space
|
61
|
+
@variable_creation_space = nil
|
62
|
+
|
63
|
+
perform_queued_gecode_interactions
|
64
|
+
end
|
65
|
+
|
66
|
+
# Perform the search.
|
67
|
+
result = Gecode::Raw::bab(selected_space,
|
68
|
+
Gecode::Raw::Search::Config::MINIMAL_DISTANCE,
|
69
|
+
Gecode::Raw::Search::Config::ADAPTIVE_DISTANCE,
|
70
|
+
nil)
|
71
|
+
|
72
|
+
# Reset the method used constrain calls and return the result.
|
73
|
+
Model.constrain_proc = nil
|
74
|
+
return nil if result.nil?
|
75
|
+
|
76
|
+
# Refresh the solution.
|
77
|
+
result.refresh
|
78
|
+
refresh_variables
|
79
|
+
@active_space = result
|
80
|
+
return self
|
81
|
+
end
|
82
|
+
|
83
|
+
class <<self
|
84
|
+
# Sets the proc that should be used to handle constrain requests.
|
85
|
+
def constrain_proc=(proc) #:nodoc:
|
86
|
+
@constrain_proc = proc
|
87
|
+
end
|
88
|
+
|
89
|
+
# Called by spaces when they want to constrain as part of BAB-search.
|
90
|
+
def constrain(home, best) #:nodoc:
|
91
|
+
if @constrain_proc.nil?
|
92
|
+
raise NotImplementedError, 'Constrain method not implemented.'
|
93
|
+
else
|
94
|
+
@constrain_proc.call(home, best)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
# Creates a depth first search engine for search, executing any
|
102
|
+
# unexecuted constraints first.
|
103
|
+
def dfs_engine
|
104
|
+
# Execute constraints.
|
105
|
+
perform_queued_gecode_interactions
|
106
|
+
|
107
|
+
# Construct the engine.
|
108
|
+
Gecode::Raw::DFS.new(selected_space,
|
109
|
+
Gecode::Raw::Search::Config::MINIMAL_DISTANCE,
|
110
|
+
Gecode::Raw::Search::Config::ADAPTIVE_DISTANCE,
|
111
|
+
nil)
|
112
|
+
end
|
113
|
+
|
114
|
+
# Executes any interactions with Gecode still waiting in the queue
|
115
|
+
# (emptying the queue) in the process.
|
116
|
+
def perform_queued_gecode_interactions
|
117
|
+
allow_space_access do
|
118
|
+
gecode_interaction_queue.each{ |con| con.call }
|
119
|
+
gecode_interaction_queue.clear # Empty the queue.
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|