Skip to content

✨ Add fuse-two-qubit-unitary-runs pass - #1865

Open
simon1hofmann wants to merge 48 commits into
mainfrom
feat/fuse-two-qubit-unitary-runs
Open

✨ Add fuse-two-qubit-unitary-runs pass#1865
simon1hofmann wants to merge 48 commits into
mainfrom
feat/fuse-two-qubit-unitary-runs

Conversation

@simon1hofmann

@simon1hofmann simon1hofmann commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Description

Add a fuse-two-qubit-unitary-runs MLIR pass that fuses compile-time two-qubit unitary windows and resynthesizes them to a native gateset via Weyl/KAK decomposition.

AI Assistance

Used Composer 2.5 via Cursor for parts of this change. I reviewed the full
diff and take responsibility for everything in this PR.

Checklist

  • The pull request only contains commits that are focused and relevant to this change.
  • I have added appropriate tests that cover the new/changed functionality.
  • I have updated the documentation to reflect these changes.
  • I have added entries to the changelog for any noteworthy additions, changes, fixes, or removals.
  • I have added migration instructions to the upgrade guide (if needed).
  • The changes follow the project's style guidelines and introduce no new warnings.
  • The changes are fully tested and pass the CI checks.
  • I have reviewed my own code changes.

If PR contains AI-assisted content:

  • I have disclosed the use of AI tools in the PR description as per our AI Usage Guidelines.
  • AI-assisted commits include an Assisted-by: [Model Name] via [Tool Name] footer.
  • I confirm that I have personally reviewed and understood all AI-generated content, and accept full responsibility for it.

simon1hofmann and others added 3 commits July 7, 2026 10:02
Add a `fuse-two-qubit-unitary-runs` MLIR pass that fuses compile-time
two-qubit unitary windows and resynthesizes them to a native gateset via
Weyl/KAK decomposition. Includes the pass definition, implementation,
unit tests, and CMake wiring.

Also add the `isEquivalentUpToGlobalPhase` matrix helper used by the new
tests to compare unitaries up to a global phase.

Assisted-by: Claude Opus 4.8 via Cursor
Co-authored-by: Cursor <cursoragent@cursor.com>
@simon1hofmann simon1hofmann changed the title ✨ Add fuse-two-qubit-unitary-runs pass ✨ Add fuse-two-qubit-unitary-runs pass Jul 7, 2026
@simon1hofmann simon1hofmann self-assigned this Jul 7, 2026
@simon1hofmann simon1hofmann added enhancement Improvement of existing feature c++ Anything related to C++ code MLIR Anything related to MLIR labels Jul 7, 2026
@simon1hofmann simon1hofmann added this to the MLIR Support milestone Jul 7, 2026
@codecov

codecov Bot commented Jul 7, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.10895% with 10 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...sforms/NativeSynthesis/FuseTwoQubitUnitaryRuns.cpp 95.0% 10 Missing ⚠️

📢 Thoughts on this report? Let us know!

@simon1hofmann

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: e8ebe942-d65f-4282-bad3-b3744a0de71e

📥 Commits

Reviewing files that changed from the base of the PR and between 5e17af0 and b9ec3d0.

📒 Files selected for processing (4)
  • mlir/include/mlir/Dialect/QCO/Transforms/Decomposition/NativeGateset.h
  • mlir/tools/mqt-cc/CMakeLists.txt
  • mlir/tools/mqt-cc/mqt-cc.cpp
  • mlir/tools/mqt-cc/tests/check-native-gates-empty.cmake

📝 Walkthrough

Summary by CodeRabbit

  • New Features
    • Added fuse-two-qubit-unitary-runs pass to fuse eligible two-qubit unitary runs and lower to a provided native gate menu.
    • Added native-gates / --native-gates support in mqt-cc, plus QCOProgram.fuse_two_qubit_unitary_runs(native_gates=...) in C++ and Python.
  • Bug Fixes
    • Improved validation and eligibility checks, including special handling for controlled bodies, and now prefers CZ over CX when both are available.
  • Tests
    • Added unit/integration tests covering empty menus (no-op), invalid menus (failure), correctness/equivalence, and determinism.
  • Documentation
    • Updated the unreleased changelog entry for the new pass.

