Splitting remove_identity() into a unitary-optimization pass and an idle-stripping pass. They are different concerns with different consequences, and the DEM currently uses the combined one to mean only the second.
What it removes today
is_identity_gate (crates/pecos-quantum/src/pass.rs:299):
match gate.gate_type {
GateType::I | GateType::Idle => true,
gt if is_rotation(gt) => gate.angles.len() == 1 && gate.angles[0].is_zero(),
_ => false,
}
So it strips I, Idle, and zero-angle RX/RY/RZ/RXX/RYY/RZZ/CRZ — everything that is identity by effect.
Why conflating them matters
These are not the same kind of thing:
| removed |
what it is |
consequence |
Idle |
a duration-carrying scheduling marker that drives idle noise |
removing it removes idle noise — the intended effect |
I, zero-angle rotations |
no-op unitaries |
removing them removes their gate noise — an unintended side effect |
RZ is a p1 fault site in the DEM builder (crates/pecos-qec/src/fault_tolerance/dem_builder/mem_builder.rs:130), so a zero-angle RZ still carries single-qubit gate noise. Deleting it deletes that fault mechanism.
The DEM builder calls remove_identity() to implement strip_traced_idles, whose documented purpose is only to avoid double-counting idle noise (python/quantum-pecos/src/pecos/qec/dem.py:311). So a noise-modelling decision is silently also performing a gate-noise-removing optimization.
Frequency: latent, not currently biting
Measured on traced circuits:
| program |
gates |
remove_identity dropped |
| plain Clifford (H, CX, measure) |
11 |
0 |
| repetition-code memory |
30 |
0 |
explicit rz(angle(0.0)) |
12 |
1 |
Lowering does not manufacture zero-angle rotations — traced circuits contain RZ, R1XY, RZZ with nonzero angles. A zero-angle rotation appears only if the program contains one.
That makes this latent today, but reachable: a parameterised program whose angle evaluates to zero for some setting is an ordinary thing to write, and a sweep is exactly where a silently-missing fault site would be hardest to notice.
Proposal
Split the pass:
remove_identity() — unitary identity gates only (I, zero-angle rotations). A genuine optimization, semantically neutral in an ideal circuit; callers opting into it accept losing those gates' noise sites.
strip_idles() — Idle gates only. A noise-modelling decision.
Then have the DEM builder's strip_traced_idles call strip_idles(), which is what it actually means.
Acceptance
- A traced circuit containing a zero-angle rotation keeps its
p1 fault mechanism after strip_idles(), and loses it after remove_identity().
strip_traced_idles=True no longer changes the emitted DEM for a circuit whose only identity-like gates are zero-angle rotations.
- Existing behaviour for circuits with no zero-angle rotations is byte-identical — which per the table above is every traced circuit measured so far.
Found while documenting the workflow example in PR #420. Not fixed there: it changes a pass's semantics and would move DEM numbers for affected circuits, and that PR already carries three number-moving changes.
Splitting
remove_identity()into a unitary-optimization pass and an idle-stripping pass. They are different concerns with different consequences, and the DEM currently uses the combined one to mean only the second.What it removes today
is_identity_gate(crates/pecos-quantum/src/pass.rs:299):So it strips
I,Idle, and zero-angleRX/RY/RZ/RXX/RYY/RZZ/CRZ— everything that is identity by effect.Why conflating them matters
These are not the same kind of thing:
IdleI, zero-angle rotationsRZis ap1fault site in the DEM builder (crates/pecos-qec/src/fault_tolerance/dem_builder/mem_builder.rs:130), so a zero-angleRZstill carries single-qubit gate noise. Deleting it deletes that fault mechanism.The DEM builder calls
remove_identity()to implementstrip_traced_idles, whose documented purpose is only to avoid double-counting idle noise (python/quantum-pecos/src/pecos/qec/dem.py:311). So a noise-modelling decision is silently also performing a gate-noise-removing optimization.Frequency: latent, not currently biting
Measured on traced circuits:
remove_identitydroppedrz(angle(0.0))Lowering does not manufacture zero-angle rotations — traced circuits contain
RZ,R1XY,RZZwith nonzero angles. A zero-angle rotation appears only if the program contains one.That makes this latent today, but reachable: a parameterised program whose angle evaluates to zero for some setting is an ordinary thing to write, and a sweep is exactly where a silently-missing fault site would be hardest to notice.
Proposal
Split the pass:
remove_identity()— unitary identity gates only (I, zero-angle rotations). A genuine optimization, semantically neutral in an ideal circuit; callers opting into it accept losing those gates' noise sites.strip_idles()—Idlegates only. A noise-modelling decision.Then have the DEM builder's
strip_traced_idlescallstrip_idles(), which is what it actually means.Acceptance
p1fault mechanism afterstrip_idles(), and loses it afterremove_identity().strip_traced_idles=Trueno longer changes the emitted DEM for a circuit whose only identity-like gates are zero-angle rotations.Found while documenting the workflow example in PR #420. Not fixed there: it changes a pass's semantics and would move DEM numbers for affected circuits, and that PR already carries three number-moving changes.