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.
Files changed (142) hide show
  1. data/CHANGES +15 -0
  2. data/README +6 -2
  3. data/example/equation_system.rb +15 -0
  4. data/example/magic_sequence.rb +7 -7
  5. data/example/money.rb +36 -0
  6. data/example/queens.rb +7 -8
  7. data/example/send_most_money.rb +1 -1
  8. data/example/square_tiling.rb +2 -2
  9. data/example/sudoku-set.rb +11 -12
  10. data/example/sudoku.rb +40 -45
  11. data/ext/extconf.rb +0 -0
  12. data/lib/gecoder/bindings.rb +42 -0
  13. data/lib/gecoder/bindings/bindings.rb +16 -0
  14. data/lib/gecoder/interface.rb +2 -1
  15. data/lib/gecoder/interface/branch.rb +16 -9
  16. data/lib/gecoder/interface/constraints.rb +410 -451
  17. data/lib/gecoder/interface/constraints/bool/boolean.rb +205 -213
  18. data/lib/gecoder/interface/constraints/bool/channel.rb +4 -5
  19. data/lib/gecoder/interface/constraints/bool/linear.rb +192 -21
  20. data/lib/gecoder/interface/constraints/bool_enum/channel.rb +43 -39
  21. data/lib/gecoder/interface/constraints/bool_enum/extensional.rb +43 -49
  22. data/lib/gecoder/interface/constraints/bool_enum/relation.rb +38 -71
  23. data/lib/gecoder/interface/constraints/bool_enum_constraints.rb +73 -22
  24. data/lib/gecoder/interface/constraints/bool_var_constraints.rb +140 -61
  25. data/lib/gecoder/interface/constraints/extensional_regexp.rb +4 -4
  26. data/lib/gecoder/interface/constraints/fixnum_enum/element.rb +63 -0
  27. data/lib/gecoder/interface/constraints/fixnum_enum/operation.rb +65 -0
  28. data/lib/gecoder/interface/constraints/fixnum_enum_constraints.rb +42 -0
  29. data/lib/gecoder/interface/constraints/int/arithmetic.rb +131 -130
  30. data/lib/gecoder/interface/constraints/int/channel.rb +21 -31
  31. data/lib/gecoder/interface/constraints/int/domain.rb +45 -42
  32. data/lib/gecoder/interface/constraints/int/linear.rb +85 -239
  33. data/lib/gecoder/interface/constraints/int/relation.rb +141 -0
  34. data/lib/gecoder/interface/constraints/int_enum/arithmetic.rb +55 -64
  35. data/lib/gecoder/interface/constraints/int_enum/channel.rb +35 -37
  36. data/lib/gecoder/interface/constraints/int_enum/count.rb +53 -78
  37. data/lib/gecoder/interface/constraints/int_enum/distinct.rb +36 -46
  38. data/lib/gecoder/interface/constraints/int_enum/element.rb +39 -57
  39. data/lib/gecoder/interface/constraints/int_enum/equality.rb +15 -19
  40. data/lib/gecoder/interface/constraints/int_enum/extensional.rb +65 -72
  41. data/lib/gecoder/interface/constraints/int_enum/sort.rb +42 -45
  42. data/lib/gecoder/interface/constraints/int_enum_constraints.rb +79 -22
  43. data/lib/gecoder/interface/constraints/int_var_constraints.rb +215 -44
  44. data/lib/gecoder/interface/constraints/reifiable_constraints.rb +14 -14
  45. data/lib/gecoder/interface/constraints/selected_set/select.rb +120 -0
  46. data/lib/gecoder/interface/constraints/selected_set_constraints.rb +75 -0
  47. data/lib/gecoder/interface/constraints/set/cardinality.rb +43 -53
  48. data/lib/gecoder/interface/constraints/set/channel.rb +26 -29
  49. data/lib/gecoder/interface/constraints/set/connection.rb +89 -152
  50. data/lib/gecoder/interface/constraints/set/domain.rb +112 -65
  51. data/lib/gecoder/interface/constraints/set/include.rb +36 -0
  52. data/lib/gecoder/interface/constraints/set/operation.rb +96 -110
  53. data/lib/gecoder/interface/constraints/set/relation.rb +114 -137
  54. data/lib/gecoder/interface/constraints/set_elements/relation.rb +116 -0
  55. data/lib/gecoder/interface/constraints/set_elements_constraints.rb +97 -0
  56. data/lib/gecoder/interface/constraints/set_enum/channel.rb +23 -27
  57. data/lib/gecoder/interface/constraints/set_enum/distinct.rb +18 -19
  58. data/lib/gecoder/interface/constraints/set_enum/operation.rb +62 -53
  59. data/lib/gecoder/interface/constraints/set_enum/select.rb +79 -0
  60. data/lib/gecoder/interface/constraints/set_enum_constraints.rb +73 -23
  61. data/lib/gecoder/interface/constraints/set_var_constraints.rb +222 -57
  62. data/lib/gecoder/interface/enum_matrix.rb +4 -4
  63. data/lib/gecoder/interface/enum_wrapper.rb +71 -22
  64. data/lib/gecoder/interface/model.rb +167 -12
  65. data/lib/gecoder/interface/model_sugar.rb +84 -0
  66. data/lib/gecoder/interface/search.rb +30 -18
  67. data/lib/gecoder/interface/variables.rb +103 -33
  68. data/lib/gecoder/version.rb +2 -2
  69. data/specs/bool_var.rb +19 -12
  70. data/specs/constraints/{boolean.rb → bool/boolean.rb} +103 -28
  71. data/specs/constraints/bool/boolean_properties.rb +51 -0
  72. data/specs/constraints/bool/linear.rb +213 -0
  73. data/specs/constraints/bool_enum/bool_enum_relation.rb +117 -0
  74. data/specs/constraints/bool_enum/channel.rb +102 -0
  75. data/specs/constraints/{extensional.rb → bool_enum/extensional.rb} +32 -101
  76. data/specs/constraints/constraint_helper.rb +149 -179
  77. data/specs/constraints/constraint_receivers.rb +103 -0
  78. data/specs/constraints/constraints.rb +6 -63
  79. data/specs/constraints/fixnum_enum/element.rb +58 -0
  80. data/specs/constraints/fixnum_enum/operation.rb +67 -0
  81. data/specs/constraints/int/arithmetic.rb +149 -0
  82. data/specs/constraints/int/channel.rb +101 -0
  83. data/specs/constraints/int/domain.rb +106 -0
  84. data/specs/constraints/int/linear.rb +183 -0
  85. data/specs/constraints/int/linear_properties.rb +97 -0
  86. data/specs/constraints/int/relation.rb +84 -0
  87. data/specs/constraints/int_enum/arithmetic.rb +72 -0
  88. data/specs/constraints/int_enum/channel.rb +57 -0
  89. data/specs/constraints/int_enum/count.rb +72 -0
  90. data/specs/constraints/int_enum/distinct.rb +80 -0
  91. data/specs/constraints/int_enum/element.rb +61 -0
  92. data/specs/constraints/int_enum/equality.rb +29 -0
  93. data/specs/constraints/int_enum/extensional.rb +224 -0
  94. data/specs/constraints/int_enum/sort.rb +167 -0
  95. data/specs/constraints/operands.rb +264 -0
  96. data/specs/constraints/property_helper.rb +443 -0
  97. data/specs/constraints/reification_sugar.rb +4 -5
  98. data/specs/constraints/selected_set/select.rb +56 -0
  99. data/specs/constraints/selected_set/select_properties.rb +157 -0
  100. data/specs/constraints/set/cardinality.rb +58 -0
  101. data/specs/constraints/set/cardinality_properties.rb +46 -0
  102. data/specs/constraints/set/channel.rb +77 -0
  103. data/specs/constraints/set/connection.rb +176 -0
  104. data/specs/constraints/set/domain.rb +197 -0
  105. data/specs/constraints/set/include.rb +36 -0
  106. data/specs/constraints/set/operation.rb +132 -0
  107. data/specs/constraints/set/relation.rb +117 -0
  108. data/specs/constraints/set_elements/relation.rb +84 -0
  109. data/specs/constraints/set_enum/channel.rb +80 -0
  110. data/specs/constraints/set_enum/distinct.rb +59 -0
  111. data/specs/constraints/set_enum/operation.rb +111 -0
  112. data/specs/constraints/set_enum/select.rb +73 -0
  113. data/specs/enum_wrapper.rb +53 -3
  114. data/specs/int_var.rb +44 -25
  115. data/specs/model.rb +58 -1
  116. data/specs/model_sugar.rb +30 -0
  117. data/specs/search.rb +24 -5
  118. data/specs/selected_set.rb +39 -0
  119. data/specs/set_elements.rb +34 -0
  120. data/specs/set_var.rb +22 -8
  121. data/specs/spec_helper.rb +206 -6
  122. data/tasks/distribution.rake +22 -7
  123. data/tasks/svn.rake +3 -1
  124. metadata +218 -134
  125. data/lib/gecoder/interface/constraints/set_enum/selection.rb +0 -217
  126. data/specs/constraints/arithmetic.rb +0 -351
  127. data/specs/constraints/bool_enum_relation.rb +0 -160
  128. data/specs/constraints/cardinality.rb +0 -157
  129. data/specs/constraints/channel.rb +0 -454
  130. data/specs/constraints/connection.rb +0 -369
  131. data/specs/constraints/count.rb +0 -146
  132. data/specs/constraints/distinct.rb +0 -164
  133. data/specs/constraints/element.rb +0 -108
  134. data/specs/constraints/equality.rb +0 -31
  135. data/specs/constraints/int_domain.rb +0 -70
  136. data/specs/constraints/int_relation.rb +0 -82
  137. data/specs/constraints/linear.rb +0 -340
  138. data/specs/constraints/selection.rb +0 -292
  139. data/specs/constraints/set_domain.rb +0 -185
  140. data/specs/constraints/set_operation.rb +0 -285
  141. data/specs/constraints/set_relation.rb +0 -197
  142. 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__) + '/../spec_helper'
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::Constraints::BoolEnum::Extensional, ' (tuple constraint)' do
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
- @expected_array = an_instance_of Gecode::Raw::BoolVarArray
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::Constraints::BoolEnum::Extensional, ' (regexp constraint)' do
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
- # Several of these shared specs requires one or more of the following instance
4
- # variables to be used:
5
- # [@expect_options] A method that creates an expectation on the aspect to be
6
- # tested, using the provided hash of Gecode values. The hash
7
- # can have values for the keys :icl (ICL_*), :pk (PK_*), and
8
- # :bool (bound reification variable). Any values not
9
- # provided are assumed to be default values (nil in the case
10
- # of :bool).
11
- # [@invoke_options] A method that invokes the aspect to be tested, with the
12
- # provided hash of options (with at most the keys :strength,
13
- # :kind and :reify).
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
- # Requires @invoke_options and @expect_options.
26
- describe 'constraint with strength option', :shared => true do
27
- { :default => Gecode::Raw::ICL_DEF,
28
- :value => Gecode::Raw::ICL_VAL,
29
- :bounds => Gecode::Raw::ICL_BND,
30
- :domain => Gecode::Raw::ICL_DOM
31
- }.each_pair do |name, gecode_value|
32
- it "should translate propagation strength #{name}" do
33
- @expect_options.call(:icl => gecode_value)
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
- it 'should default to using default as propagation strength' do
39
- @expect_options.call({})
40
- @invoke_options.call({})
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
- it 'should raise errors for unrecognized propagation strengths' do
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
- @invoke_options.call(:strength => :does_not_exist)
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
- # Requires @invoke_options and @expect_options.
51
- describe 'constraint with kind option', :shared => true do
52
- { :default => Gecode::Raw::PK_DEF,
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
- @invoke_options.call(:kind => :does_not_exist)
70
- end.should raise_error(ArgumentError)
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
- @expect_options.call(:bool => var)
80
- @invoke_options.call(:reify => var)
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
- @invoke_options.call(:reify => 'foo')
124
+ invoke(operands, :reify => 'foo')
86
125
  end.should raise_error(TypeError)
87
126
  end
88
127
  end
89
128
 
90
- # Requires @invoke_options and @expect_options.
91
- describe 'reifiable constraint', :shared => true do
92
- it_should_behave_like 'constraint with default options'
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
- @invoke_options.call(:reify => @model.bool_var)
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
- # Requires @expect_relation, @invoke_relation and @target.
119
- describe 'composite constraint', :shared => true do
120
- Gecode::Constraints::Util::RELATION_TYPES.each_pair do |relation, type|
121
- it "should translate #{relation} with constant target" do
122
- @expect_relation.call(type, 1, false)
123
- @invoke_relation.call(relation, 1, false)
124
- end
125
- end
126
-
127
- Gecode::Constraints::Util::RELATION_TYPES.each_pair do |relation, type|
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
- Gecode::Constraints::Util::NEGATED_RELATION_TYPES.each_pair do |relation, type|
135
- it "should translate negated #{relation} with constant target" do
136
- @expect_relation.call(type, 1, true)
137
- @invoke_relation.call(relation, 1, true)
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
- Gecode::Constraints::Util::NEGATED_RELATION_TYPES.each_pair do |relation, type|
142
- it "should translate negated #{relation} with variable target" do
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
- @invoke_relation.call(:==, 'hello', false)
151
- end.should raise_error(TypeError)
163
+ invoke(operands, :strength => :does_not_exist)
164
+ end.should raise_error(ArgumentError)
152
165
  end
153
166
  end
154
167
 
155
- # Requires @expect_relation, @invoke_relation and @target.
156
- describe 'composite set constraint', :shared => true do
157
- Gecode::Constraints::Util::SET_RELATION_TYPES.each_pair do |relation, type|
158
- it "should translate #{relation} with constant target" do
159
- @expect_relation.call(type, [1], false)
160
- @invoke_relation.call(relation, [1], false)
161
- end
162
- end
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
- Gecode::Constraints::Util::NEGATED_SET_RELATION_TYPES.each_pair do |relation, type|
172
- it "should translate negated #{relation} with constant target" do
173
- @expect_relation.call(type, [1], true)
174
- @invoke_relation.call(relation, [1], true)
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
- Gecode::Constraints::Util::NEGATED_SET_RELATION_TYPES.each_pair do |relation, type|
179
- it "should translate negated #{relation} with variable target" do
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
- @invoke_relation.call(:==, 'hello', false)
188
- end.should raise_error(TypeError)
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
- @invoke_options.call(:strength => :default)
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
- @invoke_options.call(:kind => :default)
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
- @invoke_options.call(:does_not_exist => :foo)
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
- @invoke_options.call(:reify => bool)
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