Skip to content

Phase 2: typed decoder-spec factories and SampleBatch.decode() with DecodeResult - #530

Open
ciaranra wants to merge 3 commits into
devfrom
unified-decode-p2a
Open

Phase 2: typed decoder-spec factories and SampleBatch.decode() with DecodeResult#530
ciaranra wants to merge 3 commits into
devfrom
unified-decode-p2a

Conversation

@ciaranra

@ciaranra ciaranra commented Aug 16, 2026

Copy link
Copy Markdown
Member

Summary

Phase 2 of the unified batch-decode API, stacked on #527 (merge that first). Two commits: the Python spec-factory layer, then the scoring entry point.

Commit 1 — typed decoder-spec factories

  • DecoderSpec as a frozen Python value object: parse(), history_dependent / wall_clock_dependent, equality, informative repr.
  • One keyword-only factory per decoder family in pecos.decoders with eager validation; pymatching(correlated=...) is required with no default (either default silently flips one of the two existing user cohorts). Composites take DecoderSpec objects, not string DSL.

Commit 2 — SampleBatch.decode() and DecodeResult

  • One scoring entry point: batch.decode(dem=None, decoder=spec_or_legacy_string, *, workers=None, predictions=False, timing=False, allow_dem_mismatch=False).
  • Deterministic execution planning as a pure function (pecos_decoders::batch::plan_execution): explicit workers>1 errors for history-dependent decoders and records a reproducibility warning for wall-clock-bounded ones; auto selection never parallelizes either, uses PyMatching's native vectorized path when eligible, and falls back sequential below a documented small-batch threshold.
  • The native observable-batch primitive is now wide (Vec<ObsMask>): PyMatching's 64-observable rejection is gone, bit-packing crosses the limb boundary correctly, and every workspace caller was migrated. Narrowing wrappers were audited: each family either produces wide masks or fails loudly at construction (guards verified per family; the windowed family gained one shared guard at its common constructor).
  • DecodeResult: counts, empirical LER, Jeffreys interval() with prevalidated domain (alpha in [1e-6, 0.5], shots in (0, 1e8]), execution_path, workers_used, reproducibility_warnings, sampling_seed_used (always None here; the fused sampler phase populates it), optional per-shot predictions (arbitrary-precision) and timing stats (wall_elapsed / summed_decode_elapsed, named for what Instant measures).
  • GIL released around construction and decoding; generic workers decode straight from the bit-packed columns with one reusable buffer each; the native path transposes in bounded sub-batches. Parallel failures deterministically report the lowest failing shot index.
  • Legacy decode methods are untouched; their removal is the migration phase.

Verification

  • cargo clippy --locked --workspace --all-targets --all-features -- -D warnings (the CI lane), plus per-crate test suites for pecos-decoders (both feature configurations), pecos-decoder-core, pecos-pymatching; cargo fmt --check; just lint.
  • Python: rslib tree 2165 passed on an mwpf-enabled build (the wall-clock-warning test runs rather than skips); qec regression suite 1620 passed.
  • Independent adversarial full-diff reviews ran on both commits; all findings fixed and re-verified, including a workspace-build breaker in a feature-gated test, a hidden dense-matrix allocation in the dimension preflight, and initially vacuous equivalence fixtures (now decorrelated with nonzero error counts).

@ciaranra ciaranra changed the title Expose typed decoder-spec factories to Python Phase 2: typed decoder-spec factories and SampleBatch.decode() with DecodeResult Aug 16, 2026
Base automatically changed from unified-decode-p1 to dev August 16, 2026 19:02
@ciaranra
ciaranra force-pushed the unified-decode-p2a branch from e546401 to d2d811d Compare August 16, 2026 19:03
@ciaranra ciaranra self-assigned this Aug 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant