Search code examples
rcpprcpparmadillo

Apply lambda function to `arma::cube` in `RcppArmadillo`


I tried to use RcppArmadillo to compute the Frobenious norm across each slice of an array(arma::cube). The example code in file cxxFuns.cpp is presented below.

// [[Rcpp::depends(RcppArmadillo)]]
#include "RcppArmadillo.h"

// [[Rcpp::export]]
arma::vec array_norm (arma::cube & x) {
    arma::vec out = x.each_slice([](arma::mat& x0) {return arma::norm(x0, "fro") ;}) ;
    return out ;
}

After the cpp file is compiled successfully, the function array_norm throws an exception:

set.seed(2020)
Rcpp::sourceCpp('cxxFuns.cpp')
x <- array(rnorm(3*4*5), 3:5)
array_norm(x)
#> error: copy into matrix: can't interpret cube with dimensions 3x4x5 as a vector
#> Error in array_norm(x) : 
#>   copy into matrix: can't interpret cube with dimensions 3x4x5 as a vector

Created on 2020-12-02 by the reprex package (v0.3.0)


Solution

  • That actually an error message from Armadillo because something is not right with your logic yet -- the result is not a vector. You can see that by changing to this (self-contained, a very nice Rcpp trick) code:

    Code

    // [[Rcpp::depends(RcppArmadillo)]]
    #include "RcppArmadillo.h"
    
    // [[Rcpp::export]]
    bool array_norm (arma::cube & x) {
        auto out = x.each_slice([](arma::mat& x0) {return arma::norm(x0, "fro") ;}) ;
        out.print("out");
        return true;
    }
    
    /*** R
    set.seed(2020)
    x <- array(rnorm(3*4*5), 3:5)
    array_norm2(x)
    */
    

    Output

    > Rcpp::sourceCpp("~/git/stackoverflow/65104769/answer.cpp")
    
    > set.seed(2020)
    
    > x <- array(rnorm(3*4*5), 3:5)
    
    > array_norm2(x)
    out
    [cube slice 0]
       0.3770  -1.1304   0.9391   0.1174
       0.3015  -2.7965  -0.2294  -0.8531
      -1.0980   0.7206   1.7591   0.9093
    
    [cube slice 1]
       1.1964   1.8000  -2.2890   1.0982
      -0.3716   1.7040   0.0583   0.3182
      -0.1233  -3.0388   2.1744  -0.0731
    
    [cube slice 2]
       0.8343   0.9367  -0.8125   2.4354
       0.1988  -0.1474  -0.7437   0.3881
       1.2978   0.1104   1.0953   0.2906
    
    [cube slice 3]
      -0.2856   0.4472  -0.3010   0.2531
       0.0760   0.9085  -0.7260  -0.3707
      -0.5603  -0.5051  -1.1801   0.0222
    
    [cube slice 4]
       0.6600   0.6014   0.1188  -1.3283
       0.4888  -0.6738   0.1212  -0.5669
      -0.1888   0.4761  -0.1860   0.5788
    
    [1] TRUE