Difference between revisions of "Local Indexes"
(Update to Local..Do and LocalIndex..Do) |
|||
(26 intermediate revisions by 4 users not shown) | |||
Line 1: | Line 1: | ||
+ | [[Category: Analytica User Guide]] | ||
+ | [[Category: Arrays]] | ||
+ | |||
+ | <breadcrumbs> Analytica User Guide > Procedural Programming > {{PAGENAME}}</breadcrumbs><br /> | ||
+ | {{ReleaseBar}} | ||
+ | You can declare a '''local index''' in the definition of a variable or function. It is possible that the value of the variable or value returned by the function is an array using this index. This is handy because it lets you define a variable or function that creates an array without relying on an externally defined index. | ||
+ | |||
+ | The construct, <code>{{LocalIndex}} i := indexExpr</code> defines an index «i» local to the definition in which it is used. The expression «indexExpr» can be a sequence, literal list, or other expression that generates an unindexed array, as used to define a global index. For example: | ||
+ | |||
+ | :<code>Variable PowersOf2 := {{LocalIndex}} j := 0..5; 2^j</code> | ||
+ | |||
+ | The new variable <code>PowersOf2</code> is an array of powers of two, indexed by the local index <code>j</code>, with values from 0 to 5: | ||
+ | |||
+ | :<code>PowersOf2 →</code> | ||
+ | |||
+ | :[[File:result-powersof2.png|200px]] | ||
+ | |||
+ | ==Dot operator: a . i== | ||
+ | |||
+ | The [[Index..Do#Dot_Operator:_A.I|dot operator]] in <code>a.i</code> lets you access a local index <code>i</code> via an array <code>a</code> that it dimensions. If a local index identifies a dimension of an array that becomes the value of a global variable, it can persist long after evaluation of the expression — unlike other [[Local Values|local values]] which disappear after the expression is evaluated. | ||
+ | |||
+ | Even though local index <code>j</code> has no global identifier, you can access it via its parent variable with the dot operator (<code>.</code>), for example: | ||
+ | |||
+ | :<code>PowersOf2.j → [0, 1, 2, 3, 4, 5]</code> | ||
+ | |||
+ | When using the [[subscript]] operation on a variable with a local index, you need to include the dot (<code>.</code>) operator, but do not need to repeat the name of the variable: | ||
+ | |||
+ | :<code>PowersOf2[.j = 5] → 32</code> | ||
+ | |||
+ | Any other variables depending on <code>PowersOf2</code> can inherit <code>j</code> as a local index — for example: | ||
+ | |||
+ | :<code>Variable P2 := PowersOf2/2</code> | ||
+ | :<code>P2[.j = 5] → 16</code> | ||
+ | |||
+ | == Example using a local index == | ||
+ | In this example, <code>MatSqr</code> is a user-defined function that returns the square of a matrix — i.e., <code>A</code> x <code>A'</code>, where <code>A'</code> is the transpose of <code>A</code>. The result is a square matrix. Rather than require a third index as a parameter, <code>MatSqr</code> creates the local index, <code>i2</code>, as a copy of index <code>i</code>. | ||
+ | |||
+ | :<code>Function MatSqr(a: Array; i, j: Index)</code> | ||
+ | :<code>Definition := {{LocalIndex}} i2:=[[CopyIndex]](i); [[Sum]](a*a[i = i2], j)</code> | ||
+ | |||
+ | The local identifier, <code>i2</code>, in <code>MatSqr</code> is not within lexical scope in the definition of <code>Z</code>, so we must use the dot operator (<code>.</code>) to access this dimension. In the example below, we <u>underline</u> the dot operator for clarity: | ||
+ | |||
+ | :<code>Variable Z := Var XX := MatSqr(X, Rows, Cols);</code> | ||
+ | ::<code>[[Sum]](XX * Y[I=XX<u>.</u>i2], XX<u>.</u>i2)</code> | ||
+ | |||
Analytica's arrays are, in general, multi-dimensional, where each dimension is identified with an Index. An Index is an Analytica object with a list of [[IndexValue]]s. Indexes in Analytica come in three varieties: | Analytica's arrays are, in general, multi-dimensional, where each dimension is identified with an Index. An Index is an Analytica object with a list of [[IndexValue]]s. Indexes in Analytica come in three varieties: | ||
− | + | * '''Global Indexes''': These appear as parallelagrams on a diagram, e.g., [[File:IndexNode.jpg|100px]] | |
− | + | * '''Self Indexes''': A variable that can serve as an index, but also has a value. See [[Self-Indexed Arrays]] | |
− | + | * '''Local Indexes''': Index objects that do not exist in the global namespace. | |
Local indexes may be temporary, disappearing after they fall out of lexical context, or they may continue to exist outside of the lexical context where they were declared if an array indexed by the local index is returned. | Local indexes may be temporary, disappearing after they fall out of lexical context, or they may continue to exist outside of the lexical context where they were declared if an array indexed by the local index is returned. | ||
− | Local indexes are declared within expressions via the | + | Local indexes are declared within expressions via the {{LocalIndex}}..Do declaration, as in this example: |
− | + | :<code>{{LocalIndex}} X := [[Sequence]](x1, x2, (x2 - x1)/1000) Do [[ArgMax]]( f(X^2), X)</code> | |
− | In the above example, the identifier X exists as a local | + | In the above example, the identifier <code>X</code> exists as a local identifier only within the body of the Do clause, and refers to the index defined as a sequence with 1000 points ranging from <code>x1</code> to <code>x2</code>. [[ArgMax]] finds the maximum of <code>f(X^2)</code> and returns a single value, after which the index <code>X</code> ceases to exist. |
Syntactically, an index can also be written using this syntax: | Syntactically, an index can also be written using this syntax: | ||
− | + | :<code>{{LocalIndex}} X := [[Sequence]](x1, x2, (x2 - x1)/1000);</code> | |
− | + | :<code>[[ArgMax]](f(X^2), X)</code> | |
− | Here the local | + | Here the local identifier <code>X</code> is recognized to the end of the current lexical context. |
− | It is possible for an expression to return an array that is indexed by a local index. When this happens, the local index continues to exist, although no local | + | It is possible for an expression to return an array that is indexed by a local index. When this happens, the local index continues to exist, although no local or global identifier refers to it directly. This happens, for example, in the following expression: |
− | + | :<code>{{LocalIndex}} Bit := 7..0;</code> | |
− | + | :<code>[[Mod]]([[Floor]](N/2^Bit), 2)</code> | |
− | which returns the following when N:=137: | + | which returns the following when <code>N := 137</code>: |
− | {| | + | :{| class="wikitable" |
− | ! .Bit & | + | ! colspan="8" style="text-align: left;" | .Bit ▶ |
|- | |- | ||
− | | | + | ! 7 !! 6 !! 5 !! 4 !! 3 !! 2 !! 1 !! 0 |
+ | |- | ||
+ | | 1 || 0 || 0 || 0 || 1 || 0 || 0 || 1 | ||
|} | |} | ||
− | After this expression is evaluated, the local | + | After this expression is evaluated, the local identifier<code>Bit</code> no longer exists, but a 1-D array indexed by <code>.Bit</code> does exist. The only way to access this local index is through the array result. Suppose <code>BinaryN</code> is defined by the expression above. The syntax <code>BinaryN.Bit</code> identifies the index. So, for example, to count the number of bits: |
− | + | :<code>[[Sum]](BinaryN, BinaryN.Bit) → 3</code> | |
where the second parameter to [[Sum]] expects an index. | where the second parameter to [[Sum]] expects an index. | ||
To access the 3rd bit of BinaryN (counting from 0), we could write | To access the 3rd bit of BinaryN (counting from 0), we could write | ||
− | + | :<code>BinaryN[BinaryN.Bit = 3]</code> | |
+ | |||
or we can abbreviate in this case as | or we can abbreviate in this case as | ||
− | + | :<code>BinaryN[.Bit = 3]</code> | |
− | |||
− | + | since it is clear that <code>.Bit</code> is referring to an index of <code>BinaryN</code>. This abbreviation is only possible within the [[Subscript/Slice Operator]], not in other contexts. | |
− | + | It is theoretically possible to create an array with more than one local index having the same name. In this case, the <code>A.I</code> syntax is ambiguous, and one index is identified. | |
− | + | Within an expression, if you have an array containing a local index, it is possible to define a [[Local Values|local]] as an [[Alias nodes|alias]] to refer to this index in order to avoid having to type, e.g., <code>BinaryN.Bit</code> every time. This is done using the {{Local}}..Do declaration, not the {{LocalIndex}}..Do, since the {{LocalIndex}}..Do construct would create an entirely new index object, and is done as follows: | |
− | + | :<code>{{Local}} I := [[Handle]](BinaryN.Bit, asIndex: True) Do expr</code> | |
− | [[ | + | where inside «expr», the local identifier «I» is an alias for the actual index object. Note that the local name used in «expr» does not have to be the same as the local index's object name. The optional «asIndex» parameter of [[Handle]] is not actually needed in the example here, but can optionally be included for clarity (it is necessary if you want to alias a [[Self-Indexed Arrays|self-index]], as opposed to aliasing the object having a self-index). As a full example, the following expression bit-shifts the complement of <code>BinaryN</code> (divides the complement by 2), note how using I as an alias for <code>BinaryN.Bit</code> helps with conciseness within the expression: |
− | + | ||
+ | :<code>{{Local}} I := [[Handle]](BinaryN.Bit) Do</code> | ||
+ | :<code>@I = 1 Or (Not BinaryN)[@I = @I - 1]</code> | ||
− | {| | + | :{| class="wikitable" |
− | ! .Bit & | + | ! colspan="8" style="text-align: left;" | .Bit ▶ |
|- | |- | ||
− | | | + | ! 7 !! 6 !! 5 !! 4 !! 3 !! 2 !! 1 !! 0 |
+ | |- | ||
+ | | 1 || 0 || 1 || 1 || 1 || 0 || 1 || 1 | ||
|} | |} | ||
The numeric equivalent is computed by | The numeric equivalent is computed by | ||
− | + | :<code>{{Local}} I := [[Handle]](BinaryN.Bit) Do</code> | |
− | + | ::<code>[[Sum]](2^I * (@I = 1 Or (Not BinaryN)[@I = @I - 1]), I)</code> | |
+ | |||
+ | which returns 187. | ||
+ | |||
+ | ==See Also== | ||
+ | * [[Global index]] | ||
+ | * [[Self-Indexed Arrays|Self Indexes]] | ||
+ | * [[Index..Do#Dot_Operator:_A.I|Dot operator]] | ||
+ | * [[Subscript/Slice Operator]] | ||
+ | * [[Index Position Operator::@]] | ||
+ | * {{LocalIndex}} declaration | ||
+ | * {{Local}} declaration | ||
+ | * [[Handle]] | ||
+ | * [[Functions that create indexes]] | ||
+ | * [[Local Values]] | ||
+ | |||
+ | |||
+ | <footer>Recursion / {{PAGENAME}} / Ensuring Array Abstraction</footer> |
Latest revision as of 17:02, 7 June 2018
Release: |
4.6 • 5.0 • 5.1 • 5.2 • 5.3 • 5.4 • 6.0 • 6.1 • 6.2 • 6.3 • 6.4 • 6.5 |
---|
You can declare a local index in the definition of a variable or function. It is possible that the value of the variable or value returned by the function is an array using this index. This is handy because it lets you define a variable or function that creates an array without relying on an externally defined index.
The construct, LocalIndex i := indexExpr
defines an index «i» local to the definition in which it is used. The expression «indexExpr» can be a sequence, literal list, or other expression that generates an unindexed array, as used to define a global index. For example:
Variable PowersOf2 := LocalIndex 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:
PowersOf2 →
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 can persist long after evaluation of the expression — unlike other local values 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 dot (.
) operator, but do not need to repeat the name of the variable:
PowersOf2[.j = 5] → 32
Any other variables depending on PowersOf2
can inherit j
as a local index — for example:
Variable P2 := PowersOf2/2
P2[.j = 5] → 16
Example 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: Array; i, j: Index)
Definition := LocalIndex i2:=CopyIndex(i); Sum(a*a[i = i2], j)
The local identifier, i2
, in MatSqr
is not within lexical scope in the definition of Z
, so we must use the dot operator (.
) to access this dimension. In the example below, we underline the dot operator for clarity:
Variable Z := Var XX := MatSqr(X, Rows, Cols);
Sum(XX * Y[I=XX.i2], XX.i2)
Analytica's arrays are, in general, multi-dimensional, where each dimension is identified with an Index. An Index is an Analytica object with a list of IndexValues. Indexes in Analytica come in three varieties:
- Global Indexes: These appear as parallelagrams on a diagram, e.g.,
- Self Indexes: A variable that can serve as an index, but also has a value. See Self-Indexed Arrays
- Local Indexes: Index objects that do not exist in the global namespace.
Local indexes may be temporary, disappearing after they fall out of lexical context, or they may continue to exist outside of the lexical context where they were declared if an array indexed by the local index is returned.
Local indexes are declared within expressions via the LocalIndex..Do declaration, as in this example:
LocalIndex X := Sequence(x1, x2, (x2 - x1)/1000) Do ArgMax( f(X^2), X)
In the above example, the identifier X
exists as a local identifier only within the body of the Do clause, and refers to the index defined as a sequence with 1000 points ranging from x1
to x2
. ArgMax finds the maximum of f(X^2)
and returns a single value, after which the index X
ceases to exist.
Syntactically, an index can also be written using this syntax:
LocalIndex X := Sequence(x1, x2, (x2 - x1)/1000);
ArgMax(f(X^2), X)
Here the local identifier X
is recognized to the end of the current lexical context.
It is possible for an expression to return an array that is indexed by a local index. When this happens, the local index continues to exist, although no local or global identifier refers to it directly. This happens, for example, in the following expression:
LocalIndex Bit := 7..0;
Mod(Floor(N/2^Bit), 2)
which returns the following when N := 137
:
.Bit ▶ 7 6 5 4 3 2 1 0 1 0 0 0 1 0 0 1
After this expression is evaluated, the local identifierBit
no longer exists, but a 1-D array indexed by .Bit
does exist. The only way to access this local index is through the array result. Suppose BinaryN
is defined by the expression above. The syntax BinaryN.Bit
identifies the index. So, for example, to count the number of bits:
Sum(BinaryN, BinaryN.Bit) → 3
where the second parameter to Sum expects an index.
To access the 3rd bit of BinaryN (counting from 0), we could write
BinaryN[BinaryN.Bit = 3]
or we can abbreviate in this case as
BinaryN[.Bit = 3]
since it is clear that .Bit
is referring to an index of BinaryN
. This abbreviation is only possible within the Subscript/Slice Operator, not in other contexts.
It is theoretically possible to create an array with more than one local index having the same name. In this case, the A.I
syntax is ambiguous, and one index is identified.
Within an expression, if you have an array containing a local index, it is possible to define a local as an alias to refer to this index in order to avoid having to type, e.g., BinaryN.Bit
every time. This is done using the Local..Do declaration, not the LocalIndex..Do, since the LocalIndex..Do construct would create an entirely new index object, and is done as follows:
where inside «expr», the local identifier «I» is an alias for the actual index object. Note that the local name used in «expr» does not have to be the same as the local index's object name. The optional «asIndex» parameter of Handle is not actually needed in the example here, but can optionally be included for clarity (it is necessary if you want to alias a self-index, as opposed to aliasing the object having a self-index). As a full example, the following expression bit-shifts the complement of BinaryN
(divides the complement by 2), note how using I as an alias for BinaryN.Bit
helps with conciseness within the expression:
.Bit ▶ 7 6 5 4 3 2 1 0 1 0 1 1 1 0 1 1
The numeric equivalent is computed by
which returns 187.
See Also
- Global index
- Self Indexes
- Dot operator
- Subscript/Slice Operator
- Index Position Operator::@
- LocalIndex declaration
- Local declaration
- Handle
- Functions that create indexes
- Local Values
Enable comment auto-refresher