random: std/random (RANDOM slice 1) #3

Closed
opened 2026-10-05 21:06:59 +00:00 by orion · 8 comments
Collaborator

Context

A seedable, splittable generator that is a value. Section 2 leaves the algorithm and the distributions open.

Source

Acceptance criteria

  • Algorithm and distributions decided in RANDOM.md section 2
  • The generator, seeding, splitting, uniform integers and floats, shuffling
  • Seeds from Entropy

Dependencies

None known.

Moved from the planning lists of the docs; the design record stays the specification.

## Context A seedable, splittable generator that is a value. Section 2 leaves the algorithm and the distributions open. ## Source - [RANDOM.md slice 1](https://git.torb.dev/torbscript/language/src/commit/393ef2608e4a60b8ff76d8b6b408951b822d887d/docs/design/RANDOM.md#L35) ## Acceptance criteria - [ ] Algorithm and distributions decided in RANDOM.md section 2 - [ ] The generator, seeding, splitting, uniform integers and floats, shuffling - [ ] Seeds from `Entropy` ## Dependencies None known. _Moved from the planning lists of the docs; the design record stays the specification._
Author
Collaborator

[loop:torbscript] intake: in scope (author orion, label loop). Implements RANDOM.md slice 1. Owner question likely: the first criterion leaves algorithm and distributions open (RANDOM.md section 2), a library design choice; to be filed as owner decision in refine. Release freeze for 0.1.0 (2026-10-06) holds new PRs, next: refine (queued, buffer >= 2 ready)

[loop:torbscript] intake: in scope (author orion, label loop). Implements RANDOM.md slice 1. Owner question likely: the first criterion leaves algorithm and distributions open (RANDOM.md section 2), a library design choice; to be filed as owner decision in refine. Release freeze for 0.1.0 (2026-10-06) holds new PRs, next: refine (queued, buffer >= 2 ready)
Author
Collaborator

[loop:torbscript] claim refine by session:loop-torbscript-20261007 until 2026-10-07T17:35:00Z

[loop:torbscript] claim refine by session:loop-torbscript-20261007 until 2026-10-07T17:35:00Z
Author
Collaborator

[loop:torbscript] owner decision: algorithm and distributions of std/random (RANDOM.md section 2)

What. RANDOM.md section 1 fixes the shape (a seedable, splittable value; drawing takes a var binding; Random.seeded 42 repeats on every machine and in both back ends; the seed comes in as a value, never from std/os). Section 2 leaves two library design choices open, and slice 1 cannot be built before they are answered:

  1. The algorithm, and whether it is a public promise.
  2. Which distributions ship in slice 1 and which wait for std/statistics.

Facts that bound the options. UInt64 has addedWrapping/multipliedWrapping and Bits (std/number), so a 64-bit generator is pure TorbScript: no new native, no seed change, no capability. There is no 64x64 -> 128-bit multiply, which a 64-bit Philox or the 128-bit-state PCG variants would need. std/identifier (URI.md slice 6, Uuid.version4/7(var source: Random, ...)) is blocked on the surface chosen here.

