将Fort,C与R集成

我的任务是在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),这在处理多种语言时是必需的.

我不确定当他们试图将它卷成一个包时会发生什么,这就是我制作这个例子的原因.

上一篇:iOS开发之应用沙盒


下一篇:从fortran调用c sub时运行时间中止