我最近发现了TMB的奇迹,而且我正在开发一个包,理想情况下包含TMB c ++模板,用于计算相当昂贵的模型。
我假设有可能:
但我无法在TMB文档中找到有关此问题的明确指南。截至目前,我的另一种方法是编写在第一次调用使用未编译类的函数时编译TMB代码的函数......但我觉得有更好的方法可以做到这一点。
有没有人成功将TMB功能包含在另一个包中,并且可以指向相关文档或示例的方向?
答案 0 :(得分:3)
通过更多的搜索,我终于在thread中找到了答案。我想我错过了它,因为它详细的分辨率被移动到名为 development 的wiki页面,其中内容专门针对希望为TMB开发做出贡献的用户,而我只是想分发代码这使得TMB陷入困境。
总结一下,该主题建议我采用的一些更改( myPkg 应该是您的包的名称):
.cpp
模板放入mypkg/src
。在构建软件包时,这将由R自动编译。将这些行添加到描述文件中,以便R拥有编译模型模板所需的所有工具。
Depends: TMB, RcppEigen
LinkingTo: TMB, RcppEigen
现在我们需要将TMB模板添加到命名空间文件中。我们可以通过制作像这样的虚拟文件轻松地通过roxygen来实现这一点:
#' Roxygen commands
#'
#' @useDynLib myPkg
#'
dummy <- function(){
return(NULL)
}
虚函数只是在我的源代码中某处有标记@useDynLib myPkg
的借口,我不会把它搞乱。此标记将使用useDynLib(myPkg)
填充 NAMESPACE ...并且据我所知,这会在为您加载包时加载共享库。
最后,在致电MakeADFun
时,请设置DLL="myPkg"
。通过此设置,您可以将单个 TMB模型编译到您的包中。这是因为在./src/
文件夹中编译的内容将根据您的包名自动重命名,因此您无法创建唯一命名的模型。
经过一些搜索(与上面提到的相同的线程)...我意识到官方维基中描述的解决方案(以及上面详述的)仅与分发单个dll(即单个TMB模型)相关。
如果要在程序包中分发多个TMB模型,则必须使用自己的makefile。我已经给出了更详细的描述in my blog,所以我只简要介绍一下这些步骤与我之前描述的步骤的不同之处。
您必须为自己的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
。
这与上面略有不同:
#' 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都会调用R_init_survTMB
(或类似的名称)。因此,您不能使用它。解决此问题的一种方法是创建自定义构建脚本similar to the one here。删除Rcpp::compileAttributes
创建的R CMD INSTALL
文件后,它实际上调用RcppExports.cpp
。我还喜欢通过调用Rcpp::compileAttributes
来运行测试,但是您可以根据需要将其删除。