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.
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