【问题标题】:Can I create a version of the logistic map function without a for loop?我可以创建一个没有 for 循环的逻辑映射函数版本吗?
【发布时间】:2019-03-08 09:01:45
【问题描述】:

我有一个 R 函数来计算 logistic map,如下所示,使用 for 循环。但是有没有办法改变它(例如矢量化它)使其不使用循环?

logistic_map <- function(x,   # starting condition
                         r,   # rate parameter
                         N) { # number of iterations
    results <- numeric(length = N + 1)
    results[1] <- x
    for (i in seq_len(N)) {
        results[i + 1] <- r * results[i] * (1 - results[i])
    }

    data.frame(i = c(0, seq_len(N)), 
               x = results)
}

我查看了apply() 函数家族和purrr 中的函数,但我正在努力确定这是否可能。我很想得出这不可能的结论,因为每一步都完全依赖于前一步,但完全有可能有一个我无法找到的优雅解决方案。

我可以在没有 for 循环的情况下执行此操作吗?

【问题讨论】:

    标签: r for-loop vectorization


    【解决方案1】:
    library(Rcpp)
    
    cppFunction('NumericVector cpp_loop (NumericVector x, double r) {
      int n = x.size(), i = 0; n--;
      for (; i < n; i++) x[i + 1] = r * x[i] * (1 - x[i]);
      return x;
      }')
    
    logistic_map <- function(x,   # starting condition
                             r,   # rate parameter
                             N) { # number of iterations
        results <- numeric(length = N + 1)
        results[1] <- x
        cpp_loop(results, r)
    
        data.frame(i = c(0, seq_len(N)), 
                   x = results)
    }
    
    logistic_map(2, 0.2, 100)
    

    【讨论】:

    • 我可以看到,当它编译成 C++ 时,它会更快,但这并没有真正矢量化我的意思的函数。我将编辑问题以使其更加明确。
    • @Hamed 仔细阅读我的答案stackoverflow.com/q/52597296/4891738,了解什么是“写入后读取”数据依赖性以及为什么 SIMD 感知“矢量化”是不可能的。但是,将 R 级循环实现为 C/C++/FORTRAN 级循环是 R-sense“矢量化”。后者是大多数时间在 R 中讨论的内容。
    • 是的,我已经阅读了,谢谢。因此,这具有写后读依赖的事实意味着它不能在我想的意义上被矢量化,但是你给出的将实现类似的东西:对吗?
    • 在两个版本的代码上运行microbenchmark(),C++ 版本要快得多,平均时间为 2.5 毫秒,而原始版本为 15.5 毫秒。
    【解决方案2】:

    当然可以,这里有一个for-loop-free Reduce 方法,只使用基础 R:

    > v = {r=2.8;Reduce(function(a,b){xn=a[length(a)];b=r*xn*(1-xn);c(a,b)},rep(0,100),init=0.5)}
    > v
      [1] 0.5000000 0.7000000 0.5880000 0.6783168 0.6109687 0.6655206 0.6232882
      [8] 0.6574401 0.6305953 0.6522456 0.6350996 0.6488947 0.6379250 0.6467347
     [15] 0.6397130 0.6453448 0.6408497 0.6444518 0.6415743 0.6438788 0.6420369
    

    你是否应该是一个不同的问题。如果您这样做是为了获得一些速度,那么您应该首先学习基准测试,然后看看这是否更快。使用for 循环是他们告诉你的一件坏事,但不要听他们 - 有时for 循环比任何一个循环都快他们的包。

    更基本地说,像这样的分形递归关系的属性之一是它们往往没有封闭形式的解决方案。封闭形式的解决方案可以让您计算 x[i] 而无需先计算 x[i-1],因此可以轻松矢量化。对于逻辑图,维基百科告诉我们:https://en.wikipedia.org/wiki/Logistic_map 只有r 的某些值才存在封闭形式的解决方案。在这些值之外,您必须迭代计算。

    【讨论】:

    • 是的,我省略了这是否是个好主意的问题,但这样的事情更接近我的想法。我可以在我的函数中使用Reduce(),这样你只需传递xrN 参数,它就会在里面做它的事情吗?
    • 是的,我刚刚在命令行上破解了它。用你的变量替换正确的数字,它应该都可以工作。我希望它比你的 for 循环慢,因为它会增长一个向量。
    • 谢谢。似乎我最初问题的答案是“是的,但可能不要打扰,只需使用循环”!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-14
    • 1970-01-01
    • 2020-08-04
    相关资源
    最近更新 更多