13

I having trouble figuring out how to return an RcppArmadillo colvec as a standard R vector. I was hoping I could typecast through as<NumericVector>(wrap()) but I still end up with objects that are R matrices. Here's a bit of code to show what I've tried (partially inspired by this previous question):

// [[Rcpp::export]]                                                                                                                     
List testthis(NumericVector x) {
  arma::colvec y = x;
  arma::vec z = x;

  return List::create(Rcpp::Named("y1")=y,
                      Rcpp::Named("y2")=wrap(y),
                      Rcpp::Named("y3")=as<NumericVector>(wrap(y)),
                      Rcpp::Named("z1")=z,
                      Rcpp::Named("z2")=arma::trans(z),
                      Rcpp::Named("z3")=as<NumericVector>(wrap(z))
                      );
}

and if I look at the output I get the following which are all R matrix objects. Can I cast it to R vectors?

> testthis(c(1:3))
$y1
     [,1]
[1,]    1
[2,]    2
[3,]    3

$y2
     [,1]
[1,]    1
[2,]    2
[3,]    3

$y3
     [,1]
[1,]    1
[2,]    2
[3,]    3

$z1
     [,1]
[1,]    1
[2,]    2
[3,]    3

$z2
     [,1] [,2] [,3]
[1,]    1    2    3

$z3
     [,1]
[1,]    1
[2,]    2
[3,]    3
ekstroem
  • 5,957
  • 3
  • 22
  • 48

3 Answers3

13

You can just set the dim attribute to NULL, since matrices are pretty much just regular vectors with a dimensional attribute. From the C++ side it looks like this:

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

// [[Rcpp::export]]
Rcpp::List testthis(Rcpp::NumericVector x) {
  arma::colvec y = x;
  arma::vec z = x;

  Rcpp::NumericVector tmp = Rcpp::wrap(y);
  tmp.attr("dim") = R_NilValue;

  Rcpp::List result = Rcpp::List::create(
    Rcpp::Named("arma_vec") = y,
    Rcpp::Named("R_vec") = tmp);

  return result;
}

/*** R

R> testthis(c(1:3))
# $arma_vec
#   [,1]
# [1,]    1
# [2,]    2
# [3,]    3
#
# $R_vec
#   [1] 1 2 3

R> dim(testthis(c(1:3))[[1]])
#[1] 3 1
R> dim(testthis(c(1:3))[[2]])
#  NULL

*/
nrussell
  • 18,382
  • 4
  • 47
  • 60
  • 1
    Both @nrussell's and Dirk's answers helped me with my question. Since they provide slightly different (but valid) solutions I flipped a coin as to who should get the answer credit. Thanks both! – ekstroem Sep 15 '15 at 10:34
  • I spent days scratching my head about this. Thank you!! – Jake Oct 16 '19 at 16:36
8

It's a "feature". At some point very early on we decided to keep dimensions, so vectors always come back as matrices with one row or column. As this API was established quite some time ago, it is now hard to change as we would break existing code.

Kudos for trying all the variations above. Here is another that helps by going via std::vector<double>:

R> cppFunction("std::vector<double> foo(arma::vec v) { 
+                               return as<std::vector<double> >(wrap(v)); }", 
+              depends="RcppArmadillo")
R> foo(c(5.5,6.6,7.42))
[1] 5.50 6.60 7.42
R> 

It is probably more efficient to just strip the dimension on the R side though.

Dirk Eddelbuettel
  • 360,940
  • 56
  • 644
  • 725
6

This is an old question but it still pops at first rows when searching for the subject so I would like to share another option which is possible since the version 0.7.960.1.0. Insert an appropriate #define before #include and voilà:

#define RCPP_ARMADILLO_RETURN_COLVEC_AS_VECTOR
#include <RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]

// [[Rcpp::export]]
arma::vec testthis(arma::vec x) {
   return x+1;
}
/*** R
testthis(1:3)
*/

> testthis(1:3)
[1] 2 3 4

You can replace COLVEC in #define by ROWVEC or ANYVEC if appropriate.

Serguei Sokol
  • 61
  • 1
  • 2