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

时间:2017-04-15 21:32:42

标签: c++ r rcpp

我正在阅读许多参考文献中的非常通用的建议,包括来自Rcpp主页和stackoverflow中的其他帖子的介绍,例如Calling an R function using inline and rcpp is still just as low as original R

我担心的是,当我们构建一个CRAN包时,应该在R中声明后验分布的评估(是的,我是贝叶斯)。主算法是用Rcpp编写的,NumericMatrix sampling(NumericVector x, Function func)。 我试过(1)简单地输入R函数和(2)定义一个带有cppFunction的对象来传递给cpp脚本。当然,它没有预期的性能差异。

所以我的主要问题应该是

  

如果用户提供了C / C ++中的表单,是否有其他方法可以将evaluting函数func作为输入参数传递给我们的通用Rcpp脚本?

我一直在努力解决这个问题很长一段时间 - 看看Rcpp画廊及其相关项目。由于我们的目标受众在编码方面的文化程度远低于我,因此我们希望指定一个函数不应该超过简单地编写内联函数。我们非常感谢任何建议。

1 个答案:

答案 0 :(得分:4)

我试图创建一个受RcppDE启发的例子。

首先我们定义一个C ++函数,它调用n次a&#34; sum&#34;函数作为参数传递。给定的函数可以是R函数或包含函数指针的xptr<> 代码:

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;
}
")

然后,在C ++中我们定义&#34; mySum&#34;函数和另一个函数返回xptr<>包装它 代码:

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));
}
")

最后,我们定义了一个函数,它计算C ++中的所有总和(即没有接收函数作为参数)。代码:

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;
  }
}

")

让我们测试在以下情况下会发生什么:

  • 测试1:我们称R函数(总和)为100万次
  • TEST 2:我们称Rcpp函数(mySum)为100万次
  • TEST 3:我们将{C}函数调用xptr<>包裹了100万次
  • 测试4:我们用C ++做所有事情(即我们用C ++计算总和100万次)

代码:

# 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

正如您所看到的,当我们将编译函数(即包含在R <-> C++中的函数指针)传递给C ++时,xptr<>转换开销消失了,实际上TEST 3和4基本相同性能