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 "BasicOptimisation.hpp" | |||
16 | ||||
17 | #include <optional> | |||
18 | #include <tkassert/Assert.hpp> | |||
19 | ||||
20 | #include "Characterisation/DeviceCharacterisation.hpp" | |||
21 | #include "Characterisation/ErrorTypes.hpp" | |||
22 | #include "Circuit/CircPool.hpp" | |||
23 | #include "Circuit/CircUtils.hpp" | |||
24 | #include "Circuit/Command.hpp" | |||
25 | #include "Circuit/DAGDefs.hpp" | |||
26 | #include "Decomposition.hpp" | |||
27 | #include "Gate/Gate.hpp" | |||
28 | #include "Gate/GatePtr.hpp" | |||
29 | #include "Gate/Rotation.hpp" | |||
30 | #include "Transform.hpp" | |||
31 | #include "Utils/EigenConfig.hpp" | |||
32 | #include "Utils/MatrixAnalysis.hpp" | |||
33 | ||||
34 | namespace tket { | |||
35 | ||||
36 | namespace Transforms { | |||
37 | ||||
38 | static bool redundancy_removal(Circuit &circ); | |||
39 | static bool remove_redundancy( | |||
40 | Circuit &circ, const Vertex &vert, VertexSet &bin, | |||
41 | std::set<IVertex> &new_affected_verts, IndexMap &im); | |||
42 | static bool commute_singles_to_front(Circuit &circ); | |||
43 | ||||
44 |
1/2✓ Branch 2 taken 1638 times.
✗ Branch 3 not taken.
|
1638 | Transform remove_redundancies() { return Transform(redundancy_removal); } | |
45 | ||||
46 | // this method annihilates all primitives next to each other (accounting for | |||
47 | // previous annihilations) | |||
48 | // also removes redundant non-classically controlled Z basis gates before a z | |||
49 | // basis measurement so that eg. -H-X-X-H- always annihilates to ----- | |||
50 | 2016 | static bool redundancy_removal(Circuit &circ) { | ||
51 | 2016 | bool success = false; | ||
52 | 2016 | bool found_redundancy = true; | ||
53 |
1/2✓ Branch 1 taken 2016 times.
✗ Branch 2 not taken.
|
2016 | IndexMap im = circ.index_map(); | |
54 | 2016 | std::set<IVertex> old_affected_verts; | ||
55 |
7/8✓ Branch 1 taken 2016 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 74300 times.
✓ Branch 5 taken 2016 times.
✓ Branch 7 taken 74300 times.
✓ Branch 8 taken 2016 times.
✓ Branch 10 taken 2016 times.
✓ Branch 11 taken 2016 times.
|
78332 | BGL_FORALL_VERTICES(v, circ.dag, DAG) { | |
56 |
2/4✓ Branch 1 taken 74300 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 74300 times.
✗ Branch 6 not taken.
|
74300 | old_affected_verts.insert({im.at(v), v}); | |
57 | } | |||
58 | 2016 | VertexSet bin; | ||
59 |
2/2✓ Branch 0 taken 3332 times.
✓ Branch 1 taken 2016 times.
|
2/2✓ Decision 'true' taken 3332 times.
✓ Decision 'false' taken 2016 times.
|
5348 | while (found_redundancy) { |
60 | 3332 | std::set<IVertex> new_affected_verts; | ||
61 | 3332 | bool removed = false; | ||
62 |
2/2✓ Branch 4 taken 77365 times.
✓ Branch 5 taken 3332 times.
|
2/2✓ Decision 'true' taken 77365 times.
✓ Decision 'false' taken 3332 times.
|
80697 | for (const IVertex &p : old_affected_verts) { |
63 |
1/2✓ Branch 1 taken 77365 times.
✗ Branch 2 not taken.
|
77365 | removed |= remove_redundancy(circ, p.second, bin, new_affected_verts, im); | |
64 | } | |||
65 | 3332 | found_redundancy = removed; | ||
66 | 3332 | success |= removed; | ||
67 |
1/2✓ Branch 1 taken 3332 times.
✗ Branch 2 not taken.
|
3332 | old_affected_verts = new_affected_verts; | |
68 | 3332 | } | ||
69 |
1/2✓ Branch 1 taken 2016 times.
✗ Branch 2 not taken.
|
2016 | circ.remove_vertices( | |
70 | bin, Circuit::GraphRewiring::No, Circuit::VertexDeletion::Yes); | |||
71 | 2016 | return success; | ||
72 | 2016 | } | ||
73 | ||||
74 | // called by the previous method. This should generally not be called | |||
75 | // independently | |||
76 | 77365 | static bool remove_redundancy( | ||
77 | Circuit &circ, const Vertex &vert, VertexSet &bin, | |||
78 | std::set<IVertex> &new_affected_verts, IndexMap &im) { | |||
79 |
1/2✓ Branch 1 taken 77365 times.
✗ Branch 2 not taken.
|
77365 | const Op_ptr op = circ.get_Op_ptr_from_Vertex(vert); | |
80 |
1/2✓ Branch 2 taken 77365 times.
✗ Branch 3 not taken.
|
77365 | const OpDesc desc = op->get_desc(); | |
81 |
3/4✓ Branch 1 taken 77365 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12904 times.
✓ Branch 4 taken 64461 times.
|
2/2✓ Decision 'true' taken 64461 times.
✓ Decision 'false' taken 12904 times.
|
77365 | if (!desc.is_gate()) return false; |
82 | ||||
83 |
3/4✓ Branch 1 taken 64461 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 535 times.
✓ Branch 4 taken 63926 times.
|
2/2✓ Decision 'true' taken 535 times.
✓ Decision 'false' taken 63926 times.
|
64461 | if (bin.contains(vert)) { |
84 | 535 | return false; // we have already removed it | ||
85 | } | |||
86 | ||||
87 | 379 | auto remove_single_vertex = [&bin, &circ, &new_affected_verts, | ||
88 | 1520 | &im](const Vertex &v_remove) { | ||
89 | 379 | bin.insert(v_remove); | ||
90 |
3/4✓ Branch 1 taken 379 times.
✗ Branch 2 not taken.
✓ Branch 7 taken 383 times.
✓ Branch 8 taken 379 times.
|
0/1? Decision couldn't be analyzed.
|
762 | for (const Vertex &l : circ.get_predecessors(v_remove)) { |
91 |
2/4✓ Branch 1 taken 383 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 383 times.
✗ Branch 6 not taken.
|
383 | new_affected_verts.insert({im.at(l), l}); | |
92 | 379 | } | ||
93 | 379 | circ.remove_vertex( | ||
94 | v_remove, Circuit::GraphRewiring::Yes, Circuit::VertexDeletion::No); | |||
95 | 379 | }; | ||
96 | // remove identities from circuit | |||
97 |
1/2✓ Branch 2 taken 63926 times.
✗ Branch 3 not taken.
|
63926 | std::optional<double> a = op->is_identity(); | |
98 |
2/2✓ Branch 1 taken 375 times.
✓ Branch 2 taken 63551 times.
|
2/2✓ Decision 'true' taken 375 times.
✓ Decision 'false' taken 63551 times.
|
63926 | if (a) { |
99 |
1/2✓ Branch 1 taken 375 times.
✗ Branch 2 not taken.
|
375 | remove_single_vertex(vert); | |
100 |
3/6✓ Branch 1 taken 375 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 375 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 375 times.
✗ Branch 8 not taken.
|
375 | circ.add_phase(a.value()); | |
101 | 375 | return true; | ||
102 | } | |||
103 |
1/2✓ Branch 1 taken 63551 times.
✗ Branch 2 not taken.
|
63551 | VertexVec kids = circ.get_successors(vert); | |
104 | ||||
105 | // if op is immediately followed by a z basis measurement on all qubits, | |||
106 | // remove | |||
107 |
3/4✓ Branch 1 taken 63551 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 63468 times.
✓ Branch 4 taken 83 times.
|
2/2✓ Decision 'true' taken 63468 times.
✓ Decision 'false' taken 83 times.
|
63551 | if (circ.n_out_edges_of_type(vert, EdgeType::Classical) == 0) { |
108 | 63468 | bool z_followed_by_measures = true; | ||
109 |
6/6✓ Branch 1 taken 87443 times.
✓ Branch 2 taken 39511 times.
✓ Branch 3 taken 63486 times.
✓ Branch 4 taken 23957 times.
✓ Branch 5 taken 63486 times.
✓ Branch 6 taken 63468 times.
|
0/1? Decision couldn't be analyzed.
|
126954 | for (port_t port = 0; port < kids.size() && z_followed_by_measures; |
110 | port++) { | |||
111 |
3/4✓ Branch 2 taken 63486 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 54 times.
✓ Branch 5 taken 63432 times.
|
2/2✓ Decision 'true' taken 54 times.
✓ Decision 'false' taken 63432 times.
|
63486 | if (circ.get_OpType_from_Vertex(kids[port]) == OpType::Measure) { |
112 | 54 | z_followed_by_measures &= | ||
113 |
1/2✓ Branch 2 taken 54 times.
✗ Branch 3 not taken.
|
54 | circ.commutes_with_basis(vert, Pauli::Z, PortType::Source, port); | |
114 | } else { | |||
115 | 63432 | z_followed_by_measures = false; | ||
116 | } | |||
117 | } | |||
118 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 63464 times.
|
2/2✓ Decision 'true' taken 4 times.
✓ Decision 'false' taken 63464 times.
|
63468 | if (z_followed_by_measures) { |
119 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | remove_single_vertex(vert); | |
120 | 4 | return true; | ||
121 | } | |||
122 | } | |||
123 | ||||
124 | // check that both the vertex and its successor have each other and only each | |||
125 | // other | |||
126 |
9/12✓ Branch 1 taken 39490 times.
✓ Branch 2 taken 24057 times.
✓ Branch 5 taken 39490 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 13743 times.
✓ Branch 9 taken 25747 times.
✓ Branch 10 taken 39490 times.
✓ Branch 11 taken 24057 times.
✓ Branch 13 taken 13743 times.
✓ Branch 14 taken 49804 times.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
|
2/2✓ Decision 'true' taken 13743 times.
✓ Decision 'false' taken 49804 times.
|
63547 | if ((kids.size() == 1) && (circ.get_predecessors(kids[0]).size() == 1)) { |
127 | // check that the ports match up between vertices | |||
128 | 13743 | Vertex b = kids[0]; | ||
129 |
1/2✓ Branch 1 taken 13743 times.
✗ Branch 2 not taken.
|
13743 | EdgeVec ins = circ.get_in_edges(b); | |
130 |
2/2✓ Branch 5 taken 14852 times.
✓ Branch 6 taken 13606 times.
|
2/2✓ Decision 'true' taken 14852 times.
✓ Decision 'false' taken 13606 times.
|
28458 | for (const Edge &in : ins) { |
131 |
4/6✓ Branch 1 taken 14852 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 14852 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 137 times.
✓ Branch 7 taken 14715 times.
|
2/2✓ Decision 'true' taken 13606 times.
✓ Decision 'false' taken 1246 times.
|
14852 | if (circ.get_source_port(in) != circ.get_target_port(in)) return false; |
132 | } | |||
133 | ||||
134 | // check that the classical edges match up correctly | |||
135 |
2/4✓ Branch 1 taken 13606 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 13606 times.
|
1/2✓ Decision 'true' taken 13606 times.
✗ Decision 'false' not taken.
|
13606 | if (circ.n_in_edges_of_type(vert, EdgeType::Boolean) != 0) return false; |
136 | ||||
137 |
1/2✓ Branch 1 taken 13606 times.
✗ Branch 2 not taken.
|
13606 | const Op_ptr b_op = circ.get_Op_ptr_from_Vertex(b); | |
138 |
1/2✓ Branch 2 taken 13606 times.
✗ Branch 3 not taken.
|
13606 | const OpDesc b_desc = b_op->get_desc(); | |
139 | ||||
140 |
3/4✓ Branch 1 taken 13606 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 10715 times.
✓ Branch 4 taken 2891 times.
|
2/2✓ Decision 'true' taken 10715 times.
✓ Decision 'false' taken 2891 times.
|
13606 | if (!b_desc.is_oneway()) { |
141 | // if A = B.dagger(), AB = I | |||
142 | // This method cannot detect matches between rotation gates. | |||
143 | // Rotation gates are covered by the rotation gate combiner, everything | |||
144 | // else in this. | |||
145 |
4/6✓ Branch 3 taken 10715 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 10715 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1463 times.
✓ Branch 11 taken 9252 times.
|
2/2✓ Decision 'true' taken 1463 times.
✓ Decision 'false' taken 9252 times.
|
10715 | if (*b_op->dagger() == *op) { |
146 |
1/2✓ Branch 1 taken 1463 times.
✗ Branch 2 not taken.
|
1463 | bin.insert(vert); | |
147 |
1/2✓ Branch 1 taken 1463 times.
✗ Branch 2 not taken.
|
1463 | bin.insert(b); | |
148 |
1/2✓ Branch 1 taken 1463 times.
✗ Branch 2 not taken.
|
1463 | VertexVec last_verts = circ.get_predecessors(vert); | |
149 |
2/2✓ Branch 4 taken 2532 times.
✓ Branch 5 taken 1463 times.
|
2/2✓ Decision 'true' taken 2532 times.
✓ Decision 'false' taken 1463 times.
|
3995 | for (const Vertex &l : last_verts) { |
150 |
2/4✓ Branch 1 taken 2532 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 2532 times.
✗ Branch 6 not taken.
|
2532 | new_affected_verts.insert({im.at(l), l}); | |
151 | } | |||
152 |
1/2✓ Branch 2 taken 1463 times.
✗ Branch 3 not taken.
|
1463 | VertexList to_detach{vert, b}; | |
153 | // detached from circuit but not removed from graph | |||
154 |
1/2✓ Branch 1 taken 1463 times.
✗ Branch 2 not taken.
|
1463 | circ.remove_vertices( | |
155 | to_detach, Circuit::GraphRewiring::Yes, | |||
156 | Circuit::VertexDeletion::No); | |||
157 | 1463 | return true; | ||
158 |
3/4✓ Branch 3 taken 9252 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2106 times.
✓ Branch 6 taken 7146 times.
|
2/2✓ Decision 'true' taken 2106 times.
✓ Decision 'false' taken 8609 times.
|
10715 | } else if (desc.is_rotation()) { |
159 | // combine two rotation gates together, then if the combined | |||
160 | // operation is the identity up to phase, remove from circuit | |||
161 |
4/6✓ Branch 1 taken 2106 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2106 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 160 times.
✓ Branch 7 taken 1946 times.
|
2/2✓ Decision 'true' taken 160 times.
✓ Decision 'false' taken 1946 times.
|
2106 | if (b_desc.type() == desc.type()) { |
162 |
2/4✓ Branch 2 taken 160 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 160 times.
✗ Branch 7 not taken.
|
160 | Expr expr1 = op->get_params()[0]; | |
163 |
2/4✓ Branch 2 taken 160 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 160 times.
✗ Branch 7 not taken.
|
160 | Expr expr2 = b_op->get_params()[0]; | |
164 |
1/2✓ Branch 1 taken 160 times.
✗ Branch 2 not taken.
|
160 | VertexVec last_verts = circ.get_predecessors(vert); | |
165 |
2/2✓ Branch 4 taken 160 times.
✓ Branch 5 taken 160 times.
|
2/2✓ Decision 'true' taken 160 times.
✓ Decision 'false' taken 160 times.
|
320 | for (const Vertex &l : last_verts) { |
166 |
2/4✓ Branch 1 taken 160 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 160 times.
✗ Branch 6 not taken.
|
160 | new_affected_verts.insert({im.at(l), l}); | |
167 | } | |||
168 |
1/2✓ Branch 1 taken 160 times.
✗ Branch 2 not taken.
|
160 | circ.remove_vertex( | |
169 | b, Circuit::GraphRewiring::Yes, Circuit::VertexDeletion::No); | |||
170 |
1/2✓ Branch 1 taken 160 times.
✗ Branch 2 not taken.
|
160 | bin.insert(b); | |
171 |
2/4✓ Branch 1 taken 160 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 160 times.
✗ Branch 6 not taken.
|
480 | std::vector<Expr> params_new = {expr1 + expr2}; | |
172 |
2/4✓ Branch 2 taken 160 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 160 times.
✗ Branch 6 not taken.
|
160 | Op_ptr op_new = get_op_ptr(desc.type(), params_new, ins.size()); | |
173 |
1/2✓ Branch 2 taken 160 times.
✗ Branch 3 not taken.
|
160 | std::optional<double> a = op_new->is_identity(); | |
174 |
2/2✓ Branch 1 taken 53 times.
✓ Branch 2 taken 107 times.
|
2/2✓ Decision 'true' taken 53 times.
✓ Decision 'false' taken 107 times.
|
160 | if (a) { |
175 |
1/2✓ Branch 1 taken 53 times.
✗ Branch 2 not taken.
|
53 | bin.insert(vert); | |
176 |
1/2✓ Branch 1 taken 53 times.
✗ Branch 2 not taken.
|
53 | circ.remove_vertex( | |
177 | vert, Circuit::GraphRewiring::Yes, Circuit::VertexDeletion::No); | |||
178 |
3/6✓ Branch 1 taken 53 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 53 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 53 times.
✗ Branch 8 not taken.
|
53 | circ.add_phase(a.value()); | |
179 | } else { | |||
180 |
2/4✓ Branch 1 taken 107 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 107 times.
✗ Branch 6 not taken.
|
107 | new_affected_verts.insert({im[vert], vert}); | |
181 |
1/2✓ Branch 1 taken 107 times.
✗ Branch 2 not taken.
|
107 | circ.dag[vert].op = op_new; | |
182 | } | |||
183 | 160 | return true; | ||
184 | 160 | } | ||
185 | } | |||
186 | } | |||
187 |
6/6✓ Branch 1 taken 11983 times.
✓ Branch 2 taken 1623 times.
✓ Branch 4 taken 11983 times.
✓ Branch 5 taken 1623 times.
✓ Branch 7 taken 11983 times.
✓ Branch 8 taken 1760 times.
|
16989 | } | |
188 | 61787 | return false; | ||
189 | 77365 | } | ||
190 | ||||
191 | 150 | Transform commute_through_multis() { | ||
192 |
1/2✓ Branch 2 taken 150 times.
✗ Branch 3 not taken.
|
150 | return Transform(commute_singles_to_front); | |
193 | } | |||
194 | ||||
195 | // whether source and target commute | |||
196 | 16182 | static bool ends_commute(const Circuit &circ, const Edge &e) { | ||
197 |
1/2✓ Branch 1 taken 16182 times.
✗ Branch 2 not taken.
|
16182 | const std::pair<port_t, port_t> ports = circ.get_ports(e); | |
198 |
1/2✓ Branch 1 taken 16182 times.
✗ Branch 2 not taken.
|
16182 | const Vertex source = circ.source(e); | |
199 |
1/2✓ Branch 1 taken 16182 times.
✗ Branch 2 not taken.
|
16182 | const Vertex target = circ.target(e); | |
200 | ||||
201 | // We currently do not support commuting multi-qubit gates | |||
202 | // TODO: It would be useful to support commuting single-qubit gates with | |||
203 | // classical conditioning | |||
204 |
7/10✓ Branch 1 taken 16182 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 16182 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 16182 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 48 times.
✓ Branch 9 taken 16134 times.
✓ Branch 10 taken 48 times.
✓ Branch 11 taken 16134 times.
|
2/2✓ Decision 'true' taken 48 times.
✓ Decision 'false' taken 16134 times.
|
16182 | if (circ.n_in_edges(source) > 1 && circ.n_in_edges(target) > 1) { |
205 | 48 | return false; | ||
206 | } | |||
207 | ||||
208 |
1/2✓ Branch 1 taken 16134 times.
✗ Branch 2 not taken.
|
16134 | auto colour = circ.commuting_basis(target, PortType::Target, ports.second); | |
209 | 32268 | return circ.commutes_with_basis( | ||
210 |
1/2✓ Branch 1 taken 16134 times.
✗ Branch 2 not taken.
|
16134 | source, colour, PortType::Source, ports.first); | |
211 | } | |||
212 | ||||
213 | // moves single qubit operations past multiqubit operations they commute with, | |||
214 | // towards front of circuit (hardcoded) | |||
215 | 419 | static bool commute_singles_to_front(Circuit &circ) { | ||
216 | 419 | bool success = false; | ||
217 | // follow each qubit path from output to input | |||
218 |
3/4✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 8 taken 1577 times.
✓ Branch 9 taken 419 times.
|
0/1? Decision couldn't be analyzed.
|
1996 | for (const Qubit &q : circ.all_qubits()) { |
219 |
1/2✓ Branch 1 taken 1577 times.
✗ Branch 2 not taken.
|
1577 | Vertex prev_v = circ.get_out(q); | |
220 |
1/2✓ Branch 1 taken 1577 times.
✗ Branch 2 not taken.
|
1577 | Edge current_e = circ.get_nth_in_edge(prev_v, 0); | |
221 |
1/2✓ Branch 1 taken 1577 times.
✗ Branch 2 not taken.
|
1577 | Vertex current_v = circ.source(current_e); | |
222 |
4/6✓ Branch 1 taken 44928 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 44928 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 43351 times.
✓ Branch 7 taken 1577 times.
|
0/1? Decision couldn't be analyzed.
|
44928 | while (!is_initial_q_type(circ.get_OpType_from_Vertex(current_v))) { |
223 |
1/2✓ Branch 1 taken 43351 times.
✗ Branch 2 not taken.
|
43351 | const Op_ptr curr_op = circ.get_Op_ptr_from_Vertex(current_v); | |
224 | // if current vertex is a multiqubit gate | |||
225 |
3/4✓ Branch 1 taken 43351 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 21481 times.
✓ Branch 4 taken 21870 times.
|
2/2✓ Decision 'true' taken 41026 times.
✓ Decision 'false' taken 2325 times.
|
43351 | if (circ.n_in_edges_of_type(current_v, EdgeType::Quantum) > 1) { |
226 |
5/6✓ Branch 1 taken 24844 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 16182 times.
✓ Branch 4 taken 8662 times.
✓ Branch 5 taken 3363 times.
✓ Branch 6 taken 21481 times.
|
0/1? Decision couldn't be analyzed.
|
41026 | while (circ.n_in_edges_of_type(prev_v, EdgeType::Quantum) == 1 && |
227 |
3/4✓ Branch 1 taken 16182 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3363 times.
✓ Branch 4 taken 12819 times.
|
16182 | ends_commute(circ, current_e)) { | |
228 | // subsequent op on qubit path is a single qubit gate | |||
229 | // and commutes with current multi qubit gate | |||
230 | 3363 | success = true; | ||
231 | 3363 | EdgeVec rewire_edges; | ||
232 | 3363 | op_signature_t edge_types; | ||
233 |
3/4✓ Branch 1 taken 3363 times.
✗ Branch 2 not taken.
✓ Branch 8 taken 3363 times.
✓ Branch 9 taken 3363 times.
|
0/1? Decision couldn't be analyzed.
|
6726 | for (const Edge &e : circ.get_in_edges(prev_v)) { |
234 |
1/2✓ Branch 1 taken 3363 times.
✗ Branch 2 not taken.
|
3363 | EdgeType type = circ.get_edgetype(e); | |
235 |
1/2✓ Branch 1 taken 3363 times.
✗ Branch 2 not taken.
|
3363 | Edge boundary_edge; | |
236 | // Currently, only purely-quantum operations can be commuted | |||
237 | // through. This is guaranteed by `ends_commute`. It follows that | |||
238 | // any wire out of `prev_v` must be EdgeType::Quantum. | |||
239 | TKET_ASSERT(type == EdgeType::Quantum); | |||
240 |
1/2✓ Branch 1 taken 3363 times.
✗ Branch 2 not taken.
|
3363 | boundary_edge = circ.get_last_edge(current_v, current_e); | |
241 |
1/2✓ Branch 1 taken 3363 times.
✗ Branch 2 not taken.
|
3363 | rewire_edges.push_back(boundary_edge); | |
242 |
1/2✓ Branch 1 taken 3363 times.
✗ Branch 2 not taken.
|
3363 | edge_types.push_back(type); | |
243 | 3363 | } | ||
244 |
1/2✓ Branch 1 taken 3363 times.
✗ Branch 2 not taken.
|
3363 | const port_t backup_port = circ.get_source_port(current_e); | |
245 |
1/2✓ Branch 1 taken 3363 times.
✗ Branch 2 not taken.
|
3363 | circ.remove_vertex( | |
246 | prev_v, Circuit::GraphRewiring::Yes, Circuit::VertexDeletion::No); | |||
247 |
1/2✓ Branch 1 taken 3363 times.
✗ Branch 2 not taken.
|
3363 | circ.rewire(prev_v, rewire_edges, edge_types); | |
248 |
1/2✓ Branch 1 taken 3363 times.
✗ Branch 2 not taken.
|
3363 | current_e = circ.get_nth_out_edge(current_v, backup_port); | |
249 |
1/2✓ Branch 1 taken 3363 times.
✗ Branch 2 not taken.
|
3363 | prev_v = circ.target(current_e); | |
250 | 3363 | } | ||
251 | } | |||
252 | // move to next vertex (towards input) | |||
253 | 43351 | prev_v = current_v; | ||
254 |
1/2✓ Branch 1 taken 43351 times.
✗ Branch 2 not taken.
|
43351 | std::tie(current_v, current_e) = circ.get_prev_pair(current_v, current_e); | |
255 | 43351 | } | ||
256 | 419 | } | ||
257 | ||||
258 | 419 | return success; | ||
259 | } | |||
260 | ||||
261 | // helper class subcircuits representing 2qb interactions | |||
262 | struct Interaction { | |||
263 |
2/4✓ Branch 3 taken 749 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 749 times.
✗ Branch 7 not taken.
|
749 | Interaction(const Qubit &_q0, const Qubit &_q1) : q0(_q0), q1(_q1) {} | |
264 | Qubit q0; // Qubit numbers | |||
265 | Qubit q1; | |||
266 | Edge e0; // In edges starting interaction | |||
267 | Edge e1; | |||
268 | unsigned count; // Number of two qubit gates in interaction | |||
269 | VertexSet vertices; // Vertices in interaction subcircuit | |||
270 | }; | |||
271 | ||||
272 | 150 | static bool replace_two_qubit_interaction( | ||
273 | Circuit &circ, Interaction &i, std::map<Qubit, Edge> ¤t_edges, | |||
274 | VertexList &bin, OpType target, double cx_fidelity, bool allow_swaps) { | |||
275 |
1/2✓ Branch 2 taken 150 times.
✗ Branch 3 not taken.
|
150 | EdgeVec in_edges = {i.e0, i.e1}; | |
276 |
3/6✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 150 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 150 times.
✗ Branch 9 not taken.
|
150 | EdgeVec out_edges = {current_edges[i.q0], current_edges[i.q1]}; | |
277 |
2/4✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 150 times.
✗ Branch 5 not taken.
|
150 | Edge next0, next1; | |
278 |
1/2✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
|
150 | bool q0_is_out = is_final_q_type( | |
279 |
3/6✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 150 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 150 times.
✗ Branch 8 not taken.
|
150 | circ.get_OpType_from_Vertex(circ.target(current_edges[i.q0]))); | |
280 |
1/2✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
|
150 | bool q1_is_out = is_final_q_type( | |
281 |
3/6✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 150 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 150 times.
✗ Branch 8 not taken.
|
150 | circ.get_OpType_from_Vertex(circ.target(current_edges[i.q1]))); | |
282 |
2/2✓ Branch 0 taken 106 times.
✓ Branch 1 taken 44 times.
|
2/2✓ Decision 'true' taken 106 times.
✓ Decision 'false' taken 44 times.
|
150 | if (!q0_is_out) { |
283 | 106 | next0 = circ.get_next_edge( | ||
284 |
4/8✓ Branch 1 taken 106 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 106 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 106 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 106 times.
✗ Branch 11 not taken.
|
106 | circ.target(current_edges[i.q0]), current_edges[i.q0]); | |
285 | } | |||
286 |
2/2✓ Branch 0 taken 94 times.
✓ Branch 1 taken 56 times.
|
2/2✓ Decision 'true' taken 94 times.
✓ Decision 'false' taken 56 times.
|
150 | if (!q1_is_out) { |
287 | 94 | next1 = circ.get_next_edge( | ||
288 |
4/8✓ Branch 1 taken 94 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 94 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 94 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 94 times.
✗ Branch 11 not taken.
|
94 | circ.target(current_edges[i.q1]), current_edges[i.q1]); | |
289 | } | |||
290 | // Circuit to (potentially) substitute | |||
291 |
1/2✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
|
150 | Subcircuit sub = {in_edges, out_edges, i.vertices}; | |
292 |
1/2✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
|
150 | Circuit subc = circ.subcircuit(sub); | |
293 | ||||
294 | // Try to simplify using KAK | |||
295 |
1/2✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
|
150 | Circuit replacement = subc; | |
296 |
2/4✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 150 times.
✗ Branch 5 not taken.
|
150 | decompose_multi_qubits_TK2().apply(replacement); | |
297 |
1/2✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
|
150 | Eigen::Matrix4cd mat = get_matrix_from_2qb_circ(replacement); | |
298 |
2/4✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 150 times.
✗ Branch 5 not taken.
|
150 | replacement = two_qubit_canonical(mat); | |
299 | 150 | TwoQbFidelities fid; | ||
300 | 150 | fid.CX_fidelity = cx_fidelity; | ||
301 |
2/2✓ Branch 0 taken 111 times.
✓ Branch 1 taken 39 times.
|
2/2✓ Decision 'true' taken 111 times.
✓ Decision 'false' taken 39 times.
|
150 | if (target != OpType::TK2) { |
302 |
2/4✓ Branch 1 taken 111 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 111 times.
✗ Branch 5 not taken.
|
111 | decompose_TK2(fid, allow_swaps).apply(replacement); | |
303 | } | |||
304 | ||||
305 | // Whether to substitute old circuit with new | |||
306 | 150 | bool substitute = false; | ||
307 |
3/4✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
✓ Branch 8 taken 1176 times.
✓ Branch 9 taken 126 times.
|
0/1? Decision couldn't be analyzed.
|
1302 | for (Vertex v : subc.vertices_in_order()) { |
308 |
1/2✓ Branch 1 taken 1176 times.
✗ Branch 2 not taken.
|
1176 | unsigned n_ins = subc.n_in_edges_of_type(v, EdgeType::Quantum); | |
309 |
7/8✓ Branch 0 taken 346 times.
✓ Branch 1 taken 830 times.
✓ Branch 3 taken 346 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 24 times.
✓ Branch 6 taken 322 times.
✓ Branch 7 taken 24 times.
✓ Branch 8 taken 1152 times.
|
2/2✓ Decision 'true' taken 24 times.
✓ Decision 'false' taken 1152 times.
|
1176 | if (n_ins == 2 && subc.get_OpType_from_Vertex(v) != target) { |
310 | // Old circuit has non-target gates => we need to substitute | |||
311 | 24 | substitute = true; | ||
312 | 24 | break; | ||
313 | } | |||
314 | 150 | } | ||
315 |
2/2✓ Branch 0 taken 126 times.
✓ Branch 1 taken 24 times.
|
2/2✓ Decision 'true' taken 126 times.
✓ Decision 'false' taken 24 times.
|
150 | if (!substitute) { |
316 |
2/2✓ Branch 0 taken 103 times.
✓ Branch 1 taken 23 times.
|
2/2✓ Decision 'true' taken 103 times.
✓ Decision 'false' taken 23 times.
|
126 | if (target == OpType::CX) { |
317 |
1/2✓ Branch 1 taken 103 times.
✗ Branch 2 not taken.
|
103 | unsigned nb_2qb_old = subc.count_gates(target); | |
318 |
1/2✓ Branch 1 taken 103 times.
✗ Branch 2 not taken.
|
103 | unsigned nb_2qb_new = replacement.count_gates(target); | |
319 | 103 | substitute |= nb_2qb_new < nb_2qb_old; | ||
320 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
1/2✓ Decision 'true' taken 23 times.
✗ Decision 'false' not taken.
|
23 | } else if (target == OpType::TK2) { |
321 | 23 | unsigned cnt_2qb = 0; | ||
322 |
3/4✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
✓ Branch 7 taken 212 times.
✓ Branch 8 taken 23 times.
|
0/1? Decision couldn't be analyzed.
|
235 | for (Vertex v : subc.vertices_in_order()) { |
323 |
1/2✓ Branch 1 taken 212 times.
✗ Branch 2 not taken.
|
212 | unsigned n_ins = subc.n_in_edges_of_type(v, EdgeType::Quantum); | |
324 | 212 | cnt_2qb += n_ins == 2; | ||
325 | 23 | } | ||
326 | 23 | substitute |= cnt_2qb >= 2; | ||
327 | } | |||
328 | } | |||
329 | ||||
330 |
2/2✓ Branch 0 taken 110 times.
✓ Branch 1 taken 40 times.
|
2/2✓ Decision 'true' taken 110 times.
✓ Decision 'false' taken 40 times.
|
150 | if (substitute) { |
331 | // Substitute interaction with new circuit | |||
332 |
1/2✓ Branch 5 taken 110 times.
✗ Branch 6 not taken.
|
110 | bin.insert(bin.end(), sub.verts.begin(), sub.verts.end()); | |
333 |
1/2✓ Branch 1 taken 110 times.
✗ Branch 2 not taken.
|
110 | circ.substitute(replacement, sub, Circuit::VertexDeletion::No); | |
334 |
2/2✓ Branch 0 taken 70 times.
✓ Branch 1 taken 40 times.
|
2/2✓ Decision 'true' taken 70 times.
✓ Decision 'false' taken 40 times.
|
110 | if (!q0_is_out) { |
335 |
3/6✓ Branch 1 taken 70 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 70 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 70 times.
✗ Branch 8 not taken.
|
70 | current_edges[i.q0] = circ.get_last_edge(circ.source(next0), next0); | |
336 | } | |||
337 |
2/2✓ Branch 0 taken 72 times.
✓ Branch 1 taken 38 times.
|
2/2✓ Decision 'true' taken 72 times.
✓ Decision 'false' taken 38 times.
|
110 | if (!q1_is_out) { |
338 |
3/6✓ Branch 1 taken 72 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 72 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 72 times.
✗ Branch 8 not taken.
|
72 | current_edges[i.q1] = circ.get_last_edge(circ.source(next1), next1); | |
339 | } | |||
340 | 110 | return true; | ||
341 | } else { | |||
342 | // Leave circuit untouched | |||
343 | 40 | return false; | ||
344 | } | |||
345 | 150 | } | ||
346 | ||||
347 | 12 | Transform commute_and_combine_HQS2() { | ||
348 | 20 | return Transform([](Circuit &circ) { | ||
349 | 20 | bool success = false; | ||
350 | 20 | VertexList bin; | ||
351 |
7/8✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 578 times.
✓ Branch 6 taken 20 times.
✓ Branch 8 taken 578 times.
✓ Branch 9 taken 20 times.
✓ Branch 11 taken 20 times.
✓ Branch 12 taken 20 times.
|
618 | BGL_FORALL_VERTICES(v, circ.dag, DAG) { | |
352 |
1/2✓ Branch 1 taken 578 times.
✗ Branch 2 not taken.
|
578 | EdgeVec outs = circ.get_all_out_edges(v); | |
353 |
6/8✓ Branch 1 taken 578 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 78 times.
✓ Branch 4 taken 500 times.
✓ Branch 6 taken 78 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 78 times.
✓ Branch 9 taken 500 times.
|
2/2✓ Decision 'true' taken 78 times.
✓ Decision 'false' taken 500 times.
|
578 | if (circ.get_OpType_from_Vertex(v) == OpType::ZZMax && outs.size() == 2) { |
354 | 78 | Vertex next0 = boost::target(outs[0], circ.dag); | ||
355 | 78 | Vertex next1 = boost::target(outs[1], circ.dag); | ||
356 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 78 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 78 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 78 times.
|
78 | if (next0 == next1 && |
357 | ✗ | circ.get_OpType_from_Vertex(next0) == OpType::ZZMax) { | ||
358 | ✗ | success = true; | ||
359 | ✗ | EdgeVec h_in = circ.get_in_edges(v); | ||
360 | ✗ | EdgeVec h_out = circ.get_all_out_edges(next0); | ||
361 |
0/2✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
|
✗ | if (circ.get_target_port(outs[0]) != 0) { | |
362 | ✗ | h_out = {h_out[1], h_out[0]}; | ||
363 | } | |||
364 | ✗ | bin.push_back(v); | ||
365 | ✗ | bin.push_back(next0); | ||
366 | ✗ | Subcircuit sub = {h_in, h_out}; | ||
367 | ✗ | circ.substitute( | ||
368 | CircPool::two_Rz1(), sub, Circuit::VertexDeletion::No); | |||
369 | ✗ | circ.add_phase(0.5); | ||
370 | ✗ | continue; | ||
371 | } | |||
372 |
3/4✓ Branch 1 taken 78 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 19 times.
✓ Branch 4 taken 59 times.
|
2/2✓ Decision 'true' taken 19 times.
✓ Decision 'false' taken 59 times.
|
78 | if (circ.get_OpType_from_Vertex(next0) == OpType::Rz) { |
373 | 19 | success = true; | ||
374 |
1/2✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
|
19 | circ.remove_vertex( | |
375 | next0, Circuit::GraphRewiring::Yes, Circuit::VertexDeletion::No); | |||
376 |
1/2✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
|
19 | Edge in_0 = circ.get_nth_in_edge(v, 0); | |
377 |
3/6✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 19 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 19 times.
✗ Branch 10 not taken.
|
19 | circ.rewire(next0, {in_0}, {EdgeType::Quantum}); | |
378 | } | |||
379 |
2/4✓ Branch 1 taken 78 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 78 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 78 times.
|
78 | if (circ.get_OpType_from_Vertex(next1) == OpType::Rz) { |
380 | ✗ | success = true; | ||
381 | ✗ | circ.remove_vertex( | ||
382 | next1, Circuit::GraphRewiring::Yes, Circuit::VertexDeletion::No); | |||
383 | ✗ | Edge in_1 = circ.get_nth_in_edge(v, 1); | ||
384 | ✗ | circ.rewire(next1, {in_1}, {EdgeType::Quantum}); | ||
385 | } | |||
386 | } | |||
387 |
1/2✓ Branch 1 taken 578 times.
✗ Branch 2 not taken.
|
578 | } | |
388 |
1/2✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
|
20 | circ.remove_vertices( | |
389 | bin, Circuit::GraphRewiring::No, Circuit::VertexDeletion::Yes); | |||
390 | 20 | return success; | ||
391 |
1/2✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
|
32 | }); | |
392 | } | |||
393 | ||||
394 | 31 | Transform two_qubit_squash(bool allow_swaps) { | ||
395 | 31 | return two_qubit_squash(OpType::CX, 1., allow_swaps); | ||
396 | } | |||
397 | ||||
398 | 82 | Transform two_qubit_squash( | ||
399 | OpType target_2qb_gate, double cx_fidelity, bool allow_swaps) { | |||
400 |
1/2✓ Branch 2 taken 82 times.
✗ Branch 3 not taken.
|
82 | const std::set<OpType> accepted_ots{OpType::CX, OpType::TK2}; | |
401 |
2/4✓ Branch 1 taken 82 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 82 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 82 times.
|
82 | if (!accepted_ots.contains(target_2qb_gate)) { |
402 | ✗ | throw BadOpType( | ||
403 | "KAKDecomposition currently supports CX and TK2. " | |||
404 | "Cannot decompose to", | |||
405 | ✗ | target_2qb_gate); | ||
406 | } | |||
407 |
2/4✓ Branch 0 taken 82 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 82 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 82 times.
|
82 | if (cx_fidelity < 0 || cx_fidelity > 1) { |
408 | ✗ | throw std::invalid_argument("The CX fidelity must be between 0 and 1."); | ||
409 | } | |||
410 | ||||
411 | 235 | return Transform([target_2qb_gate, cx_fidelity, allow_swaps](Circuit &circ) { | ||
412 | 85 | bool success = false; | ||
413 | 85 | VertexList bin; | ||
414 | // Get map from vertex/port to qubit number | |||
415 | 85 | std::map<VertPort, Qubit> v_to_qb; | ||
416 | 85 | std::map<Qubit, Edge> current_edge_on_qb; | ||
417 | 85 | std::vector<Interaction> i_vec; | ||
418 | 85 | std::map<Qubit, int> current_interaction; | ||
419 |
3/4✓ Branch 1 taken 85 times.
✗ Branch 2 not taken.
✓ Branch 7 taken 254 times.
✓ Branch 8 taken 85 times.
|
0/1? Decision couldn't be analyzed.
|
339 | for (const Qubit &qb : circ.all_qubits()) { |
420 |
3/4✓ Branch 1 taken 254 times.
✗ Branch 2 not taken.
✓ Branch 7 taken 3780 times.
✓ Branch 8 taken 254 times.
|
0/1? Decision couldn't be analyzed.
|
4034 | for (const VertPort &vp : circ.unit_path(qb)) { |
421 |
1/2✓ Branch 2 taken 3780 times.
✗ Branch 3 not taken.
|
3780 | v_to_qb.insert({vp, qb}); | |
422 | 254 | } | ||
423 |
1/2✓ Branch 1 taken 254 times.
✗ Branch 2 not taken.
|
254 | Vertex input = circ.get_in(qb); | |
424 |
1/2✓ Branch 1 taken 254 times.
✗ Branch 2 not taken.
|
254 | Edge e = circ.get_nth_out_edge(input, 0); | |
425 |
1/2✓ Branch 1 taken 254 times.
✗ Branch 2 not taken.
|
254 | current_edge_on_qb[qb] = e; | |
426 |
1/2✓ Branch 1 taken 254 times.
✗ Branch 2 not taken.
|
254 | current_interaction[qb] = -1; | |
427 | 85 | } | ||
428 |
1/2✓ Branch 1 taken 85 times.
✗ Branch 2 not taken.
|
85 | SliceVec slices = circ.get_slices(); | |
429 |
2/4✓ Branch 1 taken 85 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 85 times.
✗ Branch 7 not taken.
|
85 | slices.insert(slices.begin(), circ.q_inputs()); | |
430 |
2/4✓ Branch 1 taken 85 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 85 times.
✗ Branch 5 not taken.
|
85 | slices.push_back(circ.q_outputs()); | |
431 |
2/2✓ Branch 4 taken 1717 times.
✓ Branch 5 taken 85 times.
|
2/2✓ Decision 'true' taken 1717 times.
✓ Decision 'false' taken 85 times.
|
1802 | for (SliceVec::iterator s = slices.begin(); s != slices.end(); ++s) { |
432 |
2/2✓ Branch 6 taken 2793 times.
✓ Branch 7 taken 1717 times.
|
2/2✓ Decision 'true' taken 2793 times.
✓ Decision 'false' taken 1717 times.
|
4510 | for (Slice::iterator v = s->begin(); v != s->end(); ++v) { |
433 |
1/2✓ Branch 2 taken 2793 times.
✗ Branch 3 not taken.
|
2793 | const Op_ptr o = circ.get_Op_ptr_from_Vertex(*v); | |
434 | 2793 | OpType type = o->get_type(); | ||
435 |
1/2✓ Branch 2 taken 2793 times.
✗ Branch 3 not taken.
|
2793 | unsigned n_ins = circ.n_in_edges_of_type(*v, EdgeType::Quantum); | |
436 | // Ignore classical ops | |||
437 |
3/4✓ Branch 1 taken 2793 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 2788 times.
|
2/2✓ Decision 'true' taken 5 times.
✓ Decision 'false' taken 2788 times.
|
2793 | if (is_classical_type(type)) { |
438 | 5 | continue; | ||
439 | 2788 | } else if ( | ||
440 |
4/6✓ Branch 1 taken 2774 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2520 times.
✓ Branch 4 taken 254 times.
✓ Branch 5 taken 2520 times.
✗ Branch 6 not taken.
|
2774 | is_projective_type(type) || is_final_q_type(type) || | |
441 |
4/4✓ Branch 0 taken 2513 times.
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 2509 times.
✓ Branch 3 taken 4 times.
|
2520 | type == OpType::Barrier || type == OpType::Conditional || | |
442 |
10/14✓ Branch 1 taken 2788 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2774 times.
✓ Branch 4 taken 14 times.
✓ Branch 7 taken 2509 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 11 times.
✓ Branch 11 taken 2498 times.
✓ Branch 12 taken 2509 times.
✓ Branch 13 taken 279 times.
✓ Branch 15 taken 290 times.
✓ Branch 16 taken 2498 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
|
5562 | n_ins > 2 || !o->free_symbols().empty()) { | |
443 | // Measures, resets, outputs, barriers, symbolic gates, conditionals | |||
444 | // and many-qubit gates close interactions | |||
445 |
1/2✓ Branch 2 taken 290 times.
✗ Branch 3 not taken.
|
290 | EdgeVec q_edges = circ.get_in_edges_of_type(*v, EdgeType::Quantum); | |
446 | 290 | std::vector<port_t> q_ports; | ||
447 |
2/2✓ Branch 4 taken 301 times.
✓ Branch 5 taken 290 times.
|
2/2✓ Decision 'true' taken 301 times.
✓ Decision 'false' taken 290 times.
|
591 | for (const Edge &e : q_edges) { |
448 |
2/4✓ Branch 1 taken 301 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 301 times.
✗ Branch 5 not taken.
|
301 | q_ports.push_back(circ.get_target_port(e)); | |
449 | } | |||
450 |
2/2✓ Branch 5 taken 301 times.
✓ Branch 6 taken 290 times.
|
2/2✓ Decision 'true' taken 301 times.
✓ Decision 'false' taken 290 times.
|
591 | for (const port_t &port : q_ports) { |
451 |
1/2✓ Branch 3 taken 301 times.
✗ Branch 4 not taken.
|
301 | Qubit q = v_to_qb.at({*v, port}); | |
452 |
1/2✓ Branch 1 taken 301 times.
✗ Branch 2 not taken.
|
301 | int i = current_interaction[q]; | |
453 |
2/2✓ Branch 0 taken 121 times.
✓ Branch 1 taken 180 times.
|
2/2✓ Decision 'true' taken 121 times.
✓ Decision 'false' taken 180 times.
|
301 | if (i != -1) { |
454 |
2/2✓ Branch 1 taken 59 times.
✓ Branch 2 taken 62 times.
|
2/2✓ Decision 'true' taken 59 times.
✓ Decision 'false' taken 62 times.
|
121 | if (i_vec[i].count >= 2) { |
455 | // Replace subcircuit | |||
456 |
1/2✓ Branch 1 taken 59 times.
✗ Branch 2 not taken.
|
59 | success |= replace_two_qubit_interaction( | |
457 | 59 | circ, i_vec[i], current_edge_on_qb, bin, target_2qb_gate, | ||
458 | cx_fidelity, allow_swaps); | |||
459 | } | |||
460 |
1/2✓ Branch 2 taken 121 times.
✗ Branch 3 not taken.
|
121 | current_interaction[i_vec[i].q0] = -1; | |
461 |
1/2✓ Branch 2 taken 121 times.
✗ Branch 3 not taken.
|
121 | current_interaction[i_vec[i].q1] = -1; | |
462 | } | |||
463 |
3/4✓ Branch 1 taken 301 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 47 times.
✓ Branch 4 taken 254 times.
|
2/2✓ Decision 'true' taken 47 times.
✓ Decision 'false' taken 254 times.
|
301 | if (!is_final_q_type(type)) { |
464 |
1/2✓ Branch 1 taken 47 times.
✗ Branch 2 not taken.
|
47 | current_edge_on_qb[q] = | |
465 |
2/4✓ Branch 1 taken 47 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 47 times.
✗ Branch 6 not taken.
|
47 | circ.get_next_edge(*v, current_edge_on_qb[q]); | |
466 | } | |||
467 | 301 | } | ||
468 |
3/4✓ Branch 4 taken 2498 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 981 times.
✓ Branch 7 taken 1517 times.
|
2/2✓ Decision 'true' taken 981 times.
✓ Decision 'false' taken 1807 times.
|
2788 | } else if (circ.n_in_edges_of_type(*v, EdgeType::Quantum) == 2) { |
469 | // Check for 2qb gate | |||
470 |
1/2✓ Branch 3 taken 981 times.
✗ Branch 4 not taken.
|
981 | Qubit q0 = v_to_qb.at({*v, 0}); | |
471 |
1/2✓ Branch 3 taken 981 times.
✗ Branch 4 not taken.
|
981 | Qubit q1 = v_to_qb.at({*v, 1}); | |
472 |
1/2✓ Branch 1 taken 981 times.
✗ Branch 2 not taken.
|
981 | int i0 = current_interaction[q0]; | |
473 |
1/2✓ Branch 1 taken 981 times.
✗ Branch 2 not taken.
|
981 | int i1 = current_interaction[q1]; | |
474 | // If they are already interacting, extend it | |||
475 |
4/4✓ Branch 0 taken 642 times.
✓ Branch 1 taken 339 times.
✓ Branch 2 taken 232 times.
✓ Branch 3 taken 410 times.
|
2/2✓ Decision 'true' taken 232 times.
✓ Decision 'false' taken 749 times.
|
981 | if (i0 != -1 && i0 == i1) { |
476 | 232 | i_vec[i0].count++; | ||
477 |
1/2✓ Branch 3 taken 232 times.
✗ Branch 4 not taken.
|
232 | i_vec[i0].vertices.insert(*v); | |
478 |
1/2✓ Branch 1 taken 232 times.
✗ Branch 2 not taken.
|
232 | current_edge_on_qb[q0] = | |
479 |
2/4✓ Branch 1 taken 232 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 232 times.
✗ Branch 6 not taken.
|
232 | circ.get_next_edge(*v, current_edge_on_qb[q0]); | |
480 |
1/2✓ Branch 1 taken 232 times.
✗ Branch 2 not taken.
|
232 | current_edge_on_qb[q1] = | |
481 |
2/4✓ Branch 1 taken 232 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 232 times.
✗ Branch 6 not taken.
|
232 | circ.get_next_edge(*v, current_edge_on_qb[q1]); | |
482 | } else { | |||
483 | // End any other interactions on q0 | |||
484 |
2/2✓ Branch 0 taken 410 times.
✓ Branch 1 taken 339 times.
|
2/2✓ Decision 'true' taken 410 times.
✓ Decision 'false' taken 339 times.
|
749 | if (i0 != -1) { |
485 |
2/2✓ Branch 1 taken 54 times.
✓ Branch 2 taken 356 times.
|
2/2✓ Decision 'true' taken 54 times.
✓ Decision 'false' taken 356 times.
|
410 | if (i_vec[i0].count >= 2) { |
486 | // Replace subcircuit | |||
487 |
1/2✓ Branch 1 taken 54 times.
✗ Branch 2 not taken.
|
54 | success |= replace_two_qubit_interaction( | |
488 | 54 | circ, i_vec[i0], current_edge_on_qb, bin, target_2qb_gate, | ||
489 | cx_fidelity, allow_swaps); | |||
490 | } | |||
491 |
1/2✓ Branch 2 taken 410 times.
✗ Branch 3 not taken.
|
410 | current_interaction[i_vec[i0].q0] = -1; | |
492 |
1/2✓ Branch 2 taken 410 times.
✗ Branch 3 not taken.
|
410 | current_interaction[i_vec[i0].q1] = -1; | |
493 | } | |||
494 | // End any other interactions on q1 | |||
495 |
2/2✓ Branch 0 taken 218 times.
✓ Branch 1 taken 531 times.
|
2/2✓ Decision 'true' taken 218 times.
✓ Decision 'false' taken 531 times.
|
749 | if (i1 != -1) { |
496 |
2/2✓ Branch 1 taken 37 times.
✓ Branch 2 taken 181 times.
|
2/2✓ Decision 'true' taken 37 times.
✓ Decision 'false' taken 181 times.
|
218 | if (i_vec[i1].count >= 2) { |
497 | // Replace subcircuit | |||
498 | ||||
499 |
1/2✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
|
37 | success |= replace_two_qubit_interaction( | |
500 | 37 | circ, i_vec[i1], current_edge_on_qb, bin, target_2qb_gate, | ||
501 | cx_fidelity, allow_swaps); | |||
502 | } | |||
503 |
1/2✓ Branch 2 taken 218 times.
✗ Branch 3 not taken.
|
218 | current_interaction[i_vec[i1].q0] = -1; | |
504 |
1/2✓ Branch 2 taken 218 times.
✗ Branch 3 not taken.
|
218 | current_interaction[i_vec[i1].q1] = -1; | |
505 | } | |||
506 | // Add new interaction | |||
507 |
1/2✓ Branch 1 taken 749 times.
✗ Branch 2 not taken.
|
749 | Interaction new_i(q0, q1); | |
508 |
1/2✓ Branch 1 taken 749 times.
✗ Branch 2 not taken.
|
749 | new_i.e0 = current_edge_on_qb[q0]; | |
509 |
1/2✓ Branch 1 taken 749 times.
✗ Branch 2 not taken.
|
749 | new_i.e1 = current_edge_on_qb[q1]; | |
510 | 749 | new_i.count = 1; | ||
511 |
1/2✓ Branch 2 taken 749 times.
✗ Branch 3 not taken.
|
749 | new_i.vertices = {*v}; | |
512 |
1/2✓ Branch 2 taken 749 times.
✗ Branch 3 not taken.
|
749 | current_interaction[q0] = i_vec.size(); | |
513 |
1/2✓ Branch 2 taken 749 times.
✗ Branch 3 not taken.
|
749 | current_interaction[q1] = i_vec.size(); | |
514 |
1/2✓ Branch 1 taken 749 times.
✗ Branch 2 not taken.
|
749 | i_vec.push_back(new_i); | |
515 |
1/2✓ Branch 1 taken 749 times.
✗ Branch 2 not taken.
|
749 | current_edge_on_qb[q0] = | |
516 |
2/4✓ Branch 1 taken 749 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 749 times.
✗ Branch 6 not taken.
|
749 | circ.get_next_edge(*v, current_edge_on_qb[q0]); | |
517 |
1/2✓ Branch 1 taken 749 times.
✗ Branch 2 not taken.
|
749 | current_edge_on_qb[q1] = | |
518 |
2/4✓ Branch 1 taken 749 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 749 times.
✗ Branch 6 not taken.
|
749 | circ.get_next_edge(*v, current_edge_on_qb[q1]); | |
519 | 749 | } | ||
520 | 981 | } else { | ||
521 | // We don't care about single-qubit vertices, so just update edges | |||
522 | // and add vertices if interactions exist | |||
523 |
3/4✓ Branch 2 taken 2780 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1263 times.
✓ Branch 5 taken 1517 times.
|
0/1? Decision couldn't be analyzed.
|
2780 | for (port_t i = 0; i < circ.n_in_edges(*v); i++) { |
524 |
1/2✓ Branch 3 taken 1263 times.
✗ Branch 4 not taken.
|
1263 | Qubit q = v_to_qb.at({*v, i}); | |
525 |
1/2✓ Branch 1 taken 1263 times.
✗ Branch 2 not taken.
|
1263 | current_edge_on_qb[q] = | |
526 |
2/4✓ Branch 1 taken 1263 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1263 times.
✗ Branch 6 not taken.
|
1263 | circ.get_next_edge(*v, current_edge_on_qb[q]); | |
527 |
1/2✓ Branch 1 taken 1263 times.
✗ Branch 2 not taken.
|
1263 | int inter = current_interaction[q]; | |
528 |
2/2✓ Branch 0 taken 1054 times.
✓ Branch 1 taken 209 times.
|
2/2✓ Decision 'true' taken 1054 times.
✓ Decision 'false' taken 209 times.
|
1263 | if (inter != -1) { |
529 |
1/2✓ Branch 3 taken 1054 times.
✗ Branch 4 not taken.
|
1054 | i_vec[inter].vertices.insert(*v); | |
530 | } | |||
531 | 1263 | } | ||
532 | } | |||
533 |
2/2✓ Branch 1 taken 2788 times.
✓ Branch 2 taken 5 times.
|
2793 | } | |
534 | } | |||
535 |
1/2✓ Branch 1 taken 85 times.
✗ Branch 2 not taken.
|
85 | circ.remove_vertices( | |
536 | bin, Circuit::GraphRewiring::No, Circuit::VertexDeletion::Yes); | |||
537 | ||||
538 |
2/2✓ Branch 0 taken 60 times.
✓ Branch 1 taken 25 times.
|
2/2✓ Decision 'true' taken 60 times.
✓ Decision 'false' taken 25 times.
|
85 | if (success) { |
539 |
2/4✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 60 times.
✗ Branch 5 not taken.
|
60 | squash_1qb_to_tk1().apply(circ); | |
540 | } | |||
541 | 85 | return success; | ||
542 |
2/4✓ Branch 1 taken 82 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 82 times.
✗ Branch 5 not taken.
|
249 | }); | |
543 | 82 | } | ||
544 | ||||
545 | // Given a 'SWAP_chain', finds edge in chain (or qubit wire) with best fidelity | |||
546 | // and rewires the associated single qubit vertex in to it | |||
547 | ✗ | static bool find_edge_rewire_vertex( | ||
548 | Circuit &circ, | |||
549 | std::pair<std::vector<std::pair<Edge, double>>, Vertex> &entry) { | |||
550 | ✗ | std::vector<std::pair<Edge, double>> candidates = entry.first; | ||
551 | ✗ | std::pair<Edge, double> best_pair = candidates[0]; | ||
552 | ✗ | bool do_rewire = false; // prevents rewiring if current edge is best edge | ||
553 | // (causes many issues...) | |||
554 |
0/2✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
|
✗ | for (unsigned i = 1; i < candidates.size(); i++) { // find best edge | |
555 |
0/2✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
|
✗ | if (candidates[i].second > best_pair.second) { | |
556 | ✗ | best_pair = candidates[i]; | ||
557 | ✗ | do_rewire = true; | ||
558 | } | |||
559 | } | |||
560 |
0/2✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
|
✗ | if (do_rewire) { | |
561 | // rewire in to best edge | |||
562 | ✗ | circ.remove_vertex( | ||
563 | ✗ | entry.second, Circuit::GraphRewiring::Yes, Circuit::VertexDeletion::No); | ||
564 | ✗ | circ.rewire(entry.second, {best_pair.first}, {EdgeType::Quantum}); | ||
565 | } | |||
566 | ✗ | return do_rewire; | ||
567 | } | |||
568 | ||||
569 | // Given a SWAP vertex, which has some predecessor SWAP vertex, find the | |||
570 | // 'SWAP_chain' this predecessor SWAP vertex is in and add to it | |||
571 | ✗ | static void extend_SWAP_chain( | ||
572 | std::list<std::pair<std::vector<std::pair<Edge, double>>, Vertex>> | |||
573 | &swap_chains, | |||
574 | Edge entry_edge, Node entry_node, const Edge &match, const Circuit &circ, | |||
575 | const DeviceCharacterisation &characterisation) { | |||
576 |
0/2✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
|
✗ | for (auto it = swap_chains.begin(); it != swap_chains.end(); ++it) { | |
577 |
0/2✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
|
✗ | if ((*it).first.back().first == match) { | |
578 | // extend chain, adding a new pair of edge and double to the end | |||
579 | ✗ | (*it).first.push_back( | ||
580 | {entry_edge, | |||
581 | ✗ | 1.0 - characterisation.get_error( | ||
582 | ✗ | entry_node, circ.get_OpType_from_Vertex((*it).second))}); | ||
583 | ✗ | return; | ||
584 | } | |||
585 | } | |||
586 | } | |||
587 | ||||
588 | // Finds sequences of adjacent SWAP gates, with a predecessor Single Qubit | |||
589 | // Vertex. The error rate of the required Single Qubit Vertex is stored for each | |||
590 | // of the PhysicalQubits the LogicalQubit passes through Once 'SWAP_chains' are | |||
591 | // found throughout the whole circuit, predecessor Single Qubit Vertices are | |||
592 | // rewired into the edge with best error rate | |||
593 | ✗ | static bool find_rewire_sq( | ||
594 | Circuit &circ, const DeviceCharacterisation &characterisation) { | |||
595 | std::list<std::pair<std::vector<std::pair<Edge, double>>, Vertex>> | |||
596 | ✗ | swap_chains; | ||
597 |
0/1? Decision couldn't be analyzed.
|
✗ | for (auto it = circ.begin(); it != circ.end(); ++it) { | |
598 |
0/2✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
|
✗ | if (it->get_op_ptr()->get_type() == OpType::SWAP) { | |
599 | // find SWAP, if either predecessor is a single qubit unitary | |||
600 | // find resulting swap chain... | |||
601 | ✗ | Vertex swap_vert = it.get_vertex(); | ||
602 | ✗ | unit_vector_t qubits = it->get_args(); | ||
603 | ✗ | node_vector_t nodes = {qubits.begin(), qubits.end()}; | ||
604 | ✗ | VertexVec pred_verts = circ.get_predecessors(swap_vert); | ||
605 | ✗ | EdgeVec pred_edges = circ.get_in_edges(swap_vert); | ||
606 | ✗ | EdgeVec post_edges = circ.get_all_out_edges(swap_vert); | ||
607 |
0/2✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
|
✗ | for (unsigned i = 0; i < pred_verts.size(); i++) { | |
608 | ✗ | OpType optype = circ.get_OpType_from_Vertex( | ||
609 | ✗ | pred_verts[i]); // OPT IS PREDECESSOR OPTYPE | ||
610 |
0/2✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
|
✗ | if (circ.detect_singleq_unitary_op(pred_verts[i])) { | |
611 | // wire has single qubit unitary->add a new swap chain | |||
612 | std::vector<std::pair<Edge, double>> swap_chain = { | |||
613 | ✗ | {pred_edges[i], | ||
614 | ✗ | 1.0 - characterisation.get_error(nodes[i], optype)}, | ||
615 | ✗ | {post_edges[1 - i], | ||
616 | ✗ | 1.0 - characterisation.get_error(nodes[1 - i], optype)}}; | ||
617 | ✗ | swap_chains.push_back(std::make_pair(swap_chain, pred_verts[i])); | ||
618 |
0/2✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
|
✗ | } else if (optype == OpType::SWAP) { // wire has swap->assume this swap | |
619 | // already in chain, find chain | |||
620 | ✗ | Edge pre_edge = pred_edges[i]; | ||
621 | ✗ | extend_SWAP_chain( | ||
622 | ✗ | swap_chains, post_edges[1 - i], nodes[1 - i], pre_edge, circ, | ||
623 | characterisation); | |||
624 | } | |||
625 | } | |||
626 | } | |||
627 | } | |||
628 | // having produced swap chains, now find best qubit for gate to act on and | |||
629 | // implement | |||
630 | ✗ | bool success = false; | ||
631 |
0/2✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
|
✗ | while (!swap_chains.empty()) { | |
632 |
0/2✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
|
✗ | if (find_edge_rewire_vertex(circ, (*swap_chains.begin())) == true) { | |
633 | ✗ | success = true; | ||
634 | } | |||
635 | ✗ | swap_chains.erase(swap_chains.begin()); | ||
636 | } | |||
637 | ✗ | return success; | ||
638 | } | |||
639 | ||||
640 | ✗ | static Transform commute_SQ_gates_through_SWAPS_helper( | ||
641 | const DeviceCharacterisation &characterisation) { | |||
642 | ✗ | return Transform([characterisation](Circuit &circ) { | ||
643 | ✗ | bool success = false; | ||
644 |
0/2✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
|
✗ | while (find_rewire_sq(circ, characterisation)) { | |
645 | ✗ | success = true; | ||
646 | } | |||
647 | ✗ | return success; | ||
648 | ✗ | }); | ||
649 | } | |||
650 | ||||
651 | ✗ | Transform commute_SQ_gates_through_SWAPS(const avg_node_errors_t &node_errors) { | ||
652 | return commute_SQ_gates_through_SWAPS_helper( | |||
653 | ✗ | DeviceCharacterisation(node_errors)); | ||
654 | } | |||
655 | ✗ | Transform commute_SQ_gates_through_SWAPS(const op_node_errors_t &node_errors) { | ||
656 | return commute_SQ_gates_through_SWAPS_helper( | |||
657 | ✗ | DeviceCharacterisation(node_errors)); | ||
658 | } | |||
659 | ||||
660 | 62 | Transform absorb_Rz_NPhasedX() { | ||
661 | 62 | return Transform([](Circuit &circ) { | ||
662 | 62 | bool success = false; | ||
663 | 62 | VertexSet all_bins; | ||
664 | ||||
665 | // Start by squashing Rz gates | |||
666 |
2/4✓ Branch 1 taken 62 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 62 times.
✗ Branch 5 not taken.
|
62 | success |= squash_1qb_to_pqp(OpType::Rz, OpType::Rx).apply(circ); | |
667 | ||||
668 | // Loop through all NPhasedX gates | |||
669 |
7/8✓ Branch 1 taken 62 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1332 times.
✓ Branch 6 taken 62 times.
✓ Branch 8 taken 1332 times.
✓ Branch 9 taken 62 times.
✓ Branch 11 taken 62 times.
✓ Branch 12 taken 62 times.
|
1456 | BGL_FORALL_VERTICES(v, circ.dag, DAG) { | |
670 |
1/2✓ Branch 1 taken 1332 times.
✗ Branch 2 not taken.
|
1332 | Op_ptr op = circ.get_Op_ptr_from_Vertex(v); | |
671 |
2/2✓ Branch 2 taken 167 times.
✓ Branch 3 taken 1165 times.
|
2/2✓ Decision 'true' taken 167 times.
✓ Decision 'false' taken 1165 times.
|
1332 | if (op->get_type() == OpType::NPhasedX) { |
672 | // gather surrounding Rz gates | |||
673 |
1/2✓ Branch 2 taken 167 times.
✗ Branch 3 not taken.
|
167 | unsigned arity = op->n_qubits(); | |
674 |
1/2✓ Branch 2 taken 167 times.
✗ Branch 3 not taken.
|
167 | std::vector<Expr> in_rz(arity); | |
675 |
1/2✓ Branch 2 taken 167 times.
✗ Branch 3 not taken.
|
167 | std::vector<Expr> out_rz(arity); | |
676 |
1/2✓ Branch 1 taken 167 times.
✗ Branch 2 not taken.
|
167 | EdgeVec in_edges = circ.get_in_edges_of_type(v, EdgeType::Quantum); | |
677 |
1/2✓ Branch 1 taken 167 times.
✗ Branch 2 not taken.
|
167 | EdgeVec out_edges = circ.get_out_edges_of_type(v, EdgeType::Quantum); | |
678 | TKET_ASSERT(in_edges.size() == arity); | |||
679 | TKET_ASSERT(out_edges.size() == arity); | |||
680 |
2/2✓ Branch 0 taken 554 times.
✓ Branch 1 taken 167 times.
|
2/2✓ Decision 'true' taken 554 times.
✓ Decision 'false' taken 167 times.
|
721 | for (unsigned i = 0; i < arity; ++i) { |
681 |
1/2✓ Branch 2 taken 554 times.
✗ Branch 3 not taken.
|
554 | Vertex in_v = circ.source(in_edges[i]); | |
682 |
1/2✓ Branch 1 taken 554 times.
✗ Branch 2 not taken.
|
554 | Op_ptr in_op = circ.get_Op_ptr_from_Vertex(in_v); | |
683 |
1/2✓ Branch 2 taken 554 times.
✗ Branch 3 not taken.
|
554 | Vertex out_v = circ.target(out_edges[i]); | |
684 |
1/2✓ Branch 1 taken 554 times.
✗ Branch 2 not taken.
|
554 | Op_ptr out_op = circ.get_Op_ptr_from_Vertex(out_v); | |
685 | ||||
686 |
2/2✓ Branch 2 taken 313 times.
✓ Branch 3 taken 241 times.
|
2/2✓ Decision 'true' taken 313 times.
✓ Decision 'false' taken 241 times.
|
554 | if (in_op->get_type() == OpType::Rz) { |
687 |
3/6✓ Branch 2 taken 313 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 313 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 313 times.
✗ Branch 9 not taken.
|
313 | in_rz[i] = -in_op->get_params().at(0); | |
688 | } else { | |||
689 |
1/2✓ Branch 1 taken 241 times.
✗ Branch 2 not taken.
|
241 | in_rz[i] = 0.; | |
690 | } | |||
691 |
2/2✓ Branch 2 taken 315 times.
✓ Branch 3 taken 239 times.
|
2/2✓ Decision 'true' taken 315 times.
✓ Decision 'false' taken 239 times.
|
554 | if (out_op->get_type() == OpType::Rz) { |
692 |
3/6✓ Branch 2 taken 315 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 315 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 315 times.
✗ Branch 10 not taken.
|
315 | out_rz[i] = out_op->get_params().at(0); | |
693 | } else { | |||
694 |
1/2✓ Branch 1 taken 239 times.
✗ Branch 2 not taken.
|
239 | out_rz[i] = 0.; | |
695 | } | |||
696 | 554 | } | ||
697 | ||||
698 | // Find out which Rz angle is most popular. | |||
699 | // Note that we only compare expr[i] with expr[j] when j < i. This means | |||
700 | // that only the largest i from a set of equivalent exprs will have the | |||
701 | // right occurence count, but that is good enough. | |||
702 |
1/2✓ Branch 1 taken 167 times.
✗ Branch 2 not taken.
|
167 | std::vector<Expr> all_rz = in_rz; | |
703 |
1/2✓ Branch 5 taken 167 times.
✗ Branch 6 not taken.
|
167 | all_rz.insert(all_rz.end(), out_rz.begin(), out_rz.end()); | |
704 |
1/2✓ Branch 2 taken 167 times.
✗ Branch 3 not taken.
|
167 | std::vector<unsigned> occurences_count(2 * arity); | |
705 |
2/2✓ Branch 0 taken 1108 times.
✓ Branch 1 taken 167 times.
|
2/2✓ Decision 'true' taken 1108 times.
✓ Decision 'false' taken 167 times.
|
1275 | for (unsigned i = 0; i < 2 * arity; ++i) { |
706 | 1108 | unsigned cnt = 0; | ||
707 |
2/2✓ Branch 0 taken 3354 times.
✓ Branch 1 taken 1108 times.
|
2/2✓ Decision 'true' taken 3354 times.
✓ Decision 'false' taken 1108 times.
|
4462 | for (unsigned j = 0; j < i; ++j) { |
708 |
3/4✓ Branch 3 taken 3354 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1088 times.
✓ Branch 6 taken 2266 times.
|
2/2✓ Decision 'true' taken 1088 times.
✓ Decision 'false' taken 2266 times.
|
3354 | if (equiv_expr(all_rz[i], all_rz[j], 4)) { |
709 | 1088 | ++cnt; | ||
710 | } | |||
711 | } | |||
712 | 1108 | occurences_count[i] = cnt; | ||
713 | } | |||
714 | unsigned max_i = | |||
715 |
1/2✓ Branch 3 taken 167 times.
✗ Branch 4 not taken.
|
167 | std::max_element(occurences_count.begin(), occurences_count.end()) - | |
716 | 167 | occurences_count.begin(); | ||
717 |
1/2✓ Branch 2 taken 167 times.
✗ Branch 3 not taken.
|
167 | Expr absorb_rz = all_rz[max_i]; | |
718 | ||||
719 |
3/4✓ Branch 1 taken 167 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 64 times.
✓ Branch 4 taken 103 times.
|
2/2✓ Decision 'true' taken 64 times.
✓ Decision 'false' taken 103 times.
|
167 | if (!equiv_0(absorb_rz, 4)) { |
720 | 64 | success = true; | ||
721 | ||||
722 | // Subtract absorb_rz in NPhasedX | |||
723 |
1/2✓ Branch 2 taken 64 times.
✗ Branch 3 not taken.
|
64 | std::vector<Expr> new_params = op->get_params(); | |
724 | TKET_ASSERT(new_params.size() == 2); | |||
725 |
1/2✓ Branch 2 taken 64 times.
✗ Branch 3 not taken.
|
64 | new_params[1] += absorb_rz; | |
726 |
3/6✓ Branch 2 taken 64 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 64 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 64 times.
✗ Branch 9 not taken.
|
64 | circ.dag[v] = get_op_ptr(OpType::NPhasedX, new_params, arity); | |
727 | ||||
728 | // Finally, adjust +-absorb_rz in Rz everywhere around | |||
729 |
2/2✓ Branch 0 taken 229 times.
✓ Branch 1 taken 64 times.
|
2/2✓ Decision 'true' taken 229 times.
✓ Decision 'false' taken 64 times.
|
293 | for (unsigned i = 0; i < arity; ++i) { |
730 |
1/2✓ Branch 2 taken 229 times.
✗ Branch 3 not taken.
|
229 | Vertex in_v = circ.source(in_edges[i]); | |
731 |
1/2✓ Branch 1 taken 229 times.
✗ Branch 2 not taken.
|
229 | Op_ptr in_op = circ.get_Op_ptr_from_Vertex(in_v); | |
732 |
1/2✓ Branch 2 taken 229 times.
✗ Branch 3 not taken.
|
229 | Vertex out_v = circ.target(out_edges[i]); | |
733 |
1/2✓ Branch 1 taken 229 times.
✗ Branch 2 not taken.
|
229 | Op_ptr out_op = circ.get_Op_ptr_from_Vertex(out_v); | |
734 | ||||
735 |
1/2✓ Branch 1 taken 229 times.
✗ Branch 2 not taken.
|
229 | Expr angle; | |
736 |
2/4✓ Branch 1 taken 229 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 229 times.
✗ Branch 5 not taken.
|
229 | Edge in_e, out_e; | |
737 | 229 | VertexSet bin; | ||
738 |
2/2✓ Branch 2 taken 199 times.
✓ Branch 3 taken 30 times.
|
2/2✓ Decision 'true' taken 199 times.
✓ Decision 'false' taken 30 times.
|
229 | if (in_op->get_type() == OpType::Rz) { |
739 |
3/6✓ Branch 2 taken 199 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 199 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 199 times.
✗ Branch 9 not taken.
|
199 | angle = in_op->get_params().at(0) + absorb_rz; | |
740 | 199 | out_e = in_edges[i]; | ||
741 |
1/2✓ Branch 1 taken 199 times.
✗ Branch 2 not taken.
|
199 | in_e = circ.get_last_edge(in_v, out_e); | |
742 |
1/2✓ Branch 1 taken 199 times.
✗ Branch 2 not taken.
|
199 | bin = {in_v}; | |
743 | } else { | |||
744 |
1/2✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
|
30 | angle = absorb_rz; | |
745 | 30 | out_e = in_edges[i]; | ||
746 | 30 | in_e = out_e; | ||
747 |
1/2✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
|
30 | bin = {}; | |
748 | } | |||
749 |
3/6✓ Branch 2 taken 229 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 229 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 229 times.
✗ Branch 10 not taken.
|
458 | Subcircuit sub{{in_e}, {out_e}, bin}; | |
750 |
1/2✓ Branch 2 taken 229 times.
✗ Branch 3 not taken.
|
229 | Circuit c(1); | |
751 |
3/4✓ Branch 1 taken 229 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 105 times.
✓ Branch 4 taken 124 times.
|
2/2✓ Decision 'true' taken 105 times.
✓ Decision 'false' taken 124 times.
|
229 | if (!equiv_0(angle, 4)) { |
752 |
2/4✓ Branch 3 taken 105 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 105 times.
✗ Branch 7 not taken.
|
105 | c.add_op<unsigned>(OpType::Rz, angle, {0}); | |
753 | } | |||
754 |
1/2✓ Branch 1 taken 229 times.
✗ Branch 2 not taken.
|
229 | circ.substitute(c, sub, Circuit::VertexDeletion::No); | |
755 |
1/2✓ Branch 3 taken 229 times.
✗ Branch 4 not taken.
|
229 | all_bins.insert(bin.begin(), bin.end()); | |
756 | ||||
757 |
2/2✓ Branch 2 taken 172 times.
✓ Branch 3 taken 57 times.
|
2/2✓ Decision 'true' taken 172 times.
✓ Decision 'false' taken 57 times.
|
229 | if (out_op->get_type() == OpType::Rz) { |
758 |
3/6✓ Branch 2 taken 172 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 172 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 172 times.
✗ Branch 9 not taken.
|
172 | angle = out_op->get_params().at(0) - absorb_rz; | |
759 | 172 | in_e = out_edges[i]; | ||
760 |
1/2✓ Branch 1 taken 172 times.
✗ Branch 2 not taken.
|
172 | out_e = circ.get_next_edge(out_v, in_e); | |
761 |
1/2✓ Branch 1 taken 172 times.
✗ Branch 2 not taken.
|
172 | bin = {out_v}; | |
762 | } else { | |||
763 |
1/2✓ Branch 1 taken 57 times.
✗ Branch 2 not taken.
|
57 | angle = -absorb_rz; | |
764 | 57 | in_e = out_edges[i]; | ||
765 | 57 | out_e = in_e; | ||
766 |
1/2✓ Branch 1 taken 57 times.
✗ Branch 2 not taken.
|
57 | bin = {}; | |
767 | } | |||
768 |
3/6✓ Branch 2 taken 229 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 229 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 229 times.
✗ Branch 10 not taken.
|
229 | sub = Subcircuit{{in_e}, {out_e}, bin}; | |
769 |
2/4✓ Branch 2 taken 229 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 229 times.
✗ Branch 6 not taken.
|
229 | c = Circuit(1); | |
770 |
3/4✓ Branch 1 taken 229 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 175 times.
✓ Branch 4 taken 54 times.
|
2/2✓ Decision 'true' taken 175 times.
✓ Decision 'false' taken 54 times.
|
229 | if (!equiv_0(angle, 4)) { |
771 |
2/4✓ Branch 3 taken 175 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 175 times.
✗ Branch 7 not taken.
|
175 | c.add_op<unsigned>(OpType::Rz, angle, {0}); | |
772 | } | |||
773 |
1/2✓ Branch 1 taken 229 times.
✗ Branch 2 not taken.
|
229 | circ.substitute(c, sub, Circuit::VertexDeletion::No); | |
774 |
1/2✓ Branch 3 taken 229 times.
✗ Branch 4 not taken.
|
229 | all_bins.insert(bin.begin(), bin.end()); | |
775 | 229 | } | ||
776 | 64 | } | ||
777 | 167 | } | ||
778 | 1332 | } | ||
779 |
1/2✓ Branch 1 taken 62 times.
✗ Branch 2 not taken.
|
62 | circ.remove_vertices( | |
780 | all_bins, Circuit::GraphRewiring::No, Circuit::VertexDeletion::Yes); | |||
781 | ||||
782 | 62 | return success; | ||
783 |
1/2✓ Branch 2 taken 62 times.
✗ Branch 3 not taken.
|
124 | }); | |
784 | } | |||
785 | ||||
786 | 2 | Transform ZZPhase_to_Rz() { | ||
787 | // basic optimisation, replace ZZPhase with two Rz(1) | |||
788 | 4 | return Transform([](Circuit &circ) { | ||
789 | 4 | bool success = false; | ||
790 | 4 | VertexSet bin; | ||
791 | ||||
792 |
7/8✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 102 times.
✓ Branch 6 taken 4 times.
✓ Branch 8 taken 102 times.
✓ Branch 9 taken 4 times.
✓ Branch 11 taken 4 times.
✓ Branch 12 taken 4 times.
|
110 | BGL_FORALL_VERTICES(v, circ.dag, DAG) { | |
793 |
1/2✓ Branch 1 taken 102 times.
✗ Branch 2 not taken.
|
102 | Op_ptr op = circ.get_Op_ptr_from_Vertex(v); | |
794 |
2/2✓ Branch 2 taken 10 times.
✓ Branch 3 taken 92 times.
|
2/2✓ Decision 'true' taken 10 times.
✓ Decision 'false' taken 92 times.
|
102 | if (op->get_type() == OpType::ZZPhase) { |
795 |
1/2✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
|
10 | auto params = op->get_params(); | |
796 | TKET_ASSERT(params.size() == 1); | |||
797 | // evaluate | |||
798 |
2/4✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 10 times.
✗ Branch 6 not taken.
|
10 | double param_value = eval_expr(params[0]).value(); | |
799 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 8 times.
|
2/2✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 8 times.
|
10 | if (std::abs(param_value) == 1.0) { |
800 | 2 | success = true; | ||
801 | // basic optimisation, replace ZZPhase with two Rz(1) | |||
802 |
1/2✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | Circuit replacement(2); | |
803 |
3/6✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 2 times.
✗ Branch 10 not taken.
|
2 | replacement.add_op<unsigned>(OpType::Rz, 1.0, {0}); | |
804 |
3/6✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 2 times.
✗ Branch 10 not taken.
|
2 | replacement.add_op<unsigned>(OpType::Rz, 1.0, {1}); | |
805 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | circ.substitute(replacement, v, Circuit::VertexDeletion::No); | |
806 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | bin.insert(v); | |
807 | 2 | } | ||
808 | 10 | } | ||
809 | 102 | } | ||
810 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | circ.remove_vertices( | |
811 | bin, Circuit::GraphRewiring::No, Circuit::VertexDeletion::Yes); | |||
812 | 4 | return success; | ||
813 |
1/2✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
6 | }); | |
814 | } | |||
815 | ||||
816 | 60 | Transform normalise_TK2() { | ||
817 | 65 | return Transform([](Circuit &circ) { | ||
818 | 65 | bool success = false; | ||
819 | 65 | VertexSet bin; | ||
820 | ||||
821 |
7/8✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 5686 times.
✓ Branch 6 taken 65 times.
✓ Branch 8 taken 5686 times.
✓ Branch 9 taken 65 times.
✓ Branch 11 taken 65 times.
✓ Branch 12 taken 65 times.
|
5816 | BGL_FORALL_VERTICES(v, circ.dag, DAG) { | |
822 |
1/2✓ Branch 1 taken 5686 times.
✗ Branch 2 not taken.
|
5686 | Op_ptr op = circ.get_Op_ptr_from_Vertex(v); | |
823 | 5686 | bool conditional = op->get_type() == OpType::Conditional; | ||
824 |
2/2✓ Branch 0 taken 27 times.
✓ Branch 1 taken 5659 times.
|
2/2✓ Decision 'true' taken 27 times.
✓ Decision 'false' taken 5659 times.
|
5686 | if (conditional) { |
825 | 27 | const Conditional &cond = static_cast<const Conditional &>(*op); | ||
826 |
1/2✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
|
27 | op = cond.get_op(); | |
827 | } | |||
828 |
2/2✓ Branch 2 taken 26 times.
✓ Branch 3 taken 5660 times.
|
2/2✓ Decision 'true' taken 26 times.
✓ Decision 'false' taken 5660 times.
|
5686 | if (op->get_type() == OpType::TK2) { |
829 |
1/2✓ Branch 2 taken 26 times.
✗ Branch 3 not taken.
|
26 | auto params = op->get_params(); | |
830 | TKET_ASSERT(params.size() == 3); | |||
831 |
6/10✓ Branch 2 taken 26 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 26 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 26 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 26 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 4 times.
✓ Branch 17 taken 22 times.
|
2/2✓ Decision 'true' taken 4 times.
✓ Decision 'false' taken 22 times.
|
26 | if (!in_weyl_chamber({params[0], params[1], params[2]})) { |
832 | 4 | success = true; | ||
833 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
|
2/2✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 3 times.
|
4 | if (conditional) { |
834 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | circ.substitute_conditional( | |
835 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
2 | CircPool::TK2_using_normalised_TK2( | |
836 | 1 | params[0], params[1], params[2]), | ||
837 | v, Circuit::VertexDeletion::No); | |||
838 | } else { | |||
839 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | circ.substitute( | |
840 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
6 | CircPool::TK2_using_normalised_TK2( | |
841 | 3 | params[0], params[1], params[2]), | ||
842 | v, Circuit::VertexDeletion::No); | |||
843 | } | |||
844 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | bin.insert(v); | |
845 | } | |||
846 | 26 | } | ||
847 | 5686 | } | ||
848 | ||||
849 |
1/2✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
|
65 | circ.remove_vertices( | |
850 | bin, Circuit::GraphRewiring::No, Circuit::VertexDeletion::Yes); | |||
851 | ||||
852 | 65 | return success; | ||
853 |
1/2✓ Branch 2 taken 60 times.
✗ Branch 3 not taken.
|
125 | }); | |
854 | } | |||
855 | ||||
856 | } // namespace Transforms | |||
857 | ||||
858 | } // namespace tket | |||
859 |