gecoder 0.8.3 → 0.9.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 +15 -0
- data/README +6 -2
- data/example/equation_system.rb +15 -0
- data/example/magic_sequence.rb +7 -7
- data/example/money.rb +36 -0
- data/example/queens.rb +7 -8
- data/example/send_most_money.rb +1 -1
- data/example/square_tiling.rb +2 -2
- data/example/sudoku-set.rb +11 -12
- data/example/sudoku.rb +40 -45
- data/ext/extconf.rb +0 -0
- data/lib/gecoder/bindings.rb +42 -0
- data/lib/gecoder/bindings/bindings.rb +16 -0
- data/lib/gecoder/interface.rb +2 -1
- data/lib/gecoder/interface/branch.rb +16 -9
- data/lib/gecoder/interface/constraints.rb +410 -451
- data/lib/gecoder/interface/constraints/bool/boolean.rb +205 -213
- data/lib/gecoder/interface/constraints/bool/channel.rb +4 -5
- data/lib/gecoder/interface/constraints/bool/linear.rb +192 -21
- data/lib/gecoder/interface/constraints/bool_enum/channel.rb +43 -39
- data/lib/gecoder/interface/constraints/bool_enum/extensional.rb +43 -49
- data/lib/gecoder/interface/constraints/bool_enum/relation.rb +38 -71
- data/lib/gecoder/interface/constraints/bool_enum_constraints.rb +73 -22
- data/lib/gecoder/interface/constraints/bool_var_constraints.rb +140 -61
- data/lib/gecoder/interface/constraints/extensional_regexp.rb +4 -4
- data/lib/gecoder/interface/constraints/fixnum_enum/element.rb +63 -0
- data/lib/gecoder/interface/constraints/fixnum_enum/operation.rb +65 -0
- data/lib/gecoder/interface/constraints/fixnum_enum_constraints.rb +42 -0
- data/lib/gecoder/interface/constraints/int/arithmetic.rb +131 -130
- data/lib/gecoder/interface/constraints/int/channel.rb +21 -31
- data/lib/gecoder/interface/constraints/int/domain.rb +45 -42
- data/lib/gecoder/interface/constraints/int/linear.rb +85 -239
- data/lib/gecoder/interface/constraints/int/relation.rb +141 -0
- data/lib/gecoder/interface/constraints/int_enum/arithmetic.rb +55 -64
- data/lib/gecoder/interface/constraints/int_enum/channel.rb +35 -37
- data/lib/gecoder/interface/constraints/int_enum/count.rb +53 -78
- data/lib/gecoder/interface/constraints/int_enum/distinct.rb +36 -46
- data/lib/gecoder/interface/constraints/int_enum/element.rb +39 -57
- data/lib/gecoder/interface/constraints/int_enum/equality.rb +15 -19
- data/lib/gecoder/interface/constraints/int_enum/extensional.rb +65 -72
- data/lib/gecoder/interface/constraints/int_enum/sort.rb +42 -45
- data/lib/gecoder/interface/constraints/int_enum_constraints.rb +79 -22
- data/lib/gecoder/interface/constraints/int_var_constraints.rb +215 -44
- data/lib/gecoder/interface/constraints/reifiable_constraints.rb +14 -14
- data/lib/gecoder/interface/constraints/selected_set/select.rb +120 -0
- data/lib/gecoder/interface/constraints/selected_set_constraints.rb +75 -0
- data/lib/gecoder/interface/constraints/set/cardinality.rb +43 -53
- data/lib/gecoder/interface/constraints/set/channel.rb +26 -29
- data/lib/gecoder/interface/constraints/set/connection.rb +89 -152
- data/lib/gecoder/interface/constraints/set/domain.rb +112 -65
- data/lib/gecoder/interface/constraints/set/include.rb +36 -0
- data/lib/gecoder/interface/constraints/set/operation.rb +96 -110
- data/lib/gecoder/interface/constraints/set/relation.rb +114 -137
- data/lib/gecoder/interface/constraints/set_elements/relation.rb +116 -0
- data/lib/gecoder/interface/constraints/set_elements_constraints.rb +97 -0
- data/lib/gecoder/interface/constraints/set_enum/channel.rb +23 -27
- data/lib/gecoder/interface/constraints/set_enum/distinct.rb +18 -19
- data/lib/gecoder/interface/constraints/set_enum/operation.rb +62 -53
- data/lib/gecoder/interface/constraints/set_enum/select.rb +79 -0
- data/lib/gecoder/interface/constraints/set_enum_constraints.rb +73 -23
- data/lib/gecoder/interface/constraints/set_var_constraints.rb +222 -57
- data/lib/gecoder/interface/enum_matrix.rb +4 -4
- data/lib/gecoder/interface/enum_wrapper.rb +71 -22
- data/lib/gecoder/interface/model.rb +167 -12
- data/lib/gecoder/interface/model_sugar.rb +84 -0
- data/lib/gecoder/interface/search.rb +30 -18
- data/lib/gecoder/interface/variables.rb +103 -33
- data/lib/gecoder/version.rb +2 -2
- data/specs/bool_var.rb +19 -12
- data/specs/constraints/{boolean.rb → bool/boolean.rb} +103 -28
- data/specs/constraints/bool/boolean_properties.rb +51 -0
- data/specs/constraints/bool/linear.rb +213 -0
- data/specs/constraints/bool_enum/bool_enum_relation.rb +117 -0
- data/specs/constraints/bool_enum/channel.rb +102 -0
- data/specs/constraints/{extensional.rb → bool_enum/extensional.rb} +32 -101
- data/specs/constraints/constraint_helper.rb +149 -179
- data/specs/constraints/constraint_receivers.rb +103 -0
- data/specs/constraints/constraints.rb +6 -63
- data/specs/constraints/fixnum_enum/element.rb +58 -0
- data/specs/constraints/fixnum_enum/operation.rb +67 -0
- data/specs/constraints/int/arithmetic.rb +149 -0
- data/specs/constraints/int/channel.rb +101 -0
- data/specs/constraints/int/domain.rb +106 -0
- data/specs/constraints/int/linear.rb +183 -0
- data/specs/constraints/int/linear_properties.rb +97 -0
- data/specs/constraints/int/relation.rb +84 -0
- data/specs/constraints/int_enum/arithmetic.rb +72 -0
- data/specs/constraints/int_enum/channel.rb +57 -0
- data/specs/constraints/int_enum/count.rb +72 -0
- data/specs/constraints/int_enum/distinct.rb +80 -0
- data/specs/constraints/int_enum/element.rb +61 -0
- data/specs/constraints/int_enum/equality.rb +29 -0
- data/specs/constraints/int_enum/extensional.rb +224 -0
- data/specs/constraints/int_enum/sort.rb +167 -0
- data/specs/constraints/operands.rb +264 -0
- data/specs/constraints/property_helper.rb +443 -0
- data/specs/constraints/reification_sugar.rb +4 -5
- data/specs/constraints/selected_set/select.rb +56 -0
- data/specs/constraints/selected_set/select_properties.rb +157 -0
- data/specs/constraints/set/cardinality.rb +58 -0
- data/specs/constraints/set/cardinality_properties.rb +46 -0
- data/specs/constraints/set/channel.rb +77 -0
- data/specs/constraints/set/connection.rb +176 -0
- data/specs/constraints/set/domain.rb +197 -0
- data/specs/constraints/set/include.rb +36 -0
- data/specs/constraints/set/operation.rb +132 -0
- data/specs/constraints/set/relation.rb +117 -0
- data/specs/constraints/set_elements/relation.rb +84 -0
- data/specs/constraints/set_enum/channel.rb +80 -0
- data/specs/constraints/set_enum/distinct.rb +59 -0
- data/specs/constraints/set_enum/operation.rb +111 -0
- data/specs/constraints/set_enum/select.rb +73 -0
- data/specs/enum_wrapper.rb +53 -3
- data/specs/int_var.rb +44 -25
- data/specs/model.rb +58 -1
- data/specs/model_sugar.rb +30 -0
- data/specs/search.rb +24 -5
- data/specs/selected_set.rb +39 -0
- data/specs/set_elements.rb +34 -0
- data/specs/set_var.rb +22 -8
- data/specs/spec_helper.rb +206 -6
- data/tasks/distribution.rake +22 -7
- data/tasks/svn.rake +3 -1
- metadata +218 -134
- data/lib/gecoder/interface/constraints/set_enum/selection.rb +0 -217
- data/specs/constraints/arithmetic.rb +0 -351
- data/specs/constraints/bool_enum_relation.rb +0 -160
- data/specs/constraints/cardinality.rb +0 -157
- data/specs/constraints/channel.rb +0 -454
- data/specs/constraints/connection.rb +0 -369
- data/specs/constraints/count.rb +0 -146
- data/specs/constraints/distinct.rb +0 -164
- data/specs/constraints/element.rb +0 -108
- data/specs/constraints/equality.rb +0 -31
- data/specs/constraints/int_domain.rb +0 -70
- data/specs/constraints/int_relation.rb +0 -82
- data/specs/constraints/linear.rb +0 -340
- data/specs/constraints/selection.rb +0 -292
- data/specs/constraints/set_domain.rb +0 -185
- data/specs/constraints/set_operation.rb +0 -285
- data/specs/constraints/set_relation.rb +0 -197
- data/specs/constraints/sort.rb +0 -179
@@ -0,0 +1,102 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../constraint_helper'
|
2
|
+
|
3
|
+
class BoolChannelSampleProblem < Gecode::Model
|
4
|
+
attr :bool_enum
|
5
|
+
attr :bool
|
6
|
+
attr :int
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@bool_enum = bool_var_array(4)
|
10
|
+
@int = int_var(0..3)
|
11
|
+
@bool = bool_var
|
12
|
+
|
13
|
+
branch_on @int
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe Gecode::BoolEnum::Channel, ' (bool enum as lhs with int variable)' do
|
18
|
+
before do
|
19
|
+
@model = BoolChannelSampleProblem.new
|
20
|
+
@bools = @model.bool_enum
|
21
|
+
@int = @model.int
|
22
|
+
|
23
|
+
@types = [:bool_enum, :int]
|
24
|
+
@invoke = lambda do |receiver, int, hash|
|
25
|
+
receiver.channel(int, hash)
|
26
|
+
@model.solve!
|
27
|
+
end
|
28
|
+
@expect = lambda do |var1, var2, opts, reif_var|
|
29
|
+
Gecode::Raw.should_receive(:channel).once.with(
|
30
|
+
an_instance_of(Gecode::Raw::Space),
|
31
|
+
var1, var2, 0, *opts)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should channel the bool enum with the integer variable' do
|
36
|
+
@int.must > 2
|
37
|
+
@bools.must.channel @int
|
38
|
+
@model.solve!.should_not be_nil
|
39
|
+
int_val = @int.value
|
40
|
+
@bools.values.each_with_index do |bool, index|
|
41
|
+
bool.should == (index == int_val)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should take the offset into account when channeling' do
|
46
|
+
@int.must > 2
|
47
|
+
offset = 1
|
48
|
+
@bools.must.channel(@int, :offset => offset)
|
49
|
+
@model.solve!.should_not be_nil
|
50
|
+
int_val = @int.value
|
51
|
+
@bools.values.each_with_index do |bool, index|
|
52
|
+
bool.should == (index + offset == int_val)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
it_should_behave_like 'non-reifiable constraint'
|
57
|
+
it_should_behave_like 'non-negatable constraint'
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
describe Gecode::BoolEnum::Channel, ' (int variable as lhs with bool enum)' do
|
62
|
+
before do
|
63
|
+
@model = BoolChannelSampleProblem.new
|
64
|
+
@bools = @model.bool_enum
|
65
|
+
@int = @model.int
|
66
|
+
|
67
|
+
@types = [:int, :bool_enum]
|
68
|
+
@invoke = lambda do |receiver, bool_enum, hash|
|
69
|
+
receiver.channel(bool_enum, hash)
|
70
|
+
@model.solve!
|
71
|
+
end
|
72
|
+
@expect = lambda do |var1, var2, opts, reif_var|
|
73
|
+
Gecode::Raw.should_receive(:channel).once.with(
|
74
|
+
an_instance_of(Gecode::Raw::Space),
|
75
|
+
var2, var1, 0, *opts)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'should channel the bool enum with the integer variable' do
|
80
|
+
@int.must > 2
|
81
|
+
@int.must.channel @bools
|
82
|
+
@model.solve!.should_not be_nil
|
83
|
+
int_val = @int.value
|
84
|
+
@bools.values.each_with_index do |bool, index|
|
85
|
+
bool.should == (index == int_val)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'should take the offset into account when channeling' do
|
90
|
+
@int.must > 2
|
91
|
+
offset = 1
|
92
|
+
@int.must.channel(@bools, :offset => offset)
|
93
|
+
@model.solve!.should_not be_nil
|
94
|
+
int_val = @int.value
|
95
|
+
@bools.values.each_with_index do |bool, index|
|
96
|
+
bool.should == (index + offset == int_val)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
it_should_behave_like 'non-reifiable constraint'
|
101
|
+
it_should_behave_like 'non-negatable constraint'
|
102
|
+
end
|
@@ -1,21 +1,7 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/../
|
2
|
-
require File.dirname(__FILE__) + '/constraint_helper'
|
1
|
+
require File.dirname(__FILE__) + '/../constraint_helper'
|
3
2
|
|
4
3
|
# Assumes that @variables, @expected_array and @tuples are defined.
|
5
|
-
describe 'tuple constraint', :shared => true do
|
6
|
-
before do
|
7
|
-
@invoke_options = lambda do |hash|
|
8
|
-
@variables.must_be.in(@tuples, hash)
|
9
|
-
@model.solve!
|
10
|
-
end
|
11
|
-
@expect_options = option_expectation do |strength, kind, reif_var|
|
12
|
-
Gecode::Raw.should_receive(:extensional).once.with(
|
13
|
-
an_instance_of(Gecode::Raw::Space),
|
14
|
-
@expected_array,
|
15
|
-
an_instance_of(Gecode::Raw::TupleSet), strength, kind)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
4
|
+
describe 'bool tuple constraint', :shared => true do
|
19
5
|
it 'should not allow negation' do
|
20
6
|
lambda do
|
21
7
|
@variables.must_not_be.in @tuples
|
@@ -40,51 +26,26 @@ describe 'tuple constraint', :shared => true do
|
|
40
26
|
@variables.must_be.in ['h'*size, 'i'*size]
|
41
27
|
end.should raise_error(TypeError)
|
42
28
|
end
|
43
|
-
|
44
|
-
it_should_behave_like 'non-reifiable constraint'
|
45
|
-
end
|
46
|
-
|
47
|
-
describe Gecode::Constraints::IntEnum::Extensional, ' (tuple constraint)' do
|
48
|
-
before do
|
49
|
-
@model = Gecode::Model.new
|
50
|
-
@tuples = [[1,7], [5,1]]
|
51
|
-
@variables = @digits = @model.int_var_array(2, 0..9)
|
52
|
-
@model.branch_on @digits
|
53
|
-
|
54
|
-
@expected_array = an_instance_of Gecode::Raw::IntVarArray
|
55
|
-
end
|
56
|
-
|
57
|
-
it 'should constrain the domain of all variables' do
|
58
|
-
@digits.must_be.in @tuples
|
59
|
-
|
60
|
-
found_solutions = []
|
61
|
-
@model.each_solution do |m|
|
62
|
-
found_solutions << @digits.values
|
63
|
-
end
|
64
|
-
|
65
|
-
found_solutions.size.should == 2
|
66
|
-
(found_solutions - @tuples).should be_empty
|
67
|
-
end
|
68
|
-
|
69
|
-
it 'should raise error if the right hand side is not an enumeration' do
|
70
|
-
lambda{ @digits.must_be.in 4711 }.should raise_error(TypeError)
|
71
|
-
end
|
72
|
-
|
73
|
-
it 'should raise error if the right hand side does not contain tuples' do
|
74
|
-
lambda{ @digits.must_be.in [17, 4711] }.should raise_error(TypeError)
|
75
|
-
end
|
76
|
-
|
77
|
-
it_should_behave_like 'tuple constraint'
|
78
29
|
end
|
79
30
|
|
80
|
-
describe Gecode::
|
31
|
+
describe Gecode::BoolEnum::Extensional, ' (tuple constraint)' do
|
81
32
|
before do
|
82
33
|
@model = Gecode::Model.new
|
83
34
|
@tuples = [[true, false, true], [false, false, true]]
|
84
35
|
@variables = @bools = @model.bool_var_array(3)
|
85
36
|
@model.branch_on @bools
|
86
37
|
|
87
|
-
@
|
38
|
+
@types = [:bool_enum]
|
39
|
+
@invoke = lambda do |receiver, hash|
|
40
|
+
receiver.in([[true, false, true, false, true],
|
41
|
+
[false, true, true, true, true]], hash)
|
42
|
+
@model.solve!
|
43
|
+
end
|
44
|
+
@expect = lambda do |var, opts, reif_var|
|
45
|
+
Gecode::Raw.should_receive(:extensional).once.with(
|
46
|
+
an_instance_of(Gecode::Raw::Space),
|
47
|
+
var, an_instance_of(Gecode::Raw::TupleSet), *opts)
|
48
|
+
end
|
88
49
|
end
|
89
50
|
|
90
51
|
it 'should constrain the domain of all variables' do
|
@@ -107,25 +68,14 @@ describe Gecode::Constraints::BoolEnum::Extensional, ' (tuple constraint)' do
|
|
107
68
|
lambda{ @bools.must_be.in [true, false] }.should raise_error(TypeError)
|
108
69
|
end
|
109
70
|
|
110
|
-
it_should_behave_like 'tuple constraint'
|
71
|
+
it_should_behave_like 'bool tuple constraint'
|
72
|
+
it_should_behave_like 'non-reifiable constraint'
|
111
73
|
end
|
112
74
|
|
75
|
+
|
113
76
|
# Assumes that @variables, @expected_array, @value1, @value2 (must not
|
114
77
|
# 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
|
-
|
78
|
+
describe 'bool regular expression constraint', :shared => true do
|
129
79
|
it 'should handle values grouped in a single array' do
|
130
80
|
@variables.must.match [@value1, @value2, @value1]
|
131
81
|
@model.solve!.should_not be_nil
|
@@ -231,40 +181,9 @@ describe 'regular expression constraint', :shared => true do
|
|
231
181
|
@variables.must_not.match @regexp
|
232
182
|
end.should raise_error(Gecode::MissingConstraintError)
|
233
183
|
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
184
|
end
|
266
185
|
|
267
|
-
describe Gecode::
|
186
|
+
describe Gecode::BoolEnum::Extensional, ' (regexp constraint)' do
|
268
187
|
before do
|
269
188
|
@model = Gecode::Model.new
|
270
189
|
@variables = @bools = @model.bool_var_array(3)
|
@@ -273,6 +192,17 @@ describe Gecode::Constraints::BoolEnum::Extensional, ' (regexp constraint)' do
|
|
273
192
|
@value1 = true
|
274
193
|
@value2 = false
|
275
194
|
@regexp = [true, @model.any(true, false), @model.at_most_once(true)]
|
195
|
+
|
196
|
+
@types = [:bool_enum]
|
197
|
+
@invoke = lambda do |receiver, hash|
|
198
|
+
receiver.match(@regexp, hash)
|
199
|
+
@model.solve!
|
200
|
+
end
|
201
|
+
@expect = lambda do |var, opts, reif_var|
|
202
|
+
Gecode::Raw.should_receive(:extensional).once.with(
|
203
|
+
an_instance_of(Gecode::Raw::Space),
|
204
|
+
var, an_instance_of(Gecode::Raw::REG), *opts)
|
205
|
+
end
|
276
206
|
end
|
277
207
|
|
278
208
|
it 'should handle the any operation' do
|
@@ -290,5 +220,6 @@ describe Gecode::Constraints::BoolEnum::Extensional, ' (regexp constraint)' do
|
|
290
220
|
@bools.values.should == [true, true, true]
|
291
221
|
end
|
292
222
|
|
293
|
-
it_should_behave_like 'regular expression constraint'
|
223
|
+
it_should_behave_like 'bool regular expression constraint'
|
224
|
+
it_should_behave_like 'non-reifiable constraint'
|
294
225
|
end
|
@@ -1,264 +1,234 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/../spec_helper'
|
2
2
|
|
3
|
-
#
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
|
13
|
-
|
3
|
+
# Every constraint should have a spec that specs the following:
|
4
|
+
#
|
5
|
+
# * An example where the constraint is used to constrain a sample
|
6
|
+
# problem (and one for negation if deemed necessary).
|
7
|
+
# * should_behave_like [non-reifiable|reifiable] constraint (possibly
|
8
|
+
# indirect).
|
9
|
+
# * Those constraints that do not support negation must
|
10
|
+
# should_behave_like 'non-negatable constraint'
|
11
|
+
#
|
12
|
+
|
13
|
+
|
14
|
+
# These specs assume that the following variables are defined:
|
15
|
+
# [@expect] A proc that creates an expectation corresponding to
|
16
|
+
# constraint. It should take three parameter. The
|
17
|
+
# first is an array of operands of types specified by
|
18
|
+
# @types. The second is whether or not the constraint
|
19
|
+
# should be negated. The third is a hash that can
|
20
|
+
# have values for the keys :icl (ICL_*), :pk (PK_*),
|
21
|
+
# and :bool (bound reification variable). Any values
|
22
|
+
# not provided are assumed to be default values (nil
|
23
|
+
# in the case of :bool).
|
24
|
+
# [@invoke] A proc that invokes the constraint to be tested, It
|
25
|
+
# should have arity arity(@types) + 1. The first
|
26
|
+
# parameter is a constraint receiver (type decided by
|
27
|
+
# @types). The next arity(@types)-1 parameters are
|
28
|
+
# given operands of types specified by @types. The
|
29
|
+
# last parameter is a hash of options (with at most
|
30
|
+
# the keys :strength, :kind and :reify)..
|
31
|
+
# [@types] An array of symbols signaling what types of
|
32
|
+
# arguments @ accepts. The symbols
|
33
|
+
# must be one of: :int, :bool, :set, :int_enum,
|
34
|
+
# :bool_enum, :set_enum, :fixnum_enum.
|
14
35
|
# [@model] The model instance that contains the aspects being tested.
|
15
|
-
# [@expect_relation] A method that takes a relation, right hand side, and
|
16
|
-
# whether it's negated, as arguments and sets up the
|
17
|
-
# corresponding expectations.
|
18
|
-
# [@invoke_relation] A method that takes a relation, right hand side, and
|
19
|
-
# whether it's negated, as arguments and adds the
|
20
|
-
# corresponding constraint and invokes it.
|
21
|
-
# [@target] A legal right hand side that can be used as argument to
|
22
|
-
# the above two methods.
|
23
36
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
@invoke_options.call(:strength => name)
|
37
|
+
def expect(variables, options)
|
38
|
+
bool = options[:bool]
|
39
|
+
bool = @model.allow_space_access{ bool.bind } unless bool.nil?
|
40
|
+
args = @model.allow_space_access do
|
41
|
+
variables.map do |var|
|
42
|
+
if var.respond_to? :bind
|
43
|
+
var.bind
|
44
|
+
else
|
45
|
+
var.bind_array
|
46
|
+
end
|
35
47
|
end
|
36
48
|
end
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
49
|
+
args << [options[:icl] || Gecode::Raw::ICL_DEF,
|
50
|
+
options[:pk] || Gecode::Raw::PK_DEF]
|
51
|
+
args << bool
|
52
|
+
@expect.call(*args)
|
53
|
+
end
|
54
|
+
|
55
|
+
def invoke(operands, options)
|
56
|
+
base_op = operands.first
|
57
|
+
if options.delete(:negate)
|
58
|
+
receiver = base_op.must_not
|
59
|
+
else
|
60
|
+
receiver = base_op.must
|
41
61
|
end
|
42
|
-
|
43
|
-
|
62
|
+
args = ([receiver] + operands[1..-1]) << options
|
63
|
+
@invoke.call(*args)
|
64
|
+
end
|
65
|
+
|
66
|
+
describe 'reifiable constraint', :shared => true do
|
67
|
+
it_should_behave_like 'constraint with default options'
|
68
|
+
it_should_behave_like 'constraint with reification option'
|
69
|
+
it_should_behave_like 'constraint'
|
70
|
+
end
|
71
|
+
|
72
|
+
describe 'non-reifiable constraint', :shared => true do
|
73
|
+
it 'should raise errors if reification is used' do
|
74
|
+
operands, variables = produce_general_arguments(@types)
|
44
75
|
lambda do
|
45
|
-
|
76
|
+
invoke(operands, :reify => @model.bool_var)
|
46
77
|
end.should raise_error(ArgumentError)
|
47
78
|
end
|
79
|
+
|
80
|
+
it_should_behave_like 'constraint with default options'
|
81
|
+
it_should_behave_like 'constraint'
|
48
82
|
end
|
49
83
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
:speed => Gecode::Raw::PK_SPEED,
|
54
|
-
:memory => Gecode::Raw::PK_MEMORY
|
55
|
-
}.each_pair do |name, gecode_value|
|
56
|
-
it "should translate propagation kind #{name}" do
|
57
|
-
@expect_options.call(:pk => gecode_value)
|
58
|
-
@invoke_options.call(:kind => name)
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
it 'should default to using default as propagation kind' do
|
63
|
-
@expect_options.call({})
|
64
|
-
@invoke_options.call({})
|
65
|
-
end
|
66
|
-
|
67
|
-
it 'should raise errors for unrecognized propagation kinds' do
|
84
|
+
describe 'non-negatable constraint', :shared => true do
|
85
|
+
it 'should raise errors if negation is used' do
|
86
|
+
operands, variables = produce_general_arguments(@types)
|
68
87
|
lambda do
|
69
|
-
|
70
|
-
end.should raise_error(
|
88
|
+
invoke(operands, :negate => true)
|
89
|
+
end.should raise_error(Gecode::MissingConstraintError)
|
71
90
|
end
|
72
91
|
end
|
73
92
|
|
93
|
+
describe 'constraint', :shared => true do
|
94
|
+
it 'should raise errors if parameters of the incorrect type are given' do
|
95
|
+
operands, variables = produce_general_arguments(@types)
|
96
|
+
(1...operands.size).each do |i|
|
97
|
+
bogus_operands = operands.clone
|
98
|
+
bogus_operands[i] = Object.new
|
99
|
+
lambda do
|
100
|
+
invoke(bogus_operands, {})
|
101
|
+
end.should raise_error(TypeError)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
74
105
|
|
75
|
-
# Requires @invoke_options and @expect_options.
|
76
106
|
describe 'constraint with reification option', :shared => true do
|
77
107
|
it 'should translate reification' do
|
108
|
+
operands, variables = produce_general_arguments(@types)
|
78
109
|
var = @model.bool_var
|
79
|
-
|
80
|
-
|
110
|
+
expect(variables, :bool => var)
|
111
|
+
invoke(operands, :reify => var)
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'should translate reification with arbitrary bool operand' do
|
115
|
+
operands, variables = produce_general_arguments(@types)
|
116
|
+
op, bool_var = general_bool_operand(@model)
|
117
|
+
expect(variables, :bool => bool_var)
|
118
|
+
invoke(operands, :reify => op)
|
81
119
|
end
|
82
120
|
|
83
121
|
it 'should raise errors for reification variables of incorrect type' do
|
122
|
+
operands, variables = produce_general_arguments(@types)
|
84
123
|
lambda do
|
85
|
-
|
124
|
+
invoke(operands, :reify => 'foo')
|
86
125
|
end.should raise_error(TypeError)
|
87
126
|
end
|
88
127
|
end
|
89
128
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
it_should_behave_like 'constraint with reification option'
|
94
|
-
end
|
95
|
-
|
96
|
-
# Requires @invoke_options, @expect_options and @model.
|
97
|
-
describe 'non-reifiable constraint', :shared => true do
|
98
|
-
it 'should raise errors if reification is used' do
|
129
|
+
describe 'constraint with default options', :shared => true do
|
130
|
+
it 'should raise errors for unrecognized options' do
|
131
|
+
operands, variables = produce_general_arguments(@types)
|
99
132
|
lambda do
|
100
|
-
|
133
|
+
invoke(operands, :does_not_exist => :foo)
|
101
134
|
end.should raise_error(ArgumentError)
|
102
135
|
end
|
103
|
-
|
104
|
-
it_should_behave_like 'constraint with default options'
|
105
|
-
end
|
106
136
|
|
107
|
-
# Requires @invoke_options and @expect_options.
|
108
|
-
describe 'constraint with default options', :shared => true do
|
109
|
-
it 'should raise errors for unrecognized options' do
|
110
|
-
lambda{ @invoke_options.call(:does_not_exist => :foo) }.should(
|
111
|
-
raise_error(ArgumentError))
|
112
|
-
end
|
113
|
-
|
114
137
|
it_should_behave_like 'constraint with strength option'
|
115
138
|
it_should_behave_like 'constraint with kind option'
|
116
139
|
end
|
117
140
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
it "should translate #{relation} with variable target" do
|
129
|
-
@expect_relation.call(type, @target, false)
|
130
|
-
@invoke_relation.call(relation, @target, false)
|
141
|
+
describe 'constraint with strength option', :shared => true do
|
142
|
+
{ :default => Gecode::Raw::ICL_DEF,
|
143
|
+
:value => Gecode::Raw::ICL_VAL,
|
144
|
+
:bounds => Gecode::Raw::ICL_BND,
|
145
|
+
:domain => Gecode::Raw::ICL_DOM
|
146
|
+
}.each_pair do |name, gecode_value|
|
147
|
+
it "should translate propagation strength #{name}" do
|
148
|
+
operands, variables = produce_general_arguments(@types)
|
149
|
+
expect(variables, :icl => gecode_value)
|
150
|
+
invoke(operands, :strength => name)
|
131
151
|
end
|
132
152
|
end
|
133
153
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
end
|
154
|
+
it 'should default to using default as propagation strength' do
|
155
|
+
operands, variables = produce_general_arguments(@types)
|
156
|
+
expect(variables, {})
|
157
|
+
invoke(operands, {})
|
139
158
|
end
|
140
159
|
|
141
|
-
|
142
|
-
|
143
|
-
@expect_relation.call(type, @target, true)
|
144
|
-
@invoke_relation.call(relation, @target, true)
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
it 'should raise error if the target is of the wrong type' do
|
160
|
+
it 'should raise errors for unrecognized propagation strengths' do
|
161
|
+
operands, variables = produce_general_arguments(@types)
|
149
162
|
lambda do
|
150
|
-
|
151
|
-
end.should raise_error(
|
163
|
+
invoke(operands, :strength => :does_not_exist)
|
164
|
+
end.should raise_error(ArgumentError)
|
152
165
|
end
|
153
166
|
end
|
154
167
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
Gecode::Constraints::Util::SET_RELATION_TYPES.each_pair do |relation, type|
|
165
|
-
it "should translate #{relation} with variable target" do
|
166
|
-
@expect_relation.call(type, @target, false)
|
167
|
-
@invoke_relation.call(relation, @target, false)
|
168
|
+
describe 'constraint with kind option', :shared => true do
|
169
|
+
{ :default => Gecode::Raw::PK_DEF,
|
170
|
+
:speed => Gecode::Raw::PK_SPEED,
|
171
|
+
:memory => Gecode::Raw::PK_MEMORY
|
172
|
+
}.each_pair do |name, gecode_value|
|
173
|
+
it "should translate propagation kind #{name}" do
|
174
|
+
operands, variables = produce_general_arguments(@types)
|
175
|
+
expect(variables, :pk => gecode_value)
|
176
|
+
invoke(operands, :kind => name)
|
168
177
|
end
|
169
178
|
end
|
170
179
|
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
end
|
180
|
+
it 'should default to using default as propagation kind' do
|
181
|
+
operands, variables = produce_general_arguments(@types)
|
182
|
+
expect(variables, {})
|
183
|
+
invoke(operands, {})
|
176
184
|
end
|
177
185
|
|
178
|
-
|
179
|
-
|
180
|
-
@expect_relation.call(type, @target, true)
|
181
|
-
@invoke_relation.call(relation, @target, true)
|
182
|
-
end
|
183
|
-
end
|
184
|
-
|
185
|
-
it 'should raise error if the target is of the wrong type' do
|
186
|
+
it 'should raise errors for unrecognized propagation kinds' do
|
187
|
+
operands, variables = produce_general_arguments(@types)
|
186
188
|
lambda do
|
187
|
-
|
188
|
-
end.should raise_error(
|
189
|
+
invoke(operands, :kind => :does_not_exist)
|
190
|
+
end.should raise_error(ArgumentError)
|
189
191
|
end
|
190
192
|
end
|
191
193
|
|
192
194
|
describe 'set constraint', :shared => true do
|
193
195
|
it 'should not accept strength option' do
|
196
|
+
operands, variables = produce_general_arguments(@types)
|
194
197
|
lambda do
|
195
|
-
|
198
|
+
invoke(operands, :strength => :default)
|
196
199
|
end.should raise_error(ArgumentError)
|
197
200
|
end
|
198
201
|
|
199
202
|
it 'should not accept kind option' do
|
203
|
+
operands, variables = produce_general_arguments(@types)
|
200
204
|
lambda do
|
201
|
-
|
205
|
+
invoke(operands, :kind => :default)
|
202
206
|
end.should raise_error(ArgumentError)
|
203
207
|
end
|
204
208
|
|
205
209
|
it 'should raise errors for unrecognized options' do
|
210
|
+
operands, variables = produce_general_arguments(@types)
|
206
211
|
lambda do
|
207
|
-
|
212
|
+
invoke(operands, :does_not_exist => :foo)
|
208
213
|
end.should raise_error(ArgumentError)
|
209
214
|
end
|
215
|
+
|
216
|
+
it_should_behave_like 'constraint'
|
210
217
|
end
|
211
218
|
|
212
|
-
# Requires @invoke_options and @model.
|
213
219
|
describe 'non-reifiable set constraint', :shared => true do
|
214
220
|
it 'should not accept reification option' do
|
215
221
|
bool = @model.bool_var
|
222
|
+
operands, variables = produce_general_arguments(@types)
|
216
223
|
lambda do
|
217
|
-
|
224
|
+
invoke(operands, :reify => bool)
|
218
225
|
end.should raise_error(ArgumentError)
|
219
226
|
end
|
220
227
|
|
221
228
|
it_should_behave_like 'set constraint'
|
222
229
|
end
|
223
230
|
|
224
|
-
# Requires @invoke_options, @expect_options and @model.
|
225
231
|
describe 'reifiable set constraint', :shared => true do
|
226
232
|
it_should_behave_like 'set constraint'
|
227
233
|
it_should_behave_like 'constraint with reification option'
|
228
234
|
end
|
229
|
-
|
230
|
-
# Help methods for the GecodeR specs.
|
231
|
-
module GecodeR::Specs
|
232
|
-
module SetHelper
|
233
|
-
module_function
|
234
|
-
|
235
|
-
# Returns the arguments that should be used in a partial mock to expect the
|
236
|
-
# specified constant set (possibly an array of arguments).
|
237
|
-
def expect_constant_set(constant_set)
|
238
|
-
if constant_set.kind_of? Range
|
239
|
-
return constant_set.first, constant_set.last
|
240
|
-
elsif constant_set.kind_of? Fixnum
|
241
|
-
constant_set
|
242
|
-
else
|
243
|
-
an_instance_of(Gecode::Raw::IntSet)
|
244
|
-
end
|
245
|
-
end
|
246
|
-
end
|
247
|
-
end
|
248
|
-
|
249
|
-
# Helper for creating @expect_option. Creates a method which takes a hash that
|
250
|
-
# may have values for the keys :icl (ICL_*), :pk (PK_*), and :bool (reification
|
251
|
-
# variable). Expectations corresponding to the hash values are given to the
|
252
|
-
# specified block in the order of icl, pk and bool. Default values are provided
|
253
|
-
# if the hash doesn't specify anything else.
|
254
|
-
def option_expectation(&block)
|
255
|
-
lambda do |hash|
|
256
|
-
bool = hash[:bool]
|
257
|
-
# We loosen the expectation some to avoid practical problems with expecting
|
258
|
-
# specific variables not under our control.
|
259
|
-
bool = an_instance_of(Gecode::Raw::BoolVar) unless bool.nil?
|
260
|
-
yield(hash[:icl] || Gecode::Raw::ICL_DEF,
|
261
|
-
hash[:pk] || Gecode::Raw::PK_DEF,
|
262
|
-
bool)
|
263
|
-
end
|
264
|
-
end
|