gecoder 0.7.0 → 0.7.1

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 (46) hide show
  1. data/CHANGES +6 -0
  2. data/README +1 -1
  3. data/example/square_tiling.rb +84 -0
  4. data/example/sudoku-set.rb +107 -0
  5. data/example/sudoku.rb +2 -6
  6. data/lib/gecoder/bindings.rb +1 -1
  7. data/lib/gecoder/bindings/bindings.rb +20 -0
  8. data/lib/gecoder/interface/binding_changes.rb +2 -2
  9. data/lib/gecoder/interface/branch.rb +50 -51
  10. data/lib/gecoder/interface/constraints.rb +10 -10
  11. data/lib/gecoder/interface/constraints/bool/boolean.rb +79 -5
  12. data/lib/gecoder/interface/constraints/bool/linear.rb +29 -0
  13. data/lib/gecoder/interface/constraints/bool_enum/boolean.rb +34 -4
  14. data/lib/gecoder/interface/constraints/bool_var_constraints.rb +14 -9
  15. data/lib/gecoder/interface/constraints/int/arithmetic.rb +26 -8
  16. data/lib/gecoder/interface/constraints/int/domain.rb +30 -3
  17. data/lib/gecoder/interface/constraints/int/linear.rb +82 -16
  18. data/lib/gecoder/interface/constraints/int_enum/arithmetic.rb +31 -3
  19. data/lib/gecoder/interface/constraints/int_enum/channel.rb +63 -3
  20. data/lib/gecoder/interface/constraints/int_enum/count.rb +20 -3
  21. data/lib/gecoder/interface/constraints/int_enum/distinct.rb +22 -2
  22. data/lib/gecoder/interface/constraints/int_enum/element.rb +23 -4
  23. data/lib/gecoder/interface/constraints/int_enum/equality.rb +9 -2
  24. data/lib/gecoder/interface/constraints/int_enum/sort.rb +28 -3
  25. data/lib/gecoder/interface/constraints/int_enum_constraints.rb +1 -1
  26. data/lib/gecoder/interface/constraints/int_var_constraints.rb +13 -8
  27. data/lib/gecoder/interface/constraints/set/cardinality.rb +27 -8
  28. data/lib/gecoder/interface/constraints/set/connection.rb +72 -6
  29. data/lib/gecoder/interface/constraints/set/domain.rb +46 -3
  30. data/lib/gecoder/interface/constraints/set/operation.rb +35 -4
  31. data/lib/gecoder/interface/constraints/set/relation.rb +59 -6
  32. data/lib/gecoder/interface/constraints/set_enum/distinct.rb +22 -3
  33. data/lib/gecoder/interface/constraints/set_enum/operation.rb +26 -2
  34. data/lib/gecoder/interface/constraints/set_enum/selection.rb +110 -36
  35. data/lib/gecoder/interface/constraints/set_var_constraints.rb +11 -7
  36. data/lib/gecoder/interface/model.rb +6 -6
  37. data/lib/gecoder/interface/search.rb +6 -6
  38. data/lib/gecoder/interface/variables.rb +56 -12
  39. data/lib/gecoder/version.rb +1 -1
  40. data/specs/constraints/linear.rb +167 -1
  41. data/specs/constraints/set_domain.rb +6 -0
  42. data/tasks/distribution.rake +25 -3
  43. data/tasks/website.rake +5 -12
  44. metadata +10 -4
  45. data/vendor/rust/configure.rb +0 -6
  46. data/vendor/rust/out.rb +0 -627
@@ -15,11 +15,11 @@ module Gecode
15
15
  # (but not enumerations).
16
16
  module Constraints::Set
17
17
  # An expression with a set as left hand side.
18
- class Expression < Gecode::Constraints::Expression
18
+ class Expression < Gecode::Constraints::Expression #:nodoc:
19
19
  end
20
20
 
21
21
  # Utility methods for sets.
22
- module Util
22
+ module Util #:nodoc:
23
23
  module_function
24
24
  def decode_options(options)
25
25
  if options.has_key? :strength
@@ -32,7 +32,7 @@ module Gecode
32
32
 
33
33
  # A composite expression which is an set expression with a left hand side
34
34
  # resulting from a previous constraint.
35
- class CompositeExpression < Gecode::Constraints::CompositeExpression
35
+ class CompositeExpression < Gecode::Constraints::CompositeExpression #:nodoc:
36
36
  # The block given should take three parameters. The first is the variable
