Pregunta

¿Cuál es la mejor manera de hacer uso de una biblioteca de C ++ en I, es de esperar preservar las estructuras de datos del C ++. No estoy en absoluto un usuario C ++, así que no estoy claro sobre los méritos relativos de los enfoques disponibles. El manual de R-ext parece sugerir envolver cada función C ++ en C. Sin embargo, al menos cuatro o cinco otros medios de la incorporación de C ++ existe.

Dos formas son paquetes w / linaje similares, el RCPP (mantenido por los prolíficos overflower Dirk Eddelbuettel) y RcppTemplate paquetes (tanto en CRAN), ¿cuáles son las diferencias entre los dos?

Otro paquete, rcppbind disponibles, en forja R que pretende adoptar un enfoque diferente a C ++ vinculante y R (no estoy capacitado para decir).

El paquete en línea disponibles en CRAN, afirma que permita línea C / C ++ No estoy seguro de que esto se diferencia del construido en la funcionalidad, a un lado para permitir que el código sea en línea w / R.

Y, por último RSwig que parece ser href="http://www.swig.org/Doc1.3/R.html" en el salvaje pero es claro cómo soportado es, como de la autor de la página no ha sido actualizado desde hace años.

Mi pregunta es, ¿cuáles son las ventajas relativas de estos diferentes enfoques. Cuáles son las más portátil y robusto, que son los más fáciles de implementar. Si está pensando en distribuir un paquete en CRAN cuál de los métodos usaría?

¿Fue útil?

Solución

En primer lugar, una aclaración: yo uso RCPP todo el tiempo. De hecho, cuando (habiendo sido rebautizado por el tiempo transcurrido desde RCPP) RcppTemplate ya había quedado huérfano y sin versiones de dos años, empecé a mantenerla bajo su nombre inicial de RCPP (en las que se había contribuido a RQuantLib ). Eso fue hace aproximadamente un año, y he hecho un par de cambios incrementales que se pueden encontrar documentados en el registro de cambios.

Ahora RcppTemplate ha llegado hace muy poco tiempo de vuelta después de un total de treinta y cinco meses sin actualizar o corregir. Contiene interesantes código de nuevo, pero parece que no es compatible con versiones anteriores, así que no voy a utilizar en la que ya se utiliza RCPP.

Rcppbind no se mantuvo muy activa cada vez que lo comprobé. Whit Armstrong también tiene un paquete de interfaz de plantilla llamada rabstraction .

Inline es algo completamente diferente: se facilita la compilación / link ciclo 'Empotrados' de su programa como una cadena de caracteres R, que luego se compila, ligado, y se carga. He hablado con Oleg acerca de tener apoyo en línea RCPP que sería bueno.

trago es interesante también. Joe Wang hizo un gran trabajo allí y se envuelve todos QuantLib para R. Pero la última vez que lo probé, ya no funcionó debido a algunos cambios en las partes internas de I. De acuerdo con alguien del equipo de trago, Joe todavía puede trabajar en él. El objetivo de trago es bibliotecas más grandes de todos modos. Este proyecto probablemente podría hacer con un renacimiento, pero no está exenta de problemas técnicos.

Otra mención debe ir a RInside que trabaja con RCPP y permite incorporar dentro de R de aplicaciones C ++.

Así que para resumir: RCPP funciona bien para mí, sobre todo para las pequeñas exploratoria proyectos en el que sólo desea agregar una función o dos. Es el enfoque es la facilidad de uso, y que le permite 'esconder' algunas de las partes internas de I que no son siempre divertido trabajar con él. Sé de un número de otros usuarios a los que me han ayudado en y fuera y por correo electrónico. Así que diría que ir para éste.

Mi 'Introducción a HPC con R' tutoriales tener algunos ejemplos de RCPP, RInside y en línea.

