gecoder-with-gecode 0.8.1-mswin32 → 0.8.2-mswin32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGES +10 -0
- data/lib/gecode.dll +0 -0
- data/lib/gecoder/bindings/bindings.rb +35 -0
- data/lib/gecoder/interface/constraints.rb +34 -0
- data/lib/gecoder/interface/constraints/bool/boolean.rb +7 -0
- data/lib/gecoder/interface/constraints/bool/channel.rb +23 -0
- data/lib/gecoder/interface/constraints/bool_enum/channel.rb +59 -0
- data/lib/gecoder/interface/constraints/bool_enum/extensional.rb +10 -9
- data/lib/gecoder/interface/constraints/bool_enum_constraints.rb +1 -0
- data/lib/gecoder/interface/constraints/bool_var_constraints.rb +1 -0
- data/lib/gecoder/interface/constraints/int/arithmetic.rb +78 -1
- data/lib/gecoder/interface/constraints/int/channel.rb +73 -0
- data/lib/gecoder/interface/constraints/int_enum/channel.rb +10 -2
- data/lib/gecoder/interface/constraints/int_enum/extensional.rb +12 -9
- data/lib/gecoder/interface/constraints/int_var_constraints.rb +1 -0
- data/lib/gecoder/interface/enum_wrapper.rb +3 -0
- data/lib/gecoder/interface/search.rb +34 -2
- data/lib/gecoder/version.rb +1 -1
- data/specs/constraints/arithmetic.rb +108 -41
- data/specs/constraints/boolean.rb +4 -0
- data/specs/constraints/channel.rb +235 -5
- data/specs/constraints/distinct.rb +1 -1
- data/specs/constraints/extensional.rb +46 -41
- data/specs/constraints/linear.rb +8 -0
- data/specs/enum_wrapper.rb +8 -1
- data/specs/search.rb +119 -61
- data/specs/spec_helper.rb +0 -28
- data/tasks/distribution.rake +2 -3
- metadata +10 -4
@@ -6,6 +6,9 @@ module Gecode
|
|
6
6
|
unless enum.kind_of? Enumerable
|
7
7
|
raise TypeError, 'Only enumerables can be wrapped.'
|
8
8
|
end
|
9
|
+
if enum.kind_of? Gecode::EnumMethods
|
10
|
+
raise ArgumentError, 'The enumration is already wrapped.'
|
11
|
+
end
|
9
12
|
elements = enum.to_a
|
10
13
|
if elements.empty?
|
11
14
|
raise ArgumentError, 'Enumerable must not be empty.'
|
@@ -4,7 +4,9 @@ module Gecode
|
|
4
4
|
# to that solution. Returns the model if a solution was found, nil
|
5
5
|
# otherwise.
|
6
6
|
def solve!
|
7
|
-
|
7
|
+
dfs = dfs_engine
|
8
|
+
space = dfs.next
|
9
|
+
@statistics = dfs.statistics
|
8
10
|
return nil if space.nil?
|
9
11
|
self.active_space = space
|
10
12
|
return self
|
@@ -14,6 +16,7 @@ module Gecode
|
|
14
16
|
# might have been performed). Returns the reset model.
|
15
17
|
def reset!
|
16
18
|
self.active_space = base_space
|
19
|
+
@statistics = nil
|
17
20
|
return self
|
18
21
|
end
|
19
22
|
|
@@ -33,11 +36,33 @@ module Gecode
|
|
33
36
|
next_solution = nil
|
34
37
|
while not (next_solution = dfs.next).nil?
|
35
38
|
self.active_space = next_solution
|
39
|
+
@statistics = dfs.statistics
|
36
40
|
yield self
|
37
41
|
end
|
38
42
|
self.reset!
|
39
43
|
end
|
40
44
|
|
45
|
+
# Returns search statistics providing various information from Gecode about
|
46
|
+
# the search that resulted in the model's current variable state. If the
|
47
|
+
# model's variables have not undegone any search then nil is returned. The
|
48
|
+
# statistics is a hash with the following keys:
|
49
|
+
# [:propagations] The number of propagation steps performed.
|
50
|
+
# [:failures] The number of failed nodes in the search tree.
|
51
|
+
# [:clones] The number of clones created.
|
52
|
+
# [:commits] The number of commit operations performed.
|
53
|
+
# [:memory] The peak memory allocated to Gecode.
|
54
|
+
def search_stats
|
55
|
+
return nil if @statistics.nil?
|
56
|
+
|
57
|
+
return {
|
58
|
+
:propagations => @statistics.propagate,
|
59
|
+
:failures => @statistics.fail,
|
60
|
+
:clones => @statistics.clone,
|
61
|
+
:commits => @statistics.commit,
|
62
|
+
:memory => @statistics.memory
|
63
|
+
}
|
64
|
+
end
|
65
|
+
|
41
66
|
# Finds the optimal solution. Optimality is defined by the provided block
|
42
67
|
# which is given one parameter, a solution to the problem. The block should
|
43
68
|
# constrain the solution so that that only "better" solutions can be new
|
@@ -70,7 +95,14 @@ module Gecode
|
|
70
95
|
options.c_d = Gecode::Raw::Search::Config::MINIMAL_DISTANCE
|
71
96
|
options.a_d = Gecode::Raw::Search::Config::ADAPTIVE_DISTANCE
|
72
97
|
options.stop = nil
|
73
|
-
|
98
|
+
bab = Gecode::Raw::BAB.new(selected_space, options)
|
99
|
+
|
100
|
+
result = nil
|
101
|
+
previous_solution = nil
|
102
|
+
until (previous_solution = bab.next).nil?
|
103
|
+
result = previous_solution
|
104
|
+
end
|
105
|
+
@statistics = bab.statistics
|
74
106
|
|
75
107
|
# Reset the method used constrain calls and return the result.
|
76
108
|
Model.constrain_proc = nil
|
data/lib/gecoder/version.rb
CHANGED
@@ -17,6 +17,55 @@ class ArithmeticSampleProblem < Gecode::Model
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
+
# Construct a method placing expectations for an arithmetic constraint with the
|
21
|
+
# specified arity (number of variables before must) and the specified name in
|
22
|
+
# Gecode.
|
23
|
+
def arithmetic_expectation(gecode_name, arity)
|
24
|
+
lambda do |relation, rhs, strength, kind, reif_var, negated|
|
25
|
+
# Construct the arguments expected to be passed to the Gecode variant of
|
26
|
+
# the constraint.
|
27
|
+
rhs = an_instance_of(Gecode::Raw::IntVar) if rhs.respond_to? :bind
|
28
|
+
expected_gecode_arguments = [an_instance_of(Gecode::Raw::Space)]
|
29
|
+
arity.times do
|
30
|
+
expected_gecode_arguments << an_instance_of(Gecode::Raw::IntVar)
|
31
|
+
end
|
32
|
+
can_use_single_gecode_constraint = reif_var.nil? && !negated &&
|
33
|
+
relation == Gecode::Raw::IRT_EQ && !rhs.kind_of?(Fixnum)
|
34
|
+
if can_use_single_gecode_constraint
|
35
|
+
expected_gecode_arguments << rhs
|
36
|
+
else
|
37
|
+
expected_gecode_arguments << an_instance_of(Gecode::Raw::IntVar)
|
38
|
+
end
|
39
|
+
expected_gecode_arguments.concat([strength, kind])
|
40
|
+
|
41
|
+
# Create the actual method producing the expectation.
|
42
|
+
@model.allow_space_access do
|
43
|
+
if reif_var.nil?
|
44
|
+
if can_use_single_gecode_constraint
|
45
|
+
Gecode::Raw.should_receive(gecode_name).once.with(
|
46
|
+
*expected_gecode_arguments)
|
47
|
+
Gecode::Raw.should_receive(:rel).exactly(0).times
|
48
|
+
else
|
49
|
+
Gecode::Raw.should_receive(gecode_name).once.with(
|
50
|
+
*expected_gecode_arguments)
|
51
|
+
Gecode::Raw.should_receive(:rel).once.with(
|
52
|
+
an_instance_of(Gecode::Raw::Space),
|
53
|
+
an_instance_of(Gecode::Raw::IntVar),
|
54
|
+
relation, rhs, strength, kind)
|
55
|
+
end
|
56
|
+
else
|
57
|
+
Gecode::Raw.should_receive(gecode_name).once.with(
|
58
|
+
*expected_gecode_arguments)
|
59
|
+
Gecode::Raw.should_receive(:rel).once.with(
|
60
|
+
an_instance_of(Gecode::Raw::Space),
|
61
|
+
an_instance_of(Gecode::Raw::IntVar), relation, rhs,
|
62
|
+
an_instance_of(Gecode::Raw::BoolVar),
|
63
|
+
strength, kind)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
20
69
|
# Requires @stub, @target, @model and @expect.
|
21
70
|
describe 'arithmetic constraint', :shared => true do
|
22
71
|
before do
|
@@ -228,46 +277,7 @@ describe Gecode::Constraints::Int::Arithmetic, ' (multiplication)' do
|
|
228
277
|
@stub = @var * @var2
|
229
278
|
@target = @model.var3
|
230
279
|
|
231
|
-
|
232
|
-
@expect = lambda do |relation, rhs, strength, kind, reif_var, negated|
|
233
|
-
@model.allow_space_access do
|
234
|
-
rhs = an_instance_of(Gecode::Raw::IntVar) if rhs.respond_to? :bind
|
235
|
-
if reif_var.nil?
|
236
|
-
if !negated and relation == Gecode::Raw::IRT_EQ and
|
237
|
-
!rhs.kind_of? Fixnum
|
238
|
-
Gecode::Raw.should_receive(:mult).once.with(
|
239
|
-
an_instance_of(Gecode::Raw::Space),
|
240
|
-
an_instance_of(Gecode::Raw::IntVar),
|
241
|
-
an_instance_of(Gecode::Raw::IntVar),
|
242
|
-
rhs, strength, kind)
|
243
|
-
Gecode::Raw.should_receive(:rel).exactly(0).times
|
244
|
-
else
|
245
|
-
Gecode::Raw.should_receive(:mult).once.with(
|
246
|
-
an_instance_of(Gecode::Raw::Space),
|
247
|
-
an_instance_of(Gecode::Raw::IntVar),
|
248
|
-
an_instance_of(Gecode::Raw::IntVar),
|
249
|
-
an_instance_of(Gecode::Raw::IntVar),
|
250
|
-
strength, kind)
|
251
|
-
Gecode::Raw.should_receive(:rel).once.with(
|
252
|
-
an_instance_of(Gecode::Raw::Space),
|
253
|
-
an_instance_of(Gecode::Raw::IntVar),
|
254
|
-
relation, rhs, strength, kind)
|
255
|
-
end
|
256
|
-
else
|
257
|
-
Gecode::Raw.should_receive(:mult).once.with(
|
258
|
-
an_instance_of(Gecode::Raw::Space),
|
259
|
-
an_instance_of(Gecode::Raw::IntVar),
|
260
|
-
an_instance_of(Gecode::Raw::IntVar),
|
261
|
-
an_instance_of(Gecode::Raw::IntVar),
|
262
|
-
strength, kind)
|
263
|
-
Gecode::Raw.should_receive(:rel).once.with(
|
264
|
-
an_instance_of(Gecode::Raw::Space),
|
265
|
-
an_instance_of(Gecode::Raw::IntVar), relation, rhs,
|
266
|
-
an_instance_of(Gecode::Raw::BoolVar),
|
267
|
-
strength, kind)
|
268
|
-
end
|
269
|
-
end
|
270
|
-
end
|
280
|
+
@expect = arithmetic_expectation(:mult, 2)
|
271
281
|
end
|
272
282
|
|
273
283
|
it 'should constrain the value of the multiplication' do
|
@@ -281,4 +291,61 @@ describe Gecode::Constraints::Int::Arithmetic, ' (multiplication)' do
|
|
281
291
|
end
|
282
292
|
|
283
293
|
it_should_behave_like 'arithmetic constraint'
|
284
|
-
end
|
294
|
+
end
|
295
|
+
|
296
|
+
describe Gecode::Constraints::Int::Arithmetic, ' (squared)' do
|
297
|
+
before do
|
298
|
+
@model = ArithmeticSampleProblem.new
|
299
|
+
@var = @model.var
|
300
|
+
@stub = @var.squared
|
301
|
+
@target = @model.var2
|
302
|
+
|
303
|
+
@expect = arithmetic_expectation(:sqr, 1)
|
304
|
+
end
|
305
|
+
|
306
|
+
it 'should constrain the value of the variable squared' do
|
307
|
+
@var.squared.must == 9
|
308
|
+
sol = @model.solve!
|
309
|
+
sol.var.value.abs.should == 3
|
310
|
+
end
|
311
|
+
|
312
|
+
it_should_behave_like 'arithmetic constraint'
|
313
|
+
end
|
314
|
+
|
315
|
+
describe Gecode::Constraints::Int::Arithmetic, ' (square root)' do
|
316
|
+
before do
|
317
|
+
@model = ArithmeticSampleProblem.new
|
318
|
+
@var = @model.var
|
319
|
+
@stub = @var.square_root
|
320
|
+
@target = @model.var2
|
321
|
+
|
322
|
+
@expect = arithmetic_expectation(:sqrt, 1)
|
323
|
+
end
|
324
|
+
|
325
|
+
it 'should constrain the square root of the variable' do
|
326
|
+
@var.square_root.must == 3
|
327
|
+
sol = @model.solve!
|
328
|
+
Math.sqrt(sol.var.value).floor.should == 3
|
329
|
+
end
|
330
|
+
|
331
|
+
it 'should constrain the square root of the variable (2)' do
|
332
|
+
@var.square_root.must == 0
|
333
|
+
sol = @model.solve!
|
334
|
+
Math.sqrt(sol.var.value).floor.should == 0
|
335
|
+
end
|
336
|
+
|
337
|
+
it 'should constrain the square root of the variable (3)' do
|
338
|
+
@var.must < 0
|
339
|
+
@var.square_root.must == 0
|
340
|
+
@model.solve!.should be_nil
|
341
|
+
end
|
342
|
+
|
343
|
+
it 'should round down the square root' do
|
344
|
+
@var.must > 4
|
345
|
+
@var.square_root.must == 2
|
346
|
+
sol = @model.solve!
|
347
|
+
sol.var.value.should be_between(5,8)
|
348
|
+
end
|
349
|
+
|
350
|
+
it_should_behave_like 'arithmetic constraint'
|
351
|
+
end
|
@@ -228,5 +228,9 @@ describe Gecode::Constraints::Bool do
|
|
228
228
|
sol.b3.value.should be_true
|
229
229
|
end
|
230
230
|
|
231
|
+
it 'should raise error on right hand sides of the wrong type' do
|
232
|
+
lambda{ @b1.must == 'hello' }.should raise_error(TypeError)
|
233
|
+
end
|
234
|
+
|
231
235
|
it_should_behave_like 'reifiable constraint'
|
232
236
|
end
|
@@ -16,6 +16,20 @@ class ChannelSampleProblem < Gecode::Model
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
+
class BoolChannelSampleProblem < Gecode::Model
|
20
|
+
attr :bool_enum
|
21
|
+
attr :bool
|
22
|
+
attr :int
|
23
|
+
|
24
|
+
def initialize
|
25
|
+
@bool_enum = bool_var_array(4)
|
26
|
+
@int = int_var(0..3)
|
27
|
+
@bool = bool_var
|
28
|
+
|
29
|
+
branch_on wrap_enum([@int])
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
19
33
|
describe Gecode::Constraints::IntEnum::Channel, ' (two int enums)' do
|
20
34
|
before do
|
21
35
|
@model = ChannelSampleProblem.new
|
@@ -67,13 +81,21 @@ describe Gecode::Constraints::IntEnum::Channel, ' (one int enum and one set enum
|
|
67
81
|
@model = ChannelSampleProblem.new
|
68
82
|
@positions = @model.positions
|
69
83
|
@sets = @model.sets
|
84
|
+
|
85
|
+
@invoke_options = lambda do |hash|
|
86
|
+
@positions.must.channel @sets, hash
|
87
|
+
@model.solve!
|
88
|
+
end
|
89
|
+
@expect_options = option_expectation do |strength, kind, reif_var|
|
90
|
+
Gecode::Raw.should_receive(:channel).once.with(
|
91
|
+
an_instance_of(Gecode::Raw::Space),
|
92
|
+
an_instance_of(Gecode::Raw::IntVarArray),
|
93
|
+
an_instance_of(Gecode::Raw::SetVarArray))
|
94
|
+
end
|
70
95
|
end
|
71
96
|
|
72
97
|
it 'should translate into a channel constraint' do
|
73
|
-
|
74
|
-
an_instance_of(Gecode::Raw::Space),
|
75
|
-
an_instance_of(Gecode::Raw::IntVarArray),
|
76
|
-
an_instance_of(Gecode::Raw::SetVarArray))
|
98
|
+
@expect_options.call({})
|
77
99
|
@positions.must.channel @sets
|
78
100
|
@model.solve!
|
79
101
|
end
|
@@ -87,6 +109,8 @@ describe Gecode::Constraints::IntEnum::Channel, ' (one int enum and one set enum
|
|
87
109
|
sets[position].value.should include(i)
|
88
110
|
end
|
89
111
|
end
|
112
|
+
|
113
|
+
it_should_behave_like 'non-reifiable set constraint'
|
90
114
|
end
|
91
115
|
|
92
116
|
describe Gecode::Constraints::SetEnum, ' (channel with set as left hand side)' do
|
@@ -123,4 +147,210 @@ describe Gecode::Constraints::SetEnum, ' (channel with set as left hand side)' d
|
|
123
147
|
end
|
124
148
|
|
125
149
|
it_should_behave_like 'non-reifiable set constraint'
|
126
|
-
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# Requires @model, @bool and @int. Also requires @place_constraint which is a
|
153
|
+
# method that takes five variables: a boolean variable, an integer variable,
|
154
|
+
# the name of the equality method to use, whether or not the constraint should
|
155
|
+
# be negated and a hash of options, and places the channel constraint on them.
|
156
|
+
describe 'channel constraint between one int and one bool variable', :shared => true do
|
157
|
+
before do
|
158
|
+
@invoke_options = lambda do |hash|
|
159
|
+
@place_constraint.call(@bool, @int, :==, false, hash)
|
160
|
+
@model.solve!
|
161
|
+
end
|
162
|
+
@expect_options = option_expectation do |strength, kind, reif_var|
|
163
|
+
Gecode::Raw.should_receive(:channel).once.with(
|
164
|
+
an_instance_of(Gecode::Raw::Space),
|
165
|
+
an_instance_of(Gecode::Raw::IntVar),
|
166
|
+
an_instance_of(Gecode::Raw::BoolVar),
|
167
|
+
strength, kind)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
([:==] + Gecode::Constraints::Util::COMPARISON_ALIASES[:==]).each do |ali|
|
172
|
+
it "should translate #{ali} into a channel constraint" do
|
173
|
+
@expect_options.call({})
|
174
|
+
@place_constraint.call(@bool, @int, ali, false, {})
|
175
|
+
@model.solve!
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
it 'should constrain the int variable to be 1 when the boolean variable is true' do
|
180
|
+
@bool.must_be.true
|
181
|
+
@place_constraint.call(@bool, @int, :==, false, {})
|
182
|
+
@model.solve!
|
183
|
+
@int.value.should == 1
|
184
|
+
end
|
185
|
+
|
186
|
+
it 'should constrain the int variable to be 0 when the boolean variable is false' do
|
187
|
+
@bool.must_be.false
|
188
|
+
@place_constraint.call(@bool, @int, :==, false, {})
|
189
|
+
@model.solve!
|
190
|
+
@int.value.should == 0
|
191
|
+
end
|
192
|
+
|
193
|
+
it 'should not allow negation' do
|
194
|
+
lambda do
|
195
|
+
@place_constraint.call(@bool, @int, :==, true, {})
|
196
|
+
end.should raise_error(Gecode::MissingConstraintError)
|
197
|
+
end
|
198
|
+
|
199
|
+
it_should_behave_like 'non-reifiable constraint'
|
200
|
+
end
|
201
|
+
|
202
|
+
describe Gecode::Constraints::Int::Channel, ' (one int and one bool variable)' do
|
203
|
+
before do
|
204
|
+
@model = BoolChannelSampleProblem.new
|
205
|
+
@bool = @model.bool_var
|
206
|
+
@int = @model.int_var
|
207
|
+
|
208
|
+
@place_constraint = lambda do |bool, int, equals_method_name, negate, options|
|
209
|
+
if negate
|
210
|
+
int.must_not.method(equals_method_name).call(bool, options)
|
211
|
+
else
|
212
|
+
int.must.method(equals_method_name).call(bool, options)
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
it 'should not shadow linear boolean constraints' do
|
218
|
+
lambda do
|
219
|
+
(@bool + @bool).must == @bool
|
220
|
+
@model.solve!
|
221
|
+
end.should_not raise_error
|
222
|
+
end
|
223
|
+
|
224
|
+
it 'should raise error for unsupported right hand sides' do
|
225
|
+
lambda{ @int.must == 'hello' }.should raise_error(TypeError)
|
226
|
+
end
|
227
|
+
|
228
|
+
it_should_behave_like 'channel constraint between one int and one bool variable'
|
229
|
+
end
|
230
|
+
|
231
|
+
describe Gecode::Constraints::Int::Channel, ' (one bool and one int variable)' do
|
232
|
+
before do
|
233
|
+
@model = BoolChannelSampleProblem.new
|
234
|
+
@bool = @model.bool_var
|
235
|
+
@int = @model.int_var
|
236
|
+
|
237
|
+
@place_constraint = lambda do |bool, int, equals_method_name, negate, options|
|
238
|
+
if negate
|
239
|
+
bool.must_not.method(equals_method_name).call(int, options)
|
240
|
+
else
|
241
|
+
bool.must.method(equals_method_name).call(int, options)
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
it 'should not shadow linear boolean constraints' do
|
247
|
+
lambda do
|
248
|
+
@bool.must == @bool + @bool
|
249
|
+
@model.solve!
|
250
|
+
end.should_not raise_error
|
251
|
+
end
|
252
|
+
|
253
|
+
it 'should raise error for unsupported right hand sides' do
|
254
|
+
lambda{ @bool.must == 'hello' }.should raise_error(TypeError)
|
255
|
+
end
|
256
|
+
|
257
|
+
it_should_behave_like 'channel constraint between one int and one bool variable'
|
258
|
+
end
|
259
|
+
|
260
|
+
# Requires @model, @bool_enum and @int. Also requires @place_constraint which
|
261
|
+
# is a method that takes four variables: a boolean enum, an integer variable,
|
262
|
+
# whether or not the constraint should be negated and a hash of options, and
|
263
|
+
# places the channel constraint on them.
|
264
|
+
describe 'channel constraint between bool enum and int variable', :shared => true do
|
265
|
+
before do
|
266
|
+
@invoke_options = lambda do |hash|
|
267
|
+
@place_constraint.call(@bools, @int, false, hash)
|
268
|
+
@model.solve!
|
269
|
+
end
|
270
|
+
@expect_options = option_expectation do |strength, kind, reif_var|
|
271
|
+
Gecode::Raw.should_receive(:channel).once.with(
|
272
|
+
an_instance_of(Gecode::Raw::Space),
|
273
|
+
an_instance_of(Gecode::Raw::BoolVarArray),
|
274
|
+
an_instance_of(Gecode::Raw::IntVar), 0,
|
275
|
+
strength, kind)
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
it 'should channel the bool enum with the integer variable' do
|
280
|
+
@int.must > 2
|
281
|
+
@place_constraint.call(@bools, @int, false, {})
|
282
|
+
@model.solve!.should_not be_nil
|
283
|
+
int_val = @int.value
|
284
|
+
@bools.values.each_with_index do |bool, index|
|
285
|
+
bool.should == (index == int_val)
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
it 'should take the offset into account when channeling' do
|
290
|
+
@int.must > 2
|
291
|
+
offset = 1
|
292
|
+
@place_constraint.call(@bools, @int, false, :offset => offset)
|
293
|
+
@model.solve!.should_not be_nil
|
294
|
+
int_val = @int.value
|
295
|
+
@bools.values.each_with_index do |bool, index|
|
296
|
+
bool.should == (index + offset == int_val)
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
it 'should not allow negation' do
|
301
|
+
lambda do
|
302
|
+
@place_constraint.call(@bools, @int, true, {})
|
303
|
+
end.should raise_error(Gecode::MissingConstraintError)
|
304
|
+
end
|
305
|
+
|
306
|
+
it_should_behave_like 'non-reifiable constraint'
|
307
|
+
end
|
308
|
+
|
309
|
+
describe Gecode::Constraints::BoolEnum::Channel, ' (bool enum as lhs with int variable)' do
|
310
|
+
before do
|
311
|
+
@model = BoolChannelSampleProblem.new
|
312
|
+
@bools = @model.bool_enum
|
313
|
+
@int = @model.int
|
314
|
+
|
315
|
+
@place_constraint = lambda do |bools, int, negate, options|
|
316
|
+
unless negate
|
317
|
+
bools.must.channel(int, options)
|
318
|
+
else
|
319
|
+
bools.must_not.channel(int, options)
|
320
|
+
end
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
it 'should raise error if an integer variable is not given as right hand side' do
|
325
|
+
lambda do
|
326
|
+
@bools.must.channel 'hello'
|
327
|
+
end.should raise_error(TypeError)
|
328
|
+
end
|
329
|
+
|
330
|
+
it_should_behave_like 'channel constraint between bool enum and int variable'
|
331
|
+
end
|
332
|
+
|
333
|
+
|
334
|
+
describe Gecode::Constraints::BoolEnum::Channel, ' (int variable as lhs with bool enum)' do
|
335
|
+
before do
|
336
|
+
@model = BoolChannelSampleProblem.new
|
337
|
+
@bools = @model.bool_enum
|
338
|
+
@int = @model.int
|
339
|
+
|
340
|
+
@place_constraint = lambda do |bools, int, negate, options|
|
341
|
+
unless negate
|
342
|
+
int.must.channel(bools, options)
|
343
|
+
else
|
344
|
+
int.must_not.channel(bools, options)
|
345
|
+
end
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
it 'should raise error if a boolean enum is not given as right hand side' do
|
350
|
+
lambda do
|
351
|
+
@int.must.channel 'hello'
|
352
|
+
end.should raise_error(TypeError)
|
353
|
+
end
|
354
|
+
|
355
|
+
it_should_behave_like 'channel constraint between bool enum and int variable'
|
356
|
+
end
|