gecoder-with-gecode 0.8.2 → 0.8.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. data/CHANGES +14 -0
  2. data/ext/gecoder.cpp +181 -0
  3. data/ext/gecoder.h +94 -0
  4. data/ext/vararray.cpp +3 -3
  5. data/lib/gecoder/bindings/bindings.rb +104 -46
  6. data/lib/gecoder/interface/binding_changes.rb +1 -301
  7. data/lib/gecoder/interface/branch.rb +15 -11
  8. data/lib/gecoder/interface/constraints.rb +38 -0
  9. data/lib/gecoder/interface/constraints/bool/boolean.rb +56 -52
  10. data/lib/gecoder/interface/constraints/bool/channel.rb +1 -16
  11. data/lib/gecoder/interface/constraints/bool_enum/channel.rb +13 -8
  12. data/lib/gecoder/interface/constraints/bool_enum/extensional.rb +48 -0
  13. data/lib/gecoder/interface/constraints/extensional_regexp.rb +101 -0
  14. data/lib/gecoder/interface/constraints/int/channel.rb +1 -13
  15. data/lib/gecoder/interface/constraints/int_enum/channel.rb +15 -35
  16. data/lib/gecoder/interface/constraints/int_enum/extensional.rb +130 -0
  17. data/lib/gecoder/interface/constraints/set/channel.rb +54 -0
  18. data/lib/gecoder/interface/constraints/set_enum/channel.rb +37 -6
  19. data/lib/gecoder/interface/constraints/set_var_constraints.rb +1 -0
  20. data/lib/gecoder/interface/model.rb +110 -85
  21. data/lib/gecoder/interface/variables.rb +3 -21
  22. data/lib/gecoder/version.rb +1 -1
  23. data/specs/branch.rb +16 -1
  24. data/specs/constraints/bool_enum_relation.rb +6 -6
  25. data/specs/constraints/boolean.rb +31 -25
  26. data/specs/constraints/channel.rb +102 -4
  27. data/specs/constraints/extensional.rb +185 -2
  28. data/specs/constraints/reification_sugar.rb +2 -46
  29. data/specs/model.rb +85 -7
  30. data/tasks/dependencies.txt +1 -0
  31. data/vendor/rust/rust/class.rb +33 -35
  32. data/vendor/rust/rust/templates/ClassDeclarations.rusttpl +1 -1
  33. data/vendor/rust/rust/templates/CxxClassDefinitions.rusttpl +10 -1
  34. metadata +707 -706
  35. data/example/raw_bindings.rb +0 -44
  36. data/ext/missing.cpp +0 -328
  37. data/ext/missing.h +0 -120
  38. data/specs/binding_changes.rb +0 -76
@@ -15,8 +15,8 @@ class BoolEnumSampleProblem < Gecode::Model
15
15
  end
16
16
  end
17
17
 
18
- # Expects @stub, which contains the started constraint and @compute_result which
19
- # computes whether the left hand side is true or not.
18
+ # Expects @stub, which contains the started constraint and @compute_result
19
+ # which computes whether the left hand side is true or not.
20
20
  describe 'bool enum relation constraint', :shared => true do
21
21
  it 'should handle being constrained to be true' do
22
22
  @stub.must_be.true
@@ -76,7 +76,7 @@ describe Gecode::Constraints::BoolEnum::Relation, ' (conjunction)' do
76
76
 
77
77
  # For constraint option spec.
78
78
  @invoke_options = lambda do |hash|
79
- @bools.conjunction.must_be.equal_to(true, hash)
79
+ @bools.conjunction.must.equal(@b1, hash)
80
80
  @model.solve!
81
81
  end
82
82
  @expect_options = option_expectation do |strength, kind, reif_var|
@@ -94,7 +94,7 @@ describe Gecode::Constraints::BoolEnum::Relation, ' (conjunction)' do
94
94
  an_instance_of(Gecode::Raw::BoolVar),
95
95
  anything,
96
96
  an_instance_of(Gecode::Raw::BoolVar),
