Question

Quelle est la meilleure façon d'utiliser une bibliothèque C ++ en R, en préservant les structures, espérons de données C +. Je ne suis pas du tout un utilisateur C ++, donc je ne suis pas clair sur les mérites relatifs des approches disponibles. Le manuel R-ext semble suggérer envelopper chaque fonction C ++ en C. Cependant, au moins quatre ou cinq autres moyens d'incorporation de C ++ existe.

Deux voies sont paquets w / lignée similaire, le CRPP (maintenu par les prolifiques overflower Dirk Eddelbuettel) paquets et RcppTemplate (à la fois sur CRAN), quelles sont les différences entre les deux?

Un autre paquet, rcppbind disponible, sur la forge de R qui prétend adopter une approche différente à la liaison C ++ et R (Je ne suis pas bien informé de dire).

La ligne de package disponible sur CRAN, prétend permettre inline C / C ++ Je ne suis pas sûr que cela diffère de la fonctionnalité intégrée, permettant de côté pour que le code soit en ligne w / R.

Et enfin RSwig qui semble être dans la sauvage, mais il est ne sait pas comment il est pris en charge, comme la page n'a pas été mis à jour depuis des années.

Ma question est, quels sont les mérites relatifs de ces différentes approches. Quelles sont les plus portables et robustes, qui sont les plus faciles à mettre en œuvre. Si vous aviez l'intention de distribuer un paquet sur lequel des CRAN méthodes utiliseriez-vous?

Était-ce utile?

La solution

Tout d'abord, un avertissement: J'utilise CRPP tout le temps. En fait, quand (après avoir été renommé par le temps de CRPP) RcppTemplate avait déjà été rendus orphelins et sans mises à jour pendant deux ans, je commençais à le maintenir sous son nom initial de CRPP (en vertu de laquelle il avait été contribué à rquantlib ). C'était il y a environ un an, et je l'ai fait quelques changements supplémentaires que vous pouvez trouver documentés dans le ChangeLog.

RcppTemplate est venu récemment de retour après trente-cinq mois complets sans aucune mise à jour ou corriger. Il contient un nouveau code intéressant, mais il semble qu'il ne soit pas rétrocompatible, donc je ne vais pas l'utiliser où je l'ai déjà utilisé CRPP.

Rcppbind n'a pas été maintenu très activement chaque fois que je vérifié. Whit Armstrong a aussi un paquet d'interface appelé rabstraction .

Inline est quelque chose de complètement différent: il facilite la compilation / cycle de lien par « intégration » de votre programme en tant que chaîne de caractères R qui obtient ensuite compilé, lié et chargé. J'ai parlé à Oleg d'avoir un soutien en ligne CRPP qui serait bien.

Swig est trop intéressante. Joe Wang a fait beaucoup de travail là-bas et enveloppé tous QuantLib pour R. Mais dernière fois que je l'ai essayé, il ne fonctionnait plus en raison de certains changements dans R internes. Selon une personne de l'équipe Swig, Joe peut encore travailler. L'objectif de Swig est de plus grandes bibliothèques de toute façon. Ce projet pourrait probablement faire avec un réveil mais pas sans difficultés techniques.

Une autre mention devrait aller à RInside qui fonctionne avec CRPP et vous permet d'intégrer R à l'intérieur des applications de carbone.

Donc, pour résumer: CRPP fonctionne bien pour moi, en particulier pour les petites exploratoires projets dans lesquels vous voulez juste ajouter une fonction ou deux. Il Concentrons est la facilité d'utilisation, et il vous permet de « cacher » certains des R internes qui ne sont pas toujours amusant de travailler avec. Je connais un certain nombre d'autres utilisateurs que je l'ai aidé sur et hors et par courrier électronique. Je dirais donc aller pour celui-ci.

My 'Introduction à la HPC avec R' tutoriels ont quelques exemples de CRPP, RInside et en ligne.

Modifier Alors regardons un exemple concret (tiré de la « HPC avec R Intro » diapositives et emprunté à Stephen Milborrow qui a pris de Venables et Ripley). La tâche est d'énumérer toutes les combinaisons possibles du déterminant d'une matrice 2x2 contenant seulement un seul chiffre dans chaque position. Cela peut se faire de façon intelligente vectorisées (comme nous le verrons dans les coulisses de tutoriel) ou par la force brute comme suit:

#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 vous enregistrez ce que, disons, dd.rcpp.cpp et ont CRPP installé, simplement utiliser

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

pour construire une bibliothèque partagée. Nous utilisons Rscript (ou r) demander CRPP sur ses sites d'en-tête et bibliothèque. Une fois construit, nous pouvons charger et utiliser de R comme suit:

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

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

De la même manière, vous pouvez envoyer des vecteurs, MATRICS, ... de divers R et les types de données C de back-end en avant avec facilité. Espérons que cela aide un peu.

Edit 2 (environ cinq ans plus tard +):

Alors cette réponse viens de recevoir un upvote et donc barboter dans ma file d'attente. beaucoup de temps écoulé depuis je l'ai écrit, et CRPP hcomme obtenu beaucoup plus riche en fonctionnalités. Donc, très rapidement, j'écrit ce

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

qui peut être utilisé comme suit avec le code dans un fichier /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> 

Certaines des principales différences sont les suivantes:

  • construction plus simple: il suffit sourceCpp() il; même exécute le code de test R à la fin
  • type IntegerVector à part entière
  • wrapper de gestion des exceptions ajouté automatiquement par le générateur de code sourceCpp()
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top