Skip to content

Commit

Permalink
update Alternating Checker to use new features of
Browse files Browse the repository at this point in the history
  • Loading branch information
reb-ddm committed Jan 26, 2024
1 parent 4815c2a commit dd874c0
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 29 deletions.
47 changes: 19 additions & 28 deletions src/checker/dd/DDAlternatingChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,39 +93,30 @@ void DDAlternatingChecker::postprocess() {
if (isDone()) {
return;
}

// sum up the contributions of garbage qubits
taskManager1.reduceGarbage(functionality);
if (isDone()) {
return;
}
taskManager2.reduceGarbage(functionality);
if (isDone()) {
return;
}
}

EquivalenceCriterion DDAlternatingChecker::checkEquivalence() {
// create the full identity matrix
auto goalMatrix = dd->makeIdent(nqubits);
dd->incRef(goalMatrix);

// account for any garbage
taskManager1.reduceGarbage(goalMatrix);
taskManager2.reduceGarbage(goalMatrix);

taskManager1.reduceAncillae(goalMatrix);
taskManager2.reduceAncillae(goalMatrix);
std::vector<bool> garbage(nqubits);
// is it guaranteed that the two circuits have the same garbage qubits?
for (qc::Qubit q = 0U; q < nqubits; ++q) {
garbage[static_cast<std::size_t>(q)] =
qc1.logicalQubitIsGarbage(q) && qc2.logicalQubitIsGarbage(q);
}

// the resulting goal matrix is
// [1 0] if the qubit is no ancillary
// [0 1]
//
// [1 0] (= |0><0>|) for an ancillary that is present in either circuit
// [0 0]
// if partial equivalence is being checked instead of total equivalence, it
// suffices to change the last parameter of isCloseToIdentity to `false`
bool isClose = dd->isCloseToIdentity(
functionality, configuration.functionality.traceThreshold, garbage, true);

// compare the obtained functionality to the goal matrix
return equals(functionality, goalMatrix);
if (isClose) {
// whenever the top edge weight is not one, both decision diagrams are only
// equivalent up to a global phase
if (!functionality.w.approximatelyEquals(dd::Complex::one())) {
return EquivalenceCriterion::EquivalentUpToGlobalPhase;
}
return EquivalenceCriterion::Equivalent;
}
return EquivalenceCriterion::NotEquivalent;
}

[[nodiscard]] bool DDAlternatingChecker::gatesAreIdentical() const {
Expand Down
3 changes: 2 additions & 1 deletion test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ package_add_test(
test_gate_cost_application_scheme.cpp
test_equality.cpp
test_zx.cpp
test_symbolic.cpp)
test_symbolic.cpp
test_partial_equivalence.cpp)
142 changes: 142 additions & 0 deletions test/test_partial_equivalence.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
//
// This file is part of the MQT QCEC library released under the MIT license.
// See README.md or go to https://github.com/cda-tum/qcec for more information.
//

#include "EquivalenceCheckingManager.hpp"

#include "gtest/gtest.h"

class PartialEqualityTest : public testing::Test {
void SetUp() override {
qc1 = qc::QuantumComputation(nqubits);
qc2 = qc::QuantumComputation(nqubits);
config.optimizations.fuseSingleQubitGates = false;
config.optimizations.reorderOperations = false;
config.optimizations.reconstructSWAPs = false;
config.optimizations.fixOutputPermutationMismatch = true;

config.execution.runSimulationChecker = false;
config.execution.runAlternatingChecker = false;
config.execution.runConstructionChecker = false;
config.execution.runZXChecker = false;
}

protected:
std::size_t nqubits = 3U;
qc::QuantumComputation qc1;
qc::QuantumComputation qc2;
ec::Configuration config{};
};

