{-# 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
(Seed -> Seed -> Bool) -> (Seed -> Seed -> Bool) -> Eq Seed
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
Eq Seed
-> (Seed -> Seed -> Ordering)
-> (Seed -> Seed -> Bool)
-> (Seed -> Seed -> Bool)
-> (Seed -> Seed -> Bool)
-> (Seed -> Seed -> Bool)
-> (Seed -> Seed -> Seed)
-> (Seed -> Seed -> Seed)
-> Ord 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
$cp1Ord :: Eq Seed
Ord, Seed -> Q Exp
Seed -> Q (TExp Seed)
(Seed -> Q Exp) -> (Seed -> Q (TExp Seed)) -> Lift Seed
forall t. (t -> Q Exp) -> (t -> Q (TExp t)) -> Lift t
liftTyped :: Seed -> Q (TExp Seed)
$cliftTyped :: Seed -> Q (TExp Seed)
lift :: Seed -> Q Exp
$clift :: Seed -> Q Exp
Lift)
instance Show Seed where
showsPrec :: Int -> Seed -> ShowS
showsPrec Int
p (Seed Word64
v Word64
g) =
Bool -> ShowS -> ShowS
showParen (Int
p Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
10) (ShowS -> ShowS) -> ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$
String -> ShowS
showString String
"Seed " ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
Int -> Word64 -> ShowS
forall a. Show a => Int -> a -> ShowS
showsPrec Int
11 Word64
v ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
Char -> ShowS
showChar Char
' ' ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
Int -> Word64 -> ShowS
forall a. Show a => Int -> a -> ShowS
showsPrec Int
11 Word64
g
instance Read Seed where
readsPrec :: Int -> ReadS Seed
readsPrec Int
p =
Bool -> ReadS Seed -> ReadS Seed
forall a. Bool -> ReadS a -> ReadS a
readParen (Int
p Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
10) (ReadS Seed -> ReadS Seed) -> ReadS Seed -> ReadS Seed
forall a b. (a -> b) -> a -> b
$ \String
r0 -> do
(String
"Seed", String
r1) <- ReadS String
lex String
r0
(Word64
v, String
r2) <- Int -> ReadS Word64
forall a. Read a => Int -> ReadS a
readsPrec Int
11 String
r1
(Word64
g, String
r3) <- Int -> ReadS Word64
forall a. Read a => Int -> ReadS a
readsPrec Int
11 String
r2
(Seed, String) -> [(Seed, String)]
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 =
IO (IORef Seed) -> IORef Seed
forall a. IO a -> a
unsafePerformIO (IO (IORef Seed) -> IORef Seed) -> IO (IORef Seed) -> IORef Seed
forall a b. (a -> b) -> a -> b
$ do
POSIXTime
seconds <- IO POSIXTime
getPOSIXTime
Seed -> IO (IORef Seed)
forall a. a -> IO (IORef a)
IORef.newIORef (Seed -> IO (IORef Seed)) -> Seed -> IO (IORef Seed)
forall a b. (a -> b) -> a -> b
$ Word64 -> Seed
from (POSIXTime -> Word64
forall a b. (RealFrac a, Integral b) => a -> b
round (POSIXTime
seconds POSIXTime -> POSIXTime -> POSIXTime
forall a. Num a => a -> a -> a
* POSIXTime
1000))
{-# NOINLINE global #-}
random :: MonadIO m => m Seed
random :: m Seed
random =
IO Seed -> m Seed
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Seed -> m Seed) -> IO Seed -> m Seed
forall a b. (a -> b) -> a -> b
$ IORef Seed -> (Seed -> (Seed, Seed)) -> IO Seed
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 Word64 -> Word64 -> Word64
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 Word64 -> Word64 -> Word64
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 =
(Integer, Integer) -> Seed -> (Integer, Seed)
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 =
(Double, Double) -> Seed -> (Double, Seed)
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 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
`xor` (Word64
x Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
33)) Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
* Word64
0xff51afd7ed558ccd
z :: Word64
z = (Word64
y Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
`xor` (Word64
y Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
33)) Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
* Word64
0xc4ceb9fe1a85ec53
in
Word64
z Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
`xor` (Word64
z Word64 -> Int -> Word64
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 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
`xor` (Word64
x Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
33)) Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
* Word64
0xff51afd7ed558ccd
z :: Word64
z = (Word64
y Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
`xor` (Word64
y Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
33)) Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
* Word64
0xc4ceb9fe1a85ec53
in
Word64 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
z Word64 -> Int -> Word64
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 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
`xor` (Word64
x Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
30)) Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
* Word64
0xbf58476d1ce4e5b9
z :: Word64
z = (Word64
y Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
`xor` (Word64
y Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
27)) Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
* Word64
0x94d049bb133111eb
in
Word64
z Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
`xor` (Word64
z Word64 -> Int -> Word64
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 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. Word64
1
n :: Int
n = Word64 -> Int
forall a. Bits a => a -> Int
popCount (Word64 -> Int) -> Word64 -> Int
forall a b. (a -> b) -> a -> b
$ Word64
y Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
`xor` (Word64
y Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
1)
in
if Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
24 then
Word64
y Word64 -> Word64 -> Word64
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 =
(Word64 -> Int) -> (Word64, Seed) -> (Int, Seed)
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral ((Word64, Seed) -> (Int, Seed))
-> (Seed -> (Word64, Seed)) -> Seed -> (Int, Seed)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Seed -> (Word64, Seed)
nextWord64
genRange :: Seed -> (Int, Int)
genRange Seed
_ =
(Int64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int64
forall a. Bounded a => a
minBound :: Int64), Int64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int64
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