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
@@ -0,0 +1,141 @@
1
+ module Gecode::Int
2
+ class IntConstraintReceiver
3
+ # Constrains the integer operand to equal +int_operand_or_fixnum+.
4
+ # #equal and #equal_to are aliases of this method.
5
+ #
6
+ # ==== Examples
7
+ #
8
+ # # +int1+ must equal +int2+
9
+ # int1.must == int2
10
+ #
11
+ # # +int+ must equal 17
12
+ # int.must == 17
13
+ #
14
+ # # +int1+ must equal +int2+. We reify the constraint with
15
+ # # +bool+ and select +domain+ as strength.
16
+ # int1.must.equal(int2, :reify => bool, :strength => :domain)
17
+ def ==(int_operand_or_fixnum, options = {})
18
+ comparison(:==, int_operand_or_fixnum, options)
19
+ end
20
+
21
+ # Constrains the integer operand to be strictly greater than
22
+ # +int_operand_or_fixnum+. #greater and #greater_than are
23
+ # aliases of this method.
24
+ #
25
+ # ==== Examples
26
+ #
27
+ # # +int1+ must be strictly greater than +int2+
28
+ # int1.must > int2
29
+ #
30
+ # # +int+ must be strictly greater than 17
31
+ # int.must > 17
32
+ #
33
+ # # +int1+ must be strictly greater than +int2+. We reify the
34
+ # # constraint with +bool+ and select +domain+ as strength.
35
+ # int1.must_be.greater_than(int2, :reify => bool, :strength => :domain)
36
+ def >(int_operand_or_fixnum, options = {})
37
+ comparison(:>, int_operand_or_fixnum, options)
38
+ end
39
+
40
+ # Constrains the integer operand to be greater than or equal to
41
+ # +int_operand_or_fixnum+. #greater_or_equal and
42
+ # #greater_than_or_equal_to are aliases of this method.
43
+ #
44
+ # ==== Examples
45
+ #
46
+ # # +int1+ must be greater than or equal to +int2+
47
+ # int1.must >= int2
48
+ #
49
+ # # +int+ must be greater than or equal to 17
50
+ # int.must >= 17
51
+ #
52
+ # # +int1+ must be greater than or equal to +int2+. We reify the
53
+ # # constraint with +bool+ and select +domain+ as strength.
54
+ # int1.must.greater_or_equal(int2, :reify => bool, :strength => :domain)
55
+ def >=(int_operand_or_fixnum, options = {})
56
+ comparison(:>=, int_operand_or_fixnum, options)
57
+ end
58
+
59
+ # Constrains the integer operand to be strictly less than
60
+ # +int_operand_or_fixnum+. #lesser and #lesser_than are
61
+ # aliases of this method.
62
+ #
63
+ # ==== Examples
64
+ #
65
+ # # +int1+ must be strictly less than +int2+
66
+ # int1.must < int2
67
+ #
68
+ # # +int+ must be strictly less than 17
69
+ # int.must < 17
70
+ #
71
+ # # +int1+ must be strictly less than +int2+. We reify the
72
+ # # constraint with +bool+ and select +domain+ as strength.
73
+ # int1.must_be.less_than(int2, :reify => bool, :strength => :domain)
74
+ def <(int_operand_or_fixnum, options = {})
75
+ comparison(:<, int_operand_or_fixnum, options)
76
+ end
77
+
78
+ # Constrains the integer operand to be less than or equal to
79
+ # +int_operand_or_fixnum+. #less_or_equal and
80
+ # #less_than_or_equal_to are aliases of this method.
81
+ #
82
+ # ==== Examples
83
+ #
84
+ # # +int1+ must be less than or equal to +int2+
85
+ # int1.must <= int2
86
+ #
87
+ # # +int+ must be less than or equal to 17
88
+ # int.must <= 17
89
+ #
90
+ # # +int1+ must be less than or equal to +int2+. We reify the
91
+ # # constraint with +bool+ and select +domain+ as strength.
92
+ # int1.must.less_or_equal(int2, :reify => bool, :strength => :domain)
93
+ def <=(int_operand_or_fixnum, options = {})
94
+ comparison(:<=, int_operand_or_fixnum, options)
95
+ end
96
+
97
+ alias_comparison_methods
98
+
99
+ private
100
+
101
+ # Helper for the comparison methods. The reason that they are not
102
+ # generated in a loop is that it would mess up the RDoc.
103
+ def comparison(name, int_operand_or_fixnum, options)
104
+ unless int_operand_or_fixnum.respond_to?(:to_int_var) or
105
+ int_operand_or_fixnum.kind_of?(Fixnum)
106
+ raise TypeError, "Expected int operand or integer, got " +
107
+ "#{int_operand_or_fixnum.class}."
108
+ end
109
+
110
+ unless @params[:negate]
111
+ relation_type = Gecode::Util::RELATION_TYPES[name]
112
+ else
113
+ relation_type = Gecode::Util::NEGATED_RELATION_TYPES[name]
114
+ end
115
+ @params.update Gecode::Util.decode_options(options)
116
+ @model.add_constraint Relation::RelationConstraint.new(@model,
117
+ @params.update(:relation_type => relation_type,
118
+ :rhs => int_operand_or_fixnum))
119
+ end
120
+ end
121
+
122
+ # A module that gathers the classes and modules used in relation constraints.
123
+ module Relation #:nodoc:
124
+ class RelationConstraint < Gecode::ReifiableConstraint #:nodoc:
125
+ def post
126
+ # Fetch the parameters to Gecode.
127
+ lhs, relation, rhs, reif_var =
128
+ @params.values_at(:lhs, :relation_type, :rhs, :reif)
129
+
130
+ rhs = rhs.to_int_var.bind if rhs.respond_to? :to_int_var
131
+ if reif_var.nil?
132
+ Gecode::Raw::rel(@model.active_space, lhs.to_int_var.bind,
133
+ relation, rhs, *propagation_options)
134
+ else
135
+ Gecode::Raw::rel(@model.active_space, lhs.to_int_var.bind,
136
+ relation, rhs, reif_var.to_bool_var.bind, *propagation_options)
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end
@@ -1,72 +1,63 @@
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)
1
+ module Gecode::IntEnum
2
+ module IntEnumOperand
3
+ # Produces an IntOperand representing the maximum value of the
4
+ # integer operands in this enumeration.
5
+ #
6
+ # ==== Examples
7
+ #
8
+ # # The maximum of +int_enum+.
9
+ # int_enum.max
10
+ def max
11
+ Arithmetic::IntEnumMaxOperand.new(@model, self)
12
+ end
13
+
14
+ # Produces an IntOperand representing the minimum value of the
15
+ # integer operands in this enumeration.
16
+ #
17
+ # ==== Examples
18
+ #
19
+ # # The minimum of +int_enum+.
20
+ # int_enum.min
21
+ def min
22
+ Arithmetic::IntEnumMinOperand.new(@model, self)
23
+ end
14
24
  end
