gecoder 0.6.0 → 0.6.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 (45) hide show
  1. data/CHANGES +9 -1
  2. data/Rakefile +3 -0
  3. data/example/send_most_money.rb +58 -0
  4. data/ext/missing.cpp +26 -1
  5. data/ext/missing.h +2 -0
  6. data/ext/vararray.cpp +31 -11
  7. data/ext/vararray.h +6 -0
  8. data/lib/gecoder/bindings.rb +5 -5
  9. data/lib/gecoder/bindings/bindings.rb +52 -0
  10. data/lib/gecoder/interface/binding_changes.rb +16 -11
  11. data/lib/gecoder/interface/constraints.rb +28 -15
  12. data/lib/gecoder/interface/constraints/bool_enum/boolean.rb +8 -17
  13. data/lib/gecoder/interface/constraints/bool_var_constraints.rb +8 -3
  14. data/lib/gecoder/interface/constraints/int/arithmetic.rb +10 -15
  15. data/lib/gecoder/interface/constraints/int_enum/arithmetic.rb +10 -16
  16. data/lib/gecoder/interface/constraints/int_enum/element.rb +6 -11
  17. data/lib/gecoder/interface/constraints/int_var_constraints.rb +2 -1
  18. data/lib/gecoder/interface/constraints/set/cardinality.rb +4 -7
  19. data/lib/gecoder/interface/constraints/set/connection.rb +13 -22
  20. data/lib/gecoder/interface/model.rb +52 -41
  21. data/lib/gecoder/interface/search.rb +29 -24
  22. data/lib/gecoder/interface/variables.rb +27 -15
  23. data/lib/gecoder/version.rb +1 -1
  24. data/specs/constraints/arithmetic.rb +27 -17
  25. data/specs/constraints/bool_enum.rb +4 -2
  26. data/specs/constraints/boolean.rb +5 -2
  27. data/specs/constraints/cardinality.rb +28 -8
  28. data/specs/constraints/connection.rb +58 -37
  29. data/specs/constraints/constraints.rb +2 -2
  30. data/specs/constraints/count.rb +3 -3
  31. data/specs/constraints/element.rb +5 -5
  32. data/specs/constraints/int_domain.rb +4 -2
  33. data/specs/constraints/set_domain.rb +8 -4
  34. data/specs/constraints/set_relation.rb +10 -5
  35. data/specs/int_var.rb +3 -3
  36. data/specs/model.rb +10 -9
  37. data/specs/search.rb +54 -5
  38. data/specs/spec_helper.rb +2 -0
  39. data/tasks/distribution.rake +8 -1
  40. data/tasks/specs.rake +0 -1
  41. data/vendor/rust/rust/class.rb +6 -1
  42. data/vendor/rust/rust/templates/CxxClassDefinitions.rusttpl +3 -3
  43. data/vendor/rust/rust/templates/CxxStandaloneClassDefinitions.rusttpl +15 -1
  44. data/vendor/rust/rust/templates/StandaloneClassDeclarations.rusttpl +2 -0
  45. metadata +51 -21
@@ -196,15 +196,19 @@ module Gecode
196
196
  class CompositeExpression < Gecode::Constraints::Expression
197
197
  # The expression class should be the class of the expression delegated to,
198
198
  # the variable class the kind of single variable used in the expression.
199
- # The block given should take three parameters. The first is the variable
200
- # that should be the left hand side, if it's nil then a new one should be
201
- # created. The second is the has of parameters. The block should return
202
- # the variable used as left hand side.
203
- def initialize(expression_class, variable_class, model, params, &block)
199
+ # The new var proc should produce a new variable (of the appropriate type)
200
+ # which has an unconstricted domain. The block given should take three
201
+ # parameters. The first is the variable that should be the left hand side.
202
+ # The second is the hash of parameters. The third is a boolean, it it's
203
+ # true then the block should try to constrain the first variable's domain
204
+ # as much as possible.
205
+ def initialize(expression_class, variable_class, new_var_proc, model,
206
+ params, &block)
204
207
  super(model, params)
