Repository navigation
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #1643, which is stacked on #1642; review those first. This is the second part of adding qubit loss to
GeneralNoiseModel. It adds loss state, loss sources, recovery and partner spreading, and gives thelostreadout rows from #1643 their meaning.What changes
Loss is separate from leakage. A loss event resets the backend qubit with an injected
PZ, marks the atom lost and clears its leakage mark. An atom is never both lost and leaked. Injected resets and recovery Paulis make no noise draws and do not change the prepared-qubit pool. Shot reset clears loss state but keeps the configuration.Configuration (Rust
QubitLoss::builder()/GeneralNoiseModelBuilder::with_loss/without_loss, JSONlosssection, Pythonwith_loss(dict), which converts the dict strictly to JSON and then uses the same parser):measurement: per operand, after each user measurement; the current readout is unchanged.prep: per operand, after a preparation runs.idle_rate: a rate, drawn asclamp(rate * duration, 0, 1)at each idle site before ordinary idle noise.eventschannels atbefore_/after_single_qubitandbefore_/after_two_qubitsites: an outer probability, then one conditional label such asLI,IL,LLor a Pauli.recoverychannels: a lost atom draws the false-negative rate, a present one the false-positive rate. A detection resets the atom to the maximally mixed state. Withdefault_recovery(on by default), a model with no listed recovery channel gets one before-two-qubit channel at1e-3/1e-3.lost_partner: at a two-qubit gate suppressed by an earlier loss, the surviving atom is lost withloss_probability(default 1), or else gets a Pauli from the optionalpauli_model. So with{"enabled": true}alone, the present atom in such a pair is always lost too. A pair lost by that same command's own before-two-qubit events channel does not spread at that gate.reload_on_prep:PZandMPZrestore a lost atom.Gates on lost atoms.
Customcounts as one operation: a lost operand left after the before-site recovery suppresses the whole command.MeasureZLostandMeasureZLeakedLostreturn 3.MZ,MPZandMeasureZLeakedread a lost atom as 0, then apply the model'sp_meas_0flip (the non-matrix readout path). A configuredlostreadout row replaces that fallback.Hook order. At a before-site: recovery, then the existing non-loss hooks, then loss events. At an after-site: loss entries, then non-loss hooks. Non-loss before-hooks skip groups that are still lost after recovery; after-hooks skip groups that are lost or whose gate was suppressed for loss. All loss state survives simulator round trips.
Scaling and validation.
scalingscales the measurement, prep, idle and event outer probabilities.lost_partnerare not scaled.[0, 1]both before and after scaling. Error messages name the field, the channel index and the bad value. Python errors give the JSON key path.Unsupported paths reject loss:
RuntimeNoise/ runtime frames and the Selene general-noise adapter say to remove thelosssection; neo routing gives its existing beyond-the-simple-subset error, which says to use.stack(SimStack::Engines). Loss is outside the simple probability subset.Docs. A "Qubit loss" section in
docs/user-guide/noise-model-builders.mdgives the semantics. It also has recipes for published loss models with numeric JSON instances:It notes that the chain loss in Coble et al. 2511.16632 cannot be expressed. The changelog has an entry.
Known limitations
MXandMeasureFreeare not tracked by this model and already fail its outcome-count check; loss does not change that.Customoperands one at a time (GeneralNoiseModel applies per-operand single-qubit noise and leakage filtering to multi-qubit Custom gates #1646).Verification
just rstest,just python-ci-lint,just python-ci-core,just docs-testand the docs Rust crate test pass locally. Rust lanes ran pinned to the E-cores (taskset -c 16-31).just rstestwere run after it.crates/pecos-engines/tests/general_noise_loss.rs);crates/pecos/tests/general_noise_loss_statistics.rs);python/pecos-rslib/tests/test_general_noise_loss.py);crates/pecos-engines/src/noise/general/loss.rs, including a check that the seven published-model numeric instances build without adding default recovery;t20_qubit_loss_is_rejected) and neo routing (t20_neo_stack_rejects_qubit_loss).