Skip to content

Improve STN/MAST simulators: locality-ordered projection, prefix-tree sampling, qec-grade defaults, full Python exposure and docs - #523

Draft
ciaranra wants to merge 20 commits into
devfrom
stn-simulator-improvements
Draft

Improve STN/MAST simulators: locality-ordered projection, prefix-tree sampling, qec-grade defaults, full Python exposure and docs#523
ciaranra wants to merge 20 commits into
devfrom
stn-simulator-improvements

Conversation

@ciaranra

@ciaranra ciaranra commented Aug 15, 2026

Copy link
Copy Markdown
Member

Improves the experimental STN/MAST simulators (exp/pecos-stab-tn) with techniques
validated against sibling implementations of the same representation, flips the general
defaults to the qec-grade posture, and closes the Python exposure gaps. Design notes,
cross-review record, and benchmarks live in the design vault; cross-implementation
correctness was verified against an independent oracle (all backends agree to 1e-16 on
identical small circuits).

Simulator improvements

  • MinSpan deferred projection order for Mast (now the default; Input preserves the
    legacy order bit-for-bit including RNG consumption). Ancillas are projected by dynamic
    frame locality, recomputed after every collapse. At the T=2N saturation regime
    (32 data / 64 T), peak projection bond drops 64 -> <=2 and wall time 12.8 s -> 7 ms.
    Verified by 5-sigma sampled-distribution tests against exact STN probabilities at
    n=3..5, T=3..6. Per-projection diagnostics (projection_records) included.
  • Numerical |0> flag re-detection (opt-in numerical_flag_redetection): when the
    symbolic disentangling-flag search misses, product sites are tested numerically at a
    fixed 1e-12 tolerance and the existing verified fast path takes over. Detection only —
    no new absorption algebra. Adversarial-regime fast-path rate improves 1.8% -> 6.2%
    (deep 2q) and 16.4% -> 24.0% with mean bond 1.43 -> 1.23 (T-heavy 3q); research-target
    regimes are unchanged (already optimal). Guarded off while lazy deferred ops are
    pending (stored tensors differ from the effective state by the deferred Clifford).
  • Prefix-sharing perfect sampling (sample_bitstrings): depth-first prefix tree over
    the existing forced-projection sequence; each distinct measurement prefix is projected
    once and shared across all shots taking that branch. At n=20 / 10k shots: 24 s -> 9 ms
    vs the per-shot-clone sampler. Distribution equivalence verified at 5 sigma against
    exact probabilities; original simulator state preserved; the existing sample_bitstring
    is unchanged.
  • Typed execution advice (StabMpsCompile::advise): injection-mode recommendation
    (direct / immediate / deferred) with ancilla-budget feasibility (one fresh ancilla per
    non-Clifford RZ under deferral), exact Angle64 injectable classification (a gate's
    correction is Clifford iff its doubled angle is Clifford, matching the MAST
    correction), and warnings as data. SimulatorKind gains Mast; recommend() is
    unchanged for existing callers.

Defaults

StabMps now defaults to the qec-grade posture: max bond 128, adaptive truncation-error
bound 1e-8, merged same-qubit RZ. MpsConfig::default() is aligned so StabMps, Mast,
direct Mps use, and the sim_neo lane share one default posture. Every legacy behavior is
one explicit call away (max_bond_dim(64), max_truncation_error(0.0) — the documented
disable, verified by a dedicated test — merge_rz(false), ProjectionOrder::Input).
Tests that exercised legacy paths now pin those paths explicitly; no assertion was
weakened.

Python bindings (pecos-rslib-exp)

  • Boolean constructor kwargs are tri-state (None = default, explicit True/False
    actually applies — previously False was silently ignored).
  • New constructor kwargs: svd_cutoff, numerical_flag_redetection; Mast gains
    projection_order ("min_span" | "input") and numerical_flag_redetection.
  • New surfaces: sample_bitstrings, amplitude, amplitude_iterative,
    overlap_with_stabilizer, renyi_s2 / s2_pce / s2_pcmps, disentangle,
    stats(), OFD telemetry (ofd_nullity, theoretical_min_bond_dim, ...),
    bond_cap_hits, apply_bit_flip / apply_phase_flip, Mast projection diagnostics,
    and a new StabMpsCompile class with recommend() / advise().
  • Python smoke tests in python/pecos-rslib-exp/tests/test_exposure.py (require a built
    wheel; exercised in the comparison-harness environment).

