Skip to content

Add PCG64DXSM variant of the PCG64 bitgenerator. #32

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/bitgen.ml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ module SeedSequence = Seed.SeedSequence

module SFC64 = Sfc.SFC64
module PCG64 = Pcg.PCG64
module PCG64DXSM = Pcg.PCG64DXSM
module Xoshiro256 = Xoshiro.Xoshiro256StarStar
module Philox4x64 = Philox.Philox
module ChaCha = Chacha.ChaCha128Counter
56 changes: 47 additions & 9 deletions lib/pcg.ml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
open Stdint


module PCG64 : sig
module type PCG_TYPE = sig
(** PCG-64 is a 128-bit implementation of O'Neill's permutation congruential
generator. PCG-64 has a period of {m 2^{128}} and supports advancing an arbitrary
number of steps as well as {m 2^{127}} streams.
Expand All @@ -23,16 +23,24 @@ module PCG64 : sig
val advance : int128 -> t -> t
(** [advance delta] Advances the underlying RNG as if [delta] draws have been made.
The returned state is that of the generator [delta] steps forward. *)
end


module type FUNCTOR_SIG = sig
type t = {s : setseq; ustore : uint32 option}
and setseq = {state : uint128; increment : uint128}
val multiplier : uint128
val output : uint128 -> uint64
val next : setseq -> uint64 * setseq
end

val next_bounded_uint64 : uint64 -> t -> uint64 * t
(** [next_bounded_uint64 bound t] returns an unsigned 64bit integers in the range
(0, bound) as well as the state of the generator advanced one step forward. *)
end = struct

module PCG64Impl = struct
type t = {s : setseq; ustore : uint32 option}
and setseq = {state : uint128; increment : uint128}

let multiplier = Uint128.of_string "0x2360ed051fc65da44385df649fccf645"
let sixtythree = Uint32.of_int 63
let sixtythree = Uint32.of_int32 63l

(* Uses the XSL-RR output function *)
let output state =
Expand All @@ -45,14 +53,40 @@ end = struct
let next {state; increment} =
let state' = Uint128.(state * multiplier + increment) in
output state', {state = state'; increment}
end


module PCG64DXSMImpl = struct
type t = {s : setseq; ustore : uint32 option}
and setseq = {state : uint128; increment : uint128}

let cheap_multiplier = Uint64.of_string "0xda942042e4dd58b5"
let multiplier = Uint128.of_uint64 cheap_multiplier

let output state =
let hi0 = Uint128.(shift_right state 64 |> to_uint64) in
let lo = Uint128.(logor state one |> to_uint64) in
let hi1 = Uint64.(shift_right hi0 32 |> logxor hi0) in
let hi2 = Uint64.(hi1 * cheap_multiplier) in
let hi3 = Uint64.(shift_right hi2 48 |> logxor hi2) in
let hi4 = Uint64.(hi3 * lo) in
hi4


let next {state; increment} =
output state, {state = Uint128.(state * multiplier + increment); increment}
end


module Make (M : FUNCTOR_SIG) = struct
include M


let next_uint64 t = match next t.s with
| u, s -> u, {t with s}


let next_uint32 t =
match Common.next_uint32 ~next:next t.s t.ustore with

let next_uint32 t = match Common.next_uint32 ~next:next t.s t.ustore with
| u, s, ustore -> u, {s; ustore}


Expand Down Expand Up @@ -83,3 +117,7 @@ end = struct
let initialize seed =
{s = set_seed (Seed.SeedSequence.generate_64bit_state 4 seed); ustore = None}
end


module PCG64DXSM : PCG_TYPE = Make (PCG64DXSMImpl)
module PCG64 : PCG_TYPE = Make (PCG64Impl)
8 changes: 7 additions & 1 deletion test/test_pcg.ml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,13 @@ let test_pcg_datasets _ =
(Sys.getcwd () ^ "/../../../test/data/pcg64-testset-1.csv");
Testconf.bitgen_groundtruth
(module PCG64)
(Sys.getcwd () ^ "/../../../test/data/pcg64-testset-2.csv")
(Sys.getcwd () ^ "/../../../test/data/pcg64-testset-2.csv");
Testconf.bitgen_groundtruth
(module PCG64DXSM)
(Sys.getcwd () ^ "/../../../test/data/pcg64dxsm-testset-1.csv");
Testconf.bitgen_groundtruth
(module PCG64DXSM)
(Sys.getcwd () ^ "/../../../test/data/pcg64dxsm-testset-2.csv")


let test_bounded_u64 _ = Testconf.test_bounded_u64 (module PCG64)
Expand Down