{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE RankNTypes #-}

module LAoP.Dist.Internal
        (
        Dist(..),
        Prob,

        Countable,
        CountableN,
        CountableDimsN,
        FLN,
        Liftable,
        TrivialP,

        fmapD,
        unitD,
        multD,
        selectD,
        branchD,
        ifD,
        returnD,
        bindD,
        (??),

        choose,
        shape,
        linear,
        uniform,
        negExp,
        normal,
        toValues,
        prettyDist,
        prettyPrintDist
        )
    where

import LAoP.Matrix.Type hiding (TrivialP, Countable, CountableDims, CountableN, CountableDimsN, Liftable, FLN)
import Prelude hiding (id, (.))
import qualified LAoP.Matrix.Internal as I
import LAoP.Utils
import GHC.TypeLits
import Data.Proxy
import Data.List (sortBy)
import Control.DeepSeq
import Data.Bool

-- | Type synonym for probability value
type Prob = Double

-- | Type synonym for column vector matrices. This represents a probability
-- distribution.
newtype Dist a = D (Matrix Prob () a)
  deriving (Int -> Dist a -> ShowS
[Dist a] -> ShowS
Dist a -> String
(Int -> Dist a -> ShowS)
-> (Dist a -> String) -> ([Dist a] -> ShowS) -> Show (Dist a)
forall a. Int -> Dist a -> ShowS
forall a. [Dist a] -> ShowS
forall a. Dist a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Dist a] -> ShowS
$cshowList :: forall a. [Dist a] -> ShowS
show :: Dist a -> String
$cshow :: forall a. Dist a -> String
showsPrec :: Int -> Dist a -> ShowS
$cshowsPrec :: forall a. Int -> Dist a -> ShowS
Show, Integer -> Dist a
Dist a -> Dist a
Dist a -> Dist a -> Dist a
(Dist a -> Dist a -> Dist a)
-> (Dist a -> Dist a -> Dist a)
-> (Dist a -> Dist a -> Dist a)
-> (Dist a -> Dist a)
-> (Dist a -> Dist a)
-> (Dist a -> Dist a)
-> (Integer -> Dist a)
-> Num (Dist a)
forall a. Integer -> Dist a
forall a. Dist a -> Dist a
forall a. Dist a -> Dist a -> Dist a
forall a.
(a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a)
-> (a -> a)
-> (a -> a)
-> (Integer -> a)
-> Num a
fromInteger :: Integer -> Dist a
$cfromInteger :: forall a. Integer -> Dist a
signum :: Dist a -> Dist a
$csignum :: forall a. Dist a -> Dist a
abs :: Dist a -> Dist a
$cabs :: forall a. Dist a -> Dist a
negate :: Dist a -> Dist a
$cnegate :: forall a. Dist a -> Dist a
* :: Dist a -> Dist a -> Dist a
$c* :: forall a. Dist a -> Dist a -> Dist a
- :: Dist a -> Dist a -> Dist a
$c- :: forall a. Dist a -> Dist a -> Dist a
+ :: Dist a -> Dist a -> Dist a
$c+ :: forall a. Dist a -> Dist a -> Dist a
Num, Dist a -> Dist a -> Bool
(Dist a -> Dist a -> Bool)
-> (Dist a -> Dist a -> Bool) -> Eq (Dist a)
forall a. Dist a -> Dist a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Dist a -> Dist a -> Bool
$c/= :: forall a. Dist a -> Dist a -> Bool
== :: Dist a -> Dist a -> Bool
$c== :: forall a. Dist a -> Dist a -> Bool
Eq, Eq (Dist a)
Eq (Dist a)
-> (Dist a -> Dist a -> Ordering)
-> (Dist a -> Dist a -> Bool)
-> (Dist a -> Dist a -> Bool)
-> (Dist a -> Dist a -> Bool)
-> (Dist a -> Dist a -> Bool)
-> (Dist a -> Dist a -> Dist a)
-> (Dist a -> Dist a -> Dist a)
-> Ord (Dist a)
Dist a -> Dist a -> Bool
Dist a -> Dist a -> Ordering
Dist a -> Dist a -> Dist a
forall a. Eq (Dist a)
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall a. Dist a -> Dist a -> Bool
forall a. Dist a -> Dist a -> Ordering
forall a. Dist a -> Dist a -> Dist a
min :: Dist a -> Dist a -> Dist a
$cmin :: forall a. Dist a -> Dist a -> Dist a
max :: Dist a -> Dist a -> Dist a
$cmax :: forall a. Dist a -> Dist a -> Dist a
>= :: Dist a -> Dist a -> Bool
$c>= :: forall a. Dist a -> Dist a -> Bool
> :: Dist a -> Dist a -> Bool
$c> :: forall a. Dist a -> Dist a -> Bool
<= :: Dist a -> Dist a -> Bool
$c<= :: forall a. Dist a -> Dist a -> Bool
< :: Dist a -> Dist a -> Bool
$c< :: forall a. Dist a -> Dist a -> Bool
compare :: Dist a -> Dist a -> Ordering
$ccompare :: forall a. Dist a -> Dist a -> Ordering
$cp1Ord :: forall a. Eq (Dist a)
Ord, Dist a -> ()
(Dist a -> ()) -> NFData (Dist a)
forall a. Dist a -> ()
forall a. (a -> ()) -> NFData a
rnf :: Dist a -> ()
$crnf :: forall a. Dist a -> ()
NFData) via (Matrix Prob () a)

