Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Integrate Fortran, C++ with R

Tags:

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)

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);
}

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!

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

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")

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.

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?

Thanks for your help.

like image 849
Dajun Xu Avatar asked Jul 14 '15 02:07

Dajun Xu


People also ask

Is R based on Fortran?

R itself uses Fortran for much of its hard number crunching. There is a built-in base-R interface named .

Is it possible to run FORTRAN code in R?

DISCLAIMER: To accomplish this work requires the presence of a working Fortran compiler such as the GNU suite of compilers (g77, gfortran, gcc, etc). Relative to operating systems I use Linux and OSX. I rarely use Windows though do know that the GNU suite is available for that OS so you should be able to link Fortran code into R there.

Is there a Fortran function that does the same thing as C function?

Here is a Fortran function that does the same thing (downloadable as bar.f). subroutine bar(n, x) integer n double precision x(n) integer i do 100 i = 1, n x(i) = x(i) ** 2 100 continue end Notice it has the same two properties as the C function.

What operating systems do you use for Fortran programming?

I’ll talk about how to integrate Fortran code with R and, in a later post, discuss doing the same with C and C++. DISCLAIMER: To accomplish this work requires the presence of a working Fortran compiler such as the GNU suite of compilers (g77, gfortran, gcc, etc). Relative to operating systems I use Linux and OSX.

How do I use the Fortran interface with subroutines?

And speaking of subroutines it is important to know that to use the .Fortran interface one must make reference to Fortran subroutines only – not Fortran functions or full on programs. So if you have some code that you want to bring in then you will need to embed that code within a subroutine definition.


1 Answers

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.

The steps I took were as follows:

  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/")

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:

fortranfunction.f90

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

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 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. 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. 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

Likely sources of the original poster's problems

  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.

like image 58
duckmayr Avatar answered Sep 28 '22 04:09

duckmayr