-- | Simulation
module Numeric.Probability.Simulation where

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

import System.Random (Random, )

import qualified Numeric.Probability.Monad as MonadExt


{-

Naming convention:

 * @*@   takes @n :: Int@ and a generator and iterates the generator n times

 * @.@   produces a single result

 * @..@  produces a trace

 * @~@   takes @k :: Int@ [and @n :: Int@] and a generator and simulates
         the [n-fold repetition of the] generator k times


There are the following functions:

 * @n *.  t@   iterates t and produces a distribution

 * @n *.. t@   iterates t and produces a trace

 * @k     ~.  t@   simulates t and produces a distribution

 * @(k,n) ~*. t@   simulates the n-fold repetition of t and produces a distribution

 * @(k,n) ~.. t@   simulates the n-fold repetition of t and produces a trace


Iteration captures three iteration strategies:
iter builds an n-fold composition of a (randomized) transition
while and until implement conditional repetitions

The class Iterate allows the overloading of iteration for different
kinds of generators, namely transitions and Rnd.change changes:

 *  @Trans   a = a -> Dist a    ==>   c = Dist@

 *  @RChange a = a -> Rnd.T a   ==>   c = Rnd.T = IO@

-}


{- |
Simulation means to repeat a Rnd.change change many times and
to accumulate all results into a distribution. Therefore,
simulation can be regarded as an approximation of distributions
through randomization.

The Sim class allows the overloading of simulation for different
kinds of generators, namely transitions and Rnd.change changes:

  * @Trans   a = a -> Dist a   ==>   c = Dist@

  * @RChange a = a -> Rnd.T a  ==>   c = Rnd.T = IO@
-}
class C c where
  -- | returns the final randomized transition
  (~.)  :: (Fractional prob, Ord prob, Random prob, Ord a) =>
              Int       -> (a -> c a) -> Rnd.Transition prob a
  -- | returns the whole trace for a k-fold simulation
  (~..) :: (Fractional prob, Ord prob, Random prob, Ord a) =>
              (Int,Int) -> (a -> c a) -> Trace.RExpand prob a
  -- | returns the whole trace for a single simulation
  (~*.) :: (Fractional prob, Ord prob, Random prob, Ord a) =>
              (Int,Int) -> (a -> c a) -> Rnd.Transition prob a

infix 6 ~. , ~..

infix 8 ~*.


-- simulation for transitions
--
instance (Num prob, Ord prob, Random prob) => C (Dist.T prob) where
  ~. :: forall prob a.
(Fractional prob, Ord prob, Random prob, Ord a) =>
Int -> (a -> T prob a) -> Transition prob a
(~.)  Int
x = forall (c :: * -> *) prob a.
(C c, Fractional prob, Ord prob, Random prob, Ord a) =>
Int -> (a -> c a) -> Transition prob a
(~.)  Int
x forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall prob a.
(Num prob, Ord prob, Random prob) =>
T prob a -> Change a
Rnd.change
  ~.. :: forall prob a.
(Fractional prob, Ord prob, Random prob, Ord a) =>
(Int, Int) -> (a -> T prob a) -> RExpand prob a
(~..) (Int, Int)
x = forall (c :: * -> *) prob a.
(C c, Fractional prob, Ord prob, Random prob, Ord a) =>
(Int, Int) -> (a -> c a) -> RExpand prob a
(~..) (Int, Int)
x forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall prob a.
(Num prob, Ord prob, Random prob) =>
T prob a -> Change a
Rnd.change
  ~*. :: forall prob a.
(Fractional prob, Ord prob, Random prob, Ord a) =>
(Int, Int) -> (a -> T prob a) -> Transition prob a
(~*.) (Int, Int)
x = forall (c :: * -> *) prob a.
(C c, Fractional prob, Ord prob, Random prob, Ord a) =>
(Int, Int) -> (a -> c a) -> Transition prob a
(~*.) (Int, Int)
x forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall prob a.
(Num prob, Ord prob, Random prob) =>
T prob a -> Change a
Rnd.change


-- simulation for Rnd.change changes
--
instance C Rnd.T where
  ~. :: forall prob a.
(Fractional prob, Ord prob, Random prob, Ord a) =>
Int -> (a -> T a) -> Transition prob a
(~.)     Int
n  a -> T a
t = forall prob a.
(Fractional prob, Ord a) =>
[T a] -> Distribution prob a
Rnd.dist forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Int -> a -> [a]
replicate Int
n forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> T a
t
  ~.. :: forall prob a.
(Fractional prob, Ord prob, Random prob, Ord a) =>
(Int, Int) -> (a -> T a) -> RExpand prob a
(~..) (Int
k,Int
n) a -> T a
t = forall prob a.
(Fractional prob, Ord a) =>
[RTrace a] -> RSpace prob a
Trace.merge forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Int -> a -> [a]
replicate Int
k forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a. Monad m => Int -> (a -> m a) -> a -> m [a]
MonadExt.walk Int
n a -> T a
t
  ~*. :: forall prob a.
(Fractional prob, Ord prob, Random prob, Ord a) =>
(Int, Int) -> (a -> T a) -> Transition prob a
(~*.) (Int
k,Int
n) a -> T a
t = Int
k forall (c :: * -> *) prob a.
(C c, Fractional prob, Ord prob, Random prob, Ord a) =>
Int -> (a -> c a) -> Transition prob a
~. forall (m :: * -> *) a. Monad m => Int -> (a -> m a) -> a -> m a
MonadExt.iterate Int
n a -> T a
t