RC Interface: Multidimensional Array Transfer

I wrote a function โ€œfooโ€ in C that I want to call from an R program. The function takes as an input matrix and performs some operations on it (for example, add 1 to each element). While itโ€™s easy for one vector like

.C("foo", n=as.integer(5), x=as.double(rnorm(5))) 

with foo implemented as

 void foo(int *nin, double *x) { int n = nin[0]; int i; for (i=0; i<n; i++) x[i] = x[i] * x[i]; } 

How to pass in a two-dimensional array? If I change "double * x" to "double ** x", this will give a segmentation error. Any pointers appreciated.

+6
source share
3 answers

No need to give up .C for direct manipulations like this. Remember that a matrix in R is a vector + dimension. Similarly in C, pass the matrix and its dimensions, as well as the matrix access elements corresponding to the displacements in the vector. Sort of

 void cplus1(double *x, int *dim) { for (int j = 0; j < dim[1]; ++j) for (int i = 0; i < dim[0]; ++i) x[j * dim[0] + i] += 1; } 

so using inline as a nice party trick

 library(inline) sig <- signature(x="numeric", dim="integer") body <- " for (int j = 0; j < dim[1]; ++j) for (int i = 0; i < dim[0]; ++i) x[j * dim[0] + i] += 1; " cfun <- cfunction(sig, body=body, language="C", convention=".C") plus1 <- function(m) { m[] = cfun(as.numeric(m), dim(m))$x m } 
+7
source

Give up .C() and switch to .Call() , which allows you to transfer entire R objects as so-called SEXP objects.

You can analyze these difficulties using the C API R or through Rcpp using (which, in our opinion) good higher-level abstractions.

 R> library(inline) # use version 0.3.10 for rcpp() wrapper R> R> addMat <- rcpp(signature(ms="numeric"), body=' + Rcpp::NumericMatrix M(ms); + Rcpp::NumericMatrix N = Rcpp::clone(M); + for (int i=0; i<M.nrow(); i++) + for (int j=0; j<M.ncol(); j++) + N(i,j) = M(i,j) + 1; + return(N); + ') R> addMat(matrix(1:9,3,3)) [,1] [,2] [,3] [1,] 2 5 8 [2,] 3 6 9 [3,] 4 7 10 R> 
+8
source

With .C you need to pass the matrix size with additional parameters, as in @Martin Morgan's answer.

With .Call

 SEXP foo(SEXP mat){ SEXP dims = getAttttrib(mat, R_DimSymbol); int nrow = INTEGER(dims)[0]; int ncol = INTEGER(dims)[1]; //... } 
0
source

All Articles