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,13 +1,19 @@
1
- module Gecode::Constraints::Int
2
- class Expression
1
+ module Gecode::Int
2
+ class IntConstraintReceiver
3
3
  alias_method :pre_channel_equals, :==
4
4
 
5
- # Constrains the integer variable to be equal to the specified boolean
6
- # variable. I.e. constrains the integer variable to be 1 when the boolean
7
- # variable is true and 0 if the boolean variable is false.
5
+ # Constrains the integer operand to be equal to the specified boolean
6
+ # operand. I.e. constrains the integer operand to be 1 when the boolean
7
+ # operand is true and 0 if the boolean operand is false.
8
+ #
9
+ # ==== Examples
10
+ #
11
+ # # The integer operand +int+ must be one exactly when the boolean
12
+ # # operand +bool+ is true.
13
+ # int.must == bool
8
14
  def ==(bool, options = {})
9
- unless @params[:lhs].kind_of?(Gecode::FreeIntVar) and
10
- bool.kind_of?(Gecode::FreeBoolVar)
15
+ unless @params[:lhs].respond_to? :to_int_var and
16
+ bool.respond_to? :to_bool_var
11
17
  return pre_channel_equals(bool, options)
12
18
  end
13
19
 
@@ -20,42 +26,26 @@ module Gecode::Constraints::Int
20
26
  'constraint.'
21
27
  end
22
28
 
23
- @params.update(Gecode::Constraints::Util.decode_options(options))
29
+ @params.update(Gecode::Util.decode_options(options))
24
30
  @params[:rhs] = bool
25
31
  @model.add_constraint Channel::ChannelConstraint.new(@model, @params)
26
32
  end
27
33
 
28
34
  alias_comparison_methods
29
35
 
30
- # Adds a channel constraint on the integer variable and the variables in
31
- # the specifed enum of boolean variables. Beyond the common options the
32
- # channel constraint can also take the following option:
33
- #
34
- # [:offset] Specifies an offset for the integer variable. If the offset is
35
- # set to k then the integer variable takes value i+k exactly
36
- # when the variable at index i in the boolean enumration is true
37
- # and the rest are false.
38
- provide_commutivity(:channel){ |rhs, _| rhs.respond_to? :to_bool_var_array }
36
+ # Provides commutativity with BoolEnumConstraintReceiver#channel .
37
+ provide_commutativity(:channel){ |rhs, _| rhs.respond_to? :to_bool_enum }
39
38
  end
40
39
 
41
40
  # A module that gathers the classes and modules used in channel constraints
42
- # involving a single integer variable.
41
+ # involving a single integer operand.
43
42
  module Channel #:nodoc:
44
- # Describes a channel constraint that constrains an integer variable to be
45
- # 1 if a boolean variable is true, and 0 when the boolean variable is false.
46
- # Does not support negation nor reification.
47
- #
48
- # == Examples
49
- #
50
- # # The integer variable +x+ must be one exactly when the boolean
51
- # # variable +bool+ is true.
52
- # x.must == bool
53
- class ChannelConstraint < Gecode::Constraints::Constraint
43
+ class ChannelConstraint < Gecode::Constraint #:nodoc:
54
44
  def post
55
45
  lhs, rhs = @params.values_at(:lhs, :rhs)
56
- Gecode::Raw::channel(@model.active_space, lhs.bind, rhs.bind,
57
- *propagation_options)
46
+ Gecode::Raw::channel(@model.active_space, lhs.to_int_var.bind,
47
+ rhs.to_bool_var.bind, *propagation_options)
58
48
  end
59
49
  end
60
50
  end
61
- end
51
+ end
@@ -1,8 +1,34 @@
1
- module Gecode::Constraints::Int
2
- class Expression
3
- # Creates a domain constraint using the specified domain.
1
+ module Gecode::Int
2
+ class IntConstraintReceiver
3
+ # Creates a domain constraint using the specified domain, specified
4
+ # as an enumeration of integers. The integer operand is constrained
5
+ # to take a value in the domain. Domains should be specified as
6
+ # ranges if possible.
7
+ #
8
+ # ==== Examples
9
+ #
10
+ # # +x+ must be in the range 1..10
11
+ # x.must_be.in 1..10
12
+ #
13
+ # # +x+ must not be in the range -5...5
14
+ # x.must_not_be.in -5...5
15
+ #
16
+ # # Specifies the above, but reifies the constraint with the boolean
17
+ # # operand +bool+ and specified +value+ as strength.
18
+ # x.must_not_be.in(-5...5, :reify => bool, :strength => :value)
19
+ #
20
+ # # +x+ must be in the enumeration [3,5,7].
21
+ # x.must_be.in [3,5,7]
22
+ #
23
+ # # +x+ must not be in the enumeration [5,6,7,17].
24
+ # x.must_not_be.in [5,6,7,17]
25
+ #
26
+ # # Specifies the above, but reifies the constraint with the boolean
27
+ # # operand +bool+ and specified +value+ as strength.
28
+ # x.must_not_be.in([5,6,7,17], :reify => bool, :strength => :value)
29
+ #
4
30
  def in(domain, options = {})
5
- @params.update(Gecode::Constraints::Util.decode_options(options))
31
+ @params.update(Gecode::Util.decode_options(options))
6
32
  @params[:domain] = domain
7
33
  if domain.kind_of? Range
8
34
  @model.add_constraint Domain::RangeDomainConstraint.new(@model, @params)
@@ -17,28 +43,17 @@ module Gecode::Constraints::Int
17
43
 
18
44
  # A module that gathers the classes and modules used in domain constraints.
19
45
  module Domain #:nodoc:
20
- # Range domain constraints specify that an integer variable must be
21
- # contained within a specified range of integers. Supports reification and
22
- # negation.
23
- #
24
- # == Examples
25
- #
26
- # # +x+ must be in the range 1..10
27
- # x.must_be.in 1..10
28
- #
29
- # # +x+ must not be in the range -5...5
30
- # x.must_not_be.in -5...5
31
- #
32
- # # Specifies the above, but but reifies the constraint with the boolean
33
- # # variable +bool+ and specified +value+ as strength.
34
- # x.must_not_be.in(-5...5, :reify => bool, :strength => :value)
35
- class RangeDomainConstraint < Gecode::Constraints::ReifiableConstraint
46
+ # Range domain constraints specify that an integer operand must be
47
+ # contained within a specified range of integers.
48
+ class RangeDomainConstraint < Gecode::ReifiableConstraint #:nodoc:
36
49
  def post
37
50
  var, domain, reif_var = @params.values_at(:lhs, :domain, :reif)
38
51
 
39
- (params = []) << var.bind
40
- params << domain.first << domain.last
41
- params << reif_var.bind if reif_var.respond_to? :bind
52
+ (params = []) << var.to_int_var.bind
53
+ last = domain.last
54
+ last -= 1 if domain.exclude_end?
55
+ params << domain.first << last
56
+ params << reif_var.to_bool_var.bind if reif_var.respond_to? :to_bool_var
42
57
  params.concat propagation_options
43
58
 
44
59
  Gecode::Raw::dom(@model.active_space, *params)
@@ -46,27 +61,15 @@ module Gecode::Constraints::Int
46
61
  negate_using_reification
47
62
  end
48
63
 
49
- # Enum domain constraints specify that an integer variable must be contained
50
- # in an enumeration of integers. Supports reification and negation.
51
- #
52
- # == Examples
53
- #
54
- # # +x+ must be in the enumeration [3,5,7].
55
- # x.must_be.in [3,5,7]
56
- #
57
- # # +x+ must not be in the enumeration [5,6,7,17].
58
- # x.must_not_be.in [5,6,7,17]
59
- #
60
- # # Specifies the above, but but reifies the constraint with the boolean
61
- # # variable +bool+ and specified +value+ as strength.
62
- # x.must_not_be.in(-[5,6,7,17], :reify => bool, :strength => :value)
63
- class EnumDomainConstraint < Gecode::Constraints::ReifiableConstraint
64
+ # Enum domain constraints specify that an integer operand must be contained
65
+ # in an enumeration of integers.
66
+ class EnumDomainConstraint < Gecode::ReifiableConstraint #:nodoc:
64
67
  def post
