gecoder 0.8.3 → 0.9.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 (142) hide show
  1. data/CHANGES +15 -0
  2. data/README +6 -2
  3. data/example/equation_system.rb +15 -0
  4. data/example/magic_sequence.rb +7 -7
  5. data/example/money.rb +36 -0
  6. data/example/queens.rb +7 -8
  7. data/example/send_most_money.rb +1 -1
  8. data/example/square_tiling.rb +2 -2
  9. data/example/sudoku-set.rb +11 -12
  10. data/example/sudoku.rb +40 -45
  11. data/ext/extconf.rb +0 -0
  12. data/lib/gecoder/bindings.rb +42 -0
  13. data/lib/gecoder/bindings/bindings.rb +16 -0
  14. data/lib/gecoder/interface.rb +2 -1
  15. data/lib/gecoder/interface/branch.rb +16 -9
  16. data/lib/gecoder/interface/constraints.rb +410 -451
  17. data/lib/gecoder/interface/constraints/bool/boolean.rb +205 -213
  18. data/lib/gecoder/interface/constraints/bool/channel.rb +4 -5
  19. data/lib/gecoder/interface/constraints/bool/linear.rb +192 -21
  20. data/lib/gecoder/interface/constraints/bool_enum/channel.rb +43 -39
  21. data/lib/gecoder/interface/constraints/bool_enum/extensional.rb +43 -49
  22. data/lib/gecoder/interface/constraints/bool_enum/relation.rb +38 -71
  23. data/lib/gecoder/interface/constraints/bool_enum_constraints.rb +73 -22
  24. data/lib/gecoder/interface/constraints/bool_var_constraints.rb +140 -61
  25. data/lib/gecoder/interface/constraints/extensional_regexp.rb +4 -4
  26. data/lib/gecoder/interface/constraints/fixnum_enum/element.rb +63 -0
  27. data/lib/gecoder/interface/constraints/fixnum_enum/operation.rb +65 -0
  28. data/lib/gecoder/interface/constraints/fixnum_enum_constraints.rb +42 -0
  29. data/lib/gecoder/interface/constraints/int/arithmetic.rb +131 -130
  30. data/lib/gecoder/interface/constraints/int/channel.rb +21 -31
  31. data/lib/gecoder/interface/constraints/int/domain.rb +45 -42
  32. data/lib/gecoder/interface/constraints/int/linear.rb +85 -239
  33. data/lib/gecoder/interface/constraints/int/relation.rb +141 -0
  34. data/lib/gecoder/interface/constraints/int_enum/arithmetic.rb +55 -64
  35. data/lib/gecoder/interface/constraints/int_enum/channel.rb +35 -37
  36. data/lib/gecoder/interface/constraints/int_enum/count.rb +53 -78
  37. data/lib/gecoder/interface/constraints/int_enum/distinct.rb +36 -46
  38. data/lib/gecoder/interface/constraints/int_enum/element.rb +39 -57
  39. data/lib/gecoder/interface/constraints/int_enum/equality.rb +15 -19
  40. data/lib/gecoder/interface/constraints/int_enum/extensional.rb +65 -72
  41. data/lib/gecoder/interface/constraints/int_enum/sort.rb +42 -45
  42. data/lib/gecoder/interface/constraints/int_enum_constraints.rb +79 -22
  43. data/lib/gecoder/interface/constraints/int_var_constraints.rb +215 -44
  44. data/lib/gecoder/interface/constraints/reifiable_constraints.rb +14 -14
  45. data/lib/gecoder/interface/constraints/selected_set/select.rb +120 -0
  46. data/lib/gecoder/interface/constraints/selected_set_constraints.rb +75 -0
  47. data/lib/gecoder/interface/constraints/set/cardinality.rb +43 -53
  48. data/lib/gecoder/interface/constraints/set/channel.rb +26 -29
  49. data/lib/gecoder/interface/constraints/set/connection.rb +89 -152
  50. data/lib/gecoder/interface/constraints/set/domain.rb +112 -65
  51. data/lib/gecoder/interface/constraints/set/include.rb +36 -0
  52. data/lib/gecoder/interface/constraints/set/operation.rb +96 -110
  53. data/lib/gecoder/interface/constraints/set/relation.rb +114 -137
  54. data/lib/gecoder/interface/constraints/set_elements/relation.rb +116 -0
  55. data/lib/gecoder/interface/constraints/set_elements_constraints.rb +97 -0
  56. data/lib/gecoder/interface/constraints/set_enum/channel.rb +23 -27
  57. data/lib/gecoder/interface/constraints/set_enum/distinct.rb +18 -19
  58. data/lib/gecoder/interface/constraints/set_enum/operation.rb +62 -53
  59. data/lib/gecoder/interface/constraints/set_enum/select.rb +79 -0
  60. data/lib/gecoder/interface/constraints/set_enum_constraints.rb +73 -23
  61. data/lib/gecoder/interface/constraints/set_var_constraints.rb +222 -57
  62. data/lib/gecoder/interface/enum_matrix.rb +4 -4
  63. data/lib/gecoder/interface/enum_wrapper.rb +71 -22
  64. data/lib/gecoder/interface/model.rb +167 -12
  65. data/lib/gecoder/interface/model_sugar.rb +84 -0
  66. data/lib/gecoder/interface/search.rb +30 -18
  67. data/lib/gecoder/interface/variables.rb +103 -33
  68. data/lib/gecoder/version.rb +2 -2
  69. data/specs/bool_var.rb +19 -12
  70. data/specs/constraints/{boolean.rb → bool/boolean.rb} +103 -28
  71. data/specs/constraints/bool/boolean_properties.rb +51 -0
  72. data/specs/constraints/bool/linear.rb +213 -0
  73. data/specs/constraints/bool_enum/bool_enum_relation.rb +117 -0
  74. data/specs/constraints/bool_enum/channel.rb +102 -0
  75. data/specs/constraints/{extensional.rb → bool_enum/extensional.rb} +32 -101
  76. data/specs/constraints/constraint_helper.rb +149 -179
  77. data/specs/constraints/constraint_receivers.rb +103 -0
  78. data/specs/constraints/constraints.rb +6 -63
  79. data/specs/constraints/fixnum_enum/element.rb +58 -0
  80. data/specs/constraints/fixnum_enum/operation.rb +67 -0
  81. data/specs/constraints/int/arithmetic.rb +149 -0
  82. data/specs/constraints/int/channel.rb +101 -0
  83. data/specs/constraints/int/domain.rb +106 -0
  84. data/specs/constraints/int/linear.rb +183 -0
  85. data/specs/constraints/int/linear_properties.rb +97 -0
  86. data/specs/constraints/int/relation.rb +84 -0
  87. data/specs/constraints/int_enum/arithmetic.rb +72 -0
  88. data/specs/constraints/int_enum/channel.rb +57 -0
  89. data/specs/constraints/int_enum/count.rb +72 -0
  90. data/specs/constraints/int_enum/distinct.rb +80 -0
  91. data/specs/constraints/int_enum/element.rb +61 -0
  92. data/specs/constraints/int_enum/equality.rb +29 -0
  93. data/specs/constraints/int_enum/extensional.rb +224 -0
  94. data/specs/constraints/int_enum/sort.rb +167 -0
  95. data/specs/constraints/operands.rb +264 -0
  96. data/specs/constraints/property_helper.rb +443 -0
  97. data/specs/constraints/reification_sugar.rb +4 -5
  98. data/specs/constraints/selected_set/select.rb +56 -0
  99. data/specs/constraints/selected_set/select_properties.rb +157 -0
  100. data/specs/constraints/set/cardinality.rb +58 -0
  101. data/specs/constraints/set/cardinality_properties.rb +46 -0
  102. data/specs/constraints/set/channel.rb +77 -0
  103. data/specs/constraints/set/connection.rb +176 -0
  104. data/specs/constraints/set/domain.rb +197 -0
  105. data/specs/constraints/set/include.rb +36 -0
  106. data/specs/constraints/set/operation.rb +132 -0
  107. data/specs/constraints/set/relation.rb +117 -0
  108. data/specs/constraints/set_elements/relation.rb +84 -0
  109. data/specs/constraints/set_enum/channel.rb +80 -0
  110. data/specs/constraints/set_enum/distinct.rb +59 -0
  111. data/specs/constraints/set_enum/operation.rb +111 -0
  112. data/specs/constraints/set_enum/select.rb +73 -0
  113. data/specs/enum_wrapper.rb +53 -3
  114. data/specs/int_var.rb +44 -25
  115. data/specs/model.rb +58 -1
  116. data/specs/model_sugar.rb +30 -0
  117. data/specs/search.rb +24 -5
  118. data/specs/selected_set.rb +39 -0
  119. data/specs/set_elements.rb +34 -0
  120. data/specs/set_var.rb +22 -8
  121. data/specs/spec_helper.rb +206 -6
  122. data/tasks/distribution.rake +22 -7
  123. data/tasks/svn.rake +3 -1
  124. metadata +218 -134
  125. data/lib/gecoder/interface/constraints/set_enum/selection.rb +0 -217
  126. data/specs/constraints/arithmetic.rb +0 -351
  127. data/specs/constraints/bool_enum_relation.rb +0 -160
  128. data/specs/constraints/cardinality.rb +0 -157
  129. data/specs/constraints/channel.rb +0 -454
  130. data/specs/constraints/connection.rb +0 -369
  131. data/specs/constraints/count.rb +0 -146
  132. data/specs/constraints/distinct.rb +0 -164
  133. data/specs/constraints/element.rb +0 -108
  134. data/specs/constraints/equality.rb +0 -31
  135. data/specs/constraints/int_domain.rb +0 -70
  136. data/specs/constraints/int_relation.rb +0 -82
  137. data/specs/constraints/linear.rb +0 -340
  138. data/specs/constraints/selection.rb +0 -292
  139. data/specs/constraints/set_domain.rb +0 -185
  140. data/specs/constraints/set_operation.rb +0 -285
  141. data/specs/constraints/set_relation.rb +0 -197
  142. data/specs/constraints/sort.rb +0 -179