205
208
  @expression_class = expression_class
206
209
  @variable_class = variable_class
207
- @proc = block
210
+ @new_var_proc = new_var_proc
211
+ @constrain_equal_proc = block
208
212
  end
209
213
 
210
214
  # Delegate to an instance of the expression class when we get something
@@ -215,9 +219,17 @@ module Gecode
215
219
  if args.size >= 2 and args[1].kind_of? Hash
216
220
  options = args[1]
217
221
  end
222
+
223
+ # Link a variable to the composite constraint.
218
224
  @params.update Gecode::Constraints::Util.decode_options(options.clone)
219
- @params[:lhs] = @proc.call(nil, @params)
220
- @expression_class.new(@model, @params).send(name, *args)
225
+ variable = @new_var_proc.call
226
+ @model.add_interaction do
227
+ @constrain_equal_proc.call(variable, @params, true)
228
+ end
229
+
230
+ # Perform the operation on the linked variable.
231
+ int_var_params = @params.clone.update(:lhs => variable)
232
+ @expression_class.new(@model, int_var_params).send(name, *args)
221
233
  else
222
234
  super
223
235
  end
@@ -228,7 +240,9 @@ module Gecode
228
240
  expression.kind_of? @variable_class
229
241
  # We don't need any additional constraints.
230
242
  @params.update Gecode::Constraints::Util.decode_options(options)
231
- @proc.call(expression, @params)
243
+ @model.add_interaction do
244
+ @constrain_equal_proc.call(expression, @params, false)
245
+ end
232
246
  else
233
247
  method_missing(:==, expression, options)
234
248
  end
@@ -299,18 +313,17 @@ module Gecode
299
313
  private
300
314
 
301
315
  # Constrains the result of the stub to be equal to the specified variable
302
- # with the specified parameters. If the variable given is nil then a new
303
- # variable should be created for the purpose and returned. This is an
304
- # abstract method and should be overridden by all sub-classes.
305
- def constrain_equal(variable, params)
316
+ # with the specified parameters. If constrain is true then the variable's
317
+ # domain should additionally be constrained as much as possible.
318
+ def constrain_equal(variable, params, constrain)
306
319
  raise NoMethodError, 'Abstract method has not been implemented.'
307
320
  end
308
321
 
309
322
  # Produces an expression with position for the lhs module.
310
323
  def expression(params)
311
324
  @params.update params
312
- @composite_class.new(@model, @params) do |var, params|
313
- constrain_equal(var, params)
325
+ @composite_class.new(@model, @params) do |var, params, constrain|
326
+ constrain_equal(var, params, constrain)
314
327
  end
315
328
  end
316
329
  end
@@ -19,11 +19,8 @@ module Gecode
19
19
  # Describes an expression stub started with a bool var enum following by
20
20
  # #conjunction.
21
21
  class ConjunctionStub < Gecode::Constraints::Bool::CompositeStub
22
- def constrain_equal(variable, params)
22
+ def constrain_equal(variable, params, constrain)
23
23
  enum, strength = @params.values_at(:lhs, :strength)
24
- if variable.nil?
25
- variable = @model.bool_var
26
- end
27
24
 
28
25
  @model.add_interaction do
29
26
  if variable.respond_to? :bind
@@ -41,22 +38,16 @@ module Gecode
41
38
  # Describes an expression stub started with a bool var enum following by
42
39
  # #disjunction.
43
40
  class DisjunctionStub < Gecode::Constraints::Bool::CompositeStub
44
- def constrain_equal(variable, params)
41
+ def constrain_equal(variable, params, constrain)
45
42
  enum, strength = @params.values_at(:lhs, :strength)
46
- if variable.nil?
47
- variable = @model.bool_var
48
- end
49
43
 