TEST_F(PartialEqualityTest, AlternatingCheckerGarbage) {
// these circuits have the same gates acting on the measured qubit
// and random gates acting on the two garbage qubits
qc1.cswap(1, 0, 2);
qc1.cx(2, 0);
qc1.h(0);
qc1.tdg(1);
qc1.s(1);
qc1.z(2);

qc2.cswap(1, 0, 2);
qc2.cx(2, 0);
qc2.h(0);
qc2.h(2);
qc2.rz(dd::PI_4, 1);
qc2.ry(0.1, 1);
qc2.cx(1, 2);

qc1.setLogicalQubitGarbage(2);
qc1.setLogicalQubitGarbage(1);
qc2.setLogicalQubitGarbage(2);
qc2.setLogicalQubitGarbage(1);

config.execution.runAlternatingChecker = true;
ec::EquivalenceCheckingManager ecm(qc1, qc2, config);
ecm.setApplicationScheme(ec::ApplicationSchemeType::Proportional);
ecm.run();
EXPECT_EQ(ecm.equivalence(),
ec::EquivalenceCriterion::EquivalentUpToGlobalPhase);
}

TEST_F(PartialEqualityTest, AlternatingCheckerGarbage2) {
// measured qubit: 1
qc1.setLogicalQubitGarbage(2);
qc1.setLogicalQubitGarbage(0);

qc1.h(1);
qc1.tdg(0);
qc1.s(0);
qc1.z(2);

// measured qubit: 1
qc2.setLogicalQubitGarbage(0);
qc2.setLogicalQubitGarbage(2);

qc2.h(1);
qc2.h(0);
qc2.rz(dd::PI_4, 2);
qc2.ry(0.1, 2);
qc2.cx(2, 0);

config.execution.runAlternatingChecker = true;
ec::EquivalenceCheckingManager ecm(qc1, qc2, config);
ecm.setApplicationScheme(ec::ApplicationSchemeType::Proportional);
ecm.run();
EXPECT_EQ(ecm.equivalence(),
ec::EquivalenceCriterion::EquivalentUpToGlobalPhase);
}

TEST_F(PartialEqualityTest, AlternatingCheckerGarbageAndAncillary) {
qc1.setLogicalQubitGarbage(2);
qc1.setLogicalQubitGarbage(1);
qc1.setLogicalQubitAncillary(2);

qc1.h(0);
qc1.tdg(1);
qc1.s(1);
// ancillary qubits are initialized to zero, therefore this gate doesn't
// change the functionality of the circuit
qc1.cx(2, 0);

qc::QuantumComputation qc3(nqubits - 1);
qc3.setLogicalQubitGarbage(2);
qc3.setLogicalQubitGarbage(1);

qc3.h(0);
qc3.rz(dd::PI_4, 1);
qc3.ry(0.1, 1);

config.execution.runAlternatingChecker = true;
ec::EquivalenceCheckingManager ecm(qc1, qc3, config);
ecm.setApplicationScheme(ec::ApplicationSchemeType::Proportional);
ecm.run();
EXPECT_EQ(ecm.equivalence(),
ec::EquivalenceCriterion::EquivalentUpToGlobalPhase);
}

TEST_F(PartialEqualityTest, AlternatingCheckerGarbageNotEquivalent) {
// example from the paper https://arxiv.org/abs/2208.07564
// these two circuits are only partially equivalent,
// therefore the equivalence checker returns NotEquivalent
qc1.cswap(1, 0, 2);
qc1.h(0);
qc1.z(2);
qc1.cswap(1, 0, 2);

qc2.x(1);
qc2.ch(1, 0);

qc1.setLogicalQubitGarbage(2);
qc1.setLogicalQubitGarbage(1);
qc2.setLogicalQubitGarbage(2);
qc2.setLogicalQubitGarbage(1);

std::cout << "qc1:\n";
config.execution.runAlternatingChecker = true;
ec::EquivalenceCheckingManager ecm(qc1, qc2, config);
ecm.setApplicationScheme(ec::ApplicationSchemeType::Proportional);
ecm.run();
EXPECT_EQ(ecm.equivalence(), ec::EquivalenceCriterion::NotEquivalent);
}

0 comments on commit dd874c0

Please sign in to comment.