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
@@ -1,4 +1,5 @@
1
1
  require File.dirname(__FILE__) + '/spec_helper'
2
+ require File.dirname(__FILE__) + '/constraints/property_helper'
2
3
 
3
4
  describe 'non-empty int variable', :shared => true do
4
5
  it 'should have min equal to the lower domain bound' do
@@ -35,18 +36,22 @@ describe 'non-empty int variable', :shared => true do
35
36
  it 'should have a zero degree' do
36
37
  @var.degree.should be_zero
37
38
  end
39
+
40
+ it 'should return the correct domain through #domain' do
41
+ @var.domain.to_a.should == @domain.to_a
42
+ end
43
+
44
+ it_should_behave_like 'int var operand'
38
45
  end
39
46
 
40
- describe Gecode::FreeIntVar, ' (with range domain of size > 1)' do
47
+ describe Gecode::IntVar, ' (with range domain of size > 1)' do
41
48
  before do
42
49
  @range = -4..3
43
50
  @domain = @range.to_a
44
- model = Gecode::Model.new
45
- @var = model.int_var(@range)
51
+ @model = Gecode::Model.new
52
+ @operand = @var = @model.int_var(@range)
46
53
  end
47
54
 
48
- it_should_behave_like 'non-empty int variable'
49
-
50
55
  it 'should not be assigned' do
51
56
  @var.should_not be_assigned
52
57
  end
@@ -58,28 +63,28 @@ describe Gecode::FreeIntVar, ' (with range domain of size > 1)' do
58
63
  it 'should raise error when trying to access assigned value' do
59
64
  lambda{ @var.value }.should raise_error(RuntimeError)
60
65
  end
66
+
67
+ it_should_behave_like 'non-empty int variable'
61
68
  end
62
69
 
63
- describe Gecode::FreeIntVar, ' (defined with three-dot range)' do
70
+ describe Gecode::IntVar, ' (defined with three-dot range)' do
64
71
  before do
65
72
  @range = -4...3
66
73
  @domain = @range.to_a
67
- model = Gecode::Model.new
68
- @var = model.int_var(@range)
74
+ @model = Gecode::Model.new
75
+ @operand = @var = @model.int_var(@range)
69
76
  end
70
77
 
71
78
  it_should_behave_like 'non-empty int variable'
72
79
  end
73
80
 
74
- describe Gecode::FreeIntVar, ' (with non-range domain of size > 1)' do
81
+ describe Gecode::IntVar, ' (with non-range domain of size > 1)' do
75
82
  before do
76
83
  @domain = [-3, -2, -1, 1]
77
- model = Gecode::Model.new
78
- @var = model.int_var(@domain)
84
+ @model = Gecode::Model.new
85
+ @operand = @var = @model.int_var(@domain)
79
86
  end
80
87
 
81
- it_should_behave_like 'non-empty int variable'
82
-
83
88
  it 'should not be assigned' do
84
89
  @var.should_not be_assigned
85
90
  end
@@ -91,17 +96,17 @@ describe Gecode::FreeIntVar, ' (with non-range domain of size > 1)' do
91
96
  it 'should not contain the domain\'s holes' do
92
97
  @var.should_not include(0)
93
98
  end
99
+
100
+ it_should_behave_like 'non-empty int variable'
94
101
  end
95
102
 
96
- describe Gecode::FreeIntVar, ' (with a domain of size 1)' do
103
+ describe Gecode::IntVar, ' (with a domain of size 1)' do
97
104
  before do
98
105
  @domain = [1]
99
- model = Gecode::Model.new
100
- @var = model.int_var(*@domain)
106
+ @model = Gecode::Model.new
107
+ @operand = @var = @model.int_var(*@domain)
101
108
  end
102
109
 
103
- it_should_behave_like 'non-empty int variable'
104
-
105
110
  it 'should be assigned' do
106
111
  @var.should be_assigned
107
112
  end
@@ -109,13 +114,15 @@ describe Gecode::FreeIntVar, ' (with a domain of size 1)' do
109
114
  it 'should be a range domain' do
110
115
  @var.should be_range
111
116
  end
