Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
3e32169
🔥 Remove Eigen dependency from QCO MLIR dialect and replace with cust…
simon1hofmann Jun 8, 2026
fc1453b
🚨 Fix linter warnings
simon1hofmann Jun 8, 2026
504f603
🎨 Rename Matrix2 and Matrix4 to Matrix2x2 and Matrix4x4
simon1hofmann Jun 8, 2026
67bcda4
🎨 Address feedback
simon1hofmann Jun 9, 2026
44098e8
Merge branch 'main' into remove-eigen
simon1hofmann Jun 9, 2026
d0e7bae
🚨 Fix linter warnings
simon1hofmann Jun 9, 2026
7dc510f
🔧 Fix element access in UnitMatrix1x1 test to ensure proper compariso…
simon1hofmann Jun 9, 2026
2b95d09
✨ Enhance DynamicMatrix with dimension validation and storage size ch…
simon1hofmann Jun 9, 2026
4ea56f7
:adhesive_bandage: fix missing link library in MLIRQTensorUtils
burgholzer Jun 9, 2026
0042db0
:art: remove redundant namespace qualifiers
burgholzer Jun 9, 2026
28063ce
:zap: Slightly optimize the optional case for the matrix getter bodies
burgholzer Jun 9, 2026
46571ae
:recycle: Turn assert in CtrlOp to a runtime error with an appropriat…
burgholzer Jun 9, 2026
1582355
:art: Cleanup and streamline unitary matrix definitions
burgholzer Jun 9, 2026
f3c7adf
:rotating_light: Fix local clang-tidy warning in test
burgholzer Jun 9, 2026
43dc4cf
:truck: Generalize matrix utils to not refer to unitary
burgholzer Jun 9, 2026
0264720
:zap: Pass complex numbers by const reference to avoid copies
burgholzer Jun 9, 2026
a6de65c
:art: Drop namespace qualifiers
burgholzer Jun 9, 2026
7695d54
:art: optimize approximate equality check
burgholzer Jun 9, 2026
7882534
:rotating_light: fix clang-tidy warning
burgholzer Jun 9, 2026
e14e76f
Simplify .clang-format
denialhaag Jun 9, 2026
8a49452
Define unitaryMatrixDynamicMethodBody
denialhaag Jun 9, 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
2 changes: 0 additions & 2 deletions .clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ IncludeCategories:
Priority: 1
- Regex: '^<.*\.(h|hpp)>'
Priority: 2
- Regex: "^<Eigen/.*>"
Priority: 2
- Regex: "^<.*>"
Priority: 3
PointerAlignment: Left
Expand Down
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ This project adheres to [Semantic Versioning], with the exception that minor rel
- ✨ Add conversions between `jeff` and QCO ([#1479], [#1548], [#1565], [#1637], [#1676], [#1706]) ([**@denialhaag**], [**@burgholzer**])
- ✨ Add a `place-and-route` pass for mapping circuits to architectures with restricted topologies ([#1537], [#1547], [#1568], [#1581], [#1583], [#1588], [#1600], [#1664], [#1709], [#1716], [#1748]) ([**@MatthiasReumann**], [**@burgholzer**])
- ✨ Add initial infrastructure for new QC and QCO MLIR dialects
([#1264], [#1330], [#1402], [#1428], [#1430], [#1436], [#1443], [#1446], [#1464], [#1465], [#1470], [#1471], [#1472], [#1474], [#1475], [#1506], [#1510], [#1513], [#1521], [#1542], [#1548], [#1550], [#1554], [#1567], [#1569], [#1570], [#1572], [#1573], [#1580], [#1602], [#1620], [#1623], [#1624], [#1626], [#1627], [#1635], [#1638], [#1673], [#1675], [#1700], [#1717], [#1728], [#1730], [#1749], [#1762], [#1765])
([#1264], [#1330], [#1402], [#1428], [#1430], [#1436], [#1443], [#1446], [#1464], [#1465], [#1470], [#1471], [#1472], [#1474], [#1475], [#1506], [#1510], [#1513], [#1521], [#1542], [#1548], [#1550], [#1554], [#1567], [#1569], [#1570], [#1572], [#1573], [#1580], [#1602], [#1620], [#1623], [#1624], [#1626], [#1627], [#1635], [#1638], [#1673], [#1675], [#1700], [#1717], [#1728], [#1730], [#1749], [#1762], [#1765], [#1774])
([**@burgholzer**], [**@denialhaag**], [**@taminob**], [**@DRovara**], [**@li-mingbao**], [**@Ectras**], [**@MatthiasReumann**], [**@simon1hofmann**])

### Changed
Expand Down Expand Up @@ -402,6 +402,7 @@ _📚 Refer to the [GitHub Release Notes](https://github.com/munich-quantum-tool

<!-- PR links -->

[#1774]: https://github.com/munich-quantum-toolkit/core/pull/1774
[#1765]: https://github.com/munich-quantum-toolkit/core/pull/1765
[#1762]: https://github.com/munich-quantum-toolkit/core/pull/1762
[#1749]: https://github.com/munich-quantum-toolkit/core/pull/1749
Expand Down
30 changes: 0 additions & 30 deletions cmake/ExternalDependencies.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,6 @@ if(BUILD_MQT_CORE_BINDINGS)
endif()

if(BUILD_MQT_CORE_MLIR)
set(Eigen_VERSION
5.0.1
CACHE STRING "Eigen version")
set(Eigen_URL
https://gitlab.com/libeigen/eigen/-/archive/${Eigen_VERSION}/eigen-${Eigen_VERSION}.tar.gz)
set(EIGEN_BUILD_TESTING
OFF
CACHE INTERNAL "Disable building Eigen tests")
FetchContent_Declare(Eigen URL ${Eigen_URL} FIND_PACKAGE_ARGS ${Eigen_VERSION})
list(APPEND FETCH_PACKAGES Eigen)

# Fetch jeff-mlir
FetchContent_Declare(
jeff-mlir
Expand Down Expand Up @@ -132,25 +121,6 @@ list(APPEND FETCH_PACKAGES spdlog)
# Make all declared dependencies available.
FetchContent_MakeAvailable(${FETCH_PACKAGES})

# Treat Eigen headers as system headers to avoid surfacing third-party warnings.
set(_eigen_target "")
if(TARGET Eigen3::Eigen)
set(_eigen_target Eigen3::Eigen)
elseif(TARGET Eigen::Eigen)
set(_eigen_target Eigen::Eigen)
endif()
if(_eigen_target)
get_target_property(_eigen_alias_target ${_eigen_target} ALIASED_TARGET)
if(_eigen_alias_target)
set(_eigen_target ${_eigen_alias_target})
endif()
get_target_property(_eigen_includes ${_eigen_target} INTERFACE_INCLUDE_DIRECTORIES)
if(_eigen_includes)
set_target_properties(${_eigen_target} PROPERTIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES
"${_eigen_includes}")
endif()
endif()

# Install nlohmann_json with explicit MQT components.
if(MQT_CORE_JSON_INSTALL AND TARGET nlohmann_json)
set(MQT_CORE_JSON_CONFIG_INSTALL_DIR "${CMAKE_INSTALL_DATADIR}/cmake/nlohmann_json")
Expand Down
4 changes: 0 additions & 4 deletions mlir/.clang-tidy
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,3 @@ Checks: |
-misc-use-anonymous-namespace,
-modernize-type-traits,
-*-const-correctness,

CheckOptions:
- key: misc-include-cleaner.IgnoreHeaders
value: "Eigen/.*;unsupported/Eigen/.*"
3 changes: 2 additions & 1 deletion mlir/include/mlir/Dialect/QCO/IR/QCOInterfaces.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@

#pragma once

#include <Eigen/Core>
#include "mlir/Dialect/QCO/Utils/Matrix.h"

#include <llvm/Support/ErrorHandling.h>
#include <mlir/IR/OpDefinition.h>
#include <mlir/Support/LLVM.h>
Expand Down
159 changes: 89 additions & 70 deletions mlir/include/mlir/Dialect/QCO/IR/QCOInterfaces.td
Original file line number Diff line number Diff line change
Expand Up @@ -28,57 +28,90 @@ def UnitaryOpInterface : OpInterface<"UnitaryOpInterface"> {

let cppNamespace = "::mlir::qco";

// Generic implementation body for getUnitaryMatrix methods
defvar unitaryMatrixMethodBody = [{
auto process = [&]<typename MatrixType>(MatrixType&& m) -> bool {
using TargetT = std::remove_cvref_t<decltype(out)>;
using SourceT = std::remove_cvref_t<MatrixType>;

constexpr bool isTargetDynamic =
(TargetT::SizeAtCompileTime == Eigen::Dynamic);
constexpr bool isSourceDynamic =
(SourceT::SizeAtCompileTime == Eigen::Dynamic);

// Case 1: Target is Dynamic. Always accepts source.
if constexpr (isTargetDynamic) {
out = std::forward<MatrixType>(m);
// Size-specific bodies
// Each helper only accepts the matching matrix type.
defvar unitaryMatrix1x1MethodBody = [{
if constexpr (requires { $_op.getUnitaryMatrix().has_value(); }) {
using ValueT = std::remove_cvref_t<decltype(*std::declval<decltype($_op.getUnitaryMatrix())>())>;
if constexpr (std::is_same_v<ValueT, Matrix1x1>) {
if (auto matrix = $_op.getUnitaryMatrix()) {
out = *matrix;
return true;
}
// Case 2: Target is Fixed.
else {
// Case 2a: Source is Dynamic. Runtime dimension check required.
if constexpr (isSourceDynamic) {
if (m.rows() == static_cast<Eigen::Index>(TargetT::RowsAtCompileTime) &&
m.cols() == static_cast<Eigen::Index>(TargetT::ColsAtCompileTime))
[[likely]] {
out = std::forward<MatrixType>(m);
return true;
}
}
// Case 2b: Source is Fixed. Compile-time check.
else if constexpr (static_cast<Eigen::Index>(
SourceT::RowsAtCompileTime) ==
static_cast<Eigen::Index>(
TargetT::RowsAtCompileTime) &&
static_cast<Eigen::Index>(
SourceT::ColsAtCompileTime) ==
static_cast<Eigen::Index>(
TargetT::ColsAtCompileTime)) {
out = std::forward<MatrixType>(m);
return true;
}
}
return false;
};
} else {
return false;
}
} else if constexpr (requires { $_op.getUnitaryMatrix(); }) {
using ValueT = std::remove_cvref_t<decltype($_op.getUnitaryMatrix())>;
if constexpr (std::is_same_v<ValueT, Matrix1x1>) {
out = $_op.getUnitaryMatrix();
return true;
}
return false;
} else {
llvm::reportFatalUsageError("Operation '" + $_op.getBaseSymbol() + "' has no unitary matrix definition!");
}
}];

defvar unitaryMatrix2x2MethodBody = [{
if constexpr (requires { $_op.getUnitaryMatrix().has_value(); }) {
using ValueT = std::remove_cvref_t<decltype(*std::declval<decltype($_op.getUnitaryMatrix())>())>;
if constexpr (std::is_same_v<ValueT, Matrix2x2>) {
if (auto matrix = $_op.getUnitaryMatrix()) {
out = *matrix;
return true;
}
return false;
} else {
return false;
}
} else if constexpr (requires { $_op.getUnitaryMatrix(); }) {
using ValueT = std::remove_cvref_t<decltype($_op.getUnitaryMatrix())>;
if constexpr (std::is_same_v<ValueT, Matrix2x2>) {
out = $_op.getUnitaryMatrix();
return true;
}
return false;
} else {
llvm::reportFatalUsageError("Operation '" + $_op.getBaseSymbol() + "' has no unitary matrix definition!");
}
}];

defvar unitaryMatrix4x4MethodBody = [{
if constexpr (requires { $_op.getUnitaryMatrix().has_value(); }) {
if (auto&& matrix = $_op.getUnitaryMatrix()) {
return process(std::move(*matrix));
using ValueT = std::remove_cvref_t<decltype(*std::declval<decltype($_op.getUnitaryMatrix())>())>;
if constexpr (std::is_same_v<ValueT, Matrix4x4>) {
if (auto matrix = $_op.getUnitaryMatrix()) {
out = *matrix;
return true;
}
return false;
} else {
return false;
}
} else if constexpr (requires { $_op.getUnitaryMatrix(); }) {
using ValueT = std::remove_cvref_t<decltype($_op.getUnitaryMatrix())>;
if constexpr (std::is_same_v<ValueT, Matrix4x4>) {
out = $_op.getUnitaryMatrix();
return true;
}
return false;
} else {
llvm::reportFatalUsageError("Operation '" + $_op.getBaseSymbol() + "' has no unitary matrix definition!");
}
}];

defvar unitaryMatrixDynamicMethodBody = [{
if constexpr (requires { $_op.getUnitaryMatrix().has_value(); }) {
if (auto matrix = $_op.getUnitaryMatrix()) {
out.assignFrom(*matrix);
return true;
}
return false;
} else if constexpr (requires { $_op.getUnitaryMatrix(); }) {
return process($_op.getUnitaryMatrix());
out.assignFrom($_op.getUnitaryMatrix());
return true;
} else {
llvm::reportFatalUsageError("Operation '" + $_op.getBaseSymbol() + "' has no unitary matrix definition!");
}
Expand Down Expand Up @@ -156,48 +189,34 @@ def UnitaryOpInterface : OpInterface<"UnitaryOpInterface"> {

// Unitary matrix helpers
InterfaceMethod<"Populates the given 1x1 unitary matrix if possible.",
"bool", "getUnitaryMatrix1x1",
(ins "Eigen::Matrix<std::complex<double>, 1, 1>&":$out),
unitaryMatrixMethodBody>,
"bool", "getUnitaryMatrix1x1", (ins "Matrix1x1&":$out),
unitaryMatrix1x1MethodBody>,
InterfaceMethod<"Populates the given 2x2 unitary matrix if possible.",
"bool", "getUnitaryMatrix2x2",
(ins "Eigen::Matrix2cd&":$out), unitaryMatrixMethodBody>,
"bool", "getUnitaryMatrix2x2", (ins "Matrix2x2&":$out),
unitaryMatrix2x2MethodBody>,
InterfaceMethod<"Populates the given 4x4 unitary matrix if possible.",
"bool", "getUnitaryMatrix4x4",
(ins "Eigen::Matrix4cd&":$out), unitaryMatrixMethodBody>,
"bool", "getUnitaryMatrix4x4", (ins "Matrix4x4&":$out),
unitaryMatrix4x4MethodBody>,
InterfaceMethod<"Populates the given dynamic unitary matrix.", "bool",
"getUnitaryMatrixDynamic", (ins "Eigen::MatrixXcd&":$out),
unitaryMatrixMethodBody>];
"getUnitaryMatrixDynamic", (ins "DynamicMatrix&":$out),
unitaryMatrixDynamicMethodBody>];

let extraClassDeclaration = [{
template<typename MatrixType>
std::optional<MatrixType> getUnitaryMatrix() {
static_assert(is_supported_matrix_v<MatrixType>,
"MatrixType must be Matrix1x1, Matrix2x2, Matrix4x4, or DynamicMatrix");
MatrixType out;
bool result = false;

// Dispatch to the appropriate fixed-size or dynamic method based on the
// matrix type.
if constexpr (MatrixType::RowsAtCompileTime == 1 &&
MatrixType::ColsAtCompileTime == 1) {
if constexpr (std::is_same_v<MatrixType, Matrix1x1>) {
result = this->getUnitaryMatrix1x1(out);
} else if constexpr (MatrixType::RowsAtCompileTime == 2 &&
MatrixType::ColsAtCompileTime == 2) {
} else if constexpr (std::is_same_v<MatrixType, Matrix2x2>) {
result = this->getUnitaryMatrix2x2(out);
} else if constexpr (MatrixType::RowsAtCompileTime == 4 &&
MatrixType::ColsAtCompileTime == 4) {
} else if constexpr (std::is_same_v<MatrixType, Matrix4x4>) {
result = this->getUnitaryMatrix4x4(out);
} else if constexpr (MatrixType::SizeAtCompileTime == Eigen::Dynamic) {
} else if constexpr (std::is_same_v<MatrixType, DynamicMatrix>) {
result = this->getUnitaryMatrixDynamic(out);
} else {
// Fallback: Try obtaining dynamic matrix and see if size matches
Eigen::MatrixXcd dynamicOut;
if (this->getUnitaryMatrixDynamic(dynamicOut)) {
if (dynamicOut.rows() == MatrixType::RowsAtCompileTime &&
dynamicOut.cols() == MatrixType::ColsAtCompileTime) {
out = dynamicOut;
result = true;
}
}
}

if (result) {
Expand Down
Loading
Loading