API consistency and usability

From an audited ergonomics review of both API surfaces:

  • One bitstring convention everywhere: bits[q] == qubit q for prob_bitstring,
    amplitude, amplitude_iterative, and both samplers (previously the probability and
    amplitude APIs interpreted their argument reversed, so sampled rows fed back into
    prob_bitstring silently produced wrong values). Breaking change to those two APIs,
    documented at crate level and pinned by a sampler-to-probability round-trip
    regression test.
  • Python reads materialize pending state: read methods flush merged RZs and lazy
    deferred operations first, so results are never stale; status reads
    (is_state_exact, pragmatic_drift_count) deliberately do not flush. Rust flush()
    now materializes lazy deferred operations as well as pending RZs.
  • Uniform Python validation: qubit bounds raise IndexError, malformed
    bitstrings / Pauli strings / probabilities raise ValueError across all three
    classes; no Rust panic is reachable from bad Python arguments.
  • Mast capacity visibility: remaining_injections() (Rust and Python) plus
    constructor docs for the capacity workflow; advise() computes the requirement.
  • Docstrings across both surfaces carry conventions, costs, and performance steering
    (per-shot vs prefix-tree sampling, dense vs iterative amplitude), with Python
    quickstart documentation under docs/ wired into the doc-test framework.

Breaking changes

For existing users of the experimental pecos-stab-tn crate and pecos_rslib_exp
bindings (this crate carries no stability promise, but these change observable
behavior and are called out explicitly):

  • prob_bitstring, amplitude, amplitude_iterative: the bitstring argument is now
    bits[q] == qubit q (previously reversed). Asymmetric bitstrings return different
    values than before; the old convention produced silently wrong values when combined
    with sampler output.
  • MpsConfig::default() and StabMpsBuilder defaults: bond cap 64 -> 128, adaptive
    truncation bound off -> 1e-8, merge_rz off -> on. The prior behavior is
    max_bond_dim(64), max_truncation_error(0.0), merge_rz(false).
  • Mast default projection order is now MinSpan; ProjectionOrder::Input restores
    the legacy reverse-injection order.
  • MAST's deferred-correction protocol was corrected per arXiv:2411.12482
    (predetermined gadget outcomes, corrections applied at the injection point, forced
    end-of-circuit projections). Seeded MAST RNG streams differ from prior releases;
    prior MAST results on circuits with basis-changing Cliffords after injections were
    incorrect.
  • amplitude_iterative previously returned 0 for a class of nonzero amplitudes; it is
    now correct, so prior zeros may become nonzero.
  • Seeded reset() now deterministically replays the construction stream (previously
    reseeded from OS entropy); reset() also clears runtime statistics.
  • sim_neo stab_mps() engine defaults follow the new StabMpsBuilder defaults.

Verification

  • Full crate suite (unit + verification + doc tests) and clippy (--all-targets -D warnings) green on every commit; caches forced cold on changed code.
  • Cross-implementation validation: 1,470 comparisons on identical circuits against an
    independent dense oracle — statevector, Pauli expectation, and bitstring probability
    agreement at ~1e-16 for both PECOS configurations.
  • Benchmarks recorded with environment/commit provenance in the comparison harness;
    headline numbers above reproduce on rerun.

@ciaranra

Copy link
Copy Markdown
Member Author

API-naming question for the owner (carried from the predecessor PR): the sampler pair is sample_bitstring (legacy, per-shot clone — kept for per-shot RNG-order reproducibility) and sample_bitstrings (prefix-tree, the documented primary). The ergonomics audit recommended renaming to sample_bitstrings_independent / sample_bitstrings_prefix_tree with deprecated aliases. Rename or keep as is?

Status: draft while the deep-review fix program lands (deferred-correction physics fix per arXiv:2411.12482, amplitude_iterative determinism, reset reproducibility, binding-contract items).

…covery; deterministic seeded reset; pure Mast getters; truncation-bound validation
…on-time corrections, forced projections) and the exact forced-projection phase-gauge, complement, and bitset defects
…ons; flush before disentangle; dense-oracle coverage with a triggering circuit
…, redetection scale relaxation, and the review doc sweep
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