Skip to content

Commit

Permalink
Make tests more concise and readable.
Browse files Browse the repository at this point in the history
  • Loading branch information
Pass Automated Testing Suite authored and Pass Automated Testing Suite committed Apr 29, 2024
1 parent 0f29e6d commit 4db8472
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 79 deletions.
11 changes: 4 additions & 7 deletions test/test_chacha.ml
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,16 @@ let test_advance _ =
(* manually advance ChaCha n times. Since Chacha generates 32bit ints,
we advance manually using next_uint32, else if we used next_uint64 we
would need to use n/2 steps.*)
let rec advance_n t = function
| 0 -> t
| i -> advance_n (ChaCha.next_uint32 t |> snd) (i - 1)
in
let t = ChaCha.initialize_full (SeedSequence.initialize [Uint128.of_int 12345]) Uint64.(max_int, zero) 4 in
let advance n = Seq.(iterate (fun s -> ChaCha.next_uint32 s |> snd) t |> drop n |> uncons |> Option.get |> fst) in
assert_equal
(ChaCha.advance (Uint128.of_int 1000) t |> ChaCha.next_uint32 |> fst |> Uint32.to_string)
(advance_n t 1000 |> ChaCha.next_uint32 |> fst |> Uint32.to_string)
(ChaCha.advance (Uint128.of_int 100) t |> ChaCha.next_uint32 |> fst |> Uint32.to_string)
(advance 100 |> ChaCha.next_uint32 |> fst |> Uint32.to_string)
~printer:(fun x -> x);
(* Test zero advancing *)
assert_equal
(ChaCha.advance Uint128.zero t |> ChaCha.next_uint32 |> fst |> Uint32.to_string)
(advance_n t 0 |> ChaCha.next_uint32 |> fst |> Uint32.to_string)
(advance 0 |> ChaCha.next_uint32 |> fst |> Uint32.to_string)
~printer:(fun x -> x);
(* Advancing with the largest 128bit integer should not fail *)
ignore (ChaCha.advance Uint128.max_int t)
Expand Down
10 changes: 3 additions & 7 deletions test/test_pcg.ml
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,11 @@ open Bitgen

