While..Do
While (test) Do body
While evaluates «body» repeatedly as long as «test» <> 0.
In order for While to terminate, «body» must produce a side-effect on a local variable that is used by «test», causing «test» eventually to equal 0. If «test» never becomes false, While continues to loop indefinitely. If you suspect that might be happening, type Control+Break or Control+. (Control+period) to interrupt evaluation.
While returns the final value found in the last iteration of «body», or Null if no iterations occur.
«Test» must evaluate to an atomic (non-array) value; therefore, it is a good idea to force any local variable used in «test» to be atomic valued. While is one of the few constructs in Analytica that does not generalize completely to handle arrays. But, there are ways to ensure that variables and functions using While support Intelligent Arrays and probabilistic evaluation.
Examples
Local n := 1;
While n < 1000 do n := 2*n
n → 1024
Local x := 1;
Local prev := 0;
while Abs(x - prev) > 1e-6 do (
prev := x ;
x := 1 + 1/(1 + x)
)
x → 1.414214
Array Abstraction with While
The While construct is one of a few constructs in Analytica that does not fully array abstract. The limitation arises from the fact that «test» must be a scalar value, i.e., it cannot be array valued. Consider, for example, the following expression:
Local n := start;
Local steps := 0;
While n > 1 do (
n := If Mod(n, 2) = 0 then n/2 else 3*n + 1;
steps := steps + 1
)
If start = 20
when this is evaluated, this returns 7
(n steps through values of 20, 10, 5, 16, 8, 4, 2, 1
). If start = 22
, it returns 15
, and for start = 27
it returns 111
. One of the key features of an Analytica model is the ability to easily add a dimension to an input without having to change the model's internals. So what we'd like is that when start
is set to the list [20, 22, 27]
, the expression would array-abstract and return the result array [7, 15, 111]
. However, the above expression will result in an error, complaining that «test» is not a scalar.
While disallows «test» to be an array, because otherwise the criteria for termination is ambiguous. It may be that for certain elements, the loop should be terminated, while for others it should not.
These problems can be addressed by declaring the dimensionality of all parameters that influence «test». We can do this simply in this example by listing the dimensions of n when it is declared -- in this case listing zero dimensions, hence there are no index identifiers between the brackets in its declaration:
Local n[ ] := start;
Local steps := 0;
While n > 1 do (
n := If Mod(n, 2) = 0 then n/2 else 3*n + 1;
steps := steps + 1
)
When this is evaluated and start
is array-valued, Analytica sees that n must be scalar in the expression that uses n. To accomplish that, Analytica will iterate as necessary, setting n to a single scalar value each time. Without the brackets, n is passed down as an array.
The While..Do construct is used most often from within User-Defined Functions. In this case, the dimensionality declaration should be placed on the Function Parameter Qualifiers. In this case, we would declare the parameter start
to be atomic:
Function Num3nSteps(start: atomic)
Definition:
Local n := start;
Local steps := 0;
While n > 1 do (
n := If Mod(n, 2) = 0 then n/2 else 3*n + 1;
steps := steps + 1
)
While Any cond Do
When the condition evaluates to an array, the keyword Any can be specified to indicate that the while loop is to continue as long as any of the elements of the array is non-zero. Example:
Local steps := 0;
Local x := start;
While Any x > 1 Do (
steps := If x > 1 Then steps + 1 Else steps;
x := If x < 2 Then x
Else If Mod(x, 2) = 0 Then x/2
Else 3*x + 1;
);
steps
In general, Any iterates most elements more times than necessary in order to handle extra dimensions.
Enable comment auto-refresher