gecoder 0.8.2 → 0.8.3
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 +14 -0
- data/ext/gecoder.cpp +181 -0
- data/ext/gecoder.h +94 -0
- data/ext/vararray.cpp +3 -3
- data/lib/gecoder/bindings/bindings.rb +104 -46
- data/lib/gecoder/interface/binding_changes.rb +1 -301
- data/lib/gecoder/interface/branch.rb +15 -11
- data/lib/gecoder/interface/constraints/bool/boolean.rb +56 -52
- data/lib/gecoder/interface/constraints/bool/channel.rb +1 -16
- data/lib/gecoder/interface/constraints/bool_enum/channel.rb +13 -8
- data/lib/gecoder/interface/constraints/bool_enum/extensional.rb +48 -0
- data/lib/gecoder/interface/constraints/extensional_regexp.rb +101 -0
- data/lib/gecoder/interface/constraints/int/channel.rb +1 -13
- data/lib/gecoder/interface/constraints/int_enum/channel.rb +15 -35
- data/lib/gecoder/interface/constraints/int_enum/extensional.rb +130 -0
- data/lib/gecoder/interface/constraints/set/channel.rb +54 -0
- data/lib/gecoder/interface/constraints/set_enum/channel.rb +37 -6
- data/lib/gecoder/interface/constraints/set_var_constraints.rb +1 -0
- data/lib/gecoder/interface/constraints.rb +38 -0
- data/lib/gecoder/interface/model.rb +110 -85
- data/lib/gecoder/interface/variables.rb +3 -21
- data/lib/gecoder/version.rb +1 -1
- data/specs/branch.rb +16 -1
- data/specs/constraints/bool_enum_relation.rb +6 -6
- data/specs/constraints/boolean.rb +31 -25
- data/specs/constraints/channel.rb +102 -4
- data/specs/constraints/extensional.rb +185 -2
- data/specs/constraints/reification_sugar.rb +2 -46
- data/specs/model.rb +85 -7
- data/tasks/dependencies.txt +1 -0
- data/vendor/rust/rust/class.rb +33 -35
- data/vendor/rust/rust/templates/ClassDeclarations.rusttpl +1 -1
- data/vendor/rust/rust/templates/CxxClassDefinitions.rusttpl +10 -1
- metadata +185 -184
- data/example/raw_bindings.rb +0 -44
- data/ext/missing.cpp +0 -328
- data/ext/missing.h +0 -120
- data/specs/binding_changes.rb +0 -76
@@ -1,117 +1,109 @@
|
|
1
1
|
module Gecode
|
2
2
|
# Model is the base class that all models must inherit from.
|
3
3
|
class Model
|
4
|
+
# The largest integer allowed in the domain of an integer variable.
|
5
|
+
MAX_INT = Gecode::Raw::IntLimits::MAX
|
6
|
+
# The smallest integer allowed in the domain of an integer variable.
|
7
|
+
MIN_INT = Gecode::Raw::IntLimits::MIN
|
8
|
+
|
9
|
+
# The largest integer allowed in the domain of a set variable.
|
10
|
+
SET_MAX_INT = Gecode::Raw::SetLimits::MAX
|
11
|
+
# The smallest integer allowed in the domain of a set variable.
|
12
|
+
SET_MIN_INT = Gecode::Raw::SetLimits::MIN
|
13
|
+
|
14
|
+
# The largest possible domain for an integer variable.
|
15
|
+
LARGEST_INT_DOMAIN = MIN_INT..MAX_INT
|
16
|
+
# The largest possible domain, without negative integers, for an
|
17
|
+
# integer variable.
|
18
|
+
NON_NEGATIVE_INT_DOMAIN = 0..MAX_INT
|
19
|
+
|
20
|
+
# The largest possible bound for a set variable.
|
21
|
+
LARGEST_SET_BOUND = SET_MIN_INT..SET_MAX_INT
|
22
|
+
|
4
23
|
# Creates a new integer variable with the specified domain. The domain can
|
5
24
|
# either be a range, a single element, or an enumeration of elements. If no
|
6
25
|
# domain is specified then the largest possible domain is used.
|
7
|
-
def int_var(domain =
|
8
|
-
|
9
|
-
|
10
|
-
index = variable_creation_space.new_int_vars(enum).first
|
11
|
-
FreeIntVar.new(self, index)
|
26
|
+
def int_var(domain = LARGEST_INT_DOMAIN)
|
27
|
+
args = domain_arguments(domain)
|
28
|
+
FreeIntVar.new(self, variable_creation_space.new_int_var(*args))
|
12
29
|
end
|
13
30
|
|
14
31
|
# Creates an array containing the specified number of integer variables
|
15
32
|
# with the specified domain. The domain can either be a range, a single
|
16
|
-
# element, or an enumeration of elements.
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
33
|
+
# element, or an enumeration of elements. If no domain is specified then
|
34
|
+
# the largest possible domain is used.
|
35
|
+
def int_var_array(count, domain = LARGEST_INT_DOMAIN)
|
36
|
+
args = domain_arguments(domain)
|
37
|
+
build_var_array(count) do
|
38
|
+
FreeIntVar.new(self, variable_creation_space.new_int_var(*args))
|
22
39
|
end
|
23
|
-
return wrap_enum(variables)
|
24
40
|
end
|
25
41
|
|
26
42
|
# Creates a matrix containing the specified number rows and columns of
|
27
43
|
# integer variables with the specified domain. The domain can either be a
|
28
|
-
# range, a single element, or an enumeration of elements.
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
rows << indices[(i*col_count)...(i.succ*col_count)].map! do |index|
|
35
|
-
FreeIntVar.new(self, index)
|
36
|
-
end
|
44
|
+
# range, a single element, or an enumeration of elements. If no domain
|
45
|
+
# is specified then the largest possible domain is used.
|
46
|
+
def int_var_matrix(row_count, col_count, domain = LARGEST_INT_DOMAIN)
|
47
|
+
args = domain_arguments(domain)
|
48
|
+
build_var_matrix(row_count, col_count) do
|
49
|
+
FreeIntVar.new(self, variable_creation_space.new_int_var(*args))
|
37
50
|
end
|
38
|
-
return wrap_enum(Util::EnumMatrix.rows(rows, false))
|
39
51
|
end
|
40
52
|
|
41
53
|
# Creates a new boolean variable.
|
42
54
|
def bool_var
|
43
|
-
|
44
|
-
FreeBoolVar.new(self, index)
|
55
|
+
FreeBoolVar.new(self, variable_creation_space.new_bool_var)
|
45
56
|
end
|
46
57
|
|
47
58
|
# Creates an array containing the specified number of boolean variables.
|
48
59
|
def bool_var_array(count)
|
49
|
-
|
50
|
-
|
51
|
-
variables << FreeBoolVar.new(self, index)
|
60
|
+
build_var_array(count) do
|
61
|
+
FreeBoolVar.new(self, variable_creation_space.new_bool_var)
|
52
62
|
end
|
53
|
-
return wrap_enum(variables)
|
54
63
|
end
|
55
64
|
|
56
65
|
# Creates a matrix containing the specified number rows and columns of
|
57
66
|
# boolean variables.
|
58
67
|
def bool_var_matrix(row_count, col_count)
|
59
|
-
|
60
|
-
|
61
|
-
row_count.times do |i|
|
62
|
-
rows << indices[(i*col_count)...(i.succ*col_count)].map! do |index|
|
63
|
-
FreeBoolVar.new(self, index)
|
64
|
-
end
|
68
|
+
build_var_matrix(row_count, col_count) do
|
69
|
+
FreeBoolVar.new(self, variable_creation_space.new_bool_var)
|
65
70
|
end
|
66
|
-
return wrap_enum(Util::EnumMatrix.rows(rows, false))
|
67
71
|
end
|
68
72
|
|
69
73
|
# Creates a set variable with the specified domain for greatest lower bound
|
70
74
|
# and least upper bound (specified as either a fixnum, range or enum). If
|
71
|
-
# no bounds are specified then the empty set is used as
|
72
|
-
# and the
|
73
|
-
#
|
74
|
-
#
|
75
|
+
# no bounds are specified then the empty set is used as greatest lower
|
76
|
+
# bound and the largest possible set as least upper bound.
|
77
|
+
#
|
78
|
+
# A range for the allowed cardinality of the set can also be
|
79
|
+
# specified, if none is specified, or nil is given, then the default
|
80
|
+
# range (anything) will be used. If only a single Fixnum is
|
75
81
|
# specified as cardinality_range then it's used as lower bound.
|
76
|
-
def set_var(glb_domain = [], lub_domain =
|
77
|
-
Gecode::Raw::SetLimits::MIN..Gecode::Raw::SetLimits::MAX,
|
82
|
+
def set_var(glb_domain = [], lub_domain = LARGEST_SET_BOUND,
|
78
83
|
cardinality_range = nil)
|
79
|
-
|
80
|
-
|
81
|
-
index = variable_creation_space.new_set_vars(glb_domain, lub_domain,
|
82
|
-
to_set_cardinality_range(cardinality_range)).first
|
83
|
-
FreeSetVar.new(self, index)
|
84
|
+
args = set_bounds_to_parameters(glb_domain, lub_domain, cardinality_range)
|
85
|
+
FreeSetVar.new(self, variable_creation_space.new_set_var(*args))
|
84
86
|
end
|
85
87
|
|
86
88
|
# Creates an array containing the specified number of set variables. The
|
87
89
|
# parameters beyond count are the same as for #set_var .
|
88
|
-
def set_var_array(count, glb_domain, lub_domain
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
to_set_cardinality_range(cardinality_range), count).each do |index|
|
94
|
-
variables << FreeSetVar.new(self, index)
|
90
|
+
def set_var_array(count, glb_domain = [], lub_domain = LARGEST_SET_BOUND,
|
91
|
+
cardinality_range = nil)
|
92
|
+
args = set_bounds_to_parameters(glb_domain, lub_domain, cardinality_range)
|
93
|
+
build_var_array(count) do
|
94
|
+
FreeSetVar.new(self, variable_creation_space.new_set_var(*args))
|
95
95
|
end
|
96
|
-
return wrap_enum(variables)
|
97
96
|
end
|
98
97
|
|
99
98
|
# Creates a matrix containing the specified number of rows and columns
|
100
99
|
# filled with set variables. The parameters beyond row and column counts are
|
101
100
|
# the same as for #set_var .
|
102
|
-
def set_var_matrix(row_count, col_count, glb_domain
|
103
|
-
cardinality_range = nil)
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
to_set_cardinality_range(cardinality_range), row_count*col_count)
|
108
|
-
rows = []
|
109
|
-
row_count.times do |i|
|
110
|
-
rows << indices[(i*col_count)...(i.succ*col_count)].map! do |index|
|
111
|
-
FreeSetVar.new(self, index)
|
112
|
-
end
|
101
|
+
def set_var_matrix(row_count, col_count, glb_domain = [],
|
102
|
+
lub_domain = LARGEST_SET_BOUND, cardinality_range = nil)
|
103
|
+
args = set_bounds_to_parameters(glb_domain, lub_domain, cardinality_range)
|
104
|
+
build_var_matrix(row_count, col_count) do
|
105
|
+
FreeSetVar.new(self, variable_creation_space.new_set_var(*args))
|
113
106
|
end
|
114
|
-
return wrap_enum(Util::EnumMatrix.rows(rows, false))
|
115
107
|
end
|
116
108
|
|
117
109
|
# Retrieves the currently used space. Calling this method is only allowed
|
@@ -176,20 +168,49 @@ module Gecode
|
|
176
168
|
|
177
169
|
private
|
178
170
|
|
179
|
-
#
|
180
|
-
#
|
181
|
-
def
|
171
|
+
# Creates an array containing the specified number of variables, all
|
172
|
+
# constructed using the provided block..
|
173
|
+
def build_var_array(count, &block)
|
174
|
+
variables = []
|
175
|
+
count.times do
|
176
|
+
variables << yield
|
177
|
+
end
|
178
|
+
return wrap_enum(variables)
|
179
|
+
end
|
180
|
+
|
181
|
+
# Creates a matrix containing the specified number rows and columns of
|
182
|
+
# variables, all constructed using the provided block.
|
183
|
+
def build_var_matrix(row_count, col_count, &block)
|
184
|
+
rows = []
|
185
|
+
row_count.times do |i|
|
186
|
+
row = []
|
187
|
+
col_count.times do |j|
|
188
|
+
row << yield
|
189
|
+
end
|
190
|
+
rows << row
|
191
|
+
end
|
192
|
+
return wrap_enum(Util::EnumMatrix.rows(rows, false))
|
193
|
+
end
|
194
|
+
|
195
|
+
# Returns the array of arguments that correspond to the specified
|
196
|
+
# domain when given to Gecode. The domain can be given as a range,
|
197
|
+
# a single number, or an enumerable of elements.
|
198
|
+
def domain_arguments(domain)
|
182
199
|
if domain.respond_to?(:first) and domain.respond_to?(:last) and
|
183
200
|
domain.respond_to?(:exclude_end?)
|
184
201
|
if domain.exclude_end?
|
185
|
-
return domain.first
|
202
|
+
return [domain.first, (domain.last - 1)]
|
186
203
|
else
|
187
|
-
return domain
|
204
|
+
return [domain.first, domain.last]
|
188
205
|
end
|
189
206
|
elsif domain.kind_of? Enumerable
|
190
|
-
|
207
|
+
array = domain.to_a
|
208
|
+
return [Gecode::Raw::IntSet.new(array, array.size)]
|
209
|
+
elsif domain.kind_of? Fixnum
|
210
|
+
return [domain, domain]
|
191
211
|
else
|
192
|
-
|
212
|
+
raise TypeError, 'The domain must be given as an instance of ' +
|
213
|
+
"Enumerable or Fixnum, but #{domain.class} was given."
|
193
214
|
end
|
194
215
|
end
|
195
216
|
|
@@ -204,6 +225,21 @@ module Gecode
|
|
204
225
|
end
|
205
226
|
end
|
206
227
|
|
228
|
+
# Converts the specified set var domain to parameters accepted by
|
229
|
+
# Gecode. The bounds can be specified as a fixnum, range or # enum.
|
230
|
+
# The parameters are returned as an array.
|
231
|
+
def set_bounds_to_parameters(glb_domain, lub_domain, cardinality_range)
|
232
|
+
check_set_bounds(glb_domain, lub_domain)
|
233
|
+
args = []
|
234
|
+
args << Gecode::Constraints::Util.constant_set_to_int_set(glb_domain)
|
235
|
+
args << Gecode::Constraints::Util.constant_set_to_int_set(lub_domain)
|
236
|
+
card_range = to_set_cardinality_range(cardinality_range)
|
237
|
+
if card_range.nil?
|
238
|
+
card_range = 0..Gecode::Raw::SetLimits::CARD
|
239
|
+
end
|
240
|
+
args << card_range.first << card_range.last
|
241
|
+
end
|
242
|
+
|
207
243
|
# Checks whether the specified greatest lower bound is a subset of least
|
208
244
|
# upper bound. Raises ArgumentError if that is not the case.
|
209
245
|
def check_set_bounds(glb, lub)
|
@@ -243,15 +279,6 @@ module Gecode
|
|
243
279
|
@variable_creation_space || selected_space
|
244
280
|
end
|
245
281
|
|
246
|
-
# Refreshes all cached variables. This should be called if the variables
|
247
|
-
# in an existing space were changed.
|
248
|
-
def refresh_variables
|
249
|
-
return if @variables.nil?
|
250
|
-
@variables.each do |variable|
|
251
|
-
variable.refresh if variable.cached?
|
252
|
-
end
|
253
|
-
end
|
254
|
-
|
255
282
|
# Executes any interactions with Gecode still waiting in the queue
|
256
283
|
# (emptying the queue) in the process.
|
257
284
|
def perform_queued_gecode_interactions
|
@@ -266,8 +293,6 @@ module Gecode
|
|
266
293
|
# assigned directly.
|
267
294
|
def active_space=(new_space)
|
268
295
|
@active_space = new_space
|
269
|
-
new_space.refresh
|
270
|
-
refresh_variables
|
271
296
|
end
|
272
297
|
end
|
273
|
-
end
|
298
|
+
end
|
@@ -8,21 +8,9 @@ module Gecode
|
|
8
8
|
def initialize(model, index)
|
9
9
|
@model = model
|
10
10
|
@index = index
|
11
|
-
@bound_space = @bound_var = nil
|
12
11
|
model.track_variable(self)
|
13
12
|
end
|
14
|
-
|
15
|
-
# Checks whether the variable is cached, i.e. whether it needs to be
|
16
|
-
# rebound after changes to a space.
|
17
|
-
def cached?
|
18
|
-
not @bound_space.nil?
|
19
|
-
end
|
20
|
-
|
21
|
-
# Forces the variable to refresh itself.
|
22
|
-
def refresh
|
23
|
-
@bound_space = nil
|
24
|
-
end
|
25
|
-
|
13
|
+
|
26
14
|
def inspect
|
27
15
|
if assigned?
|
28
16
|
"#<#{self.class} #{domain}>"
|
@@ -54,13 +42,7 @@ module Gecode
|
|
54
42
|
# Binds the int variable to the currently active space of the model,
|
55
43
|
# returning the bound int variable.
|
56
44
|
def bind
|
57
|
-
|
58
|
-
unless @bound_space == space
|
59
|
-
# We have not bound the variable to this space, so we do it now.
|
60
|
-
@bound = space.method(:#{space_bind_method}).call(@index)
|
61
|
-
@bound_space = space
|
62
|
-
end
|
63
|
-
return @bound
|
45
|
+
active_space.method(:#{space_bind_method}).call(@index)
|
64
46
|
end
|
65
47
|
|
66
48
|
private
|
@@ -251,4 +233,4 @@ module Gecode
|
|
251
233
|
end
|
252
234
|
end
|
253
235
|
end
|
254
|
-
end
|
236
|
+
end
|
data/lib/gecoder/version.rb
CHANGED
data/specs/branch.rb
CHANGED
@@ -37,6 +37,16 @@ describe Gecode::Model, ' (integer branch)' do
|
|
37
37
|
@model.solve!.bools.each{ |var| var.should be_assigned }
|
38
38
|
end
|
39
39
|
|
40
|
+
it 'should allow branching on a single integer variable' do
|
41
|
+
@model.branch_on @vars.first
|
42
|
+
@model.solve!.vars.first.should be_assigned
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should allow branching on a single boolean variable' do
|
46
|
+
@model.branch_on @bools.first
|
47
|
+
@model.solve!.bools.first.should be_assigned
|
48
|
+
end
|
49
|
+
|
40
50
|
supported_var_selectors = {
|
41
51
|
:none => Gecode::Raw::INT_VAR_NONE,
|
42
52
|
:smallest_min => Gecode::Raw::INT_VAR_MIN_MIN,
|
@@ -120,6 +130,11 @@ describe Gecode::Model, ' (set branch)' do
|
|
120
130
|
@model.branch_on @sets
|
121
131
|
@model.solve!.sets.each{ |var| var.should be_assigned }
|
122
132
|
end
|
133
|
+
|
134
|
+
it 'should allow branching on a single set variable' do
|
135
|
+
@model.branch_on @sets.first
|
136
|
+
@model.solve!.sets.first.should be_assigned
|
137
|
+
end
|
123
138
|
|
124
139
|
supported_var_selectors = {
|
125
140
|
:none => Gecode::Raw::SET_VAR_NONE,
|
@@ -167,4 +182,4 @@ describe Gecode::Model, ' (set branch)' do
|
|
167
182
|
@model.branch_on @sets, :foo => 5
|
168
183
|
end.should raise_error(ArgumentError)
|
169
184
|
end
|
170
|
-
end
|
185
|
+
end
|
@@ -15,8 +15,8 @@ class BoolEnumSampleProblem < Gecode::Model
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
-
# Expects @stub, which contains the started constraint and @compute_result
|
19
|
-
# computes whether the left hand side is true or not.
|
18
|
+
# Expects @stub, which contains the started constraint and @compute_result
|
19
|
+
# which computes whether the left hand side is true or not.
|
20
20
|
describe 'bool enum relation constraint', :shared => true do
|
21
21
|
it 'should handle being constrained to be true' do
|
22
22
|
@stub.must_be.true
|
@@ -76,7 +76,7 @@ describe Gecode::Constraints::BoolEnum::Relation, ' (conjunction)' do
|
|
76
76
|
|
77
77
|
# For constraint option spec.
|
78
78
|
@invoke_options = lambda do |hash|
|
79
|
-
@bools.conjunction.
|
79
|
+
@bools.conjunction.must.equal(@b1, hash)
|
80
80
|
@model.solve!
|
81
81
|
end
|
82
82
|
@expect_options = option_expectation do |strength, kind, reif_var|
|
@@ -94,7 +94,7 @@ describe Gecode::Constraints::BoolEnum::Relation, ' (conjunction)' do
|
|
94
94
|
an_instance_of(Gecode::Raw::BoolVar),
|
95
95
|
anything,
|
96
96
|
an_instance_of(Gecode::Raw::BoolVar),
|
97
|
-
anything, anything
|
97
|
+
anything, anything)
|
98
98
|
Gecode::Raw.should_receive(:rel).once.with(
|
99
99
|
an_instance_of(Gecode::Raw::Space),
|
100
100
|
Gecode::Raw::BOT_AND,
|
@@ -122,7 +122,7 @@ describe Gecode::Constraints::BoolEnum::Relation, ' (disjunction)' do
|
|
122
122
|
|
123
123
|
# For constraint option spec.
|
124
124
|
@invoke_options = lambda do |hash|
|
125
|
-
@bools.disjunction.
|
125
|
+
@bools.disjunction.must.equal(@b1, hash)
|
126
126
|
@model.solve!
|
127
127
|
end
|
128
128
|
@expect_options = option_expectation do |strength, kind, reif_var|
|
@@ -140,7 +140,7 @@ describe Gecode::Constraints::BoolEnum::Relation, ' (disjunction)' do
|
|
140
140
|
an_instance_of(Gecode::Raw::BoolVar),
|
141
141
|
anything,
|
142
142
|
an_instance_of(Gecode::Raw::BoolVar),
|
143
|
-
anything, anything
|
143
|
+
anything, anything)
|
144
144
|
Gecode::Raw.should_receive(:rel).once.with(
|
145
145
|
an_instance_of(Gecode::Raw::Space),
|
146
146
|
Gecode::Raw::BOT_OR,
|
@@ -22,28 +22,22 @@ describe Gecode::Constraints::Bool do
|
|
22
22
|
|
23
23
|
# For constraint option spec.
|
24
24
|
@invoke_options = lambda do |hash|
|
25
|
-
(@b1 | @b2).must_be.
|
25
|
+
(@b1 | @b2).must_be.true(hash)
|
26
26
|
@model.solve!
|
27
27
|
end
|
28
28
|
@expect_options = option_expectation do |strength, kind, reif_var|
|
29
29
|
@model.allow_space_access do
|
30
|
-
|
31
|
-
an_instance_of(Gecode::Raw::Space),
|
32
|
-
an_instance_of(Gecode::Raw::BoolVar),
|
33
|
-
Gecode::Raw::BOT_OR,
|
34
|
-
an_instance_of(Gecode::Raw::BoolVar),
|
35
|
-
an_instance_of(Gecode::Raw::BoolVar),
|
36
|
-
Gecode::Raw::ICL_DEF, Gecode::Raw::PK_DEF)
|
30
|
+
# We only test the non-MiniModel parts.
|
37
31
|
unless reif_var.nil?
|
38
32
|
Gecode::Raw.should_receive(:rel).once.with(
|
39
33
|
an_instance_of(Gecode::Raw::Space),
|
40
|
-
an_instance_of(Gecode::Raw::BoolVar), Gecode::Raw::
|
41
|
-
an_instance_of(Gecode::Raw::BoolVar),
|
34
|
+
an_instance_of(Gecode::Raw::BoolVar), Gecode::Raw::IRT_EQ,
|
35
|
+
an_instance_of(Gecode::Raw::BoolVar), strength, kind)
|
42
36
|
end
|
43
37
|
end
|
44
38
|
end
|
45
39
|
end
|
46
|
-
|
40
|
+
|
47
41
|
it 'should handle single variables constrainted to be true' do
|
48
42
|
@b1.must_be.true
|
49
43
|
b1 = @model.solve!.b1
|
@@ -79,7 +73,7 @@ describe Gecode::Constraints::Bool do
|
|
79
73
|
sol.b1.value.should_not be_true
|
80
74
|
sol.b2.value.should be_true
|
81
75
|
end
|
82
|
-
|
76
|
+
|
83
77
|
it 'should handle negated disjunction' do
|
84
78
|
@b1.must_be.false
|
85
79
|
(@b1 | @b2).must_not_be.true
|
@@ -87,7 +81,7 @@ describe Gecode::Constraints::Bool do
|
|
87
81
|
sol.b1.value.should_not be_true
|
88
82
|
sol.b2.value.should_not be_true
|
89
83
|
end
|
90
|
-
|
84
|
+
|
91
85
|
it 'should handle conjunction' do
|
92
86
|
(@b1 & @b2).must_be.true
|
93
87
|
sol = @model.solve!
|
@@ -142,7 +136,7 @@ describe Gecode::Constraints::Bool do
|
|
142
136
|
sol.b1.value.should_not be_true
|
143
137
|
sol.b2.value.should_not be_true
|
144
138
|
end
|
145
|
-
|
139
|
+
|
146
140
|
it 'should handle imply after must_not' do
|
147
141
|
@b1.must_be.true
|
148
142
|
@b1.must_not.imply @b2
|
@@ -166,7 +160,7 @@ describe Gecode::Constraints::Bool do
|
|
166
160
|
sol.b1.value.should be_true
|
167
161
|
sol.b2.value.should_not be_true
|
168
162
|
end
|
169
|
-
|
163
|
+
|
170
164
|
it 'should handle expressions as right hand side' do
|
171
165
|
@b1.must == (@b2 | @b3)
|
172
166
|
@b2.must_be.true
|
@@ -174,7 +168,7 @@ describe Gecode::Constraints::Bool do
|
|
174
168
|
sol.b1.value.should be_true
|
175
169
|
sol.b2.value.should be_true
|
176
170
|
end
|
177
|
-
|
171
|
+
|
178
172
|
it 'should handle nested expressions as left hand side' do
|
179
173
|
((@b1 & @b2) | @b3 | (@b1 & @b3)).must_be.true
|
180
174
|
@b1.must_be.false
|
@@ -182,7 +176,7 @@ describe Gecode::Constraints::Bool do
|
|
182
176
|
sol.b1.value.should_not be_true
|
183
177
|
sol.b3.value.should be_true
|
184
178
|
end
|
185
|
-
|
179
|
+
|
186
180
|
it 'should handle nested expressions on both side' do
|
187
181
|
((@b1 & @b1) | @b3).must == ((@b1 & @b3) & @b2)
|
188
182
|
@b1.must_be.true
|
@@ -191,7 +185,15 @@ describe Gecode::Constraints::Bool do
|
|
191
185
|
sol.b2.value.should be_true
|
192
186
|
sol.b3.value.should be_true
|
193
187
|
end
|
194
|
-
|
188
|
+
|
189
|
+
it 'should handle nested expressions with implication' do
|
190
|
+
((@b1 & @b1) | @b3).must.imply(@b1 ^ @b2)
|
191
|
+
@b1.must_be.true
|
192
|
+
sol = @model.solve!
|
193
|
+
sol.b1.value.should be_true
|
194
|
+
sol.b2.value.should be_false
|
195
|
+
end
|
196
|
+
|
195
197
|
it 'should handle nested expressions containing exclusive or' do
|
196
198
|
((@b1 ^ @b1) & @b3).must == ((@b2 | @b3) ^ @b2)
|
197
199
|
@b1.must_be.true
|
@@ -201,7 +203,7 @@ describe Gecode::Constraints::Bool do
|
|
201
203
|
sol.b2.value.should_not be_true
|
202
204
|
sol.b3.value.should_not be_true
|
203
205
|
end
|
204
|
-
|
206
|
+
|
205
207
|
it 'should handle nested expressions on both sides with negation' do
|
206
208
|
((@b1 & @b1) | @b3).must_not == ((@b1 | @b3) & @b2)
|
207
209
|
@b1.must_be.true
|
@@ -211,7 +213,7 @@ describe Gecode::Constraints::Bool do
|
|
211
213
|
sol.b2.value.should_not be_true
|
212
214
|
sol.b3.value.should be_true
|
213
215
|
end
|
214
|
-
|
216
|
+
|
215
217
|
it 'should translate reification with a variable right hand side' do
|
216
218
|
@b1.must_be.equal_to(@b2, :reify => @b3)
|
217
219
|
@b1.must_be.true
|
@@ -219,8 +221,8 @@ describe Gecode::Constraints::Bool do
|
|
219
221
|
sol = @model.solve!
|
220
222
|
sol.b3.value.should_not be_true
|
221
223
|
end
|
222
|
-
|
223
|
-
it 'should translate reification with a variable right hand side and negation'
|
224
|
+
|
225
|
+
it 'should translate reification with a variable right hand side and negation' do
|
224
226
|
@b1.must_not_be.equal_to(@b2, :reify => @b3)
|
225
227
|
@b1.must_be.true
|
226
228
|
@b2.must_be.false
|
@@ -228,9 +230,13 @@ describe Gecode::Constraints::Bool do
|
|
228
230
|
sol.b3.value.should be_true
|
229
231
|
end
|
230
232
|
|
231
|
-
it 'should raise error on right hand sides of
|
233
|
+
it 'should raise error on right hand sides of incorrect type given to #==' do
|
232
234
|
lambda{ @b1.must == 'hello' }.should raise_error(TypeError)
|
233
235
|
end
|
234
|
-
|
236
|
+
|
237
|
+
it 'should raise error on right hand sides of incorrect type given to #imply' do
|
238
|
+
lambda{ @b1.must.imply 'hello' }.should raise_error(TypeError)
|
239
|
+
end
|
240
|
+
|
235
241
|
it_should_behave_like 'reifiable constraint'
|
236
|
-
end
|
242
|
+
end
|