-
Notifications
You must be signed in to change notification settings - Fork 22
/
Copy pathtest_equality.cpp
167 lines (137 loc) · 4.87 KB
/
test_equality.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
//
// 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 "checker/dd/applicationscheme/GateCostApplicationScheme.hpp"
#include "gtest/gtest.h"
#include <functional>
#include <sstream>
using namespace dd::literals;
class EqualityTest : 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.execution.runSimulationChecker = false;
config.execution.runAlternatingChecker = false;
config.execution.runConstructionChecker = false;
config.execution.runZXChecker = false;
}
protected:
dd::QubitCount nqubits = 1U;
qc::QuantumComputation qc1;
qc::QuantumComputation qc2;
ec::Configuration config{};
};
TEST_F(EqualityTest, GlobalPhase) {
qc1.x(0);
qc2.x(0);
// add a global phase of -1
qc2.z(0);
qc2.x(0);
qc2.z(0);
qc2.x(0);
config.execution.runAlternatingChecker = true;
ec::EquivalenceCheckingManager ecm(qc1, qc2, config);
ecm.run();
EXPECT_EQ(ecm.equivalence(),
ec::EquivalenceCriterion::EquivalentUpToGlobalPhase);
}
TEST_F(EqualityTest, CloseButNotEqualAlternating) {
qc1.x(0);
qc2.x(0);
qc2.phase(0, dd::PI / 1024.);
config.functionality.traceThreshold = 1e-2;
config.execution.runAlternatingChecker = true;
ec::EquivalenceCheckingManager ecm(qc1, qc2, config);
ecm.run();
std::cout << ecm << std::endl;
EXPECT_EQ(ecm.equivalence(), ec::EquivalenceCriterion::Equivalent);
}
TEST_F(EqualityTest, CloseButNotEqualConstruction) {
qc1.x(0);
qc2.x(0);
qc2.phase(0, dd::PI / 1024.);
config.functionality.traceThreshold = 1e-2;
config.execution.runConstructionChecker = true;
ec::EquivalenceCheckingManager ecm(qc1, qc2, config);
ecm.run();
std::cout << ecm << std::endl;
EXPECT_EQ(ecm.equivalence(), ec::EquivalenceCriterion::Equivalent);
}
TEST_F(EqualityTest, CloseButNotEqualAlternatingGlobalPhase) {
qc1.x(0);
qc2.x(0);
qc2.phase(0, dd::PI / 1024.);
// add a global phase of -1
qc2.z(0);
qc2.x(0);
qc2.z(0);
qc2.x(0);
config.functionality.traceThreshold = 1e-2;
config.execution.runAlternatingChecker = true;
ec::EquivalenceCheckingManager ecm(qc1, qc2, config);
ecm.run();
std::cout << ecm << std::endl;
EXPECT_EQ(ecm.equivalence(),
ec::EquivalenceCriterion::EquivalentUpToGlobalPhase);
}
TEST_F(EqualityTest, CloseButNotEqualSimulation) {
qc1.h(0);
qc2.h(0);
qc2.phase(0, dd::PI / 1024.);
config.simulation.fidelityThreshold = 1e-2;
config.execution.runSimulationChecker = true;
ec::EquivalenceCheckingManager ecm(qc1, qc2, config);
ecm.run();
std::cout << ecm << std::endl;
EXPECT_EQ(ecm.equivalence(), ec::EquivalenceCriterion::ProbablyEquivalent);
}
TEST_F(EqualityTest, SimulationMoreThan64Qubits) {
qc1 = qc::QuantumComputation(65U);
qc1.h(0);
for (auto i = 0U; i < 64U; ++i) {
qc1.x(static_cast<dd::Qubit>(i + 1), 0_pc);
}
qc2 = qc1.clone();
config.execution.runSimulationChecker = true;
ec::EquivalenceCheckingManager ecm(qc1, qc2, config);
ecm.run();
std::cout << ecm << std::endl;
EXPECT_EQ(ecm.equivalence(), ec::EquivalenceCriterion::ProbablyEquivalent);
}
TEST_F(EqualityTest, AutomaticSwitchToConstructionChecker) {
// add ancillary qubits to both circuits
qc1.addAncillaryQubit(1, -1);
qc2.addAncillaryQubit(1, -1);
// perform the same action on both circuits' primary qubit
qc1.x(0);
qc2.x(0);
// perform a different action on the ancillary qubit
qc1.x(1);
qc2.z(1);
// setup default configuration
config = ec::Configuration{};
ec::EquivalenceCheckingManager ecm(qc1, qc2, config);
// this should notice that the alternating checker is not capable of running
// the circuit and should switch to the construction checker
const auto runConfig = ecm.getConfiguration();
EXPECT_TRUE(runConfig.execution.runConstructionChecker);
EXPECT_FALSE(runConfig.execution.runAlternatingChecker);
// run the equivalence checker
ecm.run();
// both circuits should be equivalent since their action only differs on an
// ancillary and garbage qubit
const auto result = ecm.equivalence();
EXPECT_EQ(result, ec::EquivalenceCriterion::Equivalent);
// Check an exception is raised for a checker configured after initialization.
// Note: this exception can only be caught in sequential mode since it is
// raised in a different thread otherwise.
ecm.reset();
ecm.setAlternatingChecker(true);
ecm.setParallel(false);
EXPECT_THROW(ecm.run(), std::invalid_argument);
}