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
var n := 1; while n<1000 do n := 2*n --> returns 1024
var x := 1; var prev := 0; while abs(x-prev)>1e-6 do ( prev:=x ; x:=1 + 1/(1+x) ) --> returns 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:
Var n := start; Var 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 the 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:
Var n[ ] := start; Var 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 shoudl be placed on the Function Parameter Qualifiers. In this case, we would declare the parameter start to be atomic:
Function Num3nSteps( start : atomic ) Definition: Var n := start; Var 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:
Var steps := 0; Var 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