Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
e5280c5
✨ Add Euler decomposition and supporting decomposition primitives
simon1hofmann Apr 28, 2026
01ff591
🐇 Address Rabbit's Comments
simon1hofmann Apr 28, 2026
2c74981
📝 Update factorization documentation in EulerDecomposition
simon1hofmann Apr 28, 2026
b7307a3
📝 Update docs and comments
simon1hofmann Apr 29, 2026
e978f16
🐇 Address Rabbit's Comments
simon1hofmann Apr 29, 2026
d1a85d3
Merge branch 'main' into decomp/euler
denialhaag Apr 29, 2026
1d1ba72
Adapt to new include style
denialhaag Apr 29, 2026
3c7370d
Merge branch 'main' into decomp/euler
simon1hofmann May 19, 2026
ab35f91
✨ Add QCO UnitaryMatrixOpInterface for compile-time unitary matrices
simon1hofmann May 19, 2026
6cb4af2
♻️ Use UnitaryMatrixOpInterface in CtrlOp and InvOp matrix expansion
simon1hofmann May 19, 2026
abd87fc
♻️ Consolidate QCO Euler decomposition into Euler.h/cpp
simon1hofmann May 19, 2026
9c10cb6
✨ Add fuse-single-qubit-unitary-runs pass for Euler resynthesis
simon1hofmann May 19, 2026
54ca07d
✅ Add tests for Euler synthesis and fuse-single-qubit-unitary-runs
simon1hofmann May 19, 2026
1c01e71
📝 Document fuse-single-qubit-unitary-runs in CHANGELOG
simon1hofmann May 19, 2026
a92a2b6
🚨 Fix linter warnings
simon1hofmann May 19, 2026
577c094
🚨 Fix linter warnings
simon1hofmann May 19, 2026
6e7fa7f
🐇 Address Rabbit's comments
simon1hofmann May 19, 2026
ebc984f
Merge branch 'main' into decomp/euler
simon1hofmann Jun 2, 2026
418b17e
✅ Refactor QCO decomposition tests and update dependencies
simon1hofmann Jun 3, 2026
7da85cd
🎨 Refactor Euler basis handling in QCO transformations
simon1hofmann Jun 3, 2026
5e2cbdc
🎨 Refactor Euler decomposition operations in QCO
simon1hofmann Jun 3, 2026
8eb937c
🎨 Refactor matrix handling and wire start collection in QCO transform…
simon1hofmann Jun 3, 2026
e287b80
🎨 Enhance Euler decomposition in QCO
simon1hofmann Jun 3, 2026
20d5835
🚨 fix clang-tidy warnings
simon1hofmann Jun 3, 2026
1b541d3
🚨 fix clang-tidy warnings
simon1hofmann Jun 3, 2026
3d54872
⚡️Increase single qubit fusion performance
simon1hofmann Jun 4, 2026
a94b83f
Merge branch 'main' into decomp/euler
simon1hofmann Jun 4, 2026
608491f
🎨 Enhance WireIterator to include YieldOp in boundary checks
simon1hofmann Jun 4, 2026
98266bd
📝 Refine Euler decomposition and synthesis documentation
simon1hofmann Jun 4, 2026
d2e7731
🔀 Merge branch 'main' into decomp/euler, fix conflicts and remove Eig…
simon1hofmann Jun 10, 2026
0302530
🎨 missing new line
simon1hofmann Jun 10, 2026
b8d506d
🚨 Fix linter warnings
simon1hofmann Jun 10, 2026
3496c5f
🎨 Enhance Euler decomposition: update documentation, add support for …
simon1hofmann Jun 10, 2026
5d08032
🚨 Fix linter warnings
simon1hofmann Jun 10, 2026
5c6b317
🎨 Enhance QCO matrix handling: add `assignFrom` methods for `DynamicM…
simon1hofmann Jun 10, 2026
2bab298
🎨 Multiple small fixes
simon1hofmann Jun 10, 2026
981fdc8
☂️ increase coverage
simon1hofmann Jun 10, 2026
ee5199d
🚨 Fix linter warnings
simon1hofmann Jun 10, 2026
20b7e1f
Merge remote-tracking branch 'origin/main' into decomp/euler
simon1hofmann Jun 11, 2026
37383f1
✨ Implement composeSingleQubitBodyMatrix function for InvOp and enhan…
simon1hofmann Jun 11, 2026
215ad55
✨ Fuse modifiers with multiple single unitary operations
simon1hofmann Jun 11, 2026
fe6c413
Merge branch 'main' into decomp/euler
simon1hofmann Jun 11, 2026
4cff97e
🚨 Fix linter warnings
simon1hofmann Jun 11, 2026
fa5444e
☂️ Increase coverage
simon1hofmann Jun 11, 2026
74002cd
🎨 Simplify code and remove testcase
simon1hofmann Jun 11, 2026
a19abaa
🐇 Address rabbit's comments
simon1hofmann Jun 11, 2026
9e2502d
🚨 Fix linter warnings
simon1hofmann Jun 11, 2026
150e50d
Merge branch 'main' into decomp/euler
simon1hofmann Jun 12, 2026
a0a9a83
:rotating_light: Please local clang-tidy
burgholzer Jun 12, 2026
fa85055
:art: Drop redundant namespace qualifiers
burgholzer Jun 12, 2026
98886a5
:art: Consistently use `isNearZeroRotationAngle`
burgholzer Jun 12, 2026
93ef9eb
:art: Code quality improvements and cleanup
burgholzer Jun 12, 2026
a9009fe
Merge branch 'main' into decomp/euler
burgholzer Jun 12, 2026
093ba8b
✨ Enhance matrix operations with element-wise scaling and adjoint fun…
simon1hofmann Jun 15, 2026
39a8d4f
🎨 Update default tolerance for MLIR dialect numerics and revert error…
simon1hofmann Jun 15, 2026
1d076c7
🎨 Refactor Euler synthesis functions and improve gate fusion logic
simon1hofmann Jun 15, 2026
b8b6616
⚡️ Improve fusable run logic
simon1hofmann Jun 15, 2026
63f5994
Merge branch 'main' into decomp/euler
simon1hofmann Jun 15, 2026
257bc0f
🚨 Fix linter warnings
simon1hofmann Jun 15, 2026
9c1a659
🎨 Refactor Euler decomposition and fuse single-qubit run logic
simon1hofmann Jun 15, 2026
902729f
🚨 Fix linter warnings
simon1hofmann Jun 15, 2026
c7551bf
🎨 Update tolerance check for global complex value in InvOp.cpp
simon1hofmann Jun 15, 2026
2d71d9b
🚨 Fix linter warnings
simon1hofmann Jun 15, 2026
3701236
✅ Refactor test_euler_decomposition.cpp: streamline includes, rename …
simon1hofmann Jun 15, 2026
c9b7a3c
🚨 Fix linter warnings
simon1hofmann Jun 15, 2026
91c8184
🚨 Fix linter warnings
simon1hofmann Jun 15, 2026
ed4121e
📝 Streamline docstrings and comments
simon1hofmann Jun 15, 2026
8843648
🎨 Remove unnecessary llvm namespace from SmallVector usage in Euler.cpp
simon1hofmann Jun 15, 2026
61cddb0
🎨 Update function signatures in FuseSingleQubitUnitaryRuns.cpp to use…
simon1hofmann Jun 15, 2026
217407e
✅ Organize test_euler_decomposition.cpp
simon1hofmann Jun 15, 2026
9f19d9b
🔀 Merge main
burgholzer Jun 17, 2026
a22d8ec
⚡ Optimize the implementation of the Euler decomposition
burgholzer Jun 17, 2026
85fa0fc
🎨 Better debuggability by printing matrices upon mismatch
burgholzer Jun 17, 2026
9806784
🚸 Add efficient check for compile-time availability of a unitary matrix
burgholzer Jun 17, 2026
8e5b09e
🩹 Ensure Barrier defines its unitary matrix
burgholzer Jun 17, 2026
177e534
🚸 Add a `WireRange` construct that wraps a `WireIterator` for easy us…
burgholzer Jun 17, 2026
f094f33
♻️ Simplify the implementation of the single-qubit gate fusion
burgholzer Jun 17, 2026
a04bc3d
📝 Add to changelog
burgholzer Jun 17, 2026
0f86d05
🚨 Address clang-tidy warnings
burgholzer Jun 17, 2026
6fdebf3
Merge branch 'main' into decomp/euler
simon1hofmann Jun 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ with the exception that minor releases may include breaking changes.

### Added

- ✨ Add a `fuse-single-qubit-unitary-runs` pass
for fusing compile-time single-qubit unitary runs via Euler resynthesis
([#1672]) ([**@simon1hofmann**], [**@burgholzer**])
- ✨ Add QIR program format support to the DDSIM QDMI Device ([#1766])
([**@rturrado**])
- 🚸 Add [CMake presets] to provide a standardized
Expand Down Expand Up @@ -621,6 +624,7 @@ changelogs._
[#1675]: https://github.com/munich-quantum-toolkit/core/pull/1675
[#1674]: https://github.com/munich-quantum-toolkit/core/pull/1674
[#1673]: https://github.com/munich-quantum-toolkit/core/pull/1673
[#1672]: https://github.com/munich-quantum-toolkit/core/pull/1672
[#1664]: https://github.com/munich-quantum-toolkit/core/pull/1664
[#1662]: https://github.com/munich-quantum-toolkit/core/pull/1662
[#1660]: https://github.com/munich-quantum-toolkit/core/pull/1660
Expand Down
17 changes: 15 additions & 2 deletions mlir/include/mlir/Dialect/QCO/IR/QCODialect.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

#pragma once

#include "mlir/Dialect/Utils/Utils.h"

#include <llvm/ADT/STLExtras.h>
#include <mlir/Dialect/Func/IR/FuncOps.h>
#include <mlir/IR/Attributes.h>
Expand Down Expand Up @@ -127,6 +129,16 @@ template <size_t T, size_t P> class TargetAndParameterArityTrait {
llvm::reportFatalUsageError(
"Given qubit is not an input of the operation");
}

[[nodiscard]] bool hasCompileTimeKnownUnitaryMatrix() {
if constexpr (P == 0) {
return true;
} else {
return llvm::all_of(this->getParameters(), [](Value param) {
return utils::valueToDouble(param).has_value();
});
}
}
};
};

Expand All @@ -151,8 +163,9 @@ inline func::FuncOp getEntryPoint(ModuleOp op) {
};

for (auto func : op.getOps<func::FuncOp>()) {
const auto passthrough = func->getAttrOfType<ArrayAttr>(PASSTHROUGH_LABEL);
if (passthrough && llvm::any_of(passthrough, isEntry)) {
if (const auto passthrough =
func->getAttrOfType<ArrayAttr>(PASSTHROUGH_LABEL);
passthrough && llvm::any_of(passthrough, isEntry)) {
return func;
}
}
Expand Down
18 changes: 18 additions & 0 deletions mlir/include/mlir/Dialect/QCO/IR/QCOInterfaces.td
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ def UnitaryOpInterface : OpInterface<"UnitaryOpInterface"> {
return true;
}
return false;
} else if constexpr (std::is_same_v<ValueT, DynamicMatrix>) {
if (auto matrix = $_op.getUnitaryMatrix()) {
return out.assignFrom(*matrix);
}
return false;
} else {
return false;
}
Expand All @@ -63,6 +68,11 @@ def UnitaryOpInterface : OpInterface<"UnitaryOpInterface"> {
return true;
}
return false;
} else if constexpr (std::is_same_v<ValueT, DynamicMatrix>) {
if (auto matrix = $_op.getUnitaryMatrix()) {
return out.assignFrom(*matrix);
}
return false;
} else {
return false;
}
Expand All @@ -87,6 +97,11 @@ def UnitaryOpInterface : OpInterface<"UnitaryOpInterface"> {
return true;
}
return false;
} else if constexpr (std::is_same_v<ValueT, DynamicMatrix>) {
if (auto matrix = $_op.getUnitaryMatrix()) {
return out.assignFrom(*matrix);
}
return false;
} else {
return false;
}
Expand Down Expand Up @@ -188,6 +203,9 @@ def UnitaryOpInterface : OpInterface<"UnitaryOpInterface"> {
"StringRef", "getBaseSymbol", (ins)>,

// Unitary matrix helpers
InterfaceMethod<"Returns true if the operation has a compile-time known "
"unitary matrix representation, false otherwise.",
"bool", "hasCompileTimeKnownUnitaryMatrix", (ins)>,
InterfaceMethod<"Populates the given 1x1 unitary matrix if possible.",
"bool", "getUnitaryMatrix1x1", (ins "Matrix1x1&":$out),
unitaryMatrix1x1MethodBody>,
Expand Down
4 changes: 4 additions & 0 deletions mlir/include/mlir/Dialect/QCO/IR/QCOOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -1030,6 +1030,8 @@ def BarrierOp : QCOOp<"barrier", traits = [UnitaryOpInterface]> {
static Value getParameter(size_t i) { llvm::reportFatalUsageError("BarrierOp has no parameters"); }
static OperandRange getParameters() { return {nullptr, 0}; }
[[nodiscard]] static StringRef getBaseSymbol() { return "barrier"; }
[[nodiscard]] bool hasCompileTimeKnownUnitaryMatrix() const { return true; }
[[nodiscard]] DynamicMatrix getUnitaryMatrix();
}];

let builders = [OpBuilder<(ins "ValueRange":$qubits)>];
Expand Down Expand Up @@ -1126,6 +1128,7 @@ def CtrlOp : QCOOp<"ctrl",
Value getParameter(size_t i) { llvm::reportFatalUsageError("CtrlOp does not have parameters"); }
OperandRange getParameters() { return {nullptr, 0}; }
[[nodiscard]] static StringRef getBaseSymbol() { return "ctrl"; }
[[nodiscard]] bool hasCompileTimeKnownUnitaryMatrix();
[[nodiscard]] std::optional<DynamicMatrix> getUnitaryMatrix();
}];

Expand Down Expand Up @@ -1199,6 +1202,7 @@ def InvOp : QCOOp<"inv", traits = [UnitaryOpInterface,
Value getParameter(size_t i) { llvm::reportFatalUsageError("InvOp does not have parameters"); }
OperandRange getParameters() { return {nullptr, 0}; }
[[nodiscard]] static StringRef getBaseSymbol() { return "inv"; }
[[nodiscard]] bool hasCompileTimeKnownUnitaryMatrix();
[[nodiscard]] std::optional<DynamicMatrix> getUnitaryMatrix();
}];

Expand Down
66 changes: 66 additions & 0 deletions mlir/include/mlir/Dialect/QCO/Transforms/Decomposition/Euler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* 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/Support/LLVM.h>

#include <cstddef>
#include <cstdint>
#include <optional>

namespace mlir::qco::decomposition {

/**
* @brief Native gate sets for single-qubit Euler synthesis.
*/
enum class EulerBasis : std::uint8_t {
ZYZ = 0, ///< `RZ(phi) * RY(theta) * RZ(lambda)`.
ZXZ = 1, ///< `RZ(phi) * RX(theta) * RZ(lambda)`.
XZX = 2, ///< `RX(phi) * RZ(theta) * RX(lambda)`.
XYX = 3, ///< `RX(phi) * RY(theta) * RX(lambda)`.
U = 4, ///< `U(theta, phi, lambda)`.
ZSXX = 5, ///< `RZ` / `SX` / `X` synthesis via ZYZ decomposition.
};

/**
* @brief Parses a basis name (e.g. `zyz`, `zsxx`; case-insensitive).
*
* @param basis The basis name.
* @return The parsed basis, or `std::nullopt` if unrecognized.
*/
[[nodiscard]] std::optional<EulerBasis> parseEulerBasis(StringRef basis);

/**
* @brief Synthesizes a composed single-qubit unitary as gates in @p basis.
*
* Returns `std::nullopt` when @p hasNonBasisGate is false and resynthesis
* would not shorten a run of @p runSize gates; otherwise emits gates
* (including `qco.gphase` when needed).
*
* @param builder Builder for the emitted operations.
* @param loc Location for the emitted operations.
* @param qubit Input qubit value.
* @param composed Composed unitary to synthesize.
* @param runSize Number of gates in the run.
* @param hasNonBasisGate Whether the run contains a gate outside @p basis.
* @param basis The target Euler basis.
* @return The synthesized qubit, or `std::nullopt` if synthesis is skipped.
*/
[[nodiscard]] std::optional<Value>
synthesizeUnitary1QEuler(OpBuilder& builder, Location loc, Value qubit,
const Matrix2x2& composed, std::size_t runSize,
bool hasNonBasisGate, EulerBasis basis);

} // namespace mlir::qco::decomposition
26 changes: 26 additions & 0 deletions mlir/include/mlir/Dialect/QCO/Transforms/Passes.td
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,32 @@ def MergeSingleQubitRotationGates
}];
}

def FuseSingleQubitUnitaryRuns
: Pass<"fuse-single-qubit-unitary-runs", "mlir::ModuleOp"> {
let dependentDialects = ["mlir::qco::QCODialect",
"::mlir::arith::ArithDialect",
"::mlir::qtensor::QTensorDialect"];
let summary = "Fuse single-qubit unitary runs using Euler resynthesis";
let description = [{
Matches maximal runs of consecutive single-qubit unitary operations on the
same qubit wire (anchored at each run head), composes their constant unitary
matrices, and replaces a run with an equivalent sequence of basis gates when
beneficial: when the run contains a gate outside the target `basis`, or when
Euler resynthesis would shorten it (`synthesizeUnitary1QEuler`). Runs that are
already in the target `basis` and no shorter than the canonical synthesis
length are left unchanged.

The emitted basis is controlled via the `basis` option (e.g. `zyz`, `zsxx`).
A `gphase` correction is inserted when needed so the rewritten sequence
matches the composed matrix exactly (not only up to global phase).

Currently, only operations whose unitary matrix can be obtained at compile
time are fused.
Comment thread
burgholzer marked this conversation as resolved.
}];
Comment thread
simon1hofmann marked this conversation as resolved.
let options = [Option<"basis", "basis", "std::string", "\"zyz\"",
"Target Euler basis (zyz, zxz, xzx, xyx, u, zsxx).">];
Comment thread
burgholzer marked this conversation as resolved.
}

def QuantumLoopUnroll
: InterfacePass<"quantum-loop-unroll", "FunctionOpInterface"> {
let dependentDialects = ["mlir::qco::QCODialect", "mlir::scf::SCFDialect"];
Expand Down
Loading