-- |
-- Module     : Simulation.Aivika.Trans.Parameter.Random
-- Copyright  : Copyright (c) 2009-2017, David Sorokin <david.sorokin@gmail.com>
-- License    : BSD3
-- Maintainer : David Sorokin <david.sorokin@gmail.com>
-- Stability  : experimental
-- Tested with: GHC 8.0.1
--
-- This module defines the random parameters of simulation experiments.
--
-- To create a parameter that would return the same value within the simulation run,
-- you should memoize the computation with help of 'memoParameter', which is important
-- for the Monte-Carlo simulation.
--
-- To create a random function that would return the same values in the integration
-- time points within the simulation run, you should either lift the computation to
-- the 'Dynamics' computation and then memoize it too but using the 'memo0Dynamics'
-- function for that computation, or just take the predefined function that does
-- namely this.

module Simulation.Aivika.Trans.Parameter.Random
       (randomUniform,
        randomUniformInt,
        randomTriangular,
        randomNormal,
        randomLogNormal,
        randomExponential,
        randomErlang,
        randomPoisson,
        randomBinomial,
        randomGamma,
        randomBeta,
        randomWeibull,
        randomDiscrete,
        randomTrue,
        randomFalse) where

import Control.Monad.Trans

import Simulation.Aivika.Trans.Generator
import Simulation.Aivika.Trans.Comp
import Simulation.Aivika.Trans.Internal.Specs
import Simulation.Aivika.Trans.Internal.Parameter
import Simulation.Aivika.Trans.Dynamics
import Simulation.Aivika.Trans.Dynamics.Memo.Unboxed

