gecoder 0.3.0 → 0.4.0

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 (56) hide show
  1. data/CHANGES +17 -2
  2. data/README +7 -1
  3. data/Rakefile +4 -0
  4. data/lib/gecoder/interface/constraints/bool/boolean.rb +1 -4
  5. data/lib/gecoder/interface/constraints/int/arithmetic.rb +77 -0
  6. data/lib/gecoder/interface/constraints/int/domain.rb +50 -0
  7. data/lib/gecoder/interface/constraints/int/linear.rb +12 -44
  8. data/lib/gecoder/interface/constraints/int_enum/arithmetic.rb +72 -0
  9. data/lib/gecoder/interface/constraints/int_enum/channel.rb +32 -0
  10. data/lib/gecoder/interface/constraints/int_enum/count.rb +90 -0
  11. data/lib/gecoder/interface/constraints/int_enum/distinct.rb +3 -8
  12. data/lib/gecoder/interface/constraints/int_enum/element.rb +75 -0
  13. data/lib/gecoder/interface/constraints/int_enum/equality.rb +31 -0
  14. data/lib/gecoder/interface/constraints/int_enum/sort.rb +104 -0
  15. data/lib/gecoder/interface/constraints/int_enum_constraints.rb +6 -0
  16. data/lib/gecoder/interface/constraints/int_var_constraints.rb +2 -0
  17. data/lib/gecoder/interface/constraints/reifiable_constraints.rb +21 -0
  18. data/lib/gecoder/interface/constraints.rb +57 -6
  19. data/lib/gecoder/interface/enum_matrix.rb +64 -0
  20. data/lib/gecoder/interface/enum_wrapper.rb +33 -5
  21. data/lib/gecoder/interface/model.rb +36 -6
  22. data/lib/gecoder/interface.rb +1 -0
  23. data/lib/gecoder/version.rb +4 -0
  24. data/lib/gecoder.rb +1 -0
  25. data/specs/binding_changes.rb +72 -0
  26. data/specs/bool_var.rb +20 -0
  27. data/specs/branch.rb +104 -0
  28. data/specs/constraints/arithmetic.rb +227 -0
  29. data/specs/constraints/boolean.rb +132 -0
  30. data/specs/constraints/channel.rb +55 -0
  31. data/specs/constraints/constraint_helper.rb +48 -0
  32. data/specs/constraints/constraints.rb +28 -0
  33. data/specs/constraints/count.rb +99 -0
  34. data/specs/constraints/distinct.rb +99 -0
  35. data/specs/constraints/domain.rb +56 -0
  36. data/specs/constraints/element.rb +128 -0
  37. data/specs/constraints/equality.rb +30 -0
  38. data/specs/constraints/linear.rb +166 -0
  39. data/specs/constraints/reification_sugar.rb +92 -0
  40. data/specs/constraints/relation.rb +72 -0
  41. data/specs/constraints/sort.rb +173 -0
  42. data/specs/enum_matrix.rb +43 -0
  43. data/specs/enum_wrapper.rb +100 -0
  44. data/specs/int_var.rb +108 -0
  45. data/specs/model.rb +84 -0
  46. data/specs/search.rb +157 -0
  47. data/specs/spec_helper.rb +63 -0
  48. data/specs/tmp +135 -0
  49. data/tasks/all_tasks.rb +1 -0
  50. data/tasks/distribution.rake +64 -0
  51. data/tasks/rcov.rake +17 -0
  52. data/tasks/specs.rake +16 -0
  53. data/tasks/svn.rake +11 -0
  54. data/tasks/website.rake +58 -0
  55. data/vendor/rust/include/rust_conversions.hh +1 -2
  56. metadata +53 -2
