module QuantLib.Stochastic.PureMT
  (
    PureMT
  , newPureMT
  , randomDouble
  , splitMT
  , splitMTwithSeed
  ) where

import           Data.Time.Calendar
import           Data.Time.Clock
import           System.CPUTime
import qualified System.Random.Mersenne.Pure64 as P

data PureMT = PureMT P.PureMT Integer

newPureMT :: IO PureMT
newPureMT :: IO PureMT
newPureMT = do
    Integer
ct <- IO Integer
getCPUTime
    UTCTime
t  <- IO UTCTime
getCurrentTime
    let seed :: Integer
seed = Day -> Integer
toModifiedJulianDay (UTCTime -> Day
utctDay UTCTime
t) Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ DiffTime -> Integer
diffTimeToPicoseconds (UTCTime -> DiffTime
utctDayTime UTCTime
t) Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
ct
    PureMT -> IO PureMT
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (PureMT -> IO PureMT) -> PureMT -> IO PureMT
forall a b. (a -> b) -> a -> b
$ PureMT -> Integer -> PureMT
PureMT (Word64 -> PureMT
P.pureMT (Word64 -> PureMT) -> Word64 -> PureMT
forall a b. (a -> b) -> a -> b
$ Integer -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
seed) Integer
seed

randomDouble:: PureMT -> (Double, PureMT)
randomDouble :: PureMT -> (Double, PureMT)
randomDouble (PureMT PureMT
mt Integer
seed) = (Double
r, PureMT -> Integer -> PureMT
PureMT PureMT
newMt Integer
seed)
  where
    (Double
r, PureMT
newMt) = PureMT -> (Double, PureMT)
P.randomDouble PureMT
mt

splitMT :: PureMT -> (PureMT, PureMT)
splitMT :: PureMT -> (PureMT, PureMT)
splitMT = Integer -> PureMT -> (PureMT, PureMT)
splitMTwithSeed Integer
1

splitMTwithSeed :: Integer -> PureMT -> (PureMT, PureMT)
splitMTwithSeed :: Integer -> PureMT -> (PureMT, PureMT)
splitMTwithSeed Integer
addedSeed mt :: PureMT
mt@(PureMT PureMT
_ Integer
seed) = (PureMT
mt, PureMT -> Integer -> PureMT
PureMT PureMT
newMt Integer
newSeed)
  where
    newSeed :: Integer
newSeed = Integer
seed Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
addedSeed
    newMt :: PureMT
newMt = Word64 -> PureMT
P.pureMT (Word64 -> PureMT) -> Word64 -> PureMT
forall a b. (a -> b) -> a -> b
$ Integer -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
newSeed