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.
R itself uses Fortran for much of its hard number crunching. There is a built-in base-R interface named .
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.
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.
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.
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.
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:
RcppArmadillo::RcppArmadillo.package.skeleton("mixedlang")
(I only used RcppArmadillo rather than Rcpp since the OP was -- there's nothing Armadillo specific to this example)src/
folderRcpp::compileAttributes("mixedlang/")
then devtools::install("mixedlang/")
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
Now we need to call this Fortran code from our C++ code. When doing this, we need to take into account a few things:
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;
}
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
RcppArmadillo.h
was.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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With