Monte-Carlo family: McFamily over a seed set, analog to SweepFamily (C12 axis 4) #68

Closed
opened 2026-06-14 23:08:29 +02:00 by Brummel · 3 comments
Owner

C12 axis 4: Monte-Carlo as a sweep over seeds. A Monte-Carlo run is monte_carlo(blueprint, base_point, seeds) → an McFamily analog of SweepFamily — the same disjoint-parallel sweep_with_threads core (aura-engine/src/sweep.rs), but the varying dimension is the seed (C12: MC = sweep over seeds), not a tuning param. Each realization is a disjoint C1 unit; parallelism is across realizations, never within one.

Build

  • A monte_carlo(...) entry returning McFamily: the per-seed RunReports plus an aggregate (mean / median / quantiles of the chosen metric across realizations).
  • Reuse the existing disjoint-parallel executor; do not fork a new run loop.

Depends on

  • Seed-as-input plumbing (the seed must actually perturb the run).
  • Reads readable per-seed params (helped by #57's named point).

Acceptance

N seeds → N disjoint deterministic realizations; the family is reproducible (same seed set → same McFamily); the aggregate is a pure post-run reduction.

Contracts

C12 axis 4, C21 (family orchestration), C1 (each realization bit-identical).

C12 axis 4: Monte-Carlo as a sweep over seeds. A Monte-Carlo run is `monte_carlo(blueprint, base_point, seeds)` → an `McFamily` analog of SweepFamily — the same disjoint-parallel `sweep_with_threads` core (aura-engine/src/sweep.rs), but the varying dimension is the *seed* (C12: MC = sweep over seeds), not a tuning param. Each realization is a disjoint C1 unit; parallelism is across realizations, never within one. ## Build - A `monte_carlo(...)` entry returning `McFamily`: the per-seed RunReports plus an aggregate (mean / median / quantiles of the chosen metric across realizations). - Reuse the existing disjoint-parallel executor; do not fork a new run loop. ## Depends on - Seed-as-input plumbing (the seed must actually perturb the run). - Reads readable per-seed params (helped by #57's named point). ## Acceptance N seeds → N disjoint deterministic realizations; the family is reproducible (same seed set → same McFamily); the aggregate is a pure post-run reduction. ## Contracts C12 axis 4, C21 (family orchestration), C1 (each realization bit-identical).
Brummel added this to the The World, part II — orchestration families milestone 2026-06-14 23:08:29 +02:00
Brummel added the feature label 2026-06-14 23:08:29 +02:00
Author
Owner

Design constraint (World-II eager-agnostic firewall — refs #71)

The MC family API must NOT take or store a materialized per-draw Vec<Stream>. monte_carlo(...) takes seeds: &[u64] + a per-draw closure Fn(u64, &[Scalar]) -> RunReport, and McFamily holds only the per-seed RunReports + the aggregate. Seed->source construction stays a closure-body concern (it builds a Source the way #66 wires it), so a later lazy Harness::run needs no McFamily API break. Reuse sweep_with_threads; do not fork the executor. Depends on #66 + #71.

## Design constraint (World-II eager-agnostic firewall — refs #71) The MC family API must NOT take or store a materialized per-draw `Vec<Stream>`. `monte_carlo(...)` takes `seeds: &[u64]` + a per-draw closure `Fn(u64, &[Scalar]) -> RunReport`, and `McFamily` holds only the per-seed `RunReport`s + the aggregate. Seed->source construction stays a closure-body concern (it builds a `Source` the way #66 wires it), so a later lazy `Harness::run` needs no `McFamily` API break. Reuse `sweep_with_threads`; do not fork the executor. Depends on #66 + #71.
Author
Owner

Design reconciliation (aggregate fork — settled for a future specify)

While scoping #68 in a /boss session, specify bounced at its precondition
gate on one unresolved load-bearing fork: the aggregate semantics. The
comment above pins monte_carlo(seeds, closure) with no metric param, yet calls
the aggregate "mean/median/quantiles of the chosen metric" — the two cannot
both be honoured literally. Three candidates were weighed:

  • V1McAggregate covers all three metrics (total_pips,
    max_drawdown, exposure_sign_flips), each with mean/median/quantiles at a
    fixed set (p5/p25/p50/p75/p95). No metric param → honours the stated signature.
  • V2 — add a metric: &str param, aggregate only the chosen metric (honours
    "chosen metric" but breaks the stated signature; discards the other two).
  • V3McFamily stores only draws; aggregate is a separate
    mc_aggregate(&family, metric) function (cleanest Registry analogy, but
    contradicts the comment's literal "McFamily holds … the aggregate").

Decision: V1. Provenance: user (@Brummel) decided in the in-context design
discussion, 2026-06-15 — verbatim "ja, wir machen v1". Rationale that drove it:
the raw per-seed draws are retained in every variant, so custom statistics
(custom quantiles, histograms, A/B distribution comparison) always read draws
directly — V3 unlocks no capability the draws don't already give. The stored
aggregate field is therefore pure convenience for the common case
(robustness / tail-drawdown), costs nothing, and honours the literal signature.

Implementation deferred to a fresh session (user's choice). Depends on #66
(seed-as-input, landed: commit c9f0e43) + #71 (Source seam, landed). When
resumed: settled design → specify direct-entry, no brainstorm needed.

## Design reconciliation (aggregate fork — settled for a future `specify`) While scoping #68 in a `/boss` session, `specify` bounced at its precondition gate on one unresolved load-bearing fork: the **aggregate semantics**. The comment above pins `monte_carlo(seeds, closure)` with no metric param, yet calls the aggregate "mean/median/quantiles of the **chosen** metric" — the two cannot both be honoured literally. Three candidates were weighed: - **V1** — `McAggregate` covers **all three** metrics (`total_pips`, `max_drawdown`, `exposure_sign_flips`), each with mean/median/quantiles at a fixed set (p5/p25/p50/p75/p95). No metric param → honours the stated signature. - **V2** — add a `metric: &str` param, aggregate only the chosen metric (honours "chosen metric" but breaks the stated signature; discards the other two). - **V3** — `McFamily` stores only `draws`; aggregate is a separate `mc_aggregate(&family, metric)` function (cleanest Registry analogy, but contradicts the comment's literal "McFamily holds … the aggregate"). **Decision: V1.** Provenance: user (@Brummel) decided in the in-context design discussion, 2026-06-15 — verbatim "ja, wir machen v1". Rationale that drove it: the raw per-seed `draws` are retained in every variant, so custom statistics (custom quantiles, histograms, A/B distribution comparison) always read `draws` directly — V3 unlocks no capability the draws don't already give. The stored `aggregate` field is therefore pure convenience for the common case (robustness / tail-drawdown), costs nothing, and honours the literal signature. Implementation deferred to a fresh session (user's choice). Depends on #66 (seed-as-input, landed: commit c9f0e43) + #71 (Source seam, landed). When resumed: settled design → `specify` direct-entry, no `brainstorm` needed.
Author
Owner

Landed in e2c550f (monte_carlo family — McFamily over a seed set, V1 aggregate) and audited drift-clean in cycle 0043 (61a8436). Reuses the disjoint-parallel executor via a shared run_indexed core (behaviour-preserving sweep refactor); eager-agnostic API (seeds + per-draw closure, no materialized stream Vec). Closing.

Landed in e2c550f (monte_carlo family — McFamily over a seed set, V1 aggregate) and audited drift-clean in cycle 0043 (61a8436). Reuses the disjoint-parallel executor via a shared run_indexed<T> core (behaviour-preserving sweep refactor); eager-agnostic API (seeds + per-draw closure, no materialized stream Vec). Closing.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Brummel/Aura#68