【问题标题】:Possible to do recursive definitions with unboxed vectors?可以用未装箱的向量进行递归定义吗?
【发布时间】:2016-07-06 01:21:46
【问题描述】:

我想递归地生成一个未装箱的向量。举个简单的例子:

import qualified Data.Vector as V

fib :: V.Vector Int
fib = V.generate 10 f
  where
    f 0 = 0
    f 1 = 1
    f x = (fib V.! (x - 1)) + (fib V.! (x - 2))

函数正确生成斐波那契数列。但是,如果我改用Data.Vector.Unboxed,代码将挂起。我理解这是为什么,但我仍然希望能够进行递归定义并获得未装箱向量的速度。这样做有什么可能吗?

【问题讨论】:

    标签: haskell recursion vector


    【解决方案1】:

    一种可能性是使用未装箱的可变向量并在构造完成后冻结

    import Control.Monad.ST (runST)
    import Control.Monad (forM_, ap)
    import qualified Data.Vector.Unboxed as U
    import qualified Data.Vector.Unboxed.Mutable as M
    
    fib :: Int -> U.Vector Int
    fib s = runST $ M.new s >>= ap ((>>) . forM_ [0..s - 1] . f) U.unsafeFreeze
        where
        f v 0 = M.write v 0 0
        f v 1 = M.write v 1 1
        f v i = do
            a <- M.read v (i - 1)
            b <- M.read v (i - 2)
            M.write v i (a + b)
    

    【讨论】:

      【解决方案2】:

      constructN 做你想做的事,即使是在未装箱的情况下。下面,v 是目前构建的向量前缀,f v 返回下一个元素。

      最优 O(N) 复杂度。

      import qualified Data.Vector.Unboxed as V
      
      fib :: V.Vector Int
      fib = V.constructN 10 f
        where
          f v = case V.length v of
                  0 -> 0
                  1 -> 1
                  n -> (v V.! (n - 1)) + (v V.! (n - 2))
      

      【讨论】:

      • 如果 f(n) 不是 only 先前索引 0..n-1 的函数怎么办?比如说,您正在遍历一个图,并且在每个节点处,感兴趣的索引是相邻节点的索引
      • @behzad.nouri 当然,在一般情况下constructN 是不够的,但我想它在实践中涵盖了很多情况。在最一般的情况下,我会使用盒装向量。如果我知道达到固定点需要多少步(通常,这可能远小于向量的长度),我也可能会在您的答案中考虑可变向量。
      【解决方案3】:

      我能想到的唯一方法是生成一个惰性递归列表,然后将其转换为未装箱的向量。

      令人困惑的标准咒语

      fibs = 1 : 1 : zipWith (+) fibs (tail fibs)
      

      将为您提供无限的斐波那契数列。然后,您可以从中构建一个未装箱的列表,此后将具有快速索引。

      当然,它实际上并没有使用向量来计算斐波那契数。但它也没有对链表进行 O(n) 索引,所以它应该相当快。

      【讨论】:

      • 谢谢。不幸的是,我实际上正在实现一个动态编程算法,这样当我完成计算向量时,我也会得到我的答案并完成它。所以在我的实际情况下,这不会很有用。但总的来说,我会说这是一个好方法。
      • @ritzymon 在这种情况下,您确定要一个未装箱的矢量吗?使用列表的标准动态编程技术通常非常高效——特别是它们通常不会在任何时候将整个列表存储在内存中。
      猜你喜欢
      • 1970-01-01
      • 2013-05-06
      • 1970-01-01
      • 2013-06-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-14
      • 1970-01-01
      相关资源
      最近更新 更多