gev-lib-0.1.0.0: src/Gev/GevDist.hs
module Gev.GevDist
(
GevDistribution
-- * constructors
, gevDist
, gevDistMaybe
-- * accessors
, location
, scale
, shape
) where
import qualified Gev
data GevDistribution = GEV {
location :: {-# UNPACK #-} !Double
, scale :: {-# UNPACK #-} !Double
, shape :: {-# UNPACK #-} !Double
} deriving (Eq)
instance Show GevDistribution where
show (GEV loc sc sh) = show "GEV Distribution; loc: " ++ show loc ++ ", scale: " ++ show sc ++ " and shape: " ++ show sh
-- error message when initiating GEV Distribution with scale parameter less than 0.
gevErrMsg :: Double -> Double -> Double -> String
gevErrMsg loc scale sh = "Gev.GevDist: "
++ "loc = " ++ show loc
++ " scale = " ++ show scale
++ " schape = " ++ show sh
++ ", but the scale parameter must be positive!"
gevDistMaybe :: Double -> Double -> Double -> Maybe GevDistribution
gevDistMaybe loc sc sh
| sc > 0 = Just $ GEV loc sc sh
| otherwise = Nothing
gevDist :: Double -> Double -> Double -> GevDistribution
gevDist loc sc sh = maybe (error $ gevErrMsg loc sc sh) id $ gevDistMaybe loc sh sc
-- | helper function: checks that the given x value falls in the valid part of the GEV domain.
-- -- actually this i isn't needed, just included as a guard pattern it'll be fine..
gevDomainCheck :: GevDistribution -> Double -> Bool
gevDomainCheck (GEV loc sc sh) x =
if 1 + sh * (x - loc / sc) > 0 then True else False
-- | t(x) function depends on if the shape parameter (\zeta) is 0 or not.
-- t(x) = \exp \left(x) = \left( 1 + \zeta \left( \frac{x - \mu}{ \sigma} \right) \right)^{- \frac{1}{\zeta}}$$ if $\zeta \neq 0$,
-- or $t(x) = \exp \left \{ - \frac{x - \mu}{ \sigma } \right \}$ if $\zeta = 0$
gevArg :: Double -> Double -> Double -> Double -> Double
gevArg loc sc sh x =
if sh == 0 then one else two
where
y = (x - loc) / sc
one = exp $ - y
two = (1 + sh * y) ** (- 1 / sh)
-- | CDF of the GEV Distribution.
cdfGEV :: GevDistribution -> Double -> Double
cdfGEV (GEV loc sc sh) x
| x <= 0 = 0
| 1 + sh * (x - loc / sc) > 0 = exp $ - tVal
| otherwise =
error $ "Gev.GevDist.cdf: The given x value is not in the support of the Distribution: " ++ show x
where
tVal = gevArg loc sc sh x
-- | PDF of the GEV Distribution.
pdfGEV :: GevDistribution -> Double -> Double
pdfGEV (GEV loc sc sh) x
| 1 + sh * (x - loc / sc) > 0 = const * middle * exp ( - tVal)
| otherwise =
error $ "Gev.GevDist.pdf: The given x value is not in the support of the Distribution: " ++ show x
where
tVal = gevArg loc sc sh x
const = 1 / sc
middle = tVal ** (sh + 1)
-- | Quantile function of the GEV Distribution
-- Quantile function of the Frechet Distribution
quantileGEV :: GevDistribution -> Double -> Double
quantileGEV (GEV loc sc sh) x
| x == 0 = -inf
| x == 1 = inf
| x > 0 && x < 1 = if sh == 0 then one else two
| otherwise =
error $ "Gev.GEVDist.quantile: The given value must be between 0 and 1, got: " ++ show x
where
inf = 1 / 0
logx = - log x
one = - sc * log logx + loc
const = sc / sh
two = const * (logx ** (- sh)) - const + loc
instance Gev.Distribution GevDistribution where
cdf = cdfGEV
pdf = pdfGEV
quantile = quantileGEV