gecoder-with-gecode 0.7.1-mswin32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (159) hide show
  1. data/CHANGES +81 -0
  2. data/COPYING +17 -0
  3. data/LGPL-LICENSE +458 -0
  4. data/README +45 -0
  5. data/Rakefile +13 -0
  6. data/example/example_helper.rb +1 -0
  7. data/example/magic_sequence.rb +43 -0
  8. data/example/queens.rb +43 -0
  9. data/example/raw_bindings.rb +42 -0
  10. data/example/send_more_money.rb +43 -0
  11. data/example/send_most_money.rb +58 -0
  12. data/example/square_tiling.rb +84 -0
  13. data/example/sudoku-set.rb +110 -0
  14. data/example/sudoku.rb +61 -0
  15. data/lib/gecode.dll +0 -0
  16. data/lib/gecoder.rb +5 -0
  17. data/lib/gecoder/bindings.rb +54 -0
  18. data/lib/gecoder/bindings/bindings.rb +2210 -0
  19. data/lib/gecoder/interface.rb +8 -0
  20. data/lib/gecoder/interface/binding_changes.rb +313 -0
  21. data/lib/gecoder/interface/branch.rb +152 -0
  22. data/lib/gecoder/interface/constraints.rb +397 -0
  23. data/lib/gecoder/interface/constraints/bool/boolean.rb +246 -0
  24. data/lib/gecoder/interface/constraints/bool/linear.rb +29 -0
  25. data/lib/gecoder/interface/constraints/bool_enum/boolean.rb +84 -0
  26. data/lib/gecoder/interface/constraints/bool_enum_constraints.rb +8 -0
  27. data/lib/gecoder/interface/constraints/bool_var_constraints.rb +75 -0
  28. data/lib/gecoder/interface/constraints/int/arithmetic.rb +71 -0
  29. data/lib/gecoder/interface/constraints/int/domain.rb +78 -0
  30. data/lib/gecoder/interface/constraints/int/linear.rb +295 -0
  31. data/lib/gecoder/interface/constraints/int_enum/arithmetic.rb +72 -0
  32. data/lib/gecoder/interface/constraints/int_enum/channel.rb +100 -0
  33. data/lib/gecoder/interface/constraints/int_enum/count.rb +92 -0
  34. data/lib/gecoder/interface/constraints/int_enum/distinct.rb +69 -0
  35. data/lib/gecoder/interface/constraints/int_enum/element.rb +82 -0
  36. data/lib/gecoder/interface/constraints/int_enum/equality.rb +38 -0
  37. data/lib/gecoder/interface/constraints/int_enum/sort.rb +126 -0
  38. data/lib/gecoder/interface/constraints/int_enum_constraints.rb +37 -0
  39. data/lib/gecoder/interface/constraints/int_var_constraints.rb +58 -0
  40. data/lib/gecoder/interface/constraints/reifiable_constraints.rb +78 -0
  41. data/lib/gecoder/interface/constraints/set/cardinality.rb +75 -0
  42. data/lib/gecoder/interface/constraints/set/connection.rb +193 -0
  43. data/lib/gecoder/interface/constraints/set/domain.rb +109 -0
  44. data/lib/gecoder/interface/constraints/set/operation.rb +132 -0
  45. data/lib/gecoder/interface/constraints/set/relation.rb +178 -0
  46. data/lib/gecoder/interface/constraints/set_enum/channel.rb +18 -0
  47. data/lib/gecoder/interface/constraints/set_enum/distinct.rb +80 -0
  48. data/lib/gecoder/interface/constraints/set_enum/operation.rb +60 -0
  49. data/lib/gecoder/interface/constraints/set_enum/selection.rb +217 -0
  50. data/lib/gecoder/interface/constraints/set_enum_constraints.rb +34 -0
  51. data/lib/gecoder/interface/constraints/set_var_constraints.rb +72 -0
  52. data/lib/gecoder/interface/enum_matrix.rb +64 -0
  53. data/lib/gecoder/interface/enum_wrapper.rb +153 -0
  54. data/lib/gecoder/interface/model.rb +251 -0
  55. data/lib/gecoder/interface/search.rb +123 -0
  56. data/lib/gecoder/interface/variables.rb +254 -0
  57. data/lib/gecoder/version.rb +4 -0
  58. data/specs/binding_changes.rb +76 -0
  59. data/specs/bool_var.rb +74 -0
  60. data/specs/branch.rb +170 -0
  61. data/specs/constraints/arithmetic.rb +266 -0
  62. data/specs/constraints/bool_enum.rb +140 -0
  63. data/specs/constraints/boolean.rb +232 -0
  64. data/specs/constraints/cardinality.rb +154 -0
  65. data/specs/constraints/channel.rb +126 -0
  66. data/specs/constraints/connection.rb +373 -0
  67. data/specs/constraints/constraint_helper.rb +180 -0
  68. data/specs/constraints/constraints.rb +74 -0
  69. data/specs/constraints/count.rb +139 -0
  70. data/specs/constraints/distinct.rb +218 -0
  71. data/specs/constraints/element.rb +106 -0
  72. data/specs/constraints/equality.rb +31 -0
  73. data/specs/constraints/int_domain.rb +69 -0
  74. data/specs/constraints/int_relation.rb +78 -0
  75. data/specs/constraints/linear.rb +332 -0
  76. data/specs/constraints/reification_sugar.rb +96 -0
  77. data/specs/constraints/selection.rb +292 -0
  78. data/specs/constraints/set_domain.rb +181 -0
  79. data/specs/constraints/set_operation.rb +285 -0
  80. data/specs/constraints/set_relation.rb +201 -0
  81. data/specs/constraints/sort.rb +175 -0
  82. data/specs/distribution.rb +14 -0
  83. data/specs/enum_matrix.rb +43 -0
  84. data/specs/enum_wrapper.rb +122 -0
  85. data/specs/int_var.rb +144 -0
  86. data/specs/logging.rb +24 -0
  87. data/specs/model.rb +190 -0
  88. data/specs/search.rb +246 -0
  89. data/specs/set_var.rb +68 -0
  90. data/specs/spec_helper.rb +93 -0
  91. data/tasks/all_tasks.rb +1 -0
  92. data/tasks/building.howto +65 -0
  93. data/tasks/distribution.rake +156 -0
  94. data/tasks/rcov.rake +17 -0
  95. data/tasks/specs.rake +15 -0
  96. data/tasks/svn.rake +11 -0
  97. data/tasks/website.rake +51 -0
  98. data/vendor/gecode/win32/lib/libgecodeint.dll +0 -0
  99. data/vendor/gecode/win32/lib/libgecodekernel.dll +0 -0
  100. data/vendor/gecode/win32/lib/libgecodeminimodel.dll +0 -0
  101. data/vendor/gecode/win32/lib/libgecodesearch.dll +0 -0
  102. data/vendor/gecode/win32/lib/libgecodeset.dll +0 -0
  103. data/vendor/rust/README +28 -0
  104. data/vendor/rust/bin/cxxgenerator.rb +93 -0
  105. data/vendor/rust/include/rust_checks.hh +115 -0
  106. data/vendor/rust/include/rust_conversions.hh +102 -0
  107. data/vendor/rust/rust.rb +67 -0
  108. data/vendor/rust/rust/attribute.rb +51 -0
  109. data/vendor/rust/rust/bindings.rb +172 -0
  110. data/vendor/rust/rust/class.rb +339 -0
  111. data/vendor/rust/rust/constants.rb +48 -0
  112. data/vendor/rust/rust/container.rb +110 -0
  113. data/vendor/rust/rust/cppifaceparser.rb +129 -0
  114. data/vendor/rust/rust/cwrapper.rb +72 -0
  115. data/vendor/rust/rust/cxxclass.rb +98 -0
  116. data/vendor/rust/rust/element.rb +81 -0
  117. data/vendor/rust/rust/enum.rb +63 -0
  118. data/vendor/rust/rust/function.rb +407 -0
  119. data/vendor/rust/rust/namespace.rb +61 -0
  120. data/vendor/rust/rust/templates/AttributeDefinition.rusttpl +17 -0
  121. data/vendor/rust/rust/templates/AttributeInitBinding.rusttpl +9 -0
  122. data/vendor/rust/rust/templates/BindingsHeader.rusttpl +24 -0
  123. data/vendor/rust/rust/templates/BindingsUnit.rusttpl +46 -0
  124. data/vendor/rust/rust/templates/CWrapperClassDefinitions.rusttpl +64 -0
  125. data/vendor/rust/rust/templates/ClassDeclarations.rusttpl +7 -0
  126. data/vendor/rust/rust/templates/ClassInitialize.rusttpl +6 -0
  127. data/vendor/rust/rust/templates/ConstructorStub.rusttpl +21 -0
  128. data/vendor/rust/rust/templates/CxxClassDefinitions.rusttpl +91 -0
  129. data/vendor/rust/rust/templates/CxxMethodStub.rusttpl +12 -0
  130. data/vendor/rust/rust/templates/CxxStandaloneClassDefinitions.rusttpl +26 -0
  131. data/vendor/rust/rust/templates/EnumDeclarations.rusttpl +3 -0
  132. data/vendor/rust/rust/templates/EnumDefinitions.rusttpl +29 -0
  133. data/vendor/rust/rust/templates/FunctionDefinition.rusttpl +9 -0
  134. data/vendor/rust/rust/templates/FunctionInitAlias.rusttpl +5 -0
  135. data/vendor/rust/rust/templates/FunctionInitBinding.rusttpl +9 -0
  136. data/vendor/rust/rust/templates/MethodInitBinding.rusttpl +9 -0
  137. data/vendor/rust/rust/templates/ModuleDeclarations.rusttpl +3 -0
  138. data/vendor/rust/rust/templates/ModuleDefinitions.rusttpl +3 -0
  139. data/vendor/rust/rust/templates/StandaloneClassDeclarations.rusttpl +7 -0
  140. data/vendor/rust/rust/templates/VariableFunctionCall.rusttpl +14 -0
  141. data/vendor/rust/rust/type.rb +98 -0
  142. data/vendor/rust/test/Makefile +4 -0
  143. data/vendor/rust/test/constants.rb +36 -0
  144. data/vendor/rust/test/cppclass.cc +45 -0
  145. data/vendor/rust/test/cppclass.hh +67 -0
  146. data/vendor/rust/test/cppclass.rb +59 -0
  147. data/vendor/rust/test/cwrapper.c +74 -0
  148. data/vendor/rust/test/cwrapper.h +41 -0
  149. data/vendor/rust/test/cwrapper.rb +56 -0
  150. data/vendor/rust/test/dummyclass.hh +31 -0
  151. data/vendor/rust/test/lib/extension-test.rb +98 -0
  152. data/vendor/rust/test/operators.cc +41 -0
  153. data/vendor/rust/test/operators.hh +39 -0
  154. data/vendor/rust/test/operators.rb +39 -0
  155. data/vendor/rust/test/test-constants.rb +43 -0
  156. data/vendor/rust/test/test-cppclass.rb +82 -0
  157. data/vendor/rust/test/test-cwrapper.rb +80 -0
  158. data/vendor/rust/test/test-operators.rb +42 -0
  159. 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