@@ -1,36 +1,60 @@
1
- module Gecode::Constraints::IntEnum
2
- class Expression
3
- # Initiates a sort constraint. Beyond the common options the sort constraint
4
- # can also take the following options:
1
+ module Gecode::IntEnum
2
+ class IntEnumConstraintReceiver
3
+ # Constrains the elements in this enumeration to be sorted in ascending
4
+ # order. The following options can be given in addition to the
5
+ # common constraint options:
5
6
  #
6
- # [:as] Defines a target (must be an int variable enumerable) that will
7
+ # [:as] Defines a target (must be an IntEnum) that will
7
8
  # hold the sorted version of the original enumerable. The original
8
9
  # enumerable will not be affected (i.e. will not necessarily be
9
10
  # sorted)
10
- # [:order] Sets an int variable enumerable that should be used to store the
11
- # order of the original enum's variables when sorted. The original
11
+ # [:order] Sets an IntEnum that should be used to store the
12
+ # order of the original enum's operands when sorted. The original
12
13
  # enumerable will not be affected (i.e. will not necessarily be
13
14
  # sorted)
14
15
  #
15
16
  # If neither of those options are specified then the original enumerable
16
17
  # will be constrained to be sorted (otherwise not). Sort constraints with
17
18
  # options do not allow negation.
