R中F95的高效调用:使用.Fortran还是.Call?
Efficient calling of F95 in R: use .Fortran or .Call?
我正在编写一些 R 模拟代码,但想利用 Fortran 的 swift 线性代数库来替换核心迭代循环。到目前为止,我主要关注的是使用 .Fortran 调用链接的 F95 子程序的明显选择;我想我应该优化内存使用(我正在传递非常大的数组)并设置 DUP=FALSE
但后来我在手册中阅读了关于这种方法的危险及其在 R 3.1.0 中的贬值和 R 3.2 中的禁用的警告.0。现在手册建议切换到 .Call
,但此函数本身不提供 Fortran 支持。
我的谷歌搜索 a Whosebug question 探索了一种通过 C 代码 链接 Fortran 子例程 并使用 .Call
调用它的方法。在我看来,这似乎是一种既可以像魅力也可以像诅咒一样起作用的东西。因此,我的问题是:
- 以速度和健壮性为目标,通过
.Fortran
和 .Call
调用 Fortran 的风险和好处是什么?
- 有没有更elegant/efficient的方法使用
.Call
调用Fortran子程序?
- 还有别的选择吗?
这是我对这种情况的看法:
.Call
是通常首选的接口。它直接为您提供了一个指向底层 R 数据对象 (a SEXP
) 的指针,因此所有的内存管理都由您来决定。您可以尊重 NAMED
字段并根据需要复制数据,或者忽略它(如果您知道您不会就地修改数据,或者感觉舒适 table 为其他人这样做原因)
.Fortran
尝试自动将适当的数据类型从 R SEXP
对象提供给 Fortran 子例程;但是,通常不鼓励使用它(老实说,出于我不完全清楚的原因)
从 C/C++ 例程调用已编译的 Fortran 代码应该运气不错。给定一个名为 fortran_subroutine
的 Fortran 子例程,您应该能够在 C / C++ 代码中提供前向声明,例如(注意:C++ 代码需要前导 extern "C"
):
void fortran_subroutine_(<args>);
请注意函数名后面的下划线——这就是 Fortran 编译器(我熟悉的,例如 gfortran
)默认情况下 'mangle' 符号名称的方式,因此符号是made available 将带有尾随下划线。
此外,您需要确保您选择的 <args>
从相应的 C 类型映射到相应的 Fortran 类型。幸运的是,R-exts提供了这样一个table。
最后,R 的 R CMD build
会自动促进 R 包的编译 + 链接过程。因为我显然是一个贪吃惩罚的人,所以我 produced an example package 应该提供足够的信息让你了解绑定是如何工作的。
3。还有另一种选择吗?是
R 包 dotCall64 可能是一个有趣的选择。它提供了.C64()
,它是Foreign Function Interface的增强版本,即.C()
和.Fortran()
。
接口 .C64()
可用于连接 Fortran 和 C/C++ 代码。它
- 与
.C()
和 .Fortran()
的用法相似
- 提供一种机制来避免不必要的只读和只写参数副本
- 支持长向量(包含超过 2^31-1 个元素的向量)
- 支持 64 位整数类型参数
因此,可以避免不必要的只读参数副本,同时避免 .Call()
接口与 C 包装函数相结合。
一些链接:
- R包dotCall64:https://CRAN.R-project.org/package=dotCall64
- dotCall64 的描述及示例:https://doi.org/10.1016/j.softx.2018.06.002
- 其中 dotCall64 用于使稀疏矩阵代数 R 包 spam 与巨大的稀疏矩阵(超过 2^ 31-1非零元素):https://doi.org/10.1016/j.cageo.2016.11.015
我是 dotCall64 和 spam 的作者之一。
我正在编写一些 R 模拟代码,但想利用 Fortran 的 swift 线性代数库来替换核心迭代循环。到目前为止,我主要关注的是使用 .Fortran 调用链接的 F95 子程序的明显选择;我想我应该优化内存使用(我正在传递非常大的数组)并设置 DUP=FALSE
但后来我在手册中阅读了关于这种方法的危险及其在 R 3.1.0 中的贬值和 R 3.2 中的禁用的警告.0。现在手册建议切换到 .Call
,但此函数本身不提供 Fortran 支持。
我的谷歌搜索 a Whosebug question 探索了一种通过 C 代码 链接 Fortran 子例程 并使用 .Call
调用它的方法。在我看来,这似乎是一种既可以像魅力也可以像诅咒一样起作用的东西。因此,我的问题是:
- 以速度和健壮性为目标,通过
.Fortran
和.Call
调用 Fortran 的风险和好处是什么? - 有没有更elegant/efficient的方法使用
.Call
调用Fortran子程序? - 还有别的选择吗?
这是我对这种情况的看法:
.Call
是通常首选的接口。它直接为您提供了一个指向底层 R 数据对象 (a SEXP
) 的指针,因此所有的内存管理都由您来决定。您可以尊重 NAMED
字段并根据需要复制数据,或者忽略它(如果您知道您不会就地修改数据,或者感觉舒适 table 为其他人这样做原因)
.Fortran
尝试自动将适当的数据类型从 R SEXP
对象提供给 Fortran 子例程;但是,通常不鼓励使用它(老实说,出于我不完全清楚的原因)
从 C/C++ 例程调用已编译的 Fortran 代码应该运气不错。给定一个名为 fortran_subroutine
的 Fortran 子例程,您应该能够在 C / C++ 代码中提供前向声明,例如(注意:C++ 代码需要前导 extern "C"
):
void fortran_subroutine_(<args>);
请注意函数名后面的下划线——这就是 Fortran 编译器(我熟悉的,例如 gfortran
)默认情况下 'mangle' 符号名称的方式,因此符号是made available 将带有尾随下划线。
此外,您需要确保您选择的 <args>
从相应的 C 类型映射到相应的 Fortran 类型。幸运的是,R-exts提供了这样一个table。
最后,R 的 R CMD build
会自动促进 R 包的编译 + 链接过程。因为我显然是一个贪吃惩罚的人,所以我 produced an example package 应该提供足够的信息让你了解绑定是如何工作的。
3。还有另一种选择吗?是
R 包 dotCall64 可能是一个有趣的选择。它提供了.C64()
,它是Foreign Function Interface的增强版本,即.C()
和.Fortran()
。
接口 .C64()
可用于连接 Fortran 和 C/C++ 代码。它
- 与
.C()
和.Fortran()
的用法相似
- 提供一种机制来避免不必要的只读和只写参数副本
- 支持长向量(包含超过 2^31-1 个元素的向量)
- 支持 64 位整数类型参数
因此,可以避免不必要的只读参数副本,同时避免 .Call()
接口与 C 包装函数相结合。
一些链接:
- R包dotCall64:https://CRAN.R-project.org/package=dotCall64
- dotCall64 的描述及示例:https://doi.org/10.1016/j.softx.2018.06.002
- 其中 dotCall64 用于使稀疏矩阵代数 R 包 spam 与巨大的稀疏矩阵(超过 2^ 31-1非零元素):https://doi.org/10.1016/j.cageo.2016.11.015
我是 dotCall64 和 spam 的作者之一。