24.2 Some Differences in the Modeling Languages
The BUGS modeling language follows an R-like syntax in which line breaks are meaningful. Stan follows the rules of C, in which line breaks are equivalent to spaces, and each statement ends in a semicolon. For example:
y ~ normal(mu, sigma);
and
for (i in 1:n) y[i] ~ normal(mu, sigma);
Or, equivalently (recall that a line break is just another form of whitespace),
for (i in 1:n)
y[i] ~ normal(mu, sigma);
and also equivalently,
for (i in 1:n) {
y[i] ~ normal(mu, sigma);
}
There’s a semicolon after the model statement but not after the brackets indicating the body of the for loop.
In Stan, variables can have names constructed
using letters, numbers, and the underscore (_
) symbol, but
nothing else (and a variable name cannot begin with a number).
BUGS variables can also include the dot, or period (.
) symbol.
In Stan, the second argument to the “normal” function is the
standard deviation (i.e., the scale), not the variance (as in Bayesian Data Analysis)
and not the inverse-variance (i.e., precision) (as in BUGS).
Thus a normal with mean 1 and standard deviation 2 is normal(1,2)
,
not normal(1,4)
or normal(1,0.25)
.
Similarly, the second argument to the “multivariate normal” function is the covariance matrix and not the inverse covariance matrix (i.e., the precision matrix) (as in BUGS). The same is true for the “multivariate student” distribution.
The distributions have slightly different names:
BUGS | Stan |
---|---|
dnorm |
normal |
dbinom |
binomial |
dpois |
poisson |
… | … |
Stan, unlike BUGS, allows intermediate quantities, in the form of local variables, to be reassigned. For example, the following is legal and meaningful (if possibly inefficient) Stan code.
{
total = 0;
for (i in 1:n){
theta[i] ~ normal(total, sigma);
total = total + theta[i];
}
}
In BUGS, the above model would not be legal because the variable
total
is defined more than once. But in Stan, the loop is
executed in order, so total
is overwritten in each step.
Stan uses explicit declarations. Variables are declared with base type integer or real, and vectors, matrices, and arrays have specified dimensions. When variables are bounded, we give that information also. For data and transformed parameters, the bounds are used for error checking. For parameters, the constraints are critical to sampling as they determine the geometry over which the Hamiltonian is simulated.
In Stan, variables can be declared as data, transformed data, parameters, transformed parameters, or generated quantities. They can also be declared as local variables within blocks. For more information, see the part of this manual devoted to the Stan programming language and examine at the example models.
Stan allows all sorts of tricks with vector and matrix operations which can make Stan models more compact. For example, arguments to probability functions may be vectorized,48 allowing
for (i in 1:n)
y[i] ~ normal(mu[i], sigma[i]);
to be expressed more compactly as
y ~ normal(mu, sigma);
The vectorized form is also more efficient because Stan can unfold the computation of the chain rule during algorithmic differentiation.
Stan also allows for arrays of vectors and matrices.
For example, in a hierarchical model might have a vector of K
parameters for each of J
groups; this can be declared using
vector[K] theta[J];
Then theta[j]
is an expression denoting a K
-vector and
may be used in the code just like any other vector variable.
An alternative encoding would be with a two-dimensional array, as in
real theta[J,K];
The vector version can have some advantages, both in convenience and in computational speed for some operations.
A third encoding would use a matrix:
matrix[J,K] theta;
but in this case, theta[j]
is a row vector, not a vector, and
accessing it as a vector is less efficient than with an array of
vectors. The transposition operator, as in theta[j]'
, may be
used to convert the row vector theta[j]
to a (column) vector.
Column vector and row vector types are not interchangeable everywhere
in Stan; see the function signature declarations in the programming
language section of this manual.
Stan supports general conditional statements using a standard if-else syntax. For example, a zero-inflated (or -deflated) Poisson mixture model is defined using the if-else syntax as described in the zero inflation section.
Stan supports general while loops using a standard syntax. While loops give Stan full Turing equivalent computational power. They are useful for defining iterative functions with complex termination conditions. As an illustration of their syntax, the for-loop
model {
....
for (n in 1:N) {
... do something with n ....
}
}
may be recoded using the following while loop.
model {
int n;
...
n = 1;
while (n <= N) {
... do something with n ...
n = n + 1;
}
}
Most distributions have been vectorized, but currently the truncated versions may not exist and may not be vectorized.↩