fix: cross-engine rng parity via shared splitmix64 + seed builtin#503
Merged
Conversation
❌ 2 Tests Failed:
View the top 2 failed test(s) by shortest run time
To view more test analytics, go to the Test Analytics Dashboard |
0b559be to
e0b63d9
Compare
Collaborator
Author
|
Closing to unstick the merge queue. The keep-both rebase strategy can't handle this PR cleanly (it touches the same dispatch table every other PR appends to, producing broken-brace artifacts on rebase). Will reimplement against current main after the rest of the queue drains. |
4 tasks
All engines now share a single AtomicU64 PRNG state (SplitMix64). Default seed is 0xCAFEBABEDEADBEEF - deterministic, no wall-clock, no OS entropy. Cross-platform: identical sequences on Mac, Linux, Windows for same seed.
Replace all fastrand::f64()/i64() calls with crate::rng::f64()/i64_range(). Add OP_SEED opcode (189) dispatched in VM and both Cranelift backends via jit_seed extern-C helper. box_muller_normal delegates to crate::rng::normal. Every engine now advances the same AtomicU64 state - no per-engine divergence.
seed n > _ pins the shared SplitMix64 state. Registered in Builtin enum, from_name/name round-trip, verify.rs BUILTINS arity table, and the VM compiler special-case (Builtin::Seed, 1) => OP_SEED emission path. Deterministic programs use seed N at startup; entropy via seed (now-ms).
regression_rng_parity.rs: 8 tests covering seed+rnd/rndn/rnd-range parity across VM and JIT, default-seed determinism, reseed replay, and a Monte Carlo mean stability check (50 draws, pinned to 0.493...). examples/rng-seed-parity.ilo: run/out markers so the engine harness exercises seed + three sequential rnd draws with expected output pinned.
seed n > _ documented in SPEC.md math table alongside rnd/rndn. ai.txt BUILTINS line gets seed entry with SplitMix64 and entropy note. SKILL.md 4-char+ builtin list includes seed.
e0b63d9 to
4b7ec07
Compare
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
AtomicU64PRNG state implemented as SplitMix64 insrc/rng.rsfastrand::f64()/fastrand::i64()which was seeded from OS entropy and could diverge across engines0xCAFEBABEDEADBEEF- deterministic, no wall-clock; programs opt in to entropy viaseed (now-ms)seed n > _builtin to set the PRNG state explicitly, enabling reproducible stochastic workloadsRepro before/after
Before:
ilo run --vm 'f>n;rnd' fandilo run --jit 'f>n;rnd' fproduced different values each run and different values from each other.After:
Same value, same engine, same run - every time.
What's in the diff
add shared splitmix64 rng module-src/rng.rs: SplitMix64 in ~80 lines, norandcrate,AtomicU64state,f64(),i64_range(),normal()(Box-Muller)wire rnd/rndn through shared rng in tree, VM, JIT, AOT- all four engines callcrate::rng::*instead offastrand::*; addsOP_SEED(189) andjit_seedextern-C helperadd seed builtin - set PRNG state, returns nil-Builtin::Seed,from_name/name, verify arity table, VM compiler emissionadd cross-engine rng parity regression tests and example- 8 tests inregression_rng_parity.rs;examples/rng-seed-parity.ilowith pinned outputdoc sync: add seed to SPEC.md, ai.txt, SKILL.md- all four canonical docs updatedTest plan
seed_rnd_same_on_all_engines- pinned to0.7415648787718233on VM and JITseed_rnd_range_same_on_all_engines- 5 seeds, VM == JITseed_rndn_same_on_all_engines- normal draw, VM == JITdefault_seed_is_deterministic_across_runs- two runs, same outputdefault_seed_same_across_engines- no explicit seed, VM == JITseed_returns_nil- seed composes silently in statement positionreseed_replays_sequence- seed 999; seed 42 replays seed 42's sequencemonte_carlo_mean_same_across_engines- 50-draw mean pinned to0.49380530229783287Follow-ups
fastrandcrate is still a dependency (used in other context - audio/sampling in persona tests). Removing it entirely is a separate cleanup.seedis light since AOT linking requires the pre-builtlibilo.awhich is env-dependent in CI.