首页 > 解决方案 > RInside - 包装 C++ 函数以在 R 函数中使用

问题描述

我希望在使用 RInside 的 C++ 程序中使用 R 库 cmaes(协方差矩阵适应进化策略)。

https://www.rdocumentation.org/packages/cmaes/versions/1.0-11/topics/cma_es

有相同算法(libcmaes)的 C++ 实现,但处理约束的方式(这不是算法的固有部分)与 R 实现不同。我以前没有使用过 RInside,所以我使用与库一起分发的示例作为参考点:

https://github.com/eddelbuettel/rinside/tree/master/inst/examples/standard

作为一个最小的例子,我试图集成到 C++ 中的 R 脚本如下所示:

library(cmaes)

seednum<-100
set.seed(seednum, kind="Mersenne-Twister")

ctl_list[["stop.tolx"]]<-0.001

initpar<-c(7.488549, 3.403088, 7.773092, 4.331335, 1.881067)

objfun<-function(pop){

  val<-0

  for (element in pop)
  {
    val<-val+(element*element)
  }

  val
}

res<-cma_es(initpar, objfun, lower=-10, upper=10, control=ctl_list)

print(res)

我面临的问题是我的目标函数(它是 cma_es 的函数参数)是用 C++ 编写的(出于性能原因必须保留在 C++ 中),因此它必须以 R 函数接受它的方式包装. 我在示例中看不到任何东西来实现这样的事情。到目前为止,我拥有的 C++ 代码如下:

#include <RInside.h>            // for the embedded R via RInside

double objfun (std::vector<double> x)
{
   double val = 0.0;

   for (unsigned i = 0; i < x.size(); i++)
      val += x[i]*x[i];

   return val;
}

int main(int argc, char *argv[])
{
   try
   {
      RInside R(argc, argv);        // create an embedded R instance 

      std::string load_str = "suppressMessages(library(cmaes))";
      R.parseEvalQ(load_str);       // load library, no return value

      std::vector<double> initpar = {7.480042, 2.880649, 8.380858, 4.620689, 1.910938};

      R["initpar"] = initpar;       // or R.assign(initpar, "initpar");

      std::string seed_str = "seednum<-100; set.seed(seednum, kind='Mersenne-Twister')";

      R.parseEval(seed_str);            // Parse and evaluate, nothing to return

      std::string list = "ctl_list<-list()";

      R.parseEval(list);

      R.parseEvalQ("ctl_list[['stop.tolx']]<-0.001");

      std::string cmd = "cma_es(initpar, objfun, lower=-10, upper=10, control=ctl_list)";

      Rcpp::CharacterVector res = R.parseEval(cmd); // parse, eval + return result

      for (int i = 0; i < res.size(); i++)  // loop over vector and output
      {
         std::cout << res[i];
      }
      std::cout << std::endl;

   }
   catch(std::exception& ex)
   {
      std::cerr << "Exception caught: " << ex.what() << std::endl;
   }
   catch(...)
   {
      std::cerr << "Unknown exception caught" << std::endl;
   }

    exit(0);
}

如果使用 Rcpp 将 C++ 函数传递给 R,则将// [[Rcpp::export]]使用它来传递它,但此处不适用。以上显然无法执行,并出现以下错误:

Error in FUN(newX[, i], ...) : object 'objfun' not found
Exception caught: Error evaluating: cma_es(initpar, objfun, lower=-10, upper=10, control=ctl_list)

所以问题很简单,我如何使用 RInside 包装 C++ 函数,使其可以传递给 R 函数?

标签: c++rrinside

解决方案


推荐阅读