lib/gecoder/interface/constraints/set/connection.rb in gecoder-0.8.3 vs lib/gecoder/interface/constraints/set/connection.rb in gecoder-0.9.0

- old
+ new

@@ -1,193 +1,130 @@ -module Gecode - class FreeSetVar - # Starts a constraint on the minimum value of the set. +module Gecode::Set + module SetOperand + # Produces an IntOperand representing the minimum of the set. + # + # ==== Examples + # + # # The minimum of +set+. + # set.min def min - params = {:lhs => self} - Gecode::Constraints::Set::Connection::MinExpressionStub.new(@model, params) + Connection::SetMinOperand.new(@model, self) end - # Starts a constraint on the maximum value of the set. + # Produces an IntOperand representing the maximum of the set. + # + # ==== Examples + # + # # The maximum of +set+. + # set.max def max - params = {:lhs => self} - Gecode::Constraints::Set::Connection::MaxExpressionStub.new(@model, params) + Connection::SetMaxOperand.new(@model, self) end - # Starts a constraint on the sum of the set. The option :weights may - # optionally be given with a hash of weights as value. If it is then the - # weighted sum, using the hash as weight function, will be constrained. The - # option :substitutions may also be given (with a hash as value), if it is - # then the sum of the set with all elements replaced according to the hash - # is constrained. Elements mapped to nil by the weights or substitutions - # hash are removed from the upper bound of the set. Only one of the two - # options may be given at the same time. + # Produces an IntOperand representing the sum of the values in the + # set. One of the following options may also be given: + # [:weights] Produces the weighted sum using the specified hash + # of weights. The hash should map each value to + # that value's weight. + # [:substitutions] Produces the sum of the set with all elements + # replaced according to the hash. + # + # Elements not included in the weights or substitutions hash are + # removed from the upper bound of the set. + # + # ==== Examples + # + # # The sum of +set+. + # set.sum + # + # # The sum of +set+ with primes < 10 given twice the weight. + # set.sum(:weights => {2 => 2, 3 => 2, 5 => 2, 7 => 2}) + # + # # The sum of +set+ with odd values in [1,6] being counted as 1. + # set.sum(:substitutions => {1 => 1, 3 => 1, 5 => 1}) def sum(options = {:weights => weights = Hash.new(1)}) if options.empty? or options.keys.size > 1 - raise ArgumentError, 'One of the options :weights and :substitutions, ' + - 'or neither, must be specified.' + raise ArgumentError, 'At most one of the options :weights and ' + + ':substitutions may be specified.' end - params = {:lhs => self} - unless options.empty? - case options.keys.first - when :substitutions: params.update(options) - when :weights: - weights = options[:weights] - substitutions = Hash.new do |hash, key| - if weights[key].nil? - hash[key] = nil - else - hash[key] = key * weights[key] - end + + case options.keys.first + when :substitutions: subs = options[:substitutions] + when :weights: + weights = options[:weights] + subs = Hash.new do |hash, key| + if weights[key].nil? + hash[key] = nil + else + hash[key] = key * weights[key] end - params.update(:substitutions => substitutions) - else raise ArgumentError, "Unrecognized option #{options.keys.first}." - end + end + else raise ArgumentError, "Unrecognized option #{options.keys.first}." end - Gecode::Constraints::Set::Connection::SumExpressionStub.new(@model, params) + Connection::SetSumOperand.new(@model, self, subs) end end -end - -module Gecode::Constraints::Set - class Expression - # Adds a constraint that forces specified values to be included in the - # set. This constraint has the side effect of sorting the variables in - # non-descending order. - def include(variables) - unless variables.respond_to? :to_int_var_array - raise TypeError, "Expected int var enum, got #{variables.class}." - end - if @params[:negate] - raise Gecode::MissingConstraintError, 'A negated include is not ' + - 'implemented.' - end - - @params.update(:variables => variables) - @model.add_constraint Connection::IncludeConstraint.new(@model, @params) - end - end - + # A module that gathers the classes and modules used in connection # constraints. module Connection #:nodoc: - # Describes a CompositeStub for the min constraint which constrains the - # minimum value of a set variable. - # - # == Examples - # - # # Constrains the minimum value of +set+ to be larger than 17. - # set.min.must > 17 - # - # # Constrains the minimum value of +set+ to equal the integer variable - # # +min+. - # set.min.must == min - # - # # Constrains the minimum value of +set+ to not be larger than the - # # integer variable +ceil+. - # set.min.must_not > ceil - # - # # The same as above but reified with the boolean variable - # # +is_not_above_ceiling+ and with the strength +domain+ applied. - # set.min.must_not_be.larger_than(ceil, :reify => :is_not_above_ceiling, - # :strength => :domain) - class MinExpressionStub < Gecode::Constraints::Int::CompositeStub - def constrain_equal(variable, params, constrain) - set = params[:lhs] + class SetMinOperand < Gecode::Int::ShortCircuitEqualityOperand #:nodoc: + def initialize(model, set_op) + super model + @set = set_op + end + + def constrain_equal(int_operand, constrain, propagation_options) + set = @set.to_set_var if constrain - variable.must_be.in set.upper_bound.min..set.lower_bound.min + int_operand.must_be.in set.upper_bound.min..set.lower_bound.min end - Gecode::Raw::min(@model.active_space, set.bind, variable.bind) + Gecode::Raw::min(@model.active_space, set.bind, + int_operand.to_int_var.bind) end end - # Describes a CompositeStub for the max constraint which constrains the - # maximum value of a set variable. - # - # == Examples - # - # # Constrains the maximum value of +set+ to be larger than 17. - # set.max.must > 17 - # - # # Constrains the maximum value of +set+ to equal the integer variable - # # +max+. - # set.max.must == max - # - # # Constrains the maximum value of +set+ to not be less than the - # # integer variable +floor+. - # set.max.must_not < floor - # - # # The same as above but reified with the boolean variable - # # +is_not_below_floor+ and with the strength +domain+ applied. - # set.max.must_not_be.less_than(ceil, :reify => :is_not_below_floor, - # :strength => :domain) - class MaxExpressionStub < Gecode::Constraints::Int::CompositeStub - def constrain_equal(variable, params, constrain) - set = params[:lhs] + class SetMaxOperand < Gecode::Int::ShortCircuitEqualityOperand #:nodoc: + def initialize(model, set_op) + super model + @set = set_op + end + + def constrain_equal(int_operand, constrain, propagation_options) + set = @set.to_set_var if constrain - variable.must_be.in set.lower_bound.max..set.upper_bound.max + int_operand.must_be.in set.upper_bound.min..set.lower_bound.min end - Gecode::Raw::max(@model.active_space, set.bind, variable.bind) + Gecode::Raw::max(@model.active_space, set.bind, + int_operand.to_int_var.bind) end end - # Describes a CompositeStub for the sum constraint which constrains the - # sum of all values in a set variable. - # - # == Examples - # - # # Constrains the sum of all values in +set+ to be larger than 17. - # set.sum.must > 17 - # - # # Constrains the sum of all values in +set+ to equal the integer - # # variable +sum+. - # set.sum.must == sum - # - # # Constrains the sum of all values in +set+ to not be larger than the - # # integer variable +resources+. - # set.sum.must_not > resources - # - # # The same as above but reified with the boolean variable - # # +not_over_budget+ and with the strength +domain+ applied. - # set.sum.must_not_be.larger_than(resources, :reify => :not_over_budget, - # :strength => :domain) - class SumExpressionStub < Gecode::Constraints::Int::CompositeStub - def constrain_equal(variable, params, constrain) - set, subs = params.values_at(:lhs, :substitutions) + class SetSumOperand < Gecode::Int::ShortCircuitEqualityOperand #:nodoc: + def initialize(model, set_op, subs) + super model + @set = set_op + @subs = subs + end + + def constrain_equal(int_operand, constrain, propagation_options) + set = @set.to_set_var lub = set.upper_bound.to_a - lub.delete_if{ |e| subs[e].nil? } - substituted_lub = lub.map{ |e| subs[e] } + lub.delete_if{ |e| @subs[e].nil? } + substituted_lub = lub.map{ |e| @subs[e] } if constrain # Compute the theoretical bounds of the weighted sum. This is slightly # sloppy since we could also use the contents of the greatest lower # bound. min = substituted_lub.find_all{ |e| e < 0}.inject(0){ |x, y| x + y } max = substituted_lub.find_all{ |e| e > 0}.inject(0){ |x, y| x + y } - variable.must_be.in min..max + int_operand.must_be.in min..max end Gecode::Raw::weights(@model.active_space, lub, substituted_lub, - set.bind, variable.bind) + set.bind, int_operand.to_int_var.bind) end end - - # Describes an include constraint, which constrains the set to include the - # values of the specified enumeration of integer variables. - # - # The constraint has the side effect of sorting the integer variables in a - # non-descending order. It does not support reification nor negation. - # - # == Examples - # - # # Constrain +set+ to include the values of all variables in - # # +int_enum+. - # set.must.include int_enum - class IncludeConstraint < Gecode::Constraints::Constraint - def post - set, variables = @params.values_at(:lhs, :variables) - Gecode::Raw::match(@model.active_space, set.bind, - variables.to_int_var_array) - end - end end -end \ No newline at end of file +end