15
- end
16
25
 
17
- # A module that gathers the classes and modules used by arithmetic constraints.
18
- module Gecode::Constraints::IntEnum::Arithmetic #:nodoc:
19
- # Describes a CompositeStub for the max constraint, which constrains the
20
- # maximum value of the integer variables in an enumeration.
21
- #
22
- # == Example
23
- #
24
- # # The maximum must be positive.
25
- # int_enum.max.must > 0
26
- #
27
- # # The maximum must equal a integer variable +max+.
28
- # int_enum.max.must == max
29
- #
30
- # # The maximum must not be negative. The constraint is reified with the
31
- # # boolean variable +is_negative+ and strength +domain+ is selected.
32
- # int_enum.max.must_not_be.less_than(0, :reify => is_negative,
33
- # :strength => :domain)
34
- class MaxExpressionStub < Gecode::Constraints::Int::CompositeStub
35
- def constrain_equal(variable, params, constrain)
36
- enum = @params[:lhs]
37
- if constrain
38
- variable.must_be.in enum.domain_range
26
+ # A module that gathers the classes and modules used by arithmetic
27
+ # constraints.
28
+ module Arithmetic #:nodoc:
29
+ class IntEnumMaxOperand < Gecode::Int::ShortCircuitEqualityOperand #:nodoc:
30
+ def initialize(model, int_enum)
31
+ super model
32
+ @int_enum = int_enum
33
+ end
34
+
35
+ def constrain_equal(int_operand, constrain, propagation_options)
36
+ enum = @int_enum.to_int_enum
37
+ if constrain
38
+ int_operand.must_be.in enum.domain_range
39
+ end
40
+
41
+ Gecode::Raw::max(@model.active_space, enum.bind_array,
42
+ int_operand.to_int_var.bind, *propagation_options)
39
43
  end
