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.
- data/CHANGES +6 -0
- data/README +1 -1
- data/example/square_tiling.rb +84 -0
- data/example/sudoku-set.rb +107 -0
- data/example/sudoku.rb +2 -6
- data/lib/gecoder/bindings.rb +1 -1
- data/lib/gecoder/bindings/bindings.rb +20 -0
- data/lib/gecoder/interface/binding_changes.rb +2 -2
- data/lib/gecoder/interface/branch.rb +50 -51
- data/lib/gecoder/interface/constraints.rb +10 -10
- data/lib/gecoder/interface/constraints/bool/boolean.rb +79 -5
- data/lib/gecoder/interface/constraints/bool/linear.rb +29 -0
- data/lib/gecoder/interface/constraints/bool_enum/boolean.rb +34 -4
- data/lib/gecoder/interface/constraints/bool_var_constraints.rb +14 -9
- data/lib/gecoder/interface/constraints/int/arithmetic.rb +26 -8
- data/lib/gecoder/interface/constraints/int/domain.rb +30 -3
- data/lib/gecoder/interface/constraints/int/linear.rb +82 -16
- data/lib/gecoder/interface/constraints/int_enum/arithmetic.rb +31 -3
- data/lib/gecoder/interface/constraints/int_enum/channel.rb +63 -3
- data/lib/gecoder/interface/constraints/int_enum/count.rb +20 -3
- data/lib/gecoder/interface/constraints/int_enum/distinct.rb +22 -2
- data/lib/gecoder/interface/constraints/int_enum/element.rb +23 -4
- data/lib/gecoder/interface/constraints/int_enum/equality.rb +9 -2
- data/lib/gecoder/interface/constraints/int_enum/sort.rb +28 -3
- data/lib/gecoder/interface/constraints/int_enum_constraints.rb +1 -1
- data/lib/gecoder/interface/constraints/int_var_constraints.rb +13 -8
- data/lib/gecoder/interface/constraints/set/cardinality.rb +27 -8
- data/lib/gecoder/interface/constraints/set/connection.rb +72 -6
- data/lib/gecoder/interface/constraints/set/domain.rb +46 -3
- data/lib/gecoder/interface/constraints/set/operation.rb +35 -4
- data/lib/gecoder/interface/constraints/set/relation.rb +59 -6
- data/lib/gecoder/interface/constraints/set_enum/distinct.rb +22 -3
- data/lib/gecoder/interface/constraints/set_enum/operation.rb +26 -2
- data/lib/gecoder/interface/constraints/set_enum/selection.rb +110 -36
- data/lib/gecoder/interface/constraints/set_var_constraints.rb +11 -7
- data/lib/gecoder/interface/model.rb +6 -6
- data/lib/gecoder/interface/search.rb +6 -6
- data/lib/gecoder/interface/variables.rb +56 -12
- data/lib/gecoder/version.rb +1 -1
- data/specs/constraints/linear.rb +167 -1
- data/specs/constraints/set_domain.rb +6 -0
- data/tasks/distribution.rake +25 -3
- data/tasks/website.rake +5 -12
- metadata +10 -4
- data/vendor/rust/configure.rb +0 -6
- 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
|
-
#
|
53
|
-
#
|
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
|
-
#
|
47
|
-
#
|
48
|
-
#
|
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
|
-
#
|
3
|
-
|
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
|
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
|
-
#
|
238
|
+
# Iterates over every element in the view.
|
195
239
|
def each(&block)
|
196
240
|
enum.each(&block)
|
197
241
|
end
|
data/lib/gecoder/version.rb
CHANGED
data/specs/constraints/linear.rb
CHANGED
@@ -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
|
+
|