使用 Xptr 和 Function 调用 Rcpp 函数 - 仅适用于 xptr 案例 [英] Calling Rcpp function with Xptr and Function - only xptr case works

查看:48
本文介绍了使用 Xptr 和 Function 调用 Rcpp 函数 - 仅适用于 xptr 案例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试开发一个包,我需要在其中输入用户的函数(可以使用 Rcpp 或在 R 中定义),将其发送到另一个函数(在包内)在 struct 中并在那里处理它.

当我使用 Rcpp::Xptr(即函数指针)时,代码有效,但同样不适用于 Rcpp::Function.为用户使用 Rcpp::Function 的好处是他们可以在 R 中定义函数(尽管会损失很多性能增益).>

首先是什么:

#include 使用命名空间 Rcpp;//定义结构结构 xptr_data{SEXP xptr;};//一个最小函数(用户定义)//[[Rcpp::export]]NumericVector timesTwo(NumericVector x) {返回 x * 2;}//指向已定义函数的指针typedef NumericVector (*funcPtr) (NumericVector y);//[[Rcpp::export]]XPtr<funcPtr>putFunPtrInXPtr() {XPtr<funcPtr>rhs_ptr(new funcPtr(&timesTwo), false);返回 rhs_ptr;}//这个函数会在包里NumericVector call_by_xptr_struct(NumericVector y, void* user_data){struct xptr_data *my_rhs_ptr = (struct xptr_data*)user_data;SEXP xpsexp = (*my_rhs_ptr).xptr;//使用函数指针获取导数XPtr<funcPtr>rhs_xptr(xpsexp);funcPtr rhs_fun = *rhs_xptr;//使用函数计算 RHS 的值 ----返回(rhs_fun(y));}//使用 xptr 来评估函数 - 这将被导出//从包//[[Rcpp::export]]NumericVector xptr_call_struct(NumericVector y, SEXP xpsexp){struct xptr_data my_xptr = {NULL};my_xptr.xptr = xpsexp;返回 call_by_xptr_struct(y, (void*)&my_xptr);}/*** Rrhs_ptr <- putFunPtrInXPtr()xptr_call_struct(c(1,2), rhs_ptr)[1] 2 4*/

什么不起作用,

如果函数是在 R 中定义的,而我直接使用 Rcpp::Function,它会导致整个 R 会话崩溃,

#include 使用命名空间 Rcpp;//定义基于函数的结构结构函数数据{函数 func;};//处理输入函数NumericVector call_by_func_struct(NumericVector y, void* user_data){struct func_data *my_rhs_fun = (struct func_data*)user_data;函数 func = (*my_rhs_fun).func;返回(功能(y));}//这将从包中导出//[[Rcpp::export]]NumericVector func_call_struct(NumericVector y, 函数函数){struct func_data my_func = {NULL};my_func.func = func;return call_by_func_struct(y, (void*)&my_func);}/*** RtimesThree <- 函数(y){y <- 3 * y是}*/

上面的代码编译得很好,但是当我调用函数 func_call_struct(c(1,2), timesThree)) 时,它会导致整个 R 会话崩溃.

任何关于 R 崩溃的原因以及如何输入 R 中定义的函数的指导都会非常有帮助.

此外,有没有办法传递Rcpp(例如上面的timesTwo)中定义的输入函数,而不是它们的Xptr.我认为在不牺牲 Rcpp 带来的速度的情况下,这对最终用户来说会稍微减少一些混乱(因为他们不必生成函数指针).

解决方案

如果您使用可用的Function初始化结构:

<代码>[...]//这将从包中导出//[[Rcpp::export]]NumericVector func_call_struct(NumericVector y, 函数函数){struct func_data my_func = {func};return call_by_func_struct(y, (void*)&my_func);}

至于您的附加问题:我看不到在不使用外部指针的情况下在 R 中存储 C++ 函数指针的可能性.你不能提供一个从函数指针创建外部指针的辅助函数(可能是 wrap())吗?一些类似的东西:

