feat(prng): order-independent derived streams and distribution helpers - #38
Open
cmaycumber wants to merge 1 commit into
Open
cmaycumber wants to merge 1 commit into
cmaycumber wants to merge 1 commit into
Conversation
`fork(label)` consumes a draw from the parent, so a child stream depends on how many values were drawn before it. That is right for per-entity streams created in a fixed order, and it is left exactly as it was. Procedural generation needs the opposite: adding a draw to one step (placing a new kind of landmark, say) must not reshuffle every other step. - `derive(label)`: a child that is a pure function of this stream's seed identity and the label. It never advances the parent and ignores prior draws, and nested labels compose. The identity is carried in exportState/restoreState; states exported before this change (no `origin` field) still restore. - Helpers used constantly by procedural code: `range(min, max)`, `pick(items)`, `weighted(items, weights)`, `gaussian(mean, stdDev)`, `shuffle(items)` and `fn()` for libraries that take a random function, such as noise generators. - `gaussian` sums twelve uniforms rather than using Box-Muller, whose Math.log and Math.cos are not bit-identical across JavaScript engines; a world generated with it could differ between two browsers in a lockstep session. Bounded to six standard deviations. - Diagnostics RND_0501 to RND_0504 for empty picks and invalid weights. - The base PCG32 sequence and `fork` are byte-identical to before. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This branch has not been deployed
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.
fork(label)consumes a draw from the parent, so a child stream depends on how many values were drawn before it. That's right for per-entity streams created in a fixed order, andforkis unchanged. Procedural generation needs the opposite: adding a draw to one generation step must not reshuffle every other step.derive(label): a child that is a pure function of the stream's seed identity and the label. It never advances the parent, and nested labels compose. The identity is carried inexportState/restoreState, and older states without it still restore.range,pick,weighted,gaussian,shuffle, andfn()for libraries that take a random function (noise generators).gaussiansums twelve uniforms (Irwin–Hall) instead of Box–Muller.Math.log/Math.cosare not bit-identical across JS engines, which would break lockstep determinism. The result is bounded to ±6σ.forkare byte-identical to before.Verification: typecheck, build, 242/242 tests.
🤖 Generated with Claude Code