Walkthrough

Adds an MLIR QCO pass that fuses two-qubit unitary runs, resynthesizes them to a native gateset, and validates the result. Compiler, CLI, and Python APIs, reusable single-qubit fusion wiring, tests, and changelog entries are also added.

Changes

Two-Qubit Unitary Fusion Pass

Layer / File(s) Summary
Native gateset and single-qubit fusion contracts
mlir/include/.../Decomposition/*, mlir/lib/.../NativeGateset.cpp, mlir/lib/.../FuseSingleQubitUnitaryRuns.cpp, mlir/unittests/.../test_weyl_decomposition.cpp
Adds operation eligibility checks and reusable single-qubit fusion patterns that can skip controlled bodies.
Pass definition and two-qubit synthesis
mlir/include/.../Passes.td, mlir/lib/.../FuseTwoQubitUnitaryRuns.cpp
Defines the pass and implements run scanning, Weyl resynthesis, off-gateset lowering, orchestration, and convergence validation.
Compiler, CLI, and Python integration
mlir/include/mlir/Compiler/Programs.h, mlir/lib/Compiler/Programs.cpp, mlir/tools/mqt-cc/mqt-cc.cpp, bindings/mlir/register_mlir.cpp, python/mqt/core/mlir.pyi
Registers the pass and exposes two-qubit fusion through compiler, command-line, and Python APIs.
Fusion test coverage and build wiring
mlir/unittests/Dialect/QCO/Transforms/..., mlir/unittests/Compiler/test_compiler_pipeline.cpp, mlir/tools/mqt-cc/tests/*, test/python/test_mlir.py
Adds native-compliance, equivalence, boundary, failure, determinism, API, CLI, and build coverage.
Changelog update
CHANGELOG.md
Adds the unreleased pass entry and PR reference.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

Suggested labels: feature

Suggested reviewers: burgholzer, denialhaag

Poem

I hopped through qubits, two by two,
And shaped their runs in native hue.
Weyl sang softly, gates aligned,
While tests kept every phase in mind.
🐰✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and clearly names the main change: adding the fuse-two-qubit-unitary-runs pass.
Description check ✅ Passed The description includes the change summary, AI assistance note, and checklist; only optional issue/dependency details are missing.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch feat/fuse-two-qubit-unitary-runs

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 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/Passes.td`:
- Around line 88-89: The gate-set docs in Passes.td are advertising the
unsupported `p` alias even though `parseGateToken` only recognizes `rz`, so
update the `QCO` pass descriptions to match the parser by either adding `p`
handling in `parseGateToken` or removing `p` from the documented token list and
any related examples/comments. Make sure the wording around the gate tokens in
the pass definitions stays consistent with the actual accepted syntax.

In `@mlir/lib/Dialect/QCO/Transforms/NativeSynthesis/FuseTwoQubitUnitaryRuns.cpp`:
- Around line 248-250: The comparison in the `FuseTwoQubitUnitaryRuns` scan is
unsafe because `uniqueUnitaryUser()` does not guarantee `nextOnA` and `nextOnB`
are in the same block, so `isBeforeInBlock` can trip MLIR preconditions when the
run spans blocks or regions. Update the logic around the `aSingle`/`bSingle`
check to first verify both successors are in the same block, and if not, stop
the scan before calling `isBeforeInBlock`; use the existing `nextOnA`,
`nextOnB`, and `sameOp` flow in `FuseTwoQubitUnitaryRuns.cpp` to place this
guard.

In `@mlir/unittests/Dialect/QCO/Transforms/NativeSynthesis/CMakeLists.txt`:
- Around line 12-26: The NativeSynthesis test target is missing the MemRef
dialect dependency even though the test registers memref::MemRefDialect in the
related test source. Update the target_link_libraries list for the test target
to include MLIRMemRefDialect alongside the existing MLIR dialect libraries,
matching the pattern used by other QCO test targets such as test_qc_ir.cpp and
test_qc_to_qco.cpp.

In
`@mlir/unittests/Dialect/QCO/Transforms/NativeSynthesis/test_fuse_two_qubit_unitary_runs.cpp`:
- Around line 388-390: The boundary comment in the test is stale and contradicts
the current pass behavior: in the scenario around the entangler and the
three-qubit gate, the wider gate should be described as stopping the run scan
and being left untouched, not “for the pass to reject.” Update the comment near
the affected test case in test_fuse_two_qubit_unitary_runs.cpp so it matches the
contract exercised by the surrounding test and the NativeSynthesis pass
behavior.
🪄 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: dbd760f5-f291-4778-bbd7-825ed27db900

📥 Commits

Reviewing files that changed from the base of the PR and between 5a1ea9d and 0b7922d.

📒 Files selected for processing (11)
  • CHANGELOG.md
  • mlir/include/mlir/Dialect/QCO/Transforms/Decomposition/Euler.h
  • mlir/include/mlir/Dialect/QCO/Transforms/Decomposition/NativeGateset.h
  • mlir/include/mlir/Dialect/QCO/Transforms/Passes.td
  • mlir/lib/Dialect/QCO/Transforms/Decomposition/NativeGateset.cpp
  • mlir/lib/Dialect/QCO/Transforms/NativeSynthesis/FuseSingleQubitUnitaryRuns.cpp
  • mlir/lib/Dialect/QCO/Transforms/NativeSynthesis/FuseTwoQubitUnitaryRuns.cpp
  • mlir/unittests/Dialect/QCO/Transforms/CMakeLists.txt
  • mlir/unittests/Dialect/QCO/Transforms/Decomposition/test_weyl_decomposition.cpp
  • mlir/unittests/Dialect/QCO/Transforms/NativeSynthesis/CMakeLists.txt
  • mlir/unittests/Dialect/QCO/Transforms/NativeSynthesis/test_fuse_two_qubit_unitary_runs.cpp

Comment thread mlir/include/mlir/Dialect/QCO/Transforms/Passes.td Outdated
@simon1hofmann

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@mergify mergify Bot added the conflict label Jul 8, 2026
simon1hofmann and others added 2 commits July 23, 2026 09:59
Co-authored-by: Cursor <cursoragent@cursor.com>
Assisted-by: Cursor Grok 4.5 via Cursor
@mergify mergify Bot added conflict and removed conflict labels Jul 23, 2026
@mergify mergify Bot removed the conflict label Jul 24, 2026
burgholzer and others added 12 commits July 27, 2026 16:06
Assisted-by: GPT-5 via Codex
Move QCO cleanup ahead of explicit native synthesis so no later QCO
transformation can reintroduce off-menu gates, and reject native-gate
menus for raw QCO output where they cannot be applied.

Add end-to-end driver regressions for both contracts.

Assisted-by: GPT-5 via Codex
Assisted-by: GPT-5 via Codex
Assisted-by: GPT-5 via Codex
Assisted-by: GPT-5 via Codex
Match the --pass-pipeline guard so the option is not silently ignored when
optimization is skipped.
Emit the off-gateset convergence error on the leftover operation and cover
runtime-parameterized residuals with a unit test.
Use h+swap input and assert synthesized ctrl output rather than only
single-qubit lowering.
@simon1hofmann

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
mlir/include/mlir/Dialect/QCO/Transforms/Decomposition/NativeGateset.h (1)

70-78: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Document the exact qco.ctrl shape accepted by allowsOp.

entanglerKindFor requires exactly one control, one target, and one body unitary, but this documentation only says “single-target.” Align it with the implementation and pass contract to avoid implying that multi-control shells are accepted.

Proposed wording
- * and single-target `qco.ctrl` shells (with an `X`/`Z` body) are checked
+ * and single-control/single-target `qco.ctrl` shells with one `X`/`Z` body
+ * are checked
🤖 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/include/mlir/Dialect/QCO/Transforms/Decomposition/NativeGateset.h`
around lines 70 - 78, Update the documentation for NativeGateset::allowsOp to
state that accepted qco.ctrl shells have exactly one control, one target, and
one body unitary, with the body restricted to X or Z; do not describe them only
as “single-target,” which could imply multi-control shells are valid.
🤖 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/tools/mqt-cc/mqt-cc.cpp`:
- Around line 397-403: Validate the trimmed native-gates value whenever
nativeGates was explicitly provided, rejecting empty values such as
--native-gates= or whitespace-only input before selecting the optimized-output
path. Reuse this same non-empty validation in the pass-construction logic near
the native-gates fusion handling so an empty menu cannot be skipped or treated
as successful synthesis.

---

Outside diff comments:
In `@mlir/include/mlir/Dialect/QCO/Transforms/Decomposition/NativeGateset.h`:
- Around line 70-78: Update the documentation for NativeGateset::allowsOp to
state that accepted qco.ctrl shells have exactly one control, one target, and
one body unitary, with the body restricted to X or Z; do not describe them only
as “single-target,” which could imply multi-control shells are valid.
🪄 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 Plus

Run ID: 77c5595d-4693-45e3-a339-38f9eb1bae88

📥 Commits

Reviewing files that changed from the base of the PR and between 7b2cd01 and 5e17af0.

📒 Files selected for processing (20)
  • CHANGELOG.md
  • bindings/mlir/register_mlir.cpp
  • mlir/include/mlir/Compiler/Programs.h
  • mlir/include/mlir/Dialect/QCO/Transforms/Decomposition/NativeGateset.h
  • mlir/include/mlir/Dialect/QCO/Transforms/Passes.td
  • mlir/lib/Compiler/Programs.cpp
  • mlir/lib/Dialect/QCO/Transforms/Decomposition/NativeGateset.cpp
  • mlir/lib/Dialect/QCO/Transforms/NativeSynthesis/FuseSingleQubitUnitaryRuns.cpp
  • mlir/lib/Dialect/QCO/Transforms/NativeSynthesis/FuseTwoQubitUnitaryRuns.cpp
  • mlir/lib/Support/Passes.cpp
  • mlir/tools/mqt-cc/CMakeLists.txt
  • mlir/tools/mqt-cc/mqt-cc.cpp
  • mlir/tools/mqt-cc/tests/check-native-gates-raw-qco.cmake
  • mlir/tools/mqt-cc/tests/native-gates.qasm
  • mlir/unittests/Compiler/test_compiler_pipeline.cpp
  • mlir/unittests/Dialect/QCO/Transforms/Decomposition/test_weyl_decomposition.cpp
  • mlir/unittests/Dialect/QCO/Transforms/NativeSynthesis/CMakeLists.txt
  • mlir/unittests/Dialect/QCO/Transforms/NativeSynthesis/test_fuse_two_qubit_unitary_runs.cpp
  • python/mqt/core/mlir.pyi
  • test/python/test_mlir.py

Comment thread mlir/tools/mqt-cc/mqt-cc.cpp
@simon1hofmann

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Exercise one- and two-qubit synthesis through the compiler API and rely on the dedicated native-synthesis suite for equivalence coverage.

Assisted-by: GPT-5 via Codex
Document the pass scope, compile-time matrix requirement, and exact native controlled-gate shape.

Assisted-by: GPT-5 via Codex

@burgholzer burgholzer left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Let's get this in 🚀

@burgholzer
burgholzer enabled auto-merge (squash) July 29, 2026 12:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c++ Anything related to C++ code enhancement Improvement of existing feature MLIR Anything related to MLIR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants