gecoder 0.4.0 → 0.5.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 (68) hide show
  1. data/CHANGES +11 -0
  2. data/README +12 -1
  3. data/example/example_helper.rb +1 -0
  4. data/example/magic_sequence.rb +43 -0
  5. data/example/queens.rb +43 -0
  6. data/example/raw_bindings.rb +42 -0
  7. data/example/send_more_money.rb +43 -0
  8. data/example/sudoku.rb +65 -0
  9. data/ext/missing.cpp +15 -21
  10. data/ext/missing.h +14 -20
  11. data/ext/vararray.cpp +14 -20
  12. data/ext/vararray.h +18 -22
  13. data/lib/gecoder/bindings/bindings.rb +1979 -1969
  14. data/lib/gecoder/interface/binding_changes.rb +123 -2
  15. data/lib/gecoder/interface/constraints/bool/boolean.rb +80 -65
  16. data/lib/gecoder/interface/constraints/bool_enum/boolean.rb +59 -0
  17. data/lib/gecoder/interface/constraints/bool_enum_constraints.rb +8 -0
  18. data/lib/gecoder/interface/constraints/bool_var_constraints.rb +42 -0
  19. data/lib/gecoder/interface/constraints/int/arithmetic.rb +21 -44
  20. data/lib/gecoder/interface/constraints/int/domain.rb +6 -4
  21. data/lib/gecoder/interface/constraints/int_enum/arithmetic.rb +18 -44
  22. data/lib/gecoder/interface/constraints/int_enum/count.rb +3 -18
  23. data/lib/gecoder/interface/constraints/int_enum/distinct.rb +4 -16
  24. data/lib/gecoder/interface/constraints/int_enum/element.rb +9 -20
  25. data/lib/gecoder/interface/constraints/int_var_constraints.rb +28 -0
  26. data/lib/gecoder/interface/constraints/set/cardinality.rb +56 -0
  27. data/lib/gecoder/interface/constraints/set/domain.rb +66 -0
  28. data/lib/gecoder/interface/constraints/set/relation.rb +125 -0
  29. data/lib/gecoder/interface/constraints/set_var_constraints.rb +37 -0
  30. data/lib/gecoder/interface/constraints.rb +229 -65
  31. data/lib/gecoder/interface/enum_wrapper.rb +42 -11
  32. data/lib/gecoder/interface/model.rb +75 -0
  33. data/lib/gecoder/interface/search.rb +4 -9
  34. data/lib/gecoder/interface/variables.rb +36 -2
  35. data/lib/gecoder/version.rb +1 -1
  36. data/specs/bool_var.rb +58 -0
  37. data/specs/constraints/arithmetic.rb +91 -90
  38. data/specs/constraints/bool_enum.rb +130 -0
  39. data/specs/constraints/boolean.rb +95 -2
  40. data/specs/constraints/cardinality.rb +127 -0
  41. data/specs/constraints/constraint_helper.rb +91 -0
  42. data/specs/constraints/constraints.rb +31 -0
  43. data/specs/constraints/element.rb +43 -72
  44. data/specs/constraints/{domain.rb → int_domain.rb} +4 -0
  45. data/specs/constraints/{relation.rb → int_relation.rb} +0 -0
  46. data/specs/constraints/set_domain.rb +165 -0
  47. data/specs/constraints/set_relation.rb +181 -0
  48. data/specs/enum_wrapper.rb +13 -2
  49. data/specs/int_var.rb +33 -1
  50. data/specs/model.rb +80 -0
  51. data/specs/set_var.rb +39 -0
  52. data/specs/spec_helper.rb +35 -0
  53. data/specs/tmp +11 -124
  54. data/tasks/distribution.rake +1 -1
  55. data/vendor/rust/rust/class.rb +10 -10
  56. data/vendor/rust/rust/constants.rb +1 -1
  57. data/vendor/rust/rust/function.rb +5 -5
  58. data/vendor/rust/rust/type.rb +1 -1
  59. data/vendor/rust/test/constants.rb +1 -0
  60. data/vendor/rust/test/cppclass.cc +5 -0
  61. data/vendor/rust/test/cppclass.hh +4 -0
  62. data/vendor/rust/test/lib/extension-test.rb +1 -1
  63. data/vendor/rust/test/operators.cc +41 -0
  64. data/vendor/rust/test/operators.hh +39 -0
  65. data/vendor/rust/test/operators.rb +39 -0
  66. data/vendor/rust/test/test-cwrapper.rb +3 -0
  67. data/vendor/rust/test/test-operators.rb +42 -0
  68. metadata +31 -4
