GCC Code Coverage Report


Directory: ./
File: Transformations/CliffordOptimisation.cpp
Date: 2022-10-15 05:10:18
Warnings: 2 unchecked decisions!
Exec Total Coverage
Lines: 457 477 95.8%
Functions: 8 8 100.0%
Branches: 624 1013 61.6%
Decisions: 16 20 80.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 "CliffordOptimisation.hpp"
16
17 #include <vector>
18
19 #include "BasicOptimisation.hpp"
20 #include "Circuit/CircPool.hpp"
21 #include "Circuit/DAGDefs.hpp"
22 #include "Decomposition.hpp"
23 #include "Transform.hpp"
24
25 namespace tket {
26
27 namespace Transforms {
28
29 static bool multiq_clifford_match(Circuit &circ, bool allow_swaps);
30 static bool copy_pi_through_CX_method(Circuit &circ);
31
32 16 Transform multiq_clifford_replacement(bool allow_swaps) {
33 16 return Transform([allow_swaps](Circuit &circ) {
34 16 return multiq_clifford_match(circ, allow_swaps);
35
1/2
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
16 });
36 }
37
38 16 static bool multiq_clifford_match(Circuit &circ, bool allow_swaps) {
39 16 bool success = false;
40 // map from vertex/port to qubit number
41
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 std::map<Vertex, unit_set_t> v_to_qb = circ.vertex_unit_map();
42 // map from vertex to its depth from slices/reverse_slices
43
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 std::map<Vertex, unsigned> v_to_depth = circ.vertex_depth_map();
44
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 std::map<Vertex, unsigned> v_to_rev_depth = circ.vertex_rev_depth_map();
45 // Analysis complete, we can now go through and actually do the transformation
46 16 VertexList bin;
47
7/8
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 313 times.
✓ Branch 6 taken 16 times.
✓ Branch 8 taken 313 times.
✓ Branch 9 taken 16 times.
✓ Branch 11 taken 16 times.
✓ Branch 12 taken 16 times.
345 BGL_FORALL_VERTICES(v, circ.dag, DAG) {
48
5/6
✓ Branch 1 taken 313 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 76 times.
✓ Branch 4 taken 237 times.
✓ Branch 5 taken 56 times.
✓ Branch 6 taken 257 times.
2/2
✓ Decision 'true' taken 56 times.
✓ Decision 'false' taken 333 times.
389 if (circ.get_OpType_from_Vertex(v) == OpType::CX &&
49
3/4
✓ Branch 1 taken 76 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 56 times.
✓ Branch 4 taken 20 times.
76 circ.n_out_edges(v) == 2) {
50 // Walk to next CX on the same pair
51
2/4
✓ Branch 1 taken 56 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 56 times.
✗ Branch 5 not taken.
56 unit_set_t cx_units = v_to_qb.at(v);
52
1/2
✓ Branch 4 taken 56 times.
✗ Branch 5 not taken.
56 qubit_vector_t qbs(cx_units.begin(), cx_units.end());
53 56 QPathDetailed path0;
54 56 QPathDetailed path1;
55 56 bool found_cnot = false;
56
1/2
✓ Branch 1 taken 56 times.
✗ Branch 2 not taken.
56 Edge e0 = circ.get_nth_out_edge(v, 0);
57
1/2
✓ Branch 1 taken 56 times.
✗ Branch 2 not taken.
56 Vertex v0 = circ.target(e0);
58
1/2
✓ Branch 1 taken 56 times.
✗ Branch 2 not taken.
56 port_t port = circ.get_target_port(e0);
59 while (true) {
60
1/2
✓ Branch 1 taken 135 times.
✗ Branch 2 not taken.
135 OpType v_type = circ.get_OpType_from_Vertex(v0);
61
3/4
✓ Branch 1 taken 135 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 27 times.
✓ Branch 4 taken 108 times.
2/2
✓ Decision 'true' taken 27 times.
✓ Decision 'false' taken 108 times.
135 if (is_final_q_type(v_type)) {
62 27 break;
63
8/10
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 64 times.
✓ Branch 3 taken 44 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 44 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 29 times.
✓ Branch 9 taken 15 times.
✓ Branch 10 taken 29 times.
✓ Branch 11 taken 79 times.
2/2
✓ Decision 'true' taken 29 times.
✓ Decision 'false' taken 79 times.
108 } else if (v_type == OpType::CX && v_to_qb.at(v0) == cx_units) {
64 29 found_cnot = true;
65 29 break;
66 }
67
1/2
✓ Branch 2 taken 79 times.
✗ Branch 3 not taken.
79 path0.push_back({v0, port});
68
1/2
✓ Branch 1 taken 79 times.
✗ Branch 2 not taken.
79 e0 = circ.get_next_edge(v0, e0);
69
1/2
✓ Branch 1 taken 79 times.
✗ Branch 2 not taken.
79 v0 = circ.target(e0);
70
1/2
✓ Branch 1 taken 79 times.
✗ Branch 2 not taken.
79 port = circ.get_target_port(e0);
71 79 }
72
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 29 times.
2/2
✓ Decision 'true' taken 27 times.
✓ Decision 'false' taken 29 times.
56 if (!found_cnot) {
73 27 continue;
74 }
75
1/2
✓ Branch 1 taken 29 times.
✗ Branch 2 not taken.
29 Edge e1 = circ.get_nth_out_edge(v, 1);
76
1/2
✓ Branch 1 taken 29 times.
✗ Branch 2 not taken.
29 Vertex v1 = circ.target(e1);
77
2/2
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 29 times.
2/2
✓ Decision 'true' taken 55 times.
✓ Decision 'false' taken 29 times.
84 while (v1 != v0) {
78
2/4
✓ Branch 1 taken 55 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 55 times.
✗ Branch 6 not taken.
55 path1.push_back({v1, circ.get_target_port(e1)});
79
1/2
✓ Branch 1 taken 55 times.
✗ Branch 2 not taken.
55 e1 = circ.get_next_edge(v1, e1);
80
1/2
✓ Branch 1 taken 55 times.
✗ Branch 2 not taken.
55 v1 = circ.target(e1);
81 }
82 29 unsigned path0_length = path0.size();
83 29 unsigned path1_length = path1.size();
84 29 unsigned front0_index = 0;
85 29 unsigned front1_index = 0;
86
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 11 times.
2/2
✓ Decision 'true' taken 22 times.
✓ Decision 'false' taken 11 times.
55 while (front0_index < path0_length &&
87
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 18 times.
22 circ.commutes_with_basis(
88
3/4
✓ Branch 3 taken 22 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 29 times.
55 path0[front0_index].first, Pauli::Z, PortType::Target,
89 22 path0[front0_index].second)) {
90 4 front0_index++;
91 }
92
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 12 times.
2/2
✓ Decision 'true' taken 26 times.
✓ Decision 'false' taken 12 times.
64 while (front1_index < path1_length &&
93
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 17 times.
26 circ.commutes_with_basis(
94
3/4
✓ Branch 3 taken 26 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 9 times.
✓ Branch 6 taken 29 times.
64 path1[front1_index].first, Pauli::X, PortType::Target,
95 26 path1[front1_index].second)) {
96 9 front1_index++;
97 }
98
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 15 times.
2/2
✓ Decision 'true' taken 14 times.
✓ Decision 'false' taken 15 times.
29 if (port == 0) {
99 // CXs have same orientation
100 // We walk back from the end of the path
101 // unsigned is used as this is semantically an index and the check for
102 // -1 functions the same as if it were signed
103 14 unsigned back0_index = path0_length - 1;
104
4/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 7 times.
0/1
? Decision couldn't be analyzed.
21 while (back0_index != front0_index && back0_index != (unsigned)-1 &&
105
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 circ.commutes_with_basis(
106
3/4
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 14 times.
21 path0[back0_index].first, Pauli::Z, PortType::Target,
107 4 path0[back0_index].second)) {
108 3 back0_index--;
109 }
110 14 unsigned back1_index = path1_length - 1;
111
4/4
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 7 times.
0/1
? Decision couldn't be analyzed.
30 while (back1_index != front1_index && back1_index != (unsigned)-1 &&
112
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 2 times.
9 circ.commutes_with_basis(
113
3/4
✓ Branch 3 taken 9 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 7 times.
✓ Branch 6 taken 14 times.
30 path1[back1_index].first, Pauli::X, PortType::Target,
114 9 path1[back1_index].second)) {
115 7 back1_index--;
116 }
117 // Check for valid causal ordering
118 Vertex front0pre =
119
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 13 times.
14 (front0_index == 0) ? v : path0[front0_index - 1].first;
120 Vertex front0post =
121
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 times.
14 (front0_index == path0_length) ? v0 : path0[front0_index].first;
122 Vertex front1pre =
123
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 10 times.
14 (front1_index == 0) ? v : path1[front1_index - 1].first;
124 Vertex front1post =
125
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 times.
14 (front1_index == path1_length) ? v0 : path1[front1_index].first;
126 Vertex back0pre =
127
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 times.
14 (back0_index == (unsigned)-1) ? v : path0[back0_index].first;
128 14 Vertex back0post = (back0_index == path0_length - 1)
129
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 12 times.
16 ? v0
130 2 : path0[back0_index + 1].first;
131 Vertex back1pre =
132
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 times.
14 (back1_index == (unsigned)-1) ? v : path1[back1_index].first;
133 14 Vertex back1post = (back1_index == path1_length - 1)
134
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 10 times.
18 ? v0
135 4 : path1[back1_index + 1].first;
136
3/4
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 13 times.
14 if (circ.in_causal_order(
137 front1pre, front0post, true, v_to_depth, v_to_qb))
138 4 continue;
139
2/4
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 13 times.
13 if (circ.in_causal_order(
140 front0pre, front1post, true, v_to_depth, v_to_qb))
141 continue;
142
2/4
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 13 times.
13 if (circ.in_causal_order(
143 back1post, back0pre, false, v_to_rev_depth, v_to_qb))
144 continue;
145
3/4
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 12 times.
13 if (circ.in_causal_order(
146 back0post, back1pre, false, v_to_rev_depth, v_to_qb))
147 1 continue;
148 // Identify which pattern to replace
149 12 bool v_on_q0 = false;
150
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 7 times.
12 if (front0_index != path0_length) {
151
2/4
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 5 times.
5 if (circ.get_OpType_from_Vertex(path0[front0_index].first) !=
152 OpType::V) {
153 // The only non-empty pattern we can recognise is from a V
154 continue;
155 }
156 5 v_on_q0 = true;
157
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (back0_index != front0_index) {
158 // There are some ops after the V that we cannot commute past the CX
159 continue;
160 }
161 }
162 12 bool s_on_q1 = false;
163
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 if (front1_index != path1_length) {
164
3/4
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 5 times.
6 if (circ.get_OpType_from_Vertex(path1[front1_index].first) !=
165 OpType::S) {
166 // The only non-empty pattern we can recognise is from a S
167 1 continue;
168 }
169 5 s_on_q1 = true;
170 11 if (back1_index == front1_index + 2 &&
171
2/4
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 circ.get_OpType_from_Vertex(path1[front1_index + 1].first) ==
172
4/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 4 times.
6 OpType::V &&
173
2/4
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 circ.get_OpType_from_Vertex(path1[front1_index + 2].first) ==
174 OpType::S) {
175 /* --C-- ... --C-- --C-- ... --C-- */
176 /* | | => | | */
177 /* --X--S--V--S--X-- --X--V--S--V--X-- */
178
3/6
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
1 circ.dag[path1[front1_index].first] = {get_op_ptr(OpType::V)};
179
3/6
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
1 circ.dag[path1[front1_index + 1].first] = {get_op_ptr(OpType::S)};
180
3/6
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
1 circ.dag[path1[front1_index + 2].first] = {get_op_ptr(OpType::V)};
181
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 circ.add_phase(0.25);
182 1 front1_index++;
183 1 back1_index--;
184
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 } else if (back1_index != front1_index) {
185 // There are some ops after the S that we cannot commute past the CX
186 continue;
187 }
188 }
189
4/6
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 5 times.
11 if (!allow_swaps && v_on_q0 && s_on_q1) {
190 continue;
191 }
192 11 success = true;
193 // Always remove the CX pair, saving the new edges from the second
194
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 Edge next_e0 = circ.get_nth_out_edge(v0, 0);
195
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 Edge next_e1 = circ.get_nth_out_edge(v0, 1);
196
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 Vertex next_v0 = circ.target(next_e0);
197
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 Vertex next_v1 = circ.target(next_e1);
198
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 port_t next_p0 = circ.get_target_port(next_e0);
199
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 port_t next_p1 = circ.get_target_port(next_e1);
200
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 bin.push_back(v);
201
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 bin.push_back(v0);
202
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 circ.remove_vertex(
203 v, Circuit::GraphRewiring::Yes, Circuit::VertexDeletion::No);
204
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 circ.remove_vertex(
205 v0, Circuit::GraphRewiring::Yes, Circuit::VertexDeletion::No);
206
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 Edge default_h0 = circ.get_nth_in_edge(next_v0, next_p0);
207
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 Edge default_h1 = circ.get_nth_in_edge(next_v1, next_p1);
208
209 11 Subcircuit sub;
210 const Circuit *replacement;
211
2/4
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 11 times.
✗ Branch 5 not taken.
11 Qubit q0, q1;
212
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 6 times.
11 if (v_on_q0) {
213 5 Vertex v_gate = path0[front0_index].first;
214
2/4
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
5 q0 = Qubit(*v_to_qb.at(v_gate).begin());
215
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 q1 = qbs.at(0);
216
3/6
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
5 if (q0 == q1) q1 = qbs.at(1);
217
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (s_on_q1) {
218 /* --C--V--C-- --Z--S--V--X--S--\ /-- */
219 /* | | => | \ */
220 /* --X--S--X-- --X--V--S--C--V--/ \-- */
221 Vertex s_gate = path1[front1_index].first;
222 bin.push_back(v_gate);
223 bin.push_back(s_gate);
224 sub = {
225 {circ.get_nth_in_edge(v_gate, 0),
226 circ.get_nth_in_edge(s_gate, 0)},
227 {circ.get_nth_out_edge(v_gate, 0),
228 circ.get_nth_out_edge(s_gate, 0)},
229 {v_gate, s_gate}};
230 replacement = &CircPool::CX_VS_CX_reduced();
231 } else {
232 /* --C--V--C-- --X--V--S--V--C--V--S-- */
233 /* | | => | */
234 /* --X-----X-- --V-----------X-------- */
235
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 bin.push_back(v_gate);
236 sub = {
237
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 {circ.get_nth_in_edge(v_gate, 0), default_h1},
238
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 {circ.get_nth_out_edge(v_gate, 0), default_h1},
239
4/8
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 5 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 5 times.
✗ Branch 14 not taken.
10 {v_gate}};
240
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 replacement = &CircPool::CX_V_CX_reduced();
241 }
242
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 times.
6 } else if (s_on_q1) {
243 /* --C-----C-- --S-----------C-------- */
244 /* | | => | */
245 /* --X--S--X-- --Z--S--V--S--X--S--V-- */
246 5 Vertex s_gate = path1[front1_index].first;
247
2/4
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
5 q1 = Qubit(*v_to_qb.at(s_gate).begin());
248
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 q0 = qbs.at(0);
249
2/6
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
5 if (q0 == q1) q0 = qbs.at(1);
250
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 bin.push_back(s_gate);
251 sub = {
252 {default_h0, circ.get_nth_in_edge(s_gate, 0)},
253 {default_h0, circ.get_nth_out_edge(s_gate, 0)},
254
6/12
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 5 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 5 times.
✗ Branch 9 not taken.
✓ Branch 12 taken 5 times.
✗ Branch 13 not taken.
✓ Branch 16 taken 5 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 5 times.
✗ Branch 20 not taken.
5 {s_gate}};
255
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 replacement = &CircPool::CX_S_CX_reduced();
256 } else {
257 /* --C--C-- ---- */
258 /* | | => */
259 /* --X--X-- ---- */
260 1 continue;
261 }
262
1/2
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
10 Vertex b0 = circ.source(sub.q_in_hole[0]);
263
1/2
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
10 port_t p0 = circ.get_source_port(sub.q_in_hole[0]);
264
1/2
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
10 Vertex b1 = circ.source(sub.q_in_hole[1]);
265
1/2
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
10 port_t p1 = circ.get_source_port(sub.q_in_hole[1]);
266
1/2
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
10 Vertex a0 = circ.target(sub.q_out_hole[0]);
267
1/2
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
10 Vertex a1 = circ.target(sub.q_out_hole[1]);
268
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 circ.substitute(*replacement, sub, Circuit::VertexDeletion::No);
269 // Scan through hole and add vertices to v_to_qb
270 // and give estimates of depth and rev_depth
271
2/4
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
10 unsigned new_depth = std::min(v_to_depth[a0], v_to_depth[a1]);
272 unsigned new_rev_depth =
273
2/4
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
10 std::min(v_to_rev_depth[b0], v_to_rev_depth[b1]);
274
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 Edge ei0 = circ.get_nth_out_edge(b0, p0);
275
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 Vertex vi0 = circ.target(ei0);
276
2/2
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 10 times.
55 while (vi0 != a0) {
277
5/10
✓ Branch 3 taken 45 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 45 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 45 times.
✗ Branch 10 not taken.
✓ Branch 14 taken 45 times.
✓ Branch 15 taken 45 times.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
90 v_to_qb.insert({vi0, {q0}});
278
1/2
✓ Branch 1 taken 45 times.
✗ Branch 2 not taken.
45 v_to_depth[vi0] = new_depth;
279
1/2
✓ Branch 1 taken 45 times.
✗ Branch 2 not taken.
45 v_to_rev_depth[vi0] = new_rev_depth;
280
1/2
✓ Branch 1 taken 45 times.
✗ Branch 2 not taken.
45 ei0 = circ.get_next_edge(vi0, ei0);
281
1/2
✓ Branch 1 taken 45 times.
✗ Branch 2 not taken.
45 vi0 = circ.target(ei0);
282 }
283
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 Edge ei1 = circ.get_nth_out_edge(b1, p1);
284
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 Vertex vi1 = circ.target(ei1);
285
2/2
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 10 times.
55 while (vi1 != a1) {
286
3/4
✓ Branch 2 taken 45 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 35 times.
✓ Branch 6 taken 10 times.
45 if (v_to_qb.find(vi1) == v_to_qb.end())
287
5/10
✓ Branch 3 taken 35 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 35 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 35 times.
✗ Branch 10 not taken.
✓ Branch 14 taken 35 times.
✓ Branch 15 taken 35 times.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
70 v_to_qb.insert({vi1, {q1}});
288 else
289
2/4
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
10 v_to_qb.at(vi1).insert(q1);
290
1/2
✓ Branch 1 taken 45 times.
✗ Branch 2 not taken.
45 v_to_depth[vi1] = new_depth;
291
1/2
✓ Branch 1 taken 45 times.
✗ Branch 2 not taken.
45 v_to_rev_depth[vi1] = new_rev_depth;
292
1/2
✓ Branch 1 taken 45 times.
✗ Branch 2 not taken.
45 ei1 = circ.get_next_edge(vi1, ei1);
293
1/2
✓ Branch 1 taken 45 times.
✗ Branch 2 not taken.
45 vi1 = circ.target(ei1);
294 }
295
6/6
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 1 times.
✓ Branch 4 taken 10 times.
✓ Branch 5 taken 1 times.
✓ Branch 7 taken 10 times.
✓ Branch 8 taken 1 times.
13 } else {
296 // CXs have different orientation
297 15 unsigned back0_index = path0_length - 1;
298
4/4
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 4 times.
36 while (back0_index >= front0_index && back0_index != (unsigned)-1 &&
299
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 9 times.
15 circ.commutes_with_basis(
300
3/4
✓ Branch 3 taken 15 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
✓ Branch 6 taken 15 times.
36 path0[back0_index].first, Pauli::X, PortType::Target,
301 15 path0[back0_index].second)) {
302 6 back0_index--;
303 }
304 15 unsigned back1_index = path1_length - 1;
305
4/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 4 times.
32 while (back1_index >= front1_index && back1_index != (unsigned)-1 &&
306
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 9 times.
13 circ.commutes_with_basis(
307
3/4
✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 15 times.
32 path1[back1_index].first, Pauli::Z, PortType::Target,
308 13 path1[back1_index].second)) {
309 4 back1_index--;
310 }
311 Vertex front0pre =
312
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 13 times.
15 (front0_index == 0) ? v : path0[front0_index - 1].first;
313 Vertex front0post =
314
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 4 times.
15 (front0_index == path0_length) ? v0 : path0[front0_index].first;
315 Vertex front1pre =
316
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 13 times.
15 (front1_index == 0) ? v : path1[front1_index - 1].first;
317 Vertex front1post =
318
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 (front1_index == path1_length) ? v0 : path1[front1_index].first;
319 Vertex back0pre =
320
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 4 times.
15 (back0_index == (unsigned)-1) ? v : path0[back0_index].first;
321 15 Vertex back0post = (back0_index == path0_length - 1)
322
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 11 times.
19 ? v0
323 4 : path0[back0_index + 1].first;
324 Vertex back1pre =
325
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 4 times.
15 (back1_index == (unsigned)-1) ? v : path1[back1_index].first;
326 15 Vertex back1post = (back1_index == path1_length - 1)
327
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 12 times.
18 ? v0
328 3 : path1[back1_index + 1].first;
329
3/4
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 14 times.
15 if (circ.in_causal_order(
330 front1pre, front0post, true, v_to_depth, v_to_qb))
331 8 continue;
332
2/4
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 14 times.
14 if (circ.in_causal_order(
333 front0pre, front1post, true, v_to_depth, v_to_qb))
334 continue;
335
2/4
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 14 times.
14 if (circ.in_causal_order(
336 back1post, back0pre, false, v_to_rev_depth, v_to_qb))
337 continue;
338
2/4
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 14 times.
14 if (circ.in_causal_order(
339 back0post, back1pre, false, v_to_rev_depth, v_to_qb))
340 continue;
341 // Identify which pattern
342 14 bool vs_on_q0 = false;
343
4/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 3 times.
14 if (back0_index >= front0_index && back0_index != (unsigned)-1) {
344
4/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 6 times.
17 if (!(back0_index == front0_index + 1 &&
345
3/4
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 2 times.
8 circ.get_OpType_from_Vertex(path0[front0_index].first) ==
346 OpType::V &&
347
2/4
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
6 circ.get_OpType_from_Vertex(path0[back0_index].first) ==
348 OpType::S)) {
349 // The only non-empty pattern we can recognise is from VS
350 3 continue;
351 }
352 6 vs_on_q0 = true;
353 }
354 11 bool sv_on_q1 = false;
355
4/4
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 4 times.
11 if (back1_index >= front1_index && back1_index != (unsigned)-1) {
356
4/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 5 times.
11 if (!(back1_index == front1_index + 1 &&
357
2/4
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
5 circ.get_OpType_from_Vertex(path1[front1_index].first) ==
358 OpType::S &&
359
2/4
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 5 times.
5 circ.get_OpType_from_Vertex(path1[back1_index].first) ==
360 OpType::V)) {
361 // The only non-empty pattern we can recognise is from SV
362 1 continue;
363 }
364 5 sv_on_q1 = true;
365 }
366
6/6
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 3 times.
10 if (!allow_swaps && !vs_on_q0 && !sv_on_q1) {
367 1 continue;
368 }
369 9 success = true;
370 // Always remove the CX pair, saving the edges to insert the replacement
371 // circuit
372 Vertex before0, before1, after0, after1;
373 port_t pb0, pb1, pa0, pa1;
374
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 8 times.
9 if (front0_index > 0) {
375 1 before0 = path0[front0_index - 1].first;
376 1 pb0 = path0[front0_index - 1].second;
377 } else {
378
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 Edge pre0 = circ.get_nth_in_edge(v, 0);
379
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 before0 = circ.source(pre0);
380
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 pb0 = circ.get_source_port(pre0);
381 }
382
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 8 times.
9 if (front1_index > 0) {
383 1 before1 = path1[front1_index - 1].first;
384 1 pb1 = path1[front1_index - 1].second;
385 } else {
386
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 Edge pre1 = circ.get_nth_in_edge(v, 1);
387
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 before1 = circ.source(pre1);
388
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 pb1 = circ.get_source_port(pre1);
389 }
390
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 7 times.
9 if (back0_index + 1 < path0_length) {
391 2 after0 = path0[back0_index + 1].first;
392 2 pa0 = path0[back0_index + 1].second;
393 } else {
394
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 Edge post0 = circ.get_nth_out_edge(v0, 1);
395
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 after0 = circ.target(post0);
396
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 pa0 = circ.get_target_port(post0);
397 }
398
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 7 times.
9 if (back1_index + 1 < path1_length) {
399 2 after1 = path1[back1_index + 1].first;
400 2 pa1 = path1[back1_index + 1].second;
401 } else {
402
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 Edge post1 = circ.get_nth_out_edge(v0, 0);
403
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 after1 = circ.target(post1);
404
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 pa1 = circ.get_target_port(post1);
405 }
406
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 bin.push_back(v);
407
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 bin.push_back(v0);
408
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 circ.remove_vertex(
409 v, Circuit::GraphRewiring::Yes, Circuit::VertexDeletion::No);
410
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 circ.remove_vertex(
411 v0, Circuit::GraphRewiring::Yes, Circuit::VertexDeletion::No);
412 9 VertexSet to_remove;
413 const Circuit *replacement;
414
2/4
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
9 Qubit q0, q1;
415
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 4 times.
9 if (vs_on_q0) {
416 5 Vertex v_gate = path0[front0_index].first;
417
2/4
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
5 q0 = Qubit(*v_to_qb.at(v_gate).begin());
418
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 q1 = qbs.at(0);
419
3/6
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
5 if (q0 == q1) q1 = qbs.at(1);
420
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
5 if (sv_on_q1) {
421 /* --C--V--S--X-- --V--S-- */
422 /* | | => */
423 /* --X--S--V--C-- --S--V-- */
424 2 continue;
425 } else {
426 /* --C--V--S--X-- --S-----C--V--S-- */
427 /* | | => | */
428 /* --X--------C-- --Z--S--X--S----- */
429
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 replacement = &CircPool::CX_V_S_XC_reduced();
430 }
431
1/2
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 bin.push_back(path0[front0_index].first);
432
1/2
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 bin.push_back(path0[back0_index].first);
433
1/2
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 to_remove.insert(path0[front0_index].first);
434
1/2
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 to_remove.insert(path0[back0_index].first);
435
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 } else if (sv_on_q1) {
436 /* --C--------X-- --X--V--C--V----- */
437 /* | | => | */
438 /* --X--S--V--C-- --V-----X--S--V-- */
439 3 Vertex s_gate = path1[front1_index].first;
440
2/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
3 q1 = Qubit(*v_to_qb.at(s_gate).begin());
441
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 q0 = qbs.at(0);
442
4/6
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 1 times.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
3 if (q0 == q1) q0 = qbs.at(1);
443
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 replacement = &CircPool::CX_S_V_XC_reduced();
444
1/2
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 bin.push_back(path1[front1_index].first);
445
1/2
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 bin.push_back(path1[back1_index].first);
446
1/2
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 to_remove.insert(path1[front1_index].first);
447
1/2
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 to_remove.insert(path1[back1_index].first);
448 } else {
449 /* --C--X-- --X--\ /-- */
450 /* | | => | \ */
451 /* --X--C-- --C--/ \-- */
452
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 q0 = qbs.at(0);
453
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 q1 = qbs.at(1);
454
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 replacement = &CircPool::CX_XC_reduced();
455 }
456 Subcircuit sub = {
457
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 {circ.get_nth_out_edge(before0, pb0),
458
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 circ.get_nth_out_edge(before1, pb1)},
459
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 {circ.get_nth_in_edge(after0, pa0),
460
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 circ.get_nth_in_edge(after1, pa1)},
461
3/6
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 7 times.
✗ Branch 10 not taken.
21 to_remove};
462
1/2
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
7 Vertex b0 = circ.source(sub.q_in_hole[0]);
463
1/2
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
7 port_t p0 = circ.get_source_port(sub.q_in_hole[0]);
464
1/2
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
7 Vertex b1 = circ.source(sub.q_in_hole[1]);
465
1/2
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
7 port_t p1 = circ.get_source_port(sub.q_in_hole[1]);
466
1/2
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
7 Vertex a0 = circ.target(sub.q_out_hole[0]);
467
1/2
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
7 Vertex a1 = circ.target(sub.q_out_hole[1]);
468
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 circ.substitute(*replacement, sub, Circuit::VertexDeletion::No);
469 // Scan through hole and add vertices to v_to_qb
470
2/4
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
7 unsigned new_depth = std::min(v_to_depth[a0], v_to_depth[a1]);
471 unsigned new_rev_depth =
472
2/4
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
7 std::min(v_to_rev_depth[b0], v_to_rev_depth[b1]);
473
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 Edge ei0 = circ.get_nth_out_edge(b0, p0);
474
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 Vertex vi0 = circ.target(ei0);
475
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 7 times.
33 while (vi0 != a0) {
476
5/10
✓ Branch 3 taken 26 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 26 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 26 times.
✗ Branch 10 not taken.
✓ Branch 14 taken 26 times.
✓ Branch 15 taken 26 times.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
52 v_to_qb.insert({vi0, {q0}});
477
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 v_to_depth[vi0] = new_depth;
478
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 v_to_rev_depth[vi0] = new_rev_depth;
479
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 ei0 = circ.get_next_edge(vi0, ei0);
480
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 vi0 = circ.target(ei0);
481 }
482
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 Edge ei1 = circ.get_nth_out_edge(b1, p1);
483
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 Vertex vi1 = circ.target(ei1);
484
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 7 times.
33 while (vi1 != a1) {
485
3/4
✓ Branch 2 taken 26 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 18 times.
✓ Branch 6 taken 8 times.
26 if (v_to_qb.find(vi1) == v_to_qb.end())
486
5/10
✓ Branch 3 taken 18 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 18 times.
✗ Branch 10 not taken.
✓ Branch 14 taken 18 times.
✓ Branch 15 taken 18 times.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
36 v_to_qb.insert({vi1, {q1}});
487 else
488
2/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
8 v_to_qb.at(vi1).insert(q1);
489
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 v_to_depth[vi1] = new_depth;
490
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 v_to_rev_depth[vi1] = new_rev_depth;
491
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 ei1 = circ.get_next_edge(vi1, ei1);
492
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 vi1 = circ.target(ei1);
493 }
494
6/6
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 2 times.
✓ Branch 5 taken 7 times.
✓ Branch 6 taken 2 times.
✓ Branch 8 taken 7 times.
✓ Branch 9 taken 2 times.
13 }
495
8/8
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 39 times.
✓ Branch 4 taken 17 times.
✓ Branch 5 taken 39 times.
✓ Branch 7 taken 17 times.
✓ Branch 8 taken 39 times.
✓ Branch 10 taken 17 times.
✓ Branch 11 taken 39 times.
173 }
496 }
497
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 if (allow_swaps) {
498
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 circ.replace_SWAPs();
499 }
500
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 circ.remove_vertices(
501 bin, Circuit::GraphRewiring::No, Circuit::VertexDeletion::Yes);
502 16 return success;
503 16 }
504
505
1/2
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
5 Transform copy_pi_through_CX() { return Transform(copy_pi_through_CX_method); }
506
507 // TODO:: Copy classical-controls and any controls from CX
508 5 static bool copy_pi_through_CX_method(Circuit &circ) {
509 5 bool success = false;
510 5 VertexList bin;
511
7/8
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 41 times.
✓ Branch 6 taken 5 times.
✓ Branch 8 taken 41 times.
✓ Branch 9 taken 5 times.
✓ Branch 11 taken 5 times.
✓ Branch 12 taken 5 times.
51 BGL_FORALL_VERTICES(vert, circ.dag, DAG) {
512
5/6
✓ Branch 1 taken 41 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 32 times.
✓ Branch 5 taken 9 times.
✓ Branch 6 taken 32 times.
50 if (circ.get_OpType_from_Vertex(vert) == OpType::CX &&
513
2/4
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
✗ Branch 4 not taken.
9 circ.n_out_edges(vert) == 2) {
514
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 Edge e0 = circ.get_nth_out_edge(vert, 0);
515
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 Vertex v0 = circ.target(e0);
516
3/4
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 7 times.
9 if (circ.get_OpType_from_Vertex(v0) == OpType::X) {
517 2 success = true;
518
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 Edge afterX = circ.get_next_edge(v0, e0);
519
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 Edge after1 = circ.get_nth_out_edge(vert, 1);
520
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 Vertex v_after1 = circ.target(after1);
521
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 port_t pa1 = circ.get_target_port(after1);
522
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 bin.push_back(vert);
523
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 circ.remove_vertex(
524 vert, Circuit::GraphRewiring::Yes, Circuit::VertexDeletion::No);
525
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 after1 = circ.get_nth_in_edge(v_after1, pa1);
526
3/6
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
4 Subcircuit sub = {{afterX, after1}, {afterX, after1}};
527
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
2 circ.substitute(CircPool::X1_CX(), sub, Circuit::VertexDeletion::No);
528 2 continue;
529 2 }
530
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 Edge e1 = circ.get_nth_out_edge(vert, 1);
531
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 Vertex v1 = circ.target(e1);
532
3/4
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 6 times.
7 if (circ.get_OpType_from_Vertex(v1) == OpType::Z) {
533 1 success = true;
534
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 Edge afterZ = circ.get_next_edge(v1, e1);
535
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 Edge after0 = circ.get_nth_out_edge(vert, 0);
536
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 Vertex v_after0 = circ.target(after0);
537
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 port_t pa0 = circ.get_target_port(after0);
538
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 bin.push_back(vert);
539
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 circ.remove_vertex(
540 vert, Circuit::GraphRewiring::Yes, Circuit::VertexDeletion::No);
541
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 after0 = circ.get_nth_in_edge(v_after0, pa0);
542
3/6
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
2 Subcircuit sub = {{after0, afterZ}, {after0, afterZ}};
543
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 circ.substitute(CircPool::Z0_CX(), sub, Circuit::VertexDeletion::No);
544 1 }
545 }
546 }
547
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 circ.remove_vertices(
548 bin, Circuit::GraphRewiring::No, Circuit::VertexDeletion::Yes);
549 5 return success;
550 5 }
551
552 // TODO:: Detect classical controls and stop simplification
553 3530 static bool singleq_clifford_from_edge(
554 Circuit &circ, Edge &e, VertexList &bin) {
555 3530 VertexSet single_vs;
556 3530 Edge ei = e;
557
1/2
✓ Branch 1 taken 3530 times.
✗ Branch 2 not taken.
3530 Vertex vi = circ.target(ei);
558 // stuff to check if it is already in standard form
559 // 6 = not consumed anything, 5=Z, 4=X, 3=first S, 2=V, 1=second S, 0=other
560 3530 unsigned cliff_last = 6;
561
3/4
✓ Branch 1 taken 19160 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 15630 times.
✓ Branch 4 taken 3530 times.
19160 while (circ.detect_singleq_unitary_op(vi)) {
562 // i.e. we have a single qubit unitary
563
1/2
✓ Branch 1 taken 15630 times.
✗ Branch 2 not taken.
15630 single_vs.insert(vi);
564
565 // keep track of clifford standard form
566
6/7
✓ Branch 1 taken 15630 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2027 times.
✓ Branch 4 taken 2831 times.
✓ Branch 5 taken 3296 times.
✓ Branch 6 taken 3646 times.
✓ Branch 7 taken 3830 times.
15630 switch (circ.get_OpType_from_Vertex(vi)) {
567 2027 case OpType::Z: {
568
2/2
✓ Branch 0 taken 473 times.
✓ Branch 1 taken 1554 times.
2027 cliff_last = (cliff_last > 5) ? 5 : 0;
569 2027 break;
570 }
571 2831 case OpType::X: {
572
2/2
✓ Branch 0 taken 634 times.
✓ Branch 1 taken 2197 times.
2831 cliff_last = (cliff_last > 4) ? 4 : 0;
573 2831 break;
574 }
575 3296 case OpType::S: {
576
2/2
✓ Branch 0 taken 633 times.
✓ Branch 1 taken 2663 times.
3296 if (cliff_last > 3)
577 633 cliff_last = 3;
578
2/2
✓ Branch 0 taken 641 times.
✓ Branch 1 taken 2022 times.
2663 else if (cliff_last == 2)
579 641 cliff_last = 1;
580 else
581 2022 cliff_last = 0;
582 3296 break;
583 }
584 3646 case OpType::V: {
585
2/2
✓ Branch 0 taken 1402 times.
✓ Branch 1 taken 2244 times.
3646 cliff_last = (cliff_last > 2) ? 2 : 0;
586 3646 break;
587 }
588 3830 default: {
589 3830 cliff_last = 0;
590 3830 break;
591 }
592 }
593
594
1/2
✓ Branch 1 taken 15630 times.
✗ Branch 2 not taken.
15630 ei = circ.get_next_edge(vi, ei);
595
1/2
✓ Branch 1 taken 15630 times.
✗ Branch 2 not taken.
15630 vi = circ.target(ei);
596 }
597 // if the sequence is not in the standard form, replace it
598
2/2
✓ Branch 0 taken 2502 times.
✓ Branch 1 taken 1028 times.
3530 if (cliff_last == 0) {
599
3/6
✓ Branch 2 taken 2502 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 2502 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 2502 times.
✗ Branch 10 not taken.
5004 Subcircuit s = {{e}, {ei}, single_vs};
600
1/2
✓ Branch 1 taken 2502 times.
✗ Branch 2 not taken.
2502 Circuit sub = circ.subcircuit(s);
601
4/8
✓ Branch 1 taken 2502 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2502 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2502 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 2502 times.
✗ Branch 11 not taken.
7506 bool reduced = (decompose_single_qubits_TK1() >> squash_1qb_to_tk1() >>
602
1/2
✓ Branch 1 taken 2502 times.
✗ Branch 2 not taken.
5004 decompose_cliffords_std())
603
1/2
✓ Branch 1 taken 2502 times.
✗ Branch 2 not taken.
2502 .apply(sub);
604
1/2
✓ Branch 0 taken 2502 times.
✗ Branch 1 not taken.
2502 if (reduced) {
605
1/2
✓ Branch 1 taken 2502 times.
✗ Branch 2 not taken.
2502 circ.substitute(sub, s, Circuit::VertexDeletion::No);
606
1/2
✓ Branch 5 taken 2502 times.
✗ Branch 6 not taken.
2502 bin.insert(bin.end(), single_vs.begin(), single_vs.end());
607 2502 return true;
608 }
609
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 2502 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2502 times.
5004 }
610 1028 return false;
611 3530 }
612
613 171 Transform singleq_clifford_sweep() {
614 174 return Transform([](Circuit &circ) {
615 174 bool success = false;
616 174 VertexList bin;
617
1/2
✓ Branch 1 taken 174 times.
✗ Branch 2 not taken.
174 std::vector<Vertex> vertices = circ.vertices_in_order();
618
3/4
✓ Branch 4 taken 16029 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 15855 times.
✓ Branch 7 taken 174 times.
16029 for (auto it = vertices.crbegin(); it != vertices.crend(); ++it) {
619 15855 const Vertex &v = *it;
620
3/4
✓ Branch 1 taken 15855 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1518 times.
✓ Branch 4 taken 14337 times.
15855 if (circ.get_OpType_from_Vertex(v) == OpType::CX) {
621
2/2
✓ Branch 0 taken 3036 times.
✓ Branch 1 taken 1518 times.
4554 for (port_t p = 0; p < 2; p++) {
622 // put both subsequent single qubit sequences into normal form
623 // stuff for obtaining next single qubit subcircuit
624
1/2
✓ Branch 1 taken 3036 times.
✗ Branch 2 not taken.
3036 Edge e = circ.get_nth_out_edge(v, p);
625
5/6
✓ Branch 1 taken 3036 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 929 times.
✓ Branch 4 taken 2107 times.
✓ Branch 5 taken 800 times.
✓ Branch 6 taken 129 times.
3036 success = singleq_clifford_from_edge(circ, e, bin) || success;
626 }
627 // commute Z, X and whatever else we can through
628
1/2
✓ Branch 1 taken 1518 times.
✗ Branch 2 not taken.
1518 Edge e0 = circ.get_nth_out_edge(v, 0);
629
1/2
✓ Branch 1 taken 1518 times.
✗ Branch 2 not taken.
1518 Vertex v0 = circ.target(e0);
630
631
3/4
✓ Branch 1 taken 1518 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 214 times.
✓ Branch 4 taken 1304 times.
1518 if (circ.get_OpType_from_Vertex(v0) == OpType::Z) {
632
1/2
✓ Branch 1 taken 214 times.
✗ Branch 2 not taken.
214 circ.remove_vertex(
633 v0, Circuit::GraphRewiring::Yes, Circuit::VertexDeletion::No);
634
1/2
✓ Branch 1 taken 214 times.
✗ Branch 2 not taken.
214 Edge in_e = circ.get_nth_in_edge(v, 0);
635
3/6
✓ Branch 2 taken 214 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 214 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 214 times.
✗ Branch 10 not taken.
214 circ.rewire(v0, {in_e}, {EdgeType::Quantum});
636 214 success = true;
637
1/2
✓ Branch 1 taken 214 times.
✗ Branch 2 not taken.
214 e0 = circ.get_nth_out_edge(v, 0);
638
1/2
✓ Branch 1 taken 214 times.
✗ Branch 2 not taken.
214 v0 = circ.target(e0);
639 }
640
3/4
✓ Branch 1 taken 1518 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 352 times.
✓ Branch 4 taken 1166 times.
1518 if (circ.get_OpType_from_Vertex(v0) == OpType::X) {
641
1/2
✓ Branch 1 taken 352 times.
✗ Branch 2 not taken.
352 circ.remove_vertex(
642 v0, Circuit::GraphRewiring::Yes, Circuit::VertexDeletion::No);
643
1/2
✓ Branch 1 taken 352 times.
✗ Branch 2 not taken.
352 Edge in_e = circ.get_nth_in_edge(v, 0);
644
3/6
✓ Branch 2 taken 352 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 352 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 352 times.
✗ Branch 10 not taken.
352 circ.rewire(v0, {in_e}, {EdgeType::Quantum});
645
1/2
✓ Branch 2 taken 352 times.
✗ Branch 3 not taken.
352 Vertex new_v = circ.add_vertex(OpType::X);
646
1/2
✓ Branch 1 taken 352 times.
✗ Branch 2 not taken.
352 in_e = circ.get_nth_in_edge(v, 1);
647
3/6
✓ Branch 2 taken 352 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 352 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 352 times.
✗ Branch 10 not taken.
352 circ.rewire(new_v, {in_e}, {EdgeType::Quantum});
648 352 success = true;
649
1/2
✓ Branch 1 taken 352 times.
✗ Branch 2 not taken.
352 e0 = circ.get_nth_out_edge(v, 0);
650
1/2
✓ Branch 1 taken 352 times.
✗ Branch 2 not taken.
352 v0 = circ.target(e0);
651 }
652
3/4
✓ Branch 1 taken 1518 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 355 times.
✓ Branch 4 taken 1163 times.
1518 if (circ.get_OpType_from_Vertex(v0) == OpType::S) {
653
1/2
✓ Branch 1 taken 355 times.
✗ Branch 2 not taken.
355 circ.remove_vertex(
654 v0, Circuit::GraphRewiring::Yes, Circuit::VertexDeletion::No);
655
1/2
✓ Branch 1 taken 355 times.
✗ Branch 2 not taken.
355 Edge in_e = circ.get_nth_in_edge(v, 0);
656
3/6
✓ Branch 2 taken 355 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 355 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 355 times.
✗ Branch 10 not taken.
355 circ.rewire(v0, {in_e}, {EdgeType::Quantum});
657 355 success = true;
658 }
659
1/2
✓ Branch 1 taken 1518 times.
✗ Branch 2 not taken.
1518 Edge e1 = circ.get_nth_out_edge(v, 1);
660
1/2
✓ Branch 1 taken 1518 times.
✗ Branch 2 not taken.
1518 Vertex v1 = circ.target(e1);
661
3/4
✓ Branch 1 taken 1518 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 266 times.
✓ Branch 4 taken 1252 times.
1518 if (circ.get_OpType_from_Vertex(v1) == OpType::Z) {
662
1/2
✓ Branch 1 taken 266 times.
✗ Branch 2 not taken.
266 circ.remove_vertex(
663 v1, Circuit::GraphRewiring::Yes, Circuit::VertexDeletion::No);
664
1/2
✓ Branch 1 taken 266 times.
✗ Branch 2 not taken.
266 Edge in_e = circ.get_nth_in_edge(v, 1);
665
3/6
✓ Branch 2 taken 266 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 266 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 266 times.
✗ Branch 10 not taken.
266 circ.rewire(v1, {in_e}, {EdgeType::Quantum});
666
1/2
✓ Branch 2 taken 266 times.
✗ Branch 3 not taken.
266 Vertex new_v = circ.add_vertex(OpType::Z);
667
1/2
✓ Branch 1 taken 266 times.
✗ Branch 2 not taken.
266 in_e = circ.get_nth_in_edge(v, 0);
668
3/6
✓ Branch 2 taken 266 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 266 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 266 times.
✗ Branch 10 not taken.
266 circ.rewire(new_v, {in_e}, {EdgeType::Quantum});
669 266 success = true;
670
1/2
✓ Branch 1 taken 266 times.
✗ Branch 2 not taken.
266 e1 = circ.get_nth_out_edge(v, 1);
671
1/2
✓ Branch 1 taken 266 times.
✗ Branch 2 not taken.
266 v1 = circ.target(e1);
672 }
673
3/4
✓ Branch 1 taken 1518 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 360 times.
✓ Branch 4 taken 1158 times.
1518 if (circ.get_OpType_from_Vertex(v1) == OpType::X) {
674
1/2
✓ Branch 1 taken 360 times.
✗ Branch 2 not taken.
360 circ.remove_vertex(
675 v1, Circuit::GraphRewiring::Yes, Circuit::VertexDeletion::No);
676
1/2
✓ Branch 1 taken 360 times.
✗ Branch 2 not taken.
360 Edge in_e = circ.get_nth_in_edge(v, 1);
677
3/6
✓ Branch 2 taken 360 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 360 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 360 times.
✗ Branch 10 not taken.
360 circ.rewire(v1, {in_e}, {EdgeType::Quantum});
678 360 success = true;
679
1/2
✓ Branch 1 taken 360 times.
✗ Branch 2 not taken.
360 e1 = circ.get_nth_out_edge(v, 1);
680
1/2
✓ Branch 1 taken 360 times.
✗ Branch 2 not taken.
360 v1 = circ.target(e1);
681 }
682
3/4
✓ Branch 1 taken 1518 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 164 times.
✓ Branch 4 taken 1354 times.
1518 if (circ.get_OpType_from_Vertex(v1) == OpType::V) {
683
1/2
✓ Branch 1 taken 164 times.
✗ Branch 2 not taken.
164 circ.remove_vertex(
684 v1, Circuit::GraphRewiring::Yes, Circuit::VertexDeletion::No);
685
1/2
✓ Branch 1 taken 164 times.
✗ Branch 2 not taken.
164 Edge in_e = circ.get_nth_in_edge(v, 1);
686
3/6
✓ Branch 2 taken 164 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 164 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 164 times.
✗ Branch 10 not taken.
164 circ.rewire(v1, {in_e}, {EdgeType::Quantum});
687 164 success = true;
688 }
689 }
690 }
691 // clean up the start of the circuit
692
3/4
✓ Branch 1 taken 174 times.
✗ Branch 2 not taken.
✓ Branch 7 taken 494 times.
✓ Branch 8 taken 174 times.
668 for (const Vertex &i : circ.q_inputs()) {
693
1/2
✓ Branch 1 taken 494 times.
✗ Branch 2 not taken.
494 Edge e = circ.get_nth_out_edge(i, 0);
694
5/6
✓ Branch 1 taken 494 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 99 times.
✓ Branch 4 taken 395 times.
✓ Branch 5 taken 80 times.
✓ Branch 6 taken 19 times.
494 success = singleq_clifford_from_edge(circ, e, bin) || success;
695 174 }
696
1/2
✓ Branch 1 taken 174 times.
✗ Branch 2 not taken.
174 circ.remove_vertices(
697 bin, Circuit::GraphRewiring::No, Circuit::VertexDeletion::Yes);
698 174 return success;
699
1/2
✓ Branch 2 taken 171 times.
✗ Branch 3 not taken.
345 });
700 }
701
702 } // namespace Transforms
703
704 } // namespace tket
705