{-# LANGUAGE DeriveDataTypeable, DeriveGeneric, OverloadedStrings #-}
module Statistics.Distribution.DiscreteUniform
(
DiscreteUniform
, discreteUniform
, discreteUniformAB
, rangeFrom
, rangeTo
) where
import Control.Applicative ((<$>), (<*>), empty)
import Data.Aeson (FromJSON(..), ToJSON, Value(..), (.:))
import Data.Binary (Binary(..))
import Data.Data (Data, Typeable)
import GHC.Generics (Generic)
import qualified Statistics.Distribution as D
import Statistics.Internal
data DiscreteUniform = U {
rangeFrom :: {-# UNPACK #-} !Int
, rangeTo :: {-# UNPACK #-} !Int
} deriving (Eq, Typeable, Data, Generic)
instance Show DiscreteUniform where
showsPrec i (U a b) = defaultShow2 "discreteUniformAB" a b i
instance Read DiscreteUniform where
readPrec = defaultReadPrecM2 "discreteUniformAB" (\a b -> Just (discreteUniformAB a b))
instance ToJSON DiscreteUniform
instance FromJSON DiscreteUniform where
parseJSON (Object v) = do
a <- v .: "uniformA"
b <- v .: "uniformB"
return $ discreteUniformAB a b
parseJSON _ = empty
instance Binary DiscreteUniform where
put (U a b) = put a >> put b
get = discreteUniformAB <$> get <*> get
instance D.Distribution DiscreteUniform where
cumulative (U a b) x
| x < fromIntegral a = 0
| x > fromIntegral b = 1
| otherwise = fromIntegral (floor x - a + 1) / fromIntegral (b - a + 1)
instance D.DiscreteDistr DiscreteUniform where
probability (U a b) k
| k >= a && k <= b = 1 / fromIntegral (b - a + 1)
| otherwise = 0
instance D.Mean DiscreteUniform where
mean (U a b) = fromIntegral (a+b)/2
instance D.Variance DiscreteUniform where
variance (U a b) = (fromIntegral (b - a + 1)^(2::Int) - 1) / 12
instance D.MaybeMean DiscreteUniform where
maybeMean = Just . D.mean
instance D.MaybeVariance DiscreteUniform where
maybeStdDev = Just . D.stdDev
maybeVariance = Just . D.variance
instance D.Entropy DiscreteUniform where
entropy (U a b) = log $ fromIntegral $ b - a + 1
instance D.MaybeEntropy DiscreteUniform where
maybeEntropy = Just . D.entropy
discreteUniform :: Int
-> DiscreteUniform
discreteUniform n
| n < 1 = error $ msg ++ "range must be > 0. Got " ++ show n
| otherwise = U 1 n
where msg = "Statistics.Distribution.DiscreteUniform.discreteUniform: "
discreteUniformAB :: Int
-> Int
-> DiscreteUniform
discreteUniformAB a b
| b < a = U b a
| otherwise = U a b