#include 使用命名空间 Rcpp;//定义结构结构 xptr_data{SEXP xptr;};//指向已定义函数的指针typedef NumericVector (*funcPtr) (NumericVector y);//这个函数会在包里NumericVector call_by_xptr_struct(NumericVector y, void* user_data){struct xptr_data *my_rhs_ptr = (struct xptr_data*)user_data;SEXP xpsexp = (*my_rhs_ptr).xptr;//使用函数指针获取导数XPtr<funcPtr>rhs_xptr(xpsexp);funcPtr rhs_fun = *rhs_xptr;//使用函数计算 RHS 的值 ----返回(rhs_fun(y));}//使用 xptr 来评估函数 - 这将被导出//从包//[[Rcpp::export]]NumericVector xptr_call_struct(NumericVector y, SEXP xpsexp){struct xptr_data my_xptr = {xpsexp};返回 call_by_xptr_struct(y, (void*)&my_xptr);}//包中的函数,只有 C++ APIXPtr<funcPtr>wrapFunPtr(funcPtr& f) {XPtr<funcPtr>rhs_ptr(&f, false);返回 rhs_ptr;}//用户自定义函数NumericVector timesTwo(NumericVector x) {返回 x * 2;}//[[Rcpp::export]]XPtr<funcPtr>putFunPtrInXPtr() {静态 funcPtr f = &timesTwo;返回 wrapFunPtr(f);}/*** Rrhs_ptr <- putFunPtrInXPtr()xptr_call_struct(c(1,2), rhs_ptr)*/

用户将提供最后两个函数.使用 C++11,这可以简化如下:

//[[Rcpp::export]]XPtr<funcPtr>putFunPtrInXPtr() {静态 funcPtr timesTwo{ [](NumericVector x) ->NumericVector { 返回 x * 2;} };返回 wrapFunPtr(timesTwo);}

虽然在这种情况下使用可能就足够了

//[[Rcpp::export]]XPtr<funcPtr>putFunPtrInXPtr() {静态 funcPtr timesTwo{ [](NumericVector x) ->NumericVector { 返回 x * 2;} };XPtr<funcPtr>rhs_ptr(timesTwo, false);返回 rhs_ptr;}

不需要包中的 wrapFunPtr.用户必须提供一个函数,其中包括一些样板代码以及 lambda 表达式中的实际肉".

I am trying to develop a package in which I need to input a function from user (could be defined using Rcpp or in R), send it to another function (within the package) in a struct and process it there.

When I use Rcpp::Xptr (i.e., function pointer) the code works, but the same does not work with Rcpp::Function. The advantage with using Rcpp::Function for the user would be that they would be able to define the function in R (although lose a lot of performance gain).

First what works:

#include <Rcpp.h>
using namespace Rcpp;

// define the structure
struct xptr_data{
  SEXP xptr;
};

// a minimal function (user-defined)
// [[Rcpp::export]]
NumericVector timesTwo(NumericVector x) {
  return x * 2;
}

// pointer to function defined
typedef NumericVector (*funcPtr) (NumericVector y);

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

  XPtr<funcPtr> rhs_ptr(new funcPtr(&timesTwo), false); 
  return rhs_ptr;
}

// this function will be in the package
NumericVector call_by_xptr_struct(NumericVector y, void* user_data){

  struct xptr_data *my_rhs_ptr = (struct xptr_data*)user_data;
  SEXP xpsexp = (*my_rhs_ptr).xptr;

  // use function pointer to get the derivatives
  XPtr<funcPtr> rhs_xptr(xpsexp);
  funcPtr rhs_fun = *rhs_xptr;

  // use the function to calculate value of RHS ----
  return(rhs_fun(y));
}


// using xptr to evaluate function - this will be exported
// from the package
//[[Rcpp::export]]
NumericVector xptr_call_struct(NumericVector y, SEXP xpsexp){

  struct xptr_data my_xptr = {NULL};

  my_xptr.xptr = xpsexp;
  return call_by_xptr_struct(y, (void*)&my_xptr);
}

/*** R    
rhs_ptr <- putFunPtrInXPtr()

xptr_call_struct(c(1,2), rhs_ptr)
[1] 2 4
*/ 

What doesn't work,

If the function is defined in R and I use Rcpp::Function directly, it crashes the entire R session,

