Как избежать чтения данных из среды R внутри функции Rcpp - PullRequest
1 голос
/ 09 марта 2019

Даже если MyCppFunction(NumericVector x) возвращает желаемый результат, я не уверен в правильном / эффективном способе избежать чтения данных в переменной myY без передачи ее в качестве аргумента функции.

Причина, по которой яне передавайте данные в качестве аргумента, так как в конечном итоге я передам функцию C ++ в качестве целевой функции для минимизации, а подпрограмма минимизации принимает функцию только с одним аргументом, а именно myX. Просто в качестве примера: в R я бы передал myY на optim(...) следующим образом: optim(par,fn=MyRFunction,y=myY).

Любой совет о том, как правильно получить доступ к myY изв C ++ функция приветствуется, вот минимальный пример того, что я боюсь, что это действительно неправильный способ сделать это:

Обновление : я изменил код, чтобы лучше отражать контекста также то, что было предложено в ответах.На всякий случай, фокус моего вопроса лежит на этой строке: NumericVector y = env["myY"]; // How to avoid this?

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
double MyCppFunction(NumericVector x) {

  Environment env = Environment::global_env();
  NumericVector y = env["myY"];  // How to avoid this?

  double res = 0;

  for (int i = 0; i < x.size(); i++) res = res + (x(i) * y(i));

  return res;
}

double MyCppFunctionNoExport(NumericVector x) {

  Environment env = Environment::global_env();
  NumericVector y = env["myY"];  // How to avoid this?

  double res = 0;

  for (int i = 0; i < x.size(); i++) res = res + (x(i) * y(i));

  return res;
}

// [[Rcpp::export]]
double MyCppFunction2(NumericVector x, NumericVector y) {
  double res = 0;

  for (int i = 0; i < x.size(); i++) res = res + (x(i) * y(i));

  return res;
}

// [[Rcpp::export]]
double MyRoutine(NumericVector x, Function fn) {

  for (int i = 0; i < x.size(); i++) fn(x);

  return 0;
}

// [[Rcpp::export]]
double MyRoutineNoExport(NumericVector x) {

  for (int i = 0; i < x.size(); i++) MyCppFunctionNoExport(x);

  return 0;
}

/*** R
MyRFunction <- function(x, y=myY) {
  res = 0
  for(i in 1:length(x)) res = res + (x[i]*y[i])
  return (res)
}

callMyCppFunction2 <- function(x) {
   MyCppFunction2(x, myY)
}

set.seed(123456)

myY = rnorm(1e3)
myX = rnorm(1e3)

all.equal(MyCppFunction(myX), MyRFunction(myX), callMyCppFunction2(myX))

require(rbenchmark)

benchmark(MyRoutine(myX, fn=MyCppFunction),
          MyRoutine(myX, fn=MyRFunction),
          MyRoutine(myX, fn=callMyCppFunction2),
          MyRoutineNoExport(myX), order="relative")[, 1:4]

*/

Вывод :

$ Rscript -e 'Rcpp::sourceCpp("stack.cpp")'
> MyRFunction <- function(x, y = myY) {
+     res = 0
+     for (i in 1:length(x)) res = res + (x[i] * y[i])
+     return(res)
+ }

> callMyCppFunction2 <- function(x) {
+     MyCppFunction2(x, myY)
+ }

> set.seed(123456)

> myY = rnorm(1000)

> myX = rnorm(1000)

> all.equal(MyCppFunction(myX), MyRFunction(myX), callMyCppFunction2(myX))
[1] TRUE

> require(rbenchmark)
Loading required package: rbenchmark

> benchmark(MyRoutine(myX, fn = MyCppFunction), MyRoutine(myX, 
+     fn = MyRFunction), MyRoutine(myX, fn = callMyCppFunction2), 
+     MyRoutineNoEx .... [TRUNCATED] 
                                     test replications elapsed relative
4                  MyRoutineNoExport(myX)          100   1.692    1.000
1      MyRoutine(myX, fn = MyCppFunction)          100   3.047    1.801
3 MyRoutine(myX, fn = callMyCppFunction2)          100   3.454    2.041
2        MyRoutine(myX, fn = MyRFunction)          100   8.277    4.892

Ответы [ 3 ]

3 голосов
/ 09 марта 2019

Используйте два параметра и оберните функцию C ++ в функцию R.

#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
double MyCppFunction(NumericVector x, NumericVector y) {
  return (sum(x) + sum(y));
}

R сторона:

callMyCFunc <- function(x) {
   MyCppFunction(x, myY)
}
2 голосов
/ 09 марта 2019

optim позволяет передавать дополнительные переменные. Здесь мы минимизируем f над x и передаем дополнительную переменную a.

f <- function(x, a) sum((x - a)^2)
optim(1:2, f, a = 1)

дает:

$par
[1] 1.0000030 0.9999351

$value
[1] 4.22133e-09

$counts
function gradient 
      63       NA 

$convergence
[1] 0

$message
NULL
1 голос
/ 09 марта 2019

Другое решение.Установить глобальный в пространстве C:

#include <Rcpp.h>
using namespace Rcpp;

static NumericVector yglobal;

// [[Rcpp::export]]
void set_Y(NumericVector y) {
  yglobal = y;
}

// [[Rcpp::export]]
double MyCppFunction(NumericVector x) {
  double res = 0;
  for (int i = 0; i < x.size(); i++) res = res + (x(i) * yglobal(i));
  return res;
}

Сторона R:

set.seed(123456)

myY = rnorm(1000)
set_Y(myY);
myX = rnorm(1000)

MyCppFunction(myX)

(Примечание: цель static - ограничить область действия переменной вашим конкретным сценарием)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...