37
37
  # that should be the left hand side, if it's nil then a new one should be
38
38
  # created. The second is the has of parameters. The block should return
@@ -45,14 +45,18 @@ module Gecode
45
45
 
46
46
  # Describes a stub that produces a set variable, which can then be used with
47
47
  # the normal set variable constraints. An example of a set composite
48
- # constraints would be set selection.
48
+ # constraints would be set selection constraint.
49
49
  #
50
50
  # sets[int_var].must_be.subset_of(another_set)
51
51
  #
52
- # "sets[int_var]" produces a bool variable which the constraint
53
- # ".must_be.subset_of(another_set)" is then applied to.In the above case
54
- # two constraints (and one temporary variable) are required, but in the
52
+ # <tt>sets[int_var]</tt> produces a set variable which the constraint
53
+ # <tt>.must_be.subset_of(another_set)</tt> is then applied to.In the above
54
+ # case two constraints (and one temporary variable) are required, but in the
55
55
  # case of equality only one constraint is required.
56
+ #
57
+ # Whether a constraint involving a reification stub supports negation and
58
+ # reification depends on the constraint on the right hand side (none
59
+ # support the strength option as no set constraints do).
56
60
  class CompositeStub < Gecode::Constraints::CompositeStub
57
61
  def initialize(model, params)
58
62
  super(CompositeExpression, model, params)
@@ -120,7 +120,7 @@ module Gecode
120
120
  #
121
121
  # The space returned by this method should never be stored, it should be
122
122
  # rerequested from the model every time that it's needed.
123
- def active_space
123
+ def active_space #:nodoc:
124
124
  unless @allow_space_access
125
125
  raise 'Space access is restricted and the permission to access the ' +
126
126
  'space has not been given.'
@@ -130,7 +130,7 @@ module Gecode
130
130
 
131
131
  # Adds the specified constraint to the model. Returns the newly added
132
132
  # constraint.
133
- def add_constraint(constraint)
133
+ def add_constraint(constraint) #:nodoc:
134
134
  add_interaction do
135
135
  constraint.post
136
136
  end
@@ -139,7 +139,7 @@ module Gecode
139
139
 
140
140
  # Adds a block containing something that interacts with Gecode to a queue
141
141
  # where it is potentially executed.
142
- def add_interaction(&block)
142
+ def add_interaction(&block) #:nodoc:
143
143
  gecode_interaction_queue << block
144
144
  end
145
145
 
@@ -149,7 +149,7 @@ module Gecode
149
149
  # the block ends.
150
150
  #
151
151
  # Returns the result of the block.
152
- def allow_space_access(&block)
152
+ def allow_space_access(&block) #:nodoc:
153
153
  # We store the old value so that nested calls don't become a problem, i.e.
154
154
  # access is allowed as long as one call to this method is still on the
155
155
  # stack.
@@ -162,7 +162,7 @@ module Gecode
162
162
 
163
163
  # Starts tracking a variable that depends on the space. All variables
164
164
  # created should call this method for their respective models.
165
- def track_variable(variable)
165
+ def track_variable(variable) #:nodoc:
166
166
  (@variables ||= []) << variable
167
167
  end
168
168
 
@@ -170,7 +170,7 @@ module Gecode
170
170
 
171
171
  # Gets a queue of objects that can be posted to the model's active_space
172
172
  # (by calling their post method).
173
- def gecode_interaction_queue
173
+ def gecode_interaction_queue #:nodoc:
174
174
  @gecode_interaction_queue ||= []
175
175
  end
176
176
 
@@ -43,9 +43,9 @@ module Gecode
43
43
  # (accessible from the model) to be as low as possible then one should write
44
44
  # the following.
45
45
  #
46
- # model.optimize! do |model, best_so_far|
47
- # model.price.must < best_so_far.price.val
48
- # end
46
+ # model.optimize! do |model, best_so_far|
47
+ # model.price.must < best_so_far.price.val
48
+ # end
49
49
  #
50
50
  # Returns nil if there is no solution.
51
51
  def optimize!(&block)
@@ -80,14 +80,14 @@ module Gecode
80
80
  return self
81
81
  end
82
82
 
83
- class <<self
83
+ class <<self
84
84
  # Sets the proc that should be used to handle constrain requests.
