Iterate
Iterate( initial, expr, until, maxIter, warn )
Iterates a computation until a termination condition (such as convergence) is satisfied, or until a maximum number of iterations is reached.
To use Iterate, the call to Iterate must occur at the top level of the definition (similar to how Dynamic must occur at the top level). The first parameter, initial, specifies the starting value for the iteration, and the second parameter, expr, specifies how the subsequent values are computed from the previous value. The second parameter, expr, can depend directly or indirectly upon the variable defined by Iterate, forming a recurrence.
The third parameter, until, specifies a termination condition. Iterate continues evaluating expr until all array elements returned by expr are non-zero (true), or until the maximum number of iterations specified by the optional fourth parameter is reached. If the fifth parameter is specified as true, a warning is issued if the maximum number of iterations is reached without full convergence.
Iterate is often used when the iteration should occur over a large portion of your model. For smaller loops that can be self-contained in a single definition, or that appear in User-Defined Functions, the While..Do construct is usually used instead.
Example
In the model depicted, the manner in which the market price reacts to a imbalance between supply and demand is modeled. Given a Price, the supply and demand at that price are forecast, and then used to determine a market price at that supply/demand point. By iterating on Price, the steady-state market equilibrium price is computed. This iteration is accomplished by defining Price as:
Iterate( Price_Guess, Next_price, abs(Next_price-price)<0.01, 50 )
This iterates until the change in price is less than 0.01, or until 50 iterations are computed.
Iterating Multiple Variables
In some cases, you may have several variables that you need to update in each iteration. For example, you may wish to update estimates for both Price and Market_size at each iteration. When you do this, it is important that you have only one node defined using Iterate. You would NOT want to define both Price and Market_size using Iterate. Two instances of iterate in that fashion would specify two separate (and nested) iterations, which is not what is intended. Instead, what you need to do is group all variables into a single state representation. The components of that state are listed along an index.
In the above diagram, State_Index is defined as a list of labels:
| State_index ↓ |
|---|
| "Price" |
| "Market Size" |
Initial_state is defined as a table:
Table(State_index)(Price_Guess,Market_size_guess)
and Next_State is similarly defined:
Table(State_Index)(Price_Guess,Market_size_guess)
and a single call to Iterate is present in State:
Iterate( Initial_state, Next_State, abs(state-next_state)<0.01, 50)
for convenience, Price and Market_Size break out the elements of State so that their identifiers can be used directly in expressions. For example, Price is defined as Price[State_Index='Price'].
The preceeding definitions assume that State and Market_size have the same dimensionality. For example, both may be scalars, or both contain exactly the same indexes. When iterating over multiple variables, this is not always the case. When the indexes may differ, then you should place each component inside a reference. The preceeding definitions would thus become:
Initial_state := Table(State_index)(\Price_guess,\Market_size_guess) Next_state := Table(State_Index)(\Price_Guess,\Market_size_guess) Price := #State[State_index='Price'] Market_size := #State[State_index='Market Size'] State := Iterate( Initial_state, Next_State, abs(price-next_price)<0.01 and abs(market_size-next_market_size)<1, 50)
Note that \ and # are the reference and de-reference operators.
The method of gathering references to values into an array is a flexible method that generalizes to any number of variables.
Iterate with Dynamic
Iterate can be used in conjunction with Dynamic. Depending on the model structure, this can either result in an iteration within a dynamic loop, where the iteration to convergence occurs at each point in time, or it can result in a dynamic loop within an iteration, in which case the entire dynamic loop is computed to completion within each iteration.
Suppose X is a variable defined with Iterate, and Y is a variable defined with Dynamic. Then X might depend directly or indirectly on Y, and Y might depend directly or indirectly on X. This creates four distinct depedency structures. When neither X nor Y depends on the other, then there is no iteraction. Similarly, when Y depends on X, but X is not downstream of Y, then X is not within Y's dynamic loop, so again there is no interaction. In this case, X is iterated to completion once, indepedent of the dynamic loop, then the dynamic loop performs its looping using this value.
When X depends on Y, but Y does not depend on X, then the dynamic loop is completely inside the Iteration for X, so that the dynamic loop is computed to completion within each iteration.
The most difficult case is when X and Y both depend on the other. When this happens, the iterate expression could, in principle, be interpreted as being inside the dynamic or around the dynamic. Analytica resolves this ambiguity by assuming that the iterate is inside the dynamic, so that as the dynamic loop is evaluated at each time period, the iteration in X is run to completion for that time period. Variables inside X's definition are implicitly assumed to be sliced by the current dynamic time (as occurs with any variable appearing inside a dynamic loop).
You may encounter situations where you want to compute one or more variables using Iterate, which in turn are utilized within a dynamic loop, but where you desire the Iteration to occur around the dynamic loop. For example, you may have completed an entire Dynamic model, and now you want to wrap Iterate around the full model to adjust an input parameter. In the future, we may introduce a new variation on the iterate function that would make it possible to specify that Iterate is wrapped around a given dynamic loop. Until then, one way to cause Iterate to wrap around a dynamic loop is by using a WhatIf to compute the value of the input parameter. To demonstrate, suppose you have an input parameter, K, used by a dynamic model having some output Y. We want to define K using Iterate where the update expression and termination expressions depend on Y. To do this, we introduce two variables:
Variable Y2 := WhatIf(Y,K,K2) Variable K2 := Iterate(K,f(K2,Y2), g(K2,Y2) )
here f( ) is the update expression and g( ) is the termination expression. When K2 is evaluated, the iteration re-evaluates the full model repeatedly, with K2 eventually being set to the "converged" value for the parameter K. As a final step, we may want to set K to be this computed value for K2. For this last step, we would need to use a button:
Button Update_K := (K := K2)
Pressing the button causes the entire evaluation to take place.
(To do: provide some examples)
Interacting Iterate Functions
If you have two (or more) variables defined using the Iterate function, they should not be mutually dependent on each other. This case creates an ambiguity (for example, the result would depend on which was evaluated first), and results in an error message.
It is okay for one to be nested within the other, in which case the inner iteration runs to convergence during each iteration of the outer iterate. However, the need for nested iterations like this are rare. You should make sure that you don't intend to have a single iteration with multiple variables updated in the same iteration (see the earlier section on this page).
If you have two interacting Iterate loops that are not clearly nested, you will see this error message:
A disallowed cyclic dependency involving the Iterate function in ident detected. You may have two nodes defined with Iterate functions, with each depending on the other. If you use two Iterate functions, one needs to be clearly nested inside the other. If you intend to have a single iteration involving two or more nodes, the Iterate function should appear noly once.
Iterate with Change in Evaluation Mode
Suppose X is defined using Iterate, and the update expression depends on Sample(X) -- for example, it may use a statistical function like Mean(X). If X is evaluated in Mid mode, it appears as if there are two interacting Iterate loops, and the above error message, A disallowed cyclic dependency involving Iterate.... occurs.
Iterate vs. While..Do
Iterate and While..Do are closely related, and both are often used for implementing convergence algorithms. When implementing an iterative algorithm in a User-Defined Function, you would normally use While..Do. However, in some situations you may develop a fairly sizeable influence diagram model, where you wish to iterate over the entire model. In that case, Iterate is very convenient, and may require only small modifications.
The While..Do construct requires its parameter, which determines when the loop terminates, to be atomic, while Iterate allows array-valued termination conditions, but continues until all cells are true.
There are a few other approaches to implementing iterations within Analytica. NlpDefine performs a full optimization search. The Solve and GoalSeek functions are similar, although scaled down somewhat in their sophistication. User-Defined Functions can be recursive, although the recursion depth is usually limited to 255, which can be a limiting factor. And to iterate over an existing model structure, While..Do can be used with WhatIf, or from a button script, While..Do can be used with assignment (often a useful way to iterate in very large scale sampling applications that exceed memory required for built-in Monte Carlo sampling). And of course, there is Dynamic.
See Also
- Analytica User Group Webinar on the Iterate Function
- Dynamic
- While..Do
- Using References


Enable comment auto-refresher