Usando C ++ bibliotecas en un paquete R
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?
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()