50
- @model.add_interaction do
51
- if variable.respond_to? :bind
52
- bound = variable.bind
53
- else
54
- bound = variable
55
- end
56
- Gecode::Raw::bool_or(@model.active_space, enum.to_bool_var_array,
57
- bound, strength)
44
+ if variable.respond_to? :bind
45
+ bound = variable.bind
46
+ else
47
+ bound = variable
58
48
  end
59
- return variable
49
+ Gecode::Raw::bool_or(@model.active_space, enum.to_bool_var_array,
50
+ bound, strength)
60
51
  end
61
52
  end
62
53
  end
@@ -26,21 +26,26 @@ module Gecode
26
26
  # created. The second is the has of parameters. The block should return
27
27
  # the variable used as left hand side.
28
28
  def initialize(model, params, &block)
29
- super(Expression, Gecode::FreeIntVar, model, params, &block)
29
+ super(Expression, Gecode::FreeBoolVar, lambda{ model.bool_var }, model,
30
+ params, &block)
30
31
  end
31
32
 
32
33
  # Override to also deal with constant booleans.
33
34
  def true(options = {})
34
35
  # We don't need any additional constraints.
35
36
  @params.update Gecode::Constraints::Util.decode_options(options)
36
- @proc.call(!@params[:negate], @params)
37
+ @model.add_interaction do
38
+ @constrain_equal_proc.call(!@params[:negate], @params)
39
+ end
37
40
  end
38
41
 
39
42
  # Override to also deal with constant booleans.
40
43
  def false(options = {})
41
44
  # We don't need any additional constraints.
42
45
  @params.update Gecode::Constraints::Util.decode_options(options)
43
- @proc.call(@params[:negate], @params)
46
+ @model.add_interaction do
47
+ @constrain_equal_proc.call(@params[:negate], @params)
48
+ end
44
49
  end
45
50
  end
46
51
 
@@ -23,36 +23,31 @@ module Gecode::Constraints::Int::Arithmetic
23
23
  # Describes an expression stub started with an integer variable followed by
24
24
  # #abs .
25
25
  class AbsExpressionStub < Gecode::Constraints::Int::CompositeStub
26
- def constrain_equal(variable, params)
26
+ def constrain_equal(variable, params, constrain)
27
27
  lhs, strength = @params.values_at(:lhs, :strength)
28
- if variable.nil?
29
- variable = @model.int_var(lhs.min..lhs.max)
28
+ if constrain
29
+ bounds = [lhs.min.abs, lhs.max.abs]
30
+ variable.must_be.in bounds.min..bounds.max
30
31
  end
31
32
 
32
- @model.add_interaction do
33
- Gecode::Raw::abs(@model.active_space, lhs.bind, variable.bind, strength)
34
- end
35
- return variable
33
+ Gecode::Raw::abs(@model.active_space, lhs.bind, variable.bind, strength)
36
34
  end
37
35
  end
38
36
 
39
37
  # Describes an expression stub started with an integer variable followed by
40
38
  # #* .
41
39
  class MultExpressionStub < Gecode::Constraints::Int::CompositeStub
42
- def constrain_equal(variable, params)
40
+ def constrain_equal(variable, params, constrain)
43
41
  lhs, lhs2, strength = @params.values_at(:lhs, :var, :strength)
44
- if variable.nil?
42
+ if constrain
45
43
  a_min = lhs.min; a_max = lhs.max
46
44
  b_min = lhs2.min; b_max = lhs2.max
47
45
  products = [a_min*b_min, a_min*b_max, a_max*b_min, a_max*b_max]
48
- variable = @model.int_var(products.min..products.max)
46
+ variable.must_be.in products.min..products.max
49
47
  end
50
48
 
