gecoder 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|