data/CHANGES CHANGED
@@ -1,9 +1,25 @@
1
+ == Version 0.4.0
2
+ This release adds most of the constraints supported by Gecode for integer
3
+ variables.
4
+
5
+ * [#11861] Fixed a bug stopping the creating of int variables with non-range domains.
6
+ * Added domain constraints for int variables.
7
+ * Added equality constraint for int enums.
8
+ * Matrices of integer and boolean variables can now be created using Model#int_var_matrix Model#bool_var_matrix.
9
+ * Added channel constraint for int enums.
10
+ * Added element constraints (variable array access).
11
+ * Added count constraints.
12
+ * Added sortedness constraints.
13
+ * Added arithmetic constraints (min, max, abs and variable multiplication).
14
+
1
15
  == Version 0.3.0
16
+ This release fleshes out the existing constraints with things such as
17
+ reification and adds boolean variables and their basic constraints.
2
18
 
3
19
  * The constructor of Gecode::Model no longer has to be called by classes inheriting from it.
4
20
  * Added Model#reset! which resets a model after search.
5
21
  * Added Model#solution which passes the first solution to a block and returns the result of that block.
6
- * Added Model#each_soltion which iterates over each solution.
22
+ * Added Model#each_solution which iterates over each solution.
7
23
  * Added boolean variables. They are created using Model#bool_var and Model#bool_var_array .
8
24
  * Added two options to constraints: propagation strength and reification variable.
9
25
  * Linear and simple relation constraints can now also be specified using #equal, #equal_to, #greater, #greater_than,... in addition to comparison operators.
@@ -13,7 +29,6 @@
13
29
  * Added syntactic sugar for combining reifiable constraints with | and &.
14
30
 
15
31
  == Version 0.2.0
16
-
17
32
  This is the first release of Gecode/R, a Ruby interface to Gecode.
18
33
 
19
34
  * Added support for finite domain integers.
data/README CHANGED
@@ -25,4 +25,10 @@ instructions.
25
25
  === Building the gem
26
26
 
27
27
  rake gem
28
- gem install pkg/gecoder-0.x.x.gem
28
+ gem install pkg/gecoder-0.x.x.gem
29
+
30
+ == Running the tests
31
+
32
+ rake specs
33
+
34
+ Requires RSpec (1.0.5, but other version should hopefully work).
data/Rakefile CHANGED
@@ -4,3 +4,7 @@ require 'rake/rdoctask'
4
4
  require 'rake/gempackagetask'
5
5
 
6
6
  require 'tasks/all_tasks'
7
+ task :default => [:verify_rcov]
8
+
9
+ desc 'Performs the tasks necessary when releasing'
10
+ task :release => [:publish_website, :publish_packages, :tag]
@@ -10,14 +10,11 @@ module Gecode
10
10
  end
11
11
 
12
12
  module Constraints::Bool
13
- # Add some relation selection based on whether the expression is negated.
14
- alias_method :pre_bool_rel_initialize, :initialize
15
13
  class Expression
16
14
  def ==(expression)
17
15
  add_boolean_constraint(expression)
18
16
  end
19
- alias_method :equal, :==
20
- alias_method :equal_to, :==
17
+ alias_comparison_methods
21
18
 
22
19
  def true
23
20
  # Bind parameters.
@@ -0,0 +1,77 @@
1
+ class Gecode::FreeIntVar
2
+ # Initiates an arithmetic absolute value constraint.
3
+ def abs
4
+ Gecode::Constraints::Int::Arithmetic::AbsExpressionStub.new(@model,
5
+ :lhs => self)
6
+ end
7
+
8
+ # Creates a linear expression where the int variable is multiplied with
9
+ # a constant integer.
10
+ alias_method :pre_arith_mult, :* if instance_methods.include? '*'
11
+ def *(var)
12
+ if var.kind_of? Gecode::FreeIntVar
13
+ Gecode::Constraints::Int::Arithmetic::MultExpressionStub.new(
14
+ @model, :lhs => self, :var => var)
15
+ else
16
+ pre_arith_mult(var) if respond_to? :pre_arith_mult
17
+ end
18
+ end
19
+ end
20
+
21
+ # A module that gathers the classes and modules used by arithmetic constraints.
22
+ module Gecode::Constraints::Int::Arithmetic
23
+ # Describes an expression stub started with an integer variable followed by
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.
38
+
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))
48
+ end
49
+ end
50
+
51
+ # Describes an expression stub started with an integer variable followed by
52
+ # #* .
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))
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,50 @@
1
+ module Gecode::Constraints::Int
2
+ class Expression
3
+ # Creates a domain constraint using the specified domain.
4
+ def in(domain, options = {})
5
+ @params.update(Gecode::Constraints::Util.decode_options(options))
6
+ @params[:domain] = domain
7
+ if domain.kind_of? Range
8
+ @model.add_constraint Domain::RangeDomainConstraint.new(@model, @params)
9
+ else
10
+ @model.add_constraint Domain::NonRangeDomainConstraint.new(@model,
11
+ @params)
12
+ end
13
+ end
14
+ end
15
+
16
+ # A module that gathers the classes and modules used in domain constraints.
17
+ module Domain
18
+ # Describes a range domain constraint.
19
+ class RangeDomainConstraint < Gecode::Constraints::ReifiableConstraint
20
+ def post
21
+ var, domain, reif_var, strength = @params.values_at(:lhs, :domain,
22
+ :reif, :strength)
23
+ (params = []) << var.bind
24
+ params << domain.first << domain.last
25
+ params << reif_var.bind if reif_var.respond_to? :bind
26
+ params << strength
27
+ Gecode::Raw::dom(@model.active_space, *params)
28
+ end
29
+ negate_using_reification
30
+ end
31
+
32
+ # Describes a non-range domain constraint.
33
+ class NonRangeDomainConstraint < Gecode::Constraints::ReifiableConstraint
34
+ def post
35
+ space = @model.active_space
36
+
37
+ var, domain, reif_var, strength = @params.values_at(:lhs, :domain,
38
+ :reif, :strength)
39
+ domain = domain.to_a
40
+
41
+ (params = []) << var.bind
42
+ params << Gecode::Raw::IntSet.new(domain, domain.size)
43
+ params << reif_var.bind if reif_var.respond_to? :bind
44
+ params << strength
45
+ Gecode::Raw::dom(space, *params)
46
+ end
47
+ negate_using_reification
48
+ end
49
+ end
50
+ end
@@ -8,9 +8,14 @@ module Gecode
8
8
 
