| 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 |