Overview

Writing up analyses with TMB in R scripts is easy enough as there are plenty of examples on the official documentation. While the documentation can be a bit intimidating at first, I personally found Sean Anderson’s blog to be a great introduction to TMB.

When trying to bundle my TMB scripts into an R package however, things were less clear. Ideally TMB can be distributed in such a way that:

  • c++ model templates (dll or so files) are compiled when the user installs the package.
  • The required dynamic libraries are loaded when the package is loaded.

The official TMB wiki only deals with the special case of distributing a single .dll (or .so for linux users) which shares the same name as the package your bundling it into. To bundle multiple model templates (i.e. multiple dynamic libraries), you’ll have to create your own makefile. Below are the key steps I used to do exactly that, bundle multiple TMB models into an R package where the dynamic libraries are compiled on install and then are loaded when the package is. I used the official wiki as a starting point, and there were some really helpful tips in this thread to get this working.

Here we’ll assume that you’re making a package named myPackage which holds two TMB templates template1 and template2.

Note: Linux uses shared object libraries (.so) while the windows equivalent is the dynamic link libraries (.dll). To keep things simple, I’ll refer to both of these as dynamic libraries as this guide is intended for both windows and linux (although it was only tested on linux)

File structure

Place all your .cpp files (model templates) into the ./src directory of your package. For this example, these key files should match the structure shown here (where ./ is your root package directory):

  • ./src/
    • template1.cpp
    • template2.cpp
    • Makefile
    • Makefile.win
  • ./R/
    • roxygentags.r
  • ./DESCRIPTION

R will use the src/ folder for compiling code on the package installation and having a makefile for each platform (UNIX vs Windows) should allow this to be cross platform.

DESCRIPTION

Now, lets make sure that your R package has access to the tools it needs to compile the c++ templates. Insert these lines into your DESCRIPTION file for your package:

Imports: TMB, RcppEigen
LinkingTo: TMB, RcppEigen

Makefile

By default, R Studio will compile the .cpp file found in ./src into a dynamic library which has the same name as the R package. As we’re trying to compile multiple dynamic libraries, we’ll have to write our own compiling protocol by defining a Makefile. This Makefile example below should work fine for UNIX systems.

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

For the windows makefile Makefile.win, just replace the .so extensions with .dll and change the -00 -g to the windows flag (see ?gdbsource()), and adjust the clean command accordingly.

all: template1.dll template2.dll
	# Comment here preserves the prior tab
template1.dll: template1.cpp
    Rscript --vanilla -e "TMB::compile('template1.cpp', '-O1 -g',DLLFLAGS='')"
template2.dll: template2.cpp
    Rscript --vanilla -e "TMB::compile('template2.cpp', '-O1 -g',DLLFLAGS='')"

clean:
    rm -rf *.dll

This example was adapted from this stackoverflow question which resulted from a discussion in the comments below.

The compiler flag -00 -g is for enabling debugging through the TMB function gdbsource(). Also, be careful about making sure you are using tabs and not spaces here, as that can lead to frustrating compiler errors. I kept on getting the Nothing to do for all errors when trying to compile, when I finally realized that R studio was automatically removing my trailing white spaces on save. I couldn’t stop R Studio from automatically doing this, so I inserted a comment on line 2 to keep the tab from vanishing and thus avoiding compilation errors.

Loading Dynamic Libraries

Finally, to load these libraries on package load, you’ll have to update your package namespace. If your using roxygen2 (as is default for packages in R studio), then you’ll have to drop some roxygen tags somewhere. To avoid muddying up my other code, I just created a dummy function in a separate file, roxygentags.r like so:

#' 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)
}

Using the templates

Finally, all you need to do to make use of these templates is implement MakeADFun anywhere in your code like so:

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

As we’ve already done the compiling and loading of these dynamic libraries, there’s no need to use TMB::compile() or dyn.load(TMB::dynlib()) anywhere within your package when calling your model templates.

Updated on: 2018-09-29