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,197 @@
1
+ require File.dirname(__FILE__) + '/../constraint_helper'
2
+
3
+ Gecode::Util::SET_RELATION_TYPES.each_pair do |relation, type|
4
+ next if relation == :==
5
+
6
+ describe Gecode::Set::Domain, " (#{relation})" do
7
+ include GecodeR::Specs::SetHelper
8
+
9
+ before do
10
+ @model = Gecode::Model.new
11
+ @glb = []
12
+ @lub = 0..3
13
+ @set = @model.set_var(@glb, @lub)
14
+ @model.branch_on @set
15
+ @range = 0..1
16
+ @non_range = [0, 2]
17
+ @singleton = 0
18
+
19
+ @types = [:set]
20
+ @invoke = lambda do |receiver, hash|
21
+ receiver.method(relation).call(@non_range, hash)
22
+ @model.solve!
23
+ end
24
+ @expect = lambda do |var, opts, reif_var|
25
+ @expect_with_rhs.call(var, opts, reif_var, @non_range)
26
+ end
27
+ @expect_with_rhs = lambda do |var, opts, reif_var, rhs|
28
+ if reif_var.nil?
29
+ Gecode::Raw.should_receive(:dom).once.with(
30
+ an_instance_of(Gecode::Raw::Space),
31
+ var, type,
32
+ *expect_constant_set(rhs))
33
+ else
34
+ params = [an_instance_of(Gecode::Raw::Space),
35
+ var, type]
36
+ params << expect_constant_set(rhs)
37
+ params << reif_var
38
+ Gecode::Raw.should_receive(:dom).once.with(*params.flatten)
39
+ end
40
+ end
41
+ end
42
+
43
+ it "should translate #{relation} with constant range to domain constraint" do
44
+ @expect_with_rhs.call(@model.allow_space_access{ @set.bind },
45
+ nil, nil, @range)
46
+ @set.must.send(relation, @range)
47
+ @model.solve!
48
+ end
49
+
50
+ it "should translate #{relation} with constant non-range to domain constraint" do
51
+ @expect_with_rhs.call(@model.allow_space_access{ @set.bind },
52
+ nil, nil, @non_range)
53
+ @set.must.send(relation, @non_range)
54
+ @model.solve!
55
+ end
56
+
57
+ it "should translate #{relation} with constant singleton to domain constraint" do
58
+ @expect_with_rhs.call(@model.allow_space_access{ @set.bind },
59
+ nil, nil, @singleton)
60
+ @set.must.send(relation, @singleton)
61
+ @model.solve!
62
+ end
63
+
64
+ it 'should raise error if the right hand side is not a constant set' do
65
+ lambda do
66
+ @set.must.send(relation, 'not a constant set')
67
+ end.should raise_error(TypeError)
68
+ end
69
+
70
+ it "should constrain the domain when #{relation} is used" do
71
+ @set = @model.set_var if relation == :complement
72
+ @set.must.method(relation).call(@non_range)
73
+ @model.solve!
74
+ @set.should be_assigned
75
+ case relation
76
+ when :superset
77
+ (@non_range - @set.value.to_a).should be_empty
78
+ when :subset
79
+ (@set.value.to_a - @non_range).should be_empty
80
+ when :complement
81
+ val = @set.value
82
+ val.min.should == Gecode::Model::SET_MIN_INT
83
+ val.max.should == Gecode::Model::SET_MAX_INT
84
+ @non_range.each do |element|
85
+ @set.not_in_upper_bound?(element).should be_true
86
+ end
87
+ when :disjoint
88
+ (@non_range & @set.value.to_a).should be_empty
89
+ end
90
+ end
91
+
92
+ it "should constrain the domain when negated #{relation} is used" do
93
+ @set.must_not.method(relation).call(@non_range)
94
+ @model.solve!
95
+ @set.should be_assigned
96
+ case relation
97
+ when :superset
98
+ (@non_range - @set.value.to_a).should_not be_empty
99
+ when :subset
100
+ (@set.value.to_a - @non_range).should_not be_empty
101
+ when :complement
102
+ val = @set.value
103
+ ((val.min != Gecode::Model::SET_MIN_INT) ||
104
+ (val.max != Gecode::Model::SET_MAX_INT) ||
105
+ @non_range.any?{ |element| @set.in_lower_bound?(element) }
106
+ ).should be_true
107
+ when :disjoint
108
+ (@non_range & @set.value.to_a).should_not be_empty
109
+ end
110
+ end
111
+
112
+ it_should_behave_like 'reifiable set constraint'
113
+ end
114
+ end
115
+
116
+ describe Gecode::Set::Domain, ' (equality)' do
117
+ include GecodeR::Specs::SetHelper
118
+
119
+ before do
120
+ @model = Gecode::Model.new
121
+ @glb = [0]
122
+ @lub = 0..3
123
+ @set = @model.set_var(@glb, @lub)
124
+ @range = 0..1
125
+ @non_range = [0, 2]
126
+ @singleton = 0
127
+ @model.branch_on @model.wrap_enum([@set])
128
+
129
+ @types = [:set]
130
+ @invoke = lambda do |receiver, hash|
131
+ receiver.equal(@non_range, hash)
132
+ @model.solve!
133
+ end
134
+ @expect = lambda do |var, opts, reif_var|
135
+ @expect_with_rhs.call(var, opts, reif_var, @non_range)
136
+ end
137
+ @expect_with_rhs = lambda do |var, opts, reif_var, rhs|
138
+ if reif_var.nil?
139
+ Gecode::Raw.should_receive(:dom).once.with(
140
+ an_instance_of(Gecode::Raw::Space),
141
+ var, Gecode::Raw::SRT_EQ,
142
+ *expect_constant_set(rhs))
143
+ else
144
+ params = [an_instance_of(Gecode::Raw::Space),
145
+ var, Gecode::Raw::SRT_EQ]
146
+ params << expect_constant_set(rhs)
147
+ params << reif_var
148
+ Gecode::Raw.should_receive(:dom).once.with(*params.flatten)
149
+ end
150
+ end
151
+ end
152
+
153
+ it 'should translate equality with constant range to domain constraint' do
154
+ @expect_with_rhs.call(@model.allow_space_access{ @set.bind },
155
+ nil, nil, @range)
156
+ @set.must == @range
157
+ @model.solve!
158
+ end
159
+
160
+ it 'should translate equality with constant non-range to domain constraint' do
161
+ @expect_with_rhs.call(@model.allow_space_access{ @set.bind },
162
+ nil, nil, @non_range)
163
+ @set.must == @non_range
164
+ @model.solve!
165
+ end
166
+
167
+ it 'should translate equality with constant singleton to domain constraint' do
168
+ @expect_with_rhs.call(@model.allow_space_access{ @set.bind },
169
+ nil, nil, @singleton)
170
+ @set.must == @singleton
171
+ @model.solve!
172
+ end
173
+
174
+ it 'should constrain the domain with equality' do
175
+ @set.must == @singleton
176
+ @model.solve!
177
+ @set.should be_assigned
178
+ @set.value.should include(@singleton)
179
+ @set.value.size.should == 1
180
+ end
181
+
182
+ it 'should constrain the domain with inequality' do
183
+ @set.must_not == @singleton
184
+ @model.solve!
185
+ @set.should be_assigned
186
+ @set.value.should include(@singleton)
187
+ ((@set.value.size > 1) || (@set.value != [@singleton])).should be_true
188
+ end
189
+
190
+ it 'should raise error if the right hand side is not a constant set' do
191
+ lambda do
192
+ @set.must == 'not a constant set'
193
+ end.should raise_error(TypeError)
194
+ end
195
+
196
+ it_should_behave_like 'reifiable set constraint'
197
+ end
@@ -0,0 +1,36 @@
1
+ require File.dirname(__FILE__) + '/../constraint_helper'
2
+
3
+ describe Gecode::Set::Connection, ' (include)' do
4
+ before do
5
+ @model = Gecode::Model.new
6
+ @set = @model.set_var([], 2..5)
7
+ @array = @model.int_var_array(4, 0..9)
8
+ @array.must_be.distinct
9
+ @model.branch_on @array
10
+ #@model.branch_on @model.wrap_enum([@set])
11
+
12
+ @types = [:set, :int_enum]
13
+ @invoke = lambda do |receiver, int_enum, hash|
14
+ if hash.empty?
15
+ receiver.include(int_enum)
16
+ else
17
+ receiver.include(int_enum, hash)
18
+ end
19
+ @model.solve!
20
+ end
21
+ @expect = lambda do |var1, var2, opts, reif_var|
22
+ Gecode::Raw.should_receive(:match).once.with(
23
+ an_instance_of(Gecode::Raw::Space),
24
+ var1, var2)
25
+ end
26
+ end
27
+
28
+ it 'should constrain the variables to be included in the set' do
29
+ @set.must.include @array
30
+ @model.solve!.should_not be_nil
31
+ @array.all?{ |x| @set.lower_bound.include? x.value }.should be_true
32
+ end
33
+
34
+ it_should_behave_like 'non-reifiable set constraint'
35
+ it_should_behave_like 'non-negatable constraint'
36
+ end
@@ -0,0 +1,132 @@
1
+ require File.dirname(__FILE__) + '/../property_helper'
2
+
3
+ Gecode::Util::SET_OPERATION_TYPES.each_pair do |operation, type|
4
+ describe Gecode::Set::Operation, " (#{operation} with set variable)" do
5
+ before do
6
+ @model = Gecode::Model.new
7
+ @set1 = @model.set_var([0], 0..20)
8
+ @set2 = @model.set_var([1], 0..20)
9
+ @constant_set = [2, 3, 5]
10
+ @rhs = @model.set_var([], 0..20)
11
+ @model.branch_on @model.wrap_enum([@set1, @set2, @rhs])
12
+
13
+ @property_types = [:set, :set]
14
+ @select_property = lambda do |set1, set2|
15
+ set1.method(operation).call(set2)
16
+ end
17
+ @selected_property = @set1.method(operation).call(@set2)
18
+ @constraint_class =
19
+ Gecode::Set::Operation::OperationConstraint
20
+ end
21
+
22
+ it "should translate #{operation} into an operation constraint" do
23
+ @model.allow_space_access do
24
+ Gecode::Raw.should_receive(:rel).once.with(
25
+ an_instance_of(Gecode::Raw::Space), @set1.bind, type, @set2.bind,
26
+ Gecode::Raw::SRT_EQ, @rhs.bind)
27
+ end
28
+ @set1.method(operation).call(@set2).must == @rhs
29
+ @model.solve!
30
+ end
31
+
32
+ it "should constrain the #{operation} of the sets with variable rhs" do
33
+ @set1.method(operation).call(@set2).must == @rhs
34
+ @model.solve!
35
+
36
+ s1 = @set1.value.to_a
37
+ s2 = @set2.value.to_a
38
+ rhs = @rhs.value.to_a
39
+ case operation
40
+ when :union
41
+ (s1 | s2).should == rhs
42
+ when :disjoint_union
43
+ (s1 | s2).sort.should == rhs.sort
44
+ when :intersection
45
+ (s1 & s2).should == rhs
46
+ when :minus
47
+ (s1 - s2).should == rhs
48
+ end
49
+ end
50
+
51
+ it "should constrain the #{operation} of the sets when used with constant rhs" do
52
+ if operation == :union || operation == :disjoint_union
53
+ @constant_set << 0 << 1 # Or there will not be any solution.
54
+ end
55
+ @set1.method(operation).call(@set2).must == @constant_set
56
+ @model.solve!
57
+
58
+ s1 = @set1.value.to_a
59
+ s2 = @set2.value.to_a
60
+ rhs = @constant_set
61
+ case operation
62
+ when :union
63
+ (s1 | s2).sort.should == rhs.sort
64
+ when :disjoint_union
65
+ (s1 | s2).sort.should == rhs.sort
66
+ when :intersection
67
+ (s1 & s2).should == rhs
68
+ when :minus
69
+ (s1 - s2).should == rhs
70
+ end
71
+ end
72
+
73
+ it_should_behave_like(
74
+ 'property that produces set operand by short circuiting set relations')
75
+ end
76
+ end
77
+
78
+ Gecode::Util::SET_OPERATION_TYPES.each_pair do |operation, type|
79
+ describe Gecode::Set::Operation, " (#{operation} with constant set)" do
80
+ before do
81
+ @model = Gecode::Model.new
82
+ @set = @model.set_var([0], 0..20)
83
+ @constant_set = [1, 3, 5]
84
+ @rhs = @model.set_var([], 0..20)
85
+ @model.branch_on @model.wrap_enum([@set, @rhs])
86
+
87
+ @property_types = [:set, :set]
88
+ @select_property = lambda do |set1, set2|
89
+ set1.method(operation).call(set2)
90
+ end
91
+ @selected_property = @set.method(operation).call(@constant_set)
92
+ @constraint_class =
93
+ Gecode::Set::Operation::OperationConstraint
94
+ end
95
+
96
+ it "should translate #{operation} into an operation constraint" do
97
+ @model.allow_space_access do
98
+ Gecode::Raw.should_receive(:rel).once.with(
99
+ an_instance_of(Gecode::Raw::Space), @set.bind, type,
100
+ an_instance_of(Gecode::Raw::IntSet),
101
+ Gecode::Raw::SRT_EQ, @rhs.bind)
102
+ end
103
+ @set.method(operation).call(@constant_set).must == @rhs
104
+ @model.solve!
105
+ end
106
+
107
+ it "should constrain the #{operation} of the sets with a variable rhs" do
108
+ @set.method(operation).call(@constant_set).must == @rhs
109
+ @model.solve!
110
+
111
+ s1 = @set.value.to_a
112
+ s2 = @constant_set
113
+ rhs = @rhs.value.to_a
114
+ case operation
115
+ when :union
116
+ (s1 | s2).should == rhs
117
+ when :disjoint_union
118
+ (s1 | s2).sort.should == rhs.sort
119
+ when :intersection
120
+ (s1 & s2).should == rhs
121
+ when :minus
122
+ (s1 - s2).should == rhs
123
+ end
124
+ end
125
+
126
+ # We do not test with a constant rhs since we do not have enough
127
+ # degrees of freedom to always find a solution.
128
+
129
+ it_should_behave_like(
130
+ 'property that produces set operand by short circuiting set relations')
131
+ end
132
+ end
@@ -0,0 +1,117 @@
1
+ require File.dirname(__FILE__) + '/../constraint_helper'
2
+
3
+ Gecode::Util::SET_RELATION_TYPES.each_pair do |relation, type|
4
+ next if relation == :==
5
+
6
+ describe Gecode::Set::Relation, " (#{relation})" do
7
+ before do
8
+ @model = Gecode::Model.new
9
+ @set = @model.set_var([0], 0..3)
10
+ @set2 = @model.set_var([1], 0..3)
11
+ @model.branch_on @model.wrap_enum([@set, @set2])
12
+
13
+ @types = [:set, :set]
14
+ @invoke = lambda do |receiver, set_op, hash|
15
+ receiver.method(relation).call(set_op, hash)
16
+ @model.solve!
17
+ end
18
+ @expect = lambda do |var1, var2, opts, reif_var|
19
+ if reif_var.nil?
20
+ Gecode::Raw.should_receive(:rel).once.with(
21
+ an_instance_of(Gecode::Raw::Space),
22
+ var1, type, var2)
23
+ else
24
+ Gecode::Raw.should_receive(:rel).once.with(
25
+ an_instance_of(Gecode::Raw::Space),
26
+ var1, type, var2, reif_var)
27
+ end
28
+ end
29
+ end
30
+
31
+ it "should correctly constrain the set when #{relation} is used" do
32
+ @set = @model.set_var if relation == :complement
33
+ @set.must.method(relation).call(@set2)
34
+ @model.solve!
35
+ @set.should be_assigned
36
+ @set2.should be_assigned
37
+ case relation
38
+ when :superset
39
+ (@set2.value.to_a - @set.value.to_a).should be_empty
40
+ when :subset
41
+ (@set.value.to_a - @set2.value.to_a).should be_empty
42
+ when :complement
43
+ val = @set.value
44
+ val.min.should == Gecode::Model::SET_MIN_INT
45
+ val.max.should == Gecode::Model::SET_MAX_INT
46
+ @set2.value.each do |element|
47
+ @set.not_in_upper_bound?(element).should be_true
48
+ end
49
+ when :disjoint
50
+ (@set2.value.to_a & @set.value.to_a).should be_empty
51
+ end
52
+ end
53
+
54
+ it "should correctly constrain the set when negated #{relation} is used" do
55
+ @set.must_not.method(relation).call(@set2)
56
+ @model.solve!
57
+ @set.should be_assigned
58
+ @set2.should be_assigned
59
+ case relation
60
+ when :superset
61
+ (@set2.value.to_a - @set.value.to_a).should_not be_empty
62
+ when :subset
63
+ (@set.value.to_a - @set2.value.to_a).should_not be_empty
64
+ when :complement
65
+ val = @set.value
66
+ ((val.min != Gecode::Model::SET_MIN_INT) ||
67
+ (val.max != Gecode::Model::SET_MAX_INT) ||
68
+ @set.value.to_a.any?{ |element| @set.in_lower_bound?(element) }
69
+ ).should be_true
70
+ when :disjoint
71
+ (@set.value.to_a & @set.value.to_a).should_not be_empty
72
+ end
73
+ end
74
+
75
+ it_should_behave_like 'reifiable set constraint'
76
+ end
77
+ end
78
+
79
+ describe Gecode::Set::Relation, ' (equality)' do
80
+ before do
81
+ @model = Gecode::Model.new
82
+ @set = @model.set_var([0], 0..1)
83
+ @set2 = @model.set_var([1], 0..1)
84
+ @model.branch_on @model.wrap_enum([@set, @set2])
85
+
86
+ @types = [:set, :set]
87
+ @invoke = lambda do |receiver, set_op, hash|
88
+ receiver.equal(set_op, hash)
89
+ @model.solve!
90
+ end
91
+ @expect = lambda do |var1, var2, opts, reif_var|
92
+ if reif_var.nil?
93
+ Gecode::Raw.should_receive(:rel).once.with(
94
+ an_instance_of(Gecode::Raw::Space),
95
+ var1, Gecode::Raw::SRT_EQ, var2)
96
+ else
97
+ Gecode::Raw.should_receive(:rel).once.with(
98
+ an_instance_of(Gecode::Raw::Space),
99
+ var1, Gecode::Raw::SRT_EQ, var2, reif_var)
100
+ end
101
+ end
102
+ end
103
+
104
+ it 'should constrain sets to be equal' do
105
+ @set.must == @set2
106
+ @model.solve!
107
+ @set.value.to_a.should == @set2.value.to_a
108
+ end
109
+
110
+ it 'should constrain sets to not be equal when negated' do
111
+ @set.must_not == @set2
112
+ @model.solve!
113
+ @set.value.to_a.should_not == @set2.value.to_a
114
+ end
115
+
116
+ it_should_behave_like 'reifiable set constraint'
117
+ end