85
- def constrain_proc=(proc)
85
+ def constrain_proc=(proc) #:nodoc:
86
86
  @constrain_proc = proc
87
87
  end
88
88
 
89
89
  # Called by spaces when they want to constrain as part of BAB-search.
90
- def constrain(home, best)
90
+ def constrain(home, best) #:nodoc:
91
91
  if @constrain_proc.nil?
92
92
  raise NotImplementedError, 'Constrain method not implemented.'
93
93
  else
@@ -1,6 +1,7 @@
1
1
  module Gecode
2
- # An variable that is bound to a model, but not to a particular space.
3
- class FreeVarBase
2
+ # Describes a variable that is bound to a model, but not to a particular
3
+ # space.
4
+ class FreeVarBase #:nodoc:
4
5
  attr_accessor :model
5
6
 
6
7
  # Creates an int variable with the specified index.
@@ -81,26 +82,44 @@ module Gecode
81
82
  return clazz
82
83
  end
83
84
 
84
- # Int variables.
85
85
  FreeIntVar = FreeVar(Gecode::Raw::IntVar, :int_var)
86
+ # Describes an integer variable. Each integer variable has a domain of several
87
+ # integers which represent the possible values that the variable may take.
88
+ # An integer variable is said to be assigned once the domain only contains a
89
+ # single element, at which point #value can be used to retrieve the value.
86
90
  class FreeIntVar
91
+ # Gets the minimum value still in the domain of the variable.
87
92
  delegate :min
93
+ # Gets the maximum value still in the domain of the variable.
88
94
  delegate :max
95
+ # Gets the number of elements still in the domain of the variable.
89
96
  delegate :size
97
+ # Gets the width of the variable's domain, i.e. the distance between the
98
+ # maximum and minimum values.
90
99
  delegate :width
100
+ # Gets the degree of the variable. The degree is the number of constraints
101
+ # that are affected by the variable. So if the variable is used in two
102
+ # constraints then the value will be 2.
91
103
  delegate :degree
104
+ # Checks whether the domain is a range, i.e. doesn't contain any holes.
92
105
  delegate :range?, :range
106
+ # Checks whether the variable has been assigned, i.e. its domain only
107
+ # contains one element.
93
108
  delegate :assigned?, :assigned
109
+ # Checks whether a specified integer is in the variable's domain.
94
110
  delegate :include?, :in
95
111
 
96
- # Gets the value of the assigned integer variable (a fixnum).
112
+ # Gets the value of the assigned integer variable (a Fixnum). The variable
113
+ # must be assigned, if it isn't then a RuntimeError is raised.
97
114
  def value
98
115
  raise 'No value is assigned.' unless assigned?
99
116
  send_bound(:val)
100
117
  end
101
118
 
119
+ private
120
+
102
121
  # Returns a string representation of the the range of the variable's domain.
103
- def domain
122
+ def domain #:nodoc:
104
123
  if assigned?
105
124
  "range: #{value.to_s}"
106
125
  else
@@ -109,17 +128,22 @@ module Gecode
109
128
  end
110
129
  end
111
130
 
112
- # Bool variables.
113
131
  FreeBoolVar = FreeVar(Gecode::Raw::BoolVar, :bool_var)
132
+ # Describes a boolean variable. A boolean variable can be either true or
133
+ # false.
114
134
  class FreeBoolVar
135
+ # Checks whether the variable has been assigned.
115
136
  delegate :assigned?, :assigned
116
137
 
117
- # Gets the values in the assigned boolean variable (true or false).
138
+ # Gets the values in the assigned boolean variable (true or false). The
139
+ # variable must be assigned, if it isn't then a RuntimeError is raised.
118
140
  def value
119
141
  raise 'No value is assigned.' unless assigned?
120
142
  send_bound(:val) == 1
121
143
  end
122
144
 
145
+ private
146
+
123
147
  # Returns a string representation of the the variable's domain.
124
148
  def domain
125
149
  if assigned?
@@ -130,12 +154,26 @@ module Gecode
130
154
  end
131
155
  end
132
156
 
133
- # Set variables.
134
157
  FreeSetVar = FreeVar(Gecode::Raw::SetVar, :set_var)
