{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE CPP #-} {-# LANGUAGE BangPatterns #-} {-# LANGUAGE TypeFamilies #-} {- λ: let bin = binDU (V.fromList [0,1,2]) λ: bin # BinDU cuts 0.0 1.0 2.0 λ: addCut bin 3 # BinDU cuts 0.0 1.0 2.0 3.0 λ: deleteCut bin 0 # BinDU cuts 1.0 2.0 -} module Data.Histogram.Bin.BinDU ( -- * Specialized to Double, Unboxed Vectors BinDU(..) , binDU , cuts , unsafeBinDU , AdaptableBin(..) ) where import Control.DeepSeq (NFData(..)) import Data.Data (Data,Typeable) import Data.Vector.Unboxed (Vector,(!)) import qualified Data.Vector.Unboxed as VU import Data.Maybe import Data.Histogram.Bin.Classes -- | Double bins of unequal sizes. -- Bins are defined by a vector of cuts marking bounadries between bins (The entire range is continuous. There are n+1 cuts for n bins -- Cuts are assumed to be in ascending order -- Specialized on Data.Vector.Unboxed -- TODO: Generic Vector type. -- Type paramter: -- -- [@v@] type of vector used to define bin cuts data BinDU = BinDU !(Vector Double) -- vector of cuts deriving (Data,Typeable,Eq) -- | Create bins unsafely unsafeBinDU :: Vector Double -- ^ cuts -> BinDU unsafeBinDU = BinDU binDU :: Vector Double -- ^ cuts -> BinDU binDU c | VU.length c < 2 = error "Data.Histogram.Bin.BinDU.binDU': nonpositive number of bins" | VU.any (uncurry (>)) (VU.zip (VU.init c) (VU.drop 1 c)) = error "Data.Histogram.Bin.BinDU.binDU': cuts not in ascending order" | otherwise = BinDU c cuts :: BinDU -> Vector Double cuts (BinDU c) = c instance Bin BinDU where type BinValue BinDU = Double toIndex (BinDU c) !x = case VU.findIndex (>x) c of Nothing -> error "Data.Histogram.Bin.BinDU.toIndex: above range" Just i -> case i of 0 -> error "Data.Histogram.Bin.BinDU.toIndex: below range" _ -> i-1 fromIndex (BinDU c) !i | i >= VU.length c - 1 = error "Data.Histogram.Bin.BinDU.fromIndex: above range" | otherwise = ((c ! i) + (c ! (i+1)))/2 nBins (BinDU c) = if VU.length c < 2 then 0 else VU.length c - 1 {-# INLINE toIndex #-} instance IntervalBin BinDU where binInterval (BinDU c) i = (c ! i, c ! (i+1)) instance Bin1D BinDU where lowerLimit (BinDU c) = VU.head c upperLimit (BinDU c) = VU.last c instance SliceableBin BinDU where unsafeSliceBin i j (BinDU c) = BinDU (VU.drop i $ VU.take (j-i) c) instance VariableBin BinDU where binSizeN (BinDU c) !i = c ! (i+1) - c ! i -- | Equality is up to 3e-11 (2/3th of digits) instance BinEq BinDU where binEq (BinDU c) (BinDU c') = isNothing (VU.find (\(d,d') -> d - d' > eps * abs d) $ VU.zip c c') where eps = 3e-11 instance Show BinDU where show (BinDU c) = "# BinDU cuts\n" ++ concat (fmap showCut $ VU.toList c) ++ "\n\n" where showCut x = show x ++ "\t" instance NFData BinDU -- | Binning algorithms which support adaption. class Bin b => AdaptableBin b where -- | delete a bin deleteCut :: b -> Int -> b -- | add a new bin addCut :: b -> Double -> b instance AdaptableBin BinDU where deleteCut (BinDU c) !i | VU.length c <= 2 = error "Data.Histogram.Bin.BinDU.deletBin: deleting single bin" | otherwise = BinDU (VU.take i c VU.++ VU.drop (i+1) c) addCut (BinDU c) !x = BinDU (VU.concat [VU.take i c, VU.singleton x, VU.drop i c]) where i = fromMaybe (VU.length c) (VU.findIndex (> x) c)