117
+
118
+ it_should_behave_like 'non-empty int variable'
112
119
  end
113
120
 
114
- describe Gecode::FreeIntVar, ' (assigned)' do
121
+ describe Gecode::IntVar, ' (assigned)' do
115
122
  before do
116
123
  @domain = 1
117
- model = Gecode::Model.new
118
- @var = model.int_var(*@domain)
124
+ @model = Gecode::Model.new
125
+ @operand = @var = @model.int_var(*@domain)
119
126
  end
120
127
 
121
128
  it 'should be assigned' do
@@ -125,13 +132,19 @@ describe Gecode::FreeIntVar, ' (assigned)' do
125
132
  it 'should give the assigned number when inspecting' do
126
133
  @var.inspect.should include(" #{@domain[0]}>")
127
134
  end
135
+
136
+ it 'should return the correct domain through #domain' do
137
+ @var.domain.to_a.should == [@domain]
138
+ end
139
+
140
+ it_should_behave_like 'int var operand'
128
141
  end
129
142
 
130
- describe Gecode::FreeIntVar, ' (not assigned)' do
143
+ describe Gecode::IntVar, ' (not assigned)' do
131
144
  before do
132
145
  @domain = 1..2
133
- model = Gecode::Model.new
134
- @var = model.int_var(@domain)
146
+ @model = Gecode::Model.new
147
+ @operand = @var = @model.int_var(@domain)
135
148
  end
136
149
 
137
150
  it 'should not be assigned' do
@@ -141,4 +154,10 @@ describe Gecode::FreeIntVar, ' (not assigned)' do
141
154
  it 'should give the domain range when inspecting' do
142
155
  @var.inspect.should include(" #{@domain.first}..#{@domain.last}>")
143
156
  end
144
- end
157
+
158
+ it 'should return the correct domain through #domain' do
159
+ @var.domain.to_a.should == @domain.to_a
160
+ end
161
+
162
+ it_should_behave_like 'int var operand'
163
+ end
@@ -265,4 +265,61 @@ describe Gecode::Model, ' (space access restriction)' do
265
265
  end
266
266
  end.should_not raise_error(RuntimeError)
267
267
  end
268
- end
268
+ end
269
+
270
+ describe Gecode::Model, ' (accessible variable creation)' do
271
+ before do
272
+ @model = Class.new(Gecode::Model).new
273
+ end
274
+
275
+ it 'should allow creation of named variable using #foo_is_a' do
276
+ var = @model.int_var(17)
277
+ lambda{ @model.foo }.should raise_error(NoMethodError)
278
+ @model.instance_eval{ foo_is_a var }
279
+ lambda{ @model.foo }.should_not raise_error
280
+ @model.foo.should == var
281
+ end
282
+
283
+ it 'should allow creation of named variable using #foo_is_an' do
284
+ var = @model.int_var(17)
285
+ lambda{ @model.foo }.should raise_error(NoMethodError)
286
+ @model.instance_eval{ foo_is_an var }
287
+ lambda{ @model.foo }.should_not raise_error
288
+ @model.foo.should == var
289
+ end
290
+
291
+ it 'should only allow one argument to be given to #foo_is_a' do
292
+ lambda do
293
+ @model.instance_eval{ foo_is_a }
294
+ end.should raise_error(ArgumentError)
295
+ lambda do
296
+ @model.instance_eval{ foo_is_a bool_var, bool_var }
297
+ end.should raise_error(ArgumentError)
298
+ end
299
+
300
+ it 'should only define the variable in the current instance' do
301
+ klass = Class.new Gecode::Model
302
+ model_a = klass.new
303
+ model_b = klass.new
304
+
305
+ model_a.instance_eval{ bar_is_a bool_var }
306
+ lambda{ model_a.bar }.should_not raise_error
307
+ lambda{ model_b.bar }.should raise_error(NoMethodError)
308
+ end
309
+
310
+ it 'should raise error if a method would be overwritten' do
311
+ var = @model.int_var(17)
312
+ lambda{ @model.class }.should_not raise_error
313
+ lambda do
314
+ @model.instance_eval{ class_is_an var }
315
+ end.should raise_error(ArgumentError)
316
+ end
317
+
318
+ it 'should raise error if an instance variable would be overwritten' do
319
+ @model.instance_eval{ @foo = 17 }
320
+ var = @model.int_var(17)
321
+ lambda do
322
+ @model.instance_eval{ foo_is_a var }
323
+ end.should raise_error(ArgumentError)
324
+ end
325
+ end
@@ -0,0 +1,30 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe Gecode, ' (Model sugar)' do
4
+ it 'should provide #solve as sugar for constructing a model and running solve!' do
5
+ Gecode.solve do
6
+ numbers_is_an int_var_array(2, 0..5)
7
+ x, y = numbers
8
+ (x * y).must == 25
9
+ branch_on numbers
10
+ end.numbers.values.should == [5,5]
11
+ end
12
+
13
+ it 'should provide #maximize as sugar for constructing a model and running maximize!' do
14
+ Gecode.maximize :z do
15
+ z_is_an int_var
16
+ x, y = vars = int_var_array(2, 0..5)
17
+ (x*2 - y).must == z
18
+ branch_on vars
19
+ end.z.value.should equal(10)
20
+ end
21
+
22
+ it 'should provide #minimize as sugar for constructing a model and running minimize!' do
23
+ Gecode.minimize :z do
24
+ z_is_an int_var
25
+ x, y = vars = int_var_array(2, 0..5)
26
+ (x*2 - y).must == z
27
+ branch_on vars
28
+ end.z.value.should equal(-5)
29
+ end
30
+ end
@@ -201,16 +201,35 @@ describe Gecode::Model, ' (without solution)' do
201
201
  end
