gecoder-with-gecode 0.7.1-mswin32
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.
- data/CHANGES +81 -0
- data/COPYING +17 -0
- data/LGPL-LICENSE +458 -0
- data/README +45 -0
- data/Rakefile +13 -0
- data/example/example_helper.rb +1 -0
- data/example/magic_sequence.rb +43 -0
- data/example/queens.rb +43 -0
- data/example/raw_bindings.rb +42 -0
- data/example/send_more_money.rb +43 -0
- data/example/send_most_money.rb +58 -0
- data/example/square_tiling.rb +84 -0
- data/example/sudoku-set.rb +110 -0
- data/example/sudoku.rb +61 -0
- data/lib/gecode.dll +0 -0
- data/lib/gecoder.rb +5 -0
- data/lib/gecoder/bindings.rb +54 -0
- data/lib/gecoder/bindings/bindings.rb +2210 -0
- data/lib/gecoder/interface.rb +8 -0
- data/lib/gecoder/interface/binding_changes.rb +313 -0
- data/lib/gecoder/interface/branch.rb +152 -0
- data/lib/gecoder/interface/constraints.rb +397 -0
- data/lib/gecoder/interface/constraints/bool/boolean.rb +246 -0
- data/lib/gecoder/interface/constraints/bool/linear.rb +29 -0
- data/lib/gecoder/interface/constraints/bool_enum/boolean.rb +84 -0
- data/lib/gecoder/interface/constraints/bool_enum_constraints.rb +8 -0
- data/lib/gecoder/interface/constraints/bool_var_constraints.rb +75 -0
- data/lib/gecoder/interface/constraints/int/arithmetic.rb +71 -0
- data/lib/gecoder/interface/constraints/int/domain.rb +78 -0
- data/lib/gecoder/interface/constraints/int/linear.rb +295 -0
- data/lib/gecoder/interface/constraints/int_enum/arithmetic.rb +72 -0
- data/lib/gecoder/interface/constraints/int_enum/channel.rb +100 -0
- data/lib/gecoder/interface/constraints/int_enum/count.rb +92 -0
- data/lib/gecoder/interface/constraints/int_enum/distinct.rb +69 -0
- data/lib/gecoder/interface/constraints/int_enum/element.rb +82 -0
- data/lib/gecoder/interface/constraints/int_enum/equality.rb +38 -0
- data/lib/gecoder/interface/constraints/int_enum/sort.rb +126 -0
- data/lib/gecoder/interface/constraints/int_enum_constraints.rb +37 -0
- data/lib/gecoder/interface/constraints/int_var_constraints.rb +58 -0
- data/lib/gecoder/interface/constraints/reifiable_constraints.rb +78 -0
- data/lib/gecoder/interface/constraints/set/cardinality.rb +75 -0
- data/lib/gecoder/interface/constraints/set/connection.rb +193 -0
- data/lib/gecoder/interface/constraints/set/domain.rb +109 -0
- data/lib/gecoder/interface/constraints/set/operation.rb +132 -0
- data/lib/gecoder/interface/constraints/set/relation.rb +178 -0
- data/lib/gecoder/interface/constraints/set_enum/channel.rb +18 -0
- data/lib/gecoder/interface/constraints/set_enum/distinct.rb +80 -0
- data/lib/gecoder/interface/constraints/set_enum/operation.rb +60 -0
- data/lib/gecoder/interface/constraints/set_enum/selection.rb +217 -0
- data/lib/gecoder/interface/constraints/set_enum_constraints.rb +34 -0
- data/lib/gecoder/interface/constraints/set_var_constraints.rb +72 -0
- data/lib/gecoder/interface/enum_matrix.rb +64 -0
- data/lib/gecoder/interface/enum_wrapper.rb +153 -0
- data/lib/gecoder/interface/model.rb +251 -0
- data/lib/gecoder/interface/search.rb +123 -0
- data/lib/gecoder/interface/variables.rb +254 -0
- data/lib/gecoder/version.rb +4 -0
- data/specs/binding_changes.rb +76 -0
- data/specs/bool_var.rb +74 -0
- data/specs/branch.rb +170 -0
- data/specs/constraints/arithmetic.rb +266 -0
- data/specs/constraints/bool_enum.rb +140 -0
- data/specs/constraints/boolean.rb +232 -0
- data/specs/constraints/cardinality.rb +154 -0
- data/specs/constraints/channel.rb +126 -0
- data/specs/constraints/connection.rb +373 -0
- data/specs/constraints/constraint_helper.rb +180 -0
- data/specs/constraints/constraints.rb +74 -0
- data/specs/constraints/count.rb +139 -0
- data/specs/constraints/distinct.rb +218 -0
- data/specs/constraints/element.rb +106 -0
- data/specs/constraints/equality.rb +31 -0
- data/specs/constraints/int_domain.rb +69 -0
- data/specs/constraints/int_relation.rb +78 -0
- data/specs/constraints/linear.rb +332 -0
- data/specs/constraints/reification_sugar.rb +96 -0
- data/specs/constraints/selection.rb +292 -0
- data/specs/constraints/set_domain.rb +181 -0
- data/specs/constraints/set_operation.rb +285 -0
- data/specs/constraints/set_relation.rb +201 -0
- data/specs/constraints/sort.rb +175 -0
- data/specs/distribution.rb +14 -0
- data/specs/enum_matrix.rb +43 -0
- data/specs/enum_wrapper.rb +122 -0
- data/specs/int_var.rb +144 -0
- data/specs/logging.rb +24 -0
- data/specs/model.rb +190 -0
- data/specs/search.rb +246 -0
- data/specs/set_var.rb +68 -0
- data/specs/spec_helper.rb +93 -0
- data/tasks/all_tasks.rb +1 -0
- data/tasks/building.howto +65 -0
- data/tasks/distribution.rake +156 -0
- data/tasks/rcov.rake +17 -0
- data/tasks/specs.rake +15 -0
- data/tasks/svn.rake +11 -0
- data/tasks/website.rake +51 -0
- data/vendor/gecode/win32/lib/libgecodeint.dll +0 -0
- data/vendor/gecode/win32/lib/libgecodekernel.dll +0 -0
- data/vendor/gecode/win32/lib/libgecodeminimodel.dll +0 -0
- data/vendor/gecode/win32/lib/libgecodesearch.dll +0 -0
- data/vendor/gecode/win32/lib/libgecodeset.dll +0 -0
- data/vendor/rust/README +28 -0
- data/vendor/rust/bin/cxxgenerator.rb +93 -0
- data/vendor/rust/include/rust_checks.hh +115 -0
- data/vendor/rust/include/rust_conversions.hh +102 -0
- data/vendor/rust/rust.rb +67 -0
- data/vendor/rust/rust/attribute.rb +51 -0
- data/vendor/rust/rust/bindings.rb +172 -0
- data/vendor/rust/rust/class.rb +339 -0
- data/vendor/rust/rust/constants.rb +48 -0
- data/vendor/rust/rust/container.rb +110 -0
- data/vendor/rust/rust/cppifaceparser.rb +129 -0
- data/vendor/rust/rust/cwrapper.rb +72 -0
- data/vendor/rust/rust/cxxclass.rb +98 -0
- data/vendor/rust/rust/element.rb +81 -0
- data/vendor/rust/rust/enum.rb +63 -0
- data/vendor/rust/rust/function.rb +407 -0
- data/vendor/rust/rust/namespace.rb +61 -0
- data/vendor/rust/rust/templates/AttributeDefinition.rusttpl +17 -0
- data/vendor/rust/rust/templates/AttributeInitBinding.rusttpl +9 -0
- data/vendor/rust/rust/templates/BindingsHeader.rusttpl +24 -0
- data/vendor/rust/rust/templates/BindingsUnit.rusttpl +46 -0
- data/vendor/rust/rust/templates/CWrapperClassDefinitions.rusttpl +64 -0
- data/vendor/rust/rust/templates/ClassDeclarations.rusttpl +7 -0
- data/vendor/rust/rust/templates/ClassInitialize.rusttpl +6 -0
- data/vendor/rust/rust/templates/ConstructorStub.rusttpl +21 -0
- data/vendor/rust/rust/templates/CxxClassDefinitions.rusttpl +91 -0
- data/vendor/rust/rust/templates/CxxMethodStub.rusttpl +12 -0
- data/vendor/rust/rust/templates/CxxStandaloneClassDefinitions.rusttpl +26 -0
- data/vendor/rust/rust/templates/EnumDeclarations.rusttpl +3 -0
- data/vendor/rust/rust/templates/EnumDefinitions.rusttpl +29 -0
- data/vendor/rust/rust/templates/FunctionDefinition.rusttpl +9 -0
- data/vendor/rust/rust/templates/FunctionInitAlias.rusttpl +5 -0
- data/vendor/rust/rust/templates/FunctionInitBinding.rusttpl +9 -0
- data/vendor/rust/rust/templates/MethodInitBinding.rusttpl +9 -0
- data/vendor/rust/rust/templates/ModuleDeclarations.rusttpl +3 -0
- data/vendor/rust/rust/templates/ModuleDefinitions.rusttpl +3 -0
- data/vendor/rust/rust/templates/StandaloneClassDeclarations.rusttpl +7 -0
- data/vendor/rust/rust/templates/VariableFunctionCall.rusttpl +14 -0
- data/vendor/rust/rust/type.rb +98 -0
- data/vendor/rust/test/Makefile +4 -0
- data/vendor/rust/test/constants.rb +36 -0
- data/vendor/rust/test/cppclass.cc +45 -0
- data/vendor/rust/test/cppclass.hh +67 -0
- data/vendor/rust/test/cppclass.rb +59 -0
- data/vendor/rust/test/cwrapper.c +74 -0
- data/vendor/rust/test/cwrapper.h +41 -0
- data/vendor/rust/test/cwrapper.rb +56 -0
- data/vendor/rust/test/dummyclass.hh +31 -0
- data/vendor/rust/test/lib/extension-test.rb +98 -0
- data/vendor/rust/test/operators.cc +41 -0
- data/vendor/rust/test/operators.hh +39 -0
- data/vendor/rust/test/operators.rb +39 -0
- data/vendor/rust/test/test-constants.rb +43 -0
- data/vendor/rust/test/test-cppclass.rb +82 -0
- data/vendor/rust/test/test-cwrapper.rb +80 -0
- data/vendor/rust/test/test-operators.rb +42 -0
- metadata +293 -0
@@ -0,0 +1,397 @@
|
|
1
|
+
module Gecode
|
2
|
+
# An error signaling that the constraint specified is missing (e.g. one tried
|
3
|
+
# to negate a constraint, but no negated form is implemented).
|
4
|
+
class MissingConstraintError < StandardError
|
5
|
+
end
|
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
|
34
|
+
end
|
35
|
+
|
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 names of the methods to the corresponding integer relation
|
48
|
+
# type in Gecode.
|
49
|
+
RELATION_TYPES = {
|
50
|
+
:== => Gecode::Raw::IRT_EQ,
|
51
|
+
:<= => Gecode::Raw::IRT_LQ,
|
52
|
+
:< => Gecode::Raw::IRT_LE,
|
53
|
+
:>= => Gecode::Raw::IRT_GQ,
|
54
|
+
:> => Gecode::Raw::IRT_GR
|
55
|
+
}
|
56
|
+
# The same as above, but negated.
|
57
|
+
NEGATED_RELATION_TYPES = {
|
58
|
+
:== => Gecode::Raw::IRT_NQ,
|
59
|
+
:<= => Gecode::Raw::IRT_GR,
|
60
|
+
:< => Gecode::Raw::IRT_GQ,
|
61
|
+
:>= => Gecode::Raw::IRT_LE,
|
62
|
+
:> => Gecode::Raw::IRT_LQ
|
63
|
+
}
|
64
|
+
|
65
|
+
# Maps the names of the methods to the corresponding set relation type in
|
66
|
+
# Gecode.
|
67
|
+
SET_RELATION_TYPES = {
|
68
|
+
:== => Gecode::Raw::SRT_EQ,
|
69
|
+
:superset => Gecode::Raw::SRT_SUP,
|
70
|
+
:subset => Gecode::Raw::SRT_SUB,
|
71
|
+
:disjoint => Gecode::Raw::SRT_DISJ,
|
72
|
+
:complement => Gecode::Raw::SRT_CMPL
|
73
|
+
}
|
74
|
+
# The same as above, but negated.
|
75
|
+
NEGATED_SET_RELATION_TYPES = {
|
76
|
+
:== => Gecode::Raw::SRT_NQ
|
77
|
+
}
|
78
|
+
# Maps the names of the methods to the corresponding set operation type in
|
79
|
+
# Gecode.
|
80
|
+
SET_OPERATION_TYPES = {
|
81
|
+
:union => Gecode::Raw::SOT_UNION,
|
82
|
+
:disjoint_union => Gecode::Raw::SOT_DUNION,
|
83
|
+
:intersection => Gecode::Raw::SOT_INTER,
|
84
|
+
:minus => Gecode::Raw::SOT_MINUS
|
85
|
+
}
|
86
|
+
|
87
|
+
# Various method aliases for comparison methods. Maps the original
|
88
|
+
# (symbol) name to an array of aliases.
|
89
|
+
COMPARISON_ALIASES = {
|
90
|
+
:== => [:equal, :equal_to],
|
91
|
+
:> => [:greater, :greater_than],
|
92
|
+
:>= => [:greater_or_equal, :greater_than_or_equal_to],
|
93
|
+
:< => [:less, :less_than],
|
94
|
+
:<= => [:less_or_equal, :less_than_or_equal_to]
|
95
|
+
}
|
96
|
+
SET_ALIASES = {
|
97
|
+
:== => [:equal, :equal_to],
|
98
|
+
:superset => [:superset_of],
|
99
|
+
:subset => [:subset_of],
|
100
|
+
:disjoint => [:disjoint_with],
|
101
|
+
:complement => [:complement_of]
|
102
|
+
}
|
103
|
+
|
104
|
+
module_function
|
105
|
+
|
106
|
+
# Decodes the common options to constraints: strength and reification.
|
107
|
+
# Returns a hash with up to two values. :strength is the strength that
|
108
|
+
# should be used for the constraint and :reif is the (bound) boolean
|
109
|
+
# variable that should be used for reification. The decoded options are
|
110
|
+
# removed from the hash (so in general the hash will be consumed in the
|
111
|
+
# process).
|
112
|
+
#
|
113
|
+
# Raises ArgumentError if an unrecognized option is found in the specified
|
114
|
+
# hash. Or if an unrecognized strength is given. Raises TypeError if the
|
115
|
+
# reification variable is not a boolean variable.
|
116
|
+
def decode_options(options)
|
117
|
+
# Propagation strength.
|
118
|
+
strength = options.delete(:strength) || :default
|
119
|
+
unless PROPAGATION_STRENGTHS.include? strength
|
120
|
+
raise ArgumentError, "Unrecognized propagation strength #{strength}."
|
121
|
+
end
|
122
|
+
|
123
|
+
# Reification.
|
124
|
+
reif_var = options.delete(:reify)
|
125
|
+
unless reif_var.nil? or reif_var.kind_of? FreeBoolVar
|
126
|
+
raise TypeError, 'Only boolean variables may be used for reification.'
|
127
|
+
end
|
128
|
+
|
129
|
+
# Check for unrecognized options.
|
130
|
+
unless options.empty?
|
131
|
+
raise ArgumentError, 'Unrecognized constraint option: ' +
|
132
|
+
options.keys.first.to_s
|
133
|
+
end
|
134
|
+
return {:strength => PROPAGATION_STRENGTHS[strength], :reif => reif_var}
|
135
|
+
end
|
136
|
+
|
137
|
+
# Converts the different ways to specify constant sets in the interface
|
138
|
+
# to the form that the set should be represented in Gecode (possibly
|
139
|
+
# multiple paramters. The different forms accepted are:
|
140
|
+
# * Single instance of Fixnum (singleton set).
|
141
|
+
# * Range (set containing all numbers in range), treated differently from
|
142
|
+
# other enumerations.
|
143
|
+
# * Enumeration of integers (set contaning all numbers in set).
|
144
|
+
def constant_set_to_params(constant_set)
|
145
|
+
unless constant_set?(constant_set)
|
146
|
+
raise TypeError, "Expected a constant set, got: #{constant_set}."
|
147
|
+
end
|
148
|
+
|
149
|
+
if constant_set.kind_of? Range
|
150
|
+
return constant_set.first, constant_set.last
|
151
|
+
elsif constant_set.kind_of? Fixnum
|
152
|
+
return constant_set
|
153
|
+
else
|
154
|
+
constant_set = constant_set.to_a
|
155
|
+
return Gecode::Raw::IntSet.new(constant_set, constant_set.size)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
# Converts the different ways to specify constant sets in the interface
|
160
|
+
# to an instance of Gecode::Raw::IntSet. The different forms accepted are:
|
161
|
+
# * Single instance of Fixnum (singleton set).
|
162
|
+
# * Range (set containing all numbers in range), treated differently from
|
163
|
+
# other enumerations.
|
164
|
+
# * Enumeration of integers (set contaning all numbers in set).
|
165
|
+
def constant_set_to_int_set(constant_set)
|
166
|
+
unless constant_set?(constant_set)
|
167
|
+
raise TypeError, "Expected a constant set, got: #{constant_set}."
|
168
|
+
end
|
169
|
+
|
170
|
+
if constant_set.kind_of? Range
|
171
|
+
return Gecode::Raw::IntSet.new(constant_set.first, constant_set.last)
|
172
|
+
elsif constant_set.kind_of? Fixnum
|
173
|
+
return Gecode::Raw::IntSet.new([constant_set], 1)
|
174
|
+
else
|
175
|
+
constant_set = constant_set.to_a
|
176
|
+
return Gecode::Raw::IntSet.new(constant_set, constant_set.size)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
# Checks whether the specified expression is regarded as a constant set.
|
181
|
+
# Returns true if it is, false otherwise.
|
182
|
+
def constant_set?(expression)
|
183
|
+
return (
|
184
|
+
expression.kind_of?(Range) && # It's a range.
|
185
|
+
expression.first.kind_of?(Fixnum) &&
|
186
|
+
expression.last.kind_of?(Fixnum)) ||
|
187
|
+
expression.kind_of?(Fixnum) || # It's a single fixnum.
|
188
|
+
(expression.kind_of?(Enumerable) && # It's an enum of fixnums.
|
189
|
+
expression.all?{ |e| e.kind_of? Fixnum })
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
# Describes a constraint expressions. An expression is produced by calling
|
194
|
+
# some form of must on a left hand side. The expression waits for a right
|
195
|
+
# hand side so that it can post the corresponding constraint.
|
196
|
+
class Expression #:nodoc:
|
197
|
+
# Constructs a new expression with the specified parameters. The
|
198
|
+
# parameters shoud at least contain the keys :lhs, and :negate.
|
199
|
+
#
|
200
|
+
# Raises ArgumentError if any of those keys are missing.
|
201
|
+
def initialize(model, params)
|
202
|
+
unless params.has_key?(:lhs) and params.has_key?(:negate)
|
203
|
+
raise ArgumentError, 'Expression requires at least :lhs, ' +
|
204
|
+
"and :negate as parameter keys, got #{params.keys.join(', ')}."
|
205
|
+
end
|
206
|
+
|
207
|
+
@model = model
|
208
|
+
@params = params
|
209
|
+
end
|
210
|
+
|
211
|
+
private
|
212
|
+
|
213
|
+
# Creates aliases for any defined comparison methods.
|
214
|
+
def self.alias_comparison_methods
|
215
|
+
Gecode::Constraints::Util::COMPARISON_ALIASES.each_pair do |orig, aliases|
|
216
|
+
if instance_methods.include?(orig.to_s)
|
217
|
+
aliases.each do |name|
|
218
|
+
alias_method(name, orig)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
# Creates aliases for any defined set methods.
|
225
|
+
def self.alias_set_methods
|
226
|
+
Gecode::Constraints::Util::SET_ALIASES.each_pair do |orig, aliases|
|
227
|
+
if instance_methods.include?(orig.to_s)
|
228
|
+
aliases.each do |name|
|
229
|
+
alias_method(name, orig)
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
# A composite expression which is a expression with a left hand side
|
237
|
+
# resulting from a previous constraint.
|
238
|
+
class CompositeExpression < Gecode::Constraints::Expression #:nodoc:
|
239
|
+
# The expression class should be the class of the expression delegated to,
|
240
|
+
# the variable class the kind of single variable used in the expression.
|
241
|
+
# The new var proc should produce a new variable (of the appropriate type)
|
242
|
+
# which has an unconstricted domain. The block given should take three
|
243
|
+
# parameters. The first is the variable that should be the left hand side.
|
244
|
+
# The second is the hash of parameters. The third is a boolean, it it's
|
245
|
+
# true then the block should try to constrain the first variable's domain
|
246
|
+
# as much as possible.
|
247
|
+
def initialize(expression_class, variable_class, new_var_proc, model,
|
248
|
+
params, &block)
|
249
|
+
super(model, params)
|
250
|
+
@expression_class = expression_class
|
251
|
+
@variable_class = variable_class
|
252
|
+
@new_var_proc = new_var_proc
|
253
|
+
@constrain_equal_proc = block
|
254
|
+
end
|
255
|
+
|
256
|
+
# Delegate to an instance of the expression class when we get something
|
257
|
+
# that we can't handle.
|
258
|
+
def method_missing(name, *args)
|
259
|
+
if @expression_class.instance_methods.include? name.to_s
|
260
|
+
options = {}
|
261
|
+
if args.size >= 2 and args[1].kind_of? Hash
|
262
|
+
options = args[1]
|
263
|
+
end
|
264
|
+
|
265
|
+
# Link a variable to the composite constraint.
|
266
|
+
@params.update Gecode::Constraints::Util.decode_options(options.clone)
|
267
|
+
variable = @new_var_proc.call
|
268
|
+
@model.add_interaction do
|
269
|
+
@constrain_equal_proc.call(variable, @params, true)
|
270
|
+
end
|
271
|
+
|
272
|
+
# Perform the operation on the linked variable.
|
273
|
+
int_var_params = @params.clone.update(:lhs => variable)
|
274
|
+
@expression_class.new(@model, int_var_params).send(name, *args)
|
275
|
+
else
|
276
|
+
super
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
def ==(expression, options = {})
|
281
|
+
if !@params[:negate] and options[:reify].nil? and
|
282
|
+
expression.kind_of? @variable_class
|
283
|
+
# We don't need any additional constraints.
|
284
|
+
@params.update Gecode::Constraints::Util.decode_options(options)
|
285
|
+
@model.add_interaction do
|
286
|
+
@constrain_equal_proc.call(expression, @params, false)
|
287
|
+
end
|
288
|
+
else
|
289
|
+
method_missing(:==, expression, options)
|
290
|
+
end
|
291
|
+
end
|
292
|
+
alias_comparison_methods
|
293
|
+
end
|
294
|
+
|
295
|
+
# Describes a constraint expression that has yet to be completed. I.e. a
|
296
|
+
# form of must has not yet been called, but some method has been called to
|
297
|
+
# initiate the expression. An example is distinct with offsets:
|
298
|
+
#
|
299
|
+
# enum.with_offsets(0..n).must_be.distinct
|
300
|
+
#
|
301
|
+
# The call of with_offsets initiates the constraint as a stub, even though
|
302
|
+
# must has not yet been called.
|
303
|
+
class ExpressionStub #:nodoc:
|
304
|
+
# Constructs a new expression with the specified parameters.
|
305
|
+
def initialize(model, params)
|
306
|
+
@model = model
|
307
|
+
@params = params
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
# Describes an expression stub which includes left hand side methods and
|
312
|
+
# just sends models and parameters through a supplied block to construct the
|
313
|
+
# resulting expression.
|
314
|
+
class SimpleExpressionStub < ExpressionStub #:nodoc:
|
315
|
+
include Gecode::Constraints::LeftHandSideMethods
|
316
|
+
|
317
|
+
# The block provided is executed when the expression demanded by the left
|
318
|
+
# hand side methods is to be constructed. The block should take two
|
319
|
+
# parameters: model and params (which have been updated with negate and
|
320
|
+
# so on). The block should return an expression.
|
321
|
+
def initialize(model, params, &block)
|
322
|
+
super(model, params)
|
323
|
+
@proc = block
|
324
|
+
end
|
325
|
+
|
326
|
+
private
|
327
|
+
|
328
|
+
# Produces an expression with offsets for the lhs module.
|
329
|
+
def expression(params)
|
330
|
+
@params.update(params)
|
331
|
+
@proc.call(@model, @params)
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
# Describes a stub that produces a variable, which can then be used with
|
336
|
+
# that variable's normalconstraints. An example with int variables would be
|
337
|
+
# the element constraint.
|
338
|
+
#
|
339
|
+
# int_enum[int_var].must > rhs
|
340
|
+
#
|
341
|
+
# The int_enum[int_var] part produces an int variable which the constraint
|
342
|
+
# ".must > rhs" is then applied to. In the above case two constraints (and
|
343
|
+
# one temporary variable) are required, but in the case of equality only
|
344
|
+
# one constraint is required.
|
345
|
+
class CompositeStub < Gecode::Constraints::ExpressionStub #:nodoc:
|
346
|
+
include Gecode::Constraints::LeftHandSideMethods
|
347
|
+
|
348
|
+
# The composite expression class should be the class that the stub uses
|
349
|
+
# when creating its expressions.
|
350
|
+
def initialize(composite_expression_class, model, params)
|
351
|
+
super(model, params)
|
352
|
+
@composite_class = composite_expression_class
|
353
|
+
end
|
354
|
+
|
355
|
+
private
|
356
|
+
|
357
|
+
# Constrains the result of the stub to be equal to the specified variable
|
358
|
+
# with the specified parameters. If constrain is true then the variable's
|
359
|
+
# domain should additionally be constrained as much as possible.
|
360
|
+
def constrain_equal(variable, params, constrain)
|
361
|
+
raise NoMethodError, 'Abstract method has not been implemented.'
|
362
|
+
end
|
363
|
+
|
364
|
+
# Produces an expression with position for the lhs module.
|
365
|
+
def expression(params)
|
366
|
+
@params.update params
|
367
|
+
@composite_class.new(@model, @params) do |var, params, constrain|
|
368
|
+
constrain_equal(var, params, constrain)
|
369
|
+
end
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
# Base class for all constraints.
|
374
|
+
class Constraint
|
375
|
+
# Creates a constraint with the specified parameters, bound to the
|
376
|
+
# specified model.
|
377
|
+
def initialize(model, params)
|
378
|
+
@model = model
|
379
|
+
@params = params.clone
|
380
|
+
end
|
381
|
+
|
382
|
+
# Posts the constraint, adding it to the model. This is an abstract
|
383
|
+
# method and should be overridden by all sub-classes.
|
384
|
+
def post
|
385
|
+
raise NoMethodError, 'Abstract method has not been implemented.'
|
386
|
+
end
|
387
|
+
end
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
391
|
+
require 'gecoder/interface/constraints/reifiable_constraints'
|
392
|
+
require 'gecoder/interface/constraints/int_var_constraints'
|
393
|
+
require 'gecoder/interface/constraints/int_enum_constraints'
|
394
|
+
require 'gecoder/interface/constraints/bool_var_constraints'
|
395
|
+
require 'gecoder/interface/constraints/bool_enum_constraints'
|
396
|
+
require 'gecoder/interface/constraints/set_var_constraints'
|
397
|
+
require 'gecoder/interface/constraints/set_enum_constraints'
|
@@ -0,0 +1,246 @@
|
|
1
|
+
module Gecode
|
2
|
+
class FreeBoolVar
|
3
|
+
# Initiates a boolean constraint with this variable or +var+.
|
4
|
+
def |(var)
|
5
|
+
Constraints::Bool::ExpressionNode.new(self, @model) | var
|
6
|
+
end
|
7
|
+
|
8
|
+
# Initiates a boolean constraint with this variable and +var+.
|
9
|
+
def &(var)
|
10
|
+
Constraints::Bool::ExpressionNode.new(self, @model) & var
|
11
|
+
end
|
12
|
+
|
13
|
+
# Initiates a boolean constraint with this variable exclusive or +var+.
|
14
|
+
def ^(var)
|
15
|
+
Constraints::Bool::ExpressionNode.new(self, @model) ^ var
|
16
|
+
end
|
17
|
+
|
18
|
+
# Initiates a boolean constraint with this variable implies +var+.
|
19
|
+
def implies(var)
|
20
|
+
Constraints::Bool::ExpressionNode.new(self, @model).implies var
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# A module that gathers the classes and modules used in boolean constraints.
|
25
|
+
module Constraints::Bool
|
26
|
+
# Describes a boolean expression (following after must*).
|
27
|
+
class Expression #:nodoc:
|
28
|
+
def ==(expression, options = {})
|
29
|
+
@params.update Gecode::Constraints::Util.decode_options(options)
|
30
|
+
@model.add_constraint BooleanConstraint.new(@model,
|
31
|
+
@params.update(:rhs => expression))
|
32
|
+
end
|
33
|
+
alias_comparison_methods
|
34
|
+
|
35
|
+
# Constrains the boolean expression to imply the specified expression.
|
36
|
+
def imply(expression, options = {})
|
37
|
+
@params.update Gecode::Constraints::Util.decode_options(options)
|
38
|
+
@params.update(:lhs => @params[:lhs].implies(expression), :rhs => true)
|
39
|
+
@model.add_constraint BooleanConstraint.new(@model, @params)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Constrains the boolean expression to be true.
|
43
|
+
def true
|
44
|
+
@params.update Gecode::Constraints::Util.decode_options({})
|
45
|
+
@model.add_constraint BooleanConstraint.new(@model,
|
46
|
+
@params.update(:rhs => true))
|
47
|
+
end
|
48
|
+
|
49
|
+
# Constrains the boolean expression to be false.
|
50
|
+
def false
|
51
|
+
@params[:negate] = !@params[:negate]
|
52
|
+
self.true
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Describes a constraint on a boolean expression.
|
57
|
+
#
|
58
|
+
# == Boolean expressions
|
59
|
+
#
|
60
|
+
# A boolean expression consists of several boolean variable with various
|
61
|
+
# boolean operators. The available operators are:
|
62
|
+
#
|
63
|
+
# [<tt>|</tt>] Or
|
64
|
+
# [<tt>&</tt>] And
|
65
|
+
# [<tt>^</tt>] Exclusive or
|
66
|
+
# [+implies+] Implication
|
67
|
+
#
|
68
|
+
# === Examples
|
69
|
+
#
|
70
|
+
# # +b1+ and +b2+
|
71
|
+
# b1 & b2
|
72
|
+
#
|
73
|
+
# # (+b1+ and +b2+) or +b3+
|
74
|
+
# (b1 & b1) | b3
|
75
|
+
#
|
76
|
+
# # (+b1+ and +b2+) or (+b3+ exclusive or +b1+)
|
77
|
+
# (b1 & b2) | (b3 ^ b1)
|
78
|
+
#
|
79
|
+
# # (+b1+ implies +b2+) and (+b3+ implies +b2+)
|
80
|
+
# (b1.implies b2) & (b3.implies b2)
|
81
|
+
#
|
82
|
+
# == Domain
|
83
|
+
#
|
84
|
+
# A domain constraint just specifies that a boolean expression must be true
|
85
|
+
# or false. Negation and reification are supported.
|
86
|
+
#
|
87
|
+
# === Examples
|
88
|
+
#
|
89
|
+
# # +b1+ and +b2+ must be true.
|
90
|
+
# (b1 & b2).must_be.true
|
91
|
+
#
|
92
|
+
# # (+b1+ implies +b2+) and (+b3+ implies +b2+) must be false.
|
93
|
+
# ((b1.implies b2) & (b3.implies b2)).must_be.false
|
94
|
+
#
|
95
|
+
# # +b1+ and +b2+ must be true. We reify it with +bool+ and select the
|
96
|
+
# # strength +domain+.
|
97
|
+
# (b1 & b2).must_be.true(:reify => bool, :strength => :domain)
|
98
|
+
#
|
99
|
+
# == Equality
|
100
|
+
#
|
101
|
+
# A constraint with equality specifies that two boolean expressions must be
|
102
|
+
# equal. Negation and reification are supported. Any of <tt>==</tt>,
|
103
|
+
# +equal+ and +equal_to+ may be used for equality.
|
104
|
+
#
|
105
|
+
# === Examples
|
106
|
+
#
|
107
|
+
# # +b1+ and +b2+ must equal +b1+ or +b2+.
|
108
|
+
# (b1 & b2).must == (b1 | b2)
|
109
|
+
#
|
110
|
+
# # +b1+ and +b2+ must not equal +b3+. We reify it with +bool+ and select
|
111
|
+
# # the strength +domain+.
|
112
|
+
# (b1 & b2).must_not.equal(b3, :reify => bool, :select => :domain)
|
113
|
+
#
|
114
|
+
# == Implication
|
115
|
+
#
|
116
|
+
# A constraint using +imply+ specified that one boolean expression must
|
117
|
+
# imply the other. Negation and reification are supported.
|
118
|
+
#
|
119
|
+
# === Examples
|
120
|
+
#
|
121
|
+
# # +b1+ must imply +b2+
|
122
|
+
# b1.must.imply b2
|
123
|
+
#
|
124
|
+
# # +b1+ and +b2+ must not imply +b3+. We reify it with +bool+ and select
|
125
|
+
# # +domain+ as strength.
|
126
|
+
# (b1 & b2).must_not.imply b3
|
127
|
+
class BooleanConstraint < Gecode::Constraints::ReifiableConstraint
|
128
|
+
def post
|
129
|
+
lhs, rhs, negate, strength, reif_var = @params.values_at(:lhs, :rhs,
|
130
|
+
:negate, :strength, :reif)
|
131
|
+
space = (lhs.model || rhs.model).active_space
|
132
|
+
|
133
|
+
# TODO: It should be possible to reduce the number of necessary
|
134
|
+
# variables and constraints a bit by altering the way that the top node
|
135
|
+
# is posted, using its constraint for reification etc when possible.
|
136
|
+
|
137
|
+
if rhs.respond_to? :bind
|
138
|
+
if reif_var.nil?
|
139
|
+
Gecode::Raw::bool_eqv(space, lhs.bind, rhs.bind, !negate, strength)
|
140
|
+
else
|
141
|
+
if negate
|
142
|
+
Gecode::Raw::bool_xor(space, lhs.bind, rhs.bind, reif_var.bind,
|
143
|
+
strength)
|
144
|
+
else
|
145
|
+
Gecode::Raw::bool_eqv(space, lhs.bind, rhs.bind, reif_var.bind,
|
146
|
+
strength)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
else
|
150
|
+
should_hold = !negate & rhs
|
151
|
+
if reif_var.nil?
|
152
|
+
Gecode::Raw::MiniModel::BoolExpr.new(lhs.bind).post(space,
|
153
|
+
should_hold)
|
154
|
+
else
|
155
|
+
Gecode::Raw::bool_eqv(space, lhs.bind, reif_var.bind, should_hold,
|
156
|
+
strength)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
# A module containing the methods for the basic boolean operations. Depends
|
163
|
+
# on that the class mixing it in defined #model.
|
164
|
+
module OperationMethods #:nodoc
|
165
|
+
include Gecode::Constraints::LeftHandSideMethods
|
166
|
+
|
167
|
+
private
|
168
|
+
|
169
|
+
# Maps the names of the methods to the corresponding bool constraint in
|
170
|
+
# Gecode.
|
171
|
+
OPERATION_TYPES = {
|
172
|
+
:| => :bool_or,
|
173
|
+
:& => :bool_and,
|
174
|
+
:^ => :bool_xor,
|
175
|
+
:implies => :bool_imp
|
176
|
+
}
|
177
|
+
|
178
|
+
public
|
179
|
+
|
180
|
+
OPERATION_TYPES.each_pair do |name, operation|
|
181
|
+
module_eval <<-"end_code"
|
182
|
+
def #{name}(expression)
|
183
|
+
unless expression.kind_of? ExpressionTree
|
184
|
+
expression = ExpressionNode.new(expression)
|
185
|
+
end
|
186
|
+
ExpressionTree.new(self, expression) do |model, var1, var2|
|
187
|
+
new_var = model.bool_var
|
188
|
+
Gecode::Raw::#{operation}(model.active_space, var1.bind, var2.bind,
|
189
|
+
new_var.bind, Gecode::Raw::ICL_DEF)
|
190
|
+
new_var
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end_code
|
194
|
+
end
|
195
|
+
|
196
|
+
private
|
197
|
+
|
198
|
+
# Produces an expression for the lhs module.
|
199
|
+
def expression(params)
|
200
|
+
params.update(:lhs => self)
|
201
|
+
Gecode::Constraints::Bool::Expression.new(model, params)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
# Describes a binary tree of expression nodes which together form a boolean
|
206
|
+
# expression.
|
207
|
+
class ExpressionTree #:nodoc:
|
208
|
+
include OperationMethods
|
209
|
+
|
210
|
+
# Constructs a new expression with the specified nodes. The proc should
|
211
|
+
# take a model followed by two variables and return a new variable.
|
212
|
+
def initialize(left_tree, right_tree, &block)
|
213
|
+
@left = left_tree
|
214
|
+
@right = right_tree
|
215
|
+
@bind_proc = block
|
216
|
+
end
|
217
|
+
|
218
|
+
# Returns a bound boolean variable representing the expression.
|
219
|
+
def bind
|
220
|
+
@bind_proc.call(model, @left, @right).bind
|
221
|
+
end
|
222
|
+
|
223
|
+
# Fetches the space that the expression's variables is in.
|
224
|
+
def model
|
225
|
+
@left.model || @right.model
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
# Describes a single node in a boolean expression.
|
230
|
+
class ExpressionNode #:nodoc:
|
231
|
+
include OperationMethods
|
232
|
+
|
233
|
+
attr :model
|
234
|
+
|
235
|
+
def initialize(value, model = nil)
|
236
|
+
@value = value
|
237
|
+
@model = model
|
238
|
+
end
|
239
|
+
|
240
|
+
# Returns a bound boolean variable representing the expression.
|
241
|
+
def bind
|
242
|
+
@value.bind
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|