97
- anything, anything, anything)
97
+ anything, anything)
98
98
  Gecode::Raw.should_receive(:rel).once.with(
99
99
  an_instance_of(Gecode::Raw::Space),
100
100
  Gecode::Raw::BOT_AND,
@@ -122,7 +122,7 @@ describe Gecode::Constraints::BoolEnum::Relation, ' (disjunction)' do
122
122
 
123
123
  # For constraint option spec.
124
124
  @invoke_options = lambda do |hash|
125
- @bools.disjunction.must_be.equal_to(true, hash)
125
+ @bools.disjunction.must.equal(@b1, hash)
126
126
  @model.solve!
127
127
  end
128
128
  @expect_options = option_expectation do |strength, kind, reif_var|
@@ -140,7 +140,7 @@ describe Gecode::Constraints::BoolEnum::Relation, ' (disjunction)' do
140
140
  an_instance_of(Gecode::Raw::BoolVar),
141
141
  anything,
142
142
  an_instance_of(Gecode::Raw::BoolVar),
143
- anything, anything, anything)
143
+ anything, anything)
144
144
  Gecode::Raw.should_receive(:rel).once.with(
145
145
  an_instance_of(Gecode::Raw::Space),
146
146
  Gecode::Raw::BOT_OR,
@@ -22,28 +22,22 @@ describe Gecode::Constraints::Bool do
22
22
 
23
23
  # For constraint option spec.
24
24
  @invoke_options = lambda do |hash|
25
- (@b1 | @b2).must_be.equal_to(true, hash)
25
+ (@b1 | @b2).must_be.true(hash)
26
26
  @model.solve!
27
27
  end
28
28
  @expect_options = option_expectation do |strength, kind, reif_var|
29
29
  @model.allow_space_access do
30
- Gecode::Raw.should_receive(:rel).once.with(
31
- an_instance_of(Gecode::Raw::Space),
32
- an_instance_of(Gecode::Raw::BoolVar),
33
- Gecode::Raw::BOT_OR,
34
- an_instance_of(Gecode::Raw::BoolVar),
35
- an_instance_of(Gecode::Raw::BoolVar),
36
- Gecode::Raw::ICL_DEF, Gecode::Raw::PK_DEF)
30
+ # We only test the non-MiniModel parts.
37
31
  unless reif_var.nil?
38
32
  Gecode::Raw.should_receive(:rel).once.with(
39
33
  an_instance_of(Gecode::Raw::Space),
40
- an_instance_of(Gecode::Raw::BoolVar), Gecode::Raw::BOT_EQV,
41
- an_instance_of(Gecode::Raw::BoolVar), 1, strength, kind)
34
+ an_instance_of(Gecode::Raw::BoolVar), Gecode::Raw::IRT_EQ,
35
+ an_instance_of(Gecode::Raw::BoolVar), strength, kind)
42
36
  end
43
37
  end
44
38
  end
45
39
  end
46
-
40
+
47
41
  it 'should handle single variables constrainted to be true' do
48
42
  @b1.must_be.true
49
43
  b1 = @model.solve!.b1
@@ -79,7 +73,7 @@ describe Gecode::Constraints::Bool do
79
73
  sol.b1.value.should_not be_true
80
74
  sol.b2.value.should be_true
81
75
  end
82
-
76
+
83
77
  it 'should handle negated disjunction' do
84
78
  @b1.must_be.false
85
79
  (@b1 | @b2).must_not_be.true
@@ -87,7 +81,7 @@ describe Gecode::Constraints::Bool do
87
81
  sol.b1.value.should_not be_true
88
82
  sol.b2.value.should_not be_true
89
83
  end
90
-
84
+
91
85
  it 'should handle conjunction' do
92
86
  (@b1 & @b2).must_be.true
93
87
  sol = @model.solve!
@@ -142,7 +136,7 @@ describe Gecode::Constraints::Bool do
142
136
  sol.b1.value.should_not be_true
143
137
  sol.b2.value.should_not be_true
144
138
  end
145
-
139
+
146
140
  it 'should handle imply after must_not' do
147
141
  @b1.must_be.true
148
142
  @b1.must_not.imply @b2
@@ -166,7 +160,7 @@ describe Gecode::Constraints::Bool do
166
160
  sol.b1.value.should be_true
167
161
  sol.b2.value.should_not be_true
168
162
  end
169
-
163
+
170
164
  it 'should handle expressions as right hand side' do
171
165
  @b1.must == (@b2 | @b3)
172
166
  @b2.must_be.true
@@ -174,7 +168,7 @@ describe Gecode::Constraints::Bool do
174
168
  sol.b1.value.should be_true
175
169
  sol.b2.value.should be_true
176
170
  end
177
-
171
+
178
172
  it 'should handle nested expressions as left hand side' do
179
173
  ((@b1 & @b2) | @b3 | (@b1 & @b3)).must_be.true
180
174
  @b1.must_be.false
