Skip to content

Commit 3c3b41f

Browse files
committed
add unittest for weyl decomposition
1 parent 66ec9a6 commit 3c3b41f

3 files changed

Lines changed: 142 additions & 0 deletions

File tree

mlir/unittests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@
77
# Licensed under the MIT License
88

99
add_subdirectory(translation)
10+
add_subdirectory(decomposition)
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Copyright (c) 2023 - 2025 Chair for Design Automation, TUM
2+
# Copyright (c) 2025 Munich Quantum Software Company GmbH
3+
# All rights reserved.
4+
#
5+
# SPDX-License-Identifier: MIT
6+
#
7+
# Licensed under the MIT License
8+
9+
set(testname "mqt-core-mlir-decomposition-test")
10+
file(GLOB_RECURSE DECOMPOSITION_TEST_SOURCES *.cpp)
11+
12+
if(NOT TARGET ${testname})
13+
# create an executable in which the tests will be stored
14+
add_executable(${testname} ${DECOMPOSITION_TEST_SOURCES})
15+
# link the Google test infrastructure and a default main function to the test executable.
16+
target_link_libraries(${testname} PRIVATE GTest::gmock GTest::gtest_main LLVMFileCheck MLIRPass
17+
MLIRTransforms MLIRMQTOptTransforms)
18+
# discover tests
19+
gtest_discover_tests(${testname} DISCOVERY_TIMEOUT 60)
20+
set_target_properties(${testname} PROPERTIES FOLDER unittests)
21+
endif()
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/*
2+
* Copyright (c) 2023 - 2025 Chair for Design Automation, TUM
3+
* Copyright (c) 2025 Munich Quantum Software Company GmbH
4+
* All rights reserved.
5+
*
6+
* SPDX-License-Identifier: MIT
7+
*
8+
* Licensed under the MIT License
9+
*/
10+
11+
#include "mlir/Dialect/MQTOpt/Transforms/Decomposition/WeylDecomposition.h"
12+
13+
#include <gtest/gtest.h>
14+
15+
using namespace mqt::ir::opt;
16+
using namespace mqt::ir::opt::decomposition;
17+
18+
namespace {
19+
[[nodiscard]] matrix4x4 randomUnitaryMatrix() {
20+
[[maybe_unused]] static auto initializeRandom = []() {
21+
// Eigen uses std::rand() internally, use fixed seed for deterministic
22+
// testing behavior
23+
std::srand(123456UL);
24+
return true;
25+
}();
26+
matrix4x4 randomMatrix = matrix4x4::Random();
27+
Eigen::HouseholderQR<matrix4x4> qr{};
28+
qr.compute(randomMatrix);
29+
matrix4x4 unitaryMatrix = qr.householderQ();
30+
assert(helpers::isUnitaryMatrix(unitaryMatrix));
31+
return unitaryMatrix;
32+
}
33+
} // namespace
34+
35+
class WeylDecompositionTest : public testing::TestWithParam<matrix4x4> {
36+
public:
37+
[[nodiscard]] static matrix4x4
38+
restore(const TwoQubitWeylDecomposition& decomposition) {
39+
return k1(decomposition) * can(decomposition) * k2(decomposition) *
40+
globalPhaseFactor(decomposition);
41+
}
42+
43+
[[nodiscard]] static qfp
44+
globalPhaseFactor(const TwoQubitWeylDecomposition& decomposition) {
45+
return std::exp(IM * decomposition.globalPhase);
46+
}
47+
[[nodiscard]] static matrix4x4
48+
can(const TwoQubitWeylDecomposition& decomposition) {
49+
return decomposition.getCanonicalMatrix();
50+
}
51+
[[nodiscard]] static matrix4x4
52+
k1(const TwoQubitWeylDecomposition& decomposition) {
53+
return helpers::kroneckerProduct(decomposition.k1l, decomposition.k1r);
54+
}
55+
[[nodiscard]] static matrix4x4
56+
k2(const TwoQubitWeylDecomposition& decomposition) {
57+
return helpers::kroneckerProduct(decomposition.k2l, decomposition.k2r);
58+
}
59+
};
60+
61+
TEST_P(WeylDecompositionTest, TestExact) {
62+
const auto& originalMatrix = GetParam();
63+
auto decomposition = TwoQubitWeylDecomposition::create(originalMatrix, 1.0);
64+
auto restoredMatrix = restore(decomposition);
65+
66+
EXPECT_TRUE(restoredMatrix.isApprox(originalMatrix))
67+
<< "RESULT:\n"
68+
<< restoredMatrix << '\n';
69+
}
70+
71+
TEST_P(WeylDecompositionTest, TestApproximation) {
72+
const auto& originalMatrix = GetParam();
73+
auto decomposition =
74+
TwoQubitWeylDecomposition::create(originalMatrix, 1.0 - 1e-12);
75+
auto restoredMatrix = restore(decomposition);
76+
77+
EXPECT_TRUE(restoredMatrix.isApprox(originalMatrix))
78+
<< "RESULT:\n"
79+
<< restoredMatrix << '\n';
80+
}
81+
82+
TEST(WeylDecompositionTest, Random) {
83+
auto stopTime = std::chrono::steady_clock::now() + std::chrono::seconds{10};
84+
auto iterations = 0;
85+
while (std::chrono::steady_clock::now() < stopTime) {
86+
auto originalMatrix = randomUnitaryMatrix();
87+
auto decomposition =
88+
TwoQubitWeylDecomposition::create(originalMatrix, 1.0 - 1e-12);
89+
auto restoredMatrix = WeylDecompositionTest::restore(decomposition);
90+
91+
EXPECT_TRUE(restoredMatrix.isApprox(originalMatrix))
92+
<< "ORIGINAL:\n"
93+
<< originalMatrix << '\n'
94+
<< "RESULT:\n"
95+
<< restoredMatrix << '\n';
96+
++iterations;
97+
}
98+
99+
RecordProperty("iterations", iterations);
100+
std::cerr << "Iterations: " << iterations << '\n';
101+
}
102+
103+
INSTANTIATE_TEST_CASE_P(
104+
SingleQubitMatrices, WeylDecompositionTest,
105+
::testing::Values(helpers::kroneckerProduct(IDENTITY_GATE, IDENTITY_GATE),
106+
helpers::kroneckerProduct(rzMatrix(1.0), ryMatrix(3.1)),
107+
helpers::kroneckerProduct(IDENTITY_GATE, rxMatrix(0.1))));
108+
109+
INSTANTIATE_TEST_CASE_P(
110+
TwoQubitMatrices, WeylDecompositionTest,
111+
::testing::Values(
112+
rzzMatrix(2.0), ryyMatrix(1.0) * rzzMatrix(3.0) * rxxMatrix(2.0),
113+
TwoQubitWeylDecomposition{1.5, -0.2, 0.0}.getCanonicalMatrix() *
114+
helpers::kroneckerProduct(rxMatrix(1.0), IDENTITY_GATE),
115+
helpers::kroneckerProduct(rxMatrix(1.0), ryMatrix(1.0)) *
116+
TwoQubitWeylDecomposition{1.1, 0.2, 3.0}.getCanonicalMatrix() *
117+
helpers::kroneckerProduct(rxMatrix(1.0), IDENTITY_GATE),
118+
helpers::kroneckerProduct(H_GATE, IPZ) *
119+
getTwoQubitMatrix({.type = qc::X, .qubitId = {0, 1}}) *
120+
helpers::kroneckerProduct(IPX, IPY)));

0 commit comments

Comments
 (0)