9
9
  # Creates a linear expression where the int variable is multiplied with
10
10
  # a constant integer.
11
+ alias_method :pre_linear_mult, :* if instance_methods.include? '*'
11
12
  def *(int)
12
- Gecode::Constraints::Int::Linear::ExpressionNode.new(self,
13
- @model) * int
13
+ if int.kind_of? Fixnum
14
+ Gecode::Constraints::Int::Linear::ExpressionNode.new(self,
15
+ @model) * int
16
+ else
17
+ pre_linear_mult(int) if respond_to? :pre_linear_mult
18
+ end
14
19
  end
15
20
 
16
21
  # Creates a linear expression where the specified variable is subtracted
@@ -23,55 +28,24 @@ module Gecode
23
28
 
24
29
  module Constraints::Int
25
30
  class Expression
26
- private
27
-
28
- # Maps the names of the methods to the corresponding integer relation
29
- # type in Gecode.
30
- RELATION_TYPES = {
31
- :== => Gecode::Raw::IRT_EQ,
32
- :<= => Gecode::Raw::IRT_LQ,
33
- :< => Gecode::Raw::IRT_LE,
34
- :>= => Gecode::Raw::IRT_GQ,
35
- :> => Gecode::Raw::IRT_GR }
36
- # The same as above, but negated.
37
- NEGATED_RELATION_TYPES = {
38
- :== => Gecode::Raw::IRT_NQ,
39
- :<= => Gecode::Raw::IRT_GR,
40
- :< => Gecode::Raw::IRT_GQ,
41
- :>= => Gecode::Raw::IRT_LE,
42
- :> => Gecode::Raw::IRT_LQ
43
- }
44
-
45
- # Various method aliases for the class. Maps the original name to an
46
- # array of aliases.
47
- METHOD_ALIASES = {
48
- :== => [:equal, :equal_to],
49
- :> => [:greater, :greater_than],
50
- :>= => [:greater_or_equal, :greater_than_or_equal_to],
51
- :< => [:less, :less_than],
52
- :<= => [:less_or_equal, :less_than_or_equal_to]
53
- }
54
-
55
- public
56
-
57
31
  # Add some relation selection based on whether the expression is negated.
58
32
  alias_method :pre_linear_initialize, :initialize
59
33
  def initialize(model, params)
60
34
  pre_linear_initialize(model, params)
61
35
  unless params[:negate]
62
- @method_relations = RELATION_TYPES
36
+ @method_relations = Constraints::Util::RELATION_TYPES
63
37
  else
64
- @method_relations = NEGATED_RELATION_TYPES
38
+ @method_relations = Constraints::Util::NEGATED_RELATION_TYPES
65
39
  end
66
40
  end
67
41
 
68
42
  # Define the relation methods.
69
- RELATION_TYPES.each_key do |name|
43
+ Constraints::Util::RELATION_TYPES.each_key do |name|
70
44
  module_eval <<-"end_code"
71
45
  def #{name}(expression, options = {})
72
46
  relation = @method_relations[:#{name}]
73
47
  @params.update(
74
- Gecode::Constraints::OptionUtil.decode_options(options))
48
+ Gecode::Constraints::Util.decode_options(options))
75
49
  if self.simple_expression? and simple_expression?(expression)
76
50
  # A relation constraint is enough.
77
51
  add_relation_constraint(relation, expression)
@@ -81,13 +55,7 @@ module Gecode
81
55
  end
82
56
  end_code
83
57
  end
84
-
85
- # Various aliases.
86
- METHOD_ALIASES.each_pair do |orig, alias_names|
87
- alias_names.each do |name|
88
- alias_method name, orig
89
- end
90
- end
58
+ alias_comparison_methods
91
59
 
92
60
  protected
93
61
 
@@ -0,0 +1,72 @@
1
+ module Gecode::IntEnumMethods
2
+ # Starts an arithmetic max constraint. This overrides the normal enum max, but
3
+ # that's not a problem since variables are not implemented to be comparable.
4
+ def max
5
+ return Gecode::Constraints::IntEnum::Arithmetic::MaxExpressionStub.new(
6
+ @model, :lhs => self)
7
+ end
8
+
9
+ # Starts an arithmetic min constraint. This overrides the normal enum min, but
10
+ # that's not a problem since variables are not implemented to be comparable.
11
+ def min
12
+ return Gecode::Constraints::IntEnum::Arithmetic::MinExpressionStub.new(
13
+ @model, :lhs => self)
14
+ end
15
+ end
16
+
17
+ # A module that gathers the classes and modules used by arithmetic constraints.
18
+ module Gecode::Constraints::IntEnum::Arithmetic
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.
33
+
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))
43
+ end
44
+ end
45
+
46
+ # 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
65
+
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))
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,32 @@
1
+ module Gecode::Constraints::IntEnum
2
+ class Expression
3
+ # Posts a channel constraint on the variables in the enum with the specified
4
+ # other enum.
5
+ def channel(enum, options = {})
6
+ if @params[:negate]
7
+ raise Gecode::MissingConstraintError, 'A negated channel constraint ' +
8
+ 'is not implemented.'
9
+ end
10
+
11
+ @params.update(Gecode::Constraints::Util.decode_options(options))
12
+ @params.update(:rhs => enum)
13
+ @model.add_constraint Channel::ChannelConstraint.new(@model, @params)
14
+ end
15
+ end
16
+
17
+ # A module that gathers the classes and modules used in channel constraints.
18
+ module Channel
19
+ # Describes a channel constraint.
20
+ class ChannelConstraint < Gecode::Constraints::Constraint
21
+ def post
22
+ lhs, rhs, strength = @params.values_at(:lhs, :rhs, :strength)
23
+
24
+ # Bind both sides.
25
+ lhs = lhs.to_int_var_array
26
+ rhs = rhs.to_int_var_array
27
+
28
+ Gecode::Raw::channel(@model.active_space, lhs, rhs, strength)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,90 @@
1
+ module Gecode
2
+ module IntEnumMethods
3
+ # Specifies that a specific element should be counted, starting a count
4
+ # constraint. The element can be either an int var or a fixnum.
5
+ def count(element)
6
+ unless element.kind_of?(FreeIntVar) or element.kind_of?(Fixnum)
7
+ raise TypeError, 'Elements used with count can not be of type ' +
8
+ "#{element.class}."
9
+ end
10
+ params = {:lhs => self, :element => element}
11
+ return Gecode::Constraints::IntEnum::Count::ExpressionStub.new(
12
+ @model, params)
13
+ end
14
+ end
15
+ end
16
+
17
+ # A module that gathers the classes and modules used in count constraints.
18
+ module Gecode::Constraints::IntEnum::Count
19
+
20
+
21
+ # Describes an expression stub started with an int var enum followed by
22
+ # #count .
23
+ class ExpressionStub < Gecode::Constraints::ExpressionStub
24
+ include Gecode::Constraints::LeftHandSideMethods
25
+
26
+ private
27
+
28
+ # Produces an expression with the element for the lhs module.
29
+ def expression(params)
30
+ params.update(@params)
31
+ Gecode::Constraints::IntEnum::Count::Expression.new(@model, params)
32
+ end
33
+ end
34
+
35
+ # Describes an expression
36
+ class Expression < Gecode::Constraints::IntEnum::Expression
37
+ def initialize(model, params)
38
+ super
39
+ unless params[:negate]
40
+ @method_relations = Gecode::Constraints::Util::RELATION_TYPES
41
+ else
42
+ @method_relations = Gecode::Constraints::Util::NEGATED_RELATION_TYPES
43
+ end
44
+ end
45
+
46
+ Gecode::Constraints::Util::RELATION_TYPES.each_pair do |name, type|
47
+ class_eval <<-"end_code"
48
+ def #{name}(expression, options = {})
49
+ unless expression.kind_of?(Fixnum) or
50
+ expression.kind_of?(Gecode::FreeIntVar)
51
+ raise TypeError, 'Invalid right hand side of count constraint: ' +
52
+ "\#{expression.class}."
53
+ end
54
+
55
+ relation = @method_relations[:#{name}]
56
+ @params.update(Gecode::Constraints::Util.decode_options(options))
57
+ @params.update(:rhs => expression, :relation_type => relation)
58
+ @model.add_constraint CountConstraint.new(@model, @params)
59
+ end
60
+ end_code
61
+ end
62
+ alias_comparison_methods
63
+ end
64
+
65
+ # Describes a count constraint.
66
+ class CountConstraint < Gecode::Constraints::ReifiableConstraint
67
+ def post
68
+ lhs, element, relation_type, rhs, strength, reif_var =
69
+ @params.values_at(:lhs, :element, :relation_type, :rhs, :strength,
70
+ :reif)
71
+
72
+ # Bind variables if needed.
73
+ element = element.bind if element.respond_to? :bind
74
+ rhs = rhs.bind if rhs.respond_to? :bind
75
+
76
+ # Post the constraint to gecode.
77
+ if reif_var.nil?
78
+ Gecode::Raw::count(@model.active_space, lhs.to_int_var_array,
79
+ element, relation_type, rhs, strength)
80
+ else
81
+ # We use a proxy int variable to get the reification.
82
+ proxy = @model.int_var(rhs.min..rhs.max)
83
+ rel = Gecode::Constraints::Util::RELATION_TYPES.invert[relation_type]
84
+ proxy.must.send(rel, @params[:rhs], :reify => reif_var)
85
+ Gecode::Raw::count(@model.active_space, lhs.to_int_var_array,
86
+ element, Gecode::Raw::IRT_EQ, proxy.bind, strength)
87
+ end
88
+ end
89
+ end
90
+ end
@@ -7,7 +7,7 @@ module Gecode
7
7
  offsets = *offsets
8
8
  end
9
9
  params = {:lhs => self, :offsets => offsets}
10
- return Gecode::Constraints::IntEnum::Distinct::OffsetExpression.new(
10
+ return Gecode::Constraints::IntEnum::Distinct::OffsetExpressionStub.new(
11
11
  @model, params)
12
12
  end
13
13
  end
@@ -25,7 +25,7 @@ module Gecode::Constraints::IntEnum
25
25
  end
26
26
 
27
27
  @model.add_constraint Distinct::DistinctConstraint.new(@model,
28
- @params.update(Gecode::Constraints::OptionUtil.decode_options(options)))
28
+ @params.update(Gecode::Constraints::Util.decode_options(options)))
29
29
  end
30
30
  end
31
31
 
@@ -33,14 +33,9 @@ module Gecode::Constraints::IntEnum
33
33
  module Distinct
34
34
  # Describes an expression started with an int var enum following with
35
35
  # #with_offsets .
36
- class OffsetExpression < Gecode::Constraints::IntEnum::Expression
36
+ class OffsetExpressionStub < Gecode::Constraints::ExpressionStub
37
37
  include Gecode::Constraints::LeftHandSideMethods
38
38
 
39
- def initialize(model, params)
40
- @model = model
41
- @params = params
42
- end
43
-
44
39
  private
45
40
 
46
41
  # Produces an expression with offsets for the lhs module.
@@ -0,0 +1,75 @@
1
+ # A module that gathers the classes and modules used by element constraints.
2
+ module Gecode::Constraints::IntEnum::Element
3
+ # Describes an expression stub started with an int var enum following with an
4
+ # array access using an integer variables .
5
+ class ExpressionStub < Gecode::Constraints::ExpressionStub
6
+ include Gecode::Constraints::LeftHandSideMethods
7
+
8
+ private
9
+
10
+ # Produces an expression with position for the lhs module.
11
+ def expression(params)
12
+ # We extract the integer and continue as if it had been specified as
13
+ # left hand side. This might be elegant, but it could get away with
14
+ # fewer constraints at times (when only equality is used) and
15
+ # propagation strength can't be specified.
16
+ # TODO: cut down on the number of constraints when possible. See if
17
+ # there's some neat way of getting the above remarks.
18
+
19
+ params.update(@params)
20
+ enum, position = params.values_at(:lhs, :position)
21
+ tmp = @model.int_var(enum.domain_range)
22
+ enum = enum.to_int_var_array if enum.respond_to? :to_int_var_array
23
+
24
+ Gecode::Raw::element(@model.active_space, enum,
25
+ position.bind, tmp.bind, Gecode::Raw::ICL_DEF)
26
+ Gecode::Constraints::Int::Expression.new(@model,
27
+ params.update(:lhs => tmp))
28
+ end
29
+ end
30
+
31
+ # Methods needed to add support for element constraints to enums.
32
+ module AdditionalEnumMethods
33
+ # This adds the adder for the methods in the modules including it. The
34
+ # reason for doing it so indirect is that the first #[] won't be defined
35
+ # before the module that this is mixed into is mixed into an enum.
36
+ def self.included(enum_mod)
37
+ enum_mod.module_eval do
38
+ # Now we enter the module AdditionalEnumMethods is mixed into.
39
+ class << self
40
+ alias_method :pre_element_included, :included
41
+ def included(mod)
42
+ mod.module_eval do
43
+ # Now we enter the module that the module possibly defining #[]
44
+ # is mixed into.
45
+ if instance_methods.include? '[]'
46
+ alias_method :pre_element_access, :[]
47
+ end
48
+
49
+ def [](*vars)
50
+ # Hook in an element constraint if a variable is used for array
51
+ # access.
52
+ if vars.first.kind_of? Gecode::FreeIntVar
53
+ params = {:lhs => self, :position => vars.first}
54
+ return Gecode::Constraints::IntEnum::Element::ExpressionStub.new(
55
+ @model, params)
56
+ else
57
+ pre_element_access(*vars) if respond_to? :pre_element_access
58
+ end
59
+ end
60
+ end
61
+ pre_element_included(mod)
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+ module Gecode::IntEnumMethods
70
+ include Gecode::Constraints::IntEnum::Element::AdditionalEnumMethods
71
+ end
72
+
73
+ module Gecode::FixnumEnumMethods
74
+ include Gecode::Constraints::IntEnum::Element::AdditionalEnumMethods
75
+ end
@@ -0,0 +1,31 @@
1
+ module Gecode::Constraints::IntEnum
2
+ class Expression
3
+ # Posts an equality constraint on the variables in the enum.
4
+ def equal(options = {})
5
+ if @params[:negate]
6
+ # The best we could implement it as from here would be a bunch of
7
+ # reified pairwise inequality constraints.
8
+ raise Gecode::MissingConstraintError, 'A negated equality is not ' +
9
+ 'implemented.'
10
+ end
11
+
12
+ @model.add_constraint Equality::EqualityConstraint.new(@model,
13
+ @params.update(Gecode::Constraints::Util.decode_options(options)))
14
+ end
15
+ end
16
+
17
+ # A module that gathers the classes and modules used in equality constraints.
18
+ module Equality
19
+ # Describes an equality constraint.
20
+ class EqualityConstraint < Gecode::Constraints::Constraint
21
+ def post
22
+ # Bind lhs.
23
+ @params[:lhs] = @params[:lhs].to_int_var_array
24
+
25
+ # Fetch the parameters to Gecode.
26
+ params = @params.values_at(:lhs, :strength)
27
+ Gecode::Raw::eq(@model.active_space, *params)
28
+ end
29
+ end
30
+ end
31
+ end