Skip to content

Add MeasureZLost and MeasureZLeakedLost herald gates and per-flavor readout matrices to GeneralNoiseModel - #1643

Open
ciaranra wants to merge 7 commits into
devfrom
qubit-loss-1a
Open

ciaranra wants to merge 7 commits into
devfrom
qubit-loss-1a

Conversation

@ciaranra

@ciaranra ciaranra commented Nov 12, 2026 •

Copy link
Copy Markdown
Member

Follows #1642 (the MeasureZ rename, merged). This is the first part of adding qubit loss to GeneralNoiseModel. It adds the measurement gates and readout configuration that loss needs, without any loss state yet.

What changes

An invariance test for GeneralNoiseModel (first commit). crates/pecos-engines/tests/general_noise_invariance.rs drives 17 feature-specific scenarios by hand through start / continue_processing. It compares each simulator round trip's commands, the final outcomes, and the next four u64 from a clone of the model RNG against golden files in tests/fixtures/general_noise_invariance/. It pins today's behaviour, so later loss work can show that runs with loss disabled stay bit-identical. Fixtures are regenerated only with PECOS_UPDATE_GENERAL_NOISE_FIXTURE=1; a missing fixture is a failure.

Two herald gates. GateType::MeasureZLost (wire value 108, outcomes {0, 1, 3}) and GateType::MeasureZLeakedLost (109, {0, 1, 2, 3}), where 2 means leaked and 3 means lost. Like MeasureZLeaked, they are record-less Z measurements; GateType::is_recordless_z_measurement names the three heralds. Sites that classify gates as Z measurements treat them alike: core metadata, simulators and engines, the depolarizing models, circuit display (MLo, MLL), DAG/tick circuits, QEC propagators and fault samplers, QASM, and the experimental crates. Consumers that cannot represent them reject them by name: the runtime-frame and scheduled wire tables, ScheduledBackend, EEG expansion, and the neo conversions. In QEC fault analysis a herald is a collapse with no record: it takes X-only Pauli faults and no measurement-flip mechanism, matching FaultCatalog. Without loss configured, MeasureZLost reads exactly like MZ and MeasureZLeakedLost exactly like MeasureZLeaked.

