Stan functions exported to R: how do argument type conversions work?

When using rstan::expose_stan_functions(), functions defined in the functions block of Stan code get exported to R. My question is that are there some rules to determine what the R type of the function arguments should be given the Stan type? This is difficult to know with multidimensional arrays (or arrays of vectors/matrices). Sometimes the first dimension of an array has be encoded using a list in R. For one-dimensional arrays of reals apparently not. So far I have only tried to infer the types by trial and error but it is slow because error messages are not very informative, like:

VECTOR_ELT() can only be applied to a 'list', not a 'double'

Like currently I have the above message, but I have several arguments and I have no information which one of them is the one that is in wrong format. There is this small discussion Rstan error: VECTOR_ELT() can only be applied to a 'list', not a 'double' it focuses only on one specific case

The mapping is numeric/integer scalars for int and real types, numeric vectors for vector and real[] types, matrix for matrix, and lists of the above for any arrays of containers.

We can verify this with a toy example. First, a functions block that just returns the input argument for a variety of types:

test_fun = "

functions {

real real_tester(real real_arg) {
 return real_arg;            
}

int int_tester(int int_arg) {
 return int_arg;            
}

vector vector_tester(vector vector_arg) {
 return vector_arg;            
}

real[] real_array_tester(real[] real_array_arg) {
 return real_array_arg;            
}

matrix matrix_tester(matrix matrix_arg) {
 return matrix_arg;            
}

vector[] vector_array_tester(vector[] vector_array_arg) {
 return vector_array_arg;            
}

matrix[] matrix_array_tester(matrix[] matrix_array_arg) {
 return matrix_array_arg;            
}

matrix[,] nested_matrix_array_tester(matrix[,] nested_matrix_array_arg) {
 return nested_matrix_array_arg;            
}
}
"

Next, we just the input arguments of the correct type to verify that all works:

> real_tester(1)
[1] 1
> int_tester(1)
[1] 1
> vector_tester(1:3)
[1] 1 2 3
> real_array_tester(1:3)
[1] 1 2 3
> matrix_tester(matrix(1:6,ncol=3,nrow=2))
     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    2    4    6
> vector_array_tester(list(1:3,4:7))
[[1]]
[1] 1 2 3

[[2]]
[1] 4 5 6 7

> matrix_array_tester(list(matrix(1:6,ncol=3,nrow=2),
+                          matrix(7:10,ncol=2,nrow=2)))
[[1]]
     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    2    4    6

[[2]]
     [,1] [,2]
[1,]    7    9
[2,]    8   10

> nested_matrix_array_tester(
+   list(
+     list(matrix(1:6,ncol=3,nrow=2),matrix(7:10,ncol=2,nrow=2)),
+     list(matrix(1:4,ncol=2,nrow=2),matrix(5:10,ncol=2,nrow=3))
+   )
+ )
[[1]]
[[1]][[1]]
     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    2    4    6

[[1]][[2]]
     [,1] [,2]
[1,]    7    9
[2,]    8   10


[[2]]
[[2]][[1]]
     [,1] [,2]
[1,]    1    3
[2,]    2    4

[[2]][[2]]
     [,1] [,2]
[1,]    5    8
[2,]    6    9
[3,]    7   10
2 Likes

Also, if this relates to the standalone functions for your lgpr package, I have updates to rstantools in the pipeline for automatically generating the exports for standalone functions. So you won’t need to manually generate/modify these in future

1 Like

Yes it relates to that and other similar development. The only ‘manual’ thing that I currently have to do is to run this script lgpr/cpp.R at master · jtimonen/lgpr · GitHub to get the export, so that is not the slow part. But of course it would be better if it was done by rstantools. The bigger problem has
been not knowing how to call the exported functions, but now it should be clear since you explained it.