Intégrer Fortran, C++ avec R

ma tâche est de réécrire une fonction R en C++ pour accélérer les boucles while. Tous les codes R ont été réécrits à L'aide de Rcpp et Armadillo sauf le .Fortran(). J'essaie D'utiliser Rinside à la première et il fonctionne à une vitesse très lente comme Dirk indiqué. (C'est cher pour les données à passer par R -> C++ -> R -> Fortran)

comme je ne veux pas réécrire les codes Fortran en C++ et vice versa, il semble naturel d'accélérer les programmes en liant directement 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);
}

le problème est que je peux intégrer C++ avec Fortran et intégrer R avec C++, mais je ne peux pas faire fonctionner ces trois choses ensemble!

j'essaie de compiler le C++ sous Linux mais il ne trouve pas RcppArmadillo.h et namespace Rcpp:

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

Lorsque j'appelle sourceCpp("test.cpp") en R directement, la console affiche:

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.

j'essaie aussi de combiner toutes ces choses dans un paquet par

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

Mais je ne sais pas la façon de traiter avec le paquet TTTest (je crois qu'il n'a pas pu être installé) après j'ai ajouter le .cpp et .f fichiers /src et run compileAttributes.

alors, est-il possible de faire des choses comme ce que J'imagine par Rcpp? Ou est-il nécessaire de convertir les codes Fortran en codes C/C++?

Merci pour votre aide.

17
demandé sur CKE 2015-07-14 05:49:35

1 réponses

je suggérerais pour de tels projets de rouler votre code dans un paquet. J'ai créé un exemple simple d'un tel paquet, j'ai appelé mixedlang qui est disponible à ce dépôt GitHub. Je décrirai ici le processus de création du paquet.

les mesures que j'ai prises étaient les suivantes:

  1. configurer la structure du paquet à partir de R avec RcppArmadillo::RcppArmadillo.package.skeleton("mixedlang") (j'ai seulement utilisé RcppArmadillo plutôt que Rcpp depuis L'opération était -- il n'y a rien Armadillo spécifique à cette exemple)
  2. a ajouté les fichiers de code C++ et Fortran décrits ci-dessous à src/ dossier
  3. Dans R, run Rcpp::compileAttributes("mixedlang/")devtools::install("mixedlang/")

Le Code

j'ai créé une simple fonction C++ dont le seul but (essentiellement) était d'appeler une fonction Fortran. La fonction example prend un vecteur numérique, multiplie chaque élément par son index, et renvoie le résultat. Examinons tout d'abord le Fortran code:

fortranfunction.f90

cette fonction prend juste deux doubles et les multiplie, retournant le résultat:

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

test_function.rpc

maintenant nous devons appeler ce code Fortran à partir de notre code C++. Pour ce faire, nous devons tenir compte de certaines choses:

  1. les arguments Fortran sont passés par référence, pas par valeur.
  2. Depuis MULTIPLY est défini dans un autre fichier, nous devons déclarez - le dans notre fichier C++ pour que le compilateur connaisse les types d'argument et de retour.

    A. Lors de la déclaration de la fonction Fortran pour notre fichier C++, Nous supprimerons le cas du nom de la fonction et ajouterons un underscore, puisque le compilateur Fortran devrait le faire par défaut.

    B. Nous devons déclarer la fonction dans un extern "C" lien de spécification; compilateurs C++ ne peuvent pas utiliser les noms de fonction comme identifiants uniques, car il permet à la surcharge, mais pour appeler Fortran fonctions, nous en avons besoin pour faire exactement cela qui l' extern "C" lien spécification accomplit (voir, par exemple, ceci AFIN de répondre à).

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

Exemple de sortie

après avoir installé le paquet, j'ai couru comme exemple

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

sources probables des problèmes de l'affiche originale

  1. en essayant de compiler initialement, ils n'ont pas laissé le compilateur savoir où RcppArmadillo.h être.
  2. Essayer de le faire avec sourceCpp ne demande que des ennuis; il n'a pas vraiment été fait pour gérer plusieurs fichiers (voir par exemple cette réponse par Dirk Eddelbuettel), ce qui est nécessaire pour traiter plusieurs langues.

je ne suis pas sûr de ce qui s'est passé quand ils ont essayé de rouler en paquet, c'est pourquoi j'ai rédigé cet exemple.

22
répondu duckmayr 2018-09-02 19:06:41