Editar Así que vamos a ver un ejemplo concreto (tomado de la HPC con R Intro 'diapositivas y tomado de Stephen Milborrow quien lo tomó de Venables y Ripley). La tarea consiste en enumerar todas las combinaciones posibles del determinante de una matriz de 2x2 que contiene sólo dígitos individuales en cada posición. Esto se puede hacer de una forma vectorizada inteligentes (como veremos en las diapositivas de tutoría) o por la fuerza bruta de la siguiente manera:

#include <Rcpp.h>

RcppExport SEXP dd_rcpp(SEXP v) {
  SEXP  rl = R_NilValue;        // Use this when there is nothing to be returned.
  char* exceptionMesg = NULL;   // msg var in case of error

  try {
    RcppVector<int> vec(v);     // vec parameter viewed as vector of ints
    int n = vec.size(), i = 0;
    if (n != 10000) 
       throw std::length_error("Wrong vector size");
    for (int a = 0; a < 9; a++)
      for (int b = 0; b < 9; b++)
        for (int c = 0; c < 9; c++)
          for (int d = 0; d < 9; d++)
            vec(i++) = a*b - c*d;

    RcppResultSet rs;           // Build result set to be returned as list to R
    rs.add("vec", vec);         // vec as named element with name 'vec'
    rl = rs.getReturnList();    // Get the list to be returned to R.
  } catch(std::exception& ex) {
    exceptionMesg = copyMessageToR(ex.what());
  } catch(...) {
    exceptionMesg = copyMessageToR("unknown reason");
  }

  if (exceptionMesg != NULL) 
     Rf_error(exceptionMesg);

  return rl;
}

Si salva esto como, por ejemplo, dd.rcpp.cpp y tienen RCPP instalado, a continuación, simplemente utilizar

PKG_CPPFLAGS=`Rscript -e 'Rcpp:::CxxFlags()'`  \
    PKG_LIBS=`Rscript -e 'Rcpp:::LdFlags()'`  \
    R CMD SHLIB dd.rcpp.cpp

para construir una biblioteca compartida. Utilizamos Rscript (o r) para pedir RCPP sobre sus lugares de encabezado y biblioteca. Una vez construido, se puede cargar y utilizar esto desde R de la siguiente manera:

dyn.load("dd.rcpp.so")

dd.rcpp <- function() {
    x <- integer(10000)
    res <- .Call("dd_rcpp", x)
    tabulate(res$vec)
}

De la misma manera, puede enviar vectores, MATRICS, ... de diferentes R y C ++ tipos de datos back-end a otro con facilidad. Espero que esto ayude un poco.

Editar 2 (+ unos cinco años más tarde):

Así que esta respuesta acaba de conseguir un upvote y por lo tanto burbujeaba en mi cola. Un mucho de tiempo ha pasado desde que lo escribí, y RCPP hcomo metido mucho más rica en características. Así que muy rápidamente escribí este

#include <Rcpp.h>

// [[Rcpp::export]]
Rcpp::IntegerVector dd2(Rcpp::IntegerVector vec) {
    int n = vec.size(), i = 0;
    if (n != 10000) 
        throw std::length_error("Wrong vector size");
    for (int a = 0; a < 9; a++)
        for (int b = 0; b < 9; b++)
            for (int c = 0; c < 9; c++)
                for (int d = 0; d < 9; d++)
                    vec(i++) = a*b - c*d;
    return vec;
}

/*** R
x <- integer(10000)
tabulate( dd2(x) )
*/

que puede ser utilizado de la siguiente manera con el código en un /tmp/dd.cpp archivo

R> Rcpp::sourceCpp("/tmp/dd.cpp")    # on from any other file and path

R> x <- integer(10000)

R> tabulate( dd2(x) )
 [1]  87 132 105 155  93 158  91 161  72 104  45 147  41  96
[15]  72 120  36  90  32  87  67  42  26 120  41  36  27  75
[29]  20  62  16  69  19  28  49  45  12  18  11  57  14  48
[43]  10  18   7  12   6  46  23  10   4  10   4   6   3  38
[57]   2   4   2   3   2   2   1  17
R> 

Algunas de las principales diferencias son:

  • más simple de construcción: simplemente sourceCpp() ella; incluso ejecuta código de prueba R al final
  • tipo IntegerVector de pleno derecho
  • envoltura de control de excepciones añadido automáticamente por el generador de código sourceCpp()
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top