@@ -5,43 +5,53 @@ class ArithmeticSampleProblem < Gecode::Model
5
5
  attr :numbers
6
6
  attr :var
7
7
  attr :var2
8
+ attr :var3
8
9
 
9
10
  def initialize
10
11
  @numbers = int_var_array(4, 0..9)
11
12
  @var = int_var(-9..9)
12
13
  @var2 = int_var(0..9)
14
+ @var3 = int_var(0..9)
13
15
  branch_on @numbers
14
- branch_on wrap_enum([@var, @var2])
16
+ branch_on wrap_enum([@var, @var2, @var3])
15
17
  end
16
18
  end
17
19
 
20
+ # Requires @stub, @target, @model and @expect.
18
21
  describe 'arithmetic constraint', :shared => true do
19
- situations = {
20
- 'variable bound' => nil,
21
- 'constant bound' => 5
22
- }.each_pair do |description, bound|
23
- Gecode::Constraints::Util::RELATION_TYPES.each_pair do |relation, type|
24
- it "should translate #{relation} with #{description}" do
25
- bound = @var if bound.nil?
26
- @expect.call(type, bound, Gecode::Raw::ICL_DEF, nil)
27
- @stub.must.send(relation, bound)
28
- @model.solve!
29
- end
22
+ before do
23
+ # For constraint option spec.
24
+ @invoke_options = lambda do |hash|
25
+ @stub.must_be.greater_than(@target, hash)
26
+ @model.solve!
27
+ end
28
+ @expect_options = lambda do |strength, reif_var|
29
+ @expect.call(Gecode::Raw::IRT_GR, @target, strength, reif_var, false)
30
30
  end
31
- Gecode::Constraints::Util::NEGATED_RELATION_TYPES.each_pair do |relation, type|
32
- it "should translate negated #{relation} with #{description}" do
33
- bound = @var if bound.nil?
34
- @expect.call(type, bound, Gecode::Raw::ICL_DEF, nil)
35
- @stub.must_not.send(relation, bound)
36
- @model.solve!
31
+
32
+ # For composite spec.
33
+ @invoke_relation = lambda do |relation, target, negated|
34
+ if negated
35
+ @stub.must_not.send(relation, target)
36
+ else
37
+ @stub.must.send(relation, target)
37
38
  end
39
+ @model.solve!
40
+ end
41
+ @expect_relation = lambda do |relation, target, negated|
42
+ @expect.call(relation, target, Gecode::Raw::ICL_DEF, nil, negated)
38
43
  end
39
44
  end
40
45
 
41
- it 'should raise error if the right hand side is of the wrong type' do
42
- lambda{ @stub.must == 'hello' }.should raise_error(TypeError)
46
+ it 'should translate reification when using equality' do
47
+ bool_var = @model.bool_var
48
+ @expect.call(Gecode::Raw::IRT_EQ, @target, Gecode::Raw::ICL_DEF, bool_var,
49
+ false)
50
+ @stub.must_be.equal_to(@target, :reify => bool_var)
51
+ @model.solve!
43
52
  end
44
53
 
54
+ it_should_behave_like 'composite constraint'
45
55
  it_should_behave_like 'constraint with options'
46
56
  end
47
57
 
@@ -49,36 +59,34 @@ describe Gecode::Constraints::IntEnum::Arithmetic, ' (max)' do
49
59
  before do
50
60
  @model = ArithmeticSampleProblem.new
51
61
  @numbers = @model.numbers
52
- @var = @model.var
62
+ @target = @var = @model.var
53
63
  @stub = @numbers.max
54
64
 
55
65
  # Creates an expectation corresponding to the specified input.
56
- @expect = lambda do |relation, rhs, strength, reif_var|
66
+ @expect = lambda do |relation, rhs, strength, reif_var, negated|
57
67
  rhs = rhs.bind if rhs.respond_to? :bind
58
68
  if reif_var.nil?
