gecoder 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. data/CHANGES +11 -0
  2. data/README +12 -1
  3. data/example/example_helper.rb +1 -0
  4. data/example/magic_sequence.rb +43 -0
  5. data/example/queens.rb +43 -0
  6. data/example/raw_bindings.rb +42 -0
  7. data/example/send_more_money.rb +43 -0
  8. data/example/sudoku.rb +65 -0
  9. data/ext/missing.cpp +15 -21
  10. data/ext/missing.h +14 -20
  11. data/ext/vararray.cpp +14 -20
  12. data/ext/vararray.h +18 -22
  13. data/lib/gecoder/bindings/bindings.rb +1979 -1969
  14. data/lib/gecoder/interface/binding_changes.rb +123 -2
  15. data/lib/gecoder/interface/constraints/bool/boolean.rb +80 -65
  16. data/lib/gecoder/interface/constraints/bool_enum/boolean.rb +59 -0
  17. data/lib/gecoder/interface/constraints/bool_enum_constraints.rb +8 -0
  18. data/lib/gecoder/interface/constraints/bool_var_constraints.rb +42 -0
  19. data/lib/gecoder/interface/constraints/int/arithmetic.rb +21 -44
  20. data/lib/gecoder/interface/constraints/int/domain.rb +6 -4
  21. data/lib/gecoder/interface/constraints/int_enum/arithmetic.rb +18 -44
  22. data/lib/gecoder/interface/constraints/int_enum/count.rb +3 -18
  23. data/lib/gecoder/interface/constraints/int_enum/distinct.rb +4 -16
  24. data/lib/gecoder/interface/constraints/int_enum/element.rb +9 -20
  25. data/lib/gecoder/interface/constraints/int_var_constraints.rb +28 -0
  26. data/lib/gecoder/interface/constraints/set/cardinality.rb +56 -0
  27. data/lib/gecoder/interface/constraints/set/domain.rb +66 -0
  28. data/lib/gecoder/interface/constraints/set/relation.rb +125 -0
  29. data/lib/gecoder/interface/constraints/set_var_constraints.rb +37 -0
  30. data/lib/gecoder/interface/constraints.rb +229 -65
  31. data/lib/gecoder/interface/enum_wrapper.rb +42 -11
  32. data/lib/gecoder/interface/model.rb +75 -0
  33. data/lib/gecoder/interface/search.rb +4 -9
  34. data/lib/gecoder/interface/variables.rb +36 -2
  35. data/lib/gecoder/version.rb +1 -1
  36. data/specs/bool_var.rb +58 -0
  37. data/specs/constraints/arithmetic.rb +91 -90
  38. data/specs/constraints/bool_enum.rb +130 -0
  39. data/specs/constraints/boolean.rb +95 -2
  40. data/specs/constraints/cardinality.rb +127 -0
  41. data/specs/constraints/constraint_helper.rb +91 -0
  42. data/specs/constraints/constraints.rb +31 -0
  43. data/specs/constraints/element.rb +43 -72
  44. data/specs/constraints/{domain.rb → int_domain.rb} +4 -0
  45. data/specs/constraints/{relation.rb → int_relation.rb} +0 -0
  46. data/specs/constraints/set_domain.rb +165 -0
  47. data/specs/constraints/set_relation.rb +181 -0
  48. data/specs/enum_wrapper.rb +13 -2
  49. data/specs/int_var.rb +33 -1
  50. data/specs/model.rb +80 -0
  51. data/specs/set_var.rb +39 -0
  52. data/specs/spec_helper.rb +35 -0
  53. data/specs/tmp +11 -124
  54. data/tasks/distribution.rake +1 -1
  55. data/vendor/rust/rust/class.rb +10 -10
  56. data/vendor/rust/rust/constants.rb +1 -1
  57. data/vendor/rust/rust/function.rb +5 -5
  58. data/vendor/rust/rust/type.rb +1 -1
  59. data/vendor/rust/test/constants.rb +1 -0
  60. data/vendor/rust/test/cppclass.cc +5 -0
  61. data/vendor/rust/test/cppclass.hh +4 -0
  62. data/vendor/rust/test/lib/extension-test.rb +1 -1
  63. data/vendor/rust/test/operators.cc +41 -0
  64. data/vendor/rust/test/operators.hh +39 -0
  65. data/vendor/rust/test/operators.rb +39 -0
  66. data/vendor/rust/test/test-cwrapper.rb +3 -0
  67. data/vendor/rust/test/test-operators.rb +42 -0
  68. metadata +31 -4
