gecoder 0.4.0 → 0.5.0
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 +11 -0
- data/README +12 -1
- 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/sudoku.rb +65 -0
- data/ext/missing.cpp +15 -21
- data/ext/missing.h +14 -20
- data/ext/vararray.cpp +14 -20
- data/ext/vararray.h +18 -22
- data/lib/gecoder/bindings/bindings.rb +1979 -1969
- data/lib/gecoder/interface/binding_changes.rb +123 -2
- data/lib/gecoder/interface/constraints/bool/boolean.rb +80 -65
- data/lib/gecoder/interface/constraints/bool_enum/boolean.rb +59 -0
- data/lib/gecoder/interface/constraints/bool_enum_constraints.rb +8 -0
- data/lib/gecoder/interface/constraints/bool_var_constraints.rb +42 -0
- data/lib/gecoder/interface/constraints/int/arithmetic.rb +21 -44
- data/lib/gecoder/interface/constraints/int/domain.rb +6 -4
- data/lib/gecoder/interface/constraints/int_enum/arithmetic.rb +18 -44
- data/lib/gecoder/interface/constraints/int_enum/count.rb +3 -18
- data/lib/gecoder/interface/constraints/int_enum/distinct.rb +4 -16
- data/lib/gecoder/interface/constraints/int_enum/element.rb +9 -20
- data/lib/gecoder/interface/constraints/int_var_constraints.rb +28 -0
- data/lib/gecoder/interface/constraints/set/cardinality.rb +56 -0
- data/lib/gecoder/interface/constraints/set/domain.rb +66 -0
- data/lib/gecoder/interface/constraints/set/relation.rb +125 -0
- data/lib/gecoder/interface/constraints/set_var_constraints.rb +37 -0
- data/lib/gecoder/interface/constraints.rb +229 -65
- data/lib/gecoder/interface/enum_wrapper.rb +42 -11
- data/lib/gecoder/interface/model.rb +75 -0
- data/lib/gecoder/interface/search.rb +4 -9
- data/lib/gecoder/interface/variables.rb +36 -2
- data/lib/gecoder/version.rb +1 -1
- data/specs/bool_var.rb +58 -0
- data/specs/constraints/arithmetic.rb +91 -90
- data/specs/constraints/bool_enum.rb +130 -0
- data/specs/constraints/boolean.rb +95 -2
- data/specs/constraints/cardinality.rb +127 -0
- data/specs/constraints/constraint_helper.rb +91 -0
- data/specs/constraints/constraints.rb +31 -0
- data/specs/constraints/element.rb +43 -72
- data/specs/constraints/{domain.rb → int_domain.rb} +4 -0
- data/specs/constraints/{relation.rb → int_relation.rb} +0 -0
- data/specs/constraints/set_domain.rb +165 -0
- data/specs/constraints/set_relation.rb +181 -0
- data/specs/enum_wrapper.rb +13 -2
- data/specs/int_var.rb +33 -1
- data/specs/model.rb +80 -0
- data/specs/set_var.rb +39 -0
- data/specs/spec_helper.rb +35 -0
- data/specs/tmp +11 -124
- data/tasks/distribution.rake +1 -1
- data/vendor/rust/rust/class.rb +10 -10
- data/vendor/rust/rust/constants.rb +1 -1
- data/vendor/rust/rust/function.rb +5 -5
- data/vendor/rust/rust/type.rb +1 -1
- data/vendor/rust/test/constants.rb +1 -0
- data/vendor/rust/test/cppclass.cc +5 -0
- data/vendor/rust/test/cppclass.hh +4 -0
- data/vendor/rust/test/lib/extension-test.rb +1 -1
- 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-cwrapper.rb +3 -0
- data/vendor/rust/test/test-operators.rb +42 -0
- metadata +31 -4
@@ -33,70 +33,6 @@ module Gecode
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
-
# Describes a constraint expressions. An expression is produced by calling
|
37
|
-
# some form of must on a left hand side. The expression waits for a right
|
38
|
-
# hand side so that it can post the corresponding constraint.
|
39
|
-
class Expression
|
40
|
-
# Constructs a new expression with the specified parameters. The
|
41
|
-
# parameters shoud at least contain the keys :lhs, and :negate.
|
42
|
-
#
|
43
|
-
# Raises ArgumentError if any of those keys are missing.
|
44
|
-
def initialize(model, params)
|
45
|
-
unless params.has_key?(:lhs) and params.has_key?(:negate)
|
46
|
-
raise ArgumentError, 'Expression requires at least :lhs, ' +
|
47
|
-
"and :negate as parameter keys, got #{params.keys.join(', ')}."
|
48
|
-
end
|
49
|
-
|
50
|
-
@model = model
|
51
|
-
@params = params
|
52
|
-
end
|
53
|
-
|
54
|
-
private
|
55
|
-
|
56
|
-
# Creates aliases for any defined comparison methods.
|
57
|
-
def self.alias_comparison_methods
|
58
|
-
Gecode::Constraints::Util::COMPARISON_ALIASES.each_pair do |orig, aliases|
|
59
|
-
if instance_methods.include?(orig.to_s)
|
60
|
-
aliases.each do |name|
|
61
|
-
alias_method(name, orig)
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
# Describes a constraint expression that has yet to be completed. I.e. a
|
69
|
-
# form of must has not yet been called, but some method has been called to
|
70
|
-
# initiate the expression. An example is distinct with offsets:
|
71
|
-
#
|
72
|
-
# enum.with_offsets(0..n).must_be.distinct
|
73
|
-
#
|
74
|
-
# The call of with_offsets initiates the constraint as a stub, even though
|
75
|
-
# must has not yet been called.
|
76
|
-
class ExpressionStub
|
77
|
-
# Constructs a new expression with the specified parameters.
|
78
|
-
def initialize(model, params)
|
79
|
-
@model = model
|
80
|
-
@params = params
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
# Base class for all constraints.
|
85
|
-
class Constraint
|
86
|
-
# Creates a constraint with the specified parameters, bound to the
|
87
|
-
# specified model.
|
88
|
-
def initialize(model, params)
|
89
|
-
@model = model
|
90
|
-
@params = params.clone
|
91
|
-
end
|
92
|
-
|
93
|
-
# Posts the constraint, adding it to the model. This is an abstract
|
94
|
-
# method and should be overridden by all sub-classes.
|
95
|
-
def post
|
96
|
-
raise NoMethodError, 'Abstract method has not been implemented.'
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
36
|
# A module that provides some utility-methods for constraints.
|
101
37
|
module Util
|
102
38
|
# Maps the name used in options to the value used in Gecode for
|
@@ -115,7 +51,8 @@ module Gecode
|
|
115
51
|
:<= => Gecode::Raw::IRT_LQ,
|
116
52
|
:< => Gecode::Raw::IRT_LE,
|
117
53
|
:>= => Gecode::Raw::IRT_GQ,
|
118
|
-
:> => Gecode::Raw::IRT_GR
|
54
|
+
:> => Gecode::Raw::IRT_GR
|
55
|
+
}
|
119
56
|
# The same as above, but negated.
|
120
57
|
NEGATED_RELATION_TYPES = {
|
121
58
|
:== => Gecode::Raw::IRT_NQ,
|
@@ -125,6 +62,20 @@ module Gecode
|
|
125
62
|
:> => Gecode::Raw::IRT_LQ
|
126
63
|
}
|
127
64
|
|
65
|
+
# Maps the names of the methods to the corresponding set relation type in
|
66
|
+
# Gecode.
|
67
|
+
SET_RELATION_TYPES = {
|
68
|
+
:== => Gecode::Raw::SRT_EQ,
|
69
|
+
:superset => Gecode::Raw::SRT_SUP,
|
70
|
+
:subset => Gecode::Raw::SRT_SUB,
|
71
|
+
:disjoint => Gecode::Raw::SRT_DISJ,
|
72
|
+
:complement => Gecode::Raw::SRT_CMPL
|
73
|
+
}
|
74
|
+
# The same as above, but negated.
|
75
|
+
NEGATED_SET_RELATION_TYPES = {
|
76
|
+
:== => Gecode::Raw::SRT_NQ
|
77
|
+
}
|
78
|
+
|
128
79
|
# Various method aliases for comparison methods. Maps the original
|
129
80
|
# (symbol) name to an array of aliases.
|
130
81
|
COMPARISON_ALIASES = {
|
@@ -134,6 +85,13 @@ module Gecode
|
|
134
85
|
:< => [:less, :less_than],
|
135
86
|
:<= => [:less_or_equal, :less_than_or_equal_to]
|
136
87
|
}
|
88
|
+
SET_ALIASES = {
|
89
|
+
:== => [:equal, :equal_to],
|
90
|
+
:superset => [:superset_of],
|
91
|
+
:subset => [:subset_of],
|
92
|
+
:disjoint => [:disjoint_with],
|
93
|
+
:complement => [:complement_of]
|
94
|
+
}
|
137
95
|
|
138
96
|
module_function
|
139
97
|
|
@@ -167,6 +125,210 @@ module Gecode
|
|
167
125
|
end
|
168
126
|
return {:strength => PROPAGATION_STRENGTHS[strength], :reif => reif_var}
|
169
127
|
end
|
128
|
+
|
129
|
+
# Converts the different ways to specify constant sets in the interface
|
130
|
+
# to the form that the set should be represented in Gecode (possibly
|
131
|
+
# multiple paramters. The different forms accepted are:
|
132
|
+
# * Single instance of Fixnum (singleton set).
|
133
|
+
# * Range (set containing all numbers in range), treated differently from
|
134
|
+
# other enumerations.
|
135
|
+
# * Enumeration of integers (set contaning all numbers in set).
|
136
|
+
def constant_set_to_params(constant_set)
|
137
|
+
if constant_set.kind_of? Range
|
138
|
+
return constant_set.first, constant_set.last
|
139
|
+
elsif constant_set.kind_of? Fixnum
|
140
|
+
return constant_set
|
141
|
+
else
|
142
|
+
constant_set = constant_set.to_a
|
143
|
+
unless constant_set.all?{ |e| e.kind_of? Fixnum }
|
144
|
+
raise TypeError, "Not a constant set: #{constant_set}."
|
145
|
+
end
|
146
|
+
return Gecode::Raw::IntSet.new(constant_set, constant_set.size)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# Describes a constraint expressions. An expression is produced by calling
|
152
|
+
# some form of must on a left hand side. The expression waits for a right
|
153
|
+
# hand side so that it can post the corresponding constraint.
|
154
|
+
class Expression
|
155
|
+
# Constructs a new expression with the specified parameters. The
|
156
|
+
# parameters shoud at least contain the keys :lhs, and :negate.
|
157
|
+
#
|
158
|
+
# Raises ArgumentError if any of those keys are missing.
|
159
|
+
def initialize(model, params)
|
160
|
+
unless params.has_key?(:lhs) and params.has_key?(:negate)
|
161
|
+
raise ArgumentError, 'Expression requires at least :lhs, ' +
|
162
|
+
"and :negate as parameter keys, got #{params.keys.join(', ')}."
|
163
|
+
end
|
164
|
+
|
165
|
+
@model = model
|
166
|
+
@params = params
|
167
|
+
end
|
168
|
+
|
169
|
+
private
|
170
|
+
|
171
|
+
# Creates aliases for any defined comparison methods.
|
172
|
+
def self.alias_comparison_methods
|
173
|
+
Gecode::Constraints::Util::COMPARISON_ALIASES.each_pair do |orig, aliases|
|
174
|
+
if instance_methods.include?(orig.to_s)
|
175
|
+
aliases.each do |name|
|
176
|
+
alias_method(name, orig)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
# Creates aliases for any defined set methods.
|
183
|
+
def self.alias_set_methods
|
184
|
+
Gecode::Constraints::Util::SET_ALIASES.each_pair do |orig, aliases|
|
185
|
+
if instance_methods.include?(orig.to_s)
|
186
|
+
aliases.each do |name|
|
187
|
+
alias_method(name, orig)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
# A composite expression which is a expression with a left hand side
|
195
|
+
# resulting from a previous constraint.
|
196
|
+
class CompositeExpression < Gecode::Constraints::Expression
|
197
|
+
# The expression class should be the class of the expression delegated to,
|
198
|
+
# the variable class the kind of single variable used in the expression.
|
199
|
+
# The block given should take three parameters. The first is the variable
|
200
|
+
# that should be the left hand side, if it's nil then a new one should be
|
201
|
+
# created. The second is the has of parameters. The block should return
|
202
|
+
# the variable used as left hand side.
|
203
|
+
def initialize(expression_class, variable_class, model, params, &block)
|
204
|
+
super(model, params)
|
205
|
+
@expression_class = expression_class
|
206
|
+
@variable_class = variable_class
|
207
|
+
@proc = block
|
208
|
+
end
|
209
|
+
|
210
|
+
# Delegate to an instance of the expression class when we get something
|
211
|
+
# that we can't handle.
|
212
|
+
def method_missing(name, *args)
|
213
|
+
if @expression_class.instance_methods.include? name.to_s
|
214
|
+
options = {}
|
215
|
+
if args.size >= 2 and args[1].kind_of? Hash
|
216
|
+
options = args[1]
|
217
|
+
end
|
218
|
+
@params.update Gecode::Constraints::Util.decode_options(options.clone)
|
219
|
+
@params[:lhs] = @proc.call(nil, @params)
|
220
|
+
@expression_class.new(@model, @params).send(name, *args)
|
221
|
+
else
|
222
|
+
super
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def ==(expression, options = {})
|
227
|
+
if !@params[:negate] and options[:reify].nil? and
|
228
|
+
expression.kind_of? @variable_class
|
229
|
+
# We don't need any additional constraints.
|
230
|
+
@params.update Gecode::Constraints::Util.decode_options(options)
|
231
|
+
@proc.call(expression, @params)
|
232
|
+
else
|
233
|
+
method_missing(:==, expression, options)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
alias_comparison_methods
|
237
|
+
end
|
238
|
+
|
239
|
+
# Describes a constraint expression that has yet to be completed. I.e. a
|
240
|
+
# form of must has not yet been called, but some method has been called to
|
241
|
+
# initiate the expression. An example is distinct with offsets:
|
242
|
+
#
|
243
|
+
# enum.with_offsets(0..n).must_be.distinct
|
244
|
+
#
|
245
|
+
# The call of with_offsets initiates the constraint as a stub, even though
|
246
|
+
# must has not yet been called.
|
247
|
+
class ExpressionStub
|
248
|
+
# Constructs a new expression with the specified parameters.
|
249
|
+
def initialize(model, params)
|
250
|
+
@model = model
|
251
|
+
@params = params
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
# Describes an expression stub which includes left hand side methods and
|
256
|
+
# just sends models and parameters through a supplied block to construct the
|
257
|
+
# resulting expression.
|
258
|
+
class SimpleExpressionStub < ExpressionStub
|
259
|
+
include Gecode::Constraints::LeftHandSideMethods
|
260
|
+
|
261
|
+
# The block provided is executed when the expression demanded by the left
|
262
|
+
# hand side methods is to be constructed. The block should take two
|
263
|
+
# parameters: model and params (which have been updated with negate and
|
264
|
+
# so on). The block should return an expression.
|
265
|
+
def initialize(model, params, &block)
|
266
|
+
super(model, params)
|
267
|
+
@proc = block
|
268
|
+
end
|
269
|
+
|
270
|
+
private
|
271
|
+
|
272
|
+
# Produces an expression with offsets for the lhs module.
|
273
|
+
def expression(params)
|
274
|
+
@params.update(params)
|
275
|
+
@proc.call(@model, @params)
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
# Describes a stub that produces a variable, which can then be used with
|
280
|
+
# that variable's normalconstraints. An example with int variables would be
|
281
|
+
# the element constraint.
|
282
|
+
#
|
283
|
+
# int_enum[int_var].must > rhs
|
284
|
+
#
|
285
|
+
# The int_enum[int_var] part produces an int variable which the constraint
|
286
|
+
# ".must > rhs" is then applied to. In the above case two constraints (and
|
287
|
+
# one temporary variable) are required, but in the case of equality only
|
288
|
+
# one constraint is required.
|
289
|
+
class CompositeStub < Gecode::Constraints::ExpressionStub
|
290
|
+
include Gecode::Constraints::LeftHandSideMethods
|
291
|
+
|
292
|
+
# The composite expression class should be the class that the stub uses
|
293
|
+
# when creating its expressions.
|
294
|
+
def initialize(composite_expression_class, model, params)
|
295
|
+
super(model, params)
|
296
|
+
@composite_class = composite_expression_class
|
297
|
+
end
|
298
|
+
|
299
|
+
private
|
300
|
+
|
301
|
+
# Constrains the result of the stub to be equal to the specified variable
|
302
|
+
# with the specified parameters. If the variable given is nil then a new
|
303
|
+
# variable should be created for the purpose and returned. This is an
|
304
|
+
# abstract method and should be overridden by all sub-classes.
|
305
|
+
def constrain_equal(variable, params)
|
306
|
+
raise NoMethodError, 'Abstract method has not been implemented.'
|
307
|
+
end
|
308
|
+
|
309
|
+
# Produces an expression with position for the lhs module.
|
310
|
+
def expression(params)
|
311
|
+
@params.update params
|
312
|
+
@composite_class.new(@model, @params) do |var, params|
|
313
|
+
constrain_equal(var, params)
|
314
|
+
end
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
# Base class for all constraints.
|
319
|
+
class Constraint
|
320
|
+
# Creates a constraint with the specified parameters, bound to the
|
321
|
+
# specified model.
|
322
|
+
def initialize(model, params)
|
323
|
+
@model = model
|
324
|
+
@params = params.clone
|
325
|
+
end
|
326
|
+
|
327
|
+
# Posts the constraint, adding it to the model. This is an abstract
|
328
|
+
# method and should be overridden by all sub-classes.
|
329
|
+
def post
|
330
|
+
raise NoMethodError, 'Abstract method has not been implemented.'
|
331
|
+
end
|
170
332
|
end
|
171
333
|
end
|
172
334
|
end
|
@@ -175,3 +337,5 @@ require 'gecoder/interface/constraints/reifiable_constraints'
|
|
175
337
|
require 'gecoder/interface/constraints/int_var_constraints'
|
176
338
|
require 'gecoder/interface/constraints/int_enum_constraints'
|
177
339
|
require 'gecoder/interface/constraints/bool_var_constraints'
|
340
|
+
require 'gecoder/interface/constraints/bool_enum_constraints'
|
341
|
+
require 'gecoder/interface/constraints/set_var_constraints'
|
@@ -11,15 +11,19 @@ module Gecode
|
|
11
11
|
raise ArgumentError, 'Enumerable must not be empty.'
|
12
12
|
end
|
13
13
|
|
14
|
-
if elements.
|
14
|
+
if elements.all?{ |var| var.kind_of? FreeIntVar }
|
15
15
|
class <<enum
|
16
16
|
include Gecode::IntEnumMethods
|
17
17
|
end
|
18
|
-
elsif elements.
|
18
|
+
elsif elements.all?{ |var| var.kind_of? FreeBoolVar }
|
19
19
|
class <<enum
|
20
20
|
include Gecode::BoolEnumMethods
|
21
21
|
end
|
22
|
-
elsif elements.
|
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 }
|
23
27
|
class <<enum
|
24
28
|
include Gecode::FixnumEnumMethods
|
25
29
|
end
|
@@ -48,10 +52,14 @@ module Gecode
|
|
48
52
|
|
49
53
|
# Returns an int variable array with all the bound variables.
|
50
54
|
def to_int_var_array
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
+
space = @model.active_space
|
56
|
+
unless @bound_space == space
|
57
|
+
elements = to_a
|
58
|
+
@bound_arr = Gecode::Raw::IntVarArray.new(active_space, elements.size)
|
59
|
+
elements.each_with_index{ |var, index| @bound_arr[index] = var.bind }
|
60
|
+
@bound_space = space
|
61
|
+
end
|
62
|
+
return @bound_arr
|
55
63
|
end
|
56
64
|
alias_method :to_var_array, :to_int_var_array
|
57
65
|
|
@@ -76,14 +84,37 @@ module Gecode
|
|
76
84
|
|
77
85
|
# Returns a bool variable array with all the bound variables.
|
78
86
|
def to_bool_var_array
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
87
|
+
space = @model.active_space
|
88
|
+
unless @bound_space == space
|
89
|
+
elements = to_a
|
90
|
+
@bound_arr = Gecode::Raw::BoolVarArray.new(active_space, elements.size)
|
91
|
+
elements.each_with_index{ |var, index| @bound_arr[index] = var.bind }
|
92
|
+
@bound_space = space
|
93
|
+
end
|
94
|
+
return @bound_arr
|
83
95
|
end
|
84
96
|
alias_method :to_var_array, :to_bool_var_array
|
85
97
|
end
|
86
98
|
|
99
|
+
# A module containing the methods needed by enumerations containing set
|
100
|
+
# variables. Requires that it's included in an enumerable.
|
101
|
+
module SetEnumMethods
|
102
|
+
include EnumMethods
|
103
|
+
|
104
|
+
# Returns a set variable array with all the bound variables.
|
105
|
+
def to_set_var_array
|
106
|
+
space = @model.active_space
|
107
|
+
unless @bound_space == space
|
108
|
+
elements = to_a
|
109
|
+
@bound_arr = Gecode::Raw::SetVarArray.new(active_space, elements.size)
|
110
|
+
elements.each_with_index{ |var, index| @bound_arr[index] = var.bind }
|
111
|
+
@bound_space = space
|
112
|
+
end
|
113
|
+
return @bound_arr
|
114
|
+
end
|
115
|
+
alias_method :to_var_array, :to_set_var_array
|
116
|
+
end
|
117
|
+
|
87
118
|
# A module containing the methods needed by enumerations containing fixnums.
|
88
119
|
# Requires that it's included in an enumerable.
|
89
120
|
module FixnumEnumMethods
|
@@ -72,6 +72,51 @@ module Gecode
|
|
72
72
|
return wrap_enum(Util::EnumMatrix.rows(rows, false))
|
73
73
|
end
|
74
74
|
|
75
|
+
# Creates a set variable with the specified domain for greatest lower bound
|
76
|
+
# and least upper bound (specified as either a range or enum). A range for
|
77
|
+
# the allowed cardinality of the set can also be specified, if none is
|
78
|
+
# specified, or nil is given, then the default range (anything) will be
|
79
|
+
# used. If only a single Fixnum is specified as cardinality_range then it's
|
80
|
+
# used as lower bound.
|
81
|
+
def set_var(glb_domain, lub_domain, cardinality_range = nil)
|
82
|
+
check_set_bounds(glb_domain, lub_domain)
|
83
|
+
|
84
|
+
index = active_space.new_set_vars(glb_domain, lub_domain,
|
85
|
+
to_set_cardinality_range(cardinality_range)).first
|
86
|
+
FreeSetVar.new(self, index)
|
87
|
+
end
|
88
|
+
|
89
|
+
# Creates an array containing the specified number of set variables. The
|
90
|
+
# parameters beyond count are the same as for #set_var .
|
91
|
+
def set_var_array(count, glb_domain, lub_domain, cardinality_range = nil)
|
92
|
+
check_set_bounds(glb_domain, lub_domain)
|
93
|
+
|
94
|
+
variables = []
|
95
|
+
active_space.new_set_vars(glb_domain, lub_domain,
|
96
|
+
to_set_cardinality_range(cardinality_range), count).each do |index|
|
97
|
+
variables << FreeSetVar.new(self, index)
|
98
|
+
end
|
99
|
+
return wrap_enum(variables)
|
100
|
+
end
|
101
|
+
|
102
|
+
# Creates a matrix containing the specified number of rows and columns
|
103
|
+
# filled with set variables. The parameters beyond row and column counts are
|
104
|
+
# the same as for #set_var .
|
105
|
+
def set_var_matrix(row_count, col_count, glb_domain, lub_domain,
|
106
|
+
cardinality_range = nil)
|
107
|
+
check_set_bounds(glb_domain, lub_domain)
|
108
|
+
|
109
|
+
indices = active_space.new_set_vars(glb_domain, lub_domain,
|
110
|
+
to_set_cardinality_range(cardinality_range), row_count*col_count)
|
111
|
+
rows = []
|
112
|
+
row_count.times do |i|
|
113
|
+
rows << indices[(i*col_count)...(i.succ*col_count)].map! do |index|
|
114
|
+
FreeSetVar.new(self, index)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
return wrap_enum(Util::EnumMatrix.rows(rows, false))
|
118
|
+
end
|
119
|
+
|
75
120
|
# Retrieves the currently active space (the one which variables refer to).
|
76
121
|
def active_space
|
77
122
|
@active_space ||= base_space
|
@@ -121,6 +166,36 @@ module Gecode
|
|
121
166
|
return min..max
|
122
167
|
end
|
123
168
|
|
169
|
+
# Transforms the argument to a set cardinality range, returns nil if the
|
170
|
+
# default range should be used. If arg is a range then that's used,
|
171
|
+
# otherwise if the argument is a fixnum it's used as lower bound.
|
172
|
+
def to_set_cardinality_range(arg)
|
173
|
+
if arg.kind_of? Fixnum
|
174
|
+
arg..Gecode::Raw::Limits::Set::CARD_MAX
|
175
|
+
else
|
176
|
+
arg
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
# Checks whether the specified greatest lower bound is a subset of least
|
181
|
+
# upper bound. Raises ArgumentError if that is not the case.
|
182
|
+
def check_set_bounds(glb, lub)
|
183
|
+
unless valid_set_bounds?(glb, lub)
|
184
|
+
raise ArgumentError,
|
185
|
+
"Invalid set bounds: #{glb} is not a subset of #{lub}."
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
# Returns whether the greatest lower bound is a subset of least upper
|
190
|
+
# bound.
|
191
|
+
def valid_set_bounds?(glb, lub)
|
192
|
+
if glb.kind_of?(Range) and lub.kind_of?(Range)
|
193
|
+
glb.first >= lub.first and glb.last <= lub.last
|
194
|
+
else
|
195
|
+
(glb.to_a - lub.to_a).empty?
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
124
199
|
# Creates an integer variable from the specified index and domain. The
|
125
200
|
# domain can either be given as a range or as a number of elements.
|
126
201
|
def construct_int_var(index, *domain_args)
|
@@ -1,13 +1,5 @@
|
|
1
1
|
module Gecode
|
2
2
|
class Model
|
3
|
-
private
|
4
|
-
|
5
|
-
# Used during the search.
|
6
|
-
COPY_DIST = 16
|
7
|
-
ADAPTATION_DIST = 4
|
8
|
-
|
9
|
-
public
|
10
|
-
|
11
3
|
# Finds the first solution to the modelled problem and updates the variables
|
12
4
|
# to that solution. Returns the model if a solution was found, nil
|
13
5
|
# otherwise.
|
@@ -54,7 +46,10 @@ module Gecode
|
|
54
46
|
constraints.clear # Empty the queue.
|
55
47
|
|
56
48
|
stop = Gecode::Raw::Search::Stop.new
|
57
|
-
Gecode::Raw::DFS.new(active_space,
|
49
|
+
Gecode::Raw::DFS.new(active_space,
|
50
|
+
Gecode::Raw::Search::Config::MINIMAL_DISTANCE,
|
51
|
+
Gecode::Raw::Search::Config::ADAPTIVE_DISTANCE,
|
52
|
+
stop)
|
58
53
|
end
|
59
54
|
end
|
60
55
|
end
|
@@ -46,9 +46,9 @@ module Gecode
|
|
46
46
|
|
47
47
|
def inspect
|
48
48
|
if assigned?
|
49
|
-
"
|
49
|
+
"#<\#{self.class} \#{domain}>"
|
50
50
|
else
|
51
|
-
"
|
51
|
+
"#<\#{self.class} \#{domain}>"
|
52
52
|
end
|
53
53
|
end
|
54
54
|
end_method_definitions
|
@@ -57,6 +57,40 @@ module Gecode
|
|
57
57
|
|
58
58
|
# Int variables.
|
59
59
|
FreeIntVar = FreeVar(Gecode::Raw::IntVar, :int_var)
|
60
|
+
class FreeIntVar
|
61
|
+
# Returns a string representation of the the range of the variable's domain.
|
62
|
+
def domain
|
63
|
+
if assigned?
|
64
|
+
"range: #{val.to_s}"
|
65
|
+
else
|
66
|
+
"range: #{min}..#{max}"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
60
71
|
# Bool variables.
|
61
72
|
FreeBoolVar = FreeVar(Gecode::Raw::BoolVar, :bool_var)
|
73
|
+
class FreeBoolVar
|
74
|
+
# Returns a string representation of the the variable's domain.
|
75
|
+
def domain
|
76
|
+
if assigned?
|
77
|
+
true?.to_s
|
78
|
+
else
|
79
|
+
'unassigned'
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Set variables.
|
85
|
+
FreeSetVar = FreeVar(Gecode::Raw::SetVar, :set_var)
|
86
|
+
class FreeSetVar
|
87
|
+
# Returns a string representation of the the variable's domain.
|
88
|
+
def domain
|
89
|
+
if assigned?
|
90
|
+
"#{glb_min}..#{lub_min}"
|
91
|
+
else
|
92
|
+
"glb-range: #{glb_min}..#{glb_max}, lub-range: #{lub_min}..#{lub_max}"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
62
96
|
end
|
data/lib/gecoder/version.rb
CHANGED
data/specs/bool_var.rb
CHANGED
@@ -17,4 +17,62 @@ describe Gecode::FreeBoolVar, '(not assigned)' do
|
|
17
17
|
it 'should not be assigned' do
|
18
18
|
@var.should_not be_assigned
|
19
19
|
end
|
20
|
+
|
21
|
+
it "should say that it's not assigned when inspecting" do
|
22
|
+
@var.inspect.should include('unassigned')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe Gecode::FreeBoolVar, '(assigned true)' do
|
27
|
+
before do
|
28
|
+
model = Gecode::Model.new
|
29
|
+
@var = model.bool_var
|
30
|
+
@var.must_be.true
|
31
|
+
model.solve!
|
32
|
+
end
|
33
|
+
|
34
|
+
it_should_behave_like 'non-empty bool variable'
|
35
|
+
|
36
|
+
it 'should be assigned' do
|
37
|
+
@var.should be_assigned
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should respond true to true?' do
|
41
|
+
@var.true?.should be_true
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should not respond true to false?' do
|
45
|
+
@var.false?.should_not be_true
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should say that it's true when inspecting" do
|
49
|
+
@var.inspect.should include('true')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe Gecode::FreeBoolVar, '(assigned false)' do
|
54
|
+
before do
|
55
|
+
model = Gecode::Model.new
|
56
|
+
@var = model.bool_var
|
57
|
+
@var.must_be.false
|
58
|
+
model.solve!
|
59
|
+
end
|
60
|
+
|
61
|
+
it_should_behave_like 'non-empty bool variable'
|
62
|
+
|
63
|
+
it 'should be assigned' do
|
64
|
+
@var.should be_assigned
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'should respond not true to true?' do
|
68
|
+
@var.true?.should_not be_true
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'should respond true to false?' do
|
72
|
+
@var.false?.should be_true
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should say that it's false when inspecting" do
|
76
|
+
@var.inspect.should include('false')
|
77
|
+
end
|
20
78
|
end
|