dph-prim-seq-0.5.1.1: Data/Array/Parallel/Unlifted/Sequential/Vector.hs
{-# LANGUAGE ScopedTypeVariables, BangPatterns, CPP #-}
#include "fusion-phases.h"
-- | Wrappers for primitives defined in @Data.Vector@
module Data.Array.Parallel.Unlifted.Sequential.Vector (
-- * Array classes
Unbox,
-- * Array types
Vector, MVector,
-- * Streaming
stream, unstream,
-- * Basic operations
length, null, empty, singleton, cons, units,
replicate,
-- replicateEachU,
(!), (++),
interleave, indexed, repeat, repeatS,
-- * Subarrays
slice, extract,
tail,
take, drop, splitAt,
-- * Permutations
permute, bpermute, mbpermute, bpermuteDft, reverse, update,
-- * Higher-order operations
map, zipWith, zipWith3,
filter, pack,
combine, combine2ByTag,
foldl, foldl1, foldl1Maybe,
fold, fold1, fold1Maybe,
scanl, scanl1,
scan, scan1,
scanRes,
-- * Searching
elem, notElem,
-- * Logical operations
and, or, any, all,
-- * Arithmetic operations
sum, product,
maximum, minimum,
maximumBy, minimumBy,
maxIndex, minIndex,
maxIndexBy, minIndexBy,
-- * Arrays of pairs
zip, unzip, fsts, snds,
-- * Enumerations
enumFromTo, enumFromThenTo, enumFromStepLen, enumFromToEach, enumFromStepLenEach,
-- * Searching
find, findIndex,
-- * Conversions to\/from lists
toList, fromList,
-- * Random arrays
random, randomR,
-- * Mutating operations
new, copy,
-- * Mutable vectors
newM, unsafeFreeze, M.write, M.read, mpermute, mupdate,
mdrop, mslice,
-- * I\/O
UIO(..)
) where
import Data.Array.Parallel.Stream
import Data.Array.Parallel.Base ( Tag, checkEq, ST )
import Data.Vector.Unboxed hiding ( slice, zip, unzip, foldl, foldl1, scanl, scanl1 )
import qualified Data.Vector.Unboxed as V
import qualified Data.Vector.Unboxed.Mutable as M
import qualified Data.Vector.Unboxed.Base as VBase
import Data.Vector.Generic ( stream, unstream )
import qualified Data.Vector.Generic as G
import qualified Data.Vector.Generic.Mutable as MG
import qualified Data.Vector.Storable as Storable
import qualified Data.Vector.Storable.Mutable as MStorable
import qualified Data.Vector.Generic.New as New
import qualified Data.Vector.Fusion.Stream as S
import Data.Vector.Fusion.Stream.Monadic ( Stream(..), Step(..) )
import Data.Vector.Fusion.Stream.Size ( Size(..) )
import Prelude hiding ( length, null,
replicate, (++), repeat,
tail, take, drop, splitAt,
reverse,
map, zipWith, zipWith3, filter,
foldl, foldl1, scanl, scanl1,
elem, notElem,
and, or, any, all,
sum, product,
maximum, minimum,
zip, unzip,
enumFromTo, enumFromThenTo )
import qualified Prelude
import qualified System.Random as R
import Foreign hiding ( new )
import System.IO
here s = "Data.Array.Parallel.Unlifted.Sequential.Flat." Prelude.++ s
new :: Unbox a => Int -> (forall s. MVector s a -> ST s ()) -> Vector a
{-# INLINE new #-}
new n p = V.create (do
v <- M.new n
p v
return v)
newM :: Unbox a => Int -> ST s (MVector s a)
{-# INLINE newM #-}
newM = M.new
-- | Yield an array of units
units :: Int -> Vector ()
{-# INLINE units #-}
units n = replicate n ()
-- | Interleave the elements of two arrays
interleave :: Unbox e => Vector e -> Vector e -> Vector e
{-# INLINE_U interleave #-}
interleave xs ys = unstream (interleaveS (stream xs) (stream ys))
-- | Repeat an array @n@ times
repeat :: Unbox e => Int -> Vector e -> Vector e
{-# INLINE_U repeat #-}
repeat n xs = unstream (repeatS n xs)
repeatS :: Unbox e => Int -> Vector e -> S.Stream e
{-# INLINE_STREAM repeatS #-}
repeatS k !xs = Stream next (0,k) (Exact (k*n))
where
!n = length xs
{-# INLINE next #-}
next (i,0) = return Done
next (i,k) | i == n = return $ Skip (0,k-1)
| otherwise = return $ Yield (unsafeIndex xs i) (i+1,k)
slice :: Unbox a => Vector a -> Int -> Int -> Vector a
{-# INLINE_U slice #-}
slice xs i n = V.slice i n xs
extract :: Unbox a => Vector a -> Int -> Int -> Vector a
{-# INLINE_U extract #-}
extract xs i n = force (V.slice i n xs)
mupdate :: Unbox e => MVector s e -> Vector (Int,e) -> ST s ()
{-# INLINE_U mupdate #-}
mupdate marr xs = MG.update marr (stream xs)
mpermute :: Unbox e => MVector s e -> Vector e -> Vector Int -> ST s ()
{-# INLINE_U mpermute #-}
mpermute marr xs is = MG.update marr (stream (zip is xs))
permute :: Unbox e => Vector e -> Vector Int -> Vector e
{-# INLINE_U permute #-}
permute xs is = create (do
v <- M.new (length xs)
mpermute v xs is
return v)
bpermute :: Unbox e => Vector e -> Vector Int -> Vector e
{-# INLINE_U bpermute #-}
bpermute = backpermute
mbpermute :: (Unbox e, Unbox d) => (e -> d) -> Vector e -> Vector Int -> Vector d
{-# INLINE_STREAM mbpermute #-}
mbpermute f es is = unstream (mbpermuteS f es (stream is))
bpermuteS :: Unbox e => Vector e -> S.Stream Int -> S.Stream e
{-# INLINE_STREAM bpermuteS #-}
bpermuteS !a s = S.map (a!) s
mbpermuteS:: Unbox e => (e -> d) -> Vector e -> S.Stream Int -> S.Stream d
{-# INLINE_STREAM mbpermuteS #-}
mbpermuteS f !a = S.map (f . (a!))
-- | Default back permute
--
-- * The values of the index-value pairs are written into the position in the
-- result array that is indicated by the corresponding index.
--
-- * All positions not covered by the index-value pairs will have the value
-- determined by the initialiser function for that index position.
--
bpermuteDft :: Unbox e
=> Int -- ^ length of result array
-> (Int -> e) -- ^ initialiser function
-> Vector (Int,e) -- ^ index-value pairs
-> Vector e
{-# INLINE_U bpermuteDft #-}
bpermuteDft n init = update (map init (enumFromN 0 n))
-- | Extract all elements from an array according to a given flag array
pack:: Unbox e => Vector e -> Vector Bool -> Vector e
{-# INLINE_U pack #-}
pack xs = map fst . filter snd . zip xs
combine :: Unbox a
=> Vector Bool -> Vector a -> Vector a -> Vector a
{-# INLINE combine #-}
combine bs = combine2ByTag (map (\b -> if b then 0 else 1) bs)
combine2ByTag :: Unbox a => Vector Tag -> Vector a -> Vector a -> Vector a
{-# INLINE_U combine2ByTag #-}
combine2ByTag ts xs ys
= checkEq (here "combine2ByTag")
("tags length /= sum of args length")
(length ts) (length xs + length ys)
$ unstream (combine2ByTagS (stream ts) (stream xs) (stream ys))
-- | Array reduction proceeding from the left
foldl :: Unbox a => (b -> a -> b) -> b -> Vector a -> b
{-# INLINE_U foldl #-}
foldl = foldl'
-- | Array reduction proceeding from the left for non-empty arrays
foldl1 :: Unbox a => (a -> a -> a) -> Vector a -> a
{-# INLINE_U foldl1 #-}
foldl1 = foldl1'
-- | Array reduction that requires an associative combination function with its
-- unit
fold :: Unbox a => (a -> a -> a) -> a -> Vector a -> a
{-# INLINE_U fold #-}
fold = foldl
-- | Reduction of a non-empty array which requires an associative combination
-- function
fold1 :: Unbox a => (a -> a -> a) -> Vector a -> a
{-# INLINE_U fold1 #-}
fold1 = foldl1
foldl1Maybe :: Unbox a => (a -> a -> a) -> Vector a -> Maybe a
{-# INLINE_U foldl1Maybe #-}
foldl1Maybe f xs = foldl' join Nothing xs
where
{-# INLINE join #-}
join Nothing y = Just $! y
join (Just x) y = Just $! f x y
fold1Maybe :: Unbox a => (a -> a -> a) -> Vector a -> Maybe a
{-# INLINE_U fold1Maybe #-}
fold1Maybe = foldl1Maybe
-- | Prefix scan proceedings from left to right
scanl :: (Unbox a, Unbox b) => (b -> a -> b) -> b -> Vector a -> Vector b
{-# INLINE_U scanl #-}
scanl = prescanl'
-- | Prefix scan of a non-empty array proceeding from left to right
scanl1 :: Unbox a => (a -> a -> a) -> Vector a -> Vector a
{-# INLINE_U scanl1 #-}
scanl1 = scanl1'
-- | Prefix scan proceeding from left to right that needs an associative
-- combination function with its unit
scan :: Unbox a => (a -> a -> a) -> a -> Vector a -> Vector a
{-# INLINE_U scan #-}
scan = scanl
-- | Prefix scan of a non-empty array proceeding from left to right that needs
-- an associative combination function
scan1 :: Unbox a => (a -> a -> a) -> Vector a -> Vector a
{-# INLINE_U scan1 #-}
scan1 = scanl1
scanRes :: Unbox a => (a -> a -> a) -> a -> Vector a -> (Vector a,a)
{-# INLINE_U scanRes #-}
scanRes f z xs = let ys = scanl' f z xs
in
(unsafeInit ys, unsafeLast ys)
fsts :: (Unbox a, Unbox b) => Vector (a,b) -> Vector a
{-# INLINE_STREAM fsts #-}
fsts (VBase.V_2 _ xs ys) = xs
snds :: (Unbox a, Unbox b) => Vector (a,b) -> Vector b
{-# INLINE_STREAM snds #-}
snds (VBase.V_2 _ xs ys) = ys
zip :: (Unbox a, Unbox b) => Vector a -> Vector b -> Vector (a,b)
{-# INLINE_STREAM zip #-}
zip !xs !ys = V.zip xs ys
unzip :: (Unbox a, Unbox b) => Vector (a,b) -> (Vector a, Vector b)
{-# INLINE_STREAM unzip #-}
unzip ps = V.unzip ps
{-# RULES
"fsts/new/unstream [dph-prim-seq]" forall xs.
fsts (G.new (New.unstream xs)) = V.map fst (G.new (New.unstream xs))
"snds/new/unstream [dph-prim-seq]" forall xs.
snds (G.new (New.unstream xs)) = V.map snd (G.new (New.unstream xs))
"stream/zip [dph-prim-seq]" forall xs ys.
G.stream (zip xs ys) = S.zip (G.stream xs) (G.stream ys)
#-}
enumFromStepLen :: Int -> Int -> Int -> Vector Int
{-# INLINE_U enumFromStepLen #-}
enumFromStepLen = enumFromStepN
enumFromToEach :: Int -> Vector (Int,Int) -> Vector Int
{-# INLINE_U enumFromToEach #-}
enumFromToEach n = unstream . enumFromToEachS n . stream
enumFromStepLenEach :: Int -> Vector Int -> Vector Int -> Vector Int -> Vector Int
{-# INLINE_U enumFromStepLenEach #-}
enumFromStepLenEach len starts steps lens
= unstream $ enumFromStepLenEachS len $ stream $ V.zip3 starts steps lens
random :: (Unbox a, R.Random a, R.RandomGen g) => Int -> g -> Vector a
{-# INLINE_U random #-}
random n = unstream . randomS n
randomR :: (Unbox a, R.Random a, R.RandomGen g) => Int -> (a,a) -> g -> Vector a
{-# INLINE_U randomR #-}
randomR n r = unstream . randomRS n r
randomS :: (R.RandomGen g, R.Random a) => Int -> g -> S.Stream a
{-# INLINE_STREAM randomS #-}
randomS n g = Stream step (g,n) (Exact n)
where
{-# INLINE step #-}
step (g,0) = return Done
step (g,n) = let (x,g') = R.random g
in return $ Yield x (g',n-1)
randomRS :: (R.RandomGen g, R.Random a) => Int -> (a,a) -> g -> S.Stream a
{-# INLINE_STREAM randomRS #-}
randomRS n r g = Stream step (g,n) (Exact n)
where
{-# INLINE step #-}
step (g,0) = return Done
step (g,n) = let (x,g') = R.randomR r g
in return $ Yield x (g',n-1)
mdrop :: Unbox a => Int -> MVector s a -> MVector s a
{-# INLINE mdrop #-}
mdrop = M.drop
mslice :: Unbox a => Int -> Int -> MVector s a -> MVector s a
{-# INLINE mslice #-}
mslice = M.slice
hGetStorable :: forall a. Storable a => Handle -> IO (Storable.Vector a)
hGetStorable h =
alloca $ \iptr ->
do
hGetBuf h iptr (sizeOf (undefined :: Int))
n <- peek iptr
v <- MStorable.unsafeNew n
let bytes = sizeOf (undefined :: a) * MStorable.length v
r <- MStorable.unsafeWith v $ \ptr -> hGetBuf h ptr bytes
Storable.unsafeFreeze (MStorable.take r v)
hPutStorable :: forall a. Storable a => Handle -> Storable.Vector a -> IO ()
hPutStorable h xs =
alloca $ \iptr ->
do
poke iptr n
hPutBuf h iptr (sizeOf n)
Storable.unsafeWith xs $ \ptr ->
do
hPutBuf h ptr (sizeOf (undefined :: a) * n)
return ()
where
!n = Storable.length xs
class Unbox a => UIO a where
hPut :: Handle -> Vector a -> IO ()
hGet :: Handle -> IO (Vector a)
primPut :: (Unbox a, Storable a) => Handle -> Vector a -> IO ()
{-# INLINE primPut #-}
primPut h = hPutStorable h . Storable.convert
primGet :: (Unbox a, Storable a) => Handle -> IO (Vector a)
{-# INLINE primGet #-}
primGet = fmap convert . hGetStorable
instance UIO Int where
{-# INLINE hPut #-}
hPut = primPut
{-# INLINE hGet #-}
hGet = primGet
instance UIO Double where
{-# INLINE hPut #-}
hPut = primPut
{-# INLINE hGet #-}
hGet = primGet
instance (UIO a, UIO b) => UIO (a,b) where
{-# INLINE hPut #-}
hPut h xs = case V.unzip xs of
(ys,zs) -> do hPut h ys
hPut h zs
{-# INLINE hGet #-}
hGet h = do xs <- hGet h
ys <- hGet h
return (V.zip xs ys)