2013-12-09 3 views
12

Sto provando a chiamare una routine C dal pacchetto cubature in una funzione C++ per eseguire l'integrazione multidimensionale.utilizzando la funzione C da un altro pacchetto in Rcpp

L'esempio di base R Sto cercando di riprodurre è

library(cubature) 
integrand <- function(x) sin(x) 
adaptIntegrate(integrand, 0, pi) 

ho potuto solo chiamare questa funzione R da Rcpp seguente this recipe from the gallery, ma ci sarebbe qualche penalizzazione delle prestazioni nel passaggio avanti e indietro da C/C++ a R. Sembra più sensato chiamare direttamente la funzione C da C++.

Il C di routine adapt_integrate viene esportato da cubature con

// R_RegisterCCallable("cubature", "adapt_integrate", (DL_FUNC) adapt_integrate); 

Non capisco come chiamare da C++, tuttavia. Ecco il mio tentativo zoppo,

sourceCpp(code = ' 
#include <Rcpp.h> 
using namespace Rcpp; 

// [[Rcpp::export]] 
double integrand(double x){ 
return(sin(x)); 
} 

// [[Rcpp::depends(cubature)]] 
// [[Rcpp::export]] 
Rcpp::List integratecpp(double llim, double ulim) 
{ 
    Rcpp::Function p_cubature = R_GetCCallable("cubature", "adapt_integrate"); 

    Rcpp::List result = p_cubature(integrand, llim, ulim); 
    return(result); 
} 
' 
) 

integratecpp(0, pi) 

Questo non riesce a compilare; chiaramente sto facendo qualcosa di molto sciocco e mi mancano alcuni passaggi importanti per convertire l'output di R_GetCCallable in un Rcpp::Function (o chiamarlo direttamente?). Ho letto diversi post correlati che trattano i puntatori di funzione, ma non ho visto un esempio utilizzando una funzione C esterna.

risposta

6

Purtroppo cubature non spedire le intestazioni in inst/include, in modo da avere a prendere in prestito che da loro e fare qualcosa del genere nel codice:

typedef void (*integrand) (unsigned ndim, const double *x, void *, 
      unsigned fdim, double *fval); 

int adapt_integrate(
    unsigned fdim, integrand f, void *fdata, 
    unsigned dim, const double *xmin, const double *xmax, 
    unsigned maxEval, double reqAbsError, double reqRelError, 
    double *val, double *err) 
{ 
    typedef int (*Fun)(unsigned,integrand,void*,unsigned, 
     const double*,const double*, unsigned, double, double, double*, double*) ; 
    Fun fun = (Fun) R_GetCCallable("cubature", "adapt_integrate") ;   
    return fun(fdim,f,fdata,dim,xmin,xmax,maxEval,reqAbsError, reqRelError,val,err); 
} 

Potrebbe essere una buona idea di negoziare con il manutentore di cubature che spedisce dichiarazioni in inst/include in modo da utilizzare solo LinkingTo.

+0

Mille grazie per aver assemblato questi pezzi mancanti. Dovrò ripensare il problema, sfortunatamente, perché da quello che vedo 'adapt_integrate' non accetterò facilmente un integrando che ho definito usando le strutture dati di armadillo. Per completezza, saresti in grado di aggiungere un minimo esempio di utilizzo? – baptiste

+0

Quello che ti dà è l'accesso al puntatore alla funzione che 'cubature' ha registrato. Non so cosa dovresti fare con la funzione C ... –

+0

anzi, [considerando un esempio di utilizzo] (http://ab-initio.mit.edu/wiki/index.php/Cubature# Esempio) Vedo problemi in avanti: 'adapt_integrate_v' si aspetta puntatori a oggetti come' * fdata', l'integrando si aspetta puntatori come '* fval', mentre gli argomenti che voglio veramente passare sono ad es. oggetti 'arma :: colvec'. Non penso che sarò in grado di fare un ponte tra i due. Potrei dover rimanere con l'interfaccia a livello R, o implementare la mia quadratura 2D in C++. – baptiste

2

Non ho visto questa domanda prima, e sembra che @Romain sia indirizzata.

Per completezza, un esempio pratico di come eseguire questa operazione quando tutte le parti giocano è fornito dai pacchetti xts e RcppXts. In xts, facciamo questo (per una decina di funzioni) nel (fonte) File inst/include/xtsAPI.h:

SEXP attribute_hidden xtsLag(SEXP x, SEXP k, SEXP pad) {  
    static SEXP(*fun)(SEXP,SEXP,SEXP) = NULL;   
    if (fun == NULL)         
     fun = (SEXP(*)(SEXP,SEXP,SEXP)) R_GetCCallable("xts","lagXts"); 
    return fun(x, k, pad);        
} 

insieme alla solita attività di R_registerRoutines e R_RegisterCCallable.

In RcppXts questo viene prelevato (in un modulo Rcpp) come

function("xtsLag", 
     &xtsLag,  
     List::create(Named("x"), Named("k"), Named("pad")), 
     "Extract the coredata from xts object"); 

che funziona abbastanza bene. Qualcuno mi ha rimproverato di scrivere il lato xts in modo più compatto (dato che lo if NULL è spurio) che alla fine arriverò ... alla fine.

+0

grazie per i puntatori, purtroppo questo è un caso in cui elaborare la giusta colla tra i due pezzi di codice mi avrebbe portato via più tempo e sofferenza che effettivamente facendo i calcoli con l'implementazione R più lenta. In caso contrario, prenderei in considerazione il collegamento diretto al codice originale della cubatura piuttosto che tramite il pacchetto R, che utilizza una versione precedente. – baptiste

0

Questa domanda è di tre anni ormai, ma voglio sottolineare che l'integrazione multidimensionale con Rcpp può essere più facile, ora che la libreria RcppNumerical è disponibile: https://github.com/yixuan/RcppNumerical

Le routine per gli integrali di calcolo si basano su Cuba di Thomas Hahn pacchetto e sono anche disponibili nella libreria R2Cuba su CRAN, quindi se è possibile accettare l'utilizzo delle routine Cuba tramite la funzione adaptIntegrate() da Cubature, questo pacchetto potrebbe essere di interesse.

+0

grazie per il puntatore. Tuttavia è probabilmente meglio tenerlo come un commento, poiché la domanda non riguardava specificamente l'integrazione, ma piuttosto l'accesso a una funzione C da un altro pacchetto. Apprezzo molto il collegamento, ho finito per usare la mia copia di cubatura, ma questa sembra una valida alternativa (in particolare se si sta già utilizzando Eigen, ma sono abituato ad Armadillo). Un vantaggio di cubatura è la capacità di gestire integrandi con valori vettoriali. – baptiste