59
- Gecode::Raw.should_receive(:max).once.with(@model.active_space,
60
- an_instance_of(Gecode::Raw::IntVarArray),
61
- an_instance_of(Gecode::Raw::IntVar), an_instance_of(Fixnum))
62
- Gecode::Raw.should_receive(:rel).once.with(@model.active_space,
63
- an_instance_of(Gecode::Raw::IntVar), relation, rhs, strength)
69
+ if !negated and relation == Gecode::Raw::IRT_EQ and
70
+ rhs.kind_of? Gecode::Raw::IntVar
71
+ Gecode::Raw.should_receive(:max).once.with(@model.active_space,
72
+ an_instance_of(Gecode::Raw::IntVarArray), rhs, strength)
73
+ Gecode::Raw.should_receive(:rel).exactly(0).times
74
+ else
75
+ Gecode::Raw.should_receive(:max).once.with(@model.active_space,
76
+ an_instance_of(Gecode::Raw::IntVarArray),
77
+ an_instance_of(Gecode::Raw::IntVar), strength)
78
+ Gecode::Raw.should_receive(:rel).once.with(@model.active_space,
79
+ an_instance_of(Gecode::Raw::IntVar), relation, rhs, strength)
80
+ end
64
81
  else
65
82
  Gecode::Raw.should_receive(:max).once.with(@model.active_space,
66
83
  an_instance_of(Gecode::Raw::IntVarArray),
67
- an_instance_of(Gecode::Raw::IntVar), an_instance_of(Fixnum))
84
+ an_instance_of(Gecode::Raw::IntVar), strength)
68
85
  Gecode::Raw.should_receive(:rel).once.with(@model.active_space,
69
86
  an_instance_of(Gecode::Raw::IntVar), relation, rhs, reif_var.bind,
70
87
  strength)
71
88
  end
72
89
  end
73
-
74
- # For constraint option spec.
75
- @invoke_options = lambda do |hash|
76
- @numbers.max.must_be.greater_than(@var, hash)
77
- @model.solve!
78
- end
79
- @expect_options = lambda do |strength, reif_var|
80
- @expect.call(Gecode::Raw::IRT_GR, @var, strength, reif_var)
81
- end
82
90
  end
83
91
 
84
92
  it 'should constrain the maximum value' do
@@ -93,36 +101,34 @@ describe Gecode::Constraints::IntEnum::Arithmetic, ' (min)' do
93
101
  before do
94
102
  @model = ArithmeticSampleProblem.new
95
103
  @numbers = @model.numbers
96
- @var = @model.var
104
+ @target = @var = @model.var
97
105
  @stub = @numbers.min
98
106
 
99
107
  # Creates an expectation corresponding to the specified input.
100
- @expect = lambda do |relation, rhs, strength, reif_var|
108
+ @expect = lambda do |relation, rhs, strength, reif_var, negated|
101
109
  rhs = rhs.bind if rhs.respond_to? :bind
102
110
  if reif_var.nil?
103
- Gecode::Raw.should_receive(:min).once.with(@model.active_space,
104
- an_instance_of(Gecode::Raw::IntVarArray),
105
- an_instance_of(Gecode::Raw::IntVar), an_instance_of(Fixnum))
106
- Gecode::Raw.should_receive(:rel).once.with(@model.active_space,
107
- an_instance_of(Gecode::Raw::IntVar), relation, rhs, strength)
111
+ if !negated and relation == Gecode::Raw::IRT_EQ and
112
+ rhs.kind_of? Gecode::Raw::IntVar
113
+ Gecode::Raw.should_receive(:min).once.with(@model.active_space,
114
+ an_instance_of(Gecode::Raw::IntVarArray), rhs, strength)
115
+ Gecode::Raw.should_receive(:rel).exactly(0).times
116
+ else
117
+ Gecode::Raw.should_receive(:min).once.with(@model.active_space,
118
+ an_instance_of(Gecode::Raw::IntVarArray),
119
+ an_instance_of(Gecode::Raw::IntVar), strength)
120
+ Gecode::Raw.should_receive(:rel).once.with(@model.active_space,
121
+ an_instance_of(Gecode::Raw::IntVar), relation, rhs, strength)
122
+ end
108
123
  else
109
124
  Gecode::Raw.should_receive(:min).once.with(@model.active_space,
110
125
  an_instance_of(Gecode::Raw::IntVarArray),
111
- an_instance_of(Gecode::Raw::IntVar), an_instance_of(Fixnum))
126
+ an_instance_of(Gecode::Raw::IntVar), strength)
112
127
  Gecode::Raw.should_receive(:rel).once.with(@model.active_space,
113
128
  an_instance_of(Gecode::Raw::IntVar), relation, rhs, reif_var.bind,
114
129
  strength)
115
130
  end
116
131
  end
117
-
118
- # For constraint option spec.
119
- @invoke_options = lambda do |hash|
120
- @numbers.min.must_be.greater_than(@var, hash)
121
- @model.solve!
122
- end
123
- @expect_options = lambda do |strength, reif_var|
124
- @expect.call(Gecode::Raw::IRT_GR, @var, strength, reif_var)
125
- end
126
132
  end