@@ -21,16 +21,31 @@ module Gecode
21
21
  end
22
22
 
23
23
  # Creates the specified number of boolean variables in the space. Returns
24
- # the indices with which they can then be accessed using int_var.
24
+ # the indices with which they can then be accessed using bool_var.
25
25
  def new_bool_vars(count = 1)
26
26
  bool_var_store.new_vars(count)
27
27
  end
28
28
 
29
- # Gets the int variable with the specified index, nil if none exists.
29
+ # Gets the bool variable with the specified index, nil if none exists.
30
30
  def bool_var(index)
31
31
  bool_var_store[index]
32
32
  end
33
33
 
34
+ # Creates the specified number of set variables in the space with the
35
+ # specified domain for greatest lower bound and least upper bound
36
+ # (specified as either a range or enum). A range for the allowed
37
+ # cardinality of the set can also be specified, if none is specified, or
38
+ # nil is given, then the default range (anything) will be used. Returns
39
+ # the indices with which they can then be accessed using set_var.
40
+ def new_set_vars(*vars)
41
+ set_var_store.new_vars(*vars)
42
+ end
43
+
44
+ # Gets the set variable with the specified index, nil if none exists.
45
+ def set_var(index)
46
+ set_var_store[index]
47
+ end
48
+
34
49
  private
35
50
 
36
51
  # Retrieves the store used for integer variables. Creates one if none
@@ -50,6 +65,14 @@ module Gecode
50
65
  end
51
66
  return @bool_var_store
52
67
  end
68
+
69
+ # Retrieves the store used for set variables. Creates one if none exists.
70
+ def set_var_store
71
+ if @set_var_store.nil?
72
+ @set_var_store = Gecode::Util::SetVarStore.new(self)
73
+ end
74
+ return @set_var_store
75
+ end
53
76
  end
54
77
 
55
78
  class IntVar
@@ -67,6 +90,33 @@ module Gecode
67
90
  def true?
68
91
  val == 1
69
92
  end
93
+
94
+ def false?
95
+ val == 0
96
+ end
97
+ end
98
+
99
+ class SetVar
100
+ # Aliases to make method-names more ruby-like.
101
+ alias_method :assigned?, :assigned
102
+
103
+ alias_method :include_glb?, :contains
104
+ alias_method :include?, :contains
105
+ def include_lub?(element)
106
+ !notContains(element)
107
+ end
108
+
109
+ alias_method :glb_min, :glbMin
110
+ alias_method :glb_max, :glbMax
111
+ alias_method :lub_min, :lubMin
112
+ alias_method :lub_max, :lubMax
113
+
114
+ alias_method :glb_size, :glbSize
115
+ alias_method :val_size, :glbSize
116
+ alias_method :lub_size, :lubSize
117
+
118
+ alias_method :card_min, :cardMin
119
+ alias_method :card_max, :cardMax
70
120
  end
71
121
  end
72
122
 
@@ -209,5 +259,76 @@ module Gecode
209
259
  return arr
210
260
  end
211
261
  end