let test_advance _ =
let open Stdint in
(* manually advance PCG64 n times and return the (n+1)'th random value. *)
let rec advance_n i t n = match i >= n with
| true -> PCG64.next_uint64 t |> fst |> Uint64.to_string
| false -> advance_n (i + 1) (PCG64.next_uint64 t |> snd) n
in
let t = SeedSequence.initialize [Uint128.of_int 12345] |> PCG64.initialize in
let advance n = Seq.(iterate (fun s -> PCG64.next_uint64 s |> snd) t |> drop n |> uncons |> Option.get |> fst) in
assert_equal
(PCG64.advance (Int128.of_int 12344) t |> PCG64.next_uint64 |> fst |> Uint64.to_string)
(advance_n 0 t 12344)
(PCG64.advance (Int128.of_int 100) t |> PCG64.next_uint64 |> fst |> Uint64.to_string)
(advance 100 |> PCG64.next_uint64 |> fst |> Uint64.to_string)
~printer:(fun x -> x)


Expand Down
11 changes: 4 additions & 7 deletions test/test_philox.ml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ let test_counter_init _ =
let ss = SeedSequence.initialize [Uint128.of_int 12345] in
let next_int init =
Philox4x64.initialize_ctr ~counter:init ss
|> Philox4x64.next_uint64 |> fst |> Uint64.to_string
in
|> Philox4x64.next_uint64 |> fst |> Uint64.to_string in
let base = next_int Uint64.(max_int, max_int, max_int, max_int) in
assert_bool "" (base <> next_int Uint64.(max_int, max_int, max_int, zero));
assert_bool "" (base <> next_int Uint64.(max_int, max_int, zero, zero));
Expand All @@ -33,22 +32,20 @@ let test_jump _ =
let ss = SeedSequence.initialize [] in
let t = Philox4x64.initialize_ctr ~counter:Uint64.(max_int, max_int, max_int, max_int) ss |> Philox4x64.jump in
let t' = Philox4x64.initialize_ctr ~counter:Uint64.(max_int, max_int, zero, max_int) ss |> Philox4x64.jump in
assert_bool "" ((Philox4x64.next_double t |> fst) <> (Philox4x64.next_double t' |> fst))
assert_bool "" ((Philox4x64.next_uint64 t |> fst) <> (Philox4x64.next_uint64 t' |> fst))


let test_advance _ =
let open Stdint in
(* since advance uses a 256-bit integer to advance, the equivalent number of
steps if manually calling next_uint64 would be 4 times larger than the
steps used to call advance. *)
let rec advance_n t = function
| 0 -> t
| i -> advance_n (Philox4x64.next_uint64 t |> snd) (i - 1) in
let t = SeedSequence.initialize [Uint128.of_int 12345]
|> Philox4x64.initialize_ctr ~counter:Uint64.(max_int, max_int, zero, zero) in
let advance n = Seq.(iterate (fun s -> Philox4x64.next_uint64 s |> snd) t |> drop n |> uncons |> Option.get |> fst) in
assert_equal
(Philox4x64.advance Uint64.(of_int 2, zero, zero, zero) t |> Philox4x64.next_uint64 |> fst |> Uint64.to_string)
(advance_n t (4 * 2) |> Philox4x64.next_uint64 |> fst |> Uint64.to_string)
(advance (4 * 2) |> Philox4x64.next_uint64 |> fst |> Uint64.to_string)
~printer:(fun x -> x)


Expand Down
5 changes: 2 additions & 3 deletions test/test_xoshiro.ml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,9 @@ let test_bounded_u64 _ = Testconf.test_bounded_u64 (module Xoshiro256)


let test_jump _ =
let ss = SeedSequence.initialize [] in
let t = Xoshiro256.initialize ss |> Xoshiro256.jump in
let t = SeedSequence.initialize [] |> Xoshiro256.initialize |> Xoshiro256.jump in
let t' = Xoshiro256.jump t in
assert_bool "" ((Xoshiro256.next_double t |> fst) <> (Xoshiro256.next_double t' |> fst))
assert_bool "" ((Xoshiro256.next_uint64 t |> fst) <> (Xoshiro256.next_uint64 t' |> fst))


let tests = [
Expand Down
94 changes: 39 additions & 55 deletions test/testconf.ml
Original file line number Diff line number Diff line change
Expand Up @@ -2,75 +2,59 @@ open OUnit2
open Stdint


let maxint32 = Uint64.of_int 0xffffffff
let uint32_of_uint64 x =
let upper = Uint64.(shift_right x 32 |> to_uint32) in
let lower = Uint64.(of_int 0xffffffff |> logand x |> to_uint32) in
Uint32.[to_string_hex lower; to_string_hex upper]
let upper = Uint64.(shift_right x 32 |> to_uint32) in
let lower = Uint64.(logand maxint32 x |> to_uint32) in
Uint32.[to_string_hex lower; to_string_hex upper]


let dbl_const = 1.0 /. 9007199254740992.0
let uniform_of_uint64 x =
Uint64.(shift_right x 11 |> to_string |> Float.of_string) *. (1.0 /. 9007199254740992.0) |> Float.to_string
Uint64.(shift_right x 11 |> to_string |> Float.of_string) *. dbl_const |> Float.to_string


module type S = sig
type t
val next_uint64 : t -> uint64 * t
val next_uint32 : t -> uint32 * t
val next_double : t -> float * t
val next_bounded_uint64: uint64 -> t -> uint64 * t
val initialize : Bitgen.SeedSequence.t -> t
type t
val next_uint64 : t -> uint64 * t
val next_uint32 : t -> uint32 * t
val next_double : t -> float * t
val next_bounded_uint64: uint64 -> t -> uint64 * t
val initialize : Bitgen.SeedSequence.t -> t
end


let test_bounded_u64 (module M : S) =
let open Stdint in
let is_less bound t = match M.next_bounded_uint64 bound t with
| u, t' -> Some (u < bound, t') in
let t = Bitgen.SeedSequence.initialize [Uint128.of_int 12345] |> M.initialize in
let all_true b = Seq.(unfold (is_less b) t |> take 100 |> fold_left (&&) true) in
List.iter (fun b -> assert_equal true (all_true b)) Uint64.[of_int 1; of_int 4193609425186963870]
let open Stdint in
let is_less bound t = match M.next_bounded_uint64 bound t with
| u, t' -> Some (u < bound, t') in
let t = Bitgen.SeedSequence.initialize [Uint128.of_int 12345] |> M.initialize in
let all_true b = Seq.(unfold (is_less b) t |> take 100 |> fold_left (&&) true) in
List.iter (fun b -> assert_equal true (all_true b)) Uint64.[of_int 1; of_int 4193609425186963870]


(* This tests the correctness of a bitgenerator's implementation against groundtruth data for a given seed.
This function takes the module representing the bitgenerator as well as the path to the CSV file
containing the groundtruth data. The data is sourced from numpy's random module test suite. *)
let bitgen_groundtruth (module M : S) file =
(* Draw a random 64 bit integer n times from Bitgenerator M. *)
let rec loop i t acc n = match i >= n with
| true -> List.rev acc
| false ->
let u, t' = M.next_uint64 t in
loop (i + 1) t' (Uint64.to_string_hex u :: acc) n
in
(* Draw a random 32 bit integer n times from Bitgenerator M. *)
let rec loop_u32 i t acc n = match i >= n with
| true -> List.rev acc
| false ->
let u, t' = M.next_uint32 t in
loop_u32 (i + 1) t' (Uint32.to_string_hex u :: acc) n
in
(* Draw a random 64bit float n times from Bitgenerator M. *)
let rec loopf i t acc n = match i >= n with
| true -> List.rev acc
| false ->
let u, t' = M.next_double t in
loopf (i + 1) t' (Float.to_string u :: acc) n
in
open_in file |> Csv.load_in |> List.(map tl) |> List.flatten |> function
| [] ->
assert_failure "There was an error parsing the CSV file"
| seed :: data ->
let t = Bitgen.SeedSequence.initialize [Uint128.of_string seed] |> M.initialize
in
assert_equal
data
(loop 0 t [] (List.length data))
~printer:(List.fold_left (^) "");
assert_equal
(List.map uint32_of_uint64 (List.map Uint64.of_string data) |> List.concat)
(loop_u32 0 t [] (List.length data * 2))
~printer:(List.fold_left (^) "");
assert_equal
(List.map uniform_of_uint64 (List.map Uint64.of_string data))
(loopf 0 t [] (List.length data))
~printer:(List.fold_left (^) "");
let u64 t = let u, t' = M.next_uint64 t in Some (Uint64.to_string_hex u, t')
and u32 t = let u, t' = M.next_uint32 t in Some (Uint32.to_string_hex u, t')
and double t = let u, t' = M.next_double t in Some (Float.to_string u, t')

in open_in file |> Csv.load_in |> List.(map tl) |> List.flatten |> function
| [] -> assert_failure "There was an error parsing the CSV file"
| seed :: data ->
let t = Bitgen.SeedSequence.initialize [Uint128.of_string seed] |> M.initialize in
let n = List.length data in
assert_equal
data Seq.(unfold u64 t |> take n |> List.of_seq) ~printer:(List.fold_left (^) "");

assert_equal
List.(map Uint64.of_string data |> map uint32_of_uint64 |> concat)
Seq.(unfold u32 t |> take (n * 2) |> List.of_seq)
~printer:(List.fold_left (^) "");

assert_equal
List.(map Uint64.of_string data |> map uniform_of_uint64)
Seq.(unfold double t |> take n |> List.of_seq)
~printer:(List.fold_left (^) "");

0 comments on commit 4db8472

Please sign in to comment.