-
-
Notifications
You must be signed in to change notification settings - Fork 72
✨ Add decompose-multi-controlled pass for multi-controlled X/Z decomposition
#1810
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
simon1hofmann
wants to merge
30
commits into
main
Choose a base branch
from
decompose-multi-controlled-gates
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
30 commits
Select commit
Hold shift + click to select a range
bec1fdf
✨ Implement `decompose-multi-controlled` pass for decomposing multi-c…
simon1hofmann d48be9c
✨ Extend `decompose-multi-controlled` pass to support decomposition o…
simon1hofmann f0de507
📝 Update copyright year in QCO dialect files to 2025 and remove outda…
simon1hofmann 08a9dfa
📝 Refine comments in McxSynthesis.cpp for clarity and update test des…
simon1hofmann d47641d
🚨 Fix linter warnings
simon1hofmann e0b53a4
📝 Update CHANGELOG.md to include pull request link for `decompose-mul…
simon1hofmann 0ef3f71
☂️ Increase coverage
simon1hofmann dff6eeb
🚨 Fix linter warnings
simon1hofmann 9ec9e6f
🐇 Address Rabbit's comments
cf57d47
✨ Add project options for MLIRQCOTransforms in CMakeLists.txt
0292b3e
🎨 pre-commit fixes
pre-commit-ci[bot] b2f30eb
☂️ Increase coverage
55176d1
🐇 Address Rabbit's comments
968d06c
Merge branch 'main' into decompose-multi-controlled-gates
simon1hofmann 1351927
Merge remote-tracking branch 'origin/main' into decompose-multi-contr…
simon1hofmann 0b297c5
Merge branch 'main' into decompose-multi-controlled-gates
simon1hofmann f782391
Merge branch 'main' into decompose-multi-controlled-gates
simon1hofmann 0905bd3
Merge branch 'main' into decompose-multi-controlled-gates
simon1hofmann 77b384b
✨ Enhance documentation for multi-controlled gate decomposition optio…
simon1hofmann 735f8fd
✨ Introduce RCCX operation for three-qubit relative-phase CCX gate, i…
simon1hofmann 78edde7
✨ Implement multi-controlled gate decomposition enhancements, introdu…
simon1hofmann 48c29d7
Merge remote-tracking branch 'origin/main' into decompose-multi-contr…
simon1hofmann 86f52b5
🔧 Refactor control operation lambda functions in MultiControlled.cpp
simon1hofmann dd067f2
✨ Introduce `addGadget` method to encapsulate gadget creation logic i…
simon1hofmann 3a75a99
Merge remote-tracking branch 'origin/main' into decompose-multi-contr…
simon1hofmann 495f55b
🔀 Merge main and adapt tests
simon1hofmann 95da2b2
🔧 Update decomposition tests to use EXPECT_EQ for matrix comparison
simon1hofmann 6539e1a
🚨 Fix linter warnings
simon1hofmann daa0f4a
🚨 Fix linter warnings
simon1hofmann 559c5d7
🚨 Fix linter warnings
simon1hofmann File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
146 changes: 146 additions & 0 deletions
146
mlir/include/mlir/Dialect/QCO/Transforms/Decomposition/MultiControlled.h
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,146 @@ | ||
| /* | ||
| * Copyright (c) 2023 - 2026 Chair for Design Automation, TUM | ||
| * Copyright (c) 2025 - 2026 Munich Quantum Software Company GmbH | ||
| * All rights reserved. | ||
| * | ||
| * SPDX-License-Identifier: MIT | ||
| * | ||
| * Licensed under the MIT License | ||
| */ | ||
|
|
||
| #pragma once | ||
|
|
||
| #include "mlir/Dialect/QCO/Utils/Matrix.h" | ||
|
|
||
| #include <mlir/IR/Builders.h> | ||
| #include <mlir/IR/Location.h> | ||
| #include <mlir/IR/Value.h> | ||
| #include <mlir/Support/LLVM.h> | ||
|
|
||
| #include <cstdint> | ||
| #include <optional> | ||
|
|
||
| namespace mlir::qco::decomposition { | ||
|
|
||
| /// Target Pauli or phase gate inside a multi-controlled `qco.ctrl` body. | ||
| enum class ControlledTarget : std::uint8_t { X, Z, Phase }; | ||
|
|
||
| /** | ||
| * @brief Synthesizes a two-controlled Pauli-X, Pauli-Z, or phase gate. | ||
| * | ||
| * @param builder Builder positioned at the desired insertion point. | ||
| * @param loc Location attached to the emitted operations. | ||
| * @param control0 First control qubit (MSB). | ||
| * @param control1 Second control qubit. | ||
| * @param target Target qubit (LSB). | ||
| * @param gate Target gate type (`CCX`, `CCZ`, or `CCPhase`). | ||
| * @param theta Phase angle in radians when @p gate is | ||
| * `ControlledTarget::Phase`. | ||
| * @return The updated SSA values `[control0, control1, target]`. | ||
| */ | ||
| [[nodiscard]] SmallVector<Value> | ||
| synthesizeTwoControlled(OpBuilder& builder, Location loc, Value control0, | ||
| Value control1, Value target, ControlledTarget gate, | ||
| std::optional<double> theta = std::nullopt); | ||
|
|
||
| /** | ||
| * @brief Synthesizes a compile-time-known two-controlled unitary. | ||
| * | ||
| * @details Dispatches to @ref synthesizeTwoControlled when the unitary matches | ||
| * two-controlled @f$X@f$ or two-controlled phase patterns. | ||
| * | ||
| * @param builder Builder positioned at the desired insertion point. | ||
| * @param loc Location attached to the emitted operations. | ||
| * @param control0 First control qubit (MSB). | ||
| * @param control1 Second control qubit. | ||
| * @param target Target qubit (LSB). | ||
| * @param unitary Compile-time-known @f$8 \times 8@f$ unitary matrix. | ||
| * @return The updated SSA values `[control0, control1, target]`. | ||
| * | ||
| * @pre @p unitary must be @f$8 \times 8@f$. | ||
| */ | ||
| [[nodiscard]] SmallVector<Value> | ||
| synthesizeTwoControlled(OpBuilder& builder, Location loc, Value control0, | ||
| Value control1, Value target, | ||
| const DynamicMatrix& unitary); | ||
|
|
||
| /** | ||
| * @brief Emits an elementary-gate decomposition of a relative-phase CCX | ||
| * (`RCCX`). | ||
| * | ||
| * @param builder Builder positioned at the desired insertion point. | ||
| * @param loc Location attached to the emitted operations. | ||
| * @param control0 First control qubit. | ||
| * @param control1 Second control qubit. | ||
| * @param target Target qubit. | ||
| * @return The updated SSA values `[control0, control1, target]`. | ||
| */ | ||
| [[nodiscard]] SmallVector<Value> synthesizeRCCX(OpBuilder& builder, | ||
| Location loc, Value control0, | ||
| Value control1, Value target); | ||
|
|
||
| /** | ||
| * @brief Synthesizes a three-controlled Pauli-X, Pauli-Z, or phase gate. | ||
| * | ||
| * @param builder Builder positioned at the desired insertion point. | ||
| * @param loc Location attached to the emitted operations. | ||
| * @param controls Exactly three control qubits. | ||
| * @param target Target qubit. | ||
| * @param gate Target gate type (`CCCX`, `CCCZ`, or `CCCPhase`). | ||
| * @param theta Phase angle in radians when @p gate is | ||
| * `ControlledTarget::Phase`. | ||
| * @return The updated SSA values, ordered as `[controls..., target]`. | ||
| * | ||
| * @pre @p controls must contain exactly three qubits. | ||
| */ | ||
| [[nodiscard]] SmallVector<Value> | ||
| synthesizeThreeControlled(OpBuilder& builder, Location loc, ValueRange controls, | ||
| Value target, ControlledTarget gate, | ||
| std::optional<double> theta = std::nullopt); | ||
|
|
||
| /** | ||
| * @brief Emits a decomposition of a multi-controlled Pauli-X, Pauli-Z, or | ||
| * phase gate. | ||
| * | ||
| * @details For exactly three controls, dispatches to @ref | ||
| * synthesizeThreeControlled (used by @c decompose-three-controlled). For four | ||
| * or more controls, applies the Huang-Palsberg (PLDI 2024) no-ancilla MCX core | ||
| * (with target Hadamard bookends for Pauli-X). Subcircuits with two or three | ||
| * controls are expanded via @ref synthesizeTwoControlled and @ref | ||
| * synthesizeThreeControlled when @p minControls is at most the subcircuit | ||
| * control count; otherwise the corresponding `qco.ctrl` building blocks are | ||
| * retained for subsequent passes. | ||
| * | ||
| * @note Adapted from ``synth_mcx_noaux_hp24`` and ``synth_mcx_n_dirty_i15`` in | ||
| * the IBM Qiskit framework. | ||
| * (C) Copyright IBM 2025 | ||
| * | ||
| * This code is licensed under the Apache License, Version 2.0. You may | ||
| * obtain a copy of this license in the LICENSE.txt file in the root | ||
| * directory of this source tree or at | ||
| * https://www.apache.org/licenses/LICENSE-2.0. | ||
| * | ||
| * Any modifications or derivative works of this code must retain this | ||
| * copyright notice, and modified files need to carry a notice | ||
| * indicating that they have been altered from the originals. | ||
| * | ||
| * @param builder Builder positioned at the desired insertion point. | ||
| * @param loc Location attached to the emitted operations. | ||
| * @param controls Control qubits (at least three). | ||
| * @param target Target qubit. | ||
| * @param minControls Minimum control count for which subcircuits are expanded | ||
| * rather than retained as building-block `qco.ctrl` operations. | ||
| * @param gate Target gate type. | ||
| * @param theta Phase angle when @p gate is `ControlledTarget::Phase`. | ||
| * @return The updated SSA values, ordered as `[controls..., target]`. | ||
| * | ||
| * @pre @p controls must contain at least three qubits. The HP24 core is used | ||
| * only when @p controls has four or more elements. | ||
| */ | ||
| [[nodiscard]] SmallVector<Value> | ||
| synthesizeMultiControlled(OpBuilder& builder, Location loc, ValueRange controls, | ||
| Value target, std::uint64_t minControls, | ||
| ControlledTarget gate, | ||
| std::optional<double> theta = std::nullopt); | ||
|
|
||
| } // namespace mlir::qco::decomposition |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -201,4 +201,75 @@ def HadamardLifting : Pass<"hadamard-lifting", "mlir::ModuleOp"> { | |
| }]; | ||
| } | ||
|
|
||
| //===----------------------------------------------------------------------===// | ||
| // Decomposition Passes | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| def DecomposeMultiControlled | ||
| : Pass<"decompose-multi-controlled", "mlir::ModuleOp"> { | ||
| let dependentDialects = ["mlir::qco::QCODialect", | ||
| "::mlir::arith::ArithDialect"]; | ||
| let summary = | ||
| "Decompose four-or-more-controlled gates via Huang-Palsberg synthesis"; | ||
| let description = [{ | ||
| Decomposes multi-controlled Pauli-X, Pauli-Z, and phase gates (`qco.ctrl` | ||
| with `qco.x`, `qco.z`, or `qco.p` body) with at least four controls via | ||
| @ref mlir::qco::decomposition::synthesizeMultiControlled. | ||
|
|
||
| Gates with exactly three controls are handled by | ||
| @c decompose-three-controlled. Subcircuits with two or three controls are | ||
| expanded inline when `min-controls` is at most the subcircuit control count; | ||
| otherwise the corresponding `qco.ctrl` building blocks are retained for | ||
| subsequent @c decompose-three-controlled and @c decompose-two-controlled | ||
| passes. | ||
|
|
||
| The pass matches `qco.ctrl` operations with at least `min-controls` and at | ||
| least four control qubits. | ||
| }]; | ||
| let options = [Option< | ||
| "minControls", "min-controls", "uint64_t", "2", | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IIRC tablegen also allows to directly place constraints on options/parameters. Maybe it is worth looking into whether this would simplify some of the error handling code throughout this PR. |
||
| "Minimum control count for decomposing a top-level gate (must be at " | ||
| "least 4). Controlled gates with fewer than four controls are left to " | ||
| "@c decompose-three-controlled or @c decompose-two-controlled. Must be " | ||
| "at least 2.">]; | ||
| } | ||
|
|
||
| def DecomposeThreeControlled | ||
| : Pass<"decompose-three-controlled", "mlir::ModuleOp"> { | ||
| let dependentDialects = ["mlir::qco::QCODialect", | ||
| "::mlir::arith::ArithDialect"]; | ||
| let summary = | ||
| "Decompose three-control CCCX/CCCZ/CCCP gates via three-controlled " | ||
| "synthesis"; | ||
| let description = [{ | ||
| Decomposes three-control building-block gates (`CCCX`, `CCCZ`, and | ||
| `CCCPhase`) via @ref mlir::qco::decomposition::synthesizeThreeControlled. | ||
|
|
||
| Pauli-X and Pauli-Z gates are expanded to elementary one- and two-qubit | ||
| gates. Phase gates are lowered to a three-control `qco.ctrl` with a | ||
| `qco.p` body for subsequent passes. | ||
|
|
||
| The pass matches `qco.ctrl` operations with exactly three controls and a | ||
| single `qco.x`, `qco.z`, or `qco.p` body on one target. Gates with fewer | ||
| than three controls (e.g. `CX`, `CCX`) are left unchanged. | ||
| }]; | ||
| } | ||
|
|
||
| def DecomposeTwoControlled | ||
| : Pass<"decompose-two-controlled", "mlir::ModuleOp"> { | ||
| let dependentDialects = ["mlir::qco::QCODialect", | ||
| "::mlir::arith::ArithDialect"]; | ||
| let summary = "Decompose two-control CCX/CCZ/CCPhase and RCCX gates via " | ||
| "two-controlled synthesis"; | ||
| let description = [{ | ||
| Decomposes two-control building-block gates (`CCX`, `CCZ`, `CCPhase`) via | ||
| @ref mlir::qco::decomposition::synthesizeTwoControlled and standalone | ||
| `qco.rccx` gates via @ref mlir::qco::decomposition::synthesizeRCCX. | ||
|
|
||
| The pass matches `qco.ctrl` operations with exactly two controls and a | ||
| single `qco.x`, `qco.z`, or `qco.p` body on one target. Single-control | ||
| gates (e.g. `CX`, `CP`) are left unchanged. | ||
| }]; | ||
| } | ||
|
|
||
| #endif // MLIR_DIALECT_QCO_TRANSFORMS_PASSES_TD | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might once more just be me, but is there really any value in having a dedicated header file for these functions? Couldn't these simply be part of the respective pass CPP file?
It feels like these are very particular function that do not have any public API usage or at least none that I could foresee.
Would you agree?
Edit: having gone through more of the PR, I think I just don't quite like the idea that so much of the pass logic is actively decoupled from MLIR. For the most part, we have the MLIR pass logic and that then builds some auxiliary data structures, which are passed to a collection of methods that doesn't even really care about MLIR.
I would have thought/hoped that we could integrate the respective functionality a little tighter with MLIR itself and avoid auxiliary boilerplate as much as possible.
However, I can also see that the current design also has its pro's; decoupling the infrastructure from the actual pass logic.
Maybe this is just me leaning towards the tightly integrated solution.
Tagging @munich-quantum-toolkit/mqt-cc here for visibility. Maybe someone has a comment or a different perspective