与Stan

时间:2018-06-04 18:23:06

标签: r rcpp stan rstan

我有一个R包,它使用 Rcpp 来执行某些内部功能。这些函数不会导出以供用户直接访问(请参阅rcpptest存储库中的最低可重现性示例)。

我现在正在尝试将 Stan 代码添加到安装软件包时要编译的src/目录中(rcppstan存储库中的可重现示例)。但是,当我修改包以使用Stan时,我在R CMD CHECK中收到以下错误:

#> ❯ checking R code for possible problems ... NOTE
#>   meanC: no visible binding for global variable ‘_rcppstan_meanC’
#>   Undefined global functions or variables:
#>     _rcppstan_meanC

事实上,当我尝试调用使用meanC函数的R函数时,我收到错误Error in meanC(x) : object '_rcppstan_meanC' not found

据我所知,当我修改包以使用 rstan 时,这就是正在发生的变化,因此可能是原因。

  1. 仅使用 Rcpp 时,以下内容属于src/RcppExports.cpp

    static const R_CallMethodDef CallEntries[] = {
        {"_rcpptest_timesTwo", (DL_FUNC) &_rcpptest_timesTwo, 1},
        {NULL, NULL, 0}
    };
    
    RcppExport void R_init_rcpptest(DllInfo *dll) {
        R_registerRoutines(dll, NULL, CallEntries, NULL, NULL);
        R_useDynamicSymbols(dll, FALSE);
    }
    
  2. 合并 Stan 时,src/RcppExports.cpp文件中不再生成该代码。相反,它似乎是由 rstantools 包创建的src/init.cpp文件处理。该文件中的相关块位于:

    static const R_CallMethodDef CallEntries[] = {
      {NULL, NULL, 0}
    };
    
    void attribute_visible R_init_rcppstan(DllInfo *dll) {
      // next line is necessary to avoid a NOTE from R CMD check
      R_registerRoutines(dll, NULL, CallEntries, NULL, NULL);
      R_useDynamicSymbols(dll, TRUE); // necessary for .onLoad() to work
    }
    
  3. 为什么src/init.cpp中的代码使 Rcpp 函数未定义?相反,有没有办法编辑src/init.cpp,以便 Stan 模型能够正确编译和访问,同时仍允许定义 Rcpp 函数?

1 个答案:

答案 0 :(得分:1)

init.cpp注册方法,Makevars禁止编译cpp文件。通过Makevars(和Makevars.win)中的以下更改,我得到了编译:

diff --git a/src/Makevars b/src/Makevars
index 7aedc5b..3ea312e 100644
--- a/src/Makevars
+++ b/src/Makevars
@@ -1,8 +1,9 @@
 STANHEADERS_SRC = `"$(R_HOME)/bin$(R_ARCH_BIN)/Rscript" --vanilla -e "cat(system.file('include', 'src', package = 'StanHeaders'))"`
 PKG_CPPFLAGS = -I"../inst/include" -I"$(STANHEADERS_SRC)" -DBOOST_RESULT_OF_USE_TR1 -DBOOST_NO_DECLTYPE -DBOOST_DISABLE_ASSERTS -DEIGEN_NO_DEBUG -DBOOST_MATH_OVERFLOW_ERROR_POLICY=errno_on_error

-SOURCES = $(wildcard stan_files/*.stan)
-OBJECTS = $(SOURCES:.stan=.o) init.o
+CPP_SOURCES = $(wildcard *.cpp)
+STAN_SOURCES = $(wildcard stan_files/*.stan)
+OBJECTS = $(STAN_SOURCES:.stan=.o) $(CPP_SOURCES:.cpp=.o)

 all: $(SHLIB)
                @if test -e "/usr/bin/install_name_tool" && test -e "/usr/local/clang4/lib/libc++.1.dylib" && test -e "/usr/lib/libc++.1.dylib"; then /usr/bin/install_name_tool -change /usr/local/clang4/lib/libc++.1.dylib /usr/lib/libc++.1.dylib $(SHLIB); fi

调用Rcpp::compileAttributes()后,方法注册再次出现在RcppExports.cpp中。当我尝试R CMD INSTALL时,我收到了来自.onLoad()的错误,c.f。 https://github.com/stan-dev/rstanarm/issues/190。使用那里的解决方法,即R CMD INSTALL --preclean首先解决了问题,但不可靠。为我解决问题的是改变

R_useDynamicSymbols(dll, FALSE);

R_useDynamicSymbols(dll, TRUE);
RcppExports.cpp中的

。这当然是有问题的,因为该文件可能被覆盖,特别是在使用RStudio / devtools时。一个相当hacky的解决方案是添加

RcppExports.o: patch

patch:
        sed -i 's/R_useDynamicSymbols(dll, FALSE)/R_useDynamicSymbols(dll, TRUE)/' RcppExports.cpp

.phony: all clean patch
Makevars(.win)中的

。但最终问题似乎是在包安装期间在src的子目录中生成了Rcpp模块的C ++代码。因此Rcpp::compileAttributes()不能在已注册方法列表中包含相应的方法。我没有看到一个很好的解决方案。 现在,软件包构建,检查并安装两个NOTE:

N  checking installed package size
   installed size is  7.8Mb
   sub-directories of 1Mb or more:
     libs   7.7Mb
N  checking for GNU extensions in Makefiles
   GNU make is a SystemRequirements.