65
68
  var, domain, reif_var = @params.values_at(:lhs, :domain, :reif)
66
69
 
67
- (params = []) << var.bind
68
- params << Gecode::Constraints::Util.constant_set_to_int_set(domain)
69
- params << reif_var.bind if reif_var.respond_to? :bind
70
+ (params = []) << var.to_int_var.bind
71
+ params << Gecode::Util.constant_set_to_int_set(domain)
72
+ params << reif_var.to_bool_var.bind if reif_var.respond_to? :to_bool_var
70
73
  params.concat propagation_options
71
74
 
72
75
  Gecode::Raw::dom(@model.active_space, *params)
@@ -74,4 +77,4 @@ module Gecode::Constraints::Int
74
77
  negate_using_reification
75
78
  end
76
79
  end
77
- end
80
+ end
@@ -1,156 +1,72 @@
1
- module Gecode
2
- class FreeIntVar
3
- # Creates a linear expression where the int variables are summed.
4
- def +(var)
5
- Gecode::Constraints::Int::Linear::ExpressionNode.new(self,
6
- @model) + var
1
+ module Gecode::Int
2
+ module IntOperand
3
+ # Produces a new IntOperand representing this operand plus
4
+ # +int_operand_or_fixnum+.
5
+ #
6
+ # ==== Examples
7
+ #
8
+ # # +int1+ plus +int2+
9
+ # int1 + int2
10
+ #
11
+ # # +int+ plus 17
12
+ # int + 17
13
+ def +(int_operand_or_fixnum)
14
+ int_linear_expression_operation(:+, int_operand_or_fixnum)
7
15
  end
8
16
 
9
- alias_method :pre_linear_mult, :* if instance_methods.include? '*'
17
+ # Produces a new IntOperand representing this operand minus
18
+ # +int_operand_or_fixnum+.
19
+ #
20
+ # ==== Examples
21
+ #
22
+ # # +int1+ minus +int2+
23
+ # int1 - int2
24
+ #
25
+ # # +int+ minus 17
26
+ # int - 17
27
+ def -(int_operand_or_fixnum)
28
+ int_linear_expression_operation(:-, int_operand_or_fixnum)
29
+ end
10
30
 
11
- # Creates a linear expression where the int variable is multiplied with
12
- # a constant integer.
13
- def *(int)
14
- if int.kind_of? Fixnum
15
- Gecode::Constraints::Int::Linear::ExpressionNode.new(self,
16
- @model) * int
31
+ # Produces a new IntOperand representing this operand times a
32
+ # constant.
33
+ #
34
+ # ==== Examples
35
+ #
36
+ # # +int+ times 17
37
+ # int * 17
38
+ def *(fixnum)
39
+ if fixnum.kind_of? Fixnum
40
+ int_linear_expression_operation(:*, fixnum)
17
41
  else
18
- pre_linear_mult(int) if respond_to? :pre_linear_mult
42
+ raise TypeError, "Expected fixnum, got #{fixnum.class}."
19
43
  end
20
44
  end
