# Integer Enumeration Operands

An integer enumeration operand is an enumeration of integer operands.

#### Examples of Integer Enumeration Operands

Enumerations of integer operands are commonly created using `Gecode::Mixin#int_var_array` and `Gecode::Mixin#int_var_matrix`.

```# Creates an array of five integer operands with domain 0..9 .
int_enum = int_var_array(5, 0..9)
```

A less common way to create the operands is by using `Gecode::Mixin#wrap_enum` to wrap an existing enumeration that contains integer operands.

```int_enum = wrap_enum([int_operand1, int_operand2])
```

## Constraints

Generated from `IntEnumConstraintReceiver`.

### `distinct`

`distinct(options = {})`

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)
```

### `channel`

`channel(int_enum, options = {})`

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 n-1.
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..(n-1) 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..(n-1). This relationship is enforced by the channel constraint as follows.

```elements.must.channel positions
```

### `in`

`in(tuples, options = {})`

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)
```

### `match`

`match(regexp, options = {})`

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

```[[, 7]]
```

A couple of methods provided by Mixin are used to express patterns beyond mere sequences:

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.
Mixin#any
Used for specifying alternatives.

Additionally Mixin#at_least_once and 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.
[, [repeat()]]

# 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)
```

### `sorted`

`sorted(options = {})`

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)
```

### `equal`

`equal(options = {})`

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
```

## Properties

Generated from `IntEnumOperand`.

### `[]`

`[](*vars)`

Produces an IntOperand representing the i:th integer operand in the enumeration, where i is the value of the integer operand used as index. Think of it as array access in the world of constraint programming.

##### Examples
```# The operand at the +x+:th position in +int_enum+,
# where +x+ is an integer operand.
int_enum[x]
```

### `count`

`count(int_operand_or_fixnum)`

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)
```

### `max`

`max()`

Produces an IntOperand representing the maximum value of the integer operands in this enumeration.

##### Examples
```# The maximum of +int_enum+.
int_enum.max
```

### `min`

`min()`

Produces an IntOperand representing the minimum value of the integer operands in this enumeration.

##### Examples
```# The minimum of +int_enum+.
int_enum.min
```