我最近在用 mgcv
GAM 做一些计算测试。修改了原有的一些功能,增加了一些。为了不破坏兼容性,对于我想修改的每个函数,我都创建了一个新版本,函数名中带有 .zheyuan
后缀。例如,使用 Sl.fit
函数进行惩罚最小二乘拟合,我将有一个 Sl.fit.zheyuan
。我只是将我编写的所有 R 函数收集到一个独立的 R 脚本“zheyuan.R”中。通过将此文件添加到 R
package source 的 mgcv_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/