Per-flavor readout matrices. ReadoutMatrix::new(flavor, rows) and GeneralNoiseModelBuilder::with_readout, JSON measurement.readout, and Python with_readout(gate_name, rows). These configure, for each Z-measurement flavor (MZ, MeasureZLeaked, MeasureZLost, MeasureZLeakedLost; MPZ uses MZ's), the outcome distribution for each true state (0, 1, leaked):

"measurement": {"readout": {"MeasureZLost": {
  "0": {"0": 0.9958, "1": 0.004, "3": 0.0002},
  "1": {"1": 0.9958, "0": 0.004, "3": 0.0002}
}}}
  • A configured row replaces the default for that flavor and true state only, and always makes exactly one categorical draw. Unconfigured rows keep today's p_meas_0 / p_meas_1 behaviour and draws.
  • Configured rows are not scaled. Noiseless gates read nominally with no draw; the noiseless key is each flavor's own gate type (MZ for MZ and MPZ).
  • Matrices apply only to user measurements, never to measurements injected by transition hooks or crosstalk.
  • Validation errors name the flavor, row and bad value, and say how to fix it. A lost row is accepted by the constructor but rejected at build until qubit loss exists.
  • The neo routing path, RuntimeNoise, and the Selene general-noise adapter reject models with configured readout, because those paths do not implement it.

Error text. The unsupported runtime-frame and scheduled gate errors now append the gate name after their existing prefix. Scheduled errors for MeasureZLost and MeasureZLeakedLost suggest MeasureZLeaked (which cannot herald loss) or a non-scheduled engine.

ReadoutMatrix exports. ReadoutMatrix is re-exported from the pecos-engines prelude and pecos::noise.

Docs: a "Readout matrices" section in docs/user-guide/noise-model-builders.md and changelog entries.

Fixes from review

A multi-model review of the first version found pre-existing defects on paths the heralds reach. They are fixed here, each with a regression test:

  • The QEC fault-injection runner now executes gates its preflight already accepted but its dispatch silently skipped: QAlloc, herald collapses, and Clifford-angle rotations (RX/RY/RZ/RXX/RYY/RZZ/U). This fixes wrong FaultChecker results on those circuits.
  • Raw-measurement sampling and LookupDecoder choose custom Pauli weights by gate kind, so p1 weights no longer scale or zero preparation and MZ noise, and heralds and transparent gates get no p1 noise. Batched DAG nodes are split into independent per-qubit or per-pair channels.
  • PerGateTypeNoise::to_neo_channel returns an error for an unmapped gate instead of panicking.
  • GeneralNoiseConfig JSON rejects duplicate object keys at any depth. Readout parse errors name the flavor, row and column, and JSON and Python share one flavor parser. In JSON, an explicit null on an optional parameter means unset; the user guide says which fields reject null.

Not in this PR

Qubit-loss state, the loss config section, recovery and loss spreading, and the semantics of lost rows come in the next part.

Verification

  • just rstest, just python-ci-lint, just python-ci-core, just docs-test, pre-commit, just build-selene and the Selene plugin tests (177 passed) pass locally on the final tree. Rust lanes ran pinned to the machine's E-cores to avoid a known host-local flake in sparse_stab_oracle.
  • The invariance test passes unchanged against fixtures captured before the readout changes.
  • Statistical readout tests in crates/pecos/tests/general_noise_readout_statistics.rs use Jeffreys intervals (alpha 1e-6, n = 20000, fixed seed).
  • New and extended tests were mutation-checked: removing the behaviour each guards makes it fail.
  • The fixture files are platform-sensitive (they pin RNG use and f64 bit patterns); the cross-platform CI run is the check for that.

@ciaranra
ciaranra changed the base branch from measure-z-rename to dev November 12, 2026 17:03
# Conflicts:
#	crates/pecos-core/src/gate_type.rs
#	crates/pecos-core/src/gates.rs
#	crates/pecos-core/src/unitary_rep.rs
#	crates/pecos-engines/src/byte_message/builder.rs
#	crates/pecos-engines/src/noise/biased_depolarizing.rs
#	crates/pecos-engines/src/noise/depolarizing.rs
#	crates/pecos-engines/src/noise/general.rs
#	crates/pecos-engines/src/quantum.rs
#	crates/pecos-engines/src/scheduled_frame.rs
#	crates/pecos-qasm/src/engine.rs
#	crates/pecos-qasm/src/parser/native_gates.rs
#	crates/pecos-qec/src/fault_tolerance/circuit_definitions/tests.rs
#	crates/pecos-qec/src/fault_tolerance/dem_builder/builder.rs
#	crates/pecos-qec/src/fault_tolerance/fault_sampler.rs
#	crates/pecos-qec/src/fault_tolerance/gadget_checker.rs
#	crates/pecos-qec/src/fault_tolerance/influence_builder.rs
#	crates/pecos-qec/src/fault_tolerance/pauli_frame.rs
#	crates/pecos-qec/src/fault_tolerance/pauli_prop_checker.rs
#	crates/pecos-qec/src/fault_tolerance/propagator.rs
#	crates/pecos-qec/src/fault_tolerance/propagator/pauli.rs
#	crates/pecos-qec/tests/fault_catalog_definitions.rs
#	crates/pecos-qec/tests/symbolic_hidden_sources_tests.rs
#	crates/pecos-qis/src/ccengine.rs
#	crates/pecos-quantum/src/circuit_display.rs
#	crates/pecos-quantum/src/dag_circuit.rs
#	crates/pecos-quantum/src/tick_circuit.rs
#	crates/pecos-quantum/src/unitary_matrix.rs
#	crates/pecos-quantum/tests/diagonal_gates.rs
#	crates/pecos-selene-general-noise-adapter/src/simulator.rs
#	docs/releases/changelog.md
#	exp/pecos-eeg/src/coherent_dem.rs
#	exp/pecos-eeg/src/expand.rs
#	exp/pecos-eeg/src/heisenberg.rs
#	exp/pecos-eeg/src/noise_compression.rs
#	exp/pecos-experimental/src/symbolic_executor.rs
#	exp/pecos-experimental/src/symbolic_reference.rs
#	exp/pecos-neo/src/inline_channel.rs
#	exp/pecos-stab-active/src/heisenberg/tests.rs
#	python/pecos-rslib/src/gate_registry_bindings.rs
#	python/quantum-pecos/tests/qec/test_tick_circuit_gate_classification.py
# Conflicts:
#	docs/releases/changelog.md
…led errors, readout errors, and duplicate JSON keys.
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