packages feed

dph-prim-par 0.5.1.1 → 0.6.0.1

raw patch · 36 files changed

+3931/−1502 lines, 36 filesdep ~basedep ~dph-basedep ~dph-prim-interfacePVP ok

version bump matches the API change (PVP)

Dependency ranges changed: base, dph-base, dph-prim-interface, dph-prim-seq, old-time, vector

API changes (from Hackage documentation)

- Data.Array.Parallel.Unlifted: (!:) :: Elt a => Array a -> Int -> a
- Data.Array.Parallel.Unlifted.Distributed: elementsUSegdD :: Dist USegd -> Dist Int
- Data.Array.Parallel.Unlifted.Distributed: indicesUSegdD :: Dist USegd -> Dist (Vector Int)
- Data.Array.Parallel.Unlifted.Distributed: lengthUSegdD :: Dist USegd -> Dist Int
- Data.Array.Parallel.Unlifted.Distributed: lengthsUSegdD :: Dist USegd -> Dist (Vector Int)
- Data.Array.Parallel.Unlifted.Distributed: splitSD :: Unbox a => Gang -> Dist USegd -> Vector a -> Dist (Vector a)
- Data.Array.Parallel.Unlifted.Distributed: splitSegdD :: Gang -> USegd -> Dist USegd
- Data.Array.Parallel.Unlifted.Distributed: splitSegdD' :: Gang -> USegd -> Dist ((USegd, Int), Int)
- Data.Array.Parallel.Unlifted.Parallel: data UPSegd
- Data.Array.Parallel.Unlifted.Parallel: data UPSel2
- Data.Array.Parallel.Unlifted.Parallel: distUPSegd :: UPSegd -> Dist ((USegd, Int), Int)
- Data.Array.Parallel.Unlifted.Parallel: elementsUPSegd :: UPSegd -> Int
- Data.Array.Parallel.Unlifted.Parallel: elementsUPSel2_0 :: UPSel2 -> Int
- Data.Array.Parallel.Unlifted.Parallel: elementsUPSel2_1 :: UPSel2 -> Int
- Data.Array.Parallel.Unlifted.Parallel: elementsUPSelRep2_0 :: Vector Tag -> UPSelRep2 -> Int
- Data.Array.Parallel.Unlifted.Parallel: elementsUPSelRep2_1 :: Vector Tag -> UPSelRep2 -> Int
- Data.Array.Parallel.Unlifted.Parallel: fold1SUP :: Unbox a => (a -> a -> a) -> UPSegd -> Vector a -> Vector a
- Data.Array.Parallel.Unlifted.Parallel: foldSUP :: Unbox a => (a -> a -> a) -> a -> UPSegd -> Vector a -> Vector a
- Data.Array.Parallel.Unlifted.Parallel: indicesSUP :: UPSegd -> Vector Int
- Data.Array.Parallel.Unlifted.Parallel: indicesUPSegd :: UPSegd -> Vector Int
- Data.Array.Parallel.Unlifted.Parallel: indicesUPSel2 :: UPSel2 -> Vector Int
- Data.Array.Parallel.Unlifted.Parallel: indicesUPSelRep2 :: Vector Tag -> UPSelRep2 -> Vector Int
- Data.Array.Parallel.Unlifted.Parallel: lengthUPSegd :: UPSegd -> Int
- Data.Array.Parallel.Unlifted.Parallel: lengthsToUPSegd :: Vector Int -> UPSegd
- Data.Array.Parallel.Unlifted.Parallel: lengthsUPSegd :: UPSegd -> Vector Int
- Data.Array.Parallel.Unlifted.Parallel: mkUPSegd :: Vector Int -> Vector Int -> Int -> UPSegd
- Data.Array.Parallel.Unlifted.Parallel: mkUPSel2 :: Vector Tag -> Vector Int -> Int -> Int -> UPSelRep2 -> UPSel2
- Data.Array.Parallel.Unlifted.Parallel: mkUPSelRep2 :: Vector Tag -> UPSelRep2
- Data.Array.Parallel.Unlifted.Parallel: repUPSel2 :: UPSel2 -> UPSelRep2
- Data.Array.Parallel.Unlifted.Parallel: replicateSUP :: Unbox a => UPSegd -> Vector a -> Vector a
- Data.Array.Parallel.Unlifted.Parallel: segdUPSegd :: UPSegd -> USegd
- Data.Array.Parallel.Unlifted.Parallel: selUPSel2 :: UPSel2 -> USel2
- Data.Array.Parallel.Unlifted.Parallel: sumSUP :: (Num e, Unbox e) => UPSegd -> Vector e -> Vector e
- Data.Array.Parallel.Unlifted.Parallel: tagsUPSel2 :: UPSel2 -> Vector Tag
- Data.Array.Parallel.Unlifted.Parallel: type UPSelRep2 = Dist ((Int, Int), (Int, Int))
+ Data.Array.Parallel.Unlifted: appendSSegd :: SSegd -> Int -> SSegd -> Int -> SSegd
+ Data.Array.Parallel.Unlifted: appendVSegd :: VSegd -> Int -> VSegd -> Int -> VSegd
+ Data.Array.Parallel.Unlifted: appends :: (Elt a, Elts a) => Arrays a -> Arrays a -> Arrays a
+ Data.Array.Parallel.Unlifted: class (Unboxes a, DT a) => Elts a
+ Data.Array.Parallel.Unlifted: combine2VSegd :: Sel2 -> VSegd -> Int -> VSegd -> Int -> VSegd
+ Data.Array.Parallel.Unlifted: count_ss :: (Elt a, Eq a) => SSegd -> Vector (Array a) -> a -> Array Int
+ Data.Array.Parallel.Unlifted: emptySSegd :: SSegd
+ Data.Array.Parallel.Unlifted: emptySegd :: Segd
+ Data.Array.Parallel.Unlifted: emptyVSegd :: VSegd
+ Data.Array.Parallel.Unlifted: emptys :: Arrays a
+ Data.Array.Parallel.Unlifted: extracts_ass :: (Elt a, Elts a) => SSegd -> Arrays a -> Array a
+ Data.Array.Parallel.Unlifted: extracts_avs :: (Elt a, Elts a) => VSegd -> Arrays a -> Array a
+ Data.Array.Parallel.Unlifted: extracts_nss :: Elt a => SSegd -> Vector (Array a) -> Array a
+ Data.Array.Parallel.Unlifted: fold1_ss :: (Elts a, Elt a) => (a -> a -> a) -> SSegd -> Arrays a -> Array a
+ Data.Array.Parallel.Unlifted: fold1_vs :: (Elts a, Elt a) => (a -> a -> a) -> VSegd -> Arrays a -> Array a
+ Data.Array.Parallel.Unlifted: fold_ss :: (Elts a, Elt a) => (a -> a -> a) -> a -> SSegd -> Arrays a -> Array a
+ Data.Array.Parallel.Unlifted: fold_vs :: (Elts a, Elt a) => (a -> a -> a) -> a -> VSegd -> Arrays a -> Array a
+ Data.Array.Parallel.Unlifted: fromVectors :: (Elt a, Elts a) => Vector (Array a) -> Arrays a
+ Data.Array.Parallel.Unlifted: getSegOfSSegd :: SSegd -> Int -> (Int, Int, Int, Int)
+ Data.Array.Parallel.Unlifted: getSegOfVSegd :: VSegd -> Int -> (Int, Int, Int)
+ Data.Array.Parallel.Unlifted: index :: Elt a => String -> Array a -> Int -> a
+ Data.Array.Parallel.Unlifted: indexs :: Elt a => Array a -> Array Int -> Array a
+ Data.Array.Parallel.Unlifted: indexs_avs :: (Elt a, Elts a) => Arrays a -> VSegd -> Array (Int, Int) -> Array a
+ Data.Array.Parallel.Unlifted: indicesOfSSegd :: SSegd -> Array Int
+ Data.Array.Parallel.Unlifted: instance Elts Double
+ Data.Array.Parallel.Unlifted: instance Elts Float
+ Data.Array.Parallel.Unlifted: instance Elts Int
+ Data.Array.Parallel.Unlifted: instance Elts Word8
+ Data.Array.Parallel.Unlifted: isContiguousSSegd :: SSegd -> Bool
+ Data.Array.Parallel.Unlifted: isContiguousVSegd :: VSegd -> Bool
+ Data.Array.Parallel.Unlifted: isManifestVSegd :: VSegd -> Bool
+ Data.Array.Parallel.Unlifted: lengthOfSSegd :: SSegd -> Int
+ Data.Array.Parallel.Unlifted: lengthOfVSegd :: VSegd -> Int
+ Data.Array.Parallel.Unlifted: lengths :: Elts a => Arrays a -> Int
+ Data.Array.Parallel.Unlifted: lengthsOfSSegd :: SSegd -> Array Int
+ Data.Array.Parallel.Unlifted: mkSSegd :: Array Int -> Array Int -> Segd -> SSegd
+ Data.Array.Parallel.Unlifted: mkVSegd :: Array Int -> SSegd -> VSegd
+ Data.Array.Parallel.Unlifted: promoteSSegdToVSegd :: SSegd -> VSegd
+ Data.Array.Parallel.Unlifted: promoteSegdToSSegd :: Segd -> SSegd
+ Data.Array.Parallel.Unlifted: promoteSegdToVSegd :: Segd -> VSegd
+ Data.Array.Parallel.Unlifted: replicatedVSegd :: Int -> Int -> VSegd
+ Data.Array.Parallel.Unlifted: singletonSSegd :: Int -> SSegd
+ Data.Array.Parallel.Unlifted: singletonSegd :: Int -> Segd
+ Data.Array.Parallel.Unlifted: singletonVSegd :: Int -> VSegd
+ Data.Array.Parallel.Unlifted: singletons :: (Elt a, Elts a) => Array a -> Arrays a
+ Data.Array.Parallel.Unlifted: sourcesOfSSegd :: SSegd -> Array Int
+ Data.Array.Parallel.Unlifted: startsOfSSegd :: SSegd -> Array Int
+ Data.Array.Parallel.Unlifted: sum_ss :: (Num a, Elts a, Elt a) => SSegd -> Arrays a -> Array a
+ Data.Array.Parallel.Unlifted: takeLengthsOfVSegd :: VSegd -> Array Int
+ Data.Array.Parallel.Unlifted: takeSSegdOfVSegd :: VSegd -> SSegd
+ Data.Array.Parallel.Unlifted: takeSSegdRedundantOfVSegd :: VSegd -> SSegd
+ Data.Array.Parallel.Unlifted: takeVSegidsOfVSegd :: VSegd -> Array Int
+ Data.Array.Parallel.Unlifted: takeVSegidsRedundantOfVSegd :: VSegd -> Array Int
+ Data.Array.Parallel.Unlifted: toVectors :: (Elt a, Elts a) => Arrays a -> Vector (Array a)
+ Data.Array.Parallel.Unlifted: type Arrays = Vectors
+ Data.Array.Parallel.Unlifted: type SSegd = UPSSegd
+ Data.Array.Parallel.Unlifted: type SelRep2 = UPSelRep2
+ Data.Array.Parallel.Unlifted: type VSegd = UPVSegd
+ Data.Array.Parallel.Unlifted: unsafeDemoteToSSegdOfVSegd :: VSegd -> SSegd
+ Data.Array.Parallel.Unlifted: unsafeDemoteToSegdOfVSegd :: VSegd -> Segd
+ Data.Array.Parallel.Unlifted: unsafeIndex2s :: (Elt a, Elts a) => Arrays a -> Int -> Int -> a
+ Data.Array.Parallel.Unlifted: unsafeIndexs :: (Elt a, Elts a) => Arrays a -> Int -> Array a
+ Data.Array.Parallel.Unlifted: unzip3 :: (Elt a, Elt b, Elt c) => Array (a, b, c) -> (Array a, Array b, Array c)
+ Data.Array.Parallel.Unlifted: updateVSegsOfVSegd :: (Array Int -> Array Int) -> VSegd -> VSegd
+ Data.Array.Parallel.Unlifted: updateVSegsReachableOfVSegd :: (Array Int -> Array Int) -> VSegd -> VSegd
+ Data.Array.Parallel.Unlifted: validSSegd :: SSegd -> Bool
+ Data.Array.Parallel.Unlifted: validSegd :: Segd -> Bool
+ Data.Array.Parallel.Unlifted: validVSegd :: VSegd -> Bool
+ Data.Array.Parallel.Unlifted: zip3 :: (Elt a, Elt b, Elt c) => Array a -> Array b -> Array c -> Array (a, b, c)
+ Data.Array.Parallel.Unlifted.Distributed: carryD :: (Unbox a, DT a) => Gang -> (a -> a -> a) -> a -> Dist Bool -> Dist (Vector a) -> (Dist (Vector a), a)
+ Data.Array.Parallel.Unlifted.Distributed: glueSegdD :: Gang -> Dist ((USegd, Int), Int) -> Dist USegd
+ Data.Array.Parallel.Unlifted.Distributed.Gang: data Gang
+ Data.Array.Parallel.Unlifted.Distributed.Gang: forkGang :: Int -> IO Gang
+ Data.Array.Parallel.Unlifted.Distributed.Gang: gangIO :: Gang -> (Int -> IO ()) -> IO ()
+ Data.Array.Parallel.Unlifted.Distributed.Gang: gangST :: Gang -> (Int -> ST s ()) -> ST s ()
+ Data.Array.Parallel.Unlifted.Distributed.Gang: gangSize :: Gang -> Int
+ Data.Array.Parallel.Unlifted.Distributed.Gang: instance Show Gang
+ Data.Array.Parallel.Unlifted.Distributed.Gang: seqGang :: Gang -> Gang
+ Data.Array.Parallel.Unlifted.Distributed.Gang: traceGang :: String -> IO ()
+ Data.Array.Parallel.Unlifted.Distributed.Gang: traceGangST :: String -> ST s ()
+ Data.Array.Parallel.Unlifted.Distributed.TheGang: theGang :: Gang
+ Data.Array.Parallel.Unlifted.Parallel: allUP :: Unbox e => (e -> Bool) -> Vector e -> Bool
+ Data.Array.Parallel.Unlifted.Parallel: anyUP :: Unbox e => (e -> Bool) -> Vector e -> Bool
+ Data.Array.Parallel.Unlifted.Parallel: emptyUP :: Unbox e => Vector e
+ Data.Array.Parallel.Unlifted.Parallel: extractsFromNestedUPSSegd :: Unbox a => UPSSegd -> Vector (Vector a) -> Vector a
+ Data.Array.Parallel.Unlifted.Parallel: extractsFromVectorsUPSSegd :: (Unbox a, Unboxes a) => UPSSegd -> Vectors a -> Vector a
+ Data.Array.Parallel.Unlifted.Parallel: extractsFromVectorsUPVSegd :: (Unbox a, Unboxes a) => UPVSegd -> Vectors a -> Vector a
+ Data.Array.Parallel.Unlifted.Parallel: fold1UP :: (DT a, Unbox a) => (a -> a -> a) -> Vector a -> a
+ Data.Array.Parallel.Unlifted.Parallel: foldl1UP :: (DT a, Unbox a) => (a -> a -> a) -> Vector a -> a
+ Data.Array.Parallel.Unlifted.Parallel: foldlUP :: (DT a, Unbox a) => (a -> a -> a) -> a -> Vector a -> a
+ Data.Array.Parallel.Unlifted.Parallel: indexsFromVector :: Unbox a => Vector a -> Vector Int -> Vector a
+ Data.Array.Parallel.Unlifted.Parallel: indexsFromVectorsUPVSegd :: (Unbox a, Unboxes a) => Vectors a -> UPVSegd -> Vector (Int, Int) -> Vector a
+ Data.Array.Parallel.Unlifted.Parallel: lengthUP :: Unbox e => Vector e -> Int
+ Data.Array.Parallel.Unlifted.Parallel: maximumByUP :: (DT e, Unbox e) => (e -> e -> Ordering) -> Vector e -> e
+ Data.Array.Parallel.Unlifted.Parallel: maximumIndexByUP :: (DT e, Unbox e) => (e -> e -> Ordering) -> Vector e -> Int
+ Data.Array.Parallel.Unlifted.Parallel: maximumUP :: (DT e, Ord e, Unbox e) => Vector e -> e
+ Data.Array.Parallel.Unlifted.Parallel: nullUP :: Unbox e => Vector e -> Bool
+ Data.Array.Parallel.Unlifted.Parallel: orUP :: Vector Bool -> Bool
+ Data.Array.Parallel.Unlifted.Parallel: productUP :: (DT e, Num e, Unbox e) => Vector e -> e
+ Data.Array.Parallel.Unlifted.Parallel.UPSSegd: appendWith :: UPSSegd -> Int -> UPSSegd -> Int -> UPSSegd
+ Data.Array.Parallel.Unlifted.Parallel.UPSSegd: data UPSSegd
+ Data.Array.Parallel.Unlifted.Parallel.UPSSegd: empty :: UPSSegd
+ Data.Array.Parallel.Unlifted.Parallel.UPSSegd: fold1WithP :: (Unbox a, Unboxes a) => (a -> a -> a) -> UPSSegd -> Vectors a -> Vector a
+ Data.Array.Parallel.Unlifted.Parallel.UPSSegd: foldSegsWithP :: (Unbox a, Unboxes a) => (a -> a -> a) -> (USSegd -> Vectors a -> Vector a) -> UPSSegd -> Vectors a -> Vector a
+ Data.Array.Parallel.Unlifted.Parallel.UPSSegd: foldWithP :: (Unbox a, Unboxes a) => (a -> a -> a) -> a -> UPSSegd -> Vectors a -> Vector a
+ Data.Array.Parallel.Unlifted.Parallel.UPSSegd: fromUPSegd :: UPSegd -> UPSSegd
+ Data.Array.Parallel.Unlifted.Parallel.UPSSegd: fromUSSegd :: USSegd -> UPSSegd
+ Data.Array.Parallel.Unlifted.Parallel.UPSSegd: getSeg :: UPSSegd -> Int -> (Int, Int, Int, Int)
+ Data.Array.Parallel.Unlifted.Parallel.UPSSegd: instance PprPhysical UPSSegd
+ Data.Array.Parallel.Unlifted.Parallel.UPSSegd: instance Show UPSSegd
+ Data.Array.Parallel.Unlifted.Parallel.UPSSegd: isContiguous :: UPSSegd -> Bool
+ Data.Array.Parallel.Unlifted.Parallel.UPSSegd: length :: UPSSegd -> Int
+ Data.Array.Parallel.Unlifted.Parallel.UPSSegd: mkUPSSegd :: Vector Int -> Vector Int -> UPSegd -> UPSSegd
+ Data.Array.Parallel.Unlifted.Parallel.UPSSegd: singleton :: Int -> UPSSegd
+ Data.Array.Parallel.Unlifted.Parallel.UPSSegd: sumWithP :: (Num a, Unbox a, Unboxes a) => UPSSegd -> Vectors a -> Vector a
+ Data.Array.Parallel.Unlifted.Parallel.UPSSegd: takeDistributed :: UPSSegd -> Dist ((USSegd, Int), Int)
+ Data.Array.Parallel.Unlifted.Parallel.UPSSegd: takeElements :: UPSSegd -> Int
+ Data.Array.Parallel.Unlifted.Parallel.UPSSegd: takeIndices :: UPSSegd -> Vector Int
+ Data.Array.Parallel.Unlifted.Parallel.UPSSegd: takeLengths :: UPSSegd -> Vector Int
+ Data.Array.Parallel.Unlifted.Parallel.UPSSegd: takeSources :: UPSSegd -> Vector Int
+ Data.Array.Parallel.Unlifted.Parallel.UPSSegd: takeStarts :: UPSSegd -> Vector Int
+ Data.Array.Parallel.Unlifted.Parallel.UPSSegd: takeUSSegd :: UPSSegd -> USSegd
+ Data.Array.Parallel.Unlifted.Parallel.UPSSegd: valid :: UPSSegd -> Bool
+ Data.Array.Parallel.Unlifted.Parallel.UPSegd: UPSegd :: !USegd -> Dist ((USegd, Int), Int) -> UPSegd
+ Data.Array.Parallel.Unlifted.Parallel.UPSegd: data UPSegd
+ Data.Array.Parallel.Unlifted.Parallel.UPSegd: empty :: UPSegd
+ Data.Array.Parallel.Unlifted.Parallel.UPSegd: fold1WithP :: Unbox a => (a -> a -> a) -> UPSegd -> Vector a -> Vector a
+ Data.Array.Parallel.Unlifted.Parallel.UPSegd: foldSegsWithP :: Unbox a => (a -> a -> a) -> (USegd -> Vector a -> Vector a) -> UPSegd -> Vector a -> Vector a
+ Data.Array.Parallel.Unlifted.Parallel.UPSegd: foldWithP :: Unbox a => (a -> a -> a) -> a -> UPSegd -> Vector a -> Vector a
+ Data.Array.Parallel.Unlifted.Parallel.UPSegd: fromLengths :: Vector Int -> UPSegd
+ Data.Array.Parallel.Unlifted.Parallel.UPSegd: fromUSegd :: USegd -> UPSegd
+ Data.Array.Parallel.Unlifted.Parallel.UPSegd: indicesP :: UPSegd -> Vector Int
+ Data.Array.Parallel.Unlifted.Parallel.UPSegd: instance PprPhysical UPSegd
+ Data.Array.Parallel.Unlifted.Parallel.UPSegd: length :: UPSegd -> Int
+ Data.Array.Parallel.Unlifted.Parallel.UPSegd: mkUPSegd :: Vector Int -> Vector Int -> Int -> UPSegd
+ Data.Array.Parallel.Unlifted.Parallel.UPSegd: replicateWithP :: Unbox a => UPSegd -> Vector a -> Vector a
+ Data.Array.Parallel.Unlifted.Parallel.UPSegd: singleton :: Int -> UPSegd
+ Data.Array.Parallel.Unlifted.Parallel.UPSegd: sumWithP :: (Num e, Unbox e) => UPSegd -> Vector e -> Vector e
+ Data.Array.Parallel.Unlifted.Parallel.UPSegd: takeDistributed :: UPSegd -> Dist ((USegd, Int), Int)
+ Data.Array.Parallel.Unlifted.Parallel.UPSegd: takeElements :: UPSegd -> Int
+ Data.Array.Parallel.Unlifted.Parallel.UPSegd: takeIndices :: UPSegd -> Vector Int
+ Data.Array.Parallel.Unlifted.Parallel.UPSegd: takeLengths :: UPSegd -> Vector Int
+ Data.Array.Parallel.Unlifted.Parallel.UPSegd: takeUSegd :: UPSegd -> USegd
+ Data.Array.Parallel.Unlifted.Parallel.UPSegd: upsegd_dsegd :: UPSegd -> Dist ((USegd, Int), Int)
+ Data.Array.Parallel.Unlifted.Parallel.UPSegd: upsegd_usegd :: UPSegd -> !USegd
+ Data.Array.Parallel.Unlifted.Parallel.UPSegd: valid :: UPSegd -> Bool
+ Data.Array.Parallel.Unlifted.Parallel.UPSel: data UPSel2
+ Data.Array.Parallel.Unlifted.Parallel.UPSel: elementsUPSel2_0 :: UPSel2 -> Int
+ Data.Array.Parallel.Unlifted.Parallel.UPSel: elementsUPSel2_1 :: UPSel2 -> Int
+ Data.Array.Parallel.Unlifted.Parallel.UPSel: elementsUPSelRep2_0 :: Vector Tag -> UPSelRep2 -> Int
+ Data.Array.Parallel.Unlifted.Parallel.UPSel: elementsUPSelRep2_1 :: Vector Tag -> UPSelRep2 -> Int
+ Data.Array.Parallel.Unlifted.Parallel.UPSel: indicesUPSel2 :: UPSel2 -> Vector Int
+ Data.Array.Parallel.Unlifted.Parallel.UPSel: indicesUPSelRep2 :: Vector Tag -> UPSelRep2 -> Vector Int
+ Data.Array.Parallel.Unlifted.Parallel.UPSel: mkUPSel2 :: Vector Tag -> Vector Int -> Int -> Int -> UPSelRep2 -> UPSel2
+ Data.Array.Parallel.Unlifted.Parallel.UPSel: mkUPSelRep2 :: Vector Tag -> UPSelRep2
+ Data.Array.Parallel.Unlifted.Parallel.UPSel: repUPSel2 :: UPSel2 -> UPSelRep2
+ Data.Array.Parallel.Unlifted.Parallel.UPSel: selUPSel2 :: UPSel2 -> USel2
+ Data.Array.Parallel.Unlifted.Parallel.UPSel: tagsUPSel2 :: UPSel2 -> Vector Tag
+ Data.Array.Parallel.Unlifted.Parallel.UPSel: type UPSelRep2 = Dist ((Int, Int), (Int, Int))
+ Data.Array.Parallel.Unlifted.Parallel.UPVSegd: appendWith :: UPVSegd -> Int -> UPVSegd -> Int -> UPVSegd
+ Data.Array.Parallel.Unlifted.Parallel.UPVSegd: combine2 :: UPSel2 -> UPVSegd -> Int -> UPVSegd -> Int -> UPVSegd
+ Data.Array.Parallel.Unlifted.Parallel.UPVSegd: data UPVSegd
+ Data.Array.Parallel.Unlifted.Parallel.UPVSegd: empty :: UPVSegd
+ Data.Array.Parallel.Unlifted.Parallel.UPVSegd: fromUPSSegd :: UPSSegd -> UPVSegd
+ Data.Array.Parallel.Unlifted.Parallel.UPVSegd: fromUPSegd :: UPSegd -> UPVSegd
+ Data.Array.Parallel.Unlifted.Parallel.UPVSegd: getSeg :: UPVSegd -> Int -> (Int, Int, Int)
+ Data.Array.Parallel.Unlifted.Parallel.UPVSegd: instance PprPhysical UPVSegd
+ Data.Array.Parallel.Unlifted.Parallel.UPVSegd: instance Show UPVSegd
+ Data.Array.Parallel.Unlifted.Parallel.UPVSegd: isContiguous :: UPVSegd -> Bool
+ Data.Array.Parallel.Unlifted.Parallel.UPVSegd: isManifest :: UPVSegd -> Bool
+ Data.Array.Parallel.Unlifted.Parallel.UPVSegd: length :: UPVSegd -> Int
+ Data.Array.Parallel.Unlifted.Parallel.UPVSegd: mkUPVSegd :: Vector Int -> UPSSegd -> UPVSegd
+ Data.Array.Parallel.Unlifted.Parallel.UPVSegd: replicated :: Int -> Int -> UPVSegd
+ Data.Array.Parallel.Unlifted.Parallel.UPVSegd: singleton :: Int -> UPVSegd
+ Data.Array.Parallel.Unlifted.Parallel.UPVSegd: takeLengths :: UPVSegd -> Vector Int
+ Data.Array.Parallel.Unlifted.Parallel.UPVSegd: takeUPSSegd :: UPVSegd -> UPSSegd
+ Data.Array.Parallel.Unlifted.Parallel.UPVSegd: takeUPSSegdRedundant :: UPVSegd -> UPSSegd
+ Data.Array.Parallel.Unlifted.Parallel.UPVSegd: takeVSegids :: UPVSegd -> Vector Int
+ Data.Array.Parallel.Unlifted.Parallel.UPVSegd: takeVSegidsRedundant :: UPVSegd -> Vector Int
+ Data.Array.Parallel.Unlifted.Parallel.UPVSegd: unsafeDemoteToUPSSegd :: UPVSegd -> UPSSegd
+ Data.Array.Parallel.Unlifted.Parallel.UPVSegd: unsafeDemoteToUPSegd :: UPVSegd -> UPSegd
+ Data.Array.Parallel.Unlifted.Parallel.UPVSegd: updateVSegs :: (Vector Int -> Vector Int) -> UPVSegd -> UPVSegd
+ Data.Array.Parallel.Unlifted.Parallel.UPVSegd: updateVSegsReachable :: (Vector Int -> Vector Int) -> UPVSegd -> UPVSegd
+ Data.Array.Parallel.Unlifted.Parallel.UPVSegd: valid :: UPVSegd -> Bool
- Data.Array.Parallel.Unlifted.Distributed: class DT a where { data family Dist a; data family MDist a :: * -> *; { deepSeqD = seq measureD _ = "None" } }
+ Data.Array.Parallel.Unlifted.Distributed: class DT a where data family Dist a data family MDist a :: * -> * deepSeqD = seq measureD _ = "None"
- Data.Array.Parallel.Unlifted.Distributed: indexD :: DT a => Dist a -> Int -> a
+ Data.Array.Parallel.Unlifted.Distributed: indexD :: DT a => String -> Dist a -> Int -> a

Files

