{-# LANGUAGE
    MultiParamTypeClasses,
    FlexibleInstances, FlexibleContexts,
    UndecidableInstances
  #-}

module Data.Random.Distribution.Triangular where

import Data.Random.RVar
import Data.Random.Distribution
import Data.Random.Distribution.Uniform

-- |A description of a triangular distribution - a distribution whose PDF
-- is a triangle ramping up from a lower bound to a specified midpoint
-- and back down to the upper bound.  This is a very simple distribution
-- that does not generally occur naturally but is used sometimes as an
-- estimate of a true distribution when only the range of the values and
-- an approximate mode of the true distribution are known.
data Triangular a = Triangular {
    -- |The lower bound of the triangle in the PDF (the smallest number the distribution can generate)
    Triangular a -> a
triLower  :: a,
    -- |The midpoint of the triangle (also the mode of the distribution)
    Triangular a -> a
triMid    :: a,
    -- |The upper bound of the triangle (and the largest number the distribution can generate)
    Triangular a -> a
triUpper  :: a}
    deriving (Triangular a -> Triangular a -> Bool
(Triangular a -> Triangular a -> Bool)
-> (Triangular a -> Triangular a -> Bool) -> Eq (Triangular a)
forall a. Eq a => Triangular a -> Triangular a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Triangular a -> Triangular a -> Bool
$c/= :: forall a. Eq a => Triangular a -> Triangular a -> Bool
== :: Triangular a -> Triangular a -> Bool
$c== :: forall a. Eq a => Triangular a -> Triangular a -> Bool
Eq, Int -> Triangular a -> ShowS
[Triangular a] -> ShowS
Triangular a -> String
(Int -> Triangular a -> ShowS)
-> (Triangular a -> String)
-> ([Triangular a] -> ShowS)
-> Show (Triangular a)
forall a. Show a => Int -> Triangular a -> ShowS
forall a. Show a => [Triangular a] -> ShowS
forall a. Show a => Triangular a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Triangular a] -> ShowS
$cshowList :: forall a. Show a => [Triangular a] -> ShowS
show :: Triangular a -> String
$cshow :: forall a. Show a => Triangular a -> String
showsPrec :: Int -> Triangular a -> ShowS
$cshowsPrec :: forall a. Show a => Int -> Triangular a -> ShowS
Show)

-- |Compute a triangular distribution for a 'Floating' type.
floatingTriangular :: (Floating a, Ord a, Distribution StdUniform a) => a -> a -> a -> RVarT m a
floatingTriangular :: a -> a -> a -> RVarT m a
floatingTriangular a
a a
b a
c
    | a
a a -> a -> Bool
forall a. Ord a => a -> a -> Bool
> a
b     = a -> a -> a -> RVarT m a
forall a (m :: * -> *).
(Floating a, Ord a, Distribution StdUniform a) =>
a -> a -> a -> RVarT m a
floatingTriangular a
b a
a a
c
    | a
b a -> a -> Bool
forall a. Ord a => a -> a -> Bool
> a
c     = a -> a -> a -> RVarT m a
forall a (m :: * -> *).
(Floating a, Ord a, Distribution StdUniform a) =>
a -> a -> a -> RVarT m a
floatingTriangular a
a a
c a
b
    | Bool
otherwise = do
        let p :: a
p = (a
ca -> a -> a
forall a. Num a => a -> a -> a
-a
b)a -> a -> a
forall a. Fractional a => a -> a -> a
/(a
ca -> a -> a
forall a. Num a => a -> a -> a
-a
a)
        a
u <- RVarT m a
forall a (m :: * -> *). Distribution StdUniform a => RVarT m a
stdUniformT
        let d :: a
d   | a
u a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= a
p    = a
a
                | Bool
otherwise = a
c
            x :: a
x   | a
u a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= a
p    = (a
u a -> a -> a
forall a. Num a => a -> a -> a
- a
p) a -> a -> a
forall a. Fractional a => a -> a -> a
/ (a
1 a -> a -> a
forall a. Num a => a -> a -> a
- a
p)
                | Bool
otherwise = a
u a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
p
-- may prefer this: reusing u costs resolution, especially if p or 1-p is small and c-a is large.
--        x <- stdUniform
        a -> RVarT m a
forall (m :: * -> *) a. Monad m => a -> m a
return (a
b a -> a -> a
forall a. Num a => a -> a -> a
- ((a
1 a -> a -> a
forall a. Num a => a -> a -> a
- a -> a
forall a. Floating a => a -> a
sqrt a
x) a -> a -> a
forall a. Num a => a -> a -> a
* (a
ba -> a -> a
forall a. Num a => a -> a -> a
-a
d)))

-- |@triangularCDF a b c@ is the CDF of @realFloatTriangular a b c@.
triangularCDF :: RealFrac a => a -> a -> a -> a -> Double
triangularCDF :: a -> a -> a -> a -> Double
triangularCDF a
a a
b a
c a
x
    | a
x a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
a
    = Double
0
    | a
x a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= a
b
    = a -> Double
forall a b. (Real a, Fractional b) => a -> b
realToFrac ((a
x a -> a -> a
forall a. Num a => a -> a -> a
- a
a)a -> Int -> a
forall a b. (Num a, Integral b) => a -> b -> a
^(Int
2 :: Int) a -> a -> a
forall a. Fractional a => a -> a -> a
/ ((a
c a -> a -> a
forall a. Num a => a -> a -> a
- a
a) a -> a -> a
forall a. Num a => a -> a -> a
* (a
b a -> a -> a
forall a. Num a => a -> a -> a
- a
a)))
    | a
x a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= a
c
    = a -> Double
forall a b. (Real a, Fractional b) => a -> b
realToFrac (a
1 a -> a -> a
forall a. Num a => a -> a -> a
- (a
c a -> a -> a
forall a. Num a => a -> a -> a
- a
x)a -> Int -> a
forall a b. (Num a, Integral b) => a -> b -> a
^(Int
2 :: Int) a -> a -> a
forall a. Fractional a => a -> a -> a
/ ((a
c a -> a -> a
forall a. Num a => a -> a -> a
- a
a) a -> a -> a
forall a. Num a => a -> a -> a
* (a
c a -> a -> a
forall a. Num a => a -> a -> a
- a
b)))
    | Bool
otherwise
    = Double
1

instance (RealFloat a, Ord a, Distribution StdUniform a) => Distribution Triangular a where
    rvarT :: Triangular a -> RVarT n a
rvarT (Triangular a
a a
b a
c) = a -> a -> a -> RVarT n a
forall a (m :: * -> *).
(Floating a, Ord a, Distribution StdUniform a) =>
a -> a -> a -> RVarT m a
floatingTriangular a
a a
b a
c
instance (RealFrac a, Distribution Triangular a) => CDF Triangular a where
    cdf :: Triangular a -> a -> Double
cdf  (Triangular a
a a
b a
c) = a -> a -> a -> a -> Double
forall a. RealFrac a => a -> a -> a -> a -> Double
triangularCDF a
a a
b a
c