262
+
263
+ # A store in which int variables are created and stored.
264
+ class SetVarStore
265
+ include VarStoreMethods
266
+
267
+ private
268
+
269
+ # A string that identifies the array used by the store.
270
+ ARRAY_IDENTIFIER = 'set_array'
271
+
272
+ public
273
+
274
+ # Creates a store for the specified space with the specified capacit.
275
+ def initialize(space)
276
+ @space = space
277
+
278
+ @var_array = space.set_var_array(ARRAY_IDENTIFIER)
279
+ if @var_array.nil?
280
+ # Create a new one.
281
+ @var_array = new_storage_array(0)
282
+ end
283
+
284
+ @size = @var_array.size
285
+ @next_index = @size
286
+ end
287
+
288
+ # Creates the specified number of set variables in the space with the
289
+ # specified domain for greatest lower bound and least upper bound
290
+ # (specified as either a range or enum). A range for the allowed
291
+ # cardinality of the set can also be specified, if none is specified, or
292
+ # nil is given, then the default range (anything) will be used. Returns
293
+ # the indices with which they can then be accessed using set_var.
294
+ def new_vars(glb_domain, lub_domain, cardinality_range = nil, count = 1)
295
+ grow(@next_index + count) # See the design note for more information.
296
+
297
+ if cardinality_range.nil?
298
+ cardinality_range = 0..Gecode::Raw::Limits::Set::CARD_MAX
299
+ end
300
+
301
+ params = [@space]
302
+ params << domain_to_args(glb_domain)
303
+ params << domain_to_args(lub_domain)
304
+ params << cardinality_range.first << cardinality_range.last
305
+ count.times do |i|
306
+ @var_array[@next_index] = Gecode::Raw::SetVar.new(*params.flatten)
307
+ @next_index += 1
308
+ end
309
+
310
+ ((@next_index - count)...@next_index).to_a
311
+ end
312
+
313
+ private
314
+
315
+ # Transforms a lub or glb domain given as a range or enumeration into one
316
+ # or more parameters that describe the domain to Gecode::Raw::SetVar .
317
+ def domain_to_args(domain)
318
+ if domain.kind_of? Range
319
+ return domain.first, domain.last
320
+ else
321
+ elements = domain.to_a
322
+ return Gecode::Raw::IntSet.new(domain, domain.size)
323
+ end
324
+ end
325
+
326
+ # Creates a new storage array for bool variables.
327
+ def new_storage_array(new_size)
328
+ arr = Gecode::Raw::SetVarArray.new(@space, new_size)
329
+ @space.own(arr, ARRAY_IDENTIFIER)
330
+ return arr
331
+ end
332
+ end
212
333
  end
213
334
  end
@@ -7,71 +7,81 @@ module Gecode
7
7
  def &(var)
8
8
  Constraints::Bool::ExpressionNode.new(self, @model) & var
9
9
  end
10
+
11
+ def ^(var)
12
+ Constraints::Bool::ExpressionNode.new(self, @model) ^ var
13
+ end
14
+
15
+ def implies(var)
16
+ Constraints::Bool::ExpressionNode.new(self, @model).implies var
17
+ end
10
18
  end
11
19
 
20
+ # A module that gathers the classes and modules used in boolean constraints.
12
21
  module Constraints::Bool
22
+ # Describes a boolean expression (following after must*).
13
23
  class Expression
14
- def ==(expression)
15
- add_boolean_constraint(expression)
24
+ def ==(expression, options = {})
25
+ @params.update Gecode::Constraints::Util.decode_options(options)
26
+ @model.add_constraint BooleanConstraint.new(@model,
27
+ @params.update(:rhs => expression))
16
28
  end
17
29
  alias_comparison_methods
18
30
 
31
+ # Constrains the boolean expression to imply the specified expression.
32
+ def imply(expression, options = {})
33
+ @params.update Gecode::Constraints::Util.decode_options(options)
34
+ @params.update(:lhs => @params[:lhs].implies(expression), :rhs => true)
35
+ @model.add_constraint BooleanConstraint.new(@model, @params)
36
+ end
37
+
38
+ # Constrains the boolean expression to be true.
19
39
  def true