@@ -182,7 +176,7 @@ describe Gecode::Constraints::Bool do
182
176
  sol.b1.value.should_not be_true
183
177
  sol.b3.value.should be_true
184
178
  end
185
-
179
+
186
180
  it 'should handle nested expressions on both side' do
187
181
  ((@b1 & @b1) | @b3).must == ((@b1 & @b3) & @b2)
188
182
  @b1.must_be.true
@@ -191,7 +185,15 @@ describe Gecode::Constraints::Bool do
191
185
  sol.b2.value.should be_true
192
186
  sol.b3.value.should be_true
193
187
  end
194
-
188
+
189
+ it 'should handle nested expressions with implication' do
190
+ ((@b1 & @b1) | @b3).must.imply(@b1 ^ @b2)
191
+ @b1.must_be.true
192
+ sol = @model.solve!
193
+ sol.b1.value.should be_true
194
+ sol.b2.value.should be_false
195
+ end
196
+
195
197
  it 'should handle nested expressions containing exclusive or' do
196
198
  ((@b1 ^ @b1) & @b3).must == ((@b2 | @b3) ^ @b2)
197
199
  @b1.must_be.true
@@ -201,7 +203,7 @@ describe Gecode::Constraints::Bool do
201
203
  sol.b2.value.should_not be_true
202
204
  sol.b3.value.should_not be_true
203
205
  end
204
-
206
+
205
207
  it 'should handle nested expressions on both sides with negation' do
206
208
  ((@b1 & @b1) | @b3).must_not == ((@b1 | @b3) & @b2)
207
209
  @b1.must_be.true
@@ -211,7 +213,7 @@ describe Gecode::Constraints::Bool do
211
213
  sol.b2.value.should_not be_true
212
214
  sol.b3.value.should be_true
213
215
  end
214
-
216
+
215
217
  it 'should translate reification with a variable right hand side' do
216
218
  @b1.must_be.equal_to(@b2, :reify => @b3)
217
219
  @b1.must_be.true
@@ -219,8 +221,8 @@ describe Gecode::Constraints::Bool do
219
221
  sol = @model.solve!
220
222
  sol.b3.value.should_not be_true
221
223
  end
222
-
223
- it 'should translate reification with a variable right hand side and negation' do
224
+
225
+ it 'should translate reification with a variable right hand side and negation' do
224
226
  @b1.must_not_be.equal_to(@b2, :reify => @b3)
225
227
  @b1.must_be.true
226
228
  @b2.must_be.false
@@ -228,9 +230,13 @@ describe Gecode::Constraints::Bool do
228
230
  sol.b3.value.should be_true
229
231
  end
230
232
 
231
- it 'should raise error on right hand sides of the wrong type' do
233
+ it 'should raise error on right hand sides of incorrect type given to #==' do
232
234
  lambda{ @b1.must == 'hello' }.should raise_error(TypeError)
233
235
  end
234
-
236
+
237
+ it 'should raise error on right hand sides of incorrect type given to #imply' do
238
+ lambda{ @b1.must.imply 'hello' }.should raise_error(TypeError)
239
+ end
240
+
235
241
  it_should_behave_like 'reifiable constraint'
236
- end
242
+ end
@@ -26,10 +26,23 @@ class BoolChannelSampleProblem < Gecode::Model
26
26
  @int = int_var(0..3)
27
27
  @bool = bool_var
28
28
 
29
- branch_on wrap_enum([@int])
29
+ branch_on @int
30
30
  end
31
31
  end
32
32
 
33
+ class SetChannelSampleProblem < Gecode::Model
34
+ attr :bool_enum
35
+ attr :set
36
+
37
+ def initialize
38
+ @bool_enum = bool_var_array(4)
39
+ @set = set_var([], 0..3)
40
+
41
+ branch_on @bool_enum
42
+ end
43
+ end
44
+
45
+
33
46
  describe Gecode::Constraints::IntEnum::Channel, ' (two int enums)' do
34
47
  before do
35
48
  @model = ChannelSampleProblem.new
@@ -73,10 +86,10 @@ describe Gecode::Constraints::IntEnum::Channel, ' (two int enums)' do
73
86
  lambda{ @elements.must.channel 'hello' }.should raise_error(TypeError)
74
87
  end
75
88
 
76
- it_should_behave_like 'reifiable constraint'
89
+ it_should_behave_like 'non-reifiable constraint'
77
90
  end
78
91
 
