I have a vector x of type Eigen::VectorXi with more than 2^31-1 entries, which I would like to return to R. I can do that by copying x entry-wisely to a new vector of type Rcpp::IntegerVector, but that seems to be quite slow.
I am wondering:
- whether there is a more efficient workaround;
- why in the following reproducible example
Rcpp::wrap(x)doesn't work.
test.cpp
#include <RcppEigen.h>
// [[Rcpp::depends(RcppEigen)]]
// [[Rcpp::export]]
SEXP foo(const R_xlen_t size) {
Eigen::VectorXi x(size);
for (R_xlen_t i = 0; i < size; i++) {
x(i) = 1;
}
return Rcpp::wrap(x);
}
// [[Rcpp::export]]
Rcpp::IntegerVector fooSlow(const R_xlen_t size) {
Eigen::VectorXi x(size);
for (R_xlen_t i = 0; i < size; i++) {
x(i) = 1;
}
Rcpp::IntegerVector y(size);
for (R_xlen_t i = 0; i < size; i++) {
y(i) = x(i);
}
return y;
}
test.R
Rcpp::sourceCpp("./test.cpp")
a <- foo(2^(31)) # Error in foo(2^(31)) : negative length vectors are not allowed
a <- fooSlow(2^(31)) # runs fine but it's slow
Rcpp::wrapis dispatching to a method for Eigen matrices and vectors implemented inRcppEigen. That method doesn't appear to support long vectors, currently. (Edit: It now does; see below.)The error about negative length is thrown by
allocVector3here. It arises whenallocVector3is called with a negative value for its argumentlength. My guess is thatRcpp::wraptries to represent2^31as anint, resulting in integer overflow. Maybe this happens here?In any case, you seem to have stumbled on a bug, so you might consider sharing your example with the
RcppEigenmaintainers on GitHub. (Edit: Never mind - I've just submitted a patch.) (Edit: Patched now, if you'd like to buildRcppEigenfrom sources [commit 5fd125e or later] in order to update yourRcpp::wrap.)Attempting to answer your first question, I compared your two approaches with my own based on
std::memcpy. Thestd::memcpyapproach supports long vectors and is only slightly slower thanRcpp::wrap.The
std::memcpyapproachThe C arrays beneath
Eigen::VectorXi xandRcpp::IntegerVector yhave the same type (int) and length (n), so they contain the same number of bytes. You can usestd::memcpyto copy that number of bytes from one's memory address to other's without aforloop. The hard part is knowing how to obtain the addresses.Eigen::VectorXihas a member functiondatathat returns the address of the underlyingintarray. R objects of integer type useINTEGERfrom the R API, which does the same thing.Tests