[英]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.