gecoder 0.2.0 → 0.3.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 +21 -0
- data/README +9 -1
- data/ext/missing.cpp +1 -1
- data/ext/vararray.cpp +4 -0
- data/ext/vararray.h +2 -1
- data/lib/gecoder/bindings/bindings.rb +55 -5
- data/lib/gecoder/interface.rb +1 -0
- data/lib/gecoder/interface/binding_changes.rb +183 -81
- data/lib/gecoder/interface/branch.rb +1 -1
- data/lib/gecoder/interface/constraints.rb +121 -5
- data/lib/gecoder/interface/constraints/bool/boolean.rb +160 -0
- data/lib/gecoder/interface/constraints/bool_var_constraints.rb +23 -0
- data/lib/gecoder/interface/constraints/int/linear.rb +258 -0
- data/lib/gecoder/interface/constraints/int_enum/distinct.rb +66 -0
- data/lib/gecoder/interface/constraints/int_enum_constraints.rb +31 -0
- data/lib/gecoder/interface/constraints/int_var_constraints.rb +22 -0
- data/lib/gecoder/interface/constraints/reifiable_constraints.rb +57 -0
- data/lib/gecoder/interface/enum_wrapper.rb +39 -33
- data/lib/gecoder/interface/model.rb +44 -64
- data/lib/gecoder/interface/search.rb +40 -3
- data/lib/gecoder/interface/variables.rb +62 -0
- metadata +19 -8
- data/lib/gecoder/interface/constraints/distinct.rb +0 -15
- data/lib/gecoder/interface/constraints/linear.rb +0 -158
- data/lib/gecoder/interface/constraints/relation.rb +0 -76
@@ -95,7 +95,7 @@ module Gecode
|
|
95
95
|
end
|
96
96
|
|
97
97
|
# Add the branching.
|
98
|
-
Gecode::Raw.branch(active_space, variables.
|
98
|
+
Gecode::Raw.branch(active_space, variables.to_var_array,
|
99
99
|
BRANCH_VAR_CONSTANTS[var_strat], BRANCH_VALUE_CONSTANTS[val_strat])
|
100
100
|
end
|
101
101
|
end
|
@@ -1,10 +1,126 @@
|
|
1
|
-
require 'gecoder/interface/constraints/relation'
|
2
|
-
require 'gecoder/interface/constraints/distinct'
|
3
|
-
require 'gecoder/interface/constraints/linear'
|
4
|
-
|
5
1
|
module Gecode
|
6
2
|
# An error signaling that the constraint specified is missing (e.g. one tried
|
7
3
|
# to negate a constraint, but no negated form is implemented).
|
8
4
|
class MissingConstraintError < StandardError
|
9
5
|
end
|
10
|
-
|
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
|
14
|
+
# Specifies that a constraint must hold for the integer variable enum.
|
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 integer
|
21
|
+
# variable.
|
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
|
+
# Describes a constraint expressions. An expression is produced by calling
|
37
|
+
# some form of must on a left hand side. The expression waits for a right
|
38
|
+
# hand side so that it can post the corresponding constraint.
|
39
|
+
class Expression
|
40
|
+
# Constructs a new expression with the specified parameters. The
|
41
|
+
# parameters shoud at least contain the keys :lhs, and :negate.
|
42
|
+
#
|
43
|
+
# Raises ArgumentError if any of those keys are missing.
|
44
|
+
def initialize(model, params)
|
45
|
+
unless params.has_key?(:lhs) and params.has_key?(:negate)
|
46
|
+
raise ArgumentError, 'Expression requires at least :lhs, ' +
|
47
|
+
"and :negate as parameter keys, got #{params.keys.join(', ')}."
|
48
|
+
end
|
49
|
+
|
50
|
+
@model = model
|
51
|
+
@params = params
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Base class for all constraints.
|
56
|
+
class Constraint
|
57
|
+
# Creates a constraint with the specified parameters, bound to the
|
58
|
+
# specified model.
|
59
|
+
def initialize(model, params)
|
60
|
+
@model = model
|
61
|
+
@params = params.clone
|
62
|
+
end
|
63
|
+
|
64
|
+
# Posts the constraint, adding it to the model. This is an abstract
|
65
|
+
# method and should be overridden by all sub-classes.
|
66
|
+
def post
|
67
|
+
raise NoMethodError, 'Abstract method has not been implemented.'
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# A module that provides some utility-methods for decoding options given to
|
72
|
+
# constraints.
|
73
|
+
module OptionUtil
|
74
|
+
private
|
75
|
+
|
76
|
+
# Maps the name used in options to the value used in Gecode for
|
77
|
+
# propagation strengths.
|
78
|
+
PROPAGATION_STRENGTHS = {
|
79
|
+
:default => Gecode::Raw::ICL_DEF,
|
80
|
+
:value => Gecode::Raw::ICL_VAL,
|
81
|
+
:bounds => Gecode::Raw::ICL_BND,
|
82
|
+
:domain => Gecode::Raw::ICL_DOM
|
83
|
+
}
|
84
|
+
|
85
|
+
public
|
86
|
+
|
87
|
+
module_function
|
88
|
+
|
89
|
+
# Decodes the common options to constraints: strength and reification.
|
90
|
+
# Returns a hash with up to two values. :strength is the strength that
|
91
|
+
# should be used for the constraint and :reif is the (bound) boolean
|
92
|
+
# variable that should be used for reification. The decoded options are
|
93
|
+
# removed from the hash (so in general the hash will be consumed in the
|
94
|
+
# process).
|
95
|
+
#
|
96
|
+
# Raises ArgumentError if an unrecognized option is found in the specified
|
97
|
+
# hash. Or if an unrecognized strength is given. Raises TypeError if the
|
98
|
+
# reification variable is not a boolean variable.
|
99
|
+
def decode_options(options)
|
100
|
+
# Propagation strength.
|
101
|
+
strength = options.delete(:strength) || :default
|
102
|
+
unless PROPAGATION_STRENGTHS.include? strength
|
103
|
+
raise ArgumentError, "Unrecognized propagation strength #{strength}."
|
104
|
+
end
|
105
|
+
|
106
|
+
# Reification.
|
107
|
+
reif_var = options.delete(:reify)
|
108
|
+
unless reif_var.nil? or reif_var.kind_of? FreeBoolVar
|
109
|
+
raise TypeError, 'Only boolean variables may be used for reification.'
|
110
|
+
end
|
111
|
+
|
112
|
+
# Check for unrecognized options.
|
113
|
+
unless options.empty?
|
114
|
+
raise ArgumentError, 'Unrecognized constraint option: ' +
|
115
|
+
options.keys.first.to_s
|
116
|
+
end
|
117
|
+
return {:strength => PROPAGATION_STRENGTHS[strength], :reif => reif_var}
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
require 'gecoder/interface/constraints/reifiable_constraints'
|
124
|
+
require 'gecoder/interface/constraints/int_var_constraints'
|
125
|
+
require 'gecoder/interface/constraints/int_enum_constraints'
|
126
|
+
require 'gecoder/interface/constraints/bool_var_constraints'
|
@@ -0,0 +1,160 @@
|
|
1
|
+
module Gecode
|
2
|
+
class FreeBoolVar
|
3
|
+
def |(var)
|
4
|
+
Constraints::Bool::ExpressionNode.new(self, @model) | var
|
5
|
+
end
|
6
|
+
|
7
|
+
def &(var)
|
8
|
+
Constraints::Bool::ExpressionNode.new(self, @model) & var
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
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
|
+
class Expression
|
16
|
+
def ==(expression)
|
17
|
+
add_boolean_constraint(expression)
|
18
|
+
end
|
19
|
+
alias_method :equal, :==
|
20
|
+
alias_method :equal_to, :==
|
21
|
+
|
22
|
+
def true
|
23
|
+
# Bind parameters.
|
24
|
+
lhs = @params[:lhs]
|
25
|
+
unless lhs.respond_to? :to_minimodel_lin_exp
|
26
|
+
lhs = ExpressionNode.new(lhs, @model)
|
27
|
+
end
|
28
|
+
|
29
|
+
@model.add_constraint BooleanConstraint.new(@model,
|
30
|
+
@params.update(:expression => lhs.to_minimodel_lin_exp))
|
31
|
+
end
|
32
|
+
|
33
|
+
def false
|
34
|
+
# Bind parameters.
|
35
|
+
lhs = @params[:lhs]
|
36
|
+
unless lhs.respond_to? :to_minimodel_lin_exp
|
37
|
+
lhs = ExpressionNode.new(lhs, @model)
|
38
|
+
end
|
39
|
+
|
40
|
+
@params.update(:expression => Gecode::Raw::MiniModel::BoolExpr.new(
|
41
|
+
lhs.to_minimodel_lin_exp, Gecode::Raw::MiniModel::BoolExpr::BT_NOT))
|
42
|
+
@model.add_constraint BooleanConstraint.new(@model, @params)
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
# Adds the boolean constraint corresponding to equivalence between the
|
48
|
+
# left and right hand sides.
|
49
|
+
#
|
50
|
+
# Raises TypeError if the element is of a type that doesn't allow a
|
51
|
+
# relation to be specified.
|
52
|
+
def add_boolean_constraint(right_hand_side = nil)
|
53
|
+
# Bind parameters.
|
54
|
+
lhs = @params[:lhs]
|
55
|
+
unless lhs.respond_to? :to_minimodel_lin_exp
|
56
|
+
lhs = ExpressionNode.new(lhs, @model)
|
57
|
+
end
|
58
|
+
unless right_hand_side.respond_to? :to_minimodel_lin_exp
|
59
|
+
right_hand_side = ExpressionNode.new(right_hand_side, @model)
|
60
|
+
end
|
61
|
+
|
62
|
+
expression = ExpressionTree.new(lhs, right_hand_side,
|
63
|
+
Gecode::Raw::MiniModel::BoolExpr::BT_EQV)
|
64
|
+
@model.add_constraint BooleanConstraint.new(@model,
|
65
|
+
@params.update(:expression => expression.to_minimodel_lin_exp))
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Describes a boolean constraint.
|
70
|
+
class BooleanConstraint < Gecode::Constraints::ReifiableConstraint
|
71
|
+
def post
|
72
|
+
unless @params[:reif].nil?
|
73
|
+
@params[:expression] = Gecode::Raw::MiniModel::BoolExpr.new(
|
74
|
+
@params[:expression], Gecode::Raw::MiniModel::BoolExpr::BT_EQV,
|
75
|
+
Gecode::Raw::MiniModel::BoolExpr.new(@params[:reif].bind))
|
76
|
+
end
|
77
|
+
@params[:expression].post(@model.active_space, !@params[:negate])
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# A module containing the methods for the basic boolean operations. Depends
|
82
|
+
# on that the class mixing it in defined #model.
|
83
|
+
module OperationMethods
|
84
|
+
include Gecode::Constraints::LeftHandSideMethods
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
# Maps the names of the methods to the corresponding bool operation type
|
89
|
+
# in Gecode.
|
90
|
+
OPERATION_TYPES = {
|
91
|
+
:| => Gecode::Raw::MiniModel::BoolExpr::BT_OR,
|
92
|
+
:& => Gecode::Raw::MiniModel::BoolExpr::BT_AND
|
93
|
+
}
|
94
|
+
|
95
|
+
public
|
96
|
+
|
97
|
+
OPERATION_TYPES.each_pair do |name, operation|
|
98
|
+
module_eval <<-"end_code"
|
99
|
+
def #{name}(expression)
|
100
|
+
unless expression.kind_of? ExpressionTree
|
101
|
+
expression = ExpressionNode.new(expression)
|
102
|
+
end
|
103
|
+
ExpressionTree.new(self, expression, #{operation})
|
104
|
+
end
|
105
|
+
end_code
|
106
|
+
end
|
107
|
+
|
108
|
+
private
|
109
|
+
|
110
|
+
# Produces an expression for the lhs module.
|
111
|
+
def expression(params)
|
112
|
+
params.update(:lhs => self)
|
113
|
+
Gecode::Constraints::Bool::Expression.new(model, params)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# Describes a binary tree of expression nodes which together form a boolean
|
118
|
+
# expression.
|
119
|
+
class ExpressionTree
|
120
|
+
include OperationMethods
|
121
|
+
|
122
|
+
# Constructs a new expression with the specified variable
|
123
|
+
def initialize(left_node, right_node, operation)
|
124
|
+
@left = left_node
|
125
|
+
@right = right_node
|
126
|
+
@operation = operation
|
127
|
+
end
|
128
|
+
|
129
|
+
# Converts the boolean expression to an instance of
|
130
|
+
# Gecode::Raw::MiniModel::BoolExpr
|
131
|
+
def to_minimodel_lin_exp
|
132
|
+
Gecode::Raw::MiniModel::BoolExpr.new(@left.to_minimodel_lin_exp,
|
133
|
+
@operation, @right.to_minimodel_lin_exp)
|
134
|
+
end
|
135
|
+
|
136
|
+
# Fetches the space that the expression's variables is in.
|
137
|
+
def model
|
138
|
+
@left.model || @right.model
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# Describes a single node in a boolean expression.
|
143
|
+
class ExpressionNode
|
144
|
+
include OperationMethods
|
145
|
+
|
146
|
+
attr :model
|
147
|
+
|
148
|
+
def initialize(value, model = nil)
|
149
|
+
@value = value
|
150
|
+
@model = model
|
151
|
+
end
|
152
|
+
|
153
|
+
# Converts the linear expression to an instance of
|
154
|
+
# Gecode::Raw::MiniModel::BoolExpr
|
155
|
+
def to_minimodel_lin_exp
|
156
|
+
Gecode::Raw::MiniModel::BoolExpr.new(@value.bind)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Gecode
|
2
|
+
class FreeBoolVar
|
3
|
+
include Gecode::Constraints::LeftHandSideMethods
|
4
|
+
|
5
|
+
private
|
6
|
+
|
7
|
+
# Produces an expression for the lhs module.
|
8
|
+
def expression(params)
|
9
|
+
params.update(:lhs => self)
|
10
|
+
Constraints::Bool::Expression.new(@model, params)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# A module containing constraints that have int variables as left hand side
|
15
|
+
# (but not enumerations).
|
16
|
+
module Constraints::Bool
|
17
|
+
# Describes a boolean expression.
|
18
|
+
class Expression < Gecode::Constraints::Expression
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
require 'gecoder/interface/constraints/bool/boolean'
|
@@ -0,0 +1,258 @@
|
|
1
|
+
module Gecode
|
2
|
+
class FreeIntVar
|
3
|
+
# Creates a linear expression where the int variables are summed.
|
4
|
+
def +(var)
|
5
|
+
Gecode::Constraints::Int::Linear::ExpressionNode.new(self,
|
6
|
+
@model) + var
|
7
|
+
end
|
8
|
+
|
9
|
+
# Creates a linear expression where the int variable is multiplied with
|
10
|
+
# a constant integer.
|
11
|
+
def *(int)
|
12
|
+
Gecode::Constraints::Int::Linear::ExpressionNode.new(self,
|
13
|
+
@model) * int
|
14
|
+
end
|
15
|
+
|
16
|
+
# Creates a linear expression where the specified variable is subtracted
|
17
|
+
# from this one.
|
18
|
+
def -(var)
|
19
|
+
Gecode::Constraints::Int::Linear::ExpressionNode.new(self,
|
20
|
+
@model) - var
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
module Constraints::Int
|
25
|
+
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
|
+
# Add some relation selection based on whether the expression is negated.
|
58
|
+
alias_method :pre_linear_initialize, :initialize
|
59
|
+
def initialize(model, params)
|
60
|
+
pre_linear_initialize(model, params)
|
61
|
+
unless params[:negate]
|
62
|
+
@method_relations = RELATION_TYPES
|
63
|
+
else
|
64
|
+
@method_relations = NEGATED_RELATION_TYPES
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Define the relation methods.
|
69
|
+
RELATION_TYPES.each_key do |name|
|
70
|
+
module_eval <<-"end_code"
|
71
|
+
def #{name}(expression, options = {})
|
72
|
+
relation = @method_relations[:#{name}]
|
73
|
+
@params.update(
|
74
|
+
Gecode::Constraints::OptionUtil.decode_options(options))
|
75
|
+
if self.simple_expression? and simple_expression?(expression)
|
76
|
+
# A relation constraint is enough.
|
77
|
+
add_relation_constraint(relation, expression)
|
78
|
+
else
|
79
|
+
add_linear_constraint(relation, expression)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end_code
|
83
|
+
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
|
91
|
+
|
92
|
+
protected
|
93
|
+
|
94
|
+
# Checks whether the given expression is simple enough to be used in a
|
95
|
+
# simple relation constraint. Returns true if it is, false otherwise. If
|
96
|
+
# no expression is given then the this expression's left hand side is
|
97
|
+
# checked.
|
98
|
+
def simple_expression?(expression = nil)
|
99
|
+
if expression.nil?
|
100
|
+
simple_expression?(@params[:lhs])
|
101
|
+
else
|
102
|
+
expression.kind_of?(Gecode::FreeIntVar) or expression.kind_of?(Fixnum)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
private
|
107
|
+
|
108
|
+
# Places the linear constraint corresponding to the specified (integer)
|
109
|
+
# relation type (as specified by Gecode) in relation to the specifed
|
110
|
+
# expression.
|
111
|
+
#
|
112
|
+
# Raises TypeError if the element is of a type that doesn't allow a
|
113
|
+
# relation to be specified.
|
114
|
+
def add_linear_constraint(relation_type, right_hand_side)
|
115
|
+
# Bind parameters.
|
116
|
+
lhs = @params[:lhs]
|
117
|
+
if lhs.kind_of? Gecode::FreeIntVar
|
118
|
+
lhs = lhs * 1 # Convert to Gecode::Raw::LinExp
|
119
|
+
end
|
120
|
+
if right_hand_side.respond_to? :to_minimodel_lin_exp
|
121
|
+
right_hand_side = right_hand_side.to_minimodel_lin_exp
|
122
|
+
elsif right_hand_side.kind_of? Gecode::FreeIntVar
|
123
|
+
right_hand_side = right_hand_side.bind * 1
|
124
|
+
elsif not right_hand_side.kind_of? Fixnum
|
125
|
+
raise TypeError, 'Invalid right hand side of linear equation.'
|
126
|
+
end
|
127
|
+
|
128
|
+
@params.update(:relation_type => relation_type, :lhs => lhs,
|
129
|
+
:rhs => right_hand_side)
|
130
|
+
@model.add_constraint Linear::LinearConstraint.new(@model, @params)
|
131
|
+
end
|
132
|
+
|
133
|
+
# Places the relation constraint corresponding to the specified (integer)
|
134
|
+
# relation type (as specified by Gecode) in relation to the specifed
|
135
|
+
# element.
|
136
|
+
def add_relation_constraint(relation_type, element)
|
137
|
+
# Bind parameters.
|
138
|
+
@params[:lhs] = @params[:lhs].bind
|
139
|
+
if element.kind_of? FreeIntVar
|
140
|
+
element = element.bind
|
141
|
+
end
|
142
|
+
|
143
|
+
@model.add_constraint Linear::SimpleRelationConstraint.new(@model,
|
144
|
+
@params.update(:relation_type => relation_type, :element => element))
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
# A module that gathers the classes and modules used in linear constraints.
|
150
|
+
module Constraints::Int::Linear
|
151
|
+
# Describes a linear constraint.
|
152
|
+
class LinearConstraint < Gecode::Constraints::ReifiableConstraint
|
153
|
+
def post
|
154
|
+
lhs, rhs, relation_type, reif_var, strength = @params.values_at(:lhs,
|
155
|
+
:rhs, :relation_type, :reif, :strength)
|
156
|
+
reif_var = reif_var.bind if reif_var.respond_to? :bind
|
157
|
+
|
158
|
+
final_exp = (lhs.to_minimodel_lin_exp - rhs)
|
159
|
+
if reif_var.nil?
|
160
|
+
final_exp.post(@model.active_space, relation_type, strength)
|
161
|
+
else
|
162
|
+
final_exp.post(@model.active_space, relation_type, reif_var)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
# Describes a simple relation constraint.
|
168
|
+
class SimpleRelationConstraint < Gecode::Constraints::ReifiableConstraint
|
169
|
+
def post
|
170
|
+
# Fetch the parameters to Gecode.
|
171
|
+
params = @params.values_at(:lhs, :relation_type, :element, :reif,
|
172
|
+
:strength)
|
173
|
+
params[3] = params[3].bind unless params[3].nil? # Bind reification var.
|
174
|
+
params.delete_if{ |x| x.nil? }
|
175
|
+
Gecode::Raw::rel(@model.active_space, *params)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
# Helper methods for linear expressions. Classes mixing in this module must
|
180
|
+
# have a method #model which gives the model the expression is operating in.
|
181
|
+
module Helper
|
182
|
+
include Gecode::Constraints::LeftHandSideMethods
|
183
|
+
|
184
|
+
private
|
185
|
+
|
186
|
+
OPERATION_TYPES = [:+, :-, :*]
|
187
|
+
|
188
|
+
public
|
189
|
+
|
190
|
+
# Define methods for the available operations.
|
191
|
+
OPERATION_TYPES.each do |name|
|
192
|
+
module_eval <<-"end_code"
|
193
|
+
def #{name}(expression)
|
194
|
+
unless expression.kind_of? ExpressionTree
|
195
|
+
expression = ExpressionNode.new(expression)
|
196
|
+
end
|
197
|
+
ExpressionTree.new(self, expression, :#{name})
|
198
|
+
end
|
199
|
+
end_code
|
200
|
+
end
|
201
|
+
|
202
|
+
private
|
203
|
+
|
204
|
+
# Produces an expression for the lhs module.
|
205
|
+
def expression(params)
|
206
|
+
params.update(:lhs => self)
|
207
|
+
Gecode::Constraints::Int::Expression.new(model, params)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
# Describes a binary tree of expression nodes which together form a linear
|
212
|
+
# expression.
|
213
|
+
class ExpressionTree
|
214
|
+
include Helper
|
215
|
+
|
216
|
+
# Constructs a new expression with the specified variable
|
217
|
+
def initialize(left_node, right_node, operation)
|
218
|
+
@left = left_node
|
219
|
+
@right = right_node
|
220
|
+
@operation = operation
|
221
|
+
end
|
222
|
+
|
223
|
+
# Converts the linear expression to an instance of
|
224
|
+
# Gecode::Raw::MiniModel::LinExpr
|
225
|
+
def to_minimodel_lin_exp
|
226
|
+
@left.to_minimodel_lin_exp.send(@operation, @right.to_minimodel_lin_exp)
|
227
|
+
end
|
228
|
+
|
229
|
+
# Fetches the space that the expression's variables is in.
|
230
|
+
def model
|
231
|
+
@left.model || @right.model
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
# Describes a single node in a linear expression.
|
236
|
+
class ExpressionNode
|
237
|
+
include Helper
|
238
|
+
|
239
|
+
attr :model
|
240
|
+
|
241
|
+
def initialize(value, model = nil)
|
242
|
+
@value = value
|
243
|
+
@model = model
|
244
|
+
end
|
245
|
+
|
246
|
+
# Converts the linear expression to an instance of
|
247
|
+
# Gecode::Raw::MiniModel::LinExpr
|
248
|
+
def to_minimodel_lin_exp
|
249
|
+
expression = @value
|
250
|
+
if expression.kind_of? Gecode::FreeIntVar
|
251
|
+
# Minimodel requires that we do this first.
|
252
|
+
expression = expression.bind * 1
|
253
|
+
end
|
254
|
+
expression
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|