【问题标题】:Guidelines for including TMB c++ code in an R package在 R 包中包含 TMB c++ 代码的指南
【发布时间】:2018-02-05 16:28:26
【问题描述】:

我最近发现了 TMB 的神奇之处,并且我正在开发一个包,该包最好在其中包含 TMB c++ 模板,用于计算相当昂贵的模型。

我假设有以下可能性:

  • 在安装包时自动编译 TMB 源代码

但我在 TMB 文档中找不到任何明确的指导方针。到目前为止,我的替代方法是编写函数,在第一次调用使用未编译类的函数时编译 TMB 代码......但我觉得有更好的方法来做到这一点。

有没有人成功地将 TMB 功能包含在另一个包中,并且可以为我指明相关文档或示例的方向?

【问题讨论】:

    标签: c++ r tmb


    【解决方案1】:

    经过一番搜索,我终于在thread 中找到了答案。我想我错过了它,因为它详细说明的解决方案已移至标题为 development 的 wiki 页面,其中内容专门针对希望为 TMB 开发做出贡献的用户,而我只想分发代码其中包含 TMB。

    总而言之,该线程建议我采用这样的一些更改(myPkg 应该是您的包的名称):

    src/

    • .cpp 模板放入mypkg/src。然后,当您构建包时,R 会自动编译它。

    说明

    将这些行添加到您的描述文件中,以便 R 拥有编译模型模板所需的所有工具。

    Depends: TMB, RcppEigen
    LinkingTo: TMB, RcppEigen
    

    R/roxygentags.r

    现在我们需要将我们的 TMB 模板添加到命名空间文件中。我们可以通过 roxygen 轻松地做到这一点,方法是制作一个像这样的虚拟文件:

    #' Roxygen commands
    #'
    #' @useDynLib myPkg
    #'
    dummy <- function(){
      return(NULL)
    }
    

    虚拟函数只是在我的源代码中的某个地方添加标签@useDynLib myPkg 的借口,我不会弄乱它。此标签将使用useDynLib(myPkg)...填充您的NAMESPACE,据我所知,这会在为您加载包时加载共享库。

    调用包中的函数:

    最后,在调用MakeADFun时,设置DLL="myPkg"。通过此设置,您可以将单个 TMB 模型编译到您的包中。这是因为你的./src/文件夹中编译的内容会根据你的包名自动重命名,所以你不能创建唯一命名的模型。

    编辑:分发多个 DLL 的解决方案

    经过更多搜索(与上面引用的相同线程)...我意识到官方 wiki 中描述的解决方案(以及上面详细说明)仅与分发单个 dll(即单个 TMB 模型)有关。

    如果您想在一个包中分发多个 TMB 模型,您必须使用自己的 makefile。我已经给出了更详细的描述in my blog,所以我将在这里仅简要描述这些步骤,说明它们与我之前描述的步骤有何不同。

    src/Makefile

    你必须定义你自己的Makefile(或Makefile.win对于windows用户)并将它放到你的src/目录中。这是一个适合我的示例:

    all: template1.so template2.so
        # Comment here preserves the prior tab
    template1.so: template1.cpp
        Rscript --vanilla -e "TMB::compile('template1.cpp','-O0 -g')"
    template2.so: template2.cpp
        Rscript --vanilla -e "TMB::compile('template2.cpp','-O0 -g')"
    
    clean:
        rm -rf *o 
    

    对于 Windows,将 so 替换为 dll,并使用相关的编译器标志(用于调试)。有关用于调试的编译器标志的信息,请参阅 ?TMB::compile

    R/roxygentags.r

    这与上面略有不同:

    #' Roxygen commands
    #'
    #' This is a dummy function who's purpose is to hold the useDynLib roxygen tag.
    #' This tag will populate the namespace with compiled c++ functions upon package install.
    #'
    #' @useDynLib template1
    #' @useDynLib template2
    #'
    dummy <- function(){
      return(NULL)
    }
    

    使用包中的模型

    最后,上述更改将编译多个唯一命名的 TMB 模板并将它们加载到命名空间中。要在包中调用这些模型,下面是一个示例:

    obj <- MakeADFun(data = data,
                       parameters = params,
                       DLL="template1", 
                       inner.control = list(maxit = 10000),
                       silent=F)
    

    提示...

    当我尝试在 Windows 机器上编译它时遇到了问题……结果证明与未正确清理 src 文件夹有关,并且我将旧的 linux 编译文件卡在了那里。如果您有编译问题,值得手动清除之前构建的 src/ 目录中的残留文件......或者也许有人可以提供一些关于编写更好的 make 文件的好建议!

    【讨论】:

    【解决方案2】:

    如果您想使用来自 TMB 的附加代码访问 CppAD 库(这非常重要!),那么您可以使用 WITH_LIBTMB 宏变量,就像我在此标头 here 中所做的那样。这将允许您拥有多个可以单独编译的 .cpp 文件。重要的是,您只需使用 a file like this 编译 TMB 标头中的代码一次,其中 #includes TMB.hpp 标头而不定义 WITH_LIBTMB

    这大大减少了编译时间,因为您可以独立编译每个 .cpp,而无需 TMB.hpp 中声明的所有代码。此外,如果您像我在链接中所做的那样undefine and define 一些宏,您也可以将代码与 Rcpp 一起使用。

    您还可以拥有一个可供TMB::MakeADFun 使用的文件。它需要一些手动工作,但也可以通过使用 Rcpp::compileAttributes 并将创建的名为 RcppExports.cpp 的文件更改为名为 init.cpp 的同时使用 Rcpp 来完成,然后将这些附加行包含在 CallEntries 数组和 @ 987654333@函数:

    使用 Rstudio 的注意事项

    Rstudio 每次构建时都会调用Rcpp::compileAttributes(或类似的东西)。因此,您不能使用它。解决此问题的一种方法是创建自定义构建脚本similar to the one here。在删除了由Rcpp::compileAttributes 创建的RcppExports.cpp 文件后,它实际上调用了R CMD INSTALL。我也喜欢通过调用 devtools::test() 来运行测试,但如果你愿意,可以删除它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-04-05
      • 2023-04-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-06
      相关资源
      最近更新 更多