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,7 +1,7 @@
1
1
  module Gecode
2
2
  class Model
3
3
  # Specifies which variables that should be branched on (given as an
4
- # enum of variables or as a single variable). One can optionally
4
+ # enum of operands or as a single operand). One can optionally
5
5
  # also select which of the variables that should be used first with
6
6
  # the :variable option and which value in that variable's domain
7
7
  # that should be used with the :value option. If nothing is
@@ -62,16 +62,23 @@ module Gecode
62
62
  # [:min] Selects the smallest value in the unknown part of the set.
63
63
  # [:max] Selects the largest value in the unknown part of the set.
64
64
  def branch_on(variables, options = {})
65
- if variables.respond_to? :bind
65
+ if variables.respond_to?(:to_int_var) or
66
+ variables.respond_to?(:to_bool_var) or
67
+ variables.respond_to?(:to_set_var)
66
68
  variables = wrap_enum [variables]
67
69
  end
68
70
 
69
- if variables.respond_to? :to_int_var_array or
70
- variables.respond_to? :to_bool_var_array
71
- add_branch(variables, options, Constants::BRANCH_INT_VAR_CONSTANTS,
71
+ if variables.respond_to? :to_int_enum
72
+ add_branch(variables.to_int_enum, options,
73
+ Constants::BRANCH_INT_VAR_CONSTANTS,
72
74
  Constants::BRANCH_INT_VALUE_CONSTANTS)
73
- elsif variables.respond_to? :to_set_var_array
74
- add_branch(variables, options, Constants::BRANCH_SET_VAR_CONSTANTS,
75
+ elsif variables.respond_to? :to_bool_enum
76
+ add_branch(variables.to_bool_enum, options,
77
+ Constants::BRANCH_INT_VAR_CONSTANTS,
78
+ Constants::BRANCH_INT_VALUE_CONSTANTS)
79
+ elsif variables.respond_to? :to_set_enum
80
+ add_branch(variables.to_set_enum, options,
81
+ Constants::BRANCH_SET_VAR_CONSTANTS,
75
82
  Constants::BRANCH_SET_VALUE_CONSTANTS)
76
83
  else
77
84
  raise TypeError, "Unknown type of variable enum #{variables.class}."
@@ -126,7 +133,7 @@ module Gecode
126
133
  }
127
134
  end
128
135
 
129
- # Adds a branching selection for the specified variable with the specified
136
+ # Adds a branching selection for the specified variables with the specified
130
137
  # options. The hashes are used to decode the options into Gecode's
131
138
  # constants.
132
139
  def add_branch(variables, options, branch_var_hash, branch_value_hash)
@@ -148,7 +155,7 @@ module Gecode
148
155
 
149
156
  # Add the branching as a gecode interaction.
150
157
  add_interaction do
151
- Gecode::Raw.branch(active_space, variables.to_var_array,
158
+ Gecode::Raw.branch(active_space, variables.bind_array,
152
159
  branch_var_hash[var_strat], branch_value_hash[val_strat])
153
160
  end
154
161
  end
@@ -4,499 +4,455 @@ module Gecode
4
4
  class MissingConstraintError < StandardError
5
5
  end
6
6
 
7
- # A module containing all the constraints.
8
- module Constraints
9
- # A module that should be mixed in to class of objects that should be usable
10
- # as left hand sides (i.e. the part before must*) when specifying
11
- # constraints. Assumes that a method #expression is defined which produces
12
- # a new expression given the current constraint parameters.
13
- module LeftHandSideMethods #:nodoc:
14
- # Specifies that a constraint must hold for the keft hand side.
15
- def must
16
- expression update_params(:negate => false)
17
- end
18
- alias_method :must_be, :must
19
-
20
- # Specifies that the negation of a constraint must hold for the left hand
21
- # side.
22
- def must_not
23
- expression update_params(:negate => true)
24
- end
25
- alias_method :must_not_be, :must_not
26
-
27
- private
28
-
29
- # Updates the parameters with the specified new parameters.
30
- def update_params(params_to_add)
31
- @constraint_params ||= {}
32
- @constraint_params.update(params_to_add)
33
- end
7
+ # Describes an operand, something that a constraint can be placed
8
+ # on. Constraints are placed by calling #must or #must_not (the
9
+ # latter negates the constraint). This produces a
10
+ # ConstraintReceiver, which defines methods that places constraints
11
+ # on the operand.
12
+ #
13
+ # In general this produces something like the following.
14
+ #
15
+ # operand.must.constraint_method(params)
16
+ #
17
+ # See e.g. Gecode::Int::IntOperand for concrete examples.
18
+ #
19
+ # Classes that mix in Operand must define the methods #model
20
+ # and #construct_receiver. They should also define a method that converts
21
+ # the operand into a variable of the operand's type (e.g. int var
22
+ # operands should define a method #to_int_var that returns an
23
+ # instance of Gecode::IntVar that represents the operand). The
24
+ # latter method should be used by constraints to fetch variables
25
+ # needed when posting constraints. The presence of the method should
26
+ # also be used for type checking (rather than e.g. checking whether
27
+ # a parameter is of type IntOperand).
28
+ module Operand
29
+ # Specifies that a constraint must hold for the left hand side.
30
+ def must
31
+ construct_receiver :lhs => self, :negate => false
34
32
  end
33
+ alias_method :must_be, :must
35
34
 
36
- # A module that provides some utility-methods for constraints.
37
- module Util #:nodoc:
38
- # Maps the name used in options to the value used in Gecode for
39
- # propagation strengths.
40
- PROPAGATION_STRENGTHS = {
41
- :default => Gecode::Raw::ICL_DEF,
42
- :value => Gecode::Raw::ICL_VAL,
43
- :bounds => Gecode::Raw::ICL_BND,
44
- :domain => Gecode::Raw::ICL_DOM
45
- }
46
-
47
- # Maps the name used in options to the value used in Gecode for
48
- # propagation kinds.
49
- PROPAGATION_KINDS = {
50
- :default => Gecode::Raw::PK_DEF,
51
- :speed => Gecode::Raw::PK_SPEED,
52
- :memory => Gecode::Raw::PK_MEMORY,
53
- }
54
-
55
- # Maps the names of the methods to the corresponding integer relation
56
- # type in Gecode.
57
- RELATION_TYPES = {
58
- :== => Gecode::Raw::IRT_EQ,
59
- :<= => Gecode::Raw::IRT_LQ,
60
- :< => Gecode::Raw::IRT_LE,
61
- :>= => Gecode::Raw::IRT_GQ,
62
- :> => Gecode::Raw::IRT_GR
63
- }
64
- # The same as above, but negated.
65
- NEGATED_RELATION_TYPES = {
66
- :== => Gecode::Raw::IRT_NQ,
67
- :<= => Gecode::Raw::IRT_GR,
68
- :< => Gecode::Raw::IRT_GQ,
69
- :>= => Gecode::Raw::IRT_LE,
70
- :> => Gecode::Raw::IRT_LQ
71
- }
72
-
73
- # Maps the names of the methods to the corresponding set relation type in
74
- # Gecode.
75
- SET_RELATION_TYPES = {
76
- :== => Gecode::Raw::SRT_EQ,
77
- :superset => Gecode::Raw::SRT_SUP,
78
- :subset => Gecode::Raw::SRT_SUB,
79
- :disjoint => Gecode::Raw::SRT_DISJ,
80
- :complement => Gecode::Raw::SRT_CMPL
81
- }
82
- # The same as above, but negated.
83
- NEGATED_SET_RELATION_TYPES = {
84
- :== => Gecode::Raw::SRT_NQ
85
- }
86
- # Maps the names of the methods to the corresponding set operation type in
87
- # Gecode.
88
- SET_OPERATION_TYPES = {
89
- :union => Gecode::Raw::SOT_UNION,
90
- :disjoint_union => Gecode::Raw::SOT_DUNION,
91
- :intersection => Gecode::Raw::SOT_INTER,
92
- :minus => Gecode::Raw::SOT_MINUS
93
- }
94
-
95
- # Various method aliases for comparison methods. Maps the original
96
- # (symbol) name to an array of aliases.
97
- COMPARISON_ALIASES = {
98
- :== => [:equal, :equal_to],
99
- :> => [:greater, :greater_than],
100
- :>= => [:greater_or_equal, :greater_than_or_equal_to],
101
- :< => [:less, :less_than],
102
- :<= => [:less_or_equal, :less_than_or_equal_to]
103
- }
104
- SET_ALIASES = {
105
- :== => [:equal, :equal_to],
106
- :superset => [:superset_of],
107
- :subset => [:subset_of],
108
- :disjoint => [:disjoint_with],
109
- :complement => [:complement_of]
110
- }
111
-
112
- module_function
113
-
114
- # Decodes the common options to constraints: strength, kind and
115
- # reification. Returns a hash with up to three values. :strength is the
116
- # strength that should be used for the constraint, :kind is the
117
- # propagation kind that should be used, and :reif is the (bound) boolean
118
- # variable that should be used for reification. The decoded options are
119
- # removed from the hash (so in general the hash will be consumed in the
120
- # process).
121
- #
122
- # Raises ArgumentError if an unrecognized option is found in the specified
123
- # hash. Or if an unrecognized strength is given. Raises TypeError if the
124
- # reification variable is not a boolean variable.
125
- def decode_options(options)
126
- # Propagation strength.
127
- strength = options.delete(:strength) || :default
128
- unless PROPAGATION_STRENGTHS.include? strength
129
- raise ArgumentError, "Unrecognized propagation strength #{strength}."
130
- end
131
-
132
- # Propagation kind.
133
- kind = options.delete(:kind) || :default
134
- unless PROPAGATION_KINDS.include? kind
135
- raise ArgumentError, "Unrecognized propagation kind #{kind}."
136
- end
137
-
138
- # Reification.
139
- reif_var = options.delete(:reify)
140
- unless reif_var.nil? or reif_var.kind_of? FreeBoolVar
141
- raise TypeError, 'Only boolean variables may be used for reification.'
142
- end
143
-
144
- # Check for unrecognized options.
145
- unless options.empty?
146
- raise ArgumentError, 'Unrecognized constraint option: ' +
147
- options.keys.first.to_s
148
- end
149
- return {
150
- :strength => PROPAGATION_STRENGTHS[strength],
151
- :kind => PROPAGATION_KINDS[kind],
152
- :reif => reif_var
153
- }
154
- end
155
-
156
- # Converts the different ways to specify constant sets in the interface
157
- # to the form that the set should be represented in Gecode (possibly
158
- # multiple paramters. The different forms accepted are:
159
- # * Single instance of Fixnum (singleton set).
160
- # * Range (set containing all numbers in range), treated differently from
161
- # other enumerations.
162
- # * Enumeration of integers (set contaning all numbers in set).
163
- def constant_set_to_params(constant_set)
164
- unless constant_set?(constant_set)
165
- raise TypeError, "Expected a constant set, got: #{constant_set}."
166
- end
167
-
168
- if constant_set.kind_of? Range
169
- return constant_set.first, constant_set.last
170
- elsif constant_set.kind_of? Fixnum
171
- return constant_set
172
- else
173
- constant_set = constant_set.to_a
174
- return Gecode::Raw::IntSet.new(constant_set, constant_set.size)
175
- end
176
- end
177
-
178
- # Converts the different ways to specify constant sets in the interface
179
- # to an instance of Gecode::Raw::IntSet. The different forms accepted are:
180
- # * Single instance of Fixnum (singleton set).
181
- # * Range (set containing all numbers in range), treated differently from
182
- # other enumerations.
183
- # * Enumeration of integers (set contaning all numbers in set).
184
- def constant_set_to_int_set(constant_set)
185
- unless constant_set?(constant_set)
186
- raise TypeError, "Expected a constant set, got: #{constant_set}."
187
- end
188
-
189
- if constant_set.kind_of? Range
190
- return Gecode::Raw::IntSet.new(constant_set.first, constant_set.last)
191
- elsif constant_set.kind_of? Fixnum
192
- return Gecode::Raw::IntSet.new([constant_set], 1)
193
- else
194
- constant_set = constant_set.to_a
195
- return Gecode::Raw::IntSet.new(constant_set, constant_set.size)
196
- end
197
- end
198
-
199
- # Checks whether the specified expression is regarded as a constant set.
200
- # Returns true if it is, false otherwise.
201
- def constant_set?(expression)
202
- return (
203
- expression.kind_of?(Range) && # It's a range.
204
- expression.first.kind_of?(Fixnum) &&
205
- expression.last.kind_of?(Fixnum)) ||
206
- expression.kind_of?(Fixnum) || # It's a single fixnum.
207
- (expression.kind_of?(Enumerable) && # It's an enum of fixnums.
208
- expression.all?{ |e| e.kind_of? Fixnum })
209
- end
210
-
211
- # Extracts an array of the values selected for the standard propagation
212
- # options (propagation strength and propagation kind) from the hash of
213
- # parameters given. The options are returned in the order that they are
214
- # given when posting constraints to Gecode.
215
- def extract_propagation_options(params)
216
- params.values_at(:strength, :kind)
217
- end
35
+ # Specifies that the negation of a constraint must hold for the left hand
36
+ # side.
37
+ def must_not
38
+ construct_receiver :lhs => self, :negate => true
218
39
  end
219
-
220
- # A module that contains utility-methods for extensional constraints.
221
- module Util::Extensional #:nodoc:
222
- module_function
223
-
224
- # Checks that the specified enumeration is an enumeration containing
225
- # one or more tuples of the specified size. It also allows the caller
226
- # to define additional tests by providing a block, which is given each
227
- # tuple. If a test fails then an appropriate error is raised.
228
- def perform_tuple_checks(tuples, expected_size, &additional_test)
229
- unless tuples.respond_to?(:each)
230
- raise TypeError, 'Expected an enumeration with tuples, got ' +
231
- "#{tuples.class}."
232
- end
233
-
234
- if tuples.empty?
235
- raise ArgumentError, 'One or more tuples must be specified.'
236
- end
237
-
238
- tuples.each do |tuple|
239
- unless tuple.respond_to?(:each)
240
- raise TypeError, 'Expected an enumeration containing enumeraions, ' +
241
- "got #{tuple.class}."
242
- end
243
-
244
- unless tuple.size == expected_size
245
- raise ArgumentError, 'All tuples must be of the same size as the ' +
246
- 'number of variables in the array.'
247
- end
248
-
249
- yield tuple
250
- end
251
- end
40
+ alias_method :must_not_be, :must_not
41
+
42
+ # Fetches the model that the operand belongs to.
43
+ def model
44
+ raise NotImplementedError, 'Abstract method has not been implemented.'
252
45
  end
253
46
 
254
- # Describes a constraint expressions. An expression is produced by calling
255
- # some form of must on a left hand side. The expression waits for a right
256
- # hand side so that it can post the corresponding constraint.
257
- class Expression #:nodoc:
258
- # Constructs a new expression with the specified parameters. The
259
- # parameters shoud at least contain the keys :lhs, and :negate.
260
- #
261
- # Raises ArgumentError if any of those keys are missing.
262
- def initialize(model, params)
263
- unless params.has_key?(:lhs) and params.has_key?(:negate)
264
- raise ArgumentError, 'Expression requires at least :lhs, ' +
265
- "and :negate as parameter keys, got #{params.keys.join(', ')}."
266
- end
267
-
268
- @model = model
269
- @params = params
47
+ private
48
+
49
+ # Constructs the appropriate constraint receiver given the
50
+ # specified parameters.
51
+ def construct_receiver(params)
52
+ raise NotImplementedError, 'Abstract method has not been implemented.'
53
+ end
54
+ end
55
+
56
+ # Describes a constraint receiver, something that receives and
57
+ # places constraints on various Operand. Constraint receivers
58
+ # are created by calling #must or #must_not (the latter negates
59
+ # the constraint) on something that mixes in Operand.
60
+ #
61
+ # A constraint is placed on an Operand +operand+ as follows:
62
+ #
63
+ # operand.must.constraint_method(params)
64
+ #
65
+ # The constraint receiver is created by the call to #must and the
66
+ # constraint is then placed by the call to #constraint_method.
67
+ # See e.g. Gecode::Int::IntConstraintReceiver for
68
+ # concrete examples.
69
+ #
70
+ # The following options can be specified in a hash with symbols as
71
+ # keys when placing a constraint:
72
+ #
73
+ # [:strength] The propagation strength suggests how much effort the
74
+ # solver should put into trying to prune the domains of
75
+ # variables using the constraint.
76
+ #
77
+ # The allowed values are:
78
+ # [:value] Value consistency (naive).
79
+ # [:bounds] Bounds consistency. The bounds of the operand
80
+ # will always be constrained as much as possible
81
+ # (but pruning may not be done inside the
82
+ # bounds, even though it may be possible).
83
+ # [:domain] Domain consistency. All values that can be pruned
84
+ # away, given the current amount of information,
85
+ # are pruned away.
86
+ # [:default] Uses the default consistency of the constraint.
87
+ #
88
+ # The strength generally progresses as
89
+ # :value < :bounds < :domain (:value being the weakest,
90
+ # :domain being the strongest). A higher strength can
91
+ # reduce the search space quicker, but at the cost of
92
+ # making each propagation more costly.
93
+ #
94
+ # [:kind] The propagation kind option suggests the implementation
95
+ # that should be preferred if there are multiple
96
+ # implementations of a constraint.
97
+ #
98
+ # The different kinds are:
99
+ # [:speed] Prefer speed over memory consumption.
100
+ # [:memory] Prefer low memory consumption over speed.
101
+ # [:default] Uses the constraint's default propagation kind.
102
+ #
103
+ # [:reify] Reification is used to link a constraint to a boolean
104
+ # operand in such a way that the variable is true if and
105
+ # only if the constraint is satisfied. The propagation
106
+ # goes both ways, so if the variable is constrained to be
107
+ # false then the constraint is not allowed to be
108
+ # satisfied.
109
+ #
110
+ # Reification can be thought of as a last resort glue which
111
+ # can be used to combine constraints so that e.g. exactly
112
+ # 3 out of 17 constraints must be satisfied.
113
+ #
114
+ # Not all constraints accept all options. Constraints that have sets
115
+ # as operands (e.g. SetConstraintReceiver and
116
+ # SetEnumConstraintReceiver) do not accept the :strength and :kind
117
+ # options, all other do. Some constraints do not accept the :reify
118
+ # option.
119
+ #
120
+ # See e.g. Gecode::Int::IntConstraintReceiver for
121
+ # concrete examples of options being specified.
122
+ class ConstraintReceiver
123
+ # Constructs a new expression with the specified parameters. The
124
+ # parameters should at least contain the keys :lhs, and :negate.
125
+ #
126
+ # Raises ArgumentError if any of those keys are missing or if :lhs
127
+ # is not an operand.
128
+ def initialize(model, params)
129
+ unless params.has_key?(:lhs) and params.has_key?(:negate)
130
+ raise ArgumentError, 'Expression requires at least :lhs, ' +
131
+ "and :negate as parameter keys, got #{params.keys.join(', ')}."
270
132
  end
271
-
272
- private
273
-
274
- # Provides commutivity for the constraint with the specified method name.
275
- # If the method with the specified method name is called with something
276
- # that, when given to the block, evaluates to true, then the constraint
277
- # will be called on the right hand side with the left hand side as
278
- # argument.
279
- #
280
- # The original constraint method is assumed to take two arguments: a
281
- # right hand side and a hash of options.
282
- def self.provide_commutivity(constraint_name, &block)
283
- unique_id = constraint_name.to_sym.to_i
284
- pre_alias_method_name = 'pre_commutivity_' << unique_id.to_s
285
- if method_defined? constraint_name
286
- alias_method pre_alias_method_name, constraint_name
287
- end
288
-
289
- module_eval <<-end_code
290
- @@commutivity_check_#{unique_id} = block
291
- def #{constraint_name}(rhs, options = {})
292
- if @@commutivity_check_#{unique_id}.call(rhs, options)
293
- if @params[:negate]
294
- rhs.must_not.method(:#{constraint_name}).call(
295
- @params[:lhs], options)
296
- else
297
- rhs.must.method(:#{constraint_name}).call(
298
- @params[:lhs], options)
299
- end
300
- else
301
- if self.class.method_defined? :#{pre_alias_method_name}
302
- #{pre_alias_method_name}(rhs, options)
303
- else
304
- raise TypeError, \"Unexpected argument type \#{rhs.class}.\"
305
- end
306
- end
307
- end
308
- end_code
133
+ unless params[:lhs].kind_of? Operand
134
+ raise ArgumentError, 'Expected :lhs to be an operand, received ' +
135
+ "#{params[:lhs].class}."
309
136
  end
310
137
 
311
- # Creates aliases for any defined comparison methods.
312
- def self.alias_comparison_methods
313
- Gecode::Constraints::Util::COMPARISON_ALIASES.each_pair do |orig, aliases|
314
- if instance_methods.include?(orig.to_s)
315
- aliases.each do |name|
316
- alias_method(name, orig)
317
- end
318
- end
319
- end
138
+ @model = model
139
+ @params = params
140
+ end
141
+
142
+ private
143
+
144
+ # Provides commutativity for the constraint with the specified
145
+ # method name. If the method with the specified method name is
146
+ # called with something that, when given to the block, evaluates
147
+ # to true, then the constraint will be called on the right hand
148
+ # side with the left hand side as argument.
149
+ #
150
+ # The original constraint method is assumed to take two arguments:
151
+ # a right hand side and a hash of options.
152
+ def self.provide_commutativity(constraint_name, &block)
153
+ unique_id = constraint_name.to_sym.to_i
154
+ pre_alias_method_name = 'pre_commutivity_' << unique_id.to_s
155
+ if method_defined? constraint_name
156
+ alias_method pre_alias_method_name, constraint_name
320
157
  end
321
158
 
322
- # Creates aliases for any defined set methods.
323
- def self.alias_set_methods
324
- Gecode::Constraints::Util::SET_ALIASES.each_pair do |orig, aliases|
325
- if instance_methods.include?(orig.to_s)
326
- aliases.each do |name|
327
- alias_method(name, orig)
159
+ module_eval <<-end_code
160
+ @@commutivity_check_#{unique_id} = block
161
+ def #{constraint_name}(rhs, options = {})
162
+ if @@commutivity_check_#{unique_id}.call(rhs, options)
163
+ if @params[:negate]
164
+ rhs.must_not.method(:#{constraint_name}).call(
165
+ @params[:lhs], options)
166
+ else
167
+ rhs.must.method(:#{constraint_name}).call(
168
+ @params[:lhs], options)
169
+ end
170
+ else
171
+ if self.class.method_defined? :#{pre_alias_method_name}
172
+ #{pre_alias_method_name}(rhs, options)
173
+ else
174
+ raise TypeError, \"Unexpected argument type \#{rhs.class}.\"
328
175
  end
329
176
  end
330
177
  end
331
- end
178
+ end_code
332
179
  end
333
180
 
334
- # A composite expression which is a expression with a left hand side
335
- # resulting from a previous constraint.
336
- class CompositeExpression < Gecode::Constraints::Expression #:nodoc:
337
- # The expression class should be the class of the expression delegated to,
338
- # the variable class the kind of single variable used in the expression.
339
- # The new var proc should produce a new variable (of the appropriate type)
340
- # which has an unconstricted domain. The block given should take three
341
- # parameters. The first is the variable that should be the left hand side.
342
- # The second is the hash of parameters. The third is a boolean, it it's
343
- # true then the block should try to constrain the first variable's domain
344
- # as much as possible.
345
- def initialize(expression_class, variable_class, new_var_proc, model,
346
- params, &block)
347
- super(model, params)
348
- @expression_class = expression_class
349
- @variable_class = variable_class
350
- @new_var_proc = new_var_proc
351
- @constrain_equal_proc = block
352
- end
353
-
354
- # Delegate to an instance of the expression class when we get something
355
- # that we can't handle.
356
- def method_missing(name, *args)
357
- if @expression_class.instance_methods.include? name.to_s
358
- options = {}
359
- if args.size >= 2 and args[1].kind_of? Hash
360
- options = args[1]
181
+ # Creates aliases for any defined comparison methods.
182
+ def self.alias_comparison_methods
183
+ Gecode::Util::COMPARISON_ALIASES.each_pair do |orig, aliases|
184
+ if instance_methods.include?(orig.to_s)
185
+ aliases.each do |name|
186
+ alias_method(name, orig)
361
187
  end
362
-
363
- # Link a variable to the composite constraint.
364
- @params.update Gecode::Constraints::Util.decode_options(options.clone)
365
- variable = @new_var_proc.call
366
- @model.add_interaction do
367
- @constrain_equal_proc.call(variable, @params, true)
368
- end
369
-
370
- # Perform the operation on the linked variable.
371
- int_var_params = @params.clone.update(:lhs => variable)
372
- @expression_class.new(@model, int_var_params).send(name, *args)
373
- else
374
- super
375
188
  end
376
189
  end
377
-
378
- def ==(expression, options = {})
379
- if !@params[:negate] and options[:reify].nil? and
380
- expression.kind_of? @variable_class
381
- # We don't need any additional constraints.
382
- @params.update Gecode::Constraints::Util.decode_options(options)
383
- @model.add_interaction do
384
- @constrain_equal_proc.call(expression, @params, false)
190
+ end
191
+
192
+ # Creates aliases for any defined set methods.
193
+ def self.alias_set_methods
194
+ Gecode::Util::SET_ALIASES.each_pair do |orig, aliases|
195
+ if instance_methods.include?(orig.to_s)
196
+ aliases.each do |name|
197
+ alias_method(name, orig)
385
198
  end
386
- else
387
- method_missing(:==, expression, options)
388
199
  end
389
200
  end
390
- alias_comparison_methods
201
+ end
202
+ end
203
+
204
+ # Base class for all constraints.
205
+ class Constraint #:nodoc:
206
+ # Creates a constraint with the specified parameters, bound to the
207
+ # specified model.
208
+ def initialize(model, params)
209
+ @model = model
210
+ @params = params.clone
391
211
  end
392
212
 
393
- # Describes a constraint expression that has yet to be completed. I.e. a
394
- # form of must has not yet been called, but some method has been called to
395
- # initiate the expression. An example is distinct with offsets:
396
- #
397
- # enum.with_offsets(0..n).must_be.distinct
398
- #
399
- # The call of with_offsets initiates the constraint as a stub, even though
400
- # must has not yet been called.
401
- class ExpressionStub #:nodoc:
402
- # Constructs a new expression with the specified parameters.
403
- def initialize(model, params)
404
- @model = model
405
- @params = params
406
- end
213
+ # Posts the constraint, adding it to the model. This is an abstract
214
+ # method and should be overridden by all sub-classes.
215
+ def post
216
+ raise NotImplementedError, 'Abstract method has not been implemented.'
407
217
  end
408
218
 
409
- # Describes an expression stub which includes left hand side methods and
410
- # just sends models and parameters through a supplied block to construct the
411
- # resulting expression.
412
- class SimpleExpressionStub < ExpressionStub #:nodoc:
413
- include Gecode::Constraints::LeftHandSideMethods
219
+ private
414
220
 
415
- # The block provided is executed when the expression demanded by the left
416
- # hand side methods is to be constructed. The block should take two
417
- # parameters: model and params (which have been updated with negate and
418
- # so on). The block should return an expression.
419
- def initialize(model, params, &block)
420
- super(model, params)
421
- @proc = block
221
+ # Gives an array of the values selected for the standard propagation
222
+ # options (propagation strength and propagation kind) in the order that
223
+ # they are given when posting constraints to Gecode.
224
+ def propagation_options
225
+ Gecode::Util::extract_propagation_options(@params)
226
+ end
227
+ end
228
+
229
+ # A constraint that can be specified by providing a block containing the
230
+ # post method.
231
+ class BlockConstraint < Constraint #:nodoc:
232
+ def initialize(model, params, &block)
233
+ super(model, params)
234
+ @proc = block
235
+ end
236
+
237
+ def post
238
+ @proc.call
239
+ end
240
+ end
241
+
242
+ # A module that provides some utility-methods for constraints.
243
+ module Util #:nodoc:
244
+ # Maps the name used in options to the value used in Gecode for
245
+ # propagation strengths.
246
+ PROPAGATION_STRENGTHS = {
247
+ :default => Gecode::Raw::ICL_DEF,
248
+ :value => Gecode::Raw::ICL_VAL,
249
+ :bounds => Gecode::Raw::ICL_BND,
250
+ :domain => Gecode::Raw::ICL_DOM
251
+ }
252
+
253
+ # Maps the name used in options to the value used in Gecode for
254
+ # propagation kinds.
255
+ PROPAGATION_KINDS = {
256
+ :default => Gecode::Raw::PK_DEF,
257
+ :speed => Gecode::Raw::PK_SPEED,
258
+ :memory => Gecode::Raw::PK_MEMORY,
259
+ }
260
+
261
+ # Maps the names of the methods to the corresponding integer relation
262
+ # type in Gecode.
263
+ RELATION_TYPES = {
264
+ :== => Gecode::Raw::IRT_EQ,
265
+ :<= => Gecode::Raw::IRT_LQ,
266
+ :< => Gecode::Raw::IRT_LE,
267
+ :>= => Gecode::Raw::IRT_GQ,
268
+ :> => Gecode::Raw::IRT_GR
269
+ }
270
+ # The same as above, but negated.
271
+ NEGATED_RELATION_TYPES = {
272
+ :== => Gecode::Raw::IRT_NQ,
273
+ :<= => Gecode::Raw::IRT_GR,
274
+ :< => Gecode::Raw::IRT_GQ,
275
+ :>= => Gecode::Raw::IRT_LE,
276
+ :> => Gecode::Raw::IRT_LQ
277
+ }
278
+
279
+ # Maps the names of the methods to the corresponding set relation type in
280
+ # Gecode.
281
+ SET_RELATION_TYPES = {
282
+ :== => Gecode::Raw::SRT_EQ,
283
+ :superset => Gecode::Raw::SRT_SUP,
284
+ :subset => Gecode::Raw::SRT_SUB,
285
+ :disjoint => Gecode::Raw::SRT_DISJ,
286
+ :complement => Gecode::Raw::SRT_CMPL
287
+ }
288
+ # The same as above, but negated.
289
+ NEGATED_SET_RELATION_TYPES = {
290
+ :== => Gecode::Raw::SRT_NQ
291
+ }
292
+ # Maps the names of the methods to the corresponding set operation type in
293
+ # Gecode.
294
+ SET_OPERATION_TYPES = {
295
+ :union => Gecode::Raw::SOT_UNION,
296
+ :disjoint_union => Gecode::Raw::SOT_DUNION,
297
+ :intersection => Gecode::Raw::SOT_INTER,
298
+ :minus => Gecode::Raw::SOT_MINUS
299
+ }
300
+
301
+ # Various method aliases for comparison methods. Maps the original
302
+ # (symbol) name to an array of aliases.
303
+ COMPARISON_ALIASES = {
304
+ :== => [:equal, :equal_to],
305
+ :> => [:greater, :greater_than],
306
+ :>= => [:greater_or_equal, :greater_than_or_equal_to],
307
+ :< => [:less, :less_than],
308
+ :<= => [:less_or_equal, :less_than_or_equal_to]
309
+ }
310
+ SET_ALIASES = {
311
+ :== => [:equal, :equal_to],
312
+ :superset => [:superset_of],
313
+ :subset => [:subset_of],
314
+ :disjoint => [:disjoint_with],
315
+ :complement => [:complement_of]
316
+ }
317
+
318
+ module_function
319
+
320
+ # Decodes the common options to constraints: strength, kind and
321
+ # reification. Returns a hash with up to three values. :strength is the
322
+ # strength that should be used for the constraint, :kind is the
323
+ # propagation kind that should be used, and :reif is the (bound) boolean
324
+ # operand that should be used for reification. The decoded options are
325
+ # removed from the hash (so in general the hash will be consumed in the
326
+ # process).
327
+ #
328
+ # Raises ArgumentError if an unrecognized option is found in the specified
329
+ # hash. Or if an unrecognized strength is given. Raises TypeError if the
330
+ # reification operand is not a boolean operand.
331
+ def decode_options(options)
332
+ # Propagation strength.
333
+ strength = options.delete(:strength) || :default
334
+ unless PROPAGATION_STRENGTHS.include? strength
335
+ raise ArgumentError, "Unrecognized propagation strength #{strength}."
422
336
  end
423
337
 
424
- private
338
+ # Propagation kind.
339
+ kind = options.delete(:kind) || :default
340
+ unless PROPAGATION_KINDS.include? kind
341
+ raise ArgumentError, "Unrecognized propagation kind #{kind}."
342
+ end
343
+
344
+ # Reification.
345
+ reif_var = options.delete(:reify)
346
+ unless reif_var.nil? or reif_var.respond_to? :to_bool_var
347
+ raise TypeError, 'Only boolean operands may be used for reification.'
348
+ end
425
349
 
426
- # Produces an expression with offsets for the lhs module.
427
- def expression(params)
428
- @params.update(params)
429
- @proc.call(@model, @params)
350
+ # Check for unrecognized options.
351
+ unless options.empty?
352
+ raise ArgumentError, 'Unrecognized constraint option: ' +
353
+ options.keys.first.to_s
430
354
  end
355
+ return {
356
+ :strength => PROPAGATION_STRENGTHS[strength],
357
+ :kind => PROPAGATION_KINDS[kind],
358
+ :reif => reif_var
359
+ }
431
360
  end
432
361
 
433
- # Describes a stub that produces a variable, which can then be used with
434
- # that variable's normalconstraints. An example with int variables would be
435
- # the element constraint.
436
- #
437
- # int_enum[int_var].must > rhs
438
- #
439
- # The int_enum[int_var] part produces an int variable which the constraint
440
- # ".must > rhs" is then applied to. In the above case two constraints (and
441
- # one temporary variable) are required, but in the case of equality only
442
- # one constraint is required.
443
- class CompositeStub < Gecode::Constraints::ExpressionStub #:nodoc:
444
- include Gecode::Constraints::LeftHandSideMethods
445
-
446
- # The composite expression class should be the class that the stub uses
447
- # when creating its expressions.
448
- def initialize(composite_expression_class, model, params)
449
- super(model, params)
450
- @composite_class = composite_expression_class
362
+ # Converts the different ways to specify constant sets in the interface
363
+ # to the form that the set should be represented in Gecode (possibly
364
+ # multiple paramters. The different forms accepted are:
365
+ # * Single instance of Fixnum (singleton set).
366
+ # * Range (set containing all numbers in range), treated differently from
367
+ # other enumerations.
368
+ # * Enumeration of integers (set contaning all numbers in set).
369
+ def constant_set_to_params(constant_set)
370
+ unless constant_set?(constant_set)
371
+ raise TypeError, "Expected a constant set, got: #{constant_set}."
451
372
  end
452
-
453
- private
454
-
455
- # Constrains the result of the stub to be equal to the specified variable
456
- # with the specified parameters. If constrain is true then the variable's
457
- # domain should additionally be constrained as much as possible.
458
- def constrain_equal(variable, params, constrain)
459
- raise NoMethodError, 'Abstract method has not been implemented.'
373
+
374
+ if constant_set.kind_of? Range
375
+ return constant_set.first, constant_set.last
376
+ elsif constant_set.kind_of? Fixnum
377
+ return constant_set
378
+ else
379
+ constant_set = constant_set.to_a
380
+ return Gecode::Raw::IntSet.new(constant_set, constant_set.size)
460
381
  end
461
-
462
- # Produces an expression with position for the lhs module.
463
- def expression(params)
464
- @params.update params
465
- @composite_class.new(@model, @params) do |var, params, constrain|
466
- constrain_equal(var, params, constrain)
467
- end
382
+ end
383
+
384
+ # Converts the different ways to specify constant sets in the interface
385
+ # to an instance of Gecode::Raw::IntSet. The different forms accepted are:
386
+ # * Single instance of Fixnum (singleton set).
387
+ # * Range (set containing all numbers in range), treated differently from
388
+ # other enumerations.
389
+ # * Enumeration of integers (set contaning all numbers in set).
390
+ def constant_set_to_int_set(constant_set)
391
+ unless constant_set?(constant_set)
392
+ raise TypeError, "Expected a constant set, got: #{constant_set}."
468
393
  end
469
394
 
470
- # Gives an array of the values selected for the standard propagation
471
- # options (propagation strength and propagation kind) in the order that
472
- # they are given when posting constraints to Gecode.
473
- def propagation_options
474
- Gecode::Constraints::Util::extract_propagation_options(@params)
475
- end
395
+ if constant_set.kind_of? Range
396
+ return Gecode::Raw::IntSet.new(constant_set.first, constant_set.last)
397
+ elsif constant_set.kind_of? Fixnum
398
+ return Gecode::Raw::IntSet.new([constant_set], 1)
399
+ else
400
+ constant_set = constant_set.to_a
401
+ return Gecode::Raw::IntSet.new(constant_set, constant_set.size)
402
+ end
476
403
  end
477
404
 
478
- # Base class for all constraints.
479
- class Constraint
480
- # Creates a constraint with the specified parameters, bound to the
481
- # specified model.
482
- def initialize(model, params)
483
- @model = model
484
- @params = params.clone
405
+ # Checks whether the specified expression is regarded as a constant set.
406
+ # Returns true if it is, false otherwise.
407
+ def constant_set?(expression)
408
+ return (
409
+ expression.kind_of?(Range) && # It's a range.
410
+ expression.first.kind_of?(Fixnum) &&
411
+ expression.last.kind_of?(Fixnum)) ||
412
+ expression.kind_of?(Fixnum) || # It's a single fixnum.
413
+ (expression.kind_of?(Enumerable) && # It's an enum of fixnums.
414
+ expression.all?{ |e| e.kind_of? Fixnum })
415
+ end
416
+
417
+ # Extracts an array of the values selected for the standard propagation
418
+ # options (propagation strength and propagation kind) from the hash of
419
+ # parameters given. The options are returned in the order that they are
420
+ # given when posting constraints to Gecode.
421
+ def extract_propagation_options(params)
422
+ params.values_at(:strength, :kind)
423
+ end
424
+ end
425
+
426
+ # A module that contains utility-methods for extensional constraints.
427
+ module Util::Extensional #:nodoc:
428
+ module_function
429
+
430
+ # Checks that the specified enumeration is an enumeration containing
431
+ # one or more tuples of the specified size. It also allows the caller
432
+ # to define additional tests by providing a block, which is given each
433
+ # tuple. If a test fails then an appropriate error is raised.
434
+ def perform_tuple_checks(tuples, expected_size, &additional_test)
435
+ unless tuples.respond_to?(:each)
436
+ raise TypeError, 'Expected an enumeration with tuples, got ' +
437
+ "#{tuples.class}."
485
438
  end
486
439
 
487
- # Posts the constraint, adding it to the model. This is an abstract
488
- # method and should be overridden by all sub-classes.
489
- def post
490
- raise NoMethodError, 'Abstract method has not been implemented.'
440
+ if tuples.empty?
441
+ raise ArgumentError, 'One or more tuples must be specified.'
491
442
  end
492
443
 
493
- private
494
-
495
- # Gives an array of the values selected for the standard propagation
496
- # options (propagation strength and propagation kind) in the order that
497
- # they are given when posting constraints to Gecode.
498
- def propagation_options
499
- Gecode::Constraints::Util::extract_propagation_options(@params)
444
+ tuples.each do |tuple|
445
+ unless tuple.respond_to?(:each)
446
+ raise TypeError, 'Expected an enumeration containing enumeraions, ' +
447
+ "got #{tuple.class}."
448
+ end
449
+
450
+ unless tuple.size == expected_size
451
+ raise ArgumentError, 'All tuples must be of the same size as the ' +
452
+ 'number of operands in the array.'
453
+ end
454
+
455
+ yield tuple
500
456
  end
501
457
  end
502
458
  end
@@ -509,4 +465,7 @@ require 'gecoder/interface/constraints/bool_var_constraints'
509
465
  require 'gecoder/interface/constraints/bool_enum_constraints'
510
466
  require 'gecoder/interface/constraints/set_var_constraints'
511
467
  require 'gecoder/interface/constraints/set_enum_constraints'
468
+ require 'gecoder/interface/constraints/selected_set_constraints'
469
+ require 'gecoder/interface/constraints/set_elements_constraints'
470
+ require 'gecoder/interface/constraints/fixnum_enum_constraints'
512
471
  require 'gecoder/interface/constraints/extensional_regexp'