20
- # Bind parameters.
21
- lhs = @params[:lhs]
22
- unless lhs.respond_to? :to_minimodel_lin_exp
23
- lhs = ExpressionNode.new(lhs, @model)
24
- end
25
-
40
+ @params.update Gecode::Constraints::Util.decode_options({})
26
41
  @model.add_constraint BooleanConstraint.new(@model,
27
- @params.update(:expression => lhs.to_minimodel_lin_exp))
42
+ @params.update(:rhs => true))
28
43
  end
29
44
 
45
+ # Constrains the boolean expression to be false.
30
46
  def false
31
- # Bind parameters.
32
- lhs = @params[:lhs]
33
- unless lhs.respond_to? :to_minimodel_lin_exp
34
- lhs = ExpressionNode.new(lhs, @model)
35
- end
36
-
37
- @params.update(:expression => Gecode::Raw::MiniModel::BoolExpr.new(
38
- lhs.to_minimodel_lin_exp, Gecode::Raw::MiniModel::BoolExpr::BT_NOT))
39
- @model.add_constraint BooleanConstraint.new(@model, @params)
40
- end
41
-
42
- private
43
-
44
- # Adds the boolean constraint corresponding to equivalence between the
45
- # left and right hand sides.
46
- #
47
- # Raises TypeError if the element is of a type that doesn't allow a
48
- # relation to be specified.
49
- def add_boolean_constraint(right_hand_side = nil)
50
- # Bind parameters.
51
- lhs = @params[:lhs]
52
- unless lhs.respond_to? :to_minimodel_lin_exp
53
- lhs = ExpressionNode.new(lhs, @model)
54
- end
55
- unless right_hand_side.respond_to? :to_minimodel_lin_exp
56
- right_hand_side = ExpressionNode.new(right_hand_side, @model)
57
- end
58
-
59
- expression = ExpressionTree.new(lhs, right_hand_side,
60
- Gecode::Raw::MiniModel::BoolExpr::BT_EQV)
61
- @model.add_constraint BooleanConstraint.new(@model,
62
- @params.update(:expression => expression.to_minimodel_lin_exp))
47
+ @params[:negate] = !@params[:negate]
48
+ self.true
63
49
  end
64
50
  end
65
51
 
66
52
  # Describes a boolean constraint.
67
53
  class BooleanConstraint < Gecode::Constraints::ReifiableConstraint
68
54
  def post
69
- unless @params[:reif].nil?
70
- @params[:expression] = Gecode::Raw::MiniModel::BoolExpr.new(
71
- @params[:expression], Gecode::Raw::MiniModel::BoolExpr::BT_EQV,
72
- Gecode::Raw::MiniModel::BoolExpr.new(@params[:reif].bind))
55
+ lhs, rhs, negate, strength, reif_var = @params.values_at(:lhs, :rhs,
56
+ :negate, :strength, :reif)
57
+ space = (lhs.model || rhs.model).active_space
58
+
59
+ # TODO: It should be possible to reduce the number of necessary
60
+ # variables and constraints a bit by altering the way that the top node
61
+ # is posted, using its constraint for reification etc when possible.
62
+
63
+ if rhs.respond_to? :bind
64
+ if reif_var.nil?
65
+ Gecode::Raw::bool_eqv(space, lhs.bind, rhs.bind, !negate, strength)
66
+ else
67
+ if negate
68
+ Gecode::Raw::bool_xor(space, lhs.bind, rhs.bind, reif_var.bind,
69
+ strength)
70
+ else
71
+ Gecode::Raw::bool_eqv(space, lhs.bind, rhs.bind, reif_var.bind,
72
+ strength)
73
+ end
74
+ end
75
+ else
76
+ should_hold = !negate & rhs
77
+ if reif_var.nil?
78
+ Gecode::Raw::MiniModel::BoolExpr.new(lhs.bind).post(space,
79
+ should_hold)
80
+ else
81
+ Gecode::Raw::bool_eqv(space, lhs.bind, reif_var.bind, should_hold,
82
+ strength)
83
+ end
73
84
  end
