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,224 @@
1
+ require File.dirname(__FILE__) + '/../constraint_helper'
2
+
3
+ # Assumes that @variables, @expected_array and @tuples are defined.
4
+ describe 'int tuple constraint', :shared => true do
5
+ it 'should not allow negation' do
6
+ lambda do
7
+ @variables.must_not_be.in @tuples
8
+ end.should raise_error(Gecode::MissingConstraintError)
9
+ end
10
+
11
+ it 'should not allow empty tuples' do
12
+ lambda do
13
+ @variables.must_be.in []
14
+ end.should raise_error(ArgumentError)
15
+ end
16
+
17
+ it 'should not allow tuples of sizes other than the number of variables' do
18
+ lambda do
19
+ @variables.must_be.in([@tuples.first * 2])
20
+ end.should raise_error(ArgumentError)
21
+ end
22
+
23
+ it 'should raise error if the right hand side does not contain tuples of correct type' do
24
+ lambda do
25
+ size = @variables.size
26
+ @variables.must_be.in ['h'*size, 'i'*size]
27
+ end.should raise_error(TypeError)
28
+ end
29
+ end
30
+
31
+ describe Gecode::IntEnum::Extensional, ' (tuple constraint)' do
32
+ before do
33
+ @model = Gecode::Model.new
34
+ @tuples = [[1,7], [5,1]]
35
+ @variables = @digits = @model.int_var_array(2, 0..9)
36
+ @model.branch_on @digits
37
+
38
+ @types = [:int_enum]
39
+ @invoke = lambda do |receiver, hash|
40
+ receiver.in([[1, 7, 5, 3, 0], [8, 9, 9, 9, 0]], hash)
41
+ @model.solve!
42
+ end
43
+ @expect = lambda do |var, opts, reif_var|
44
+ Gecode::Raw.should_receive(:extensional).once.with(
45
+ an_instance_of(Gecode::Raw::Space),
46
+ var, an_instance_of(Gecode::Raw::TupleSet), *opts)
47
+ end
48
+ end
49
+
50
+ it 'should constrain the domain of all variables' do
51
+ @digits.must_be.in @tuples
52
+
53
+ found_solutions = []
54
+ @model.each_solution do |m|
55
+ found_solutions << @digits.values
56
+ end
57
+
58
+ found_solutions.size.should == 2
59
+ (found_solutions - @tuples).should be_empty
60
+ end
61
+
62
+ it 'should raise error if the right hand side is not an enumeration' do
63
+ lambda{ @digits.must_be.in 4711 }.should raise_error(TypeError)
64
+ end
65
+
66
+ it 'should raise error if the right hand side does not contain tuples' do
67
+ lambda{ @digits.must_be.in [17, 4711] }.should raise_error(TypeError)
68
+ end
69
+
70
+ it_should_behave_like 'int tuple constraint'
71
+ it_should_behave_like 'non-reifiable constraint'
72
+ end
73
+
74
+ # Assumes that @variables, @expected_array, @value1, @value2 (must not
75
+ # equal @value1) and @regexp are defined.
76
+ describe 'int regular expression constraint', :shared => true do
77
+ it 'should handle values grouped in a single array' do
78
+ @variables.must.match [@value1, @value2, @value1]
79
+ @model.solve!.should_not be_nil
80
+ @variables.values.should == [@value1, @value2, @value1]
81
+ end
82
+
83
+ it 'should allow nested groups of values' do
84
+ @variables.must.match [@value1, [@value2, [@value1]]]
85
+ @model.solve!.should_not be_nil
86
+ @variables.values.should == [@value1, @value2, @value1]
87
+ end
88
+
89
+ it 'should handle the repeat operation' do
90
+ @variables.must.match [@value1, @model.repeat([@value2], 1, 2)]
91
+ @model.solve!.should_not be_nil
92
+ @variables.values.should == [@value1, @value2, @value2]
93
+ end
94
+
95
+ it 'should handle repeat operations that do not encase constant values in arrays' do
96
+ @variables.must.match [@value1, @model.repeat(@value2, 1, 2)]
97
+ @model.solve!.should_not be_nil
98
+ @variables.values.should == [@value1, @value2, @value2]
99
+ end
100
+
101
+ it 'should handle nested repeat operations' do
102
+ @variables.must.match [[@model.repeat(@model.repeat([@value2], 1, 3), 1, 2)]]
103
+ @model.solve!.should_not be_nil
104
+ @variables.values.should == [@value2, @value2, @value2]
105
+ end
106
+
107
+ it 'should handle nested repeat operations (2)' do
108
+ @variables.must.match [[@model.repeat([@model.repeat(@value2, 1, 3)], 1, 2)]]
109
+ @model.solve!.should_not be_nil
110
+ @variables.values.should == [@value2, @value2, @value2]
111
+ end
112
+
113
+ it 'should interpret the repeat operation with the last argument omitted as only giving a lower bound' do
114
+ @variables.must.match [@value1, @model.repeat([@value2], 1)]
115
+ @model.solve!.should_not be_nil
116
+ @variables.values.should == [@value1, @value2, @value2]
117
+ end
118
+
119
+ it 'should interpret the repeat operation with all but the first argument omitted as not giving any bound' do
120
+ @variables.must.match [@model.repeat(@value2), @value1, @value1, @value1]
121
+ @model.solve!.should_not be_nil
122
+ @variables.values.should == [@value1, @value1, @value1]
123
+ end
124
+
125
+ it 'should interpret the repeat operation with all but the first argument omitted as not giving any bound (2)' do
126
+ @variables.must.match [@model.repeat(@value2)]
127
+ @model.solve!.should_not be_nil
128
+ @variables.values.should == [@value2, @value2, @value2]
129
+ end
130
+
131
+ it 'should translate at_most_once(reg) to repeat(reg, 0, 1)' do
132
+ @model.should_receive(:repeat).once.with([@value1], 0, 1)
133
+ @model.at_most_once [@value1]
134
+ end
135
+
136
+ it 'should translate at_least_once(reg) to repeat(reg, 1)' do
137
+ @model.should_receive(:repeat).once.with([@value1], 1)
138
+ @model.at_least_once [@value1]
139
+ end
140
+
141
+ it 'should raise error if the right hand side is not an enumeration' do
142
+ lambda do
143
+ @variables.must.match Object.new
144
+ end.should raise_error(TypeError)
145
+ end
146
+
147
+ it 'should raise error if the right hand side does not a regexp of the right type' do
148
+ lambda do
149
+ @variables.must.match [@value1, 'foo']
150
+ end.should raise_error(TypeError)
151
+ end
152
+
153
+ it 'should raise error if the right hand side contains a nested element of an incorrect type' do
154
+ lambda do
155
+ @variables.must.match [@value1, [@value2, 'foo']]
156
+ end.should raise_error(TypeError)
157
+ end
158
+
159
+ it 'should raise error if the repeat operation is given arguments of incorrect type (2)' do
160
+ lambda do
161
+ @variables.must.match @model.repeat(@value1, [0], 1)
162
+ end.should raise_error(TypeError)
163
+ end
164
+
165
+ it 'should raise error if the repeat operation is given arguments of incorrect type (3)' do
166
+ lambda do
167
+ @variables.must.match @model.repeat(@value1, 0, [1])
168
+ end.should raise_error(TypeError)
169
+ end
170
+
171
+ it 'should raise error if the repeat operation is given arguments of incorrect type' do
172
+ lambda do
173
+ @variables.must.match @model.repeat('foo', 0, 1)
174
+ end.should raise_error(TypeError)
175
+ end
176
+
177
+ it 'should not allow negation' do
178
+ lambda do
179
+ @variables.must_not.match @regexp
180
+ end.should raise_error(Gecode::MissingConstraintError)
181
+ end
182
+ end
183
+
184
+ describe Gecode::IntEnum::Extensional, ' (regexp constraint)' do
185
+ before do
186
+ @model = Gecode::Model.new
187
+ @variables = @digits = @model.int_var_array(3, 0..9)
188
+ @model.branch_on @digits
189
+ @expected_array = an_instance_of Gecode::Raw::IntVarArray
190
+ @value1 = 3
191
+ @value2 = 5
192
+ @regexp = [1, @model.any(3, 4), @model.at_most_once(5)]
193
+
194
+ @types = [:int_enum]
195
+ @invoke = lambda do |receiver, hash|
196
+ receiver.match(@regexp, hash)
197
+ @model.solve!
198
+ end
199
+ @expect = lambda do |var, opts, reif_var|
200
+ Gecode::Raw.should_receive(:extensional).once.with(
201
+ an_instance_of(Gecode::Raw::Space),
202
+ var, an_instance_of(Gecode::Raw::REG), *opts)
203
+ end
204
+ end
205
+
206
+ it 'should handle the any operation' do
207
+ @digits.must.match [1, @model.any(1, 2, 3), 3]
208
+ @model.solve!.should_not be_nil
209
+ values = @digits.values
210
+ values.size.should == 3
211
+ values.should == values.sort
212
+ end
213
+
214
+ it 'should handle the any operator with nested expressions' do
215
+ @digits.must.match [1, @model.any(@model.at_least_once(2), [3, 5])]
216
+ @digits[2].must < 4
217
+ @model.solve!.should_not be_nil
218
+ @digits.values.should == [1,2,2]
219
+ end
220
+
221
+ it_should_behave_like 'int regular expression constraint'
222
+ it_should_behave_like 'non-reifiable constraint'
223
+ end
224
+
@@ -0,0 +1,167 @@
1
+ require File.dirname(__FILE__) + '/../constraint_helper'
2
+
3
+ class SortSampleProblem < Gecode::Model
4
+ attr :vars
5
+ attr :sorted
6
+ attr :indices
7
+
8
+ def initialize
9
+ @vars = int_var_array(4, 10..19)
10
+ @sorted = int_var_array(4, 10..19)
11
+ @indices = int_var_array(4, 0..9)
12
+
13
+ # To make it more interesting
14
+ @vars.must_be.distinct
15
+
16
+ branch_on @vars
17
+ end
18
+ end
19
+
20
+ describe Gecode::IntEnum::Sort, ' (without :as and :order)' do
21
+ before do
22
+ @model = SortSampleProblem.new
23
+ @vars = @model.vars
24
+ @sorted = @model.sorted
25
+
26
+ @types = [:int_enum]
27
+ @invoke = lambda do |receiver, hash|
28
+ receiver.sorted(hash)
29
+ @model.solve!
30
+ end
31
+ @expect = lambda do |var, opts, reif_var|
32
+ if reif_var.nil?
33
+ Gecode::Raw.should_receive(:rel).exactly(var.size - 1).times.with(
34
+ an_instance_of(Gecode::Raw::Space),
35
+ an_instance_of(Gecode::Raw::IntVar), Gecode::Raw::IRT_LQ,
36
+ an_instance_of(Gecode::Raw::IntVar), *opts)
37
+ else
38
+ Gecode::Raw.should_receive(:rel).once.with(
39
+ an_instance_of(Gecode::Raw::Space), anything,
40
+ an_instance_of(Gecode::Raw::BoolVarArray),
41
+ anything, anything, anything)
42
+ Gecode::Raw.should_receive(:rel).exactly(var.size - 1).times.with(
43
+ an_instance_of(Gecode::Raw::Space),
44
+ an_instance_of(Gecode::Raw::IntVar), Gecode::Raw::IRT_LQ,
45
+ an_instance_of(Gecode::Raw::IntVar),
46
+ an_instance_of(Gecode::Raw::BoolVar), *opts)
47
+ end
48
+ end
49
+ end
50
+
51
+ it 'should constraint variables to be sorted' do
52
+ @vars.must_be.sorted
53
+ values = @model.solve!.vars.values
54
+ values.should == values.sort
55
+ end
56
+
57
+ it 'should allow negation' do
58
+ @vars.must_not_be.sorted
59
+ @model.solve!
60
+ values = @vars.values
61
+ values.should_not == values.sort
62
+ end
63
+
64
+ it_should_behave_like 'reifiable constraint'
65
+ end
66
+
67
+ describe Gecode::IntEnum::Sort, ' (with :as)' do
68
+ before do
69
+ @model = SortSampleProblem.new
70
+ @vars = @model.vars
71
+ @sorted = @model.sorted
72
+
73
+ # Make it a bit more interesting.
74
+ @vars[0].must > @vars[3] + 1
75
+
76
+ @types = [:int_enum, :int_enum]
77
+ @invoke = lambda do |receiver, int_enum, hash|
78
+ receiver.sorted hash.update(:as => int_enum)
79
+ @model.solve!
80
+ end
81
+ @expect = lambda do |var1, var2, opts, reif_var|
82
+ Gecode::Raw.should_receive(:sorted).once.with(
83
+ an_instance_of(Gecode::Raw::Space),
84
+ var1, var2, *opts)
85
+ end
86
+ end
87
+
88
+ it 'should constraint variables to be sorted' do
89
+ @vars.must_be.sorted(:as => @sorted)
90
+ @model.solve!
91
+ values = @sorted.values
92
+ values.should == values.sort
93
+ end
94
+
95
+ it_should_behave_like 'non-reifiable constraint'
96
+ it_should_behave_like 'non-negatable constraint'
97
+ end
98
+
99
+ describe Gecode::IntEnum::Sort, ' (with :order)' do
100
+ before do
101
+ @model = SortSampleProblem.new
102
+ @vars = @model.vars
103
+ @sorted = @model.sorted
104
+ @indices = @model.indices
105
+
106
+ # Make it a bit more interesting.
107
+ @vars[0].must > @vars[3] + 1
108
+
109
+ @types = [:int_enum, :int_enum]
110
+ @invoke = lambda do |receiver, int_enum, hash|
111
+ receiver.sorted hash.update(:order => int_enum)
112
+ @model.solve!
113
+ end
114
+ @expect = lambda do |var1, var2, opts, reif_var|
115
+ Gecode::Raw.should_receive(:sorted).once.with(
116
+ an_instance_of(Gecode::Raw::Space),
117
+ var1, an_instance_of(Gecode::Raw::IntVarArray), var2,
118
+ *opts)
119
+ end
120
+ end
121
+
122
+ it 'should constraint variables to be sorted with the specified indices' do
123
+ @vars.must_be.sorted(:order => @indices)
124
+ @model.solve!
125
+ sorted_values = @vars.values.sort
126
+ expected_indices = @vars.map{ |v| sorted_values.index(v.value) }
127
+ @indices.values.should == expected_indices
128
+ end
129
+
130
+ it_should_behave_like 'non-reifiable constraint'
131
+ it_should_behave_like 'non-negatable constraint'
132
+ end
133
+
134
+ describe Gecode::IntEnum::Sort, ' (with :order and :as)' do
135
+ before do
136
+ @model = SortSampleProblem.new
137
+ @vars = @model.vars
138
+ @sorted = @model.sorted
139
+ @indices = @model.indices
140
+
141
+ # Make it a bit more interesting.
142
+ @vars[0].must > @vars[3] + 1
143
+
144
+ @types = [:int_enum, :int_enum, :int_enum]
145
+ @invoke = lambda do |receiver, int_enum1, int_enum2, hash|
146
+ receiver.sorted hash.update(:as => int_enum1, :order => int_enum2)
147
+ @model.solve!
148
+ end
149
+ @expect = lambda do |var1, var2, var3, opts, reif_var|
150
+ Gecode::Raw.should_receive(:sorted).once.with(
151
+ an_instance_of(Gecode::Raw::Space),
152
+ var1, var2, var3, *opts)
153
+ end
154
+ end
155
+
156
+ it 'should constraint variables to be sorted with the specified indices' do
157
+ @vars.must_be.sorted(:as => @sorted, :order => @indices)
158
+ @model.solve!
159
+ sorted_values = @sorted.values
160
+ sorted_values.should == sorted_values.sort
161
+ expected_indices = @vars.map{ |v| sorted_values.index(v.value) }
162
+ @indices.values.should == expected_indices
163
+ end
164
+
165
+ it_should_behave_like 'non-reifiable constraint'
166
+ it_should_behave_like 'non-negatable constraint'
167
+ end
@@ -0,0 +1,264 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe 'operand', :shared => true do
4
+ it 'should not shadow method missing' do
5
+ lambda do
6
+ @operand.does_not_exist
7
+ end.should raise_error(NoMethodError)
8
+ end
9
+ end
10
+
11
+ describe 'variable operand', :shared => true do
12
+ it 'should fall back to the underlying variable' do
13
+ lambda do
14
+ @operand.assigned?
15
+ end.should_not raise_error
16
+ end
17
+
18
+ it_should_behave_like 'operand'
19
+ end
20
+
21
+ describe 'enum operand', :shared => true do
22
+ it 'should fall back to the underlying enum' do
23
+ lambda do
24
+ @operand[0]
25
+ end.should_not raise_error
26
+ end
27
+
28
+ it_should_behave_like 'operand'
29
+ end
30
+
31
+ describe Gecode::Operand do
32
+ before do
33
+ model = Gecode::Model.new
34
+ @operand = Object.new
35
+ class <<@operand
36
+ include Gecode::Operand
37
+ end
38
+ end
39
+
40
+ it 'should raise error if #model is not defined' do
41
+ lambda do
42
+ @operand.model
43
+ end.should raise_error(NotImplementedError)
44
+ end
45
+
46
+ it 'should raise error if #construct_receiver is not defined' do
47
+ lambda do
48
+ @operand.must
49
+ end.should raise_error(NotImplementedError)
50
+ end
51
+ end
52
+
53
+ describe Gecode::Int::IntOperand do
54
+ before do
55
+ model = Gecode::Model.new
56
+ @operand, _ = general_int_operand(model)
57
+ end
58
+
59
+ it_should_behave_like 'variable operand'
60
+ end
61
+
62
+ describe Gecode::Int::ShortCircuitEqualityOperand, ' (not subclassed)' do
63
+ before do
64
+ @model = Gecode::Model.new
65
+ @operand = Gecode::Int::ShortCircuitEqualityOperand.new(@model)
66
+ end
67
+
68
+ it 'should raise error if #constrain_equal is called' do
69
+ lambda do
70
+ @operand.to_int_var
71
+ @model.solve!
72
+ end.should raise_error(NotImplementedError)
73
+ end
74
+ end
75
+
76
+ describe Gecode::Int::ShortCircuitRelationsOperand, ' (not subclassed)' do
77
+ before do
78
+ @model = Gecode::Model.new
79
+ @operand = Gecode::Int::ShortCircuitRelationsOperand.new(@model)
80
+ end
81
+
82
+ it 'should raise error if #constrain_equal is called' do
83
+ lambda do
84
+ @operand.to_int_var
85
+ @model.solve!
86
+ end.should raise_error(NotImplementedError)
87
+ end
88
+ end
89
+
90
+ describe Gecode::IntEnum::IntEnumOperand do
91
+ before do
92
+ model = Gecode::Model.new
93
+ @operand, _ = general_int_enum_operand(model)
94
+ end
95
+
96
+ it_should_behave_like 'enum operand'
97
+ end
98
+
99
+ describe Gecode::Bool::BoolOperand do
100
+ before do
101
+ model = Gecode::Model.new
102
+ @operand, _ = general_bool_operand(model)
103
+ end
104
+
105
+ it_should_behave_like 'variable operand'
106
+ end
107
+
108
+ describe Gecode::Bool::ShortCircuitEqualityOperand, ' (not subclassed)' do
109
+ before do
110
+ @model = Gecode::Model.new
111
+ @operand = Gecode::Bool::ShortCircuitEqualityOperand.new(@model)
112
+ end
113
+
114
+ it 'should raise error if #constrain_equal is called' do
115
+ lambda do
116
+ @operand.to_bool_var
117
+ @model.solve!
118
+ end.should raise_error(NotImplementedError)
119
+ end
120
+ end
121
+
122
+ describe Gecode::BoolEnum::BoolEnumOperand do
123
+ before do
124
+ model = Gecode::Model.new
125
+ @operand, _ = general_bool_enum_operand(model)
126
+ end
127
+
128
+ it_should_behave_like 'enum operand'
129
+ end
130
+
131
+ describe Gecode::Set::SetOperand do
132
+ before do
133
+ model = Gecode::Model.new
134
+ @operand, _ = general_set_operand(model)
135
+ end
136
+
137
+ it_should_behave_like 'variable operand'
138
+ end
139
+
140
+ describe Gecode::Set::ShortCircuitEqualityOperand, ' (not subclassed)' do
141
+ before do
142
+ @model = Gecode::Model.new
143
+ @operand = Gecode::Set::ShortCircuitEqualityOperand.new(@model)
144
+ end
145
+
146
+ it 'should raise error if #constrain_equal is called' do
147
+ lambda do
148
+ @operand.to_set_var
149
+ @model.solve!
150
+ end.should raise_error(NotImplementedError)
151
+ end
152
+ end
153
+
154
+ describe Gecode::Set::ShortCircuitRelationsOperand, ' (not subclassed)' do
155
+ before do
156
+ @model = Gecode::Model.new
157
+ @operand = Gecode::Set::ShortCircuitRelationsOperand.new(@model)
158
+ end
159
+
160
+ it 'should raise error if #constrain_equal is called' do
161
+ lambda do
162
+ @operand.to_set_var
163
+ @model.solve!
164
+ end.should raise_error(NotImplementedError)
165
+ end
166
+ end
167
+
168
+ describe Gecode::SelectedSet::SelectedSetOperand do
169
+ before do
170
+ model = Gecode::Model.new
171
+ @operand, ops = general_selected_set_operand(model)
172
+ @enum, @set = ops
173
+ end
174
+
175
+ it 'should raise error if set enum operand is not given' do
176
+ lambda do
177
+ Gecode::SelectedSet::SelectedSetOperand.new(:foo, @set)
178
+ end.should raise_error(TypeError)
179
+ end
180
+
181
+ it 'should raise error if set operand is not given' do
182
+ lambda do
183
+ Gecode::SelectedSet::SelectedSetOperand.new(@enum, :foo)
184
+ end.should raise_error(TypeError)
185
+ end
186
+
187
+ it_should_behave_like 'operand'
188
+ end
189
+
190
+ describe Gecode::SetElements::SetElementsOperand do
191
+ before do
192
+ model = Gecode::Model.new
193
+ @operand, @set = general_set_elements_operand(model)
194
+ end
195
+
196
+ it 'should raise error if set operand is not given' do
197
+ lambda do
198
+ Gecode::SetElements::SetElementsOperand.new(:foo)
199
+ end.should raise_error(TypeError)
200
+ end
201
+
202
+ it_should_behave_like 'operand'
203
+ end
204
+
205
+ describe Gecode::SetEnum::SetEnumOperand do
206
+ before do
207
+ model = Gecode::Model.new
208
+ @operand, _ = general_set_enum_operand(model)
209
+ end
210
+
211
+ it_should_behave_like 'enum operand'
212
+ end
213
+
214
+ describe Gecode::FixnumEnum::FixnumEnumOperand do
215
+ before do
216
+ model = Gecode::Model.new
217
+ @operand, _ = general_fixnum_enum_operand(model)
218
+ end
219
+
220
+ it 'should raise error if constraint receiver is called' do
221
+ lambda do
222
+ @operand.must
223
+ end.should raise_error(NotImplementedError)
224
+ end
225
+
226
+ it_should_behave_like 'enum operand'
227
+ end
228
+
229
+ # High level sanity check.
230
+ describe 'operand combination' do
231
+ it 'should allow placing constraints on complicated combinations of operands' do
232
+ model = Gecode::Model.new
233
+ sets = model.set_var_array(2, [], 0..9)
234
+ set1, set2 = sets
235
+ (set1.size + set2.size).must == 5
236
+ set1.size.must > 1
237
+ set2.size.must > 1
238
+ model.branch_on sets
239
+
240
+ model.solve!
241
+
242
+ (set1.value.size + set2.value.size).should == 5
243
+ set1.value.size.should > 1
244
+ set2.value.size.should > 1
245
+ end
246
+
247
+ it 'should allow placing constraints on complicated combinations of operands (2)' do
248
+ model = Gecode::Model.new
249
+ sets = model.set_var_array(3, [], 0..9)
250
+ set1, set2, set3 = sets
251
+ (set1.size + set2.size).must == (set3.size - set1.max)
252
+ set3.size.must > 3
253
+ set2.size.must < 3
254
+ set1.size.must > 0
255
+ model.branch_on sets
256
+
257
+ model.solve!
258
+
259
+ (set1.value.size + set2.value.size).should == (set3.value.size - set1.value.max)
260
+ set3.value.size.should > 3
261
+ set2.value.size.should < 3
262
+ set1.value.size.should > 0
263
+ end
264
+ end