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 "Utils/GraphHeaders.hpp" | |||
16 | #include "ZX/Rewrite.hpp" | |||
17 | ||||
18 | namespace tket { | |||
19 | ||||
20 | namespace zx { | |||
21 | ||||
22 | /** | |||
23 | * Helper method for local complementation and pivoting. | |||
24 | * Checks that all neighbours of some vertex v are also ZSpiders. | |||
25 | * If v is Classical, all neighbours must also be Classical. | |||
26 | */ | |||
27 | 21 | static bool can_complement_neighbourhood( | ||
28 | const ZXDiagram& diag, QuantumType vqtype, const ZXVertVec& neighbours) { | |||
29 |
2/2✓ Branch 5 taken 55 times.
✓ Branch 6 taken 10 times.
|
2/2✓ Decision 'true' taken 55 times.
✓ Decision 'false' taken 10 times.
|
65 | for (const ZXVert& n : neighbours) { |
30 |
4/6✓ Branch 1 taken 55 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 44 times.
✓ Branch 4 taken 11 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 44 times.
|
2/2✓ Decision 'true' taken 11 times.
✓ Decision 'false' taken 44 times.
|
55 | if (diag.get_zxtype(n) != ZXType::ZSpider || |
31 | ✗ | (vqtype == QuantumType::Classical && | ||
32 |
2/6✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 11 times.
✓ Branch 7 taken 44 times.
|
55 | *diag.get_qtype(n) == QuantumType::Quantum)) | |
33 | 11 | return false; | ||
34 | } | |||
35 | 10 | return true; | ||
36 | } | |||
37 | ||||
38 | 1 | bool Rewrite::remove_interior_cliffords_fun(ZXDiagram& diag) { | ||
39 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
|
1/2✓ Decision 'true' taken 1 times.
✗ Decision 'false' not taken.
|
1 | if (!diag.is_graphlike()) return false; |
40 | 1 | bool success = false; | ||
41 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | ZXVertSeqSet candidates; | |
42 |
8/10✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 28 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 28 times.
✓ Branch 10 taken 1 times.
✓ Branch 12 taken 28 times.
✓ Branch 13 taken 1 times.
✓ Branch 15 taken 1 times.
✓ Branch 16 taken 1 times.
|
30 | BGL_FORALL_VERTICES(v, *diag.graph, ZXGraph) { candidates.insert(v); } | |
43 | 1 | auto& view = candidates.get<TagSeq>(); | ||
44 |
2/2✓ Branch 1 taken 41 times.
✓ Branch 2 taken 1 times.
|
2/2✓ Decision 'true' taken 41 times.
✓ Decision 'false' taken 1 times.
|
42 | while (!candidates.empty()) { |
45 | 41 | auto it = view.begin(); | ||
46 |
1/2✓ Branch 1 taken 41 times.
✗ Branch 2 not taken.
|
41 | ZXVert v = *it; | |
47 |
1/2✓ Branch 1 taken 41 times.
✗ Branch 2 not taken.
|
41 | view.erase(it); | |
48 |
3/4✓ Branch 1 taken 41 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 24 times.
✓ Branch 4 taken 17 times.
|
2/2✓ Decision 'true' taken 17 times.
✓ Decision 'false' taken 33 times.
|
50 | if (!diag.is_proper_clifford_spider(v)) continue; |
49 |
1/2✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
|
17 | const PhasedGen& spid = diag.get_vertex_ZXGen<PhasedGen>(v); | |
50 |
1/2✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
|
17 | QuantumType vqtype = *spid.get_qtype(); | |
51 |
1/2✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
|
17 | ZXVertVec neighbours = diag.neighbours(v); | |
52 |
3/4✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 8 times.
|
2/2✓ Decision 'true' taken 8 times.
✓ Decision 'false' taken 9 times.
|
17 | if (!can_complement_neighbourhood(diag, vqtype, neighbours)) continue; |
53 | // Found an internal proper clifford spider on which we can perform local | |||
54 | // complementation | |||
55 | /** | |||
56 | * Complement the neighbourhoods' edges and modify the phase information | |||
57 | * on the neighbours. | |||
58 | **/ | |||
59 | 8 | auto xi = neighbours.begin(), x_end = neighbours.end(); | ||
60 |
2/2✓ Branch 2 taken 25 times.
✓ Branch 3 taken 8 times.
|
2/2✓ Decision 'true' taken 25 times.
✓ Decision 'false' taken 8 times.
|
33 | for (; xi != x_end; ++xi) { |
61 |
2/2✓ Branch 3 taken 31 times.
✓ Branch 4 taken 25 times.
|
2/2✓ Decision 'true' taken 31 times.
✓ Decision 'false' taken 25 times.
|
56 | for (auto yi = xi + 1; yi != x_end; ++yi) { |
62 | // Don't add a doubled edge between classicals to preserve graph-like | |||
63 |
1/2✓ Branch 0 taken 31 times.
✗ Branch 1 not taken.
|
2/2✓ Decision 'true' taken 31 times.
✓ Decision 'false' taken 31 times.
|
62 | if (!(vqtype == QuantumType::Quantum && |
64 |
2/4✓ Branch 2 taken 31 times.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 31 times.
|
31 | *diag.get_qtype(*xi) == QuantumType::Classical && | |
65 |
1/6✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 31 times.
✗ Branch 8 not taken.
|
31 | *diag.get_qtype(*yi) == QuantumType::Classical)) { | |
66 |
1/2✓ Branch 3 taken 31 times.
✗ Branch 4 not taken.
|
31 | std::optional<Wire> wire = diag.wire_between(*xi, *yi); | |
67 |
2/2✓ Branch 1 taken 6 times.
✓ Branch 2 taken 25 times.
|
2/2✓ Decision 'true' taken 6 times.
✓ Decision 'false' taken 25 times.
|
31 | if (wire) |
68 |
1/2✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
|
6 | diag.remove_wire(*wire); | |
69 | else | |||
70 |
1/2✓ Branch 5 taken 25 times.
✗ Branch 6 not taken.
|
25 | diag.add_wire(*xi, *yi, ZXWireType::H, vqtype); | |
71 | } | |||
72 | } | |||
73 |
1/2✓ Branch 2 taken 25 times.
✗ Branch 3 not taken.
|
25 | const PhasedGen& xi_op = diag.get_vertex_ZXGen<PhasedGen>(*xi); | |
74 | // If `v` is Quantum, Classical neighbours will pick up both the +theta | |||
75 | // and -theta phases, cancelling out | |||
76 |
1/2✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 50 times.
|
50 | if (vqtype == QuantumType::Quantum && |
77 |
3/6✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 25 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 25 times.
|
50 | *xi_op.get_qtype() == QuantumType::Classical) | |
78 | ✗ | continue; | ||
79 | // Update phase information | |||
80 | 25 | ZXGen_ptr xi_new_op = std::make_shared<const PhasedGen>( | ||
81 |
4/8✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 25 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 25 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 25 times.
✗ Branch 11 not taken.
|
50 | ZXType::ZSpider, xi_op.get_param() - spid.get_param(), | |
82 |
1/2✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
|
50 | *xi_op.get_qtype()); | |
83 |
1/2✓ Branch 2 taken 25 times.
✗ Branch 3 not taken.
|
25 | diag.set_vertex_ZXGen_ptr(*xi, xi_new_op); | |
84 |
1/2✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
|
25 | candidates.insert( | |
85 | 25 | *xi); // Changing the phase could introduce a new proper Clifford | ||
86 | 25 | } | ||
87 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | diag.remove_vertex(v); | |
88 | 8 | success = true; | ||
89 |
2/2✓ Branch 1 taken 8 times.
✓ Branch 2 taken 9 times.
|
17 | } | |
90 | 1 | return success; | ||
91 | 1 | } | ||
92 | ||||
93 | 1 | Rewrite Rewrite::remove_interior_cliffords() { | ||
94 |
1/2✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | return Rewrite(remove_interior_cliffords_fun); | |
95 | } | |||
96 | ||||
97 | 3 | static void add_phase_to_vertices( | ||
98 | ZXDiagram& diag, const ZXVertSeqSet& verts, const Expr& phase) { | |||
99 |
5/8✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 6 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 3 times.
✓ Branch 12 taken 3 times.
|
0/1? Decision couldn't be analyzed.
|
6 | for (const ZXVert& v : verts) { |
100 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | const PhasedGen& old_spid = diag.get_vertex_ZXGen<PhasedGen>(v); | |
101 | 3 | ZXGen_ptr new_spid = std::make_shared<const PhasedGen>( | ||
102 |
4/8✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
|
9 | ZXType::ZSpider, old_spid.get_param() + phase, *old_spid.get_qtype()); | |
103 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | diag.set_vertex_ZXGen_ptr(v, new_spid); | |
104 | 3 | } | ||
105 | 3 | } | ||
106 | ||||
107 | 3 | static void bipartite_complementation( | ||
108 | ZXDiagram& diag, const ZXVertSeqSet& sa, const ZXVertSeqSet& sb, | |||
109 | QuantumType qtype) { | |||
110 |
5/8✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 4 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 3 times.
|
0/1? Decision couldn't be analyzed.
|
4 | for (const ZXVert& a : sa.get<TagSeq>()) { |
111 |
5/8✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 2 times.
✓ Branch 13 taken 1 times.
|
0/1? Decision couldn't be analyzed.
|
3 | for (const ZXVert& b : sb.get<TagSeq>()) { |
112 | // Don't add a doubled edge between classicals to preserve graph-like | |||
113 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2/2✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 2 times.
|
4 | if (!(qtype == QuantumType::Quantum && |
114 |
2/4✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
|
2 | *diag.get_qtype(a) == QuantumType::Classical && | |
115 |
1/6✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
|
2 | *diag.get_qtype(b) == QuantumType::Classical)) { | |
116 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | std::optional<Wire> wire = diag.wire_between(a, b); | |
117 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 2 times.
|
2 | if (wire) |
118 | ✗ | diag.remove_wire(*wire); | ||
119 | else | |||
120 |
1/2✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
|
2 | diag.add_wire(a, b, ZXWireType::H, qtype); | |
121 | } | |||
122 | } | |||
123 | } | |||
124 | 3 | } | ||
125 | ||||
126 | 1 | bool Rewrite::remove_interior_paulis_fun(ZXDiagram& diag) { | ||
127 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
|
1/2✓ Decision 'true' taken 1 times.
✗ Decision 'false' not taken.
|
1 | if (!diag.is_graphlike()) return false; |
128 | 1 | bool success = false; | ||
129 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | ZXVertSeqSet candidates; // Need an indirect iterator as BGL_FORALL_VERTICES | |
130 | // breaks when removing the current vertex | |||
131 |
8/10✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 20 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 20 times.
✓ Branch 10 taken 1 times.
✓ Branch 12 taken 20 times.
✓ Branch 13 taken 1 times.
✓ Branch 15 taken 1 times.
✓ Branch 16 taken 1 times.
|
22 | BGL_FORALL_VERTICES(v, *diag.graph, ZXGraph) { candidates.insert(v); } | |
132 | 1 | auto& view = candidates.get<TagSeq>(); | ||
133 |
2/2✓ Branch 1 taken 19 times.
✓ Branch 2 taken 1 times.
|
2/2✓ Decision 'true' taken 19 times.
✓ Decision 'false' taken 1 times.
|
20 | while (!candidates.empty()) { |
134 | 19 | auto it = view.begin(); | ||
135 |
1/2✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
|
19 | ZXVert v = *it; | |
136 |
1/2✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
|
19 | view.erase(it); | |
137 | // Check `v` is an interior Pauli | |||
138 |
3/4✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 16 times.
✓ Branch 4 taken 3 times.
|
2/2✓ Decision 'true' taken 3 times.
✓ Decision 'false' taken 18 times.
|
21 | if (!diag.is_pauli_spider(v)) continue; |
139 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | ZXVertVec v_ns = diag.neighbours(v); | |
140 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | QuantumType vqtype = *diag.get_qtype(v); | |
141 |
3/4✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 1 times.
|
2/2✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 2 times.
|
3 | if (!can_complement_neighbourhood(diag, vqtype, v_ns)) continue; |
142 | // Look for an interior Pauli neighbour | |||
143 | 1 | bool pair_found = false; | ||
144 | ZXVert u; | |||
145 | 1 | ZXVertVec u_ns; | ||
146 |
1/2✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
|
1/2✓ Decision 'true' taken 1 times.
✗ Decision 'false' not taken.
|
1 | for (const ZXVert& n : v_ns) { |
147 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
|
1/2✓ Decision 'true' taken 1 times.
✗ Decision 'false' not taken.
|
1 | if (!diag.is_pauli_spider(n)) continue; |
148 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | ZXVertVec n_ns = diag.neighbours(n); | |
149 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | QuantumType nqtype = *diag.get_qtype(n); | |
150 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
|
1/2✓ Decision 'true' taken 1 times.
✗ Decision 'false' not taken.
|
1 | if (can_complement_neighbourhood(diag, nqtype, n_ns)) { |
151 | 1 | pair_found = true; | ||
152 | 1 | u = n; | ||
153 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | u_ns = n_ns; | |
154 | 1 | break; | ||
155 | } | |||
156 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | } | |
157 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1/2✓ Decision 'true' taken 1 times.
✗ Decision 'false' not taken.
|
1 | if (!pair_found) continue; |
158 | // Found a valid pair | |||
159 | // Identify the three sets from the neighbourhoods of `u` and `v` | |||
160 |
2/4✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
|
1 | ZXVertSeqSet excl_v{v_ns.begin(), v_ns.end()}; | |
161 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | excl_v.erase(u); | |
162 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | ZXVertSeqSet excl_u, joint; | |
163 | 1 | auto& lookup_v = excl_v.get<TagKey>(); | ||
164 |
2/2✓ Branch 5 taken 2 times.
✓ Branch 6 taken 1 times.
|
2/2✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 1 times.
|
3 | for (const ZXVert& nu : u_ns) { |
165 |
3/6✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 2 times.
|
2 | if (lookup_v.find(nu) != lookup_v.end()) |
166 | ✗ | joint.insert(nu); | ||
167 | else | |||
168 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | excl_u.insert(nu); | |
169 | } | |||
170 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | excl_u.erase(v); | |
171 |
1/2✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
|
1 | excl_v.erase(joint.begin(), joint.end()); | |
172 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | const PhasedGen& v_spid = diag.get_vertex_ZXGen<PhasedGen>(v); | |
173 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | const PhasedGen& u_spid = diag.get_vertex_ZXGen<PhasedGen>(u); | |
174 | ||||
175 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | add_phase_to_vertices( | |
176 |
5/10✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
|
2 | diag, joint, v_spid.get_param() + u_spid.get_param() + 1.); | |
177 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | add_phase_to_vertices(diag, excl_u, v_spid.get_param()); | |
178 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | add_phase_to_vertices(diag, excl_v, u_spid.get_param()); | |
179 | ||||
180 | // Because `can_complement_neighbourhood` checks all neighbours, | |||
181 | // v and u have the same QuantumType | |||
182 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | bipartite_complementation(diag, joint, excl_u, vqtype); | |
183 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | bipartite_complementation(diag, joint, excl_v, vqtype); | |
184 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | bipartite_complementation(diag, excl_u, excl_v, vqtype); | |
185 | ||||
186 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | diag.remove_vertex(u); | |
187 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | diag.remove_vertex(v); | |
188 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | candidates.erase(u); | |
189 | 1 | success = true; | ||
190 |
3/4✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 2 times.
|
3 | } | |
191 | 1 | return success; | ||
192 | 1 | } | ||
193 | ||||
194 | 1 | Rewrite Rewrite::remove_interior_paulis() { | ||
195 |
1/2✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | return Rewrite(remove_interior_paulis_fun); | |
196 | } | |||
197 | ||||
198 | 1 | bool Rewrite::extend_at_boundary_paulis_fun(ZXDiagram& diag) { | ||
199 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1/2✓ Decision 'true' taken 1 times.
✗ Decision 'false' not taken.
|
1 | if (!diag.is_graphlike()) return false; |
200 | 1 | bool success = false; | ||
201 |
3/4✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 10 taken 8 times.
✓ Branch 11 taken 1 times.
|
0/1? Decision couldn't be analyzed.
|
9 | for (const ZXVert& b : diag.get_boundary()) { |
202 | // Valid ZX graph requires boundaries to have a unique neighbour | |||
203 |
2/4✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
|
8 | Wire bw = diag.adj_wires(b).at(0); | |
204 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | ZXVert u = diag.other_end(bw, b); | |
205 |
3/4✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 2 times.
|
2/2✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 8 times.
|
10 | if (!diag.is_pauli_spider(u)) continue; |
206 | 2 | bool has_internal_pauli = false; | ||
207 |
3/4✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 8 taken 6 times.
✓ Branch 9 taken 2 times.
|
0/1? Decision couldn't be analyzed.
|
8 | for (const ZXVert& w : diag.neighbours(u)) { |
208 |
2/4✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 6 times.
|
6 | if (!diag.is_pauli_spider(w)) continue; |
209 | ✗ | bool interior = true; | ||
210 |
0/1? Decision couldn't be analyzed.
|
✗ | for (const ZXVert& wn : diag.neighbours(w)) { | |
211 |
0/2✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
|
✗ | if (is_boundary_type(diag.get_zxtype(wn))) { | |
212 | ✗ | interior = false; | ||
213 | ✗ | break; | ||
214 | } | |||
215 | } | |||
216 |
0/2✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
|
✗ | if (interior) { | |
217 | ✗ | has_internal_pauli = true; | ||
218 | ✗ | break; | ||
219 | } | |||
220 | 2 | } | ||
221 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 2 times.
|
2 | if (!has_internal_pauli) continue; |
222 | // We would like to pivot about (`u`, `w`) but `u` is by a boundary, so we | |||
223 | // extend it | |||
224 | ✗ | ZXGen_ptr u_op = diag.get_vertex_ZXGen_ptr(u); | ||
225 | ✗ | QuantumType qtype = *u_op->get_qtype(); | ||
226 | ZXGen_ptr id = | |||
227 | ✗ | std::make_shared<const PhasedGen>(ZXType::ZSpider, 0., qtype); | ||
228 | ✗ | ZXVert z1 = diag.add_vertex(id); | ||
229 | ✗ | ZXVert z2 = diag.add_vertex(u_op); | ||
230 | ✗ | diag.add_wire(u, z1, ZXWireType::H, qtype); | ||
231 | ✗ | diag.add_wire(z1, z2, ZXWireType::H, qtype); | ||
232 | ✗ | diag.add_wire(z2, b, ZXWireType::Basic, qtype); | ||
233 | ✗ | diag.remove_wire(bw); | ||
234 | ✗ | diag.set_vertex_ZXGen_ptr(u, id); | ||
235 | ✗ | success = true; | ||
236 | 1 | } | ||
237 | 1 | return success; | ||
238 | } | |||
239 | ||||
240 | 1 | Rewrite Rewrite::extend_at_boundary_paulis() { | ||
241 |
1/2✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | return Rewrite(extend_at_boundary_paulis_fun); | |
242 | } | |||
243 | ||||
244 | } // namespace zx | |||
245 | ||||
246 | } // namespace tket | |||
247 |