158
+ # Describes a set variable.
159
+ #
160
+ # A set variable's domain, i.e. possible values that it can take, are
161
+ # represented with a greatest lower bound (GLB) and a least upper bound (LUB).
162
+ # The set variable may then take any set value S such that S is a subset of
163
+ # the least upper bound and the greatest lower bound is a subset of S.
164
+ #
165
+ # If for instance the set has a greatest lower bound {1} and least upper bound
166
+ # {1,3,5} then the assigned set may be any of the following four sets: {1},
167
+ # {1,3}, {1,5}, {1,3,5}.
168
+ #
169
+ # The domain of a set variable may also specify the cardinality of the set,
170
+ # i.e. the number of elements that the set may contains.
135
171
  class FreeSetVar
172
+ # Checks whether the variable has been assigned.
136
173
  delegate :assigned?, :assigned
137
174
 
138
- # Gets all the elements located in the greatest lower bound of the set.
175
+ # Gets all the elements located in the greatest lower bound of the set (an
176
+ # Enumerable).
139
177
  def lower_bound
140
178
  min = send_bound(:glbMin)
141
179
  max = send_bound(:glbMax)
@@ -144,7 +182,8 @@ module Gecode
144
182
  end
145
183
  end
146
184
 
147
- # Gets all the elements located in the least upper bound of the set.
185
+ # Gets all the elements located in the least upper bound of the set (an
186
+ # Enumerable).
148
187
  def upper_bound
149
188
  min = send_bound(:lubMin)
150
189
  max = send_bound(:lubMax)
@@ -164,6 +203,8 @@ module Gecode
164
203
  send_bound(:cardMin)..send_bound(:cardMax)
165
204
  end
166
205
 
206
+ private
207
+
167
208
  # Returns a string representation of the the variable's domain.
168
209
  def domain
169
210
  if assigned?
@@ -175,9 +216,12 @@ module Gecode
175
216
  end
176
217
 
177
218
  # Describes an immutable view of an enumerable.
178
- class EnumerableView
219
+ class EnumerableView #:nodoc:
220
+ # Gets the number of elements in the view.
179
221
  attr :size
222
+ # Gets the minimum element of the view.
180
223
  attr :min
224
+ # Gets the maximum element of the view.
181
225
  attr :max
182
226
  include Enumerable
183
227
 
@@ -191,7 +235,7 @@ module Gecode
191
235
  @enum = nil
192
236
  end
193
237
 
194
- # Used by Enumerable.
238
+ # Iterates over every element in the view.
195
239
  def each(&block)
196
240
  enum.each(&block)
197
241
  end
@@ -1,4 +1,4 @@
1
1
  module GecodeR
2
2
  # A string representation of the Gecode/R version.
3
- VERSION = '0.7.0'
3
+ VERSION = '0.7.1'
4
4
  end
@@ -14,6 +14,31 @@ class LinearSampleProblem < Gecode::Model
14
14
  end
15
15
  end
16
16
 
17
+ class BoolLinearSampleProblem < Gecode::Model
18
+ attr :x
19
+ attr :y
20
+ attr :z
21
+
22
+ def initialize
23
+ @x = self.bool_var
24
+ @y = self.bool_var
25
+ @z = self.bool_var
26
+ branch_on wrap_enum([@x, @y, @z])
27
+ end
28
+ end
29
+
30
+ class TrueClass
31
+ def to_i
32
+ 1
33
+ end
34
+ end
35
+
36
+ class FalseClass
37
+ def to_i
38
+ 0
39
+ end
40
+ end
41
+
17
42
  describe Gecode::Constraints::Int::Linear do
18
43
  before do
19
44
  @x_dom = 0..2
@@ -163,4 +188,145 @@ describe Gecode::Constraints::Int::Linear do
163
188
  end
164
189
 
165
190
  it_should_behave_like 'constraint with options'