51
- @model.add_interaction do
52
- Gecode::Raw::mult(@model.active_space, lhs.bind, lhs2.bind,
53
- variable.bind, strength)
54
- end
55
- return variable
49
+ Gecode::Raw::mult(@model.active_space, lhs.bind, lhs2.bind,
50
+ variable.bind, strength)
56
51
  end
57
52
  end
58
53
  end
@@ -18,33 +18,27 @@ end
18
18
  module Gecode::Constraints::IntEnum::Arithmetic
19
19
  # Describes an expression stub started with an int var enum following by #max.
20
20
  class MaxExpressionStub < Gecode::Constraints::Int::CompositeStub
21
- def constrain_equal(variable, params)
21
+ def constrain_equal(variable, params, constrain)
22
22
  enum, strength = @params.values_at(:lhs, :strength)
23
- if variable.nil?
24
- variable = @model.int_var(enum.domain_range)
23
+ if constrain
24
+ variable.must_be.in enum.domain_range
25
25
  end
26
26
 
27
- @model.add_interaction do
28
- Gecode::Raw::max(@model.active_space, enum.to_int_var_array,
29
- variable.bind, strength)
30
- end
31
- return variable
27
+ Gecode::Raw::max(@model.active_space, enum.to_int_var_array,
28
+ variable.bind, strength)
32
29
  end
33
30
  end
34
31
 
35
32
  # Describes an expression stub started with an int var enum following by #min.
36
33
  class MinExpressionStub < Gecode::Constraints::Int::CompositeStub
37
- def constrain_equal(variable, params)
34
+ def constrain_equal(variable, params, constrain)
38
35
  enum, strength = @params.values_at(:lhs, :strength)
39
- if variable.nil?
40
- variable = @model.int_var(enum.domain_range)
36
+ if constrain
37
+ variable.must_be.in enum.domain_range
41
38
  end
42
39
 
43
- @model.add_interaction do
44
- Gecode::Raw::min(@model.active_space, enum.to_int_var_array,
45
- variable.bind, strength)
46
- end
47
- return variable
40
+ Gecode::Raw::min(@model.active_space, enum.to_int_var_array,
41
+ variable.bind, strength)
48
42
  end
49
43
  end
50
44
  end
@@ -3,19 +3,14 @@ module Gecode::Constraints::IntEnum::Element
3
3
  # Describes an expression stub started with an int var enum following with an
4
4
  # array access using an integer variables .
5
5
  class ExpressionStub < Gecode::Constraints::Int::CompositeStub
6
- def constrain_equal(variable, params)
6
+ def constrain_equal(variable, params, constrain)
7
7
  enum, position, strength = @params.values_at(:lhs, :position, :strength)
8
- if variable.nil?
9
- variable = @model.int_var(enum.domain_range)
10
- end
8
+ variable.must_be.in enum.domain_range
11
9
 
12
- @model.add_interaction do
13
- # The enum can be a constant array.
14
- enum = enum.to_int_var_array if enum.respond_to? :to_int_var_array
15
- Gecode::Raw::element(@model.active_space, enum,
16
- position.bind, variable.bind, strength)
17
- end
18
- return variable
10
+ # The enum can be a constant array.
11
+ enum = enum.to_int_var_array if enum.respond_to? :to_int_var_array
12
+ Gecode::Raw::element(@model.active_space, enum,
13
+ position.bind, variable.bind, strength)
19
14
  end
20
15
  end
21
16
 
@@ -25,7 +25,8 @@ module Gecode
25
25
  # created. The second is the has of parameters. The block should return
26
26
  # the variable used as left hand side.
27
27
  def initialize(model, params, &block)
28
- super(Expression, Gecode::FreeIntVar, model, params, &block)
28
+ super(Expression, Gecode::FreeIntVar, lambda{ model.int_var }, model,
29
+ params, &block)
29
30
  end
30
31
  end
31
32
 
@@ -43,16 +43,13 @@ module Gecode::Constraints::Set
43
43
  # Describes an expression stub started with a set variable followed by