21
-
22
- # Creates a linear expression where the specified variable is subtracted
23
- # from this one.
24
- def -(var)
25
- Gecode::Constraints::Int::Linear::ExpressionNode.new(self,
26
- @model) - var
27
- end
28
- end
29
-
30
- module Constraints::Int
31
- class Expression #:nodoc:
32
- # Add some relation selection based on whether the expression is negated.
33
- alias_method :pre_linear_initialize, :initialize
34
- def initialize(model, params)
35
- pre_linear_initialize(model, params)
36
- unless params[:negate]
37
- @method_relations = Constraints::Util::RELATION_TYPES
38
- else
39
- @method_relations = Constraints::Util::NEGATED_RELATION_TYPES
40
- end
41
- end
42
-
43
- # Define the relation methods.
44
- Constraints::Util::RELATION_TYPES.each_key do |name|
45
- module_eval <<-"end_code"
46
- def #{name}(expression, options = {})
47
- relation = @method_relations[:#{name}]
48
- @params.update(
49
- Gecode::Constraints::Util.decode_options(options))
50
- if self.simple_expression? and simple_expression?(expression)
51
- # A relation constraint is enough.
52
- add_relation_constraint(relation, expression)
53
- else
54
- add_linear_constraint(relation, expression)
55
- end
56
- end
57
- end_code
58
- end
59
- alias_comparison_methods
60
-
61
- protected
62
-
63
- # Checks whether the given expression is simple enough to be used in a
64
- # simple relation constraint. Returns true if it is, false otherwise. If
65
- # no expression is given then the this expression's left hand side is
66
- # checked.
67
- def simple_expression?(expression = nil)
68
- if expression.nil?
69
- simple_expression?(@params[:lhs])
70
- else
71
- expression.kind_of?(Gecode::FreeIntVar) or
72
- expression.kind_of?(Gecode::FreeBoolVar) or
73
- expression.kind_of?(Fixnum)
74
- end
75
- end
76
-
77
- private
78
-
79
- # Places the linear constraint corresponding to the specified (integer)
80
- # relation type (as specified by Gecode) in relation to the specifed
81
- # expression.
82
- #
83
- # Raises TypeError if the element is of a type that doesn't allow a
84
- # relation to be specified.
85
- def add_linear_constraint(relation_type, right_hand_side)
86
- # Bind parameters.
87
- lhs = @params[:lhs]
88
- if lhs.kind_of?(Gecode::FreeIntVar) or lhs.kind_of?(Gecode::FreeBoolVar)
89
- lhs = lhs * 1 # Convert to Gecode::Raw::LinExp
90
- end
91
- if not (right_hand_side.respond_to? :to_minimodel_lin_exp or
92
- right_hand_side.kind_of?(Gecode::FreeIntVar) or
93
- right_hand_side.kind_of?(Gecode::FreeBoolVar) or
94
- right_hand_side.kind_of?(Fixnum))
95
- raise TypeError, 'Invalid right hand side of linear equation.'
96
- end
97
-
98
- @params.update(:relation_type => relation_type, :lhs => lhs,
99
- :rhs => right_hand_side)
100
- @model.add_constraint Linear::LinearConstraint.new(@model, @params)
45
+
46
+ private
47
+
48
+ # Performs the int linear expression operation +operator+ on self
49
+ # and +operand2+.
50
+ def int_linear_expression_operation(operator, operand2)
51
+ unless operand2.respond_to? :to_minimodel_lin_exp
52
+ operand2 = Linear::ExpressionNode.new operand2
101
53
  end
102
-
103
- # Places the relation constraint corresponding to the specified (integer)
104
- # relation type (as specified by Gecode) in relation to the specifed
105
- # element.
106
- def add_relation_constraint(relation_type, element)
107
- @model.add_constraint Linear::SimpleRelationConstraint.new(@model,
108
- @params.update(:relation_type => relation_type, :element => element))
54
+ operand1 = self
55
+ unless operand1.respond_to? :to_minimodel_lin_exp
56
+ operand1 = Linear::ExpressionNode.new(self, @model)
109
57
  end
58
+ Linear::ExpressionTree.new(operand1, operand2, operator)
110
59
  end
111
60
  end
112
-
61
+
113
62
  # A module that gathers the classes and modules used in linear constraints.
114
- module Constraints::Int::Linear #:nodoc:
115
- # Linear constraints specify that an integer variable must have a linear
116
- # equation containing variables must hold. The same relations and options
117
- # used in +SimpleRelationConstraint+ can also be used for linear
118
- # constraints.
119
- #
120
- # Boolean variables can also be used instead of integer variables. In that
121
- # case a boolean variable assigned true is equal to 1 and a boolean variable
122
- # assigned false is equal to 0. There is one exception: boolean variables
123
- # can not be used alone as left hand side.
124
- #
125
- # Do not mix boolean and integer variables. Even if possible it's not
126
- # supported, and might be removed in the future.
127
- #
128
- # == Examples
129
- #
130
- # # The sum of the int variables +x+ and +y+ must equal +z+ + 3.
131
- # (x + y).must == z + 3
132
- #
133
- # # Another way of writing the above.
134
- # z.must == x + y - 3
135
- #
136
- # # The inequality 10(x + y) > 3x must not hold.
137
- # (x + y)*10.must_not > x*3
138
- #
139
- # # Specifies the above, but reifies the constraint with the boolean
140
- # # variable +bool+ and gives it propagation strength +domain+.
141
- # (x + y)*10.must_not_be.greater_than(x*3, :reify => bool, :strength => :domain)
142
- class LinearConstraint < Gecode::Constraints::ReifiableConstraint
63
+ module Linear #:nodoc:
64
+ class LinearRelationConstraint < Gecode::ReifiableConstraint #:nodoc:
143
65
  def post
144
66
  lhs, rhs, relation_type, reif_var =
145
67
  @params.values_at(:lhs, :rhs, :relation_type, :reif)
146
- reif_var = reif_var.bind if reif_var.respond_to? :bind
147
- if rhs.respond_to? :to_minimodel_lin_exp
148
- rhs = rhs.to_minimodel_lin_exp
149
- elsif rhs.respond_to? :bind
150
- rhs = rhs.bind * 1
151
- end
152
-
153
- final_exp = (lhs.to_minimodel_lin_exp - rhs)
68
+ reif_var = reif_var.to_bool_var.bind if reif_var.respond_to? :to_bool_var
69
+ final_exp = (lhs.to_minimodel_lin_exp - rhs.to_minimodel_lin_exp)
154
70
  if reif_var.nil?
155
71
  final_exp.post(@model.active_space, relation_type,
156
72
  *propagation_options)
@@ -161,102 +77,18 @@ module Gecode
161
77
  end
162
78
  end
163
79
 
164
- # Simple relation constraints specify that an integer variable must have a
165
- # specified relation to a constant integer or another integer variable. The
166
- # following relations are supported (the aliases of each relation are also
167
- # listed).
168
- #
169
- # * <, lesser, lesser_than
170
- # * >, greater, greater_than
171
- # * >=, greater_or_equal, greater_than_or_equal_to
172
- # * <=, less_or_equal, less_than_or_equal_to
173
- # * ==, equal, equal_to
174
- #
175
- # Each can be negated by using +must_not+ instead of +must+.
176
- #
177
- # Two options (given as a hash) are available:
178
- #
179
- # [strength] Specifies the propagation strength of the constraint. Must be
180
- # one of +value+, +bounds+, +domain+ and +default+. The
181
- # strength generally progresses as +value+ -> +bounds+ ->
182
- # +domain+ (+value+ being the weakest, but usually cheapest,
183
- # while +domain+ is the strongest but usually costly).
184
- # [reify] Specifies a boolean variable that should be used for
185
- # reification (see +ReifiableConstraint+).
186
- #
187
- # == Examples
188
- #
189
- # # Int variable +x+ must not equal 0.
190
- # x.must_not.equal(0)
191
- #
192
- # # Another way of writing the above.
193
- # x.must_not == 0
194
- #
195
- # # +x+ must be strictly larger than +y+.
196
- # x.must > y
197
- #
198
- # # Specifies the above, but reifies the constraint with the boolean
199
- # # variable +bool+.
200
- # x.must_be.greater_than(y, :reify => bool)
201
- class SimpleRelationConstraint < Gecode::Constraints::ReifiableConstraint
202
- def post
203
- # Fetch the parameters to Gecode.
204
- lhs, relation, rhs, reif_var =
205
- @params.values_at(:lhs, :relation_type, :element, :reif)
206
-
207
- rhs = rhs.bind if rhs.respond_to? :bind
208
- if reif_var.nil?
209
- Gecode::Raw::rel(@model.active_space, lhs.bind, relation, rhs,
210
- *propagation_options)
211
- else
212
- Gecode::Raw::rel(@model.active_space, lhs.bind, relation, rhs,
213
- reif_var.bind, *propagation_options)
214
- end
215
- end
216
- end
217
-
218
- # Helper methods for linear expressions. Classes mixing in this module must
219
- # have a method #model which gives the model the expression is operating in.
220
- module Helper #:nodoc:
221
- include Gecode::Constraints::LeftHandSideMethods
222
-
223
- private
224
-
225
- OPERATION_TYPES = [:+, :-, :*]
226
-
227
- public
228
-
229
- # Define methods for the available operations.
230
- OPERATION_TYPES.each do |name|
231
- module_eval <<-"end_code"
232
- def #{name}(expression)
233
- unless expression.kind_of? ExpressionTree
234
- expression = ExpressionNode.new(expression)
235
- end
236
- ExpressionTree.new(self, expression, :#{name})
237
- end
238
- end_code
239
- end
240
-
241
- private
242
-
243
- # Produces an expression for the lhs module.
244
- def expression(params)
245
- params.update(:lhs => self)
246
- Gecode::Constraints::Int::Expression.new(model, params)
247
- end
248
- end
249
-
250
80
  # Describes a binary tree of expression nodes which together form a linear
251
81
  # expression.
252
- class ExpressionTree #:nodoc:
253
- include Helper
254
-
255
- # Constructs a new expression with the specified variable
82
+ class ExpressionTree < Gecode::Int::ShortCircuitRelationsOperand #:nodoc:
83
+ attr :model
84
+
85
+ # Constructs a new expression with the specified operands.
256
86
  def initialize(left_node, right_node, operation)
87
+ super(left_node.model || right_node.model)
257
88
  @left = left_node
258
89
  @right = right_node
259
90
  @operation = operation
91
+ @model = @left.model || @right.model
260
92
  end
261
93
 
262
94
  # Converts the linear expression to an instance of
@@ -264,20 +96,35 @@ module Gecode
264
96
  def to_minimodel_lin_exp
265
97
  @left.to_minimodel_lin_exp.send(@operation, @right.to_minimodel_lin_exp)
266
98
  end
267
-
268
- # Fetches the space that the expression's variables is in.
269
- def model
270
- @left.model || @right.model
99
+
100
+ def relation_constraint(relation, int_operand_or_fix, params)
101
+ unless params[:negate]
102
+ relation_type =
103
+ Gecode::Util::RELATION_TYPES[relation]
104
+ else
105
+ relation_type =
106
+ Gecode::Util::NEGATED_RELATION_TYPES[relation]
107
+ end
108
+
109
+ unless int_operand_or_fix.respond_to? :to_minimodel_lin_exp
110
+ int_operand_or_fix = Linear::ExpressionNode.new(int_operand_or_fix);
111
+ end
112
+
113
+ params.update(:lhs => self, :rhs => int_operand_or_fix,
114
+ :relation_type => relation_type)
115
+ LinearRelationConstraint.new(model, params)
271
116
  end
272
117
  end
273
118
 
274
119
  # Describes a single node in a linear expression.
275
120
  class ExpressionNode #:nodoc:
276
- include Helper
277
-
278
121
  attr :model
279
122
 
280
123
  def initialize(value, model = nil)
124
+ unless value.respond_to?(:to_int_var) or value.kind_of?(Fixnum)
125
+ raise TypeError, 'Expected int operand or fixnum, ' +
126
+ "got #{value.class}."
127
+ end
281
128
  @value = value
282
129
  @model = model
283
130
  end
@@ -286,12 +133,11 @@ module Gecode
286
133
  # Gecode::Raw::MiniModel::LinExpr
287
134
  def to_minimodel_lin_exp
288
135
  expression = @value
289
- if expression.respond_to? :bind
290
- # Minimodel requires that we do this first.
291
- expression = expression.bind * 1
136
+ if expression.respond_to? :to_int_var
137
+ expression = expression.to_int_var.bind * 1
292
138
  end
293
139
  expression
294
140
  end
295
141
  end
296
142
  end
297
- end
143
+ end