简体   繁体   English

从Rcpp调用R函数的替代方法

[英]Alternatives to calling an R function from Rcpp

I was reading up very generic advice from lots of references, including the very introduction from Rcpp homepage and other posts in stackoverflow, such as Calling an R function using inline and rcpp is still just as low as original R . 我从许多参考文献中获得了非常通用的建议,包括Rcpp主页的介绍以及stackoverflow中的其他帖子,例如使用内联和rcpp调用R函数仍然与原始R一样低

My concern is that as we are building a CRAN package, evaluation of a posterior distribution (yes, I'm Bayesian) should be declared in R. Main algorithm was written in Rcpp, NumericMatrix sampling(NumericVector x, Function func) . 我担心的是,在构建CRAN程序包时,应该在R中声明后验分布的评估(是,我是贝叶斯)。主要算法是用Rcpp编写的, NumericMatrix sampling(NumericVector x, Function func) I tried (1) simply inputting R function and (2) define an object with cppFunction to be passed into cpp script. 我尝试了(1)仅输入R函数,(2)使用cppFunction定义了一个要传递到cpp脚本中的对象。 It has, of course, no performance difference as expected. 当然,它没有预期的性能差异。

So my main question should be 所以我的主要问题应该是

Should there be other ways to pass an evaluting function func as an input argument to generic Rcpp script of ours if its form in C/C++ is provided by an user ? 如果以用户提供的C / C ++形式的Rcpp脚本形式,还有其他方法可以将评估函数func作为输入参数传递给我们的通用Rcpp脚本吗?

I've been struggling with this issue for quite a long time - looking through Rcpp gallery and its related projects. 我已经为这个问题苦苦挣扎了很长时间了-通过Rcpp画廊及其相关项目进行研究。 Since our target audience is much less literate in coding than I am, we hope specifying a function should not far exceed than simply writing an inline function. 由于我们的目标受众在编码方面的素养远不如我,因此我们希望指定函数的范围不应该超过编写内联函数的范围。 We would really appreciate any advice in advance. 我们非常感谢您提前提出任何建议。

I tried to create an example, inspired by RcppDE. 我尝试创建一个受RcppDE启发的示例。

First we define a C++ function which calls n-times a "sum" function passed as argument. 首先,我们定义一个C ++函数,该函数将n次调用作为参数传递的“ sum”函数。 The given function can be an R function or a xptr<> wrapping a function pointer. 给定的函数可以是R函数或包装函数指针的xptr<>
Code: 码:

require(Rcpp)

# C++ function which calls a given "sum" function n-times.
# The passed function can be an R function or 
# an xptr wrapping a function pointer.
sourceCpp(code="
#include <Rcpp.h>

typedef double (*sumFnPtr)(Rcpp::NumericVector);

// [[Rcpp::export]]
Rcpp::NumericVector callSumFunctionNTimes(SEXP sumFn, Rcpp::NumericVector toSum,int times){
  Rcpp::NumericVector output(times);
  switch (TYPEOF(sumFn)){ 
    case EXTPTRSXP:
    {
      Rcpp::XPtr<sumFnPtr> xptr = Rcpp::as< Rcpp::XPtr<sumFnPtr> >(sumFn);
      for(int i = 0; i < times; i++){
        output[i] = (*(xptr))(toSum);
      }
      break;
    }
    // we suppose is a R function
    default: 
    {
      Rcpp::Function fn = Rcpp::as<Rcpp::Function>(sumFn);
      for(int i = 0; i < times; i++)
        output[i] = Rcpp::as<double>( fn(toSum) );
      break;
    }
  }
  return output;
}
")

Then, in C++ we define "mySum" function and another function returning a xptr<> wrapping it. 然后,在C ++中,我们定义“ mySum”函数和另一个返回包装xptr<>函数。
Code : 代码:

require(Rcpp)

# Here we define the sum function in C++ and we also 
# define a function returning a xptr wrapping the function
sourceCpp(code="
#include <Rcpp.h>

typedef double (*sumFnPtr)(Rcpp::NumericVector);

// [[Rcpp::export]]
double mySum(Rcpp::NumericVector toSum){
  double s = 0;
  for(int i = 0; i < toSum.length(); i++){
    s += toSum[i];
  }
  return s;
}

// [[Rcpp::export]]
SEXP getSumFunctionPtr(){
  return Rcpp::XPtr<sumFnPtr>(new sumFnPtr(&mySum));
}
")

Finally, we define a function which computes all the sums in C++ (ie without receiving the function as argument). 最后,我们定义一个函数,该函数计算C ++中的所有总和(即不接收该函数作为参数)。 Code : 代码:

require(Rcpp)

sourceCpp(code="
#include <Rcpp.h>

// [[Rcpp::export]]
Rcpp::NumericVector doEverythingInCpp(Rcpp::NumericVector toSum, int times){
  Rcpp::NumericVector output(times);
  for(int i = 0; i < times; i++){
    double s = 0;
    for(int j =0; j < toSum.length();j++){
      s += toSum[j];
    }
    output[i] = s;
  }
}

")

Let's test what happens when : 让我们测试一下在以下情况下会发生什么:

  • TEST 1 : we call an R function (sum) 1 million times 测试1:我们称R函数(总和)为一百万次
  • TEST 2 : we call an Rcpp function (mySum) 1 million times 测试2:我们将Rcpp函数(mySum)调用一百万次
  • TEST 3 : we call an Rcpp function wrapped in xptr<> 1 million times 测试3:我们调用包装在xptr<>一百万次中的Rcpp函数
  • TEST 4 : we do everything in C++ (ie we compute the sum 1 million times in C++) 测试4:我们用C ++做所有事情(即,我们用C ++计算一百万次)

Code: 码:

# TEST 1
system.time(callSumFunctionNTimes(sum,1:100,1e6))
#  user  system elapsed 
# 13.45    0.00   13.45 

# TEST 2
system.time(callSumFunctionNTimes(mySum,1:100,1e6))
#  user  system elapsed 
# 13.97    0.00   13.97

# TEST 3
mySumFunctionnPtr <- getSumFunctionPtr()
system.time(callSumFunctionNTimes(mySumFunctionnPtr,1:100,1e6))
# user  system elapsed 
# 0.28    0.00    0.29

# TEST 4
system.time(doEverythingInCpp(1:100,1e6))
# user  system elapsed 
# 0.27    0.00    0.27

As you can see the R <-> C++ transition overhead disappears when we pass a compiled function (ie the function pointer wrapped in an xptr<> ) to C++, in fact the TEST 3 and 4 have basically the same performance. 正如您所看到的,当我们将编译后的函数(即包装在xptr<>的函数指针)传递给C ++时, R <-> C++转换开销消失了,实际上TEST 3和TEST 4具有基本相同的性能。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM