加速具有2个输入/输出的迭代功能

时间:2016-02-02 05:12:18

标签: r performance

使用R,我想知道迭代评估多个输入和输出函数的最佳方法是什么。我受到了http://paulbourke.net/fractals/clifford/

所见情节的激励

关键等式是:

x_{n+1} = sin(A* y_n) + C* cos(A* x_n)
y_{n+1} = sin(B* x_n) + D* cos(B* y_n)

我想存储每次迭代的结果。我猜测有一种比通过以下代码中描述的循环更快的方式:

#Parameters
A <- -1.4
B <- 1.6
C <- 1.0
D <- 0.7

n_iter <- 10000000

#Initial values
x0 <- 0 
y0 <- 0 

#function to calculate n+1 points
cliff <- function(x,y){
    c(sin(A*y) + C*cos(A*x), sin(B*x) + D*cos(B*y))
}

#matrix to store results
res_mat <- matrix(0,nrow=n_iter,ncol=2)

#recursive loop (definitely not the fastest way to do this?)
for (i in 2:n_iter){
    res_mat[i,] <-  cliff(res_mat[i-1,1],res_mat[i-1,2])
}

我想这实际上并不是一个单独的函数,而是2对彼此的输出进行操作。任何有关评估这些功能的更合适方法的见解将不胜感激。我敢说我会从一些一般的编程建议中受益,这些建议不一定是R特定的。

1 个答案:

答案 0 :(得分:4)

一种选择是使用Rcpp;对于像这样的迭代函数,每个新值都是前一个迭代值的复杂函数,这通常会产生相当好的加速。

library(Rcpp)
cliff.rcpp = cppFunction("
NumericMatrix cliff(int nIter, double A, double B, double C, double D) {
  NumericMatrix x(nIter, 2);
  for (int i=1; i < nIter; ++i) {
    x(i,0) = sin(A*x(i-1,1)) + C*cos(A*x(i-1,0));
    x(i,1) = sin(B*x(i-1,0)) + D*cos(B*x(i-1,1));
  }
  return x;
}")
cliff.rcpp(10, 1, 2, 3, 4)
#             [,1]       [,2]
#  [1,]  0.0000000  0.0000000
#  [2,]  3.0000000  4.0000000
#  [3,] -3.7267800 -0.8614156
#  [4,] -3.2595913 -1.5266964
#  [5,] -3.9781665 -4.2182644
#  [6,] -1.1296464 -3.1953775
#  [7,]  1.3346977  3.2046776
#  [8,]  0.6386906  4.4230487
#  [9,]  1.4501988 -2.3914781
# [10,] -0.3208062  0.5208984

我们可以看到这会将相同的结果返回给问题中的代码:

cliff.orig <- function(n_iter, A, B, C, D) {
  #function to calculate n+1 points
  cliff <- function(x,y){
    c(sin(A*y) + C*cos(A*x), sin(B*x) + D*cos(B*y))
  }

  #matrix to store results
  res_mat <- matrix(0,nrow=n_iter,ncol=2)

  #recursive loop (definitely not the fastest way to do this?)
  for (i in 2:n_iter){
    res_mat[i,] <-  cliff(res_mat[i-1,1],res_mat[i-1,2])
  }
  res_mat
}
identical(cliff.rcpp(10, 1, 2, 3, 4), cliff.orig(10, 1, 2, 3, 4))
# [1] TRUE

对于原始问题中的输入,Rcpp方法产生~50倍的加速:

system.time(cliff.rcpp(10000000, -1.4, 1.6, 1.0, 0.7))
#    user  system elapsed 
#   0.661   0.046   0.717 
system.time(cliff.orig(10000000, -1.4, 1.6, 1.0, 0.7))
#    user  system elapsed 
#  34.591   0.245  35.040 
相关问题