class Gecode::IntEnum::IntEnumConstraintReceiver
IntEnumConstraintReceiver contains all constraints that can be placed on a IntEnumOperand.
Constraints are placed by calling Gecode::Operand#must (or any other of the variations defined in Operand), which produces a IntEnumConstraintReceiver from which the desired constraint can be used.
Some constraint accepts a number of options. See ConstraintReceiver for more information.
Examples ¶ ↑
Constrains the integer operands in int_enum
to take on
different values by using #distinct:
int_enum.must_be.distinct
Constrains int_enum2
to have the same elements as
int_enum
, but sorted in ascending order. Uses #sorted:
int_enum.must_be.sorted(:as => int_enum2)
The same as above, but specifying that strength :domain should be used and
that the constraint should be reified with bool_operand
:
int_enum.must_be.sorted(:as => int_enum2, :strength => :domain, :reify => bool_operand)
Public Instance Methods
Constrains this enumeration to “channel” int_enum
.
Channel constraints are used to give access to multiple viewpoints when
modelling.
The channel constraint can be thought of as constraining the arrays to be each other’s inverses. I.e. if the i:th value in the first enumeration is j, then the j:th value in the second enumeration is constrained to be i.
Neither reification nor negation is supported.
Examples ¶ ↑
Lets say that we’re modelling a sequence of numbers that must be distinct and that we want access to the following two view simultaneously.
First view¶ ↑
The sequence is modelled as an array of integer variables where the first variable holds the value of the first position in the sequence, the second the value of the second position and so on.
# n variables with values from 0 to n1. elements = int_var_array(n, 0...n) elements.must_be.distinct
That way elements
will contain the actual sequence when the
problem has been solved.
Second view¶ ↑
The sequence is modelled as the positions of each value in 0..(n1) in the sequence. That way the first variable would hold the positions of 0 in the sequence, the second variable would hold the positions of 1 in the sequence and so on.
positions = int_var_array(n, 0...n) positions.must_be.distinct
Connecting the views¶ ↑
In essence the relationship between the two arrays elements
and positions
is that
elements.map{ e e.val }[i] == positions.map{ p p.val }.index(i)
for all i in 0..(n1). This relationship is enforced by the channel constraint as follows.
elements.must.channel positions
# File lib/gecoder/interface/constraints/int_enum/channel.rb, line 54 def channel(int_enum, options = {}) if @params[:negate] raise Gecode::MissingConstraintError, 'A negated channel constraint ' + 'is not implemented.' end unless int_enum.respond_to? :to_int_enum raise TypeError, "Expected int enum, got #{int_enum.class}." end if options.has_key? :reify raise ArgumentError, 'The channel constraints does not support the ' + 'reification option.' end @params.update(Gecode::Util.decode_options(options)) @params.update(:rhs => int_enum) @model.add_constraint Channel::ChannelConstraint.new(@model, @params) end
Constrains all integer operands in the enumeration to be distinct (different). The constraint can also be used with constant offsets, so that the operands, with specified offsets added, must be distinct.
The constraint does not support negation nor reification.
Examples ¶ ↑
# Constrains all operands in +int_enum+ to be assigned different # values. int_enum.must_be.distinct # The same as above, but also selects that the strength +domain+ should # be used. int_enum.must_be.distinct(:strength => :domain) # Uses the offset to constrain that no number may be the previous number # incremented by one. numbers = int_var_array(8, 0..9) numbers.must_be.distinct(:offsets => (1..numbers.size).to_a.reverse)
# File lib/gecoder/interface/constraints/int_enum/distinct.rb, line 24 def distinct(options = {}) if @params[:negate] # The best we could implement it as from here would be a bunch of # reified pairwise equality constraints. raise Gecode::MissingConstraintError, 'A negated distinct is not ' + 'implemented.' end unless options[:reify].nil? raise ArgumentError, 'Reification is not supported by the distinct ' + 'constraint.' end if options.has_key? :offsets offsets = options.delete(:offsets) unless offsets.kind_of? Enumerable raise TypeError, 'Expected Enumerable as offsets, got ' + "#{offsets.class}." end @params[:offsets] = offsets end @model.add_constraint Distinct::DistinctConstraint.new(@model, @params.update(Gecode::Util.decode_options(options))) end
Constrains all operands in the enumeration to be equal. Neither negation nor reification is supported.
Examples ¶ ↑
# Constrains all operands in +int_enum+ to be equal. int_enum.must_be.equal
# File lib/gecoder/interface/constraints/int_enum/equality.rb, line 10 def equal(options = {}) if @params[:negate] # The best we could implement it as from here would be a bunch of # reified pairwise inequality constraints. raise Gecode::MissingConstraintError, 'A negated equality is not ' + 'implemented.' end unless options[:reify].nil? raise ArgumentError, 'Reification is not supported by the equality ' + 'constraint.' end @model.add_constraint Equality::EqualityConstraint.new(@model, @params.update(Gecode::Util.decode_options(options))) end
Constrains all the operands in this enumeration to be equal to one of the specified tuples. Neither negation nor reification is supported.
Examples ¶ ↑
# Constrains the two integer operands in +numbers+ to either have # values 1 and 7, or values 47 and 11. numbers.must_be.in [[1,7], [47,11]] # The same as above, but preferring speed over low memory usage. numbers.must_be.in([[1,7], [47,11]], :kind => :speed)
# File lib/gecoder/interface/constraints/int_enum/extensional.rb, line 15 def in(tuples, options = {}) if @params[:negate] raise Gecode::MissingConstraintError, 'A negated tuple constraint is ' + 'not implemented.' end unless options[:reify].nil? raise ArgumentError, 'Reification is not supported by the tuple ' + 'constraint.' end util = Gecode::Util # Check that the tuples are correct. expected_size = @params[:lhs].size util::Extensional.perform_tuple_checks(tuples, expected_size) do tuple unless tuple.all?{ x x.kind_of? Fixnum } raise TypeError, 'All tuples must contain Fixnum.' end end @params[:tuples] = tuples @model.add_constraint Extensional::TupleConstraint.new(@model, @params.update(util.decode_options(options))) end
Constrains the sequence of operands in this enumeration to match a specified regexp in the integer domain. Neither negation nor reification is supported.
Regexp syntax¶ ↑
The regular expressions are specified using arrays, integers and a few methods provided by Mixin. Arrays are used to group the integers in sequences that must be matched. The following array describes a regular expression matching a 1 followed by a 7.
[1, 7]
Arrays can be nested or left out when not needed. I.e. the above is semantically equal to
[[[1], 7]]
A couple of methods provided by Mixin are used to express patterns beyond mere sequences:
 Gecode::Mixin#repeat

