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.
Closes #893. Closes #888.
#893 — two-qubit noise silently discarded, or a crash
GenericErrorModel.processmerged memory noise into gate noise withlist.extend()mutates in place and returnsNone, so this had three failure modes withp2_memconfigured:qops_afterbecameNone, the laterif qops_after:was false, and all two-qubit noise for that gate was silently droppedqops_after.extend(None)raisedTypeError: 'NoneType' object is not iterableif qops_after:The same line existed in
DepolarizingErrorModel(depolarizing_error_model.py:191). A repo-wide sweep for= <list>.extend(...)-style assignments found exactly those two; both are fixed.#888 — the gate was never suppressed on a leaked qubit
noise_tq_depolarizing_leakagefiltered leaked pairs into a local rebinding and returned only noise, so the caller emitted the original unfiltered gate. Its own comment says "Don't apply a gate if an input qubit has already leaked", which did not happen. The single-qubit helper does honour it, by returning the filtered gate inside its result.The caller now owns suppression, and the helper's internal filter is deleted. Copying the single-qubit pattern would not work: with
p2_memthe two-qubit path calls the helper twice, so a gate-returning helper would emit the gate twice.A pure
surviving_two_qubit_op(op, machine)— no sampling, no mutation — returns the op restricted to pairs where neither qubit has already leaked, orNone.processcalls it twice, because the gate's own noise can leak a qubit through an"L"fault and so change the machine state mid-operation:RNG behaviour is unchanged. Each helper call receives exactly the pairs its old internal filter would have retained at that moment, so draw counts match per call; a zero-pair call is skipped and consumes nothing. Verified by 800 seeded comparisons against the original helper on noise operations, leakage state and subsequent RNG output, plus a test using a
("L", "I")fault model, the case that makes the two filters differ.Also removed:
qops_before, initialised every iteration and never assigned anywhere, along with its emission branch.Tests
tests/pecos/unit/test_two_qubit_noise.pynow covers the caller, which had no direct tests despite producing four defects (#816, #888, #893, #897):Mutation-checked, by me as well as the implementer: restoring the
extendassignment fails 8 tests; emitting the unfiltered op instead of the survivor fails 21; moving the single-qubit call into the append-after slot fails the slot test.Reported, not fixed
#897: the gate is emitted only on the
erroneous_ops is Nonebranch, so a helper returning[]rather thanNonemakes the gate vanish. Unreachable with the shippedGenericMachine, whoseleak()always returns anInitop, but reachable for a custom machine implementing the protocol.Verification
just python-ci-build-test,just pytest-ci-core-shard rest(6786 passed, 50 skipped, the pre-existing #889 xfail),just python-ci-lint. Branch is level withdev.How this was produced
Implemented by OpenAI
gpt-6-astra(Codex CLI 0.154.0) from a task packet written by Claude Fable 5.1 in Claude Code. The arm stopped once rather than implement my design: I had specified filtering once up front, and it showed that gate noise can leak a qubit between the two helper calls, so one filter cannot preserve either the old eligibility or the RNG stream. That stop produced the filter-twice design here. It also found the secondextendinstance. Claude reviewed every hunk, tightened two readability points directly (a comment explaining why a clean gate travels in theerroneous_opsslot, and computing the memory filter only whenp2_memis set), re-ran the named lanes, and repeated two mutation checks independently. Posted at the maintainer's request.