-- | Constraint type synonyms to keep the type signatures less convoluted
type Countable a        = KnownNat (I.Count a)
type CountableN a       = KnownNat (I.Count (I.Normalize a))
type CountableDimsN a b = (CountableN a, CountableN b)
type FLN a b            = I.FL (I.Normalize a) (I.Normalize b)
type Liftable a b       = (Bounded a, Bounded b, Enum a, Enum b, Eq b, Num Prob, Ord Prob)
type TrivialP a b       = Normalize (a, b) ~ Normalize (Normalize a, Normalize b)

-- | Functor instance
fmapD :: 
     ( Liftable a b,
       CountableDimsN a b,
       FLN b a
     )
     =>
     (a -> b) -> Dist a -> Dist b
fmapD :: (a -> b) -> Dist a -> Dist b
fmapD a -> b
f (D Matrix Prob () a
m) = Matrix Prob () b -> Dist b
forall a. Matrix Prob () a -> Dist a
D ((a -> b) -> Matrix Prob a b
forall e a b cols rows.
(Liftable e a b, CountableDimsN cols rows, FLN rows cols) =>
(a -> b) -> Matrix e cols rows
fromF' a -> b
f Matrix Prob a b -> Matrix Prob () a -> Matrix Prob () b
forall e cr rows cols.
Num e =>
Matrix e cr rows -> Matrix e cols cr -> Matrix e cols rows
`comp` Matrix Prob () a
m)

-- | Applicative/Monoidal instance 'unit' function
unitD :: Dist ()
unitD :: Dist ()
unitD = Matrix Prob () () -> Dist ()
forall a. Matrix Prob () a -> Dist a
D (Prob -> Matrix Prob () ()
forall e. e -> Matrix e () ()
one Prob
1)

-- | Applicative/Monoidal instance 'mult' function
multD :: 
      ( CountableDimsN a b,
        CountableN (a, b),
        FLN (a, b) a,
        FLN (a, b) b,
        TrivialP a b
      ) => Dist a -> Dist b -> Dist (a, b)
multD :: Dist a -> Dist b -> Dist (a, b)
multD (D Matrix Prob () a
a) (D Matrix Prob () b
b) = Matrix Prob () (a, b) -> Dist (a, b)
forall a. Matrix Prob () a -> Dist a
D (Matrix Prob () a -> Matrix Prob () b -> Matrix Prob () (a, b)
forall e cols a b.
(Num e, CountableDimsN a b, CountableN (a, b), FLN (a, b) a,
 FLN (a, b) b, TrivialP a b) =>
Matrix e cols a -> Matrix e cols b -> Matrix e cols (a, b)
kr Matrix Prob () a
a Matrix Prob () b
b)