44
44
  # #size .
45
45
  class SizeExpressionStub < CompositeStub
46
- def constrain_equal(variable, params)
46
+ def constrain_equal(variable, params, constrain)
47
47
  lhs = @params[:lhs]
48
- if variable.nil?
49
- variable = @model.int_var(lhs.lower_bound.size, lhs.upper_bound.size)
48
+ if constrain
49
+ variable.must_be.in lhs.lower_bound.size..lhs.upper_bound.size
50
50
  end
51
51
 
52
- @model.add_interaction do
53
- Gecode::Raw::cardinality(@model.active_space, lhs.bind, variable.bind)
54
- end
55
- return variable
52
+ Gecode::Raw::cardinality(@model.active_space, lhs.bind, variable.bind)
56
53
  end
57
54
  end
58
55
  end
@@ -71,55 +71,46 @@ module Gecode::Constraints::Set
71
71
  module Connection
72
72
  # Describes an expression stub started with an int var following by #min.
73
73
  class MinExpressionStub < Gecode::Constraints::Int::CompositeStub
74
- def constrain_equal(variable, params)
74
+ def constrain_equal(variable, params, constrain)
75
75
  set = params[:lhs]
76
- if variable.nil?
77
- variable = @model.int_var(set.upper_bound.min, set.lower_bound.min)
76
+ if constrain
77
+ variable.must_be.in set.upper_bound.min..set.lower_bound.min
78
78
  end
79
79
 
80
- @model.add_interaction do
81
- Gecode::Raw::min(@model.active_space, set.bind, variable.bind)
82
- end
83
- return variable
80
+ Gecode::Raw::min(@model.active_space, set.bind, variable.bind)
84
81
  end
85
82
  end
86
83
 
87
84
  # Describes an expression stub started with an int var following by #max.
88
85
  class MaxExpressionStub < Gecode::Constraints::Int::CompositeStub
89
- def constrain_equal(variable, params)
86
+ def constrain_equal(variable, params, constrain)
90
87
  set = params[:lhs]
91
- if variable.nil?
92
- variable = @model.int_var(set.upper_bound.max, set.lower_bound.max)
88
+ if constrain
89
+ variable.must_be.in set.lower_bound.max..set.upper_bound.max
93
90
  end
94
91
 
95
- @model.add_interaction do
96
- Gecode::Raw::max(@model.active_space, set.bind, variable.bind)
97
- end
98
- return variable
92
+ Gecode::Raw::max(@model.active_space, set.bind, variable.bind)
99
93
  end
100
94
  end
101
95
 
102
96
  # Describes an expression stub started with an int var following by #max.
103
97
  class SumExpressionStub < Gecode::Constraints::Int::CompositeStub
104
- def constrain_equal(variable, params)
98
+ def constrain_equal(variable, params, constrain)
105
99
  set, subs = params.values_at(:lhs, :substitutions)
106
100
  lub = set.upper_bound.to_a
107
101
  lub.delete_if{ |e| subs[e].nil? }
108
102
  substituted_lub = lub.map{ |e| subs[e] }
109
- if variable.nil?
103
+ if constrain
110
104
  # Compute the theoretical bounds of the weighted sum. This is slightly
111
105
  # sloppy since we could also use the contents of the greatest lower
112
106
  # bound.
113
107
  min = substituted_lub.find_all{ |e| e < 0}.inject(0){ |x, y| x + y }
114
108
  max = substituted_lub.find_all{ |e| e > 0}.inject(0){ |x, y| x + y }
115
- variable = @model.int_var(min..max)
109
+ variable.must_be.in min..max
116
110
  end
117
111
 
118
- @model.add_interaction do
119
- Gecode::Raw::weights(@model.active_space, lub, substituted_lub,
120
- set.bind, variable.bind)
121
- end
122
- return variable
112
+ Gecode::Raw::weights(@model.active_space, lub, substituted_lub,
113
+ set.bind, variable.bind)
123
114
  end
