12

我正在为我的问题使用非常具体的模拟退火算法在 R 中构建一个包,我对我无法解决的 C 代码和 SEXP 有疑问。我不是 R 方面的专家,我只使用它 3 周......但我必须这样做。

据我所知,.CallR 中的函数通过引用将参数作为 SEXP 结构传递给 C(即它们不重复)。我对吗?如果我在 C 中有另一个函数从需要这个 SEXP 结构的 C 中的第一个函数调用,该怎么办?(见示例)。我之所以问是因为其中一个参数很大并且占用了大量空间(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 中?非常感谢您的帮助。

4

1 回答 1

8

编写的代码几乎(语法上)正确,并且没有内存复制;从 R 传递给 C 的参数应被视为“只读”。

一个常见的范例是编写一个 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在 Energy 中使用的)。你的使用PROTECT(...); REAL(Ene)[0] = ...; UNPROTECT(Ene);是正确的。

于 2013-09-27T12:37:02.440 回答