使用Rcpp中其他包中的C函数

using C function from other package in Rcpp

本文关键字:函数 包中 其他 Rcpp 使用      更新时间:2023-10-16

我正试图从C++函数中的cubature包中调用一个C例程来执行多维集成。

我试图复制的基本R示例是

library(cubature)
integrand <- function(x) sin(x)
adaptIntegrate(integrand, 0, pi)

我可以按照库中的这个配方从Rcpp调用这个R函数,但从c/c++到R来回切换会有一些性能损失。从c++直接调用c函数似乎更明智。

使用从cubature导出C例程adapt_integrate

 // R_RegisterCCallable("cubature", "adapt_integrate", (DL_FUNC) adapt_integrate);

然而,我不明白如何从c++中调用它。这是我拙劣的尝试,

sourceCpp(code = '
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
double integrand(double x){
 return(sin(x));
}
// [[Rcpp::depends(cubature)]]
// [[Rcpp::export]]
Rcpp::List integratecpp(double llim, double ulim)
{
  Rcpp::Function p_cubature = R_GetCCallable("cubature", "adapt_integrate");
  Rcpp::List result = p_cubature(integrand, llim, ulim);
  return(result);
}
'
)
integratecpp(0, pi)

这无法编译;很明显,我正在做一些非常愚蠢的事情,并且错过了将R_GetCCallable的输出转换为Rcpp::Function(或者直接调用它?)的一些重要步骤。我读过几篇关于函数指针的相关文章,但还没有看到使用外部C函数的例子。

不幸的是,cubature没有在inst/include中提供标头,因此您必须借用它们,并在代码中执行类似操作:

typedef void (*integrand) (unsigned ndim, const double *x, void *,
           unsigned fdim, double *fval);
int adapt_integrate(
    unsigned fdim, integrand f, void *fdata,
    unsigned dim, const double *xmin, const double *xmax, 
    unsigned maxEval, double reqAbsError, double reqRelError, 
    double *val, double *err)
{
    typedef int (*Fun)(unsigned,integrand,void*,unsigned,
        const double*,const double*, unsigned, double, double, double*, double*) ;
    Fun fun = (Fun) R_GetCCallable( "cubature", "adapt_integrate" ) ;           
    return fun(fdim,f,fdata,dim,xmin,xmax,maxEval,reqAbsError, reqRelError,val,err); 
}

cubature的维护者协商,他在inst/include中发布声明,这样您就只需要使用LinkingTo,这可能是一个好主意。

之前没有看到这个问题,看起来@Romain解决了这个问题。

为了完整起见,xtsRcppXts包提供了一个在各方合作时如何做到这一点的工作示例。在xts中,我们在(源)文件inst/include/xtsAPI.h:中这样做(针对大约十个函数)

SEXP attribute_hidden xtsLag(SEXP x, SEXP k, SEXP pad) {     
    static SEXP(*fun)(SEXP,SEXP,SEXP) = NULL;         
    if (fun == NULL)                                  
        fun = (SEXP(*)(SEXP,SEXP,SEXP)) R_GetCCallable("xts","lagXts");   
    return fun(x, k, pad);                               
}  

以及CCD_ 14和CCD_。

RcppXts中,这被作为(在Rcpp模块中)拾取

function("xtsLag", 
         &xtsLag,    
         List::create(Named("x"), Named("k"), Named("pad")),   
         "Extract the coredata from xts object");

这非常有效。有人斥责我把xts写得更紧凑(因为if NULL是假的),我会得到。。。最后

这个问题已经存在三年了,但我想指出的是,既然RcppNumerical库可用,与Rcpp的多维集成可能会更容易:https://github.com/yixuan/RcppNumerical

计算积分的例程基于Thomas Hahn的Cuba包,也可以在CRAN的R2Cuba库中找到,所以如果你可以接受在Cubature的函数adaptIntegrate()上使用Cuba例程,这个包可能会很有趣。