gecoder 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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