124
115
  end
125
116
 
@@ -2,22 +2,22 @@ module Gecode
2
2
  # Model is the base class that all models must inherit from.
3
3
  class Model
4
4
  # Creates a new integer variable with the specified domain. The domain can
5
- # either be a range or a number of elements.
6
- def int_var(*domain_args)
7
- enum = domain_enum(*domain_args)
8
- index = selected_space.new_int_vars(enum).first
5
+ # either be a range, a single element, or an enumeration of elements. If no
6
+ # domain is specified then the largest possible domain is used.
7
+ def int_var(domain =
8
+ Gecode::Raw::Limits::Int::INT_MIN..Gecode::Raw::Limits::Int::INT_MAX)
9
+ enum = domain_enum(domain)
10
+ index = variable_creation_space.new_int_vars(enum).first
9
11
  FreeIntVar.new(self, index)
10
12
  end
11
13
 
12
14
  # Creates an array containing the specified number of integer variables
13
- # with the specified domain. The domain can either be a range or a number
14
- # of elements.
15
- def int_var_array(count, *domain_args)
16
- # TODO: Maybe the custom domain should be specified as an array instead?
17
-
18
- enum = domain_enum(*domain_args)
15
+ # with the specified domain. The domain can either be a range, a single
16
+ # element, or an enumeration of elements.
17
+ def int_var_array(count, domain)
18
+ enum = domain_enum(domain)
19
19
  variables = []
20
- selected_space.new_int_vars(enum, count).each do |index|
20
+ variable_creation_space.new_int_vars(enum, count).each do |index|
21
21
  variables << FreeIntVar.new(self, index)
22
22
  end
23
23
  return wrap_enum(variables)
@@ -25,12 +25,10 @@ module Gecode
25
25
 
26
26
  # Creates a matrix containing the specified number rows and columns of
27
27
  # integer variables with the specified domain. The domain can either be a
28
- # range or a number of elements.
29
- def int_var_matrix(row_count, col_count, *domain_args)
30
- # TODO: Maybe the custom domain should be specified as an array instead?
31
-
32
- enum = domain_enum(*domain_args)
33
- indices = selected_space.new_int_vars(enum, row_count*col_count)
28
+ # range, a single element, or an enumeration of elements.
29
+ def int_var_matrix(row_count, col_count, domain)
30
+ enum = domain_enum(domain)
31
+ indices = variable_creation_space.new_int_vars(enum, row_count*col_count)
34
32
  rows = []
35
33
  row_count.times do |i|
36
34
  rows << indices[(i*col_count)...(i.succ*col_count)].map! do |index|
@@ -41,15 +39,15 @@ module Gecode
41
39
  end
42
40
 
43
41
  # Creates a new boolean variable.
44
- def bool_var(*domain_args)
45
- index = selected_space.new_bool_vars.first
42
+ def bool_var
43
+ index = variable_creation_space.new_bool_vars.first
46
44
  FreeBoolVar.new(self, index)
47
45
  end
48
46
 
49
47
  # Creates an array containing the specified number of boolean variables.
50
48
  def bool_var_array(count)
51
49
  variables = []
52
- selected_space.new_bool_vars(count).each do |index|
50
+ variable_creation_space.new_bool_vars(count).each do |index|
53
51
  variables << FreeBoolVar.new(self, index)
54
52
  end
55
53
  return wrap_enum(variables)
@@ -58,7 +56,7 @@ module Gecode
58
56
  # Creates a matrix containing the specified number rows and columns of
59
57
  # boolean variables.
60
58
  def bool_var_matrix(row_count, col_count)
61
- indices = selected_space.new_bool_vars(row_count*col_count)
59
+ indices = variable_creation_space.new_bool_vars(row_count*col_count)
62
60
  rows = []
63
61
  row_count.times do |i|
