module Stochastic.Uniform(xorshift128plus,
UniformRandom,
nWayAllocate,
splitAllocate,
RandomGen(..)) where
import Stochastic.Generator
import Data.Word
import Data.Bits
import Data.Typeable
import Control.Exception(throw, Exception)
import System.Random(RandomGen(..))
data UniformRandom = XorShift128Plus Word64 Word64 Integer
data EntropyExhausted = EntropyExhausted
deriving(Eq, Typeable)
instance Exception EntropyExhausted where
instance Show EntropyExhausted where
show e = "EntropyExhausted"
xorshift128plus :: Integer -> UniformRandom
xorshift128plus seed = XorShift128Plus high low entropy
where
high = fromInteger seed
low = fromInteger seed
entropy = (2^127)
nWayAllocate :: Integer -> Integer -> UniformRandom -> ([UniformRandom], UniformRandom)
nWayAllocate _ 0 g0 = ([], g0)
nWayAllocate size n g0 = ((g1:gs), g3)
where
!(gs,g3) = nWayAllocate size (n1) g2
!(g1,g2) = splitAllocate size g0
splitAllocate :: Integer -> UniformRandom -> (UniformRandom, UniformRandom)
splitAllocate count g@(XorShift128Plus high low entropy) =
((XorShift128Plus high low count), g')
where
!g' = step (next) (count) g
instance RandomGen UniformRandom where
next (XorShift128Plus high low entropy)
| entropy == 0 = throw EntropyExhausted
| otherwise = final
where
final = (ret, XorShift128Plus high' low' entropy')
!ret = fromInteger $ toInteger $ high' + high
x = low `xor` (low `shift` 23)
high' = x `xor` high `xor` (x `shift` (17)) `xor` (high `shift` (26))
low' = high
entropy' = entropy 1
split g@(XorShift128Plus high low entropy) =
((XorShift128Plus high low entropy'), g')
where
!entropy' = (2^32)
!g' = step (next) (entropy') g
step :: (g -> (a,g)) -> Integer -> g -> g
step f 0 g'' = g''
step f n g'' = step (f) (n1) $! (snd $ f g'')