feat(algorithms): implement Canonical Quantum Amplitude Estimation (QAE) using QPE - #27
Conversation
…AE) using QPE - Implement Canonical QAE in AmplitudeEstimation class replacing previous NotImplementedError stubs. - Synthesize controlled Grover operator powers C-Q^(2^j) via exact quantum gate decomposition: C-Q = A · (C-S_0) · A^\dagger · (C-S_chi) - Apply Inverse QFT on evaluation register to extract amplitude estimate a = sin^2(pi * y / 2^m). - Add unit tests for circuit construction and local statevector simulator estimation.
…nd fix raw docstring warning
…ed Grover operator minus sign
…ome distribution in estimate()
|
Hi, Just following up on this PR! As a quick recap, this PR completes the
Whenever you get a chance to review, let me know if any adjustments are needed. Thanks! |
|
Thanks for implementing canonical QAE and adding local simulator coverage. I reviewed the implementation against the repository’s QPE/QFT conventions and found two correctness issues that should be addressed before merging:
Please also update the main README and algorithm guide, which still state that canonical The PR merges cleanly with current |
|
Thanks for the detailed review, and for actually running the broader amplitude sweep — that was exactly the gap. I've confirmed both issues locally:
One related issue I found while verifying your numbers: Will also update Will push an update shortly — thanks for holding the bar here. |
…good_state Evaluation qubit j applied Q^(2^j), but the little-endian inverse-QFT convention requires Q^(2^(m-1-j)), matching QuantumPhaseEstimation. The theta=0.8 test passed by coincidence; theta=0.2 returned 0.378 instead of 0.010. Additionally, _apply_controlled_s_chi always marked the all-ones state on the objective qubits and never consulted problem.is_good_state, so custom predicates silently estimated a different event. The predicate is now enumerated over the state register and synthesised into an explicit oracle when it differs from the default marking; the default path is unchanged and emits identical gates. Registers larger than MAX_ORACLE_QUBITS are rejected with a ValueError. The multi-controlled-Z pattern duplicated across S_chi and S_0 is factored into a single helper.
…aviour Adds a six-point amplitude sweep, boundary amplitudes, custom and degenerate is_good_state predicates, _resolve_good_states unit tests, and oversized-register rejection. Each new test fails against the previous implementation.
Both READMEs stated the canonical QPE-based variant was planned or raised NotImplementedError. Adds a worked example and documents custom is_good_state support.
The CI spell check rejected the en-GB spelling synthesise/synthesised, which is not in the cspell.json word list.
|
Pushed the fixes in d7dcce5, 1cb2354 and 570e0f5. 1. Controlled-power ordering (d7dcce5)
2. Custom good-state predicates (d7dcce5)
Verified against predicates that genuinely cannot be expressed as the default marking — "exactly one qubit is 1", "both qubits are 0", 3-qubit odd parity — plus the degenerate cases marking nothing and marking everything. Worst error 0.0107. I also factored the multi-controlled-Z pattern, which was written out three times across 3. Tests (1cb2354) Amplitude sweep, boundary amplitudes, custom and degenerate predicates, 4. Docs (570e0f5) Updated both READMEs, added a worked example, documented custom Correction to my previous comment: I claimed the expectation-value decode in On the failing checks — they look unrelated to this PR. All five jobs fail at The vulnerable package is main last ran green on 2026-08-12 and this advisory postdates that, so I'd expect any PR in the repo to hit it right now. Likely needs a pip bump in CI or Locally the full suite is 268 passed, 15 skipped with |
|
Thanks for the update. I pulled the latest commits and checked the changes locally. The original power-ordering issue is fixed, and the new canonical QAE tests look good. I noticed one remaining problem around I think the cleanest approach for this PR is:
The canonical implementation itself is in much better shape now. Once these remaining inconsistencies are cleaned up, I’m happy to take another look. |
…dicates MAX_ORACLE_QUBITS was enforced before checking whether a custom predicate was supplied, so the default objective-qubit marking was rejected on large state registers even though it needs no enumeration. The bound now applies only on the enumeration path. The error also recommended IterativeAmplitudeEstimation, which builds its Grover operator from objective_qubits alone and does not honour is_good_state either; it now points at objective_qubits instead. has_custom_good_state compares the predicate by identity against the default, so reassigning is_good_state after construction reaches the oracle rather than only the result counting.
Custom predicates are supported by the canonical variant only; IterativeAmplitudeEstimation does not yet build its Grover operator from the predicate. Also clarifies that the oracle size limit applies only to custom predicates, and removes a stale note stating the canonical variant is planned.
|
Thanks — all four addressed in d2ba927 and d817240. Oracle size limit — you're right, this was a regression I introduced. The IAE as fallback — removed. You're right that it isn't a valid fallback: "Both variants" claim — removed. The docs now say custom predicates are supported by the canonical variant only, and note explicitly that Stale note — fixed. That one was in the summary section at the bottom of One related thing I tightened while in there: I've left the IAE oracle itself alone as you suggested. Happy to open a separate issue for it, or send a follow-up PR once this lands — whichever you prefer. On the failing checks — they look unrelated to this PR again. All five jobs fail at The flagged package is
All three are fixed in 6.5.8, so Locally the full suite is 278 passed, 16 skipped with |
|
Thanks — I merged the current main into this branch so it picks up the Tornado 6.5.8 lockfile update and gets a fresh CI run. One small follow-up: could you update the PR description as well? The controlled-power bullet still says Q^(2^j), but the corrected ordering is Q^(2^(m-1-j)), and the “48 algorithm unit tests” count is now stale. It may be better to remove the fixed test count and simply mention the focused amplitude-estimation coverage. |
|
Thanks for merging main in — and for the catch on the description. Updated it:
I also added a bullet for the custom Let me know if you'd like the IAE oracle handled as a separate issue or a follow-up PR once this lands. |
|
Thanks for updating this. It looks like the description change may not have saved, though. I still see the old Q^(2^j) ordering and the “48 algorithm unit tests” line in the PR description. Could you please check it once more? Everything else looks good from my side, and CI is green across all Python versions. |
|
Sorry about that — I'd edited the title area rather than the description body the first time, so only part of it saved. Updated properly now:
Thanks for the patience on this one — and for confirming CI is green. |
|
Thanks for working through the review feedback and updating the implementation, tests, and documentation. I’ve checked the final changes again, including the controlled-power ordering, custom The iterative QAE custom-predicate limitation can be handled separately. Approving and merging this. |
Summary
Closes #26.
Implements Canonical Quantum Amplitude Estimation (
AmplitudeEstimation) using Quantum Phase Estimation (QPE), resolving the previousNotImplementedErrorstubs.Implementation Details
QuantumPhaseEstimation.is_good_statepredicate is honoured: it is enumerated over the state register and synthesized into an explicit oracle when it differs from the default all-objective-qubits-are-1 marking. Problems using the default marking take the compact objective-qubit encoding and emit identical gates. The enumeration is bounded byMAX_ORACLE_QUBITS; the default marking carries no such bound.IterativeAmplitudeEstimationdoes not yet build its Grover operator from the predicate, and the documentation states this.Verification
Focused coverage for amplitude estimation in
tests/algorithms/test_amplitude_estimation.py:is_good_stateafter construction reaches the oracle rather than only the result counting.Ruff and cspell pass, and the full suite is green locally with
RUN_ALGO_CORRECTNESS=1andTEST_OPTIMIZERS=1.