将Fortran,C ++与R集成

问题描述 投票:18回答:1

我的任务是用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.hnamespace 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")

但是我将TTTest.cpp文件添加到.f并运行/src后,我不知道如何处理包compileAttributes(我相信它无法安装)。

那么,是否有可能像Rcpp那样做我想象的事情?或者有必要将Fortran代码转换为C / C ++代码?

谢谢你的帮助。

c++ r fortran rcpp armadillo
1个回答
24
投票

我建议这些项目将代码转换为包。我创建了一个简单的例子,我在mixedlang上提供了一个名为this GitHub repo的软件包。我将在这里描述创建包的过程。

我采取的步骤如下:

  1. 使用RcppArmadillo::RcppArmadillo.package.skeleton("mixedlang")设置R的包结构(我只使用了RcppArmadillo而不是Rcpp,因为OP是 - 这个例子没有特定的Armadillo)
  2. 将下面描述的C ++和Fortran代码文件添加到src/文件夹中
  3. 在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代码。这样做时,我们需要考虑以下几点:

  1. Fortran参数通过引用传递,而不是通过值传递。
  2. 由于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

可能是原始海报问题的根源

  1. 当最初尝试编译时,他们没有让编译器知道RcppArmadillo.h在哪里。
  2. 尝试用sourceCpp做这件事只是在惹麻烦;它并没有真正处理多个文件(例如参见this answerDirk Eddelbuettel),这在处理多种语言时是必需的。

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

© www.soinside.com 2019 - 2024. All rights reserved.