74
- @params[:expression].post(@model.active_space, !@params[:negate])
75
85
  end
76
86
  end
77
87
 
@@ -82,11 +92,13 @@ module Gecode
82
92
 
83
93
  private
84
94
 
85
- # Maps the names of the methods to the corresponding bool operation type
86
- # in Gecode.
95
+ # Maps the names of the methods to the corresponding bool constraint in
96
+ # Gecode.
87
97
  OPERATION_TYPES = {
88
- :| => Gecode::Raw::MiniModel::BoolExpr::BT_OR,
89
- :& => Gecode::Raw::MiniModel::BoolExpr::BT_AND
98
+ :| => :bool_or,
99
+ :& => :bool_and,
100
+ :^ => :bool_xor,
101
+ :implies => :bool_imp
90
102
  }
91
103
 
92
104
  public
@@ -97,7 +109,12 @@ module Gecode
97
109
  unless expression.kind_of? ExpressionTree
98
110
  expression = ExpressionNode.new(expression)
99
111
  end
100
- ExpressionTree.new(self, expression, #{operation})
112
+ ExpressionTree.new(self, expression) do |model, var1, var2|
113
+ new_var = model.bool_var
114
+ Gecode::Raw::#{operation}(model.active_space, var1.bind, var2.bind,
115
+ new_var.bind, Gecode::Raw::ICL_DEF)
116
+ new_var
117
+ end
101
118
  end
102
119
  end_code
103
120
  end
@@ -116,18 +133,17 @@ module Gecode
116
133
  class ExpressionTree
117
134
  include OperationMethods
118
135
 
119
- # Constructs a new expression with the specified variable
120
- def initialize(left_node, right_node, operation)
121
- @left = left_node
122
- @right = right_node
123
- @operation = operation
136
+ # Constructs a new expression with the specified nodes. The proc should
137
+ # take a model followed by two variables and return a new variable.
138
+ def initialize(left_tree, right_tree, &block)
139
+ @left = left_tree
140
+ @right = right_tree
141
+ @bind_proc = block
124
142
  end
125
143
 
126
- # Converts the boolean expression to an instance of
127
- # Gecode::Raw::MiniModel::BoolExpr
128
- def to_minimodel_lin_exp
129
- Gecode::Raw::MiniModel::BoolExpr.new(@left.to_minimodel_lin_exp,
130
- @operation, @right.to_minimodel_lin_exp)
144
+ # Returns a bound boolean variable representing the expression.
145
+ def bind
146
+ @bind_proc.call(model, @left, @right).bind
131
147
  end
132
148
 
133
149
  # Fetches the space that the expression's variables is in.
@@ -147,10 +163,9 @@ module Gecode
147
163
  @model = model
148
164
  end
149
165
 
150
- # Converts the linear expression to an instance of
151
- # Gecode::Raw::MiniModel::BoolExpr
152
- def to_minimodel_lin_exp
153
- Gecode::Raw::MiniModel::BoolExpr.new(@value.bind)
166
+ # Returns a bound boolean variable representing the expression.
167
+ def bind
168
+ @value.bind
154
169
  end
155
170
  end
156
171
  end