127
133
 
128
134
  it 'should constrain the minimum value' do
@@ -137,35 +143,32 @@ describe Gecode::Constraints::Int::Arithmetic, ' (abs)' do
137
143
  before do
138
144
  @model = ArithmeticSampleProblem.new
139
145
  @var = @model.var
146
+ @target = @model.var2
140
147
  @stub = @var.abs
141
148
 
142
149
  # Creates an expectation corresponding to the specified input.
143
- @expect = lambda do |relation, rhs, strength, reif_var|
150
+ @expect = lambda do |relation, rhs, strength, reif_var, negated|
144
151
  rhs = rhs.bind if rhs.respond_to? :bind
145
152
  if reif_var.nil?
146
- Gecode::Raw.should_receive(:abs).once.with(@model.active_space,
147
- @var.bind, an_instance_of(Gecode::Raw::IntVar),
148
- an_instance_of(Fixnum))
149
- Gecode::Raw.should_receive(:rel).once.with(@model.active_space,
150
- an_instance_of(Gecode::Raw::IntVar), relation, rhs, strength)
153
+ if !negated and relation == Gecode::Raw::IRT_EQ and
154
+ rhs.kind_of? Gecode::Raw::IntVar
155
+ Gecode::Raw.should_receive(:abs).once.with(@model.active_space,
156
+ @var.bind, rhs, strength)
157
+ Gecode::Raw.should_receive(:rel).exactly(0).times
158
+ else
159
+ Gecode::Raw.should_receive(:abs).once.with(@model.active_space,
160
+ @var.bind, an_instance_of(Gecode::Raw::IntVar), strength)
161
+ Gecode::Raw.should_receive(:rel).once.with(@model.active_space,
162
+ an_instance_of(Gecode::Raw::IntVar), relation, rhs, strength)
163
+ end
151
164
  else
152
165
  Gecode::Raw.should_receive(:abs).once.with(@model.active_space,
153
- @var.bind, an_instance_of(Gecode::Raw::IntVar),
154
- an_instance_of(Fixnum))
166
+ @var.bind, an_instance_of(Gecode::Raw::IntVar), strength)
155
167
  Gecode::Raw.should_receive(:rel).once.with(@model.active_space,
156
- an_instance_of(Gecode::Raw::IntVar), relation, rhs, reif_var.bind,
157
- strength)
168
+ an_instance_of(Gecode::Raw::IntVar), relation, rhs,
169
+ an_instance_of(Gecode::Raw::BoolVar), strength)
158
170
  end
159
171
  end
160
-
161
- # For constraint option spec.
162
- @invoke_options = lambda do |hash|
163
- @var.abs.must_be.greater_than(@var, hash)
164
- @model.solve!
165
- end
166
- @expect_options = lambda do |strength, reif_var|
167
- @expect.call(Gecode::Raw::IRT_GR, @var, strength, reif_var)
168
- end
169
172
  end
170
173
 
171
174
  it 'should constrain the absolute value' do
@@ -183,34 +186,32 @@ describe Gecode::Constraints::Int::Arithmetic, ' (multiplication)' do
183
186
  @var = @model.var
184
187
  @var2 = @model.var2
185
188
  @stub = @var * @var2
189
+ @target = @model.var3
186
190
 
187
191
  # Creates an expectation corresponding to the specified input.
188
- @expect = lambda do |relation, rhs, strength, reif_var|
192
+ @expect = lambda do |relation, rhs, strength, reif_var, negated|
189
193
  rhs = rhs.bind if rhs.respond_to? :bind
190
194
  if reif_var.nil?
191
- Gecode::Raw.should_receive(:mult).once.with(@model.active_space,
192
- @var.bind, @var2.bind, an_instance_of(Gecode::Raw::IntVar),
193
- an_instance_of(Fixnum))
194
- Gecode::Raw.should_receive(:rel).once.with(@model.active_space,
195
- an_instance_of(Gecode::Raw::IntVar), relation, rhs, strength)
195
+ if !negated and relation == Gecode::Raw::IRT_EQ and
196
+ rhs.kind_of? Gecode::Raw::IntVar
197
+ Gecode::Raw.should_receive(:mult).once.with(@model.active_space,
198
+ @var.bind, @var2.bind, rhs, strength)
199
+ Gecode::Raw.should_receive(:rel).exactly(0).times
200
+ else
201
+ Gecode::Raw.should_receive(:mult).once.with(@model.active_space,
202
+ @var.bind, @var2.bind, an_instance_of(Gecode::Raw::IntVar),
203
+ strength)
204
+ Gecode::Raw.should_receive(:rel).once.with(@model.active_space,
205
+ an_instance_of(Gecode::Raw::IntVar), relation, rhs, strength)
206
+ end
196
207
  else