202
202
 
203
203
  it 'should return nil when calling #solution' do
204
- @model.var.must < 0
205
204
  @model.solution{ |s| 'test' }.should be_nil
206
205
  end
206
+
207
+ it 'should not yield anything to #each_solution' do
208
+ @model.each_solution{ |s| violated }
209
+ end
207
210
 
208
- it 'should return nil when calling #solve!' do
209
- @model.solve!.should be_nil
211
+ it 'should raise NoSolutionError when calling #solve!' do
212
+ lambda do
213
+ @model.solve!
214
+ end.should raise_error(Gecode::NoSolutionError)
210
215
  end
211
216
 
212
- it 'should return nil when calling #optimize!' do
213
- @model.optimize!{}.should be_nil
217
+ it 'should raise NoSolutionError when calling #optimize!' do
218
+ lambda do
219
+ @model.optimize!{}
220
+ end.should raise_error(Gecode::NoSolutionError)
221
+ end
222
+
223
+ it 'should raise NoSolutionError when calling #minimize!' do
224
+ lambda do
225
+ @model.optimize!{}
226
+ end.should raise_error(Gecode::NoSolutionError)
227
+ end
228
+
229
+ it 'should raise NoSolutionError when calling #maximize!' do
230
+ lambda do
231
+ @model.maximize!(:var)
232
+ end.should raise_error(Gecode::NoSolutionError)
214
233
  end
215
234
  end
216
235
 