40
-
41
- Gecode::Raw::max(@model.active_space, enum.to_int_var_array,
42
- variable.bind, *propagation_options)
43
44
  end
44
- end
45
-
46
- # Describes a CompositeStub for the min constraint, which constrains the
47
- # minimum value of the integer variables in an enumeration.
48
- #
49
- # == Example
50
- #
51
- # # The minimum must be positive.
52
- # int_enum.min.must > 0
53
- #
54
- # # The minimum must equal a integer variable +min+.
55
- # int_enum.min.must == min
56
- #
57
- # # The minimum must not be non-positive. The constraint is reified with the
58
- # # boolean variable +is_positive+ and strength +domain+ is selected.
59
- # int_enum.min.must_not_be.less_or_equal(0, :reify => is_positive,
60
- # :strength => :domain)
61
- class MinExpressionStub < Gecode::Constraints::Int::CompositeStub
62
- def constrain_equal(variable, params, constrain)
63
- enum = @params[:lhs]
64
- if constrain
65
- variable.must_be.in enum.domain_range
45
+
46
+ class IntEnumMinOperand < Gecode::Int::ShortCircuitEqualityOperand #:nodoc:
47
+ def initialize(model, int_enum)
48
+ super model
49
+ @int_enum = int_enum
50
+ end
51
+
52
+ def constrain_equal(int_operand, constrain, propagation_options)
53
+ enum = @int_enum.to_int_enum
54
+ if constrain
55
+ int_operand.must_be.in enum.domain_range
56
+ end
57
+
58
+ Gecode::Raw::min(@model.active_space, enum.bind_array,
59
+ int_operand.to_int_var.bind, *propagation_options)
66
60
  end
67
-
68
- Gecode::Raw::min(@model.active_space, enum.to_int_var_array,
69
- variable.bind, *propagation_options)
70
61
  end
71
62
  end
72
63
  end
@@ -1,34 +1,8 @@
1
- module Gecode::Constraints::IntEnum
2
- class Expression
3
- # Adds a channel constraint on the variables in the enum with the specified
4
- # other set or int 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
- unless enum.respond_to?(:to_int_var_array)
11
- raise TypeError, "Expected int enum, got #{enum.class}."
12
- end
13
- if options.has_key? :reify
14
- raise ArgumentError, 'The channel constraints does not support the ' +
15
- 'reification option.'
16
- end
17
-
18
- @params.update(Gecode::Constraints::Util.decode_options(options))
19
- @params.update(:rhs => enum)
20
- @model.add_constraint Channel::ChannelConstraint.new(@model, @params)
21
- end
22
-
23
- provide_commutivity(:channel){ |rhs, _| rhs.respond_to? :to_set_var_array }
24
- end
25
-
26
- # A module that gathers the classes and modules used in channel constraints.
27
- module Channel #:nodoc:
28
- # Describes a channel constraint which "channels" two enumerations of
29
- # integer variables or one enumeration of integer variables and one
30
- # enumeration of set variables. Channel constraints are used to give
31
- # access to multiple viewpoints when modelling.
1
+ module Gecode::IntEnum
2
+ class IntEnumConstraintReceiver
3
+ # Constrains this enumeration to "channel" +int_enum+. Channel
4
+ # constraints are used to give access to multiple viewpoints when
5
+ # modelling.
32
6
  #
33
7
  # The channel constraint can be thought of as constraining the arrays to
34
8
  # be each other's inverses. I.e. if the i:th value in the first enumeration
@@ -37,9 +11,9 @@ module Gecode::Constraints::IntEnum
37
11
  #
38
12
  # Neither reification nor negation is supported.
39
13
  #
40
- # == Example
14
+ # ==== Examples
41
15
  #
