2013-09-27 18 views
12

Sto costruendo un pacchetto in R con un algoritmo di Annealing Simulato molto specifico per il mio problema, e ho un dubbio sul codice C e sul SEXP che non sono stato in grado di risolvere. Non sono un esperto di R, ci lavoro da solo 3 settimane ... ma devo farlo.R, .Call function e strutture SEXP

Per quanto ne so, la funzione .Call in R passa i parametri come struttura SEXP a C per riferimento (ovvero non sono duplicati). Ho ragione? Cosa succede se ho un'altra funzione in C chiamata dalla prima funzione in C che ha bisogno di questa struttura SEXP? (Vedi esempio). Sto chiedendo perché uno di questi parametri è abbastanza grande e usa molto spazio (10^7 ~ 10^18 raddoppia, anche se non li uso tutti in ogni iterazione) e chiamerò questa funzione un bel po 'di volte , quindi se ogni volta che lo chiamo questo parametro viene duplicato, esaurirò la memoria.

MWE:

R chiamata

MySimAn <- function(def_energy, i_pos, T0, Tfinal){ 
    ret <- .Call("CMySimAn",def_energy, i_pos, T0, Tfinal, seq0) 
    ret 
} 

funzioni C

double Energy(SEXP def_energy, SEXP seq0, int i0){ 
    int i; 
    double res=0; 
    for(i=0;i<INTEGER(GET_DIM(seq0))[0];i++){ 
    res += NUMERIC(def_energy)[i0+INTEGER(seq0)[i]]; 
    } 
    return(res); 
} 

SEXP CmySimAn(SEXP def_energy, SEXP i_pos, SEXP T0, SEXP Tfinal, SEXP seq0){ 
    SEXP = Ene; 
    PROTECT(Ene = NEW_NUMERIC(1)); 
    REAL(Ene)[0] = Energy(def_energy, seq0, INTEGER(i_pos)); 
    UNPROTECT(1); 
    return Ene; 
} 

Sarebbe qualcosa di simile a questo lavoro (il codice nella funzione Energy non viene controllato in modo potrebbe essere sbagliato)? Creerei un duplicato di def_energy ogni volta che lo chiamo, sia in R o C? Grazie mille per il tuo aiuto.

risposta

8

Il codice è quasi (sintatticamente) corretto come scritto, e non c'è copia di memoria; gli argomenti passati a C da R devono essere trattati come "di sola lettura".

Un paradigma comune è quello di scrivere uno strato di interfaccia R/C, con qualsiasi funzione chiamata da tale strato in puro (non R) C. Quindi

double Energy(const double *def_energy, const int *seq0, int dim0, int i0) 
{ 
    int i; 
    double res=0; 
    for(i = 0; i < dim0; i++) { 
    res += def_energy[i0 + seq0[i]]; 
    } 
    return(res); 
} 

Usa const ad applicare il contratto implicito che il i valori passati da R non dovrebbero essere scritti su. Con l'involucro di R/C

SEXP CmySimAn(SEXP def_energy, SEXP i_pos, SEXP T0, SEXP Tfinal, SEXP seq0){ 
    double Ene = Energy(REAL(def_energy), INTEGER(seq0), INTEGER(GET_DIM(seq0)[0]), 
         INTEGER(i_pos)[0]); 
    return ScalarReal(Ene); 
} 

La funzione di accesso per gli elementi numerici è REAL() (si è utilizzato NUMERIC in Energy). L'utilizzo di PROTECT(...); REAL(Ene)[0] = ...; UNPROTECT(Ene); era corretto.

+1

Grazie mille. Quindi, tutte le funzioni C "interne" chiamate in puro C. L''INTEGER (i_pos) [0]' è perché 'INTEGER (i_pos)' è un puntatore, vero? –

+3

Sì, gli accessori 'INTEGER()', 'REAL()' sono tutti punti di ritorno. –

Problemi correlati