gecoder 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|