19
+ #
20
+ # ==== Examples
21
+ #
22
+ # # Constrain +numbers+ to be sorted.
23
+ # numbers.must_be.sorted
24
+ #
25
+ # # Constrain +numbers+ to not be sorted.
26
+ # numbers.must_not_be.sorted
27
+ #
28
+ # # Constrain +sorted_numbers+ to be a sorted version of +numbers+.
29
+ # numbers.must_be.sorted(:as => sorted_numbers)
30
+ #
31
+ # # Constrain +order+ to be the order in which +numbers+ has to be
32
+ # # ordered to be sorted.
33
+ # numbers.must_be.sorted(:order => order)
34
+ #
35
+ # # Constrain +sorted_numbers+ to be +numbers+ sorted in the order
36
+ # # described by the IntEnum +order+.
37
+ # numbers.must_be.sorted(:as => sorted_numbers, :order => order)
38
+ #
39
+ # # Constrains +numbers+ to be sorted, reifying with the boolean
40
+ # # operand +is_sorted+, while selecting +domain+ as strength.
41
+ # numbers.must_be.sorted(:reify => :is_sorted, :strength => :domain)
18
42
  def sorted(options = {})
19
43
  # Extract and check options.
20
44
  target = options.delete(:as)
21
45
  order = options.delete(:order)