197
208
  Gecode::Raw.should_receive(:mult).once.with(@model.active_space,
198
- @var.bind, @var2.bind, an_instance_of(Gecode::Raw::IntVar),
199
- an_instance_of(Fixnum))
209
+ @var.bind, @var2.bind, an_instance_of(Gecode::Raw::IntVar), strength)
200
210
  Gecode::Raw.should_receive(:rel).once.with(@model.active_space,
201
211
  an_instance_of(Gecode::Raw::IntVar), relation, rhs, reif_var.bind,
202
212
  strength)
203
213
  end
204
214
  end
205
-
206
- # For constraint option spec.
207
- @invoke_options = lambda do |hash|
208
- (@var * @var2).must_be.greater_than(@var, hash)
209
- @model.solve!
210
- end
211
- @expect_options = lambda do |strength, reif_var|
212
- @expect.call(Gecode::Raw::IRT_GR, @var, strength, reif_var)
213
- end
214
215
  end
215
216
 
216
217
  it 'should constrain the value of the multiplication' do
@@ -0,0 +1,130 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+ require File.dirname(__FILE__) + '/constraint_helper'
3
+
4
+ class BoolEnumSampleProblem < Gecode::Model
5
+ attr :bools
6
+ attr :b1
7
+ attr :b2
8
+
9
+ def initialize
10
+ @bools = bool_var_array(4)
11
+ @b1 = bool_var
12
+ @b2 = bool_var
13
+ branch_on @bools
14
+ branch_on wrap_enum([@b1, @b2])
15
+ end
16
+ end
17
+
18
+ # Expects @stub, which contains the started constraint and @compute_result which
19
+ # computes whether the left hand side is true or not.
20
+ describe 'bool enum constraint', :shared => true do
21
+ it 'should handle being constrained to be true' do
22
+ @stub.must_be.true
23
+ @model.solve!
24
+ @compute_result.call.should be_true
25
+ end
26
+
27
+ it 'should handle being constrained to be negated true' do
28
+ @stub.must_not_be.true
29
+ @model.solve!
30
+ @compute_result.call.should_not be_true
31
+ end
32
+
33
+ it 'should handle being constrained to be false' do
34
+ @stub.must_be.false
35
+ @model.solve!
36
+ @compute_result.call.should_not be_true
37
+ end
38
+
39
+ it 'should handle being constrained to be negated false' do
40
+ @stub.must_not_be.false
41
+ @model.solve!
42
+ @compute_result.call.should be_true
43
+ end
44
+
45
+ it 'should handle being constrained to be equal to a variable' do
46
+ @stub.must_be == @b1
47
+ @model.solve!
48
+ @compute_result.call.should == @b1.true?
49
+ end
50
+
51
+ it 'should handle being constrained to not be equal to a variable' do
52
+ @stub.must_not_be == @b1
53
+ @model.solve!
54
+ @compute_result.call.should_not == @b1.true?
55
+ end
56
+
57
+ it 'should handle being constrained to be equal to be a nested expression' do
58
+ @stub.must_be == (@b1 | @b2) & @b1
59
+ @model.solve!
60
+ @compute_result.call.should == (@b1.true? | @b2.true?) & @b1.true?
61
+ end
62
+
63
+ it 'should handle being constrained to not be equal to be a nested expression' do
64
+ @stub.must_not_be == (@b1 | @b2) & @b1
65
+ @model.solve!
66
+ @compute_result.call.should_not == (@b1.true? | @b2.true?) & @b1.true?
67
+ end
68
+ end
69
+
70
+ describe Gecode::Constraints::BoolEnum, ' (conjunction)' do
71
+ before do
72
+ @model = BoolEnumSampleProblem.new
73
+ @bools = @model.bools
74
+ @b1 = @model.b1
75
+ @b2 = @model.b2
76
+
77
+ # For constraint option spec.
78
+ @invoke_options = lambda do |hash|
79
+ @bools.conjunction.must_be.equal_to(true, hash)
80
+ @model.solve!
81
+ end
82
+ @expect_options = lambda do |strength, reif_var|
83
+ Gecode::Raw.should_receive(:bool_and).once.with(@model.active_space,
84
+ an_instance_of(Gecode::Raw::BoolVarArray),
85
+ an_instance_of(Gecode::Raw::BoolVar), strength)
86
+ unless reif_var.nil?
87
+ Gecode::Raw.should_receive(:bool_eqv).once.with(@model.active_space,
88
+ an_instance_of(Gecode::Raw::BoolVar), reif_var.bind, true, strength)
89
+ end
90
+ end
91
+
92
+ # For bool enum spec.
93
+ @stub = @bools.conjunction
94
+ @compute_result = lambda{ @bools.all?{ |b| b.true? } }
95
+ end
96
+
97
+ it_should_behave_like 'bool enum constraint'
98
+ it_should_behave_like 'constraint with options'
99
+ end
100
+
101
+ describe Gecode::Constraints::BoolEnum, ' (disjunction)' do
102
+ before do
103
+ @model = BoolEnumSampleProblem.new
104
+ @bools = @model.bools
105
+ @b1 = @model.b1
106
+ @b2 = @model.b2
107
+
108
+ # For constraint option spec.
109
+ @invoke_options = lambda do |hash|
110
+ @bools.disjunction.must_be.equal_to(true, hash)
111
+ @model.solve!
112
+ end
113
+ @expect_options = lambda do |strength, reif_var|
114
+ Gecode::Raw.should_receive(:bool_or).once.with(@model.active_space,
115
+ an_instance_of(Gecode::Raw::BoolVarArray),
116
+ an_instance_of(Gecode::Raw::BoolVar), strength)
117
+ unless reif_var.nil?
118
+ Gecode::Raw.should_receive(:bool_eqv).once.with(@model.active_space,
119
+ an_instance_of(Gecode::Raw::BoolVar), reif_var.bind, true, strength)
120
+ end
121
+ end
122
+
123
+ # For bool enum spec.
124
+ @stub = @bools.disjunction
125
+ @compute_result = lambda{ @bools.any?{ |b| b.true? } }
126
+ end
127
+
128
+ it_should_behave_like 'bool enum constraint'
129
+ it_should_behave_like 'constraint with options'
130
+ end
@@ -1,4 +1,5 @@
1
1
  require File.dirname(__FILE__) + '/../spec_helper'