64
62
  rows << indices[(i*col_count)...(i.succ*col_count)].map! do |index|
@@ -77,7 +75,7 @@ module Gecode
77
75
  def set_var(glb_domain, lub_domain, cardinality_range = nil)
78
76
  check_set_bounds(glb_domain, lub_domain)
79
77
 
80
- index = selected_space.new_set_vars(glb_domain, lub_domain,
78
+ index = variable_creation_space.new_set_vars(glb_domain, lub_domain,
81
79
  to_set_cardinality_range(cardinality_range)).first
82
80
  FreeSetVar.new(self, index)
83
81
  end
@@ -88,7 +86,7 @@ module Gecode
88
86
  check_set_bounds(glb_domain, lub_domain)
89
87
 
90
88
  variables = []
91
- selected_space.new_set_vars(glb_domain, lub_domain,
89
+ variable_creation_space.new_set_vars(glb_domain, lub_domain,
92
90
  to_set_cardinality_range(cardinality_range), count).each do |index|
93
91
  variables << FreeSetVar.new(self, index)
94
92
  end
@@ -102,7 +100,7 @@ module Gecode
102
100
  cardinality_range = nil)
103
101
  check_set_bounds(glb_domain, lub_domain)
104
102
 
105
- indices = selected_space.new_set_vars(glb_domain, lub_domain,
103
+ indices = variable_creation_space.new_set_vars(glb_domain, lub_domain,
106
104
  to_set_cardinality_range(cardinality_range), row_count*col_count)
107
105
  rows = []
108
106
  row_count.times do |i|
@@ -159,6 +157,12 @@ module Gecode
159
157
  return res
160
158
  end
161
159
 
160
+ # Starts tracking a variable that depends on the space. All variables
161
+ # created should call this method for their respective models.
162
+ def track_variable(variable)
163
+ (@variables ||= []) << variable
164
+ end
165
+
162
166
  protected
163
167
 
164
168
  # Gets a queue of objects that can be posted to the model's active_space
@@ -170,25 +174,19 @@ module Gecode
170
174
  private
171
175
 
172
176
  # Returns an enumeration of the specified domain arguments, which can
173
- # either be given as a range or a number of elements. Raises ArgumentError
174
- # if no arguments have been specified.
175
- def domain_enum(*domain_args)
176
- if domain_args.empty?
177
- raise ArgumentError, 'A domain has to be specified.'
178
- elsif domain_args.size > 1
179
- return domain_args
180
- else
181
- element = domain_args.first
182
- if element.respond_to?(:first) and element.respond_to?(:last) and
183
- element.respond_to?(:exclude_end?)
184
- if element.exclude_end?
185
- return element.first..(element.last - 1)
186
- else
187
- return element
188
- end
177
+ # either be given as a range, a single number, or an enumerable of elements.
178
+ def domain_enum(domain)
179
+ if domain.respond_to?(:first) and domain.respond_to?(:last) and
180
+ domain.respond_to?(:exclude_end?)
181
+ if domain.exclude_end?
182
+ return domain.first..(domain.last - 1)
189
183
  else
190
- return element..element
184
+ return domain
191
185
  end
186
+ elsif domain.kind_of? Enumerable
187
+ return domain
188
+ else
189
+ return domain..domain
192
190
  end
193
191
  end
194
192
 
@@ -232,5 +230,18 @@ module Gecode
232
230
  def selected_space
233
231
  @active_space ||= base_space
234
232
  end
233
+
234
+ # Retrieves the space that should be used for variable creation.
235
+ def variable_creation_space
236
+ @variable_creation_space || selected_space
237
+ end
238
+
239
+ # Refreshes all cached variables. This should be called if the variables
240
+ # in an existing space were changed.
241
+ def refresh_variables
242
+ @variables.each do |variable|
243
+ variable.refresh if variable.cached?
244
+ end
245
+ end
235
246
  end
236
247
  end