22
- unless target.nil? or target.respond_to? :to_int_var_array
46
+ unless target.nil? or target.respond_to? :to_int_enum
23
47
  raise TypeError, 'Expected int var enum as :as, got ' +
24
48
  "#{target.class}."
25
49
  end
26
- unless order.nil? or order.respond_to? :to_int_var_array
50
+ unless order.nil? or order.respond_to? :to_int_enum
27
51
  raise TypeError, 'Expected int var enum as :order, got ' +
28
52
  "#{order.class}."
29
53
  end
30
54
 
31
55
  # Extract standard options and convert to constraint.
32
56
  reified = !options[:reify].nil?
33
- @params.update(Gecode::Constraints::Util.decode_options(options))
57
+ @params.update(Gecode::Util.decode_options(options))
34
58
  if target.nil? and order.nil?
35
59
  @model.add_constraint Sort::SortConstraint.new(@model, @params)
36
60
  else
@@ -53,33 +77,18 @@ module Gecode::Constraints::IntEnum
53
77
 
54
78
  # A module that gathers the classes and modules used in sort constraints.
55
79
  module Sort #:nodoc:
56
- # Describes a sort constraint which constrains a target enumeration of
57
- # integer variables to be the sorted version of another set of integer
58
- # variables. Optionally a third enumeration may be used to define the order
59
- # in which the the variables should be sorted.
60
- #
61
- # Neither negation nor reification is supported.
62
- #
63
- # == Example
64
- #
65
- # # Constrains +sorted_numbers+ to be a sorted version of +numbers+.
66
- # numbers.must_be.sorted(:as => sorted_numbers)
67
- #
68
- # # Constrains +sorted_numbers+ to be +numbers+ sorted in the order
69
- # # described by the integer variable enumeration +order+.
70
- # numbers.must_be.sorted(:as => sorted_numbers, :order => order)
71
- class SortConstraintWithOptions < Gecode::Constraints::Constraint
80
+ class SortConstraintWithOptions < Gecode::Constraint #:nodoc:
72
81
  def post
73
82
  if @params[:target].nil?
74
83
  # We must have a target.
75
- lhs = @params[:lhs]
84
+ lhs = @params[:lhs].to_int_enum
76
85
  @params[:target] = @model.int_var_array(lhs.size, lhs.domain_range)
77
86
  end
78
87
 
79
88
  # Prepare the parameters.
80
89
  params = @params.values_at(:lhs, :target, :order).map do |param|
81
- if param.respond_to? :to_int_var_array
82
- param.to_int_var_array
90
+ if param.respond_to? :to_int_enum
91
+ param.to_int_enum.bind_array
83
92
  else
84
93
  param
85
94
  end
@@ -91,19 +100,7 @@ module Gecode::Constraints::IntEnum
91
100
  end
92
101
  end
93
102
 
94
- # Describes a sort constraint which constrains an enumeration of integer
95
- # variables to be sorted. Supports reification and negation.
96
- #
97
- # == Example
98
- #
99
- # # Constrains the variables in +int_enum+ to be sorted ascendingly.
100
- # int_enum.must_be.sorted
101
- #
102
- # # Reifies the constraint that the variables in +int_enum+ to be sorted
103
- # # ascendingly with the boolean variable +is_sorted+, while selecting
104
- # # +domain+ as strength.
105
- # int_enum.must_be.sorted(:reify => :is_sorted, :strength => :domain)
106
- class SortConstraint < Gecode::Constraints::ReifiableConstraint
103
+ class SortConstraint < Gecode::ReifiableConstraint #:nodoc:
107
104
  def post
