{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
{- |
Portability: Multi-parameter type class with functional dependency

Abstract interface to probabilistic objects
like random generators and probability distributions.
It allows to use the same code
both for computing complete distributions
and for generating random values according to the distribution.
The latter one is of course more efficient
and may be used for approximation of the distribution by simulation.

Maybe a better name is @Experiment@.
-}
module Numeric.Probability.Object where

import qualified Numeric.Probability.Distribution as Dist
import qualified Numeric.Probability.Random as Rnd
import qualified Numeric.Probability.Shape as Shape

import qualified Data.List as List

import qualified Control.Monad.Trans.Except as ME
import Control.Monad (liftM, )


class Monad obj => C prob obj | obj -> prob where
   fromFrequencies :: [(a,prob)] -> obj a


instance C Double Rnd.T where
   fromFrequencies :: forall a. [(a, Double)] -> T a
fromFrequencies = forall prob a. (Num prob, Ord prob, Random prob) => T prob a -> T a
Rnd.pick forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall prob a. Fractional prob => [(a, prob)] -> T prob a
Dist.fromFreqs

instance Fractional prob => C prob (Dist.T prob) where
   fromFrequencies :: forall a. [(a, prob)] -> T prob a
fromFrequencies = forall prob a. Fractional prob => [(a, prob)] -> T prob a
Dist.fromFreqs

instance C prob obj => C prob (ME.ExceptT b obj) where
   fromFrequencies :: forall a. [(a, prob)] -> ExceptT b obj a
fromFrequencies =
      forall e (m :: * -> *) a. m (Either e a) -> ExceptT e m a
ME.ExceptT forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM forall a b. b -> Either a b
Right forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall prob (obj :: * -> *) a. C prob obj => [(a, prob)] -> obj a
fromFrequencies



type Spread obj a = [a] -> obj a

shape :: (C prob obj, Fractional prob) =>
   (prob -> prob) -> Spread obj a
shape :: forall prob (obj :: * -> *) a.
(C prob obj, Fractional prob) =>
(prob -> prob) -> Spread obj a
shape prob -> prob
_ [] = forall a. HasCallStack => [Char] -> a
error [Char]
"Probability.shape: empty list"
shape prob -> prob
f [a]
xs =
   let incr :: prob
incr = prob
1 forall a. Fractional a => a -> a -> a
/ forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall (t :: * -> *) a. Foldable t => t a -> Int
length [a]
xs forall a. Num a => a -> a -> a
- Int
1)
       ps :: [prob]
ps = forall a b. (a -> b) -> [a] -> [b]
List.map prob -> prob
f (forall a. (a -> a) -> a -> [a]
iterate (forall a. Num a => a -> a -> a
+prob
incr) prob
0)
   in  forall prob (obj :: * -> *) a. C prob obj => [(a, prob)] -> obj a
fromFrequencies (forall a b. [a] -> [b] -> [(a, b)]
zip [a]
xs [prob]
ps)

linear :: (C prob obj, Fractional prob) => Spread obj a
linear :: forall prob (obj :: * -> *) a.
(C prob obj, Fractional prob) =>
Spread obj a
linear = forall prob (obj :: * -> *) a.
(C prob obj, Fractional prob) =>
(prob -> prob) -> Spread obj a
shape forall prob. Fractional prob => T prob
Shape.linear

uniform :: (C prob obj, Fractional prob) => Spread obj a
uniform :: forall prob (obj :: * -> *) a.
(C prob obj, Fractional prob) =>
Spread obj a
uniform = forall prob (obj :: * -> *) a.
(C prob obj, Fractional prob) =>
(prob -> prob) -> Spread obj a
shape forall prob. Fractional prob => T prob
Shape.uniform

negExp :: (C prob obj, Floating prob) => Spread obj a
negExp :: forall prob (obj :: * -> *) a.
(C prob obj, Floating prob) =>
Spread obj a
negExp = forall prob (obj :: * -> *) a.
(C prob obj, Fractional prob) =>
(prob -> prob) -> Spread obj a
shape forall prob. Floating prob => T prob
Shape.negExp

normal :: (C prob obj, Floating prob) => Spread obj a
normal :: forall prob (obj :: * -> *) a.
(C prob obj, Floating prob) =>
Spread obj a
normal = forall prob (obj :: * -> *) a.
(C prob obj, Fractional prob) =>
(prob -> prob) -> Spread obj a
shape forall prob. Floating prob => T prob
Shape.normal

enum :: (C prob obj, Floating prob) => [Int] -> Spread obj a
enum :: forall prob (obj :: * -> *) a.
(C prob obj, Floating prob) =>
[Int] -> Spread obj a
enum  =  forall prob (obj :: * -> *) a.
(C prob obj, Floating prob) =>
[prob] -> Spread obj a
relative forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
List.map forall a b. (Integral a, Num b) => a -> b
fromIntegral

{- |
Give a list of frequencies, they do not need to sum up to 1.
-}
relative :: (C prob obj, Floating prob) => [prob] -> Spread obj a
relative :: forall prob (obj :: * -> *) a.
(C prob obj, Floating prob) =>
[prob] -> Spread obj a
relative [prob]
ns = forall prob (obj :: * -> *) a. C prob obj => [(a, prob)] -> obj a
fromFrequencies forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b c. (a -> b -> c) -> b -> a -> c
flip forall a b. [a] -> [b] -> [(a, b)]
zip [prob]
ns