Reputation: 21
Say I have an R package called "packA" that contains the following file "funcA.cpp":
// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::interfaces(r, cpp)]]
#include <RcppArmadillo.h>
using namespace Rcpp;
// [[Rcpp::export]]
void funcA (arma::vec& x) {
x += 1;
}
Calling this function from R yields the expected result of adding 1 to each element of the vector in-place:
> vec <- c(1, 2, 3)
> funcA(vec)
> vec
[1] 2 3 4
Now say I have a second package "packB" that wants to call the function "funcA". It contains the following file called "funcB.cpp":
// [[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadillo.h>
#include <packA.h>
using namespace Rcpp;
// [[Rcpp::export]]
void funcB() {
arma::vec x = {1, 2, 3};
Rcout << x << "\n";
packA::funcA(x);
Rcout << x << "\n";
}
Calling this function no longer yields the desired result, as it would appear that the vector x is no longer modified in-place:
> funcB()
1.0000
2.0000
3.0000
1.0000
2.0000
3.0000
Is there any way to preserve the in-place operations of C++ functions while still using Rcpp? Thanks in advance for any advice.
Edit: I modified "funcB.cpp" according to Dirk Eddelbüttel's suggestion:
// [[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadillo.h>
#include <packA.h>
using namespace Rcpp;
// [[Rcpp::export]]
void funcB(arma::vec& y) {
packA::funcA(y);
}
Unfortunately, the result when calling the function from R was the same:
> vec <- c(1, 2, 3)
> funcB(vec)
> vec
[1] 1 2 3
Edit 2:
After some further experimentation I noticed that things start to break down as soon as arma::vec& x
is in the footprint of funcA
. Simply using a NumericVector
works:
"funcA.cpp"
// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::interfaces(r, cpp)]]
#include <RcppArmadillo.h>
using namespace Rcpp;
// [[Rcpp::export]]
void funcA (NumericVector& num_x) {
num_x[2] = 10 + num_x[2];
}
> vec <- c(1, 2, 3)
> funcA(vec)
> vec
[1] 1 2 13
"funcB.cpp"
// [[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadillo.h>
#include <packA.h>
using namespace Rcpp;
// [[Rcpp::export]]
void funcB(NumericVector& num_y) {
packA::funcA(num_y);
}
> vec <- c(1, 2, 3)
> funcB(vec)
> vec
[1] 1 2 13
Even using the advanced arma::vec
constructor to create an Armadillo vector with shared memory works as long as the input is a NumericVector
:
"funcA.cpp"
// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::interfaces(r, cpp)]]
#include <RcppArmadillo.h>
using namespace Rcpp;
// [[Rcpp::export]]
void funcA (NumericVector& num_x) {
arma::vec x_int = arma::vec(num_x.begin(), 3, false, false);
x_int(2) = 10 + x_int(2);
}
> vec <- c(1, 2, 3)
> funcA(vec)
> vec
[1] 1 2 13
> vec <- c(1, 2, 3)
> funcB(vec)
> vec
[1] 1 2 13
Trying the same thing with an arma::vec
no longer works.
"funcA.cpp"
// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::interfaces(r, cpp)]]
#include <RcppArmadillo.h>
using namespace Rcpp;
// [[Rcpp::export]]
void funcA (arma::vec& x) {
arma::vec x_int = arma::vec(x.begin(), 3, false, false);
x(2) = 10 + x(2);
}
> vec <- c(1, 2, 3)
> funcA(vec)
> vec
[1] 1 2 13
"funcB.cpp"
// [[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadillo.h>
#include <packA.h>
using namespace Rcpp;
// [[Rcpp::export]]
void funcB(arma::vec& y) {
packA::funcA(y);
}
> vec <- c(1, 2, 3)
> funcB(vec)
> vec
[1] 1 2 3
Upvotes: 2
Views: 193
Reputation: 368181
I think that is a different topic. When you call A
, you create an R vector. That R vector is constructed with R memory, which R "own" and which we let Armadillo reuse. In-place is possible there.
But when you run B
, you construct an Armadillo vector not owned by R. That is not "our" memory in R, and the content only ever comes back via a copy. And you loose the in-place mod. Make that function have an arma::vec
signature, and pass an existing vector instead.
Upvotes: 1