Used for specifying patterns that include patterns that may be repeated a given number of times. The number of times to repeat a pattern can be specified using a lower and upper bound, but the bounds can be omitted to for instance allow an expression to be repeated any number of times.
 Gecode::Mixin#any

Used for specifying alternatives.
Additionally Gecode::Mixin#at_least_once and Gecode::Mixin#at_most_once are provided as convenience methods.
Examples ¶ ↑
# Matches 1 followed by any number of 2s. [1, repeat(2)] # Semantically the same as above. It just has a bunch of # needless brackets thrown in. [[1], [repeat([2])]] # Matches 1 followed by [a 2 followed by a 3] at least two times. # Matches e.g. 1, 2, 3, 2, 3 [1, repeat([2, 3], 2)] # Matches between one and two [2 followed by [at least three 1]] # followed by between three and four 3. Matches e.g. # 2, 1, 1, 1, 2, 1, 1, 1, 3, 3, 3 [repeat([2, repeat(1, 3], 1, 2), repeat(3, 3, 4)] # Matches [1, 2 or 3] followed by 4. Matches e.g. 2, 4 [any(1, 2, 3), 4] # Matches 0 followed by [[1 followed by 2] or [3 followed by 5]]. # Matches e.g. 0, 1, 2 as well as 0, 3, 5 [0, any([1, 2], [3, 5])] # Matches 0 followed by [[[1 followed by 7] at least two times] # or [[8, 9], at most two times]. Matches e.g. # 0, 1, 7, 1, 7, 1, 7 as well as 0, 8, 9 [0, any(repeat([1, 7], 2), repeat([8, 9], 0, 2)] # Matches 0 followed by at least one 1. [0, at_least_once(1)] # Exactly the same as the above. [0, repeat(1, 1)] # Matches 0 followed by at least one [[1 followed by 7] or [3 # followed by 2]]. Matches e.g. 0, 1, 7, 3, 2, 1, 7 [0, at_least_once(any([1, 7], [3, 2]] # Matches 0 followed by at either [[1 followed by 7] at least once] # or [[3 followed by 2] at least once]. Matches e.g. # 0, 1, 7, 1, 7 but does _not_ match 0, 1, 7, 3, 2, 1, 7 [0, any(at_least_once([1, 7]), at_least_once([3, 2])] # Matches 0, followed by at most one 1. Matches 0 as well as # 0, 1 [0, at_most_once(1)] # Exactly the same as the above. [0, repeat(1, 0, 1)]
Examples ¶ ↑
# Constrains the two integer operands in +numbers+ to have # values 1 and 7. numbers.must.match [1, 7] # Constrains the integer operands in +numbers+ to contain the # value 47 followed by 11, with all other values set to 1. numbers.must.match [repeat(1), 47, 11, repeat(1)] # Constrains exactly three of the integer operands in +numbers+ to # contain 47 or 11, each followed by at least two # operands set to 1. All other operands are constrained to # equal 1. numbers.must.match repeat([repeat(1), any(11, 47), repeat(1, 2)], 3, 3)
# File lib/gecoder/interface/constraints/int_enum/extensional.rb, line 141 def match(regexp, options = {}) if @params[:negate] raise Gecode::MissingConstraintError, 'A negated regexp constraint ' + 'is not implemented.' end unless options[:reify].nil? raise ArgumentError, 'Reification is not supported by the regexp ' + 'constraint.' end @params[:regexp] = Gecode::Util::Extensional.parse_regexp regexp @params.update Gecode::Util.decode_options(options) @model.add_constraint Extensional::RegexpConstraint.new(@model, @params) end
Constrains the elements in this enumeration to be sorted in ascending order. The following options can be given in addition to the common constraint options:
 :as

