module Feldspar.Vector.Push where
import qualified Prelude
import Feldspar hiding (sugar,desugar)
import qualified Feldspar.Vector as V
import Language.Syntactic (Syntactic(..))
data PushVector a where
Push :: ((Data Index -> a -> M ()) -> M ()) -> Data Length -> PushVector a
type PushVector1 a = PushVector (Data a)
instance Syntax a => Syntactic (PushVector a)
where
type Domain (PushVector a) = FeldDomain
type Internal (PushVector a) = [Internal a]
desugar = desugar . freezePush
sugar = thawPush . sugar
freezePush :: Syntax a => PushVector a -> Data [Internal a]
freezePush (Push _ 0) = parallel 0 $ Prelude.error "freezePush: indexing empty array"
freezePush (Push k l) = runMutableArray $ do
arr <- newArr_ l
k (\i a -> setArr arr i (resugar a))
return arr
freezeToVector :: Syntax a => PushVector a -> V.Vector a
freezeToVector = V.map resugar . V.thawVector . freezePush
thawPush :: Syntax a => Data [Internal a] -> PushVector a
thawPush arr = Push f (getLength arr)
where f k = forM (getLength arr) $ \ix ->
k ix (resugar (arr ! ix))
class Pushy arr where
toPush :: Syntax a => arr a -> PushVector a
instance Pushy PushVector where
toPush = id
instance Pushy V.Vector where
toPush vec = Push (\k -> forM (length vec) (\i -> k i (vec!i))) (length vec)
instance Functor PushVector where
fmap f (Push g l) = Push (\k -> g (\i a -> k i (f a))) l
(++) :: (Pushy arr1, Pushy arr2, Syntax a) => arr1 a -> arr2 a -> PushVector a
v1 ++ v2 = Push (\func -> f func >>
g (\i a -> func (l1 + i) a))
(l1 + l2)
where
Push f l1 = toPush v1
Push g l2 = toPush v2
unpair :: (Pushy arr, Syntax a) => arr (a,a) -> PushVector a
unpair = unpairWith everyOther
unpairWith :: (Pushy arr, Syntax a)
=> ((Data Index -> a -> M ()) -> Data Index -> (a,a) -> M ())
-> arr (a,a) -> PushVector a
unpairWith spread arr = Push (f . spread) (2*l)
where
Push f l = toPush arr
everyOther :: (Data Index -> a -> M b)
-> Data Index -> (a,a) -> M b
everyOther f = \ix (a1,a2) -> f (ix * 2) a1 >> f (ix * 2 + 1) a2
zipUnpair :: Syntax a => V.Vector a -> V.Vector a -> PushVector a
zipUnpair v1 v2 = unpair (V.zip v1 v2)
class Ixmap arr where
ixmap :: Syntax a => (Data Index -> Data Index) -> arr a -> arr a
instance Ixmap V.Vector where
ixmap f vec = V.indexed (length vec) (\i -> vec ! (f i))
instance Ixmap PushVector where
ixmap f (Push g l) = Push (\k -> g (\i a -> k (f i) a)) l
reverse :: (Ixmap arr, Len arr, Syntax a) =>
arr a -> arr a
reverse arr = ixmap (\ix -> length arr ix 1) arr
halve :: Syntax a => V.Vector a -> (V.Vector a, V.Vector a)
halve v = (V.indexed (l `div` 2) ixf
,V.indexed ((l+1) `div` 2) (\i -> ixf (i + (l `div` 2))))
where l = length v
ixf = (v!)
riffle :: Syntax a => V.Vector a -> PushVector a
riffle = unpair . uncurry V.zip . halve
class Len arr where
length :: arr a -> Data Length
instance Len V.Vector where
length = V.length
instance Len PushVector where
length (Push _ l) = l
chunk :: (Pushy arr1, Pushy arr2, Syntax b)
=> Data Length
-> (V.Vector a -> arr1 b)
-> (V.Vector a -> arr2 b)
-> V.Vector a
-> PushVector b
chunk c f g v = Push loop (noc * c)
++ toPush (g (V.drop (noc * c) v))
where l = length v
noc = l `div` c
loop func = forM noc $ \i ->
do let (Push k _) = toPush $ f (V.take c (V.drop (c*i) v))
k (\j a -> func (c*i + j) a)
scanl :: (Syntax a, Syntax b)
=> (a -> b -> a) -> a -> V.Vector b -> PushVector a
scanl f init v = Push g l
where
l = length v
g k = do s <- newRef init
forM l $ \ix -> do
modifyRef s (`f` (v ! ix))
getRef s >>= k ix
empty :: PushVector a
empty = Push (const (return ())) 0
flatten :: Syntax a => V.Vector (PushVector a) -> PushVector a
flatten v = Push f len
where len = V.sum (V.map length v)
f k = do l <- newRef 0
forM (length v) $ \i ->
do let (Push g m) = v ! i
n <- getRef l
g (\j a -> k (n + j) a)
setRef l (n+m)