Fail loudly when DEM construction meets a gate Pauli propagation cannot represent - #600
Fail loudly when DEM construction meets a gate Pauli propagation cannot represent#600ciaranra wants to merge 2 commits into
Conversation
Merge-risk check: does this reject anything the repository actually builds?This change makes previously-succeeding DEM construction fail on gates Pauli propagation cannot represent, so the question that matters for merging is whether any real workflow now errors. Answered two ways. The Python surface pipeline: complete gate inventoryRather than run a sample of examples and hope they cover the paths, I enumerated every gate the Python surface generators can emit and checked each against the new classification. Gate-emitting calls in
plus the generic That is the complete vocabulary:
Rust examples
|
Closes #594. Extends #549 with the builder-side half.
Problem
The DEM builders classified bare
T/Tdg-- and rotations with non-Clifford angles -- as ordinary one-qubit noisy fault locations, while the Pauli propagator had no arm for them and silently left the propagated Pauli unchanged. Faults were inserted around a gate that propagation treated as absent, producing a silently wrong detector error model with no error and no warning.This cannot be fixed by teaching the propagator to conjugate
T:Tmaps Pauli operators outside the Pauli group, so no conjugation rule exists. The input has to be rejected.Approach
apply_gate(crates/pecos-qec/src/fault_tolerance/propagator/pauli.rs) becomes the single source of truth, returningPauliPropagationOutcome::{Propagated, Unsupported}.Propagatedcovers gates actually conjugated plus those transparent to Pauli propagation by design;Unsupportedcovers everything the old code silently skipped.The transparent set is not a new hand-written list.
is_supported_prep_gate(PX,PZ,QAlloc) andis_supported_noop_or_metadata_gate(QFree,I,Idle,TrackedPauliMeta, both measurement-crosstalk payloads) were promoted intofault_tolerance/propagator.rs, and the classification,validate_tick_circuit, and the tick propagator all read that one definition. Maintaining several copies of one gate list is what produced #575.Every DEM entry point converts
Unsupportedinto a structured error naming the gate and its location, including the independently supplied exact-replay circuit accepted bywith_exact_branch_replay_context(and exposed to Python), which was previously unguarded. Tick inputs are validated before DAG conversion so the error reportsTick { tick, gate_in_tick }rather than a node index in a derived DAG.Validation of gate payloads happens once per circuit at the entry points; the repeated per-measurement propagation walks use a crate-private non-validating dispatcher that remains bounds-safe.
Scope notes
Two behaviours are documented rather than changed, because altering them belongs in separate PRs:
R1XYretains its existing1e-9-turn snapping tolerance while axis rotations require exact angle matching.InfluenceBuilderaccepts rotations only at exactly zero angle and rejects everyR1XY, includingR1XY(0, phi). This errs conservatively, so it is not silent wrongness; the accepted subset is now stated in its rustdoc.Non-DEM consumers (Pauli-frame path, propagation checker, generic propagation drivers) keep their previous permissive behaviour explicitly.
Verification
cargo test -p pecos-qec-- 991 passed, 0 failedcargo check --workspace --all-targets-- cleancargo clippy -p pecos-qec --all-targets -- -D warnings-- clean, run coldT, both eighth-turnRZsigns, non-CliffordRZ, malformed angle arity, the replay-context path, andQAlloc/QFreecircuits building successfully through every DEM entry point