避免在嵌套循环中过多"声明 Rcpp 列表的相同元素"



我想问一下如何在嵌套循环中节省访问List的计算时间。下面是一个包含两个函数的Rcpp示例:

#include <RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]
#include <Rcpp.h>
// [[Rcpp::export]]
void first(const Rcpp::List ETA
,const int N
,const int I
) {   
for(int i = 0; i < I; ++i) {
arma::rowvec eta = ETA[i];
for(int n = 0; n < N; ++n) {
// use eta to do some calculation
}
}
}
// [[Rcpp::export]]
void second(const Rcpp::List ETA
,const int N
,const int I
) {   
for(int n = 0; n < N; ++n) {
for(int i = 0; i < I; ++i) {
arma::rowvec eta = ETA[i];
// use eta to do some calculation
}
}
}

比较R:中的时间

Rcpp::sourceCpp("test.cpp") # save the above code as "test.cpp"
ETA = list()
N = 10^8
I = 10
for (i in 1:I) ETA[[i]] = rep(0,i) # just an example.
ptm <- proc.time(); first(ETA,N,I); print((proc.time() - ptm))
#    user  system elapsed 
#       0       0       0 
ptm <- proc.time(); second(ETA,N,I); print((proc.time() - ptm))
#    user  system elapsed 
#   16.69    0.00   16.69

这里,ETA是其每个元素可以具有动态长度(向量(或动态维度(矩阵(的列表。在这个代码中,第一种方式比第二种方式快得多。但出于实际需要,当有其他变量在n上迭代时,第二种方法可以减少计算时间。

问题:

无论是第一种方式还是第二种方式,我们是否可以在循环之外(之前(声明eta,这样我们就不需要多次声明相同的eta了?

在每个循环中都要进行隐式转换和深度复制,因此编译器无法对此进行优化也就不足为奇了。

你可以做的是预先计算所有的eta,并将它们存储在一个向量中。(我在循环中填写了一些工作,因为空循环可以完全优化(。

// [[Rcpp::export]]
double third(const Rcpp::List ETA
,const int N
,const int I) {   
double output=0;

// pre-create eta rowvecs
std::vector<arma::rowvec> eta_vec(Rf_xlength(ETA));
for(int i = 0; i < I; ++i) {
eta_vec[i] = arma::rowvec(Rcpp::NumericVector(ETA[i]));
}

for(int n = 0; n < N; ++n) {
for(int i = 0; i < I; ++i) {
output += sum(eta_vec[i]);
}
}
return output;
}

结果:

> ptm <- proc.time(); first(ETA,N,I); print((proc.time() - ptm))
[1] 0
user  system elapsed 
2.761   0.000   2.761 
> #    user  system elapsed 
> #       0       0       0 
> ptm <- proc.time(); second(ETA,N,I); print((proc.time() - ptm))
[1] 0
user  system elapsed 
29.935   0.000  29.930 
> 
> ptm <- proc.time(); third(ETA,N,I); print((proc.time() - ptm))
[1] 0
user  system elapsed 
2.599   0.000   2.598 

最新更新