-- |
-- Module     : Simulation.Aivika.Dynamics.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 functions that always return the same values
-- in the integration time points within a single simulation run. The values
-- for another simulation run will be regenerated anew.
--
-- For example, the computations returned by these functions can be used in
-- the equations of System Dynamics.
--
-- Also it is worth noting that the values are generated in a strong order starting
-- from 'starttime' with step 'dt'. This is how the 'memo0Dynamics' function
-- actually works.
--

module Simulation.Aivika.Dynamics.Random
       (memoRandomUniformDynamics,
        memoRandomUniformIntDynamics,
        memoRandomTriangularDynamics,
        memoRandomNormalDynamics,
        memoRandomLogNormalDynamics,
        memoRandomExponentialDynamics,
        memoRandomErlangDynamics,
        memoRandomPoissonDynamics,
        memoRandomBinomialDynamics,
        memoRandomGammaDynamics,
        memoRandomBetaDynamics,
        memoRandomWeibullDynamics,
        memoRandomDiscreteDynamics) where

import Control.Monad.Trans

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

-- | Computation that generates random numbers distributed uniformly and
-- memoizes the numbers in the integration time points.
memoRandomUniformDynamics :: Dynamics Double     -- ^ minimum
                             -> Dynamics Double  -- ^ maximum
                             -> Simulation (Dynamics Double)
memoRandomUniformDynamics :: Dynamics Double -> Dynamics Double -> Simulation (Dynamics Double)
memoRandomUniformDynamics Dynamics Double
min Dynamics Double
max =
  Dynamics Double -> Simulation (Dynamics Double)
forall e. Unboxed e => Dynamics e -> Simulation (Dynamics e)
memo0Dynamics (Dynamics Double -> Simulation (Dynamics Double))
-> Dynamics Double -> Simulation (Dynamics Double)
forall a b. (a -> b) -> a -> b
$
  (Point -> IO Double) -> Dynamics Double
forall a. (Point -> IO a) -> Dynamics a
Dynamics ((Point -> IO Double) -> Dynamics Double)
-> (Point -> IO Double) -> Dynamics Double
forall a b. (a -> b) -> a -> b
$ \Point
p ->
  do let g :: Generator
g = Run -> Generator
runGenerator (Run -> Generator) -> Run -> Generator
forall a b. (a -> b) -> a -> b
$ Point -> Run
pointRun Point
p
     Double
min' <- Point -> Dynamics Double -> IO Double
forall a. Point -> Dynamics a -> IO a
invokeDynamics Point
p Dynamics Double
min
     Double
max' <- Point -> Dynamics Double -> IO Double
forall a. Point -> Dynamics a -> IO a
invokeDynamics Point
p Dynamics Double
max
     Generator -> Double -> Double -> IO Double
generateUniform Generator
g Double
min' Double
max'

-- | Computation that generates random integer numbers distributed uniformly and
-- memoizes the numbers in the integration time points.
memoRandomUniformIntDynamics :: Dynamics Int     -- ^ minimum
                                -> Dynamics Int  -- ^ maximum
                                -> Simulation (Dynamics Int)
memoRandomUniformIntDynamics :: Dynamics Int -> Dynamics Int -> Simulation (Dynamics Int)
memoRandomUniformIntDynamics Dynamics Int
min Dynamics Int
max =
  Dynamics Int -> Simulation (Dynamics Int)
forall e. Unboxed e => Dynamics e -> Simulation (Dynamics e)
memo0Dynamics (Dynamics Int -> Simulation (Dynamics Int))
-> Dynamics Int -> Simulation (Dynamics Int)
forall a b. (a -> b) -> a -> b
$
  (Point -> IO Int) -> Dynamics Int
forall a. (Point -> IO a) -> Dynamics a
Dynamics ((Point -> IO Int) -> Dynamics Int)
-> (Point -> IO Int) -> Dynamics Int
forall a b. (a -> b) -> a -> b
$ \Point
p ->
  do let g :: Generator