#include <Rcpp.h>
using namespace Rcpp;

// define the function based structure
struct func_data{
  Function func;
};

// processes the input function 
NumericVector call_by_func_struct(NumericVector y, void* user_data){

  struct func_data *my_rhs_fun = (struct func_data*)user_data;
  Function func = (*my_rhs_fun).func;

  return(func(y));
}

// this will be exported from the package
//[[Rcpp::export]]
NumericVector func_call_struct(NumericVector y, Function func){

  struct func_data my_func = {NULL};

  my_func.func = func;
  return call_by_func_struct(y, (void*)&my_func);
}

/*** R
timesThree <- function(y){

  y <- 3 * y
  y
}

*/

The code above compiles fine, but when I call the function func_call_struct(c(1,2), timesThree)), it crashes entire R session.

Any guidance regarding why R is crashing and how to input functions defined in R would be very helpful.

Additionally, is there any way to pass input functions defined in Rcpp (e.g., timesTwo above) and not their Xptr. I am thinking that would be slightly less confusing for the end-user (as they won't have to generate a function pointer) without sacrificing the speed that comes with Rcpp.

解决方案

It works if you initialize the struct using the available Function:

[...]
// this will be exported from the package
//[[Rcpp::export]]
NumericVector func_call_struct(NumericVector y, Function func){

  struct func_data my_func = {func};
  return call_by_func_struct(y, (void*)&my_func);
}

As for your additional question: I do not see a possibility to store a C++ function pointer within R without using an external pointer. Can't you provide a helper function (possibly as wrap()) that creates the external pointer from the function pointer? Something along these lines:

#include <Rcpp.h>
using namespace Rcpp;

// define the structure
struct xptr_data{
  SEXP xptr;
};

// pointer to function defined
typedef NumericVector (*funcPtr) (NumericVector y);


// this function will be in the package
NumericVector call_by_xptr_struct(NumericVector y, void* user_data){

  struct xptr_data *my_rhs_ptr = (struct xptr_data*)user_data;
  SEXP xpsexp = (*my_rhs_ptr).xptr;

  // use function pointer to get the derivatives
  XPtr<funcPtr> rhs_xptr(xpsexp);
  funcPtr rhs_fun = *rhs_xptr;

  // use the function to calculate value of RHS ----
  return(rhs_fun(y));
}


// using xptr to evaluate function - this will be exported
// from the package
//[[Rcpp::export]]
NumericVector xptr_call_struct(NumericVector y, SEXP xpsexp){

  struct xptr_data my_xptr = {xpsexp};
  return call_by_xptr_struct(y, (void*)&my_xptr);
}


// function in package with only C++ API
XPtr<funcPtr> wrapFunPtr(funcPtr& f) {
  XPtr<funcPtr> rhs_ptr(&f, false); 
  return rhs_ptr;
}



// user-defined functions
NumericVector timesTwo(NumericVector x) {
  return x * 2;
}

// [[Rcpp::export]]
XPtr<funcPtr> putFunPtrInXPtr() {
  static funcPtr f = &timesTwo;
  return wrapFunPtr(f);
}



/*** R    
rhs_ptr <- putFunPtrInXPtr()

xptr_call_struct(c(1,2), rhs_ptr)
*/ 

The user would supply the last two functions. With C++11 this could be simplified like this:

// [[Rcpp::export]]
XPtr<funcPtr> putFunPtrInXPtr() {
  static funcPtr timesTwo{ [](NumericVector x) -> NumericVector { return x * 2; } };
  return wrapFunPtr(timesTwo); 
}

Although in this case it might be sufficient to use

// [[Rcpp::export]]
XPtr<funcPtr> putFunPtrInXPtr() {
  static funcPtr timesTwo{ [](NumericVector x) -> NumericVector { return x * 2; } };
  XPtr<funcPtr> rhs_ptr(timesTwo, false); 
  return rhs_ptr;
}

without the need for wrapFunPtr in the package. The user has to supply one function, which includes some boiler-plate code plus the actual "meat" within the lambda expression.

这篇关于使用 Xptr 和 Function 调用 Rcpp 函数 - 仅适用于 xptr 案例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