-- | Selective instance function
selectD :: 
       ( FLN b b,
         CountableN b
       ) => Dist (Either a b) -> Matrix Prob a b -> Dist b
selectD :: Dist (Either a b) -> Matrix Prob a b -> Dist b
selectD (D Matrix Prob () (Either a b)
d) Matrix Prob a b
m = Matrix Prob () b -> Dist b
forall a. Matrix Prob () a -> Dist a
D (Matrix Prob () (Either a b) -> Matrix Prob a b -> Matrix Prob () b
forall e b cols a.
(Num e, FLN b b, CountableN b) =>
Matrix e cols (Either a b) -> Matrix e a b -> Matrix e cols b
selectM Matrix Prob () (Either a b)
d Matrix Prob a b
m)

-- | Chooses which of the two given effectful
-- functions to apply to a given argument; 
branchD ::
       ( Num e,
         CountableDimsN a b,
         CountableDimsN c (Either b c),
         FLN c b,
         FLN a b,
         FLN a a,
         FLN b b,
         FLN c c,
         FLN b a,
         FLN b c,
         FLN (Either b c) b,
         FLN (Either b c) c
       )
       => Dist (Either a b) -> Matrix Prob a c -> Matrix Prob b c -> Dist c
branchD :: Dist (Either a b) -> Matrix Prob a c -> Matrix Prob b c -> Dist c
branchD Dist (Either a b)
x Matrix Prob a c
l Matrix Prob b c
r = Dist (Either a b) -> Dist (Either a (Either b c))
forall n a n.
(KnownNat (Count (Normalize n)), KnownNat (Count (Normalize a)),
 KnownNat (Count (Normalize n)),
 FromLists (Normalize n) (Normalize n),
 FromLists (Normalize n) (Normalize a),
 FromLists (Normalize n) (Normalize n),
 FromLists (Normalize a) (Normalize a),
 FromLists (Normalize a) (Normalize n)) =>
Dist (Either a n) -> Dist (Either a (Either n n))
f Dist (Either a b)
x Dist (Either a (Either b c))
-> Matrix Prob a (Either b c) -> Dist (Either b c)
forall b a.
(FLN b b, CountableN b) =>
Dist (Either a b) -> Matrix Prob a b -> Dist b
`selectD` Matrix Prob a c -> Matrix Prob a (Either b c)
forall e cr m cols.
(Num e, KnownNat (Count (Normalize cr)),
 KnownNat (Count (Normalize m)),
 FromLists (Normalize m) (Normalize cr),
 FromLists (Normalize cr) (Normalize cr)) =>
Matrix e cols cr -> Matrix e cols (Either m cr)
g Matrix Prob a c
l Dist (Either b c) -> Matrix Prob b c -> Dist c
forall b a.
(FLN b b, CountableN b) =>
Dist (Either a b) -> Matrix Prob a b -> Dist b
`selectD` Matrix Prob b c
r
  where
    f :: Dist (Either a n) -> Dist (Either a (Either n n))
f (D Matrix Prob () (Either a n)
m) = Matrix Prob () (Either a (Either n n))
-> Dist (Either a (Either n n))
forall a. Matrix Prob () a -> Dist a
D (Matrix Prob (Either a n) a
-> Matrix Prob (Either a n) (Either n n)
-> Matrix Prob (Either a n) (Either a (Either n n))
forall e cols a b.
Matrix e cols a -> Matrix e cols b -> Matrix e cols (Either a b)
fork (Matrix Prob a (Either a n) -> Matrix Prob (Either a n) a
forall e cols rows. Matrix e cols rows -> Matrix e rows cols
tr Matrix Prob a (Either a n)
forall e n m.
(Num e, CountableDimsN n m, FLN n m, FLN m m) =>
Matrix e m (Either m n)
i1) (Matrix Prob n (Either n n)
forall e n m.
(Num e, CountableDimsN n m, FLN n m, FLN m m) =>
Matrix e m (Either m n)
i1 Matrix Prob n (Either n n)
-> Matrix Prob (Either a n) n
-> Matrix Prob (Either a n) (Either n n)
forall e cr rows cols.
Num e =>
Matrix e cr rows -> Matrix e cols cr -> Matrix e cols rows
`comp` Matrix Prob n (Either a n) -> Matrix Prob (Either a n) n
forall e cols rows. Matrix e cols rows -> Matrix e rows cols
tr Matrix Prob n (Either a n)
forall e n m.
(Num e, CountableDimsN n m, FLN m n, FLN n n) =>
Matrix e n (Either m n)
i2) Matrix Prob (Either a n) (Either a (Either n n))
-> Matrix Prob () (Either a n)
-> Matrix Prob () (Either a (Either n n))
forall e cr rows cols.
Num e =>
Matrix e cr rows -> Matrix e cols cr -> Matrix e cols rows
`comp` Matrix Prob () (Either a n)
m)
    g :: Matrix e cols cr -> Matrix e cols (Either m cr)
