From 212533c820ae4740666fe538229334680e253543 Mon Sep 17 00:00:00 2001 From: "jannik.pflieger" Date: Tue, 11 Mar 2025 08:24:19 +0100 Subject: [PATCH 01/21] isCliffordCheck --- .../circuit_optimizer/CircuitOptimizer.hpp | 2 +- include/mqt-core/ir/operations/Operation.hpp | 17 +++++++++++++++++ src/circuit_optimizer/CircuitOptimizer.cpp | 7 ++++++- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/include/mqt-core/circuit_optimizer/CircuitOptimizer.hpp b/include/mqt-core/circuit_optimizer/CircuitOptimizer.hpp index 24b54f2d1..264ba6996 100644 --- a/include/mqt-core/circuit_optimizer/CircuitOptimizer.hpp +++ b/include/mqt-core/circuit_optimizer/CircuitOptimizer.hpp @@ -94,7 +94,7 @@ class CircuitOptimizer { * @param qc the quantum circuit * @param maxBlockSize the maximum size of a block */ - static void collectBlocks(QuantumComputation& qc, std::size_t maxBlockSize); + static void collectBlocks(QuantumComputation& qc, std::size_t maxBlockSize, bool collectCliffords); /** * @brief Elide permutations by propagating them through the circuit. diff --git a/include/mqt-core/ir/operations/Operation.hpp b/include/mqt-core/ir/operations/Operation.hpp index 1d6197122..b9f301ba6 100644 --- a/include/mqt-core/ir/operations/Operation.hpp +++ b/include/mqt-core/ir/operations/Operation.hpp @@ -22,6 +22,7 @@ #include #include #include +#include namespace qc { class Operation { @@ -154,6 +155,22 @@ class Operation { [[nodiscard]] virtual bool isControlled() const { return !controls.empty(); } + [[nodiscard]] virtual bool isClifford() const { + static const std::unordered_set cliffordGateNames = { + "X", // Pauli-X + "Y", // Pauli-Y + "Z", // Pauli-Z + "H", // Hadamard + "S", // Phase gate + "Sdag", // Inverse phase gate + "CNOT", + "CZ", + "SWAP" // Often SWAP is Clifford, but include only if your usage agrees + }; + + const std::string opName = this->getName(); + return (cliffordGateNames.find(opName) != cliffordGateNames.end());} + /** * @brief Checks whether a gate is global. * @details A StandardOperation is global if it acts on all qubits. diff --git a/src/circuit_optimizer/CircuitOptimizer.cpp b/src/circuit_optimizer/CircuitOptimizer.cpp index cdda2696f..5ce333c7a 100644 --- a/src/circuit_optimizer/CircuitOptimizer.cpp +++ b/src/circuit_optimizer/CircuitOptimizer.cpp @@ -1425,7 +1425,7 @@ struct DSU { }; void CircuitOptimizer::collectBlocks(QuantumComputation& qc, - const std::size_t maxBlockSize) { + const std::size_t maxBlockSize, bool collectCliffords) { if (qc.size() <= 1) { return; } @@ -1446,6 +1446,11 @@ void CircuitOptimizer::collectBlocks(QuantumComputation& qc, canProcess = false; } + // check if the operation is a Clifford operation + if (collectCliffords && op->isClifford()) { + bool isClifford = true; + } + const auto usedQubits = op->getUsedQubits(); if (canProcess) { From 3f64b2f39ab86b558d90674b71d054f6f8bb3b88 Mon Sep 17 00:00:00 2001 From: "jannik.pflieger" Date: Wed, 19 Mar 2025 14:20:45 +0100 Subject: [PATCH 02/21] added isCliffordOperation --- include/mqt-core/ir/operations/Operation.hpp | 46 ++++++++++++++------ 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/include/mqt-core/ir/operations/Operation.hpp b/include/mqt-core/ir/operations/Operation.hpp index b9f301ba6..7fa15b150 100644 --- a/include/mqt-core/ir/operations/Operation.hpp +++ b/include/mqt-core/ir/operations/Operation.hpp @@ -156,20 +156,38 @@ class Operation { [[nodiscard]] virtual bool isControlled() const { return !controls.empty(); } [[nodiscard]] virtual bool isClifford() const { - static const std::unordered_set cliffordGateNames = { - "X", // Pauli-X - "Y", // Pauli-Y - "Z", // Pauli-Z - "H", // Hadamard - "S", // Phase gate - "Sdag", // Inverse phase gate - "CNOT", - "CZ", - "SWAP" // Often SWAP is Clifford, but include only if your usage agrees - }; - - const std::string opName = this->getName(); - return (cliffordGateNames.find(opName) != cliffordGateNames.end());} + OpType opType = this->getType(); + bool controlled = this->isControlled(); + std::size_t number_of_controls = this->getNcontrols(); + std::size_t number_of_targets = this->getNtargets(); + switch (opType) { + case I: + case X: + if ((controlled) && ((number_of_controls >= 2))){ + return false; + } + case Y: + if ((controlled) && ((number_of_controls >= 2))){ + return false; + } + case Z: + if ((controlled) && ((number_of_controls >= 2))){ + return false; + } + case H: + case S: + case Sdg: + case SX: + case SXdg: + case DCX: + case SWAP: + case iSWAP: + case ECR: + return true; + default: + return false; + } +} /** * @brief Checks whether a gate is global. From 5db7ac58050aee94ef08bf188375aff7a37bb4c2 Mon Sep 17 00:00:00 2001 From: "jannik.pflieger" Date: Thu, 20 Mar 2025 09:32:49 +0100 Subject: [PATCH 03/21] edited collectBlocks to handle CliffordBlocks --- src/circuit_optimizer/CircuitOptimizer.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/circuit_optimizer/CircuitOptimizer.cpp b/src/circuit_optimizer/CircuitOptimizer.cpp index 5ce333c7a..a7fe100a1 100644 --- a/src/circuit_optimizer/CircuitOptimizer.cpp +++ b/src/circuit_optimizer/CircuitOptimizer.cpp @@ -1440,6 +1440,7 @@ void CircuitOptimizer::collectBlocks(QuantumComputation& qc, auto& op = *opIt; bool canProcess = true; bool makesTooBig = false; + bool isClifford = false; // check if the operation can be processed if (!op->isUnitary()) { @@ -1448,7 +1449,11 @@ void CircuitOptimizer::collectBlocks(QuantumComputation& qc, // check if the operation is a Clifford operation if (collectCliffords && op->isClifford()) { - bool isClifford = true; + isClifford = true; + } + + if (collectCliffords && !isClifford){ + canProcess = false; } const auto usedQubits = op->getUsedQubits(); From 4995e479e4a769e8a88d8b9854f4cad1ad941399 Mon Sep 17 00:00:00 2001 From: "jannik.pflieger" Date: Fri, 21 Mar 2025 13:16:04 +0100 Subject: [PATCH 04/21] Added Tests and redefined if statements in opertaon --- include/mqt-core/ir/operations/Operation.hpp | 7 +- .../circuit_optimizer/test_collect_blocks.cpp | 95 ++++++++++++++++--- 2 files changed, 86 insertions(+), 16 deletions(-) diff --git a/include/mqt-core/ir/operations/Operation.hpp b/include/mqt-core/ir/operations/Operation.hpp index 7fa15b150..e50eb2006 100644 --- a/include/mqt-core/ir/operations/Operation.hpp +++ b/include/mqt-core/ir/operations/Operation.hpp @@ -159,20 +159,25 @@ class Operation { OpType opType = this->getType(); bool controlled = this->isControlled(); std::size_t number_of_controls = this->getNcontrols(); - std::size_t number_of_targets = this->getNtargets(); switch (opType) { case I: case X: if ((controlled) && ((number_of_controls >= 2))){ return false; + }else{ + return true; } case Y: if ((controlled) && ((number_of_controls >= 2))){ return false; + }else{ + return true; } case Z: if ((controlled) && ((number_of_controls >= 2))){ return false; + }else{ + return true; } case H: case S: diff --git a/test/circuit_optimizer/test_collect_blocks.cpp b/test/circuit_optimizer/test_collect_blocks.cpp index 4934176c2..9277e174d 100644 --- a/test/circuit_optimizer/test_collect_blocks.cpp +++ b/test/circuit_optimizer/test_collect_blocks.cpp @@ -16,7 +16,13 @@ namespace qc { TEST(CollectBlocks, emptyCircuit) { QuantumComputation qc(1); - qc::CircuitOptimizer::collectBlocks(qc, 1); + qc::CircuitOptimizer::collectBlocks(qc, 1, false); + EXPECT_EQ(qc.getNindividualOps(), 0); +} + +TEST(CollectBlocks, emptyCliffordCircuit) { + QuantumComputation qc(1); + qc::CircuitOptimizer::collectBlocks(qc, 1, true); EXPECT_EQ(qc.getNindividualOps(), 0); } @@ -24,7 +30,17 @@ TEST(CollectBlocks, singleGate) { QuantumComputation qc(1); qc.h(0); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 1); + qc::CircuitOptimizer::collectBlocks(qc, 1,false); + std::cout << qc << "\n"; + EXPECT_EQ(qc.size(), 1); + EXPECT_TRUE(qc.front()->isStandardOperation()); +} + +TEST(CollectBlocks, singleCliffordGate) { + QuantumComputation qc(1); + qc.t(0); + std::cout << qc << "\n"; + qc::CircuitOptimizer::collectBlocks(qc, 1,true); std::cout << qc << "\n"; EXPECT_EQ(qc.size(), 1); EXPECT_TRUE(qc.front()->isStandardOperation()); @@ -37,7 +53,56 @@ TEST(CollectBlocks, collectMultipleSingleQubitGates) { qc.x(0); qc.x(1); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 1); + qc::CircuitOptimizer::collectBlocks(qc, 1, false); + std::cout << qc << "\n"; + EXPECT_EQ(qc.size(), 2); + EXPECT_TRUE(qc.front()->isCompoundOperation()); + EXPECT_TRUE(qc.back()->isCompoundOperation()); +} + +TEST(CollectBlocks, collectMultipleSingleQubitCliffordGates) { + QuantumComputation qc(2); + qc.h(0); + qc.h(1); + qc.t(0); + qc.t(1); + qc.x(0); + qc.x(1); + std::cout << qc << "\n"; + qc::CircuitOptimizer::collectBlocks(qc, 1, true); + std::cout << qc << "\n"; + EXPECT_EQ(qc.size(), 2); + EXPECT_TRUE(qc.front()->isCompoundOperation()); + EXPECT_TRUE(qc.back()->isCompoundOperation()); +} + +TEST(CollectBlocks, collectMultipleCliffordGates) { + QuantumComputation qc(2); + qc.h(0); + qc.h(1); + qc.t(0); + //qc.t(1); + qc.x(0); + qc.x(1); + std::cout << qc << "\n"; + qc::CircuitOptimizer::collectBlocks(qc, 2, true); + std::cout << qc << "\n"; + EXPECT_EQ(qc.size(), 2); + EXPECT_TRUE(qc.front()->isCompoundOperation()); + EXPECT_TRUE(qc.back()->isCompoundOperation()); +} + +TEST(CollectBlocks, collectTwoQubitCliffordGates) { + QuantumComputation qc(2); + qc.h(0); + qc.h(1); + qc.cx(0,1); + qc.t(0); + //qc.t(1); + qc.x(0); + qc.x(1); + std::cout << qc << "\n"; + qc::CircuitOptimizer::collectBlocks(qc, 2, true); std::cout << qc << "\n"; EXPECT_EQ(qc.size(), 2); EXPECT_TRUE(qc.front()->isCompoundOperation()); @@ -50,7 +115,7 @@ TEST(CollectBlocks, mergeBlocks) { qc.h(1); qc.cx(0, 1); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 2); + qc::CircuitOptimizer::collectBlocks(qc, 2,false); std::cout << qc << "\n"; EXPECT_EQ(qc.size(), 1); EXPECT_TRUE(qc.front()->isCompoundOperation()); @@ -65,7 +130,7 @@ TEST(CollectBlocks, mergeBlocks2) { qc.z(0); qc.cx(0, 1); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 2); + qc::CircuitOptimizer::collectBlocks(qc, 2,false); std::cout << qc << "\n"; EXPECT_EQ(qc.size(), 1); EXPECT_TRUE(qc.front()->isCompoundOperation()); @@ -77,7 +142,7 @@ TEST(CollectBlocks, addToMultiQubitBlock) { qc.cx(0, 1); qc.cz(0, 1); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 2); + qc::CircuitOptimizer::collectBlocks(qc, 2,false); std::cout << qc << "\n"; EXPECT_EQ(qc.size(), 1); EXPECT_TRUE(qc.front()->isCompoundOperation()); @@ -90,7 +155,7 @@ TEST(CollectBlocks, gateTooBig) { qc.h(1); qc.mcx({0, 1}, 2); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 2); + qc::CircuitOptimizer::collectBlocks(qc, 2,false); std::cout << qc << "\n"; EXPECT_EQ(qc.size(), 2); EXPECT_TRUE(qc.front()->isCompoundOperation()); @@ -103,7 +168,7 @@ TEST(CollectBlocks, gateTooBig2) { qc.h(1); qc.mcx({0, 1}, 2); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 1); + qc::CircuitOptimizer::collectBlocks(qc, 1,false); std::cout << qc << "\n"; EXPECT_EQ(qc.size(), 3); EXPECT_TRUE(qc.front()->isStandardOperation()); @@ -117,7 +182,7 @@ TEST(CollectBlocks, gateTooBig3) { qc.h(4); qc.mcx({0, 1, 2, 3}, 4); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 3); + qc::CircuitOptimizer::collectBlocks(qc, 3,false); std::cout << qc << "\n"; EXPECT_EQ(qc.size(), 3); EXPECT_TRUE(qc.back()->isStandardOperation()); @@ -129,7 +194,7 @@ TEST(CollectBlocks, endingBlocks) { qc.cx(1, 2); qc.cx(0, 1); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 2); + qc::CircuitOptimizer::collectBlocks(qc, 2,false); std::cout << qc << "\n"; EXPECT_EQ(qc.size(), 2); EXPECT_TRUE(qc.front()->isStandardOperation()); @@ -142,7 +207,7 @@ TEST(CollectBlocks, endingBlocks2) { qc.cx(1, 2); qc.mcx({0, 1}, 3); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 3); + qc::CircuitOptimizer::collectBlocks(qc, 3,false); std::cout << qc << "\n"; EXPECT_EQ(qc.size(), 2); EXPECT_TRUE(qc.front()->isCompoundOperation()); @@ -155,7 +220,7 @@ TEST(CollectBlocks, interruptBlock) { qc.reset(0); qc.h(0); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 2); + qc::CircuitOptimizer::collectBlocks(qc, 2,false); std::cout << qc << "\n"; EXPECT_EQ(qc.size(), 3); EXPECT_TRUE(qc.front()->isStandardOperation()); @@ -167,7 +232,7 @@ TEST(CollectBlocks, unprocessableAtBegin) { qc.reset(0); qc.h(0); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 1); + qc::CircuitOptimizer::collectBlocks(qc, 1,false); std::cout << qc << "\n"; EXPECT_EQ(qc.size(), 2); EXPECT_TRUE(qc.front()->isNonUnitaryOperation()); @@ -181,7 +246,7 @@ TEST(CollectBlocks, handleCompoundOperation) { qc.emplace_back(op.asCompoundOperation()); qc.x(1); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 1); + qc::CircuitOptimizer::collectBlocks(qc, 1,false); std::cout << qc << "\n"; EXPECT_EQ(qc.size(), 2); EXPECT_TRUE(qc.front()->isStandardOperation()); @@ -196,7 +261,7 @@ TEST(CollectBlocks, handleCompoundOperation2) { qc.emplace_back(op.asCompoundOperation()); qc.x(0); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 1); + qc::CircuitOptimizer::collectBlocks(qc, 1,false); std::cout << qc << "\n"; EXPECT_EQ(qc.size(), 1); EXPECT_TRUE(qc.front()->isCompoundOperation()); From 62004e51746275c2567c0b83f41aea8e8bd79ba3 Mon Sep 17 00:00:00 2001 From: "jannik.pflieger" Date: Fri, 21 Mar 2025 13:52:30 +0100 Subject: [PATCH 05/21] fixed Testcases --- test/circuit_optimizer/test_collect_blocks.cpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/test/circuit_optimizer/test_collect_blocks.cpp b/test/circuit_optimizer/test_collect_blocks.cpp index 9277e174d..72a4ab9a2 100644 --- a/test/circuit_optimizer/test_collect_blocks.cpp +++ b/test/circuit_optimizer/test_collect_blocks.cpp @@ -71,9 +71,7 @@ TEST(CollectBlocks, collectMultipleSingleQubitCliffordGates) { std::cout << qc << "\n"; qc::CircuitOptimizer::collectBlocks(qc, 1, true); std::cout << qc << "\n"; - EXPECT_EQ(qc.size(), 2); - EXPECT_TRUE(qc.front()->isCompoundOperation()); - EXPECT_TRUE(qc.back()->isCompoundOperation()); + EXPECT_EQ(qc.size(), 6); } TEST(CollectBlocks, collectMultipleCliffordGates) { @@ -81,15 +79,13 @@ TEST(CollectBlocks, collectMultipleCliffordGates) { qc.h(0); qc.h(1); qc.t(0); - //qc.t(1); qc.x(0); qc.x(1); std::cout << qc << "\n"; qc::CircuitOptimizer::collectBlocks(qc, 2, true); std::cout << qc << "\n"; - EXPECT_EQ(qc.size(), 2); + EXPECT_EQ(qc.size(), 4); EXPECT_TRUE(qc.front()->isCompoundOperation()); - EXPECT_TRUE(qc.back()->isCompoundOperation()); } TEST(CollectBlocks, collectTwoQubitCliffordGates) { @@ -104,9 +100,8 @@ TEST(CollectBlocks, collectTwoQubitCliffordGates) { std::cout << qc << "\n"; qc::CircuitOptimizer::collectBlocks(qc, 2, true); std::cout << qc << "\n"; - EXPECT_EQ(qc.size(), 2); + EXPECT_EQ(qc.size(), 4); EXPECT_TRUE(qc.front()->isCompoundOperation()); - EXPECT_TRUE(qc.back()->isCompoundOperation()); } TEST(CollectBlocks, mergeBlocks) { From 16560467e8d405dc538691945545b4aa9244df4e Mon Sep 17 00:00:00 2001 From: Jannik Pflieger <56534984+jannikpflieger@users.noreply.github.com> Date: Fri, 21 Mar 2025 14:22:09 +0100 Subject: [PATCH 06/21] Update ci.yml Signed-off-by: Jannik Pflieger <56534984+jannikpflieger@users.noreply.github.com> --- .github/workflows/ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 293eae4e6..879a9218a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,6 +7,10 @@ on: merge_group: workflow_dispatch: +permissions: + contents: read + id-token: write + concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true From 8c811bdd54bfabf241d8a5e1abd7b7d926ba9283 Mon Sep 17 00:00:00 2001 From: "jannik.pflieger" Date: Fri, 21 Mar 2025 14:24:46 +0100 Subject: [PATCH 07/21] Update ci.yaml again --- .github/workflows/ci.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 879a9218a..293eae4e6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,10 +7,6 @@ on: merge_group: workflow_dispatch: -permissions: - contents: read - id-token: write - concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true From d9d2132c111fcf772a5bd433b05af248eecf228a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 24 Mar 2025 07:54:14 +0000 Subject: [PATCH 08/21] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../circuit_optimizer/CircuitOptimizer.hpp | 3 +- include/mqt-core/ir/operations/Operation.hpp | 62 +++++++++---------- src/circuit_optimizer/CircuitOptimizer.cpp | 5 +- .../circuit_optimizer/test_collect_blocks.cpp | 32 +++++----- 4 files changed, 52 insertions(+), 50 deletions(-) diff --git a/include/mqt-core/circuit_optimizer/CircuitOptimizer.hpp b/include/mqt-core/circuit_optimizer/CircuitOptimizer.hpp index 264ba6996..2fcc3f612 100644 --- a/include/mqt-core/circuit_optimizer/CircuitOptimizer.hpp +++ b/include/mqt-core/circuit_optimizer/CircuitOptimizer.hpp @@ -94,7 +94,8 @@ class CircuitOptimizer { * @param qc the quantum circuit * @param maxBlockSize the maximum size of a block */ - static void collectBlocks(QuantumComputation& qc, std::size_t maxBlockSize, bool collectCliffords); + static void collectBlocks(QuantumComputation& qc, std::size_t maxBlockSize, + bool collectCliffords); /** * @brief Elide permutations by propagating them through the circuit. diff --git a/include/mqt-core/ir/operations/Operation.hpp b/include/mqt-core/ir/operations/Operation.hpp index e50eb2006..b31c4ae7c 100644 --- a/include/mqt-core/ir/operations/Operation.hpp +++ b/include/mqt-core/ir/operations/Operation.hpp @@ -21,8 +21,8 @@ #include #include #include -#include #include +#include namespace qc { class Operation { @@ -160,39 +160,39 @@ class Operation { bool controlled = this->isControlled(); std::size_t number_of_controls = this->getNcontrols(); switch (opType) { - case I: - case X: - if ((controlled) && ((number_of_controls >= 2))){ - return false; - }else{ - return true; - } - case Y: - if ((controlled) && ((number_of_controls >= 2))){ - return false; - }else{ - return true; - } - case Z: - if ((controlled) && ((number_of_controls >= 2))){ - return false; - }else{ - return true; - } - case H: - case S: - case Sdg: - case SX: - case SXdg: - case DCX: - case SWAP: - case iSWAP: - case ECR: + case I: + case X: + if ((controlled) && ((number_of_controls >= 2))) { + return false; + } else { + return true; + } + case Y: + if ((controlled) && ((number_of_controls >= 2))) { + return false; + } else { return true; - default: + } + case Z: + if ((controlled) && ((number_of_controls >= 2))) { return false; + } else { + return true; } -} + case H: + case S: + case Sdg: + case SX: + case SXdg: + case DCX: + case SWAP: + case iSWAP: + case ECR: + return true; + default: + return false; + } + } /** * @brief Checks whether a gate is global. diff --git a/src/circuit_optimizer/CircuitOptimizer.cpp b/src/circuit_optimizer/CircuitOptimizer.cpp index a7fe100a1..a883b014c 100644 --- a/src/circuit_optimizer/CircuitOptimizer.cpp +++ b/src/circuit_optimizer/CircuitOptimizer.cpp @@ -1425,7 +1425,8 @@ struct DSU { }; void CircuitOptimizer::collectBlocks(QuantumComputation& qc, - const std::size_t maxBlockSize, bool collectCliffords) { + const std::size_t maxBlockSize, + bool collectCliffords) { if (qc.size() <= 1) { return; } @@ -1452,7 +1453,7 @@ void CircuitOptimizer::collectBlocks(QuantumComputation& qc, isClifford = true; } - if (collectCliffords && !isClifford){ + if (collectCliffords && !isClifford) { canProcess = false; } diff --git a/test/circuit_optimizer/test_collect_blocks.cpp b/test/circuit_optimizer/test_collect_blocks.cpp index 72a4ab9a2..c40c87286 100644 --- a/test/circuit_optimizer/test_collect_blocks.cpp +++ b/test/circuit_optimizer/test_collect_blocks.cpp @@ -30,7 +30,7 @@ TEST(CollectBlocks, singleGate) { QuantumComputation qc(1); qc.h(0); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 1,false); + qc::CircuitOptimizer::collectBlocks(qc, 1, false); std::cout << qc << "\n"; EXPECT_EQ(qc.size(), 1); EXPECT_TRUE(qc.front()->isStandardOperation()); @@ -40,7 +40,7 @@ TEST(CollectBlocks, singleCliffordGate) { QuantumComputation qc(1); qc.t(0); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 1,true); + qc::CircuitOptimizer::collectBlocks(qc, 1, true); std::cout << qc << "\n"; EXPECT_EQ(qc.size(), 1); EXPECT_TRUE(qc.front()->isStandardOperation()); @@ -92,9 +92,9 @@ TEST(CollectBlocks, collectTwoQubitCliffordGates) { QuantumComputation qc(2); qc.h(0); qc.h(1); - qc.cx(0,1); + qc.cx(0, 1); qc.t(0); - //qc.t(1); + // qc.t(1); qc.x(0); qc.x(1); std::cout << qc << "\n"; @@ -110,7 +110,7 @@ TEST(CollectBlocks, mergeBlocks) { qc.h(1); qc.cx(0, 1); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 2,false); + qc::CircuitOptimizer::collectBlocks(qc, 2, false); std::cout << qc << "\n"; EXPECT_EQ(qc.size(), 1); EXPECT_TRUE(qc.front()->isCompoundOperation()); @@ -125,7 +125,7 @@ TEST(CollectBlocks, mergeBlocks2) { qc.z(0); qc.cx(0, 1); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 2,false); + qc::CircuitOptimizer::collectBlocks(qc, 2, false); std::cout << qc << "\n"; EXPECT_EQ(qc.size(), 1); EXPECT_TRUE(qc.front()->isCompoundOperation()); @@ -137,7 +137,7 @@ TEST(CollectBlocks, addToMultiQubitBlock) { qc.cx(0, 1); qc.cz(0, 1); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 2,false); + qc::CircuitOptimizer::collectBlocks(qc, 2, false); std::cout << qc << "\n"; EXPECT_EQ(qc.size(), 1); EXPECT_TRUE(qc.front()->isCompoundOperation()); @@ -150,7 +150,7 @@ TEST(CollectBlocks, gateTooBig) { qc.h(1); qc.mcx({0, 1}, 2); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 2,false); + qc::CircuitOptimizer::collectBlocks(qc, 2, false); std::cout << qc << "\n"; EXPECT_EQ(qc.size(), 2); EXPECT_TRUE(qc.front()->isCompoundOperation()); @@ -163,7 +163,7 @@ TEST(CollectBlocks, gateTooBig2) { qc.h(1); qc.mcx({0, 1}, 2); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 1,false); + qc::CircuitOptimizer::collectBlocks(qc, 1, false); std::cout << qc << "\n"; EXPECT_EQ(qc.size(), 3); EXPECT_TRUE(qc.front()->isStandardOperation()); @@ -177,7 +177,7 @@ TEST(CollectBlocks, gateTooBig3) { qc.h(4); qc.mcx({0, 1, 2, 3}, 4); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 3,false); + qc::CircuitOptimizer::collectBlocks(qc, 3, false); std::cout << qc << "\n"; EXPECT_EQ(qc.size(), 3); EXPECT_TRUE(qc.back()->isStandardOperation()); @@ -189,7 +189,7 @@ TEST(CollectBlocks, endingBlocks) { qc.cx(1, 2); qc.cx(0, 1); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 2,false); + qc::CircuitOptimizer::collectBlocks(qc, 2, false); std::cout << qc << "\n"; EXPECT_EQ(qc.size(), 2); EXPECT_TRUE(qc.front()->isStandardOperation()); @@ -202,7 +202,7 @@ TEST(CollectBlocks, endingBlocks2) { qc.cx(1, 2); qc.mcx({0, 1}, 3); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 3,false); + qc::CircuitOptimizer::collectBlocks(qc, 3, false); std::cout << qc << "\n"; EXPECT_EQ(qc.size(), 2); EXPECT_TRUE(qc.front()->isCompoundOperation()); @@ -215,7 +215,7 @@ TEST(CollectBlocks, interruptBlock) { qc.reset(0); qc.h(0); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 2,false); + qc::CircuitOptimizer::collectBlocks(qc, 2, false); std::cout << qc << "\n"; EXPECT_EQ(qc.size(), 3); EXPECT_TRUE(qc.front()->isStandardOperation()); @@ -227,7 +227,7 @@ TEST(CollectBlocks, unprocessableAtBegin) { qc.reset(0); qc.h(0); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 1,false); + qc::CircuitOptimizer::collectBlocks(qc, 1, false); std::cout << qc << "\n"; EXPECT_EQ(qc.size(), 2); EXPECT_TRUE(qc.front()->isNonUnitaryOperation()); @@ -241,7 +241,7 @@ TEST(CollectBlocks, handleCompoundOperation) { qc.emplace_back(op.asCompoundOperation()); qc.x(1); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 1,false); + qc::CircuitOptimizer::collectBlocks(qc, 1, false); std::cout << qc << "\n"; EXPECT_EQ(qc.size(), 2); EXPECT_TRUE(qc.front()->isStandardOperation()); @@ -256,7 +256,7 @@ TEST(CollectBlocks, handleCompoundOperation2) { qc.emplace_back(op.asCompoundOperation()); qc.x(0); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 1,false); + qc::CircuitOptimizer::collectBlocks(qc, 1, false); std::cout << qc << "\n"; EXPECT_EQ(qc.size(), 1); EXPECT_TRUE(qc.front()->isCompoundOperation()); From 3282c6783e6e3a4ee3fddebb73bb65f0ae248604 Mon Sep 17 00:00:00 2001 From: "jannik.pflieger" Date: Mon, 24 Mar 2025 16:46:55 +0100 Subject: [PATCH 09/21] more Test Coverage and fix linting errors --- include/mqt-core/ir/operations/Operation.hpp | 25 ++++--------- test/ir/test_operation.cpp | 38 ++++++++++++++++++++ 2 files changed, 44 insertions(+), 19 deletions(-) diff --git a/include/mqt-core/ir/operations/Operation.hpp b/include/mqt-core/ir/operations/Operation.hpp index b31c4ae7c..7fa4e8d3c 100644 --- a/include/mqt-core/ir/operations/Operation.hpp +++ b/include/mqt-core/ir/operations/Operation.hpp @@ -21,7 +21,6 @@ #include #include #include -#include #include namespace qc { @@ -156,29 +155,17 @@ class Operation { [[nodiscard]] virtual bool isControlled() const { return !controls.empty(); } [[nodiscard]] virtual bool isClifford() const { - OpType opType = this->getType(); - bool controlled = this->isControlled(); - std::size_t number_of_controls = this->getNcontrols(); + const OpType opType = this->getType(); + const bool controlled = this->isControlled(); + const std::size_t numberOfControls = this->getNcontrols(); + if ((controlled) && ((numberOfControls >= 2))) { + return false; + } switch (opType) { case I: case X: - if ((controlled) && ((number_of_controls >= 2))) { - return false; - } else { - return true; - } case Y: - if ((controlled) && ((number_of_controls >= 2))) { - return false; - } else { - return true; - } case Z: - if ((controlled) && ((number_of_controls >= 2))) { - return false; - } else { - return true; - } case H: case S: case Sdg: diff --git a/test/ir/test_operation.cpp b/test/ir/test_operation.cpp index 5ffda4613..d7dc4210e 100644 --- a/test/ir/test_operation.cpp +++ b/test/ir/test_operation.cpp @@ -147,6 +147,44 @@ TEST(Operation, IsIndividualGate) { EXPECT_FALSE(op3.isSingleQubitGate()); } +TEST(Operation, IsClifford) { + const qc::StandardOperation x(0, qc::X); + EXPECT_TRUE(x.isClifford()); + const qc::StandardOperation cx(0, 1, qc::X); + EXPECT_TRUE(cx.isClifford()); + const qc::StandardOperation y(0, 1, qc::Y); + EXPECT_TRUE(y.isClifford()); + const qc::StandardOperation z(0, 1, qc::Z); + EXPECT_TRUE(z.isClifford()); + const qc::StandardOperation t(0, qc::T); + EXPECT_FALSE(t.isClifford()); + qc::Controls controls = {qc::Control(0), qc::Control(1)}; + const qc::StandardOperation ccx(controls, 2, qc::X); + EXPECT_FALSE(ccx.isClifford()); + const qc::StandardOperation ccy(controls, 2, qc::Y); + EXPECT_FALSE(ccy.isClifford()); + const qc::StandardOperation ccz(controls, 2, qc::Z); + EXPECT_FALSE(ccz.isClifford()); + const qc::StandardOperation h(0, qc::H); + EXPECT_TRUE(h.isClifford()); + const qc::StandardOperation s(0, qc::S); + EXPECT_TRUE(s.isClifford()); + const qc::StandardOperation sdg(0, qc::Sdg); + EXPECT_TRUE(sdg.isClifford()); + const qc::StandardOperation sx(0, qc::SX); + EXPECT_TRUE(sx.isClifford()); + const qc::StandardOperation sxdg(0, qc::SXdg); + EXPECT_TRUE(sxdg.isClifford()); + const qc::StandardOperation dcx(0, 1, qc::DCX); + EXPECT_TRUE(dcx.isClifford()); + const qc::StandardOperation swap(0, 1, qc::SWAP); + EXPECT_TRUE(swap.isClifford()); + const qc::StandardOperation iswap(0, 1, qc::iSWAP); + EXPECT_TRUE(iswap.isClifford()); + const qc::StandardOperation ecr(0, 1, qc::ECR); + EXPECT_TRUE(ecr.isClifford()); +} + TEST(Operation, IsDiagonalGate) { const qc::StandardOperation op1(0, qc::X); EXPECT_FALSE(op1.isDiagonalGate()); From 088ada517087d092f1f3d5bc06a2b6005bdaafb8 Mon Sep 17 00:00:00 2001 From: "jannik.pflieger" Date: Mon, 24 Mar 2025 16:49:26 +0100 Subject: [PATCH 10/21] removed outcommented code --- test/circuit_optimizer/test_collect_blocks.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/test/circuit_optimizer/test_collect_blocks.cpp b/test/circuit_optimizer/test_collect_blocks.cpp index c40c87286..b44738259 100644 --- a/test/circuit_optimizer/test_collect_blocks.cpp +++ b/test/circuit_optimizer/test_collect_blocks.cpp @@ -94,7 +94,6 @@ TEST(CollectBlocks, collectTwoQubitCliffordGates) { qc.h(1); qc.cx(0, 1); qc.t(0); - // qc.t(1); qc.x(0); qc.x(1); std::cout << qc << "\n"; From 486e225adf3c1bba3e3cde1b542c3c803111ff37 Mon Sep 17 00:00:00 2001 From: "jannik.pflieger" Date: Mon, 24 Mar 2025 16:59:55 +0100 Subject: [PATCH 11/21] Added import and fixed variable const --- test/ir/test_operation.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/ir/test_operation.cpp b/test/ir/test_operation.cpp index 392a276d1..0e197ab3a 100644 --- a/test/ir/test_operation.cpp +++ b/test/ir/test_operation.cpp @@ -13,6 +13,7 @@ #include "ir/Register.hpp" #include "ir/operations/AodOperation.hpp" #include "ir/operations/CompoundOperation.hpp" +#include "ir/operations/Control.hpp" #include "ir/operations/Expression.hpp" #include "ir/operations/NonUnitaryOperation.hpp" #include "ir/operations/OpType.hpp" @@ -158,7 +159,7 @@ TEST(Operation, IsClifford) { EXPECT_TRUE(z.isClifford()); const qc::StandardOperation t(0, qc::T); EXPECT_FALSE(t.isClifford()); - qc::Controls controls = {qc::Control(0), qc::Control(1)}; + const qc::Controls controls = {qc::Control(0), qc::Control(1)}; const qc::StandardOperation ccx(controls, 2, qc::X); EXPECT_FALSE(ccx.isClifford()); const qc::StandardOperation ccy(controls, 2, qc::Y); From e1ffb253b1698ef9f52e6dcaae0aa81c91c55edf Mon Sep 17 00:00:00 2001 From: "jannik.pflieger" Date: Tue, 29 Apr 2025 06:07:48 +0200 Subject: [PATCH 12/21] changed parameter name and added docstring --- include/mqt-core/circuit_optimizer/CircuitOptimizer.hpp | 3 ++- src/circuit_optimizer/CircuitOptimizer.cpp | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/mqt-core/circuit_optimizer/CircuitOptimizer.hpp b/include/mqt-core/circuit_optimizer/CircuitOptimizer.hpp index 23106ca4d..c9a0c29ab 100644 --- a/include/mqt-core/circuit_optimizer/CircuitOptimizer.hpp +++ b/include/mqt-core/circuit_optimizer/CircuitOptimizer.hpp @@ -89,9 +89,10 @@ class CircuitOptimizer { * gates and fusing single-qubit gates. * @param qc the quantum circuit * @param maxBlockSize the maximum size of a block + * @param onlyCollectCliffords whether to collect only Clifford operations within a block, non-Clifford operations are a single block */ static void collectBlocks(QuantumComputation& qc, std::size_t maxBlockSize, - bool collectCliffords); + bool onlyCollectCliffords); /** * @brief Elide permutations by propagating them through the circuit. diff --git a/src/circuit_optimizer/CircuitOptimizer.cpp b/src/circuit_optimizer/CircuitOptimizer.cpp index c6cdefd67..fa2690d69 100644 --- a/src/circuit_optimizer/CircuitOptimizer.cpp +++ b/src/circuit_optimizer/CircuitOptimizer.cpp @@ -1418,7 +1418,7 @@ struct DSU { void CircuitOptimizer::collectBlocks(QuantumComputation& qc, const std::size_t maxBlockSize, - bool collectCliffords) { + bool onlyCollectCliffords = false) { if (qc.size() <= 1) { return; } @@ -1441,11 +1441,11 @@ void CircuitOptimizer::collectBlocks(QuantumComputation& qc, } // check if the operation is a Clifford operation - if (collectCliffords && op->isClifford()) { + if (onlyCollectCliffords && op->isClifford()) { isClifford = true; } - if (collectCliffords && !isClifford) { + if (onlyCollectCliffords && !isClifford) { canProcess = false; } From d7264a0e1ef4baa7b94dad3ecc9bb390634edb40 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 29 Apr 2025 04:10:21 +0000 Subject: [PATCH 13/21] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/mqt-core/circuit_optimizer/CircuitOptimizer.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/mqt-core/circuit_optimizer/CircuitOptimizer.hpp b/include/mqt-core/circuit_optimizer/CircuitOptimizer.hpp index 588c2b85f..f01d7eebb 100644 --- a/include/mqt-core/circuit_optimizer/CircuitOptimizer.hpp +++ b/include/mqt-core/circuit_optimizer/CircuitOptimizer.hpp @@ -90,7 +90,8 @@ class CircuitOptimizer { * gates and fusing single-qubit gates. * @param qc the quantum circuit * @param maxBlockSize the maximum size of a block - * @param onlyCollectCliffords whether to collect only Clifford operations within a block, non-Clifford operations are a single block + * @param onlyCollectCliffords whether to collect only Clifford operations + * within a block, non-Clifford operations are a single block */ static void collectBlocks(QuantumComputation& qc, std::size_t maxBlockSize, bool onlyCollectCliffords); From a12f11a32a51660adba3c2f7677ab86df5924c38 Mon Sep 17 00:00:00 2001 From: "jannik.pflieger" Date: Tue, 29 Apr 2025 06:49:28 +0200 Subject: [PATCH 14/21] reverted original tests back to normal, changed function header of collect blocks, changed isClifford function, added docstring --- .../circuit_optimizer/CircuitOptimizer.hpp | 2 +- include/mqt-core/ir/operations/OpType.hpp | 3 ++ include/mqt-core/ir/operations/Operation.hpp | 23 +++++++--- src/circuit_optimizer/CircuitOptimizer.cpp | 13 +----- .../circuit_optimizer/test_collect_blocks.cpp | 44 +++++++------------ 5 files changed, 38 insertions(+), 47 deletions(-) diff --git a/include/mqt-core/circuit_optimizer/CircuitOptimizer.hpp b/include/mqt-core/circuit_optimizer/CircuitOptimizer.hpp index 588c2b85f..571f06f5f 100644 --- a/include/mqt-core/circuit_optimizer/CircuitOptimizer.hpp +++ b/include/mqt-core/circuit_optimizer/CircuitOptimizer.hpp @@ -93,7 +93,7 @@ class CircuitOptimizer { * @param onlyCollectCliffords whether to collect only Clifford operations within a block, non-Clifford operations are a single block */ static void collectBlocks(QuantumComputation& qc, std::size_t maxBlockSize, - bool onlyCollectCliffords); + bool onlyCollectCliffords = false); /** * @brief Elide permutations by propagating them through the circuit. diff --git a/include/mqt-core/ir/operations/OpType.hpp b/include/mqt-core/ir/operations/OpType.hpp index aa6b829d6..30ff8f98a 100644 --- a/include/mqt-core/ir/operations/OpType.hpp +++ b/include/mqt-core/ir/operations/OpType.hpp @@ -66,6 +66,9 @@ std::string shortName(OpType opType); } } +/** + * @brief Checks if given OpType is a single qubit gate + */ [[nodiscard]] constexpr bool isSingleQubitGate(const OpType type) { switch (type) { case I: diff --git a/include/mqt-core/ir/operations/Operation.hpp b/include/mqt-core/ir/operations/Operation.hpp index 1614f8133..179494983 100644 --- a/include/mqt-core/ir/operations/Operation.hpp +++ b/include/mqt-core/ir/operations/Operation.hpp @@ -155,18 +155,29 @@ class Operation { [[nodiscard]] virtual bool isControlled() const { return !controls.empty(); } + /** + * @brief Checks whether a gate is a Clifford gate. + * @details + */ [[nodiscard]] virtual bool isClifford() const { - const OpType opType = this->getType(); - const bool controlled = this->isControlled(); - const std::size_t numberOfControls = this->getNcontrols(); - if ((controlled) && ((numberOfControls >= 2))) { - return false; - } + const OpType opType = getType(); + const bool controlled = isControlled(); + const std::size_t numberOfControls = getNcontrols(); + switch (opType) { case I: case X: + if ((controlled) && ((numberOfControls >= 2))) { + return false; + } case Y: + if ((controlled) && ((numberOfControls >= 2))) { + return false; + } case Z: + if ((controlled) && ((numberOfControls >= 2))) { + return false; + } case H: case S: case Sdg: diff --git a/src/circuit_optimizer/CircuitOptimizer.cpp b/src/circuit_optimizer/CircuitOptimizer.cpp index 136da27db..28f05c656 100644 --- a/src/circuit_optimizer/CircuitOptimizer.cpp +++ b/src/circuit_optimizer/CircuitOptimizer.cpp @@ -1436,17 +1436,8 @@ void CircuitOptimizer::collectBlocks(QuantumComputation& qc, bool makesTooBig = false; bool isClifford = false; - // check if the operation can be processed - if (!op->isUnitary()) { - canProcess = false; - } - - // check if the operation is a Clifford operation - if (onlyCollectCliffords && op->isClifford()) { - isClifford = true; - } - - if (onlyCollectCliffords && !isClifford) { + // check whether the operation is a Clifford operation + if (!op->isUnitary() || (onlyCollectCliffords && !op->isClifford())) { canProcess = false; } diff --git a/test/circuit_optimizer/test_collect_blocks.cpp b/test/circuit_optimizer/test_collect_blocks.cpp index 26d10d7f7..976210e9b 100644 --- a/test/circuit_optimizer/test_collect_blocks.cpp +++ b/test/circuit_optimizer/test_collect_blocks.cpp @@ -17,35 +17,21 @@ namespace qc { TEST(CollectBlocks, emptyCircuit) { QuantumComputation qc(1); - qc::CircuitOptimizer::collectBlocks(qc, 1, false); + qc::CircuitOptimizer::collectBlocks(qc, 1); EXPECT_EQ(qc.getNindividualOps(), 0); } -TEST(CollectBlocks, emptyCliffordCircuit) { - QuantumComputation qc(1); - qc::CircuitOptimizer::collectBlocks(qc, 1, true); - EXPECT_EQ(qc.getNindividualOps(), 0); -} TEST(CollectBlocks, singleGate) { QuantumComputation qc(1); qc.h(0); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 1, false); + qc::CircuitOptimizer::collectBlocks(qc, 1); std::cout << qc << "\n"; EXPECT_EQ(qc.size(), 1); EXPECT_TRUE(qc.front()->isStandardOperation()); } -TEST(CollectBlocks, singleCliffordGate) { - QuantumComputation qc(1); - qc.t(0); - std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 1, true); - std::cout << qc << "\n"; - EXPECT_EQ(qc.size(), 1); - EXPECT_TRUE(qc.front()->isStandardOperation()); -} TEST(CollectBlocks, collectMultipleSingleQubitGates) { QuantumComputation qc(2); @@ -54,7 +40,7 @@ TEST(CollectBlocks, collectMultipleSingleQubitGates) { qc.x(0); qc.x(1); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 1, false); + qc::CircuitOptimizer::collectBlocks(qc, 1); std::cout << qc << "\n"; EXPECT_EQ(qc.size(), 2); EXPECT_TRUE(qc.front()->isCompoundOperation()); @@ -110,7 +96,7 @@ TEST(CollectBlocks, mergeBlocks) { qc.h(1); qc.cx(0, 1); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 2, false); + qc::CircuitOptimizer::collectBlocks(qc, 2); std::cout << qc << "\n"; EXPECT_EQ(qc.size(), 1); EXPECT_TRUE(qc.front()->isCompoundOperation()); @@ -125,7 +111,7 @@ TEST(CollectBlocks, mergeBlocks2) { qc.z(0); qc.cx(0, 1); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 2, false); + qc::CircuitOptimizer::collectBlocks(qc, 2); std::cout << qc << "\n"; EXPECT_EQ(qc.size(), 1); EXPECT_TRUE(qc.front()->isCompoundOperation()); @@ -137,7 +123,7 @@ TEST(CollectBlocks, addToMultiQubitBlock) { qc.cx(0, 1); qc.cz(0, 1); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 2, false); + qc::CircuitOptimizer::collectBlocks(qc, 2); std::cout << qc << "\n"; EXPECT_EQ(qc.size(), 1); EXPECT_TRUE(qc.front()->isCompoundOperation()); @@ -150,7 +136,7 @@ TEST(CollectBlocks, gateTooBig) { qc.h(1); qc.mcx({0, 1}, 2); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 2, false); + qc::CircuitOptimizer::collectBlocks(qc, 2); std::cout << qc << "\n"; EXPECT_EQ(qc.size(), 2); EXPECT_TRUE(qc.front()->isCompoundOperation()); @@ -163,7 +149,7 @@ TEST(CollectBlocks, gateTooBig2) { qc.h(1); qc.mcx({0, 1}, 2); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 1, false); + qc::CircuitOptimizer::collectBlocks(qc, 1); std::cout << qc << "\n"; EXPECT_EQ(qc.size(), 3); EXPECT_TRUE(qc.front()->isStandardOperation()); @@ -177,7 +163,7 @@ TEST(CollectBlocks, gateTooBig3) { qc.h(4); qc.mcx({0, 1, 2, 3}, 4); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 3, false); + qc::CircuitOptimizer::collectBlocks(qc, 3); std::cout << qc << "\n"; EXPECT_EQ(qc.size(), 3); EXPECT_TRUE(qc.back()->isStandardOperation()); @@ -189,7 +175,7 @@ TEST(CollectBlocks, endingBlocks) { qc.cx(1, 2); qc.cx(0, 1); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 2, false); + qc::CircuitOptimizer::collectBlocks(qc, 2); std::cout << qc << "\n"; EXPECT_EQ(qc.size(), 2); EXPECT_TRUE(qc.front()->isStandardOperation()); @@ -202,7 +188,7 @@ TEST(CollectBlocks, endingBlocks2) { qc.cx(1, 2); qc.mcx({0, 1}, 3); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 3, false); + qc::CircuitOptimizer::collectBlocks(qc, 3); std::cout << qc << "\n"; EXPECT_EQ(qc.size(), 2); EXPECT_TRUE(qc.front()->isCompoundOperation()); @@ -215,7 +201,7 @@ TEST(CollectBlocks, interruptBlock) { qc.reset(0); qc.h(0); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 2, false); + qc::CircuitOptimizer::collectBlocks(qc, 2); std::cout << qc << "\n"; EXPECT_EQ(qc.size(), 3); EXPECT_TRUE(qc.front()->isStandardOperation()); @@ -227,7 +213,7 @@ TEST(CollectBlocks, unprocessableAtBegin) { qc.reset(0); qc.h(0); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 1, false); + qc::CircuitOptimizer::collectBlocks(qc, 1); std::cout << qc << "\n"; EXPECT_EQ(qc.size(), 2); EXPECT_TRUE(qc.front()->isNonUnitaryOperation()); @@ -241,7 +227,7 @@ TEST(CollectBlocks, handleCompoundOperation) { qc.emplace_back(op.asCompoundOperation()); qc.x(1); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 1, false); + qc::CircuitOptimizer::collectBlocks(qc, 1); std::cout << qc << "\n"; EXPECT_EQ(qc.size(), 2); EXPECT_TRUE(qc.front()->isStandardOperation()); @@ -256,7 +242,7 @@ TEST(CollectBlocks, handleCompoundOperation2) { qc.emplace_back(op.asCompoundOperation()); qc.x(0); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 1, false); + qc::CircuitOptimizer::collectBlocks(qc, 1); std::cout << qc << "\n"; EXPECT_EQ(qc.size(), 1); EXPECT_TRUE(qc.front()->isCompoundOperation()); From 5555b8e02b5a2d99efb45f529be7ed582daea249 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 29 Apr 2025 04:49:51 +0000 Subject: [PATCH 15/21] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/mqt-core/ir/operations/Operation.hpp | 4 ++-- test/circuit_optimizer/test_collect_blocks.cpp | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/include/mqt-core/ir/operations/Operation.hpp b/include/mqt-core/ir/operations/Operation.hpp index 179494983..2fc5b8466 100644 --- a/include/mqt-core/ir/operations/Operation.hpp +++ b/include/mqt-core/ir/operations/Operation.hpp @@ -157,13 +157,13 @@ class Operation { /** * @brief Checks whether a gate is a Clifford gate. - * @details + * @details */ [[nodiscard]] virtual bool isClifford() const { const OpType opType = getType(); const bool controlled = isControlled(); const std::size_t numberOfControls = getNcontrols(); - + switch (opType) { case I: case X: diff --git a/test/circuit_optimizer/test_collect_blocks.cpp b/test/circuit_optimizer/test_collect_blocks.cpp index 976210e9b..7d474966f 100644 --- a/test/circuit_optimizer/test_collect_blocks.cpp +++ b/test/circuit_optimizer/test_collect_blocks.cpp @@ -21,7 +21,6 @@ TEST(CollectBlocks, emptyCircuit) { EXPECT_EQ(qc.getNindividualOps(), 0); } - TEST(CollectBlocks, singleGate) { QuantumComputation qc(1); qc.h(0); @@ -32,7 +31,6 @@ TEST(CollectBlocks, singleGate) { EXPECT_TRUE(qc.front()->isStandardOperation()); } - TEST(CollectBlocks, collectMultipleSingleQubitGates) { QuantumComputation qc(2); qc.h(0); From e5de02d417def20f78a619515ff0fdd70c327d15 Mon Sep 17 00:00:00 2001 From: "jannik.pflieger" Date: Tue, 29 Apr 2025 21:00:26 +0200 Subject: [PATCH 16/21] Moved IsCliffordfunction to StandardOperation and CompoundOperation --- .../ir/operations/CompoundOperation.hpp | 2 + include/mqt-core/ir/operations/Operation.hpp | 38 +------------------ .../ir/operations/StandardOperation.hpp | 2 + src/ir/operations/CompoundOperation.cpp | 5 +++ src/ir/operations/StandardOperation.cpp | 25 ++++++++++++ 5 files changed, 35 insertions(+), 37 deletions(-) diff --git a/include/mqt-core/ir/operations/CompoundOperation.hpp b/include/mqt-core/ir/operations/CompoundOperation.hpp index d0d6599ca..e731772d0 100644 --- a/include/mqt-core/ir/operations/CompoundOperation.hpp +++ b/include/mqt-core/ir/operations/CompoundOperation.hpp @@ -58,6 +58,8 @@ class CompoundOperation final : public Operation { [[nodiscard]] bool isGlobal(size_t nQubits) const noexcept override; + [[nodiscard]] bool isClifford() const override; + void addControl(Control c) override; void clearControls() override; diff --git a/include/mqt-core/ir/operations/Operation.hpp b/include/mqt-core/ir/operations/Operation.hpp index 179494983..4b2d2d8a0 100644 --- a/include/mqt-core/ir/operations/Operation.hpp +++ b/include/mqt-core/ir/operations/Operation.hpp @@ -155,43 +155,7 @@ class Operation { [[nodiscard]] virtual bool isControlled() const { return !controls.empty(); } - /** - * @brief Checks whether a gate is a Clifford gate. - * @details - */ - [[nodiscard]] virtual bool isClifford() const { - const OpType opType = getType(); - const bool controlled = isControlled(); - const std::size_t numberOfControls = getNcontrols(); - - switch (opType) { - case I: - case X: - if ((controlled) && ((numberOfControls >= 2))) { - return false; - } - case Y: - if ((controlled) && ((numberOfControls >= 2))) { - return false; - } - case Z: - if ((controlled) && ((numberOfControls >= 2))) { - return false; - } - case H: - case S: - case Sdg: - case SX: - case SXdg: - case DCX: - case SWAP: - case iSWAP: - case ECR: - return true; - default: - return false; - } - } + [[nodiscard]] virtual bool isClifford() const {return false;} /** * @brief Checks whether a gate is global. diff --git a/include/mqt-core/ir/operations/StandardOperation.hpp b/include/mqt-core/ir/operations/StandardOperation.hpp index b488c4dd8..e3dba1a62 100644 --- a/include/mqt-core/ir/operations/StandardOperation.hpp +++ b/include/mqt-core/ir/operations/StandardOperation.hpp @@ -82,6 +82,8 @@ class StandardOperation : public Operation { [[nodiscard]] bool isGlobal(size_t nQubits) const override; + [[nodiscard]] bool isClifford() const override; + void addControl(const Control c) override { if (actsOn(c.qubit)) { throw std::runtime_error("Cannot add control on qubit " + diff --git a/src/ir/operations/CompoundOperation.cpp b/src/ir/operations/CompoundOperation.cpp index af2bc3c63..16fcb2ecb 100644 --- a/src/ir/operations/CompoundOperation.cpp +++ b/src/ir/operations/CompoundOperation.cpp @@ -87,6 +87,11 @@ bool CompoundOperation::isGlobal(const size_t nQubits) const noexcept { }); } +bool CompoundOperation::isClifford() const { + return std::all_of(ops.begin(), ops.end(), + [](const auto& op) { return op->isClifford(); }); +} + bool CompoundOperation::isSymbolicOperation() const { return std::any_of(ops.begin(), ops.end(), [](const auto& op) { return op->isSymbolicOperation(); }); diff --git a/src/ir/operations/StandardOperation.cpp b/src/ir/operations/StandardOperation.cpp index e44b52987..f38cea1d1 100644 --- a/src/ir/operations/StandardOperation.cpp +++ b/src/ir/operations/StandardOperation.cpp @@ -250,6 +250,31 @@ bool StandardOperation::isGlobal(const size_t nQubits) const { /*** * Public Methods ***/ +bool StandardOperation::isClifford() const { + switch (type) { + case I: + case Barrier: + return true; + case X: + case Y: + case Z: + return (getControls().size() <= 1); + case H: + case S: + case Sdg: + case SX: + case SXdg: + case DCX: + case SWAP: + case iSWAP: + case ECR: + return (getControls().empty()); + default: + return false; + } +} + + void StandardOperation::dumpOpenQASM( std::ostream& of, const QubitIndexToRegisterMap& qubitMap, [[maybe_unused]] const BitIndexToRegisterMap& bitMap, size_t indent, From 71e8bc68a0c93b73754b2a584b42c6b3b7f10ea3 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 29 Apr 2025 19:02:48 +0000 Subject: [PATCH 17/21] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/mqt-core/ir/operations/Operation.hpp | 2 +- src/ir/operations/StandardOperation.cpp | 39 ++++++++++---------- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/include/mqt-core/ir/operations/Operation.hpp b/include/mqt-core/ir/operations/Operation.hpp index 4b2d2d8a0..5e1d8b412 100644 --- a/include/mqt-core/ir/operations/Operation.hpp +++ b/include/mqt-core/ir/operations/Operation.hpp @@ -155,7 +155,7 @@ class Operation { [[nodiscard]] virtual bool isControlled() const { return !controls.empty(); } - [[nodiscard]] virtual bool isClifford() const {return false;} + [[nodiscard]] virtual bool isClifford() const { return false; } /** * @brief Checks whether a gate is global. diff --git a/src/ir/operations/StandardOperation.cpp b/src/ir/operations/StandardOperation.cpp index f38cea1d1..2f549eeda 100644 --- a/src/ir/operations/StandardOperation.cpp +++ b/src/ir/operations/StandardOperation.cpp @@ -252,29 +252,28 @@ bool StandardOperation::isGlobal(const size_t nQubits) const { ***/ bool StandardOperation::isClifford() const { switch (type) { - case I: - case Barrier: - return true; - case X: - case Y: - case Z: - return (getControls().size() <= 1); - case H: - case S: - case Sdg: - case SX: - case SXdg: - case DCX: - case SWAP: - case iSWAP: - case ECR: - return (getControls().empty()); - default: - return false; + case I: + case Barrier: + return true; + case X: + case Y: + case Z: + return (getControls().size() <= 1); + case H: + case S: + case Sdg: + case SX: + case SXdg: + case DCX: + case SWAP: + case iSWAP: + case ECR: + return (getControls().empty()); + default: + return false; } } - void StandardOperation::dumpOpenQASM( std::ostream& of, const QubitIndexToRegisterMap& qubitMap, [[maybe_unused]] const BitIndexToRegisterMap& bitMap, size_t indent, From f77176688a62127f328a6eb8519abd2efccdfae9 Mon Sep 17 00:00:00 2001 From: "jannik.pflieger" Date: Wed, 30 Apr 2025 19:27:08 +0200 Subject: [PATCH 18/21] Corrected Test for isClifford operations --- src/circuit_optimizer/CircuitOptimizer.cpp | 3 +-- src/ir/operations/StandardOperation.cpp | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/circuit_optimizer/CircuitOptimizer.cpp b/src/circuit_optimizer/CircuitOptimizer.cpp index 28f05c656..fd38b472f 100644 --- a/src/circuit_optimizer/CircuitOptimizer.cpp +++ b/src/circuit_optimizer/CircuitOptimizer.cpp @@ -1419,7 +1419,7 @@ struct DSU { void CircuitOptimizer::collectBlocks(QuantumComputation& qc, const std::size_t maxBlockSize, - bool onlyCollectCliffords = false) { + bool onlyCollectCliffords) { if (qc.size() <= 1) { return; } @@ -1434,7 +1434,6 @@ void CircuitOptimizer::collectBlocks(QuantumComputation& qc, auto& op = *opIt; bool canProcess = true; bool makesTooBig = false; - bool isClifford = false; // check whether the operation is a Clifford operation if (!op->isUnitary() || (onlyCollectCliffords && !op->isClifford())) { diff --git a/src/ir/operations/StandardOperation.cpp b/src/ir/operations/StandardOperation.cpp index f38cea1d1..0bbfd0cff 100644 --- a/src/ir/operations/StandardOperation.cpp +++ b/src/ir/operations/StandardOperation.cpp @@ -264,11 +264,12 @@ bool StandardOperation::isClifford() const { case Sdg: case SX: case SXdg: + return (getControls().empty()); case DCX: case SWAP: case iSWAP: case ECR: - return (getControls().empty()); + return (getControls().size() == 1); default: return false; } From 227d2ecd9855c274089195fd558cec03af43fb3b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 30 Apr 2025 17:28:03 +0000 Subject: [PATCH 19/21] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ir/operations/StandardOperation.cpp | 40 ++++++++++++------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/ir/operations/StandardOperation.cpp b/src/ir/operations/StandardOperation.cpp index 172dbed58..a3419e8ab 100644 --- a/src/ir/operations/StandardOperation.cpp +++ b/src/ir/operations/StandardOperation.cpp @@ -252,26 +252,26 @@ bool StandardOperation::isGlobal(const size_t nQubits) const { ***/ bool StandardOperation::isClifford() const { switch (type) { - case I: - case Barrier: - return true; - case X: - case Y: - case Z: - return (getControls().size() <= 1); - case H: - case S: - case Sdg: - case SX: - case SXdg: - return (getControls().empty()); - case DCX: - case SWAP: - case iSWAP: - case ECR: - return (getControls().size() == 1); - default: - return false; + case I: + case Barrier: + return true; + case X: + case Y: + case Z: + return (getControls().size() <= 1); + case H: + case S: + case Sdg: + case SX: + case SXdg: + return (getControls().empty()); + case DCX: + case SWAP: + case iSWAP: + case ECR: + return (getControls().size() == 1); + default: + return false; } } From 5ce85b493668d6eece283e5f8dc5d3ec766074c8 Mon Sep 17 00:00:00 2001 From: "jannik.pflieger" Date: Thu, 1 May 2025 14:27:35 +0200 Subject: [PATCH 20/21] Removed usless test added more meanigful ones --- .../circuit_optimizer/test_collect_blocks.cpp | 62 +++++++++++++++---- 1 file changed, 49 insertions(+), 13 deletions(-) diff --git a/test/circuit_optimizer/test_collect_blocks.cpp b/test/circuit_optimizer/test_collect_blocks.cpp index 7d474966f..034293b2f 100644 --- a/test/circuit_optimizer/test_collect_blocks.cpp +++ b/test/circuit_optimizer/test_collect_blocks.cpp @@ -45,49 +45,85 @@ TEST(CollectBlocks, collectMultipleSingleQubitGates) { EXPECT_TRUE(qc.back()->isCompoundOperation()); } -TEST(CollectBlocks, collectMultipleSingleQubitCliffordGates) { +TEST(CollectBlocks, nonCliffordOnAll) { QuantumComputation qc(2); - qc.h(0); - qc.h(1); + qc.sx(0); + qc.sxdg(1); qc.t(0); qc.t(1); qc.x(0); qc.x(1); std::cout << qc << "\n"; - qc::CircuitOptimizer::collectBlocks(qc, 1, true); + qc::CircuitOptimizer::collectBlocks(qc, 2, true); std::cout << qc << "\n"; - EXPECT_EQ(qc.size(), 6); + EXPECT_EQ(qc.size(), 4); } -TEST(CollectBlocks, collectMultipleCliffordGates) { +TEST(CollectBlocks, nonCliffordonTop) { QuantumComputation qc(2); - qc.h(0); + qc.sdg(0); qc.h(1); qc.t(0); qc.x(0); - qc.x(1); + qc.z(1); std::cout << qc << "\n"; qc::CircuitOptimizer::collectBlocks(qc, 2, true); std::cout << qc << "\n"; - EXPECT_EQ(qc.size(), 4); + EXPECT_EQ(qc.size(), 3); EXPECT_TRUE(qc.front()->isCompoundOperation()); } TEST(CollectBlocks, collectTwoQubitCliffordGates) { QuantumComputation qc(2); qc.h(0); - qc.h(1); + qc.s(1); qc.cx(0, 1); - qc.t(0); + qc.rx(0.1,0); qc.x(0); - qc.x(1); + qc.y(1); std::cout << qc << "\n"; qc::CircuitOptimizer::collectBlocks(qc, 2, true); std::cout << qc << "\n"; - EXPECT_EQ(qc.size(), 4); + EXPECT_EQ(qc.size(), 3); EXPECT_TRUE(qc.front()->isCompoundOperation()); } +TEST(CollectBlocks, TwoQubitnonClifford) { + QuantumComputation qc(2); + qc.h(0); + qc.s(1); + qc.rxx(0.1,0, 1); + qc.i(0); + qc.y(1); + std::cout << qc << "\n"; + qc::CircuitOptimizer::collectBlocks(qc, 2, true); + std::cout << qc << "\n"; + EXPECT_EQ(qc.size(), 3); + EXPECT_TRUE(qc.front()->isCompoundOperation()); +} + +TEST(CollectBlocks, nonCliffordBeginning) { + QuantumComputation qc(2); + qc.t(0); + qc.t(1); + qc.ecr(0, 1); + std::cout << qc << "\n"; + qc::CircuitOptimizer::collectBlocks(qc, 2, true); + std::cout << qc << "\n"; + EXPECT_EQ(qc.size(), 2); +} + +TEST(CollectBlocks, threeQubitnonClifford) { + QuantumComputation qc(3); + qc.mcx({0, 1}, 2); + qc.mcz({0, 2}, 1); + qc.dcx(0, 1); + std::cout << qc << "\n"; + qc::CircuitOptimizer::collectBlocks(qc, 2, true); + std::cout << qc << "\n"; + EXPECT_EQ(qc.size(), 2); +} + TEST(CollectBlocks, mergeBlocks) { QuantumComputation qc(2); qc.h(0); From ace9eaff2a98312e84f9bb43e1080d504f55bbca Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 1 May 2025 12:28:02 +0000 Subject: [PATCH 21/21] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/circuit_optimizer/test_collect_blocks.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/circuit_optimizer/test_collect_blocks.cpp b/test/circuit_optimizer/test_collect_blocks.cpp index 034293b2f..4863c16a3 100644 --- a/test/circuit_optimizer/test_collect_blocks.cpp +++ b/test/circuit_optimizer/test_collect_blocks.cpp @@ -78,7 +78,7 @@ TEST(CollectBlocks, collectTwoQubitCliffordGates) { qc.h(0); qc.s(1); qc.cx(0, 1); - qc.rx(0.1,0); + qc.rx(0.1, 0); qc.x(0); qc.y(1); std::cout << qc << "\n"; @@ -92,7 +92,7 @@ TEST(CollectBlocks, TwoQubitnonClifford) { QuantumComputation qc(2); qc.h(0); qc.s(1); - qc.rxx(0.1,0, 1); + qc.rxx(0.1, 0, 1); qc.i(0); qc.y(1); std::cout << qc << "\n";