-- | Computation that generates a new random number distributed uniformly.
randomUniform :: MonadComp m
                 => Double     -- ^ minimum
                 -> Double  -- ^ maximum
                 -> Parameter m Double
{-# INLINE randomUniform #-}
randomUniform :: forall (m :: * -> *).
MonadComp m =>
Double -> Double -> Parameter m Double
randomUniform Double
min Double
max =
  (Run m -> m Double) -> Parameter m Double
forall (m :: * -> *) a. (Run m -> m a) -> Parameter m a
Parameter ((Run m -> m Double) -> Parameter m Double)
-> (Run m -> m Double) -> Parameter m Double
forall a b. (a -> b) -> a -> b
$ \Run m
r ->
  let g :: Generator m
g = Run m -> Generator m
forall (m :: * -> *). Run m -> Generator m
runGenerator Run m
r
  in Generator m -> Double -> Double -> m Double
forall (m :: * -> *).
MonadGenerator m =>
Generator m -> Double -> Double -> m Double
generateUniform Generator m
g Double
min Double
max

-- | Computation that generates a new random integer number distributed uniformly.
randomUniformInt :: MonadComp m
                    => Int     -- ^ minimum
                    -> Int  -- ^ maximum
                    -> Parameter m Int
{-# INLINE randomUniformInt #-}
randomUniformInt :: forall (m :: * -> *). MonadComp m => Int -> Int -> Parameter m Int
randomUniformInt Int
min Int
max =
  (Run m -> m Int) -> Parameter m Int
forall (m :: * -> *) a. (Run m -> m a) -> Parameter m a
Parameter ((Run m -> m Int) -> Parameter m Int)
-> (Run m -> m Int) -> Parameter m Int
forall a b. (a -> b) -> a -> b
$ \Run m
r ->
  let g :: Generator m
g = Run m -> Generator m
forall (m :: * -> *). Run m -> Generator m
runGenerator Run m
r
  in Generator m -> Int -> Int -> m Int
forall (m :: * -> *).
MonadGenerator m =>
Generator m -> Int -> Int -> m Int
generateUniformInt Generator m
g Int
min Int
max

-- | Computation that generates a new random number from the triangular distribution.
randomTriangular :: MonadComp m
                    => Double  -- ^ minimum
                    -> Double  -- ^ median
                    -> Double  -- ^ maximum
                    -> Parameter m Double
{-# INLINE randomTriangular #-}
randomTriangular :: forall (m :: * -> *).
MonadComp m =>
Double -> Double -> Double -> Parameter m Double
randomTriangular Double
min Double
median Double
max =
  (Run m -> m Double) -> Parameter m Double
forall (m :: * -> *) a. (Run m -> m a) -> Parameter m a
Parameter ((Run m -> m Double) -> Parameter m Double)
-> (Run m -> m Double) -> Parameter m Double
forall a b. (a -> b) -> a -> b
$ \Run m
r ->
  let g :: Generator m
g = Run m -> Generator m
forall (m :: * -> *). Run m -> Generator m
runGenerator Run m
r
  in Generator m -> Double -> Double -> Double -> m Double
forall (m :: * -> *).
MonadGenerator m =>
Generator m -> Double -> Double -> Double -> m Double
generateTriangular Generator m
g Double
min Double
median Double
max

-- | Computation that generates a new random number distributed normally.
randomNormal :: MonadComp m
                => Double     -- ^ mean
                -> Double  -- ^ deviation
                -> Parameter m Double
{-# INLINE randomNormal #-}
randomNormal :: forall (m :: * -> *).
MonadComp m =>
Double -> Double -> Parameter m Double
randomNormal Double
mu Double
nu =
  (Run m -> m Double) -> Parameter m Double
forall (m :: * -> *) a. (Run m -> m a) -> Parameter m a
Parameter ((Run m -> m Double) -> Parameter m Double)
-> (Run m -> m Double) -> Parameter m Double
forall a b. (a -> b) -> a -> b
$ \Run m
r ->
  let g :: Generator m
g = Run m -> Generator m
forall (m :: * -> *). Run m -> Generator m
runGenerator Run m
r
  in Generator m -> Double -> Double -> m Double
forall (m :: * -> *).
MonadGenerator m =>
Generator m -> Double -> Double -> m Double
generateNormal Generator m
g Double
mu Double
nu

-- | Computation that generates a new random number from the lognormal distribution.
randomLogNormal :: MonadComp m
                   => Double
                   -- ^ the mean of a normal distribution
                   -- which this distribution is derived from
                   -> Double
                   -- ^ the deviation of a normal distribution
                   -- which this distribution is derived from
                   -> Parameter m Double
{-# INLINE randomLogNormal #-}
randomLogNormal :: forall (m :: * -> *).
MonadComp m =>
Double -> Double -> Parameter m Double
randomLogNormal Double
mu Double
nu =
  (Run m -> m Double) -> Parameter m Double
forall (m :: * -> *) a. (Run m -> m a) -> Parameter m a
Parameter ((Run m -> m Double) -> Parameter m Double)
-> (Run m -> m Double) -> Parameter m Double
forall a b. (a -> b) -> a -> b
$ \Run m
r ->
  let g :: Generator m
g = Run m -> Generator m
forall (m :: * -> *). Run m -> Generator m
runGenerator Run m
r
  in Generator m -> Double -> Double -> m Double
forall (m :: * -> *).
MonadGenerator m =>
Generator m -> Double -> Double -> m Double
generateLogNormal Generator m
g Double
mu Double
nu

-- | Computation that returns a new exponential random number with the specified mean
-- (the reciprocal of the rate).
randomExponential :: MonadComp m
                     => Double
                     -- ^ the mean (the reciprocal of the rate)
                     -> Parameter m Double
{-# INLINE randomExponential #-}
randomExponential :: forall (m :: * -> *). MonadComp m => Double -> Parameter m Double
randomExponential Double
mu =
  (Run m -> m Double) -> Parameter m Double
forall (m :: * -> *) a. (Run m -> m a) -> Parameter m a
Parameter ((Run m -> m Double) -> Parameter m Double)
-> (Run m -> m Double) -> Parameter m Double
forall a b. (a -> b) -> a -> b
$ \Run m
r ->
  let g :: Generator m
g = Run m -> Generator m
forall (m :: * -> *). Run m -> Generator m
runGenerator Run m
r
  in Generator m -> Double -> m Double
forall (m :: * -> *).
MonadGenerator m =>
Generator m -> Double -> m Double
generateExponential Generator m
g Double
mu

-- | Computation that returns a new Erlang random number with the specified scale
-- (the reciprocal of the rate) and integer shape.
randomErlang :: MonadComp m
                => Double
                -- ^ the scale (the reciprocal of the rate)
                -> Int
                -- ^ the shape
                -> Parameter m Double
{-# INLINE randomErlang #-}
randomErlang :: forall (m :: * -> *).
MonadComp m =>
Double -> Int -> Parameter m Double
randomErlang Double
beta Int
m =
  (Run m -> m Double) -> Parameter m Double
forall (m :: * -> *) a. (Run m -> m a) -> Parameter m a
Parameter ((Run m -> m Double) -> Parameter m Double)
-> (Run m -> m Double) -> Parameter m Double
forall a b. (a -> b) -> a -> b
$ \Run m
r ->
  let g :: Generator m
g = Run m -> Generator m
forall (m :: * -> *). Run m -> Generator m
runGenerator Run m
r
  in Generator m -> Double -> Int -> m Double
forall (m :: * -> *).
MonadGenerator m =>
Generator m -> Double -> Int -> m Double
generateErlang Generator m
g Double
beta Int
m

-- | Computation that returns a new Poisson random number with the specified mean.
randomPoisson :: MonadComp m
                 => Double
                 -- ^ the mean
                 -> Parameter m Int
{-# INLINE randomPoisson #-}
randomPoisson :: forall (m :: * -> *). MonadComp m => Double -> Parameter m Int
randomPoisson Double
mu =
  (Run m -> m Int) -> Parameter m Int
forall (m :: * -> *) a. (Run m -> m a) -> Parameter m a
Parameter ((Run m -> m Int) -> Parameter m Int)
-> (Run m -> m Int) -> Parameter m Int
forall a b. (a -> b) -> a -> b
$ \Run m
r ->
  let g :: Generator m
g = Run m -> Generator m
forall (m :: * -> *). Run m -> Generator m
runGenerator Run m
r
  in Generator m -> Double -> m Int
forall (m :: * -> *).
MonadGenerator m =>
Generator m -> Double -> m Int
generatePoisson Generator m
g Double
mu

-- | Computation that returns a new binomial random number with the specified
-- probability and trials.
randomBinomial :: MonadComp m
                  => Double  -- ^ the probability
                  -> Int  -- ^ the number of trials
                  -> Parameter m Int
{-# INLINE randomBinomial #-}
randomBinomial :: forall (m :: * -> *).
MonadComp m =>
Double -> Int -> Parameter m Int
randomBinomial Double
prob Int
trials =
  (Run m -> m Int) -> Parameter m Int
forall (m :: * -> *) a. (Run m -> m a) -> Parameter m a
Parameter ((Run m -> m Int) -> Parameter m Int)
-> (Run m -> m Int) -> Parameter m Int
forall a b. (a -> b) -> a -> b
$ \Run m
r ->
  let g :: Generator m
g = Run m -> Generator m
forall (m :: * -> *). Run m -> Generator m
runGenerator Run m
r
  in Generator m -> Double -> Int -> m Int
forall (m :: * -> *).
MonadGenerator m =>
Generator m -> Double -> Int -> m Int
generateBinomial Generator m
g Double
prob Int
trials

-- | Computation that returns a new random number from the Gamma distribution.
randomGamma :: MonadComp m
               => Double  -- ^ the shape
               -> Double  -- ^ the scale (a reciprocal of the rate)
               -> Parameter m Double
{-# INLINE randomGamma #-}
randomGamma :: forall (m :: * -> *).
MonadComp m =>
Double -> Double -> Parameter m Double
randomGamma Double
kappa Double
theta =
  (Run m -> m Double) -> Parameter m Double
forall (m :: * -> *) a. (Run m -> m a) -> Parameter m a
Parameter ((Run m -> m Double) -> Parameter m Double)
-> (Run m -> m Double) -> Parameter m Double
forall a b. (a -> b) -> a -> b
$ \Run m
r ->
  let g :: Generator m
g = Run m -> Generator m
forall (m :: * -> *). Run m -> Generator m
runGenerator Run m
r
  in Generator m -> Double -> Double -> m Double
forall (m :: * -> *).
MonadGenerator m =>
Generator m -> Double -> Double -> m Double
generateGamma Generator m
g Double
kappa Double
theta

-- | Computation that returns a new random number from the Beta distribution.
randomBeta :: MonadComp m
              => Double  -- ^ the shape (alpha)
              -> Double  -- ^ the shape (beta)
              -> Parameter m Double
{-# INLINE randomBeta #-}
randomBeta :: forall (m :: * -> *).
MonadComp m =>
Double -> Double -> Parameter m Double
randomBeta Double
alpha Double
beta =
  (Run m -> m Double) -> Parameter m Double
forall (m :: * -> *) a. (Run m -> m a) -> Parameter m a
Parameter ((Run m -> m Double) -> Parameter m Double)
-> (Run m -> m Double) -> Parameter m Double
forall a b. (a -> b) -> a -> b
$ \Run m
r ->
  let g :: Generator m
g = Run m -> Generator m
forall (m :: * -> *). Run m -> Generator m
runGenerator Run m
r
  in Generator m -> Double -> Double -> m Double
forall (m :: * -> *).
MonadGenerator m =>
Generator m -> Double -> Double -> m Double
generateBeta Generator m
g Double
alpha Double
beta

-- | Computation that returns a new random number from the Weibull distribution.
randomWeibull :: MonadComp m
                 => Double  -- ^ shape
                 -> Double  -- ^ scale
                 -> Parameter m Double
{-# INLINE randomWeibull #-}
randomWeibull :: forall (m :: * -> *).
MonadComp m =>
Double -> Double -> Parameter m Double
randomWeibull Double
alpha Double
beta =
  (Run m -> m Double) -> Parameter m Double
forall (m :: * -> *) a. (Run m -> m a) -> Parameter m a
Parameter ((Run m -> m Double) -> Parameter m Double)
-> (Run m -> m Double) -> Parameter m Double
forall a b. (a -> b) -> a -> b
$ \Run m
r ->
  let g :: Generator m
g = Run m -> Generator m
forall (m :: * -> *). Run m -> Generator m
runGenerator Run m
r
  in Generator m -> Double -> Double -> m Double
forall (m :: * -> *).
MonadGenerator m =>
Generator m -> Double -> Double -> m Double
generateWeibull Generator m
g Double
alpha Double
beta

-- | Computation that returns a new random value from the specified discrete distribution.
randomDiscrete :: MonadComp m => DiscretePDF a -> Parameter m a
{-# INLINE randomDiscrete #-}
randomDiscrete :: forall (m :: * -> *) a.
MonadComp m =>
DiscretePDF a -> Parameter m a
randomDiscrete DiscretePDF a
dpdf =
  (Run m -> m a) -> Parameter m a
forall (m :: * -> *) a. (Run m -> m a) -> Parameter m a
Parameter ((Run m -> m a) -> Parameter m a)
-> (Run m -> m a) -> Parameter m a
forall a b. (a -> b) -> a -> b
$ \Run m
r ->
  let g :: Generator m
g = Run m -> Generator m
forall (m :: * -> *). Run m -> Generator m
runGenerator Run m
r
  in Generator m -> DiscretePDF a -> m a
forall a. Generator m -> DiscretePDF a -> m a
forall (m :: * -> *) a.
MonadGenerator m =>
Generator m -> DiscretePDF a -> m a
generateDiscrete Generator m
g DiscretePDF a
dpdf

-- | Computation that returns 'True' in case of success.
randomTrue :: MonadComp m
              => Double      -- ^ the probability of the success
              -> Parameter m Bool
{-# INLINE randomTrue #-}              
randomTrue :: forall (m :: * -> *). MonadComp m => Double -> Parameter m Bool
randomTrue Double
p =
  do Double
x <- Double -> Double -> Parameter m Double
forall (m :: * -> *).
MonadComp m =>
Double -> Double -> Parameter m Double
randomUniform Double
0 Double
1
     Bool -> Parameter m Bool
forall a. a -> Parameter m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Double
x Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
<= Double
p)

-- | Computation that returns 'False' in case of success.
randomFalse :: MonadComp m
               => Double      -- ^ the probability of the success
               -> Parameter m Bool
{-# INLINE randomFalse #-}
randomFalse :: forall (m :: * -> *). MonadComp m => Double -> Parameter m Bool
randomFalse Double
p =
  do Double
x <- Double -> Double -> Parameter m Double
forall (m :: * -> *).
MonadComp m =>
Double -> Double -> Parameter m Double
randomUniform Double
0 Double
1
     Bool -> Parameter m Bool
forall a. a -> Parameter m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Double
x Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
> Double
p)