✨ Add two-qubit Weyl (KAK) decomposition library#1803
Conversation
…e tolerance checks in existing tests
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
|
@coderabbitai review |
✅ Action performedReview finished.
|
📝 WalkthroughWalkthroughAdds a full two-qubit Weyl decomposition and basis-gate synthesis pipeline to the MLIR QCO dialect. New rotation and i-Pauli matrix primitives are introduced in the Matrix utility layer, ChangesWeyl Two-Qubit Decomposition Pipeline
Sequence Diagram(s)sequenceDiagram
participant Caller
participant decomposeTwoQubitWithBasis
participant TwoQubitWeylDecomposition
participant TwoQubitBasisDecomposer
participant MagicBasis
Caller->>decomposeTwoQubitWithBasis: target, basisMatrix, basisFidelity
decomposeTwoQubitWithBasis->>TwoQubitBasisDecomposer: create(basisMatrix, basisFidelity)
TwoQubitBasisDecomposer->>TwoQubitWeylDecomposition: create(basisMatrix, fidelity)
TwoQubitWeylDecomposition->>MagicBasis: magicBasisTransform
MagicBasis-->>TwoQubitWeylDecomposition: eigenphases
TwoQubitWeylDecomposition->>TwoQubitWeylDecomposition: extract Weyl params a,b,c
TwoQubitWeylDecomposition->>TwoQubitWeylDecomposition: applySpecialization
TwoQubitWeylDecomposition-->>TwoQubitBasisDecomposer: basis Weyl decomposition
decomposeTwoQubitWithBasis->>TwoQubitWeylDecomposition: create(target, nullopt)
TwoQubitWeylDecomposition-->>decomposeTwoQubitWithBasis: target Weyl decomposition
decomposeTwoQubitWithBasis->>TwoQubitBasisDecomposer: twoQubitDecompose(targetWeyl)
TwoQubitBasisDecomposer->>TwoQubitBasisDecomposer: compute traces → score 0..3 basis uses
TwoQubitBasisDecomposer->>TwoQubitBasisDecomposer: select best basis count
TwoQubitBasisDecomposer->>TwoQubitBasisDecomposer: decomp0/1/2/3 → factors
TwoQubitBasisDecomposer-->>decomposeTwoQubitWithBasis: TwoQubitNativeDecomposition
decomposeTwoQubitWithBasis-->>Caller: TwoQubitNativeDecomposition
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches✨ Simplify code
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@mlir/lib/Dialect/QCO/Transforms/Decomposition/Weyl.cpp`:
- Around line 112-118: The hardcoded constants 1.2602066112249388 and
0.22317849046722027 assigned to randA and randB in the if (i == 0) block lack
documentation about their origin and purpose. Add a comment above the if
statement explaining that these are perturbation coefficients specifically
chosen for the first diagonalization attempt, likely derived from a reference
implementation such as Qiskit, to clarify why these specific values are used for
the initial iteration while subsequent iterations use randomly generated values
from the distribution.
In
`@mlir/unittests/Dialect/QCO/Transforms/Decomposition/test_weyl_decomposition.cpp`:
- Around line 189-193: The test fixture classes WeylDecompositionTest and
BasisDecomposerTest are defined at translation unit scope without internal
linkage, triggering a clang-tidy warning. Wrap these class definitions (and any
related helper code that is only used within this test file) in an anonymous
namespace to limit their visibility to internal linkage and resolve the warning.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: b251ecb4-6a99-454e-a2b7-dc6a2ce6d4c6
📒 Files selected for processing (9)
mlir/include/mlir/Dialect/QCO/Transforms/Decomposition/Euler.hmlir/include/mlir/Dialect/QCO/Transforms/Decomposition/Weyl.hmlir/include/mlir/Dialect/QCO/Utils/Matrix.hmlir/lib/Dialect/QCO/Transforms/Decomposition/Euler.cppmlir/lib/Dialect/QCO/Transforms/Decomposition/Weyl.cppmlir/lib/Dialect/QCO/Utils/Matrix.cppmlir/unittests/Dialect/QCO/Transforms/Decomposition/CMakeLists.txtmlir/unittests/Dialect/QCO/Transforms/Decomposition/test_euler_decomposition.cppmlir/unittests/Dialect/QCO/Transforms/Decomposition/test_weyl_decomposition.cpp
💤 Files with no reviewable changes (1)
- mlir/unittests/Dialect/QCO/Transforms/Decomposition/test_euler_decomposition.cpp
… behavior in Weyl decomposition diagonalization
|
@coderabbitai review |
✅ Action performedReview finished.
|
…get decompositions.
…eyl decomposition with new specialization phase finalization and improved fidelity calculations.
|
@coderabbitai review |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
mlir/lib/Dialect/QCO/Transforms/Decomposition/Weyl.cpp (1)
465-479: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winDo not enforce reconstruction only with
assert.These checks are the public decomposition contract, but they disappear in release builds. If specialization or numeric drift breaks reconstruction, callers receive invalid factors; keep the post-specialization check as a runtime error.
Proposed fix
- assert((Matrix4x4::kron(decomposition.k1l_, decomposition.k1r_) * - decomposition.getCanonicalMatrix() * - Matrix4x4::kron(decomposition.k2l_, decomposition.k2r_) * - std::exp(Complex{0.0, 1.0} * decomposition.globalPhase_)) - .isApprox(unitaryMatrix, WEYL_TOLERANCE)); + const auto restored = + Matrix4x4::kron(decomposition.k1l_, decomposition.k1r_) * + decomposition.getCanonicalMatrix() * + Matrix4x4::kron(decomposition.k2l_, decomposition.k2r_) * + std::exp(Complex{0.0, 1.0} * decomposition.globalPhase_); + if (!restored.isApprox(unitaryMatrix, WEYL_TOLERANCE)) { + llvm::reportFatalInternalError( + "TwoQubitWeylDecomposition: reconstructed matrix does not match input"); + }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@mlir/lib/Dialect/QCO/Transforms/Decomposition/Weyl.cpp` around lines 465 - 479, The reconstruction checks around decomposition.applySpecialization and decomposition.finalizeSpecializationPhase are currently enforced only with assert, so they vanish in release builds. Replace the post-specialization assert with a runtime validation that always runs and raises an error if the reconstructed matrix does not match unitaryMatrix within WEYL_TOLERANCE, while keeping the existing reconstruction expression and using the same decomposition fields to locate the failure.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@mlir/include/mlir/Dialect/QCO/Transforms/Decomposition/Weyl.h`:
- Around line 132-134: The public method twoQubitDecompose is missing required
Doxygen documentation. Add a Doxygen-style comment block (using /// or /** */)
immediately before the twoQubitDecompose method declaration that documents its
purpose, parameters, return type, and behavior. Specifically document what the
numBasisGateUses parameter represents including its valid range, and clarify
what happens when std::nullopt is passed for this optional parameter.
- Around line 119-130: The TwoQubitBasisDecomposer class currently has an
implicit public default constructor that allows users to instantiate it without
using the create() factory method, bypassing the necessary Weyl decomposition
and template initialization. Add an explicit private default constructor to the
TwoQubitBasisDecomposer class to prevent direct instantiation and ensure all
instances are properly initialized through the create() factory method.
In `@mlir/lib/Dialect/QCO/Transforms/Decomposition/BasisDecomposer.cpp`:
- Around line 82-84: The TwoQubitBasisDecomposer construction path accepts
basisFidelity without validating its domain, which can lead to invalid ranking
behavior when the value is non-finite or out of range. Update
TwoQubitBasisDecomposer::create (and the other affected construction sites
mentioned in the comment) to enforce that basisFidelity is finite and within the
expected bounded interval before storing or using it, and reject invalid inputs
consistently at the point of construction.
- Around line 185-209: The default case in the switch statement handling
different basis decomposition cases calls llvm::reportFatalInternalError and
llvm_unreachable, which crashes the program for invalid bestNbasis values. Since
bestNbasis is derived from externally supplied numBasisGateUses input rather
than an internal invariant, invalid values should be handled gracefully. Replace
the fatal error and unreachable calls in the default case with a return
std::nullopt statement, consistent with the pattern already established in the
function for validation failures on line 187-189.
In `@mlir/lib/Dialect/QCO/Transforms/Decomposition/Weyl.cpp`:
- Around line 449-451: The public entry point TwoQubitWeylDecomposition::create
currently forwards fidelity directly into specialization selection, which lets
negative or non-finite values skew candidate acceptance and produce invalid
decompositions. Add validation at the start of create to reject any fidelity
that is not finite or is outside the [0, 1] range before any specialization is
chosen, and keep the rest of the selection logic unchanged.
---
Outside diff comments:
In `@mlir/lib/Dialect/QCO/Transforms/Decomposition/Weyl.cpp`:
- Around line 465-479: The reconstruction checks around
decomposition.applySpecialization and decomposition.finalizeSpecializationPhase
are currently enforced only with assert, so they vanish in release builds.
Replace the post-specialization assert with a runtime validation that always
runs and raises an error if the reconstructed matrix does not match
unitaryMatrix within WEYL_TOLERANCE, while keeping the existing reconstruction
expression and using the same decomposition fields to locate the failure.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 1c0f9ce6-a169-4d2d-882e-da6288121059
📒 Files selected for processing (6)
mlir/include/mlir/Dialect/QCO/Transforms/Decomposition/Weyl.hmlir/lib/Dialect/QCO/Transforms/CMakeLists.txtmlir/lib/Dialect/QCO/Transforms/Decomposition/BasisDecomposer.cppmlir/lib/Dialect/QCO/Transforms/Decomposition/Weyl.cppmlir/unittests/Dialect/QCO/Transforms/Decomposition/test_euler_decomposition.cppmlir/unittests/Dialect/QCO/Transforms/Decomposition/test_weyl_decomposition.cpp
|
@coderabbitai review |
✅ Action performedReview finished.
|
Description
Adds a two-qubit Weyl (KAK) decomposition on top of
Matrix4x4. A 4×4 unitary is factored as(K1l ⊗ K1r) · U_canon(a,b,c) · (K2l ⊗ K2r)up to global phase, with optional canonical-gate specialization and basis-gate (CX/CZ) synthesis.This PR is intentionally scoped to the decomposition library + tests. It does not wire an MLIR pass, emit gate sequences, or add
NativeProfile/ fuse-pass integration — those are planned follow-ups.New API (
mlir/Dialect/QCO/Transforms/Decomposition/Weyl.h)TwoQubitWeylDecomposition— KAK decomposition with Weyl-chamber reduction and 10 canonical-gate specializations (identity, SWAP, partial-SWAP ±, controlled, mirror-controlled, fSim variants)TwoQubitBasisDecomposer— decomposes a Weyl result into single-qubit factors + basis-gate count (0–3 uses)Supporting changes
Matrix.h/Matrix.cpp— shared gate matrix factories:rx/ry/rz,iPauliX/Y/Z,rxx/ryy/rzzEuler.h/Euler.cpp— promoteEulerAnglesandanglesFromUnitary()to public API (used by Weyl specialization for controlled / fSim cases)AI Assistance
Used
Composer 2.5via Cursor for parts of this change. I reviewed the fulldiff and take responsibility for everything in this PR.
Checklist
If PR contains AI-assisted content:
Assisted-by: [Model Name] via [Tool Name]footer.