2013-09-27 183 views
12

Tôi đang xây dựng một gói trong R với thuật toán mô phỏng rất cụ thể cho vấn đề của tôi, và tôi nghi ngờ về mã C và SEXP mà tôi không thể giải quyết được. Tôi không phải là chuyên gia về R, tôi đã làm việc với nó chỉ trong 3 tuần ... nhưng tôi phải làm điều này.R, .Call chức năng, và cấu trúc SEXP

Theo như tôi biết, hàm .Call trong R chuyển các tham số dưới dạng cấu trúc SEXP đến C theo tham chiếu (nghĩa là chúng không bị trùng lặp). Tôi có đúng không? Điều gì sẽ xảy ra nếu tôi có một hàm khác trong C được gọi là từ hàm đầu tiên trong C cần cấu trúc SEXP này? (Xem ví dụ). Tôi hỏi vì một trong những tham số này khá lớn và sử dụng nhiều không gian (10^7 ~ 10^18 đôi, mặc dù tôi không sử dụng tất cả trong mỗi lần lặp lại) và tôi sẽ gọi hàm này khá nhiều lần , vì vậy nếu mỗi lần tôi gọi nó là tham số này sẽ bị trùng lặp, tôi sẽ hết bộ nhớ.

MWe:

R gọi

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

C chức năng

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

Would cái gì đó như công việc này (mã trong hàm Energy không được chọn nên có thể sai)? Tôi sẽ tạo một bản sao của def_energy mỗi khi tôi gọi nó, cho dù trong R hay C? Cảm ơn bạn rất nhiều vì đã giúp đỡ của bạn.

Trả lời

8

Mã gần đúng (cú pháp) như được viết và không có sao chép bộ nhớ; các đối số được chuyển đến C từ R sẽ được coi là 'chỉ đọc'.

Một mô hình phổ biến là viết một lớp giao diện R/C, với bất kỳ chức năng gọi từ lớp rằng trong tinh khiết (không-R) C. Vì vậy,

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

Sử dụng const để thực thi các hợp đồng ngầm rằng các giá trị được truyền từ R không được ghi vào. Với wrapper 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); 
} 

Các accessor cho các yếu tố số là REAL() (bạn sử dụng NUMERIC trong Năng lượng). Việc bạn sử dụng PROTECT(...); REAL(Ene)[0] = ...; UNPROTECT(Ene); là chính xác.

+1

Cảm ơn bạn rất nhiều. Vì vậy, tất cả các hàm "bên trong" C được gọi trong pure C. 'INTEGER (i_pos) [0]' là bởi vì 'INTEGER (i_pos)' là một con trỏ, tôi có đúng không? –

+3

Có, các accessor 'INTEGER()', 'REAL()' là tất cả các điểm trả về. –