module Simulation.Aivika.Branch.Generator () where
import Control.Monad
import Control.Monad.Trans
import qualified System.Random.MWC as MWC
import System.Random
import Data.IORef
import Simulation.Aivika.Trans
import Simulation.Aivika.Trans.Generator.Primitive
import Simulation.Aivika.Branch.Internal.BR
instance MonadGenerator (BR IO) where
data Generator (BR IO) =
Generator { generator01 :: BR IO Double,
generatorNormal01 :: BR IO Double,
generatorSequenceNo :: BR IO Int
}
generateUniform = generateUniform01 . generator01
generateUniformInt = generateUniformInt01 . generator01
generateTriangular = generateTriangular01 . generator01
generateNormal = generateNormal01 . generatorNormal01
generateLogNormal = generateLogNormal01 . generatorNormal01
generateExponential = generateExponential01 . generator01
generateErlang = generateErlang01 . generator01
generatePoisson = generatePoisson01 . generator01
generateBinomial = generateBinomial01 . generator01
generateGamma g = generateGamma01 (generatorNormal01 g) (generator01 g)
generateBeta g = generateBeta01 (generatorNormal01 g) (generator01 g)
generateWeibull = generateWeibull01 . generator01
generateDiscrete = generateDiscrete01 . generator01
generateSequenceNo = generatorSequenceNo
newGenerator tp =
case tp of
SimpleGenerator ->
do let g = MWC.uniform <$>
MWC.withSystemRandom (return :: MWC.GenIO -> IO MWC.GenIO)
g' <- liftIO g
newRandomGenerator01 (liftIO g')
SimpleGeneratorWithSeed x ->
error "Unsupported generator type SimpleGeneratorWithSeed: newGenerator"
CustomGenerator g ->
g
CustomGenerator01 g ->
newRandomGenerator01 g
newRandomGenerator g =
do r <- liftIO $ newIORef g
let g01 = do g <- liftIO $ readIORef r
let (x, g') = random g
liftIO $ writeIORef r g'
return x
newRandomGenerator01 g01
newRandomGenerator01 g01 =
do gNormal01 <- newNormalGenerator01 g01
gSeqNoRef <- liftIO $ newIORef 0
let gSeqNo =
do x <- liftIO $ readIORef gSeqNoRef
liftIO $ modifyIORef' gSeqNoRef (+1)
return x
return Generator { generator01 = g01,
generatorNormal01 = gNormal01,
generatorSequenceNo = gSeqNo }
newNormalGenerator01 :: BR IO Double
-> BR IO (BR IO Double)
newNormalGenerator01 g =
do nextRef <- liftIO $ newIORef 0.0
flagRef <- liftIO $ newIORef False
xi1Ref <- liftIO $ newIORef 0.0
xi2Ref <- liftIO $ newIORef 0.0
psiRef <- liftIO $ newIORef 0.0
let loop =
do psi <- liftIO $ readIORef psiRef
if (psi >= 1.0) || (psi == 0.0)
then do g1 <- g
g2 <- g
let xi1 = 2.0 * g1 1.0
xi2 = 2.0 * g2 1.0
psi = xi1 * xi1 + xi2 * xi2
liftIO $ writeIORef xi1Ref xi1
liftIO $ writeIORef xi2Ref xi2
liftIO $ writeIORef psiRef psi
loop
else liftIO $ writeIORef psiRef $ sqrt ( 2.0 * log psi / psi)
return $
do flag <- liftIO $ readIORef flagRef
if flag
then do liftIO $ writeIORef flagRef False
liftIO $ readIORef nextRef
else do liftIO $ writeIORef xi1Ref 0.0
liftIO $ writeIORef xi2Ref 0.0
liftIO $ writeIORef psiRef 0.0
loop
xi1 <- liftIO $ readIORef xi1Ref
xi2 <- liftIO $ readIORef xi2Ref
psi <- liftIO $ readIORef psiRef
liftIO $ writeIORef flagRef True
liftIO $ writeIORef nextRef $ xi2 * psi
return $ xi1 * psi