7.5 For Loops
Suppose N
is a variable of type int
, y
is a one-dimensional array of type real[]
, and mu
and sigma
are variables of type real
. Furthermore, suppose that n
has not been defined as a variable. Then the following is a well-formed for-loop statement.
for (n in 1:N) {
y[n] ~ normal(mu, sigma);
}
The loop variable is n
, the loop bounds are the values in the range 1:N
, and the body is the statement following the loop bounds.
Loop Variable Typing and Scope
The type of the loop variable is int
. Unlike in C++ and similarly to R, this variable must not be declared explicitly.
The bounds in a for loop must be integers. Unlike in R, the loop is always interpreted as an upward counting loop. The range L:H
will cause the loop to execute the loop with the loop variable taking on all integer values greater than or equal to L
and less than or equal to H
. For example, the loop for (n in 2:5)
will cause the body of the for loop to be executed with n
equal to 2, 3, 4, and 5, in order. The variable and bound for (n in 5:2)
will not execute anything because there are no integers greater than or equal to 5 and less than or equal to 2.
The scope of the loop variable is limited to the body of the loop.
Order Sensitivity and Repeated Variables
Unlike in BUGS, Stan allows variables to be reassigned. For example, the variable theta
in the following program is reassigned in each iteration of the loop.
for (n in 1:N) {
theta = inv_logit(alpha + x[n] * beta);
y[n] ~ bernoulli(theta);
}
Such reassignment is not permitted in BUGS. In BUGS, for loops are declarative, defining plates in directed graphical model notation, which can be thought of as repeated substructures in the graphical model. Therefore, it is illegal in BUGS or JAGS to have a for loop that repeatedly reassigns a value to a variable.9
In Stan, assignments are executed in the order they are encountered. As a consequence, the following Stan program has a very different interpretation than the previous one.
for (n in 1:N) {
y[n] ~ bernoulli(theta);
theta = inv_logit(alpha + x[n] * beta);
}
In this program, theta
is assigned after it is used in the probability statement. This presupposes it was defined before the first loop iteration (otherwise behavior is undefined), and then each loop uses the assignment from the previous iteration.
Stan loops may be used to accumulate values. Thus it is possible to sum the values of an array directly using code such as the following.
total = 0.0;
for (n in 1:N)
total = total + x[n];
After the for loop is executed, the variable total
will hold the sum of the elements in the array x
. This example was purely pedagogical; it is easier and more efficient to write
total = sum(x);
A variable inside (or outside) a loop may even be reassigned multiple times, as in the following legal code.
for (n in 1:100) {
y += y * epsilon;
epsilon = 0.5 * epsilon;
y += y * epsilon;
}
A programming idiom in BUGS code simulates a local variable by replacing
theta
in the above example withtheta[n]
, effectively creatingN
different variables,theta[1]
, …,theta[N]
. Of course, this is not a hack if the value oftheta[n]
is required for alln
.↩