@@ -0,0 +1,39 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe Gecode::SelectedSet::SelectedSetOperand do
4
+ before do
5
+ @model = Gecode::Model.new
6
+ set_enum = @model.set_var_array(5, [], 0..9)
7
+ set = @model.set_var([], 0..4)
8
+ @operand = Gecode::SelectedSet::SelectedSetOperand.new(
9
+ set_enum, set)
10
+ end
11
+
12
+ it 'should implement #model' do
13
+ @operand.model.should be_kind_of(Gecode::Model)
14
+ end
15
+
16
+ it 'should implement #to_selected_set' do
17
+ enum, set = @operand.to_selected_set
18
+ enum.should be_respond_to(:to_set_enum)
19
+ set.should be_respond_to(:to_set_var)
20
+ @model.solve!
21
+ set_var = set.to_set_var
22
+ ((set_var.lower_bound == []) &&
23
+ (set_var.upper_bound == Gecode::Model::LARGEST_SET_BOUND)).should_not(
24
+ be_true)
25
+ enum.each do |element|
26
+ set_var = element.to_set_var
27
+ ((set_var.lower_bound == []) &&
28
+ (set_var.upper_bound == Gecode::Model::LARGEST_SET_BOUND)).should_not(
29
+ be_true)
30
+ end
31
+ end
32
+
33
+ it 'should implement #must' do
34
+ receiver = @operand.must
35
+ receiver.should be_kind_of(
36
+ Gecode::SelectedSet::SelectedSetConstraintReceiver)
37
+ end
38
+ end
39
+
@@ -0,0 +1,34 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe Gecode::SelectedSet::SelectedSetOperand do
4
+ before do
5
+ @model = Gecode::Model.new
6
+ @set = @model.set_var([], 0..4)
7
+ @operand = Gecode::SetElements::SetElementsOperand.new(@set)
8
+ end
9
+
10
+ it 'should implement #model' do
11
+ @operand.model.should be_kind_of(Gecode::Model)
12
+ end
13
+
14
+ it 'should implement #to_set_elements' do
15
+ set = @operand.to_set_elements
16
+ set.should be_respond_to(:to_set_var)
17
+ @model.solve!
18
+ set_var = set.to_set_var
19
+ ((set_var.lower_bound == []) &&
20
+ (set_var.upper_bound == Gecode::Model::LARGEST_SET_BOUND)).should_not(
21
+ be_true)
22
+ end
23
+
24
+ it 'should implement #must' do
25
+ receiver = @operand.must
26
+ receiver.should be_kind_of(
27
+ Gecode::SetElements::SetElementsConstraintReceiver)
28
+ end
29
+
30
+ it 'should be produces by SetOperand#elements' do
31
+ @set.elements.should be_respond_to(:to_set_elements)
32
+ end
33
+ end
34
+
@@ -1,9 +1,9 @@
1
- require File.dirname(__FILE__) + '/spec_helper'
1
+ require File.dirname(__FILE__) + '/constraints/property_helper'
2
2
 
3
- describe Gecode::FreeSetVar, '(not assigned)' do
3
+ describe Gecode::SetVar, '(not assigned)' do
4
4
  before do
5
- model = Gecode::Model.new
6
- @var = model.set_var(1..3, 0..4)
5
+ @model = Gecode::Model.new
6
+ @operand = @var = @model.set_var(1..3, 0..4)
7
7
  end
8
8
 
9
9
  it 'should not be assigned' do
@@ -14,6 +14,11 @@ describe Gecode::FreeSetVar, '(not assigned)' do
14
14
  @var.inspect.should include('lub-range')
15
15
  @var.inspect.should include('glb-range')
16
16
  end
17
+
18
+ it 'should allow inspection even when the bounds are too large to display' do
19
+ var = @model.set_var
20
+ var.inspect.should include('too large')
21
+ end
17
22
 
18
23
  it 'should report the correct bounds' do
19
24
  @var.lower_bound.sort.to_a.should == (1..3).to_a
@@ -42,13 +47,15 @@ describe Gecode::FreeSetVar, '(not assigned)' do
42
47
  lower_bound.each{}
43
48
  end.should_not raise_error
44
49
  end
50
+
51
+ it_should_behave_like 'set var operand'
45
52
  end
46
53
 
47
- describe Gecode::FreeSetVar, '(assigned)' do
54
+ describe Gecode::SetVar, '(assigned)' do
48
55
  before do
49
- model = Gecode::Model.new
50
- @var = model.set_var(1, 1)
51
- model.solve!
56
+ @model = Gecode::Model.new
57
+ @operand = @var = @model.set_var(1, 1)
58
+ @model.solve!
52
59
  end
53
60
 
54
61
  it 'should be assigned' do
@@ -65,4 +72,11 @@ describe Gecode::FreeSetVar, '(assigned)' do
65
72
  @var.lower_bound.to_a.should == [1]
66
73
  @var.value.to_a.should == [1]
67
74
  end
75
+
76
+ it 'should allow inspection even when the bounds are too large to display' do
77
+ var = @model.set_var(0..10**4, 0..10**4)
78
+ var.inspect.should include('too large')
79
+ end
80
+
81
+ it_should_behave_like 'set var operand'
68
82
  end
