{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DeriveDataTypeable #-}
module Data.Histogram.Bin.LogBinD (
LogBinD
, logBinDIncrement
, logBinD
, logBinDN
) where
import Control.DeepSeq (NFData(..))
import Control.Monad (liftM3)
import GHC.Float (double2Int)
import Data.Data (Data,Typeable)
import Text.Read (Read(..))
import Data.Histogram.Bin.Classes
import Data.Histogram.Bin.Read
data LogBinD = LogBinD
{-# UNPACK #-} !Double
{-# UNPACK #-} !Double
{-# UNPACK #-} !Int
deriving (Eq,Data,Typeable)
logBinDIncrement :: LogBinD -> Double
logBinDIncrement (LogBinD _ x _) = x
logBinD :: Double
-> Int
-> Double
-> LogBinD
logBinD lo n hi
| lo * hi <= 0 = error "Data.Histogram.Bin.LogBinD.logBinD: interval must not inlude zero"
| n < 0 = error "Data.Histogram.Bin.LogBinD.logBinD: negative number of bins"
| otherwise = LogBinD lo ((hi/lo) ** (1 / fromIntegral n)) n
logBinDN :: Double
-> Double
-> Int
-> LogBinD
logBinDN lo rat n
| lo == 0 = error "Data.Histogram.Bin.LogBinD.logBinDN: zero lower bound"
| rat <= 1 = error "Data.Histogram.Bin.LogBinD.logBinDN: increment is lesser than 1"
| n < 0 = error "Data.Histogram.Bin.LogBinD.logBinDN: negative number of bins"
| otherwise = LogBinD lo rat n
floorD :: Double -> Int
floorD x | x < 0 = double2Int x - 1
| otherwise = double2Int x
{-# INLINE floorD #-}
instance Bin LogBinD where
type BinValue LogBinD = Double
toIndex (LogBinD base step _) !x = floorD $ logBase step (x / base)
fromIndex (LogBinD base step _) !i | i >= 0 = base * step ** (fromIntegral i + 0.5)
| otherwise = -1 / 0
nBins (LogBinD _ _ n) = n
{-# INLINE toIndex #-}
instance IntervalBin LogBinD where
binInterval (LogBinD base step _) i = (x, x*step) where x = base * step ** fromIntegral i
instance Bin1D LogBinD where
lowerLimit (LogBinD lo _ _) = lo
upperLimit (LogBinD lo r n) = lo * r ^ n
instance SliceableBin LogBinD where
unsafeSliceBin i j (LogBinD from step _) = LogBinD (from * step ^ i) step (j-i+1)
instance MergeableBin LogBinD where
unsafeMergeBins dir k b@(LogBinD from step _) =
case dir of
CutLower -> LogBinD (from * step^^r) (step^^k) n
CutHigher -> LogBinD from (step^^k) n
where
n = nBins b `div` k
r = nBins b - n * k
instance VariableBin LogBinD where
binSizeN (LogBinD base step _) n = let x = base * step ^ n in x*step - x
instance BinEq LogBinD where
binEq (LogBinD lo d n) (LogBinD lo' d' n')
= n == n'
&& abs (lo - lo') < eps * abs lo
&& abs (d - d' ) < eps * abs d
where
eps = 3e-11
instance Show LogBinD where
show b =
unlines [ "# LogBinD"
, "# Lo = " ++ show (lowerLimit b)
, "# N = " ++ show (nBins b)
, "# Hi = " ++ show (upperLimit b)
]
instance Read LogBinD where
readPrec = do
keyword "LogBinD"
liftM3 logBinD (value "Lo") (value "N") (value "Hi")
instance NFData LogBinD where
rnf b = b `seq` ()