Integrate Fortran, C++ with R
Integrate Fortran, C++ with R
我的任务是用c++重写一个R函数来加速while循环。除了.Fortran()
,所有的R代码都在Rcpp和Armadillo的帮助下重写了。我一开始试着使用Rinside,正如德克所说,它的工作速度非常慢。(数据通过R -> c++ -> R -> Fortran是很昂贵的)
因为我不想用c++重写Fortran代码,反之亦然,通过将c++直接链接到Fortran来加速程序看起来很自然:R -> c++ -> Fortran。
// [[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadillo.h>
using namespace Rcpp;
extern "C"{
List f_(int *n,NumericMatrix a, NumericVector c, double* eps);
}
问题是我可以把c++和Fortran集成,把R和c++集成,但是我不能让这三件事一起工作!
我试着在Linux中编译c++,但它只是找不到RcppArmadillo.h
和namespace Rcpp
:
error: RcppArmadillo.h: No such file or directory
error: 'Rcpp' is not a namespace-name
当我在R中直接调用sourceCpp("test.cpp")
时,控制台显示:
test.o:test.cpp:(.text+0x20b2): undefined reference to `f_'
collect2: ld returned 1 exit status
Error in sourceCpp("test.cpp") : Error occurred building shared library.
我还尝试通过
将所有这些东西合并到一个包中RcppArmadillo::RcppArmadillo.package.skeleton("TTTest")
但是我将.cpp
和.f
文件添加到/src
并运行compileAttributes
后,我不知道如何处理TTTest
包(我认为它无法安装)。
那么,有可能做像我想象的Rcpp那样的事情吗?或者有必要将Fortran代码转换为C/c++代码?
谢谢你的帮助。
对于这样的项目,我建议将代码卷到一个包中。我创建了一个简单的例子,我称之为mixedlang
的包,可以在这个GitHub回购。我将在这里描述创建包的过程。
我采取的步骤如下:
- 用
RcppArmadillo::RcppArmadillo.package.skeleton("mixedlang")
从R中设置包结构(我只使用RcppArmadillo而不是Rcpp,因为OP是——没有Armadillo特定于这个例子) - 将以下c++和Fortran代码文件添加到
src/
文件夹 - 在R中,先运行
Rcpp::compileAttributes("mixedlang/")
,然后运行devtools::install("mixedlang/")
我创建了一个简单的c++函数,它的唯一目的(本质上)是调用Fortran函数。示例函数接受一个数字向量,将每个元素乘以它的索引,然后返回结果。首先让我们看一下Fortran代码:
fortranfunction.f90
这个函数只接受两个双精度数并将它们相乘,返回结果:
REAL*8 FUNCTION MULTIPLY (X, Y)
REAL*8 X, Y
MULTIPLY = X * Y
RETURN
END
test_function.cpp
现在我们需要从c++代码中调用这个Fortran代码。在这样做的时候,我们需要考虑一些事情:
- Fortran参数是通过引用传递的,而不是通过值传递的。
由于
MULTIPLY
是在另一个文件中定义的,因此我们需要在c++文件中声明它,以便编译器知道实参和返回类型。。在为c++文件声明Fortran函数时,我们将去掉函数名的大小写并添加下划线,因为Fortran编译器默认会这样做。
b。我们必须在
extern "C"
链接规范中声明该函数;c++编译器通常不能使用函数名作为唯一标识符,因为它允许重载,但对于调用Fortran函数,我们需要它完全完成extern "C"
链接规范所完成的工作(例如,参见此SO答案)。
#include "RcppArmadillo.h"
// [[Rcpp::depends(RcppArmadillo)]]
// First we'll declare the MULTIPLY Fortran function
// as multiply_ in an extern "C" linkage specification
// making sure to have the arguments passed as pointers.
extern "C" {
double multiply_(double *x, double *y);
}
// Now our C++ function
// [[Rcpp::export]]
Rcpp::NumericVector test_function(Rcpp::NumericVector x) {
// Get the size of the vector
int n = x.size();
// Create a new vector for our result
Rcpp::NumericVector result(n);
for ( int i = 0; i < n; ++i ) {
// And for each element of the vector,
// store as doubles the element and the index
double starting_value = x[i], multiplier = (double)i;
// Now we can call the Fortran function,
// being sure to pass the address of the variables
result[i] = multiply_(&starting_value, &multiplier);
}
return result;
}
示例输出
安装完包后,我运行了一个示例
mixedlang::test_function(0:9)
# [1] 0 1 4 9 16 25 36 49 64 81
原海报问题的可能来源
- 初始编译时,没有让编译器知道
RcppArmadillo.h
在哪里。 - 试图用
sourceCpp
这样做只是自找麻烦;它并不是真的用来处理多个文件的(参见Dirk Eddelbuettel的回答),这在处理多种语言时是必要的。
我不确定当他们试图把它卷进一个包时发生了什么,这就是为什么我画了这个例子
- Problems with std::cin.fail()
- 应用程序崩溃并显示"symbol _ZdlPvm, version Qt_5 not defined in file libQt5Core.so.5 with link time reference"
- 这对"With a stackless coroutine, only the top-level routine may be suspended."意味着什么
- Boost.TEST with CLion: "Test framework quit unexpectedly"
- 避免碎片化的ClientHellos with OpenSSL (DTLS)
- Issues with Win32 ReadProcessMemory API
- Qt with WinAPI MouseProc
- [[maybe_unused]] with structured_binding?
- Issue with WriteProcessMemory
- OpenCV RTP-Stream with FFMPEG
- "Unable to start debugging. No process is associated with this object." - 在Visual Studio Code中使用GDB
- std::adjacent_difference with std::chrono time_point
- DLL Made with CMake 使程序崩溃
- QtCreator with C 库中的链接器问题
- SHBrowseForFolder with BIF_BROWSEFORCOMPUTER and SHGetPathFr
- specialized std::default_delete with QQmlComponent
- VS2019 - Sudo Remote Debugging on Linux with Cmake project
- Inference pytorch C++ with alexnet and cv::imread image
- Pybind11: init<> with lambda
- Incomings Call with Android Sip stack in Embarcadero C++ bui