1

I am running the following sample code from http://markovjumps.blogspot.com/2011/12/r-array-to-rcpparmadillo-cube.html which is illustrating how one can transform R array to RcppArmadillo cube. The code is as follows

require(inline)
require(RcppArmadillo)

src <- '
       using namespace Rcpp;

       NumericVector vecArray(myArray);
       IntegerVector arrayDims = vecArray.attr("dim");

       arma::cube cubeArray(vecArray.begin(), arrayDims[0], arrayDims[1], arrayDims[2], false);

       //change one element in the array/cube
       cubeArray(0,0,0) = 518;  

       return(wrap(cubeArray));  
'

readCube = cxxfunction(signature(myArray="numeric"),body=src, plugin="RcppArmadillo")

set.seed(345)
testArray = array(rnorm(8), dim=c(2,2,2))
print(testArray[1,1,1])
# -0.7849082
readCube(testArray)[1,1,1]
# 518
print(testArray)[1,1,1]
# 518

As can be seen, the testArray has been altered. However, I don't quite understand why this happens.

I did some search on the issue and found in http://arma.sourceforge.net/docs.html#Cube that "Create a cube using data from writable auxiliary (external) memory, where ptr_aux_mem is a pointer to the memory. By default the cube allocates its own memory and copies data from the auxiliary memory (for safety). However, if copy_aux_mem is set to false, the cube will instead directly use the auxiliary memory (ie. no copying); this is faster, but can be dangerous unless you know what you are doing!"

So I changed false to true and the problem is gone. However, I am still confusing since the original code create a new NumericVector vecArray and vecArray.begin() should refer to the memory of that new NumericVector object instead of the function input myArray. I feel changing cubeArray should only change vecArray but not myArray.

Bayesric
  • 329
  • 3
  • 13

1 Answers1

0

Thanks to Dirk, now I see where I was trapped. Below are my own solutions:

The problem would either be fixed via using clone() or creating a new Armadillo cube object. The two solutions are as follows.

// Using clone()
src <- '
       using namespace Rcpp;

       NumericVector vecArray(clone(myArray));
       IntegerVector arrayDims = vecArray.attr("dim");

       arma::cube cubeArray(vecArray.begin(), arrayDims[0], arrayDims[1], arrayDims[2], false);

       //change one element in the array/cube
       cubeArray(0,0,0) = 518;  

       return(wrap(cubeArray));  
'

readCube = cxxfunction(signature(myArray="numeric"),body=src, plugin="RcppArmadillo")

or

// Not using clone()
src <- '
       using namespace Rcpp;

       NumericVector vecArray(myArray);
       IntegerVector arrayDims = vecArray.attr("dim");

       arma::cube cubeArray(vecArray.begin(), arrayDims[0], arrayDims[1], arrayDims[2]);

       //change one element in the array/cube
       cubeArray(0,0,0) = 518;  

       return(wrap(cubeArray));  
'

readCube = cxxfunction(signature(myArray="numeric"),body=src, plugin="RcppArmadillo")

Note that you don't want to use clone() and at the same time also create a new cube object, since it is not efficient in memory.

Bayesric
  • 329
  • 3
  • 13