为向量写易熔O(1)更新

时间:2013-06-08 15:25:24

标签: haskell vector stream fusion

这是question的延续。由于矢量库似乎没有可熔的O(1)更新函数,我想知道是否有可能编写一个不涉及unsafeFreeze和{{1}的可熔O(1)更新函数}。它会使用unsafeThaw表示,我猜 - 我不熟悉如何使用vector streamstream编写一个 - 因此,这个问题。原因是这将使我们能够在向量上编写一个缓存友好的更新函数,其中只修改了一个狭窄的向量区域,因此,我们不想仅仅为了处理那个狭窄的区域而遍历整个向量(并且这个操作在每个函数调用中可能发生数十亿次 - 因此,保持开销非常低的动机)。转换函数如unstream处理整个向量 - 所以它们会太慢。

我有一个我想做的玩具示例,但下面的map函数使用updunsafeThaw - 它似乎没有在核心中进行优化,并且还打破了不再使用缓冲区的承诺:

unsafeFreeze

我知道如何使用module Main where import Data.Vector.Unboxed as U import Data.Vector.Unboxed.Mutable as MU import Control.Monad.ST upd :: Vector Int -> Int -> Int -> Vector Int upd v i x = runST $ do v' <- U.unsafeThaw v MU.write v' i x U.unsafeFreeze v' sum :: Vector Int -> Int sum = U.sum . (\x -> upd x 0 73) . (\x -> upd x 1 61) main = print $ Main.sum $ U.fromList [1..3] 实现命令式算法。如果您想知道为什么这种替代方法,我想尝试使用纯矢量来检查特定算法的STVector转换在使用可熔纯矢量流(使用monadic操作在引擎盖下)时的差异。课程)。

当使用GHC编写算法时,它似乎没有像我希望的那样很好地迭代(我猜想当有很多可变性时GHC优化器更难发现循环散落在周围)。所以,我正在研究这种替代方法,看看我能在那里得到一个更好的循环。

2 个答案:

答案 0 :(得分:4)

您编写的upd函数看起来不是正确,更不用说是可融合的了。 Fusion是一个库级优化,需要您从某些原型中编写代码。在这种情况下,您想要的不仅仅是融合,而是recycling,可以通过//update等批量更新操作轻松实现。这些操作会融合,甚至在很多时候都会发生。

如果你真的想编写自己的基于破坏性更新的代码,请不要使用unsafeThaw - 使用modify

答案 1 :(得分:3)

任何功能都是可熔的更新功能;你似乎试图逃避编程模型,矢量包试图让你使用

module Main where
import Data.Vector.Unboxed as U

change :: Int -> Int -> Int
change 0 n = 73
change 1 n = 61
change m n = n

myfun2 = U.sum . U.imap change .  U.enumFromStepN 1 1 
main = print $ myfun2 30000000 

- 这不会创建任何向量,更不用“更新”它们,因为您将看到是否研究核心。