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 |