studio software sitio org mexico language data c++ r fortran rcpp armadillo

c++ - software - sitio cran



Integrar Fortran, C++ con R (1)

Mi tarea es reescribir una función R en C ++ para acelerar los bucles while. Todos los códigos R han sido reescritos en la ayuda de Rcpp y Armadillo, excepto el .Fortran() . Intento usar Rinside al principio y funciona a una velocidad muy lenta como lo indicó Dirk. (Es costoso que los datos pasen por R -> C ++ -> R -> Fortran)

Como no quiero volver a escribir los códigos de Fortran en C ++ y viceversa, parece natural acelerar los programas al vincular C ++ directamente a 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); }

El problema es que puedo integrar C ++ con Fortran e integrar R con C ++, ¡pero no puedo hacer que estas tres cosas funcionen juntas!

Intento compilar C ++ en Linux, pero simplemente no puedo encontrar RcppArmadillo.h y namespace Rcpp :

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

Cuando llamo a sourceCpp("test.cpp") en R directamente, la consola mostrará:

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.

También trato de combinar todas estas cosas en un paquete por

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

Pero no sé cómo tratar con el paquete TTTest (creo que no se pudo instalar) luego de agregar los archivos .cpp y .f a /src y ejecutar compileAttributes .

Entonces, ¿es posible hacer cosas como lo que imagino por Rcpp? ¿O es necesario convertir los códigos de Fortran a códigos C / C ++?

Gracias por tu ayuda.


Yo sugeriría que tales proyectos incluyan su código en un paquete. mixedlang un ejemplo simple de tal paquete que llamé mixedlang que está disponible en este repositorio de GitHub . Describiré el proceso de creación del paquete aquí.

Los pasos que tomé fueron los siguientes:

  1. Configure la estructura del paquete desde R con RcppArmadillo::RcppArmadillo.package.skeleton("mixedlang") (solo usé RcppArmadillo en lugar de Rcpp ya que el OP era, no hay nada específico de Armadillo en este ejemplo)
  2. Se agregaron los archivos de código C ++ y Fortran que se describen a continuación a la carpeta src/
  3. En R, ejecute Rcpp::compileAttributes("mixedlang/") luego devtools::install("mixedlang/")

El código

Creé una función simple de C ++ cuyo único propósito (esencialmente) era llamar a una función de Fortran. La función de ejemplo toma un vector numérico, multiplica cada elemento por su índice y devuelve el resultado. Primero veamos el código de Fortran:

fortranfunction.f90

Esta función solo toma dos dobles y los multiplica, devolviendo el resultado:

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

test_function.cpp

Ahora necesitamos llamar a este código Fortran desde nuestro código C ++. Al hacer esto, debemos tener en cuenta algunas cosas:

  1. Los argumentos de Fortran se pasan por referencia, no por valor.
  2. Como MULTIPLY está definido en otro archivo, debemos declararlo en nuestro archivo C ++ para que el compilador conozca los tipos de argumento y retorno.

    a. Al declarar la función Fortran para nuestro archivo C ++, descartaremos el caso del nombre de la función y añadiremos un guión bajo, ya que el compilador Fortran debería hacer esto de forma predeterminada.

    segundo. Tenemos que declarar la función dentro de una especificación de vinculación extern "C" ; Normalmente, los compiladores de C ++ no pueden usar los nombres de las funciones como identificadores únicos, ya que permite la sobrecarga, pero para llamar a las funciones de Fortran, necesitamos que haga exactamente lo que cumple la especificación de vinculación extern "C" (consulte, por ejemplo, esta respuesta SO ).

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

Ejemplo de salida

Después de instalar el paquete, corrí como ejemplo

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

Fuentes probables de los problemas del cartel original.

  1. Al intentar compilar inicialmente, no le permitieron al compilador saber dónde estaba RcppArmadillo.h .
  2. Tratar de hacer esto con sourceCpp es solo pedir problemas; en realidad no fue hecho para manejar múltiples archivos (ver, por ejemplo, esta respuesta de Dirk Eddelbuettel ), lo cual es necesario cuando se trata de múltiples idiomas.

No estoy seguro de lo que sucedió cuando trataron de incluirlo en un paquete, por eso dibujé este ejemplo.