RcppEigen - 从内联到包中的.cpp函数和" Map"

时间:2014-12-15 18:28:39

标签: c++ r matrix eigen rcpp

似乎所有内容都在我的软件包中运行,但是我想检查一下使用" Map"来确定使用它的步骤是否正确以及内存使用情况。 (这是一个简单的例子,介于内联示例和fastLm()示例之间。)

这是一个内联函数,它在矩阵的每一列上取最大值:

library(Rcpp); 
library(inline); 
library(RcppEigen);

maxOverColCpp <- '
    using Eigen::Map;
    using Eigen::MatrixXd;

   // Map the double matrix AA from R
   const Map<MatrixXd> A(as<Map<MatrixXd> >(AA));

   // evaluate and columnwise maximum entry of A
   const MatrixXd Amax(A.colwise().maxCoeff());
   return wrap(Amax);
'

rcppeigen_max_over_columns <- cxxfunction(signature(AA = "matrix"), maxOverColCpp, plugin = "RcppEigen")

然后要更改函数以将其包含在现有的R包中,我重写了如下代码,将其保存在rcppeigen_max_over_columns.cpp中的现有R包中的新src文件夹中:

// we only include RcppEigen.h which pulls Rcpp.h in for us
#include <RcppEigen.h>

// via the depends attribute we tell Rcpp to create hooks for
// RcppEigen so that the build process will know what to do
//
// [[Rcpp::depends(RcppEigen)]]

// via the exports attribute we tell Rcpp to make this function
// available from R
//
// [[Rcpp::export]]
Eigen::MatrixXd rcppeigen_max_over_columns(const Eigen::MatrixXd & A){
    Eigen::MatrixXd Amax = A.colwise().maxCoeff();
    return Amax;
}

(实际上它有点长,因为我还需要包括在行上找到最大值。)

然后:

  • 使用以下行修改DESCRIPTION FILE:

    进口:Rcpp(&gt; = 0.11.3),RcppEigen(&gt; = 0.3.2.2.0)

    LinkingTo:Rcpp,RcppEigen

  • 使用以下行修改了NAMESPACE文件:

    useDynLib(toyRpackage)

    import(RcppEigen)

    importFrom(Rcpp,evalCpp)

  • 终端输入
  • ,我假设它粘合了R和C ++:

    Rcpp :: compileAttributes(pkgdir =&#34; toyRpackage&#34;,verbose = getOption(&#34; verbose&#34;))

然后,就普通包而言,我做了R CMD checkR CMD build

  • 第一个问题是将RcppEigen函数包含到现有R包中的过程是否正确? (我完全忽略了所有Makevars个文件或任何.h个文件 - 我真的不知道他们做了什么...也不太了解NAMESPACE文件的更改。我试图复制RcppEigen.package.skeleteon()设置,但是我将我的功能添加到现有的包中。所以如果我错过了以后可能会出现问题的话,那就好了。 )

  • 第二个问题是我是否需要一个&#34; Map&#34; rcppeigen_max_over_columns.cpp中的某个地方,以便矩阵在从R传递到C ++时不被复制?

我知道这是一个初学者问题,但我在理解.cpp文件中的语法方面遇到了一些麻烦,因为我不知道任何C ++。我想也许这个问题可能会帮助那些也试图在他们的包中添加一个简单功能的人。 :)

另外,如果您对使用RcppEigen而不是RcppArmadillo有任何强烈的感受,请告诉我。我读了http://thread.gmane.org/gmane.comp.lang.r.rcpp/3522这很有用。对于我采用max over columns的例子,RcppEigen看起来要快得多,不知道为什么。

2 个答案:

答案 0 :(得分:2)

  

第一个问题是将RcppEigen函数包含到现有R包中的过程是否正确? (我完全忽略了任何Makevars文件或任何.h文件 - 我真的不知道他们做了什么......也没有真正了解NAMESPACE文件的变化。我试图复制RcppEigen。 package.skeleteon()设置,但是我将我的函数添加到现有的包中。所以如果我错过了以后可能会出现问题的话,那将是好的。)

对于具有相对简单的C ++代码的基本R包,您不需要包含头文件,或自定义Makevars / Makefile或类似的东西。如果你构建了一些更复杂的东西,你可能需要Makefile / Makevars来帮助处理构建过程,并且可能想要使用头文件将接口与实现分开 - 但是为此你必须潜入深入研究并获取一些C ++书籍,因为需要学习很多东西。

换句话说 - 你正在做的事情非常好。对于简单的情况,只需在.cpp目录中使用src/文件(并让Rcpp,属性和其他兄弟包处理其余的文件)就可以了。

  

第二个问题是我是否需要一个&#34; Map&#34;在rcppeigen_max_over_columns.cpp的某处,这样当矩阵从R传递到C ++时,矩阵不会被复制?

嗯,在将R对象传输到(非 - Rcpp)类时,几乎总是会复制数据,除非您专门使用可以重用底层数据的构造函数。我不知道Eigen是否有一个可以重用内存的构造函数,但我建议除非你知道它重要,否则不要担心它(因为复制了一系列的数据通常很快)

答案 1 :(得分:2)

对于第二个问题,事实证明这种修改(感谢我的同事Eric Lin)是必要的,而且它确实似乎有帮助,至少对于A <- matrix(rnorm(10000*100), 10000, 100)的基准示例而言。使用原始cpp函数,最大列比R快约30倍,使用Eigen :: Map比R快100倍。

Eigen::MatrixXd rcppeigen_max_over_columns(const Eigen::Map<Eigen::MatrixXd>  & A){
    Eigen::MatrixXd Amax = A.colwise().maxCoeff();
    return Amax;
}