g = Run -> Generator
runGenerator (Run -> Generator) -> Run -> Generator
forall a b. (a -> b) -> a -> b
$ Point -> Run
pointRun Point
p
     Int
min' <- Point -> Dynamics Int -> IO Int
forall a. Point -> Dynamics a -> IO a
invokeDynamics Point
p Dynamics Int
min
     Int
max' <- Point -> Dynamics Int -> IO Int
forall a. Point -> Dynamics a -> IO a
invokeDynamics Point
p Dynamics Int
max
     Generator -> Int -> Int -> IO Int
generateUniformInt Generator
g Int
min' Int
max'

-- | Computation that generates random numbers from the triangular distribution
-- and memoizes the numbers in the integration time points.
memoRandomTriangularDynamics :: Dynamics Double     -- ^ minimum
                                -> Dynamics Double  -- ^ median
                                -> Dynamics Double  -- ^ maximum
                                -> Simulation (Dynamics Double)
memoRandomTriangularDynamics :: Dynamics Double
-> Dynamics Double
-> Dynamics Double
-> Simulation (Dynamics Double)
memoRandomTriangularDynamics Dynamics Double
min Dynamics Double
median Dynamics Double
max =
  Dynamics Double -> Simulation (Dynamics Double)
forall e. Unboxed e => Dynamics e -> Simulation (Dynamics e)
memo0Dynamics (Dynamics Double -> Simulation (Dynamics Double))
-> Dynamics Double -> Simulation (Dynamics Double)
forall a b. (a -> b) -> a -> b
$
  (Point -> IO Double) -> Dynamics Double
forall a. (Point -> IO a) -> Dynamics a
Dynamics ((Point -> IO Double) -> Dynamics Double)
-> (Point -> IO Double) -> Dynamics Double
forall a b. (a -> b) -> a -> b
$ \Point
p ->
  do let g :: Generator
g = Run -> Generator
runGenerator (Run -> Generator) -> Run -> Generator
forall a b. (a -> b) -> a -> b
$ Point -> Run
pointRun Point
p
     Double
min' <- Point -> Dynamics Double -> IO Double
forall a. Point -> Dynamics a -> IO a
invokeDynamics Point
p Dynamics Double
min
     Double
median' <- Point -> Dynamics Double -> IO Double
forall a. Point -> Dynamics a -> IO a
invokeDynamics Point
p Dynamics Double
median
     Double
max' <- Point -> Dynamics Double -> IO Double
forall a. Point -> Dynamics a -> IO a
invokeDynamics Point
p Dynamics Double
max
     Generator -> Double -> Double -> Double -> IO Double
generateTriangular Generator
g Double
min' Double
median' Double
max'

-- | Computation that generates random numbers distributed normally and
-- memoizes the numbers in the integration time points.
memoRandomNormalDynamics :: Dynamics Double     -- ^ mean
                            -> Dynamics Double  -- ^ deviation
                            -> Simulation (Dynamics Double)
memoRandomNormalDynamics :: Dynamics Double -> Dynamics Double -> Simulation (Dynamics Double)
memoRandomNormalDynamics Dynamics Double
mu Dynamics Double
nu =
  Dynamics Double -> Simulation (Dynamics Double)
forall e. Unboxed e => Dynamics e -> Simulation (Dynamics e)
memo0Dynamics (Dynamics Double -> Simulation (Dynamics Double))
-> Dynamics Double -> Simulation (Dynamics Double)
forall a b. (a -> b) -> a -> b
$
  (Point -> IO Double) -> Dynamics Double
forall a. (Point -> IO a) -> Dynamics a
Dynamics ((Point -> IO Double) -> Dynamics Double)
-> (Point -> IO Double) -> Dynamics Double
forall a b. (a -> b) -> a -> b
$ \Point
p ->
  do let g :: Generator
g = Run -> Generator
runGenerator (Run -> Generator) -> Run -> Generator
forall a b. (a -> b) -> a -> b
$ Point -> Run
pointRun Point
p
     Double
mu' <- Point -> Dynamics Double -> IO Double
forall a. Point -> Dynamics a -> IO a
invokeDynamics Point
p Dynamics Double
mu
     Double