g Matrix e cols cr
m = Matrix e cr (Either m cr)
forall e n m.
(Num e, CountableDimsN n m, FLN m n, FLN n n) =>
Matrix e n (Either m n)
i2 Matrix e cr (Either m cr)
-> Matrix e cols cr -> Matrix e cols (Either m cr)
forall e cr rows cols.
Num e =>
Matrix e cr rows -> Matrix e cols cr -> Matrix e cols rows
`comp` Matrix e cols cr
m

-- | Branch on a Boolean value, skipping unnecessary computations.
ifD ::
    ( CountableDimsN a (Either () a),
      FLN a a,
      FLN a (),
      FLN () a,
      FLN (Either () a) a
    )
    => Dist Bool -> Dist a -> Dist a -> Dist a
ifD :: Dist Bool -> Dist a -> Dist a -> Dist a
ifD Dist Bool
x (D Matrix Prob () a
t) (D Matrix Prob () a
e) = Dist (Either () ())
-> Matrix Prob () a -> Matrix Prob () a -> Dist a
forall e a b c.
(Num e, CountableDimsN a b, CountableDimsN c (Either b c), FLN c b,
 FLN a b, FLN a a, FLN b b, FLN c c, FLN b a, FLN b c,
 FLN (Either b c) b, FLN (Either b c) c) =>
Dist (Either a b) -> Matrix Prob a c -> Matrix Prob b c -> Dist c
branchD Dist (Either () ())
x' Matrix Prob () a
t Matrix Prob () a
e
  where
    x' :: Dist (Either () ())
x' = Either () () -> Either () () -> Bool -> Either () ()
forall a. a -> a -> Bool -> a
bool (() -> Either () ()
forall a b. b -> Either a b
Right ()) (() -> Either () ()
forall a b. a -> Either a b
Left ()) (Bool -> Either () ()) -> Dist Bool -> Dist (Either () ())
forall a b.
(Liftable a b, CountableDimsN a b, FLN b a) =>
(a -> b) -> Dist a -> Dist b
`fmapD` Dist Bool
x

-- | Monad instance 'return' function
returnD :: forall a . (Enum a, FLN () a, Countable a) => a -> Dist a
returnD :: a -> Dist a
returnD a
a = Matrix Prob () a -> Dist a
forall a. Matrix Prob () a -> Dist a
D ([Prob] -> Matrix Prob () a
forall rows e. FLN () rows => [e] -> Matrix e () rows
col [Prob]
l)
    where
        i :: Int
i = Integer -> Int
forall a. Num a => Integer -> a
fromInteger (Integer -> Int) -> Integer -> Int
forall a b. (a -> b) -> a -> b
$ Proxy (Count a) -> Integer
forall (n :: Nat) (proxy :: Nat -> *).
KnownNat n =>
proxy n -> Integer
natVal (Proxy (Count a)
forall k (t :: k). Proxy t
Proxy :: Proxy (Count a))
        x :: Int
x = a -> Int
forall a. Enum a => a -> Int
fromEnum a
a
        l :: [Prob]
