Binding Rules
Repetitive operations
During execution, indices are used to traverse a set to repeatedly apply a specific operation on all elements of a set. These operations concern
indexed assignment statements,
FOR
statements,iterative operations like summation over a domain,
constraint generation,
arc generation, and
constructed set expression.
Index binding
Index binding is the process by which AIMMS repeatedly couples the value of an index to elements of a specific set to execute repetitive operations.
Different types of binding
There are three ways in which index binding takes place:
local binding,
default binding, and
context binding.
Local binding
Local binding takes place through the use of an IN
modifier at the
index binding position as illustrated in the following example.
NettoTransport(i in SupplyCities, j in DestinationCitiesFromSupply(i)) :=
Transport(i,j) - Transport(j,i);
Instead of executing the assignment for all cities i
and j
, it
is only executed for those combinations for which city i
is in
SupplyCities
and city j
is in
DestinationCitiesFromSupply(i)
.
Default binding
Indices can have a default binding. This is the binding specified in a
declaration. You can specify a default binding either via the Index
attribute of a set, or via the Range
attribute of an Index
declaration. Whenever you use an index with a default binding and do not
specify a local binding, AIMMS will couple this index to its default set
automatically. The following example illustrates default binding.
IntermediateTransportCitiesInBetween(i,j) :=
DestinationCitiesFromSupply(i) * SupplyCitiesToDestination(j);
Assuming that i
and j
have a default binding to the set
Cities
, the assignment takes place for all tuples of cities
(i
,j
).
Context binding
Whenever you use an index that has no default binding and for which you
do not provide a local binding, AIMMS will try to determine a context
binding from the context. Assume that k
is an index without a
default binding. Further assume that LargestTransport
is an element
parameter into Cities
and indexed over Cities
. Then the
following example is an illustration of context binding.
LargestTransport(k) := ArgMax( j, Transport(k,j) );
In this assignment AIMMS will automatically bind the index k
to
Cities
, because the identifier LargestTransport
has been
declared with the index domain Cities
. Note that context binding
will only work in indexed assignments.
Nested index binding
Index binding can be nested through the use of indexed element-valued parameters on the left-hand side of an assignment. The binding takes place in the way that you would expect, applying the same rules as for non-nested index binding. For example, given the declarations
ElementParameter NextCity {
IndexDomain : i;
Range : Cities;
}
ElementParameter PreviousCity {
IndexDomain : i;
Range : Cities;
}
the following assignment, which computes the value of PreviousCity
given the contents of NextCity
, will bind the nested reference to
the index i
.
PreviousCity( NextCity(i) ) := i;
This binding is sparse, in the sense that the statement is only executed
for those i
for which NextCity(i)
assumes a nonempty value.
Compatible index binding only
In general, AIMMS will never accept the use of an index in references to indexed identifiers when the binding set does not have the same root set as the index domain of the identifier. This is even the case when the elements, referenced in the particular statement, have identical names in both the binding set and the index domain. Internally, AIMMS stores a set elements as a unique (integer) number with respect to its root set, and uses this number for storing data for that element in indexed identifiers. Thus, when the root sets of the binding set and the index domain are not identical, the set element numbers will be incompatible, preventing AIMMS from referencing the correct data.
Use indirect referencing
When you want to use a binding set which is incompatible with the index
domain of identifier on the left-hand side of an assignment, you should
manually create an element parameter which maps elements in one root to
the corresponding elements the other root set. Such a mapping can be
easily created using the function ElementCast
(discussed in
Intrinsic Functions for Sets and Set Elements), as exemplified below.
ElementMap(i) := ElementCast( IncompatibleRootSet, i );
Subsequently, you can use a nested binding through the element parameter
ElementMap
to reference elements in the index domain of the
identifier on the left-hand side of an assignment, while still using the
index i
as a binding index, as illustrated in the following
statement.
IncompatibleParameter( ElementMap(i) ) := CompatibleParameter(i);
Use the ElementCast
function
Conversely, when you want to use an incompatible set element in a
parameter reference on the right-hand side of an assignment, there is no
direct need to create a mapping parameter. In an expression on the right
of an assignment, you can use the function ElementCast
directly at
any index position, as illustrated below.
CompatibleParameter(i) := IncompatibleParameter( ElementCast(IncompatibleRootSet, i) );
Universal set
Note that you could have accomplished the same effect by creating a universal set of which all other sets are subsets. As a result, all set elements are represented as unique integer numbers with respect to the same root set, allowing the index domains of all identifiers to be referenced in a compatible manner. However, often it is not very natural to do so, and the usage of a universal set is likely to slow down the performance of AIMMS.
Index binding rules
For most situations the result of index binding is self-evident and the behavior of the system is as you would expect. Following are the precise rules for index binding.
- Dominance rule
Whenever index binding takes place, local binding precedes default binding, which in turn precedes context binding. If no method is applicable, a compile time error will result.
- Intersection rule
In indexed assignments the binding set(s) should be compatible with the index domain. The assignment will be performed for all tuples on the left-hand side that lie in the intersection of the binding set(s) and the index domain of the corresponding identifier.
- Ordering rule
Lag and lead operators, as well as the
Ord
and Sets and set elements functions operate according to the order of elements in the corresponding binding set.