{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeFamilies #-}
module Data.Dense.Base
(
Array (..)
, Boxed
, vector
, values
, unsafeThaw
, unsafeFreeze
, Delayed (..)
, delay
, manifest
, genDelayed
, indexDelayed
, Focused (..)
) where
#if __GLASGOW_HASKELL__ <= 708
import Control.Applicative (pure, (*>))
import Data.Foldable (Foldable)
import Data.Monoid (Monoid, mappend, mempty)
#endif
import Control.Applicative (liftA2)
import Control.Comonad
import Control.Comonad.Store
import Control.DeepSeq
import Control.Lens
import Control.Lens.Internal (noEffect)
import Control.Monad (guard, liftM)
import Control.Monad.Primitive
import Data.Binary as Binary
import Data.Bytes.Serial
import Data.Data
import qualified Data.Foldable as F
import Data.Functor.Apply
import Data.Functor.Classes
import Data.Functor.Extend
import Data.Hashable
import Data.Serialize as Cereal
import Data.Traversable (for)
import qualified Data.Vector as B
import Data.Vector.Generic (Vector)
import qualified Data.Vector.Generic as G
import Data.Vector.Generic.Lens (vectorTraverse)
import qualified Data.Vector.Generic.Mutable as GM
import qualified Data.Vector.Generic.New as New
import Linear hiding (vector)
import Text.ParserCombinators.ReadPrec (readS_to_Prec)
import qualified Text.Read as Read
import Data.Dense.Index
import Data.Dense.Mutable (MArray (..))
import Control.Concurrent (forkOn, getNumCapabilities,
newEmptyMVar, putMVar,
takeMVar)
import System.IO.Unsafe (unsafePerformIO)
import Prelude hiding (null, replicate,
zipWith, zipWith3)
import GHC.Types (SPEC (..))
data Array v f a = Array !(Layout f) !(v a)
deriving Typeable
values :: (Shape f, Vector v a, Vector w b)
=> IndexedTraversal (f Int) (Array v f a) (Array w f b) a b
values = \f arr -> reindexed (shapeFromIndex $ extent arr) (vector . vectorTraverse) f arr
{-# INLINE values #-}
vector :: (Vector v a, Vector w b) => IndexedLens (Layout f) (Array v f a) (Array w f b) (v a) (w b)
vector f (Array l v) =
indexed f l v <&> \w ->
sizeMissmatch (G.length v) (G.length w)
("vector: trying to replace vector of length " ++ show (G.length v) ++ " with one of length " ++ show (G.length w))
$ Array l w
{-# INLINE vector #-}
unsafeFreeze :: (PrimMonad m, Vector v a)
=> MArray (G.Mutable v) f (PrimState m) a -> m (Array v f a)
unsafeFreeze (MArray l mv) = Array l `liftM` G.unsafeFreeze mv
{-# INLINE unsafeFreeze #-}
unsafeThaw :: (PrimMonad m, Vector v a)
=> Array v f a -> m (MArray (G.Mutable v) f (PrimState m) a)
unsafeThaw (Array l v) = MArray l `liftM` G.unsafeThaw v
{-# INLINE unsafeThaw #-}
instance Shape f => HasLayout f (Array v f a) where
layout f (Array l v) = f l <&> \l' ->
sizeMissmatch (shapeSize l) (shapeSize l')
("layout (Array): trying to replace shape " ++ showShape l ++ " with " ++ showShape l')
$ Array l' v
{-# INLINE layout #-}
instance (Vector v a, Eq1 f, Eq a) => Eq (Array v f a) where
Array l1 v1 == Array l2 v2 = eq1 l1 l2 && G.eq v1 v2
{-# INLINE (==) #-}
instance (Vector v a, Show1 f, Show a) => Show (Array v f a) where
showsPrec p (Array l v2) = showParen (p > 10) $
showString "Array " . showsPrec1 11 l . showChar ' ' . G.showsPrec 11 v2
type instance Index (Array v f a) = f Int
type instance IxValue (Array v f a) = a
instance (Shape f, Vector v a) => Ixed (Array v f a) where
ix x f (Array l v)
| shapeInRange l x = f (G.unsafeIndex v i) <&>
\a -> Array l (G.modify (\mv -> GM.unsafeWrite mv i a) v)
where i = shapeToIndex l x
ix _ _ arr = pure arr
{-# INLINE ix #-}
instance (Vector v a, Vector v b) => Each (Array v f a) (Array v f b) a b where
each = vector . vectorTraverse
{-# INLINE each #-}
instance (Shape f, Vector v a) => AsEmpty (Array v f a) where
_Empty = nearly (Array zero G.empty) (F.all (==0) . extent)
{-# INLINE _Empty #-}
instance (Vector v a, Read1 f, Read a) => Read (Array v f a) where
readPrec = Read.parens $ Read.prec 10 $ do
Read.Ident "Array" <- Read.lexP
l <- readS_to_Prec readsPrec1
v <- G.readPrec
return $ Array l v
instance (NFData (f Int), NFData (v a)) => NFData (Array v f a) where
rnf (Array l v) = rnf l `seq` rnf v
{-# INLINE rnf #-}
type Boxed v = v ~ B.Vector
instance Boxed v => Functor (Array v f) where
fmap = over vector . fmap
{-# INLINE fmap #-}
instance Boxed v => F.Foldable (Array v f) where
foldMap f = F.foldMap f . view vector
{-# INLINE foldMap #-}
instance Boxed v => Traversable (Array v f) where
traverse = each
{-# INLINE traverse #-}
#if (MIN_VERSION_transformers(0,5,0)) || !(MIN_VERSION_transformers(0,4,0))
instance (Boxed v, Eq1 f) => Eq1 (Array v f) where
liftEq f (Array l1 v1) (Array l2 v2) = eq1 l1 l2 && G.and (G.zipWith f v1 v2)
{-# INLINE liftEq #-}
instance (Boxed v, Read1 f) => Read1 (Array v f) where
liftReadsPrec _ f = readsData $ readsBinaryWith readsPrec1 (const f) "Array" (\c l -> Array c (G.fromList l))
{-# INLINE liftReadsPrec #-}
#else
instance (Boxed v, Eq1 f) => Eq1 (Array v f) where
eq1 = (==)
{-# INLINE eq1 #-}
instance (Boxed v, Read1 f) => Read1 (Array v f) where
readsPrec1 = readsPrec
{-# INLINE readsPrec1 #-}
#endif
instance (Boxed v, Shape f) => FunctorWithIndex (f Int) (Array v f)
instance (Boxed v, Shape f) => FoldableWithIndex (f Int) (Array v f)
instance (Boxed v, Shape f) => TraversableWithIndex (f Int) (Array v f) where
itraverse = itraverseOf values
{-# INLINE itraverse #-}
itraversed = values
{-# INLINE itraversed #-}
instance (Boxed v, Shape f, Serial1 f) => Serial1 (Array v f) where
serializeWith putF (Array l v) = do
serializeWith serialize l
F.traverse_ putF v
deserializeWith = genGet (deserializeWith deserialize)
type instance G.Mutable (Array v f) = MArray (G.Mutable v) f
instance (Vector v a, f ~ V1) => Vector (Array v f) a where
{-# INLINE basicUnsafeFreeze #-}
{-# INLINE basicUnsafeThaw #-}
{-# INLINE basicLength #-}
{-# INLINE basicUnsafeSlice #-}
{-# INLINE basicUnsafeIndexM #-}
basicUnsafeFreeze = unsafeFreeze
basicUnsafeThaw = unsafeThaw
basicLength (Array (V1 n) _) = n
basicUnsafeSlice i n (Array _ v) = Array (V1 n) $ G.basicUnsafeSlice i n v
basicUnsafeIndexM (Array _ v) = G.basicUnsafeIndexM v
instance (Vector v a, Shape f, Serial1 f, Serial a) => Serial (Array v f a) where
serialize (Array l v) = do
serializeWith serialize l
traverseOf_ vectorTraverse serialize v
{-# INLINE serialize #-}
deserialize = genGet (deserializeWith deserialize) deserialize
{-# INLINE deserialize #-}
instance (Vector v a, Shape f, Binary (f Int), Binary a) => Binary (Array v f a) where
put (Array l v) = do
Binary.put l
traverseOf_ vectorTraverse Binary.put v
{-# INLINE put #-}
get = genGet Binary.get Binary.get
{-# INLINE get #-}
instance (Vector v a, Shape f, Serialize (f Int), Serialize a) => Serialize (Array v f a) where
put (Array l v) = do
Cereal.put l
traverseOf_ vectorTraverse Cereal.put v
{-# INLINE put #-}
get = genGet Cereal.get Cereal.get
{-# INLINE get #-}
genGet :: Monad m => (Vector v a, Shape f) => m (f Int) -> m a -> m (Array v f a)
genGet getL getA = do
l <- getL
let n = shapeSize l
nv0 = New.create (GM.new n)
f acc i = (\a -> New.modify (\mv -> GM.write mv i a) acc) `liftM` getA
nv <- F.foldlM f nv0 [0 .. n - 1]
return $! Array l (G.new nv)
{-# INLINE genGet #-}
instance (Vector v a, Foldable f, Hashable a) => Hashable (Array v f a) where
hashWithSalt s (Array l v) = G.foldl' hashWithSalt s' v
where s' = F.foldl' hashWithSalt s l
{-# INLINE hashWithSalt #-}
deriving instance (Typeable f, Typeable v, Typeable a, Data (f Int), Data (v a)) => Data (Array v f a)
data Delayed f a = Delayed !(Layout f) (f Int -> a)
deriving (Typeable, Functor)
delay :: (Vector v a, Shape f) => Array v f a -> Delayed f a
delay (Array l v) = Delayed l (G.unsafeIndex v . shapeToIndex l)
{-# INLINE delay #-}
instance Shape f => HasLayout f (Delayed f a) where
layout f (Delayed l ixF) = f l <&> \l' ->
sizeMissmatch (shapeSize l) (shapeSize l')
("layout (Delayed): trying to replace shape " ++ showShape l ++ " with " ++ showShape l')
$ Delayed l' ixF
{-# INLINE layout #-}
instance Shape f => Foldable (Delayed f) where
foldr f b (Delayed l ixF) = foldrOf shapeIndexes (\x -> f (ixF x)) b l
{-# INLINE foldr #-}
foldMap = foldDelayed . const
#if __GLASGOW_HASKELL__ >= 710
length = size
{-# INLINE length #-}
#endif
instance (Shape f, Show1 f, Show a) => Show (Delayed f a) where
showsPrec p arr@(Delayed l _) = showParen (p > 10) $
showString "Delayed " . showsPrec1 11 l . showChar ' ' . showsPrec 11 (F.toList arr)
instance Shape f => Traversable (Delayed f) where
traverse f arr = delay <$> traversed f (manifest arr)
instance Shape f => Apply (Delayed f) where
{-# INLINE (<.>) #-}
{-# INLINE (<. ) #-}
{-# INLINE ( .>) #-}
(<.>) = liftI2 id
(<. ) = liftI2 const
( .>) = liftI2 (const id)
instance Shape f => Additive (Delayed f) where
zero = _Empty # ()
{-# INLINE zero #-}
liftU2 f (Delayed l ixF) (Delayed k ixG)
| l `eq1` k = Delayed l (liftA2 f ixF ixG)
| F.all (>= EQ) cmp = Delayed l $ \x ->
if | shapeInRange l x -> liftA2 f ixF ixG x
| otherwise -> ixF x
| F.all (<= EQ) cmp = Delayed k $ \x ->
if | shapeInRange k x -> liftA2 f ixF ixG x
| otherwise -> ixG x
| otherwise = Delayed (shapeIntersect l k) $ liftA2 f ixF ixG
where cmp = liftI2 compare l k
liftI2 f (Delayed l ixF) (Delayed k ixG) = Delayed (shapeIntersect l k) $ liftA2 f ixF ixG
{-# INLINE liftI2 #-}
instance Shape f => Metric (Delayed f)
instance FunctorWithIndex (f Int) (Delayed f) where
imap f (Delayed l ixF) = Delayed l $ \x -> f x (ixF x)
{-# INLINE imap #-}
instance Shape f => FoldableWithIndex (f Int) (Delayed f) where
ifoldr f b (Delayed l ixF) = foldrOf shapeIndexes (\x -> f x (ixF x)) b l
{-# INLINE ifoldr #-}
ifolded = ifoldring ifoldr
{-# INLINE ifolded #-}
ifoldMap = foldDelayed
{-# INLINE ifoldMap #-}
instance Shape f => TraversableWithIndex (f Int) (Delayed f) where
itraverse f arr = delay <$> itraverse f (manifest arr)
{-# INLINE itraverse #-}
instance Shape f => Each (Delayed f a) (Delayed f b) a b where
each = traversed
{-# INLINE each #-}
instance Shape f => AsEmpty (Delayed f a) where
_Empty = nearly (Delayed zero (error "empty delayed array"))
(\(Delayed l _) -> F.all (==0) l)
{-# INLINE _Empty #-}
type instance Index (Delayed f a) = f Int
type instance IxValue (Delayed f a) = a
instance Shape f => Ixed (Delayed f a) where
ix x f arr@(Delayed l ixF)
| shapeInRange l x = f (ixF x) <&> \a ->
let g y | eq1 x y = a
| otherwise = ixF x
in Delayed l g
| otherwise = pure arr
{-# INLINE ix #-}
indexDelayed :: Shape f => Delayed f a -> f Int -> a
indexDelayed (Delayed l ixF) x =
boundsCheck l x $ ixF x
{-# INLINE indexDelayed #-}
foldDelayed :: (Shape f, Monoid m) => (f Int -> a -> m) -> (Delayed f a) -> m
foldDelayed f (Delayed l ixF) = unsafePerformIO $ do
childs <- for [0 .. threads - 1] $ \c -> do
child <- newEmptyMVar
_ <- forkOn c $ do
let k | c == threads - 1 = q + r
| otherwise = q
x = c * q
m = x + k
go i (Just s) acc
| i >= m = acc
| otherwise = let !acc' = acc `mappend` f s (ixF s)
in go (i+1) (shapeStep l s) acc'
go _ Nothing acc = acc
putMVar child $! go x (Just $ shapeFromIndex l x) mempty
return child
F.fold <$> for childs takeMVar
where
!n = shapeSize l
!(q, r) = n `quotRem` threads
!threads = unsafePerformIO getNumCapabilities
{-# INLINE foldDelayed #-}
manifest :: (Vector v a, Shape f) => Delayed f a -> Array v f a
manifest (Delayed l ixF) = Array l v
where
!v = unsafePerformIO $! do
mv <- GM.new n
childs <- for [0 .. threads - 1] $ \c -> do
child <- newEmptyMVar
_ <- forkOn c $ do
let k | c == threads - 1 = q + r
| otherwise = q
x = c * q
iforOf_ (linearIndexesBetween x (x+k)) l $ \i s ->
GM.unsafeWrite mv i (ixF s)
putMVar child ()
return child
F.for_ childs takeMVar
G.unsafeFreeze mv
!n = shapeSize l
!(q, r) = n `quotRem` threads
!threads = unsafePerformIO getNumCapabilities
{-# INLINE manifest #-}
linearIndexesBetween :: Shape f => Int -> Int -> IndexedFold Int (Layout f) (f Int)
linearIndexesBetween i0 k g l = go SPEC i0 (Just $ shapeFromIndex l i0)
where
go !_ i (Just x) = indexed g i x *> go SPEC (i+1) (guard (i+1 < k) *> shapeStep l x)
go !_ _ _ = noEffect
{-# INLINE linearIndexesBetween #-}
genDelayed :: Layout f -> (f Int -> a) -> Delayed f a
genDelayed = Delayed
{-# INLINE genDelayed #-}
data Focused f a = Focused !(f Int) !(Delayed f a)
deriving (Typeable, Functor)
instance Shape f => HasLayout f (Focused f a) where
layout f (Focused x (Delayed l ixF)) = f l <&> \l' ->
sizeMissmatch (shapeSize l) (shapeSize l')
("layout (Focused): trying to replace shape " ++ showShape l ++ " with " ++ showShape l')
$ Focused x (Delayed l' ixF)
{-# INLINE layout #-}
instance Shape f => Comonad (Focused f) where
{-# INLINE extract #-}
{-# INLINE extend #-}
extract (Focused x d) = indexDelayed d x
extend f (Focused x d@(Delayed l _)) =
Focused x (genDelayed l $ \i -> f (Focused i d))
instance Shape f => Extend (Focused f) where
{-# INLINE extended #-}
extended = extend
instance Shape f => ComonadStore (f Int) (Focused f) where
{-# INLINE pos #-}
{-# INLINE peek #-}
{-# INLINE peeks #-}
{-# INLINE seek #-}
{-# INLINE seeks #-}
pos (Focused x _) = x
peek x (Focused _ d) = indexDelayed d x
peeks f (Focused x d) = indexDelayed d (f x)
seek x (Focused _ d) = Focused x d
seeks f (Focused x d) = Focused (f x) d
instance (Shape f, Show1 f, Show a) => Show (Focused f a) where
showsPrec p (Focused l d) = showParen (p > 10) $
showString "Focused " . showsPrec1 11 l . showChar ' ' . showsPrec 11 d
type instance Index (Focused f a) = f Int
type instance IxValue (Focused f a) = a
instance Shape f => Foldable (Focused f) where
foldr f b (Focused _ d) = F.foldr f b d
{-# INLINE foldr #-}
foldMap f (Focused _ d) = F.foldMap f d
{-# INLINE foldMap #-}
#if __GLASGOW_HASKELL__ >= 710
length = size
{-# INLINE length #-}
#endif
instance Shape f => Traversable (Focused f) where
traverse f (Focused u d) = Focused u <$> traverse f d
{-# INLINE traverse #-}
instance Shape f => FunctorWithIndex (f Int) (Focused f) where
imap f (Focused u d) = Focused u (imap (f . (^-^ u)) d)
{-# INLINE imap #-}
instance Shape f => FoldableWithIndex (f Int) (Focused f) where
ifoldr f b (Focused u d) = ifoldr (f . (^-^ u)) b d
{-# INLINE ifoldr #-}
ifolded = ifoldring ifoldr
{-# INLINE ifolded #-}
ifoldMap f (Focused u d) = ifoldMap (f . (^-^) u) d
{-# INLINE ifoldMap #-}
instance Shape f => TraversableWithIndex (f Int) (Focused f) where
itraverse f (Focused u d) = Focused u <$> itraverse (f . (^-^ u)) d
{-# INLINE itraverse #-}
instance Shape f => Ixed (Focused f a) where
ix i f (Focused u d) = Focused u <$> ix (i ^-^ u) f d
{-# INLINE ix #-}