166
- end
191
+ end
192
+
193
+ describe Gecode::Constraints::Int::Linear, '(with booleans)' do
194
+ before do
195
+ @model = BoolLinearSampleProblem.new
196
+ @x = @model.x
197
+ @y = @model.y
198
+ @z = @model.z
199
+
200
+ # For constraint option spec.
201
+ @invoke_options = lambda do |hash|
202
+ (@x + @y).must_be.greater_than(@z, hash)
203
+ @model.solve!
204
+ end
205
+ @expect_options = lambda do |strength, reif_var|
206
+ # TODO: this is hard to spec from this level.
207
+ end
208
+ end
209
+
210
+ it 'should handle addition with a variable' do
211
+ (@x + @y).must == 0
212
+ sol = @model.solve!
213
+ x = sol.x.value.to_i
214
+ y = sol.y.value.to_i
215
+ (x + y).should be_zero
216
+ end
217
+
218
+ it 'should handle addition with multiple variables' do
219
+ (@x + @y + @z).must == 0
220
+ sol = @model.solve!
221
+ x = sol.x.value.to_i
222
+ y = sol.y.value.to_i
223
+ z = sol.z.value.to_i
224
+ (x + y + z).should be_zero
225
+ end
226
+
227
+ it 'should handle subtraction with a variable' do
228
+ (@x - @y).must == 0
229
+ sol = @model.solve!
230
+ x = sol.x.value.to_i
231
+ y = sol.y.value.to_i
232
+ (x - y).should be_zero
233
+ end
234
+
235
+ it 'should handle non-zero constants as right hand side' do
236
+ (@x + @y).must == 1
237
+ sol = @model.solve!
238
+ x = sol.x.value.to_i
239
+ y = sol.y.value.to_i
240
+ (x + y).should equal(1)
241
+ end
242
+
243
+ it 'should handle variables as right hand side' do
244
+ (@x + @y).must == @z
245
+ sol = @model.solve!
246
+ x = sol.x.value.to_i
247
+ y = sol.y.value.to_i
248
+ z = sol.z.value.to_i
249
+ (x + y).should equal(z)
250
+ end
251
+
252
+ it 'should handle linear expressions as right hand side' do
253
+ (@x + @y).must == @z + @y
254
+ sol = @model.solve!
255
+ x = sol.x.value.to_i
256
+ y = sol.y.value.to_i
257
+ z = sol.z.value.to_i
258
+ (x + y).should equal(z + y)
259
+ end
260
+
261
+ it 'should raise error on invalid right hand sides' do
262
+ lambda{ ((@x + @y).must == 'z') }.should raise_error(TypeError)
263
+ end
264
+
265
+ it 'should handle coefficients other than 1' do
266
+ (@x * 2 + @y).must == 0
267
+ sol = @model.solve!
268
+ x = sol.x.value.to_i
269
+ y = sol.y.value.to_i
270
+ (2*x + y).should equal(0)
271
+ end
272
+
273
+ it 'should handle addition with constants' do
274
+ (@y + 1).must == 1
275
+ sol = @model.solve!
276
+ y = sol.y.value.to_i
277
+ (y + 1).should equal(1)
278
+ end
279
+
280
+ it 'should handle subtraction with a constant' do
281
+ (@x - 1).must == 0
282
+ sol = @model.solve!
283
+ x = sol.x.value.to_i
284
+ (x - 1).should be_zero
285
+ end
286
+
287
+ it 'should handle parenthesis' do
288
+ (@x - (@y + @z)).must == 1
289
+ sol = @model.solve!
290
+ x = sol.x.value.to_i
291
+ y = sol.y.value.to_i
292
+ z = sol.z.value.to_i
293
+ (x - (y + z)).should equal(1)
294
+ end
295
+
296
+ it 'should handle multiplication of parenthesis' do
297
+ (((@x + @y*10)*10 + @z)*10).must == 0
298
+ sol = @model.solve!
299
+ x = sol.x.value.to_i
300
+ y = sol.y.value.to_i
301
+ z = sol.z.value.to_i
302
+ (((x + y*10)*10 + z)*10).should equal(0)
303
+ end
304
+
305
+ relations = ['>', '>=', '<', '<=', '==']
306
+
307
+ relations.each do |relation|
308
+ it "should handle #{relation} with constant integers" do
309
+ (@x + @y).must.send(relation, 1)
310
+ sol = @model.solve!
311
+ sol.should_not be_nil
312
+ (sol.x.value.to_i + sol.y.value.to_i).should.send(relation, 1)
313
+ end
314
+ end
315
+
316
+ relations.each do |relation|
317
+ it "should handle negated #{relation} with constant integers" do
318
+ (@x + @y).must_not.send(relation, 1)
319
+ sol = @model.solve!
320
+ sol.should_not be_nil
321
+ (sol.x.value.to_i + sol.y.value.to_i).should_not.send(relation, 1)
322
+ end
323
+ end
324
+
325
+ it 'should not interfere with other defined multiplication methods' do
326
+ (@x * :foo).should be_nil
327
+ end
328
+
329
+ it_should_behave_like 'constraint with options'
330
+ end
331
+
332
+