uvector-0.1: Data/Array/Vector/Strict/Basics.hs
{-# 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 <rl@cse.unsw.edu.au>
-- 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)