在R包中包含TMB c ++代码的指南

时间:2018-02-05 16:28:26

标签: c++ r tmb

我最近发现了TMB的奇迹,而且我正在开发一个包,理想情况下包含TMB c ++模板,用于计算相当昂贵的模型。

我假设有可能:

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

但我无法在TMB文档中找到有关此问题的明确指南。截至目前,我的另一种方法是编写在第一次调用使用未编译类的函数时编译TMB代码的函数......但我觉得有更好的方法可以做到这一点。

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

2 个答案:

答案 0 :(得分:3)

通过更多的搜索,我终于在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的解决方案

经过一些搜索(与上面提到的相同的线程)...我意识到官方维基中描述的解决方案(以及上面详述的)仅与分发单个dll(即单个TMB模型)相关。

如果要在程序包中分发多个TMB模型,则必须使用自己的makefile。我已经给出了更详细的描述in my blog,所以我只简要介绍一下这些步骤与我之前描述的步骤的不同之处。

的src /生成文件

您必须为自己的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文件提供一些好的建议!

答案 1 :(得分:1)

如果您想使用TMB的其他代码访问CppAD库(这是非常重要的!),则可以像在此标头here中一样使用WITH_LIBTMB宏变量。这将使您拥有多个.cpp文件,您可以分别进行编译。重要的是,您只需要使用#include TMB.hpp标头a file like this来编译TMB标头中的代码,而无需定义WITH_LIBTMB

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

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

使用Rstudio的注意事项

每次构建时,Rstudio都会调用R_init_survTMB(或类似的名称)。因此,您不能使用它。解决此问题的一种方法是创建自定义构建脚本similar to the one here。删除Rcpp::compileAttributes创建的R CMD INSTALL文件后,它实际上调用RcppExports.cpp。我还喜欢通过调用Rcpp::compileAttributes来运行测试,但是您可以根据需要将其删除。