gecoder 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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