gecoder 0.3.0 → 0.4.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.
- data/CHANGES +17 -2
- data/README +7 -1
- data/Rakefile +4 -0
- data/lib/gecoder/interface/constraints/bool/boolean.rb +1 -4
- data/lib/gecoder/interface/constraints/int/arithmetic.rb +77 -0
- data/lib/gecoder/interface/constraints/int/domain.rb +50 -0
- data/lib/gecoder/interface/constraints/int/linear.rb +12 -44
- data/lib/gecoder/interface/constraints/int_enum/arithmetic.rb +72 -0
- data/lib/gecoder/interface/constraints/int_enum/channel.rb +32 -0
- data/lib/gecoder/interface/constraints/int_enum/count.rb +90 -0
- data/lib/gecoder/interface/constraints/int_enum/distinct.rb +3 -8
- data/lib/gecoder/interface/constraints/int_enum/element.rb +75 -0
- data/lib/gecoder/interface/constraints/int_enum/equality.rb +31 -0
- data/lib/gecoder/interface/constraints/int_enum/sort.rb +104 -0
- data/lib/gecoder/interface/constraints/int_enum_constraints.rb +6 -0
- data/lib/gecoder/interface/constraints/int_var_constraints.rb +2 -0
- data/lib/gecoder/interface/constraints/reifiable_constraints.rb +21 -0
- data/lib/gecoder/interface/constraints.rb +57 -6
- data/lib/gecoder/interface/enum_matrix.rb +64 -0
- data/lib/gecoder/interface/enum_wrapper.rb +33 -5
- data/lib/gecoder/interface/model.rb +36 -6
- data/lib/gecoder/interface.rb +1 -0
- data/lib/gecoder/version.rb +4 -0
- data/lib/gecoder.rb +1 -0
- data/specs/binding_changes.rb +72 -0
- data/specs/bool_var.rb +20 -0
- data/specs/branch.rb +104 -0
- data/specs/constraints/arithmetic.rb +227 -0
- data/specs/constraints/boolean.rb +132 -0
- data/specs/constraints/channel.rb +55 -0
- data/specs/constraints/constraint_helper.rb +48 -0
- data/specs/constraints/constraints.rb +28 -0
- data/specs/constraints/count.rb +99 -0
- data/specs/constraints/distinct.rb +99 -0
- data/specs/constraints/domain.rb +56 -0
- data/specs/constraints/element.rb +128 -0
- data/specs/constraints/equality.rb +30 -0
- data/specs/constraints/linear.rb +166 -0
- data/specs/constraints/reification_sugar.rb +92 -0
- data/specs/constraints/relation.rb +72 -0
- data/specs/constraints/sort.rb +173 -0
- data/specs/enum_matrix.rb +43 -0
- data/specs/enum_wrapper.rb +100 -0
- data/specs/int_var.rb +108 -0
- data/specs/model.rb +84 -0
- data/specs/search.rb +157 -0
- data/specs/spec_helper.rb +63 -0
- data/specs/tmp +135 -0
- data/tasks/all_tasks.rb +1 -0
- data/tasks/distribution.rake +64 -0
- data/tasks/rcov.rake +17 -0
- data/tasks/specs.rake +16 -0
- data/tasks/svn.rake +11 -0
- data/tasks/website.rake +58 -0
- data/vendor/rust/include/rust_conversions.hh +1 -2
- metadata +53 -2
data/CHANGES
CHANGED
@@ -1,9 +1,25 @@
|
|
1
|
+
== Version 0.4.0
|
2
|
+
This release adds most of the constraints supported by Gecode for integer
|
3
|
+
variables.
|
4
|
+
|
5
|
+
* [#11861] Fixed a bug stopping the creating of int variables with non-range domains.
|
6
|
+
* Added domain constraints for int variables.
|
7
|
+
* Added equality constraint for int enums.
|
8
|
+
* Matrices of integer and boolean variables can now be created using Model#int_var_matrix Model#bool_var_matrix.
|
9
|
+
* Added channel constraint for int enums.
|
10
|
+
* Added element constraints (variable array access).
|
11
|
+
* Added count constraints.
|
12
|
+
* Added sortedness constraints.
|
13
|
+
* Added arithmetic constraints (min, max, abs and variable multiplication).
|
14
|
+
|
1
15
|
== Version 0.3.0
|
16
|
+
This release fleshes out the existing constraints with things such as
|
17
|
+
reification and adds boolean variables and their basic constraints.
|
2
18
|
|
3
19
|
* The constructor of Gecode::Model no longer has to be called by classes inheriting from it.
|
4
20
|
* Added Model#reset! which resets a model after search.
|
5
21
|
* Added Model#solution which passes the first solution to a block and returns the result of that block.
|
6
|
-
* Added Model#
|
22
|
+
* Added Model#each_solution which iterates over each solution.
|
7
23
|
* Added boolean variables. They are created using Model#bool_var and Model#bool_var_array .
|
8
24
|
* Added two options to constraints: propagation strength and reification variable.
|
9
25
|
* Linear and simple relation constraints can now also be specified using #equal, #equal_to, #greater, #greater_than,... in addition to comparison operators.
|
@@ -13,7 +29,6 @@
|
|
13
29
|
* Added syntactic sugar for combining reifiable constraints with | and &.
|
14
30
|
|
15
31
|
== Version 0.2.0
|
16
|
-
|
17
32
|
This is the first release of Gecode/R, a Ruby interface to Gecode.
|
18
33
|
|
19
34
|
* Added support for finite domain integers.
|
data/README
CHANGED
data/Rakefile
CHANGED
@@ -10,14 +10,11 @@ module Gecode
|
|
10
10
|
end
|
11
11
|
|
12
12
|
module Constraints::Bool
|
13
|
-
# Add some relation selection based on whether the expression is negated.
|
14
|
-
alias_method :pre_bool_rel_initialize, :initialize
|
15
13
|
class Expression
|
16
14
|
def ==(expression)
|
17
15
|
add_boolean_constraint(expression)
|
18
16
|
end
|
19
|
-
|
20
|
-
alias_method :equal_to, :==
|
17
|
+
alias_comparison_methods
|
21
18
|
|
22
19
|
def true
|
23
20
|
# Bind parameters.
|
@@ -0,0 +1,77 @@
|
|
1
|
+
class Gecode::FreeIntVar
|
2
|
+
# Initiates an arithmetic absolute value constraint.
|
3
|
+
def abs
|
4
|
+
Gecode::Constraints::Int::Arithmetic::AbsExpressionStub.new(@model,
|
5
|
+
:lhs => self)
|
6
|
+
end
|
7
|
+
|
8
|
+
# Creates a linear expression where the int variable is multiplied with
|
9
|
+
# a constant integer.
|
10
|
+
alias_method :pre_arith_mult, :* if instance_methods.include? '*'
|
11
|
+
def *(var)
|
12
|
+
if var.kind_of? Gecode::FreeIntVar
|
13
|
+
Gecode::Constraints::Int::Arithmetic::MultExpressionStub.new(
|
14
|
+
@model, :lhs => self, :var => var)
|
15
|
+
else
|
16
|
+
pre_arith_mult(var) if respond_to? :pre_arith_mult
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# A module that gathers the classes and modules used by arithmetic constraints.
|
22
|
+
module Gecode::Constraints::Int::Arithmetic
|
23
|
+
# Describes an expression stub started with an integer variable followed by
|
24
|
+
# #abs .
|
25
|
+
class AbsExpressionStub < Gecode::Constraints::ExpressionStub
|
26
|
+
include Gecode::Constraints::LeftHandSideMethods
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
# Produces a proxy expression for the lhs module.
|
31
|
+
def expression(params)
|
32
|
+
# We extract the integer and continue as if it had been specified as
|
33
|
+
# left hand side. This might be elegant, but it could get away with
|
34
|
+
# fewer constraints at times (when only equality is used) and
|
35
|
+
# propagation strength can't be specified.
|
36
|
+
# TODO: cut down on the number of constraints when possible. See if
|
37
|
+
# there's some neat way of getting the above remarks.
|
38
|
+
|
39
|
+
params.update(@params)
|
40
|
+
lhs = params[:lhs]
|
41
|
+
proxy = @model.int_var(lhs.min..lhs.max)
|
42
|
+
lhs = lhs.bind
|
43
|
+
|
44
|
+
Gecode::Raw::abs(@model.active_space, lhs, proxy.bind,
|
45
|
+
Gecode::Raw::ICL_DEF)
|
46
|
+
Gecode::Constraints::Int::Expression.new(@model,
|
47
|
+
params.update(:lhs => proxy))
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Describes an expression stub started with an integer variable followed by
|
52
|
+
# #* .
|
53
|
+
class MultExpressionStub < Gecode::Constraints::ExpressionStub
|
54
|
+
include Gecode::Constraints::LeftHandSideMethods
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
# Produces a proxy expression for the lhs module.
|
59
|
+
def expression(params)
|
60
|
+
# We extract the integer and continue as if it had been specified as
|
61
|
+
# left hand side. This might be elegant, but it could get away with
|
62
|
+
# fewer constraints at times (when only equality is used) and
|
63
|
+
# propagation strength can't be specified.
|
64
|
+
# TODO: cut down on the number of constraints when possible. See if
|
65
|
+
# there's some neat way of getting the above remarks.
|
66
|
+
|
67
|
+
params.update(@params)
|
68
|
+
lhs, var = params.values_at(:lhs, :var)
|
69
|
+
proxy = @model.int_var(-(lhs.min*var.min).abs..(lhs.max*var.max).abs) # Sloppy
|
70
|
+
|
71
|
+
Gecode::Raw::mult(@model.active_space, lhs.bind, var.bind, proxy.bind,
|
72
|
+
Gecode::Raw::ICL_DEF)
|
73
|
+
Gecode::Constraints::Int::Expression.new(@model,
|
74
|
+
params.update(:lhs => proxy))
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Gecode::Constraints::Int
|
2
|
+
class Expression
|
3
|
+
# Creates a domain constraint using the specified domain.
|
4
|
+
def in(domain, options = {})
|
5
|
+
@params.update(Gecode::Constraints::Util.decode_options(options))
|
6
|
+
@params[:domain] = domain
|
7
|
+
if domain.kind_of? Range
|
8
|
+
@model.add_constraint Domain::RangeDomainConstraint.new(@model, @params)
|
9
|
+
else
|
10
|
+
@model.add_constraint Domain::NonRangeDomainConstraint.new(@model,
|
11
|
+
@params)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# A module that gathers the classes and modules used in domain constraints.
|
17
|
+
module Domain
|
18
|
+
# Describes a range domain constraint.
|
19
|
+
class RangeDomainConstraint < Gecode::Constraints::ReifiableConstraint
|
20
|
+
def post
|
21
|
+
var, domain, reif_var, strength = @params.values_at(:lhs, :domain,
|
22
|
+
:reif, :strength)
|
23
|
+
(params = []) << var.bind
|
24
|
+
params << domain.first << domain.last
|
25
|
+
params << reif_var.bind if reif_var.respond_to? :bind
|
26
|
+
params << strength
|
27
|
+
Gecode::Raw::dom(@model.active_space, *params)
|
28
|
+
end
|
29
|
+
negate_using_reification
|
30
|
+
end
|
31
|
+
|
32
|
+
# Describes a non-range domain constraint.
|
33
|
+
class NonRangeDomainConstraint < Gecode::Constraints::ReifiableConstraint
|
34
|
+
def post
|
35
|
+
space = @model.active_space
|
36
|
+
|
37
|
+
var, domain, reif_var, strength = @params.values_at(:lhs, :domain,
|
38
|
+
:reif, :strength)
|
39
|
+
domain = domain.to_a
|
40
|
+
|
41
|
+
(params = []) << var.bind
|
42
|
+
params << Gecode::Raw::IntSet.new(domain, domain.size)
|
43
|
+
params << reif_var.bind if reif_var.respond_to? :bind
|
44
|
+
params << strength
|
45
|
+
Gecode::Raw::dom(space, *params)
|
46
|
+
end
|
47
|
+
negate_using_reification
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -8,9 +8,14 @@ module Gecode
|
|
8
8
|
|
9
9
|
# Creates a linear expression where the int variable is multiplied with
|
10
10
|
# a constant integer.
|
11
|
+
alias_method :pre_linear_mult, :* if instance_methods.include? '*'
|
11
12
|
def *(int)
|
12
|
-
|
13
|
-
|
13
|
+
if int.kind_of? Fixnum
|
14
|
+
Gecode::Constraints::Int::Linear::ExpressionNode.new(self,
|
15
|
+
@model) * int
|
16
|
+
else
|
17
|
+
pre_linear_mult(int) if respond_to? :pre_linear_mult
|
18
|
+
end
|
14
19
|
end
|
15
20
|
|
16
21
|
# Creates a linear expression where the specified variable is subtracted
|
@@ -23,55 +28,24 @@ module Gecode
|
|
23
28
|
|
24
29
|
module Constraints::Int
|
25
30
|
class Expression
|
26
|
-
private
|
27
|
-
|
28
|
-
# Maps the names of the methods to the corresponding integer relation
|
29
|
-
# type in Gecode.
|
30
|
-
RELATION_TYPES = {
|
31
|
-
:== => Gecode::Raw::IRT_EQ,
|
32
|
-
:<= => Gecode::Raw::IRT_LQ,
|
33
|
-
:< => Gecode::Raw::IRT_LE,
|
34
|
-
:>= => Gecode::Raw::IRT_GQ,
|
35
|
-
:> => Gecode::Raw::IRT_GR }
|
36
|
-
# The same as above, but negated.
|
37
|
-
NEGATED_RELATION_TYPES = {
|
38
|
-
:== => Gecode::Raw::IRT_NQ,
|
39
|
-
:<= => Gecode::Raw::IRT_GR,
|
40
|
-
:< => Gecode::Raw::IRT_GQ,
|
41
|
-
:>= => Gecode::Raw::IRT_LE,
|
42
|
-
:> => Gecode::Raw::IRT_LQ
|
43
|
-
}
|
44
|
-
|
45
|
-
# Various method aliases for the class. Maps the original name to an
|
46
|
-
# array of aliases.
|
47
|
-
METHOD_ALIASES = {
|
48
|
-
:== => [:equal, :equal_to],
|
49
|
-
:> => [:greater, :greater_than],
|
50
|
-
:>= => [:greater_or_equal, :greater_than_or_equal_to],
|
51
|
-
:< => [:less, :less_than],
|
52
|
-
:<= => [:less_or_equal, :less_than_or_equal_to]
|
53
|
-
}
|
54
|
-
|
55
|
-
public
|
56
|
-
|
57
31
|
# Add some relation selection based on whether the expression is negated.
|
58
32
|
alias_method :pre_linear_initialize, :initialize
|
59
33
|
def initialize(model, params)
|
60
34
|
pre_linear_initialize(model, params)
|
61
35
|
unless params[:negate]
|
62
|
-
@method_relations = RELATION_TYPES
|
36
|
+
@method_relations = Constraints::Util::RELATION_TYPES
|
63
37
|
else
|
64
|
-
@method_relations = NEGATED_RELATION_TYPES
|
38
|
+
@method_relations = Constraints::Util::NEGATED_RELATION_TYPES
|
65
39
|
end
|
66
40
|
end
|
67
41
|
|
68
42
|
# Define the relation methods.
|
69
|
-
RELATION_TYPES.each_key do |name|
|
43
|
+
Constraints::Util::RELATION_TYPES.each_key do |name|
|
70
44
|
module_eval <<-"end_code"
|
71
45
|
def #{name}(expression, options = {})
|
72
46
|
relation = @method_relations[:#{name}]
|
73
47
|
@params.update(
|
74
|
-
Gecode::Constraints::
|
48
|
+
Gecode::Constraints::Util.decode_options(options))
|
75
49
|
if self.simple_expression? and simple_expression?(expression)
|
76
50
|
# A relation constraint is enough.
|
77
51
|
add_relation_constraint(relation, expression)
|
@@ -81,13 +55,7 @@ module Gecode
|
|
81
55
|
end
|
82
56
|
end_code
|
83
57
|
end
|
84
|
-
|
85
|
-
# Various aliases.
|
86
|
-
METHOD_ALIASES.each_pair do |orig, alias_names|
|
87
|
-
alias_names.each do |name|
|
88
|
-
alias_method name, orig
|
89
|
-
end
|
90
|
-
end
|
58
|
+
alias_comparison_methods
|
91
59
|
|
92
60
|
protected
|
93
61
|
|
@@ -0,0 +1,72 @@
|
|
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)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# A module that gathers the classes and modules used by arithmetic constraints.
|
18
|
+
module Gecode::Constraints::IntEnum::Arithmetic
|
19
|
+
# Describes an expression stub started with an int var enum following by #max.
|
20
|
+
class MaxExpressionStub < Gecode::Constraints::ExpressionStub
|
21
|
+
include Gecode::Constraints::LeftHandSideMethods
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
# Produces an expression for the lhs module.
|
26
|
+
def expression(params)
|
27
|
+
# We extract the integer and continue as if it had been specified as
|
28
|
+
# left hand side. This might be elegant, but it could get away with
|
29
|
+
# fewer constraints at times (when only equality is used) and
|
30
|
+
# propagation strength can't be specified.
|
31
|
+
# TODO: cut down on the number of constraints when possible. See if
|
32
|
+
# there's some neat way of getting the above remarks.
|
33
|
+
|
34
|
+
params.update(@params)
|
35
|
+
lhs = params[:lhs]
|
36
|
+
proxy = @model.int_var(lhs.domain_range)
|
37
|
+
lhs = lhs.to_int_var_array
|
38
|
+
|
39
|
+
Gecode::Raw::max(@model.active_space, lhs, proxy.bind,
|
40
|
+
Gecode::Raw::ICL_DEF)
|
41
|
+
Gecode::Constraints::Int::Expression.new(@model,
|
42
|
+
params.update(:lhs => proxy))
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Describes an expression stub started with an int var enum following by #min.
|
47
|
+
class MinExpressionStub < Gecode::Constraints::ExpressionStub
|
48
|
+
include Gecode::Constraints::LeftHandSideMethods
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
# Produces an expression for the lhs module.
|
53
|
+
def expression(params)
|
54
|
+
# We extract the integer and continue as if it had been specified as
|
55
|
+
# left hand side. This might be elegant, but it could get away with
|
56
|
+
# fewer constraints at times (when only equality is used) and
|
57
|
+
# propagation strength can't be specified.
|
58
|
+
# TODO: cut down on the number of constraints when possible. See if
|
59
|
+
# there's some neat way of getting the above remarks.
|
60
|
+
|
61
|
+
params.update(@params)
|
62
|
+
lhs = params[:lhs]
|
63
|
+
proxy = @model.int_var(lhs.domain_range)
|
64
|
+
lhs = lhs.to_int_var_array
|
65
|
+
|
66
|
+
Gecode::Raw::min(@model.active_space, lhs, proxy.bind,
|
67
|
+
Gecode::Raw::ICL_DEF)
|
68
|
+
Gecode::Constraints::Int::Expression.new(@model,
|
69
|
+
params.update(:lhs => proxy))
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Gecode::Constraints::IntEnum
|
2
|
+
class Expression
|
3
|
+
# Posts a channel constraint on the variables in the enum with the specified
|
4
|
+
# other 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
|
+
|
11
|
+
@params.update(Gecode::Constraints::Util.decode_options(options))
|
12
|
+
@params.update(:rhs => enum)
|
13
|
+
@model.add_constraint Channel::ChannelConstraint.new(@model, @params)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# A module that gathers the classes and modules used in channel constraints.
|
18
|
+
module Channel
|
19
|
+
# Describes a channel constraint.
|
20
|
+
class ChannelConstraint < Gecode::Constraints::Constraint
|
21
|
+
def post
|
22
|
+
lhs, rhs, strength = @params.values_at(:lhs, :rhs, :strength)
|
23
|
+
|
24
|
+
# Bind both sides.
|
25
|
+
lhs = lhs.to_int_var_array
|
26
|
+
rhs = rhs.to_int_var_array
|
27
|
+
|
28
|
+
Gecode::Raw::channel(@model.active_space, lhs, rhs, strength)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,90 @@
|
|
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
|
+
return Gecode::Constraints::IntEnum::Count::ExpressionStub.new(
|
12
|
+
@model, params)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# A module that gathers the classes and modules used in count constraints.
|
18
|
+
module Gecode::Constraints::IntEnum::Count
|
19
|
+
|
20
|
+
|
21
|
+
# Describes an expression stub started with an int var enum followed by
|
22
|
+
# #count .
|
23
|
+
class ExpressionStub < Gecode::Constraints::ExpressionStub
|
24
|
+
include Gecode::Constraints::LeftHandSideMethods
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
# Produces an expression with the element for the lhs module.
|
29
|
+
def expression(params)
|
30
|
+
params.update(@params)
|
31
|
+
Gecode::Constraints::IntEnum::Count::Expression.new(@model, params)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Describes an expression
|
36
|
+
class Expression < Gecode::Constraints::IntEnum::Expression
|
37
|
+
def initialize(model, params)
|
38
|
+
super
|
39
|
+
unless params[:negate]
|
40
|
+
@method_relations = Gecode::Constraints::Util::RELATION_TYPES
|
41
|
+
else
|
42
|
+
@method_relations = Gecode::Constraints::Util::NEGATED_RELATION_TYPES
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
Gecode::Constraints::Util::RELATION_TYPES.each_pair do |name, type|
|
47
|
+
class_eval <<-"end_code"
|
48
|
+
def #{name}(expression, options = {})
|
49
|
+
unless expression.kind_of?(Fixnum) or
|
50
|
+
expression.kind_of?(Gecode::FreeIntVar)
|
51
|
+
raise TypeError, 'Invalid right hand side of count constraint: ' +
|
52
|
+
"\#{expression.class}."
|
53
|
+
end
|
54
|
+
|
55
|
+
relation = @method_relations[:#{name}]
|
56
|
+
@params.update(Gecode::Constraints::Util.decode_options(options))
|
57
|
+
@params.update(:rhs => expression, :relation_type => relation)
|
58
|
+
@model.add_constraint CountConstraint.new(@model, @params)
|
59
|
+
end
|
60
|
+
end_code
|
61
|
+
end
|
62
|
+
alias_comparison_methods
|
63
|
+
end
|
64
|
+
|
65
|
+
# Describes a count constraint.
|
66
|
+
class CountConstraint < Gecode::Constraints::ReifiableConstraint
|
67
|
+
def post
|
68
|
+
lhs, element, relation_type, rhs, strength, reif_var =
|
69
|
+
@params.values_at(:lhs, :element, :relation_type, :rhs, :strength,
|
70
|
+
:reif)
|
71
|
+
|
72
|
+
# Bind variables if needed.
|
73
|
+
element = element.bind if element.respond_to? :bind
|
74
|
+
rhs = rhs.bind if rhs.respond_to? :bind
|
75
|
+
|
76
|
+
# Post the constraint to gecode.
|
77
|
+
if reif_var.nil?
|
78
|
+
Gecode::Raw::count(@model.active_space, lhs.to_int_var_array,
|
79
|
+
element, relation_type, rhs, strength)
|
80
|
+
else
|
81
|
+
# We use a proxy int variable to get the reification.
|
82
|
+
proxy = @model.int_var(rhs.min..rhs.max)
|
83
|
+
rel = Gecode::Constraints::Util::RELATION_TYPES.invert[relation_type]
|
84
|
+
proxy.must.send(rel, @params[:rhs], :reify => reif_var)
|
85
|
+
Gecode::Raw::count(@model.active_space, lhs.to_int_var_array,
|
86
|
+
element, Gecode::Raw::IRT_EQ, proxy.bind, strength)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -7,7 +7,7 @@ module Gecode
|
|
7
7
|
offsets = *offsets
|
8
8
|
end
|
9
9
|
params = {:lhs => self, :offsets => offsets}
|
10
|
-
return Gecode::Constraints::IntEnum::Distinct::
|
10
|
+
return Gecode::Constraints::IntEnum::Distinct::OffsetExpressionStub.new(
|
11
11
|
@model, params)
|
12
12
|
end
|
13
13
|
end
|
@@ -25,7 +25,7 @@ module Gecode::Constraints::IntEnum
|
|
25
25
|
end
|
26
26
|
|
27
27
|
@model.add_constraint Distinct::DistinctConstraint.new(@model,
|
28
|
-
@params.update(Gecode::Constraints::
|
28
|
+
@params.update(Gecode::Constraints::Util.decode_options(options)))
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
@@ -33,14 +33,9 @@ module Gecode::Constraints::IntEnum
|
|
33
33
|
module Distinct
|
34
34
|
# Describes an expression started with an int var enum following with
|
35
35
|
# #with_offsets .
|
36
|
-
class
|
36
|
+
class OffsetExpressionStub < Gecode::Constraints::ExpressionStub
|
37
37
|
include Gecode::Constraints::LeftHandSideMethods
|
38
38
|
|
39
|
-
def initialize(model, params)
|
40
|
-
@model = model
|
41
|
-
@params = params
|
42
|
-
end
|
43
|
-
|
44
39
|
private
|
45
40
|
|
46
41
|
# Produces an expression with offsets for the lhs module.
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# A module that gathers the classes and modules used by element constraints.
|
2
|
+
module Gecode::Constraints::IntEnum::Element
|
3
|
+
# Describes an expression stub started with an int var enum following with an
|
4
|
+
# array access using an integer variables .
|
5
|
+
class ExpressionStub < Gecode::Constraints::ExpressionStub
|
6
|
+
include Gecode::Constraints::LeftHandSideMethods
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
# Produces an expression with position for the lhs module.
|
11
|
+
def expression(params)
|
12
|
+
# We extract the integer and continue as if it had been specified as
|
13
|
+
# left hand side. This might be elegant, but it could get away with
|
14
|
+
# fewer constraints at times (when only equality is used) and
|
15
|
+
# propagation strength can't be specified.
|
16
|
+
# TODO: cut down on the number of constraints when possible. See if
|
17
|
+
# there's some neat way of getting the above remarks.
|
18
|
+
|
19
|
+
params.update(@params)
|
20
|
+
enum, position = params.values_at(:lhs, :position)
|
21
|
+
tmp = @model.int_var(enum.domain_range)
|
22
|
+
enum = enum.to_int_var_array if enum.respond_to? :to_int_var_array
|
23
|
+
|
24
|
+
Gecode::Raw::element(@model.active_space, enum,
|
25
|
+
position.bind, tmp.bind, Gecode::Raw::ICL_DEF)
|
26
|
+
Gecode::Constraints::Int::Expression.new(@model,
|
27
|
+
params.update(:lhs => tmp))
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Methods needed to add support for element constraints to enums.
|
32
|
+
module AdditionalEnumMethods
|
33
|
+
# This adds the adder for the methods in the modules including it. The
|
34
|
+
# reason for doing it so indirect is that the first #[] won't be defined
|
35
|
+
# before the module that this is mixed into is mixed into an enum.
|
36
|
+
def self.included(enum_mod)
|
37
|
+
enum_mod.module_eval do
|
38
|
+
# Now we enter the module AdditionalEnumMethods is mixed into.
|
39
|
+
class << self
|
40
|
+
alias_method :pre_element_included, :included
|
41
|
+
def included(mod)
|
42
|
+
mod.module_eval do
|
43
|
+
# Now we enter the module that the module possibly defining #[]
|
44
|
+
# is mixed into.
|
45
|
+
if instance_methods.include? '[]'
|
46
|
+
alias_method :pre_element_access, :[]
|
47
|
+
end
|
48
|
+
|
49
|
+
def [](*vars)
|
50
|
+
# Hook in an element constraint if a variable is used for array
|
51
|
+
# access.
|
52
|
+
if vars.first.kind_of? Gecode::FreeIntVar
|
53
|
+
params = {:lhs => self, :position => vars.first}
|
54
|
+
return Gecode::Constraints::IntEnum::Element::ExpressionStub.new(
|
55
|
+
@model, params)
|
56
|
+
else
|
57
|
+
pre_element_access(*vars) if respond_to? :pre_element_access
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
pre_element_included(mod)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
module Gecode::IntEnumMethods
|
70
|
+
include Gecode::Constraints::IntEnum::Element::AdditionalEnumMethods
|
71
|
+
end
|
72
|
+
|
73
|
+
module Gecode::FixnumEnumMethods
|
74
|
+
include Gecode::Constraints::IntEnum::Element::AdditionalEnumMethods
|
75
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Gecode::Constraints::IntEnum
|
2
|
+
class Expression
|
3
|
+
# Posts an equality constraint on the variables in the enum.
|
4
|
+
def equal(options = {})
|
5
|
+
if @params[:negate]
|
6
|
+
# The best we could implement it as from here would be a bunch of
|
7
|
+
# reified pairwise inequality constraints.
|
8
|
+
raise Gecode::MissingConstraintError, 'A negated equality is not ' +
|
9
|
+
'implemented.'
|
10
|
+
end
|
11
|
+
|
12
|
+
@model.add_constraint Equality::EqualityConstraint.new(@model,
|
13
|
+
@params.update(Gecode::Constraints::Util.decode_options(options)))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# A module that gathers the classes and modules used in equality constraints.
|
18
|
+
module Equality
|
19
|
+
# Describes an equality constraint.
|
20
|
+
class EqualityConstraint < Gecode::Constraints::Constraint
|
21
|
+
def post
|
22
|
+
# Bind lhs.
|
23
|
+
@params[:lhs] = @params[:lhs].to_int_var_array
|
24
|
+
|
25
|
+
# Fetch the parameters to Gecode.
|
26
|
+
params = @params.values_at(:lhs, :strength)
|
27
|
+
Gecode::Raw::eq(@model.active_space, *params)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|