使用全局SEXP存储XPtr会产生垃圾值

时间:2018-04-02 16:25:00

标签: r rcpp r-package

我正在构建一个使用CVODE C例程(SUNDIALS C库的一部分)解决常微分方程(ODE)的包。

如果用户提供计算衍生工具并具有以下形式的函数

,则该包可用
#include <Rcpp.h>
using namespace Rcpp;

#include <cvode/cvode.h>               /* prototypes for CVODE fcts., consts. */
#include <nvector/nvector_serial.h>    /* serial N_Vector types, fcts., macros */

int test (realtype t, N_Vector y, N_Vector ydot, void *user_data){

  // test function
  NV_Ith_S(ydot,0) = 1*NV_Ith_S(y,0);
  NV_Ith_S(ydot,1) = 2*NV_Ith_S(y,1);
  NV_Ith_S(ydot,2) = 3*NV_Ith_S(y,2);

  return(0);

} 

typedef int (*funcPtr)(realtype t, N_Vector y, N_Vector ydot, void *user_data);

// [[Rcpp::export]]
XPtr<funcPtr> putFunPtrInXPtr() {

  // return(XPtr<funcPtr> (new funcPtr(&test)));
  XPtr<funcPtr> testptr(new funcPtr(&test), false);
  return testptr;

my_fun <- putFunPtrInXPtr()中形成一个函数指针,即Rmy_fun从包cvode输入cvode提供my_fun函数} SEXP,请参阅代码here)。 此作品,即提供正确的结果(请参阅详细说明here)。但是,这需要用户在其系统上安装SUNDIALS(以访问cvode.hnvector_serial.h)。

我正在尝试制作包,因此用户无需安装SUNDIALS。因此,获得导数(和生成函数指针)的函数将如下所示

#include <Rcpp.h>
using namespace Rcpp;

//---------------------------------------------------------------------------------
typedef NumericVector (*funcPtr1) (double t, NumericVector y, NumericVector ydot);
//---------------------------------------------------------------------------------

// [[Rcpp::export]]
NumericVector test1 (double t, NumericVector y, NumericVector ydot){

  ydot[0] = 1 * y[0];
  ydot[1] = 2 * y[1];
  ydot[2] = 3 * y[2];

  return ydot;

}

// [[Rcpp::export]]
XPtr<funcPtr1> putFunPtrInXPtr1() {

    XPtr<funcPtr1> testptr1(new funcPtr1(&test1), false);
    return testptr1;

}

在R方面,my_fun1 <- putFunPtrInXPtr1()将被运行,my_fun1将被提供给cvode_test(包中定义的测试函数,以便能够处理使用{{1}定义的派生函数只有。

在我的包中将函数指针类型从NumericVector转换为XPtr<funcPtr1>,我执行以下操作

1)全局XPtr<funcPtr>SEXP)在任何函数之外定义  2)在sexp_g中,输入cvode_test已分配给SEXP  3)最后,函数sexp_g定义如下,将fun_test1转换为N_Vector,使用NumericVector中的函数获取导数,然后将它们重新放入{ {1}},即

sexp_g

最后,在N_Vector中,此typedef int (*funcPtr_test)(double time, NumericVector y, NumericVector ydot); SEXP sexp_g; // declare a global SEXP int fun_test1(realtype t, N_Vector y, N_Vector ydot, void* user_data){ // convert y to NumericVector y1 int y_len = NV_LENGTH_S(y); NumericVector y1(y_len); // filled with zeros for (int i = 0; i < y_len; i++){ y1[i] = NV_Ith_S(y,i); } // use function pointer to get the derivatives XPtr<funcPtr_test> xpfun(sexp_g); funcPtr_test fun_test = *xpfun; NumericVector ydot1(y1.length()); ydot1 = fun_test(t, y1, ydot1); // convert ydot1 to N_Vector ydot // N_Vector ydot; ydot = NULL; ydot = N_VNew_Serial(ydot1.length()); for (int i = 0; i<ydot1.length(); i++){ NV_Ith_S(ydot, i) = ydot1[i]; } return (0); } 的使用方法如下

cvode_test

这也可以编译,但问题是当我向fun_test1提供flag = CVodeInit(cvode_mem, fun_test1, T0, y0); (即指向my_fun1)以进行集成时,我得到了垃圾值。我不确定这里出了什么问题,我已经阅读了一些关于保护test1的文章(即一个here),但我不知道如何在这里实现它。

有关此处出现问题的任何帮助,以及是否有比全局cvode_test变量更好的方法会有所帮助。由于SEXP 的rhs函数必须具有以下签名

SEXP

我发现不可能使用不同的签名(使用CVOdeInit)从包外定义的函数中插入上面定义的函数中的信息,除了使用全局变量并且一直在努力问题很长一段时间。任何帮助将不胜感激!

我没有尝试过的另一种方法是1)在任何函数之外声明int RHS_function (N_Vector, N_Vector, void*);,2)在SEXP内展开XPtr<funPtr_test>SEXP并将其分配给在函数外声明的指针。但我正在努力使用语法来声明类型为XPtr<funcPtr_test>的函数指针。

可以找到cvode_testXPtr<funcPtr_test>的完整代码here

由于

0 个答案:

没有答案