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); было правильным.