我的任务是在C中重写一个R函数来加速while循环.除了.Fortran()之外,所有R代码都在Rcpp和Armadillo的帮助下重写.我尝试首先使用Rinside,它的工作速度非常慢,正如Dirk所指出的那样. (数据通过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和命名空间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++代码?
谢谢你的帮助.
解决方法:
我建议这些项目将代码转换为包.我创建了一个这样一个简单的例子,我称之为混合语,可以在this GitHub repo获得.我将在这里描述创建包的过程.
我采取的步骤如下:
>使用RcppArmadillo设置R的包结构:: RcppArmadillo.package.skeleton(“mixedlang”)(我只使用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编译器应默认执行此操作.
湾我们必须在extern“C”链接规范中声明该函数; C编译器通常不能将函数名称用作唯一标识符,因为它允许重载,但是为了调用Fortran函数,我们需要它完全执行extern“C”链接规范完成的操作(例如,参见this SO answer).
#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执行此操作只是在寻找麻烦;它并没有真正处理多个文件(参见this answer by Dirk Eddelbuettel),这在处理多种语言时是必需的.
我不确定当他们试图将它卷成一个包时会发生什么,这就是我制作这个例子的原因.