108
105
  lhs, strength, kind, reif_var =
109
106
  @params.values_at(:lhs, :strength, :kind, :reif)
@@ -112,9 +109,9 @@ module Gecode::Constraints::IntEnum
112
109
  # We translate the constraint into n-1 relation constraints.
113
110
  options = {
114
111
  :strength =>
115
- Gecode::Constraints::Util::PROPAGATION_STRENGTHS.invert[strength],
112
+ Gecode::Util::PROPAGATION_STRENGTHS.invert[strength],
116
113
  :kind =>
117
- Gecode::Constraints::Util::PROPAGATION_KINDS.invert[kind]
114
+ Gecode::Util::PROPAGATION_KINDS.invert[kind]
118
115
  }
119
116
  if using_reification
120
117
  reification_variables = @model.bool_var_array(lhs.size - 1)
@@ -135,4 +132,4 @@ module Gecode::Constraints::IntEnum
135
132
  negate_using_reification
136
133
  end
137
134
  end
138
- end
135
+ end
@@ -1,28 +1,85 @@
1
- module Gecode
2
- module IntEnumMethods
3
- include Gecode::Constraints::LeftHandSideMethods
4
-
1
+ # A module containing constraints that have enumerations of integer
2
+ # operands as left hand side.
3
+ module Gecode::IntEnum #:nodoc:
4
+ # A IntEnumOperand is a enumeration of IntOperand on which the
5
+ # constraints defined in IntEnumConstraintReceiver can be placed.
6
+ #
7
+ # Enumerations of integer operands can be created either by using
8
+ # Gecode::Model#int_var_array and Gecode::Model#int_var_matrix, or
9
+ # by wrapping an existing enumeration containing IntOperand using
10
+ # Gecode::Model#wrap_enum. The enumerations, no matter how they were
11
+ # created, all respond to the properties defined by IntEnumOperand.
12
+ #
13
+ # ==== Examples
14
+ #
15
+ # Produces an array of five int operands with domain 0..9 inside a
16
+ # problem formulation using Gecode::Model#int_var_array:
17
+ #
18
+ # int_enum = int_var_array(5, 0..9)
19
+ #
20
+ # Uses Gecode::Model#wrap_enum inside a problem formulation to create
21
+ # a IntEnumOperand from an existing enumeration containing the
22
+ # integer operands +int_operand1+ and +int_operand2+:
23
+ #
24
+ # int_enum = wrap_enum([int_operand1, int_operand2])
25
+ #
26
+ #--
27
+ # Classes that mix in IntEnumOperand must define #model and
28
+ # #to_int_enum .
29
+ module IntEnumOperand
30
+ include Gecode::Operand
31
+
32
+ def method_missing(method, *args) #:nodoc:
33
+ if Gecode::IntEnum::Dummy.instance_methods.include? method.to_s
34
+ # Delegate to the int enum.
35
+ to_int_enum.method(method).call(*args)
36
+ else
37
+ super
38
+ end
39
+ end
40
+
5
41
  private
6
-
7
- # Produces an expression for the lhs module.
8
- def expression(params)
9
- params.update(:lhs => self)
10
- Constraints::IntEnum::Expression.new(@model, params)
42
+
43
+ def construct_receiver(params)
44
+ IntEnumConstraintReceiver.new(@model, params)
11
45
  end
12
46
  end