Data/Array/Parallel/Unlifted.hs view
@@ -1,100 +1,139 @@-{-# LANGUAGE PackageImports, CPP #-}---- | Primitive parallel combinators that work on flat, unlifted arrays.---   Some of them don't actually have parallel implementations, so we bail out---   to the regular sequential ones.+{-# LANGUAGE CPP, NoMonomorphismRestriction #-}+{-# OPTIONS -fno-warn-missing-signatures #-}+-- | Parallel implementation of the segmented array API defined in @dph-prim-interface@. -----   This set of combinators is used when the program is comiled with @-fdph-par@.---   When compiling with @-fdph-seq@, the ones in the @dph-prim-seq@ package are used---   instead. The @dph-prim-seq package@ exports the same names, but all combinators---   are implemented sequentially.+--   Some of them don't yet have parallel implementations, so we fall back+--   to the sequential ones from @dph-prim-seq@. -----   The API is defined in @DPH_Header.h@ and @DPH_Interface.h@ to ensure that both---   @dph-prim-par@ and @dph-prim-seq@ really do export the same symbols.-+--   /WARNING:/ Although this library is intended to be used as a target+--   for the DPH vectoriser, it is also fine to use it directly from non+--   DPH programs. However, this library does not support nested parallelism+--   by itself. If you try to run further parallel computations in the workers+--   passed to `map`, `zipWith`, `fold` etc, then they will just run+--   sequentially.+---+--   This API is used by the @dph-lifted-*@ libraries, and is defined in+--   @DPH_Header.h@ and @DPH_Interface.h@. We use header files to ensure+--   that this API is implemented identically by both the +--   @dph-prim-par@ and @dph-prim-seq@ packages.+-- #include "DPH_Header.h"- import Data.Array.Parallel.Unlifted.Parallel import Data.Array.Parallel.Base.TracePrim import Data.Array.Parallel.Unlifted.Distributed ( DT )-import qualified Data.Array.Parallel.Unlifted.Sequential.Vector         as Seq-import qualified Data.Array.Parallel.Unlifted.Sequential.Segmented      as Seq-import Data.Array.Parallel.Unlifted.Sequential.Vector (Unbox,Vector)-import Prelude (($!)) +import Data.Array.Parallel.Unlifted.Sequential.Vector           (Unbox,   Vector)+import Data.Array.Parallel.Unlifted.Vectors                     (Unboxes, Vectors)+import Data.Array.Parallel.Unlifted.Parallel.UPSel+import qualified Data.Array.Parallel.Unlifted.Parallel.UPSegd   as UPSegd+import qualified Data.Array.Parallel.Unlifted.Parallel.UPSSegd  as UPSSegd+import qualified Data.Array.Parallel.Unlifted.Parallel.UPVSegd  as UPVSegd+import qualified Data.Array.Parallel.Unlifted.Sequential.Vector as Seq+import qualified Data.Array.Parallel.Unlifted.Vectors           as US+import qualified Data.Array.Parallel.Unlifted.Sequential        as Seq+import Prelude (($!)) #include "DPH_Interface.h" -class (Unbox a, DT a) => Elt a+-- NOTE +-- See DPH_Interface.h for documentation. +--+-- The defs should appear in the same order as they are listed in DPH_Interface.h+--+-- Operations with at least O(n) time will print trace messages to console when+-- dph-base/D/A/P/Config.tracePrimEnabled is set to True.+-- +-- Basics ---------------------------------------------------------------------+class (Unbox a,   DT a) => Elt a++-- | Arrays are stored as unboxed vectors. +--   They have bulk-strict semantics, so demanding one element demands them all. type Array      = Vector-type Segd       = UPSegd-type Sel2       = UPSel2-type SelRep2    = UPSelRep2  --- Constant time operations ------------------------------------------------------   We don't bother tracing these.--length                  = Seq.length-empty                   = Seq.empty-zip                     = Seq.zip-unzip                   = Seq.unzip-fsts                    = Seq.fsts-snds                    = Seq.snds-(!:)                    = (Seq.!)--elementsSel2_0          = elementsUPSel2_0-elementsSel2_1          = elementsUPSel2_1-repSel2                 = repUPSel2--mkSelRep2               = mkUPSelRep2-indicesSelRep2          = indicesUPSelRep2-elementsSelRep2_0       = elementsUPSelRep2_0-elementsSelRep2_1       = elementsUPSelRep2_1--mkSegd                  = mkUPSegd-lengthSegd              = lengthUPSegd-lengthsSegd             = lengthsUPSegd-indicesSegd             = indicesUPSegd-elementsSegd            = elementsUPSegd+-- Constructors ---------------------------------------------------------------+empty   = Seq.empty +(+:+) arr1 arr2+        =  tracePrim (TraceAppend (Seq.length arr1 + Seq.length arr2))+        $! (Seq.++) arr1 arr2 ----------------------------------------------------------------------------------- These take least O(n) time in the length of the vector.---   NOTE: That actual tracing is only enabled when ---         dph-base/D/A/P/Config.tracePrimEnabled is set to True,---         otherwise tracePrim is a no-op.+append_s segd xd xs yd ys+ = let  arr     = appendSUP segd xd xs yd ys+   in   tracePrim (TraceAppend_s (Seq.length arr)) arr  replicate n val          =  tracePrim (TraceReplicate n)         $! replicateUP n val +replicate_s segd arr+        =  tracePrim (TraceReplicate_s (Seq.length arr))+        $! UPSegd.replicateWithP segd arr ++replicate_rs n arr+        =  tracePrim (TraceReplicate_rs n (Seq.length arr))+        $! replicateRSUP n arr+ repeat n _ arr         =  tracePrim (TraceRepeat n (Seq.length arr))         $! repeatUP n arr +indexed arr+        =  tracePrim (TraceIndexed (Seq.length arr))+        $! indexedUP arr +indices_s segd+ = let  arr     = UPSegd.indicesP segd+   in   tracePrim (TraceIndices_s (Seq.length arr)) arr++enumFromTo from to+ = let  arr     = enumFromToUP from to+   in   tracePrim (TraceEnumFromTo (Seq.length arr)) arr++enumFromThenTo from thn to+ = let  arr     = enumFromThenToUP from thn to+   in   tracePrim (TraceEnumFromThenTo (Seq.length arr)) arr+   +enumFromStepLen from step len+ = let  arr     = enumFromStepLenUP from step len+   in   tracePrim (TraceEnumFromStepLen (Seq.length arr)) arr++enumFromStepLenEach n starts steps lens+ = let  arr     = enumFromStepLenEachUP n starts steps lens+   in   tracePrim (TraceEnumFromStepLenEach (Seq.length arr)) arr+++-- Projections ----------------------------------------------------------------+length          = Seq.length+index           = Seq.index+indexs          = indexsFromVector+indexs_avs      = indexsFromVectorsUPVSegd+ extract arr i n         =  tracePrim (TraceExtract (Seq.length arr) i n)         $! Seq.extract arr i n +extracts_nss    = extractsFromNestedUPSSegd+extracts_ass    = extractsFromVectorsUPSSegd+extracts_avs    = extractsFromVectorsUPVSegd  drop n arr         =  tracePrim (TraceDrop n (Seq.length arr))         $! dropUP n arr  +-- Update ---------------------------------------------------------------------+update arrSrc arrNew+        =  tracePrim (TraceUpdate (Seq.length arrSrc) (Seq.length arrNew))+        $! updateUP arrSrc arrNew+++-- Permutation ---------------------------------------------------------------- permute arrSrc arrIxs         =  tracePrim (TracePermute (Seq.length arrSrc))         $! Seq.permute arrSrc arrIxs --bpermuteDft len f arrIxs-        =  tracePrim (TraceBPermuteDft len)-        $! Seq.bpermuteDft len f arrIxs-- bpermute arrSrc arrIxs         =  tracePrim (TraceBPermute (Seq.length arrSrc))         $! bpermuteUP arrSrc arrIxs@@ -104,105 +143,101 @@         =  tracePrim (TraceMBPermute (Seq.length arrSrc))         $! Seq.mbpermute f arrSrc streamIxs --update arrSrc arrNew-        =  tracePrim (TraceUpdate (Seq.length arrSrc) (Seq.length arrNew))-        $! updateUP arrSrc arrNew---(+:+) arr1 arr2-        =  tracePrim (TraceAppend (Seq.length arr1 + Seq.length arr2))-        $! (Seq.++) arr1 arr2---interleave arr1 arr2-        =  tracePrim (TraceInterleave (Seq.length arr1 + Seq.length arr2))-        $! interleaveUP arr1 arr2---pack arrSrc arrFlag-        =  tracePrim (TracePack (Seq.length arrSrc))-        $! packUP arrSrc arrFlag---combine arrSel arr1 arr2-        =  tracePrim (TraceCombine (Seq.length arrSel))-        $! combineUP arrSel arr1 arr2+bpermuteDft len f arrIxs+        =  tracePrim (TraceBPermuteDft len)+        $! Seq.bpermuteDft len f arrIxs  -combine2 arrTag sel arr1 arr2-        =  tracePrim (TraceCombine2 (Seq.length arrTag))-        $! combine2UP arrTag sel arr1 arr2+-- Zipping and Unzipping ------------------------------------------------------+zip     = Seq.zip+zip3    = Seq.zip3+unzip   = Seq.unzip+unzip3  = Seq.unzip3+fsts    = Seq.fsts+snds    = Seq.snds  +-- Map and ZipWith ------------------------------------------------------------ map f arr         =  tracePrim (TraceMap (Seq.length arr))         $! mapUP f arr --filter f src- = let  dst     = filterUP f src-   in   tracePrim (TraceFilter (Seq.length src) (Seq.length dst)) dst-- zipWith f arr1 arr2         =  tracePrim (TraceZipWith (Seq.length arr1) (Seq.length arr2))         $! zipWithUP f arr1 arr2  +-- Scans and Folds ------------------------------------------------------------+scan f x arr+        =  tracePrim (TraceScan (Seq.length arr))+        $! scanUP f x arr+ fold f x arr         =  tracePrim (TraceFold (Seq.length arr))         $! foldUP f x arr +fold_s f x segd arr+        =  tracePrim (TraceFold_s (Seq.length arr))+        $! UPSegd.foldWithP f x segd arr++fold_ss = UPSSegd.foldWithP++fold_r f z segSize arr+        =  tracePrim (TraceFold_r (Seq.length arr))+        $! Seq.foldlRU f z segSize arr          fold1 f arr         =  tracePrim (TraceFold1 (Seq.length arr))         $! Seq.fold1 f arr --and arr =  tracePrim (TraceAnd (Seq.length arr))-        $! andUP arr+fold1_s f segd arr+        =  tracePrim (TraceFold1_s (Seq.length arr))+        $! UPSegd.fold1WithP f segd arr +fold1_ss = UPSSegd.fold1WithP  sum arr =  tracePrim (TraceSum (Seq.length arr))         $! sumUP arr -                        -scan f x arr-        =  tracePrim (TraceScan (Seq.length arr))-        $! scanUP f x arr+sum_r x arr+        =  tracePrim (TraceSum_r (Seq.length arr))+        $! sumRUP x arr -        -indexed arr-        =  tracePrim (TraceIndexed (Seq.length arr))-        $! indexedUP arr+and arr =  tracePrim (TraceAnd (Seq.length arr))+        $! andUP arr  -enumFromTo from to- = let  arr     = enumFromToUP from to-   in   tracePrim (TraceEnumFromTo (Seq.length arr)) arr+-- Pack and Filter ------------------------------------------------------------+pack arrSrc arrFlag+        =  tracePrim (TracePack (Seq.length arrSrc))+        $! packUP arrSrc arrFlag -        -enumFromThenTo from thn to- = let  arr     = enumFromThenToUP from thn to-   in   tracePrim (TraceEnumFromThenTo (Seq.length arr)) arr+filter f src+ = let  dst     = filterUP f src+   in   tracePrim (TraceFilter (Seq.length src) (Seq.length dst)) dst -   -enumFromStepLen from step len- = let  arr     = enumFromStepLenUP from step len-   in   tracePrim (TraceEnumFromStepLen (Seq.length arr)) arr +-- Combine and Interleave -----------------------------------------------------+combine arrSel arr1 arr2+        =  tracePrim (TraceCombine (Seq.length arrSel))+        $! combineUP arrSel arr1 arr2 -enumFromStepLenEach n starts steps lens- = let  arr     = enumFromStepLenEachUP n starts steps lens-   in   tracePrim (TraceEnumFromStepLenEach (Seq.length arr)) arr+combine2 arrTag sel arr1 arr2+        =  tracePrim (TraceCombine2 (Seq.length arrTag))+        $! combine2UP arrTag sel arr1 arr2 +interleave arr1 arr2+        =  tracePrim (TraceInterleave (Seq.length arr1 + Seq.length arr2))+        $! interleaveUP arr1 arr2 ++-- Selectors ------------------------------------------------------------------+type Sel2               = UPSel2+ mkSel2 tag is n0 n1 rep         =  tracePrim (TraceMkSel2 (Seq.length is))         $! mkUPSel2 tag is n0 n1 rep - tagsSel2 sel  = let  tags    = tagsUPSel2 sel    in   tracePrim (TraceTagsSel2 (Seq.length tags)) tags@@ -213,54 +248,95 @@    in   tracePrim (TraceIndicesSel2 (Seq.length arr)) arr  -replicate_s segd arr-        =  tracePrim (TraceReplicate_s (Seq.length arr))-        $! replicateSUP segd arr+elementsSel2_0                  = elementsUPSel2_0+elementsSel2_1                  = elementsUPSel2_1+repSel2                         = repUPSel2 +type SelRep2                    = UPSelRep2+mkSelRep2                       = mkUPSelRep2 -replicate_rs n arr-        =  tracePrim (TraceReplicate_rs n (Seq.length arr))-        $! replicateRSUP n arr+indicesSelRep2                  = indicesUPSelRep2+elementsSelRep2_0               = elementsUPSelRep2_0+elementsSelRep2_1               = elementsUPSelRep2_1  -append_s segd xd xs yd ys- = let  arr     = appendSUP segd xd xs yd ys-   in   tracePrim (TraceAppend_s (Seq.length arr)) arr+-- Segment Descriptors --------------------------------------------------------+type Segd                       = UPSegd.UPSegd+mkSegd                          = UPSegd.mkUPSegd+validSegd                       = UPSegd.valid+emptySegd                       = UPSegd.empty+singletonSegd                   = UPSegd.singleton+lengthSegd                      = UPSegd.length+lengthsSegd                     = UPSegd.takeLengths+indicesSegd                     = UPSegd.takeIndices+elementsSegd                    = UPSegd.takeElements -        -fold_s f x segd arr-        =  tracePrim (TraceFold_s (Seq.length arr))-        $! foldSUP f x segd arr -        -fold1_s f segd arr-        =  tracePrim (TraceFold1_s (Seq.length arr))-        $! fold1SUP f segd arr+-- Scattered Segment Descriptors ----------------------------------------------+type SSegd                      = UPSSegd.UPSSegd+mkSSegd                         = UPSSegd.mkUPSSegd+promoteSegdToSSegd              = UPSSegd.fromUPSegd+validSSegd                      = UPSSegd.valid+emptySSegd                      = UPSSegd.empty+singletonSSegd                  = UPSSegd.singleton+isContiguousSSegd               = UPSSegd.isContiguous+lengthOfSSegd                   = UPSSegd.length+lengthsOfSSegd                  = UPSSegd.takeLengths+indicesOfSSegd                  = UPSSegd.takeIndices+startsOfSSegd                   = UPSSegd.takeStarts+sourcesOfSSegd                  = UPSSegd.takeSources+getSegOfSSegd                   = UPSSegd.getSeg+appendSSegd                     = UPSSegd.appendWith  -fold_r f z segSize arr-        =  tracePrim (TraceFold_r (Seq.length arr))-        $! Seq.foldlRU f z segSize arr+-- Virtual Segment Descriptors ------------------------------------------------+type VSegd                      = UPVSegd.UPVSegd+mkVSegd                         = UPVSegd.mkUPVSegd+validVSegd                      = UPVSegd.valid+emptyVSegd                      = UPVSegd.empty+singletonVSegd                  = UPVSegd.singleton+replicatedVSegd                 = UPVSegd.replicated+promoteSegdToVSegd              = UPVSegd.fromUPSegd+promoteSSegdToVSegd             = UPVSegd.fromUPSSegd+isManifestVSegd                 = UPVSegd.isManifest+isContiguousVSegd               = UPVSegd.isContiguous+lengthOfVSegd                   = UPVSegd.length+takeVSegidsOfVSegd              = UPVSegd.takeVSegids+takeVSegidsRedundantOfVSegd     = UPVSegd.takeVSegidsRedundant+takeSSegdOfVSegd                = UPVSegd.takeUPSSegd+takeSSegdRedundantOfVSegd       = UPVSegd.takeUPSSegdRedundant+takeLengthsOfVSegd              = UPVSegd.takeLengths+getSegOfVSegd                   = UPVSegd.getSeg+unsafeDemoteToSSegdOfVSegd      = UPVSegd.unsafeDemoteToUPSSegd+unsafeDemoteToSegdOfVSegd       = UPVSegd.unsafeDemoteToUPSegd+updateVSegsOfVSegd              = UPVSegd.updateVSegs+updateVSegsReachableOfVSegd     = UPVSegd.updateVSegsReachable+appendVSegd                     = UPVSegd.appendWith+combine2VSegd                   = UPVSegd.combine2  -sum_r x arr-        =  tracePrim (TraceSum_r (Seq.length arr))-        $! sumRUP x arr-+-- Irregular 2D arrays --------------------------------------------------------+class (Unboxes a, DT a) => Elts a -indices_s segd- = let  arr     = indicesSUP segd-   in   tracePrim (TraceIndices_s (Seq.length arr)) arr+type Arrays                     = Vectors+emptys                          = US.empty+lengths                         = US.length+singletons                      = US.singleton+unsafeIndexs                    = US.unsafeIndex+unsafeIndex2s                   = US.unsafeIndex2+appends                         = US.append+fromVectors                     = US.fromVector+toVectors                       = US.toVector  --- Random arrays -------------------------------------------randoms                 = Seq.random-randomRs                = Seq.randomR+-- Random arrays --------------------------------------------------------------+randoms                         = Seq.random+randomRs                        = Seq.randomR  --- IO -----------------------------------------------------+-- IO ------------------------------------------------------------------------- class Seq.UIO a => IOElt a-hPut                    = Seq.hPut-hGet                    = Seq.hGet-toList                  = Seq.toList-fromList                = Seq.fromList+hPut                            = Seq.hPut+hGet                            = Seq.hGet+toList                          = Seq.toList+fromList                        = Seq.fromList
Data/Array/Parallel/Unlifted/Distributed.hs view
@@ -1,47 +1,67 @@ -- | Distributed types and operations.-module Data.Array.Parallel.Unlifted.Distributed (-  -- * Gang operations-  Gang, forkGang, gangSize,+--+--   * This is an internal API and shouldn't need to be used directly.+--     Client programs should use "Data.Array.Parallel.Unlifted"+--+module Data.Array.Parallel.Unlifted.Distributed +        ( -- * Gang operations+          Gang, forkGang, gangSize -  -- * Gang hacks-  theGang,+          -- * Gang hacks+        , theGang -  -- * Distributed types and classes-  DT(..),+          -- * Distributed types and classes+        , DT(..) -  -- * Higher-order combinators-  mapD, zipWithD, foldD, scanD,+          -- * Higher-order combinators+        , mapD, zipWithD+        , foldD+        , scanD -  -- * Equality-  eqD, neqD,+          -- * Equality+        , eqD, neqD -  -- * Distributed scalars-  scalarD,-  andD, orD, sumD,+          -- * Distributed scalars+        , scalarD+        , andD, orD+        , sumD -  -- * Distributed pairs-  zipD, unzipD, fstD, sndD,+          -- * Distributed pairs+        , zipD, unzipD+        , fstD, sndD -  -- * Distributed arrays-  lengthD, splitLenD, splitLenIdxD,-  splitD, splitAsD, joinLengthD, joinD, splitJoinD, joinDM,-  splitSegdD, splitSegdD', splitSD,-  lengthUSegdD, lengthsUSegdD, indicesUSegdD, elementsUSegdD,-  Distribution, balanced, unbalanced,+          -- * Distributed arrays+        , lengthD+        , splitLenD+        , splitLenIdxD+        , splitD+        , splitAsD+        , joinLengthD+        , joinD+        , splitJoinD+        , joinDM+        , glueSegdD+        , carryD -  -- * Permutations-  permuteD, bpermuteD, atomicUpdateD,+        , Distribution+        , balanced+        , unbalanced -  -- * Debugging-  fromD, toD, debugD-) where+          -- * Permutations+        , permuteD, bpermuteD -import Data.Array.Parallel.Unlifted.Distributed.Gang (-  Gang, forkGang, gangSize)+          -- * Update+        , atomicUpdateD++          -- * Debugging+        , fromD, toD, debugD)+where import Data.Array.Parallel.Unlifted.Distributed.TheGang-import Data.Array.Parallel.Unlifted.Distributed.Types import Data.Array.Parallel.Unlifted.Distributed.Combinators import Data.Array.Parallel.Unlifted.Distributed.Scalars import Data.Array.Parallel.Unlifted.Distributed.Arrays+import Data.Array.Parallel.Unlifted.Distributed.USegd import Data.Array.Parallel.Unlifted.Distributed.Basics+import Data.Array.Parallel.Unlifted.Distributed.Types+import Data.Array.Parallel.Unlifted.Distributed.Gang (Gang, forkGang, gangSize) 
Data/Array/Parallel/Unlifted/Distributed/Arrays.hs view
@@ -1,38 +1,40 @@+{-# OPTIONS -Wall -fno-warn-orphans -fno-warn-missing-signatures #-} {-# LANGUAGE EmptyDataDecls, ScopedTypeVariables #-} {-# LANGUAGE CPP #-} #include "fusion-phases.h"  -- | Operations on distributed arrays.-module Data.Array.Parallel.Unlifted.Distributed.Arrays (-  lengthD, splitLenD, splitLenIdxD,-  splitAsD, splitD, joinLengthD, joinD, splitJoinD, joinDM,-  splitSegdD, splitSegdD', splitSD,+module Data.Array.Parallel.Unlifted.Distributed.Arrays +        ( -- * Distribution phantom parameter+          Distribution, balanced, unbalanced -  permuteD, bpermuteD, atomicUpdateD,+         -- * Array Lengths+        , lengthD, splitLenD, splitLenIdxD -  Distribution, balanced, unbalanced-) where-import Data.Array.Parallel.Base ( ST, runST)-import Data.Array.Parallel.Unlifted.Sequential.Vector as Seq-import Data.Array.Parallel.Unlifted.Sequential.Segmented-import Data.Array.Parallel.Unlifted.Distributed.Gang (-  Gang, gangSize, seqGang)-import Data.Array.Parallel.Unlifted.Distributed.DistST (-  DistST, stToDistST, myIndex )-import Data.Array.Parallel.Unlifted.Distributed.Types (-  DT, Dist, mkDPrim, indexD, lengthD, newD, writeMD, zipD, unzipD, fstD, sndD,-  elementsUSegdD,-  checkGangD)-import Data.Array.Parallel.Unlifted.Distributed.Basics-import Data.Array.Parallel.Unlifted.Distributed.Combinators-import Data.Array.Parallel.Unlifted.Distributed.Scalars (-  sumD)+         -- * Splitting and joining+        , splitAsD, splitD, joinLengthD, joinD, splitJoinD, joinDM -import Data.Bits ( shiftR )-import Control.Monad ( when )+         -- * Permutations+        , permuteD, bpermuteD -import GHC.Base ( quotInt, remInt )+          -- * Update+        , atomicUpdateD +          -- * Carry+        , carryD)+ where+import Data.Array.Parallel.Base (ST, runST)+import Data.Array.Parallel.Unlifted.Distributed.Gang+import Data.Array.Parallel.Unlifted.Distributed.DistST+import Data.Array.Parallel.Unlifted.Distributed.Types+import Data.Array.Parallel.Unlifted.Distributed.Combinators+import Data.Array.Parallel.Unlifted.Distributed.Scalars+import Data.Array.Parallel.Unlifted.Sequential.Vector   (Vector, MVector, Unbox)+import qualified Data.Array.Parallel.Unlifted.Sequential.Vector as Seq+import GHC.Base      ( quotInt, remInt )+import Control.Monad++here :: String -> String here s = "Data.Array.Parallel.Unlifted.Distributed.Arrays." Prelude.++ s  @@ -43,35 +45,47 @@ data Distribution  balanced :: Distribution+balanced   = error $ here "balanced: touched" {-# NOINLINE balanced #-}-balanced = error $ here "balanced: touched" + unbalanced :: Distribution-{-# NOINLINE unbalanced #-} unbalanced = error $ here "unbalanced: touched"+{-# NOINLINE unbalanced #-}   -- Splitting and Joining array lengths ------------------------------------------- | Distribute an array length over a 'Gang'.+-- | O(threads).+--   Distribute an array length over a 'Gang'. --   Each thread holds the number of elements it's reponsible for.+--   If the array length doesn't split evenly among the threads then the first+--   threads get a few more elements.+--+--   @splitLenD theGangN4 511+--      = [128,128,128,127]@+--  splitLenD :: Gang -> Int -> Dist Int-{-# INLINE splitLenD #-} splitLenD g n = generateD_cheap g len   where     !p = gangSize g     !l = n `quotInt` p-    !m = n `remInt` p+    !m = n `remInt`  p      {-# INLINE [0] len #-}     len i | i < m     = l+1           | otherwise = l+{-# INLINE splitLenD #-}  --- | Distribute an array length over a 'Gang'.+-- | O(threads).+--   Distribute an array length over a 'Gang'. --   Each thread holds the number of elements it's responsible for,  --   and the index of the start of its chunk.-splitLenIdxD :: Gang -> Int -> Dist (Int,Int)-{-# INLINE splitLenIdxD #-}+--+--   @splitLenIdxD theGangN4 511 +--      = [(128,0),(128,128),(128,256),(127,384)]@+--+splitLenIdxD :: Gang -> Int -> Dist (Int, Int) splitLenIdxD g n = generateD_cheap g len_idx   where     !p = gangSize g@@ -81,38 +95,48 @@     {-# INLINE [0] len_idx #-}     len_idx i | i < m     = (l+1, i*(l+1))               | otherwise = (l,   i*l + m)+{-# INLINE splitLenIdxD #-}  --- | Get the overall length of a distributed array.---   We ask each thread for its chunk length, and sum them all up.+-- | O(threads).+--   Get the overall length of a distributed array.+--   This is implemented by reading the chunk length from each thread, +--   and summing them up. joinLengthD :: Unbox a => Gang -> Dist (Vector a) -> Int-{-# INLINE joinLengthD #-} joinLengthD g = sumD g . lengthD+{-# INLINE joinLengthD #-}                                                  -- Splitting and Joining arrays ----------------------------------------------- -- | Distribute an array over a 'Gang' such that each threads gets the given --   number of elements.+--+--   @splitAsD theGangN4 (splitLenD theGangN4 10) [1 2 3 4 5 6 7 8 9 0]+--      = [[1 2 3] [4 5 6] [7 8] [9 0]]@+--  splitAsD :: Unbox a => Gang -> Dist Int -> Vector a -> Dist (Vector a)-{-# INLINE_DIST splitAsD #-}-splitAsD g dlen !arr = zipWithD (seqGang g) (Seq.slice arr) is dlen+splitAsD g dlen !arr +  = zipWithD (seqGang g) (Seq.slice "splitAsD" arr) is dlen   where     is = fst $ scanD g (+) 0 dlen+{-# INLINE_DIST splitAsD #-}   -- | Distribute an array over a 'Gang'. -- --   NOTE: This is defined in terms of splitD_impl to avoid introducing loops --         through RULES. Without it, splitJoinD would be a loop breaker.+--  splitD :: Unbox a => Gang -> Distribution -> Vector a -> Dist (Vector a)-{-# INLINE_DIST splitD #-} splitD g _ arr = splitD_impl g arr+{-# INLINE_DIST splitD #-} + splitD_impl :: Unbox a => Gang -> Vector a -> Dist (Vector a)-{-# INLINE_DIST splitD_impl #-}-splitD_impl g !arr = generateD_cheap g (\i -> Seq.slice arr (idx i) (len i))+splitD_impl g !arr +  = generateD_cheap g (\i -> Seq.slice "splitD_impl" arr (idx i) (len i))   where-    n = Seq.length arr+    n  = Seq.length arr     !p = gangSize g     !l = n `quotInt` p     !m = n `remInt` p@@ -124,24 +148,31 @@     {-# INLINE [0] len #-}     len i | i < m     = l+1           | otherwise = l+{-# INLINE_DIST splitD_impl #-}   -- | Join a distributed array.+--   Join sums up the array lengths of each chunk, allocates a new result array, +--   and copies each chunk into the result. -- --   NOTE: This is defined in terms of joinD_impl to avoid introducing loops --         through RULES. Without it, splitJoinD would be a loop breaker.+-- joinD :: Unbox a => Gang -> Distribution -> Dist (Vector a) -> Vector a-{-# INLINE CONLIKE [1] joinD #-} joinD g _ darr  = joinD_impl g darr+{-# INLINE CONLIKE [1] joinD #-} + joinD_impl :: forall a. Unbox a => Gang -> Dist (Vector a) -> Vector a-{-# INLINE_DIST joinD_impl #-}-joinD_impl g !darr = checkGangD (here "joinD") g darr $-                     Seq.new n (\ma -> zipWithDST_ g (copy ma) di darr)+joinD_impl g !darr +  = checkGangD (here "joinD") g darr +  $ Seq.new n (\ma -> zipWithDST_ g (copy ma) di darr)   where-    (!di,!n) = scanD g (+) 0 $ lengthD darr+    (!di,!n)      = scanD g (+) 0 $ lengthD darr+     copy :: forall s. MVector s a -> Int -> Vector a -> DistST s ()-    copy ma i arr = stToDistST (Seq.copy (mslice i (Seq.length arr) ma) arr)+    copy ma i arr = stToDistST (Seq.copy (Seq.mslice i (Seq.length arr) ma) arr)+{-# INLINE_DIST joinD_impl #-}   -- | Split a vector over a gang, run a distributed computation, then@@ -152,23 +183,24 @@         -> (Dist (Vector a) -> Dist (Vector b))         -> Vector a         -> Vector b+splitJoinD g f !xs +  = joinD_impl g (f (splitD_impl g xs)) {-# INLINE_DIST splitJoinD #-}-splitJoinD g f !xs = joinD_impl g (f (splitD_impl g xs))    -- | Join a distributed array, yielding a mutable global array joinDM :: Unbox a => Gang -> Dist (Vector a) -> ST s (MVector s a)+joinDM g darr + = checkGangD (here "joinDM") g darr + $ do   marr <- Seq.newM n+        zipWithDST_ g (copy marr) di darr+        return marr+ where+        (!di,!n) = scanD g (+) 0 $ lengthD darr++        copy ma i arr = stToDistST (Seq.copy (Seq.mslice i (Seq.length arr) ma) arr) {-# INLINE joinDM #-}-joinDM g darr = checkGangD (here "joinDM") g darr $-                do-                  marr <- Seq.newM n-                  zipWithDST_ g (copy marr) di darr-                  return marr-  where-    (!di,!n) = scanD g (+) 0 $ lengthD darr-    ---    copy ma i arr = stToDistST (Seq.copy (mslice i (Seq.length arr) ma) arr)   {-# RULES@@ -211,20 +243,24 @@  -- Permutation ---------------------------------------------------------------- -- | Permute for distributed arrays.-permuteD :: forall a. Unbox a => Gang -> Dist (Vector a) -> Dist (Vector Int) -> Vector a-{-# INLINE_DIST permuteD #-}-permuteD g darr dis = Seq.new n (\ma -> zipWithDST_ g (permute ma) darr dis)+permuteD +        :: forall a. Unbox a +        => Gang -> Dist (Vector a) -> Dist (Vector Int) -> Vector a+permuteD g darr dis +  = Seq.new n (\ma -> zipWithDST_ g (permute ma) darr dis)   where     n = joinLengthD g darr+     permute :: forall s. MVector s a -> Vector a -> Vector Int -> DistST s ()     permute ma arr is = stToDistST (Seq.mpermute ma arr is)+{-# INLINE_DIST permuteD #-}   -- NOTE: The bang is necessary because the array must be fully evaluated -- before we pass it to the parallel computation. bpermuteD :: Unbox a => Gang -> Vector a -> Dist (Vector Int) -> Dist (Vector a)-{-# INLINE bpermuteD #-} bpermuteD g !as ds = mapD g (Seq.bpermute as) ds+{-# INLINE bpermuteD #-}   -- Update ---------------------------------------------------------------------@@ -233,119 +269,99 @@ -- error. atomicUpdateD :: forall a. Unbox a              => Gang -> Dist (Vector a) -> Dist (Vector (Int,a)) -> Vector a+atomicUpdateD g darr upd + = runST + $ do   marr <- joinDM g darr+        mapDST_ g (update marr) upd+        Seq.unsafeFreeze marr+ where+        update :: forall s. MVector s a -> Vector (Int,a) -> DistST s ()+        update marr arr = stToDistST (Seq.mupdate marr arr) {-# INLINE atomicUpdateD #-}-atomicUpdateD g darr upd = runST (-  do-    marr <- joinDM g darr-    mapDST_ g (update marr) upd-    Seq.unsafeFreeze marr-  )-  where-    update :: forall s. MVector s a -> Vector (Int,a) -> DistST s ()-    update marr arr = stToDistST (Seq.mupdate marr arr)  ---- Splitting and Joining segment descriptors ----------------------------------splitSegdD :: Gang -> USegd -> Dist USegd-{-# NOINLINE splitSegdD #-}-splitSegdD g !segd = mapD g lengthsToUSegd-                   $ splitAsD g d lens-  where-    !d = snd-       . mapAccumLD g chunk 0-       . splitLenD g-       $ elementsUSegd segd--    n    = lengthUSegd segd-    lens = lengthsUSegd segd--    chunk !i !k = let !j = go i k-                  in (j,j-i)--    go !i !k | i >= n    = i-             | m == 0    = go (i+1) k-             | k <= 0    = i-             | otherwise = go (i+1) (k-m)-      where-        m = lens ! i---search :: Int -> Vector Int -> Int-search !x ys = go 0 (Seq.length ys)-  where-    go i n | n <= 0        = i-           | (ys!mid) < x = go (mid+1) (n-half-1)-           | otherwise     = go i half-      where-        half = n `shiftR` 1-        mid  = i + half---chunk :: USegd -> Int -> Int -> Bool -> (# Vector Int, Int, Int #)-chunk !segd !di !dn is_last-  = (# lens', k-left_len, left_off #)-  where-    !lens' = runST (do-                      mlens' <- Seq.newM n'-                      when (left /= 0) $ Seq.write mlens' 0 left-                      Seq.copy (Seq.mdrop left_len mlens')-                               (Seq.slice lens k (k'-k))-                      when (right /= 0) $ Seq.write mlens' (n' - 1) right-                      Seq.unsafeFreeze mlens')--    lens = lengthsUSegd segd-    idxs = indicesUSegd segd-    n    = Seq.length lens--    k  = search di idxs-    k' | is_last   = n-       | otherwise = search (di+dn) idxs--    left  | k == n    = dn-          | otherwise = min ((idxs!k) - di) dn--    right | k' == k   = 0-          | otherwise = di + dn - (idxs ! (k'-1))--    left_len | left == 0   = 0-             | otherwise   = 1--    left_off | left == 0   = 0-             | otherwise   = di - idxs ! (k-1)+-- Carry ----------------------------------------------------------------------+-- | Selectively combine the last elements of some chunks with the+--   first elements of others.+--+--   NOTE: This runs sequentially and should only be used for testing purposes.+--+-- @+-- pprp $ splitD theGang unbalanced $ fromList [80, 10, 20, 40, 50, 10 :: Int]+-- DVector lengths: [2,2,1,1]+--         chunks:  [[80,10],[20,40],[50],[10]]+-- +--  pprp $ fst +--       $ carryD theGang (+) 0 +--          (mkDPrim $ fromList [True, False, True, False]) +--          (splitD theGang unbalanced $ fromList [80, 10, 20, 40, 50, 10 :: Int])+--+--  DVector lengths: [1,2,0,1]+--          chunks: [[80],[30,40],[],[60]]+-- @+--+carryD  :: forall a+        .  (Unbox a, DT a)+        => Gang +        -> (a -> a -> a) -> a+        -> Dist Bool+        -> Dist (Vector a)+        -> (Dist (Vector a), a) -    n' = left_len + (k'-k)+carryD gang f zero shouldCarry vec+ = runST + $ do   md      <- newMD gang+        acc     <- carryD' f zero shouldCarry vec md+        d       <- unsafeFreezeMD md+        return (d, acc)  -splitSegdD' :: Gang -> USegd -> Dist ((USegd,Int),Int)-{-# INLINE splitSegdD' #-}-splitSegdD' g !segd = imapD g mk-                         (splitLenIdxD g-                         (elementsUSegd segd))-  where-    !p = gangSize g--    mk i (dn,di) = case chunk segd di dn (i == p-1) of-                     (# lens, l, o #) -> ((lengthsToUSegd lens,l),o)+carryD' :: forall a s+        .  (Unbox a, DT a)+        => (a -> a -> a) -> a+        -> Dist Bool+        -> Dist (Vector a)+        -> MDist (Vector a) s+        -> ST s a +carryD' f zero shouldCarry vec md_+ = go md_ zero 0+ where go (md :: MDist (Vector a) s) prev ix+        | ix >= sizeD vec    = return prev+        | otherwise+        = do let chunk :: Vector a+                 !chunk      = indexD (here "carryD'") vec ix+             let !chunkLen   = Seq.length chunk -joinSegD :: Gang -> Dist USegd -> USegd-{-# INLINE_DIST joinSegD #-}-joinSegD g = lengthsToUSegd-           . joinD g unbalanced-           . mapD g lengthsUSegd+             -- Whether to carry the last value of this chunk into the next chunk+             let !carry      = indexD (here "carryD") shouldCarry ix +             -- The new length for this chunk+             let !chunkLen'  +                   | chunkLen == 0 = 0+                   | carry         = chunkLen - 1+                   | otherwise     = chunkLen -splitSD :: Unbox a => Gang -> Dist USegd -> Vector a -> Dist (Vector a)-{-# INLINE_DIST splitSD #-}-splitSD g dsegd xs = splitAsD g (elementsUSegdD dsegd) xs+             -- The new value of the accumulator+             let acc            = f prev (Seq.index (here "carryD'") chunk 0)+                +             -- Allocate a mutable vector to hold the new chunk and copy+             -- source elements into it.+             mchunk' <- Seq.newM chunkLen'+             Seq.copy mchunk' (Seq.slice (here "carryD'") chunk 0 chunkLen') -{-# RULES+             when (chunkLen' /= 0)+              $ Seq.write mchunk' 0 acc -"splitSD/splitJoinD" forall g d f xs.-  splitSD g d (splitJoinD g f xs) = f (splitSD g d xs)+             -- Store the new chunk in the gang+             chunk'  <- Seq.unsafeFreeze mchunk'+             writeMD md ix chunk' -"splitSD/Seq.zip" forall g d xs ys.-  splitSD g d (Seq.zip xs ys) = zipWithD g Seq.zip (splitSD g d xs)-                                             (splitSD g d ys)+             -- What value to carry into the next chunk+             let next+                  | chunkLen' == 0      = acc+                  | carry               = Seq.index (here "next") chunk (chunkLen - 1)+                  | otherwise           = zero+                               +             go md next (ix + 1) -  #-}
Data/Array/Parallel/Unlifted/Distributed/Basics.hs view
@@ -1,44 +1,46 @@+{-# OPTIONS -Wall -fno-warn-orphans #-}+ -- | Basic operations on distributed types.-module Data.Array.Parallel.Unlifted.Distributed.Basics (-  eqD, neqD, toD, fromD-) where-import Data.Array.Parallel.Unlifted.Distributed.Gang (-  Gang, gangSize)-import Data.Array.Parallel.Unlifted.Distributed.Types (-  DT, Dist, indexD, newD, writeMD,-  checkGangD)-import Data.Array.Parallel.Unlifted.Distributed.Combinators (-  zipWithD)-import Data.Array.Parallel.Unlifted.Distributed.Scalars (-  andD, orD)+module Data.Array.Parallel.Unlifted.Distributed.Basics +        (eqD, neqD, toD, fromD)+where+import Data.Array.Parallel.Unlifted.Distributed.Gang +import Data.Array.Parallel.Unlifted.Distributed.Types+import Data.Array.Parallel.Unlifted.Distributed.Combinators +import Data.Array.Parallel.Unlifted.Distributed.Scalars import Control.Monad ( zipWithM_ ) -+here :: String -> String here s = "Data.Array.Parallel.Unlifted.Distributed.Basics." ++ s   -- | Test whether to distributed values are equal.  --   This requires a 'Gang' and hence can't be defined in terms of 'Eq'. eqD :: (Eq a, DT a) => Gang -> Dist a -> Dist a -> Bool-eqD g dx dy = andD g (zipWithD g (==) dx dy)+eqD g dx dy +        = andD g (zipWithD g (==) dx dy)   -- | Test whether to distributed values are not equal. --   This requires a 'Gang' and hence can't be defined in terms of 'Eq'. neqD :: (Eq a, DT a) => Gang -> Dist a -> Dist a -> Bool-neqD g dx dy = orD g (zipWithD g (/=) dx dy)-+neqD g dx dy +        = orD g (zipWithD g (/=) dx dy)   -- | Generate a distributed value from the first @p@ elements of a list.---   /NOTE:/ For debugging only, don't use in production code.+-- +--   * For debugging only, don't use in production code. toD :: DT a => Gang -> [a] -> Dist a toD g xs = newD g (\md -> zipWithM_ (writeMD md) [0 .. gangSize g - 1] xs)   -- | Yield all elements of a distributed value.---   /NOTE:/ For debugging only, don't use in production code.+--+--   * For debugging only, don't use in production code. fromD :: DT a => Gang -> Dist a -> [a]-fromD g dt = checkGangD (here "fromDT") g dt $-             map (indexD dt) [0 .. gangSize g - 1]+fromD g dt +        = checkGangD (here "fromDT") g dt +        $ map   (indexD (here "fromD") dt) +                [0 .. gangSize g - 1] 
Data/Array/Parallel/Unlifted/Distributed/Combinators.hs view
@@ -1,42 +1,49 @@+{-# OPTIONS -Wall -fno-warn-orphans -fno-warn-missing-signatures #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE CPP #-} #include "fusion-phases.h"  -- | Standard combinators for distributed types.-module Data.Array.Parallel.Unlifted.Distributed.Combinators (-  generateD, generateD_cheap,-  imapD, mapD, zipD, unzipD, fstD, sndD, zipWithD, izipWithD,-  foldD, scanD, mapAccumLD,+module Data.Array.Parallel.Unlifted.Distributed.Combinators +        ( generateD, generateD_cheap+        , imapD, mapD+        , zipD, unzipD+        , fstD, sndD+        , zipWithD, izipWithD+        , foldD+        , scanD+        , mapAccumLD -  -- * Monadic combinators-  mapDST_, mapDST, zipWithDST_, zipWithDST-) where+           -- * Monadic combinators+        , mapDST_, mapDST, zipWithDST_, zipWithDST)+where import Data.Array.Parallel.Base ( ST, runST)-import Data.Array.Parallel.Unlifted.Distributed.Gang (-  Gang, gangSize)-import Data.Array.Parallel.Unlifted.Distributed.Types (-  DT, Dist, MDist, indexD, zipD, unzipD, fstD, sndD, deepSeqD,-  newMD, writeMD, unsafeFreezeMD,-  checkGangD, measureD, debugD)+import Data.Array.Parallel.Unlifted.Distributed.Gang+import Data.Array.Parallel.Unlifted.Distributed.Types import Data.Array.Parallel.Unlifted.Distributed.DistST-import Debug.Trace   here s = "Data.Array.Parallel.Unlifted.Distributed.Combinators." ++ s ---- | Create a distributed value, given a function that makes the value in each thread.+-- | Create a distributed value, given a function to create the instance+--   for each thread. generateD :: DT a => Gang -> (Int -> a) -> Dist a-{-# NOINLINE generateD #-} generateD g f          = runDistST g (myIndex >>= return . f)+{-# NOINLINE generateD #-}  --- | Create a distributed value, but run it sequentially (I think?)+-- | Create a distributed value, but do it sequentially.+--  +--   This function is used when we want to operate on a distributed value, but+--   there isn't much data involved. For example, if we want to distribute +--   a single integer to each thread, then there's no need to fire up the +--   gang for this.+--    generateD_cheap :: DT a => Gang -> (Int -> a) -> Dist a-{-# NOINLINE generateD_cheap #-} generateD_cheap g f          = runDistST_seq g (myIndex >>= return . f)+{-# NOINLINE generateD_cheap #-}   -- Mapping --------------------------------------------------------------------@@ -45,26 +52,34 @@ --   As opposed to `imapD'` this version also deepSeqs each element before --   passing it to the function. imapD :: (DT a, DT b) => Gang -> (Int -> a -> b) -> Dist a -> Dist b-{-# INLINE [0] imapD #-} imapD g f d = imapD' g (\i x -> x `deepSeqD` f i x) d+{-# INLINE [0] imapD #-}   -- | Map a function across all elements of a distributed value. --   The worker function also gets the current thread index. imapD' :: (DT a, DT b) => Gang -> (Int -> a -> b) -> Dist a -> Dist b+imapD' g f !d +  = checkGangD (here "imapD") g d+  $ runDistST g +        (do i <- myIndex+            x <- myD d+            return (f i x)) {-# NOINLINE imapD' #-}-imapD' g f !d = checkGangD (here "imapD") g d-                (runDistST g (do-                                i <- myIndex-                                x <- myD d-                                return (f i x)))  --- | Map a function over a distributed value.+-- | Map a function to every instance of a distributed value.+--+--   This applies the function to every thread, but not every value held+--   by the thread. If you want that then use something like:+-- +--   @mapD theGang (V.map (+ 1)) :: Dist (Vector Int) -> Dist (Vector Int)@+-- mapD :: (DT a, DT b) => Gang -> (a -> b) -> Dist a -> Dist b-{-# INLINE mapD #-} mapD g = imapD g . const+{-# INLINE mapD #-} + {-# RULES  "imapD/generateD" forall gang f g.@@ -83,17 +98,18 @@ -- | Combine two distributed values with the given function. zipWithD :: (DT a, DT b, DT c)          => Gang -> (a -> b -> c) -> Dist a -> Dist b -> Dist c-{-# INLINE zipWithD #-} zipWithD g f dx dy = mapD g (uncurry f) (zipD dx dy)+{-# INLINE zipWithD #-}   -- | Combine two distributed values with the given function. --   The worker function also gets the index of the current thread. izipWithD :: (DT a, DT b, DT c)           => Gang -> (Int -> a -> b -> c) -> Dist a -> Dist b -> Dist c-{-# INLINE izipWithD #-} izipWithD g f dx dy = imapD g (\i -> uncurry (f i)) (zipD dx dy)+{-# INLINE izipWithD #-} + {-# RULES "zipD/imapD[1]" forall gang f xs ys.   zipD (imapD gang f xs) ys@@ -115,54 +131,66 @@   -- Folding ----------------------------------------------------------------------- | Fold a distributed value.+-- | Fold all the instances of a distributed value. foldD :: DT a => Gang -> (a -> a -> a) -> Dist a -> a-{-# NOINLINE foldD #-}-foldD g f !d = checkGangD ("here foldD") g d $-              fold 1 (d `indexD` 0)+foldD g f !d +  = checkGangD ("here foldD") g d +  $ fold 1 (indexD (here "foldD") d 0)   where     !n = gangSize g     --     fold i x | i == n    = x-             | otherwise = fold (i+1) (f x $ d `indexD` i)+             | otherwise = fold (i+1) (f x $ indexD (here "foldD") d i)+{-# NOINLINE foldD #-}  --- | Prefix sum of a distributed value.+-- | Prefix sum of the instances of a distributed value. scanD :: forall a. DT a => Gang -> (a -> a -> a) -> a -> Dist a -> (Dist a, a)-{-# NOINLINE scanD #-}-scanD g f z !d = checkGangD (here "scanD") g d $-                 runST (do-                   md <- newMD g-                   s  <- scan md 0 z-                   d' <- unsafeFreezeMD md-                   return (d',s))+scanD g f z !d+  = checkGangD (here "scanD") g d +  $ runST (do+          md <- newMD g+          s  <- scan md 0 z+          d' <- unsafeFreezeMD md+          return (d',s))   where     !n = gangSize g+         scan :: forall s. MDist a s -> Int -> a -> ST s a-    scan md i !x | i == n    = return x-                 | otherwise = do-                                 writeMD md i x-                                 scan md (i+1) (f x $ d `indexD` i)+    scan md i !x+        | i == n    = return x+        | otherwise+        = do    writeMD md i x+                scan md (i+1) (f x $ indexD (here "scanD") d i)+{-# NOINLINE scanD #-} + -- | Combination of map and fold.-mapAccumLD :: forall a b acc. (DT a, DT b)-           => Gang -> (acc -> a -> (acc,b))-                   -> acc -> Dist a -> (acc,Dist b)-{-# INLINE_DIST mapAccumLD #-}-mapAccumLD g f acc !d = checkGangD (here "mapAccumLD") g d $-                        runST (do-                          md   <- newMD g-                          acc' <- go md 0 acc-                          d'   <- unsafeFreezeMD md-                          return (acc',d'))+mapAccumLD +        :: forall a b acc. (DT a, DT b)+        => Gang+        -> (acc -> a      -> (acc, b))+        ->  acc -> Dist a -> (acc, Dist b)++mapAccumLD g f acc !d+  = checkGangD (here "mapAccumLD") g d +  $ runST (do+        md   <- newMD g+        acc' <- go md 0 acc+        d'   <- unsafeFreezeMD md+        return (acc',d'))   where     !n = gangSize g+         go :: MDist b s -> Int -> acc -> ST s acc-    go md i acc | i == n    = return acc-                | otherwise = case f acc (d `indexD` i) of-                                (acc',b) -> do-                                              writeMD md i b-                                              go md (i+1) acc'+    go md i acc'+        | i == n    = return acc'+        | otherwise+        = case f acc' (indexD (here "mapAccumLD") d i) of+                (acc'',b) -> do+                      writeMD md i b+                      go md (i+1) acc''+{-# INLINE_DIST mapAccumLD #-}                                   -- Versions that work on DistST -----------------------------------------------@@ -172,33 +200,41 @@ -- model andlead to a deadlock. Hence the bangs.  mapDST_ :: DT a => Gang -> (a -> DistST s ()) -> Dist a -> ST s ()+mapDST_ g p d + = mapDST_' g (\x -> x `deepSeqD` p x) d {-# INLINE mapDST_ #-}-mapDST_ g p d = mapDST_' g (\x -> x `deepSeqD` p x) d   mapDST_' :: DT a => Gang -> (a -> DistST s ()) -> Dist a -> ST s ()-mapDST_' g p !d = checkGangD (here "mapDST_") g d $-                  distST_ g (myD d >>= p)+mapDST_' g p !d + = checkGangD (here "mapDST_") g d + $ distST_ g (myD d >>= p)   mapDST :: (DT a, DT b) => Gang -> (a -> DistST s b) -> Dist a -> ST s (Dist b)-{-# INLINE mapDST #-} mapDST g p !d = mapDST' g (\x -> x `deepSeqD` p x) d+{-# INLINE mapDST #-} + mapDST' :: (DT a, DT b) => Gang -> (a -> DistST s b) -> Dist a -> ST s (Dist b)-mapDST' g p !d = checkGangD (here "mapDST_") g d $-                 distST g (myD d >>= p)+mapDST' g p !d + = checkGangD (here "mapDST_") g d + $ distST g (myD d >>= p)  -zipWithDST_ :: (DT a, DT b)-            => Gang -> (a -> b -> DistST s ()) -> Dist a -> Dist b -> ST s ()+zipWithDST_ +        :: (DT a, DT b)+        => Gang -> (a -> b -> DistST s ()) -> Dist a -> Dist b -> ST s ()+zipWithDST_ g p !dx !dy + = mapDST_ g (uncurry p) (zipD dx dy) {-# INLINE zipWithDST_ #-}-zipWithDST_ g p !dx !dy = mapDST_ g (uncurry p) (zipD dx dy)  -zipWithDST :: (DT a, DT b, DT c)-           => Gang-           -> (a -> b -> DistST s c) -> Dist a -> Dist b -> ST s (Dist c)+zipWithDST +        :: (DT a, DT b, DT c)+        => Gang+        -> (a -> b -> DistST s c) -> Dist a -> Dist b -> ST s (Dist c)+zipWithDST g p !dx !dy + = mapDST g (uncurry p) (zipD dx dy) {-# INLINE zipWithDST #-}-zipWithDST g p !dx !dy = mapDST g (uncurry p) (zipD dx dy) 
Data/Array/Parallel/Unlifted/Distributed/DistST.hs view
@@ -1,3 +1,4 @@+{-# OPTIONS -Wall -fno-warn-orphans -fno-warn-missing-signatures #-} {-# LANGUAGE ScopedTypeVariables #-} -- | Distributed ST computations. --@@ -7,15 +8,19 @@ --  thread. -- -- /TODO:/ Add facilities for implementing parallel scans etc.-module Data.Array.Parallel.Unlifted.Distributed.DistST (-  DistST, stToDistST, distST_, distST, runDistST, runDistST_seq, traceDistST,-  myIndex, myD, readMyMD, writeMyMD-) where-import Data.Array.Parallel.Base (-  ST, runST)+module Data.Array.Parallel.Unlifted.Distributed.DistST +        ( DistST+        , stToDistST+        , distST_, distST+        , runDistST, runDistST_seq+        , traceDistST+        , myIndex+        , myD+        , readMyMD, writeMyMD)+where+import Data.Array.Parallel.Base (ST, runST) import Data.Array.Parallel.Unlifted.Distributed.Gang-import Data.Array.Parallel.Unlifted.Distributed.Types (-  DT(..), Dist, MDist)+import Data.Array.Parallel.Unlifted.Distributed.Types (DT(..), Dist, MDist)  import Control.Monad (liftM) @@ -38,62 +43,62 @@  -- | Yields the index of the current thread within its gang. myIndex :: DistST s Int-{-# INLINE myIndex #-} myIndex = DistST return+{-# INLINE myIndex #-}   -- | Lifts an 'ST' computation into the 'DistST' monad. --   The lifted computation should be data parallel. stToDistST :: ST s a -> DistST s a+stToDistST p = DistST $ \_ -> p {-# INLINE stToDistST #-}-stToDistST p = DistST $ \i -> p   -- | Yields the 'Dist' element owned by the current thread. myD :: DT a => Dist a -> DistST s a+myD dt = liftM (indexD "myD" dt) myIndex {-# NOINLINE myD #-}-myD dt = liftM (indexD dt) myIndex   -- | Yields the 'MDist' element owned by the current thread. readMyMD :: DT a => MDist a s -> DistST s a-{-# NOINLINE readMyMD #-} readMyMD mdt   = do	i <- myIndex 	stToDistST $ readMD mdt i+{-# NOINLINE readMyMD #-}   -- | Writes the 'MDist' element owned by the current thread. writeMyMD :: DT a => MDist a s -> a -> DistST s ()-{-# NOINLINE writeMyMD #-} writeMyMD mdt x   = do	i <- myIndex 	stToDistST $ writeMD mdt i x+{-# NOINLINE writeMyMD #-}   -- | Execute a data-parallel computation on a 'Gang'. --   The same DistST comutation runs on each thread. distST_ :: Gang -> DistST s () -> ST s ()-{-# INLINE distST_ #-} distST_ g = gangST g . unDistST+{-# INLINE distST_ #-}   -- | Execute a data-parallel computation, yielding the distributed result. distST :: DT a => Gang -> DistST s a -> ST s (Dist a)-{-# INLINE distST #-} distST g p   = do	md <- newMD g         distST_ g $ writeMyMD md =<< p         unsafeFreezeMD md+{-# INLINE distST #-}   -- | Run a data-parallel computation, yielding the distributed result. runDistST :: DT a => Gang -> (forall s. DistST s a) -> Dist a-{-# NOINLINE runDistST #-} runDistST g p = runST (distST g p)+{-# NOINLINE runDistST #-} + runDistST_seq :: forall a. DT a => Gang -> (forall s. DistST s a) -> Dist a-{-# NOINLINE runDistST_seq #-} runDistST_seq g p = runST (   do      md <- newMD g@@ -106,6 +111,8 @@                             writeMD md i =<< unDistST p i                             go md (i+1)             | otherwise = return ()+{-# NOINLINE runDistST_seq #-}+  traceDistST :: String -> DistST s () traceDistST s = DistST $ \n -> traceGangST ("Worker " ++ show n ++ ": " ++ s)
Data/Array/Parallel/Unlifted/Distributed/Gang.hs view
@@ -1,32 +1,33 @@+{-# OPTIONS -Wall -fno-warn-orphans -fno-warn-missing-signatures #-} {-# LANGUAGE CPP #-} --- | Gang primitives.------ /TODO:/------ * Implement busy waiting.------ * Benchmark.------ * Generalise thread indices?-+-- If a work request is sent to the gang while another is already running+-- then just run it sequentially instead of dying. #define SEQ_IF_GANG_BUSY 1-#define TRACE_GANG 0 -module Data.Array.Parallel.Unlifted.Distributed.Gang (-  Gang, seqGang, forkGang, gangSize, gangIO, gangST, traceGang, traceGangST -) where+-- Trace all work requests sent to the gang.+#define TRACE_GANG 0 +-- | Gang primitives.+module Data.Array.Parallel.Unlifted.Distributed.Gang +        ( Gang+        , seqGang+        , forkGang+        , gangSize+        , gangIO, gangST+        , traceGang, traceGangST )+where import GHC.IO import GHC.ST-import GHC.Conc                  ( forkOn )-import GHC.Exts                  ( traceEvent )-+import Control.Concurrent        (forkOn) import Control.Concurrent.MVar-import Control.Exception         ( assert )-import Control.Monad             ( zipWithM, zipWithM_ )+import Control.Exception         (assert)+import Control.Monad +#if TRACE_GANG+import GHC.Exts                  (traceEvent) import System.Time ( ClockTime(..), getClockTime )+#endif   -- Requests and operations on them -------------------------------------------- -- | The 'Req' type encapsulates work requests for individual members of a gang. @@ -35,9 +36,9 @@ 	--   by writing to the MVar. 	= ReqDo	       (Int -> IO ()) (MVar ()) -	-- | Tell the worker that we're shutting the gang down. The worker should-	--   signal that it's received the equest down by writing to the MVar before-	--   returning to its caller (forkGang) 	+	-- | Tell the worker that we're shutting the gang down.+        --   The worker should signal that it's received the equest down by+        --   writing to the MVar before returning to its caller (forkGang) 	 	| ReqShutdown  (MVar ())  @@ -53,17 +54,16 @@ waitReq :: Req -> IO () waitReq req  = case req of-	ReqDo     fn varDone	-> takeMVar varDone+	ReqDo     _ varDone	-> takeMVar varDone 	ReqShutdown varDone	-> takeMVar varDone   -- Thread gangs and operations on them ---------------------------------------- -- | A 'Gang' is a group of threads which execute arbitrary work requests.---   To get the gang to do work, write Req-uest values---   to its MVars-data Gang = Gang !Int           -- Number of 'Gang' threads-                 [MVar Req]     -- One 'MVar' per thread-                 (MVar Bool)    -- Indicates whether the 'Gang' is busy+data Gang +        = Gang !Int           -- Number of 'Gang' threads+               [MVar Req]     -- One 'MVar' per thread+               (MVar Bool)    -- Indicates whether the 'Gang' is busy   instance Show Gang where@@ -91,7 +91,8 @@ 		start 	<- getGangTime 		action threadId 		end 	<- getGangTime-		traceGang $ "Worker " ++ show threadId ++ " end (" ++ diffTime start end ++ ")"+		traceGang $ "Worker " ++ show threadId +                          ++ " end (" ++ diffTime start end ++ ")" 		 		putMVar varDone () 		gangWorker threadId varReq@@ -102,18 +103,19 @@   -- | Finaliser for worker threads.---   We want to shutdown the corresponding thread when it's MVar becomes unreachable.---     Without this Repa programs can complain about "Blocked indefinitely on an MVar"---     because worker threads are still blocked on the request MVars when the program ends.---     Whether the finalizer is called or not is very racey. It happens about 1 in 10 runs---     when for the repa-edgedetect benchmark, and less often with the others.+--   We want to shutdown the corresponding thread when it's MVar becomes+--   unreachable. Without this the program can compilain about +--   "Blocked indefinitely on an MVar" because worker threads are still+--   blocked on the request MVars when the program ends. Whether this finalizer+--   is called or not is very racey. It can happen 1 in 10 times, or less often. --  --   We're relying on the comment in System.Mem.Weak that says---    "If there are no other threads to run, the runtime system will check for runnable---     finalizers before declaring the system to be deadlocked."+--   "If there are no other threads to run, the runtime system will check for+--    runnable finalizers before declaring the system to be deadlocked." -- ---   If we were creating and destroying the gang cleanly we wouldn't need this, but theGang ---     is created with a top-level unsafePerformIO. Hacks beget hacks beget hacks...+--   If we were creating and destroying the gang cleanly we wouldn't need this,+--   but theGang is created with a top-level unsafePerformIO.+--   Hacks beget hacks beget hacks... -- finaliseWorker :: MVar Req -> IO () finaliseWorker varReq@@ -131,7 +133,8 @@ 	-- Create the vars we'll use to issue work requests. 	mvs	<- sequence . replicate n $ newEmptyMVar 	-	-- Add finalisers so we can shut the workers down cleanly if they become unreachable.+	-- Add finalisers so we can shut the workers down cleanly if they+        -- become unreachable. 	mapM_ (\var -> addMVarFinalizer var (finaliseWorker var)) mvs  	-- Create all the worker threads@@ -144,22 +147,21 @@ 	return $ Gang n mvs busy  --- | The number of threads in the 'Gang'.+-- | O(1). Yield the number of threads in the 'Gang'. gangSize :: Gang -> Int gangSize (Gang n _ _) = n   -- | Issue work requests for the 'Gang' and wait until they have been executed.---   If the gang is already busy then just run the action in the---   requesting thread. ------   TODO: We might want to print a configurable warning that this is happening.---+--   If the gang is already busy then just run the action in the requesting+--   thread.  gangIO	:: Gang 	-> (Int -> IO ()) 	-> IO () -gangIO (Gang n [] busy)  p = mapM_ p [0 .. n-1]+gangIO (Gang n [] _)  p + = mapM_ p [0 .. n-1]+ #if SEQ_IF_GANG_BUSY gangIO (Gang n mvs busy) p   = do	traceGang   "gangIO: issuing work requests (SEQ_IF_GANG_BUSY)"@@ -170,17 +172,19 @@ 	 then mapM_ p [0 .. n-1] 	 else do 		parIO n mvs p-		swapMVar busy False+		_ <- swapMVar busy False 		return () #else gangIO (Gang n mvs busy) p = parIO n mvs p #endif + -- | Issue some requests to the worker threads and wait for them to complete. parIO 	:: Int			-- ^ Number of threads in the gang. 	-> [MVar Req]		-- ^ Request vars for worker threads.-	-> (Int -> IO ())	-- ^ Action to run in all the workers, it's given the ix of-				--   the particular worker thread it's running on.+	-> (Int -> IO ())	-- ^ Action to run in all the workers, it's+                                --   given the ix of the particular worker+                                ---  thread it's running on. 	-> IO ()  parIO n mvs p @@ -190,7 +194,7 @@ 	reqs	<- sequence . replicate n $ newReq p  	traceGang "parIO: issuing requests"-	zipWithM putMVar mvs reqs+	zipWithM_ putMVar mvs reqs  	traceGang "parIO: waiting for requests to complete" 	mapM_ waitReq reqs@@ -214,6 +218,7 @@ diffTime :: Integer -> Integer -> String diffTime x y = show (y-x) +-- | Emit a GHC event for debugging. traceGang :: String -> IO () traceGang s  = do	t <- getGangTime@@ -226,11 +231,13 @@ diffTime :: () -> () -> String diffTime _ _ = "" +-- | Emit a GHC event for debugging. traceGang :: String -> IO () traceGang _ = return ()- #endif ++-- | Emit a GHC event for debugging, in the `ST` monad. traceGangST :: String -> ST s () traceGangST s = unsafeIOToST (traceGang s) 
Data/Array/Parallel/Unlifted/Distributed/Scalars.hs view
@@ -1,21 +1,21 @@--- | Distributed scalars.+{-# OPTIONS -Wall -fno-warn-orphans -fno-warn-missing-signatures #-}++-- | Operations on distributed scalars. --   With a distributed value like (Dist Int), each thread has its own integer,  --   which may or may not have the same values as the ones on other threads.-module Data.Array.Parallel.Unlifted.Distributed.Scalars (-  unitD, scalarD,-  orD, andD, sumD-) where--import Data.Array.Parallel.Unlifted.Distributed.Gang (-  Gang)-import Data.Array.Parallel.Unlifted.Distributed.Types (-  DT, Dist, unitD)-import Data.Array.Parallel.Unlifted.Distributed.Combinators (-  mapD, foldD)+module Data.Array.Parallel.Unlifted.Distributed.Scalars +        ( scalarD+        , orD, andD+        , sumD)+where+import Data.Array.Parallel.Unlifted.Distributed.Gang+import Data.Array.Parallel.Unlifted.Distributed.Types+import Data.Array.Parallel.Unlifted.Distributed.Combinators   -- | Distribute a scalar. --   Each thread gets its own copy of the same value.+--   Example:  scalarD theGangN4 10 = [10, 10, 10, 10]  scalarD :: DT a => Gang -> a -> Dist a scalarD g x = mapD g (const x) (unitD g) 
Data/Array/Parallel/Unlifted/Distributed/TheGang.hs view
@@ -1,20 +1,22 @@---- DPH programs always used a single, shared gang of threads.--- The gang exists at top level, and is initialised unsafely.--- --- The Vectoriser guarantees that the gang is only used by a single--- computation at a time.----module Data.Array.Parallel.Unlifted.Distributed.TheGang (-  theGang-) where-+{-# OPTIONS -Wall -fno-warn-orphans -fno-warn-missing-signatures #-}+module Data.Array.Parallel.Unlifted.Distributed.TheGang +        (theGang)+where import Data.Array.Parallel.Unlifted.Distributed.Gang -+import Control.Concurrent (getNumCapabilities) import System.IO.Unsafe (unsafePerformIO)-import GHC.Conc (numCapabilities) +-- | DPH programs use this single, shared gang of threads.+--   The gang exists at top level, and is initialised at program start.+-- +--   The vectoriser guarantees that the gang is only used by a single+--   computation at a time. This is true because the program produced+--   by the vector only uses flat parallelism, so parallel computations+--   don't invoke further parallel computations. If the vectorised program+--   tries to use nested parallelism then there is a bug in the vectoriser,+--   and the code will run sequentially.+-- theGang :: Gang+theGang = unsafePerformIO (getNumCapabilities >>= forkGang) {-# NOINLINE theGang #-}-theGang = unsafePerformIO (forkGang numCapabilities) 
Data/Array/Parallel/Unlifted/Distributed/Types.hs view
@@ -1,495 +1,21 @@-{-# OPTIONS -fno-warn-incomplete-patterns #-}+{-# OPTIONS -Wall -fno-warn-orphans -fno-warn-missing-signatures #-} {-# LANGUAGE CPP #-}- #include "fusion-phases.h"  -- | Distributed types.-module Data.Array.Parallel.Unlifted.Distributed.Types (-  -- * Distributed types-  DT, Dist, MDist, DPrim(..),--  -- * Operations on immutable distributed types-  indexD, unitD, zipD, unzipD, fstD, sndD, lengthD,-  newD,-  -- zipSD, unzipSD, fstSD, sndSD,-  deepSeqD,--  lengthUSegdD, lengthsUSegdD, indicesUSegdD, elementsUSegdD,--  -- * Operations on mutable distributed types-  newMD, readMD, writeMD, unsafeFreezeMD,--  -- * Assertions-  checkGangD, checkGangMD,--  -- * Debugging functions-  sizeD, sizeMD, measureD, debugD-) where--import Data.Array.Parallel.Unlifted.Distributed.Gang (-  Gang, gangSize )-import Data.Array.Parallel.Unlifted.Sequential.Vector ( Unbox, Vector )-import qualified Data.Array.Parallel.Unlifted.Sequential.Vector as V-import Data.Array.Parallel.Unlifted.Sequential.Segmented-import Data.Array.Parallel.Base--import qualified Data.Vector.Unboxed as V-import qualified Data.Vector.Unboxed.Mutable as MV-import qualified Data.Vector as BV-import qualified Data.Vector.Mutable as MBV--import Data.Word     (Word8)-import Control.Monad (liftM, liftM2, liftM3)--import Data.List ( intercalate )--infixl 9 `indexD`--here s = "Data.Array.Parallel.Unlifted.Distributed.Types." ++ s----- Distributed Types ------------------------------------------------------------- | Class of distributable types. Instances of 'DT' can be---   distributed across all workers of a 'Gang'. ---   All such types must be hyperstrict as we do not want to pass thunks---   into distributed computations.-class DT a where-  data Dist  a-  data MDist a :: * -> *--  -- | Extract a single element of an immutable distributed value.-  indexD         :: Dist a -> Int -> a--  -- | Create an unitialised distributed value for the given 'Gang'.-  --   The gang is used (only) to know how many elements are needed-  --   in the distributed value.-  newMD          :: Gang                  -> ST s (MDist a s)--  -- | Extract an element from a mutable distributed value.-  readMD         :: MDist a s -> Int      -> ST s a--  -- | Write an element of a mutable distributed value.-  writeMD        :: MDist a s -> Int -> a -> ST s ()--  -- | Unsafely freeze a mutable distributed value.-  unsafeFreezeMD :: MDist a s             -> ST s (Dist a)--  deepSeqD       :: a -> b -> b-  deepSeqD = seq---  -- Debugging -------------------------  -- | Number of elements in the distributed value.-  --   For debugging only, as we shouldn't depend on the size of the gang.-  sizeD :: Dist a -> Int--  -- | Number of elements in the mutable distributed value.-  --   For debugging only, as we shouldn't care about the actual number.-  sizeMD :: MDist a s -> Int--  -- | Show a distributed value.-  --   For debugging only.-  measureD :: a -> String-  measureD _ = "None"---- Show instance (for debugging only)-instance (Show a, DT a) => Show (Dist a) where-  show d = show (Prelude.map (indexD d) [0 .. sizeD d - 1])------ Checking ---------------------------------------------------------------------- | Check that the sizes of the 'Gang' and of the distributed value match.-checkGangD :: DT a => String -> Gang -> Dist a -> b -> b-checkGangD loc g d v = checkEq loc "Wrong gang" (gangSize g) (sizeD d) v----- | Check that the sizes of the 'Gang' and of the mutable distributed value match.-checkGangMD :: DT a => String -> Gang -> MDist a s -> b -> b-checkGangMD loc g d v = checkEq loc "Wrong gang" (gangSize g) (sizeMD d) v----- Operations -------------------------------------------------------------------- | Given a computation that can write its result to a mutable distributed value, ---   run the computation to generate an immutable distributed value.-newD :: DT a => Gang -> (forall s . MDist a s -> ST s ()) -> Dist a-newD g init =-  runST (do-           mdt <- newMD g-           init mdt-           unsafeFreezeMD mdt)---- | Show all members of a distributed value.-debugD :: DT a => Dist a -> String-debugD d = "["-         ++ intercalate "," [measureD (indexD d i) | i <- [0 .. sizeD d-1]]-         ++ "]"----- DPrim ------------------------------------------------------------------------- | For distributed primitive values, we can just store all the members in---   a vector. The vector has the same length as the number of threads in the gang.----class Unbox e => DPrim e where--  -- | Make an immutable distributed value.-  mkDPrim :: V.Vector e -> Dist  e--  -- | Unpack an immutable distributed value back into a vector.-  unDPrim :: Dist  e -> V.Vector e--  -- | Make a mutable distributed value.-  mkMDPrim :: MV.STVector s e -> MDist  e s--  -- | Unpack a mutable distributed value back into a vector.-  unMDPrim :: MDist  e s -> MV.STVector s e----- | Get the member corresponding to a thread index.-primIndexD :: DPrim a => Dist a -> Int -> a-{-# INLINE primIndexD #-}-primIndexD = (V.!) . unDPrim----- | Create a new distributed value, having as many members as threads---   in the given 'Gang'.-primNewMD :: DPrim a => Gang -> ST s (MDist a s)-{-# INLINE primNewMD #-}-primNewMD = liftM mkMDPrim . MV.new . gangSize----- | Read the member of a distributed value corresponding to the given thread index.-primReadMD :: DPrim a => MDist a s -> Int -> ST s a-{-# INLINE primReadMD #-}-primReadMD = MV.read . unMDPrim----- | Write the member of a distributed value corresponding to the given thread index.-primWriteMD :: DPrim a => MDist a s -> Int -> a -> ST s ()-{-# INLINE primWriteMD #-}-primWriteMD = MV.write . unMDPrim----- | Freeze a mutable distributed value to an immutable one.---   You promise not to update the mutable one any further.-primUnsafeFreezeMD :: DPrim a => MDist a s -> ST s (Dist a)-{-# INLINE primUnsafeFreezeMD #-}-primUnsafeFreezeMD = liftM mkDPrim . V.unsafeFreeze . unMDPrim----- | Get the size of a distributed value, that is, the number of threads---   in the gang that it was created for.-primSizeD :: DPrim a => Dist a -> Int-{-# INLINE primSizeD #-}-primSizeD = V.length . unDPrim----- | Get the size of a distributed mutable value, that is, the number of threads---   in the gang it was created for.-primSizeMD :: DPrim a => MDist a s -> Int-{-# INLINE primSizeMD #-}-primSizeMD = MV.length . unMDPrim----- Unit ------------------------------------------------------------------------instance DT () where-  data Dist ()    = DUnit  !Int-  data MDist () s = MDUnit !Int--  indexD  (DUnit n) i       = check (here "indexD[()]") n i $ ()-  newMD                     = return . MDUnit . gangSize-  readMD   (MDUnit n) i     = check (here "readMD[()]")  n i $-                               return ()-  writeMD  (MDUnit n) i ()  = check (here "writeMD[()]") n i $-                               return ()-  unsafeFreezeMD (MDUnit n) = return $ DUnit n--  sizeD  = error "dph-prim-par:sizeD[()] undefined"-  sizeMD = error "dph-prim-par:sizeMD[()] undefined"---- | Yield a distributed unit.-unitD :: Gang -> Dist ()-{-# INLINE_DIST unitD #-}-unitD = DUnit . gangSize----- Bool ------------------------------------------------------------------------instance DPrim Bool where-  mkDPrim           = DBool-  unDPrim (DBool a) = a--  mkMDPrim            = MDBool-  unMDPrim (MDBool a) = a--instance DT Bool where-  data Dist  Bool   = DBool  !(V.Vector    Bool)-  data MDist Bool s = MDBool !(MV.STVector s Bool)--  indexD         = primIndexD-  newMD          = primNewMD-  readMD         = primReadMD-  writeMD        = primWriteMD-  unsafeFreezeMD = primUnsafeFreezeMD-  sizeD          = primSizeD-  sizeMD         = primSizeMD----- Char ------------------------------------------------------------------------instance DPrim Char where-  mkDPrim           = DChar-  unDPrim (DChar a) = a--  mkMDPrim            = MDChar-  unMDPrim (MDChar a) = a--instance DT Char where-  data Dist  Char   = DChar  !(V.Vector    Char)-  data MDist Char s = MDChar !(MV.STVector s Char)--  indexD         = primIndexD-  newMD          = primNewMD-  readMD         = primReadMD-  writeMD        = primWriteMD-  unsafeFreezeMD = primUnsafeFreezeMD-  sizeD          = primSizeD-  sizeMD         = primSizeMD----- Int -------------------------------------------------------------------------instance DPrim Int where-  mkDPrim          = DInt-  unDPrim (DInt a) = a--  mkMDPrim            = MDInt-  unMDPrim (MDInt a) = a--instance DT Int where-  data Dist  Int   = DInt  !(V.Vector    Int)-  data MDist Int s = MDInt !(MV.STVector s Int)--  indexD         = primIndexD-  newMD          = primNewMD-  readMD         = primReadMD-  writeMD        = primWriteMD-  unsafeFreezeMD = primUnsafeFreezeMD-  sizeD          = primSizeD-  sizeMD         = primSizeMD--  measureD n = "Int " ++ show n----- Word8 -----------------------------------------------------------------------instance DPrim Word8 where-  mkDPrim            = DWord8-  unDPrim (DWord8 a) = a--  mkMDPrim             = MDWord8-  unMDPrim (MDWord8 a) = a--instance DT Word8 where-  data Dist  Word8   = DWord8  !(V.Vector    Word8)-  data MDist Word8 s = MDWord8 !(MV.STVector s Word8)--  indexD         = primIndexD-  newMD          = primNewMD-  readMD         = primReadMD-  writeMD        = primWriteMD-  unsafeFreezeMD = primUnsafeFreezeMD-  sizeD          = primSizeD-  sizeMD         = primSizeMD----- Float -----------------------------------------------------------------------instance DPrim Float where-  mkDPrim            = DFloat-  unDPrim (DFloat a) = a--  mkMDPrim             = MDFloat-  unMDPrim (MDFloat a) = a--instance DT Float where-  data Dist  Float   = DFloat  !(V.Vector    Float)-  data MDist Float s = MDFloat !(MV.STVector s Float)--  indexD         = primIndexD-  newMD          = primNewMD-  readMD         = primReadMD-  writeMD        = primWriteMD-  unsafeFreezeMD = primUnsafeFreezeMD-  sizeD          = primSizeD-  sizeMD         = primSizeMD----- Double ----------------------------------------------------------------------instance DPrim Double where-  mkDPrim             = DDouble-  unDPrim (DDouble a) = a--  mkMDPrim              = MDDouble-  unMDPrim (MDDouble a) = a--instance DT Double where-  data Dist  Double   = DDouble  !(V.Vector    Double)-  data MDist Double s = MDDouble !(MV.STVector s Double)--  indexD         = primIndexD-  newMD          = primNewMD-  readMD         = primReadMD-  writeMD        = primWriteMD-  unsafeFreezeMD = primUnsafeFreezeMD-  sizeD          = primSizeD-  sizeMD         = primSizeMD----- Pairs -----------------------------------------------------------------------instance (DT a, DT b) => DT (a,b) where-  data Dist  (a,b)   = DProd  !(Dist a)    !(Dist b)-  data MDist (a,b) s = MDProd !(MDist a s) !(MDist b s)--  indexD d i               = (fstD d `indexD` i,sndD d `indexD` i)-  newMD g                  = liftM2 MDProd (newMD g) (newMD g)-  readMD  (MDProd xs ys) i = liftM2 (,) (readMD xs i) (readMD ys i)-  writeMD (MDProd xs ys) i (x,y)-                            = writeMD xs i x >> writeMD ys i y-  unsafeFreezeMD (MDProd xs ys)-                            = liftM2 DProd (unsafeFreezeMD xs)-                                           (unsafeFreezeMD ys)--  {-# INLINE deepSeqD #-}-  deepSeqD (x,y) z = deepSeqD x (deepSeqD y z)--  sizeD  (DProd  x _) = sizeD  x-  sizeMD (MDProd x _) = sizeMD x--  measureD (x,y) = "Pair " ++ "(" ++ measureD x ++ ") (" ++  measureD y ++ ")"----- | Pairing of distributed values.--- /The two values must belong to the same/ 'Gang'.-zipD :: (DT a, DT b) => Dist a -> Dist b -> Dist (a,b)-{-# INLINE [0] zipD #-}-zipD !x !y = checkEq (here "zipDT") "Size mismatch" (sizeD x) (sizeD y) $-             DProd x y---- | Unpairing of distributed values.-unzipD :: (DT a, DT b) => Dist (a,b) -> (Dist a, Dist b)-{-# INLINE_DIST unzipD #-}-unzipD (DProd dx dy) = (dx,dy)---- | Extract the first elements of a distributed pair.-fstD :: (DT a, DT b) => Dist (a,b) -> Dist a-{-# INLINE_DIST fstD #-}-fstD = fst . unzipD---- | Extract the second elements of a distributed pair.-sndD :: (DT a, DT b) => Dist (a,b) -> Dist b-{-# INLINE_DIST sndD #-}-sndD = snd . unzipD----- Maybe -----------------------------------------------------------------------instance DT a => DT (Maybe a) where-  data Dist  (Maybe a)   = DMaybe  !(Dist  Bool)   !(Dist  a)-  data MDist (Maybe a) s = MDMaybe !(MDist Bool s) !(MDist a s)--  indexD (DMaybe bs as) i-    | bs `indexD` i       = Just $ as `indexD` i-    | otherwise           = Nothing-  newMD g = liftM2 MDMaybe (newMD g) (newMD g)-  readMD (MDMaybe bs as) i =-    do-      b <- readMD bs i-      if b then liftM Just $ readMD as i-           else return Nothing-  writeMD (MDMaybe bs as) i Nothing  = writeMD bs i False-  writeMD (MDMaybe bs as) i (Just x) = writeMD bs i True-                                     >> writeMD as i x-  unsafeFreezeMD (MDMaybe bs as) = liftM2 DMaybe (unsafeFreezeMD bs)-                                                 (unsafeFreezeMD as)--  {-# INLINE deepSeqD #-}-  deepSeqD Nothing  z = z-  deepSeqD (Just x) z = deepSeqD x z--  sizeD  (DMaybe  b _) = sizeD  b-  sizeMD (MDMaybe b _) = sizeMD b--  measureD Nothing = "Nothing"-  measureD (Just x) = "Just (" ++ measureD x ++ ")"----- Vector ----------------------------------------------------------------------instance Unbox a => DT (V.Vector a) where-  data Dist  (Vector a)   = DVector  !(Dist  Int)   !(BV.Vector      (Vector a))-  data MDist (Vector a) s = MDVector !(MDist Int s) !(MBV.STVector s (Vector a))--  indexD (DVector _ a) i = a BV.! i-  newMD g = liftM2 MDVector (newMD g) (MBV.replicate (gangSize g)-                                         (error "MDist (Vector a) - uninitalised"))-  readMD (MDVector _ marr) = MBV.read marr-  writeMD (MDVector mlen marr) i a =-    do-      writeMD mlen i (V.length a)-      MBV.write marr i $! a-  unsafeFreezeMD (MDVector len a) = liftM2 DVector (unsafeFreezeMD len)-                                               (BV.unsafeFreeze a)-  sizeD  (DVector  _ a) = BV.length  a-  sizeMD (MDVector _ a) = MBV.length a--  measureD xs = "Vector " ++ show (V.length xs)----- | Yield the distributed length of a distributed array.-lengthD :: Unbox a => Dist (Vector a) -> Dist Int-lengthD (DVector l _) = l----- USegd -----------------------------------------------------------------------instance DT USegd where-  data Dist  USegd   = DUSegd  !(Dist (Vector Int))-                               !(Dist (Vector Int))-                               !(Dist Int)-  data MDist USegd s = MDUSegd !(MDist (Vector Int) s)-                               !(MDist (Vector Int) s)-                               !(MDist Int        s)--  indexD (DUSegd lens idxs eles) i-          = mkUSegd (indexD lens i) (indexD idxs i) (indexD eles i)-  newMD g = liftM3 MDUSegd (newMD g) (newMD g) (newMD g)-  readMD (MDUSegd lens idxs eles) i-          = liftM3 mkUSegd (readMD lens i) (readMD idxs i) (readMD eles i)-  writeMD (MDUSegd lens idxs eles) i segd-          = do-              writeMD lens i (lengthsUSegd  segd)-              writeMD idxs i (indicesUSegd  segd)-              writeMD eles i (elementsUSegd segd)-  unsafeFreezeMD (MDUSegd lens idxs eles)-          = liftM3 DUSegd (unsafeFreezeMD lens)-                          (unsafeFreezeMD idxs)-                          (unsafeFreezeMD eles)--  deepSeqD segd z = deepSeqD (lengthsUSegd  segd)-                  $ deepSeqD (indicesUSegd  segd)-                  $ deepSeqD (elementsUSegd segd) z--  sizeD  (DUSegd  _ _ eles) = sizeD eles-  sizeMD (MDUSegd _ _ eles) = sizeMD eles--  measureD segd = "Segd " ++ show (lengthUSegd segd) ++ " " ++ show (elementsUSegd segd)--lengthUSegdD :: Dist USegd -> Dist Int-{-# INLINE_DIST lengthUSegdD #-}-lengthUSegdD (DUSegd lens _ _) = lengthD lens--lengthsUSegdD :: Dist USegd -> Dist (Vector Int)-{-# INLINE_DIST lengthsUSegdD #-}-lengthsUSegdD (DUSegd lens _ _ ) = lens--indicesUSegdD :: Dist USegd -> Dist (Vector Int)-{-# INLINE_DIST indicesUSegdD #-}-indicesUSegdD (DUSegd _ idxs _) = idxs+module Data.Array.Parallel.Unlifted.Distributed.Types +        ( module Data.Array.Parallel.Unlifted.Distributed.Types.Vector+        , module Data.Array.Parallel.Unlifted.Distributed.Types.Maybe+        , module Data.Array.Parallel.Unlifted.Distributed.Types.Tuple+        , module Data.Array.Parallel.Unlifted.Distributed.Types.Prim+        , module Data.Array.Parallel.Unlifted.Distributed.Types.Unit+        , module Data.Array.Parallel.Unlifted.Distributed.Types.Base)+where+import Data.Array.Parallel.Unlifted.Distributed.Types.Vector+import Data.Array.Parallel.Unlifted.Distributed.Types.Maybe+import Data.Array.Parallel.Unlifted.Distributed.Types.Tuple+import Data.Array.Parallel.Unlifted.Distributed.Types.Prim+import Data.Array.Parallel.Unlifted.Distributed.Types.Unit+import Data.Array.Parallel.Unlifted.Distributed.Types.Base -elementsUSegdD :: Dist USegd -> Dist Int-{-# INLINE_DIST elementsUSegdD #-}-elementsUSegdD (DUSegd _ _ dns) = dns 
+ Data/Array/Parallel/Unlifted/Distributed/Types/Base.hs view
@@ -0,0 +1,108 @@+{-# OPTIONS -Wall -fno-warn-orphans -fno-warn-missing-signatures #-}+module Data.Array.Parallel.Unlifted.Distributed.Types.Base +        ( -- * Distributable Types+          DT(..)+        +          -- * Checking+        , checkGangD+        , checkGangMD++          -- * General Operations+        , newD+        , debugD)+where+import Data.Array.Parallel.Unlifted.Distributed.Gang    (Gang, gangSize)+import Data.Array.Parallel.Base+import Data.List                                        (intercalate)++here :: String -> String+here s = "Data.Array.Parallel.Unlifted.Distributed.Types.Base." ++ s+++-- Distributed Types ----------------------------------------------------------+infixl 9 `indexD`++-- | Class of distributable types. Instances of 'DT' can be+--   distributed across all workers of a 'Gang'. +--   All such types must be hyperstrict as we do not want to pass thunks+--   into distributed computations.+class DT a where+  data Dist  a+  data MDist a :: * -> *++  -- | Extract a single element of an immutable distributed value.+  indexD         :: String -> Dist a -> Int -> a++  -- | Create an unitialised distributed value for the given 'Gang'.+  --   The gang is used (only) to know how many elements are needed+  --   in the distributed value.+  newMD          :: Gang                  -> ST s (MDist a s)++  -- | Extract an element from a mutable distributed value.+  readMD         :: MDist a s -> Int      -> ST s a++  -- | Write an element of a mutable distributed value.+  writeMD        :: MDist a s -> Int -> a -> ST s ()++  -- | Unsafely freeze a mutable distributed value.+  unsafeFreezeMD :: MDist a s             -> ST s (Dist a)++  -- | Ensure a distributed value is fully evaluated.+  deepSeqD       :: a -> b -> b+  deepSeqD = seq+++  -- Debugging ------------------------+  -- | Number of elements in the distributed value.+  -- +  --   * For debugging only, as code shouldn't be sensitive to the return value.+  sizeD :: Dist a -> Int++  -- | Number of elements in the mutable distributed value.+  --  +  --   * For debugging only, as code shouldn't be sensitive to the return value.+  sizeMD :: MDist a s -> Int++  -- | Show a distributed value.+  --+  --   * For debugging only.+  measureD :: a -> String+  measureD _ = "None"+++-- Show -----------------------------------------------------------------------+-- Show instance (for debugging only) --+instance (Show a, DT a) => Show (Dist a) where+  show d = show (Prelude.map (indexD (here "show") d) [0 .. sizeD d - 1])+++-- Checking -------------------------------------------------------------------+-- | Check that the sizes of the 'Gang' and of the distributed value match.+checkGangD :: DT a => String -> Gang -> Dist a -> b -> b+checkGangD loc g d v+        = checkEq loc "Wrong gang" (gangSize g) (sizeD d) v+++-- | Check that the sizes of the 'Gang' and of the mutable distributed value match.+checkGangMD :: DT a => String -> Gang -> MDist a s -> b -> b+checkGangMD loc g d v+        = checkEq loc "Wrong gang" (gangSize g) (sizeMD d) v+++-- Operations -----------------------------------------------------------------+-- | Given a computation that can write its result to a mutable distributed value, +--   run the computation to generate an immutable distributed value.+newD :: DT a => Gang -> (forall s . MDist a s -> ST s ()) -> Dist a+newD g mkInit =+  runST (do+           mdt <- newMD g+           mkInit mdt+           unsafeFreezeMD mdt)++-- | Show all members of a distributed value.+debugD :: DT a => Dist a -> String+debugD d = "["+         ++ intercalate "," [measureD (indexD (here "debugD") d i) +                            | i <- [0 .. sizeD d-1]]+         ++ "]"+
+ Data/Array/Parallel/Unlifted/Distributed/Types/Maybe.hs view
@@ -0,0 +1,45 @@+{-# OPTIONS -Wall -fno-warn-orphans -fno-warn-missing-signatures #-}++-- | Distribution of Maybes.+module Data.Array.Parallel.Unlifted.Distributed.Types.Maybe where+import Data.Array.Parallel.Unlifted.Distributed.Types.Prim      ()+import Data.Array.Parallel.Unlifted.Distributed.Types.Base+import Control.Monad++instance DT a => DT (Maybe a) where+  data Dist  (Maybe a)   = DMaybe  !(Dist  Bool)   !(Dist  a)+  data MDist (Maybe a) s = MDMaybe !(MDist Bool s) !(MDist a s)++  indexD str (DMaybe bs as) i+    |        indexD (str ++ "/indexD[Maybe]") bs i+    = Just $ indexD (str ++ "/indexD[Maybe]" ++ str) as i+    | otherwise           = Nothing++  newMD g+   = liftM2 MDMaybe (newMD g) (newMD g)++  readMD (MDMaybe bs as) i +   = do b <- readMD bs i+        if b then liftM Just $ readMD as i+             else return Nothing++  writeMD (MDMaybe bs _) i Nothing +   = writeMD bs i False++  writeMD (MDMaybe bs as) i (Just x)+   = do writeMD bs i True+        writeMD as i x++  unsafeFreezeMD (MDMaybe bs as)+   = liftM2 DMaybe (unsafeFreezeMD bs)+                   (unsafeFreezeMD as)++  {-# INLINE deepSeqD #-}+  deepSeqD Nothing  z   = z+  deepSeqD (Just x) z   = deepSeqD x z++  sizeD  (DMaybe  b _)  = sizeD  b+  sizeMD (MDMaybe b _)  = sizeMD b++  measureD Nothing      = "Nothing"+  measureD (Just x)     = "Just (" ++ measureD x ++ ")"
+ Data/Array/Parallel/Unlifted/Distributed/Types/Prim.hs view
@@ -0,0 +1,250 @@+{-# OPTIONS -Wall -fno-warn-orphans -fno-warn-missing-signatures #-}++-- | Distribution of values of primitive types.+module Data.Array.Parallel.Unlifted.Distributed.Types.Prim +        ( DPrim (..)+        , DT    (..)+        , Dist  (..))+where+import Data.Array.Parallel.Unlifted.Distributed.Types.Base+import Data.Array.Parallel.Unlifted.Distributed.Gang+import Data.Array.Parallel.Unlifted.Sequential.Vector+import Data.Array.Parallel.Base+import Data.Array.Parallel.Pretty+import Data.Word+import Control.Monad+import qualified Data.Array.Parallel.Unlifted.Sequential.Vector as V+import qualified Data.Vector.Unboxed.Mutable                    as MV+import Prelude as P++-- DPrim ----------------------------------------------------------------------+-- | For distributed primitive values, we can just store all the members in+--   a vector. The vector has the same length as the number of threads in the gang.+--+class Unbox e => DPrim e where++  -- | Make an immutable distributed value.+  mkDPrim :: V.Vector e -> Dist  e++  -- | Unpack an immutable distributed value back into a vector.+  unDPrim :: Dist  e -> V.Vector e++  -- | Make a mutable distributed value.+  mkMDPrim :: MV.STVector s e -> MDist  e s++  -- | Unpack a mutable distributed value back into a vector.+  unMDPrim :: MDist  e s -> MV.STVector s e+++-- | Get the member corresponding to a thread index.+primIndexD :: DPrim a => String -> Dist a -> Int -> a+primIndexD str = (V.index (str P.++ "/primIndexD")) . unDPrim+{-# INLINE primIndexD #-}+++-- | Create a new distributed value, having as many members as threads+--   in the given 'Gang'.+primNewMD :: DPrim a => Gang -> ST s (MDist a s)+primNewMD = liftM mkMDPrim . MV.new . gangSize+{-# INLINE primNewMD #-}+++-- | Read the member of a distributed value corresponding to the given thread index.+primReadMD :: DPrim a => MDist a s -> Int -> ST s a+primReadMD = MV.read . unMDPrim+{-# INLINE primReadMD #-}+++-- | Write the member of a distributed value corresponding to the given thread index.+primWriteMD :: DPrim a => MDist a s -> Int -> a -> ST s ()+primWriteMD = MV.write . unMDPrim+{-# INLINE primWriteMD #-}+++-- | Freeze a mutable distributed value to an immutable one.+--   You promise not to update the mutable one any further.+primUnsafeFreezeMD :: DPrim a => MDist a s -> ST s (Dist a)+primUnsafeFreezeMD = liftM mkDPrim . V.unsafeFreeze . unMDPrim+{-# INLINE primUnsafeFreezeMD #-}+++-- | Get the size of a distributed value, that is, the number of threads+--   in the gang that it was created for.+primSizeD :: DPrim a => Dist a -> Int+primSizeD = V.length . unDPrim+{-# INLINE primSizeD #-}+++-- | Get the size of a distributed mutable value, that is, the number of threads+--   in the gang it was created for.+primSizeMD :: DPrim a => MDist a s -> Int+primSizeMD = MV.length . unMDPrim+{-# INLINE primSizeMD #-}+++-- Bool -----------------------------------------------------------------------+instance DPrim Bool where+  mkDPrim           = DBool+  unDPrim (DBool a) = a++  mkMDPrim            = MDBool+  unMDPrim (MDBool a) = a+++instance DT Bool where+  data Dist  Bool   = DBool  !(V.Vector    Bool)+  data MDist Bool s = MDBool !(MV.STVector s Bool)++  indexD         = primIndexD+  newMD          = primNewMD+  readMD         = primReadMD+  writeMD        = primWriteMD+  unsafeFreezeMD = primUnsafeFreezeMD+  sizeD          = primSizeD+  sizeMD         = primSizeMD+++-- Ordering -----------------------------------------------------------------------+instance DPrim Ordering where+  mkDPrim               = DOrdering+  unDPrim (DOrdering a) = a++  mkMDPrim                = MDOrdering+  unMDPrim (MDOrdering a) = a+++instance DT Ordering where+  data Dist  Ordering   = DOrdering  !(V.Vector    Ordering)+  data MDist Ordering s = MDOrdering !(MV.STVector s Ordering)++  indexD         = primIndexD+  newMD          = primNewMD+  readMD         = primReadMD+  writeMD        = primWriteMD+  unsafeFreezeMD = primUnsafeFreezeMD+  sizeD          = primSizeD+  sizeMD         = primSizeMD+++-- Integer -----------------------------------------------------------------------+-- FIXME: fake instances+instance DPrim Integer+instance DT Integer+++-- Char -----------------------------------------------------------------------+instance DPrim Char where+  mkDPrim           = DChar+  unDPrim (DChar a) = a++  mkMDPrim            = MDChar+  unMDPrim (MDChar a) = a+++instance DT Char where+  data Dist  Char   = DChar  !(V.Vector    Char)+  data MDist Char s = MDChar !(MV.STVector s Char)++  indexD         = primIndexD+  newMD          = primNewMD+  readMD         = primReadMD+  writeMD        = primWriteMD+  unsafeFreezeMD = primUnsafeFreezeMD+  sizeD          = primSizeD+  sizeMD         = primSizeMD+++-- Int ------------------------------------------------------------------------+instance DPrim Int where+  mkDPrim          = DInt+  unDPrim (DInt a) = a++  mkMDPrim            = MDInt+  unMDPrim (MDInt a) = a+++instance DT Int where+  data Dist  Int   = DInt  !(V.Vector    Int)+  data MDist Int s = MDInt !(MV.STVector s Int)++  indexD         = primIndexD+  newMD          = primNewMD+  readMD         = primReadMD+  writeMD        = primWriteMD+  unsafeFreezeMD = primUnsafeFreezeMD+  sizeD          = primSizeD+  sizeMD         = primSizeMD++  measureD n = "Int " P.++ show n++instance PprPhysical (Dist Int) where+ pprp (DInt xs)+  =  text "DInt" <+> text (show $ V.toList xs)+++-- Word8 ----------------------------------------------------------------------+instance DPrim Word8 where+  mkDPrim            = DWord8+  unDPrim (DWord8 a) = a++  mkMDPrim             = MDWord8+  unMDPrim (MDWord8 a) = a+++instance DT Word8 where+  data Dist  Word8   = DWord8  !(V.Vector    Word8)+  data MDist Word8 s = MDWord8 !(MV.STVector s Word8)++  indexD         = primIndexD+  newMD          = primNewMD+  readMD         = primReadMD+  writeMD        = primWriteMD+  unsafeFreezeMD = primUnsafeFreezeMD+  sizeD          = primSizeD+  sizeMD         = primSizeMD+++-- Float ----------------------------------------------------------------------+instance DPrim Float where+  mkDPrim            = DFloat+  unDPrim (DFloat a) = a++  mkMDPrim             = MDFloat+  unMDPrim (MDFloat a) = a+++instance DT Float where+  data Dist  Float   = DFloat  !(V.Vector    Float)+  data MDist Float s = MDFloat !(MV.STVector s Float)++  indexD         = primIndexD+  newMD          = primNewMD+  readMD         = primReadMD+  writeMD        = primWriteMD+  unsafeFreezeMD = primUnsafeFreezeMD+  sizeD          = primSizeD+  sizeMD         = primSizeMD+++-- Double ---------------------------------------------------------------------+instance DPrim Double where+  mkDPrim             = DDouble+  unDPrim (DDouble a) = a++  mkMDPrim              = MDDouble+  unMDPrim (MDDouble a) = a+++instance DT Double where+  data Dist  Double   = DDouble  !(V.Vector    Double)+  data MDist Double s = MDDouble !(MV.STVector s Double)++  indexD         = primIndexD+  newMD          = primNewMD+  readMD         = primReadMD+  writeMD        = primWriteMD+  unsafeFreezeMD = primUnsafeFreezeMD+  sizeD          = primSizeD+  sizeMD         = primSizeMD++
+ Data/Array/Parallel/Unlifted/Distributed/Types/Tuple.hs view
@@ -0,0 +1,145 @@+{-# OPTIONS -Wall -fno-warn-orphans -fno-warn-missing-signatures #-}+{-# LANGUAGE CPP #-}+#include "fusion-phases.h"++-- | Distribution of Tuples+module Data.Array.Parallel.Unlifted.Distributed.Types.Tuple +        ( -- * Pairs+          zipD, unzipD, fstD, sndD+        +           -- * Triples+        , zip3D, unzip3D)+where+import Data.Array.Parallel.Unlifted.Distributed.Types.Base+import Data.Array.Parallel.Base+import Data.Array.Parallel.Pretty+import Control.Monad++here :: String -> String+here s = "Data.Array.Parallel.Unlifted.Distributed.Types.Tuple." ++ s+++-- Pairs ----------------------------------------------------------------------+instance (DT a, DT b) => DT (a,b) where+  data Dist  (a,b)   = DProd  !(Dist a)    !(Dist b)+  data MDist (a,b) s = MDProd !(MDist a s) !(MDist b s)++  indexD str d i+   = ( indexD (str ++ "/indexD[Tuple2]") (fstD d) i+     , indexD (str ++ "/indexD[Tuple2]") (sndD d) i)++  newMD g+   = liftM2 MDProd (newMD g) (newMD g)++  readMD  (MDProd xs ys) i+   = liftM2 (,) (readMD xs i) (readMD ys i)++  writeMD (MDProd xs ys) i (x,y)+   = do writeMD xs i x+        writeMD ys i y++  unsafeFreezeMD (MDProd xs ys)+   = liftM2 DProd (unsafeFreezeMD xs)+                  (unsafeFreezeMD ys)++  {-# INLINE deepSeqD #-}+  deepSeqD (x, y) z +   = deepSeqD x (deepSeqD y z)++  sizeD  (DProd  x _) = sizeD  x+  sizeMD (MDProd x _) = sizeMD x++  measureD (x, y) +   = "Pair " ++ "(" ++ measureD x ++ ") (" ++  measureD y ++ ")"+++instance (PprPhysical (Dist a), PprPhysical (Dist b)) +        => PprPhysical (Dist (a, b)) where+ pprp (DProd xs ys)+  = text "DProd"+  $$ (nest 8 $ vcat+        [ pprp xs+        , pprp ys ])+++-- | Pairing of distributed values.+--   The two values must belong to the same 'Gang'.+zipD :: (DT a, DT b) => Dist a -> Dist b -> Dist (a,b)+zipD !x !y +        = checkEq (here "zipDT") "Size mismatch" (sizeD x) (sizeD y) +        $ DProd x y+{-# INLINE [0] zipD #-}+++-- | Unpairing of distributed values.+unzipD :: (DT a, DT b) => Dist (a,b) -> (Dist a, Dist b)+unzipD (DProd dx dy) = (dx,dy)+{-# INLINE_DIST unzipD #-}+++-- | Extract the first elements of a distributed pair.+fstD :: (DT a, DT b) => Dist (a,b) -> Dist a+fstD = fst . unzipD+{-# INLINE_DIST fstD #-}+++-- | Extract the second elements of a distributed pair.+sndD :: (DT a, DT b) => Dist (a,b) -> Dist b+sndD = snd . unzipD+{-# INLINE_DIST sndD #-}+++-- Triples --------------------------------------------------------------------+instance (DT a, DT b, DT c) => DT (a,b,c) where+  data Dist  (a,b,c)   = DProd3  !(Dist a)    !(Dist b)    !(Dist c)+  data MDist (a,b,c) s = MDProd3 !(MDist a s) !(MDist b s) !(MDist c s)++  indexD str (DProd3 xs ys zs) i+   = ( indexD (here $ "indexD[Tuple3]/" ++ str) xs i+     , indexD (here $ "indexD[Tuple3]/" ++ str) ys i+     , indexD (here $ "indexD[Tuple3]/" ++ str) zs i)++  newMD g+   = liftM3 MDProd3 (newMD g) (newMD g) (newMD g)++  readMD  (MDProd3 xs ys zs) i+   = liftM3 (,,) (readMD xs i) (readMD ys i) (readMD zs i)++  writeMD (MDProd3 xs ys zs) i (x,y,z)+   = do writeMD xs i x+        writeMD ys i y+        writeMD zs i z++  unsafeFreezeMD (MDProd3 xs ys zs)+   = liftM3 DProd3 (unsafeFreezeMD xs)+                   (unsafeFreezeMD ys)+                   (unsafeFreezeMD zs)++  {-# INLINE deepSeqD #-}+  deepSeqD (x,y,z) k +   = deepSeqD x (deepSeqD y (deepSeqD z k))++  sizeD  (DProd3  x _ _) = sizeD  x+  sizeMD (MDProd3 x _ _) = sizeMD x++  measureD (x,y,z)+   = "Triple " +        ++ "(" ++ measureD x ++ ") "+        ++ "(" ++ measureD y ++ ") "+        ++ "(" ++ measureD z ++ ")"+++-- | Pairing of distributed values.+-- /The two values must belong to the same/ 'Gang'.+zip3D   :: (DT a, DT b, DT c) => Dist a -> Dist b -> Dist c -> Dist (a,b,c)+zip3D !x !y !z+        = checkEq (here "zip3DT") "Size mismatch" (sizeD x) (sizeD y) +        $ checkEq (here "zip3DT") "Size mismatch" (sizeD x) (sizeD z) +        $ DProd3 x y z+{-# INLINE [0] zip3D #-}+++-- | Unpairing of distributed values.+unzip3D  :: (DT a, DT b, DT c) => Dist (a,b,c) -> (Dist a, Dist b, Dist c)+unzip3D (DProd3 dx dy dz) = (dx,dy,dz)+{-# INLINE_DIST unzip3D #-}
+ Data/Array/Parallel/Unlifted/Distributed/Types/USSegd.hs view
@@ -0,0 +1,130 @@+{-# OPTIONS -Wall -fno-warn-orphans -fno-warn-missing-signatures #-}+{-# LANGUAGE CPP #-}+#include "fusion-phases.h"++-- | Distribution of Segment Descriptors+module Data.Array.Parallel.Unlifted.Distributed.Types.USSegd +        ( lengthD+        , takeLengthsD+        , takeIndicesD+        , takeElementsD+        , takeStartsD+        , takeSourcesD+        , takeUSegdD)+where+import Data.Array.Parallel.Unlifted.Distributed.Types.Base+import Data.Array.Parallel.Unlifted.Sequential.USSegd                   (USSegd)+import Data.Array.Parallel.Unlifted.Sequential.USegd                    (USegd)+import Data.Array.Parallel.Unlifted.Sequential.Vector                   (Vector)+import Data.Array.Parallel.Pretty+import Control.Monad+import Prelude                                                          as P+import qualified Data.Array.Parallel.Unlifted.Distributed.Types.USegd   as DUSegd+import qualified Data.Array.Parallel.Unlifted.Distributed.Types.Vector  as DV+import qualified Data.Array.Parallel.Unlifted.Sequential.USSegd         as USSegd+++instance DT USSegd where+  data Dist USSegd   +        = DUSSegd  !(Dist (Vector Int))         -- segment starts+                   !(Dist (Vector Int))         -- segment sources+                   !(Dist USegd)                -- distributed usegd++  data MDist USSegd s +        = MDUSSegd !(MDist (Vector Int) s)      -- segment starts+                   !(MDist (Vector Int) s)      -- segment sources+                   !(MDist USegd        s)      -- distributed usegd++  indexD str (DUSSegd starts sources usegds) i+   = USSegd.mkUSSegd+        (indexD (str ++ "/indexD[USSegd]") starts i)+        (indexD (str ++ "/indexD[USSegd]") sources i)+        (indexD (str ++ "/indexD[USSegd]") usegds i)++  newMD g+   = liftM3 MDUSSegd (newMD g) (newMD g) (newMD g)++  readMD (MDUSSegd starts sources usegds) i+   = liftM3 USSegd.mkUSSegd (readMD starts i) (readMD sources i) (readMD usegds i)++  writeMD (MDUSSegd starts sources usegds) i ussegd+   = do writeMD starts  i (USSegd.takeStarts  ussegd)+        writeMD sources i (USSegd.takeSources ussegd)+        writeMD usegds  i (USSegd.takeUSegd   ussegd)++  unsafeFreezeMD (MDUSSegd starts sources usegds)+   = liftM3 DUSSegd (unsafeFreezeMD starts)+                    (unsafeFreezeMD sources)+                    (unsafeFreezeMD usegds)++  deepSeqD ussegd z+   = deepSeqD (USSegd.takeStarts  ussegd)+   $ deepSeqD (USSegd.takeSources ussegd)+   $ deepSeqD (USSegd.takeUSegd   ussegd) z++  sizeD  (DUSSegd  _ _ usegd) = sizeD usegd+  sizeMD (MDUSSegd _ _ usegd) = sizeMD usegd++  measureD ussegd +   = "USSegd "  P.++ show (USSegd.takeStarts    ussegd)+   P.++ " "     P.++ show (USSegd.takeSources   ussegd)+   P.++ " "     P.++ measureD (USSegd.takeUSegd ussegd)+++instance PprPhysical (Dist USSegd) where+ pprp (DUSSegd starts sources usegds)+  =  text "DUSSegd"+  $$ (nest 7 $ vcat+        [ text "starts:  " <+> pprp starts+        , text "sources: " <+> pprp sources+        , text "usegds:  " <+> pprp usegds])+++-- | O(1). Yield the overall number of segments.+lengthD :: Dist USSegd -> Dist Int+lengthD (DUSSegd starts _ _) +        = DV.lengthD starts+{-# INLINE_DIST lengthD #-}+++-- | O(1). Yield the lengths of the individual segments.+takeLengthsD :: Dist USSegd -> Dist (Vector Int)+takeLengthsD (DUSSegd _ _ usegds)+        = DUSegd.takeLengthsD usegds+{-# INLINE_DIST takeLengthsD #-}+++-- | O(1). Yield the segment indices.+takeIndicesD :: Dist USSegd -> Dist (Vector Int)+takeIndicesD (DUSSegd _ _ usegds)+        = DUSegd.takeIndicesD usegds+{-# INLINE_DIST takeIndicesD #-}+++-- | O(1). Yield the number of data elements.+takeElementsD :: Dist USSegd -> Dist Int+takeElementsD (DUSSegd _ _ usegds)+        = DUSegd.takeElementsD usegds+{-# INLINE_DIST takeElementsD #-}+++-- | O(1). Yield the starting indices.+takeStartsD :: Dist USSegd -> Dist (Vector Int)+takeStartsD (DUSSegd starts _ _)+        = starts+{-# INLINE_DIST takeStartsD #-}+        ++-- | O(1). Yield the source ids+takeSourcesD :: Dist USSegd -> Dist (Vector Int)+takeSourcesD (DUSSegd _ sources _)+        = sources+{-# INLINE_DIST takeSourcesD #-}+++-- | O(1). Yield the USegd+takeUSegdD :: Dist USSegd -> Dist USegd+takeUSegdD (DUSSegd _ _ usegd)+        = usegd+{-# INLINE_DIST takeUSegdD #-}+
+ Data/Array/Parallel/Unlifted/Distributed/Types/USegd.hs view
@@ -0,0 +1,113 @@+{-# OPTIONS -Wall -fno-warn-orphans -fno-warn-missing-signatures #-}+{-# LANGUAGE CPP #-}+#include "fusion-phases.h"++-- | Distribution of Segment Descriptors+module Data.Array.Parallel.Unlifted.Distributed.Types.USegd +        ( mkDUSegd+        , lengthD+        , takeLengthsD+        , takeIndicesD+        , takeElementsD)+where+import Data.Array.Parallel.Unlifted.Distributed.Types.Base+import Data.Array.Parallel.Unlifted.Sequential.USegd                    (USegd)+import Data.Array.Parallel.Unlifted.Sequential.Vector                   (Vector)+import Data.Array.Parallel.Pretty+import Control.Monad+import qualified Data.Array.Parallel.Unlifted.Distributed.Types.Vector  as DV+import qualified Data.Array.Parallel.Unlifted.Sequential.USegd          as USegd+import Prelude                                                          as P+++instance DT USegd where+  data Dist  USegd   +        = DUSegd  !(Dist (Vector Int))          -- segment lengths+                  !(Dist (Vector Int))          -- segment indices+                  !(Dist Int)                   -- number of elements in this chunk++  data MDist USegd s +        = MDUSegd !(MDist (Vector Int) s)       -- segment lengths+                  !(MDist (Vector Int) s)       -- segment indices+                  !(MDist Int        s)         -- number of elements in this chunk++  indexD str (DUSegd lens idxs eles) i+   = USegd.mkUSegd+        (indexD (str ++ "/indexD[USegd]") lens i)+        (indexD (str ++ "/indexD[USegd]") idxs i)+        (indexD (str ++ "/indexD[USegd]") eles i)++  newMD g+   = liftM3 MDUSegd (newMD g) (newMD g) (newMD g)++  readMD (MDUSegd lens idxs eles) i+   = liftM3 USegd.mkUSegd (readMD lens i) (readMD idxs i) (readMD eles i)++  writeMD (MDUSegd lens idxs eles) i segd+   = do writeMD lens i (USegd.takeLengths  segd)+        writeMD idxs i (USegd.takeIndices  segd)+        writeMD eles i (USegd.takeElements segd)++  unsafeFreezeMD (MDUSegd lens idxs eles)+   = liftM3 DUSegd (unsafeFreezeMD lens)+                   (unsafeFreezeMD idxs)+                   (unsafeFreezeMD eles)++  deepSeqD segd z+   = deepSeqD (USegd.takeLengths  segd)+   $ deepSeqD (USegd.takeIndices  segd)+   $ deepSeqD (USegd.takeElements segd) z++  sizeD  (DUSegd  _ _ eles) = sizeD eles+  sizeMD (MDUSegd _ _ eles) = sizeMD eles++  measureD segd +   = "Segd " P.++ show (USegd.length segd)+   P.++ " "  P.++ show (USegd.takeElements segd)+++instance PprPhysical (Dist USegd) where+ pprp (DUSegd lens indices elements)+  =  text "DUSegd"+  $$ (nest 7 $ vcat+        [ text "lengths: " <+> pprp lens+        , text "indices: " <+> pprp indices+        , text "elements:" <+> pprp elements])+++-- | O(1). Construct a distributed segment descriptor+mkDUSegd +        :: Dist (Vector Int)    -- ^ segment lengths+        -> Dist (Vector Int)    -- ^ segment indices+        -> Dist Int             -- ^ number of elements in each chunk+        -> Dist USegd++mkDUSegd = DUSegd+++-- | O(1). Yield the overall number of segments.+lengthD :: Dist USegd -> Dist Int+lengthD (DUSegd lens _ _) +        = DV.lengthD lens+{-# INLINE_DIST lengthD #-}+++-- | O(1). Yield the lengths of the individual segments.+takeLengthsD :: Dist USegd -> Dist (Vector Int)+takeLengthsD (DUSegd lens _ _ )+        = lens+{-# INLINE_DIST takeLengthsD #-}+++-- | O(1). Yield the segment indices of a segment descriptor.+takeIndicesD :: Dist USegd -> Dist (Vector Int)+takeIndicesD (DUSegd _ idxs _)+        = idxs+{-# INLINE_DIST takeIndicesD #-}+++-- | O(1). Yield the number of data elements.+takeElementsD :: Dist USegd -> Dist Int+takeElementsD (DUSegd _ _ dns)+        = dns+{-# INLINE_DIST takeElementsD #-}
+ Data/Array/Parallel/Unlifted/Distributed/Types/UVSegd.hs view
@@ -0,0 +1,128 @@+{-# OPTIONS -Wall -fno-warn-orphans -fno-warn-missing-signatures #-}+{-# LANGUAGE CPP #-}+#include "fusion-phases.h"++-- | Distribution of Virtual Segment Descriptors+module Data.Array.Parallel.Unlifted.Distributed.Types.UVSegd +        ( lengthD+        , takeLengthsD+        , takeIndicesD+        , takeElementsD+        , takeStartsD+        , takeSourcesD+        , takeVSegidsD+        , takeUSSegdD)+where+import Data.Array.Parallel.Unlifted.Distributed.Types.Base+import Data.Array.Parallel.Unlifted.Sequential.UVSegd                   (UVSegd)+import Data.Array.Parallel.Unlifted.Sequential.USSegd                   (USSegd)+import Data.Array.Parallel.Unlifted.Sequential.Vector+import Data.Array.Parallel.Pretty+import Control.Monad+import Prelude                                                          as P+import qualified Data.Array.Parallel.Unlifted.Sequential.UVSegd         as UVSegd+import qualified Data.Array.Parallel.Unlifted.Distributed.Types.USSegd  as DUSegd+++instance DT UVSegd where+  data Dist UVSegd   +        = DUVSegd  !(Dist (Vector Int))         -- vsegids+                   !(Dist USSegd)               -- distributed ussegd++  data MDist UVSegd s +        = MDUVSegd !(MDist (Vector Int) s)      -- vsegids+                   !(MDist USSegd       s)      -- distributed ussegd++  indexD str (DUVSegd vsegids ussegds) i+   = UVSegd.mkUVSegd+        (indexD (str P.++ "/indexD[UVSegd]") vsegids i)+        (indexD (str P.++ "/indexD[UVSegd]") ussegds i)++  newMD g+   = liftM2 MDUVSegd (newMD g) (newMD g)++  readMD (MDUVSegd vsegids ussegds) i+   = liftM2 UVSegd.mkUVSegd (readMD vsegids i) (readMD ussegds i)++  writeMD (MDUVSegd vsegids ussegds) i uvsegd+   = do writeMD vsegids  i (UVSegd.takeVSegids  uvsegd)+        writeMD ussegds  i (UVSegd.takeUSSegd   uvsegd)++  unsafeFreezeMD (MDUVSegd vsegids ussegds)+   = liftM2 DUVSegd (unsafeFreezeMD vsegids)+                    (unsafeFreezeMD ussegds)++  deepSeqD uvsegd z+   = deepSeqD (UVSegd.takeVSegids  uvsegd)+   $ deepSeqD (UVSegd.takeUSSegd   uvsegd) z++  sizeD  (DUVSegd  _ ussegd) = sizeD ussegd+  sizeMD (MDUVSegd _ ussegd) = sizeMD ussegd++  measureD uvsegd +   = "UVSegd " P.++ show (UVSegd.takeVSegids    uvsegd)+   P.++ " "    P.++ measureD (UVSegd.takeUSSegd uvsegd)+++instance PprPhysical (Dist UVSegd) where+ pprp (DUVSegd vsegids ussegds)+  =  text "DUVSegd"+  $$ (nest 7 $ vcat+        [ text "vsegids: " <+> pprp vsegids+        , text "ussegds: " <+> pprp ussegds])+++-- | O(1). Yield the overall number of segments.+lengthD :: Dist UVSegd -> Dist Int+lengthD (DUVSegd _ ussegd) +        = DUSegd.lengthD ussegd+{-# INLINE_DIST lengthD #-}+++-- | O(1). Yield the lengths of the individual segments.+takeLengthsD :: Dist UVSegd -> Dist (Vector Int)+takeLengthsD (DUVSegd _ ussegd)+        = DUSegd.takeLengthsD ussegd+{-# INLINE_DIST takeLengthsD #-}+++-- | O(1). Yield the segment indices.+takeIndicesD :: Dist UVSegd -> Dist (Vector Int)+takeIndicesD (DUVSegd _ ussegd)+        = DUSegd.takeIndicesD ussegd+{-# INLINE_DIST takeIndicesD #-}+++-- | O(1). Yield the number of data elements.+takeElementsD :: Dist UVSegd -> Dist Int+takeElementsD (DUVSegd _ ussegd)+        = DUSegd.takeElementsD ussegd+{-# INLINE_DIST takeElementsD #-}+++-- | O(1). Yield the starting indices.+takeStartsD :: Dist UVSegd -> Dist (Vector Int)+takeStartsD (DUVSegd _ ussegd)+        = DUSegd.takeStartsD ussegd+{-# INLINE_DIST takeStartsD #-}+        +        +-- | O(1). Yield the source ids+takeSourcesD :: Dist UVSegd -> Dist (Vector Int)+takeSourcesD (DUVSegd _ ussegd)+        = DUSegd.takeSourcesD ussegd+{-# INLINE_DIST takeSourcesD #-}+++-- | O(1). Yield the vsegids+takeVSegidsD :: Dist UVSegd -> Dist (Vector Int)+takeVSegidsD (DUVSegd vsegids _)+        = vsegids+{-# INLINE_DIST takeVSegidsD #-}+++-- | O(1). Yield the USSegd+takeUSSegdD :: Dist UVSegd -> Dist USSegd+takeUSSegdD (DUVSegd _ ussegd)+        = ussegd+{-# INLINE_DIST takeUSSegdD #-}
+ Data/Array/Parallel/Unlifted/Distributed/Types/Unit.hs view
@@ -0,0 +1,45 @@+{-# OPTIONS -Wall -fno-warn-orphans -fno-warn-missing-signatures #-}+{-# LANGUAGE CPP #-}+#include "fusion-phases.h"++-- | Distribution of unit values.+module Data.Array.Parallel.Unlifted.Distributed.Types.Unit +        (unitD)+where+import Data.Array.Parallel.Unlifted.Distributed.Types.Base+import Data.Array.Parallel.Unlifted.Distributed.Gang+import Data.Array.Parallel.Base++here :: String -> String+here s = "Data.Array.Parallel.Unlifted.Distributed.Types.Unit." ++ s++instance DT () where+  data Dist ()    = DUnit  !Int+  data MDist () s = MDUnit !Int++  indexD str (DUnit n) i+   = check (str ++ "/indexD[Unit]") n i+   $  ()++  newMD+   = return . MDUnit . gangSize++  readMD   (MDUnit n) i+   = check (here "readMD")  n i+   $ return ()++  writeMD  (MDUnit n) i ()+   = check (here "writeMD") n i+   $ return ()++  unsafeFreezeMD (MDUnit n)+   = return $ DUnit n++  sizeD  = error $ here "sizeD  undefined"+  sizeMD = error $ here "sizeMD undefined"+++-- | Yield a distributed unit.+unitD :: Gang -> Dist ()+unitD = DUnit . gangSize+{-# INLINE_DIST unitD #-}
+ Data/Array/Parallel/Unlifted/Distributed/Types/Vector.hs view
@@ -0,0 +1,61 @@+{-# OPTIONS -Wall -fno-warn-orphans -fno-warn-missing-signatures #-}++-- | Distribution of Vectors.+module Data.Array.Parallel.Unlifted.Distributed.Types.Vector+        (lengthD)+where+import qualified Data.Array.Parallel.Base               as B+import Data.Array.Parallel.Unlifted.Distributed.Types.Prim+import Data.Array.Parallel.Unlifted.Distributed.Gang+import Data.Array.Parallel.Pretty+import Data.Array.Parallel.Unlifted.Sequential.Vector   as V+import qualified Data.Vector                            as BV+import qualified Data.Vector.Mutable                    as MBV+import Prelude                                          as P+import Control.Monad+++here :: String -> String+here s = "Data.Array.Parallel.Unlifted.Distributed.Types.Vector." P.++ s+++instance Unbox a => DT (V.Vector a) where+  data Dist  (Vector a)   = DVector  !(Dist  Int)   !(BV.Vector      (Vector a))+  data MDist (Vector a) s = MDVector !(MDist Int s) !(MBV.STVector s (Vector a))++  indexD str (DVector _ a) i+   = B.check (here ("indexD[Vector]/" P.++ str)) (BV.length a) i $ a BV.! i++  newMD g+   = liftM2 MDVector+        (newMD g) +        (MBV.replicate (gangSize g) (error "MDist (Vector a) - uninitalised"))++  readMD (MDVector _ marr)+   = MBV.read marr++  writeMD (MDVector mlen marr) i a +   = do writeMD mlen i (V.length a)+        MBV.write marr i $! a++  unsafeFreezeMD (MDVector len a)+   = liftM2 DVector (unsafeFreezeMD len)+                    (BV.unsafeFreeze a)++  sizeD  (DVector  _ a) = BV.length  a+  sizeMD (MDVector _ a) = MBV.length a++  measureD xs           = "Vector " P.++ show (V.length xs)+++instance (Unbox a, Show a) => PprPhysical (Dist (V.Vector a)) where+ pprp (DVector (DInt lengths) chunks)+  = text "DVector"+  $$ (nest 8 $ vcat+        [ text "lengths:" <+> (text $ show $ V.toList lengths)+        , text "chunks: " <+> (text $ show $ BV.toList $ BV.map V.toList chunks) ])+++-- | Yield the distributed length of a distributed array.+lengthD :: Unbox a => Dist (Vector a) -> Dist Int+lengthD (DVector l _) = l
+ Data/Array/Parallel/Unlifted/Distributed/USSegd.hs view
@@ -0,0 +1,245 @@+{-# OPTIONS -Wall -fno-warn-orphans -fno-warn-missing-signatures #-}+{-# LANGUAGE CPP #-}+#include "fusion-phases.h"++-- | Operations on Distributed Segment Descriptors+module Data.Array.Parallel.Unlifted.Distributed.USSegd +        (splitSSegdOnElemsD)+where+import Data.Array.Parallel.Unlifted.Distributed.Arrays+import Data.Array.Parallel.Unlifted.Distributed.Combinators+import Data.Array.Parallel.Unlifted.Distributed.Types+import Data.Array.Parallel.Unlifted.Distributed.Gang+import Data.Array.Parallel.Unlifted.Sequential.USSegd                   (USSegd)+import Data.Array.Parallel.Unlifted.Sequential.Vector                   (Vector)+import Data.Array.Parallel.Base+import Data.Bits                                                        (shiftR)+import Control.Monad                                                    (when)+import Data.Array.Parallel.Unlifted.Distributed.Types.USSegd            ()+import qualified Data.Array.Parallel.Unlifted.Sequential.USegd          as USegd+import qualified Data.Array.Parallel.Unlifted.Sequential.USSegd         as USSegd+import qualified Data.Array.Parallel.Unlifted.Sequential.Vector         as Seq++here :: String -> String+here s = "Data.Array.Parallel.Unlifted.Distributed.USSegd." ++ s++-------------------------------------------------------------------------------+-- | Split a segment descriptor across the gang, element wise.+--   We try to put the same number of elements on each thread, which means+--   that segments are sometimes split across threads.+--+--   Each thread gets a slice of segment descriptor, the segid of the first +--   slice, and the offset of the first slice in its segment.+--   +--   Example:+--    In this picture each X represents 5 elements, and we have 5 segements in total.+--+-- @   segs:    ----------------------- --- ------- --------------- -------------------+--    elems:  |X X X X X X X X X|X X X X X X X X X|X X X X X X X X X|X X X X X X X X X|+--            |     thread1     |     thread2     |     thread3     |     thread4     |+--    segid:  0                 0                 3                 4+--    offset: 0                 45                0                 5+--+--    pprp $ splitSegdOnElemsD theGang +--          $ lengthsToUSegd $ fromList [60, 10, 20, 40, 50 :: Int]+--+--     segd:    DUSegd lengths:  DVector lengths: [1,3,2,1]+--                                        chunks:  [[45],[15,10,20],[40,5],[45]]+--                     indices:  DVector lengths: [1,3,2,1]+--                                        chunks:  [[0], [0,15,25], [0,40],[0]]+--                    elements:  DInt [45,45,45,45]+--+--     segids: DInt [0,0,3,4]     (segment id of first slice on thread)+--    offsets: DInt [0,45,0,5]    (offset of that slice in its segment)+-- @+--+splitSSegdOnElemsD :: Gang -> USSegd -> Dist ((USSegd,Int),Int)+splitSSegdOnElemsD g !segd +  = {-# SCC "splitSSegdOnElemsD" #-}+    imapD g mk (splitLenIdxD g (USegd.takeElements $ USSegd.takeUSegd segd))+  where +        -- Number of threads in gang.+        !nThreads = gangSize g+++        -- Build a USSegd from just the lengths, starts and sources fields.+        --   The indices and elems fields of the contained USegd are +        --   generated from the lengths.+        buildUSSegd :: Vector Int -> Vector Int -> Vector Int -> USSegd+        buildUSSegd lengths starts sources+                = USSegd.mkUSSegd starts sources+                $ USegd.fromLengths lengths++        -- Determine what elements go on a thread+        mk :: Int                  -- Thread index.+           -> (Int, Int)           -- Number of elements on this thread,+                                   --   and starting offset into the flat array.+           -> ((USSegd, Int), Int) -- Segd for this thread, segid of first slice,+                                   --   and offset of first slice.++        mk i (nElems, ixStart) +         = case chunk segd ixStart nElems (i == nThreads - 1) of+            (# lengths, starts, sources, l, o #) +             -> ((buildUSSegd lengths starts sources, l), o)++{-# NOINLINE splitSSegdOnElemsD #-}+--  NOINLINE because it's complicated and won't fuse with anything.+--  This function has a large body of code and we don't want to blow up+--  the client modules by inlining it everywhere.+++-------------------------------------------------------------------------------+-- | Determine what elements go on a thread.+--   The 'chunk' refers to the a chunk of the flat array, and is defined+--   by a set of segment slices. +--+--   Example:+--    In this picture each X represents 5 elements, and we have 5 segements in total.+--+-- @  segs:    ----------------------- --- ------- --------------- -------------------+--    elems:  |X X X X X X X X X|X X X X X X X X X|X X X X X X X X X|X X X X X X X X X|+--            |     thread1     |     thread2     |     thread3     |     thread4     |+--    segid:  0                 0                 3                 4+--    offset: 0                 45                0                 5+--    k:               0                 1                 3                 5+--    k':              1                 3                 5                 5+--    left:            0                 15                0                 45+--    right:           45                20                5                 0+--    left_len:        0                 1                 0                 1+--    left_off:        0                 45                0                 5+--    n':              1                 3                 2                 1+-- @+chunk   :: USSegd          -- ^ Segment descriptor of entire array.+        -> Int            -- ^ Starting offset into the flat array for the first+                          --    slice on this thread.+        -> Int            -- ^ Number of elements in this thread.+        -> Bool           -- ^ Whether this is the last thread in the gang.+        -> (# Vector Int  --    Lengths of segment slices, +            , Vector Int  --    Starting index of data in its vector+            , Vector Int  --    Source id+            , Int         --    segid of first slice+            , Int #)      --    offset of first slice.++chunk !ussegd !nStart !nElems is_last+  = (# lengths', starts', sources', k-left_len, left_off #)+  where+    -- Lengths of all segments.+    -- eg: [60, 10, 20, 40, 50]+    lengths     = USSegd.takeLengths ussegd++    -- Indices indices of all segments.+    -- eg: [0, 60, 70, 90, 130]+    indices     = USSegd.takeIndices ussegd++    -- Starting indices for all segments.+    starts      = USSegd.takeStarts ussegd++    -- Source ids for all segments.+    sources     = USSegd.takeSources ussegd+    +    -- Total number of segments defined by segment descriptor.+    -- eg: 5+    n    = Seq.length lengths++    -- Segid of the first seg that starts after the left of this chunk.+    k    = search nStart indices++    -- Segid of the first seg that starts after the right of this chunk.+    k'       | is_last     = n+             | otherwise   = search (nStart + nElems) indices++    -- The length of the left-most slice of this chunk.+    left     | k == n      = nElems+             | otherwise   = min ((Seq.index (here "chunk") indices k) - nStart) nElems++    -- The length of the right-most slice of this chunk.+    length_right   +             | k' == k     = 0+             | otherwise   = nStart + nElems - (Seq.index (here "chunk") indices (k'-1))++    -- Whether the first element in this chunk is an internal element of+    -- of a segment. Alternatively, indicates that the first element of +    -- the chunk is not the first element of a segment.            +    left_len | left == 0   = 0+             | otherwise   = 1++    -- If the first element of the chunk starts within a segment, +    -- then gives the index within that segment, otherwise 0.+    left_off | left == 0   = 0+             | otherwise   = nStart - (Seq.index (here "chunk") indices (k-1))++    -- How many segments this chunk straddles.+    n' = left_len + (k'-k)++    -- Create the lengths for this chunk by first copying out the lengths+    -- from the original segment descriptor. If the slices on the left+    -- and right cover partial segments, then we update the corresponding+    -- lengths.+    (!lengths', !starts', !sources')+     = runST (do+            -- Create a new array big enough to hold all the lengths for this chunk.+            mlengths' <- Seq.newM n'+            msources' <- Seq.newM n'+            mstarts'  <- Seq.newM n'++            -- If the first element is inside a segment, +            --   then update the length to be the length of the slice.+            when (left /= 0) +             $ do Seq.write mlengths' 0 left+                  Seq.write mstarts'  0 (Seq.index (here "chunk") starts  (k - left_len) + left_off)+                  Seq.write msources' 0 (Seq.index (here "chunk") sources (k - left_len))++            -- Copy out array lengths for this chunk.+            Seq.copy (Seq.mdrop left_len mlengths') (Seq.slice (here "chunk") lengths k (k'-k))+            Seq.copy (Seq.mdrop left_len mstarts')  (Seq.slice (here "chunk")  starts k (k'-k))+            Seq.copy (Seq.mdrop left_len msources') (Seq.slice (here "chunk") sources k (k'-k))++            -- If the last element is inside a segment, +            --   then update the length to be the length of the slice.+            when (length_right /= 0)+             $ do Seq.write mlengths' (n' - 1) length_right++            clengths' <- Seq.unsafeFreeze mlengths'+            cstarts'  <- Seq.unsafeFreeze mstarts'+            csources' <- Seq.unsafeFreeze msources'+            return (clengths', cstarts', csources'))++{-      = trace +        (render $ vcat+                [ text "CHUNK"+                , pprp segd+                , text "nStart:  " <+> int nStart+                , text "nElems:  " <+> int nElems+                , text "k:       " <+> int k+                , text "k':      " <+> int k'+                , text "left:    " <+> int left+                , text "right:   " <+> int right+                , text "left_len:" <+> int left_len+                , text "left_off:" <+> int left_off+                , text "n':      " <+> int n'+                , text ""]) lens'+-}++{-# INLINE chunk #-}+--  INLINE even though it should be inlined into splitSSegdOnElemsD anyway+--  because that function contains the only use.+++-------------------------------------------------------------------------------+-- O(log n).+-- Given a monotonically increasing vector of `Int`s,+-- find the first element that is larger than the given value.+-- +-- eg  search 75 [0, 60, 70, 90, 130] = 90+--     search 43 [0, 60, 70, 90, 130] = 60+--+search :: Int -> Vector Int -> Int+search !x ys = go 0 (Seq.length ys)+  where+    go i n | n <= 0        = i+           | Seq.index (here "search") ys mid < x+           = go (mid + 1) (n - half - 1)+           | otherwise     = go i half+      where+        half = n `shiftR` 1+        mid  = i + half
+ Data/Array/Parallel/Unlifted/Distributed/USegd.hs view
@@ -0,0 +1,349 @@+{-# OPTIONS -Wall -fno-warn-orphans -fno-warn-missing-signatures #-}+{-# LANGUAGE CPP #-}+#include "fusion-phases.h"++-- | Operations on Distributed Segment Descriptors+module Data.Array.Parallel.Unlifted.Distributed.USegd +        ( splitSegdOnSegsD+        , splitSegdOnElemsD+        , splitSD+        , joinSegdD+        , glueSegdD)+where+import Data.Array.Parallel.Unlifted.Distributed.Arrays+import Data.Array.Parallel.Unlifted.Distributed.Combinators+import Data.Array.Parallel.Unlifted.Distributed.Types+import Data.Array.Parallel.Unlifted.Distributed.Gang+import Data.Array.Parallel.Unlifted.Sequential.USegd                    (USegd)+import Data.Array.Parallel.Unlifted.Sequential.Vector                   (Vector, Unbox)+import Data.Array.Parallel.Base+import Data.Bits                                                        (shiftR)+import Control.Monad                                                    (when)+import qualified Data.Array.Parallel.Unlifted.Distributed.Types.USegd   as DUSegd+import qualified Data.Array.Parallel.Unlifted.Sequential.USegd          as USegd+import qualified Data.Array.Parallel.Unlifted.Sequential.Vector         as Seq++here :: String -> String+here s = "Data.Array.Parallel.Unlifted.Distributed.USegd." ++ s++-------------------------------------------------------------------------------+-- | Split a segment descriptor across the gang, segment wise.+--   Whole segments are placed on each thread, and we try to balance out+--   the segments so each thread has the same number of array elements.+--+--   We don't split segments across threads, as this would limit our ability+--   to perform intra-thread fusion of lifted operations. The down side+--   of this is that if we have few segments with an un-even size distribution+--   then large segments can cause the gang to become unbalanced.+--+--   In the following example the segment with size 100 dominates and+--   unbalances the gang. There is no reason to put any segments on the+--   the last thread because we need to wait for the first to finish anyway.+--+--   @ > pprp $ splitSegdOnSegsD theGang+--            $ lengthsToUSegd $ fromList [100, 10, 20, 40, 50  :: Int]+-- +--     DUSegd lengths:   DVector lengths:  [ 1,    3,         1,  0]+--                                chunks:  [[100],[10,20,40],[50],[]]+-- +--            indices:   DVector lengths:  [1,3,1,0]+--                                chunks:  [[0],  [0,10,30], [0], []]+--+--            elements:  DInt [100,70,50,0]+--   @+--+--  NOTE: This splitSegdOnSegsD function isn't currently used.+--+splitSegdOnSegsD :: Gang -> USegd -> Dist USegd+splitSegdOnSegsD g !segd +  = mapD g USegd.fromLengths+  $ splitAsD g d lens+  where+    !d   = snd+         . mapAccumLD g chunks 0+         . splitLenD g+         $ USegd.takeElements segd++    n    = USegd.length segd+    lens = USegd.takeLengths segd++    chunks !i !k +      = let !j = go i k+        in  (j,j-i)++    go !i !k | i >= n    = i+             | m == 0    = go (i+1) k+             | k <= 0    = i+             | otherwise = go (i+1) (k-m)+      where+        m = Seq.index (here "splitSegdOnSegsD") lens i+{-# NOINLINE splitSegdOnSegsD #-}+++-------------------------------------------------------------------------------+-- | Split a segment descriptor across the gang, element wise.+--   We try to put the same number of elements on each thread, which means+--   that segments are sometimes split across threads.+--+--   Each thread gets a slice of segment descriptor, the segid of the first +--   slice, and the offset of the first slice in its segment.+--   +--   Example:+--    In this picture each X represents 5 elements, and we have 5 segements in total.+--+-- @  segs:    ----------------------- --- ------- --------------- -------------------+--    elems:  |X X X X X X X X X|X X X X X X X X X|X X X X X X X X X|X X X X X X X X X|+--            |     thread1     |     thread2     |     thread3     |     thread4     |+--    segid:  0                 0                 3                 4+--    offset: 0                 45                0                 5+--+--    pprp $ splitSegdOnElemsD theGang4+--          $ lengthsToUSegd $ fromList [60, 10, 20, 40, 50 :: Int]+--+--     segd:    DUSegd lengths:  DVector lengths: [1,3,2,1]+--                                        chunks:  [[45],[15,10,20],[40,5],[45]]+--                     indices:  DVector lengths: [1,3,2,1]+--                                        chunks:  [[0], [0,15,25], [0,40],[0]]+--                    elements:  DInt [45,45,45,45]+--+--     segids: DInt [0,0,3,4]     (segment id of first slice on thread)+--    offsets: DInt [0,45,0,5]    (offset of that slice in its segment)+-- @+--+splitSegdOnElemsD :: Gang -> USegd -> Dist ((USegd,Int),Int)+splitSegdOnElemsD g !segd +  = {-# SCC "splitSegdOnElemsD" #-} +    imapD g mk (splitLenIdxD g (USegd.takeElements segd))+  where +        -- Number of threads in gang.+        !nThreads = gangSize g++        -- Determine what elements go on a thread+        mk :: Int                  -- Thread index.+           -> (Int, Int)           -- Number of elements on this thread,+                                   --   and starting offset into the flat array.+           -> ((USegd, Int), Int)  -- Segd for this thread, segid of first slice,+                                   --   and offset of first slice.++        mk i (nElems, ixStart) +         = case getChunk segd ixStart nElems (i == nThreads - 1) of+            (# lens, l, o #) -> ((USegd.fromLengths lens, l), o)++{-# NOINLINE splitSegdOnElemsD #-}+--  NOINLINE because this function has a large body of code and we don't want+--  to blow up the client modules by inlining it everywhere.+++-------------------------------------------------------------------------------+-- | Determine what elements go on a thread.+--   The 'chunk' refers to the a chunk of the flat array, and is defined+--   by a set of segment slices. +--+--   Example:+--    In this picture each X represents 5 elements, and we have 5 segements in total.+--+-- @+--    segs:    ----------------------- --- ------- --------------- -------------------+--    elems:  |X X X X X X X X X|X X X X X X X X X|X X X X X X X X X|X X X X X X X X X|+--            |     thread1     |     thread2     |     thread3     |     thread4     |+--    segid:  0                 0                 3                 4+--    offset: 0                 45                0                 5+--    k:               0                 1                 3                 5+--    k':              1                 3                 5                 5+--    left:            0                 15                0                 45+--    right:           45                20                5                 0+--    left_len:        0                 1                 0                 1+--    left_off:        0                 45                0                 5+--    n':              1                 3                 2                 1+-- @+getChunk+        :: USegd          -- ^ Segment descriptor of entire array.+        -> Int            -- ^ Starting offset into the flat array for the first+                          --   slice on this thread.+        -> Int            -- ^ Number of elements in this thread.+        -> Bool           -- ^ Whether this is the last thread in the gang.+        -> (# Vector Int  --   Lengths of segment slices, +            , Int         --     segid of first slice,+            , Int #)      --     offset of first slice.++getChunk !segd !nStart !nElems is_last+  = (# lens'', k-left_len, left_off #)+  where+    -- Lengths of all segments.+    -- eg: [60, 10, 20, 40, 50]+    !lens = USegd.takeLengths segd++    -- Indices indices of all segments.+    -- eg: [0, 60, 70, 90, 130]+    !idxs = USegd.takeIndices segd+    +    -- Total number of segments defined by segment descriptor.+    -- eg: 5+    !n    = Seq.length lens++    -- Segid of the first seg that starts after the left of this chunk.+    !k    = search nStart idxs++    -- Segid of the first seg that starts after the right of this chunk.+    !k'       | is_last     = n+              | otherwise   = search (nStart + nElems) idxs++    -- The length of the left-most slice of this chunk.+    !left     | k == n      = nElems+              | otherwise   = min ((Seq.index (here "getChunk") idxs k) - nStart) nElems++    -- The length of the right-most slice of this chunk.+    !right    | k' == k     = 0+              | otherwise   = nStart + nElems - (Seq.index (here "getChunk") idxs (k'-1))++    -- Whether the first element in this chunk is an internal element of+    -- of a segment. Alternatively, indicates that the first element of +    -- the chunk is not the first element of a segment.            +    !left_len | left == 0   = 0+              | otherwise   = 1++    -- If the first element of the chunk starts within a segment, +    -- then gives the index within that segment, otherwise 0.+    !left_off | left == 0   = 0+              | otherwise   = nStart - (Seq.index (here "getChunk") idxs (k-1))++    -- How many segments this chunk straddles.+    !n' = left_len + (k'-k)++    -- Create the lengths for this chunk by first copying out the lengths+    -- from the original segment descriptor. If the slices on the left+    -- and right cover partial segments, then we update the corresponding+    -- lengths.+    !lens' +     = runST (do+            -- Create a new array big enough to hold all the lengths for this chunk.+            !mlens' <- Seq.newM n'++            -- If the first element is inside a segment, +            --   then update the length to be the length of the slice.+            when (left /= 0) +             $ Seq.write mlens' 0 left++            -- Copy out array lengths for this chunk.+            Seq.copy (Seq.mdrop left_len mlens')+                     (Seq.slice "getChunk" lens k (k'-k))++            -- If the last element is inside a segment, +            --   then update the length to be the length of the slice.+            when (right /= 0)+             $ Seq.write mlens' (n' - 1) right++            Seq.unsafeFreeze mlens')++    !lens'' = lens'+{-      = trace +        (render $ vcat+                [ text "CHUNK"+                , pprp segd+                , text "nStart:  " <+> int nStart+                , text "nElems:  " <+> int nElems+                , text "k:       " <+> int k+                , text "k':      " <+> int k'+                , text "left:    " <+> int left+                , text "right:   " <+> int right+                , text "left_len:" <+> int left_len+                , text "left_off:" <+> int left_off+                , text "n':      " <+> int n'+                , text ""]) lens'+-}++{-# INLINE getChunk #-}+--  INLINE even though it should be inlined into splitSSegdOnElemsD anyway+--  because that function contains the only use.+++-------------------------------------------------------------------------------+-- O(log n). Given a monotonically increasing vector of `Int`s,+-- find the first element that is larger than the given value.+-- +-- eg  search 75 [0, 60, 70, 90, 130] = 90+--     search 43 [0, 60, 70, 90, 130] = 60+--+search :: Int -> Vector Int -> Int+search !x ys = go 0 (Seq.length ys)+  where+    go i n | n <= 0        = i++           | Seq.index (here "search") ys mid < x  +           = go (mid + 1) (n - half - 1)++           | otherwise     = go i half+      where+        half = n `shiftR` 1+        mid  = i + half+++-------------------------------------------------------------------------------+-- | time O(segs)+--   Join a distributed segment descriptor into a global one.+--   This simply joins the distributed lengths and indices fields, but does+--   not reconstruct the original segment descriptor as it was before splitting.+-- +-- @ > pprp $ joinSegdD theGang4 +--         $ fstD $ fstD $ splitSegdOnElemsD theGang+--         $ lengthsToUSegd $ fromList [60, 10, 20, 40, 50]+-- +--   USegd lengths:  [45,15,10,20,40,5,45]+--         indices:  [0,45,60,70,90,130,135]+--         elements: 180+-- @+-- +-- TODO: sequential runtime is O(segs) due to application of lengthsToUSegd+-- +joinSegdD :: Gang -> Dist USegd -> USegd+joinSegdD gang+        = USegd.fromLengths+        . joinD gang unbalanced+        . mapD  gang USegd.takeLengths+{-# INLINE_DIST joinSegdD #-}+++-------------------------------------------------------------------------------+-- | Glue a distributed segment descriptor back into the original global one.+--   Prop:  glueSegdD gang $ splitSegdOnElems gang usegd = usegd+--+--   NOTE: This is runs sequentially and should only be used for testing purposes.+--+glueSegdD :: Gang -> Dist ((USegd, Int), Int)  -> Dist USegd+glueSegdD gang bundle+ = let  !usegd           = fstD $ fstD $ bundle+        !lengths         = DUSegd.takeLengthsD usegd+                +        !firstSegOffsets = sndD bundle++        -- | Whether the last segment in this chunk extends into the next chunk.+        segSplits :: Dist Bool+        !segSplits+         = generateD_cheap gang $ \ix +         -> if ix >= sizeD lengths - 1+             then False+             else indexD (here "glueSegdD") firstSegOffsets (ix + 1) /= 0++        !lengths'       = fst $ carryD gang (+)                  0 segSplits lengths+        !dusegd'        = mapD gang USegd.fromLengths lengths'++  in    dusegd'+{-# INLINE_DIST glueSegdD #-}+++-------------------------------------------------------------------------------+splitSD :: Unbox a => Gang -> Dist USegd -> Vector a -> Dist (Vector a)+splitSD g dsegd xs+        = splitAsD g (DUSegd.takeElementsD dsegd) xs+{-# INLINE_DIST splitSD #-}++{-# RULES++"splitSD/splitJoinD" forall g d f xs.+  splitSD g d (splitJoinD g f xs) = f (splitSD g d xs)++"splitSD/Seq.zip" forall g d xs ys.+  splitSD g d (Seq.zip xs ys) = zipWithD g Seq.zip (splitSD g d xs)+                                             (splitSD g d ys)++  #-}
Data/Array/Parallel/Unlifted/Parallel.hs view
@@ -1,39 +1,75 @@--- | Parallel operations on unlifted arrays-module Data.Array.Parallel.Unlifted.Parallel (-  UPSegd, UPSel2, UPSelRep2,--  bpermuteUP, updateUP,--  enumFromToUP, enumFromThenToUP, enumFromStepLenUP, enumFromStepLenEachUP,--  mapUP, filterUP, packUP, combineUP, combine2UP,-  zipWithUP, foldUP, scanUP,+{-# LANGUAGE CPP #-}+#include "fusion-phases.h" -  andUP, sumUP,+-- | Parallel operations on unlifted arrays+--+--   * This is an internal API and shouldn't need to be used directly.+--     Client programs should use "Data.Array.Parallel.Unlifted" -  tagsUPSel2, indicesUPSel2, elementsUPSel2_0, elementsUPSel2_1,-  selUPSel2, repUPSel2, mkUPSel2,-  mkUPSelRep2, indicesUPSelRep2, elementsUPSelRep2_0, elementsUPSelRep2_1,+--   NOTE: Each of the sections in the export list corresponds to one of the+--         Parallel modules, and the names are in the same order as in those+--         modules.+--+module Data.Array.Parallel.Unlifted.Parallel +        ( -- * Basics+          lengthUP+        , nullUP+        , emptyUP+        , indexedUP+        , replicateUP+        , repeatUP+        , interleaveUP+  +          -- * Combinators+        , mapUP+        , filterUP+        , packUP+        , combineUP,  combine2UP+        , zipWithUP+        , foldUP,     fold1UP+        , foldlUP,    foldl1UP+        , scanUP+  +          -- * Enum+        , enumFromToUP+        , enumFromThenToUP+        , enumFromStepLenUP+        , enumFromStepLenEachUP+  +          -- * Permute+        , bpermuteUP+        , updateUP -  lengthUPSegd, lengthsUPSegd, indicesUPSegd, elementsUPSegd,-  segdUPSegd, distUPSegd,-  lengthsToUPSegd, mkUPSegd,- -  replicateSUP, replicateRSUP, appendSUP, indicesSUP,-  foldSUP, foldRUP, fold1SUP, sumSUP, sumRUP,+          -- * Segmented+        , replicateRSUP+        , appendSUP+        , foldRUP+        , sumRUP -  indexedUP, replicateUP, repeatUP, interleaveUP,+          -- * Index and Extracts+        , indexsFromVector+        , indexsFromVectorsUPVSegd+        , extractsFromNestedUPSSegd+        , extractsFromVectorsUPSSegd+        , extractsFromVectorsUPVSegd -  dropUP-) where-import Data.Array.Parallel.Unlifted.Parallel.Permute-import Data.Array.Parallel.Unlifted.Parallel.Combinators+          -- * Subarrays+        , dropUP+  +          -- * Sums+        , andUP+        , orUP+        , allUP,     anyUP+        , sumUP,     productUP+        , maximumUP, maximumByUP+        , maximumIndexByUP)+where import Data.Array.Parallel.Unlifted.Parallel.Basics-import Data.Array.Parallel.Unlifted.Parallel.Sums+import Data.Array.Parallel.Unlifted.Parallel.Combinators import Data.Array.Parallel.Unlifted.Parallel.Enum+import Data.Array.Parallel.Unlifted.Parallel.Permute+import Data.Array.Parallel.Unlifted.Parallel.Extracts import Data.Array.Parallel.Unlifted.Parallel.Segmented+import Data.Array.Parallel.Unlifted.Parallel.Text       () import Data.Array.Parallel.Unlifted.Parallel.Subarrays-import Data.Array.Parallel.Unlifted.Parallel.UPSegd-import Data.Array.Parallel.Unlifted.Parallel.UPSel-import Data.Array.Parallel.Unlifted.Parallel.Text ()-+import Data.Array.Parallel.Unlifted.Parallel.Sums
Data/Array/Parallel/Unlifted/Parallel/Basics.hs view
@@ -2,66 +2,80 @@ #include "fusion-phases.h"  -- | Basic operations on parallel unlifted arrays.-module Data.Array.Parallel.Unlifted.Parallel.Basics (-  lengthUP, nullUP, indexedUP,-  replicateUP, repeatUP, interleaveUP-) where-+module Data.Array.Parallel.Unlifted.Parallel.Basics +        ( emptyUP+        , replicateUP+        , repeatUP+        , lengthUP+        , nullUP+        , interleaveUP+        , indexedUP)+where import Data.Array.Parallel.Unlifted.Sequential.Vector as Seq import Data.Array.Parallel.Unlifted.Distributed-import Data.Array.Parallel.Unlifted.Parallel.Combinators ( mapUP )-import Data.Array.Parallel.Unlifted.Parallel.Enum        ( enumFromToUP )-import Data.Array.Parallel.Unlifted.Parallel.Permute     ( bpermuteUP )+import Data.Array.Parallel.Unlifted.Parallel.Combinators (mapUP)+import Data.Array.Parallel.Unlifted.Parallel.Enum        (enumFromToUP)+import Data.Array.Parallel.Unlifted.Parallel.Permute     (bpermuteUP)+import GHC.Base                                           (remInt) -import GHC.Base ( remInt ) --- NOTE: some of the functions are exactly the same as the U version---- | Test whether the given array is empty-nullUP :: Unbox e => Vector e -> Bool-nullUP  = (== 0) . Seq.length---- | Yield an empty array+-- | O(1). Construct an empty array. emptyUP :: Unbox e => Vector e emptyUP = Seq.new 0 (const $ return ())--lengthUP :: Unbox e => Vector e -> Int-lengthUP = Seq.length+{-# INLINE_UP emptyUP #-}   -- | Yield an array where all elements contain the same value replicateUP :: Unbox e => Int -> e -> Vector e+replicateUP n !e +        = joinD theGang balanced+        . mapD theGang (\n' ->Seq.replicate n' e)+        $ splitLenD theGang n {-# INLINE_UP replicateUP #-}-replicateUP n !e = joinD theGang balanced-                 . mapD theGang (\n ->Seq.replicate n e)-                 $ splitLenD theGang n   -- | Repeat an array the given number of times. repeatUP :: Unbox e => Int -> Vector e -> Vector e-{-# INLINE_UP repeatUP #-}-repeatUP n es = seq m-              . bpermuteUP es-              . mapUP (\i -> i `remInt` m)-              $ enumFromToUP 0 (m*n-1)+repeatUP n es +        = seq m+        . bpermuteUP es+        . mapUP (\i -> i `remInt` m)+        $ enumFromToUP 0 (m*n-1)   where     m = Seq.length es+{-# INLINE_UP repeatUP #-} ++-- | O(1). Take the length of an array.+lengthUP :: Unbox e => Vector e -> Int+lengthUP = Seq.length+{-# INLINE_UP lengthUP #-}+++-- | O(1). Test whether the given array is empty+nullUP :: Unbox e => Vector e -> Bool+nullUP  = (== 0) . Seq.length+{-# INLINE_UP nullUP #-}++ -- | Interleave elements of two arrays interleaveUP :: Unbox e => Vector e -> Vector e -> Vector e+interleaveUP xs ys+        = joinD theGang unbalanced+        $ zipWithD theGang Seq.interleave+                (splitD theGang balanced xs)+                (splitD theGang balanced ys) {-# INLINE_UP interleaveUP #-}-interleaveUP xs ys = joinD theGang unbalanced-                     (zipWithD theGang Seq.interleave-                       (splitD theGang balanced xs)-                       (splitD theGang balanced ys))-   ++ -- | Associate each element of the array with its index indexedUP :: (DT e, Unbox e) => Vector e -> Vector (Int,e)-{-# INLINE_U indexedUP #-}-indexedUP = splitJoinD theGang indexedFn -  where+indexedUP + = splitJoinD theGang indexedFn + where     sizes  arr   = fst $ scanD theGang (+) 0 $ lengthD arr-    indexedFn = \arr -> (zipWithD theGang (\o -> Seq.map (\(x,y) -> (x + o, y))) (sizes arr) $ -                        mapD theGang Seq.indexed arr)--+    indexedFn    = \arr -> zipWithD theGang +                                (\o -> Seq.map (\(x,y) -> (x + o, y)))+                                (sizes arr) +                         $  mapD theGang Seq.indexed arr+{-# INLINE_UP indexedUP #-}
Data/Array/Parallel/Unlifted/Parallel/Combinators.hs view
@@ -1,32 +1,39 @@ {-# LANGUAGE CPP #-} #include "fusion-phases.h" --- | Parallel combinators for unlifted arrays-module Data.Array.Parallel.Unlifted.Parallel.Combinators (-  mapUP, filterUP, packUP, combineUP, combine2UP,-  zipWithUP, foldUP, fold1UP, foldl1UP, scanUP-) where-+-- | Parallel combinators for unlifted arrays. +module Data.Array.Parallel.Unlifted.Parallel.Combinators +        ( mapUP+        , filterUP+        , packUP+        , combineUP, combine2UP+        , zipWithUP+        , foldUP, foldlUP, fold1UP, foldl1UP+        , scanUP)+where import Data.Array.Parallel.Base-import Data.Array.Parallel.Unlifted.Sequential.Vector as Seq import Data.Array.Parallel.Unlifted.Distributed import Data.Array.Parallel.Unlifted.Parallel.UPSel+import Data.Array.Parallel.Unlifted.Sequential.Vector as Seq +here :: String -> String+here s = "Data.Array.Parallel.Unlifted.Parallel.Combinators." Prelude.++ s --- | Apply a worker to all elements of a vector.++-- | Apply a worker to all elements of an array. mapUP :: (Unbox a, Unbox b) => (a -> b) -> Vector a -> Vector b-{-# INLINE mapUP #-} mapUP f xs          = splitJoinD theGang (mapD theGang (Seq.map f)) xs+{-# INLINE_UP mapUP #-}   -- | Keep elements that match the given predicate. filterUP :: Unbox a => (a -> Bool) -> Vector a -> Vector a-{-# INLINE filterUP #-} filterUP f         = joinD  theGang unbalanced         . mapD   theGang (Seq.filter f)         . splitD theGang unbalanced+{-# INLINE_UP filterUP #-}   -- | Take elements of an array where a flag value is true, and pack them into@@ -35,9 +42,9 @@ --   * The souce and flag arrays must have the same length, but this is not checked. -- packUP :: Unbox e => Vector e -> Vector Bool -> Vector e-{-# INLINE_UP packUP #-} packUP xs flags          = Seq.fsts . filterUP snd $ Seq.zip xs flags+{-# INLINE_UP packUP #-}   -- | Combine two vectors based on a selector. @@ -48,10 +55,13 @@ --     but this is not checked. --   combineUP :: Unbox a => Vector Bool -> Vector a -> Vector a -> Vector a-{-# INLINE combineUP #-} combineUP flags xs ys -        = combine2UP tags (mkUPSelRep2 tags) xs ys+        = checkEq (here "combineUP")+                ("tags length /= sum of args length")+                (Seq.length flags) (Seq.length xs + Seq.length ys)+        $ combine2UP tags (mkUPSelRep2 tags) xs ys         where tags = Seq.map (fromBool . not) flags+{-# INLINE combineUP #-}   -- | Combine two vectors based on a selector. @@ -59,28 +69,29 @@ --   * The data vectors must have enough elements to satisfy the selector, --     but this is not checked. -----   TODO: What is the difference between the Tag and the UPSelRep2?--- combine2UP :: Unbox a => Vector Tag -> UPSelRep2 -> Vector a -> Vector a -> Vector a-{-# INLINE_UP combine2UP #-} combine2UP tags rep !xs !ys -        = joinD    theGang balanced+        = checkEq (here "combine2UP")+                ("tags length /= sum of args length")+                (Seq.length tags) (Seq.length xs + Seq.length ys)+        $ joinD    theGang balanced         $ zipWithD theGang go rep         $ splitD   theGang balanced tags         where   go ((i,j), (m,n)) ts                   = Seq.combine2ByTag ts -                        (Seq.slice xs i m)-                        (Seq.slice ys j n)-    +                        (Seq.slice (here "combine2UP") xs i m)+                        (Seq.slice (here "combine2UP") ys j n)+{-# INLINE_UP combine2UP #-} --- | Combine two vectors into a third.++-- | Apply a worker function to correponding elements of two arrays. zipWithUP :: (Unbox a, Unbox b, Unbox c)            => (a -> b -> c) -> Vector a -> Vector b -> Vector c-{-# INLINE zipWithUP #-} zipWithUP f xs ys         = splitJoinD theGang                  (mapD theGang (Seq.map (uncurry f)))                  (Seq.zip xs ys)+{-# INLINE_UP zipWithUP #-}   -- | Undirected fold.@@ -88,6 +99,7 @@ --   standard fold function from the Haskell Prelude. -- --   * The worker function must be associative.+-- --   * The provided starting element must be neutral with respect to the worker. --     For example 0 is neutral wrt (+) and 1 is neutral wrt (*). --@@ -96,69 +108,72 @@ --   then we fold together all the results in the main thread. -- foldUP  :: (Unbox a, DT a) => (a -> a -> a) -> a -> Vector a -> a-{-# INLINE foldUP #-} foldUP f !z xs         = foldD theGang f                 (mapD   theGang (Seq.fold f z)                 (splitD theGang unbalanced xs))+{-# INLINE_UP foldUP #-}   -- | Left fold over an array.  -- --   * If the vector is empty then this returns the provided neural element.+-- --   * The worker function must be associative.+-- --   * The provided starting element must be neutral with respect to the worker, --     see `foldUP` for discussion. -- foldlUP :: (DT a, Unbox a) => (a -> a -> a) -> a -> Vector a -> a-{-# INLINE_UP foldlUP #-} foldlUP f z arr    | Seq.null arr = z   | otherwise    = foldl1UP f arr+{-# INLINE_UP foldlUP #-}   -- | Alias for `foldl1UP` fold1UP :: (DT a, Unbox a) => (a -> a -> a) -> Vector a -> a-{-# INLINE fold1UP #-} fold1UP = foldl1UP+{-# INLINE_UP fold1UP #-}   -- | Left fold over an array, using the first element of the vector as the --   neural element. -- --   * If the vector contains no elements then you'll get a bounds-check error.+-- --   * The worker function must be associative.+-- --   * The provided starting element must be neutral with respect to the worker, --     see `foldUP` for discussion. -----   TODO: The two type class constraints are in a different order. Does that matter?--- foldl1UP :: (DT a, Unbox a) => (a -> a -> a) -> Vector a -> a-{-# INLINE_U foldl1UP #-} foldl1UP f arr          = (maybe z (f z)-        . foldD  theGang combine+        . foldD  theGang combine'         . mapD   theGang (Seq.foldl1Maybe f)         . splitD theGang unbalanced) arr         where-                z = arr ! 0-                combine (Just x) (Just y) = Just (f x y)-                combine (Just x) Nothing  = Just x-                combine Nothing  (Just y) = Just y-                combine Nothing  Nothing  = Nothing+                z = Seq.index (here "fold1UP") arr 0+                combine' (Just x) (Just y) = Just (f x y)+                combine' (Just x) Nothing  = Just x+                combine' Nothing  (Just y) = Just y+                combine' Nothing  Nothing  = Nothing+{-# INLINE_UP foldl1UP #-}   -- | Prefix scan. Similar to fold, but produce an array of the intermediate states. -- --   * The worker function must be associative.+--  --   * The provided starting element must be neutral with respect to the worker, --     see `foldUP` for discussion. -- scanUP :: (DT a, Unbox a) => (a -> a -> a) -> a -> Vector a -> Vector a-{-# INLINE_UP scanUP #-} scanUP f z          = splitJoinD theGang go         where   go xs = let (ds,zs) = unzipD $ mapD theGang (Seq.scanRes f z) xs                             zs'     = fst (scanD theGang f z zs)                         in  zipWithD theGang (Seq.map . f) zs' ds+{-# INLINE_UP scanUP #-} 
Data/Array/Parallel/Unlifted/Parallel/Enum.hs view
@@ -2,59 +2,59 @@ #include "fusion-phases.h"  -- | Enum-related parallel operations on unlifted arrays-module Data.Array.Parallel.Unlifted.Parallel.Enum (-  enumFromToUP, enumFromThenToUP, enumFromStepLenUP, enumFromStepLenEachUP    -) where+module Data.Array.Parallel.Unlifted.Parallel.Enum +        ( enumFromToUP+        , enumFromThenToUP+        , enumFromStepLenUP+        , enumFromStepLenEachUP)+where import Data.Array.Parallel.Unlifted.Sequential.Vector as Seq-import Data.Array.Parallel.Unlifted.Distributed (-  mapD, scanD, zipD, splitLenIdxD, joinD, splitD, balanced, unbalanced,-  theGang)-import Data.Array.Parallel.Unlifted.Parallel.Combinators (-  mapUP)-import GHC.Base ( divInt )+import Data.Array.Parallel.Unlifted.Distributed+import Data.Array.Parallel.Unlifted.Parallel.Combinators (mapUP)+import GHC.Base                                          (divInt)   delay_inline :: a -> a-{-# INLINE [0] delay_inline #-} delay_inline x = x+{-# INLINE [0] delay_inline #-}   enumFromToUP :: (Unbox a, Enum a) => a -> a -> Vector a-{-# INLINE enumFromToUP #-}-enumFromToUP start end = mapUP toEnum (enumFromStepLenUP start' 1 len)-  where-    start' = fromEnum start-    end'   = fromEnum end-    len    = delay_inline max (end' - start' + 1) 0+enumFromToUP start end + = mapUP toEnum (enumFromStepLenUP start' 1 len)+ where  start' = fromEnum start+        end'   = fromEnum end+        len    = delay_inline max (end' - start' + 1) 0+{-# INLINE_UP enumFromToUP #-}   enumFromThenToUP :: (Unbox a, Enum a) => a -> a -> a -> Vector a-{-# INLINE enumFromThenToUP #-}-enumFromThenToUP start next end =-  mapUP toEnum (enumFromStepLenUP start' delta len)-  where-    start' = fromEnum start-    next'  = fromEnum next-    end'   = fromEnum end-    delta  = next' - start'-    -- distance between start' and end' expressed in deltas-    dist   = (end' - start' + delta) `divInt` delta-    len    = max dist 0+enumFromThenToUP start next end + = mapUP toEnum (enumFromStepLenUP start' delta len)+ where  start' = fromEnum start+        next'  = fromEnum next+        end'   = fromEnum end+        delta  = next' - start' +        -- distance between start' and end' expressed in deltas+        dist   = (end' - start' + delta) `divInt` delta+        len    = max dist 0+{-# INLINE_UP enumFromThenToUP #-} + enumFromStepLenUP :: Int -> Int -> Int -> Vector Int-{-# INLINE enumFromStepLenUP #-} enumFromStepLenUP start delta len =   joinD theGang balanced   (mapD theGang gen   (splitLenIdxD theGang len))   where     gen (n,i) = Seq.enumFromStepLen (i * delta + start) delta n+{-# INLINE_UP enumFromStepLenUP #-}  -enumFromStepLenEachUP :: Int -> Vector Int -> Vector Int -> Vector Int -> Vector Int-{-# INLINE enumFromStepLenEachUP #-}-enumFromStepLenEachUP n starts steps lens+enumFromStepLenEachUP +        :: Int -> Vector Int -> Vector Int -> Vector Int -> Vector Int+enumFromStepLenEachUP _n starts steps lens   = joinD theGang unbalanced   $ mapD theGang enum   $ splitD theGang unbalanced (Seq.zip (Seq.zip starts steps) lens)@@ -62,4 +62,5 @@     enum ps = let (qs, llens) = Seq.unzip ps                   (lstarts, lsteps) = Seq.unzip qs               in Seq.enumFromStepLenEach (Seq.sum llens) lstarts lsteps llens+{-# INLINE_UP enumFromStepLenEachUP #-} 
+ Data/Array/Parallel/Unlifted/Parallel/Extracts.hs view
@@ -0,0 +1,104 @@+{-# LANGUAGE CPP #-}+#include "fusion-phases.h"++-- | Parallel combinators for segmented unboxed arrays+module Data.Array.Parallel.Unlifted.Parallel.Extracts +        ( -- * Scattered indexing+          indexsFromVector+        , indexsFromVectorsUPVSegd++          -- * Scattered extracts+        , extractsFromNestedUPSSegd+        , extractsFromVectorsUPSSegd+        , extractsFromVectorsUPVSegd)+where+import Data.Array.Parallel.Unlifted.Parallel.UPSSegd                    (UPSSegd)+import Data.Array.Parallel.Unlifted.Parallel.UPVSegd                    (UPVSegd)+import Data.Array.Parallel.Unlifted.Sequential.Vector                   as Seq+import Data.Array.Parallel.Unlifted.Vectors                             (Vectors)+import qualified Data.Array.Parallel.Unlifted.Parallel.UPSSegd          as UPSSegd+import qualified Data.Array.Parallel.Unlifted.Parallel.UPVSegd          as UPVSegd+import qualified Data.Array.Parallel.Unlifted.Sequential.UVSegd         as UVSegd+import qualified Data.Array.Parallel.Unlifted.Vectors                   as US+import qualified Data.Array.Parallel.Unlifted.Stream                    as US+import qualified Data.Array.Parallel.Unlifted.Sequential                as Seq+import qualified Data.Vector                                            as V+++-- Indexvs --------------------------------------------------------------------+-- | Lookup elements from a `Vector`.+--+--   TODO: make this parallel.+--+indexsFromVector+        :: Unbox a+        => Vector a -> Vector Int -> Vector a++indexsFromVector = Seq.indexsFromVector+++-- | Lookup elements from some `Vectors` through a `UPVSegd`.+--+--   TODO: make this parallel.+--+indexsFromVectorsUPVSegd +        :: (Unbox a, US.Unboxes a)+        => Vectors a -> UPVSegd -> Vector (Int, Int) -> Vector a++indexsFromVectorsUPVSegd vectors upvsegd vsrcixs+ = let  -- Because we're just doing indexing here, we don't need the culled+        -- vsegids or ussegd, and can just use the redundant version.+        !vsegids  = UPVSegd.takeVSegidsRedundant upvsegd+        !upssegd  = UPVSegd.takeUPSSegdRedundant upvsegd+        !ussegd   = UPSSegd.takeUSSegd upssegd+   in   Seq.unstream+         $ US.streamElemsFromVectors     vectors+         $ US.streamSrcIxsThroughUSSegd  ussegd+         $ US.streamSrcIxsThroughVSegids vsegids+         $ Seq.stream vsrcixs+{-# INLINE_U indexsFromVectorsUPVSegd #-}+++-- Extracts -------------------------------------------------------------------+-- | Copy segments from a nested vectors and concatenate them into a new array.+extractsFromNestedUPSSegd+        :: Unbox a+        => UPSSegd -> V.Vector (Vector a) -> Vector a++extractsFromNestedUPSSegd upssegd vectors+        = Seq.unstream +        $ US.streamSegsFromNestedUSSegd+                vectors+                (UPSSegd.takeUSSegd upssegd)+{-# INLINE_U extractsFromNestedUPSSegd #-}+++-- | TODO: make this parallel.+extractsFromVectorsUPSSegd+        :: (Unbox a, US.Unboxes a)+        => UPSSegd+        -> Vectors a+        -> Vector a++extractsFromVectorsUPSSegd upssegd vectors+        = Seq.extractsFromVectorsUSSegd+                (UPSSegd.takeUSSegd upssegd) +                vectors+{-# INLINE_UP extractsFromVectorsUPSSegd #-}+++-- | TODO: make this parallel.+extractsFromVectorsUPVSegd+        :: (Unbox a, US.Unboxes a)+        => UPVSegd+        -> Vectors a+        -> Vector a++extractsFromVectorsUPVSegd upvsegd vectors+        = Seq.unstream +        $ US.streamSegsFromVectorsUVSegd vectors+        $ UVSegd.mkUVSegd +                (UPVSegd.takeVSegidsRedundant upvsegd)+                (UPSSegd.takeUSSegd $ UPVSegd.takeUPSSegdRedundant upvsegd)+{-# INLINE_UP extractsFromVectorsUPVSegd #-}+
Data/Array/Parallel/Unlifted/Parallel/Permute.hs view
@@ -1,17 +1,13 @@-{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE CPP, ScopedTypeVariables #-}+#include "fusion-phases.h"  -- | Parallel permutations for unlifted arrays-module Data.Array.Parallel.Unlifted.Parallel.Permute (-  bpermuteUP, updateUP-) where+module Data.Array.Parallel.Unlifted.Parallel.Permute +        ( bpermuteUP, updateUP)+where import Data.Array.Parallel.Unlifted.Sequential.Vector as Seq import Data.Array.Parallel.Unlifted.Distributed --bpermuteUP :: Unbox a => Vector a -> Vector Int -> Vector a-{-# INLINE bpermuteUP #-}-bpermuteUP as is = splitJoinD theGang (bpermuteD theGang as) is- {-   We can't support this for arbitrary types. The problem is:   what happens if the second array maps multiple elements to the same position?@@ -29,8 +25,14 @@   atomic. Otherwise, we do a sequential update. -} +-- | Backwards permutation.+bpermuteUP :: Unbox a => Vector a -> Vector Int -> Vector a+bpermuteUP as is = splitJoinD theGang (bpermuteD theGang as) is+{-# INLINE_UP bpermuteUP #-}+++-- | Update elements in an array. updateUP :: forall a. Unbox a => Vector a -> Vector (Int,a) -> Vector a-{-# INLINE updateUP #-} updateUP as us   {- hasAtomicWriteMU (undefined :: a)    = atomicUpdateD theGang (splitD theGang unbalanced as)@@ -39,4 +41,5 @@    | otherwise   = Seq.update as us+{-# INLINE_UP updateUP #-} 
Data/Array/Parallel/Unlifted/Parallel/Segmented.hs view
@@ -1,213 +1,142 @@ {-# LANGUAGE CPP #-}- #include "fusion-phases.h"  -- | Parallel combinators for segmented unboxed arrays-module Data.Array.Parallel.Unlifted.Parallel.Segmented (-  replicateSUP, replicateRSUP, appendSUP, indicesSUP,-  foldSUP, foldRUP, fold1SUP, sumSUP, sumRUP-) where-import Data.Array.Parallel.Unlifted.Sequential.Vector as Seq-import Data.Array.Parallel.Unlifted.Sequential.Segmented+module Data.Array.Parallel.Unlifted.Parallel.Segmented +        ( replicateRSUP+        , appendSUP+        , foldRUP+        , sumRUP)+where import Data.Array.Parallel.Unlifted.Distributed-import Data.Array.Parallel.Unlifted.Parallel.Combinators (-  mapUP, zipWithUP, packUP, combineUP)-import Data.Array.Parallel.Unlifted.Parallel.Sums (-  sumUP )-import Data.Array.Parallel.Unlifted.Parallel.Basics (-  replicateUP, repeatUP)-import Data.Array.Parallel.Unlifted.Parallel.Enum-import Data.Array.Parallel.Unlifted.Parallel.Permute ( bpermuteUP )-import Data.Array.Parallel.Unlifted.Parallel.UPSegd-import qualified Data.Vector.Fusion.Stream as S+import Data.Array.Parallel.Unlifted.Parallel.Basics+import Data.Array.Parallel.Unlifted.Parallel.UPSegd                     (UPSegd)+import Data.Array.Parallel.Unlifted.Sequential.USegd                    (USegd)+import Data.Array.Parallel.Unlifted.Sequential.Vector                   as Seq+import qualified Data.Array.Parallel.Unlifted.Parallel.UPSegd           as UPSegd+import qualified Data.Array.Parallel.Unlifted.Sequential                as Seq+import qualified Data.Array.Parallel.Unlifted.Sequential.USegd          as USegd import Data.Vector.Fusion.Stream.Monadic ( Stream(..), Step(..) ) import Data.Vector.Fusion.Stream.Size    ( Size(..) )-import Control.Monad.ST ( ST, runST )----- replicate ------------------------------------------------------------------+import qualified Data.Vector.Fusion.Stream                              as S --- | Segmented replication, using a segment descriptor.-replicateSUP :: Unbox a => UPSegd -> Vector a -> Vector a-{-# INLINE_UP replicateSUP #-}-replicateSUP segd !xs -  = joinD theGang balanced-  . mapD theGang rep-  $ distUPSegd segd-  where-    rep ((dsegd,di),_)-      = replicateSU dsegd (Seq.slice xs di (lengthUSegd dsegd))+here :: String -> String+here s = "Data.Array.Parallel.Unlifted.Parallel.Segmented." Prelude.++ s  +-- replicate ------------------------------------------------------------------ -- | Segmented replication. --   Each element in the vector is replicated the given number of times. --    --   @replicateRSUP 2 [1, 2, 3, 4, 5] = [1, 1, 2, 2, 3, 3, 4, 4, 5, 5]@ --+ --   TODO: make this efficient---  replicateRSUP :: Unbox a => Int -> Vector a -> Vector a-{-# INLINE_UP replicateRSUP #-} replicateRSUP n xs-        = replicateSUP (lengthsToUPSegd (replicateUP (Seq.length xs) n)) xs+        = UPSegd.replicateWithP (UPSegd.fromLengths (replicateUP (Seq.length xs) n)) xs+{-# INLINE_UP replicateRSUP #-}  --- append ---------------------------------------------------------------------+-- Append --------------------------------------------------------------------- -- | Segmented append. appendSUP         :: Unbox a-        => UPSegd       -- ^ segment descriptor of result array-        -> UPSegd       -- ^ segment descriptor of first array-        -> Vector a     -- ^ data of first array-        -> UPSegd       -- ^ segment descriptor of second array-        -> Vector a     -- ^ data of first array+        => UPSegd+        -> UPSegd -> Vector a+        -> UPSegd -> Vector a         -> Vector a -{-# INLINE_UP appendSUP #-} appendSUP segd !xd !xs !yd !ys   = joinD theGang balanced   . mapD  theGang append-  $ distUPSegd segd-  where append ((segd,seg_off),el_off)+  $ UPSegd.takeDistributed segd+  where append ((segd',seg_off),el_off)          = Seq.unstream-         $ appendSegS (segdUPSegd xd) xs-                      (segdUPSegd yd) ys-                      (elementsUSegd segd)+         $ appendSegS (UPSegd.takeUSegd xd) xs+                      (UPSegd.takeUSegd yd) ys+                      (USegd.takeElements segd')                       seg_off el_off+{-# INLINE_UP appendSUP #-}  +-- append --------------------------------------------------------------------- appendSegS         :: Unbox a      -        => USegd        -- ^ segment descriptor of first array-        -> Vector a     -- ^ data of first array-        -> USegd        -- ^ segment descriptor of second array-        -> Vector a     -- ^ data of second array-        -> Int          -- +        => USegd        -- ^ Segment descriptor of first array.+        -> Vector a     -- ^ Data of first array+        -> USegd        -- ^ Segment descriptor of second array.+        -> Vector a     -- ^ Data of second array.         -> Int         -> Int+        -> Int         -> S.Stream a -{-# INLINE_STREAM appendSegS #-} appendSegS !xd !xs !yd !ys !n seg_off el_off   = Stream next state (Exact n)   where-    !xlens = lengthsUSegd xd-    !ylens = lengthsUSegd yd+    !xlens = USegd.takeLengths xd+    !ylens = USegd.takeLengths yd +    {-# INLINE index1 #-}+    index1  = Seq.index (here "appendSegS")++    {-# INLINE index2 #-}+    index2  = Seq.index (here "appendSegS")+         state       | n == 0 = Nothing-      | el_off < xlens ! seg_off-      = let i = (indicesUSegd xd ! seg_off) + el_off-            j = indicesUSegd yd ! seg_off-            k = (lengthsUSegd xd ! seg_off) - el_off+      | el_off < xlens `index1` seg_off+      = let i = (USegd.takeIndices xd `index1` seg_off) + el_off+            j =  USegd.takeIndices yd `index1` seg_off+            k = (USegd.takeLengths xd `index1` seg_off) - el_off         in  Just (False, seg_off, i, j, k, n)        | otherwise       = let -- NOTE: *not* indicesUSegd xd ! (seg_off+1) since seg_off+1             -- might be out of bounds-            i       = (indicesUSegd xd ! seg_off) + (lengthsUSegd xd ! seg_off)-            el_off' = el_off - lengthsUSegd xd ! seg_off-            j       = (indicesUSegd yd ! seg_off) + el_off'-            k       = (lengthsUSegd yd ! seg_off) - el_off'+            i       = (USegd.takeIndices xd `index1` seg_off) + (USegd.takeLengths xd `index1` seg_off)+            el_off' = el_off - USegd.takeLengths xd `index1` seg_off+            j       = (USegd.takeIndices yd `index1` seg_off) + el_off'+            k       = (USegd.takeLengths yd `index1` seg_off) - el_off'         in  Just (True, seg_off, i, j, k, n)      {-# INLINE next #-}     next Nothing = return Done -    next (Just (False, seg, i, j, k, n))-      | n == 0    = return Done-      | k == 0    = return $ Skip (Just (True, seg, i, j, ylens ! seg, n))-      | otherwise = return $ Yield (xs!i) (Just (False, seg, i+1, j, k-1, n-1))+    next (Just (False, seg, i, j, k, n'))+      | n' == 0    = return Done+      | k  == 0    = return $ Skip (Just (True, seg, i, j, ylens `index1` seg, n'))+      | otherwise  = return $ Yield (xs `index2` i) (Just (False, seg, i+1, j, k-1, n'-1)) -    next (Just (True, seg, i, j, k, n))-      | n == 0    = return Done-      | k == 0+    next (Just (True, seg, i, j, k, n'))+      | n' == 0    = return Done+      | k  == 0       = let !seg' = seg+1-        in  return $ Skip (Just (False, seg', i, j, xlens ! seg', n))--      | otherwise = return $ Yield (ys!j) (Just (True, seg, i, j+1, k-1, n-1))----- fold ------------------------------------------------------------------------fixupFold :: Unbox a => (a -> a -> a) -> MVector s a-          -> Dist (Int,Vector a) -> ST s ()-{-# NOINLINE fixupFold #-}-fixupFold f !mrs !dcarry = go 1-  where-    !p = gangSize theGang+        in  return $ Skip (Just (False, seg', i, j, xlens `index1` seg', n')) -    go i | i >= p = return ()-         | Seq.null c = go (i+1)-         | otherwise   = do-                           x <- Seq.read mrs k-                           Seq.write mrs k (f x (c ! 0))-                           go (i+1)-      where-        (k,c) = indexD dcarry i+      | otherwise = return $ Yield (ys `index2` j) (Just (True, seg, i, j+1, k-1, n'-1))+{-# INLINE_STREAM appendSegS #-}  -folds :: Unbox a => (a -> a -> a)-              -> (USegd -> Vector a -> Vector a) -> UPSegd -> Vector a -> Vector a-{-# INLINE folds #-}-folds f g segd xs = dcarry `seq` drs `seq` runST (-  do-    mrs <- joinDM theGang drs-    fixupFold f mrs dcarry-    Seq.unsafeFreeze mrs)+-- foldR ----------------------------------------------------------------------+-- | Regular segmented fold.+foldRUP :: (Unbox a, Unbox b) => (b -> a -> b) -> b -> Int -> Vector a -> Vector b+foldRUP f z !segSize xs +  = joinD theGang unbalanced+          (mapD theGang +              (Seq.foldlRU f z segSize)+              (splitAsD theGang (mapD theGang (*segSize) dlen) xs))   where-    (dcarry,drs)-          = unzipD-          $ mapD theGang partial-          $ zipD (distUPSegd segd)-                 (splitD theGang balanced xs)--    partial (((segd,k),off), as)-      = let rs = g segd as-            {-# INLINE [0] n #-}-            n | off == 0  = 0-              | otherwise = 1-        in-        ((k, Seq.take n rs), Seq.drop n rs)---foldSUP :: Unbox a => (a -> a -> a) -> a -> UPSegd -> Vector a -> Vector a-{-# INLINE foldSUP #-}-foldSUP f !z = folds f (foldlSU f z)---fold1SUP :: Unbox a => (a -> a -> a) -> UPSegd -> Vector a -> Vector a-{-# INLINE fold1SUP #-}-fold1SUP f = folds f (fold1SU f)---sumSUP :: (Num e, Unbox e) => UPSegd -> Vector e -> Vector e-{-# INLINE sumSUP #-}-sumSUP = foldSUP (+) 0+    noOfSegs    = Seq.length xs `div` segSize+    dlen        = splitLenD theGang noOfSegs+{-# INLINE_UP foldRUP #-}  +-- sumR -----------------------------------------------------------------------+-- | Regular segmented sum. sumRUP :: (Num e, Unbox e) => Int -> Vector e -> Vector e-{-# INLINE sumRUP #-} sumRUP = foldRUP (+) 0---foldRUP :: (Unbox a, Unbox b) => (b -> a -> b) -> b -> Int -> Vector a -> Vector b-{-# INLINE foldRUP #-}-foldRUP f z !segSize xs = -   joinD theGang unbalanced-    (mapD theGang -      (foldlRU f z segSize)-      (splitAsD theGang (mapD theGang (*segSize) dlen) xs))-  where-    noOfSegs = Seq.length xs `div` segSize-    dlen = splitLenD theGang noOfSegs-+{-# INLINE_UP sumRUP #-} --- indices ---------------------------------------------------------------------indicesSUP :: UPSegd -> Vector Int-{-# INLINE_UP indicesSUP #-}-indicesSUP = joinD theGang balanced-           . mapD theGang indices-           . distUPSegd-  where-    indices ((segd,k),off) = indicesSU' off segd 
Data/Array/Parallel/Unlifted/Parallel/Subarrays.hs view
@@ -1,15 +1,18 @@ {-# LANGUAGE CPP #-}- #include "fusion-phases.h"  -- | Subarrays of flat unlifted arrays.-module Data.Array.Parallel.Unlifted.Parallel.Subarrays (-  dropUP-) where+module Data.Array.Parallel.Unlifted.Parallel.Subarrays +        (dropUP)+where import Data.Array.Parallel.Unlifted.Sequential.Vector as Seq-import Data.Array.Parallel.Unlifted.Distributed  +-- | Drop a the element at the provided index from a vector. dropUP :: Unbox e => Int -> Vector e -> Vector e-dropUP n xs = Seq.slice xs (min (max 0 n) (Seq.length xs)) (min (Seq.length xs) (Seq.length xs - n)) -{-# INLINE_U dropUP #-}+dropUP n xs +        = Seq.slice "dropUP"+                xs  +                (min (max 0 n)       (Seq.length xs))+                (min (Seq.length xs) (Seq.length xs - n)) +{-# INLINE_UP dropUP #-}
Data/Array/Parallel/Unlifted/Parallel/Sums.hs view
@@ -1,68 +1,80 @@--- | Sum-like parallel combinators for unlifted arrays-module Data.Array.Parallel.Unlifted.Parallel.Sums (-  andUP, orUP, sumUP-) where+{-# LANGUAGE CPP #-}+#include "fusion-phases.h" +-- | Sum-like parallel combinators for unlifted arrays+module Data.Array.Parallel.Unlifted.Parallel.Sums +        ( andUP, orUP+        , allUP, anyUP+        , sumUP, productUP+        , maximumUP, maximumByUP+        , maximumIndexByUP)+where import Data.Array.Parallel.Unlifted.Sequential.Vector as Seq import Data.Array.Parallel.Unlifted.Distributed-import Data.Array.Parallel.Unlifted.Parallel.Combinators (-  foldUP, foldl1UP, fold1UP, mapUP)-import Data.Array.Parallel.Unlifted.Parallel.Basics ( -  indexedUP)+import Data.Array.Parallel.Unlifted.Parallel.Combinators+import Data.Array.Parallel.Unlifted.Parallel.Basics (indexedUP) + -- | Compute the logical AND of all the elements in a array. andUP :: Vector Bool -> Bool-{-# INLINE andUP #-} andUP = foldUP (&&) True+{-# INLINE_UP andUP #-}   -- | Compute the logical OR of all the elements in a array. orUP :: Vector Bool -> Bool-{-# INLINE orUP #-} orUP = foldUP (||) False+{-# INLINE_UP orUP #-} + -- | Check whether all the elements in a array meet the given predicate. allUP :: Unbox e => (e -> Bool) -> Vector e -> Bool-{-# INLINE allUP #-} allUP p = andUP . mapUP p+{-# INLINE_UP allUP #-} + -- | Check whether any of the elements in a array meet the given predicate. anyUP :: Unbox e => (e -> Bool) -> Vector e -> Bool-{-# INLINE anyUP #-} anyUP p =  orUP . mapUP p+{-# INLINE_UP anyUP #-}   -- | Compute the sum all the elements of a array. sumUP :: (Unbox a, DT a, Num a) => Vector a -> a-{-# INLINE sumUP #-} sumUP = foldUP (+) 0+{-# INLINE_UP sumUP #-}   -- | Compute the product of all the elements of an array. productUP :: (DT e, Num e, Unbox e) => Vector e -> e-{-# INLINE productUP #-} productUP = foldUP (*) 1+{-# INLINE_UP productUP #-}   -- | Determine the maximum element in an array. maximumUP :: (DT e, Ord e, Unbox e) => Vector e -> e-{-# INLINE maximumUP #-} maximumUP = fold1UP max+{-# INLINE_UP maximumUP #-}  ---  |Determine the maximum element in an array under the given ordering+-- | Determine the maximum element in an array under the given ordering maximumByUP :: (DT e, Unbox e) => (e -> e -> Ordering) -> Vector e -> e-{-# INLINE maximumByUP #-}-maximumByUP = fold1UP . maxBy+maximumByUP +  = fold1UP . maxBy   where-    maxBy compare x y = case x `compare` y of-                          LT -> y-                          _  -> x+    maxBy compare' x y +        = case x `compare'` y of+           LT -> y+           _  -> x+{-# INLINE_UP maximumByUP #-} --- | Determine the index of the maximum element in an array under the given---   ordering-maximumIndexByUP :: (DT e, Unbox e) => (e -> e -> Ordering) -> Vector e -> Int-{-# INLINE maximumIndexByUP #-}-maximumIndexByUP cmp = fst . maximumByUP cmp' . indexedUP++-- | Determine the index of the maximum element in an array under the+--   given ordering+maximumIndexByUP +        :: (DT e, Unbox e) => (e -> e -> Ordering) -> Vector e -> Int+maximumIndexByUP cmp +  = fst . maximumByUP cmp' . indexedUP   where     cmp' (_,x) (_,y) = cmp x y+{-# INLINE_UP maximumIndexByUP #-}
Data/Array/Parallel/Unlifted/Parallel/Text.hs view
@@ -1,11 +1,9 @@+{-# OPTIONS -fno-warn-orphans #-} -- | Read\/Show instances for segmented unlifted arrays. module Data.Array.Parallel.Unlifted.Parallel.Text () where--import Data.Array.Parallel.Base (-  Read(..), showsApp)-import Data.Array.Parallel.Unlifted.Parallel.UPSegd (-  UPSegd, lengthsUPSegd )+import Data.Array.Parallel.Base.Text (showsApp)+import Data.Array.Parallel.Unlifted.Parallel.UPSegd (UPSegd, takeLengths)  instance Show UPSegd where-  showsPrec k = showsApp k "toUPSegd" . lengthsUPSegd+  showsPrec k = showsApp k "toUPSegd" . takeLengths
+ Data/Array/Parallel/Unlifted/Parallel/UPSSegd.hs view
@@ -0,0 +1,318 @@+{-# LANGUAGE CPP #-}+#include "fusion-phases.h"++-- | Parallel Scattered Segment descriptors.+--+--   See "Data.Array.Parallel.Unlifted" for how this works.+--+module Data.Array.Parallel.Unlifted.Parallel.UPSSegd +        ( -- * Types+          UPSSegd, valid++          -- * Constructors+        , mkUPSSegd, fromUSSegd, fromUPSegd+        , empty, singleton+  +          -- * Predicates+        , isContiguous++          -- * Projections+        , length+        , takeUSSegd+        , takeDistributed+        , takeLengths+        , takeIndices+        , takeElements+        , takeStarts+        , takeSources+        , getSeg+  +          -- * Append+        , appendWith  ++          -- * Segmented Folds+        , foldWithP+        , fold1WithP+        , sumWithP+        , foldSegsWithP)+where+import Data.Array.Parallel.Pretty                                 hiding (empty)+import Data.Array.Parallel.Unlifted.Distributed+import Data.Array.Parallel.Unlifted.Parallel.UPSegd               (UPSegd)+import Data.Array.Parallel.Unlifted.Sequential.USSegd             (USSegd)+import Data.Array.Parallel.Unlifted.Sequential.Vector             (Vector,  MVector, Unbox)+import Data.Array.Parallel.Unlifted.Vectors                       (Vectors, Unboxes)+import qualified Data.Array.Parallel.Unlifted.Parallel.UPSegd     as UPSegd+import qualified Data.Array.Parallel.Unlifted.Distributed.USSegd  as DUSSegd+import qualified Data.Array.Parallel.Unlifted.Sequential.USSegd   as USSegd+import qualified Data.Array.Parallel.Unlifted.Sequential.Vector   as US+import qualified Data.Array.Parallel.Unlifted.Sequential          as Seq+import Control.Monad.ST+import Prelude hiding (length)++here :: String -> String+here s = "Data.Array.Parallel.Unlifted.Parallel.UPSSegd." ++ s+++-- | Parallel Scattered Segment sescriptor+data UPSSegd +        = UPSSegd +        { upssegd_ussegd        :: !USSegd+          -- ^ Segment descriptor that describes the whole array.++        , upssegd_dssegd        :: Dist ((USSegd,Int),Int)+          -- ^ Segment descriptor for each chunk, +          --   along with segment id of first slice in the chunk,+          --   and the offset of that slice in its segment.+          --   See docs of `splitSegdOfElemsD` for an example.+        }+        deriving Show+++instance PprPhysical UPSSegd where+ pprp (UPSSegd ussegd dssegd)+  =  text "UPSSegd"+  $$ (nest 7 $ vcat+        [ text "ussegd:  " <+> pprp ussegd+        , text "dssegd:  " <+> pprp dssegd])+++-- | O(1).+--   Check the internal consistency of a scattered segment descriptor.+--- +--   * TODO: this doesn't do any checks yet+valid :: UPSSegd -> Bool+valid _ = True+{-# NOINLINE valid #-}+--  NOINLINE because it's only used during debugging anyway.+++-- Constructors ---------------------------------------------------------------+-- | Construct a new segment descriptor.+mkUPSSegd +        :: Vector Int   -- ^ Starting index of each segment in its flat array.+        -> Vector Int   -- ^ Source id of the flat array to tach each segment from.+        -> UPSegd       -- ^ Contiguous (unscattered) segment descriptor.+        -> UPSSegd++mkUPSSegd starts sources upsegd+        = fromUSSegd (USSegd.mkUSSegd starts sources (UPSegd.takeUSegd upsegd))+{-# INLINE_UP mkUPSSegd #-}+++-- | Promote a global `USSegd` to a parallel `UPSSegd` by distributing+--   it across the gang.+fromUSSegd :: USSegd -> UPSSegd+fromUSSegd ssegd +        = UPSSegd ssegd (DUSSegd.splitSSegdOnElemsD theGang ssegd)+{-# INLINE_UP fromUSSegd #-}+++-- | Promote a plain `UPSegd` to a `UPSSegd`, by assuming that all segments+--   come from a single flat array with source id 0.+---+--   * TODO:+--     This sequentially constructs the indices and source fields, and we+--     throw out the existing distributed `USegd`. We could probably keep+--     some of the existing fields and save reconstructing them.+--+fromUPSegd :: UPSegd -> UPSSegd+fromUPSegd upsegd+        = fromUSSegd $ USSegd.fromUSegd $ UPSegd.takeUSegd upsegd+{-# INLINE_UP fromUPSegd #-}+++-- | O(1). Yield an empty segment descriptor, with no elements or segments.+empty :: UPSSegd+empty   = fromUSSegd USSegd.empty+{-# INLINE_UP empty #-}+++-- | O(1).+--   Yield a singleton segment descriptor.+--   The single segment covers the given number of elements.+singleton :: Int -> UPSSegd+singleton n = fromUSSegd $ USSegd.singleton n+{-# INLINE_UP singleton #-}+++-- Predicates -----------------------------------------------------------------+-- INLINE trivial predicates as they'll expand to a simple calls.++-- | O(1). True when the starts are identical to the usegd indices field and+--   the sources are all 0's. +--+--   In this case all the data elements are in one contiguous flat+--   array, and consumers can avoid looking at the real starts and+--   sources fields.+--+isContiguous :: UPSSegd -> Bool+isContiguous    = USSegd.isContiguous . upssegd_ussegd+{-# INLINE isContiguous #-}+++-- Projections ----------------------------------------------------------------+-- INLINE trivial projections as they'll expand to a single record selector.++-- | O(1). Yield the overall number of segments.+length :: UPSSegd -> Int+length          = USSegd.length . upssegd_ussegd+{-# INLINE length #-}++-- | O(1). Yield the global `USegd` of a `UPSegd`+takeUSSegd :: UPSSegd -> USSegd+takeUSSegd      = upssegd_ussegd+{-# INLINE takeUSSegd #-}+++-- | O(1). Yield the distributed `USegd` of a `UPSegd`+takeDistributed :: UPSSegd -> Dist ((USSegd, Int), Int)+takeDistributed = upssegd_dssegd+{-# INLINE takeDistributed #-}+++-- | O(1). Yield the lengths of the individual segments.+takeLengths :: UPSSegd -> Vector Int+takeLengths     = USSegd.takeLengths . upssegd_ussegd+{-# INLINE takeLengths #-}+++-- | O(1). Yield the segment indices.+takeIndices :: UPSSegd -> Vector Int+takeIndices     = USSegd.takeIndices . upssegd_ussegd+{-# INLINE takeIndices #-}+++-- | O(1). Yield the total number of data elements.+--+--  @takeElements upssegd = sum (takeLengths upssegd)@+--+takeElements :: UPSSegd -> Int+takeElements    = USSegd.takeElements . upssegd_ussegd+{-# INLINE takeElements #-}+++-- | O(1). Yield the starting indices.+takeStarts :: UPSSegd -> Vector Int+takeStarts      = USSegd.takeStarts . upssegd_ussegd+{-# INLINE takeStarts #-}+++-- | O(1). Yield the source ids.+takeSources :: UPSSegd -> Vector Int+takeSources     = USSegd.takeSources . upssegd_ussegd +{-# INLINE takeSources #-}+++-- | O(1). Get the length, segment index, starting index, and source id of a segment.+getSeg :: UPSSegd -> Int -> (Int, Int, Int, Int)+getSeg upssegd ix+        = USSegd.getSeg (upssegd_ussegd upssegd) ix+{-# INLINE_UP getSeg #-}+++-- Append ---------------------------------------------------------------------+-- | O(n)+--   Produce a segment descriptor that describes the result of appending two+--   segmented arrays.+--+--   Appending two nested arrays is an index space transformation. Because+--   a `UPSSegd` can contain segments from multiple flat data arrays, we can+--   represent the result of the append without copying elements from the+--   underlying flat data arrays.+---+--   * TODO: This calls out to the sequential version.+--+appendWith+        :: UPSSegd              -- ^ Segment descriptor of first nested array.+        -> Int                  -- ^ Number of flat data arrays used to represent first nested array.+        -> UPSSegd              -- ^ Segment descriptor of second nested array. +        -> Int                  -- ^ Number of flat data arrays used to represent second nested array.+        -> UPSSegd+appendWith upssegd1 pdatas1+           upssegd2 pdatas2+ = fromUSSegd + $ USSegd.appendWith+        (upssegd_ussegd upssegd1) pdatas1+        (upssegd_ussegd upssegd2) pdatas2+{-# NOINLINE appendWith #-}+--  NOINLINE because we're not using it yet.+++-- Fold -----------------------------------------------------------------------+-- | Fold segments specified by a `UPSSegd`.+foldWithP :: (Unbox a, Unboxes a)+         => (a -> a -> a) -> a -> UPSSegd -> Vectors a -> Vector a+foldWithP f !z  = foldSegsWithP f (Seq.foldlSSU f z)+{-# INLINE_UP foldWithP #-}+++-- | Fold segments specified by a `UPSSegd`, with a non-empty vector.+fold1WithP :: (Unbox a, Unboxes a)+           => (a -> a -> a) -> UPSSegd -> Vectors a -> Vector a+fold1WithP f    = foldSegsWithP f (Seq.fold1SSU f)+{-# INLINE_UP fold1WithP #-}+++-- | Sum up segments specified by a `UPSSegd`.+sumWithP :: (Num a, Unbox a, Unboxes a)+        => UPSSegd -> Vectors a -> Vector a+sumWithP = foldWithP (+) 0+{-# INLINE_UP sumWithP #-}+++-- | Fold the segments specified by a `UPSSegd`.+--+--   Low level function takes a per-element worker and a per-segment worker.+--   It folds all the segments with the per-segment worker, then uses the+--   per-element worker to fixup the partial results when a segment +--   is split across multiple threads.+--   +foldSegsWithP+        :: (Unbox a, Unboxes a)+        => (a -> a -> a)+        -> (USSegd -> Vectors a -> Vector a)+        -> UPSSegd -> Vectors a -> Vector a++foldSegsWithP fElem fSeg segd xss + = dcarry `seq` drs `seq` +   runST (do+        mrs <- joinDM theGang drs+        fixupFold fElem mrs dcarry+        US.unsafeFreeze mrs)++ where  (dcarry,drs)+          = unzipD+          $ mapD theGang partial (takeDistributed segd)++        partial ((ssegd, k), off)+         = let rs = fSeg ssegd xss+               {-# INLINE [0] n #-}+               n | off == 0  = 0+                 | otherwise = 1++           in  ((k, US.take n rs), US.drop n rs)+{-# INLINE_UP foldSegsWithP #-}+++fixupFold+        :: Unbox a+        => (a -> a -> a)+        -> MVector s a+        -> Dist (Int,Vector a)+        -> ST s ()++fixupFold f !mrs !dcarry = go 1+  where+    !p = gangSize theGang++    go i | i >= p    = return ()+         | US.null c = go (i+1)+         | otherwise   +         = do   x <- US.read mrs k+                US.write mrs k (f x (US.index (here "fixupFold") c 0))+                go (i + 1)+      where+        (k,c) = indexD (here "fixupFold") dcarry i+{-# NOINLINE fixupFold #-}+
Data/Array/Parallel/Unlifted/Parallel/UPSegd.hs view
@@ -2,67 +2,287 @@ #include "fusion-phases.h"  -- | Parallel segment descriptors.-module Data.Array.Parallel.Unlifted.Parallel.UPSegd (+--+--   See "Data.Array.Parallel.Unlifted" for how this works.+--+module Data.Array.Parallel.Unlifted.Parallel.UPSegd +        ( -- * Types+          UPSegd(..)+        , valid -  -- * Types-  UPSegd,+          -- * Constructors+        , mkUPSegd, fromUSegd+        , empty, singleton, fromLengths -  -- * Operations on segment descriptors-  lengthUPSegd, lengthsUPSegd, indicesUPSegd, elementsUPSegd,-  segdUPSegd, distUPSegd,-  lengthsToUPSegd, mkUPSegd-) where+          -- * Projections+        , length+        , takeUSegd+        , takeDistributed+        , takeLengths+        , takeIndices+        , takeElements -import Data.Array.Parallel.Unlifted.Sequential.Vector as Seq-import Data.Array.Parallel.Unlifted.Sequential.Segmented.USegd+          -- * Indices+        , indicesP+  +          -- * Replicate+        , replicateWithP+    +          -- * Segmented Folds+        , foldWithP+        , fold1WithP+        , sumWithP+        , foldSegsWithP)+where import Data.Array.Parallel.Unlifted.Distributed+import Data.Array.Parallel.Unlifted.Sequential.USegd             (USegd)+import qualified Data.Array.Parallel.Unlifted.Distributed.USegd  as USegd+import qualified Data.Array.Parallel.Unlifted.Sequential         as Seq+import qualified Data.Array.Parallel.Unlifted.Sequential.Vector  as US+import qualified Data.Array.Parallel.Unlifted.Sequential.USegd   as USegd+import Data.Array.Parallel.Pretty                                hiding (empty)+import Data.Array.Parallel.Unlifted.Sequential.Vector  (Vector, MVector, Unbox)+import Control.Monad.ST+import Prelude  hiding (length) -data UPSegd = UPSegd { upsegd_usegd :: !USegd-                     , upsegd_dsegd :: Dist ((USegd,Int),Int)-                     }+here :: String -> String+here s = "Data.Array.Parallel.Unlifted.Parallel.UPSegd." ++ s  -lengthUPSegd :: UPSegd -> Int-{-# INLINE lengthUPSegd #-}-lengthUPSegd = lengthUSegd . upsegd_usegd+-- | A parallel segment descriptor holds a global (undistributed) segment+--   desciptor, as well as a distributed version. The distributed version+--   describes how to split work on the segmented array over the gang. +data UPSegd +        = UPSegd +        { upsegd_usegd :: !USegd+          -- ^ Segment descriptor that describes the whole array. +        , upsegd_dsegd :: Dist ((USegd,Int),Int)+          -- ^ Segment descriptor for each chunk, +          --   along with segment id of first slice in the chunk,+          --   and the offset of that slice in its segment.+          --   See docs of `splitSegdOfElemsD` for an example.+        } -lengthsUPSegd :: UPSegd -> Vector Int-{-# INLINE lengthsUPSegd #-}-lengthsUPSegd = lengthsUSegd . upsegd_usegd +-- Pretty ---------------------------------------------------------------------+instance PprPhysical UPSegd where+ pprp (UPSegd usegd dsegd)+  =  text "UPSegd"+  $$ (nest 7 $ vcat+        [ text "usegd:  "  <+> pprp usegd+        , text "dsegd:  "  <+> pprp dsegd]) -indicesUPSegd :: UPSegd -> Vector Int-{-# INLINE indicesUPSegd #-}-indicesUPSegd = indicesUSegd . upsegd_usegd +-- Valid ----------------------------------------------------------------------+-- | O(1).+--   Check the internal consistency of a parallel segment descriptor.+--- +--   * TODO: this doesn't do any checks yet+valid :: UPSegd -> Bool+valid _ = True+{-# NOINLINE valid #-}+--  NOINLINE because it's only used during debugging anyway. -elementsUPSegd :: UPSegd -> Int-{-# INLINE elementsUPSegd #-}-elementsUPSegd = elementsUSegd . upsegd_usegd +-- Constructors ---------------------------------------------------------------+-- | O(1). Construct a new parallel segment descriptor.+mkUPSegd +        :: Vector Int   -- ^ Length of each segment.+        -> Vector Int   -- ^ Starting index of each segment.+        -> Int          -- ^ Total number of elements in the flat array.+        -> UPSegd -segdUPSegd :: UPSegd -> USegd-{-# INLINE segdUPSegd #-}-segdUPSegd = upsegd_usegd+mkUPSegd lens idxs n+        = fromUSegd (USegd.mkUSegd lens idxs n)+{-# INLINE_UP mkUPSegd #-}  -distUPSegd :: UPSegd -> Dist ((USegd,Int),Int)-{-# INLINE distUPSegd #-}-distUPSegd = upsegd_dsegd+-- | Convert a global `USegd` to a parallel `UPSegd` by distributing +--   it across the gang.+fromUSegd :: USegd -> UPSegd+fromUSegd segd   = UPSegd segd (USegd.splitSegdOnElemsD theGang segd)+{-# INLINE_UP fromUSegd #-}  -lengthsToUPSegd :: Vector Int -> UPSegd-{-# INLINE lengthsToUPSegd #-}-lengthsToUPSegd = toUPSegd . lengthsToUSegd+-- | O(1). Construct an empty segment descriptor, with no elements or segments.+empty :: UPSegd+empty           = fromUSegd USegd.empty+{-# INLINE_UP empty #-}  -mkUPSegd :: Vector Int -> Vector Int -> Int -> UPSegd-{-# INLINE mkUPSegd #-}-mkUPSegd lens idxs n = toUPSegd (mkUSegd lens idxs n)+-- | O(1). Construct a singleton segment descriptor.+--   The single segment covers the given number of elements.+singleton :: Int -> UPSegd+singleton n     = fromUSegd $ USegd.singleton n+{-# INLINE_UP singleton #-}  -toUPSegd :: USegd -> UPSegd-{-# INLINE toUPSegd #-}-toUPSegd segd = UPSegd segd (splitSegdD' theGang segd)+-- | O(n). Convert an array of segment lengths into a parallel segment descriptor.+-- +--   The array contains the length of each segment, and we compute the +--   indices from that. Runtime is O(n) in the number of segments.+--+fromLengths :: Vector Int -> UPSegd+fromLengths     = fromUSegd . USegd.fromLengths+{-# INLINE_UP fromLengths #-} ++-- Projections ----------------------------------------------------------------+-- INLINE trivial projections as they'll expand to a single record selector.++-- | O(1). Yield the overall number of segments.+length :: UPSegd -> Int+length          = USegd.length . upsegd_usegd+{-# INLINE length #-}+++-- | O(1). Yield the global `USegd` of a `UPSegd`.+takeUSegd :: UPSegd -> USegd+takeUSegd       = upsegd_usegd+{-# INLINE takeUSegd #-}+++-- | O(1). Yield the distributed `USegd` of a `UPSegd`.+--   +--  We get a plain `USegd` for each chunk, the segment id of the first+--  slice in the chunk, and the starting offset of that slice in its segment.+-- +takeDistributed :: UPSegd -> Dist ((USegd,Int),Int)+takeDistributed = upsegd_dsegd+{-# INLINE takeDistributed #-}+++-- | O(1). Yield the lengths of the individual segments.+takeLengths :: UPSegd -> Vector Int+takeLengths     = USegd.takeLengths . upsegd_usegd+{-# INLINE takeLengths #-}+++-- | O(1). Yield the segment indices.+takeIndices :: UPSegd -> Vector Int+takeIndices     = USegd.takeIndices . upsegd_usegd+{-# INLINE takeIndices #-}+++-- | O(1). Yield the total number of array elements.+-- +--  @takeElements upsegd = sum (takeLengths upsegd)@+--+takeElements :: UPSegd -> Int+takeElements    = USegd.takeElements . upsegd_usegd+{-# INLINE takeElements #-}+++-- Indices --------------------------------------------------------------------+-- | O(n). Yield a vector containing indicies that give the position of each +--         member of the flat array in its corresponding segment.+--+--  @indicesP (fromLengths [5, 2, 3]) = [0,1,2,3,4,0,1,0,1,2]@+--+indicesP :: UPSegd -> Vector Int+indicesP+        = joinD theGang balanced+        . mapD  theGang indices+        . takeDistributed+  where+    indices ((segd,_k),off) = Seq.indicesSU' off segd+{-# NOINLINE indicesP #-}+--  NOINLINE because we're not using it yet.+++-- Replicate ------------------------------------------------------------------+-- | Copying segmented replication. Each element of the vector is physically +--   copied according to the length of each segment in the segment descriptor.+--+--   @replicateWith (fromLengths [3, 1, 2]) [5, 6, 7] = [5, 5, 5, 6, 7, 7]@+--+replicateWithP :: Unbox a => UPSegd -> Vector a -> Vector a+replicateWithP segd !xs +  = joinD theGang balanced+  . mapD  theGang rep+  $ takeDistributed segd+  where+    rep ((dsegd,di),_)+      = Seq.replicateSU dsegd +      $ US.slice (here "replicateWithP")+                xs di (USegd.length dsegd)+{-# INLINE_UP replicateWithP #-}+++-- Fold -----------------------------------------------------------------------+-- | Fold segments specified by a `UPSegd`.+foldWithP :: Unbox a+         => (a -> a -> a) -> a -> UPSegd -> Vector a -> Vector a+foldWithP f !z  = foldSegsWithP f (Seq.foldlSU f z)+{-# INLINE_UP foldWithP #-}+++-- | Fold segments specified by a `UPSegd`, with a non-empty vector.+fold1WithP :: Unbox a+         => (a -> a -> a) -> UPSegd -> Vector a -> Vector a+fold1WithP f    = foldSegsWithP f (Seq.fold1SU f)+{-# INLINE_UP fold1WithP #-}+++-- | Sum up segments specified by a `UPSegd`.+sumWithP :: (Num e, Unbox e) => UPSegd -> Vector e -> Vector e+sumWithP = foldWithP (+) 0+{-# INLINE_UP sumWithP #-}+++-- | Fold the segments specified by a `UPSegd`.+--+--   This low level function takes a per-element worker and a per-segment worker.+--   It folds all the segments with the per-segment worker, then uses the+--   per-element worker to fixup the partial results when a segment +--   is split across multiple threads.+--   +foldSegsWithP+        :: Unbox a+        => (a -> a -> a)+        -> (USegd -> Vector a -> Vector a)+        -> UPSegd -> Vector a -> Vector a++{-# INLINE_UP foldSegsWithP #-}+foldSegsWithP fElem fSeg segd xs + = dcarry `seq` drs `seq` +   runST (do+        mrs <- joinDM theGang drs+        fixupFold fElem mrs dcarry+        US.unsafeFreeze mrs)++ where  (dcarry,drs)+          = unzipD+          $ mapD theGang partial+          $ zipD (takeDistributed segd)+                 (splitD theGang balanced xs)++        partial (((segd', k), off), as)+         = let rs = fSeg segd' as+               {-# INLINE [0] n #-}+               n | off == 0  = 0+                 | otherwise = 1++           in  ((k, US.take n rs), US.drop n rs)+++fixupFold+        :: Unbox a+        => (a -> a -> a)+        -> MVector s a+        -> Dist (Int,Vector a)+        -> ST s ()+{-# NOINLINE fixupFold #-}+fixupFold f !mrs !dcarry = go 1+  where+    !p = gangSize theGang++    go i | i >= p = return ()+         | US.null c = go (i+1)+         | otherwise   = do+                           x <- US.read mrs k+                           US.write mrs k (f x (US.index (here "fixupFold") c 0))+                           go (i + 1)+      where+        (k,c) = indexD (here "fixupFold") dcarry i
Data/Array/Parallel/Unlifted/Parallel/UPSel.hs view
@@ -2,16 +2,25 @@ #include "fusion-phases.h"  -- | Parallel selectors.-module Data.Array.Parallel.Unlifted.Parallel.UPSel (-  -- * Types-  UPSel2, UPSelRep2,+module Data.Array.Parallel.Unlifted.Parallel.UPSel +        ( -- * Types+          UPSel2+        , UPSelRep2 -  -- * Operations on segment descriptors-  tagsUPSel2, indicesUPSel2, elementsUPSel2_0, elementsUPSel2_1,-  selUPSel2, repUPSel2, mkUPSel2,-  mkUPSelRep2, indicesUPSelRep2, elementsUPSelRep2_0, elementsUPSelRep2_1,-) where-import Data.Array.Parallel.Unlifted.Sequential.Vector as Seq+          -- * Operations+        , tagsUPSel2+        , indicesUPSel2+        , elementsUPSel2_0+        , elementsUPSel2_1+        , selUPSel2+        , repUPSel2+        , mkUPSel2+        , mkUPSelRep2+        , indicesUPSelRep2+        , elementsUPSelRep2_0+        , elementsUPSelRep2_1)+where+import Data.Array.Parallel.Unlifted.Sequential.Vector   as US import Data.Array.Parallel.Unlifted.Sequential.USel import Data.Array.Parallel.Unlifted.Distributed import Data.Array.Parallel.Base (Tag, tagToInt)@@ -29,102 +38,54 @@         , upsel2_rep  :: UPSelRep2 }  --- | A `UPSelRep2` describes how to distribute the two data vectors---   corresponding to a `UPSel2` across several PEs. -----   Suppose we want to perform the following combine operation:------ @---    combine [0,0,1,1,0,1,0,0,1] [A0,A1,A2,A3,A4] [B0,B1,B2,B3] ---     = [A0,A1,B0,B1,A2,B2,A3,A4,B3]--- @------   The first array is the tags array, that says which of the data arrays to---   get each successive element from. As `combine` is difficult to compute---   in parallel, if we are going to perform several combines with the same---   tag array, we can precompute a selector that tells us where to get each---   element. The selector contains the original tags, as well as the source---   index telling us where to get each element for the result array.--- --- @---    [0,0,1,1,0,1,0,0,1]      -- tags    (which data vector to take the elem from)---    [0,1,0,1,2,2,3,4,3]      -- indices (where in the vector to take the elem from)--- @------  Suppose we want to distribute the combine operation across 3 PEs. It's---  easy to split the selector like so:------ @       ---     PE0                PE1               PE2---    [0,0,1]            [1,0,1]           [0,0,1]   -- tags---    [0,1,0]            [1,2,2]           [3,4,3]   -- indices--- @------  We now need to split the two data arrays. Each PE needs slices of the data---  arrays that correspond to the parts of the selector that were given to it.---  For the current example we get:------ @---    PE0                PE1               PE2---    [A0,A1]            [A2]              [A3,A4]---    [B0]               [B1,B2]           [B3]--- @------  The `UPSelRep2` contains the starting index and length of each of of these---  slices:------ @---         PE0                PE1               PE2---    ((0, 0), (2, 1))   ((2, 1), (1, 2))  ((3, 3), (2, 1))---    indices   lens      indices  lens    indices  lens--- @--- type UPSelRep2         = Dist ((Int,Int), (Int,Int)) +-- Projections ----------------------------------------------------------------+-- INLINE trivial projections as they'll expand to a single record selector.  -- | O(1). Get the tags of a selector. tagsUPSel2 :: UPSel2 -> Vector Tag+tagsUPSel2      = tagsUSel2 .  upsel2_usel {-# INLINE tagsUPSel2 #-}-tagsUPSel2 = tagsUSel2 .  upsel2_usel   -- | O(1). Get the indices of a selector. indicesUPSel2 :: UPSel2 -> Vector Int+indicesUPSel2   = indicesUSel2 . upsel2_usel {-# INLINE indicesUPSel2 #-}-indicesUPSel2 = indicesUSel2 . upsel2_usel  --- | O(1). TODO: What is this for?+-- | O(1). Get the number of elements that will be taken from the first array. elementsUPSel2_0 :: UPSel2 -> Int-{-# INLINE elementsUPSel2_0 #-} elementsUPSel2_0 = elementsUSel2_0 . upsel2_usel+{-# INLINE elementsUPSel2_0 #-}  --- | O(1). TODO: What is this for?+-- | O(1). Get the number of elements that will be taken from the second array. elementsUPSel2_1 :: UPSel2 -> Int-{-# INLINE elementsUPSel2_1 #-} elementsUPSel2_1 = elementsUSel2_1 . upsel2_usel+{-# INLINE elementsUPSel2_1 #-}  --- | O(1). TODO: What is this for?+-- | O(1). Take the sequential `USel2` from a `UPSel2`. selUPSel2 :: UPSel2 -> USel2+selUPSel2       = upsel2_usel {-# INLINE selUPSel2 #-}-selUPSel2 = upsel2_usel  --- | O(1). TODO: What is this for?+-- | O(1). Take the `UPSelRep2` from a `UPSel2`. repUPSel2 :: UPSel2 -> UPSelRep2+repUPSel2       = upsel2_rep {-# INLINE repUPSel2 #-}-repUPSel2 = upsel2_rep   -- Representation selectors ------------------------------------------------------- | Computes a `UPSelRep2` from an array of tags. This is used when parallelising---   a `combine` operation. See the docs for `UPSelRep2` for details.+-- | Computes a `UPSelRep2` from an array of tags.+--   This is used when parallelising a `combine` operation.+--   See the docs for `UPSelRep2` for details. mkUPSelRep2 :: Vector Tag -> UPSelRep2-{-# INLINE mkUPSelRep2 #-} mkUPSelRep2 tags = zipD idxs lens   where     lens = mapD   theGang count@@ -133,38 +94,42 @@     idxs = fst          $ scanD theGang add (0,0) lens -    count bs = let ones = Seq.sum (Seq.map tagToInt bs)-               in (Seq.length bs - ones,ones)+    count bs = let ones = US.sum (US.map tagToInt bs)+               in (US.length bs - ones,ones)      add (x1,y1) (x2,y2) = (x1+x2, y1+y2)+{-# INLINE_UP mkUPSelRep2 #-}   indicesUPSelRep2 :: Vector Tag -> UPSelRep2 -> Vector Int-{-# INLINE indicesUPSelRep2 #-}-indicesUPSelRep2 tags rep = joinD theGang balanced-                          $ zipWithD theGang indices-                                             (splitD theGang balanced tags)-                                              rep+indicesUPSelRep2 tags rep +        = joinD theGang balanced+        $ zipWithD theGang indices+             (splitD theGang balanced tags)+              rep   where-    indices tags ((i,j), (m,n))-      = Seq.combine2ByTag tags (Seq.enumFromStepLen i 1 m)-                               (Seq.enumFromStepLen j 1 n)+    indices tags' ((i,j), (m,n))+      = US.combine2ByTag tags' (US.enumFromStepLen i 1 m)+                               (US.enumFromStepLen j 1 n)+{-# INLINE_UP indicesUPSelRep2 #-}  --- | O(n).+-- | O(n). Count the number of elements to take from the first array. elementsUPSelRep2_0 :: Vector Tag -> UPSelRep2 -> Int-{-# INLINE elementsUPSelRep2_0 #-}-elementsUPSelRep2_0 _ = sumD theGang . fstD . sndD+elementsUPSelRep2_0 _+        = sumD theGang . fstD . sndD+{-# INLINE_UP elementsUPSelRep2_0 #-}  --- | O(n).+-- | O(n). Count the number of elements to take from the second array. elementsUPSelRep2_1 :: Vector Tag -> UPSelRep2 -> Int-{-# INLINE elementsUPSelRep2_1 #-}-elementsUPSelRep2_1 _ = sumD theGang . sndD . sndD+elementsUPSelRep2_1 _+        = sumD theGang . sndD . sndD+{-# INLINE_UP elementsUPSelRep2_1 #-}   -- | O(1). Construct a selector. Wrapper for `UPSel2`. mkUPSel2 :: Vector Tag -> Vector Int -> Int -> Int -> UPSelRep2 -> UPSel2-{-# INLINE mkUPSel2 #-}-mkUPSel2 tags is n0 n1 rep = UPSel2 (mkUSel2 tags is n0 n1) rep-+mkUPSel2 tags is n0 n1 rep+        = UPSel2 (mkUSel2 tags is n0 n1) rep+{-# INLINE_UP mkUPSel2 #-}
+ Data/Array/Parallel/Unlifted/Parallel/UPVSegd.hs view
@@ -0,0 +1,478 @@+{-# LANGUAGE CPP #-}+#include "fusion-phases.h"+{-# OPTIONS -Wall -fno-warn-orphans -fno-warn-missing-signatures #-}++-- | Parallel virtual segment descriptors.+--+--   See "Data.Array.Parallel.Unlifted" for how this works.+--+module Data.Array.Parallel.Unlifted.Parallel.UPVSegd +        ( -- * Types+          UPVSegd++          -- * Consistency check+        , valid++          -- * Constructors+        , mkUPVSegd+        , fromUPSegd+        , fromUPSSegd+        , empty+        , singleton+        , replicated+        +        -- * Predicates+        , isManifest+        , isContiguous++        -- * Projections+        , length+        , takeVSegids, takeVSegidsRedundant+        , takeUPSSegd, takeUPSSegdRedundant+        , takeLengths+        , getSeg++        -- * Demotion+        , unsafeDemoteToUPSSegd+        , unsafeDemoteToUPSegd++        -- * Operators+        , updateVSegs+        , updateVSegsReachable++        , appendWith+        , combine2)+where+import Data.Array.Parallel.Unlifted.Parallel.Permute+import Data.Array.Parallel.Unlifted.Parallel.UPSel              (UPSel2)+import Data.Array.Parallel.Unlifted.Parallel.UPSSegd            (UPSSegd)+import Data.Array.Parallel.Unlifted.Parallel.UPSegd             (UPSegd)+import Data.Array.Parallel.Unlifted.Sequential.Vector           (Vector)+import Data.Array.Parallel.Pretty                               hiding (empty)+import Prelude                                                  hiding (length)+import qualified Data.Array.Parallel.Unlifted.Sequential.Vector as US+import qualified Data.Array.Parallel.Unlifted.Sequential.USSegd as USSegd+import qualified Data.Array.Parallel.Unlifted.Parallel.UPSel    as UPSel+import qualified Data.Array.Parallel.Unlifted.Parallel.UPSegd   as UPSegd+import qualified Data.Array.Parallel.Unlifted.Parallel.UPSSegd  as UPSSegd++here :: String -> String+here s = "Data.Array.Parallel.Unlifted.Parallel.UPVSegd." Prelude.++ s++-- UPVSegd ---------------------------------------------------------------------+-- | Parallel Virtual Segment descriptor.+--   +data UPVSegd +        = UPVSegd +        { upvsegd_manifest      :: !Bool+          -- ^ When the vsegids field holds a lazy (V.enumFromTo 0 (len - 1))+          --   then this field is True. This lets us perform some operations like+          --   demoteToUPSSegd without actually creating the vsegids field.+        +          -- | Virtual segment identifiers that indicate what physical segment+          --   to use for each virtual segment.+        , upvsegd_vsegids_redundant     :: Vector Int           -- LAZY FIELD +        , upvsegd_vsegids_culled        :: Vector Int           -- LAZY FIELD+        +          -- | Scattered segment descriptor that defines how physical segments+          --   are layed out in memory.+        , upvsegd_upssegd_redundant     :: UPSSegd              -- LAZY FIELD+        , upvsegd_upssegd_culled        :: UPSSegd              -- LAZY FIELD+        +        -- IMPORTANT:+        -- When vsegids are transformed due to a segmented replication operation, +        -- if some of the segment lengths were zero, then we will end up with +        -- physical segments that are unreachable from the vsegids.+        -- +        -- For some operations (like indexing) the fact that we have unreachable+        -- psegids doesn't matter, but for others (like segmented fold) it does.+        -- The problem is that we perform segmented fold by first folding all +        -- the physical segments, then replicating the results according to the +        -- vsegids. If no vsegids referenced a physical segment then we didn't +        -- need to fold it.+        -- +        -- When vsegids are updated the version that may have unreachable psegs+        -- is stored in the vsegids_redundant and upssegd_redundant. The _culled+        -- versions are then set to a SUSPENDED call to callOnVSegids. If no+        -- consumers every demand the culled version then we never need to compute+        -- it.+        -- +        -- The vsegids_redundant field must also be lazy (no bang) because when it+        -- has the value (V.enumFromTo 0 (len - 1)) we want to avoid building the+        -- enumeration unless it's strictly demanded.+        }+        deriving (Show)+++-- | Pretty print the physical representation of a `UVSegd`+instance PprPhysical UPVSegd where+ pprp (UPVSegd _ _ vsegids _ upssegd)+  = vcat+  [ text "UPVSegd" $$ (nest 7 $ text "vsegids: " <+> (text $ show $ US.toList vsegids))+  , pprp upssegd ]+++-- | O(1). Check the internal consistency of a virutal segmentation descriptor.+---+--   * TODO: this doesn't do any checks yet.+--+valid :: UPVSegd -> Bool+valid UPVSegd{} = True+{-# NOINLINE valid #-}+--  NOINLINE because it's only used during debugging anyway.+++-- Constructors ---------------------------------------------------------------+-- NOTE: these are NOINLINE for now just so it's easier to read the core.+--       we can INLINE them later.++-- | O(1). Construct a new virtual segment descriptor.+mkUPVSegd+        :: Vector Int   -- ^ Array saying which physical segment to use for+                        --   each virtual segment.+        -> UPSSegd      -- ^ Scattered segment descriptor defining the physical+                        --   segments.+        -> UPVSegd++mkUPVSegd vsegids ussegd+        = UPVSegd False vsegids vsegids ussegd ussegd+{-# INLINE_UP mkUPVSegd #-}+++-- | O(segs). Promote a `UPSSegd` to a `UPVSegd`.+--   The result contains one virtual segment for every physical segment+--   defined by the `UPSSegd`.+---+--   * TODO: make this parallel, use parallel version of enumFromTo.+--+fromUPSSegd :: UPSSegd -> UPVSegd+fromUPSSegd upssegd+ = let  vsegids = US.enumFromTo 0 (UPSSegd.length upssegd - 1)+   in   UPVSegd True vsegids vsegids upssegd upssegd+{-# INLINE_UP fromUPSSegd #-}+++-- | O(segs). Promote a `UPSegd` to a `UPVSegd`.+--   All segments are assumed to come from a flat array with sourceid 0.+--   The result contains one virtual segment for every physical segment+--   the provided `UPSegd`.+--+fromUPSegd :: UPSegd -> UPVSegd+fromUPSegd      = fromUPSSegd . UPSSegd.fromUPSegd+{-# INLINE_UP fromUPSegd #-}+++-- | O(1). Construct an empty segment descriptor, with no elements or segments.+empty :: UPVSegd+empty+ = let  vsegids = US.empty+        upssegd = UPSSegd.empty+   in   UPVSegd True vsegids vsegids upssegd upssegd+{-# INLINE_UP empty #-}+++-- | O(1). Construct a singleton segment descriptor.+--   The single segment covers the given number of elements in a flat array+--   with sourceid 0.+singleton :: Int -> UPVSegd+singleton n+ = let  vsegids = US.singleton 0+        upssegd = UPSSegd.singleton n+   in   UPVSegd True vsegids vsegids upssegd upssegd+{-# INLINE_UP singleton #-}+++-- | O(1). Construct a `UPVSegd` that describes an array created by replicating+--   a single segment several times.+---+--   NOTE: This is a helpful target for rewrite rules, because when we +--   see a 'replicated' we know that all segments in the virtual array+--   point to the same data.+replicated +        :: Int          -- ^ Length of segment.+        -> Int          -- ^ Number of times replicated.+        -> UPVSegd++replicated len reps+ = let  -- We have a single physical segment.+        ssegd   = UPSSegd.singleton len++        -- All virtual segments point to the same physical segment.+   in   mkUPVSegd (US.replicate reps 0) ssegd                           -- TODO: use parallel replicate+{-# INLINE_U replicated #-}+++-- Predicates -----------------------------------------------------------------+-- | O(1). Checks whether all the segments are manifest (unshared / non-virtual).+--   If this is the case, then the vsegids field will be [0..len-1]. +--+--   Consumers can check this field, avoid demanding the vsegids field.+--   This can avoid the need for it to be constructed in the first place, due to+--   lazy evaluation.+--+isManifest :: UPVSegd -> Bool+isManifest      = upvsegd_manifest+{-# INLINE isManifest #-}+++-- | O(1). True when the starts are identical to the usegd indices field and+--   the sources are all 0's. +--+--   In this case all the data elements are in one contiguous flat+--   array, and consumers can avoid looking at the real starts and+--   sources fields.+--+isContiguous    :: UPVSegd -> Bool+isContiguous    = UPSSegd.isContiguous . upvsegd_upssegd_culled+{-# INLINE isContiguous #-}+++-- Projections ----------------------------------------------------------------+-- INLINE trivial projections as they'll expand to a single record selector.++-- | O(1). Yield the overall number of segments.+length :: UPVSegd -> Int+length          = US.length . upvsegd_vsegids_redundant+{-# INLINE length #-}+++-- | O(1). Yield the virtual segment ids of `UPVSegd`.+takeVSegids :: UPVSegd -> Vector Int+takeVSegids     = upvsegd_vsegids_culled+{-# INLINE takeVSegids #-}+++-- | O(1). Take the vsegids of a `UPVSegd`, but don't require that every physical+--   segment is referenced by some virtual segment.+--+--   If you're just performing indexing and don't need the invariant that all+--   physical segments are reachable from some virtual segment, then use this+--   version as it's faster. This sidesteps the code that maintains the invariant.+--+--   The stated O(1) complexity assumes that the array has already been fully+--   evalauted. If this is not the case then we can avoid demanding the result+--   of a prior computation on the vsegids, thus reducing the cost attributed+--   to that prior computation.+takeVSegidsRedundant :: UPVSegd -> Vector Int+takeVSegidsRedundant = upvsegd_vsegids_redundant+{-# INLINE takeVSegidsRedundant #-}+++-- | O(1). Yield the `UPSSegd` of `UPVSegd`.+takeUPSSegd :: UPVSegd -> UPSSegd+takeUPSSegd     = upvsegd_upssegd_culled+{-# INLINE takeUPSSegd #-}+++-- | O(1). Take the `UPSSegd` of a `UPVSegd`, but don't require that every physical+--   segment is referenced by some virtual segment.+--+--   See the note in `takeVSegidsRedundant`.+takeUPSSegdRedundant :: UPVSegd -> UPSSegd+takeUPSSegdRedundant    = upvsegd_upssegd_redundant+{-# INLINE takeUPSSegdRedundant #-}+++-- | O(segs). Yield the lengths of the segments described by a `UPVSegd`.+---+--   * TODO: This is slow and sequential.+--+takeLengths :: UPVSegd -> Vector Int+takeLengths (UPVSegd manifest _ vsegids _ upssegd)+ | manifest     = UPSSegd.takeLengths upssegd+ | otherwise    + = let !lengths        = (UPSSegd.takeLengths upssegd)+   in  US.map (US.index (here "takeLengths") lengths) vsegids+{-# NOINLINE takeLengths #-}+--  NOINLINE because we don't want a case expression due to the test on the +--  manifest flag to appear in the core program.+++-- | O(1). Get the length, starting index, and source id of a segment.+---+--  NOTE: We don't return the segment index field from the `USSegd` as this refers+--        to the flat index relative to the `SSegd` array, rather than +--        relative to the UVSegd array. If we tried to promote the `USSegd` index+--        to a `UVSegd` index it could overflow.+--+getSeg :: UPVSegd -> Int -> (Int, Int, Int)+getSeg upvsegd ix+ = let  vsegids = upvsegd_vsegids_redundant upvsegd+        upssegd = upvsegd_upssegd_redundant upvsegd+        (len, _index, start, source)+                = UPSSegd.getSeg upssegd (US.index (here "getSeg") vsegids ix)+   in   (len, start, source)+{-# INLINE_UP getSeg #-}+++-- Demotion -------------------------------------------------------------------+-- | O(segs). Yield a `UPSSegd` that describes each segment of a `UPVSegd`+--   individually.+--+--   By doing this we lose information about which virtual segments+--   correspond to the same physical segments.+--+--   /WARNING/: Trying to take the `UPSegd` of a nested array that has been+--   constructed with replication can cause index space overflow. This is+--   because the virtual size of the corresponding flat data can be larger+--   than physical memory. If this happens then indices fields and +--   element count in the result will be invalid.+-- +unsafeDemoteToUPSSegd :: UPVSegd -> UPSSegd+unsafeDemoteToUPSSegd upvsegd+ | upvsegd_manifest upvsegd     = upvsegd_upssegd_culled upvsegd        -- TODO: take the redundant ones+ | otherwise+ = let  vsegids         = upvsegd_vsegids_culled upvsegd+        upssegd         = upvsegd_upssegd_culled upvsegd+        starts'         = bpermuteUP (UPSSegd.takeStarts  upssegd) vsegids+        sources'        = bpermuteUP (UPSSegd.takeSources upssegd) vsegids+        lengths'        = bpermuteUP (UPSSegd.takeLengths upssegd) vsegids+        upsegd'         = UPSegd.fromLengths lengths'+   in   UPSSegd.mkUPSSegd starts' sources' upsegd'+{-# NOINLINE unsafeDemoteToUPSSegd #-}+--  NOINLINE because it's complicated and won't fuse with anything.+--  In core we want to see when VSegds are being demoted.+++-- | O(segs). Yield a `UPSegd` that describes each segment of a `UPVSegd`+--   individually, assuming all segments have been concatenated to +--   remove scattering.+--+--   * See the warning in `unsafeDemoteToUPSSegd`.+---+--   * TODO: if the upvsegd is manifest and contiguous this can be O(1).+--+unsafeDemoteToUPSegd :: UPVSegd -> UPSegd+unsafeDemoteToUPSegd (UPVSegd _ _ vsegids _ upssegd)+        = {-# SCC "unsafeDemoteToUPSegd" #-}+          UPSegd.fromLengths+        $ bpermuteUP (UPSSegd.takeLengths upssegd) vsegids+{-# NOINLINE unsafeDemoteToUPSegd #-}+--  NOINLINE because it's complicated and won't fuse with anything.+--  In core we want to see when VSegds are being demoted.+++-- Operators ------------------------------------------------------------------+-- | Update the vsegids of a `UPVSegd`, and then cull the physical+--   segment descriptor so that all physical segments are reachable from+--   some virtual segment.+--+--   This function lets you perform filtering operations on the virtual segments,+--   while maintaining the invariant that all physical segments are referenced+--   by some virtual segment.+---+--   * TODO: make this parallel.+--     It runs the sequential 'cull' then reconstructs the UPSSegd.+-- +updateVSegs :: (Vector Int -> Vector Int) -> UPVSegd -> UPVSegd+updateVSegs fUpdate (UPVSegd _ vsegids _ upssegd _)+ = let  +        -- When we transform the vsegids, we don't know whether they all +        -- made it into the result. +        vsegids_redundant      = fUpdate vsegids+ +        -- Cull the psegs down to just those reachable from the vsegids, +        -- but do it lazilly so consumers can avoid demanding this +        -- culled version and save creating it.+        (  vsegids_culled+         , ussegd_culled)       = USSegd.cullOnVSegids vsegids_redundant+                                $ UPSSegd.takeUSSegd upssegd++        upssegd_culled          = UPSSegd.fromUSSegd ussegd_culled++   in   UPVSegd False+                vsegids_redundant vsegids_culled+                upssegd           upssegd_culled+{-# NOINLINE updateVSegs #-}+--  NOINLINE because we want to see this happening in core.+++-- | Update the vsegids  of `UPVSegd`, where the result is guaranteed to+--   cover all physical segments.+--+--   Using this version saves performing the 'cull' operation which +--   discards unreachable physical segments.+--+--   * The resulting vsegids must cover all physical segments.+--     If they do not then there will be physical segments that are not +--     reachable from some virtual segment, and subsequent operations+--     like segmented fold will have the wrong work complexity.+--+updateVSegsReachable :: (Vector Int -> Vector Int) -> UPVSegd -> UPVSegd+updateVSegsReachable fUpdate (UPVSegd _ _ vsegids _ upssegd)+ = let  vsegids' = fUpdate vsegids+   in   UPVSegd False vsegids' vsegids' upssegd upssegd+{-# NOINLINE updateVSegsReachable #-}+--  NOINLINE because we want to see this happening in core.+++-- Append ---------------------------------------------------------------------+-- | Produce a segment descriptor that describes the result of appending two arrays.+--- +--   * TODO: make this parallel.+--+appendWith+        :: UPVSegd      -- ^ Descriptor of first array.+        -> Int          -- ^ Number of flat physical arrays for first descriptor.+        -> UPVSegd      -- ^ Descriptor of second array.+        -> Int          -- ^ Number of flat physical arrays for second descriptor.+        -> UPVSegd++appendWith+        (UPVSegd _ _ vsegids1 _ upssegd1) pdatas1+        (UPVSegd _ _ vsegids2 _ upssegd2) pdatas2++ = let  -- vsegids releative to appended psegs+        vsegids1' = vsegids1+        vsegids2' = US.map (+ UPSSegd.length upssegd1) vsegids2+        +        -- append the vsegids+        vsegids'  = vsegids1' US.++ vsegids2'++        -- All data from the source arrays goes into the result+        upssegd'  = UPSSegd.appendWith+                                upssegd1 pdatas1+                                upssegd2 pdatas2+                                 +   in   UPVSegd False vsegids' vsegids' upssegd' upssegd'+{-# NOINLINE appendWith #-}+--  NOINLINE because it doesn't need to be specialised+--           and we're worried about code explosion.+++-- Combine --------------------------------------------------------------------+-- | Combine two virtual segment descriptors.+---+--   * TODO: make this parallel. +--+combine2+        :: UPSel2       -- ^ Selector for the combine operation.+        -> UPVSegd      -- ^ Descriptor of first array.+        -> Int          -- ^ Number of flat physical arrays for first descriptor.+        -> UPVSegd      -- ^ Descriptor of second array.+        -> Int          -- ^ Number of flat physical arrays for second descriptor.+        -> UPVSegd+        +combine2+        upsel2+        (UPVSegd _ _ vsegids1 _ upssegd1) pdatas1+        (UPVSegd _ _ vsegids2 _ upssegd2) pdatas2++ = let  -- vsegids relative to combined psegs+        vsegids1' = vsegids1+        vsegids2' = US.map (+ (US.length vsegids1)) vsegids2++        -- combine the vsegids+        vsegids'  = US.combine2ByTag (UPSel.tagsUPSel2 upsel2)+                                    vsegids1' vsegids2'++         -- All data from the source arrays goes into the result+        upssegd'  = UPSSegd.appendWith+                                upssegd1 pdatas1+                                upssegd2 pdatas2+                                  +   in   UPVSegd False vsegids' vsegids' upssegd' upssegd'+{-# NOINLINE combine2 #-}+--  NOINLINE because it doesn't need to be specialised+--           and we're worried about code explosion.+
dph-prim-par.cabal view
@@ -1,12 +1,14 @@ Name:           dph-prim-par-Version:        0.5.1.1+Version:        0.6.0.1 License:        BSD3 License-File:   LICENSE Author:         The DPH Team Maintainer:     Ben Lippmeier <benl@cse.unsw.edu.au> Homepage:       http://www.haskell.org/haskellwiki/GHC/Data_Parallel_Haskell Category:       Data Structures-Synopsis:       Parallel Primitives for Data-Parallel Haskell.+Synopsis:       Data Parallel Haskell segmented arrays. (production version)+Description:    Production implementation of the flat parallel array API defined+                in dph-prim-interface.  Cabal-Version:  >= 1.6 Build-Type:     Simple@@ -14,39 +16,59 @@ Library   Exposed-Modules:         Data.Array.Parallel.Unlifted.Distributed+        Data.Array.Parallel.Unlifted.Distributed.Gang+        Data.Array.Parallel.Unlifted.Distributed.TheGang         Data.Array.Parallel.Unlifted.Parallel+        Data.Array.Parallel.Unlifted.Parallel.UPSegd+        Data.Array.Parallel.Unlifted.Parallel.UPSSegd+        Data.Array.Parallel.Unlifted.Parallel.UPVSegd+        Data.Array.Parallel.Unlifted.Parallel.UPSel         Data.Array.Parallel.Unlifted+   Other-Modules:-        Data.Array.Parallel.Unlifted.Distributed.Gang-        Data.Array.Parallel.Unlifted.Distributed.TheGang         Data.Array.Parallel.Unlifted.Distributed.DistST         Data.Array.Parallel.Unlifted.Distributed.Types         Data.Array.Parallel.Unlifted.Distributed.Combinators         Data.Array.Parallel.Unlifted.Distributed.Scalars         Data.Array.Parallel.Unlifted.Distributed.Arrays+        Data.Array.Parallel.Unlifted.Distributed.USegd+        Data.Array.Parallel.Unlifted.Distributed.USSegd         Data.Array.Parallel.Unlifted.Distributed.Basics-        Data.Array.Parallel.Unlifted.Parallel.Combinators-        Data.Array.Parallel.Unlifted.Parallel.Sums+        Data.Array.Parallel.Unlifted.Distributed.Types.USegd+        Data.Array.Parallel.Unlifted.Distributed.Types.USSegd+        Data.Array.Parallel.Unlifted.Distributed.Types.UVSegd+        Data.Array.Parallel.Unlifted.Distributed.Types.Vector+        Data.Array.Parallel.Unlifted.Distributed.Types.Maybe+        Data.Array.Parallel.Unlifted.Distributed.Types.Tuple+        Data.Array.Parallel.Unlifted.Distributed.Types.Prim+        Data.Array.Parallel.Unlifted.Distributed.Types.Unit+        Data.Array.Parallel.Unlifted.Distributed.Types.Base         Data.Array.Parallel.Unlifted.Parallel.Basics-        Data.Array.Parallel.Unlifted.Parallel.Permute+        Data.Array.Parallel.Unlifted.Parallel.Combinators         Data.Array.Parallel.Unlifted.Parallel.Enum+        Data.Array.Parallel.Unlifted.Parallel.Extracts+        Data.Array.Parallel.Unlifted.Parallel.Permute         Data.Array.Parallel.Unlifted.Parallel.Segmented         Data.Array.Parallel.Unlifted.Parallel.Subarrays-        Data.Array.Parallel.Unlifted.Parallel.UPSegd-        Data.Array.Parallel.Unlifted.Parallel.UPSel+        Data.Array.Parallel.Unlifted.Parallel.Sums         Data.Array.Parallel.Unlifted.Parallel.Text    Exposed: False    Extensions: TypeFamilies, GADTs, RankNTypes,-              BangPatterns, MagicHash, UnboxedTuples, TypeOperators-  GHC-Options: -Odph -funbox-strict-fields -fcpr-off+              BangPatterns, MagicHash, UnboxedTuples, TypeOperators,+              FlexibleInstances, FlexibleContexts ++  GHC-Options:+        -Odph -funbox-strict-fields+        -fcpr-off -Wall+   Build-Depends:  -        base     == 4.4.*,-        random   == 1.0.*,-        vector   == 0.7.*,-        old-time == 1.0.*,-        dph-base == 0.5.*,-        dph-prim-interface == 0.5.*,-        dph-prim-seq       == 0.5.*+        base               == 4.5.*,+        random             == 1.0.*,+        vector             == 0.9.*,+        old-time           == 1.1.*,+        dph-base           == 0.6.*,+        dph-prim-interface == 0.6.*,+        dph-prim-seq       == 0.6.*