@@ -5,16 +5,25 @@ require File.dirname(__FILE__) + '/../lib/gecoder'
5
5
  module CustomVarMatchers
6
6
  class HaveDomain
7
7
  def initialize(expected)
8
- @expected = expected.to_a
8
+ @expected = expected
9
9
  end
10
10
 
11
11
  def matches?(target)
12
12
  @target = target
13
- return false unless @target.size == @expected.size
14
- @expected.each do |element|
15
- return false unless @target.include? element
13
+ if @expected.kind_of? Range
14
+ last = @expected.end
15
+ last -= 1 if @expected.exclude_end?
16
+ return @target.range? && @expected.begin == @target.min &&
17
+ last == @target.max
18
+ else
19
+ @expected = @expected.to_a
20
+ return false unless @target.size == @expected.size
21
+ @expected.each do |element|
22
+ return false unless @target.include? element
23
+ end
24
+ return true
16
25
  end
17
- return true
26
+ return false
18
27
  end
19
28
 
20
29
  def failure_message
@@ -39,7 +48,9 @@ module CustomVarMatchers
39
48
 
40
49
  def matches?(target)
41
50
  @target = target
42
- return @target.lower_bound.to_a == @expected_glb &&
51
+ return @target.lower_bound.size == @expected_glb.size &&
52
+ @target.upper_bound.size == @expected_lub.size &&
53
+ @target.lower_bound.to_a == @expected_glb &&
43
54
  @target.upper_bound.to_a == @expected_lub
44
55
  end
45
56
 
@@ -63,3 +74,192 @@ end
63
74
  Spec::Runner.configure do |config|
64
75
  config.include(CustomVarMatchers)
65
76
  end
