Pergunta

Qual é a melhor maneira de fazer uso de uma biblioteca C ++ em R, espero preservar os ++ estruturas de dados C. Eu não estou de todo usuário a C ++, então eu não estou claro sobre os méritos relativos das abordagens disponíveis. O manual R-ext parece sugerir envolvendo cada função C ++ em C. No entanto, pelo menos quatro ou cinco outros meios de incorporação de existir C ++.

Duas maneiras são pacotes w / linhagem semelhante, o Rcpp (mantido pelo prolífico overflower Dirk Eddelbuettel) e pacotes RcppTemplate (ambos em CRAN), quais são as diferenças entre os dois?

Outro pacote, rcppbind disponíveis, em R forja que afirma ter uma abordagem diferente à ligação C ++ e R (eu não sou experiente para dizer).

O pacote em linha disponível em CRAN, reivindicações para permitir linha C / C ++ não tenho certeza o que difere da construído em termos de funcionalidade, além de permitir que o código seja em linha w / R.

E, finalmente RSwig que parece ser na selvagem, mas é como claro suportado é, como página do autor não foi atualizado há anos.

A minha pergunta é, quais são os méritos relativos dessas diferentes abordagens. Quais são os mais portátil e robusta, que são os mais fáceis de implementar. Se você estava planejando distribuir um pacote em CRAN qual dos métodos você usaria?

Foi útil?

Solução

Primeiro, um aviso: eu uso Rcpp o tempo todo. Na verdade, quando (tendo sido renomeado pelo tempo de Rcpp) RcppTemplate já haviam sido órfãs e sem versões de dois anos, comecei a mantê-lo sob seu nome inicial de Rcpp (sob o qual tinha sido contribuiu para RQuantLib ). Isso foi cerca de um ano atrás, e eu fiz um par de mudanças incrementais que você pode encontrar documentados no ChangeLog.

Agora RcppTemplate chegou muito recentemente de volta depois de um total de trinta e cinco meses sem qualquer atualização ou correção. Ele contém código novo e interessante, mas parece que não é compatível com versões anteriores por isso não vou usá-lo onde eu já utilizado Rcpp.

Rcppbind não foi mantido de forma muito activa, sempre que eu verifiquei. Whit Armstrong também tem um pacote de interface de templated chamado rabstraction .

inline é algo completamente diferente: ela facilita a compilação / ciclo ligação por 'encaixar' o seu programa como uma cadeia de caracteres R que, em seguida, é compilado, vinculado, e carregado. Eu tenho conversado com Oleg sobre ter suporte embutido Rcpp que seria bom.

Swig é interessante também. Joe Wang fez grande trabalho lá e envolveu todos QuantLib para R. Mas quando eu última tentei, ele já não funcionava devido a algumas alterações nos internos R. De acordo com alguém da equipe Swig, Joe ainda pode trabalhar nele. O objetivo do Swig é bibliotecas maiores de qualquer maneira. Este projeto poderia provavelmente fazer com um renascimento, mas não é sem desafios técnicos.

Outra menção deve ir para a RInside que trabalha com Rcpp e permite que você incorpore R dentro de aplicações C ++.

Assim, para resumir: Rcpp funciona bem para mim, especialmente para pequenas exploratória projectos em que você apenas deseja adicionar uma função ou dois. É foco é a facilidade de utilização, e que lhe permite 'esconder' alguns dos internos R que não são sempre divertido trabalhar com. Eu sei de uma série de outros usuários, a quem ajudou na e e off via email. Então, eu diria que ir para este.

Meu 'Intro para HPC com R' tutoriais tem alguns exemplos de Rcpp, RInside e em linha.

Editar: Então, vamos olhar para um exemplo concreto (retirado do 'HPC com R Intro' escorregas e emprestado de Stephen Milborrow que tirou de Venables e Ripley). A tarefa consiste em enumerar todas as combinações possíveis do determinante de uma matriz 2x2 contendo apenas um dígito em cada posição. Isso pode ser feito de maneiras vectorized inteligentes (como discutimos nos slides tutorial) ou pela força bruta da seguinte forma:

#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 você salve como, digamos, dd.rcpp.cpp e têm Rcpp instalado, em seguida, basta utilização

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

para construir uma biblioteca compartilhada. Usamos Rscript (ou r) para pedir Rcpp sobre seu cabeçalho e locais de biblioteca. Uma vez construído, podemos carregar e usar isso a partir de R da seguinte forma:

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

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

Da mesma forma, você pode enviar vetores, MATRICS, ... de várias R e limits.h ++ back-end para trás com facilidade. Espero que isso ajude um pouco.

Editar 2 (cerca de cinco anos + tarde):

Assim, esta resposta só tenho um upvote e, portanto, borbulhou na minha fila. Um monte de tempo se passou desde que eu escrevi, e Rcpp hcomo obtido muito mais rico em recursos. Então, eu muito rapidamente escreveu 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 pode ser usado da seguinte maneira com o código em um arquivo /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> 

Algumas das principais diferenças são:

  • construir mais simples: basta sourceCpp()-lo; mesmo executa código de teste R no final
  • Tipo IntegerVector de pleno direito
  • embalagem de tratamento de exceção adicionado automaticamente pelo gerador de código sourceCpp()
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top