2
+ require File.dirname(__FILE__) + '/constraint_helper'
2
3
 
3
4
  class BoolSampleProblem < Gecode::Model
4
5
  attr :b1
@@ -18,6 +19,21 @@ describe Gecode::Constraints::Bool do
18
19
  @b1 = @model.b1
19
20
  @b2 = @model.b2
20
21
  @b3 = @model.b3
22
+
23
+ # For constraint option spec.
24
+ @invoke_options = lambda do |hash|
25
+ (@b1 | @b2).must_be.equal_to(true, hash)
26
+ @model.solve!
27
+ end
28
+ @expect_options = lambda do |strength, reif_var|
29
+ Gecode::Raw.should_receive(:bool_or).once.with(@model.active_space,
30
+ @b1.bind, @b2.bind, an_instance_of(Gecode::Raw::BoolVar),
31
+ Gecode::Raw::ICL_DEF)
32
+ unless reif_var.nil?
33
+ Gecode::Raw.should_receive(:bool_eqv).once.with(@model.active_space,
34
+ an_instance_of(Gecode::Raw::BoolVar), reif_var.bind, true, strength)
35
+ end
36
+ end
21
37
  end
22
38
 
23
39
  it 'should handle single variables constrainted to be true' do
@@ -34,14 +50,14 @@ describe Gecode::Constraints::Bool do
34
50
  b1.true?.should_not be_true
35
51
  end
36
52
 
37
- it 'should handle single variables constrainted not to be true' do
53
+ it 'should handle single variables constrainted not to be false' do
38
54
  @b1.must_not_be.false
39
55
  b1 = @model.solve!.b1
40
56
  b1.should be_assigned
41
57
  b1.true?.should be_true
42
58
  end
43
59
 
44
- it 'should handle single variables constrainted not to be false' do
60
+ it 'should handle single variables constrainted not to be true' do
45
61
  @b1.must_not_be.true
46
62
  b1 = @model.solve!.b1
47
63
  b1.should be_assigned
@@ -79,6 +95,54 @@ describe Gecode::Constraints::Bool do
79
95
  sol.b2.true?.should_not be_true
80
96
  end
81
97
 