79
- describe Gecode::Constraints::IntEnum::Channel, ' (one int enum and one set enum)' do
92
+ describe Gecode::Constraints::SetEnum::Channel::IntChannelConstraint, ' (channel with set as right hand side)' do
80
93
  before do
81
94
  @model = ChannelSampleProblem.new
82
95
  @positions = @model.positions
@@ -113,7 +126,7 @@ describe Gecode::Constraints::IntEnum::Channel, ' (one int enum and one set enum
113
126
  it_should_behave_like 'non-reifiable set constraint'
114
127
  end
115
128
 
116
- describe Gecode::Constraints::SetEnum, ' (channel with set as left hand side)' do
129
+ describe Gecode::Constraints::SetEnum::Channel::IntChannelConstraint, ' (channel with set as left hand side)' do
117
130
  before do
118
131
  @model = ChannelSampleProblem.new
119
132
  @positions = @model.positions
@@ -354,3 +367,88 @@ describe Gecode::Constraints::BoolEnum::Channel, ' (int variable as lhs with boo
354
367
 
355
368
  it_should_behave_like 'channel constraint between bool enum and int variable'
356
369
  end
370
+
371
+ # Requires @model, @bool_enum and @set. Also requires @place_constraint which
372
+ # is a method that takes four variables: a boolean enum, a set variable,
373
+ # whether or not the constraint should be negated and a hash of options, and
374
+ # places the channel constraint on them.
375
+ describe 'channel constraint between set variable and bool enum', :shared => true do
376
+ before do
377
+ @invoke_options = lambda do |hash|
378
+ @place_constraint.call(@bools, @set, false, hash)
379
+ @model.solve!
380
+ end
381
+ @expect_options = option_expectation do |strength, kind, reif_var|
382
+ Gecode::Raw.should_receive(:channel).once.with(
383
+ an_instance_of(Gecode::Raw::Space),
384
+ an_instance_of(Gecode::Raw::BoolVarArray),
385
+ an_instance_of(Gecode::Raw::SetVar))
386
+ end
387
+ end
388
+
389
+ it 'should channel the bool enum with the set variable' do
390
+ @set.must_be.superset_of [0, 2]
391
+ @place_constraint.call(@bools, @set, false, {})
392
+ @model.solve!.should_not be_nil
393
+ set_values = @set.value
394
+ @bools.values.each_with_index do |bool, index|
395
+ bool.should == set_values.include?(index)
396
+ end
397
+ end
398
+
399
+ it 'should not allow negation' do
400
+ lambda do
401
+ @place_constraint.call(@bools, @set, true, {})
402
+ end.should raise_error(Gecode::MissingConstraintError)
403
+ end
404
+
405
+ it_should_behave_like 'non-reifiable set constraint'
406
+ end
407
+
408
+ describe Gecode::Constraints::Set::Channel, ' (set variable as lhs with bool enum)' do
409
+ before do
410
+ @model = SetChannelSampleProblem.new
411
+ @bools = @model.bool_enum
412
+ @set = @model.set
413
+
414
+ @place_constraint = lambda do |bools, set, negate, options|
415
+ unless negate
416
+ set.must.channel(bools, options)
417
+ else
418
+ set.must_not.channel(bools, options)
419
+ end
420
+ end
421
+ end
422
+
423
+ it 'should raise error if a boolean enum is not given as right hand side' do
424
+ lambda do
425
+ @set.must.channel 'hello'
426
+ end.should raise_error(TypeError)
427
+ end
428
+
429
+ it_should_behave_like 'channel constraint between set variable and bool enum'
430
+ end
431
+
432
+ describe Gecode::Constraints::Set::Channel, ' (bool enum as lhs with set variable)' do
433
+ before do
434
+ @model = SetChannelSampleProblem.new
435
+ @bools = @model.bool_enum
436
+ @set = @model.set
437
+
438
+ @place_constraint = lambda do |bools, set, negate, options|
439
+ unless negate
440
+ bools.must.channel(set, options)
441
+ else
442
+ bools.must_not.channel(set, options)
443
+ end
444
+ end
445
+ end
446
+
447
+ it 'should raise error if an integer variable is not given as right hand side' do
448
+ lambda do
449
+ @bools.must.channel 'hello'
450
+ end.should raise_error(TypeError)
451
+ end
452
+
453
+ it_should_behave_like 'channel constraint between set variable and bool enum'
454
+ end
@@ -44,7 +44,7 @@ describe 'tuple constraint', :shared => true do
44
44
  it_should_behave_like 'non-reifiable constraint'
45
45
  end
