R,.Call и структуры SEXP
Я создаю пакет в R с очень специфическим алгоритмом Simulated Annealing для моей проблемы, и у меня есть сомнения относительно кода C и SEXP, которые я не смог решить. Я не эксперт в R, я работаю с ним всего на 3 недели... но я должен это сделать.
Насколько мне известно, функция .Call
в R передает параметры как структуру SEXP в C по ссылке (то есть они не дублируются). Я прав? Что делать, если у меня есть другая функция в C, вызванная первой функцией в C, которая нуждается в этой структуре SEXP? (См. Пример). Я спрашиваю, потому что один из этих параметров довольно большой и использует много пространства (10 ^ 7 ~ 10 ^ 18 удваивается, хотя я не использую их всех на каждой итерации), и я буду называть эту функцию довольно много раз, поэтому, если каждый раз, когда я его вызываю, этот параметр будет дублироваться, у меня закончится память.
MWE:
R вызов
MySimAn <- function(def_energy, i_pos, T0, Tfinal){
ret <- .Call("CMySimAn",def_energy, i_pos, T0, Tfinal, seq0)
ret
}
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;
}
Будет что-то вроде этой работы (код в функции Energy
не проверен, так что может быть неправильно)? Могу ли я создавать дубликат def_energy каждый раз, когда я его называю, в R или C? Большое вам спасибо за вашу помощь.
Ответы
Ответ 1
Код почти (синтаксически) корректен, как написано, и копирование памяти отсутствует; аргументы, переданные C из R, должны рассматриваться как "только для чтения".
Общая парадигма заключается в написании интерфейса интерфейса R/C с любыми функциями, называемыми из этого слоя в чистом (не-R) C. Итак
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);
}
Используйте const
для принудительного применения неявного контракта, чтобы значения, переданные из R, не записывались. С оберткой 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);
}
Аксессуар для числовых элементов REAL()
(вы использовали NUMERIC
в Энергии). Ваше использование PROTECT(...); REAL(Ene)[0] = ...; UNPROTECT(Ene);
было правильным.