42
- # Lets say that were modelling a sequence of numbers that must be distinct
16
+ # Lets say that we're modelling a sequence of numbers that must be distinct
43
17
  # and that we want access to the following two view simultaneously.
44
18
  #
45
19
  # === First view
@@ -77,12 +51,36 @@ module Gecode::Constraints::IntEnum
77
51
  #
78
52
  # elements.must.channel positions
79
53
  #
80
- class ChannelConstraint < Gecode::Constraints::Constraint
54
+ def channel(int_enum, options = {})
55
+ if @params[:negate]
56
+ raise Gecode::MissingConstraintError, 'A negated channel constraint ' +
57
+ 'is not implemented.'
58
+ end
59
+ unless int_enum.respond_to? :to_int_enum
60
+ raise TypeError, "Expected int enum, got #{int_enum.class}."
61
+ end
62
+ if options.has_key? :reify
63
+ raise ArgumentError, 'The channel constraints does not support the ' +
64
+ 'reification option.'
65
+ end
66
+
67
+ @params.update(Gecode::Util.decode_options(options))
68
+ @params.update(:rhs => int_enum)
69
+ @model.add_constraint Channel::ChannelConstraint.new(@model, @params)
70
+ end
71
+
72
+ # Provides commutativity with SetEnumConstraintReceiver#channel .
73
+ provide_commutativity(:channel){ |rhs, _| rhs.respond_to? :to_set_enum }
74
+ end
75
+
76
+ # A module that gathers the classes and modules used in channel constraints.
77
+ module Channel #:nodoc:
78
+ class ChannelConstraint < Gecode::Constraint #:nodoc:
81
79
  def post
82
80
  lhs, rhs = @params.values_at(:lhs, :rhs)
83
- Gecode::Raw::channel(@model.active_space, lhs.to_int_var_array,
84
- rhs.to_int_var_array, *propagation_options)
81
+ Gecode::Raw::channel(@model.active_space, lhs.to_int_enum.bind_array,
82
+ rhs.to_int_enum.bind_array, *propagation_options)
85
83
  end
86
84
  end
87
85
  end
88
- end
86
+ end
@@ -1,91 +1,66 @@
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
- Gecode::Constraints::SimpleExpressionStub.new(@model, params) do |m, ps|
12
- Gecode::Constraints::IntEnum::Count::Expression.new(m, ps)
1
+ module Gecode::IntEnum
2
+ module IntEnumOperand
3
+ # Produces a new IntOperand representing the number of times
4
+ # +int_operand_or_fixnum+ is present in this enumeration.
5
+ #
6
+ # ==== Examples
7
+ #
8
+ # # The number of times 17 occurs in +int_enum+.
9
+ # int_enum.count(17)
10
+ #
11
+ # # The number of times +int_operand+ occurs in +int_enum+.
12
+ # int_enum.count(int_operand)
13
+ def count(int_operand_or_fixnum)
14
+ unless int_operand_or_fixnum.respond_to? :to_int_var or
15
+ int_operand_or_fixnum.kind_of?(Fixnum)
16
+ raise TypeError, 'Expected integer operand of fixnum, got ' +
17
+ "#{int_operand_or_fixnum.class}."
13
18
  end
19
+ Count::IntEnumCountOperand.new(@model, self, int_operand_or_fixnum)
14
20
  end
15
21
  end
16
- end
17
22
 
18
- # A module that gathers the classes and modules used in count constraints.
19
- module Gecode::Constraints::IntEnum::Count #:nodoc:
20
- # Describes an expression
21
- class Expression < Gecode::Constraints::IntEnum::Expression #:nodoc:
22
- def initialize(model, params)
23
- super
24
- unless params[:negate]
25
- @method_relations = Gecode::Constraints::Util::RELATION_TYPES
26
- else
27
- @method_relations = Gecode::Constraints::Util::NEGATED_RELATION_TYPES
23
+ # A module that gathers the classes and modules used in count constraints.
24
+ module Count #:nodoc:
25
+ class IntEnumCountOperand < Gecode::Int::ShortCircuitRelationsOperand #:nodoc:
26
+ def initialize(model, int_enum, element)
27
+ super model
28
+ @enum = int_enum
29
+ @element = element
30
+ end
31
+
32
+ def relation_constraint(relation, int_operand_or_fix, params)
33
+ unless params[:negate]
34
+ relation_type =
35
+ Gecode::Util::RELATION_TYPES[relation]
36
+ else
37
+ relation_type =
38
+ Gecode::Util::NEGATED_RELATION_TYPES[relation]
39
+ end
40
+
41
+ params.update(:enum => @enum, :element => @element,
42
+ :rhs => int_operand_or_fix, :relation_type => relation_type)
43
+ CountConstraint.new(@model, params)
28
44
  end
