{-# LANGUAGE CPP #-} {-# LANGUAGE BangPatterns #-} {-# LANGUAGE TypeOperators #-} ----------------------------------------------------------------------------- -- | -- Module : Data.Array.Vector.Strict.Basics -- Copyright : (c) [2001..2002] Manuel M T Chakravarty & Gabriele Keller -- (c) 2006 Manuel M T Chakravarty & Roman Leshchinskiy -- License : see libraries/ndp/LICENSE -- -- Maintainer : Roman Leshchinskiy -- Stability : internal -- Portability : portable -- -- Description --------------------------------------------------------------- -- -- Basic operations on flat unlifted arrays. -- -- Todo ---------------------------------------------------------------------- -- #include "fusion-phases.h" module Data.Array.Vector.Strict.Basics where import Data.Array.Vector.Stream import Data.Array.Vector.UArr hiding (lengthU, indexU) import qualified Data.Array.Vector.UArr as Prim (lengthU, indexU) import Data.Array.Vector.Strict.Stream import Data.Array.Vector.Prim.Debug import Data.Array.Vector.Prim.Hyperstrict import GHC.ST import Debug.Trace ------------------------------------------------------------------------ instance (Eq e, UA e) => Eq (UArr e) where (==) = eqU -- not really fusible {-# INLINE_U eqU #-} eqU :: (Eq e, UA e) => UArr e -> UArr e -> Bool eqU a1 a2 = lengthU a1 == lengthU a2 && foldlU cmp True (zipU a1 a2) where cmp r (e1 :*: e2) = e1 == e2 && r ------------------------------------------------------------------------ -- XXX general rule: -- If we have direct implementations with better complexity than streams: -- -- length, index, take, drop -- -- Then use the direct version -- | /O(1)/, 'length' returns the length of a UArr as an 'Int'. lengthU :: UA e => UArr e -> Int lengthU = foldlU (const . (+1)) 0 -- lengthU = Prim.lengthU {-# INLINE_U lengthU #-} {- Unfused version: $ time ./length 100000000 ./length 1.10s user 1.13s system 91% cpu 2.433 total Fusible version: 100000000 ./length 0.31s user 0.00s system 97% cpu 0.318 total -} -- lengthU_stream :: UA e => UArr e -> Int -- {-# INLINE lengthU_stream #-} -- lengthU is reexported from UArr -- |Test whether the given array is empty -- nullU :: UA e => UArr e -> Bool nullU = nullS . streamU -- better code if we short circuit {-# INLINE_U nullU #-} -- nullU = (== 0) . lengthU -- |Yield an empty array -- emptyU :: UA e => UArr e emptyU = unstreamU emptyS {-# INLINE_U emptyU #-} -- emptyU = newU 0 (const $ return ()) -- |Yield a singleton array -- singletonU :: UA e => e -> UArr e {-# INLINE_U singletonU #-} singletonU = unstreamU . singletonS -- |Prepend an element to an array -- consU :: UA e => e -> UArr e -> UArr e {-# INLINE_U consU #-} consU x = unstreamU . consS x . streamU -- |Append an element to an array -- snocU :: UA e => UArr e -> e -> UArr e {-# INLINE_U snocU #-} snocU s x = unstreamU (snocS (streamU s) x) -- unitsU is reexported from Loop -- |Yield an array where all elements contain the same value -- replicateU :: UA e => Int -> e -> UArr e {-# INLINE_U replicateU #-} replicateU n e = unstreamU (replicateS n e) replicateEachU :: UA e => Int -> UArr Int -> UArr e -> UArr e {-# INLINE_U replicateEachU #-} replicateEachU n ns es = unstreamU . replicateEachS n $ zipS (streamU ns) (streamU es) -- |Array indexing -- indexU :: UA e => UArr e -> Int -> e indexU arr n = indexS (streamU arr) n {-# INLINE_U indexU #-} headU :: UA e => UArr e -> e headU = headS . streamU {-# INLINE_U headU #-} lastU :: UA e => UArr e -> e lastU = foldl1U (flip const) {-# INLINE lastU #-} -- |Concatenate two arrays -- appendU :: UA e => UArr e -> UArr e -> UArr e {-# INLINE_U appendU #-} a1 `appendU` a2 = unstreamU (streamU a1 +++ streamU a2) initU :: UA e => UArr e -> UArr e -- not unboxing initU = unstreamU . initS . streamU {-# INLINE initU #-} -- |Repeat an array @n@ times -- repeatU :: UA e => Int -> UArr e -> UArr e repeatU n = unstreamU . repS n {-# INLINE_U repeatU #-} -- No work duplicated repS :: UA e => Int -> UArr e -> Stream e {-# INLINE_STREAM repS #-} repS k xs = Stream next (0 :*: k) (k*n) where n = lengthU xs {-# INLINE next #-} next (i :*: 0) = Done next (i :*: k) | i == n = Skip (0 :*: k-1) | otherwise = Yield (xs `Prim.indexU` i) (i+1 :*: k) -- |Indexing -- --------- -- |Associate each element of the array with its index -- indexedU :: UA e => UArr e -> UArr (Int :*: e) {-# INLINE_U indexedU #-} indexedU = unstreamU . indexedS . streamU -- |Conversion -- ----------- -- |Turn a list into a parallel array -- toU :: UA e => [e] -> UArr e {-# INLINE_U toU #-} toU = unstreamU . toStream -- |Collect the elements of a parallel array in a list -- fromU :: UA e => UArr e -> [e] {-# INLINE_U fromU #-} fromU a = [a `Prim.indexU` i | i <- [0..lengthU a - 1]] ------------------------------------------------------------------------ here s = "Data.Array.Vector.Strict.Combinators." ++ s -- |Map a function over an array -- mapU :: (UA e, UA e') => (e -> e') -> UArr e -> UArr e' {-# INLINE_U mapU #-} mapU f = unstreamU . mapS f . streamU -- |Extract all elements from an array that meet the given predicate -- filterU :: UA e => (e -> Bool) -> UArr e -> UArr e {-# INLINE_U filterU #-} filterU p = unstreamU . filterS p . streamU -- |Extract all elements from an array according to a given flag array -- packU:: UA e => UArr e -> UArr Bool -> UArr e {-# INLINE_U packU #-} packU xs = fstU . filterU sndS . zipU xs -- |Array reduction proceeding from the left -- foldlU :: UA a => (b -> a -> b) -> b -> UArr a -> b {-# INLINE_U foldlU #-} foldlU f z = foldS f z . streamU -- |Array reduction proceeding from the left for non-empty arrays -- -- FIXME: Rewrite for 'Stream's. -- -- foldl1U :: UA a => (a -> a -> a) -> UArr a -> a -- {-# INLINE_U foldl1U #-} -- foldl1U f arr = checkNotEmpty (here "foldl1U") (lengthU arr) $ -- foldlU f (arr `Prim.indexU` 0) (sliceU arr 1 (lengthU arr - 1)) foldl1U :: UA a => (a -> a -> a) -> UArr a -> a foldl1U f = foldl1S f . streamU {-# INLINE foldl1U #-} foldl1MaybeU :: UA a => (a -> a -> a) -> UArr a -> MaybeS a {-# INLINE_U foldl1MaybeU #-} foldl1MaybeU f = fold1MaybeS f . streamU -- |Array reduction that requires an associative combination function with its -- unit -- foldU :: UA a => (a -> a -> a) -> a -> UArr a -> a {-# INLINE_U foldU #-} foldU = foldlU fold1MaybeU :: UA a => (a -> a -> a) -> UArr a -> MaybeS a {-# INLINE_U fold1MaybeU #-} fold1MaybeU = foldl1MaybeU -- |Reduction of a non-empty array which requires an associative combination -- function -- fold1U :: UA a => (a -> a -> a) -> UArr a -> a {-# INLINE_U fold1U #-} fold1U = foldl1U -- |Prefix scan proceedings from left to right -- scanlU :: (UA a, UA b) => (b -> a -> b) -> b -> UArr a -> UArr b {-# INLINE_U scanlU #-} scanlU f z = unstreamU . scanS f z . streamU -- |Prefix scan of a non-empty array proceeding from left to right -- scanl1U :: UA a => (a -> a -> a) -> UArr a -> UArr a {-# INLINE_U scanl1U #-} scanl1U f arr = checkNotEmpty (here "scanl1U") (lengthU arr) $ unstreamU (scan1S f (streamU arr)) -- |Prefix scan proceeding from left to right that needs an associative -- combination function with its unit -- scanU :: UA a => (a -> a -> a) -> a -> UArr a -> UArr a {-# INLINE_U scanU #-} scanU = scanlU -- |Prefix scan of a non-empty array proceeding from left to right that needs -- an associative combination function -- scan1U :: UA a => (a -> a -> a) -> UArr a -> UArr a {-# INLINE_U scan1U #-} scan1U = scanl1U scanResU :: UA a => (a -> a -> a) -> a -> UArr a -> UArr a :*: a {-# INLINE_U scanResU #-} scanResU f z = unstreamScan f z . streamU unstreamScan :: UA a => (a -> a -> a) -> a -> Stream a -> UArr a :*: a {-# INLINE_STREAM unstreamScan #-} unstreamScan f z st@(Stream _ _ n) = newDynResU n (\marr -> unstreamScanM marr f z st) unstreamScanM :: UA a => MUArr a s -> (a -> a -> a) -> a -> Stream a -> ST s (Int :*: a) {-# INLINE_U unstreamScanM #-} unstreamScanM marr f z (Stream next s n) = fill s z 0 where fill s !z !i = case next s of Done -> return (i :*: z) Skip s' -> s' `seq` fill s' z i Yield x s' -> s' `seq` do writeMU marr i z fill s' (f z x) (i+1) -- |Accumulating map from left to right. Does not return the accumulator. -- -- FIXME: Naming inconsistent with lists. -- mapAccumLU :: (UA a, UA b) => (c -> a -> c :*: b) -> c -> UArr a -> UArr b {-# INLINE_U mapAccumLU #-} mapAccumLU f z = unstreamU . mapAccumS f z . streamU -- zipU is re-exported from UArr -- | -- zip3U :: (UA e1, UA e2, UA e3) => UArr e1 -> UArr e2 -> UArr e3 -> UArr (e1 :*: e2 :*: e3) {-# INLINE_U zip3U #-} zip3U a1 a2 a3 = (a1 `zipU` a2) `zipU` a3 -- | zipWithU :: (UA a, UA b, UA c) => (a -> b -> c) -> UArr a -> UArr b -> UArr c {-# INLINE_U zipWithU #-} zipWithU f a1 a2 = unstreamU (zipWithS f (streamU a1) (streamU a2)) -- | zipWith3U :: (UA a, UA b, UA c, UA d) => (a -> b -> c -> d) -> UArr a -> UArr b -> UArr c -> UArr d {-# INLINE_U zipWith3U #-} zipWith3U f a1 a2 a3 = unstreamU (zipWith3S f (streamU a1) (streamU a2) (streamU a3)) -- unzipU is re-exported from UArr -- | unzip3U :: (UA e1, UA e2, UA e3) => UArr (e1 :*: e2 :*: e3) -> (UArr e1 :*: UArr e2 :*: UArr e3) {-# INLINE_U unzip3U #-} unzip3U a = let (a12 :*: a3) = unzipU a (a1 :*: a2) = unzipU a12 in (a1 :*: a2 :*: a3) -- fstU and sndU reexported from UArr -- | combineU :: UA a => UArr Bool -> UArr a -> UArr a -> UArr a {-# INLINE_U combineU #-} combineU f a1 a2 = checkEq (here "combineU") ("flag length not equal to sum of arg length") (lengthU f) (lengthU a1 + lengthU a2) $ trace ("combineU:\n\t" ++ show (lengthU f) ++ "\n\t" ++ show (lengthU a1) ++ "\n\t" ++ show (lengthU a2) ++ "\n") unstreamU (combineS (streamU f) (streamU a1) (streamU a2)) ------------------------------------------------------------------------ -- sliceU reexported from UArr -- {-# INLINE_U extractU #-} -- extractU :: UA a => UArr a -> Int -> Int -> UArr a -- extractU arr i n = newU n $ \marr -> copyMU marr 0 (sliceU arr i n) tailU :: UA e => UArr e -> UArr e tailU = unstreamU . tailS . streamU {-# INLINE_U tailU #-} dropU :: UA e=> Int -> UArr e -> UArr e dropU n = unstreamU . dropS n . streamU {-# INLINE dropU #-} takeU :: UA e=> Int -> UArr e -> UArr e takeU n = unstreamU . takeS n . streamU {-# INLINE takeU #-} -- |Split an array into two halves at the given index -- splitAtU :: UA e => Int -> UArr e -> (UArr e, UArr e) splitAtU n a = (takeU n a, dropU n a) {-# INLINE splitAtU #-} {- -- |Yield the tail of an array -- tailU :: UA e => UArr e -> UArr e {-# INLINE_U tailU #-} tailU = unstreamU . tailS . streamU -- |Extract a prefix of an array -- takeU :: UA e=> Int -> UArr e -> UArr e {-# INLINE_U takeU #-} takeU n a = extractU a 0 n -- |Extract a suffix of an array -- dropU :: UA e => Int -> UArr e -> UArr e {-# INLINE_U dropU #-} dropU n a = let len = lengthU a in extractU a n (len - n) -- |Split an array into two halves at the given index -- splitAtU :: UA e => Int -> UArr e -> (UArr e, UArr e) {-# INLINE_U splitAtU #-} splitAtU n a = (takeU n a, dropU n a) -} ------------------------------------------------------------------------ -- | 'takeWhile', applied to a predicate @p@ and a UArr @xs@, -- returns the longest prefix (possibly empty) of @xs@ of elements that satisfy @p@. -- takeWhileU :: UA e => (e -> Bool) -> UArr e -> UArr e takeWhileU f = unstreamU . takeWhileS f . streamU {-# INLINE_U takeWhileU #-} -- | 'dropWhile' @p xs@ returns the suffix remaining after 'takeWhile' @p xs@. dropWhileU :: UA e => (e -> Bool) -> UArr e -> UArr e dropWhileU f = unstreamU . dropWhileS f . streamU {-# INLINE_U dropWhileU #-} ------------------------------------------------------------------------ -- ** Searching with a predicate -- | /O(n)/,/fusion/. The 'find' function takes a predicate and an array -- and returns the first element in the list matching the predicate, or -- 'Nothing' if there is no such element. findU :: UA a => (a -> Bool) -> UArr a -> Maybe a {-# INLINE_U findU #-} findU p = findS p . streamU -- | /O(n)/, /fusion/, The 'findIndex' function takes a predicate and an array and returns -- the index of the first element in the array satisfying the predicate, -- or 'Nothing' if there is no such element. -- findIndexU :: UA a => (a -> Bool) -> UArr a -> Maybe Int {-# INLINE_U findIndexU #-} findIndexU p = findIndexS p . streamU -- | /O(n)/,/fusion/. 'lookup' @key assocs@ looks up a key in an array -- of pairs treated as an association table. -- lookupU :: (Eq a, UA a, UA b) => a -> UArr (a :*: b) -> Maybe b {-# INLINE_U lookupU #-} lookupU p = lookupS p . streamU ------------------------------------------------------------------------ unfoldU :: UA a => Int -> (b -> MaybeS (a :*: b)) -> b -> UArr a {-# INLINE_U unfoldU #-} unfoldU n f z = unstreamU (unfoldS n f z)