gecoder 0.7.0 → 0.7.1

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