Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
f6c61d0
:heavy_plus_sign: Add Eigen library for linear algebra
taminob Jan 7, 2026
e1077e3
:sparkles: Implement unitary matrix definition for standard gates
taminob Jan 7, 2026
bbef22a
fix coderabbit issues
taminob Jan 8, 2026
1cfac4a
add draft for unittest of unitary matrix
taminob Jan 9, 2026
aa23610
implement ctrl matrix
taminob Jan 9, 2026
7b2a4ff
add unittests for ctrl-x gate
taminob Jan 9, 2026
406083a
fix getFastUnitaryMatrix
taminob Jan 9, 2026
a839928
update license header
taminob Jan 9, 2026
923c8d7
rename UnitaryMatrixTest to QcoUnitaryMatrixTest
taminob Jan 9, 2026
295d689
add basic test case for UnitaryOpInterface::getFastUnitaryMatrix()
taminob Jan 9, 2026
fa5f5ad
move Eigen dependency to cmake/ExternalDependencies.cmake
taminob Jan 12, 2026
db5ffb0
update Eigen to 5.0.1
taminob Jan 12, 2026
842952a
remove Windows ARM Eigen workaround (EIGEN_DONT_ALIGN_STATICALLY
taminob Jan 12, 2026
ecfd8e1
remove (partially implemented) permutate() utility function
taminob Jan 12, 2026
a7ea22d
fix interface include in QCODialect.h
taminob Jan 12, 2026
340c7d2
move gphase matrix to source file
taminob Jan 12, 2026
5179257
:art: Rework unitary matrix proposal
taminob Jan 13, 2026
3e90f13
🎨 pre-commit fixes
pre-commit-ci[bot] Jan 13, 2026
434f82d
Cleanup to satisfy coderabittai
taminob Jan 13, 2026
db55c69
make eigen dependency not conditional
taminob Jan 13, 2026
b52ae0f
replace std::numbers by llvm::numbers because of windows+osx CI
taminob Jan 13, 2026
be7ad3f
Revert "replace std::numbers by llvm::numbers because of windows+osx CI"
taminob Jan 14, 2026
944d27a
fix linter and CI issues
taminob Jan 14, 2026
15a5cd7
another round of coderabittai
taminob Jan 14, 2026
e43f1e7
add more tests and fix multiple bugs
taminob Jan 15, 2026
d8e759a
swap qubit order according to qiskit for some two-qubit gates
taminob Jan 16, 2026
b9f8495
Revert "swap qubit order according to qiskit for some two-qubit gates"
taminob Jan 16, 2026
0411386
fix xx-minus-yy gate definition
taminob Jan 16, 2026
058debc
fix combine4x4UnitaryMatrices test
taminob Jan 16, 2026
86cd803
add 8x8 matrix to dynamic matrix test
taminob Jan 16, 2026
62b5133
resolve linter issues
taminob Jan 16, 2026
9d9f385
fix dynamic to static matrix conversion
taminob Jan 18, 2026
006f378
simplify control flow to make coderabbitai happy
taminob Jan 18, 2026
12bcd7c
make include cleaner happy
taminob Jan 18, 2026
7422c30
♻️ Refactor setup of Eigen dependency
burgholzer Jan 18, 2026
7542b6d
🚚 move clang-tidy config to mlir file
burgholzer Jan 18, 2026
3f7b998
Merge branch 'refs/heads/main' into taminob/mlir-qco-unitary-matrix-d…
burgholzer Jan 18, 2026
16dc21c
♻️ tweak interface implementation to make it more performant
burgholzer Jan 19, 2026
a0a3bfc
🎨 misc. tweaks for matrix implementations
burgholzer Jan 19, 2026
8254355
add overflow check
taminob Jan 18, 2026
fe3df31
:white_check_mark: Add two test cases to increase coverage
taminob Jan 19, 2026
261ca04
:recycle: Move BUILD_MQT_CORE_MLIR before ExternalDependencies
taminob Jan 19, 2026
5a8de62
Merge remote-tracking branch 'origin/main' into taminob/mlir-qco-unit…
taminob Jan 19, 2026
b586a06
fix minor linter issues
taminob Jan 19, 2026
12f6aaf
minor renames in QCOInterface refactorings
taminob Jan 19, 2026
ad87192
remove compile-time fail again for wrong matrix type
taminob Jan 19, 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: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ option(MQT_CORE_INSTALL "Generate installation instructions for MQT Core"
option(BUILD_MQT_CORE_TESTS "Build tests for the MQT Core project" ${MQT_CORE_MASTER_PROJECT})
option(BUILD_MQT_CORE_SHARED_LIBS "Build MQT Core libraries as shared libraries"
${BUILD_SHARED_LIBS})
option(BUILD_MQT_CORE_MLIR "Build the MLIR submodule of the MQT Core project" ON)

# try to determine the project version
include(GetVersion)
Expand Down Expand Up @@ -93,7 +94,6 @@ endif()

set(MQT_CORE_TARGET_NAME "mqt-core")

option(BUILD_MQT_CORE_MLIR "Build the MLIR submodule of the MQT Core project" ON)
if(APPLE AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set(BUILD_MQT_CORE_MLIR
OFF
Expand Down
13 changes: 13 additions & 0 deletions cmake/ExternalDependencies.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,19 @@ if(BUILD_MQT_CORE_BINDINGS)
find_package(nanobind CONFIG REQUIRED)
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)
endif()

set(JSON_VERSION
3.12.0
CACHE STRING "nlohmann_json version")
Expand Down
4 changes: 4 additions & 0 deletions mlir/.clang-tidy
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,7 @@ Checks: |
-misc-use-anonymous-namespace,
llvm-twine-local,
-cppcoreguidelines-pro-bounds-avoid-unchecked-container-access

CheckOptions:
- key: misc-include-cleaner.IgnoreHeaders
value: "Eigen/.*;unsupported/Eigen/.*"
5 changes: 3 additions & 2 deletions mlir/include/mlir/Dialect/QCO/IR/QCODialect.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#pragma clang diagnostic pop
#endif

#include <Eigen/Core>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n mlir/include/mlir/Dialect/QCO/IR/QCODialect.h | sed -n '20,35p'

Repository: munich-quantum-toolkit/core

Length of output: 590


🌐 Web query:

Eigen unsupported module stability KroneckerProduct API guarantees

💡 Result:

Short answer: There are no formal stability/ABI/API guarantees for Eigen's "unsupported" modules (including KroneckerProduct). They are labeled "unsupported" and provided "as is"; they may change, be moved into supported code, or be modified between releases, so you should not rely on long‑term API/ABI stability without pinning a specific Eigen version or vendoring the code. Use eval()/copies as documented when assigning results. [1][2][3]

Sources:

  • Eigen unsupported modules (general policy: "provided 'as is' without any support"). [1]
  • KroneckerProduct module docs (experimental; usage notes such as use .eval()). [2]
  • Community discussion noting no guarantees about ABI/API stability of unsupported modules. [3]

🏁 Script executed:

git log --oneline -1

Repository: munich-quantum-toolkit/core

Length of output: 99


🏁 Script executed:

cat -n mlir/include/mlir/Dialect/QCO/IR/QCODialect.h | sed -n '58,78p'

Repository: munich-quantum-toolkit/core

Length of output: 1287


🏁 Script executed:

cat -n mlir/include/mlir/Dialect/QCO/IR/QCODialect.h | sed -n '147,175p'

Repository: munich-quantum-toolkit/core

Length of output: 1060


🏁 Script executed:

git log --format=%B -1

Repository: munich-quantum-toolkit/core

Length of output: 91


🏁 Script executed:

git log --all --grep="unsupported\|KroneckerProduct" --oneline | head -20

Repository: munich-quantum-toolkit/core

Length of output: 593


Eigen unsupported module lacks stability guarantees.

The unsupported/Eigen/KroneckerProduct header is from Eigen's unsupported module, which is provided "as is" without formal ABI/API stability guarantees. These modules may change, be modified, or moved between releases. Ensure the team is aligned on pinning a specific Eigen version or has a plan for handling potential API changes before merging.

Also applies to: 32-32

#include <mlir/Bytecode/BytecodeOpInterface.h>
#include <mlir/Dialect/Arith/IR/Arith.h>
#include <mlir/IR/Value.h>
Expand Down Expand Up @@ -49,6 +50,8 @@
// Interfaces
//===----------------------------------------------------------------------===//

#include "mlir/Dialect/QCO/IR/QCOInterfaces.h.inc" // IWYU pragma: export

namespace mlir::qco {

/**
Expand Down Expand Up @@ -133,8 +136,6 @@ template <size_t T, size_t P> class TargetAndParameterArityTrait {

} // namespace mlir::qco

#include "mlir/Dialect/QCO/IR/QCOInterfaces.h.inc" // IWYU pragma: export

//===----------------------------------------------------------------------===//
// Operations
//===----------------------------------------------------------------------===//
Expand Down
118 changes: 118 additions & 0 deletions mlir/include/mlir/Dialect/QCO/IR/QCOInterfaces.td
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,62 @@ 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);
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;
};


if constexpr (requires { $_op.getUnitaryMatrix().has_value(); }) {
if (auto&& matrix = $_op.getUnitaryMatrix()) {
return process(std::move(*matrix));
}
return false;
} else if constexpr (requires { $_op.getUnitaryMatrix(); }) {
return process($_op.getUnitaryMatrix());
} else {
llvm::reportFatalUsageError("Operation '" + $_op.getBaseSymbol() + "' has no unitary matrix definition!");
}
}];

let methods = [
// Qubit accessors
InterfaceMethod<
Expand Down Expand Up @@ -107,7 +163,69 @@ def UnitaryOpInterface : OpInterface<"UnitaryOpInterface"> {
"Returns the base symbol/mnemonic of the operation.",
"StringRef", "getBaseSymbol", (ins)
>,
InterfaceMethod<
"Populates the given 1x1 unitary matrix if possible.",
"bool", "getUnitaryMatrix1x1",
(ins "Eigen::Matrix<std::complex<double>, 1, 1>&":$out),
unitaryMatrixMethodBody
>,
InterfaceMethod<
"Populates the given 2x2 unitary matrix if possible.",
"bool", "getUnitaryMatrix2x2",
(ins "Eigen::Matrix2cd&":$out),
unitaryMatrixMethodBody
>,
InterfaceMethod<
"Populates the given 4x4 unitary matrix if possible.",
"bool", "getUnitaryMatrix4x4",
(ins "Eigen::Matrix4cd&":$out),
unitaryMatrixMethodBody
>,
InterfaceMethod<
"Populates the given dynamic unitary matrix.",
"bool", "getUnitaryMatrixDynamic",
(ins "Eigen::MatrixXcd&":$out),
unitaryMatrixMethodBody
>
];

let extraClassDeclaration = [{
template<typename MatrixType>
std::optional<MatrixType> getUnitaryMatrix() {
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) {
result = this->getUnitaryMatrix1x1(out);
} else if constexpr (MatrixType::RowsAtCompileTime == 2 &&
MatrixType::ColsAtCompileTime == 2) {
result = this->getUnitaryMatrix2x2(out);
} else if constexpr (MatrixType::RowsAtCompileTime == 4 &&
MatrixType::ColsAtCompileTime == 4) {
result = this->getUnitaryMatrix4x4(out);
} else if constexpr (MatrixType::SizeAtCompileTime == Eigen::Dynamic) {
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) {
return out;
}
return std::nullopt;
}
}];
}

#endif // QCO_INTERFACES
Loading
Loading