Add amplitude damping noise model #544
Conversation
|
@pranav97nair Happy to get your feedback on this |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #544 +/- ##
==========================================
+ Coverage 88.85% 88.95% +0.09%
==========================================
Files 49 50 +1
Lines 7135 7207 +72
==========================================
+ Hits 6340 6411 +71
- Misses 795 796 +1 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
Hi @CodeMaverick2 , thanks for your contribution. As you may have noticed, several other pull requests already address the same issue. Your work is in particular quite similar to #540 . Could you clarify how your contribution differs from, or improves upon, the previous works? In particular, please explain why you consider your approach to be better. |
|
Hi @pranav97nair, thanks for the review - fair question given the number of open PRs on this issue. You're right that the core implementation (Kraus channels + AmplitudeDampingNoiseModel mirroring DepolarisingNoiseModel) is structively similar across submissions, including #540. Where I think this PR adds value is mainly in test completeness and merge readiness, based on your earlier feedback on the other PRs. Compared to #540 specifically: Analytic per-step tests on the reference patterns - Following your request on #540, this PR compares simulated density matrices against hand-derived expectations for the Hadamard pattern at each isolated noise stage (prep, entanglement, measure channel, X correction), parametrized over γ ∈ {0, 0.3, 0.7, 1.0} and both measurement outcomes. The measure step also cross-checks the closed form diag((1±√(1−γ))/2). For RZ, X/Z correction and measure-confuse tests follow the same structure as the existing depolarising suite in test_noisy_density_matrix.py. API consistency with DepolarisingNoiseModel - Parameter names (prepare_error_prob, x_error_prob, etc.) and command-injection logic match the existing depolarising model exactly, so users can swap noise models without changing call sites. AmplitudeDampingNoise.gamma is used only on the Noise objects themselves, consistent with how DepolarisingNoise.prob works. CI / tooling - Ruff, mypy, pyright, and the targeted pytest suite pass locally. The one macOS 3.12 failure on the first run was a transient PyPI/network error during uv pip install scipy, not a test failure; other 3.12 jobs passed. I'm happy to re-run or address anything else that shows up. Coverage - After the Codecov note on the first commit, I added tests for input_nodes, to_kraus_channel, and the no-flip branch of confuse_result. Patch coverage is now ~99%; What I did not try to do: reinvent the physics or the noise-model architecture - the Kraus operators and model structure are standard and aligned with the issue spec. The focus here was delivering what you flagged as the harder part: tests whose correctness is explainable, in the same style as the depolarising Hadamard/RZ tests. If there are specific gaps you still see relative to #540 (e.g. a ComposeNoiseModel integration test or a direct DensityMatrix.apply_channel check), I'm happy to add them - just point me at what you'd prefer merged. Thanks again for taking the time to review. |
There was a problem hiding this comment.
Hi @CodeMaverick2 , thanks for your response. I have submitted some small comments I would like you to address below.
The principal changes I would like to see however are in tests/test_noisy_density_matrix.py. Please see my latest review of this module in PR 540 here and implement the changes that apply to your code.
Let us know if you have any questions.
| if not 0 <= gamma <= 1: | ||
| raise ValueError("gamma must be between 0 and 1.") | ||
| sqrt_gamma = np.sqrt(gamma) | ||
| sqrt_one_minus_gamma = np.sqrt(1 - gamma) |
There was a problem hiding this comment.
This if statement is not required as a value outside this range would mean that the corresponding Kraus channel is un-normalized, and this will raise a ValueError when instantiating a KrausChannel object. See the check starting in line 127 of this module.
Also, these sqrt.. variables are not required. You may put the np.sqrt calls directly in the return statement.
| if not 0 <= gamma <= 1: | ||
| raise ValueError("gamma must be between 0 and 1.") | ||
| sqrt_gamma = np.sqrt(gamma) | ||
| sqrt_one_minus_gamma = np.sqrt(1 - gamma) | ||
| k1 = np.array([[1, 0], [0, sqrt_one_minus_gamma]], dtype=np.complex128) | ||
| k2 = np.array([[0, sqrt_gamma], [0, 0]], dtype=np.complex128) |
| def test_amplitude_damping_channel_invalid_gamma(self, gamma: float) -> None: | ||
| with pytest.raises(ValueError, match="gamma must be between 0 and 1"): | ||
| amplitude_damping_channel(gamma) | ||
| with pytest.raises(ValueError, match="gamma must be between 0 and 1"): | ||
| two_qubit_amplitude_damping_channel(gamma) |
There was a problem hiding this comment.
In line with my comment in channels.py, you can check that this raises a ValueError from the KrausChannel constructor method with the text "The specified channel is not normalized". Please update this accordingly.
|
@pranav97nair Thanks for the review. I've removed the redundant gamma validation in channels.py (normalization is enforced by KrausChannel), updated the invalid-gamma test accordingly, and refactored test_noisy_density_matrix.py to use Graphix primitives with renamed helpers, random gamma sampling, _expected_hadamard_pattern, and new _expected_rz_pattern with per-step RZ analytic tests. Let me know if anything else needs adjusting. |
|
@pranav97nair Happy to get feedback on this everything has been addressed |
|
Hi @CodeMaverick2 , thanks a lot for your updates and engaging with our feedback on this PR. We have however decided to accept PR #540 for the amplitude damping issue; I will therefore close out this PR. Thanks again for your interest in Graphix during this UnitaryHack, and we hope you will contribute again! |
Summary
Implements amplitude damping noise for the density-matrix backend (closes #497): Kraus channels, noise classes,
AmplitudeDampingNoiseModel, and analytic per-step tests on Hadamard and RZ patterns.Changes
graphix/channels.py-amplitude_damping_channel()andtwo_qubit_amplitude_damping_channel()(tensor product of independent single-qubit channels)graphix/noise_models/amplitude_damping.py-AmplitudeDampingNoise,TwoQubitAmplitudeDampingNoise,AmplitudeDampingNoiseModel(mirrorsDepolarisingNoiseModelAPI:prepare_error_prob,x_error_prob, etc.)graphix/noise_models/__init__.pyandgraphix/__init__.pytest_kraus.py,test_noise_model.py,test_noisy_density_matrix.pyTest soundness
Hadamard pattern - For each noise stage in isolation (prep, entanglement, measure channel, X correction), we compare simulation to an analytic reference
_expected_hadamard(γ, step, outcome)built from:Tests are parametrized over
γ ∈ {0, 0.3, 0.7, 1.0}and both measurement outcomes. The measure-channel step also cross-checks the closed formdiag((1±√(1−γ))/2).RZ pattern - X/Z correction tests follow the depolarising suite: damping is applied only when the correction domain fires; expected state is
single_qubit_amplitude_damping_exact(rz_exact_res(α), γ)or the noiseless RZ state. Measure-confuse and zero-parameter noiseless cases are also covered.Infrastructure - Kraus operator correctness, invalid
γvalidation, noise-model transpilation on random circuits, andconfuse_resultbehaviour are tested separately.Verification