The ast2ast package translates R functions into C++ functions, returning either an external pointer (XPtr) or an R function. This package is particularly useful for tasks requiring frequent function evaluations, such as solving ODE systems or optimization problems. Using the external pointer generated by C++ can significantly enhance performance, as shown in the benchmark below.
Supported objects:
Supported functions:
You can define the argument types for the generated functions. When generating an R function, you can use the following types:
f <- function(a, b, c, d, e, f) {
print(a) # logical scalar
print(b) # integer scalar
print(c) # double scalar
print(d) # logical vector
print(e) # integer vector
print(f) # double vector
}
library(ast2ast)
fcpp <- translate(f,
types_of_args = c("logical", "int", "double", "logical", "int", "double"),
data_structures = c("scalar", "scalar", "scalar", "vector", "vector", "vector"),
handle_inputs = c("copy", "copy", "copy", "borrow", "borrow", "borrow"),
verbose = FALSE
)
fcpp(TRUE, 1L, 1.5, c(TRUE, FALSE), c(1L, 2L), c(3.14, 3.14))
If you declare a variable in C++ the type is attached to it and
cannot be changed anymore. The default type is a vector holding doubles.
This vector can either be a matrix or a vector. Whether it is a vector
or a matrix can be changed within the function.
Additionally, other types can be defined for a variable. This is possible by using :: followed by a type during the definition of a variable. You can only do this once. The possible type words are:
f <- function() {
a::logical <- TRUE
b::integer <- 1
c::double <- 3.14
d::logical_vector <- c(TRUE, FALSE)
e::integer_vector <- c(1L, 2L, 3L)
f::double_vector <- c(3.14, 3.5)
}
library(ast2ast)
fcpp <- translate(f)
The first derivative from each variable with respect to another variable can be calculated. Three requirements have to be met in order to enable this.
In order to define the current independent variable one uses the function set_indep. The function requires one argument and does not return anything. Afterwards, one defines the function code. At the end one can get the derivative by using the function get_deriv. If several independent variables should be used one has to use unset_indep to remove the old independent variable.
f <- function(y, x) {
jac <- matrix(0, length(y), length(x))
for (i in 1:length(x)) {
set_indep(x[i])
y[1] <- (x[1]^2) * x[2]
y[2] <- 5 * x[1] + sin(x[2])
unset_indep(x[i])
jac[, i] <- get_deriv(y)
}
return(jac)
}
If you want to subset a vector or a matrix object you can use either [] or the at function. The [] is slower than at but more powerful.
The following objects can be passed to [] when using a vector or matrix:
f <- function() {
print("pass nothing")
a <- 1:8
print(a)
a[] <- 100
print(a)
print()
print("pass logical")
a <- 1:8
print(a)
a[TRUE] <- 100
print(a)
print()
print("pass scalar")
a <- 1:8
print(a)
a[1] <- 100
print(a)
print()
print("pass vector")
a <- 1:8
b <- 2:5
print(a)
a[b] <- 100
print(a)
print()
print("pass result of ==")
a <- 1:8
a[a < 5] <- 100
print(a)
print()
print("pass result of !=")
a <- 1:8
b <- c(1, 2, 3, 0, 0, 0, 0, 8)
a[a != b] <- 100
print(a)
print()
print("pass result of <=")
a <- 1:8
b <- c(1, 2, 3, 0, 0, 0, 0, 8)
a[a <= b] <- 100
print(a)
print()
print("pass result of >=")
a <- 1:8
b <- c(1, 2, 3, 0, 0, 0, 0, 9)
a[a >= b] <- 100
print(a)
print()
print("pass result of >")
a <- 1:8
b <- c(0, 2, 3, 0, 0, 0, 0, 9)
a[a > b] <- 100
print(a)
print()
print("pass result of <")
a <- 1:8
b <- c(0, 2, 3, 0, 0, 0, 0, 9)
a[a < b] <- 100
print(a)
print()
print("pass scalar, scalar")
a <- matrix(3, 4, 4)
a[1, 1] <- 100
print(a)
print()
print("pass vector, vector")
a <- matrix(3, 4, 4)
b <- c(1, 3)
c <- c(2, 4)
a[b, c] <- 100
print(a)
print()
print("pass ==, >=")
a <- matrix(1:16, 4, 4)
b <- 1:4
c <- c(1, 8, 3, 8)
a[b == c, b >= c] <- 100
print(a)
print()
print("at")
a <- 1:16
at(a, 2) <- 100
print(a)
print()
print("at")
a <- matrix(1:16, 4, 4)
at(a, 1, 4) <- 100
print(a)
print()
}
library(ast2ast)
fetr <- translate(f)
fetr()
Using the function print as common in R.
Following mathematical functions are available.
To interpolate values, the ‘cmr’ function can be used. The function needs three arguments.
f <- function() {
dep <- c(0, 1, 0.5, 2.5, 3.5, 4.5, 4)
indep <- 1:7
evalpoints <- c(
0.5, 1, 1.5, 2, 2.5,
3, 3.5, 4, 4.5, 5,
5.5, 6, 6.5
)
for (i in evalpoints) {
print(cmr(i, indep, dep))
}
}