Defines a target (must be an IntEnum) that will hold the sorted version of the original enumerable. The original enumerable will not be affected (i.e. will not necessarily be sorted)
 :order

Sets an IntEnum that should be used to store the order of the original enum’s operands when sorted. The original enumerable will not be affected (i.e. will not necessarily be sorted)
If neither of those options are specified then the original enumerable will be constrained to be sorted (otherwise not). Sort constraints with options do not allow negation.
Examples ¶ ↑
# Constrain +numbers+ to be sorted. numbers.must_be.sorted # Constrain +numbers+ to not be sorted. numbers.must_not_be.sorted # Constrain +sorted_numbers+ to be a sorted version of +numbers+. numbers.must_be.sorted(:as => sorted_numbers) # Constrain +order+ to be the order in which +numbers+ has to be # ordered to be sorted. numbers.must_be.sorted(:order => order) # Constrain +sorted_numbers+ to be +numbers+ sorted in the order # described by the IntEnum +order+. numbers.must_be.sorted(:as => sorted_numbers, :order => order) # Constrains +numbers+ to be sorted, reifying with the boolean # operand +is_sorted+, while selecting +domain+ as strength. numbers.must_be.sorted(:reify => :is_sorted, :strength => :domain)
# File lib/gecoder/interface/constraints/int_enum/sort.rb, line 42 def sorted(options = {}) # Extract and check options. target = options.delete(:as) order = options.delete(:order) unless target.nil? or target.respond_to? :to_int_enum raise TypeError, 'Expected int var enum as :as, got ' + "#{target.class}." end unless order.nil? or order.respond_to? :to_int_enum raise TypeError, 'Expected int var enum as :order, got ' + "#{order.class}." end # Extract standard options and convert to constraint. reified = !options[:reify].nil? @params.update(Gecode::Util.decode_options(options)) if target.nil? and order.nil? @model.add_constraint Sort::SortConstraint.new(@model, @params) else # Do not allow negation. if @params[:negate] raise Gecode::MissingConstraintError, 'A negated sort with options ' + 'is not implemented.' end if reified raise ArgumentError, 'Reification is not supported by the sorted ' + 'constraint.' end @params.update(:target => target, :order => order) @model.add_constraint Sort::SortConstraintWithOptions.new(@model, @params) end end