Passing an R function as a parameter to an RCpp function

I am trying to run something like

R

my_r_function <- function(input_a) {return(input_a**3)}
RunFunction(c(1,2,3), my_r_function)

      

CPP

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
NumericVector RunFunction(NumericVector a, Function func)
{
  NumericVector b = NumericVector(a.size());
  for(int i=0; i<a.size(); i++)
    b[i] = func(a[i]);
  return b;
}

      

How can I make "Function func" actually work in Rcpp?

PS I understand there are ways to do this without Rcpp (applicable for this example), but I'm just using that as an example to demonstrate what I'm looking for.

+3


source to share


2 answers


You should be able to use the example in the link above to get your code to work; but you should also take note of Dirk's warning,

The function call is simple and tempting. It is also slow as it comes with overhead. And calling it repeatedly from within your C ++ code, possibly buried in multiple loops, is downright silly.

which can be demonstrated by slightly modifying the above code and comparing the two versions:

#include <Rcpp.h>

// [[Rcpp::export]]
Rcpp::NumericVector RunFunction(Rcpp::NumericVector a, Rcpp::Function func)
{
  Rcpp::NumericVector b = func(a);
  return b;
}

// [[Rcpp::export]]
Rcpp::NumericVector RunFunction2(Rcpp::NumericVector a, Rcpp::Function func)
{
  Rcpp::NumericVector b(a.size());
  for(int i = 0; i < a.size(); i++){
    b[i] = Rcpp::as<double>(func(a[i]));
  }
  return b;
}

/*** R
my_r_function <- function(input_a) {return(input_a**3)}
x <- 1:10
##
RunFunction(x,my_r_function)

RunFunction2(x,my_r_function)
##
library(microbenchmark)
microbenchmark(
  RunFunction(rep(1:10,10),my_r_function),
  RunFunction2(rep(1:10,10),my_r_function))

Unit: microseconds
                                       expr     min       lq       mean   median       uq      max neval
  RunFunction(rep(1:10, 10), my_r_function)  21.390  22.9985   25.74988  24.0840   26.464   43.722   100
 RunFunction2(rep(1:10, 10), my_r_function) 843.864 903.0025 1048.13175 951.2405 1057.899 2387.550   100

*/

      

Note that it RunFunction

is 40x faster than RunFunction2

: in the former, we only take overhead when called func

from C ++ code once, whereas in the latter case, we have to do an exchange for each element of the input vector. If you try to run this on longer vectors, I'm sure you will see significantly worse performance from RunFunction2

relatively RunFunction

. So, if you are going to call R functions from inside your C ++ code, you should try to use R-native vectorization (if possible) rather than making R function calls repeatedly in a loop, at least for fairly simple computations such as x**3

...



Also, if you are wondering why your code was not compiling, it was because of this line:

b[i] = func(a[i]);

      

You probably got the error

cannot convert 'SEXP to' Rcpp :: traits :: storage_type <14> :: type {aka double} in assignment

which I resolved by wrapping the return value func(a[i])

in the Rcpp::as<double>()

above. However, this is clearly not worth it because you end up with a much slower function.

+7


source


You can use 'transform ()' and avoid using loops! Try the following code:



List RunFunction(List input, Function f) {

    List output(input.size());

    std::transform(input.begin(), input.end(), output.begin(), f);
    output.names() = input.names();
}

      

0


source







All Articles