{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE Rank2Types #-}
module Data.Histogram.Fill (
HistBuilder(..)
, (<<-)
, (<<-|)
, (<<?)
, (<<-$)
, (-<<)
, HBuilderM(..)
, feedOne
, freezeHBuilderM
, HBuilder(HBuilder)
, toHBuilderST
, toHBuilderIO
, toHBuilderM
, module Data.Histogram.Bin
, mkSimple
, mkWeighted
, mkMonoidal
, mkFoldBuilder
, mkSimpleG
, mkWeightedG
, mkMonoidalG
, mkFoldBuilderG
, mkFolder
, mkStatefulBuilder
, fillBuilder
, fillBuilderVec
, forceInt
, forceDouble
, forceFloat
, joinHBuilder
, joinHBuilderM
, treeHBuilderM
, treeHBuilder
) where
import Control.Applicative
import Control.Monad (when,liftM,liftM2)
import Control.Monad.ST
import Control.Monad.Primitive
import Data.Monoid (Monoid(..))
import Data.Semigroup (Semigroup(..))
import Data.Vector.Unboxed (Unbox)
import Data.Primitive.MutVar
import qualified Data.Vector.Generic as G
import qualified Data.Foldable as F
import qualified Data.Traversable as F
import Data.Histogram
import qualified Data.Histogram.Generic as H
import Data.Histogram.Bin
import Data.Histogram.ST
class HistBuilder h where
modifyOut :: (b -> b') -> h a b -> h a b'
modifyIn :: (a' -> a) -> h a b -> h a' b
fromContainer :: (forall m. Monad m => (a -> m ()) -> f a -> m ())
-> h a b -> h (f a) b
addCut :: (a -> Bool) -> h a b -> h a b
(<<-) :: HistBuilder h => h a b -> (a' -> a) -> h a' b
(<<-) = flip modifyIn
{-# INLINE (<<-) #-}
(<<-|) :: (HistBuilder h, F.Foldable f) => h a b -> (a' -> f a) -> h a' b
h <<-| f = fromContainer F.mapM_ h <<- f
{-# INLINE (<<-|) #-}
(<<?) :: HistBuilder h => h a b -> (a -> Bool) -> h a b
(<<?) = flip addCut
{-# INLINE (<<?) #-}
(<<-$) :: h a b -> (h a b -> h a' b) -> h a' b
h <<-$ f = f h
{-# INLINE (<<-$) #-}
(-<<) :: HistBuilder h => (b -> b') -> h a b -> h a b'
(-<<) = modifyOut
{-# INLINE (-<<) #-}
infixl 5 <<-
infixl 5 <<-|
infixl 5 <<?
infixl 5 <<-$
infixr 4 -<<
data HBuilderM m a b = HBuilderM { hbInput :: a -> m ()
, hbOutput :: m b
}
instance Monad m => HistBuilder (HBuilderM m) where
modifyIn f h = h { hbInput = hbInput h . f }
addCut f h = h { hbInput = \x -> when (f x) (hbInput h x) }
fromContainer fmapM_ h = h { hbInput = fmapM_ (hbInput h) }
modifyOut f h = h { hbOutput = f `liftM` hbOutput h }
instance Monad m => Functor (HBuilderM m a) where
fmap = modifyOut
instance Monad m => Applicative (HBuilderM m a) where
pure x = HBuilderM { hbInput = const $ return ()
, hbOutput = return x
}
f <*> g = HBuilderM { hbInput = \a -> hbInput f a >> hbInput g a
, hbOutput = do a <- hbOutput f
b <- hbOutput g
return (a b)
}
instance (Monad m, Semigroup b) => Semigroup (HBuilderM m a b) where
(<>) = liftA2 (<>)
{-# INLINE (<>) #-}
instance (Monad m, Monoid b) => Monoid (HBuilderM m a b) where
mempty = HBuilderM { hbInput = \_ -> return ()
, hbOutput = return mempty
}
mappend = liftA2 mappend
mconcat = fmap mconcat . F.sequenceA
{-# INLINE mempty #-}
{-# INLINE mappend #-}
{-# INLINE mconcat #-}
feedOne :: HBuilderM m a b -> a -> m ()
feedOne = hbInput
{-# INLINE feedOne #-}
freezeHBuilderM :: HBuilderM m a b -> m b
freezeHBuilderM = hbOutput
{-# INLINE freezeHBuilderM #-}
newtype HBuilder a b = HBuilder (forall m. PrimMonad m => m (HBuilderM m a b))
toHBuilderM :: PrimMonad m => HBuilder a b -> m (HBuilderM m a b)
{-# INLINE toHBuilderM #-}
toHBuilderM (HBuilder hb) = hb
toHBuilderST :: HBuilder a b -> ST s (HBuilderM (ST s) a b)
{-# INLINE toHBuilderST #-}
toHBuilderST = toHBuilderM
toHBuilderIO :: HBuilder a b -> IO (HBuilderM IO a b)
{-# INLINE toHBuilderIO #-}
toHBuilderIO = toHBuilderM
instance HistBuilder (HBuilder) where
modifyIn f (HBuilder h) = HBuilder (modifyIn f `liftM` h)
addCut f (HBuilder h) = HBuilder (addCut f `liftM` h)
fromContainer fmapM_ (HBuilder h) = HBuilder (fromContainer fmapM_ `liftM` h)
modifyOut f (HBuilder h) = HBuilder (modifyOut f `liftM` h)
instance Functor (HBuilder a) where
fmap = modifyOut
instance Applicative (HBuilder a) where
pure x = HBuilder (return $ pure x)
(HBuilder f) <*> (HBuilder g) = HBuilder $ liftM2 (<*>) f g
instance Semigroup b => Semigroup (HBuilder a b) where
(<>) = liftA2 (<>)
{-# INLINE (<>) #-}
instance Monoid b => Monoid (HBuilder a b) where
mempty = HBuilder (return mempty)
mappend = liftA2 mappend
mconcat = fmap mconcat . F.sequenceA
{-# INLINE mempty #-}
{-# INLINE mappend #-}
{-# INLINE mconcat #-}
mkSimple :: (Bin bin, Unbox val, Num val
) => bin -> HBuilder (BinValue bin) (Histogram bin val)
mkSimple = mkSimpleG
{-# INLINE mkSimple #-}
mkWeighted :: (Bin bin, Unbox val, Num val
) => bin -> HBuilder (BinValue bin,val) (Histogram bin val)
mkWeighted = mkWeightedG
{-# INLINE mkWeighted #-}
mkMonoidal :: (Bin bin, Unbox val, Monoid val
) => bin -> HBuilder (BinValue bin,val) (Histogram bin val)
mkMonoidal = mkMonoidalG
{-# INLINE mkMonoidal #-}
mkFoldBuilder :: (Bin bin, Unbox val)
=> bin
-> val
-> (val -> a -> val)
-> HBuilder (BinValue bin, a) (Histogram bin val)
{-# INLINE mkFoldBuilder #-}
mkFoldBuilder = mkFoldBuilderG
mkSimpleG :: (Bin bin, G.Vector v val, Num val
) => bin -> HBuilder (BinValue bin) (H.Histogram v bin val)
mkSimpleG bin = HBuilder $ do
acc <- newMHistogram 0 bin
return HBuilderM { hbInput = \x -> fill acc x (+) 1
, hbOutput = freezeHist acc
}
{-# INLINE mkSimpleG #-}
mkWeightedG :: (Bin bin, G.Vector v val, Num val
) => bin -> HBuilder (BinValue bin,val) (H.Histogram v bin val)
mkWeightedG bin = mkFoldBuilderG bin 0 (+)
{-# INLINE mkWeightedG #-}
mkMonoidalG :: (Bin bin, G.Vector v val, Monoid val
) => bin -> HBuilder (BinValue bin,val) (H.Histogram v bin val)
mkMonoidalG bin = mkFoldBuilderG bin mempty mappend
{-# INLINE mkMonoidalG #-}
mkFoldBuilderG :: (Bin bin, G.Vector v val)
=> bin
-> val
-> (val -> a -> val)
-> HBuilder (BinValue bin, a) (H.Histogram v bin val)
{-# INLINE mkFoldBuilderG #-}
mkFoldBuilderG bin x0 f = HBuilder $ do
acc <- newMHistogram x0 bin
return HBuilderM { hbInput = \(!x,!w) -> fill acc x f w
, hbOutput = freezeHist acc
}
mkFolder :: b -> (a -> b -> b) -> HBuilder a b
{-# INLINE mkFolder #-}
mkFolder a f = HBuilder $ do
ref <- newMutVar a
return HBuilderM { hbInput = \aa -> do b <- readMutVar ref
writeMutVar ref $! f aa b
, hbOutput = readMutVar ref
}
mkStatefulBuilder :: (a -> m ())
-> m b
-> HBuilderM m a b
{-# INLINE mkStatefulBuilder #-}
mkStatefulBuilder = HBuilderM
fillBuilder :: F.Foldable f => HBuilder a b -> f a -> b
fillBuilder hb xs =
runST $ do h <- toHBuilderST hb
F.mapM_ (feedOne h) xs
freezeHBuilderM h
fillBuilderVec :: G.Vector v a => HBuilder a b -> v a -> b
{-# INLINE fillBuilderVec #-}
fillBuilderVec hb vec =
runST $ do h <- toHBuilderST hb
G.mapM_ (feedOne h) vec
freezeHBuilderM h
forceInt :: H.Histogram v bin Int -> H.Histogram v bin Int
forceInt = id
forceDouble :: H.Histogram v bin Double -> H.Histogram v bin Double
forceDouble = id
forceFloat :: H.Histogram v bin Float -> H.Histogram v bin Float
forceFloat = id
joinHBuilderM :: (F.Traversable f, Monad m) => f (HBuilderM m a b) -> HBuilderM m a (f b)
joinHBuilderM = F.sequenceA
{-# INLINE joinHBuilderM #-}
{-# DEPRECATED joinHBuilderM "Use Data.Traversable.sequenceA instead" #-}
treeHBuilderM :: (Monad m, F.Traversable f) => f (HBuilderM m a b -> HBuilderM m a' b') -> HBuilderM m a b -> HBuilderM m a' (f b')
treeHBuilderM fs h = F.traverse ($ h) fs
{-# INLINE treeHBuilderM #-}
{-# DEPRECATED treeHBuilderM
"Use Data.Traversable.traverse. treeHBuilderM fs h = F.traverse ($ h) fs" #-}
joinHBuilder :: F.Traversable f => f (HBuilder a b) -> HBuilder a (f b)
joinHBuilder = F.sequenceA
{-# INLINE joinHBuilder #-}
{-# DEPRECATED joinHBuilder "Use Data.Traversable.sequenceA instead" #-}
treeHBuilder :: F.Traversable f => f (HBuilder a b -> HBuilder a' b') -> HBuilder a b -> HBuilder a' (f b')
treeHBuilder fs h = F.traverse ($ h) fs
{-# INLINE treeHBuilder #-}
{-# DEPRECATED treeHBuilder
"Use Data.Traversable.traverse. treeHBuilderM fs h = F.traverse ($ h) fs" #-}