77
+
78
+
79
+ # Help methods for the GecodeR specs.
80
+ module GecodeR::Specs
81
+ module SetHelper
82
+ module_function
83
+
84
+ # Returns the arguments that should be used in a partial mock to expect the
85
+ # specified constant set (possibly an array of arguments).
86
+ def expect_constant_set(constant_set)
87
+ if constant_set.kind_of? Range
88
+ return constant_set.first, constant_set.last
89
+ elsif constant_set.kind_of? Fixnum
90
+ constant_set
91
+ else
92
+ an_instance_of(Gecode::Raw::IntSet)
93
+ end
94
+ end
95
+ end
96
+
97
+ module GeneralHelper
98
+ module_function
99
+
100
+ # Produces a base operand that can be used to mock specific types of
101
+ # operands.
102
+ def general_operand_base(model)
103
+ mock_op_class = Class.new
104
+ mock_op_class.class_eval do
105
+ attr :model
106
+
107
+ def bind
108
+ raise 'Bind should not be called directly for an operand.'
109
+ end
110
+ alias_method :bind_array, :bind
111
+ end
112
+ op = mock_op_class.new
113
+ op.instance_eval do
114
+ @model = model
115
+ end
116
+ return op
117
+ end
118
+
119
+ # Produces a general int operand. The method returns two objects:
120
+ # the operand itself and the variable it returns when #to_int_var
121
+ # is called.
122
+ def general_int_operand(model)
123
+ op = general_operand_base(model)
124
+
125
+ int_var = model.int_var
126
+ class <<op
127
+ include Gecode::Int::IntOperand
128
+ attr :model
129
+ end
130
+ op.stub!(:to_int_var).and_return int_var
131
+
132
+ return op, int_var
133
+ end
134
+
135
+ # Produces a general bool operand. The method returns two objects:
136
+ # the operand itself and the variable it returns when #to_bool_var
137
+ # is called.
138
+ def general_bool_operand(model)
139
+ op = general_operand_base(model)
140
+
141
+ bool_var = model.bool_var
142
+ class <<op
143
+ include Gecode::Bool::BoolOperand
144
+ attr :model
145
+ end
146
+ op.stub!(:to_bool_var).and_return bool_var
147
+
148
+ return op, bool_var
149
+ end
150
+
151
+ # Produces a general set operand. The method returns two objects:
152
+ # the operand itself and the variable it returns when #to_set_var
153
+ # is called.
154
+ def general_set_operand(model)
155
+ op = general_operand_base(model)
156
+
157
+ set_var = model.set_var
158
+ class <<op
159
+ include Gecode::Set::SetOperand
160
+ attr :model
161
+ end
162
+ op.stub!(:to_set_var).and_return set_var
163
+
164
+ return op, set_var
165
+ end
166
+
167
+ # Produces a general int enum operand. The method returns two objects:
168
+ # the operand itself and the variable it returns when #to_int_enum
169
+ # is called.
170
+ def general_int_enum_operand(model)
171
+ op = general_operand_base(model)
172
+
173
+ int_enum = model.int_var_array(5)
174
+ class <<op
175
+ include Gecode::IntEnum::IntEnumOperand
176
+ attr :model
177
+ end
178
+ op.stub!(:to_int_enum).and_return int_enum
179
+
180
+ return op, int_enum
181
+ end
182
+
183
+ # Produces a general bool enum operand. The method returns two objects:
184
+ # the operand itself and the variable it returns when #to_bool_enum
185
+ # is called.
186
+ def general_bool_enum_operand(model)
187
+ op = general_operand_base(model)
188
+
189
+ bool_enum = model.bool_var_array(5)
190
+ class <<op
191
+ include Gecode::BoolEnum::BoolEnumOperand
192
+ attr :model
193
+ end
194
+ op.stub!(:to_bool_enum).and_return bool_enum
195
+
196
+ return op, bool_enum
197
+ end
198
+
199
+ # Produces a general set enum operand. The method returns two objects:
200
+ # the operand itself and the variable it returns when #to_set_enum
201
+ # is called.
202
+ def general_set_enum_operand(model)
203
+ op = general_operand_base(model)
204
+
205
+ set_enum = model.set_var_array(5)
206
+ class <<op
207
+ include Gecode::SetEnum::SetEnumOperand
208
+ attr :model
209
+ end
210
+ op.stub!(:to_set_enum).and_return set_enum
211
+
212
+ return op, set_enum
213
+ end
214
+
215
+ # Produces a general selected set operand. The method returns two objects:
216
+ # the operand itself and the array of variables corresponding to the
217
+ # operands it returns when # #to_selected_set is called.
218
+ def general_selected_set_operand(model)
219
+ set_enum, set_enum_var = general_set_enum_operand(model)
220
+ set, set_var = general_set_operand(model)
221
+ op = Gecode::SelectedSet::SelectedSetOperand.new(
222
+ set_enum, set)
223
+ return op, [set_enum_var, set_var]
224
+ end
225
+
226
+ # Produces a general set elements operand. The method returns two
227
+ # objects: the operand itself and the set var corresponding to the
228
+ # operands it returns when # #to_selected_set is called.
229
+ def general_set_elements_operand(model)
230
+ set, set_var = general_set_operand(model)
231
+ op = Gecode::SetElements::SetElementsOperand.new(set)
232
+ return op, set_var
233
+ end
234
+
235
+ # Produces a general fixnum enum operand. The method returns two objects:
236
+ # the operand itself and the variable it returns when #to_fixnum_enum
237
+ # is called.
238
+ def general_fixnum_enum_operand(model)
239
+ op = general_operand_base(model)
240
+
241
+ fixnum_enum = model.wrap_enum([1, -4, 9, 4, 0])
242
+ class <<op
243
+ include Gecode::FixnumEnum::FixnumEnumOperand
244
+ attr :model
245
+ end
246
+ op.stub!(:to_fixnum_enum).and_return fixnum_enum
247
+
248
+ return op, fixnum_enum
249
+ end
250
+
251
+ # Produces an array of general operands of the specified types.
252
+ # Returns an array of operands and an array of their variables.
253
+ def produce_general_arguments(property_types)
254
+ operands = []
255
+ variables = []
256
+ property_types.each do |type|
257
+ op, var = eval "general_#{type}_operand(@model)"
258
+ operands << op
259
+ variables << var
260
+ end
261
+ return operands, variables
262
+ end
263
+ end
264
+ end
265
+ include GecodeR::Specs::GeneralHelper