将Fortran,C ++与R集成 [英] Integrate Fortran, C++ with R

查看:116
本文介绍了将Fortran,C ++与R集成的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的任务是重写C ++中的R函数以加速while循环.除.Fortran()外,所有R代码均已在Rcpp和Armadillo的帮助下进行了重写.我首先尝试使用Rinside,但正如Dirk所指出的那样,它的工作速度非常慢. (通过R-> C ++-> R-> Fortran进行数据传输非常昂贵)

My task it to rewrite a R function in C++ to accelerate the while loops. All R codes has been rewritten in the help of Rcpp and Armadillo except the .Fortran(). I try to use Rinside to at first and it works at a very slow speed as Dirk indicated. (It is expensive for data to go through R -> C++ -> R -> Fortran)

由于我不想用C ++重写Fortran代码,反之亦然,通过将C ++直接链接到Fortran来加速程序看起来很自然:R-> C ++-> Fortran.

Since I don't want to rewrite the Fortran codes in C++ and vice versa, it looks natural to accelerate the programs by linking C++ directly to 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 ++集成在一起,但是我无法使这三件事协同工作!

The problem is that I can integrate C++ with Fortran and integrate R with C++, but I can't make these three things work together!

我尝试在Linux中编译C ++,但找不到RcppArmadillo.hnamespace Rcpp:

I try to compile the C++ in Linux but it just can't find RcppArmadillo.h and namespace Rcpp:

 error: RcppArmadillo.h: No such file or directory
 error: 'Rcpp' is not a namespace-name

当我直接在R中调用sourceCpp("test.cpp")时,控制台将显示:

When I call sourceCpp("test.cpp") in R directly, the console would display:

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.

我还尝试将所有这些东西组合在一个包装中,

I also try to combine all these things in a package by

RcppArmadillo::RcppArmadillo.package.skeleton("TTTest")

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

But I don't know how to deal with the package TTTest (I believe it could not be installed) after I add the .cpp and .f files to /src and run compileAttributes.

那么,是否有可能像Rcpp一样做事情?还是有必要将Fortran代码转换为C/C ++代码?

So, is it possible to do things like what I imagine by Rcpp? Or it is necessary to convert Fortran codes to C/C++ codes?

感谢您的帮助.

推荐答案

我建议此类项目将您的代码打包成一个包.我创建了一个名为mixedlang的软件包的简单示例,该软件包可在此GitHub存储库中获得.我将在这里描述创建程序包的过程.

I would suggest for such projects to roll your code into a package. I created a simple example of such a package I called mixedlang that is available at this GitHub repo. I will describe the process of creating the package here.

我采取的步骤如下:

  1. 使用RcppArmadillo::RcppArmadillo.package.skeleton("mixedlang")从R设置程序包结构(由于OP是,我仅使用RcppArmadillo而不是Rcpp -此示例没有Armadillo专用)
  2. 将以下所述的C ++和Fortran代码文件添加到src/文件夹
  3. 在R中,依次运行Rcpp::compileAttributes("mixedlang/")devtools::install("mixedlang/")
  1. Set up the package structure from R with RcppArmadillo::RcppArmadillo.package.skeleton("mixedlang") (I only used RcppArmadillo rather than Rcpp since the OP was -- there's nothing Armadillo specific to this example)
  2. Added the C++ and Fortran code files described below to the src/ folder
  3. In R, run Rcpp::compileAttributes("mixedlang/") then devtools::install("mixedlang/")

代码

我创建了一个简单的C ++函数,其唯一目的(本质上)是调用Fortran函数.示例函数接受一个数值向量,将每个元素与其索引相乘,然后返回结果.首先让我们看一下Fortran代码:

The Code

I created a simple C++ function whose only purpose (essentially) was to call a Fortran function. The example function takes in a numeric vector, multiplies each element by its index, and returns the result. First let's look at the Fortran code:

此函数只需将两个双精度数相乘并将它们相乘,即可返回结果:

This function just takes in two doubles and multiplies them, returning the result:

REAL*8 FUNCTION MULTIPLY (X, Y) 
REAL*8 X, Y
MULTIPLY = X * Y
RETURN
END

test_function.cpp

现在,我们需要从C ++代码中调用此Fortran代码.在执行此操作时,我们需要考虑以下几点:

test_function.cpp

Now we need to call this Fortran code from our C++ code. When doing this, we need to take into account a few things:

  1. Fortran参数是通过引用传递的,而不是通过值传递的.
  2. 由于MULTIPLY是在另一个文件中定义的,因此我们需要在C ++文件中声明它,以便编译器知道参数和返回类型.

  1. Fortran arguments are passed by reference, not by value.
  2. Since MULTIPLY is defined in another file, we need to declare it in our C++ file so the compiler knows the argument and return types.

a.在为我们的C ++文件声明Fortran函数时,我们将删除函数名称的大小写并添加下划线,因为Fortran编译器默认应这样做.

a. When declaring the Fortran function for our C++ file, we'll drop the case of the function name and append an underscore, since the Fortran compiler should do this by default.

b.我们必须在extern "C"链接规范中声明该函数; C ++编译器通常不能使用函数名称作为唯一标识符,因为它允许重载,但是对于调用Fortran函数,我们需要它精确执行extern "C"链接规范所要完成的工作(例如,参见

b. We have to declare the function within an extern "C" linkage specification; C++ compilers cannot typically use function names as unique identifiers since it allows overloading, but for calling Fortran functions, we need it to do exactly that which the extern "C" linkage specification accomplishes (see, for example, 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;
}

示例输出

安装软件包后,我以示例为例

Example output

After installing the package, I ran as an example

mixedlang::test_function(0:9)
# [1]  0  1  4  9 16 25 36 49 64 81

原始海报问题的来源

  1. 最初尝试进行编译时,他们没有让编译器知道RcppArmadillo.h的位置.
  2. 尝试使用sourceCpp这样做只是在麻烦.并不是真的可以处理多个文件(例如,此答案 stackoverflow.com/users/143305/dirk-eddelbuettel">Dirk Eddelbuettel ),这在处理多种语言时是必需的.
  1. When attempting to compile initially, they did not let the compiler know where RcppArmadillo.h was.
  2. Trying to do this with sourceCpp is just asking for trouble; it wasn't really made to handle multiple files (see for example this answer by Dirk Eddelbuettel), which is necessary when dealing with multiple languages.

我不确定当他们尝试将其滚动到一个程序包中时发生了什么,这就是我绘制此示例的原因.

I'm not sure what happened when they tried to roll it into a package, which is why I drew up this example.

这篇关于将Fortran,C ++与R集成的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