98
+ it 'should handle exclusive or' do
99
+ @b1.must_be.false
100
+ (@b1 ^ @b2).must_be.true
101
+ sol = @model.solve!
102
+ sol.b1.true?.should_not be_true
103
+ sol.b2.true?.should be_true
104
+ end
105
+
106
+ it 'should handle negated exclusive or' do
107
+ @b1.must_be.true
108
+ (@b1 ^ @b2).must_not_be.true
109
+ sol = @model.solve!
110
+ sol.b1.true?.should be_true
111
+ sol.b2.true?.should be_true
112
+ end
113
+
114
+ it 'should handle implication' do
115
+ @b2.must_be.false
116
+ (@b1.implies @b2).must_be.true
117
+ sol = @model.solve!
118
+ sol.b1.true?.should_not be_true
119
+ sol.b2.true?.should_not be_true
120
+ end
121
+
122
+ it 'should handle negated implication' do
123
+ @b1.must_be.true
124
+ ((@b1 | @b2).implies @b2).must_not_be.true
125
+ sol = @model.solve!
126
+ sol.b1.true?.should be_true
127
+ sol.b2.true?.should_not be_true
128
+ end
129
+
130
+ it 'should handle imply after must' do
131
+ @b2.must_be.false
132
+ @b1.must.imply @b2
133
+ sol = @model.solve!
134
+ sol.b1.true?.should_not be_true
135
+ sol.b2.true?.should_not be_true
136
+ end
137
+
138
+ it 'should handle imply after must_not' do
139
+ @b1.must_be.true
140
+ @b1.must_not.imply @b2
141
+ sol = @model.solve!
142
+ sol.b1.true?.should be_true
143
+ sol.b2.true?.should_not be_true
144
+ end
145
+
82
146
  it 'should handle single variables as right hand side' do
83
147
  @b1.must == @b2
84
148
  @b2.must_be.false
@@ -120,6 +184,16 @@ describe Gecode::Constraints::Bool do
120
184
  sol.b3.true?.should be_true
121
185
  end
122
186
 
187
+ it 'should handle nested expressions containing exclusive or' do
188
+ ((@b1 ^ @b1) & @b3).must == ((@b2 | @b3) ^ @b2)
189
+ @b1.must_be.true
190
+ @b2.must_be.false
191
+ sol = @model.solve!
192
+ sol.b1.true?.should be_true
193
+ sol.b2.true?.should_not be_true
194
+ sol.b3.true?.should_not be_true
195
+ end
196
+
123
197
  it 'should handle nested expressions on both sides with negation' do
124
198
  ((@b1 & @b1) | @b3).must_not == ((@b1 | @b3) & @b2)
125
199
  @b1.must_be.true
@@ -129,4 +203,23 @@ describe Gecode::Constraints::Bool do
129
203
  sol.b2.true?.should_not be_true
130
204
  sol.b3.true?.should be_true
131
205
  end
206
+
207
+ it 'should translate reification with a variable right hand side' do
208
+ @b1.must_be.equal_to(@b2, :reify => @b3)
209
+ @b1.must_be.true
210
+ @b2.must_be.false
211
+ sol = @model.solve!
212
+ sol.b3.true?.should_not be_true
213
+ end
214
+
215
+ it 'should translate reification with a variable right hand side and negation' do
216
+ @b1.must_not_be.equal_to(@b2, :reify => @b3)
217
+ @b1.must_be.true
218
+ @b2.must_be.false
219
+ sol = @model.solve!
220
+ sol.b3.true?.should be_true
221
+ end
222
+
223
+
224
+ it_should_behave_like 'constraint with options'
132
225
  end