nu' <- Point -> Dynamics Double -> IO Double
forall a. Point -> Dynamics a -> IO a
invokeDynamics Point
p Dynamics Double
nu
     Generator -> Double -> Double -> IO Double
generateNormal Generator
g Double
mu' Double
nu'

-- | Computation that generates random numbers from the lognormal distribution
-- and memoizes the numbers in the integration time points.
memoRandomLogNormalDynamics :: Dynamics Double
                               -- ^ the mean of a normal distribution which
                               -- this distribution is derived from
                               -> Dynamics Double
                               -- ^ the deviation of a normal distribution which
                               -- this distribution is derived from
                               -> Simulation (Dynamics Double)
memoRandomLogNormalDynamics :: Dynamics Double -> Dynamics Double -> Simulation (Dynamics Double)
memoRandomLogNormalDynamics Dynamics Double
mu Dynamics Double
nu =
  Dynamics Double -> Simulation (Dynamics Double)
forall e. Unboxed e => Dynamics e -> Simulation (Dynamics e)
memo0Dynamics (Dynamics Double -> Simulation (Dynamics Double))
-> Dynamics Double -> Simulation (Dynamics Double)
forall a b. (a -> b) -> a -> b
$
  (Point -> IO Double) -> Dynamics Double
forall a. (Point -> IO a) -> Dynamics a
Dynamics ((Point -> IO Double) -> Dynamics Double)
-> (Point -> IO Double) -> Dynamics Double
forall a b. (a -> b) -> a -> b
$ \Point
p ->
  do let g :: Generator
g = Run -> Generator
runGenerator (Run -> Generator) -> Run -> Generator
forall a b. (a -> b) -> a -> b
$ Point -> Run
pointRun Point
p
     Double
mu' <- Point -> Dynamics Double -> IO Double
forall a. Point -> Dynamics a -> IO a
invokeDynamics Point
p Dynamics Double
mu
     Double
nu' <- Point -> Dynamics Double -> IO Double
forall a. Point -> Dynamics a -> IO a
invokeDynamics Point
p Dynamics Double
nu
     Generator -> Double -> Double -> IO Double
generateLogNormal Generator
g Double
mu' Double
nu'

-- | Computation that generates exponential random numbers with the specified mean
-- (the reciprocal of the rate) and memoizes the numbers in the integration time points.
memoRandomExponentialDynamics :: Dynamics Double
                                 -- ^ the mean (a reciprocal of the rate)
                                 -> Simulation (Dynamics Double)
memoRandomExponentialDynamics :: Dynamics Double -> Simulation (Dynamics Double)
memoRandomExponentialDynamics Dynamics Double
mu =
  Dynamics Double -> Simulation (Dynamics Double)
forall e. Unboxed e => Dynamics e -> Simulation (Dynamics e)
memo0Dynamics (Dynamics Double -> Simulation (Dynamics Double))
-> Dynamics Double -> Simulation (Dynamics Double)
forall a b. (a -> b) -> a -> b
$
  (Point -> IO Double) -> Dynamics Double
forall a. (Point -> IO a) -> Dynamics a
Dynamics ((Point -> IO Double) -> Dynamics Double)
-> (Point -> IO Double) -> Dynamics Double
forall a b. (a -> b) -> a -> b
$ \Point
p ->
  do let g :: Generator
g = Run -> Generator
runGenerator (Run -> Generator) -> Run -> Generator
forall a b. (a -> b) -> a -> b
$ Point -> Run
pointRun Point
p
     Double
mu' <- Point -> Dynamics Double -> IO Double
forall a. Point -> Dynamics a -> IO a
invokeDynamics Point
p Dynamics Double
mu
     Generator -> Double -> IO Double
generateExponential Generator
g Double
mu'

-- | Computation that generates the Erlang random numbers with the specified scale
-- (the reciprocal of the rate) and integer shape but memoizes the numbers in
-- the integration time points.
memoRandomErlangDynamics :: Dynamics Double
                            -- ^ the scale (a reciprocal of the rate)
                            -> Dynamics Int
                            -- ^ the shape
                            -> Simulation (Dynamics Double)
memoRandomErlangDynamics :: Dynamics Double -> Dynamics Int -> Simulation (Dynamics Double)
memoRandomErlangDynamics Dynamics Double
beta Dynamics Int
m =
  Dynamics Double -> Simulation (Dynamics Double)
forall e. Unboxed e => Dynamics e -> Simulation (Dynamics e)
memo0Dynamics (Dynamics Double -> Simulation (Dynamics Double))
-> Dynamics Double -> Simulation (Dynamics Double)
forall a b. (a -> b) -> a -> b
$
  (Point -> IO Double) -> Dynamics Double
forall a. (Point -> IO a) -> Dynamics a
Dynamics ((Point -> IO Double) -> Dynamics Double)
-> (Point -> IO Double) -> Dynamics Double
forall a b. (a -> b) -> a -> b
$ \Point
p ->
  do let g :: Generator
g = Run -> Generator
runGenerator (Run -> Generator) -> Run -> Generator
forall a b. (a -> b) -> a -> b
$ Point -> Run
pointRun Point
p
     Double
beta' <- Point -> Dynamics Double -> IO Double
forall a. Point -> Dynamics a -> IO a
invokeDynamics Point
p Dynamics Double
beta
     Int
m' <- Point -> Dynamics Int -> IO Int
forall a. Point -> Dynamics a -> IO a
invokeDynamics Point
p Dynamics Int
m
     Generator -> Double -> Int -> IO Double
generateErlang Generator
g Double
beta' Int
m'

-- | Computation that generats the Poisson random numbers with the specified mean
-- and memoizes the numbers in the integration time points.
memoRandomPoissonDynamics :: Dynamics Double
                             -- ^ the mean
                             -> Simulation (Dynamics Int)
memoRandomPoissonDynamics :: Dynamics Double -> Simulation (Dynamics Int)
memoRandomPoissonDynamics Dynamics Double
mu =
  Dynamics Int -> Simulation (Dynamics Int)
forall e. Unboxed e => Dynamics e -> Simulation (Dynamics e)
memo0Dynamics (Dynamics Int -> Simulation (Dynamics Int))
-> Dynamics Int -> Simulation (Dynamics Int)
forall a b. (a -> b) -> a -> b
$
  (Point -> IO Int) -> Dynamics Int
forall a. (Point -> IO a) -> Dynamics a
Dynamics ((Point -> IO Int) -> Dynamics Int)
-> (Point -> IO Int) -> Dynamics Int
forall a b. (a -> b) -> a -> b
$ \Point
p ->
  do let g :: Generator
g = Run -> Generator
runGenerator (Run -> Generator) -> Run -> Generator
forall a b. (a -> b) -> a -> b
$ Point -> Run
pointRun Point
p
     Double
mu' <- Point -> Dynamics Double -> IO Double
forall a. Point -> Dynamics a -> IO a
invokeDynamics Point
p Dynamics Double
mu
     Generator -> Double -> IO Int
generatePoisson Generator
g Double
mu'

-- | Computation that generates binomial random numbers with the specified
-- probability and trials but memoizes the numbers in the integration time points.
memoRandomBinomialDynamics :: Dynamics Double  -- ^ the probability
                              -> Dynamics Int  -- ^ the number of trials
                              -> Simulation (Dynamics Int)
memoRandomBinomialDynamics :: Dynamics Double -> Dynamics Int -> Simulation (Dynamics Int)
memoRandomBinomialDynamics Dynamics Double
prob Dynamics Int
trials =
  Dynamics Int -> Simulation (Dynamics Int)
forall e. Unboxed e => Dynamics e -> Simulation (Dynamics e)
memo0Dynamics (Dynamics Int -> Simulation (Dynamics Int))
-> Dynamics Int -> Simulation (Dynamics Int)
forall a b. (a -> b) -> a -> b
$
  (Point -> IO Int) -> Dynamics Int
