Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing R Function as Parameter to RCpp Function

Tags:

c++

function

r

rcpp

I'm 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 would I make "Function func" actually work in Rcpp?

P.S. I understand there are ways to do this without Rcpp (apply comes to mind for this example) but I'm just using this as an example to demonstrate what I'm looking for.

like image 668
Coat Avatar asked Dec 10 '14 00:12

Coat


People also ask

How to call r Function in Rcpp?

Using the Function class, you can call R functions from Rcpp. The argument given to the R function is determined based on position and name. Use Named() or _[] to pass a value to an argument by specifying argument name. Name() can be used in two ways: Named("argument_name", value) or Named("argument_name") = value .

Why use Rcpp?

The 'Rcpp' package provides R functions as well as C++ classes which offer a seamless integration of R and C++. Many R data types and objects can be mapped back and forth to C++ equivalents which facilitates both writing of new code as well as easier integration of third-party libraries.


1 Answers

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

Calling a function is simple and tempting. It is also slow as there are overheads involved. And calling it repeatedly from inside your C++ code, possibly buried within several loops, is outright silly.

which can be demonstrated by modifying your above code slightly and benchmarking 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

*/

Notice that RunFunction is ~40x faster than RunFunction2: in the former we only incur the overhead of calling func from inside the C++ code once, whereas in the latter case we have to make the exchange for each element of the input vector. If you tried running this on even longer vectors, I'm sure you would see a substantially worse performance from RunFunction2 relative to RunFunction. So, if you are going to be calling R functions from inside of your C++ code, you should try to take advantage of R's native vectorization (if possible) rather than repeatedly making calls to the R function in a loop, at least for reasonably simple calculations like x**3.

Also, if you were wondering why your code wasn't compiling, it was because of this line:

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

You were presumably getting the error

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

which I resolved by wrapping the return value of func(a[i]) in Rcpp::as<double>() above. However, this clearly isn't worth the trouble because you end up with a much slower function overall anyhow.

like image 185
nrussell Avatar answered Oct 22 '22 09:10

nrussell