13
-
14
- # A module containing constraints that have enumerations of integer
15
- # variables as left hand side.
16
- module Constraints::IntEnum
17
- # Expressions with int enums as left hand sides.
18
- class Expression < Gecode::Constraints::Expression #:nodoc:
19
- # Raises TypeError unless the left hand side is an int enum.
20
- def initialize(model, params)
21
- super
22
-
23
- unless params[:lhs].respond_to? :to_int_var_array
24
- raise TypeError, 'Must have int enum as left hand side.'
25
- end
47
+
48
+ # IntEnumConstraintReceiver contains all constraints that can be
49
+ # placed on a IntEnumOperand.
50
+ #
51
+ # Constraints are placed by calling IntEnumOperand#must (or any other
52
+ # of the variations defined in Operand), which produces a
53
+ # IntEnumConstraintReceiver from which the desired constraint can be used.
54
+ #
55
+ # Some constraint accepts a number of options. See ConstraintReceiver
56
+ # for more information.
57
+ #
58
+ # ==== Examples
59
+ #
60
+ # Constrains the integer operands in +int_enum+ to take on different
61
+ # values by using IntEnumConstraintReceiver#distinct:
62
+ #
63
+ # int_enum.must_be.distinct
64
+ #
65
+ # Constrains +int_enum2+ to have the same elements as +int_enum+, but
66
+ # sorted in ascending order. Uses IntEnumConstraintReceiver#sorted:
67
+ #
68
+ # int_enum.must_be.sorted(:as => int_enum2)
69
+ #
70
+ # The same as above, but specifying that strength :domain should be
71
+ # used and that the constraint should be reified with +bool_operand+:
72
+ #
73
+ # int_enum.must_be.sorted(:as => int_enum2, :strength => :domain, :reify => bool_operand)
74
+ #
75
+ class IntEnumConstraintReceiver < Gecode::ConstraintReceiver
76
+ # Raises TypeError unless the left hand side is an int enum
77
+ # operand.
78
+ def initialize(model, params) #:nodoc:
79
+ super
80
+
81
+ unless params[:lhs].respond_to? :to_int_enum
82
+ raise TypeError, 'Must have int enum operand as left hand side.'
26
83
  end
27
84
  end
28
85
  end
@@ -1,58 +1,229 @@
1
- module Gecode
2
- class FreeIntVar
3
- include Gecode::Constraints::LeftHandSideMethods
4
-
1
+ # A module that deals with the operands, properties and constraints of
2
+ # integer variables.
3
+ module Gecode::Int #:nodoc:
4
+ # A IntOperand is a combination of variables on which the
5
+ # constraints defined in IntConstraintReceiver can be placed.
6
+ #
7
+ # Integer operands can be created either by using
8
+ # Gecode::Model#int_var et al, or by using properties that produce
9
+ # integer operands. The operands, no matter how they were created,
10
+ # all respond to the properties defined by IntOperand.
11
+ #
12
+ # ==== Examples
13
+ #
14
+ # Produces a single integer operand (more specifically an IntVar) with
15
+ # domain 0..9 inside a problem formulation, using
16
+ # Gecode::Model#int_var:
17
+ #
18
+ # int_operand = int_var(0..9)
19
+ #
20
+ # Uses the IntOperand#+ property to produce a new integer
21
+ # operand representing +int_operand1+ plus +int_operand2+:
22
+ #
23
+ # new_int_operand = int_operand1 + int_operand2
24
+ #
25
+ # Uses the IntEnumOperand#max property to produce a new
26
+ # integer operand representing the maximum value of the integer operands
27
+ # in the enumeration +int_enum+:
28
+ #
29
+ # new_int_operand = int_enum.max
30
+ #
31
+ # Uses the IntEnumOperand#[] property to produce a new integer operand
32
+ # representing the integer operand at the index decided by
33
+ # +int_operand+ (which can change during search) in the enumeration
34
+ # +int_enum+:
35
+ #
36
+ # new_int_operand = int_enum[int_operand]
37
+ #
38
+ # Uses the SetOperand#size property to produce a new integer operand
39
+ # representing the size of +set_operand+:
40
+ #
41
+ # new_int_operand = set_operand.size
42
+ #
43
+ #--
44
+ # Classes that mix in IntOperand must define #model and #to_int_var .
45
+ module IntOperand
46
+ include Gecode::Operand
47
+
48
+ def method_missing(method, *args) #:nodoc:
49
+ if Gecode::IntVar.instance_methods.include? method.to_s
50
+ # Delegate to the int var.
51
+ to_int_var.method(method).call(*args)
52
+ else
53
+ super
54
+ end
55
+ end
56
+
5
57
  private