Question 1: algorithm

  • A. SplitMix64 core (the generator behind Java's SplittableRandom): 64-bit state plus an odd gamma, split() derives a new (state, gamma). Pure UInt64 wrapping arithmetic, trivially identical in the VM and native code, fast. Passes BigCrush as a stream; the splitting is the weaker part (independence of splits is empirical, not proved).
  • B. Counter-based, Threefry-2x32/4x32 or Philox-4x32 (JAX's family): a key plus a counter, split() is a hash of the key. The strongest story for "same numbers whichever part runs first" and reproducible training, but the rounds are heavier to write without a wide multiply, and slower in the VM.
  • C. PCG64-style (small permuted congruential): good stream quality, but a 128-bit state needs emulated wide arithmetic, and PCG has no principled split (only distinct streams).
  • Sub-choice, independent of A/B/C: a public promise or not. Stable: the algorithm and the mapping from bits to integers and floats are documented and frozen, so recorded numbers survive toolchain versions (needed for golden-file tests and reproducible training; every change is then a breaking change). Unstable: "same seed, same numbers within one toolchain version" only, free to improve later.

Question 2: distributions in slice 1

  • Minimal (RANDOM.md slice 1 as written): uniform integers in a range (unbiased, by rejection, not modulo), floats in [0, 1) (53 bits), shuffled/shuffle (Fisher-Yates), plus split. Sampling a list, normal, and the rest wait.
  • Extended: the above plus sample/choice of a list and a boolean/chance. Normal and the other continuous distributions stay with std/statistics either way (they need ln/sqrt and carry accuracy promises that belong to that package).

Recommendation.

  • Algorithm: A (SplitMix64), declared stable. It needs no new native or seed change, is the smallest thing that is exactly reproducible in both back ends, and splitting is its documented purpose. Freeze the bit-to-value mappings with the algorithm and cover them with known-answer tests (published SplitMix64 vectors). B stays open as a later Random implementation behind the same surface if training needs provable independence.
  • Distributions: Minimal plus sample/choice; normal and anything numerical wait for std/statistics.

Consequences. Choosing A + stable: slice 1 is one PR in std/random (no compiler/src, runtime/ or seed change), tests include known-answer vectors, and a later algorithm swap is a breaking change that needs its own decision. Choosing unstable instead: same PR, weaker tests, no promise in the docs. Choosing B or C: larger PR, the wide-arithmetic or rounds code is the bulk of it, and slower VM runs; may need splitting into core and surface. Until answered, the issue stays without ready and the loop does not implement it.

[loop:torbscript] owner decision: algorithm and distributions of `std/random` (RANDOM.md section 2) **What.** RANDOM.md section 1 fixes the shape (a seedable, splittable value; drawing takes a `var` binding; `Random.seeded 42` repeats on every machine and in both back ends; the seed comes in as a value, never from `std/os`). Section 2 leaves two library design choices open, and slice 1 cannot be built before they are answered: 1. **The algorithm, and whether it is a public promise.** 2. **Which distributions ship in slice 1** and which wait for `std/statistics`. **Facts that bound the options.** `UInt64` has `addedWrapping`/`multipliedWrapping` and `Bits` (`std/number`), so a 64-bit generator is pure TorbScript: no new native, no seed change, no capability. There is no 64x64 -> 128-bit multiply, which a 64-bit Philox or the 128-bit-state PCG variants would need. `std/identifier` (URI.md slice 6, `Uuid.version4/7(var source: Random, ...)`) is blocked on the surface chosen here. **Question 1: algorithm** - **A. SplitMix64 core** (the generator behind Java's `SplittableRandom`): 64-bit state plus an odd gamma, `split()` derives a new (state, gamma). Pure `UInt64` wrapping arithmetic, trivially identical in the VM and native code, fast. Passes BigCrush as a stream; the splitting is the weaker part (independence of splits is empirical, not proved). - **B. Counter-based, Threefry-2x32/4x32 or Philox-4x32** (JAX's family): a key plus a counter, `split()` is a hash of the key. The strongest story for "same numbers whichever part runs first" and reproducible training, but the rounds are heavier to write without a wide multiply, and slower in the VM. - **C. PCG64-style** (small permuted congruential): good stream quality, but a 128-bit state needs emulated wide arithmetic, and PCG has no principled split (only distinct streams). - **Sub-choice, independent of A/B/C: a public promise or not.** *Stable*: the algorithm and the mapping from bits to integers and floats are documented and frozen, so recorded numbers survive toolchain versions (needed for golden-file tests and reproducible training; every change is then a breaking change). *Unstable*: "same seed, same numbers within one toolchain version" only, free to improve later. **Question 2: distributions in slice 1** - **Minimal (RANDOM.md slice 1 as written):** uniform integers in a range (unbiased, by rejection, not modulo), floats in `[0, 1)` (53 bits), `shuffled`/`shuffle` (Fisher-Yates), plus `split`. Sampling a list, normal, and the rest wait. - **Extended:** the above plus `sample`/`choice` of a list and a boolean/`chance`. Normal and the other continuous distributions stay with `std/statistics` either way (they need `ln`/`sqrt` and carry accuracy promises that belong to that package). **Recommendation.** - Algorithm: **A (SplitMix64), declared stable.** It needs no new native or seed change, is the smallest thing that is exactly reproducible in both back ends, and splitting is its documented purpose. Freeze the bit-to-value mappings with the algorithm and cover them with known-answer tests (published SplitMix64 vectors). B stays open as a later `Random` implementation behind the same surface if training needs provable independence. - Distributions: **Minimal plus `sample`/`choice`**; normal and anything numerical wait for `std/statistics`. **Consequences.** Choosing A + stable: slice 1 is one PR in `std/random` (no `compiler/src`, `runtime/` or seed change), tests include known-answer vectors, and a later algorithm swap is a breaking change that needs its own decision. Choosing unstable instead: same PR, weaker tests, no promise in the docs. Choosing B or C: larger PR, the wide-arithmetic or rounds code is the bulk of it, and slower VM runs; may need splitting into core and surface. Until answered, the issue stays without `ready` and the loop does not implement it.
Author
Collaborator

[loop:torbscript] refine: checked against RANDOM.md (sections 1-4), ROADMAP (std/random row), URI.md (std/identifier depends on it), COMPUTE.md. The record settles the shape (seedable, splittable value, var draws, seed as a value, no std/os import) but not the algorithm, its stability promise or the distribution set (section 2), so the first acceptance criterion is a language/library design choice: owner decision filed above (recommendation: SplitMix64, declared stable; uniform ints, floats in [0, 1), shuffle, sample). Seed impact: none expected for A or the minimal set (pure UInt64 wrapping arithmetic, no new native, no compiler-looked-up std name). Size: one PR for the recommended option. ready not set, next: waiting (owner decision)

[loop:torbscript] refine: checked against RANDOM.md (sections 1-4), ROADMAP (`std/random` row), URI.md (`std/identifier` depends on it), COMPUTE.md. The record settles the shape (seedable, splittable value, `var` draws, seed as a value, no `std/os` import) but not the algorithm, its stability promise or the distribution set (section 2), so the first acceptance criterion is a language/library design choice: owner decision filed above (recommendation: SplitMix64, declared stable; uniform ints, floats in `[0, 1)`, shuffle, sample). Seed impact: none expected for A or the minimal set (pure `UInt64` wrapping arithmetic, no new native, no compiler-looked-up std name). Size: one PR for the recommended option. `ready` not set, next: waiting (owner decision)
Author
Collaborator

[loop:torbscript] owner decision answered (Torben, 2026-10-07): the recommendation is accepted. Algorithm: SplitMix64, declared stable (algorithm and bit-to-value mappings documented and frozen, covered by known-answer tests with the published SplitMix64 vectors). Distributions in slice 1: uniform integers in a range (rejection, not modulo), floats in [0, 1) (53 bits), shuffled/shuffle, sample/choice, plus split; normal and other continuous distributions wait for std/statistics. RANDOM.md section 2 is to be updated with this decision in the implementing PR. next: implement

[loop:torbscript] owner decision answered (Torben, 2026-10-07): the recommendation is accepted. Algorithm: SplitMix64, declared stable (algorithm and bit-to-value mappings documented and frozen, covered by known-answer tests with the published SplitMix64 vectors). Distributions in slice 1: uniform integers in a range (rejection, not modulo), floats in `[0, 1)` (53 bits), `shuffled`/`shuffle`, `sample`/`choice`, plus `split`; normal and other continuous distributions wait for `std/statistics`. RANDOM.md section 2 is to be updated with this decision in the implementing PR. next: implement
Author
Collaborator

[loop:torbscript] claim implement by session:loop-torbscript-20261007 until 2026-10-07T21:45:51Z

[loop:torbscript] claim implement by session:loop-torbscript-20261007 until 2026-10-07T21:45:51Z
Author
Collaborator

[loop:torbscript] implement: std/random built (Random: SplitMix64 seeding, uint64/float/int(range), split, shuffled/shuffle, choice, sample; 24 VM tests incl. the published vectors; RANDOM.md section 2, docs page, roadmap, URI.md, index and skills updated), PR https://git.torb.dev/torbscript/language/pull/159, next: waiting (forge CI still running: gates, tier A/B; no C compiler on the build box, so only VM-side check/test/format/lint/docs gates ran locally; commit-messages and pdisc are green). Tokens: not readable from inside the subagent run.

[loop:torbscript] implement: `std/random` built (Random: SplitMix64 seeding, uint64/float/int(range), split, shuffled/shuffle, choice, sample; 24 VM tests incl. the published vectors; RANDOM.md section 2, docs page, roadmap, URI.md, index and skills updated), PR https://git.torb.dev/torbscript/language/pull/159, next: waiting (forge CI still running: gates, tier A/B; no C compiler on the build box, so only VM-side check/test/format/lint/docs gates ran locally; commit-messages and pdisc are green). Tokens: not readable from inside the subagent run.
argus closed this issue 2026-10-07 18:25:25 +00:00
Author
Collaborator

[loop:torbscript] close: #3 landed as 9e2ab91 (PR 159), the issue is closed. Main CI on that commit is not green yet: the pdisc / pdisc (push) job failed after 2m33s (earlier runs take about 25s), the other ci jobs are still pending. python3 tools/pdisc/scripts/pdisc.py check passes on an exact checkout of 9e2ab91 ("ok 11 docs"), so this looks like a runner or package-install failure, not a docs problem. The job log is not readable through the API and a rerun is not available to the loop, next: waiting (main CI pending; pdisc job needs a rerun by the merge gate or owner)

[loop:torbscript] close: #3 landed as 9e2ab91 (PR 159), the issue is closed. Main CI on that commit is not green yet: the `pdisc / pdisc (push)` job failed after 2m33s (earlier runs take about 25s), the other `ci` jobs are still pending. `python3 tools/pdisc/scripts/pdisc.py check` passes on an exact checkout of 9e2ab91 ("ok 11 docs"), so this looks like a runner or package-install failure, not a docs problem. The job log is not readable through the API and a rerun is not available to the loop, next: waiting (main CI pending; pdisc job needs a rerun by the merge gate or owner)
Sign in to join this conversation.
No labels
loop
ready
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
torbscript/language#3
No description provided.