簡體   English   中英

從rcpp返回R函數

[英]Returning an R function from rcpp

在Rcpp中是否有一種方法可以返回一個帶有一些預計算值的R函數,這些值只在第一次函數調用時計算出來? 考慮以下R代碼:

1: func_generator<-function(X) {
2:  X_tot<-sum(X)
3:  function(b_vec) { (X_tot*b_vec) }
4: }
5: myfunc<-func_generator(c(3,4,5))
6: myfunc(1:2)
7: myfunc(5:6)
8: myfunc2<-func_generator(c(10,11,12,13))
...

這可以用Rcpp編程嗎? 在實踐中,假設代替第2行進行更加計算密集的操作。

為了添加上下文,給定向量X和標量b,有一些似然函數f(b | X),它可以重新表達為f(b,s(X)),用於某些足夠的統計量s(X),它只是一個函數X的,涉及一些計算。 這是一個計算密集型的計算機實驗,有許多向量X(很多可能性),並且對於每個可能性有許多單獨調用f(bvec | X),所以我寧願計算s(X)一次(對於每個可能性)和以某種方式保存它而不是多次重新計算它。 我開始只是簡單編程f(bvec,X)來評估點bvec =(b_1,...,b_n)處的f(b | X),但這有額外的開銷,因為我多次調用此函數並且它每次運行時計算s(X)。 我想只計算一次s(X)。

任何有關在Rcpp中有效完成此任務的建議都將受到贊賞(無論是通過返回函數;還是通過以某種其他方式存儲中間計算)。

存儲中間結果的一種簡單方法是在函數級別的靜態變量:

// [[Rcpp::plugins(cpp11)]]
#include <thread>
#include <chrono>
#include <Rcpp.h>

// [[Rcpp::export]]
Rcpp::NumericVector foo(Rcpp::NumericVector X, Rcpp::NumericVector b, bool useCache = true) {
  static double cache;
  static bool initialized{false};
  if (!(useCache && initialized)) {
    // sleep to simulate actual work
    std::this_thread::sleep_for (std::chrono::seconds(1));
    cache = Rcpp::sum(X);
    initialized = true;
  }
  return cache * b;
}

/*** R
X <- 1:10
b <- 10:20

system.time(r1 <- foo(X, b))
system.time(r2 <- foo(X, b))
all.equal(r1, r2)
system.time(r3 <- foo(X, b, FALSE))
all.equal(r1, r3)
*/

輸出:

> system.time(r1 <- foo(X, b))
   user  system elapsed 
      0       0       1 

> system.time(r2 <- foo(X, b))
   user  system elapsed 
  0.002   0.000   0.002 

> all.equal(r1, r2)
[1] TRUE

> system.time(r3 <- foo(X, b, FALSE))
   user  system elapsed 
      0       0       1 

> all.equal(r1, r3)
[1] TRUE

當在第二個函數調用中使用緩存時,幾乎立即計算結果。

如果您可以在不同X的循環內循環不同的b則此方法很有效。 如果此限制對您不起作用,那么您可以使用R級別的memoise包來有效地存儲昂貴函數的輸出以進行任意輸入:

// [[Rcpp::plugins(cpp11)]]
#include <thread>
#include <chrono>
#include <Rcpp.h>

// [[Rcpp::export]]
Rcpp::NumericVector foo(double total, Rcpp::NumericVector b) {
  return total * b;
}

// [[Rcpp::export]]
double bar(Rcpp::NumericVector X) {
  // sleep to simulate actual work
  std::this_thread::sleep_for (std::chrono::seconds(1));
  return Rcpp::sum(X);
}


/*** R
X1 <- 1:10
b1 <- 10:20
X2 <- 10:1
b2 <- 20:10

library(memoise)
bar2 <- memoise(bar)

system.time(r11 <- foo(bar2(X1), b1))
system.time(r21 <- foo(bar2(X2), b2))
system.time(r12 <- foo(bar2(X1), b1))
system.time(r22 <- foo(bar2(X2), b2))
all.equal(r11, r12)
all.equal(r21, r22)
*/

輸出:

> system.time(r11 <- foo(bar2(X1), b1))
   user  system elapsed 
  0.001   0.000   1.001 

> system.time(r21 <- foo(bar2(X2), b2))
   user  system elapsed 
  0.033   0.000   1.033 

> system.time(r12 <- foo(bar2(X1), b1))
   user  system elapsed 
      0       0       0 

> system.time(r22 <- foo(bar2(X2), b2))
   user  system elapsed 
      0       0       0 

> all.equal(r11, r12)
[1] TRUE

> all.equal(r21, r22)
[1] TRUE

作為替代方案,您還可以將這兩個函數用作函數生成器的構建塊:

func_generator <- function(X) {
  X_tot <- bar(X)
  function(b_vec) { foo(X_tot, b_vec) }
}
myfunc <- func_generator(c(3,4,5))
myfunc2 <- func_generator(c(10,11,12,13))
myfunc(1:2)
myfunc(5:6)
myfunc2(1:2)
myfunc2(5:6)

因此,在C ++中保留數字昂貴的工作,但要保持簡單。 然后可以使用R添加功能方面。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM