module Simulation.Aivika.Trans.Generator.Primitive where
import Control.Monad
import Control.Monad.Trans
import Simulation.Aivika.Generator (DiscretePDF)
generateUniform01 :: Monad m
=> m Double
-> Double
-> Double
-> m Double
generateUniform01 g min max =
do x <- g
return $ min + x * (max min)
generateUniformInt01 :: Monad m
=> m Double
-> Int
-> Int
-> m Int
generateUniformInt01 g min max =
do x <- g
let min' = fromIntegral min 0.5
max' = fromIntegral max + 0.5
z = round (min' + x * (max' min'))
z' = if z < min
then min
else if z > max
then max
else z
return z'
generateTriangular01 :: Monad m
=> m Double
-> Double
-> Double
-> Double
-> m Double
generateTriangular01 g min median max =
do x <- g
if x <= (median min) / (max min)
then return $ min + sqrt ((median min) * (max min) * x)
else return $ max sqrt ((max median) * (max min) * (1 x))
generateNormal01 :: Monad m
=> m Double
-> Double
-> Double
-> m Double
generateNormal01 g mu nu =
do x <- g
return $ mu + nu * x
generateLogNormal01 :: Monad m
=> m Double
-> Double
-> Double
-> m Double
generateLogNormal01 g mu nu =
do x <- g
return $ exp (mu + nu * x)
generateExponential01 :: Monad m
=> m Double
-> Double
-> m Double
generateExponential01 g mu =
do x <- g
return ( log x * mu)
generateErlang01 :: Monad m
=> m Double
-> Double
-> Int
-> m Double
generateErlang01 g beta m =
do x <- loop m 1
return ( log x * beta)
where loop m acc
| m < 0 = error "Negative shape: generateErlang."
| m == 0 = return acc
| otherwise = do x <- g
loop (m 1) (x * acc)
generatePoisson01 :: Monad m
=> m Double
-> Double
-> m Int
generatePoisson01 g mu =
do prob0 <- g
let loop prob prod acc
| prob <= prod = return acc
| otherwise = loop
(prob prod)
(prod * mu / fromIntegral (acc + 1))
(acc + 1)
loop prob0 (exp ( mu)) 0
generateBinomial01 :: Monad m
=> m Double
-> Double
-> Int
-> m Int
generateBinomial01 g prob trials = loop trials 0 where
loop n acc
| n < 0 = error "Negative number of trials: generateBinomial."
| n == 0 = return acc
| otherwise = do x <- g
if x <= prob
then loop (n 1) (acc + 1)
else loop (n 1) acc
generateGamma01 :: Monad m
=> m Double
-> m Double
-> Double
-> Double
-> m Double
generateGamma01 gn gu kappa theta
| kappa <= 0 = error "The shape parameter (kappa) must be positive: generateGamma01"
| kappa > 1 =
let d = kappa 1 / 3
c = 1 / sqrt (9 * d)
loop =
do z <- gn
if z <= (1 / c)
then loop
else do let v = (1 + c * z) ** 3
u <- gu
if log u > 0.5 * z * z + d d * v + d * log v
then loop
else return $ d * v * theta
in loop
| otherwise =
do x <- generateGamma01 gn gu (1 + kappa) theta
u <- gu
return $ x * u ** (1 / kappa)
generateBeta01 :: Monad m
=> m Double
-> m Double
-> Double
-> Double
-> m Double
generateBeta01 gn gu alpha beta =
do g1 <- generateGamma01 gn gu alpha 1
g2 <- generateGamma01 gn gu beta 1
return $ g1 / (g1 + g2)
generateWeibull01 :: Monad m
=> m Double
-> Double
-> Double
-> m Double
generateWeibull01 g alpha beta =
do x <- g
return $ beta * ( log x) ** (1 / alpha)
generateDiscrete01 :: Monad m
=> m Double
-> DiscretePDF a
-> m a
generateDiscrete01 g [] = error "Empty PDF: generateDiscrete01"
generateDiscrete01 g dpdf =
do x <- g
let loop acc [(a, p)] = a
loop acc ((a, p) : dpdf) =
if x <= acc + p
then a
else loop (acc + p) dpdf
return $ loop 0 dpdf