我最近在用 mgcv GAM 做一些计算测试。修改了原有的一些功能,增加了一些。为了不破坏兼容性,对于我想修改的每个函数,我都创建了一个新版本,函数名中带有 .zheyuan 后缀。例如,使用 Sl.fit 函数进行惩罚最小二乘拟合,我将有一个 Sl.fit.zheyuan 。我只是将我编写的所有 R 函数收集到一个独立的 R 脚本“zheyuan.R”中。通过将此文件添加到 R package sourcemgcv_1.8-17 目录中,并将此修改后的包编译到本地路径中,我可以加载它以进行测试。

我在添加 R 例程时没有问题,但在添加 C 例程时没有问题。安装修改后的包时没有发生错误,但是当我调用添加的 C 例程的 R 包装函数时,我会收到问题标题中的错误。如果您对我的案例感兴趣,可以按照以下步骤重现此类错误。

第一步:下载最新的包源

从上面的链接下载 1.8-17 版本。当在 CRAN 上发布新的 mgcv 版本时,此类链接将失效。但是你可以随时去 mgcv CRAN page 下载最新版本。

让我们对源代码进行 untar。首先,删除文件 MD5 ,这样我们在编译修改版本时就不会收到恼人的 MD5 警告。下面,我们将在 R 目录和 src 目录中添加新的东西。

第 2 步:创建 R 脚本

考虑以下 R 包装函数:

RX <- function (R, X) {
  X <- X + 0
  .Call("C_mgcv_RX", R, X)
  X
  }

创建一个 R 脚本“zheyuan.R”来放置这个函数,并将其添加到 mgcv/R 中。

第 3 步:添加 C 例程

有关矩阵计算的 C 例程通常位于 src/mat.c 下。因此,让我们在此脚本的末尾附加一个新函数:
void mgcv_RX (SEXP R, SEXP X) {
  int nrowX = nrows(X);
  int ncolX = ncols(X);
  double one = 1.0;
  F77_CALL(dtrmm)("l", "u", "n", "n", &nrowX, &ncolX, &one, REAL(R), &nrowX, REAL(X), &nrowX);
  }

这是一个简单的例程,将上三角矩阵 R 与矩形矩阵 X 相乘。输出矩阵将覆盖 X 。为此将调用级别 3 BLAS dtrmm。我们不需要担心头文件或运行时链接到 BLAS 库。 header 在 mat.c 中可用,与 BLAS 的链接由 R 管理。

第 4 步:注册 C 例程

以上是不够的。 mgcv 中的每个 C 程序都会出现在三个地方。例如,让我们尝试搜索 native C 例程:
grep mgcv_RPPt mgcv/src/*
# mgcv/src/init.c:  {"mgcv_RPPt",(DL_FUNC)&mgcv_RPPt,3},
# mgcv/src/mat.c:void mgcv_RPPt(SEXP a,SEXP r, SEXP NT) {
# mgcv/src/mgcv.h:void mgcv_RPPt(SEXP a,SEXP r, SEXP NT);

我们还需要附加一个头文件 mgcv.h ,并在 init.c 中注册这个 C 例程。

让我们追加
void mgcv_RX (SEXP R, SEXP X);

mgcv.h 的末尾,在 init.c 里面,做:
R_CallMethodDef CallMethods[] = {
  {"mgcv_pmmult2", (DL_FUNC) &mgcv_pmmult2,5},
  {"mgcv_Rpiqr", (DL_FUNC) &mgcv_Rpiqr,5},
  {"mgcv_tmm",(DL_FUNC)&mgcv_tmm,5},
  {"mgcv_Rpbsi",(DL_FUNC)&mgcv_Rpbsi,2},
  {"mgcv_RPPt",(DL_FUNC)&mgcv_RPPt,3},
  {"mgcv_Rpchol",(DL_FUNC)&mgcv_Rpchol,4},
  {"mgcv_Rpforwardsolve",(DL_FUNC)&mgcv_Rpforwardsolve,3},
  {"mgcv_Rpcross",(DL_FUNC)&mgcv_Rpcross,3},
  {"mgcv_RX",(DL_FUNC)&mgcv_RX,2},  //  we add this line
  {NULL, NULL, 0}
};

第 5 步:编译并加载
tar 修改后的 mgcv 文件夹到 mgcv.tar.gz

打开一个新的、干净的 R session (可能你需要 R --vanilla 来启动)。然后指定本地库路径并运行:
path <- getwd()  ## let's just use current working directory
## make sure you move "mgcv.tar.gz" into current working path
install.packages("mgcv.tar.gz", repos = NULL, lib = path)
library(mgcv, lib.loc = path)

第 6 步:测试并得到错误
R <- matrix(runif(25), 5)
R[lower.tri(R)] <- 0
X <- matrix(runif(25), 5)
mgcv:::RX(R, X)  ## function is not exported, so use `mgcv:::` to find it

# Error in .Call("C_mgcv_RX", R, X) :
#   "C_mgcv_RX" not resolved from current namespace (mgcv)

谁能解释为什么以及如何解决这个问题?

最佳答案

我现在有一个临时的“修复”。代替

.Call("C_mgcv_RX", R, X)

使用以下任一方法:
.Call(mgcv:::"C_mgcv_RX", R, X)
.Call(getNativeSymbolInfo("mgcv_RX"), R, X)

我之所以想到这个,是因为我突然意识到 ::: 也可以提取 C 例程。既然包编译成功,那么mgcv:::就没有办法找不到这个C例程了。是的,它有效。

要检查我们定义的 C 例程在加载的共享库中是否可用,请尝试
is.loaded("mgcv_RX")
# TRUE

要列出加载的共享库中所有已注册的 C 例程,请使用
getDLLRegisteredRoutines("mgcv")

关于c - "not resolved from current namespace"错误,当从 R 调用 C 例程时,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/43662542/

10-11 23:07