46
46
 
47
- describe Gecode::Constraints::IntEnum::Extensional do
47
+ describe Gecode::Constraints::IntEnum::Extensional, ' (tuple constraint)' do
48
48
  before do
49
49
  @model = Gecode::Model.new
50
50
  @tuples = [[1,7], [5,1]]
@@ -77,7 +77,7 @@ describe Gecode::Constraints::IntEnum::Extensional do
77
77
  it_should_behave_like 'tuple constraint'
78
78
  end
79
79
 
80
- describe Gecode::Constraints::BoolEnum::Extensional do
80
+ describe Gecode::Constraints::BoolEnum::Extensional, ' (tuple constraint)' do
81
81
  before do
82
82
  @model = Gecode::Model.new
83
83
  @tuples = [[true, false, true], [false, false, true]]
@@ -109,3 +109,186 @@ describe Gecode::Constraints::BoolEnum::Extensional do
109
109
 
110
110
  it_should_behave_like 'tuple constraint'
111
111
  end
112
+
113
+ # Assumes that @variables, @expected_array, @value1, @value2 (must not
114
+ # equal @value1) and @regexp are defined.
115
+ describe 'regular expression constraint', :shared => true do
116
+ before do
117
+ @invoke_options = lambda do |hash|
118
+ @variables.must.match(@regexp, hash)
119
+ @model.solve!
120
+ end
121
+ @expect_options = option_expectation do |strength, kind, reif_var|
122
+ Gecode::Raw.should_receive(:extensional).once.with(
123
+ an_instance_of(Gecode::Raw::Space),
124
+ @expected_array,
125
+ an_instance_of(Gecode::Raw::REG), strength, kind)
126
+ end
127
+ end
128
+
129
+ it 'should handle values grouped in a single array' do
130
+ @variables.must.match [@value1, @value2, @value1]
131
+ @model.solve!.should_not be_nil
132
+ @variables.values.should == [@value1, @value2, @value1]
133
+ end
134
+
135
+ it 'should allow nested groups of values' do
136
+ @variables.must.match [@value1, [@value2, [@value1]]]
137
+ @model.solve!.should_not be_nil
138
+ @variables.values.should == [@value1, @value2, @value1]
139
+ end
140
+
141
+ it 'should handle the repeat operation' do
142
+ @variables.must.match [@value1, @model.repeat([@value2], 1, 2)]
143
+ @model.solve!.should_not be_nil
144
+ @variables.values.should == [@value1, @value2, @value2]
145
+ end
146
+
147
+ it 'should handle repeat operations that do not encase constant values in arrays' do
148
+ @variables.must.match [@value1, @model.repeat(@value2, 1, 2)]
149
+ @model.solve!.should_not be_nil
150
+ @variables.values.should == [@value1, @value2, @value2]
151
+ end
152
+
153
+ it 'should handle nested repeat operations' do
154
+ @variables.must.match [[@model.repeat(@model.repeat([@value2], 1, 3), 1, 2)]]
155
+ @model.solve!.should_not be_nil
156
+ @variables.values.should == [@value2, @value2, @value2]
157
+ end
158
+
159
+ it 'should handle nested repeat operations (2)' do
160
+ @variables.must.match [[@model.repeat([@model.repeat(@value2, 1, 3)], 1, 2)]]
161
+ @model.solve!.should_not be_nil
162
+ @variables.values.should == [@value2, @value2, @value2]
163
+ end
164
+
165
+ it 'should interpret the repeat operation with the last argument omitted as only giving a lower bound' do
166
+ @variables.must.match [@value1, @model.repeat([@value2], 1)]
167
+ @model.solve!.should_not be_nil
168
+ @variables.values.should == [@value1, @value2, @value2]
169
+ end
170
+
171
+ it 'should interpret the repeat operation with all but the first argument omitted as not giving any bound' do
172
+ @variables.must.match [@model.repeat(@value2), @value1, @value1, @value1]
173
+ @model.solve!.should_not be_nil
174
+ @variables.values.should == [@value1, @value1, @value1]
175
+ end
176
+
177
+ it 'should interpret the repeat operation with all but the first argument omitted as not giving any bound (2)' do
178
+ @variables.must.match [@model.repeat(@value2)]
179
+ @model.solve!.should_not be_nil
180
+ @variables.values.should == [@value2, @value2, @value2]
181
+ end
182
+
183
+ it 'should translate at_most_once(reg) to repeat(reg, 0, 1)' do
184
+ @model.should_receive(:repeat).once.with([@value1], 0, 1)
185
+ @model.at_most_once [@value1]
186
+ end
187
+
188
+ it 'should translate at_least_once(reg) to repeat(reg, 1)' do
189
+ @model.should_receive(:repeat).once.with([@value1], 1)
190
+ @model.at_least_once [@value1]
191
+ end
192
+
193
+ it 'should raise error if the right hand side is not an enumeration' do
194
+ lambda do
195
+ @variables.must.match Object.new
196
+ end.should raise_error(TypeError)
197
+ end
198
+
199
+ it 'should raise error if the right hand side does not a regexp of the right type' do
200
+ lambda do
201
+ @variables.must.match [@value1, 'foo']
202
+ end.should raise_error(TypeError)
203
+ end
204
+
205
+ it 'should raise error if the right hand side contains a nested element of an incorrect type' do
206
+ lambda do
207
+ @variables.must.match [@value1, [@value2, 'foo']]
208
+ end.should raise_error(TypeError)
209
+ end
210
+
211
+ it 'should raise error if the repeat operation is given arguments of incorrect type (2)' do
212
+ lambda do
213
+ @variables.must.match @model.repeat(@value1, [0], 1)
214
+ end.should raise_error(TypeError)
215
+ end
216
+
217
+ it 'should raise error if the repeat operation is given arguments of incorrect type (3)' do
218
+ lambda do
219
+ @variables.must.match @model.repeat(@value1, 0, [1])
220
+ end.should raise_error(TypeError)
221
+ end
222
+
223
+ it 'should raise error if the repeat operation is given arguments of incorrect type' do
224
+ lambda do
225
+ @variables.must.match @model.repeat('foo', 0, 1)
226
+ end.should raise_error(TypeError)
227
+ end
228
+
229
+ it 'should not allow negation' do
230
+ lambda do
231
+ @variables.must_not.match @regexp
232
+ end.should raise_error(Gecode::MissingConstraintError)
233
+ end
234
+
235
+ it_should_behave_like 'non-reifiable constraint'
236
+ end
237
+
238
+ describe Gecode::Constraints::IntEnum::Extensional, ' (regexp constraint)' do
239
+ before do
240
+ @model = Gecode::Model.new
241
+ @variables = @digits = @model.int_var_array(3, 0..9)
242
+ @model.branch_on @digits
243
+ @expected_array = an_instance_of Gecode::Raw::IntVarArray
244
+ @value1 = 3
245
+ @value2 = 5
246
+ @regexp = [1, @model.any(3, 4), @model.at_most_once(5)]
247
+ end
248
+
249
+ it 'should handle the any operation' do
250
+ @digits.must.match [1, @model.any(1, 2, 3), 3]
251
+ @model.solve!.should_not be_nil
252
+ values = @digits.values
253
+ values.size.should == 3
254
+ values.should == values.sort
255
+ end
256
+
257
+ it 'should handle the any operator with nested expressions' do
258
+ @digits.must.match [1, @model.any(@model.at_least_once(2), [3, 5])]
259
+ @digits[2].must < 4
260
+ @model.solve!.should_not be_nil
261
+ @digits.values.should == [1,2,2]
262
+ end
263
+
264
+ it_should_behave_like 'regular expression constraint'
265
+ end
266
+
267
+ describe Gecode::Constraints::BoolEnum::Extensional, ' (regexp constraint)' do
268
+ before do
269
+ @model = Gecode::Model.new
270
+ @variables = @bools = @model.bool_var_array(3)
271
+ @model.branch_on @bools
272
+ @expected_array = an_instance_of Gecode::Raw::BoolVarArray
273
+ @value1 = true
274
+ @value2 = false
275
+ @regexp = [true, @model.any(true, false), @model.at_most_once(true)]
276
+ end
277
+
278
+ it 'should handle the any operation' do
279
+ @bools.must.match [@model.repeat(@model.any(true, false))]
280
+ @bools[0].must_be.true
281
+ @bools[1].must_be.false
282
+ @model.solve!.should_not be_nil
283
+ @bools[0].value.should be_true
284
+ @bools[1].value.should be_false
285
+ end
286
+
287
+ it 'should handle the any operator with nested expressions' do
288
+ @bools.must.match [@model.any(@model.at_least_once(true), [false])]
289
+ @model.solve!.should_not be_nil
290
+ @bools.values.should == [true, true, true]
291
+ end
292
+
293
+ it_should_behave_like 'regular expression constraint'
294
+ end