This documents describes all language elements that can be compiled to Armadillo flavored C++ code.
armacmp
always compiles functions. Every function needs to have a return
statement with an optional type argument.
You can define your inputs using the standard function syntax. By default paramters are of type type_matrix
. But they can have other types such as:
type_colvec
- a column vectortype_rowvec
- a row vectortype_scalar_integer
- a single int valuetype_scalar_numeric
- a single double valuetype_scalar_bool
- a single boolean valueAll functions need to return a value using the return
function. The return
function can have an optional return type argument with return(value, type = type_rowvec())
The package supports only a very limited number of types. For scalar values these are bool
, int
and double
. All matrices and vectors are of type arma::mat/colvec/rowvec
for double matrices, arma::imat/icolvec/irowvec
for integer matrices and arma::umat/ucolvec/urowvec
for unsigned integer matrices (used for indicies).
All operations are performed either on Armadillo types or on scalar types and not on R’s data structures.
The package tries to figure out the correct types of variables and functions, but you can give type hints. If the package cannot figure out the type, the C++ type auto
is used which can have suboptimal performance when used together with Armadillo operations.
x ^ y
exp
abs
log
sum
min
max
sqrt
cos
acos
cosh
acosh
sin
asin
sinh
asinh
tan
atan
tanh
atanh
t
chol
diag
QR
svd
solve
ncol
nrow
crossprod
tcrossprod
det
[i, j]
[i, ]
[, j]
[i]
length
cumsum
sort
unique
cumsum
cumprod
pnorm
seq_len
returns a arma::colvec
(note that is corresponds to a sequence of numerics)a:b
returns an arma::colvec
from a
to b
(note that is corresponds to a sequence of numerics)rep.int
returns a arma::colvec
(note that is corresponds to a sequence of numerics)Currently if/else, for and while loops are supported.
if_clause <- compile(function(X) {
# infers that test needs to be bool (auto)
test <- sum(log(X)) < 10
X_new <- X
if (test) {
X_new <- (t(X) %*% X) + 10
} else if (sum(X) < 10) {
X_new <- t(X) %*% X
} else {
X_new <- (t(X) %*% X) + 10
}
return(X_new)
})
Just make sure all return statements return the same type.
Also if/else
cannot be used as an expression:
For loops are supported:
# currently only seq_len is available to create sequences of ints
x <- seq_len(n)
for (i in x) {
...
}
Example:
You can also define functions within your functions (lambdas).
fun <- compile(function(X) {
square <- function(y) {
return(y^2)
}
Y <- square(X)
return(Y)
})
fun(matrix(1:10))
#> [,1]
#> [1,] 1
#> [2,] 4
#> [3,] 9
#> [4,] 16
#> [5,] 25
#> [6,] 36
#> [7,] 49
#> [8,] 64
#> [9,] 81
#> [10,] 100
Using lambdas it is possible to define recursive functions as well.
is_even <- compile(function(x = type_scalar_numeric()) {
is_even_internal <- function(y = type_scalar_numeric()) {
if (y == 0) return(TRUE)
if (y < 0) return(FALSE)
return(is_even_internal(y - 2), type = type_scalar_logical())
}
return(is_even_internal(x))
})
is_even(5)
#> [1] FALSE
is_even(4)
#> [1] TRUE