Assignment Statements

Assignment

Assignment statements are used to set or change the values of sets, parameters and variables during the execution of a procedure or a function. The syntax of an assignment statement is straightforward.

Syntax

assignment-statement:

data-selection:

image/svg+xmlidentifier-part ( binding-domain )

Assignment operators

AIMMS offers several assignment operators. The standard replacement assignment operator := replaces the value of all elements specified on the left hand side with the value of the expression on the right hand side. The arithmetic assignment operators +=, -=, *=, /= and ^= combine an assignment with an arithmetic operation. Thus, the assignments

a += b, a -= b, a *= b, a /= b, a ^= b

form a shorthand notation for the assignments

a := a + b, a := a - b, a := a * b, a := a / b, a := a ^ b.

Index binding

Assignment is an index binding statement. AIMMS also binds unbound indices in (nested) references to element-valued parameters that are used for indexing the left-hand side. AIMMS will execute the assignment repeatedly for all elements in the binding domain, and in the order as specified by the declaration(s) of the binding set(s). The precise rules for index binding are explained in Binding Rules.

Allowed binding domains

In contrast to the binding domain of iterative operators and the FOR statements, the binding domain of an indexed assignment can contain the full range of element expressions:

  • references to unbound indices, which will be bound by the assignment,

  • references to scalar element parameters and bound indices,

  • references to indexed element parameters, for which any nested unbound index will be bound as well,

  • calls to element-valued functions, and

  • element-valued iterative operators.

If the element expression inside the binding domain of an indexed assignment is too lengthy, it may be better to use an intermediate element parameter to improve readability.

Conditional assignments

Like any binding domain, the binding domain of an indexed assignment can be subject to a logical condition. Such an assignment is referred to as a conditional assignment, and is only executed for those elements in the binding domain that satisfy the logical condition.

Domain checking

In addition, if the identifier on the left-hand side of the assignment has its own domain restriction, then the assignment is limited to those elements of the binding domain that satisfy this restriction. Assignments to elements outside the restricted domain are not considered.

Example

The following five examples illustrate some simple assignment statements. In all examples we assume that i and j are unbound indices into a set Cities, and that LargestCity is an element parameter into Cities.

  1. The first example illustrates a simple scalar assignment.

    TotalTransportCost := sum[(i,j), UnitTransportCost(i,j)*Transport(i,j)];
    

    The value of the scalar identifier on the left-hand side is replaced with the value of the expression on the right-hand side.

  2. The second example illustrates an index binding assignment.

    UnitTransportCost(i,j) *= CostWeightFactor(i,j) ;
    

    For all cities i and j in the index domain of UnitTransportCost , the old values of the identifier UnitTransportCost(i,j) are multiplied with the values of the identifier CostWeightFactor(i,j) and then used to replace the old values.

  3. The third example illustrates a conditional assignment.

    Transport((i,j) | UnitTransportCost(i,j) > 100) := 0;
    

    The zero assignment to Transport is made to only those cities i and j for which the UnitTransportCost is too high.

  4. The fourth example illustrates a sliced assignment, i.e. an assignment that only changes the values of a lower-dimensional subspace of the index domain of the left-hand side identifier.

    Transport(LargestCity,j) := 0;
    

    The sliced assignment in this example binds only the index j. The values of the parameter Transport are set to zero from the city LargestCity to every city j, but the values from every other city i to all cities j remain unchanged.

  5. The fifth example illustrates a nested index binding statement.

    PreviousCity( NextCity(i) ) := i;
    

    The index i is bound, because it is used in the nested reference of the element parameter NextCity(i), which in turn is used for indexing the identifier PreviousCity. Note that, in a tour, city i by definition is the previous city of the specific (next) city it is linked with.

Sequential execution

Indexed assignments are executed in a sequential manner, i.e. as if it was replaced by a sequence of individual assignments to every element in the binding domain. Thus, if Periods is the integer set {0 .. 3} with index t, then the indexed assignment

Stock( t | t > 0 ) := Stock(t-1) + Supply(t) - Demand(t);

is executed (conceptually) as the sequence of individual statements

Stock(1) := Stock(0) + Supply(1) - Demand(1);
Stock(2) := Stock(1) + Supply(2) - Demand(2);
Stock(3) := Stock(2) + Supply(3) - Demand(3);

Therefore, in the right hand side expression it is possible to refer to elements of the identifier on the left which have received their value prior to the execution of the current individual assignment. This type of behavior is typically observed and wanted in stock balance type applications which use lag references as shown above. The same argument also applies to assignments that use element parameters for indexing on either the left- or right-hand side of the assignment.

Indexed assignment versus FOR

In addition to the indexed assignment, AIMMS also possesses a more general FOR statement which repeatedly executes a group of statements for all elements in its binding domain (see also The FOR Statement). If you are familiar with programming languages like C or PASCAL you might be tempted to embed every indexed assignment into one or more FOR statements with the proper domain. Although this will conceptually produce the same results, we strongly recommend against it for two reasons.

  • By omitting the FOR statements you improve to the readability and maintainability of your model code.

  • By including the FOR statement unnecessarily you are effectively degrading the performance of your model, because AIMMS can execute an indexed assignment much more efficiently than the equivalent FOR statement.

Whenever you use a FOR statement unnecessarily, AIMMS will produce a compile time warning to tell you that the code would be more efficient by removing the FOR statement.

Example

Consider the indexed assignment

Transport((i,j) | UnitTransportCost(i,j) > 100) := 0;

and the equivalent FOR statement

for ((i,j) | UnitTransportCost(i,j) > 100) do
    Transport(i,j) := 0;
endfor;

Notice that the indexed assignment is more compact than the FOR statement and is easier to read. In this example AIMMS will warn against this use of the FOR statement, because it can be removed without any change in semantics, and will lead to more efficient execution.

Undefined left-hand references

When there are undefined references with lag and lead operators on the left-hand side of an assignment (i.e. references that evaluate to the empty element), the corresponding assignments will be skipped. The same is true if the identifier on the left contains undefined references to element parameters. Notice that this behavior is different from the behavior of a reference containing undefined lag and lead expressions on the right-hand side of an assignment. These evaluate to zero.

Example

Consider the assignment to the parameter Stock above. It could also have been written as

Stock(t+1) := Stock(t) + Supply(t+1) - Demand(t+1);

In this case, there is no need to add a condition to the assignment for t\({}=3\). The reference to t+1 is undefined, and hence the assignment will be skipped. Similarly, the assignment

PreviousCity( NextCity(i) ) := i;

will only be executed for those cities i for which NextCity(i) is defined.