在R软件包中包含TMB C 代码的指南

Guidelines for including TMB c++ code in an R package

本文关键字:代码 TMB 软件包 包含      更新时间:2023-10-16

我最近发现了TMB的奇观,我正在研究一个包装,理想情况下将其中包括TMB C 模板以用于计算昂贵的模型。

我假设有可能:

  • 在软件包安装上自动编译TMB源代码

,但我在TMB文档中找不到任何明确的准则。到目前为止,我的选择是编写在使用未编译类的函数的第一个函数上编译TMB代码的功能...但是我感觉有更好的方法可以做到。

是否有人成功地将TMB功能包括在另一个软件包中,并且可以将我指向相关文档或示例的方向?

搜索更多,我终于在此线程中找到了答案。我想我错过了它,因为IT详细信息的分辨率已移至Wiki页面,标题为 developt ,其中内容专门针对希望为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)命名空间填充您的 ...众所周知,这会在为您加载包装时加载共享库。

在包装中调用该功能:

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

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

在进行了更多搜索之后(与上面引用的线程相同(...我意识到官方Wiki中描述的解决方案(以及上面详细介绍(仅与分发单个DLL有关(即单个TMB模型(。

如果要在软件包中分发多个TMB模型,则必须使用自己的makefile。我在博客中给出了一个更详细的描述,因此我只简要描述了这些步骤与我所描述的前一步有何不同。

src/makefile

您必须定义自己的Makefile(或Windows用户的Makefile.win(,然后将其放入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,用dll替换so,并使用相关的编译器标志(用于调试(。有关调试的编译器标志的信息,请参见?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/目录中的剩余文件...或者,也许有人可以为编写更好的文件提供一些很好的建议!

如果要访问带有TMB的附加代码的CPPAD库(这很大!(,则可以像我在此标头中一样使用WITH_LIBTMB宏变量。这将使您拥有多个.cpp文件,您可以单独编译。重要的是,您只需要使用此类文件来编译TMB标头的代码,该文件 #include s tmb.hpp标头而不定义WITH_LIBTMB

这可以自行编译每个.cpp,而无需在tmb.hpp中声明的所有代码。此外,如果您不确定并定义了一些宏观,也可以将代码与RCPP一起使用。

您还可以拥有一个可以使用TMB::MakeADFun使用的文件。它需要一些手动工作,但可以通过使用Rcpp::compileAttributes并将其更改为称为rcppexports.cpp的创建的文件命名为init.cpp,然后在CallEntries数组和R_init_survTMB函数中包含这些其他行:ul>

  • callentries数组。
  • r_init_survtmb函数。
  • 使用rstudio

    注意每次构建时,

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