forall a. (Point -> IO a) -> Dynamics a
Dynamics ((Point -> IO Int) -> Dynamics Int)
-> (Point -> IO Int) -> Dynamics Int
forall a b. (a -> b) -> a -> b
$ \Point
p ->
  do let g :: Generator
g = Run -> Generator
runGenerator (Run -> Generator) -> Run -> Generator
forall a b. (a -> b) -> a -> b
$ Point -> Run
pointRun Point
p
     Double
prob' <- Point -> Dynamics Double -> IO Double
forall a. Point -> Dynamics a -> IO a
invokeDynamics Point
p Dynamics Double
prob
     Int
trials' <- Point -> Dynamics Int -> IO Int
forall a. Point -> Dynamics a -> IO a
invokeDynamics Point
p Dynamics Int
trials
     Generator -> Double -> Int -> IO Int
generateBinomial Generator
g Double
prob' Int
trials'

-- | Computation that generates random numbers from the Gamma distribution
-- with the specified shape and scale but memoizes the numbers in
-- the integration time points.
memoRandomGammaDynamics :: Dynamics Double     -- ^ shape
                           -> Dynamics Double  -- ^ scale (a reciprocal of the rate)
                           -> Simulation (Dynamics Double)
memoRandomGammaDynamics :: Dynamics Double -> Dynamics Double -> Simulation (Dynamics Double)
memoRandomGammaDynamics Dynamics Double
kappa Dynamics Double
theta =
  Dynamics Double -> Simulation (Dynamics Double)
forall e. Unboxed e => Dynamics e -> Simulation (Dynamics e)
memo0Dynamics (Dynamics Double -> Simulation (Dynamics Double))
-> Dynamics Double -> Simulation (Dynamics Double)
forall a b. (a -> b) -> a -> b
$
  (Point -> IO Double) -> Dynamics Double
forall a. (Point -> IO a) -> Dynamics a
Dynamics ((Point -> IO Double) -> Dynamics Double)
-> (Point -> IO Double) -> Dynamics Double
forall a b. (a -> b) -> a -> b
$ \Point
p ->
  do let g :: Generator
g = Run -> Generator
runGenerator (Run -> Generator) -> Run -> Generator
forall a b. (a -> b) -> a -> b
$ Point -> Run
pointRun Point
p
     Double
kappa' <- Point -> Dynamics Double -> IO Double
forall a. Point -> Dynamics a -> IO a
invokeDynamics Point
p Dynamics Double
kappa
     Double
theta' <- Point -> Dynamics Double -> IO Double
forall a. Point -> Dynamics a -> IO a
invokeDynamics Point
p Dynamics Double
theta
     Generator -> Double -> Double -> IO Double
generateGamma Generator
g Double
kappa' Double
theta'

-- | Computation that generates random numbers from the Beta distribution
-- by the specified shape parameters and memoizes the numbers in
-- the integration time points.
memoRandomBetaDynamics :: Dynamics Double     -- ^ shape (alpha)
                          -> Dynamics Double  -- ^ shape (beta)
                          -> Simulation (Dynamics Double)
memoRandomBetaDynamics :: Dynamics Double -> Dynamics Double -> Simulation (Dynamics Double)
memoRandomBetaDynamics Dynamics Double
alpha Dynamics Double
beta =
  Dynamics Double -> Simulation (Dynamics Double)
forall e. Unboxed e => Dynamics e -> Simulation (Dynamics e)
memo0Dynamics (Dynamics Double -> Simulation (Dynamics Double))
-> Dynamics Double -> Simulation (Dynamics Double)
forall a b. (a -> b) -> a -> b
$
  (Point -> IO Double) -> Dynamics Double
forall a. (Point -> IO a) -> Dynamics a
Dynamics ((Point -> IO Double) -> Dynamics Double)
-> (Point -> IO Double) -> Dynamics Double
forall a b. (a -> b) -> a -> b
$ \Point
p ->
  do let g :: Generator
g = Run -> Generator
runGenerator (Run -> Generator) -> Run -> Generator
forall a b. (a -> b) -> a -> b
$ Point -> Run
pointRun Point
p
     Double