l = Int -> [Prob] -> [Prob]
forall a. Int -> [a] -> [a]
take Int
x [Prob
0,Prob
0..] [Prob] -> [Prob] -> [Prob]
forall a. [a] -> [a] -> [a]
++ [Prob
1] [Prob] -> [Prob] -> [Prob]
forall a. [a] -> [a] -> [a]
++ Int -> [Prob] -> [Prob]
forall a. Int -> [a] -> [a]
take (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
x Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) [Prob
0,Prob
0..]

-- | Monad instance '(>>=)' function
bindD :: Dist a -> Matrix Prob a b -> Dist b
bindD :: Dist a -> Matrix Prob a b -> Dist b
bindD (D Matrix Prob () a
d) Matrix Prob a b
m = Matrix Prob () b -> Dist b
forall a. Matrix Prob () a -> Dist a
D (Matrix Prob a b
m Matrix Prob a b -> Matrix Prob () a -> Matrix Prob () b
forall e cr rows cols.
Num e =>
Matrix e cr rows -> Matrix e cols cr -> Matrix e cols rows
`comp` Matrix Prob () a
d)

-- | Extract probabilities given an Event.
(??) :: 
     ( Enum a, 
       Countable a,
       FLN () a
     ) => (a -> Bool) -> Dist a -> Prob
?? :: (a -> Bool) -> Dist a -> Prob
(??) a -> Bool
p Dist a
d =
    let l :: [(a, Prob)]
l = Dist a -> [(a, Prob)]
forall a. (Enum a, Countable a, FLN () a) => Dist a -> [(a, Prob)]
toValues Dist a
d
        x :: [(a, Prob)]
x = ((a, Prob) -> Bool) -> [(a, Prob)] -> [(a, Prob)]
forall a. (a -> Bool) -> [a] -> [a]
filter (a -> Bool
p (a -> Bool) -> ((a, Prob) -> a) -> (a, Prob) -> Bool
forall (k :: * -> * -> *) b c a.
Category k =>
k b c -> k a b -> k a c
. (a, Prob) -> a
forall a b. (a, b) -> a
fst) [(a, Prob)]
l
     in [Prob] -> Prob
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum ([Prob] -> Prob) -> ([(a, Prob)] -> [Prob]) -> [(a, Prob)] -> Prob
forall (k :: * -> * -> *) b c a.
Category k =>
k b c -> k a b -> k a c
. ((a, Prob) -> Prob) -> [(a, Prob)] -> [Prob]
forall a b. (a -> b) -> [a] -> [b]
map (a, Prob) -> Prob
forall a b. (a, b) -> b
snd ([(a, Prob)] -> Prob) -> [(a, Prob)] -> Prob
forall a b. (a -> b) -> a -> b
$ [(a, Prob)]
x

-- Distribution Construction

-- | Constructs a Bernoulli distribution
choose :: (FLN () a) => Prob -> Dist a
choose :: Prob -> Dist a
choose Prob
prob = Matrix Prob () a -> Dist a
forall a. Matrix Prob () a -> Dist a
D ([Prob] -> Matrix Prob () a
forall rows e. FLN () rows => [e] -> Matrix e () rows
col [Prob
prob, Prob
1 Prob -> Prob -> Prob
forall a. Num a => a -> a -> a
- Prob
prob])

-- | Creates a distribution given a shape function
shape :: (FLN () a) => (Prob -> Prob) -> [a] -> Dist a
shape :: (Prob -> Prob) -> [a] -> Dist a
shape Prob -> Prob
_ [] = String -> Dist a
forall a. HasCallStack => String -> a
error String
"Probability.shape: empty list"
shape Prob -> Prob
f [a]
xs =
   let incr :: Prob