29
45
  end
30
46
 
31
- Gecode::Constraints::Util::RELATION_TYPES.each_pair do |name, type|
32
- class_eval <<-"end_code"
33
- def #{name}(expression, options = {})
34
- unless expression.kind_of?(Fixnum) or
35
- expression.kind_of?(Gecode::FreeIntVar)
36
- raise TypeError, 'Invalid right hand side of count constraint: ' +
37
- "\#{expression.class}."
38
- end
47
+ class CountConstraint < Gecode::ReifiableConstraint #:nodoc:
48
+ def post
49
+ enum, element, relation_type, rhs =
50
+ @params.values_at(:enum, :element, :relation_type, :rhs)
39
51
 
40
- relation = @method_relations[:#{name}]
41
- @params.update(Gecode::Constraints::Util.decode_options(options))
42
- @params.update(:rhs => expression, :relation_type => relation)
43
- @model.add_constraint CountConstraint.new(@model, @params)
52
+ # Bind variables if needed.
53
+ unless element.kind_of? Fixnum
54
+ element = element.to_int_var.bind
44
55
  end
45
- end_code
46
- end
47
- alias_comparison_methods
48
- end
49
-
50
- # Describes a count constraint, which constrains the number of times a value
51
- # (constant or a variable) may occurr in an enumeration of integer variable.
52
- #
53
- # All relations available for +SimpleRelationConstraint+ can be used with
54
- # count constraints. Negation and reification is supported.
55
- #
56
- # == Examples
57
- #
58
- # # Constrain +int_enum+ to not contain 0 exactly once.
59
- # int_enum.count(0).must_not == 1
60
- #
61
- # # Constrain +int_enum+ to contain +x+ exactly +x_count+ times.
62
- # int_enum.count(x).must == x_count
63
- #
64
- # # Reifies the constraint that +int_enum+ has +x+ zeros with the boolean
65
- # # variable +has_x_zeros+ and selects the strength +domain+.
66
- # int_enum.count(0).must.equal(x, :reify => has_x_zeros,
67
- # :strength => :domain)
68
- class CountConstraint < Gecode::Constraints::ReifiableConstraint
69
- def post
70
- lhs, element, relation_type, rhs, reif_var =
71
- @params.values_at(:lhs, :element, :relation_type, :rhs, :reif)
72
-
73
- # Bind variables if needed.
74
- element = element.bind if element.respond_to? :bind
75
- rhs = rhs.bind if rhs.respond_to? :bind
76
-
77
- # Post the constraint to gecode.
78
- if reif_var.nil?
79
- Gecode::Raw::count(@model.active_space, lhs.to_int_var_array,
56
+ unless rhs.kind_of? Fixnum
57
+ rhs = rhs.to_int_var.bind
58
+ end
59
+
60
+ # Post the constraint to gecode.
61
+ Gecode::Raw::count(@model.active_space, enum.to_int_enum.bind_array,
80
62
  element, relation_type, rhs, *propagation_options)
81
- else
82
- # We use a proxy int variable to get the reification.
83
- proxy = @model.int_var(rhs.min..rhs.max)
84
- rel = Gecode::Constraints::Util::RELATION_TYPES.invert[relation_type]
85
- proxy.must.send(rel, @params[:rhs], :reify => reif_var)
86
- Gecode::Raw::count(@model.active_space, lhs.to_int_var_array,
87
- element, Gecode::Raw::IRT_EQ, proxy.bind, *propagation_options)
88
63
  end
89
64
  end
90
65
  end
91
- end
66
+ end