@@ -0,0 +1,59 @@
1
+ module Gecode
2
+ module BoolEnumMethods
3
+ # Produces an expression that can be handled as if it was a variable
4
+ # representing the conjunction of all boolean variables in the enumeration.
5
+ def conjunction
6
+ return Gecode::Constraints::BoolEnum::ConjunctionStub.new(
7
+ @model, :lhs => self)
8
+ end
9
+
10
+ # Produces an expression that can be handled as if it was a variable
11
+ # representing the disjunction of all boolean variables in the enumeration.
12
+ def disjunction
13
+ return Gecode::Constraints::BoolEnum::DisjunctionStub.new(
14
+ @model, :lhs => self)
15
+ end
16
+ end
17
+
18
+ module Constraints::BoolEnum
19
+ # Describes an expression stub started with a bool var enum following by
20
+ # #conjunction.
21
+ class ConjunctionStub < Gecode::Constraints::Bool::CompositeStub
22
+ def constrain_equal(variable, params)
23
+ enum, strength = @params.values_at(:lhs, :strength)
24
+ if variable.nil?
25
+ variable = @model.bool_var
26
+ end
27
+
28
+ if variable.respond_to? :bind
29
+ bound = variable.bind
30
+ else
31
+ bound = variable
32
+ end
33
+ Gecode::Raw::bool_and(@model.active_space, enum.to_bool_var_array,
34
+ bound, strength)
35
+ return variable
36
+ end
37
+ end
38
+
39
+ # Describes an expression stub started with a bool var enum following by
40
+ # #disjunction.
41
+ class DisjunctionStub < Gecode::Constraints::Bool::CompositeStub
42
+ def constrain_equal(variable, params)
43
+ enum, strength = @params.values_at(:lhs, :strength)
44
+ if variable.nil?
45
+ variable = @model.bool_var
46
+ end
47
+
48
+ if variable.respond_to? :bind
49
+ bound = variable.bind
50
+ else
51
+ bound = variable
52
+ end
53
+ Gecode::Raw::bool_or(@model.active_space, enum.to_bool_var_array,
54
+ bound, strength)
55
+ return variable
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,8 @@
1
+ module Gecode
2
+ # A module containing constraints that have enumerations of boolean variables
3
+ # as left hand side.
4
+ module Constraints::BoolEnum
5
+ end
6
+ end
7
+
8
+ require 'gecoder/interface/constraints/bool_enum/boolean'
@@ -17,6 +17,48 @@ module Gecode
17
17
  # Describes a boolean expression.
18
18
  class Expression < Gecode::Constraints::Expression
19
19
  end
20
+
21
+ # A composite expression which is an bool expression with a left hand side
22
+ # resulting from a previous constraint.
23
+ class CompositeExpression < Gecode::Constraints::CompositeExpression
24
+ # The block given should take three parameters. The first is the variable
25
+ # that should be the left hand side, if it's nil then a new one should be
26
+ # created. The second is the has of parameters. The block should return
27
+ # the variable used as left hand side.
28
+ def initialize(model, params, &block)
29
+ super(Expression, Gecode::FreeIntVar, model, params, &block)
30
+ end
31
+
32
+ # Override to also deal with constant booleans.
33
+ def true(options = {})
34
+ # We don't need any additional constraints.
35
+ @params.update Gecode::Constraints::Util.decode_options(options)
36
+ @proc.call(!@params[:negate], @params)
37
+ end
38
+
39
+ # Override to also deal with constant booleans.
40
+ def false(options = {})
41
+ # We don't need any additional constraints.
42
+ @params.update Gecode::Constraints::Util.decode_options(options)
43
+ @proc.call(@params[:negate], @params)
44
+ end
45
+ end
46
+
47
+ # Describes a stub that produces an int variable, which can then be used with
48
+ # the normal bool variable constraints. An example for boolean composite
49
+ # constraints would be conjunction.
50
+ #
51
+ # bools.conjunction.must == b1 | b2
52
+ #
53
+ # "bools.conjunction" produces a bool variable which the constraint
54
+ # ".must == b1 | b2" is then applied to.In the above case two constraints
55
+ # (and one temporary variable) are required, but in the case of equality
56
+ # only one constraint is required.
57
+ class CompositeStub < Gecode::Constraints::CompositeStub
58
+ def initialize(model, params)
59
+ super(CompositeExpression, model, params)
60
+ end
61
+ end
20
62
  end
21
63
  end
22
64
 
@@ -22,56 +22,33 @@ end
22
22
  module Gecode::Constraints::Int::Arithmetic
23
23
  # Describes an expression stub started with an integer variable followed by
24
24
  # #abs .
