Skip to content

Add amplitude damping noise model #544

Closed
CodeMaverick2 wants to merge 4 commits into
TeamGraphix:masterfrom
CodeMaverick2:feat/amplitude-damping-noise-model-497
Closed

Add amplitude damping noise model #544
CodeMaverick2 wants to merge 4 commits into
TeamGraphix:masterfrom
CodeMaverick2:feat/amplitude-damping-noise-model-497

Conversation

@CodeMaverick2

Copy link
Copy Markdown
Contributor

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() and two_qubit_amplitude_damping_channel() (tensor product of independent single-qubit channels)
  • graphix/noise_models/amplitude_damping.py - AmplitudeDampingNoise, TwoQubitAmplitudeDampingNoise, AmplitudeDampingNoiseModel (mirrors DepolarisingNoiseModel API: prepare_error_prob, x_error_prob, etc.)
  • Exports in graphix/noise_models/__init__.py and graphix/__init__.py
  • Tests in test_kraus.py, test_noise_model.py, test_noisy_density_matrix.py

Test 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:

  1. Initial two-qubit |+⟩|+⟩ state
  2. Optional amplitude damping (single- or two-qubit Kraus sum) at the stage under test
  3. CZ entangling gate
  4. X-basis measurement projector and normalization
  5. Partial trace to the output qubit
  6. Conditional X correction and optional post-correction damping
    Tests are parametrized over γ ∈ {0, 0.3, 0.7, 1.0} and both measurement outcomes. The measure-channel step also cross-checks the closed form diag((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, and confuse_result behaviour are tested separately.

Verification

uv run ruff check .
uv run ruff format --check .
uv run mypy
uv run pyright
uv run pytest tests/test_kraus.py tests/test_noise_model.py \
  tests/test_noisy_density_matrix.py::TestAmplitudeDampingAnalytic -v

@CodeMaverick2

Copy link
Copy Markdown
Contributor Author

@pranav97nair Happy to get your feedback on this

@codecov

codecov Bot commented Jun 16, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.63014% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 88.95%. Comparing base (6edaaef) to head (39b1d37).

Files with missing lines Patch % Lines
graphix/noise_models/amplitude_damping.py 98.48% 1 Missing ⚠️
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.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@pranav97nair

Copy link
Copy Markdown

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.

@CodeMaverick2

Copy link
Copy Markdown
Contributor Author

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.

@pranav97nair pranav97nair left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread graphix/channels.py Outdated
Comment on lines +204 to +207
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)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread graphix/channels.py Outdated
Comment on lines +235 to +240
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)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment on line 207.

Comment thread tests/test_kraus.py
Comment on lines +203 to +207
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)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@CodeMaverick2

Copy link
Copy Markdown
Contributor Author

@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.

@CodeMaverick2

Copy link
Copy Markdown
Contributor Author

@pranav97nair Happy to get feedback on this everything has been addressed

@pranav97nair

Copy link
Copy Markdown

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!

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.

Implement amplitude damping noise model

2 participants