Index..Do
Index I := seqExpr Do body
The construct, Index i := seqExpr
defines an index local to the definition in which it is used. The expression «seqExpr» may be a sequence, literal list, or other expression that generates an unindexed array, as used to define a global index. For example:
Variable PowersOf2
Definition: Index J := 0..5;
2^J
The new Variable PowersOf2
is an array of powers of two, indexed by the local index J
, with values from 0 to 5:
Dot Operator: A.I
The dot operator in A.I lets you access a local index «I» via an array «A» that it dimensions. If a local index identifies a dimension of an array that becomes the value of a global Variable, it may persist long after valuation of the expression—unlike other local Variables which disappear after the expression is evaluated.
Even though local index J
has no global identifier, you can access it via its parent Variable with the dot operator, ’.’, for example:
PowersOf2.J → [0, 1, 2, 3, 4, 5]
When using the subscript operation on a Variable
with a local index, you need to include the ’.’ operator, but do not need to repeat the name of the Variable
:
PowersOf2[.J = 5] → 32
Any other Variables depending on PowersOf2
may inherit J
as a local index—for example:
Variable P2
Definition: PowersOf2/2
P2[.J = 5] → 16
Examples using a local index
In this example, MatSqr
is a user-defined function that returns the square of a matrix—i.e., A x A
, where A
is the transpose of A
. The result is a square matrix. Rather than require a third index as a parameter, MatSqr
creates the local index, I2
, as a copy of index I
.
Function MatSqr(a: ArrayType; i, j: IndexType)
Definition:
Index I2 := I;
Sum(A*A[i = I2], j)
The local Variable, I2
, in MatSqr
is not within lexical scope in the definition of Z
, so we must use the dot operator ’.’ to access this dimension. We underline the dot operator for clarity:
Variable Z
Definition:
Var XX := MatSqr(X, Rows, Cols);
Sum(XX*Y[Rows = XX.I2], XX.I2)
The above definition of Z
assumes that the model contains a matrix variable, X
, indexed by Rows
and Cols
, and a variable Y
indexed by Rows
.
Detailed Notes
Specifying the Index Identifier
You can explicitly specify the identifier for an index using:
Index I / identExpr := seqExpr Do bodyExpr
the «identExpr» is evaluated, so that the identifier can be computed. The «identExpr» must evaluate to a text string containing a legal Analytica identifier. Within the lexical scope of «bodyExpr», the local identifier «I» refers to the index. To refer to an index using the dot operator, use the «identExpr». If the index appears in result windows or elsewhere, its identifier is displayed.
Examples:
Var A := (Index I / "MyInd" := 1..10 do I^2);
Sum(A, A.MyInd)
The next, more complex example, creates a list of indexes, one index corresponding to each column of a table (sans the final column). It then transforms the table into a multi-dimensional array. The number of indexes created is arbitrary. The column label is used for the local index name.
Function Table_to_array(A : Array[Rows, Columns] ; Rows, Columns: IndexType)
Definition:
MetaIndex Inds :=
(
For c := 1..Size(Columns)-1 do (
Var v := A[@Columns = c];
Index I / Slice(Columns, c) := v[Rows = Unique(v, Rows)];
VarTerm(I)
)
);
MdTable(A, Rows, Columns, inds)
Setting attributes
Index..Do creates a new index object. It does not exist in the global namespace, but it is a full-fledged object with attributes of its own, in the same way a global index or variable object has attributes. Therefore, you can set its Units, Title, Description
, etc., attributes after it is created. Analytica 4.0 will allow these side-effects, even if the expression is not being evaluated from a button script.
Example:
Index T := 1..12;
Title of T := "Time Offset";
Units of T := "Months";
T
When a local index appears in result views, attributes such as Title, Units
, and description may impact what the user sees. For example, the "Show By Identifier" toggle on the Object menu determines whether the title or identifier of the index is shown to the user.
Using an alias to an index
Within an expression, the A.I
syntax can sometimes be a lengthy way to refer to an existing index. This can be shortened by using a local variable as an alias to an existing index. For example, the following are equivalent:
Subscript(TheFinalResult, TheFinalResult.MyLongIndex, Unique(TheFinalResult, TheFinalResult.MyLongIndex))
Var R := Handle(TheFinalResult);
Var I := Handle(R.MyLongIndex, AsIndex: True); { I is an alias for TheFinalResult.MyLongIndex }
Subscript(r, I, Unique(R, I))
Note that when creating an alias for an existing index, you use Var..Do, not Index..Do. If you were to use Index..Do, you would instantiate a new index object.
Assignment
Assignment to a local index variable is a bit strange and may have a different effect than you expect unless you have a deep understanding of what is happening.
First, it is important to remember that assigning to a local index variable does not change the value of the underlying local index. Changing the index value directly is not allowed by Analytica, since there may be intermediate arrays already in memory that are indexed by that index. The following example illustrates this point:
Index J := 1..5;
Var A := J^2;
Var B := J + 5;
J := Subset(Mod(J, 2) = 1);
...
The above assignment to J
does not alter arrays A
or B
. Both arrays continue to be indexed by .J
, with length 5, even though the result of Subset is 3. In other words, the original local index J
is unaltered by the assignment operation -- only the local variable J
(as distinct from the index J
) changes.
Assignment of list or 1-D array to local index variable
New to Analytica 4.2: When you assign a list or 1-D array to a local index variable, Analytica 4.2 creates a new index object with the same identifier as was used previously, and sets it to the new value. In the above example, therefore, J
continues to function as a valid index and can be used in Slice or Subscript operators, etc. Immediately following the assignment, if the old index is still in use by existing intermediate arrays, two local indexes with the same identifier will momentarily co-exist. Consider:
Index J := 1..5;
Var A := J^2;
Var B := J + 5;
J := Subset(Mod(J, 2) = 1);
A[.J = J] + B[.J = J]
In the last line, the .J
(short for A.I
) refers to the original local index object, while the J
to the right of the equal sign refers to the new index object. The result is indexed by the new local index J
having index values [1, 3, 5]
.
Analytica 4.1 behavior
Legacy Analytica 4.1 and earlier
When you declare a local index variable, Analytica does two things: (1) It creates a local index object, and (2) it creates a local variable and assigns it a handle that points to the index object. When you assign a value to that local variable, it changes the local variable to point to the new value. So prior to the assignment operator, the local variable points to an index object, while after assignment it points to a 1-D array or list value, which is a non-object. Because the local variable no longer points to an index, it loses its index status, and from that point behaves similarly to a local variable defined using Var..Do.
To change the index value and keep the index status, you must create a new local index and then reset the local variable value with a handle to that new index. This is accomplished as follows:
Index J := 1..3;
...
Index tmp / "J" := 4..5 Do J := Handle(tmp, asIndex: true);
...
Assignment of scalar or multi-D values to local index
Analytica 4.2 will issue a warning if you attempt to assign a scalar or multi-D array to a local index variable. But it will allow the operation if you ignore the warnings. If you assign a handle to a local index variable, Analytica 4.2 will issue a warning if the object pointed to is not a valid index (note that an evaluation of the object's value might be necessary to determine this). These warnings are not present prior to Analytica 4.2.
From that point, the behavior of Analytica 4.2 and Analytica 4.1 and earlier is the same.
When you assign a scalar or multi-D value to a local index variable, the local variable is demoted from being a local index to simply being a local variable that contains the value. From that point on, it behaves similar to a local variable defined using Var..Do.
Enable comment auto-refresher