6
-
7
- # Produces an expression for the lhs module.
8
- def expression(params)
58
+
59
+ def construct_receiver(params)
60
+ IntConstraintReceiver.new(model, params)
61
+ end
62
+ end
63
+
64
+ # An operand that short circuits integer equality.
65
+ class ShortCircuitEqualityOperand #:nodoc:
66
+ include Gecode::Int::IntOperand
67
+ attr :model
68
+
69
+ def initialize(model)
70
+ @model = model
71
+ end
72
+
73
+ def construct_receiver(params)
9
74
  params.update(:lhs => self)
10
- Constraints::Int::Expression.new(@model, params)
75
+ receiver = IntConstraintReceiver.new(@model, params)
76
+ op = self
77
+ receiver.instance_eval{ @short_circuit = op }
78
+ class <<receiver
79
+ alias_method :equality_without_short_circuit, :==
80
+ def ==(operand, options = {})
81
+ if !@params[:negate] and options[:reify].nil? and
82
+ operand.respond_to? :to_int_var
83
+ # Short circuit the constraint.
84
+ @params.update Gecode::Util.decode_options(options)
85
+ @model.add_constraint(Gecode::BlockConstraint.new(
86
+ @model, @params) do
87
+ @short_circuit.constrain_equal(operand, false,
88
+ @params.values_at(:strength, :kind))
89
+ end)
90
+ else
91
+ equality_without_short_circuit(operand, options)
92
+ end
93
+ end
94
+ alias_comparison_methods
95
+ end
96
+
97
+ return receiver
98
+ end
99
+
100
+ def to_int_var
101
+ variable = model.int_var
102
+ options =
103
+ Gecode::Util.decode_options({}).values_at(:strength, :kind)
104
+ model.add_interaction do
105
+ constrain_equal(variable, true, options)
106
+ end
107
+ return variable
108
+ end
109
+
110
+ private
111
+
112
+ # Constrains this operand to equal +int_operand+ using the
113
+ # specified +propagation_options+. If +constrain_domain+ is true
114
+ # then the method should also attempt to constrain the bounds of the
115
+ # domain of +int_operand+.
116
+ def constrain_equal(int_operand, constrain_domain, propagation_options)
117
+ raise NotImplementedError, 'Abstract method has not been implemented.'
11
118
  end
12
119
  end