25
- class AbsExpressionStub < Gecode::Constraints::ExpressionStub
26
- include Gecode::Constraints::LeftHandSideMethods
27
-
28
- private
29
-
30
- # Produces a proxy expression for the lhs module.
31
- def expression(params)
32
- # We extract the integer and continue as if it had been specified as
33
- # left hand side. This might be elegant, but it could get away with
34
- # fewer constraints at times (when only equality is used) and
35
- # propagation strength can't be specified.
36
- # TODO: cut down on the number of constraints when possible. See if
37
- # there's some neat way of getting the above remarks.
25
+ class AbsExpressionStub < Gecode::Constraints::Int::CompositeStub
26
+ def constrain_equal(variable, params)
27
+ lhs, strength = @params.values_at(:lhs, :strength)
28
+ if variable.nil?
29
+ variable = @model.int_var(lhs.min..lhs.max)
30
+ end
38
31
 
39
- params.update(@params)
40
- lhs = params[:lhs]
41
- proxy = @model.int_var(lhs.min..lhs.max)
42
- lhs = lhs.bind
43
-
44
- Gecode::Raw::abs(@model.active_space, lhs, proxy.bind,
45
- Gecode::Raw::ICL_DEF)
46
- Gecode::Constraints::Int::Expression.new(@model,
47
- params.update(:lhs => proxy))
32
+ Gecode::Raw::abs(@model.active_space, lhs.bind, variable.bind, strength)
33
+ return variable
48
34
  end
49
35
  end
50
36
 
51
37
  # Describes an expression stub started with an integer variable followed by
52
38
  # #* .
53
- class MultExpressionStub < Gecode::Constraints::ExpressionStub
54
- include Gecode::Constraints::LeftHandSideMethods
55
-
56
- private
57
-
58
- # Produces a proxy expression for the lhs module.
59
- def expression(params)
60
- # We extract the integer and continue as if it had been specified as
61
- # left hand side. This might be elegant, but it could get away with
62
- # fewer constraints at times (when only equality is used) and
63
- # propagation strength can't be specified.
64
- # TODO: cut down on the number of constraints when possible. See if
65
- # there's some neat way of getting the above remarks.
66
-
67
- params.update(@params)
68
- lhs, var = params.values_at(:lhs, :var)
69
- proxy = @model.int_var(-(lhs.min*var.min).abs..(lhs.max*var.max).abs) # Sloppy
70
-
71
- Gecode::Raw::mult(@model.active_space, lhs.bind, var.bind, proxy.bind,
72
- Gecode::Raw::ICL_DEF)
73
- Gecode::Constraints::Int::Expression.new(@model,
74
- params.update(:lhs => proxy))
39
+ class MultExpressionStub < Gecode::Constraints::Int::CompositeStub
40
+ def constrain_equal(variable, params)
41
+ lhs, lhs2, strength = @params.values_at(:lhs, :var, :strength)
42
+ if variable.nil?
43
+ a_min = lhs.min; a_max = lhs.max
44
+ b_min = lhs2.min; b_max = lhs2.max
45
+ products = [a_min*b_min, a_min*b_max, a_max*b_min, a_max*b_max]
46
+ variable = @model.int_var(products.min..products.max)
47
+ end
48
+
49
+ Gecode::Raw::mult(@model.active_space, lhs.bind, lhs2.bind,
50
+ variable.bind, strength)
51
+ return variable
75
52
  end
76
53
  end
77
54
  end
@@ -6,9 +6,11 @@ module Gecode::Constraints::Int
6
6
  @params[:domain] = domain
7
7
  if domain.kind_of? Range
8
8
  @model.add_constraint Domain::RangeDomainConstraint.new(@model, @params)
