【问题标题】:using C function from other package in Rcpp在 Rcpp 中使用其他包中的 C 函数
【发布时间】:2013-12-26 18:42:33
【问题描述】:

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

我试图重现的基本 R 示例是

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

我可以在this recipe from the gallery 之后从 Rcpp 调用这个 R 函数,但是在从 c/c++ 到 R 来回切换时会有一些性能损失。直接从 C++ 调用 C 函数似乎更明智。

C 例程 adapt_integrate 是从 cubature 导出的

 // 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 函数的示例。

【问题讨论】:

    标签: c++ c r rcpp


    【解决方案1】:

    不幸的是,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

    【讨论】:

    • 非常感谢您组装这些缺失的部分。不幸的是,我将不得不重新考虑这个问题,因为从我所看到的adapt_integrate 不会轻易接受我使用犰狳的数据结构定义的被积函数。为了完整起见,您能否添加一个最小的使用示例?
    • 它给你的是访问cubature注册的函数指针。我不知道你应该用 C 函数做什么......
    • 确实,considering an example of use 我看到了前面的麻烦:adapt_integrate_v 需要指向对象的指针,例如 *fdata,被积函数需要指针,例如 *fval,而我真正想要传递的参数是例如arma::colvec 对象。我认为我无法在两者之间架起一座桥梁。我可能不得不坚持使用 R 级接口,或者在 C++ 中实现我自己的 2D 求积。
    • 当然。我只是在回答如何调用这个函数。如果你想用其他数据类型调用它,你要么做一些数据转换工作,要么与cubature的维护者协商另一个接口。
    【解决方案2】:

    之前没看到这个问题,看来@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);                               
    }  
    

    连同R_registerRoutinesR_RegisterCCallable 的日常业务。

    RcppXts 中(在 Rcpp 模块中)作为

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

    效果很好。有人斥责我要更紧凑地写xts 方面(因为if NULL 是虚假的),我最终会得到......

    【讨论】:

    • 感谢您的指点,不幸的是,与使用较慢的 R 实现实际进行计算相比,在两段代码之间计算出适当的粘合会花费我更多的时间和痛苦。否则我会考虑直接链接到原始容积代码,而不是通过使用旧版本的 R 包。
    【解决方案3】:

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

    计算积分的例程基于 Thomas Hahn 的 Cuba 包,也可以在 CRAN 上的 R2Cuba 库中找到,因此如果您可以接受使用 Cubature 的函数而不是来自 Cubature 的函数 adaptIntegrate() 的 Cuba 例程,这个包可能会感兴趣.

    【讨论】:

    • 感谢您的指点。但是,最好将其保留为注释,因为问题不是专门关于集成,而是关于从另一个包访问 C 函数。我确实很欣赏这个链接,我最终使用了我自己的 cubature 副本,但这看起来是一个值得的选择(特别是如果一个人已经在使用 Eigen,但我已经习惯了犰狳)。不过,容积率的一个优势是能够处理向量值被积函数。
    猜你喜欢
    • 1970-01-01
    • 2021-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-13
    • 2011-07-12
    相关资源
    最近更新 更多