packages feed

histogram-fill 0.1.0 → 0.2.0

raw patch · 8 files changed

+1062/−353 lines, 8 filesdep +vectordep −uvectorPVP ok

version bump matches the API change (PVP)

Dependencies added: vector

Dependencies removed: uvector

API changes (from Hackage documentation)

- Data.Histogram: Histogram :: bin -> Maybe (a, a) -> UArr a -> Histogram bin a
- Data.Histogram: asPairVector :: (UA (BinValue bin)) => Histogram bin a -> (UArr (BinValue bin), UArr a)
- Data.Histogram: asVectorPairs :: (UA (BinValue bin)) => Histogram bin a -> UArr ((BinValue bin) :*: a)
- Data.Histogram: data Histogram bin a
- Data.Histogram: histBin :: Histogram bin a -> bin
- Data.Histogram: instance (Show a, Show (BinValue bin), Show bin) => Show (Histogram bin a)
- Data.Histogram: mapHist :: (UA b) => (a -> b) -> Histogram bin a -> Histogram bin b
- Data.Histogram.Bin: instance (Bin bin1, Bin bin2) => Bin (Bin2D bin1 bin2)
- Data.Histogram.Fill: builderList :: [HBuilder a b] -> HBuilder a [b]
- Data.Histogram.Fill: builderListWrap :: [HBuilder a b] -> HBuilder a b
- Data.Histogram.Fill: class HBuilderCl h
- Data.Histogram.Fill: createHistograms :: (Monoid b) => HBuilder a b -> [a] -> b
- Data.Histogram.Fill: data HistBuilder a b
- Data.Histogram.Fill: instance HBuilderCl HBuilder
- Data.Histogram.Fill: instance HBuilderCl HBuilderList
- Data.Histogram.Fill: instance HBuilderCl HistBuilder
- Data.Histogram.Fill: runBuilder :: (HBuilderCl h) => h a b -> ST s (Accum s a b)
- Data.Histogram.ST: Accum :: h s a b -> Accum s a b
- Data.Histogram.ST: HistogramST :: bin -> MUArr a s -> MUArr a s -> HistogramST s bin a
- Data.Histogram.ST: accumHist :: (Bin bin) => (a -> HistogramST s bin val -> ST s ()) -> (Histogram bin val -> b) -> HistogramST s bin val -> ST s (Accum s a b)
- Data.Histogram.ST: accumList :: [ST s (Accum s a b)] -> ST s (Accum s a b)
- Data.Histogram.ST: class Accumulator h
- Data.Histogram.ST: data Accum s a b
- Data.Histogram.ST: data HistogramST s bin a
- Data.Histogram.ST: extract :: (Accumulator h, Monoid b) => (h s a b) -> ST s b
- Data.Histogram.ST: fillHistograms :: (Monoid b) => (forall s. ST s (Accum s a b)) -> [a] -> b
- Data.Histogram.ST: instance Accumulator Accum
- Data.Histogram.ST: instance Accumulator AccumHist
- Data.Histogram.ST: instance Accumulator AccumList
- Data.Histogram.ST: newHistogramST :: (Bin bin, UA a) => a -> bin -> ST s (HistogramST s bin a)
- Data.Histogram.ST: putOne :: (Accumulator h) => h s a b -> a -> ST s ()
+ Data.Histogram: asVector :: (Bin bin, Unbox a, Unbox (BinValue bin), Unbox (BinValue bin, a)) => Histogram bin a -> Vector (BinValue bin, a)
+ Data.Histogram: bins :: Histogram bin a -> bin
+ Data.Histogram: histMap :: (Unbox a, Unbox b) => (a -> b) -> Histogram bin a -> Histogram bin b
+ Data.Histogram: histMapBin :: (Bin bin, Bin bin') => (bin -> bin') -> Histogram bin a -> Histogram bin' a
+ Data.Histogram: histZip :: (Bin bin, Eq bin, Unbox a, Unbox b, Unbox c) => (a -> b -> c) -> Histogram bin a -> Histogram bin b -> Histogram bin c
+ Data.Histogram: histogram :: (Unbox a, Bin bin) => bin -> Vector a -> Histogram bin a
+ Data.Histogram: histogramUO :: (Unbox a, Bin bin) => bin -> Maybe (a, a) -> Vector a -> Histogram bin a
+ Data.Histogram: readFileHistogram :: (Read bin, Read a, Bin bin, Unbox a) => FilePath -> IO (Histogram bin a)
+ Data.Histogram: type Histogram bin a = Histogram Vector bin a
+ Data.Histogram.Bin: BinIx :: BinI -> BinIx i
+ Data.Histogram.Bin: binD :: Double -> Int -> Double -> BinD
+ Data.Histogram.Bin: binDn :: Double -> Double -> Double -> BinD
+ Data.Histogram.Bin: binI0 :: Int -> BinI
+ Data.Histogram.Bin: binI2binD :: BinI -> BinD
+ Data.Histogram.Bin: binI2binF :: (RealFrac f) => BinI -> BinF f
+ Data.Histogram.Bin: binInt :: Int -> Int -> Int -> BinInt
+ Data.Histogram.Bin: binIx :: (Indexable i) => i -> i -> BinIx i
+ Data.Histogram.Bin: binIx2D :: (Indexable2D i) => i -> i -> BinIx2D i
+ Data.Histogram.Bin: binX :: Bin2D bx by -> bx
+ Data.Histogram.Bin: binY :: Bin2D bx by -> by
+ Data.Histogram.Bin: binsList :: (Bin1D b) => b -> [BinValue b]
+ Data.Histogram.Bin: binsListRange :: (Bin1D b) => b -> [(BinValue b, BinValue b)]
+ Data.Histogram.Bin: class (Bin b) => Bin1D b
+ Data.Histogram.Bin: class Indexable a
+ Data.Histogram.Bin: class Indexable2D a
+ Data.Histogram.Bin: data BinD
+ Data.Histogram.Bin: data BinInt
+ Data.Histogram.Bin: data BinIx2D i
+ Data.Histogram.Bin: data LogBinD
+ Data.Histogram.Bin: deindex :: (Indexable a) => Int -> a
+ Data.Histogram.Bin: deindex2D :: (Indexable2D a) => (Int, Int) -> a
+ Data.Histogram.Bin: fmapBinX :: (Bin bx, Bin bx') => (bx -> bx') -> Bin2D bx by -> Bin2D bx' by
+ Data.Histogram.Bin: fmapBinY :: (Bin by, Bin by') => (by -> by') -> Bin2D bx by -> Bin2D bx by'
+ Data.Histogram.Bin: inRange :: (Bin b) => b -> BinValue b -> Bool
+ Data.Histogram.Bin: index :: (Indexable a) => a -> Int
+ Data.Histogram.Bin: index2D :: (Indexable2D a) => a -> (Int, Int)
+ Data.Histogram.Bin: instance (Bin binX, Bin binY) => Bin (Bin2D binX binY)
+ Data.Histogram.Bin: instance (Eq binX, Eq binY) => Eq (Bin2D binX binY)
+ Data.Histogram.Bin: instance (Eq f) => Eq (BinF f)
+ Data.Histogram.Bin: instance (Indexable a, Indexable b) => Indexable2D (a, b)
+ Data.Histogram.Bin: instance (Indexable i) => Bin (BinIx i)
+ Data.Histogram.Bin: instance (Indexable i) => Bin1D (BinIx i)
+ Data.Histogram.Bin: instance (Indexable2D i) => Bin (BinIx2D i)
+ Data.Histogram.Bin: instance (Read i, Indexable i) => Read (BinIx i)
+ Data.Histogram.Bin: instance (Read i, Indexable2D i) => Read (BinIx2D i)
+ Data.Histogram.Bin: instance (Show i, Indexable i) => Show (BinIx i)
+ Data.Histogram.Bin: instance (Show i, Indexable2D i) => Show (BinIx2D i)
+ Data.Histogram.Bin: instance Bin BinD
+ Data.Histogram.Bin: instance Bin BinInt
+ Data.Histogram.Bin: instance Bin LogBinD
+ Data.Histogram.Bin: instance Bin1D (BinF f)
+ Data.Histogram.Bin: instance Bin1D BinD
+ Data.Histogram.Bin: instance Bin1D BinI
+ Data.Histogram.Bin: instance Eq (BinIx i)
+ Data.Histogram.Bin: instance Eq BinD
+ Data.Histogram.Bin: instance Eq BinI
+ Data.Histogram.Bin: instance Eq BinInt
+ Data.Histogram.Bin: instance Eq LogBinD
+ Data.Histogram.Bin: instance Indexable Int
+ Data.Histogram.Bin: instance Read BinD
+ Data.Histogram.Bin: instance Read BinInt
+ Data.Histogram.Bin: instance Show BinD
+ Data.Histogram.Bin: instance Show BinInt
+ Data.Histogram.Bin: instance Show LogBinD
+ Data.Histogram.Bin: logBinD :: Double -> Int -> Double -> LogBinD
+ Data.Histogram.Bin: nBins2D :: (Bin bx, Bin by) => Bin2D bx by -> (Int, Int)
+ Data.Histogram.Bin: newtype BinIx i
+ Data.Histogram.Bin: scaleBinD :: Double -> Double -> BinD -> BinD
+ Data.Histogram.Bin: scaleBinF :: (RealFrac f) => f -> f -> BinF f -> BinF f
+ Data.Histogram.Bin: toIndex2D :: (Bin binX, Bin binY) => Bin2D binX binY -> Int -> (Int, Int)
+ Data.Histogram.Bin: unBinIx :: BinIx i -> BinI
+ Data.Histogram.Bin.Extra: data BinPermute b
+ Data.Histogram.Bin.Extra: instance (Bin b) => Bin (BinPermute b)
+ Data.Histogram.Bin.Extra: instance (Read BinI) => Read (BinPermute BinI)
+ Data.Histogram.Bin.Extra: instance (Show b) => Show (BinPermute b)
+ Data.Histogram.Bin.Extra: permuteBin :: (Bin b) => (Int -> Int) -> b -> Maybe (BinPermute b)
+ Data.Histogram.Fill: addCut :: (HistBuilder h) => (a -> Bool) -> h a b -> h a b
+ Data.Histogram.Fill: builderSTtoIO :: HBuilderST RealWorld a b -> HBuilderIO a b
+ Data.Histogram.Fill: class HistBuilder h
+ Data.Histogram.Fill: data HBuilderIO a b
+ Data.Histogram.Fill: data HBuilderST s a b
+ Data.Histogram.Fill: feedOne :: HBuilderST s a b -> a -> ST s ()
+ Data.Histogram.Fill: feedOneIO :: HBuilderIO a b -> a -> IO ()
+ Data.Histogram.Fill: fillBuilder :: HBuilder a b -> [a] -> b
+ Data.Histogram.Fill: freezeHBuilderIO :: HBuilderIO a b -> IO b
+ Data.Histogram.Fill: freezeHBuilderST :: HBuilderST s a b -> ST s b
+ Data.Histogram.Fill: instance Functor (HBuilder a)
+ Data.Histogram.Fill: instance Functor (HBuilderIO a)
+ Data.Histogram.Fill: instance Functor (HBuilderST s a)
+ Data.Histogram.Fill: instance HistBuilder (HBuilderST s)
+ Data.Histogram.Fill: instance HistBuilder HBuilder
+ Data.Histogram.Fill: instance HistBuilder HBuilderIO
+ Data.Histogram.Fill: joinHBuilder :: [HBuilder a b] -> HBuilder a [b]
+ Data.Histogram.Fill: joinHBuilderIO :: [HBuilderIO a b] -> HBuilderIO a [b]
+ Data.Histogram.Fill: joinHBuilderIOList :: [HBuilderIO a [b]] -> HBuilderIO a [b]
+ Data.Histogram.Fill: joinHBuilderList :: [HBuilder a [b]] -> HBuilder a [b]
+ Data.Histogram.Fill: joinHBuilderST :: [HBuilderST s a b] -> HBuilderST s a [b]
+ Data.Histogram.Fill: joinHBuilderSTList :: [HBuilderST s a [b]] -> HBuilderST s a [b]
+ Data.Histogram.Fill: mkHistMaybe :: (Bin bin, Unbox val, Num val) => bin -> (Histogram bin val -> b) -> (a -> Maybe (BinValue bin)) -> HBuilder a b
+ Data.Histogram.Fill: mkHistMonoidMaybe :: (Bin bin, Unbox val, Monoid val) => bin -> (Histogram bin val -> b) -> (a -> Maybe (BinValue bin, val)) -> HBuilder a b
+ Data.Histogram.Fill: mkHistWghMaybe :: (Bin bin, Unbox val, Num val) => bin -> (Histogram bin val -> b) -> (a -> Maybe (BinValue bin, val)) -> HBuilder a b
+ Data.Histogram.Fill: modifyMaybe :: (HistBuilder h) => h a b -> h (Maybe a) b
+ Data.Histogram.Fill: toBuilderIO :: HBuilder a b -> IO (HBuilderIO a b)
+ Data.Histogram.Fill: toBuilderST :: HBuilder a b -> (forall s. ST s (HBuilderST s a b))
+ Data.Histogram.Fill: treeHBuilder :: [HBuilder a b -> HBuilder a' b'] -> HBuilder a b -> HBuilder a' [b']
+ Data.Histogram.Fill: treeHBuilderIO :: [HBuilderIO a b -> HBuilderIO a' b'] -> HBuilderIO a b -> HBuilderIO a' [b']
+ Data.Histogram.Fill: treeHBuilderST :: [HBuilderST s a b -> HBuilderST s a' b'] -> HBuilderST s a b -> HBuilderST s a' [b']
+ Data.Histogram.Generic: asList :: (Vector v a, Bin bin) => Histogram v bin a -> [(BinValue bin, a)]
+ Data.Histogram.Generic: asVector :: (Bin bin, Vector v a, Vector v (BinValue bin), Vector v (BinValue bin, a)) => Histogram v bin a -> v (BinValue bin, a)
+ Data.Histogram.Generic: bins :: Histogram v bin a -> bin
+ Data.Histogram.Generic: data Histogram v bin a
+ Data.Histogram.Generic: histData :: Histogram v bin a -> v a
+ Data.Histogram.Generic: histMap :: (Vector v a, Vector v b) => (a -> b) -> Histogram v bin a -> Histogram v bin b
+ Data.Histogram.Generic: histMapBin :: (Bin bin, Bin bin') => (bin -> bin') -> Histogram v bin a -> Histogram v bin' a
+ Data.Histogram.Generic: histZip :: (Bin bin, Eq bin, Vector v a, Vector v b, Vector v c) => (a -> b -> c) -> Histogram v bin a -> Histogram v bin b -> Histogram v bin c
+ Data.Histogram.Generic: histogram :: (Vector v a, Bin bin) => bin -> v a -> Histogram v bin a
+ Data.Histogram.Generic: histogramUO :: (Vector v a, Bin bin) => bin -> Maybe (a, a) -> v a -> Histogram v bin a
+ Data.Histogram.Generic: instance (Eq bin, Eq a, Eq (v a)) => Eq (Histogram v bin a)
+ Data.Histogram.Generic: instance (Show a, Show (BinValue bin), Show bin, Bin bin, Vector v a) => Show (Histogram v bin a)
+ Data.Histogram.Generic: outOfRange :: Histogram v bin a -> Maybe (a, a)
+ Data.Histogram.Generic: overflows :: Histogram v bin a -> Maybe a
+ Data.Histogram.Generic: readFileHistogram :: (Read bin, Read a, Bin bin, Vector v a) => FilePath -> IO (Histogram v bin a)
+ Data.Histogram.Generic: readHistogram :: (Read bin, Read a, Bin bin, Vector v a) => String -> Histogram v bin a
+ Data.Histogram.Generic: sliceX :: (Vector v a, Bin bX, Bin bY) => Histogram v (Bin2D bX bY) a -> [(BinValue bX, Histogram v bY a)]
+ Data.Histogram.Generic: sliceY :: (Vector v a, Bin bX, Bin bY) => Histogram v (Bin2D bX bY) a -> [(BinValue bY, Histogram v bX a)]
+ Data.Histogram.Generic: underflows :: Histogram v bin a -> Maybe a
+ Data.Histogram.ST: data MHistogram s bin a
+ Data.Histogram.ST: newMHistogram :: (Bin bin, Unbox a) => a -> bin -> ST s (MHistogram s bin a)
- Data.Histogram: asList :: Histogram bin a -> [(BinValue bin, a)]
+ Data.Histogram: asList :: (Unbox a, Bin bin) => Histogram bin a -> [(BinValue bin, a)]
- Data.Histogram: histData :: Histogram bin a -> UArr a
+ Data.Histogram: histData :: Histogram bin a -> Vector a
- Data.Histogram: readHistogram :: (Read bin, Read a, Bin bin, UA a) => String -> Histogram bin a
+ Data.Histogram: readHistogram :: (Read bin, Read a, Bin bin, Unbox a) => String -> Histogram bin a
- Data.Histogram: sliceX :: (Bin bX, Bin bY) => Histogram (Bin2D bX bY) a -> [(BinValue bX, Histogram bY a)]
+ Data.Histogram: sliceX :: (Unbox a, Bin bX, Bin bY) => Histogram (Bin2D bX bY) a -> [(BinValue bX, Histogram bY a)]
- Data.Histogram: sliceY :: (Bin bX, Bin bY) => Histogram (Bin2D bX bY) a -> [(BinValue bY, Histogram bX a)]
+ Data.Histogram: sliceY :: (Unbox a, Bin bX, Bin bY) => Histogram (Bin2D bX bY) a -> [(BinValue bY, Histogram bX a)]
- Data.Histogram.Bin: (><) :: bin1 -> bin2 -> Bin2D bin1 bin2
+ Data.Histogram.Bin: (><) :: binX -> binY -> Bin2D binX binY
- Data.Histogram.Bin: Bin2D :: bin1 -> bin2 -> Bin2D bin1 bin2
+ Data.Histogram.Bin: Bin2D :: !binX -> !binY -> Bin2D binX binY
- Data.Histogram.Bin: BinI :: !Int -> !Int -> BinI
+ Data.Histogram.Bin: BinI :: !!Int -> !!Int -> BinI
- Data.Histogram.Bin: data Bin2D bin1 bin2
+ Data.Histogram.Bin: data Bin2D binX binY
- Data.Histogram.Fill: mkHist :: (Bin bin, UA val, Num val) => bin -> (Histogram bin val -> b) -> (a -> [BinValue bin]) -> HBuilder a b
+ Data.Histogram.Fill: mkHist :: (Bin bin, Unbox val, Num val) => bin -> (Histogram bin val -> b) -> (a -> [BinValue bin]) -> HBuilder a b
- Data.Histogram.Fill: mkHist1 :: (Bin bin, UA val, Num val) => bin -> (Histogram bin val -> b) -> (a -> BinValue bin) -> HBuilder a b
+ Data.Histogram.Fill: mkHist1 :: (Bin bin, Unbox val, Num val) => bin -> (Histogram bin val -> b) -> (a -> BinValue bin) -> HBuilder a b
- Data.Histogram.Fill: mkHistMonoid :: (Bin bin, UA val, Monoid val) => bin -> (Histogram bin val -> b) -> (a -> [(BinValue bin, val)]) -> HBuilder a b
+ Data.Histogram.Fill: mkHistMonoid :: (Bin bin, Unbox val, Monoid val) => bin -> (Histogram bin val -> b) -> (a -> [(BinValue bin, val)]) -> HBuilder a b
- Data.Histogram.Fill: mkHistMonoid1 :: (Bin bin, UA val, Monoid val) => bin -> (Histogram bin val -> b) -> (a -> (BinValue bin, val)) -> HBuilder a b
+ Data.Histogram.Fill: mkHistMonoid1 :: (Bin bin, Unbox val, Monoid val) => bin -> (Histogram bin val -> b) -> (a -> (BinValue bin, val)) -> HBuilder a b
- Data.Histogram.Fill: mkHistWgh :: (Bin bin, UA val, Num val) => bin -> (Histogram bin val -> b) -> (a -> [(BinValue bin, val)]) -> HBuilder a b
+ Data.Histogram.Fill: mkHistWgh :: (Bin bin, Unbox val, Num val) => bin -> (Histogram bin val -> b) -> (a -> [(BinValue bin, val)]) -> HBuilder a b
- Data.Histogram.Fill: mkHistWgh1 :: (Bin bin, UA val, Num val) => bin -> (Histogram bin val -> b) -> (a -> (BinValue bin, val)) -> HBuilder a b
+ Data.Histogram.Fill: mkHistWgh1 :: (Bin bin, Unbox val, Num val) => bin -> (Histogram bin val -> b) -> (a -> (BinValue bin, val)) -> HBuilder a b
- Data.Histogram.Fill: modifyIn :: (HBuilderCl h) => (a' -> a) -> h a b -> h a' b
+ Data.Histogram.Fill: modifyIn :: (HistBuilder h) => (a' -> a) -> h a b -> h a' b
- Data.Histogram.Fill: modifyOut :: (HBuilderCl h) => (b -> b') -> h a b -> h a b'
+ Data.Histogram.Fill: modifyOut :: (HistBuilder h) => (b -> b') -> h a b -> h a b'
- Data.Histogram.ST: fillMonoid :: (Monoid a) => HistogramST s bin a -> (BinValue bin, a) -> ST s ()
+ Data.Histogram.ST: fillMonoid :: (Monoid a) => MHistogram s bin a -> (BinValue bin, a) -> ST s ()
- Data.Histogram.ST: fillOne :: (Num a) => HistogramST s bin a -> BinValue bin -> ST s ()
+ Data.Histogram.ST: fillOne :: (Num a) => MHistogram s bin a -> BinValue bin -> ST s ()
- Data.Histogram.ST: fillOneW :: (Num a) => HistogramST s bin a -> (BinValue bin, a) -> ST s ()
+ Data.Histogram.ST: fillOneW :: (Num a) => MHistogram s bin a -> (BinValue bin, a) -> ST s ()
- Data.Histogram.ST: freezeHist :: HistogramST s bin a -> ST s (Histogram bin a)
+ Data.Histogram.ST: freezeHist :: MHistogram s bin a -> ST s (Histogram bin a)

Files

Data/Histogram.hs view
@@ -1,6 +1,8 @@+ {-# LANGUAGE GADTs #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE TypeOperators #-}+{-# LANGUAGE DeriveDataTypeable #-} -- | -- Module     : Data.Histogram -- Copyright  : Copyright (c) 2009, Alexey Khudyakov <alexey.skladnoy@gmail.com>@@ -11,119 +13,128 @@ -- Immutable histograms.   module Data.Histogram ( -- * Immutable histogram-                        Histogram(..)-                      , module Data.Histogram.Bin-                      , mapHist-                      , histBin-                      , histData-                      , underflows-                      , overflows-                      , outOfRange-                      , readHistogram-                      -- * Conversion-                      , asList-                      , asPairVector-                      , asVectorPairs-                      -- * Slicing-                      , sliceY-                      , sliceX-                      ) where+    -- * Data type+    Histogram+  , module Data.Histogram.Bin+  , histogram+  , histogramUO+    -- * Read histograms from string+  , readHistogram+  , readFileHistogram+    -- * Accessors+  , bins+  , histData+  , underflows+  , overflows+  , outOfRange+    -- ** Convert to other data types+  , asList+  , asVector+    -- * Slicing histograms+  , sliceX+  , sliceY+    -- * Modify histogram+  , histMap+  , histMapBin+  , histZip+  ) where -import Control.Arrow ((***))-import Control.Monad (ap)-import Data.Array.Vector-import Text.Read-import Text.ParserCombinators.ReadPrec (readPrec_to_S)+import qualified Data.Vector.Unboxed    as U+import Data.Vector.Unboxed (Unbox,Vector) +import qualified Data.Histogram.Generic as H import Data.Histogram.Bin-import Data.Histogram.Parse   -- | Immutable histogram. Histogram consists of binning algorithm, --   optional number of under and overflows, and data. -data Histogram bin a where-    Histogram :: (Bin bin, UA a) => -                 bin-              -> Maybe (a,a)-              -> UArr a-              -> Histogram bin a+type Histogram bin a = H.Histogram U.Vector bin a +-- | Create histogram from binning algorithm and vector with+-- data. Overflows are set to Nothing. +--+-- Number of bins and vector size must match.+histogram :: (Unbox a, Bin bin) => bin -> Vector a -> Histogram bin a+histogram = H.histogram -instance (Show a, Show (BinValue bin), Show bin) => Show (Histogram bin a) where-    show h@(Histogram bin uo _) = "# Histogram\n" ++ showUO uo ++ show bin ++-                                  (unlines $ map showT $ asList h)-        where-          showT (x,y) = show x ++ "\t" ++ show y-          showUO (Just (u,o)) = "# Underflows = " ++ show u ++ "\n" ++-                                "# Overflows  = " ++ show o ++ "\n"-          showUO Nothing      = "# Underflows = \n" ++-                                "# Overflows  = \n"+-- | Create histogram from binning algorithm and vector with data. +--+-- Number of bins and vector size must match.+histogramUO :: (Unbox a, Bin bin) => bin -> Maybe (a,a) -> Vector a -> Histogram bin a+histogramUO = H.histogramUO -histHeader :: (Read bin, Read a, Bin bin, UA a) => ReadPrec (UArr a -> Histogram bin a)-histHeader = do-  keyword "Histogram"-  u   <- maybeValue "Underflows"-  o   <- maybeValue "Overflows"-  bin <- readPrec-  return $ Histogram bin ((,) `fmap` u `ap` o) +----------------------------------------------------------------+-- Instances & reading histograms from strings +----------------------------------------------------------------++ -- | Convert String to histogram. Histogram do not have Read instance --   because of slowness of ReadP-readHistogram :: (Read bin, Read a, Bin bin, UA a) => String -> Histogram bin a-readHistogram str = -    let [(h,rest)] = readPrec_to_S histHeader 0 str -        xs = map last . filter (not . null) . map words . lines $ rest-    in h (toU $ map read xs)+readHistogram :: (Read bin, Read a, Bin bin, Unbox a) => String -> Histogram bin a+readHistogram = H.readHistogram --- | fmap lookalike. It's not possible to create Functor instance---   because of UA restriction.-mapHist :: UA b => (a -> b) -> Histogram bin a -> Histogram bin b-mapHist f (Histogram bin uo a) = Histogram bin (fmap (f *** f) uo) (mapU f a)+-- | Read histogram from file.+readFileHistogram :: (Read bin, Read a, Bin bin, Unbox a) => FilePath -> IO (Histogram bin a)+readFileHistogram = H.readFileHistogram +----------------------------------------------------------------+-- Accessors & conversion+----------------------------------------------------------------+ -- | Histogram bins-histBin :: Histogram bin a -> bin-histBin (Histogram bin _ _) = bin+bins :: Histogram bin a -> bin+bins = H.bins  -- | Histogram data as vector-histData :: Histogram bin a -> UArr a-histData (Histogram _ _ a) = a+histData :: Histogram bin a -> Vector a+histData = H.histData  -- | Number of underflows underflows :: Histogram bin a -> Maybe a-underflows (Histogram _ uo _) = fmap fst uo+underflows = H.underflows  -- | Number of overflows overflows :: Histogram bin a -> Maybe a-overflows (Histogram _ uo _) = fmap snd uo+overflows = H.overflows  -- | Underflows and overflows outOfRange :: Histogram bin a -> Maybe (a,a)-outOfRange (Histogram _ uo _) = uo+outOfRange = H.outOfRange  -- | Convert histogram to list.-asList :: Histogram bin a -> [(BinValue bin, a)]-asList (Histogram bin _ arr) = map (fromIndex bin) [0..] `zip` fromU arr+asList :: (Unbox a, Bin bin) => Histogram bin a -> [(BinValue bin, a)]+asList = H.asList --- | Convert to pair of vectors-asPairVector :: UA (BinValue bin) => Histogram bin a -> (UArr (BinValue bin), UArr a)-asPairVector (Histogram bin _ a) = (toU $ map (fromIndex bin) [0 .. nBins bin], a)+-- | Convert histogram to vector+asVector :: (Bin bin, Unbox a, Unbox (BinValue bin), Unbox (BinValue bin,a)) +         => Histogram bin a -> Vector (BinValue bin, a) +asVector = H.asVector --- | Convert to vector of pairs-asVectorPairs :: UA (BinValue bin) => Histogram bin a -> UArr ((BinValue bin) :*: a)-asVectorPairs h@(Histogram _ _ _) = uncurry zipU . asPairVector $ h+----------------------------------------------------------------+-- Modify histograms+---------------------------------------------------------------- +-- | fmap lookalike. It's not possible to create Functor instance+--   because of class restrictions+histMap :: (Unbox a, Unbox b) => (a -> b) -> Histogram bin a -> Histogram bin b+histMap = H.histMap++-- | Apply function to histogram bins. Function must not change number of bins.+--   If it does error is thrown.+histMapBin :: (Bin bin, Bin bin') => (bin -> bin') -> Histogram bin a -> Histogram bin' a+histMapBin = H.histMapBin++-- | Zip two histograms together. Bins of histograms must be equal+--   otherwise error will be called.+histZip :: (Bin bin, Eq bin, Unbox a, Unbox b, Unbox c) =>+           (a -> b -> c) -> Histogram bin a -> Histogram bin b -> Histogram bin c+histZip = H.histZip+            -- | Slice 2D histogram along Y axis. This function is fast because it does not require reallocations.-sliceY :: (Bin bX, Bin bY) => Histogram (Bin2D bX bY) a -> [(BinValue bY, Histogram bX a)]-sliceY (Histogram b@(Bin2D bX _) _ a) = map mkHist $ init [0, nBins bX .. nBins b]-    where-      mkHist i = ( snd $ fromIndex b i-                 , Histogram bX Nothing (sliceU a i (nBins bX)) )+sliceY :: (Unbox a, Bin bX, Bin bY) => Histogram (Bin2D bX bY) a -> [(BinValue bY, Histogram bX a)]+sliceY = H.sliceY  -- | Slice 2D histogram along X axis.-sliceX :: (Bin bX, Bin bY) => Histogram (Bin2D bX bY) a -> [(BinValue bX, Histogram bY a)]-sliceX (Histogram b@(Bin2D bX bY) _ a) = map mkHist $ init [0 .. nx]-    where-      nx = nBins bX-      n  = nBins b-      mkHist i = ( fst $ fromIndex b i-                 , Histogram bY Nothing (toU $ map (indexU a) [i,i+nx .. n-1]) )+sliceX :: (Unbox a, Bin bX, Bin bY) => Histogram (Bin2D bX bY) a -> [(BinValue bX, Histogram bY a)]+sliceX = H.sliceX
Data/Histogram/Bin.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE GADTs        #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE BangPatterns #-}@@ -11,26 +12,61 @@ -- Binning algorithms. This is mapping from set of interest to integer -- indices and approximate reverse.  -module Data.Histogram.Bin ( -- * Type class+module Data.Histogram.Bin ( -- * Type classes                             Bin(..)-                          -- * Integer bins+                          , Bin1D(..)+                          , Indexable(..)+                          , Indexable2D(..)+                          -- * Bin types+                          -- ** Integer bins                           , BinI(..)-                          -- * Floating point bins+                          , binI0+                          -- ** Integer bins with non-1 size+                          , BinInt+                          , binInt+                          -- ** Indexed bins +                          , BinIx(BinIx,unBinIx)+                          , binIx+                          -- ** Floating point bins                           , BinF                           , binF                           , binFn-                          -- * 2D bins+                          , binI2binF+                          , scaleBinF+                          -- *** Specialized for Double +                          , BinD+                          , binD+                          , binDn+                          , binI2binD+                          , scaleBinD+                          -- ** Log scale point+                          , LogBinD +                          , logBinD+                          -- ** 2D bins                           , Bin2D(..)                           , (><)+                          , nBins2D+                          , toIndex2D+                          , binX+                          , binY+                          , fmapBinX+                          , fmapBinY+                          -- ** 2D indexed bins+                          , BinIx2D (unBinIx2D)+                          , binIx2D                           ) where +import Control.Monad import Data.Histogram.Parse import Text.Read (Read(..)) ----- | Abstract binning algorithm. Following invariant is expected to hold: +import GHC.Float (double2Int)+----------------------------------------------------------------+-- | Abstract binning algorithm. It provides way to map some values+-- onto continous range of integer values starting from zero.  -- +-- Following invariant is expected to hold: +--  -- > toIndex . fromIndex == id --  -- Reverse is not nessearily true. @@ -39,47 +75,172 @@     type BinValue b     -- | Convert from value to index. No bound checking performed     toIndex :: b -> BinValue b -> Int-    {-# INLINE toIndex #-}     -- | Convert from index to value.      fromIndex :: b -> Int -> BinValue b +    -- | Check whether value in range.+    inRange :: b -> BinValue b -> Bool     -- | Total number of bins     nBins :: b -> Int +----------------------------------------------------------------+-- | One dimensional binning algorithm. It means that bin values have+-- some inherent ordering. For example all binning algorithms for real+-- numbers could be members or this type class whereas binning+-- algorithms for R^2 could not. +class Bin b => Bin1D b where+    -- | List of center of bins in ascending order.+    binsList :: b -> [BinValue b]+    -- | List of bins in ascending order.+    binsListRange :: b -> [(BinValue b, BinValue b)]  ----------------------------------------------------------------+-- | Indexable is value which could be converted to and from Int+-- without information loss.+--+-- Always true+--+-- > deindex . index = id+--+-- Only if Int is in range+--+-- > index . deindex = id+class Indexable a where+    -- | Convert value to index+    index :: a -> Int +    -- | Convert index to value+    deindex :: Int -> a++instance Indexable Int where+    index   = id+    deindex = id++----------------------------------------------------------------+-- | This type class is same as Indexable but for 2D values.+class Indexable2D a where+    -- | Convert value to index+    index2D :: a -> (Int,Int)+    -- | Convert index to value+    deindex2D :: (Int,Int) -> a++instance (Indexable a, Indexable b) => Indexable2D (a,b) where+    index2D   (x,y) = (index x,   index y)+    deindex2D (i,j) = (deindex i, deindex j)++---------------------------------------------------------------- -- Integer bin+----------------------------------------------------------------+-- | Simple binning algorithm which map continous range of bins onto+-- indices. Each number correcsponds to different bin+data BinI = BinI {-# UNPACK #-} !Int {-# UNPACK #-} !Int+            deriving Eq --- | Integer bins. This is inclusive interval [from,to]-data BinI = BinI !Int !Int+-- | Construct BinI with n bins. Indexing starts from 0+binI0 :: Int -> BinI+binI0 n = BinI 0 (n-1)  instance Bin BinI where     type BinValue BinI = Int     toIndex   !(BinI base _) !x = x - base+    {-# INLINE toIndex #-}     fromIndex !(BinI base _) !x = x + base+    inRange   !(BinI x y) i     = i>=x && i<=y+    {-# INLINE inRange #-}     nBins     !(BinI x y) = y - x + 1 +instance Bin1D BinI where+    binsList (BinI lo hi) = [lo .. hi]+    binsListRange b = zip (binsList b) (binsList b)+ instance Show BinI where     show (BinI lo hi) = unlines [ "# BinI"                                 , "# Low  = " ++ show lo                                 , "# High = " ++ show hi                                 ]- instance Read BinI where-    readPrec = do-      keyword "BinI"-      l <- value "Low"-      h <- value "High"-      return $ BinI l h+    readPrec = keyword "BinI" >> liftM2 BinI (value "Low") (value "High") +----------------------------------------------------------------+-- Another form of Integer bin+---------------------------------------------------------------- +-- | Integer bins with size which differ from 1.+data BinInt = BinInt +              {-# UNPACK #-} !Int -- Low bound+              {-# UNPACK #-} !Int -- Bin size+              {-# UNPACK #-} !Int -- Number of bins+              deriving Eq++-- | Construct BinInt.+binInt :: Int                   -- ^ Lower bound+       -> Int                   -- ^ Bin size+       -> Int                   -- ^ Upper bound+       -> BinInt+binInt lo n hi = BinInt lo n nb+  where+    nb = (hi-lo) `div` n ++instance Bin BinInt where+    type BinValue BinInt = Int+    toIndex   !(BinInt base sz _) !x = (x - base) `div` sz+    {-# INLINE toIndex #-}+    fromIndex !(BinInt base sz _) !x = x * sz + base+    inRange   !(BinInt base sz n) i  = i>=base && i<(base+n*sz)+    {-# INLINE inRange #-}+    nBins     !(BinInt _ _ n) = n++instance Show BinInt where+    show (BinInt base sz n) = +      unlines [ "# BinInt"+              , "# Base = " ++ show base+              , "# Step = " ++ show sz+              , "# Bins = " ++ show n+              ]++instance Read BinInt where+    readPrec = keyword "BinInt" >> liftM3 BinInt (value "Base") (value "Step") (value "Bins")+ ------------------------------------------------------------------- Floating point bin+-- Bins for indexables+---------------------------------------------------------------- +-- | Binning for indexable values+newtype BinIx i = BinIx { unBinIx :: BinI }+                  deriving Eq++-- | Construct indexed bin+binIx :: Indexable i => i -> i -> BinIx i+binIx lo hi = BinIx $ BinI (index lo) (index hi)++instance Indexable i => Bin (BinIx i) where+    type BinValue (BinIx i) = i+    toIndex   (BinIx b) x = toIndex b (index x)+    fromIndex (BinIx b) i = deindex (fromIndex b i)+    inRange   (BinIx b) x = inRange b (index x)+    nBins (BinIx b) = nBins b++instance Indexable i => Bin1D (BinIx i) where+    binsList (BinIx b) = map deindex (binsList b)+    binsListRange b    = let bins = binsList b in zip bins bins++instance (Show i, Indexable i) => Show (BinIx i) where+    show (BinIx (BinI lo hi)) = unlines [ "# BinIx"+                                        , "# Low  = " ++ show (deindex lo :: i)+                                        , "# High = " ++ show (deindex hi :: i)+                                        ]+instance (Read i, Indexable i) => Read (BinIx i) where+    readPrec = keyword "BinIx" >> liftM2 binIx (value "Low") (value "High")++----------------------------------------------------------------+-- Floating point bin+---------------------------------------------------------------- -- | Floaintg point bins with equal sizes. data BinF f where     BinF :: RealFrac f => !f -> !f -> !Int -> BinF f  --- | Create bins +instance Eq f => Eq (BinF f) where+    (BinF lo hi n) == (BinF lo' hi' n') = lo == lo'  && hi == hi' && n == n'+                                          +-- | Create bins. binF :: RealFrac f =>          f   -- ^ Lower bound of range      -> Int -- ^ Number of bins@@ -95,21 +256,37 @@       -> BinF f  binFn from step to = BinF from step (round $ (to - from) / step) +-- | Convert BinI to BinF+binI2binF :: RealFrac f => BinI -> BinF f+binI2binF b@(BinI i _) = BinF (fromIntegral i) 1 (nBins b)++-- | 'scaleBinF a b' scales BinF using linear transform 'a+b*x'+scaleBinF :: RealFrac f => f -> f -> BinF f -> BinF f+scaleBinF a b (BinF base step n) +    | b > 0     = BinF (a + b*base) (b*step) n+    | otherwise = error $ "scaleBinF: b must be positive (b = "++show b++")"+ instance Bin (BinF f) where     type BinValue (BinF f) = f      toIndex   !(BinF from step _) !x = floor $ (x-from) / step+    {-# INLINE toIndex #-}     fromIndex !(BinF from step _) !i = (step/2) + (fromIntegral i * step) + from +    inRange   !(BinF from step n) x  = x > from && x < from + step*fromIntegral n+    {-# INLINE inRange #-}     nBins     !(BinF _ _ n) = n-    {-# SPECIALIZE instance Bin (BinF Double) #-}-    {-# SPECIALIZE instance Bin (BinF Float) #-} +instance Bin1D (BinF f) where+    binsList b@(BinF _ _ n) = map (fromIndex b) [0..n-1]+    binsListRange b@(BinF _ step _) = map toPair (binsList b)+        where+          toPair x = (x - step/2, x + step/2)+ instance Show f => Show (BinF f) where     show (BinF base step n) = unlines [ "# BinF"-                                  , "# Base = " ++ show base-                                  , "# Step = " ++ show step-                                  , "# N    = " ++ show n-                                  ]-+                                      , "# Base = " ++ show base+                                      , "# Step = " ++ show step+                                      , "# N    = " ++ show n+                                      ] instance (Read f, RealFrac f) => Read (BinF f) where     readPrec = do       keyword "BinF"@@ -118,40 +295,173 @@       n    <- value "N"       return $ BinF base step n +----------------------------------------------------------------+-- Floating point bin /Specialized for Double+----------------------------------------------------------------+-- | Floaintg point bins with equal sizes. If you work with Doubles+-- this data type should be used instead of BinF.+data BinD = BinD {-# UNPACK #-} !Double {-# UNPACK #-} !Double {-# UNPACK #-} !Int +instance Eq BinD where+    (BinD lo hi n) == (BinD lo' hi' n') = lo == lo'  && hi == hi' && n == n'+                                          +-- | Create bins.+binD :: Double -- ^ Lower bound of range+     -> Int    -- ^ Number of bins+     -> Double -- ^ Upper bound of range+     -> BinD+binD from n to = BinD from ((to - from) / fromIntegral n) n++-- | Create bins. Note that actual upper bound can differ from specified.+binDn :: Double -- ^ Begin of range+      -> Double -- ^ Size of step+      -> Double -- ^ Approximation of end of range+      -> BinD+binDn from step to = BinD from step (round $ (to - from) / step)++-- | Convert BinI to BinF+binI2binD :: BinI -> BinD+binI2binD b@(BinI i _) = BinD (fromIntegral i) 1 (nBins b)++-- | 'scaleBinF a b' scales BinF using linear transform 'a+b*x'+scaleBinD :: Double -> Double -> BinD -> BinD+scaleBinD a b (BinD base step n) +    | b > 0     = BinD (a + b*base) (b*step) n+    | otherwise = error $ "scaleBinF: b must be positive (b = "++show b++")"++-- Fast variant of flooor+floorD :: Double -> Int+floorD x | x < 0     = double2Int x - 1+         | otherwise = double2Int x+{-# INLINE floorD #-}++instance Bin BinD where+    type BinValue BinD = Double+    toIndex   !(BinD from step _) !x = floorD $ (x-from) / step+    {-# INLINE toIndex #-}+    fromIndex !(BinD from step _) !i = (step/2) + (fromIntegral i * step) + from +    inRange   !(BinD from step n) x  = x > from && x < from + step*fromIntegral n+    {-# INLINE inRange #-}+    nBins     !(BinD _ _ n) = n++instance Bin1D BinD where+    binsList b@(BinD _ _ n) = map (fromIndex b) [0..n-1]+    binsListRange b@(BinD _ step _) = map toPair (binsList b)+        where+          toPair x = (x - step/2, x + step/2)++instance Show BinD where+    show (BinD base step n) = unlines [ "# BinD"+                                      , "# Base = " ++ show base+                                      , "# Step = " ++ show step+                                      , "# N    = " ++ show n+                                      ]+instance Read BinD where+    readPrec = do+      keyword "BinD"+      base <- value "Base"+      step <- value "Step"+      n    <- value "N"+      return $ BinD base step n++ ----------------------------------------------------------------+-- Log-scale bin+----------------------------------------------------------------+-- | Logarithmic scale bins.+data LogBinD = LogBinD+               Double -- Low border+               Double -- Hi border+               Double -- Increment ratio+               Int    -- Number of bins+               deriving Eq++-- | Create log-scale bins. +logBinD :: Double -> Int -> Double -> LogBinD+logBinD lo n hi = LogBinD lo hi ((hi/lo) ** (1 / fromIntegral n)) n++instance Bin LogBinD where+    type BinValue LogBinD = Double+    toIndex   !(LogBinD base _ step _) !x = floorD $ logBase step (x / base)+    {-# INLINE toIndex #-}+    fromIndex !(LogBinD base _ step _) !i = base * step ^ i+    inRange   !(LogBinD lo hi _ _) x  = x >= lo && x < hi+    {-# INLINE inRange #-}+    nBins     !(LogBinD _ _ _ n) = n++instance Show LogBinD where+    show (LogBinD lo hi step n) = +        unlines [ "# LogBinD"+                , "# Lo   = " ++ show lo+                , "# Hi   = " ++ show hi+                , "# Step = " ++ show step+                , "# N    = " ++ show n+                ]++---------------------------------------------------------------- -- 2D bin+---------------------------------------------------------------- --- | 2D bins. bin1 is binning along X axis and bin2 is one along Y axis. -data Bin2D bin1 bin2 = Bin2D bin1 bin2+-- | 2D bins. binX is binning along X axis and binY is one along Y axis. +data Bin2D binX binY = Bin2D !binX !binY+                       deriving Eq  -- | Alias for 'Bin2D'.-(><) :: bin1 -> bin2 -> Bin2D bin1 bin2+(><) :: binX -> binY -> Bin2D binX binY (><) = Bin2D -instance (Bin bin1, Bin bin2) => Bin (Bin2D bin1 bin2) where-    type BinValue (Bin2D bin1 bin2) = (BinValue bin1, BinValue bin2)+-- | Get binning algorithm along X axis+binX :: Bin2D bx by -> bx+binX !(Bin2D bx _) = bx -    toIndex   (Bin2D bx by) (x,y) -        | ix < 0 || ix >= rx || iy < 0 || iy >= ry = maxBound-        | otherwise                                = ix + iy*rx-        where-          ix = toIndex bx x-          iy = toIndex by y-          rx = nBins bx-          ry = nBins by+-- | Get binning algorithm along Y axis+binY :: Bin2D bx by -> by+binY !(Bin2D _ by) = by -    fromIndex (Bin2D bx by) i = let (iy,ix) = divMod i (nBins bx)-                                in  (fromIndex bx ix, fromIndex by iy)+instance (Bin binX, Bin binY) => Bin (Bin2D binX binY) where+    type BinValue (Bin2D binX binY) = (BinValue binX, BinValue binY)+    toIndex b@(Bin2D bx by) (x,y) +        | inRange b (x,y) = toIndex bx x + (toIndex by y)*(fromIntegral $ nBins bx)+        | otherwise       = maxBound+    {-# INLINE toIndex #-}+    fromIndex b@(Bin2D bx by) i = let (ix,iy) = toIndex2D b i+                                  in  (fromIndex bx ix, fromIndex by iy)+    inRange (Bin2D bx by) (x,y) = inRange bx x && inRange by y+    {-# INLINE inRange #-}+    nBins (Bin2D bx by) = (nBins bx) * (nBins by) -    nBins (Bin2D b1 b2) = (nBins b1) * (nBins b2)+toIndex2D :: (Bin binX, Bin binY) => Bin2D binX binY -> Int -> (Int,Int)+toIndex2D b i = let (iy,ix) = divMod i (nBins $ binX b) in (ix,iy) +-- | 2-dimensional size of binning algorithm+nBins2D :: (Bin bx, Bin by) => Bin2D bx by -> (Int,Int)+nBins2D (Bin2D bx by) = (nBins bx, nBins by)++-- | Apply function to X binning algorithm. If new binning algorithm+--   have different number of bins will fail.+fmapBinX :: (Bin bx, Bin bx') => (bx -> bx') -> Bin2D bx by -> Bin2D bx' by+fmapBinX f (Bin2D bx by) +    | nBins bx' /= nBins bx = error "fmapBinX: new binnig algorithm has different number of bins"+    | otherwise             = Bin2D bx' by+    where +      bx' = f bx++-- | Apply function to Y binning algorithm. If new binning algorithm+--   have different number of bins will fail.+fmapBinY ::(Bin by, Bin by') => (by -> by') -> Bin2D bx by -> Bin2D bx by'+fmapBinY f (Bin2D bx by)+    | nBins by' /= nBins by = error "fmapBinY: new binnig algorithm has different number of bins"+    | otherwise             = Bin2D bx by'+    where +      by' = f by+ instance (Show b1, Show b2) => Show (Bin2D b1 b2) where-    show (Bin2D b1 b2) = "# Bin2D\n" ++-                         "# X\n" ++ -                         show b1 ++-                         "# Y\n" ++-                         show b2+    show (Bin2D b1 b2) = concat [ "# Bin2D\n"+                                , "# X\n"+                                , show b1+                                , "# Y\n"+                                , show b2+                                ] instance (Read b1, Read b2) => Read (Bin2D b1 b2) where     readPrec = do       keyword "Bin2D"@@ -160,3 +470,35 @@       keyword "Y"       b2 <- readPrec       return $ Bin2D b1 b2+++----------------------------------------------------------------+-- Indexed 2D bins+----------------------------------------------------------------+-- | Binning for 2D indexable value+newtype BinIx2D i = BinIx2D {unBinIx2D :: (Bin2D BinI BinI) }++-- | Construct indexed bin+binIx2D :: Indexable2D i => i -> i -> BinIx2D i+binIx2D lo hi = let (ix,iy) = index2D lo+                    (jx,jy) = index2D hi+                in BinIx2D $ BinI ix jx >< BinI iy jy++instance Indexable2D i => Bin (BinIx2D i) where+    type BinValue (BinIx2D i) = i+    toIndex   (BinIx2D b) x = toIndex b (index2D x)+    fromIndex (BinIx2D b) i = deindex2D $ fromIndex b i+    inRange   (BinIx2D b) x = inRange b (index2D x)+    nBins     (BinIx2D b)   = nBins b++instance (Show i, Indexable2D i) => Show (BinIx2D i) where+    show (BinIx2D b) = unlines [ "# BinIx2D"+                               , "# Low  = " ++ show (deindex2D (fromIndex b 0            ) :: i)+                               , "# High = " ++ show (deindex2D (fromIndex b (nBins b - 1)) :: i)+                               ]+instance (Read i, Indexable2D i) => Read (BinIx2D i) where+    readPrec = do+      keyword "BinIx2D"+      l <- value "Low"+      h <- value "High"+      return $ binIx2D l h
+ Data/Histogram/Bin/Extra.hs view
@@ -0,0 +1,76 @@+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FlexibleContexts #-}+-- |+-- Module     : Data.Histogram.Bin+-- Copyright  : Copyright (c) 2010, Alexey Khudyakov <alexey.skladnoy@gmail.com>+-- License    : BSD3+-- Maintainer : Alexey Khudyakov <alexey.skladnoy@gmail.com>+-- Stability  : experimental+--+-- Extra binning algorithms++module Data.Histogram.Bin.Extra ( BinPermute(permutedBin, permuteTo, permuteFrom)+                                , permuteBin+                                ) where++import Control.Applicative+import Control.Monad (forM_)+import qualified Data.Vector.Unboxed         as U+import qualified Data.Vector.Unboxed.Mutable as M+import Data.Vector.Unboxed ((!))+import Text.Read++import Data.Histogram.Bin+import Data.Histogram.Parse++-- | Direct permutation of indices. +data BinPermute b = BinPermute { permutedBin :: b+                               , permuteTo   :: U.Vector Int+                               , permuteFrom :: U.Vector Int+                               }+instance Bin b => Bin (BinPermute b) where+    type BinValue (BinPermute b) = BinValue b+    toIndex   (BinPermute b to _)   x = to ! toIndex b x+    fromIndex (BinPermute b _ from) i = fromIndex b (from ! i)+    inRange   (BinPermute b _ _) x = inRange b x+    nBins     (BinPermute b _ _) = nBins b++instance Show b => Show (BinPermute b) where+    show (BinPermute b to _) = unlines [ "# BinPermute"+                                       , "# Permutation = " ++ show (U.toList to)+                                       ] ++ show b++instance Read BinI => Read (BinPermute BinI) where+    readPrec = do keyword "BinPermute"+                  to   <- U.fromList <$> value "Permutation"+                  from <- case checkPermutation (invertPermutation to) of+                            Just v  -> return v+                            Nothing -> fail "Invalid permutation"+                  b  <- readPrec +                  return $ BinPermute b to from++-- Check whether this viable permutation+checkPermutation :: U.Vector Int -> Maybe (U.Vector Int)+checkPermutation v | U.any bad v = Nothing+                   | otherwise   = Just v+                   where+                     n     = U.length v+                     bad i = i < 0 || i >= n++-- Calculate inverse permutation                     +invertPermutation :: U.Vector Int -> U.Vector Int+invertPermutation v = U.create $ do a <- M.newWith n (-1)+                                    forM_ [0..n-1] (writeInvert a)+                                    return a+  where+    n = U.length v+    writeInvert a i | j >= 0 && j < n = M.write a j i+                    | otherwise       = return ()+                    where j = v ! i++-- | Constuct bin permutation from function.+permuteBin :: Bin b => (Int -> Int) -> b -> Maybe (BinPermute b)+permuteBin f b = BinPermute b <$> checkPermutation to <*> checkPermutation (invertPermutation to)+    where+      to   = U.map f $ U.enumFromN 0 (nBins b)
Data/Histogram/Fill.hs view
@@ -1,188 +1,350 @@ {-# LANGUAGE GADTs        #-} {-# LANGUAGE Rank2Types   #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-} -- | -- Module     : Data.Histogram.Fill -- Copyright  : Copyright (c) 2009, Alexey Khudyakov <alexey.skladnoy@gmail.com> -- License    : BSD3 -- Maintainer : Alexey Khudyakov <alexey.skladnoy@gmail.com> -- Stability  : experimental--- +-- -- Module with algorithms for histogram filling. This is pure wrapper -- around stateful histograms.--- -module Data.Histogram.Fill ( -- * Type classes & wrappers-                             HBuilderCl(..)+--+module Data.Histogram.Fill ( -- * Type classes+                             HistBuilder(..)+                             -- * Histogram builders+                             -- ** Stateful+                           , HBuilderST+                           , feedOne+                           , freezeHBuilderST+                           , joinHBuilderST+                           , joinHBuilderSTList+                           , treeHBuilderST+                             -- ** IO based+                           , HBuilderIO+                           , feedOneIO+                           , freezeHBuilderIO+                           , joinHBuilderIO+                           , joinHBuilderIOList+                           , treeHBuilderIO+                             -- ** Stateless                            , HBuilder-                           , builderList-                           , builderListWrap--                           -- * Fill routines-                           , createHistograms--                           -- * Histogram constructors +                           , joinHBuilder+                           , joinHBuilderList+                           , treeHBuilder+                             -- ** Conversion between builders+                           , toBuilderST+                           , toBuilderIO+                           , builderSTtoIO+                           -- * Fill histograms+                           , fillBuilder+                           -- * Histogram constructors                            , module Data.Histogram.Bin-                           , mkHist+                           -- ** Fixed weigth histograms                            , mkHist1-                           , mkHistWgh+                           , mkHist+                           , mkHistMaybe+                           -- ** Weighted histograms                            , mkHistWgh1-                           , mkHistMonoid+                           , mkHistWgh+                           , mkHistWghMaybe+                           -- ** Histograms with monoidal bins                            , mkHistMonoid1+                           , mkHistMonoid+                           , mkHistMonoidMaybe+                           -- * Auxillary functions                            , forceInt                            , forceDouble                            , forceFloat-                           -- * Internals-                           , HistBuilder                            ) where -import Control.Monad.ST (ST)-import Data.Monoid      (Monoid, mempty)+import Control.Applicative ((<$>))+import Control.Monad       (when)+import Control.Monad.ST  -import Data.Array.Vector+import Data.Monoid         (Monoid, mempty)+import Data.Vector.Unboxed (Unbox)+ import Data.Histogram import Data.Histogram.Bin import Data.Histogram.ST  -------------------------------------------------------------------- | Create and fill histogram(s).-createHistograms :: Monoid b =>-                    HBuilder a b -- ^ Instructions how to fill histograms-                 -> [a]          -- ^ List of data to fill histogram with-                 -> b            -- ^ Result-createHistograms h xs = fillHistograms (runBuilder h) xs-+-- Type class ----------------------------------------------------------------  -- | Histogram builder typeclass. Instance of this class contain --   instructions how to build histograms.-class HBuilderCl h where +class HistBuilder h where     -- | Convert input type of histogram from a to a'-    modifyIn  :: (a' -> a) -> h a b -> h a' b -    -- | Convert output of histogram +    modifyIn  :: (a' -> a) -> h a b -> h a' b+    -- | Make input function accept value only if it's Just a.+    modifyMaybe :: h a b -> h (Maybe a) b+    -- | Add cut to histogram. Only put value histogram if condition is true.+    addCut    :: (a -> Bool) -> h a b -> h a b+    -- | Convert output of histogram     modifyOut :: (b -> b') -> h a b -> h a  b'-    -- | Create stateful histogram from instructions. Histograms could-    --   be filled either in the ST monad or with createHistograms-    runBuilder :: h a b -> ST s (Accum s a b) - ----------------------------------------------------------------+-- ST based builder+---------------------------------------------------------------- --- | Abstract histogram builder. All real builders should be wrapper---   in this type-data HBuilder a b where-    MkHBuilder :: HBuilderCl h => h a b -> HBuilder a b+-- | Stateful histogram builder.+data HBuilderST s a b = HBuilderST { hbInput  :: a -> ST s ()+                                   , hbOutput :: ST s b+                                   } -instance HBuilderCl HBuilder where -    modifyIn  f (MkHBuilder h) = MkHBuilder $ modifyIn f h-    modifyOut g (MkHBuilder h) = MkHBuilder $ modifyOut g h -    runBuilder  (MkHBuilder h) = runBuilder h+instance HistBuilder (HBuilderST s) where+    modifyIn  f h = h { hbInput  = hbInput h . f }+    addCut    f h = h { hbInput  = \x -> when (f x) (hbInput h x) }+    modifyMaybe h = h { hbInput  = modified } +        where modified (Just x) = hbInput h x+              modified Nothing  = return ()+    modifyOut f h = h { hbOutput = f `fmap` hbOutput h } +instance Functor (HBuilderST s a) where+    fmap = modifyOut +-- | Put one value into histogram+feedOne :: HBuilderST s a b -> a -> ST s ()+feedOne = hbInput++-- | Create stateful histogram from instructions. Histograms could+--   be filled either in the ST monad or with createHistograms+freezeHBuilderST :: HBuilderST s a b -> ST s b+freezeHBuilderST = hbOutput+++-- | Join list of builders into one builder+joinHBuilderST :: [HBuilderST s a b] -> HBuilderST s a [b]+joinHBuilderST hs = HBuilderST { hbInput  = \x -> mapM_ (flip hbInput x) hs+                               , hbOutput = mapM hbOutput hs+                               }++-- | Join list of builders into one builders+joinHBuilderSTList :: [HBuilderST s a [b]] -> HBuilderST s a [b]+joinHBuilderSTList = fmap concat . joinHBuilderST++treeHBuilderST :: [HBuilderST s a b -> HBuilderST s a' b'] -> HBuilderST s a b -> HBuilderST s a' [b']+treeHBuilderST fs h = joinHBuilderST $ map ($ h) fs+ ----------------------------------------------------------------+-- IO based+---------------------------------------------------------------- --- List of histograms. -newtype HBuilderList a b = HBuilderList [HBuilder a b]+-- | Stateful histogram builder.+data HBuilderIO a b = HBuilderIO { hbInputIO  :: a -> IO ()+                                 , hbOutputIO :: IO b+                                 } --- | Wrap list of histogram builders into HBuilder.-builderList :: [HBuilder a b] -> HBuilder a [b]-builderList = MkHBuilder . modifyOut (:[]) . HBuilderList+instance HistBuilder (HBuilderIO) where+    modifyIn  f h = h { hbInputIO  = hbInputIO h . f }+    addCut    f h = h { hbInputIO  = \x -> when (f x) (hbInputIO h x) }+    modifyMaybe h = h { hbInputIO  = modified } +        where modified (Just x) = hbInputIO h x+              modified Nothing  = return ()+    modifyOut f h = h { hbOutputIO = f `fmap` hbOutputIO h } --- | Wrap list of histogram builders into HBuilder and do not change return type.-builderListWrap :: [HBuilder a b] -> HBuilder a b-builderListWrap = MkHBuilder . HBuilderList+instance Functor (HBuilderIO a) where+    fmap = modifyOut -instance HBuilderCl HBuilderList where-    modifyIn  f (HBuilderList l) = HBuilderList $ map (modifyIn f) l-    modifyOut g (HBuilderList l) = HBuilderList $ map (modifyOut g) l-    runBuilder (HBuilderList l)  = accumList $ map runBuilder l+-- | Put one value into histogram+feedOneIO :: HBuilderIO a b -> a -> IO ()+feedOneIO = hbInputIO +-- | Create stateful histogram from instructions. Histograms could+--   be filled either in the ST monad or with createHistograms+freezeHBuilderIO :: HBuilderIO a b -> IO b+freezeHBuilderIO = hbOutputIO++-- | Join list of builders into one builder+joinHBuilderIO :: [HBuilderIO a b] -> HBuilderIO a [b]+joinHBuilderIO hs = HBuilderIO { hbInputIO  = \x -> mapM_ (flip hbInputIO x) hs+                               , hbOutputIO = mapM hbOutputIO hs+                               }++-- | Join list of builders into one builders+joinHBuilderIOList :: [HBuilderIO a [b]] -> HBuilderIO a [b]+joinHBuilderIOList = fmap concat . joinHBuilderIO++treeHBuilderIO :: [HBuilderIO a b -> HBuilderIO a' b'] -> HBuilderIO a b -> HBuilderIO a' [b']+treeHBuilderIO fs h = joinHBuilderIO $ map ($ h) fs+ ----------------------------------------------------------------+-- Stateless +---------------------------------------------------------------- --- | Generic histogram builder. -data HistBuilder a b where-    HistBuilder :: (Bin bin, UA val) =>-                   bin                                                -- Bin type-                -> val                                                -- Zero element-                -> (forall s . a -> HistogramST s bin val -> ST s ()) -- Input function-                -> (Histogram bin val -> b)                           -- Output function-                -> HistBuilder a b+-- | Stateless histogram builder+newtype HBuilder a b = HBuilder { toBuilderST :: (forall s . ST s (HBuilderST s a b)) } -instance HBuilderCl HistBuilder where-    modifyIn  f (HistBuilder bin z inp out) = HistBuilder bin z (inp . f) out-    modifyOut g (HistBuilder bin z inp out) = HistBuilder bin z  inp (g . out)-    runBuilder  (HistBuilder bin z inp out) = accumHist inp out =<< newHistogramST z bin+instance HistBuilder (HBuilder) where+    modifyIn  f (HBuilder h) = HBuilder (modifyIn  f <$> h)+    addCut    f (HBuilder h) = HBuilder (addCut    f <$> h)+    modifyMaybe (HBuilder h) = HBuilder (modifyMaybe <$> h)+    modifyOut f (HBuilder h) = HBuilder (modifyOut f <$> h) +instance Functor (HBuilder a) where+    fmap = modifyOut +-- | Join list of builders+joinHBuilder :: [HBuilder a b] -> HBuilder a [b]+joinHBuilder hs = HBuilder (joinHBuilderST <$> mapM toBuilderST hs) +-- | Join list of builders+joinHBuilderList :: [HBuilder a [b]] -> HBuilder a [b]+joinHBuilderList = modifyOut concat . joinHBuilder++treeHBuilder :: [HBuilder a b -> HBuilder a' b'] -> HBuilder a b -> HBuilder a' [b']+treeHBuilder fs h = joinHBuilder $ map ($ h) fs+ ------------------------------------------------------------------- Histogram constructors +-- Conversions ---------------------------------------------------------------- --- | Function used to restrict type of histrogram.-forceInt :: Histogram bin Int -> Histogram bin Int-forceInt = id+-- | Convert ST base builder to IO based one+builderSTtoIO :: HBuilderST RealWorld a b -> HBuilderIO a b+builderSTtoIO (HBuilderST i o) = HBuilderIO (stToIO . i) (stToIO o) --- | Function used to restrict type of histrogram.-forceDouble :: Histogram bin Double -> Histogram bin Double-forceDouble = id+-- | Convert stateless builder to IO based one+toBuilderIO :: HBuilder a b -> IO (HBuilderIO a b)+toBuilderIO h = builderSTtoIO `fmap` stToIO (toBuilderST h) --- | Function used to restrict type of histrogram.-forceFloat :: Histogram bin Float -> Histogram bin Float-forceFloat = id+----------------------------------------------------------------+-- Actual filling of histograms+---------------------------------------------------------------- +fillBuilder :: HBuilder a b -> [a] -> b+fillBuilder hb xs = +    runST $ do h <- toBuilderST hb+               mapM_ (feedOne h) xs+               freezeHBuilderST h+  +----------------------------------------------------------------+-- Histogram constructors+----------------------------------------------------------------+ -- | Create histogram builder which take single item as input. Each---   item has weight 1. To set type of bin 'force*' function could be used.-mkHist1 :: (Bin bin, UA val, Num val) =>+--   item has weight 1.+mkHist1 :: (Bin bin, Unbox val, Num val) =>            bin                      -- ^ Bin information         -> (Histogram bin val -> b) -- ^ Output function          -> (a -> BinValue bin)      -- ^ Input function         -> HBuilder a b-mkHist1 bin out inp = MkHBuilder $ HistBuilder bin 0 (flip fillOne . inp) out+mkHist1 bin out inp = HBuilder $ do+  acc <- newMHistogram 0 bin+  return $ HBuilderST { hbInput  = fillOne acc . inp+                      , hbOutput = fmap out (freezeHist acc)+                      }  -- | Create histogram builder which take many items as input. Each---   item has weight 1. To set type of bin 'force*' function could be---   used.-mkHist :: (Bin bin, UA val, Num val) =>+--   item has weight 1.+mkHist :: (Bin bin, Unbox val, Num val) =>           bin                      -- ^ Bin information        -> (Histogram bin val -> b) -- ^ Output function        -> (a -> [BinValue bin])    -- ^ Input function         -> HBuilder a b-mkHist bin out inp = MkHBuilder $ HistBuilder bin 0 fill out-    where-      fill a h = mapM_ (fillOne h) $ inp a+mkHist bin out inp = HBuilder $ do+  acc <- newMHistogram 0 bin+  return $ HBuilderST { hbInput  = mapM_ (fillOne acc) . inp+                      , hbOutput = fmap out (freezeHist acc)+                      } +-- | Create histogram builder which at most one item as input. Each+--   item has weight 1. +mkHistMaybe :: (Bin bin, Unbox val, Num val) =>+          bin                         -- ^ Bin information+       -> (Histogram bin val -> b)    -- ^ Output function+       -> (a -> Maybe (BinValue bin)) -- ^ Input function +       -> HBuilder a b+mkHistMaybe bin out inp = HBuilder $ do+  acc <- newMHistogram 0 bin+  return $ HBuilderST { hbInput  = maybe (return ()) (fillOne acc) . inp+                      , hbOutput = fmap out (freezeHist acc)+                      }+ -- | Create histogram with weighted bin. Takes one item at time. -mkHistWgh1 :: (Bin bin, UA val, Num val) =>+mkHistWgh1 :: (Bin bin, Unbox val, Num val) =>               bin                        -- ^ Bin information           -> (Histogram bin val -> b)    -- ^ Output function           -> (a -> (BinValue bin, val))  -- ^ Input function           -> HBuilder a b-mkHistWgh1 bin out inp = MkHBuilder $ HistBuilder bin 0 (flip fillOneW . inp) out+mkHistWgh1 bin out inp = HBuilder $ do+  acc <- newMHistogram 0 bin+  return $ HBuilderST { hbInput  = fillOneW acc . inp+                      , hbOutput = fmap out (freezeHist acc)+                      }  -- | Create histogram with weighted bin. Takes many items at time.-mkHistWgh :: (Bin bin, UA val, Num val) => +mkHistWgh :: (Bin bin, Unbox val, Num val) =>               bin                          -- ^ Bin information           -> (Histogram bin val  -> b)    -- ^ Output function           -> (a -> [(BinValue bin, val)]) -- ^ Input function           -> HBuilder a b-mkHistWgh bin out inp = MkHBuilder $ HistBuilder bin 0 fill out-    where-      fill a h = mapM_ (fillOneW h) $ inp a+mkHistWgh bin out inp = HBuilder $ do+  acc <- newMHistogram 0 bin+  return $ HBuilderST { hbInput  = mapM_ (fillOneW acc) . inp+                      , hbOutput = fmap out (freezeHist acc)+                      } +-- | Create histogram with weighted bin. Takes many items at time.+mkHistWghMaybe :: (Bin bin, Unbox val, Num val) => +                  bin                              -- ^ Bin information+               -> (Histogram bin val  -> b)        -- ^ Output function+               -> (a -> Maybe (BinValue bin, val)) -- ^ Input function+               -> HBuilder a b+mkHistWghMaybe bin out inp = HBuilder $ do+  acc <- newMHistogram 0 bin+  return $ HBuilderST { hbInput  = maybe (return ()) (fillOneW acc) . inp+                      , hbOutput = fmap out (freezeHist acc)+                      }+ -- | Create histogram with monoidal bins-mkHistMonoid1 :: (Bin bin, UA val, Monoid val) =>+mkHistMonoid1 :: (Bin bin, Unbox val, Monoid val) =>               bin                         -- ^ Bin information           -> (Histogram bin val -> b)     -- ^ Output function           -> (a -> (BinValue bin, val))   -- ^ Input function           -> HBuilder a b-mkHistMonoid1 bin out inp = MkHBuilder $ HistBuilder bin mempty (flip fillMonoid . inp) out+mkHistMonoid1 bin out inp = HBuilder $ do+  acc <- newMHistogram mempty bin+  return $ HBuilderST { hbInput  = fillMonoid acc . inp+                      , hbOutput = fmap out (freezeHist acc)+                      }  -- | Create histogram with monoidal bins. Takes many items at time.-mkHistMonoid :: (Bin bin, UA val, Monoid val) =>+mkHistMonoid :: (Bin bin, Unbox val, Monoid val) =>               bin                         -- ^ Bin information           -> (Histogram bin val -> b)     -- ^ Output function           -> (a -> [(BinValue bin, val)]) -- ^ Input function           -> HBuilder a b-mkHistMonoid bin out inp = MkHBuilder $ HistBuilder bin mempty fill out-    where-      fill a h = mapM_ (fillMonoid h) $ inp a+mkHistMonoid bin out inp = HBuilder $ do+  acc <- newMHistogram mempty bin+  return $ HBuilderST { hbInput  = mapM_ (fillMonoid acc) . inp+                      , hbOutput = fmap out (freezeHist acc)+                      }++-- | Create histogram with monoidal bins+mkHistMonoidMaybe :: (Bin bin, Unbox val, Monoid val) =>+                     bin                              -- ^ Bin information+                  -> (Histogram bin val -> b)         -- ^ Output function+                  -> (a -> Maybe (BinValue bin, val)) -- ^ Input function+                  -> HBuilder a b+mkHistMonoidMaybe bin out inp = HBuilder $ do+  acc <- newMHistogram mempty bin+  return $ HBuilderST { hbInput  = maybe (return ()) (fillMonoid acc) . inp+                      , hbOutput = fmap out (freezeHist acc)+                      }++----------------------------------------------------------------++-- | Function used to restrict type of histrogram.+forceInt :: Histogram bin Int -> Histogram bin Int+forceInt = id++-- | Function used to restrict type of histrogram.+forceDouble :: Histogram bin Double -> Histogram bin Double+forceDouble = id++-- | Function used to restrict type of histrogram.+forceFloat :: Histogram bin Float -> Histogram bin Float+forceFloat = id
+ Data/Histogram/Generic.hs view
@@ -0,0 +1,191 @@+{-# LANGUAGE FlexibleContexts #-}+-- |+-- Module     : Data.Histogram+-- Copyright  : Copyright (c) 2009, Alexey Khudyakov <alexey.skladnoy@gmail.com>+-- License    : BSD3+-- Maintainer : Alexey Khudyakov <alexey.skladnoy@gmail.com>+-- Stability  : experimental+-- +-- Generic immutable histograms. +module Data.Histogram.Generic ( +    -- * Data type+    Histogram+  , module Data.Histogram.Bin+  , histogram+  , histogramUO+    -- * Read histograms from string+  , readHistogram+  , readFileHistogram+    -- * Accessors+  , bins+  , histData+  , underflows+  , overflows+  , outOfRange+    -- ** Convert to other data types+  , asList+  , asVector+    -- * Slicing histograms+  , sliceX+  , sliceY+    -- * Modify histogram+  , histMap+  , histMapBin+  , histZip+  ) where++import Control.Applicative ((<$>),(<*>))+import Control.Arrow       ((***))+import Control.Monad       (ap, forM_)+import Control.Monad.ST    (runST)++import qualified Data.Vector.Generic.Mutable as M+import qualified Data.Vector.Generic as G+import Data.Vector.Generic  (Vector)+import Text.Read++import Data.Histogram.Bin+import Data.Histogram.Parse++----------------------------------------------------------------+-- Data type and smart constructors+----------------------------------------------------------------++-- | Immutable histogram. Histogram consists of binning algorithm,+--   optional number of under and overflows, and data. +data Histogram v bin a = Histogram bin (Maybe (a,a)) (v a)+                         deriving Eq++-- | Create histogram from binning algorithm and vector with+-- data. Overflows are set to Nothing. +--+-- Number of bins and vector size must match.+histogram :: (Vector v a, Bin bin) => bin -> v a -> Histogram v bin a+histogram b v | nBins b == G.length v = Histogram b Nothing v+              | otherwise             = error "histogram: number of bins and vector size doesn't match"+++-- | Create histogram from binning algorithm and vector with data. +--+-- Number of bins and vector size must match.+histogramUO :: (Vector v a, Bin bin) => bin -> Maybe (a,a) -> v a -> Histogram v bin a+histogramUO b uo v | nBins b == G.length v = Histogram b uo v+                   | otherwise             = error "histogram: number of bins and vector size doesn't match"+++----------------------------------------------------------------+-- Instances & reading histograms from strings +----------------------------------------------------------------++instance (Show a, Show (BinValue bin), Show bin, Bin bin, Vector v a) => Show (Histogram v bin a) where+    show h@(Histogram bin uo _) = "# Histogram\n" ++ showUO uo ++ show bin +++                                  (unlines $ map showT $ asList h)+        where+          showT (x,y) = show x ++ "\t" ++ show y+          showUO (Just (u,o)) = "# Underflows = " ++ show u ++ "\n" +++                                "# Overflows  = " ++ show o ++ "\n"+          showUO Nothing      = "# Underflows = \n" +++                                "# Overflows  = \n"++-- Parse histogram header+histHeader :: (Read bin, Read a, Bin bin, Vector v a) => ReadPrec (v a -> Histogram v bin a)+histHeader = do+  keyword "Histogram"+  u   <- maybeValue "Underflows"+  o   <- maybeValue "Overflows"+  bin <- readPrec+  return $ Histogram bin ((,) `fmap` u `ap` o)++-- | Convert String to histogram. Histogram do not have Read instance+--   because of slowness of ReadP+readHistogram :: (Read bin, Read a, Bin bin, Vector v a) => String -> Histogram v bin a+readHistogram str = +    let (h,rest) = case readPrec_to_S histHeader 0 str of+                     [x] -> x+                     _   -> error "Cannot parse histogram header"+        xs = map (unwords . tail) . filter (not . null) . map words . lines $ rest+    in h (G.fromList $ map read xs)++-- | Read histogram from file.+readFileHistogram :: (Read bin, Read a, Bin bin, Vector v a) => FilePath -> IO (Histogram v bin a)+readFileHistogram fname = readHistogram `fmap` readFile fname++----------------------------------------------------------------+-- Accessors & conversion+----------------------------------------------------------------++-- | Histogram bins+bins :: Histogram v bin a -> bin+bins (Histogram bin _ _) = bin++-- | Histogram data as vector+histData :: Histogram v bin a -> v a+histData (Histogram _ _ a) = a++-- | Number of underflows+underflows :: Histogram v bin a -> Maybe a+underflows (Histogram _ uo _) = fst <$> uo++-- | Number of overflows+overflows :: Histogram v bin a -> Maybe a+overflows (Histogram _ uo _) = snd <$> uo++-- | Underflows and overflows+outOfRange :: Histogram v bin a -> Maybe (a,a)+outOfRange (Histogram _ uo _) = uo++-- | Convert histogram to list.+asList :: (Vector v a, Bin bin) => Histogram v bin a -> [(BinValue bin, a)]+asList (Histogram bin _ arr) = map (fromIndex bin) [0..] `zip` G.toList arr++-- | Convert histogram to vector+asVector :: (Bin bin, Vector v a, Vector v (BinValue bin), Vector v (BinValue bin,a)) +         => Histogram v bin a -> v (BinValue bin, a) +asVector (Histogram bin _ arr) = G.zip (G.generate (nBins bin) (fromIndex bin) ) arr++----------------------------------------------------------------+-- Modify histograms+----------------------------------------------------------------++-- | fmap lookalike. It's not possible to create Functor instance+--   because of class restrictions+histMap :: (Vector v a, Vector v b) => (a -> b) -> Histogram v bin a -> Histogram v bin b+histMap f (Histogram bin uo a) = Histogram bin (fmap (f *** f) uo) (G.map f a)++-- | Apply function to histogram bins. Function must not change number of bins.+--   If it does error is thrown.+histMapBin :: (Bin bin, Bin bin') => (bin -> bin') -> Histogram v bin a -> Histogram v bin' a+histMapBin f (Histogram bin uo a)+    | nBins bin == nBins bin' = Histogram (f bin) uo a+    | otherwise               = error "Number of bins doesn't match"+    where+      bin' = bin++-- | Zip two histograms together. Bins of histograms must be equal+--   otherwise error will be called.+histZip :: (Bin bin, Eq bin, Vector v a, Vector v b, Vector v c) =>+           (a -> b -> c) -> Histogram v bin a -> Histogram v bin b -> Histogram v bin c+histZip f (Histogram bin uo v) (Histogram bin' uo' v')+    | bin /= bin' = error "histZip: bins are different"+    | otherwise   = Histogram bin (f2 <$> uo <*> uo') (G.zipWith f v v')+      where+        f2 (x,x') (y,y') = (f x y, f x' y')+           +-- | Slice 2D histogram along Y axis. This function is fast because it does not require reallocations.+sliceY :: (Vector v a, Bin bX, Bin bY) => Histogram v (Bin2D bX bY) a -> [(BinValue bY, Histogram v bX a)]+sliceY (Histogram b _ a) = map mkSlice [0 .. ny-1]+    where+      (nx, ny) = nBins2D b+      mkSlice i = ( fromIndex (binY b) i+                  , Histogram (binX b) Nothing (G.slice nx (nx*i) a) )++-- | Slice 2D histogram along X axis.+sliceX :: (Vector v a, Bin bX, Bin bY) => Histogram v (Bin2D bX bY) a -> [(BinValue bX, Histogram v bY a)]+sliceX (Histogram b _ a) = map mkSlice [0 .. nx-1]+    where+      (nx, ny)  = nBins2D b+      mkSlice i = ( fromIndex (binX b) i+                  , Histogram (binY b) Nothing (mkArray i))+      mkArray x = runST $ do arr <- M.new ny+                             forM_ [0 .. ny-1] $ \y -> M.write arr y (a G.! (y*nx + x))+                             G.unsafeFreeze arr
Data/Histogram/Parse.hs view
@@ -7,7 +7,6 @@  import Text.Read import Text.ParserCombinators.ReadP    (ReadP, many, satisfy, char, string)-import Text.ParserCombinators.ReadPrec  -- Whitespaces ws :: ReadP String@@ -28,8 +27,7 @@  getVal :: Read a => ReadPrec a getVal = do x <- readPrec-            lift eol -            return x+            lift eol >> return x  -- Key value pair value :: Read a => String -> ReadPrec a
Data/Histogram/ST.hs view
@@ -11,160 +11,84 @@ -- Mutable histograms.  module Data.Histogram.ST ( -- * Mutable histograms-                           HistogramST(..)-                         , newHistogramST+                           MHistogram+                         , newMHistogram                          , fillOne                          , fillOneW                          , fillMonoid                          , freezeHist--                         -- * Accumulators-                         , Accumulator(..)-                         , Accum(Accum)--                         , accumList-                         , accumHist--                         , fillHistograms                          ) where   import Control.Monad.ST -import Data.Array.Vector import Data.Monoid+import qualified Data.Vector.Unboxed as U+import qualified Data.Vector.Unboxed.Mutable as MU+import qualified Data.Vector.Generic as G  import Data.Histogram-import Data.Histogram.Bin - ---------------------------------------------------------------- -- Mutable histograms ----------------------------------------------------------------  -- | Mutable histogram.-data HistogramST s bin a where-    HistogramST :: (Bin bin, UA a) => -                   bin-                -> MUArr a s -- Over/underflows-                -> MUArr a s -- Data-                -> HistogramST s bin a+data MHistogram s bin a where+    MHistogram :: (Bin bin, MU.Unbox a) => +                  bin            -- Binning+               -> MU.MVector s a -- Over/underflows+               -> MU.MVector s a -- Data+               -> MHistogram s bin a  -- | Create new mutable histogram. All bins are set to zero element as --   passed to function.-newHistogramST :: (Bin bin, UA a) => a -> bin -> ST s (HistogramST s bin a)-newHistogramST zero bin = do-  uo <- newMU 2-  writeMU uo 0 zero >> writeMU uo 1 zero-  a <- newMU (nBins bin)-  mapM_ (\i -> writeMU a i zero) [0 .. (lengthMU a) - 1]-  return $ HistogramST bin uo a+newMHistogram :: (Bin bin, U.Unbox a) => a -> bin -> ST s (MHistogram s bin a)+newMHistogram zero bin = do+  uo <- MU.newWith 2 zero+  a  <- MU.newWith (nBins bin) zero+  return $ MHistogram bin uo a+{-# INLINE newMHistogram #-}  -- | Put one value into histogram-fillOne :: Num a => HistogramST s bin a -> BinValue bin -> ST s ()-fillOne (HistogramST bin uo arr) x-    | i < 0             = writeMU uo  0 . (+1)  =<< readMU uo 0-    | i >= lengthMU arr = writeMU uo  1 . (+1)  =<< readMU uo 1-    | otherwise         = writeMU arr i . (+1)  =<< readMU arr i+fillOne :: Num a => MHistogram s bin a -> BinValue bin -> ST s ()+fillOne (MHistogram bin uo arr) x+    | i < 0              = MU.unsafeWrite uo  0 . (+1)  =<< MU.unsafeRead uo 0+    | i >= MU.length arr = MU.unsafeWrite uo  1 . (+1)  =<< MU.unsafeRead uo 1+    | otherwise          = MU.unsafeWrite arr i . (+1)  =<< MU.unsafeRead arr i     where       i = toIndex bin x+{-# INLINE fillOne #-}  -- | Put one value into histogram with weight-fillOneW :: Num a => HistogramST s bin a -> (BinValue bin, a) -> ST s ()-fillOneW (HistogramST bin uo arr) (x,w)-    | i < 0             = writeMU uo  0 . (+w)  =<< readMU uo 0-    | i >= lengthMU arr = writeMU uo  1 . (+w)  =<< readMU uo 1-    | otherwise         = writeMU arr i . (+w)  =<< readMU arr i+fillOneW :: Num a => MHistogram s bin a -> (BinValue bin, a) -> ST s ()+fillOneW (MHistogram bin uo arr) (x,w)+    | i < 0              = MU.unsafeWrite uo  0 . (+w)  =<< MU.unsafeRead uo 0+    | i >= MU.length arr = MU.unsafeWrite uo  1 . (+w)  =<< MU.unsafeRead uo 1+    | otherwise          = MU.unsafeWrite arr i . (+w)  =<< MU.unsafeRead arr i     where       i = toIndex bin x+{-# INLINE fillOneW #-}   -- | Put one monoidal element-fillMonoid :: Monoid a => HistogramST s bin a -> (BinValue bin, a) -> ST s ()-fillMonoid (HistogramST bin uo arr) (x,m)-    | i < 0             = writeMU uo  1 . (flip mappend m)  =<< readMU uo  0-    | i >= lengthMU arr = writeMU uo  1 . (flip mappend m)  =<< readMU uo  1-    | otherwise         = writeMU arr i . (flip mappend m)  =<< readMU arr i-    where+fillMonoid :: Monoid a => MHistogram s bin a -> (BinValue bin, a) -> ST s ()+fillMonoid (MHistogram bin uo arr) (x,m)+    | i < 0              = MU.unsafeWrite uo  1 . (flip mappend m)  =<< MU.unsafeRead uo  0+    | i >= MU.length arr = MU.unsafeWrite uo  1 . (flip mappend m)  =<< MU.unsafeRead uo  1+    | otherwise          = MU.unsafeWrite arr i . (flip mappend m)  =<< MU.unsafeRead arr i+    where        i = toIndex bin x+{-# fillMonoid #-}  -- | Create immutable histogram from mutable one. This operation involve copying.-freezeHist :: HistogramST s bin a -> ST s (Histogram bin a)-freezeHist (HistogramST bin uo arr) = do-  [u,o] <- fromU `fmap` unsafeFreezeAllMU uo -- Is it safe???+freezeHist :: MHistogram s bin a -> ST s (Histogram bin a)+freezeHist (MHistogram bin uo arr) = do+  u <- MU.unsafeRead uo 0+  o <- MU.unsafeRead uo 1   -- Copy array-  let len = lengthMU arr-  tmp  <- newMU len-  memcpyOffMU arr tmp 0 0 len-  a    <- unsafeFreezeAllMU tmp-  return $ Histogram bin (Just (u,o)) a----------------------------------------------------------------------- Accumulator typeclass-------------------------------------------------------------------- | This is class with accumulation semantics. It's used to fill many---   histogram at once. It accept values of type a and return data of type b.-class Accumulator h where-    -- | Put one element into accumulator-    putOne  :: h s a b -> a   -> ST s () -    -- | Extract data from historam-    extract :: Monoid b => (h s a b) -> ST s b---- | Put many elements in histogram(s) at once -putMany :: Accumulator h => h s a b -> [a] -> ST s () -putMany !h = mapM_ (putOne h) ---- | Put all values into histogram and return result-fillHistograms :: Monoid b => (forall s . ST s (Accum s a b)) -> [a] -> b-fillHistograms h xs = runST $ do h' <- h-                                 putMany h' xs-                                 extract h'--------------------------------------------------------------------- GADT wrapper -------------------------------------------------------------------- | Abstract wrapper for histograms. -data Accum s a b where-    Accum :: Accumulator h => h s a b -> Accum s a b--instance Accumulator Accum where-    putOne  !(Accum h) !x = putOne h x -    extract !(Accum h)    = extract h---------------------------------------------------------------------- List of histograms------------------------------------------------------------------newtype AccumList s a b = AccumList [Accum s a b]- --- | Wrap list of histograms into one 'Accum'-accumList :: [ST s (Accum s a b)] -> ST s (Accum s a b)-accumList l = (Accum . AccumList) `fmap` sequence l--instance Accumulator AccumList where-    putOne  !(AccumList l) !x = mapM_ (flip putOne $ x) l -    extract !(AccumList l)    = mconcat `fmap` mapM extract l ---------------------------------------------------------------------- Generic histogram ------------------------------------------------------------------data AccumHist s a b where-    AccumHist :: (Bin bin) =>-                 (a -> HistogramST s bin val -> ST s ())-              -> (Histogram bin val -> b)-              -> HistogramST s bin val-              -> AccumHist s a b---- | Accumulator for arbitrary 'HistogramST' based histogram-accumHist :: (Bin bin) =>-             (a -> HistogramST s bin val -> ST s ())-          -> (Histogram bin val -> b)-          -> HistogramST s bin val-          -> ST s (Accum s a b)-accumHist inp out h = return . Accum $ AccumHist inp out h+  tmp  <- MU.new (MU.length arr)+  MU.copy tmp arr+  a    <- G.unsafeFreeze tmp+  return $ histogramUO bin (Just (u,o)) a+{-# INLINE freezeHist #-} -instance Accumulator AccumHist where-    putOne  !(AccumHist inp _ st) !x = inp x st-    extract !(AccumHist _ out st)    = out `fmap` freezeHist st
histogram-fill.cabal view
@@ -1,6 +1,6 @@ Name:           histogram-fill-Version:        0.1.0-Cabal-Version:  >= 1.2+Version:        0.2.0+Cabal-Version:  >= 1.6 License:        BSD3 License-File:   LICENSE Author:         Alexey Khudyakov@@ -15,12 +15,17 @@   .   This is very much work in progress so expect API breakage in future relesases. +source-repository head+  type:     hg+  location: http://bitbucket.org/Shimuuar/histogram-fill  Library-  Build-Depends:        base >=3 && <5, uvector >=0.1 && <0.2+  Build-Depends:        base >=3 && <5, vector   Exposed-modules:      Data.Histogram-                        Data.Histogram.Fill +                        Data.Histogram.Generic+                        Data.Histogram.Fill                         Data.Histogram.Bin+                        Data.Histogram.Bin.Extra                         Data.Histogram.ST   Other-modules:        Data.Histogram.Parse-  Ghc-options:          -O2 -Wall -auto-all+  Ghc-options:          -O2 -Wall