6.5 Arithmetic and Matrix Operations on Expressions

For integer and real-valued expressions, Stan supports the basic binary arithmetic operations of addition (+), subtraction (-), multiplication (*) and division (/) in the usual ways.

For integer expressions, Stan supports the modulus (%) binary arithmetic operation. Stan also supports the unary operation of negation for integer and real-valued expressions. For example, assuming n and m are integer variables and x and y real variables, the following expressions are legal.

3.0 + 0.14
-15
2 * 3 + 1
(x - y) / 2.0
(n * (n + 1)) / 2
x / n
m % n

The negation, addition, subtraction, and multiplication operations are extended to matrices, vectors, and row vectors. The transpose operation, written using an apostrophe (') is also supported for vectors, row vectors, and matrices. Return types for matrix operations are the smallest types that can be statically guaranteed to contain the result. The full set of allowable input types and corresponding return types is detailed in the list of functions.

For example, if y and mu are variables of type vector and Sigma is a variable of type matrix, then (y - mu)' * Sigma * (y - mu) is a well-formed expression of type real. The type of the complete expression is inferred working outward from the subexpressions. The subexpression(s) y - mu are of type vector because the variables y and mu are of type vector. The transpose of this expression, the subexpression (y - mu)' is of type row_vector. Multiplication is left associative and transpose has higher precedence than multiplication, so the above expression is equivalent to the following fully specified form (((y - mu)') * Sigma) * (y - mu).

The type of subexpression (y - mu)' * Sigma is inferred to be row_vector, being the result of multiplying a row vector by a matrix. The whole expression’s type is thus the type of a row vector multiplied by a (column) vector, which produces a real value.

Stan provides elementwise matrix multiplication (e.g., a .* b) and division (e.g., a ./ b) operations. These provide a shorthand to replace loops, but are not intrinsically more efficient than a version programmed with an elementwise calculations and assignments in a loop. For example, given declarations,

vector[N] a;
vector[N] b;
vector[N] c;

the assignment,

c = a .* b;

produces the same result with roughly the same efficiency as the loop

for (n in 1:N)
  c[n] = a[n] * b[n];

Stan supports exponentiation (^) of integer and real-valued expressions. The return type of exponentiation is always a real-value. For example, assuming n and m are integer variables and x and y real variables, the following expressions are legal.

3 ^ 2
3.0 ^ -2
3.0 ^ 0.14
x ^ n
n ^ x
n ^ m
x ^ y

Exponentiation is right associative, so the expression 2 ^ 3 ^ 4 is equivalent to the fully specified form 2 ^ (3 ^ 4).

Operator Precedence and Associativity

The precedence and associativity of operators, as well as built-in syntax such as array indexing and function application is given in tabular form in the operator precedence table.

Operator Precedence Table. Stan’s unary, binary, and ternary operators, with their precedences, associativities, place in an expression, and a description. The last two lines list the precedence of function application and array, matrix, and vector indexing. The operators are listed in order of precedence, from least tightly binding to most tightly binding. The full set of legal arguments and corresponding result types are provided in the function documentation for the operators (i.e., operator*(int,int):int indicates the application of the multiplication operator to two integers, which returns an integer). Parentheses may be used to group expressions explicitly rather than relying on precedence and associativity.

Op. Prec. Assoc. Placement Description
? ~ : 10 right ternary infix conditional
|| 9 left binary infix logical or
&& 8 left binary infix logical and
== 7 left binary infix equality
!= 7 left binary infix inequality
< 6 left binary infix less than
<= 6 left binary infix less than or equal
> 6 left binary infix greater than
>= 6 left binary infix greater than or equal
+ 5 left binary infix addition
- 5 left binary infix subtraction
* 4 left binary infix multiplication
/ 4 left binary infix (right) division
% 4 left binary infix modulus
\ 3 left binary infix left division
.* 2 left binary infix elementwise multiplication
./ 2 left binary infix elementwise division
! 1 n/a unary prefix logical negation
- 1 n/a unary prefix negation
+ 1 n/a unary prefix promotion (no-op in Stan)
^ 0.5 right binary infix exponentiation
' 0 n/a unary postfix transposition
() 0 n/a prefix, wrap function application
[] 0 left prefix, wrap array, matrix indexing

Other expression-forming operations, such as function application and subscripting bind more tightly than any of the arithmetic operations.

The precedence and associativity determine how expressions are interpreted. Because addition is left associative, the expression a + b + c is interpreted as (a + b) + c. Similarly, a / b * c is interpreted as (a / b) * c.

Because multiplication has higher precedence than addition, the expression a * b + c is interpreted as (a * b) + c and the expression a + b * c is interpreted as a + (b * c). Similarly, 2 * x + 3 * - y is interpreted as (2 * x) + (3 * (-y)).

Transposition and exponentiation bind more tightly than any other arithmetic or logical operation. For vectors, row vectors, and matrices, -u' is interpreted as -(u'), u * v' as u* (v'), and u' * v as (u') * v. For integer and reals, -n ^ 3 is interpreted as -(n ^ 3).