incr = Prob
1 Prob -> Prob -> Prob
forall a. Fractional a => a -> a -> a
/ Int -> Prob
forall a b. (Integral a, Num b) => a -> b
fromIntegral ([a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [a]
xs Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)
       ps :: [Prob]
ps = (Prob -> Prob) -> [Prob] -> [Prob]
forall a b. (a -> b) -> [a] -> [b]
map Prob -> Prob
f ((Prob -> Prob) -> Prob -> [Prob]
forall a. (a -> a) -> a -> [a]
iterate (Prob -> Prob -> Prob
forall a. Num a => a -> a -> a
+Prob
incr) Prob
0)
   in  [(a, Prob)] -> Dist a
forall a. FLN () a => [(a, Prob)] -> Dist a
fromFreqs ([a] -> [Prob] -> [(a, Prob)]
forall a b. [a] -> [b] -> [(a, b)]
zip [a]
xs [Prob]
ps)

-- | Constructs a Linear distribution
linear :: (FLN () a) => [a] -> Dist a
linear :: [a] -> Dist a
linear = (Prob -> Prob) -> [a] -> Dist a
forall a. FLN () a => (Prob -> Prob) -> [a] -> Dist a
shape Prob -> Prob
forall (k :: * -> * -> *) a. (Category k, Object k a) => k a a
id

-- | Constructs an Uniform distribution
uniform :: (FLN () a) => [a] -> Dist a
uniform :: [a] -> Dist a
uniform = (Prob -> Prob) -> [a] -> Dist a
forall a. FLN () a => (Prob -> Prob) -> [a] -> Dist a
shape (Prob -> Prob -> Prob
forall a b. a -> b -> a
const Prob
1)

-- | Constructs an Negative Exponential distribution
negExp :: (FLN () a) => [a] -> Dist a
negExp :: [a] -> Dist a
negExp = (Prob -> Prob) -> [a] -> Dist a
forall a. FLN () a => (Prob -> Prob) -> [a] -> Dist a
shape (\Prob
x -> Prob -> Prob
forall a. Floating a => a -> a
exp (-Prob
x))

-- | Constructs an Normal distribution
normal :: (FLN () a) => [a] -> Dist a
normal :: [a] -> Dist a
normal = (Prob -> Prob) -> [a] -> Dist a
forall a. FLN () a => (Prob -> Prob) -> [a] -> Dist a
shape (Prob -> Prob -> Prob -> Prob
normalCurve Prob
0.5 Prob
0.5)

-- | Transforms a 'Dist' into a list of pairs.
toValues :: forall a . (Enum a, Countable a, FLN () a) => Dist a -> [(a, Prob)]
toValues :: Dist a -> [(a, Prob)]
toValues (D Matrix Prob () a
d) =
    let rows :: Int
rows = Integer -> Int
forall a. Num a => Integer -> a
fromInteger (Proxy (Count a) -> Integer
forall (n :: Nat) (proxy :: Nat -> *).
KnownNat n =>
proxy n -> Integer
natVal (Proxy (Count a)
forall k (t :: k). Proxy t
Proxy :: Proxy (Count a)))
        probs :: [Prob]
probs = Matrix Prob () a -> [Prob]
forall e cols rows. Matrix e cols rows -> [e]
toList Matrix Prob () a
d
        res :: [(a, Prob)]
res = [a] -> [Prob] -> [(a, Prob)]
forall a b. [a] -> [b] -> [(a, b)]
zip ((Int -> a) -> [Int] -> [a]
forall a b. (a -> b) -> [a] -> [b]
map Int -> a
forall a. Enum a => Int -> a
toEnum [Int
0..Int
rows]) [Prob]
probs
     in [(a, Prob)]
res

-- | Pretty a distribution
prettyDist :: forall a. (Show a, Enum a, Countable a, FLN () a) => Dist a -> String
prettyDist :: Dist a -> String
prettyDist Dist a
d =
    let values :: [(a, Prob)]
values = ((a, Prob) -> (a, Prob) -> Ordering) -> [(a, Prob)] -> [(a, Prob)]
forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy (\(a
a, Prob
p1) (a
b, Prob
p2) -> Prob -> Prob -> Ordering
forall a. Ord a => a -> a -> Ordering
compare Prob
p2 Prob
p1) (Dist a -> [(a, Prob)]
forall a. (Enum a, Countable a, FLN () a) => Dist a -> [(a, Prob)]
toValues @a Dist a
d)
        w :: Int
w = [Int] -> Int
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum (((a, Prob) -> Int) -> [(a, Prob)] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map (String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (String -> Int) -> (a -> String) -> a -> Int
forall (k :: * -> * -> *) b c a.
Category k =>
k b c -> k a b -> k a c
. a -> String
forall a. Show a => a -> String
show (a -> Int) -> ((a, Prob) -> a) -> (a, Prob) -> Int
forall (k :: * -> * -> *) b c a.
Category k =>
k b c -> k a b -> k a c
. (a, Prob) -> a
forall a b. (a, b) -> a
fst) [(a, Prob)]
values)
     in ((a, Prob) -> String) -> [(a, Prob)] -> String
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap
          (\(a
x,Prob
p) -> Int -> a -> String
forall a p. Show a => p -> a -> String
showR Int
w a
x String -> ShowS
forall a. [a] -> [a] -> [a]
++ Char
' 'Char -> ShowS
forall a. a -> [a] -> [a]
: Prob -> String
forall a. (Show a, Num a) => a -> String
showProb Prob
p String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"\n")
          [(a, Prob)]
values
  where
    showProb :: a -> String
showProb a
p = a -> String
forall a. Show a => a -> String
show (a
p a -> a -> a
forall a. Num a => a -> a -> a
* a
100) String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"%"
    showR :: p -> a -> String
showR p
n a
x = a -> String
forall a. Show a => a -> String
show a
x String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" " 

-- | Pretty Print a distribution
prettyPrintDist :: forall a . (Show a, Enum a, Countable a, FLN () a) => Dist a -> IO ()
prettyPrintDist :: Dist a -> IO ()
prettyPrintDist = String -> IO ()
putStrLn (String -> IO ()) -> (Dist a -> String) -> Dist a -> IO ()
forall (k :: * -> * -> *) b c a.
Category k =>
k b c -> k a b -> k a c
. (Show a, Enum a, Countable a, FLN () a) => Dist a -> String
forall a.
(Show a, Enum a, Countable a, FLN () a) =>
Dist a -> String
prettyDist @a

-- Auxiliary functions

fromFreqs :: (FLN () a) => [(a,Prob)] -> Dist a
fromFreqs :: [(a, Prob)] -> Dist a
fromFreqs [(a, Prob)]
xs = Matrix Prob () a -> Dist a
forall a. Matrix Prob () a -> Dist a
D ([Prob] -> Matrix Prob () a
forall rows e. FLN () rows => [e] -> Matrix e () rows
col (((a, Prob) -> Prob) -> [(a, Prob)] -> [Prob]
forall a b. (a -> b) -> [a] -> [b]
map (\(a
x,Prob
p) -> Prob
pProb -> Prob -> Prob
forall a. Fractional a => a -> a -> a
/Prob
q) [(a, Prob)]
xs))
           where q :: Prob
q = [Prob] -> Prob
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum ([Prob] -> Prob) -> [Prob] -> Prob
forall a b. (a -> b) -> a -> b
$ ((a, Prob) -> Prob) -> [(a, Prob)] -> [Prob]
forall a b. (a -> b) -> [a] -> [b]
map (a, Prob) -> Prob
forall a b. (a, b) -> b
snd [(a, Prob)]
xs

normalCurve :: Prob -> Prob -> Prob -> Prob
normalCurve :: Prob -> Prob -> Prob -> Prob
normalCurve Prob
mean Prob
dev Prob
x =
   let u :: Prob
u = (Prob
x Prob -> Prob -> Prob
forall a. Num a => a -> a -> a
- Prob
mean) Prob -> Prob -> Prob
forall a. Fractional a => a -> a -> a
/ Prob
dev
   in  Prob -> Prob
forall a. Floating a => a -> a
exp (-Prob
1Prob -> Prob -> Prob
forall a. Fractional a => a -> a -> a
/Prob
2 Prob -> Prob -> Prob
forall a. Num a => a -> a -> a
* Prob
uProb -> Int -> Prob
forall a b. (Num a, Integral b) => a -> b -> a
^(Int
2::Int)) Prob -> Prob -> Prob
forall a. Fractional a => a -> a -> a
/ Prob -> Prob
forall a. Floating a => a -> a
sqrt (Prob
2 Prob -> Prob -> Prob
forall a. Num a => a -> a -> a
* Prob
forall a. Floating a => a
pi)