GCC Code Coverage Report


Directory: ./
File: Converters/PauliGadget.cpp
Date: 2022-10-15 05:10:18
Warnings: 5 unchecked decisions!
Exec Total Coverage
Lines: 186 193 96.4%
Functions: 6 6 100.0%
Branches: 212 377 56.2%
Decisions: 47 61 77.0%

Line Branch Decision Exec Source
1 // Copyright 2019-2022 Cambridge Quantum Computing
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "PauliGadget.hpp"
16
17 #include "Circuit/CircUtils.hpp"
18
19 namespace tket {
20
21 556 void append_single_pauli_gadget(
22 Circuit &circ, const QubitPauliTensor &pauli, Expr angle,
23 CXConfigType cx_config) {
24
2/2
✓ Branch 1 taken 58 times.
✓ Branch 2 taken 498 times.
2/2
✓ Decision 'true' taken 58 times.
✓ Decision 'false' taken 498 times.
556 if (pauli.coeff == -1.) {
25
2/4
✓ Branch 1 taken 58 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 58 times.
✗ Branch 5 not taken.
58 angle *= -1;
26
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 498 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 498 times.
498 } else if (pauli.coeff != 1.) {
27 throw CircuitInvalidity("Pauli coefficient must be +/- 1");
28 }
29 556 std::vector<Pauli> string;
30 556 unit_map_t mapping;
31 556 unsigned i = 0;
32
2/2
✓ Branch 4 taken 1093 times.
✓ Branch 5 taken 556 times.
2/2
✓ Decision 'true' taken 1093 times.
✓ Decision 'false' taken 556 times.
1649 for (const std::pair<const Qubit, Pauli> &term : pauli.string.map) {
33
1/2
✓ Branch 1 taken 1093 times.
✗ Branch 2 not taken.
1093 string.push_back(term.second);
34
3/6
✓ Branch 1 taken 1093 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1093 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 1093 times.
✗ Branch 9 not taken.
1093 mapping.insert({Qubit(q_default_reg(), i), term.first});
35 1093 i++;
36 }
37
1/2
✓ Branch 1 taken 556 times.
✗ Branch 2 not taken.
556 Circuit gadget = pauli_gadget(string, angle, cx_config);
38
1/2
✓ Branch 1 taken 556 times.
✗ Branch 2 not taken.
556 circ.append_with_map(gadget, mapping);
39 556 }
40
41 32 static void reduce_shared_qs_by_CX_snake(
42 Circuit &circ, std::set<Qubit> &match, QubitPauliTensor &pauli0,
43 QubitPauliTensor &pauli1) {
44 32 unsigned match_size = match.size();
45
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 32 times.
2/2
✓ Decision 'true' taken 13 times.
✓ Decision 'false' taken 32 times.
45 while (match_size > 1) { // We allow one match left over
46 13 auto it = --match.end();
47 13 Qubit to_eliminate = *it;
48
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 match.erase(it);
49 13 Qubit helper = *match.rbegin();
50 // extend CX snake
51
4/8
✓ Branch 5 taken 13 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 13 times.
✗ Branch 9 not taken.
✓ Branch 12 taken 26 times.
✓ Branch 13 taken 13 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
39 circ.add_op<Qubit>(OpType::CX, {to_eliminate, helper});
52
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 pauli0.string.map.erase(to_eliminate);
53
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 pauli1.string.map.erase(to_eliminate);
54 13 match_size--;
55 13 }
56 32 }
57
58 12 static void reduce_shared_qs_by_CX_star(
59 Circuit &circ, std::set<Qubit> &match, QubitPauliTensor &pauli0,
60 QubitPauliTensor &pauli1) {
61 12 std::set<Qubit>::iterator iter = match.begin();
62
2/2
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 12 times.
2/2
✓ Decision 'true' taken 7 times.
✓ Decision 'false' taken 12 times.
19 for (std::set<Qubit>::iterator next = match.begin(); match.size() > 1;
63 7 iter = next) {
64 7 ++next;
65 7 Qubit to_eliminate = *iter;
66
4/8
✓ Branch 7 taken 7 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 7 times.
✗ Branch 11 not taken.
✓ Branch 14 taken 14 times.
✓ Branch 15 taken 7 times.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
21 circ.add_op<Qubit>(OpType::CX, {to_eliminate, *match.rbegin()});
67
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 pauli0.string.map.erase(to_eliminate);
68
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 pauli1.string.map.erase(to_eliminate);
69
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 match.erase(iter);
70 7 }
71 12 }
72
73 13 static void reduce_shared_qs_by_CX_tree(
74 Circuit &circ, std::set<Qubit> &match, QubitPauliTensor &pauli0,
75 QubitPauliTensor &pauli1) {
76
2/2
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 13 times.
2/2
✓ Decision 'true' taken 9 times.
✓ Decision 'false' taken 13 times.
22 while (match.size() > 1) {
77 9 std::set<Qubit> remaining;
78 9 std::set<Qubit>::iterator it = match.begin();
79
2/2
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 9 times.
2/2
✓ Decision 'true' taken 10 times.
✓ Decision 'false' taken 9 times.
19 while (it != match.end()) {
80 10 Qubit maintained = *it;
81 10 it++;
82
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 remaining.insert(maintained);
83
2/2
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 1 times.
2/2
✓ Decision 'true' taken 9 times.
✓ Decision 'false' taken 1 times.
10 if (it != match.end()) {
84 9 Qubit to_eliminate = *it;
85 9 it++;
86
4/8
✓ Branch 5 taken 9 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 9 times.
✗ Branch 9 not taken.
✓ Branch 12 taken 18 times.
✓ Branch 13 taken 9 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
27 circ.add_op<Qubit>(OpType::CX, {to_eliminate, maintained});
87
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 pauli0.string.map.erase(to_eliminate);
88
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 pauli1.string.map.erase(to_eliminate);
89 9 }
90 10 }
91
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 match = remaining;
92 9 }
93 13 }
94
95 11 static void reduce_shared_qs_by_CX_multiqgate(
96 Circuit &circ, std::set<Qubit> &match, QubitPauliTensor &pauli0,
97 QubitPauliTensor &pauli1) {
98
2/2
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 5 times.
2/2
✓ Decision 'true' taken 6 times.
✓ Decision 'false' taken 5 times.
11 if (match.size() <= 1) {
99 6 return;
100 }
101 // last qubit is target
102 5 Qubit target = *match.rbegin();
103
2/2
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 5 times.
2/2
✓ Decision 'true' taken 5 times.
✓ Decision 'false' taken 5 times.
10 while (match.size() > 1) {
104 5 std::set<Qubit>::iterator iter = match.begin();
105
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 2 times.
2/2
✓ Decision 'true' taken 3 times.
✓ Decision 'false' taken 2 times.
5 if (match.size() == 2) {
106 // use CX
107 3 Qubit to_eliminate = *iter;
108
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 match.erase(iter);
109
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 pauli0.string.map.erase(to_eliminate);
110
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 pauli1.string.map.erase(to_eliminate);
111
112
4/8
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 12 taken 6 times.
✓ Branch 13 taken 3 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
9 circ.add_op<Qubit>(OpType::CX, {to_eliminate, target});
113 3 } else {
114 // use XXPhase3
115 2 Qubit to_eliminate1 = *iter;
116
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 match.erase(iter++);
117
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 pauli0.string.map.erase(to_eliminate1);
118
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 pauli1.string.map.erase(to_eliminate1);
119
120 2 Qubit to_eliminate2 = *iter;
121
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 match.erase(iter);
122
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 pauli0.string.map.erase(to_eliminate2);
123
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 pauli1.string.map.erase(to_eliminate2);
124
125
4/8
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 2 times.
✓ Branch 12 taken 2 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
4 circ.add_op<Qubit>(OpType::H, {to_eliminate1});
126
4/8
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 2 times.
✓ Branch 12 taken 2 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
4 circ.add_op<Qubit>(OpType::H, {to_eliminate2});
127
5/10
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 2 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 2 times.
✗ Branch 13 not taken.
✓ Branch 17 taken 6 times.
✓ Branch 18 taken 2 times.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
8 circ.add_op<Qubit>(
128 OpType::XXPhase3, 0.5, {to_eliminate1, to_eliminate2, target});
129
4/8
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 2 times.
✓ Branch 12 taken 2 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
4 circ.add_op<Qubit>(OpType::X, {target});
130 2 }
131 }
132 5 }
133
134 68 void append_pauli_gadget_pair(
135 Circuit &circ, QubitPauliTensor pauli0, Expr angle0,
136 QubitPauliTensor pauli1, Expr angle1, CXConfigType cx_config) {
137 /*
138 * Cowtan, Dilkes, Duncan, Simmons, Sivarajah: Phase Gadget Synthesis for
139 * Shallow Circuits, Lemma 4.9
140 * Let s and t be Pauli strings; then there exists a Clifford unitary U such
141 * that
142 * P(a, s) . P(b, t) = U . P(a, s') . P(b, t') . U^\dagger
143 * where s' and t' are Pauli strings with intersection at most 1.
144 *
145 * Follows the procedure to reduce the intersection of the gadgets and then
146 * synthesises the remainder individually.
147 */
148
1/2
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
68 pauli0.compress();
149
1/2
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
68 pauli1.compress();
150
151 /*
152 * Step 1: Partition qubits into those just affected by pauli0 (just0) and
153 * pauli1 (just1), and those in both which either match or don't
154 */
155
1/2
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
68 std::set<Qubit> just0 = pauli0.own_qubits(pauli1);
156
1/2
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
68 std::set<Qubit> just1 = pauli1.own_qubits(pauli0);
157
1/2
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
68 std::set<Qubit> match = pauli0.common_qubits(pauli1);
158
1/2
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
68 std::set<Qubit> mismatch = pauli0.conflicting_qubits(pauli1);
159
160 /*
161 * Step 2: Build the unitary U that minimises the intersection of the gadgets.
162 */
163
1/2
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
68 Circuit u;
164
3/4
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 18 times.
✓ Branch 9 taken 68 times.
0/1
? Decision couldn't be analyzed.
86 for (const Qubit &qb : just0) u.add_qubit(qb);
165
3/4
✓ Branch 4 taken 39 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 39 times.
✓ Branch 9 taken 68 times.
0/1
? Decision couldn't be analyzed.
107 for (const Qubit &qb : just1) u.add_qubit(qb);
166
3/4
✓ Branch 4 taken 69 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 69 times.
✓ Branch 9 taken 68 times.
0/1
? Decision couldn't be analyzed.
137 for (const Qubit &qb : match) u.add_qubit(qb);
167
3/4
✓ Branch 4 taken 63 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 63 times.
✓ Branch 9 taken 68 times.
0/1
? Decision couldn't be analyzed.
131 for (const Qubit &qb : mismatch) u.add_qubit(qb);
168
169 /*
170 * Step 2.i: Remove (almost) all matches by converting to Z basis and applying
171 * CXs
172 */
173
2/2
✓ Branch 5 taken 69 times.
✓ Branch 6 taken 68 times.
2/2
✓ Decision 'true' taken 69 times.
✓ Decision 'false' taken 68 times.
137 for (const Qubit &qb : match) {
174
4/5
✓ Branch 1 taken 69 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 15 times.
✓ Branch 4 taken 30 times.
✓ Branch 5 taken 24 times.
69 switch (pauli0.string.map.at(qb)) {
175
1/1
✓ Decision 'true' taken 30 times.
15 case Pauli::X:
176
4/8
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 15 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 15 times.
✓ Branch 12 taken 15 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
30 u.add_op<Qubit>(OpType::H, {qb});
177
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 pauli0.string.map.at(qb) = Pauli::Z;
178
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 pauli1.string.map.at(qb) = Pauli::Z;
179 15 break;
180
1/1
✓ Decision 'true' taken 60 times.
30 case Pauli::Y:
181
4/8
✓ Branch 4 taken 30 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 30 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 30 times.
✓ Branch 12 taken 30 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
60 u.add_op<Qubit>(OpType::V, {qb});
182
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 pauli0.string.map.at(qb) = Pauli::Z;
183
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 pauli1.string.map.at(qb) = Pauli::Z;
184 30 break;
185
1/1
✓ Decision 'true' taken 24 times.
24 default:
186 24 break;
187 }
188 }
189
4/5
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 11 times.
✗ Branch 4 not taken.
68 switch (cx_config) {
190
1/1
✓ Decision 'true' taken 32 times.
32 case CXConfigType::Snake: {
191
1/2
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
32 reduce_shared_qs_by_CX_snake(u, match, pauli0, pauli1);
192 32 break;
193 }
194
1/1
✓ Decision 'true' taken 12 times.
12 case CXConfigType::Star: {
195
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 reduce_shared_qs_by_CX_star(u, match, pauli0, pauli1);
196 12 break;
197 }
198
1/1
✓ Decision 'true' taken 13 times.
13 case CXConfigType::Tree: {
199
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 reduce_shared_qs_by_CX_tree(u, match, pauli0, pauli1);
200 13 break;
201 }
202
1/1
✓ Decision 'true' taken 11 times.
11 case CXConfigType::MultiQGate: {
203
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 reduce_shared_qs_by_CX_multiqgate(u, match, pauli0, pauli1);
204 11 break;
205 }
206
0/1
✗ Decision 'true' not taken.
default:
207 throw UnknownCXConfigType();
208 }
209 /*
210 * Step 2.ii: Convert mismatches to Z in pauli0 and X in pauli1
211 */
212
2/2
✓ Branch 4 taken 63 times.
✓ Branch 5 taken 68 times.
2/2
✓ Decision 'true' taken 63 times.
✓ Decision 'false' taken 68 times.
131 for (const Qubit &qb : mismatch) {
213
4/5
✓ Branch 1 taken 63 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 35 times.
✓ Branch 4 taken 17 times.
✓ Branch 5 taken 11 times.
63 switch (pauli0.string.map.at(qb)) {
214
1/1
✓ Decision 'true' taken 35 times.
35 case Pauli::X: {
215
3/5
✓ Branch 1 taken 35 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
✓ Branch 4 taken 24 times.
✗ Branch 5 not taken.
35 switch (pauli1.string.map.at(qb)) {
216
1/1
✓ Decision 'true' taken 22 times.
11 case Pauli::Y:
217
4/8
✓ Branch 4 taken 11 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 11 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 11 times.
✓ Branch 12 taken 11 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
22 u.add_op<Qubit>(OpType::Sdg, {qb});
218
4/8
✓ Branch 4 taken 11 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 11 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 11 times.
✓ Branch 12 taken 11 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
22 u.add_op<Qubit>(OpType::Vdg, {qb});
219 11 break;
220
1/1
✓ Decision 'true' taken 48 times.
24 case Pauli::Z:
221
4/8
✓ Branch 4 taken 24 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 24 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 24 times.
✓ Branch 12 taken 24 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
48 u.add_op<Qubit>(OpType::H, {qb});
222 24 break;
223
0/1
✗ Decision 'true' not taken.
default:
224 break; // Cannot hit this case
225 }
226 35 break;
227 }
228
1/1
✓ Decision 'true' taken 17 times.
17 case Pauli::Y: {
229
3/5
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
17 switch (pauli1.string.map.at(qb)) {
230
1/1
✓ Decision 'true' taken 26 times.
13 case Pauli::X:
231
4/8
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 13 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 13 times.
✓ Branch 12 taken 13 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
26 u.add_op<Qubit>(OpType::V, {qb});
232 13 break;
233
1/1
✓ Decision 'true' taken 8 times.
4 case Pauli::Z:
234
4/8
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 4 times.
✓ Branch 12 taken 4 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
8 u.add_op<Qubit>(OpType::V, {qb});
235
4/8
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 4 times.
✓ Branch 12 taken 4 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
8 u.add_op<Qubit>(OpType::S, {qb});
236 4 break;
237
0/1
✗ Decision 'true' not taken.
default:
238 break; // Cannot hit this case
239 }
240 17 break;
241 }
242
1/1
✓ Decision 'true' taken 11 times.
11 default: { // Necessarily Z
243
3/4
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
✓ Branch 4 taken 1 times.
0/1
? Decision couldn't be analyzed.
11 if (pauli1.string.map.at(qb) == Pauli::Y)
244
4/8
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 10 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 10 times.
✓ Branch 12 taken 10 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
20 u.add_op<Qubit>(OpType::Sdg, {qb});
245 // No need to act if already X
246 }
247 }
248
1/2
✓ Branch 1 taken 63 times.
✗ Branch 2 not taken.
63 pauli0.string.map.at(qb) = Pauli::Z;
249
1/2
✓ Branch 1 taken 63 times.
✗ Branch 2 not taken.
63 pauli1.string.map.at(qb) = Pauli::X;
250 }
251
252 /*
253 * Step 2.iii: Remove the final matching qubit against a mismatch if one
254 * exists, otherwise allow both gadgets to build it
255 */
256
2/2
✓ Branch 1 taken 33 times.
✓ Branch 2 taken 35 times.
2/2
✓ Decision 'true' taken 33 times.
✓ Decision 'false' taken 35 times.
68 if (!match.empty()) {
257 33 Qubit last_match = *match.begin();
258
1/2
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
33 match.erase(last_match);
259
2/2
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 17 times.
2/2
✓ Decision 'true' taken 16 times.
✓ Decision 'false' taken 17 times.
33 if (!mismatch.empty()) {
260 Qubit mismatch_used =
261 16 *mismatch.rbegin(); // Prefer to use the one that may be left over
262 // after reducing pairs
263
4/8
✓ Branch 4 taken 16 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 16 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 16 times.
✓ Branch 12 taken 16 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
32 u.add_op<Qubit>(OpType::S, {mismatch_used});
264
4/8
✓ Branch 5 taken 16 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 16 times.
✗ Branch 9 not taken.
✓ Branch 12 taken 32 times.
✓ Branch 13 taken 16 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
48 u.add_op<Qubit>(OpType::CX, {last_match, mismatch_used});
265
4/8
✓ Branch 4 taken 16 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 16 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 16 times.
✓ Branch 12 taken 16 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
32 u.add_op<Qubit>(OpType::Sdg, {mismatch_used});
266
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 pauli0.string.map.erase(last_match);
267
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 pauli1.string.map.erase(last_match);
268 16 } else {
269
1/2
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
17 just0.insert(last_match);
270
1/2
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
17 just1.insert(last_match);
271 }
272 33 }
273
274 /*
275 * Step 2.iv: Reduce pairs of mismatches to different qubits.
276 * Allow both gadgets to build a remaining qubit if it exists.
277 */
278 68 std::set<Qubit>::iterator mis_it = mismatch.begin();
279
2/2
✓ Branch 2 taken 42 times.
✓ Branch 3 taken 68 times.
2/2
✓ Decision 'true' taken 42 times.
✓ Decision 'false' taken 68 times.
110 while (mis_it != mismatch.end()) {
280 42 Qubit z_in_0 = *mis_it;
281
1/2
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
42 just0.insert(z_in_0);
282 42 mis_it++;
283
2/2
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 21 times.
2/2
✓ Decision 'true' taken 21 times.
✓ Decision 'false' taken 21 times.
42 if (mis_it == mismatch.end()) {
284
1/2
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
21 just1.insert(z_in_0);
285 } else {
286 21 Qubit x_in_1 = *mis_it;
287
4/8
✓ Branch 5 taken 21 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 21 times.
✗ Branch 9 not taken.
✓ Branch 12 taken 42 times.
✓ Branch 13 taken 21 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
63 u.add_op<Qubit>(OpType::CX, {x_in_1, z_in_0});
288
1/2
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
21 pauli0.string.map.erase(x_in_1);
289
1/2
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
21 pauli1.string.map.erase(z_in_0);
290
1/2
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
21 just1.insert(x_in_1);
291 21 mis_it++;
292 21 }
293 42 }
294
295 /*
296 * Step 3: Combine circuits to give final result
297 */
298
1/2
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
68 circ.append(u);
299
2/4
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 68 times.
✗ Branch 5 not taken.
68 append_single_pauli_gadget(circ, pauli0, angle0);
300
2/4
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 68 times.
✗ Branch 5 not taken.
68 append_single_pauli_gadget(circ, pauli1, angle1);
301
1/2
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
136 Circuit udg = u.dagger();
302
1/2
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
68 circ.append(udg);
303 68 }
304
305 } // namespace tket
306