module Statistics.Probability where
import Control.Lens
import Numeric.Log
import Data.Vector.Unboxed.Deriving
import Data.Vector.Unboxed (Unbox)
import Algebra.Structure.SemiRing
import Numeric.LogDomain
import Numeric.Limits
data IsNormalized = Normalized | NotNormalized
newtype Prob (n ∷ IsNormalized) x = Prob { getProb ∷ x }
deriving (Eq,Ord,Show,Read)
derivingUnbox "Prob"
[t| forall n x. Unbox x ⇒ Prob n x → x |] [| getProb |] [| Prob |]
deriving instance (Enum x) ⇒ Enum (Prob n x)
deriving instance (Num x) ⇒ Num (Prob n x)
deriving instance (Fractional x) ⇒ Fractional (Prob n x)
deriving instance (Floating x) ⇒ Floating (Prob n x)
deriving instance (Real x) ⇒ Real (Prob n x)
deriving instance (RealFrac x) ⇒ RealFrac (Prob n x)
deriving instance (RealFloat x) ⇒ RealFloat (Prob n x)
instance (Num r) ⇒ SemiRing (Prob n r) where
srplus = (+)
srmul = (*)
srzero = 0
srone = 1
prob ∷ (Ord x, Num x, Show x) ⇒ x → Prob Normalized x
prob x
| x >= 0 && x <= 1 = Prob x
| otherwise = error $ show x ++ " not in range of [0,...,1]"
{-# Inline prob #-}
prob' ∷ (Ord x, Num x, Show x) ⇒ x → Prob NotNormalized x
prob' = Prob
{-# Inline prob' #-}
newtype LogProb (n ∷ IsNormalized) x = LogProb { getLogProb ∷ x }
deriving (Eq,Ord,Show)
derivingUnbox "LogProb"
[t| forall n x. Unbox x ⇒ LogProb n x → x |] [| getLogProb |] [| LogProb |]
instance (Precise x, RealFloat x) ⇒ Num (LogProb n x) where
(+) = withLog2 (+)
(*) = withLog2 (*)
abs = withLog1 abs
signum = withLog1 signum
fromInteger = LogProb . fromInteger
negate = withLog1 negate
(-) = withLog2 (-)
instance (Num d, Fractional d) ⇒ NumericLimits (LogProb n d) where
minFinite = LogProb 0
maxFinite = LogProb (1/0)
withLog1 ∷ (Log x → Log y) → LogProb n x → LogProb n y
withLog1 op (LogProb x) = LogProb . ln $ op (Exp x)
{-# Inline withLog1 #-}
withLog2 ∷ (Log x → Log y → Log z) → LogProb n x → LogProb n y → LogProb n z
withLog2 op (LogProb x) (LogProb y) = LogProb . ln $ op (Exp x) (Exp y)
{-# Inline withLog2 #-}
p2lp ∷ (Floating x) ⇒ Prob n x → LogProb n x
p2lp (Prob x) = LogProb $ log x
{-# Inline p2lp #-}
lp2p ∷ (Floating x) ⇒ LogProb n x → Prob n x
lp2p (LogProb x) = Prob $ exp x
{-# Inline lp2p #-}
aslp ∷ (Floating x) ⇒ Iso' (Prob n x) (LogProb n x)
aslp = iso p2lp lp2p
{-# Inline aslp #-}