lib/gecoder/interface/constraints/int_enum/count.rb in gecoder-0.8.3 vs lib/gecoder/interface/constraints/int_enum/count.rb in gecoder-0.9.0
- old
+ new
@@ -1,91 +1,66 @@
-module Gecode
- module IntEnumMethods
- # Specifies that a specific element should be counted, starting a count
- # constraint. The element can be either an int var or a fixnum.
- def count(element)
- unless element.kind_of?(FreeIntVar) or element.kind_of?(Fixnum)
- raise TypeError, 'Elements used with count can not be of type ' +
- "#{element.class}."
+module Gecode::IntEnum
+ module IntEnumOperand
+ # Produces a new IntOperand representing the number of times
+ # +int_operand_or_fixnum+ is present in this enumeration.
+ #
+ # ==== Examples
+ #
+ # # The number of times 17 occurs in +int_enum+.
+ # int_enum.count(17)
+ #
+ # # The number of times +int_operand+ occurs in +int_enum+.
+ # int_enum.count(int_operand)
+ def count(int_operand_or_fixnum)
+ unless int_operand_or_fixnum.respond_to? :to_int_var or
+ int_operand_or_fixnum.kind_of?(Fixnum)
+ raise TypeError, 'Expected integer operand of fixnum, got ' +
+ "#{int_operand_or_fixnum.class}."
end
- params = {:lhs => self, :element => element}
- Gecode::Constraints::SimpleExpressionStub.new(@model, params) do |m, ps|
- Gecode::Constraints::IntEnum::Count::Expression.new(m, ps)
- end
+ Count::IntEnumCountOperand.new(@model, self, int_operand_or_fixnum)
end
end
-end
-# A module that gathers the classes and modules used in count constraints.
-module Gecode::Constraints::IntEnum::Count #:nodoc:
- # Describes an expression
- class Expression < Gecode::Constraints::IntEnum::Expression #:nodoc:
- def initialize(model, params)
- super
- unless params[:negate]
- @method_relations = Gecode::Constraints::Util::RELATION_TYPES
- else
- @method_relations = Gecode::Constraints::Util::NEGATED_RELATION_TYPES
+ # A module that gathers the classes and modules used in count constraints.
+ module Count #:nodoc:
+ class IntEnumCountOperand < Gecode::Int::ShortCircuitRelationsOperand #:nodoc:
+ def initialize(model, int_enum, element)
+ super model
+ @enum = int_enum
+ @element = element
end
+
+ def relation_constraint(relation, int_operand_or_fix, params)
+ unless params[:negate]
+ relation_type =
+ Gecode::Util::RELATION_TYPES[relation]
+ else
+ relation_type =
+ Gecode::Util::NEGATED_RELATION_TYPES[relation]
+ end
+
+ params.update(:enum => @enum, :element => @element,
+ :rhs => int_operand_or_fix, :relation_type => relation_type)
+ CountConstraint.new(@model, params)
+ end
end
- Gecode::Constraints::Util::RELATION_TYPES.each_pair do |name, type|
- class_eval <<-"end_code"
- def #{name}(expression, options = {})
- unless expression.kind_of?(Fixnum) or
- expression.kind_of?(Gecode::FreeIntVar)
- raise TypeError, 'Invalid right hand side of count constraint: ' +
- "\#{expression.class}."
- end
+ class CountConstraint < Gecode::ReifiableConstraint #:nodoc:
+ def post
+ enum, element, relation_type, rhs =
+ @params.values_at(:enum, :element, :relation_type, :rhs)
- relation = @method_relations[:#{name}]
- @params.update(Gecode::Constraints::Util.decode_options(options))
- @params.update(:rhs => expression, :relation_type => relation)
- @model.add_constraint CountConstraint.new(@model, @params)
+ # Bind variables if needed.
+ unless element.kind_of? Fixnum
+ element = element.to_int_var.bind
end
- end_code
- end
- alias_comparison_methods
- end
-
- # Describes a count constraint, which constrains the number of times a value
- # (constant or a variable) may occurr in an enumeration of integer variable.
- #
- # All relations available for +SimpleRelationConstraint+ can be used with
- # count constraints. Negation and reification is supported.
- #
- # == Examples
- #
- # # Constrain +int_enum+ to not contain 0 exactly once.
- # int_enum.count(0).must_not == 1
- #
- # # Constrain +int_enum+ to contain +x+ exactly +x_count+ times.
- # int_enum.count(x).must == x_count
- #
- # # Reifies the constraint that +int_enum+ has +x+ zeros with the boolean
- # # variable +has_x_zeros+ and selects the strength +domain+.
- # int_enum.count(0).must.equal(x, :reify => has_x_zeros,
- # :strength => :domain)
- class CountConstraint < Gecode::Constraints::ReifiableConstraint
- def post
- lhs, element, relation_type, rhs, reif_var =
- @params.values_at(:lhs, :element, :relation_type, :rhs, :reif)
-
- # Bind variables if needed.
- element = element.bind if element.respond_to? :bind
- rhs = rhs.bind if rhs.respond_to? :bind
-
- # Post the constraint to gecode.
- if reif_var.nil?
- Gecode::Raw::count(@model.active_space, lhs.to_int_var_array,
+ unless rhs.kind_of? Fixnum
+ rhs = rhs.to_int_var.bind
+ end
+
+ # Post the constraint to gecode.
+ Gecode::Raw::count(@model.active_space, enum.to_int_enum.bind_array,
element, relation_type, rhs, *propagation_options)
- else
- # We use a proxy int variable to get the reification.
- proxy = @model.int_var(rhs.min..rhs.max)
- rel = Gecode::Constraints::Util::RELATION_TYPES.invert[relation_type]
- proxy.must.send(rel, @params[:rhs], :reify => reif_var)
- Gecode::Raw::count(@model.active_space, lhs.to_int_var_array,
- element, Gecode::Raw::IRT_EQ, proxy.bind, *propagation_options)
end
end
end
-end
\ No newline at end of file
+end