mini 1.6.2.0 → 1.6.3.0
raw patch · 4 files changed
+141/−1 lines, 4 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Mini.Random.Class: class Generator g => Splittable g
+ Mini.Random.Class: instance Mini.Random.Class.Generator Mini.Random.SplitMix.SplitMix
+ Mini.Random.Class: instance Mini.Random.Class.Splittable Mini.Random.SplitMix.SplitMix
+ Mini.Random.Class: split :: Splittable g => g -> (g, g)
+ Mini.Random.SplitMix: data SplitMix
+ Mini.Random.SplitMix: instance GHC.Classes.Eq Mini.Random.SplitMix.SplitMix
+ Mini.Random.SplitMix: instance GHC.Classes.Ord Mini.Random.SplitMix.SplitMix
+ Mini.Random.SplitMix: instance GHC.Show.Show Mini.Random.SplitMix.SplitMix
+ Mini.Random.SplitMix: nextWord32 :: SplitMix -> (Word32, SplitMix)
+ Mini.Random.SplitMix: nextWord64 :: SplitMix -> (Word64, SplitMix)
+ Mini.Random.SplitMix: seed :: Word64 -> SplitMix
+ Mini.Random.SplitMix: split :: SplitMix -> (SplitMix, SplitMix)
Files
- CHANGELOG.md +9/−0
- mini.cabal +2/−1
- src/Mini/Random/Class.hs +22/−0
- src/Mini/Random/SplitMix.hs +108/−0
CHANGELOG.md view
@@ -1,3 +1,12 @@+1.6.3.0 [2026-05-02]+--------------------+* Create Mini.Random.SplitMix: An implementation of SplitMix, based on+ <https://doi.org/10.1145/2660193.2660195>+* Mini.Random.Class:+ * Add class Splittable: The class of splittable generators+ * Add instance Generator SplitMix+ * Add instance Splittable SplitMix+ 1.6.2.0 [2026-05-01] -------------------- * Create Mini.Random.Class: A pure interface for pseudorandom value generation
mini.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: mini-version: 1.6.2.0+version: 1.6.3.0 license: MIT license-file: LICENSE author: Victor Wallsten <victor.wallsten@protonmail.com>@@ -39,6 +39,7 @@ Mini.Hash.Murmur32 Mini.Optics.Lens Mini.Random.Class+ Mini.Random.SplitMix Mini.Transformers.Class Mini.Transformers.EitherT Mini.Transformers.MaybeT
src/Mini/Random/Class.hs view
@@ -5,6 +5,9 @@ nextWord32, nextWord64 ),+ Splittable (+ split+ ), Random ( random ),@@ -43,6 +46,14 @@ add, digest, )+import Mini.Random.SplitMix (+ SplitMix,+ )+import qualified Mini.Random.SplitMix as SplitMix (+ nextWord32,+ nextWord64,+ split,+ ) import Prelude ( Bool, Char,@@ -76,6 +87,17 @@ lo' = fromIntegral lo hi' = fromIntegral hi `shiftL` 32 in (lo' .|. hi', g')++instance Generator SplitMix where+ nextWord32 = SplitMix.nextWord32+ nextWord64 = SplitMix.nextWord64++-- | The class of splittable pseudorandom number generators+class (Generator g) => Splittable g where+ split :: g -> (g, g)++instance Splittable SplitMix where+ split = SplitMix.split -- | The class of types for which pseudorandom values can be generated class Random a where
+ src/Mini/Random/SplitMix.hs view
@@ -0,0 +1,108 @@+-- | An implementation of SplitMix: <https://doi.org/10.1145/2660193.2660195>+module Mini.Random.SplitMix (+ -- * Type+ SplitMix,++ -- * Construction+ seed,++ -- * Operations+ nextWord32,+ nextWord64,+ split,+) where++import Data.Bits (+ popCount,+ shiftR,+ xor,+ (.|.),+ )+import Data.Word (+ Word32,+ Word64,+ )+import Mini.Data.Recursion (+ bool,+ )+import Prelude (+ Eq,+ Ord,+ Show,+ fromIntegral,+ ($),+ (*),+ (+),+ (<),+ )++-- Type++-- | Abstract representation of a SplitMix generator+data SplitMix = SplitMix Word64 Word64+ deriving (Eq, Ord, Show)++-- Construction++-- | Make a generator from a seed+seed :: Word64 -> SplitMix+seed s = SplitMix (mix64 s) (mixGamma $ s + 0x9e3779b97f4a7c15)++-- Operations++-- | Generate the next 32-bit word+nextWord32 :: SplitMix -> (Word32, SplitMix)+nextWord32 (SplitMix s g) =+ let s' = s + g+ in (mix32 s', SplitMix s' g)++-- | Generate the next 64-bit word+nextWord64 :: SplitMix -> (Word64, SplitMix)+nextWord64 (SplitMix s g) =+ let s' = s + g+ in (mix64 s', SplitMix s' g)++-- | Split a generator into two (seemingly) independent generators+split :: SplitMix -> (SplitMix, SplitMix)+split (SplitMix s g) =+ let s' = s + g+ s'' = s' + g+ sm = SplitMix s'' g+ sm' = SplitMix (mix64 s') (mixGamma s'')+ in (sm, sm')++-- Helpers++mix64 :: Word64 -> Word64+mix64 z0 =+ let z1 = z0 `xor` (z0 `shiftR` 33)+ z2 = z1 * 0xff51afd7ed558ccd+ z3 = z2 `xor` (z2 `shiftR` 33)+ z4 = z3 * 0xc4ceb9fe1a85ec53+ z5 = z4 `xor` (z4 `shiftR` 33)+ in z5++mix32 :: Word64 -> Word32+mix32 z0 =+ let z1 = z0 `xor` (z0 `shiftR` 33)+ z2 = z1 * 0xff51afd7ed558ccd+ z3 = z2 `xor` (z2 `shiftR` 33)+ z4 = z3 * 0xc4ceb9fe1a85ec53+ z5 = z4 `shiftR` 32+ in fromIntegral z5++mix64variant13 :: Word64 -> Word64+mix64variant13 z0 =+ let z1 = z0 `xor` (z0 `shiftR` 30)+ z2 = z1 * 0xbf58476d1ce4e5b9+ z3 = z2 `xor` (z2 `shiftR` 27)+ z4 = z3 * 0x94d049bb133111eb+ z5 = z4 `xor` (z4 `shiftR` 31)+ in z5++mixGamma :: Word64 -> Word64+mixGamma z0 =+ let z1 = mix64variant13 z0 .|. 1+ n = popCount $ z1 `xor` (z1 `shiftR` 1)+ in -- based on the text on p. 466, not the code with inverted logic on p. 465+ bool z1 (z1 `xor` 0xaaaaaaaaaaaaaaaa) $ n < 24