【问题标题】:Data Parallel Haskell Prefix Sum数据并行 Haskell 前缀和
【发布时间】:2012-02-23 04:56:19
【问题描述】:

我正在使用一些 Data Parallel Haskell 代码,发现自己需要 prefix sum。但是我在 dph package 中没有看到任何基本运算符作为前缀总和。

我自己推出了自己的产品,但是,由于我是 dph 的新手,我不确定它是否正确地利用了并行化:

{-# LANGUAGE ParallelArrays #-}
{-# OPTIONS_GHC -fvectorise #-}

module PrefixSum ( scanP ) where
import Data.Array.Parallel (lengthP, indexedP, mapP, zipWithP, concatP, filterP, singletonP, sliceP, (+:+), (!:))
import Data.Array.Parallel.Prelude.Int ((<=), (-), (==), Int, mod)
-- hide prelude
import qualified Prelude 

-- assuming zipWithP (a -> b -> c) given 
-- [:a:] of length n and
-- [:b:] of length m, n /= m
-- will return
-- [:c:] of length min n m

scanP :: (a -> a -> a) -> [:a:] -> [:a:]
scanP f xs = if lengthP xs <= 1
                then xs
                else head +:+ tail
  where -- [: x_0, x_2, ..., x_2n :]
        evens = mapP snd . filterP (even . fst) $ indexedP xs
        -- [: x_1, x_3 ... :]
        odds = mapP snd . filterP (odd . fst)  $ indexedP xs
        lenEvens = lengthP evens
        lenOdds = lengthP odds
        -- calculate the prefix sums [:w:] of the pair sums [:z:]
        psums = scanP f $ zipWithP f evens odds
        -- calculate the total prefix sums as 
        -- [: x_0, w_0, f w_0 x_2, w_1, f w_1 x_4, ..., 
        head = singletonP (evens !: 0)
        body = concatP . zipWithP (\p e -> [: p, f p e :]) psums $ sliceP 1 lenOdds evens
        -- ending at either
        --    ... w_{n-1}, f w_{n-1} x_2n :]
        -- or
        --    ... w_{n-1}, f w_{n-1} x_2n, w_n :]
        -- depending on whether the length of [:x:] is 2n+1 or 2n+2
        tail = if lenEvens == lenOdds then body +:+ singletonP (psums !: (lenEvens - 1)) else body

-- reimplement some of Prelude so it can be vectorised
f $ x = f x
infixr 0 $
(.) f g y = f (g y)

snd (a,b) = b
fst (a,b) = a

even n = n `mod` 2 == 0
odd n = n `mod` 2 == 1

【问题讨论】:

  • 嗯,它甚至可以并行化吗?似乎是一个非常连续的想法,但也许我错过了一些东西。
  • @luqui:大小为n 的数组的并行前缀求和算法需要O(log n) 并行计算轮次。有两个阶段。在前进阶段,给定{a_i | i \in [0,2n-1] },您使用n/2 并行加法计算{ a_2i + a_{2i+1} | i \in [0,n-1] }。在后向阶段,给定{ \sum_0^{2i+1} a_j | i \in [0,n-1] }{ a_i | i \in [0,2n-1] },您可以使用n/2 并行加法计算{ \sum_0^i a_j | i \in [0, 2n-1 }
  • @luqui:当然,这仅适用于关联 +,因为有一个固有假设 (a_0 + a_1) + (a_2 + a_3) == ((a_0 + a_1) + a_2) + a_3
  • 对于普通数组,这将是 scanl,但我在 dph-par 中没有看到。
  • 正确。 scanl 是在 O(n) 时间内完成 O(n) 次工作,scanP 是在 O(log n) 时间内完成 O(n) 次工作。

标签: haskell parallel-processing multicore data-parallel-haskell prefix-sum


【解决方案1】:

并行前缀扫描是supported,事实上,它们是相当基础的。因此,只需将 (+) 作为关联运算符传递即可。

【讨论】:

    猜你喜欢
    • 2016-04-14
    • 1970-01-01
    • 2017-09-25
    • 2016-06-19
    • 1970-01-01
    • 2012-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多