13
-
14
- # A module containing constraints that have int variables as left hand side
15
- # (but not enumerations).
16
- module Constraints::Int
17
- # Describes an integer expression.
18
- class Expression < Gecode::Constraints::Expression #:nodoc:
19
- end
20
-
21
- # A composite expression which is an int expression with a left hand side
22
- # resulting from a previous constraint.
23
- class CompositeExpression < Gecode::Constraints::CompositeExpression #:nodoc:
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, lambda{ model.int_var }, model,
30
- params, &block)
120
+
121
+ # An operand that short circuits integer relation constraints.
122
+ class ShortCircuitRelationsOperand #:nodoc:
123
+ include Gecode::Int::IntOperand
124
+ attr :model
125
+
126
+ def initialize(model)
127
+ @model = model
128
+ end
129
+
130
+ def construct_receiver(params)
131
+ receiver = IntConstraintReceiver.new(@model, params)
132
+ op = self
133
+ receiver.instance_eval{ @short_circuit = op }
134
+ class <<receiver
135
+ Gecode::Util::COMPARISON_ALIASES.keys.each do |comp|
136
+ eval <<-end_code
137
+ alias_method :alias_#{comp.to_i}_without_short_circuit, :#{comp}
138
+ def #{comp}(operand, options = {})
139
+ if operand.respond_to?(:to_int_var) or operand.kind_of? Fixnum
140
+ # Short circuit the constraint.
141
+ @params.update Gecode::Util.decode_options(options)
142
+ @model.add_constraint(
143
+ @short_circuit.relation_constraint(
144
+ :#{comp}, operand, @params))
145
+ else
146
+ alias_#{comp.to_i}_without_short_circuit(operand, options)
147
+ end
148
+ end
149
+ end_code
150
+ end
151
+ alias_comparison_methods
31
152
  end
153
+
154
+ return receiver
155
+ end
156
+
157
+ def to_int_var
158
+ variable = model.int_var
159
+ params = {}
160
+ params.update Gecode::Util.decode_options({})
161
+ model.add_constraint relation_constraint(:==, variable, params)
162
+ return variable
163
+ end
164
+
165
+ # Returns a constraint that constrains this operand to have relation
166
+ # +relation+ to +int_operand_or_fix+, which is either an integer
167
+ # operand or a fixnum, given the specified hash +params+ of parameters.
168
+ def relation_constraint(relation, int_operand_or_fix, params)
169
+ raise NotImplementedError, 'Abstract method has not been implemented.'
32
170
  end
33
-
34
- # Describes a stub that produces an int variable, which can then be used
35
- # with the normal int variable constraints. An example would be the element
36
- # constraint.
37
- #
38
- # int_enum[int_var].must > rhs
39
- #
40
- # <tt>int_enum[int_var]</tt> produces an int variable which the constraint
41
- # <tt>.must > rhs</tt> is then applied to. In the above case two
42
- # constraints (and one temporary variable) are required, but in the case of
43
- # equality only one constraint is required.
44
- #
45
- # Whether a constraint involving a reification stub supports negation,
46
- # reification, strength options and so on depends on the constraint on the
47
- # right hand side.
48
- class CompositeStub < Gecode::Constraints::CompositeStub
49
- def initialize(model, params)
50
- super(CompositeExpression, model, params)
171
+ end
172
+
173
+ # IntConstraintReceiver contains all constraints that can be
174
+ # placed on an IntOperand.
175
+ #
176
+ # Constraints are placed by calling IntOperand#must (or any other
177
+ # of the variations defined in Operand), which produces a
178
+ # IntConstraintReceiver from which the desired constraint can be used.
179
+ #
180
+ # Each constraint accepts a number of options. See ConstraintReceiver
181
+ # for more information.
182
+ #
183
+ # ==== Examples
184
+ #
185
+ # Constrains +int_operand+ to be strictly greater than 5 using
186
+ # IntConstraintReceiver#>:
187
+ #
188
+ # int_operand.must > 5
189
+ #
190
+ # Constrains +int_operand1+ plus +int_operand2+ to be strictly
191
+ # greater than 5 using the IntOperand#+ property and
192
+ # IntConstraintReceiver#>:
193
+ #
194
+ # (int_operand1 + int_operand2).must > 5
195
+ #
196
+ # Constrains the maximum value of the integer operands in +int_enum+ to
197
+ # _not_ be in the range 3..7 using the IntEnumOperand#max property and
198
+ # IntConstraintReceiver#in:
199
+ #
200
+ # int_enum.max.must_not_be.in 3..7
201
+ #
202
+ # Constrains the integer operand at position +int_operand+ in
203
+ # +int_enum+, an enumeration of integer operands, to be greater than
204
+ # or equal to +int_operand2+. This uses the IntEnumOperand#[] property
205
+ # and IntConstraintReceiver#>=:
206
+ #
207
+ # int_enum[int_operand].must >= int_operand2
208
+ #
209
+ # The same as above, but specifying that strength :domain should be
210
+ # used and that the constraint should be reified with +bool_operand+:
211
+ #
212
+ # int_enum[int_operand].must_be.greater_or_equal(int_operand2, :strength => :domain, :reify => bool_operand)
213
+ #
214
+ class IntConstraintReceiver < Gecode::ConstraintReceiver
215
+ # Raises TypeError unless the left hand side is an int operand.
216
+ def initialize(model, params) #:nodoc:
217
+ super
218
+
219
+ unless params[:lhs].respond_to? :to_int_var
220
+ raise TypeError, 'Must have int operand as left hand side.'
51
221
  end
52
222
  end
53
223
  end
54
224
  end
55
225
 
226
+ require 'gecoder/interface/constraints/int/relation'
56
227
  require 'gecoder/interface/constraints/int/linear'
57
228
  require 'gecoder/interface/constraints/int/domain'
58
229
  require 'gecoder/interface/constraints/int/arithmetic'