Domanda

Qual è il modo migliore per fare uso di una libreria C ++ in R, si spera preservando il C ++ strutture di dati. Io non sono affatto un utente C ++, quindi non sono chiare sui meriti relativi degli approcci disponibili. Il manuale R-ext sembra suggerire avvolgere ogni funzione C ++ in C. Tuttavia, almeno quattro o cinque altri mezzi di incorporare C ++ esiste.

Due modi sono pacchetti w / simile lignaggio, il Rcpp (mantenuta dal prolifico overflower Dirk Eddelbuettel) e RcppTemplate pacchetti (sia su CRAN), quali sono le differenze tra i due?

Un altro pacchetto, rcppbind disponibili, sulla fucina R che pretende di adottare un approccio diverso al legame C ++ e R (io non sono esperto per dire).

La linea pacchetto disponibile sul CRAN, sostiene di consentire linea C / C ++ non sono sicuro che questo si differenzia dal sviluppato in funzionalità, a parte per consentire il codice per essere in linea w / R.

E, infine RSwig che sembra essere href="http://www.swig.org/Doc1.3/R.html" in natura ma è chiaro come sostenuto è, come la pagina del autore non è stato aggiornato da anni.

La mia domanda è, quali sono i meriti relativi di questi diversi approcci. Quali sono i più portatile e robusto, che sono le più facili da implementare. Se avete intenzione di distribuire un pacchetto su CRAN quale dei metodi useresti?

È stato utile?

Soluzione

Prima di tutto, un disclaimer: io uso Rcpp tutto il tempo. Infatti, quando (essendo stato rinominato per il momento da Rcpp) RcppTemplate era già stato orfano e senza aggiornamenti per due anni, ho iniziato a mantenerlo sotto il suo nome iniziale di Rcpp (in base al quale era stata contribuito a RQuantLib ). E 'stato circa un anno fa, e ho fatto un paio di modifiche incrementali che si può trovare documentati nel changelog.

Ora RcppTemplate è a poco tempo fa tornare dopo ben trentacinque mesi senza alcun aggiornamento o correggere. Contiene nuovo codice interessante, ma sembra che non sia compatibile quindi non voglio usarlo dove ho già usato Rcpp.

Rcppbind non è stata mantenuta molto attivamente ogni volta che ho controllato. Whit Armstrong ha anche un pacchetto di interfaccia su modelli chiamato rabstraction .

Inline è qualcosa di completamente diverso: facilita la compilazione / link ciclo 'incorporando' il tuo programma come una stringa di caratteri R che poi viene compilato, legata, e caricato. Ho parlato con Oleg di avere in linea il supporto Rcpp che sarebbe bello.

Swig è interessante anche. Joe Wang ha fatto grande lavoro lì e avvolto tutti QuantLib per R. Ma quando ho provato l'ultima, non è più funzionato a causa di alcuni cambiamenti nella struttura interna R. Secondo qualcuno della squadra Swig, Joe può ancora lavorare su di esso. L'obiettivo di Swig è librerie più grandi comunque. Questo progetto potrebbe probabilmente fare con un rilancio, ma non è senza sfide tecniche.

Un altro menzione dovrebbe andare a RInside che funziona con Rcpp e consente di incorporare all'interno R di applicazioni C ++.

Quindi, per riassumere: Rcpp funziona bene per me, soprattutto per le piccole esplorativa progetti in cui si desidera solo aggiungere una funzione o due. Il suo obiettivo è la facilità d'uso, e ti permette di 'nascondere' alcuni degli interni R che non sono sempre divertente lavorare con. So di un certo numero di altri utenti i quali mi hanno aiutato in e fuori e via e-mail. Quindi direi andare per questo.

Il mio 'Introduzione a HPC con R' tutorial avere alcuni esempi di Rcpp, RInside e in linea.

Modifica Quindi diamo un'occhiata a un esempio concreto (tratto dal 'HPC con R Intro' diapositive e presa in prestito da Stephen Milborrow che ha preso da Venables e Ripley). Il compito è enumerare tutte le possibili combinazioni del determinante di una matrice 2x2 contenente solo singole cifre in ciascuna posizione. Questo può essere fatto in modi Vectorised intelligenti (come vedremo nelle diapositive di tutorial) o con la forza bruta nel seguente modo:

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

Se si salva questo come, ad esempio, dd.rcpp.cpp e hanno Rcpp installato, quindi è sufficiente usare

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

per costruire una libreria condivisa. Usiamo Rscript (o r) chiedere Rcpp sulle sue sedi di intestazione e libreria. Una volta costruito, siamo in grado di caricare e utilizzare questo da R come segue:

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

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

Allo stesso modo, è possibile inviare vettori, Matrics, ... di vari R e C ++ tipi di dati back-end indietro con facilità. Spero che questo aiuti un po '.

Modifica 2 (circa cinque anni + tardi):

Quindi, questa risposta appena ricevuto un upvote e quindi gorgogliare nella mia coda. A molto di tempo è passato da quando l'ho scritto, e Rcpp hcome ottenuto molto più ricco di funzionalità. Così ho scritto molto rapidamente questo

#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) )
*/

che può essere utilizzato nel modo seguente con il codice in un file /tmp/dd.cpp

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> 

Alcune delle differenze principali sono:

  • semplice accumulo: basta sourceCpp() esso; anche esegue R codice di prova all'estremità
  • a tutti gli effetti di tipo IntegerVector
  • gestione delle eccezioni involucro aggiunto automaticamente dal generatore di codice sourceCpp()
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top