alpha' <- Point -> Dynamics Double -> IO Double
forall a. Point -> Dynamics a -> IO a
invokeDynamics Point
p Dynamics Double
alpha
     Double
beta'  <- Point -> Dynamics Double -> IO Double
forall a. Point -> Dynamics a -> IO a
invokeDynamics Point
p Dynamics Double
beta
     Generator -> Double -> Double -> IO Double
generateBeta Generator
g Double
alpha' Double
beta'

-- | Computation that generates random numbers from the Weibull distribution
-- with the specified shape and scale but memoizes the numbers in
-- the integration time points.
memoRandomWeibullDynamics :: Dynamics Double     -- ^ shape
                             -> Dynamics Double  -- ^ scale
                             -> Simulation (Dynamics Double)
memoRandomWeibullDynamics :: Dynamics Double -> Dynamics Double -> Simulation (Dynamics Double)
memoRandomWeibullDynamics Dynamics Double
alpha Dynamics Double
beta =
  Dynamics Double -> Simulation (Dynamics Double)
forall e. Unboxed e => Dynamics e -> Simulation (Dynamics e)
memo0Dynamics (Dynamics Double -> Simulation (Dynamics Double))
-> Dynamics Double -> Simulation (Dynamics Double)
forall a b. (a -> b) -> a -> b
$
  (Point -> IO Double) -> Dynamics Double
forall a. (Point -> IO a) -> Dynamics a
Dynamics ((Point -> IO Double) -> Dynamics Double)
-> (Point -> IO Double) -> Dynamics Double
forall a b. (a -> b) -> a -> b
$ \Point
p ->
  do let g :: Generator
g = Run -> Generator
runGenerator (Run -> Generator) -> Run -> Generator
forall a b. (a -> b) -> a -> b
$ Point -> Run
pointRun Point
p
     Double
alpha' <- Point -> Dynamics Double -> IO Double
forall a. Point -> Dynamics a -> IO a
invokeDynamics Point
p Dynamics Double
alpha
     Double
beta'  <- Point -> Dynamics Double -> IO Double
forall a. Point -> Dynamics a -> IO a
invokeDynamics Point
p Dynamics Double
beta
     Generator -> Double -> Double -> IO Double
generateWeibull Generator
g Double
alpha' Double
beta'

-- | Computation that generates random values from the specified discrete
-- distribution and memoizes the values in the integration time points.
memoRandomDiscreteDynamics :: Unboxed a => Dynamics (DiscretePDF a) -> Simulation (Dynamics a)
memoRandomDiscreteDynamics :: Dynamics (DiscretePDF a) -> Simulation (Dynamics a)
memoRandomDiscreteDynamics Dynamics (DiscretePDF a)
dpdf =
  Dynamics a -> Simulation (Dynamics a)
forall e. Unboxed e => Dynamics e -> Simulation (Dynamics e)
memo0Dynamics (Dynamics a -> Simulation (Dynamics a))
-> Dynamics a -> Simulation (Dynamics a)
forall a b. (a -> b) -> a -> b
$
  (Point -> IO a) -> Dynamics a
forall a. (Point -> IO a) -> Dynamics a
Dynamics ((Point -> IO a) -> Dynamics a) -> (Point -> IO a) -> Dynamics a
forall a b. (a -> b) -> a -> b
$ \Point
p ->
  do let g :: Generator
g = Run -> Generator
runGenerator (Run -> Generator) -> Run -> Generator
forall a b. (a -> b) -> a -> b
$ Point -> Run
pointRun Point
p
     DiscretePDF a
dpdf' <- Point -> Dynamics (DiscretePDF a) -> IO (DiscretePDF a)
forall a. Point -> Dynamics a -> IO a
invokeDynamics Point
p Dynamics (DiscretePDF a)
dpdf
     Generator -> DiscretePDF a -> IO a
Generator -> forall a. DiscretePDF a -> IO a
generateDiscrete Generator
g DiscretePDF a
dpdf'