9
- else
10
- @model.add_constraint Domain::NonRangeDomainConstraint.new(@model,
9
+ elsif domain.kind_of?(Enumerable) and domain.all?{ |e| e.kind_of? Fixnum }
10
+ @model.add_constraint Domain::EnumDomainConstraint.new(@model,
11
11
  @params)
12
+ else
13
+ raise TypeError, "Expected integer enumerable, got #{domain.class}."
12
14
  end
13
15
  end
14
16
  end
@@ -29,8 +31,8 @@ module Gecode::Constraints::Int
29
31
  negate_using_reification
30
32
  end
31
33
 
32
- # Describes a non-range domain constraint.
33
- class NonRangeDomainConstraint < Gecode::Constraints::ReifiableConstraint
34
+ # Describes a enum domain constraint.
35
+ class EnumDomainConstraint < Gecode::Constraints::ReifiableConstraint
34
36
  def post
35
37
  space = @model.active_space
36
38
 
@@ -17,56 +17,30 @@ end
17
17
  # A module that gathers the classes and modules used by arithmetic constraints.
18
18
  module Gecode::Constraints::IntEnum::Arithmetic
19
19
  # Describes an expression stub started with an int var enum following by #max.
20
- class MaxExpressionStub < Gecode::Constraints::ExpressionStub
21
- include Gecode::Constraints::LeftHandSideMethods
22
-
23
- private
24
-
25
- # Produces an expression for the lhs module.
26
- def expression(params)
27
- # We extract the integer and continue as if it had been specified as
28
- # left hand side. This might be elegant, but it could get away with
29
- # fewer constraints at times (when only equality is used) and
30
- # propagation strength can't be specified.
31
- # TODO: cut down on the number of constraints when possible. See if
32
- # there's some neat way of getting the above remarks.
20
+ class MaxExpressionStub < Gecode::Constraints::Int::CompositeStub
21
+ def constrain_equal(variable, params)
22
+ enum, strength = @params.values_at(:lhs, :strength)
23
+ if variable.nil?
24
+ variable = @model.int_var(enum.domain_range)
25
+ end
33
26
 
34
- params.update(@params)
35
- lhs = params[:lhs]
36
- proxy = @model.int_var(lhs.domain_range)
37
- lhs = lhs.to_int_var_array
38
-
39
- Gecode::Raw::max(@model.active_space, lhs, proxy.bind,
40
- Gecode::Raw::ICL_DEF)
41
- Gecode::Constraints::Int::Expression.new(@model,
42
- params.update(:lhs => proxy))
27
+ Gecode::Raw::max(@model.active_space, enum.to_int_var_array,
28
+ variable.bind, strength)
29
+ return variable
43
30
  end
44
31
  end
45
32
 
46
33
  # Describes an expression stub started with an int var enum following by #min.
47
- class MinExpressionStub < Gecode::Constraints::ExpressionStub
48
- include Gecode::Constraints::LeftHandSideMethods
49
-
50
- private
51
-
52
- # Produces an expression for the lhs module.
53
- def expression(params)
54
- # We extract the integer and continue as if it had been specified as
55
- # left hand side. This might be elegant, but it could get away with
56
- # fewer constraints at times (when only equality is used) and
57
- # propagation strength can't be specified.
58
- # TODO: cut down on the number of constraints when possible. See if
59
- # there's some neat way of getting the above remarks.
60
-
61
- params.update(@params)
62
- lhs = params[:lhs]
63
- proxy = @model.int_var(lhs.domain_range)
64
- lhs = lhs.to_int_var_array
34
+ class MinExpressionStub < Gecode::Constraints::Int::CompositeStub
35
+ def constrain_equal(variable, params)
36
+ enum, strength = @params.values_at(:lhs, :strength)
37
+ if variable.nil?
38
+ variable = @model.int_var(enum.domain_range)
39
+ end
65
40
 
66
- Gecode::Raw::min(@model.active_space, lhs, proxy.bind,
67
- Gecode::Raw::ICL_DEF)
68
- Gecode::Constraints::Int::Expression.new(@model,
69
- params.update(:lhs => proxy))
41
+ Gecode::Raw::min(@model.active_space, enum.to_int_var_array,
42
+ variable.bind, strength)
43
+ return variable
70
44
  end
71
45
  end
72
46
  end