Рекомендации по включению кода TMB C++ в пакет R

Недавно я обнаружил чудеса TMB, и я работаю над пакетом, который в идеале включал бы в себя шаблоны TMB C++ для довольно дорогих в вычислительном отношении моделей.

Я предполагаю, что есть возможность:

  • Автоматическая компиляция исходного кода TMB при установке пакета

но я не могу найти четких указаний в документации TMB по этому поводу. На данный момент моя альтернатива - писать функции, которые компилируют код TMB при первом вызове функции, которая использует не скомпилированный класс... но у меня есть ощущение, что есть более хорошие способы сделать это.

Кто-нибудь успешно включил функции TMB в другой пакет и может указать мне направление соответствующей документации или примеров?

1 ответ

Решение

С немного большим поиском я наконец нашел свой ответ в этой теме. Я думаю, что я пропустил это, потому что детали его решений были перенесены на вики-страницу под названием разработка, где контент специально предназначен для пользователей, желающих внести свой вклад в разработку 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 где-то в моем исходном коде, где я не буду связываться с ним. Этот тег заполнит ваше NAMESPACE useDynLib(myPkg)... и как я понимаю, это загружает общие библиотеки при загрузке пакета для вас.

Вызов функции в вашем пакете:

Наконец при звонке MakeADFun, задавать DLL="myPkg", С помощью этой настройки вы можете скомпилировать одну модель TMB в ваш пакет. Это потому, что контент, скомпилированный в вашем ./src/ папка будет автоматически переименована в соответствии с именем вашего пакета, поэтому вы не можете создавать модели с уникальными именами.

РЕДАКТИРОВАТЬ: Решение для распределения нескольких DLL

После некоторого дополнительного поиска (тот же поток, на который ссылаются выше)... Я понял, что решение, описанное в официальной вики (и подробно описанное выше), имеет отношение только к распространению одной DLL (то есть одной модели TMB).

Если вы хотите распространять несколько моделей TMB в пакете, вам придется использовать свой собственный make-файл. Я дал более подробное описание в своем блоге, поэтому я лишь кратко опишу здесь шаги относительно того, как они отличаются от предыдущих шагов, которые я описал.

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 

Для окон замените 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!

Если вам нужен доступ к библиотеке CppAD с дополнительным кодом из TMB (что довольно существенно!), Вы можете использовать WITH_LIBTMBмакропеременная как я в этом заголовке здесь. Это позволит вам иметь несколько файлов.cpp, которые вы можете компилировать отдельно. Важно отметить, что вам нужно только один раз скомпилировать код из заголовка TMB, используя такой файл, который #includes заголовок TMB.hpp без определения WITH_LIBTMB.

Это существенно сокращает время компиляции, поскольку вы можете компилировать каждый.cpp отдельно, без всего кода, объявленного в TMB.hpp. Более того, вы также можете использовать код с Rcpp, если вы отмените определение и определите несколько макросов, как я в ссылке.

У вас также может быть один файл, который может использоваться TMB::MakeADFun. Это требует немного ручной работы, но может быть выполнено и при использовании Rcpp с помощью Rcpp::compileAttributes и измените созданный файл с именем RcppExports.cpp на его имя init.cpp, а затем включите эти дополнительные строки в CallEntries массив и R_init_survTMB функция:

Замечание по использованию Rstudio

Rstudio звонки Rcpp::compileAttributes(или что-то подобное) каждый раз, когда вы строите. Следовательно, вы не можете использовать это. Один из способов обойти это - создать собственный сценарий сборки, аналогичный приведенному здесь. По сути, это вызывает R CMD INSTALL после удаления RcppExports.cpp файл, созданный Rcpp::compileAttributes. Мне также нравится запускать тесты, вызывая devtools::test() но вы можете удалить это, если хотите.

Другие вопросы по тегам