@@ -0,0 +1,127 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+ require File.dirname(__FILE__) + '/constraint_helper'
3
+
4
+ describe Gecode::Constraints::Set::Cardinality, ' (range)' do
5
+ before do
6
+ @model = Gecode::Model.new
7
+ @set = @model.set_var([], 0..10)
8
+ @model.branch_on @model.wrap_enum([@set])
9
+ @range = 1..2
10
+ @three_dot_range = 1...2
11
+
12
+ @invoke_options = lambda do |hash|
13
+ @set.size.must_be.in(@range, hash)
14
+ end
15
+
16
+ @invoke = lambda do |rhs|
17
+ @set.size.must_be.in(rhs)
18
+ @model.solve!
19
+ end
20
+ @expect = lambda do |rhs|
21
+ Gecode::Raw.should_receive(:cardinality).once.with(@model.active_space,
22
+ @set.bind, rhs.first, rhs.last)
23
+ end
24
+ end
25
+
26
+ it 'should translate cardinality constraints with ranges' do
27
+ @expect.call(@range)
28
+ @invoke.call(@range)
29
+ end
30
+
31
+ it 'should translate cardinality constraints with three dot range domains' do
32
+ @expect.call(@three_dot_range)
33
+ @invoke.call(@three_dot_range)
34
+ end
35
+
36
+ it 'should constrain the cardinality of a set' do
37
+ @set.size.must_be.in @range
38
+ @model.solve!
39
+ @range.should include(@set.val_size)
40
+ end
41
+
42
+ it 'should raise error if the right hand side is not a range' do
43
+ lambda{ @set.size.must_be.in 'hello' }.should raise_error(TypeError)
44
+ end
45
+
46
+ it 'should not shadow the integer variable domain constrain' do
47
+ Gecode::Raw.should_receive(:dom).once.with(@model.active_space,
48
+ an_instance_of(Gecode::Raw::IntVar), an_instance_of(Gecode::Raw::IntSet),
49
+ Gecode::Raw::ICL_DEF)
50
+ @set.size.must_not_be.in [1,3]
51
+ end
52
+
53
+ it_should_behave_like 'non-reifiable set constraint'
54
+ end
55
+
56
+ describe Gecode::Constraints::Set::Cardinality, ' (composite)' do
57
+ before do
58
+ @model = Gecode::Model.new
59
+ @set = @model.set_var([], 0..10)
60
+ @target = @var = @model.int_var(0..11)
61
+ @model.branch_on @model.wrap_enum([@set])
62
+ @model.branch_on @model.wrap_enum([@var])
63
+
64
+ @invoke_options = lambda do |hash|
65
+ @set.size.must_be.equal_to(@var, hash)
66
+ end
67
+
68
+ @invoke = lambda do |rhs|
69
+ @set.size.must == rhs
70
+ @model.solve!
71
+ end
72
+ @expect = lambda do |relation, rhs, strength, reif_var, negated|
73
+ rhs = rhs.bind if rhs.respond_to? :bind
74
+ if reif_var.nil?
75
+ if !negated and relation == Gecode::Raw::IRT_EQ and
76
+ rhs.kind_of? Gecode::Raw::IntVar
77
+ Gecode::Raw.should_receive(:cardinality).once.with(
78
+ @model.active_space, @set.bind, rhs)
79
+ Gecode::Raw.should_receive(:rel).exactly(0).times
80
+ else
81
+ Gecode::Raw.should_receive(:cardinality).once.with(
82
+ @model.active_space, @set.bind, an_instance_of(Gecode::Raw::IntVar))
83
+ Gecode::Raw.should_receive(:rel).once.with(@model.active_space,
84
+ an_instance_of(Gecode::Raw::IntVar), relation, rhs,
85
+ strength)
86
+ end
87
+ else
88
+ Gecode::Raw.should_receive(:cardinality).once.with(@model.active_space,
89
+ @set.bind, an_instance_of(Gecode::Raw::IntVar))
90
+ Gecode::Raw.should_receive(:rel).once.with(@model.active_space,
91
+ an_instance_of(Gecode::Raw::IntVar), relation, rhs, reif_var.bind,
92
+ strength)
93
+ end
94
+ end
95
+
96
+ # For composite spec.
97
+ @invoke_relation = lambda do |relation, target, negated|
98
+ if negated
99
+ @set.size.must_not.send(relation, target)
100
+ else
101
+ @set.size.must.send(relation, target)
102
+ end
103
+ @model.solve!
104
+ end
105
+ @expect_relation = lambda do |relation, target, negated|
106
+ @expect.call(relation, target, Gecode::Raw::ICL_DEF, nil, negated)
107
+ end
108
+
109
+ # For options spec.
110
+ @invoke_options = lambda do |hash|
111
+ @set.size.must_be.less_than_or_equal_to(17, hash)
112
+ @model.solve!
113
+ end
114
+ @expect_options = lambda do |strength, reif_var|
115
+ @expect.call(Gecode::Raw::IRT_LQ, 17, strength, reif_var, false)
116
+ end
117
+ end
118
+
119
+ it 'should constrain the cardinality of a set' do
120
+ @set.size.must == @var
121
+ @model.solve!
122
+ @set.val_size.should == @var.val
123
+ end
124
+
125
+ it_should_behave_like 'constraint with options'
126
+ it_should_behave_like 'composite constraint'
127
+ end