gecoder-with-gecode 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.rb +38 -0
- 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/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 +707 -706
- 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
@@ -0,0 +1,54 @@
|
|
1
|
+
module Gecode::Constraints::Set
|
2
|
+
class Expression
|
3
|
+
# Adds a channel constraint on the set variable with the specified enum of
|
4
|
+
# boolean variables.
|
5
|
+
def channel(bool_enum, options = {})
|
6
|
+
if @params[:negate]
|
7
|
+
raise Gecode::MissingConstraintError, 'A negated channel constraint ' +
|
8
|
+
'is not implemented.'
|
9
|
+
end
|
10
|
+
if options.has_key? :reify
|
11
|
+
raise ArgumentError, 'The channel constraint does not support the ' +
|
12
|
+
'reification option.'
|
13
|
+
end
|
14
|
+
unless bool_enum.respond_to? :to_bool_var_array
|
15
|
+
raise TypeError, 'Expected an enum of bool variables, ' +
|
16
|
+
"got #{bool_enum.class}."
|
17
|
+
end
|
18
|
+
|
19
|
+
@params.update(:rhs => bool_enum)
|
20
|
+
@params.update Gecode::Constraints::Set::Util.decode_options(options)
|
21
|
+
@model.add_constraint Channel::ChannelConstraint.new(@model, @params)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# A module that gathers the classes and modules used in channel constraints
|
26
|
+
# involving one set variable and a boolean enum.
|
27
|
+
module Channel #:nodoc:
|
28
|
+
# Describes a channel constraint that "channels" a set variable and an
|
29
|
+
# enumerations of boolean variables. This constrains the set variable to
|
30
|
+
# include value i exactly when the variable at index i in the boolean
|
31
|
+
# enumeration is true.
|
32
|
+
#
|
33
|
+
# Neither reification nor negation is supported. The boolean enum and set
|
34
|
+
# can be interchanged.
|
35
|
+
#
|
36
|
+
# == Examples
|
37
|
+
#
|
38
|
+
# # Constrains the enumeration of boolean variables called +bools+ to at
|
39
|
+
# # least have the first and third variables set to true
|
40
|
+
# set.must_be.superset_of [0, 2]
|
41
|
+
# set.must.channel bools
|
42
|
+
#
|
43
|
+
# # An alternative way of writing the above.
|
44
|
+
# set.must_be.superset_of [0, 2]
|
45
|
+
# bools.must.channel set
|
46
|
+
class ChannelConstraint < Gecode::Constraints::Constraint
|
47
|
+
def post
|
48
|
+
lhs, rhs = @params.values_at(:lhs, :rhs)
|
49
|
+
Gecode::Raw::channel(@model.active_space, rhs.to_bool_var_array,
|
50
|
+
lhs.bind)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -2,16 +2,47 @@ module Gecode::Constraints::SetEnum
|
|
2
2
|
class Expression
|
3
3
|
# Posts a channel constraint on the variables in the enum with the specified
|
4
4
|
# int enum.
|
5
|
-
def channel(enum)
|
5
|
+
def channel(enum, options = {})
|
6
6
|
unless enum.respond_to? :to_int_var_array
|
7
7
|
raise TypeError, "Expected integer variable enum, for #{enum.class}."
|
8
8
|
end
|
9
|
-
|
10
|
-
# Just provide commutativity to the corresponding int enum constraint.
|
11
9
|
if @params[:negate]
|
12
|
-
|
13
|
-
|
14
|
-
|
10
|
+
raise Gecode::MissingConstraintError, 'A negated channel constraint ' +
|
11
|
+
'is not implemented.'
|
12
|
+
end
|
13
|
+
if options.has_key? :reify
|
14
|
+
raise ArgumentError, 'The channel constraints does not support the ' +
|
15
|
+
'reification option.'
|
16
|
+
end
|
17
|
+
|
18
|
+
@params.update(Gecode::Constraints::Set::Util.decode_options(options))
|
19
|
+
@params.update(:rhs => enum)
|
20
|
+
@model.add_constraint Channel::IntChannelConstraint.new(@model, @params)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# A module that gathers the classes and modules used in channel constraints.
|
25
|
+
module Channel #:nodoc:
|
26
|
+
# Describes a channel constraint which "channels" one enumeration of
|
27
|
+
# integer variables with one enumeration of set variables. The i:th set
|
28
|
+
# in the enumeration of set variables is constrainde to includes the value
|
29
|
+
# of the j:th integer variable.
|
30
|
+
#
|
31
|
+
# Neither reification nor negation is supported.
|
32
|
+
#
|
33
|
+
# == Examples
|
34
|
+
#
|
35
|
+
# # +set_enum+ is constrained to channel +int_enum+.
|
36
|
+
# int_enum.must.channel set_enum
|
37
|
+
#
|
38
|
+
# # This is another way of saying the above.
|
39
|
+
# set_enum.must.channel int_enum
|
40
|
+
#
|
41
|
+
class IntChannelConstraint < Gecode::Constraints::Constraint
|
42
|
+
def post
|
43
|
+
lhs, rhs = @params.values_at(:lhs, :rhs)
|
44
|
+
Gecode::Raw::channel(@model.active_space, rhs.to_int_var_array,
|
45
|
+
lhs.to_set_var_array)
|
15
46
|
end
|
16
47
|
end
|
17
48
|
end
|
@@ -75,3 +75,4 @@ require 'gecoder/interface/constraints/set/relation'
|
|
75
75
|
require 'gecoder/interface/constraints/set/cardinality'
|
76
76
|
require 'gecoder/interface/constraints/set/connection'
|
77
77
|
require 'gecoder/interface/constraints/set/operation'
|
78
|
+
require 'gecoder/interface/constraints/set/channel'
|
@@ -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
|