{-# OPTIONS_HADDOCK not-home #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveLift #-}
#include "MachDeps.h"
module Hedgehog.Internal.Seed (
Seed(..)
, random
, from
, split
, nextInteger
, nextDouble
, goldenGamma
, nextWord64
, nextWord32
, mix64
, mix64variant13
, mix32
, mixGamma
) where
import Control.Monad.IO.Class (MonadIO(..))
import Data.Bifunctor (first)
import Data.Bits ((.|.), xor, shiftR, popCount)
#if (SIZEOF_HSINT == 8)
import Data.Int (Int64)
#else
import Data.Int (Int32)
#endif
import Data.Time.Clock.POSIX (getPOSIXTime)
import Data.IORef (IORef)
import qualified Data.IORef as IORef
import Data.Word (Word32, Word64)
import Language.Haskell.TH.Syntax (Lift)
import System.IO.Unsafe (unsafePerformIO)
import System.Random (RandomGen)
import qualified System.Random as Random
data Seed =
Seed {
Seed -> Word64
seedValue :: !Word64
, Seed -> Word64
seedGamma :: !Word64
} deriving (Seed -> Seed -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Seed -> Seed -> Bool
$c/= :: Seed -> Seed -> Bool
== :: Seed -> Seed -> Bool
$c== :: Seed -> Seed -> Bool
Eq, Eq Seed
Seed -> Seed -> Bool
Seed -> Seed -> Ordering
Seed -> Seed -> Seed
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Seed -> Seed -> Seed
$cmin :: Seed -> Seed -> Seed
max :: Seed -> Seed -> Seed
$cmax :: Seed -> Seed -> Seed
>= :: Seed -> Seed -> Bool
$c>= :: Seed -> Seed -> Bool
> :: Seed -> Seed -> Bool
$c> :: Seed -> Seed -> Bool
<= :: Seed -> Seed -> Bool
$c<= :: Seed -> Seed -> Bool
< :: Seed -> Seed -> Bool
$c< :: Seed -> Seed -> Bool
compare :: Seed -> Seed -> Ordering
$ccompare :: Seed -> Seed -> Ordering
Ord, forall t.
(forall (m :: * -> *). Quote m => t -> m Exp)
-> (forall (m :: * -> *). Quote m => t -> Code m t) -> Lift t
forall (m :: * -> *). Quote m => Seed -> m Exp
forall (m :: * -> *). Quote m => Seed -> Code m Seed
liftTyped :: forall (m :: * -> *). Quote m => Seed -> Code m Seed
$cliftTyped :: forall (m :: * -> *). Quote m => Seed -> Code m Seed
lift :: forall (m :: * -> *). Quote m => Seed -> m Exp
$clift :: forall (m :: * -> *). Quote m => Seed -> m Exp
Lift)
instance Show Seed where
showsPrec :: Int -> Seed -> ShowS
showsPrec Int
p (Seed Word64
v Word64
g) =
Bool -> ShowS -> ShowS
showParen (Int
p forall a. Ord a => a -> a -> Bool
> Int
10) forall a b. (a -> b) -> a -> b
$
String -> ShowS
showString String
"Seed " forall b c a. (b -> c) -> (a -> b) -> a -> c
.
forall a. Show a => Int -> a -> ShowS
showsPrec Int
11 Word64
v forall b c a. (b -> c) -> (a -> b) -> a -> c
.
Char -> ShowS
showChar Char
' ' forall b c a. (b -> c) -> (a -> b) -> a -> c
.
forall a. Show a => Int -> a -> ShowS
showsPrec Int
11 Word64
g
instance Read Seed where
readsPrec :: Int -> ReadS Seed
readsPrec Int
p =
forall a. Bool -> ReadS a -> ReadS a
readParen (Int
p forall a. Ord a => a -> a -> Bool
> Int
10) forall a b. (a -> b) -> a -> b
$ \String
r0 -> do
(String
"Seed", String
r1) <- ReadS String
lex String
r0
(Word64
v, String
r2) <- forall a. Read a => Int -> ReadS a
readsPrec Int
11 String
r1
(Word64
g, String
r3) <- forall a. Read a => Int -> ReadS a
readsPrec Int
11 String
r2
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Word64 -> Word64 -> Seed
Seed Word64
v Word64
g, String
r3)
global :: IORef Seed
global :: IORef Seed
global =
forall a. IO a -> a
unsafePerformIO forall a b. (a -> b) -> a -> b
$ do
POSIXTime
seconds <- IO POSIXTime
getPOSIXTime
forall a. a -> IO (IORef a)
IORef.newIORef forall a b. (a -> b) -> a -> b
$ Word64 -> Seed
from (forall a b. (RealFrac a, Integral b) => a -> b
round (POSIXTime
seconds forall a. Num a => a -> a -> a
* POSIXTime
1000))
{-# NOINLINE global #-}
random :: MonadIO m => m Seed
random :: forall (m :: * -> *). MonadIO m => m Seed
random =
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ forall a b. IORef a -> (a -> (a, b)) -> IO b
IORef.atomicModifyIORef' IORef Seed
global Seed -> (Seed, Seed)
split
from :: Word64 -> Seed
from :: Word64 -> Seed
from Word64
x =
Word64 -> Word64 -> Seed
Seed (Word64 -> Word64
mix64 Word64
x) (Word64 -> Word64
mixGamma (Word64
x forall a. Num a => a -> a -> a
+ Word64
goldenGamma))
goldenGamma :: Word64
goldenGamma :: Word64
goldenGamma =
Word64
0x9e3779b97f4a7c15
next :: Seed -> (Word64, Seed)
next :: Seed -> (Word64, Seed)
next (Seed Word64
v0 Word64
g) =
let
v :: Word64
v = Word64
v0 forall a. Num a => a -> a -> a
+ Word64
g
in
(Word64
v, Word64 -> Word64 -> Seed
Seed Word64
v Word64
g)
split :: Seed -> (Seed, Seed)
split :: Seed -> (Seed, Seed)
split Seed
s0 =
let
(Word64
v0, Seed
s1) = Seed -> (Word64, Seed)
next Seed
s0
(Word64
g0, Seed
s2) = Seed -> (Word64, Seed)
next Seed
s1
in
(Seed
s2, Word64 -> Word64 -> Seed
Seed (Word64 -> Word64
mix64 Word64
v0) (Word64 -> Word64
mixGamma Word64
g0))
nextWord64 :: Seed -> (Word64, Seed)
nextWord64 :: Seed -> (Word64, Seed)
nextWord64 Seed
s0 =
let
(Word64
v0, Seed
s1) = Seed -> (Word64, Seed)
next Seed
s0
in
(Word64 -> Word64
mix64 Word64
v0, Seed
s1)
nextWord32 :: Seed -> (Word32, Seed)
nextWord32 :: Seed -> (Word32, Seed)
nextWord32 Seed
s0 =
let
(Word64
v0, Seed
s1) = Seed -> (Word64, Seed)
next Seed
s0
in
(Word64 -> Word32
mix32 Word64
v0, Seed
s1)
nextInteger :: Integer -> Integer -> Seed -> (Integer, Seed)
nextInteger :: Integer -> Integer -> Seed -> (Integer, Seed)
nextInteger Integer
lo Integer
hi =
forall a g. (Random a, RandomGen g) => (a, a) -> g -> (a, g)
Random.randomR (Integer
lo, Integer
hi)
nextDouble :: Double -> Double -> Seed -> (Double, Seed)
nextDouble :: Double -> Double -> Seed -> (Double, Seed)
nextDouble Double
lo Double
hi =
forall a g. (Random a, RandomGen g) => (a, a) -> g -> (a, g)
Random.randomR (Double
lo, Double
hi)
mix64 :: Word64 -> Word64
mix64 :: Word64 -> Word64
mix64 Word64
x =
let
y :: Word64
y = (Word64
x forall a. Bits a => a -> a -> a
`xor` (Word64
x forall a. Bits a => a -> Int -> a
`shiftR` Int
33)) forall a. Num a => a -> a -> a
* Word64
0xff51afd7ed558ccd
z :: Word64
z = (Word64
y forall a. Bits a => a -> a -> a
`xor` (Word64
y forall a. Bits a => a -> Int -> a
`shiftR` Int
33)) forall a. Num a => a -> a -> a
* Word64
0xc4ceb9fe1a85ec53
in
Word64
z forall a. Bits a => a -> a -> a
`xor` (Word64
z forall a. Bits a => a -> Int -> a
`shiftR` Int
33)
mix32 :: Word64 -> Word32
mix32 :: Word64 -> Word32
mix32 Word64
x =
let
y :: Word64
y = (Word64
x forall a. Bits a => a -> a -> a
`xor` (Word64
x forall a. Bits a => a -> Int -> a
`shiftR` Int
33)) forall a. Num a => a -> a -> a
* Word64
0xff51afd7ed558ccd
z :: Word64
z = (Word64
y forall a. Bits a => a -> a -> a
`xor` (Word64
y forall a. Bits a => a -> Int -> a
`shiftR` Int
33)) forall a. Num a => a -> a -> a
* Word64
0xc4ceb9fe1a85ec53
in
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
z forall a. Bits a => a -> Int -> a
`shiftR` Int
32)
mix64variant13 :: Word64 -> Word64
mix64variant13 :: Word64 -> Word64
mix64variant13 Word64
x =
let
y :: Word64
y = (Word64
x forall a. Bits a => a -> a -> a
`xor` (Word64
x forall a. Bits a => a -> Int -> a
`shiftR` Int
30)) forall a. Num a => a -> a -> a
* Word64
0xbf58476d1ce4e5b9
z :: Word64
z = (Word64
y forall a. Bits a => a -> a -> a
`xor` (Word64
y forall a. Bits a => a -> Int -> a
`shiftR` Int
27)) forall a. Num a => a -> a -> a
* Word64
0x94d049bb133111eb
in
Word64
z forall a. Bits a => a -> a -> a
`xor` (Word64
z forall a. Bits a => a -> Int -> a
`shiftR` Int
31)
mixGamma :: Word64 -> Word64
mixGamma :: Word64 -> Word64
mixGamma Word64
x =
let
y :: Word64
y = Word64 -> Word64
mix64variant13 Word64
x forall a. Bits a => a -> a -> a
.|. Word64
1
n :: Int
n = forall a. Bits a => a -> Int
popCount forall a b. (a -> b) -> a -> b
$ Word64
y forall a. Bits a => a -> a -> a
`xor` (Word64
y forall a. Bits a => a -> Int -> a
`shiftR` Int
1)
in
if Int
n forall a. Ord a => a -> a -> Bool
< Int
24 then
Word64
y forall a. Bits a => a -> a -> a
`xor` Word64
0xaaaaaaaaaaaaaaaa
else
Word64
y
#if (SIZEOF_HSINT == 8)
instance RandomGen Seed where
next :: Seed -> (Int, Seed)
next =
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first forall a b. (Integral a, Num b) => a -> b
fromIntegral forall b c a. (b -> c) -> (a -> b) -> a -> c
. Seed -> (Word64, Seed)
nextWord64
genRange :: Seed -> (Int, Int)
genRange Seed
_ =
(forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall a. Bounded a => a
minBound :: Int64), forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall a. Bounded a => a
maxBound :: Int64))
split :: Seed -> (Seed, Seed)
split =
Seed -> (Seed, Seed)
split
#else
instance RandomGen Seed where
next =
first fromIntegral . nextWord32
genRange _ =
(fromIntegral (minBound :: Int32), fromIntegral (maxBound :: Int32))
split =
split
#endif