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 "ZX/Flow.hpp" | |||
16 | ||||
17 | #include "Utils/GraphHeaders.hpp" | |||
18 | #include "Utils/MatrixAnalysis.hpp" | |||
19 | ||||
20 | namespace tket { | |||
21 | ||||
22 | namespace zx { | |||
23 | ||||
24 | 24 | Flow::Flow( | ||
25 | const std::map<ZXVert, ZXVertSeqSet>& c, | |||
26 | 24 | const std::map<ZXVert, unsigned>& d) | ||
27 |
1/2✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
|
24 | : c_(c), d_(d) {} | |
28 | ||||
29 | 366 | ZXVertSeqSet Flow::c(const ZXVert& v) const { return c_.at(v); } | ||
30 | ||||
31 | 169 | ZXVertSeqSet Flow::odd(const ZXVert& v, const ZXDiagram& diag) const { | ||
32 |
1/2✓ Branch 1 taken 169 times.
✗ Branch 2 not taken.
|
169 | sequenced_map_t<ZXVert, unsigned> parities; | |
33 |
1/2✓ Branch 1 taken 169 times.
✗ Branch 2 not taken.
|
169 | ZXVertSeqSet cv = c(v); | |
34 |
5/8✓ Branch 4 taken 315 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 315 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 484 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 315 times.
✓ Branch 13 taken 169 times.
|
0/1? Decision couldn't be analyzed.
|
484 | for (const ZXVert& u : cv.get<TagSeq>()) { |
35 |
3/4✓ Branch 1 taken 315 times.
✗ Branch 2 not taken.
✓ Branch 8 taken 830 times.
✓ Branch 9 taken 315 times.
|
0/1? Decision couldn't be analyzed.
|
1145 | for (const ZXVert& n : diag.neighbours(u)) { |
36 |
3/4✓ Branch 1 taken 830 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 89 times.
✓ Branch 4 taken 741 times.
|
2/2✓ Decision 'true' taken 741 times.
✓ Decision 'false' taken 89 times.
|
830 | if (diag.get_zxtype(n) == ZXType::Output) continue; |
37 | sequenced_map_t<ZXVert, unsigned>::iterator found = | |||
38 |
1/2✓ Branch 2 taken 741 times.
✗ Branch 3 not taken.
|
741 | parities.get<TagKey>().find(n); | |
39 |
3/4✓ Branch 3 taken 741 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 576 times.
✓ Branch 6 taken 165 times.
|
2/2✓ Decision 'true' taken 576 times.
✓ Decision 'false' taken 165 times.
|
741 | if (found == parities.get<TagKey>().end()) { |
40 |
1/2✓ Branch 2 taken 576 times.
✗ Branch 3 not taken.
|
576 | parities.insert({n, 1}); | |
41 | } else { | |||
42 |
2/4✓ Branch 1 taken 165 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 165 times.
✗ Branch 6 not taken.
|
165 | parities.replace(found, {n, found->second + 1}); | |
43 | } | |||
44 | 315 | } | ||
45 | } | |||
46 |
1/2✓ Branch 1 taken 169 times.
✗ Branch 2 not taken.
|
169 | ZXVertSeqSet odds; | |
47 |
5/8✓ Branch 4 taken 576 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 576 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 745 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 576 times.
✓ Branch 13 taken 169 times.
|
0/1? Decision couldn't be analyzed.
|
745 | for (const std::pair<ZXVert, unsigned>& p : parities.get<TagSeq>()) { |
48 |
2/2✓ Branch 0 taken 427 times.
✓ Branch 1 taken 149 times.
|
2/2✓ Decision 'true' taken 427 times.
✓ Decision 'false' taken 149 times.
|
576 | if (p.second % 2 == 1) { |
49 |
1/2✓ Branch 1 taken 427 times.
✗ Branch 2 not taken.
|
427 | odds.insert(p.first); | |
50 | } | |||
51 | } | |||
52 | 338 | return odds; | ||
53 | 169 | } | ||
54 | ||||
55 | 758 | unsigned Flow::d(const ZXVert& v) const { return d_.at(v); } | ||
56 | ||||
57 | 24 | void Flow::verify(const ZXDiagram& diag) const { | ||
58 |
2/4✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 24 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 24 times.
|
24 | if (!diag.is_MBQC()) |
59 |
0/1? Decision couldn't be analyzed.
|
✗ | throw ZXError("Verifying a flow for a diagram that is not in MBQC form"); | |
60 | 24 | std::set<ZXVert> output_set; | ||
61 |
3/4✓ Branch 3 taken 24 times.
✗ Branch 4 not taken.
✓ Branch 9 taken 70 times.
✓ Branch 10 taken 24 times.
|
0/1? Decision couldn't be analyzed.
|
94 | for (const ZXVert& o : diag.get_boundary(ZXType::Output)) { |
62 |
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 | output_set.insert(diag.neighbours(o).at(0)); | |
63 | 24 | } | ||
64 |
7/8✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 303 times.
✓ Branch 7 taken 5 times.
✓ Branch 9 taken 303 times.
✓ Branch 10 taken 5 times.
✓ Branch 12 taken 24 times.
✓ Branch 13 taken 5 times.
|
313 | BGL_FORALL_VERTICES(u, *diag.graph, ZXGraph) { | |
65 |
1/2✓ Branch 1 taken 303 times.
✗ Branch 2 not taken.
|
303 | ZXType type = diag.get_zxtype(u); | |
66 |
8/10✓ Branch 1 taken 303 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 207 times.
✓ Branch 4 taken 96 times.
✓ Branch 7 taken 207 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 55 times.
✓ Branch 11 taken 152 times.
✓ Branch 12 taken 151 times.
✓ Branch 13 taken 152 times.
|
2/2✓ Decision 'true' taken 151 times.
✓ Decision 'false' taken 152 times.
|
303 | if (is_boundary_type(type) || output_set.find(u) != output_set.end()) |
67 | 151 | continue; | ||
68 |
1/2✓ Branch 1 taken 152 times.
✗ Branch 2 not taken.
|
152 | ZXVertSeqSet uc = c(u); | |
69 |
1/2✓ Branch 1 taken 152 times.
✗ Branch 2 not taken.
|
152 | ZXVertSeqSet uodd = odd(u, diag); | |
70 |
5/8✓ Branch 4 taken 291 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 289 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 441 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 291 times.
✓ Branch 13 taken 150 times.
|
0/1? Decision couldn't be analyzed.
|
441 | for (const ZXVert& v : uc.get<TagSeq>()) { |
71 |
1/2✓ Branch 1 taken 291 times.
✗ Branch 2 not taken.
|
291 | ZXType vt = diag.get_zxtype(v); | |
72 |
12/14✓ Branch 0 taken 239 times.
✓ Branch 1 taken 52 times.
✓ Branch 2 taken 138 times.
✓ Branch 3 taken 101 times.
✓ Branch 4 taken 107 times.
✓ Branch 5 taken 31 times.
✓ Branch 7 taken 107 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 107 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 106 times.
✓ Branch 14 taken 1 times.
✓ Branch 15 taken 290 times.
|
2/2✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 290 times.
|
291 | if (u != v && vt != ZXType::PX && vt != ZXType::PY && d(u) <= d(v)) |
73 |
2/4✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
|
1 | throw ZXError("A qubit has an X correction in its past"); | |
74 |
8/10✓ Branch 0 taken 238 times.
✓ Branch 1 taken 52 times.
✓ Branch 2 taken 31 times.
✓ Branch 3 taken 207 times.
✓ Branch 5 taken 31 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 31 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 5 times.
✓ Branch 11 taken 26 times.
|
2/2✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 294 times.
|
295 | if (u != v && vt == ZXType::PY && d(u) <= d(v) && |
75 |
6/8✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 5 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 4 times.
✓ Branch 9 taken 1 times.
✓ Branch 10 taken 289 times.
|
295 | uodd.find(v) == uodd.end()) | |
76 |
2/4✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
|
1 | throw ZXError("A past Y vertex receives an X correction"); | |
77 | } | |||
78 |
5/8✓ Branch 4 taken 377 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 375 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 525 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 377 times.
✓ Branch 13 taken 148 times.
|
0/1? Decision couldn't be analyzed.
|
525 | for (const ZXVert& v : uodd.get<TagSeq>()) { |
79 |
1/2✓ Branch 1 taken 377 times.
✗ Branch 2 not taken.
|
377 | ZXType vt = diag.get_zxtype(v); | |
80 |
12/14✓ Branch 0 taken 263 times.
✓ Branch 1 taken 114 times.
✓ Branch 2 taken 235 times.
✓ Branch 3 taken 28 times.
✓ Branch 4 taken 213 times.
✓ Branch 5 taken 22 times.
✓ Branch 7 taken 213 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 213 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 212 times.
✓ Branch 14 taken 1 times.
✓ Branch 15 taken 376 times.
|
2/2✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 376 times.
|
377 | if (u != v && vt != ZXType::PY && vt != ZXType::PZ && d(u) <= d(v)) |
81 |
2/4✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
|
1 | throw ZXError("A qubit has a Z correction in its past"); | |
82 |
14/18✓ Branch 0 taken 262 times.
✓ Branch 1 taken 114 times.
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 234 times.
✓ Branch 5 taken 28 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 28 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 5 times.
✓ Branch 11 taken 23 times.
✓ Branch 14 taken 5 times.
✗ Branch 15 not taken.
✓ Branch 17 taken 5 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 1 times.
✓ Branch 20 taken 4 times.
✓ Branch 21 taken 1 times.
✓ Branch 22 taken 375 times.
|
2/2✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 375 times.
|
376 | if (u != v && vt == ZXType::PY && d(u) <= d(v) && uc.find(v) == uc.end()) |
83 |
2/4✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
|
1 | throw ZXError("A past Y vertex receives a Z correction"); | |
84 | } | |||
85 |
2/4✓ Branch 2 taken 148 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 148 times.
✗ Branch 6 not taken.
|
148 | bool self_x = (uc.find(u) != uc.end()); | |
86 |
2/4✓ Branch 2 taken 148 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 148 times.
✗ Branch 6 not taken.
|
148 | bool self_z = (uodd.find(u) != uodd.end()); | |
87 |
6/7✓ Branch 0 taken 79 times.
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 20 times.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 12 times.
✗ Branch 6 not taken.
|
148 | switch (type) { | |
88 |
1/1✓ Decision 'true' taken 79 times.
|
79 | case ZXType::XY: { | |
89 |
4/4✓ Branch 0 taken 77 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 76 times.
|
2/2✓ Decision 'true' taken 3 times.
✓ Decision 'false' taken 76 times.
|
79 | if (self_x || !self_z) |
90 |
2/4✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
|
3 | throw ZXError("XY vertex must be corrected with a Z"); | |
91 | 76 | break; | ||
92 | } | |||
93 |
1/1✓ Decision 'true' taken 20 times.
|
20 | case ZXType::XZ: { | |
94 |
4/4✓ Branch 0 taken 18 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 17 times.
|
2/2✓ Decision 'true' taken 3 times.
✓ Decision 'false' taken 17 times.
|
20 | if (!self_x || !self_z) |
95 |
2/4✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
|
3 | throw ZXError("XZ vertex must be corrected with a Y"); | |
96 | 17 | break; | ||
97 | } | |||
98 |
1/1✓ Decision 'true' taken 20 times.
|
20 | case ZXType::YZ: { | |
99 |
4/4✓ Branch 0 taken 18 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 17 times.
|
2/2✓ Decision 'true' taken 3 times.
✓ Decision 'false' taken 17 times.
|
20 | if (!self_x || self_z) |
100 |
2/4✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
|
3 | throw ZXError("YZ vertex must be corrected with an X"); | |
101 | 17 | break; | ||
102 | } | |||
103 |
1/1✓ Decision 'true' taken 12 times.
|
12 | case ZXType::PX: { | |
104 |
4/6✓ Branch 0 taken 2 times.
✓ Branch 1 taken 10 times.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
|
2/2✓ Decision 'true' taken 10 times.
✓ Decision 'false' taken 2 times.
|
12 | if (!self_z) throw ZXError("PX vertex must be corrected with a Y or Z"); |
105 | 10 | break; | ||
106 | } | |||
107 |
1/1✓ Decision 'true' taken 5 times.
|
5 | case ZXType::PY: { | |
108 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
|
2/2✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 3 times.
|
5 | if (self_x == self_z) |
109 |
2/4✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
|
2 | throw ZXError("PY vertex must be corrected with an X or Z"); | |
110 | 3 | break; | ||
111 | } | |||
112 |
1/1✓ Decision 'true' taken 12 times.
|
12 | case ZXType::PZ: { | |
113 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 10 times.
|
2/2✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 10 times.
|
12 | if (!self_x) |
114 |
2/4✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
|
2 | throw ZXError("PZ vertex must be corrected with an X or Y"); | |
115 | 10 | break; | ||
116 | } | |||
117 |
0/1✗ Decision 'true' not taken.
|
✗ | default: | |
118 |
0/1? Decision couldn't be analyzed.
|
✗ | throw ZXError("Invalid ZXType for MBQC diagram"); | |
119 | } | |||
120 | 171 | } | ||
121 | 24 | } | ||
122 | ||||
123 | 2 | void Flow::focus(const ZXDiagram& diag) { | ||
124 | 2 | std::set<ZXVert> output_set; | ||
125 |
3/4✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 9 taken 5 times.
✓ Branch 10 taken 2 times.
|
0/1? Decision couldn't be analyzed.
|
7 | for (const ZXVert& o : diag.get_boundary(ZXType::Output)) { |
126 |
3/6✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 5 times.
✗ Branch 8 not taken.
|
5 | output_set.insert(diag.neighbours(o).at(0)); | |
127 | 2 | } | ||
128 | 2 | std::map<unsigned, ZXVertVec> order; | ||
129 |
2/2✓ Branch 5 taken 22 times.
✓ Branch 6 taken 2 times.
|
2/2✓ Decision 'true' taken 22 times.
✓ Decision 'false' taken 2 times.
|
24 | for (const std::pair<const ZXVert, unsigned>& p : d_) { |
130 |
1/2✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
|
22 | auto found = order.find(p.second); | |
131 |
2/2✓ Branch 2 taken 11 times.
✓ Branch 3 taken 11 times.
|
2/2✓ Decision 'true' taken 11 times.
✓ Decision 'false' taken 11 times.
|
22 | if (found == order.end()) |
132 |
3/6✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 11 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 11 times.
✗ Branch 9 not taken.
|
11 | order.insert({p.second, {p.first}}); | |
133 | else | |||
134 |
1/2✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
|
11 | found->second.push_back(p.first); | |
135 | } | |||
136 | ||||
137 |
2/2✓ Branch 5 taken 11 times.
✓ Branch 6 taken 2 times.
|
2/2✓ Decision 'true' taken 11 times.
✓ Decision 'false' taken 2 times.
|
13 | for (const std::pair<const unsigned, ZXVertVec>& p : order) { |
138 |
2/2✓ Branch 5 taken 22 times.
✓ Branch 6 taken 11 times.
|
2/2✓ Decision 'true' taken 22 times.
✓ Decision 'false' taken 11 times.
|
33 | for (const ZXVert& u : p.second) { |
139 |
3/4✓ Branch 2 taken 22 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 5 times.
✓ Branch 6 taken 17 times.
|
2/2✓ Decision 'true' taken 17 times.
✓ Decision 'false' taken 5 times.
|
22 | if (output_set.find(u) != output_set.end()) continue; |
140 |
1/2✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
|
17 | ZXVertSeqSet uc = c(u); | |
141 |
1/2✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
|
17 | ZXVertSeqSet uodd = odd(u, diag); | |
142 |
1/2✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
|
17 | sequenced_map_t<ZXVert, unsigned> parities; | |
143 |
6/10✓ Branch 4 taken 24 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 24 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 24 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 41 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 24 times.
✓ Branch 17 taken 17 times.
|
0/1? Decision couldn't be analyzed.
|
41 | for (const ZXVert& v : uc.get<TagSeq>()) parities.insert({v, 1}); |
144 |
5/8✓ Branch 4 taken 24 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 24 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 41 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 24 times.
✓ Branch 13 taken 17 times.
|
0/1? Decision couldn't be analyzed.
|
41 | for (const ZXVert& v : uc.get<TagSeq>()) { |
145 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 21 times.
|
2/2✓ Decision 'true' taken 21 times.
✓ Decision 'false' taken 3 times.
|
24 | if (v == u) continue; |
146 |
1/2✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
|
21 | ZXType vtype = diag.get_zxtype(v); | |
147 |
3/4✓ Branch 0 taken 2 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 11 times.
|
11 | if ((vtype != ZXType::XY && vtype != ZXType::PX && |
148 |
4/4✓ Branch 0 taken 11 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 19 times.
|
34 | vtype != ZXType::PY) || | |
149 |
4/8✓ 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.
✗ Branch 9 not taken.
✓ Branch 10 taken 21 times.
|
23 | (vtype == ZXType::PY && uodd.find(v) == uodd.end())) { | |
150 | ✗ | ZXVertSeqSet cv = c(v); | ||
151 |
0/1? Decision couldn't be analyzed.
|
✗ | for (const ZXVert& w : cv.get<TagSeq>()) { | |
152 | ✗ | auto found = parities.get<TagKey>().find(w); | ||
153 |
0/2✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
|
✗ | if (found == parities.get<TagKey>().end()) | |
154 | ✗ | parities.insert({w, 1}); | ||
155 | else | |||
156 | ✗ | parities.replace(found, {w, found->second + 1}); | ||
157 | } | |||
158 | } | |||
159 | } | |||
160 |
5/8✓ Branch 4 taken 39 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 39 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 56 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 39 times.
✓ Branch 13 taken 17 times.
|
0/1? Decision couldn't be analyzed.
|
56 | for (const ZXVert& v : uodd.get<TagSeq>()) { |
161 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 23 times.
|
2/2✓ Decision 'true' taken 23 times.
✓ Decision 'false' taken 16 times.
|
39 | if (v == u) continue; |
162 |
1/2✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
|
23 | ZXType vtype = diag.get_zxtype(v); | |
163 |
4/6✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 18 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 16 times.
✓ Branch 8 taken 2 times.
|
2/2✓ Decision 'true' taken 12 times.
✓ Decision 'false' taken 29 times.
|
41 | if ((output_set.find(v) == output_set.end() && vtype != ZXType::XZ && |
164 |
4/4✓ Branch 0 taken 14 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 12 times.
|
16 | vtype != ZXType::YZ && vtype != ZXType::PY && | |
165 |
4/4✓ Branch 0 taken 18 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 9 times.
|
43 | vtype != ZXType::PZ) || | |
166 |
5/8✓ 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.
✓ Branch 9 taken 12 times.
✓ Branch 10 taken 11 times.
|
25 | (vtype == ZXType::PY && uc.find(v) == uc.end())) { | |
167 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
12 | ZXVertSeqSet cv = c(v); | |
168 |
5/8✓ Branch 4 taken 22 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 22 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 34 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 22 times.
✓ Branch 13 taken 12 times.
|
0/1? Decision couldn't be analyzed.
|
34 | for (const ZXVert& w : cv.get<TagSeq>()) { |
169 |
1/2✓ Branch 2 taken 22 times.
✗ Branch 3 not taken.
|
22 | auto found = parities.get<TagKey>().find(w); | |
170 |
3/4✓ Branch 3 taken 22 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 21 times.
✓ Branch 6 taken 1 times.
|
2/2✓ Decision 'true' taken 21 times.
✓ Decision 'false' taken 1 times.
|
22 | if (found == parities.get<TagKey>().end()) |
171 |
1/2✓ Branch 2 taken 21 times.
✗ Branch 3 not taken.
|
21 | parities.insert({w, 1}); | |
172 | else | |||
173 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
|
1 | parities.replace(found, {w, found->second + 1}); | |
174 | } | |||
175 | 12 | } | ||
176 | } | |||
177 |
1/2✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
|
17 | ZXVertSeqSet new_c; | |
178 |
5/8✓ Branch 4 taken 45 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 45 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 62 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 45 times.
✓ Branch 14 taken 17 times.
|
0/1? Decision couldn't be analyzed.
|
62 | for (const std::pair<const ZXVert, unsigned> p : parities.get<TagSeq>()) { |
179 |
3/4✓ Branch 0 taken 44 times.
✓ Branch 1 taken 1 times.
✓ Branch 3 taken 44 times.
✗ Branch 4 not taken.
|
2/2✓ Decision 'true' taken 17 times.
✓ Decision 'false' taken 28 times.
|
45 | if (p.second % 2 == 1) new_c.insert(p.first); |
180 | } | |||
181 |
2/4✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 17 times.
✗ Branch 5 not taken.
|
17 | c_.at(u) = new_c; | |
182 | 17 | } | ||
183 | } | |||
184 | 2 | } | ||
185 | ||||
186 | 1 | Flow Flow::identify_causal_flow(const ZXDiagram& diag) { | ||
187 | // Check diagram has the expected form for causal flow | |||
188 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 1 times.
|
1 | if (!diag.is_MBQC()) |
189 | ✗ | throw ZXError("ZXDiagram must be in MBQC form to identify causal flow"); | ||
190 | 1 | std::set<ZXVert> input_set; | ||
191 |
3/4✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 9 taken 2 times.
✓ Branch 10 taken 1 times.
|
0/1? Decision couldn't be analyzed.
|
3 | for (const ZXVert& i : diag.get_boundary(ZXType::Input)) { |
192 |
3/6✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
|
2 | input_set.insert(diag.neighbours(i).at(0)); | |
193 | 1 | } | ||
194 | 1 | std::set<ZXVert> output_set; | ||
195 |
3/4✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 9 taken 2 times.
✓ Branch 10 taken 1 times.
|
0/1? Decision couldn't be analyzed.
|
3 | for (const ZXVert& o : diag.get_boundary(ZXType::Output)) { |
196 |
3/6✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
|
2 | output_set.insert(diag.neighbours(o).at(0)); | |
197 | 1 | } | ||
198 |
7/8✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 14 times.
✓ Branch 7 taken 1 times.
✓ Branch 9 taken 14 times.
✓ Branch 10 taken 1 times.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 1 times.
|
16 | BGL_FORALL_VERTICES(v, *diag.graph, ZXGraph) { | |
199 |
1/2✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
|
14 | ZXType vtype = diag.get_zxtype(v); | |
200 |
8/12✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
✓ Branch 4 taken 4 times.
✓ Branch 7 taken 10 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 8 times.
✓ Branch 11 taken 2 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 8 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 14 times.
|
14 | if (!is_boundary_type(vtype) && output_set.find(v) == output_set.end() && | |
201 | vtype != ZXType::XY) | |||
202 | ✗ | throw ZXError( | ||
203 | ✗ | "Causal flow is only defined when all measured vertices are XY"); | ||
204 | } | |||
205 | ||||
206 | // solved contains all vertices for which we have found corrections | |||
207 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | ZXVertSeqSet solved; | |
208 | // correctors are those vertices that have been solved but are not yet | |||
209 | // fl.c(u) for some u | |||
210 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | ZXVertSeqSet correctors; | |
211 | // past[v] is undefined if v is not yet solved | |||
212 | // past[v] is the number of neighbours of v that are still unsolved | |||
213 | // When past[v] drops to 1, we can correct the unsolved vertex using an X on | |||
214 | // v and Z on all of its other neighbours | |||
215 | 1 | std::map<ZXVert, unsigned> past; | ||
216 |
1/2✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
|
2 | Flow fl{{}, {}}; | |
217 | ||||
218 | // Outputs are trivially solved | |||
219 |
3/4✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 10 taken 2 times.
✓ Branch 11 taken 1 times.
|
3 | for (const ZXVert& o : diag.get_boundary(ZXType::Output)) { | |
220 | // ZX Diagrams requires each output to have a unique edge to another vertex | |||
221 |
2/4✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
2 | ZXVert n = diag.neighbours(o).at(0); | |
222 |
2/4✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
2 | past[n] = diag.degree(n) - 1; | |
223 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | solved.insert(o); | |
224 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | solved.insert(n); | |
225 |
3/6✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
|
2 | fl.c_.insert({n, {}}); | |
226 |
1/2✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | fl.d_.insert({n, 0}); | |
227 | // Add output to correctors if it is not an input | |||
228 |
3/6✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
|
2 | if (input_set.find(n) == input_set.end()) correctors.insert(n); | |
229 | 1 | } | ||
230 | ||||
231 | 1 | unsigned depth = 1; | ||
232 | ||||
233 | do { | |||
234 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | ZXVertSeqSet new_correctors; | |
235 |
5/8✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 8 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 14 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 8 times.
✓ Branch 13 taken 6 times.
|
14 | for (const ZXVert& v : correctors.get<TagSeq>()) { | |
236 | // Determine whether |N(v) cap unsolved| == 1 to find u | |||
237 | ZXVert u; | |||
238 | 8 | unsigned n_found = 0; | ||
239 |
3/4✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 8 taken 18 times.
✓ Branch 9 taken 8 times.
|
26 | for (const ZXVert& vn : diag.neighbours(v)) { | |
240 |
4/6✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 18 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 8 times.
✓ Branch 8 taken 10 times.
|
18 | if (solved.find(vn) == solved.end()) { | |
241 | 8 | u = vn; | ||
242 | 8 | ++n_found; | ||
243 | } | |||
244 | 8 | } | ||
245 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | if (n_found != 1) continue; | |
246 | ||||
247 | // Can correct u by firing stabilizer of v | |||
248 |
4/8✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 8 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 8 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 8 times.
✗ Branch 12 not taken.
|
8 | fl.c_.insert({u, {v}}); | |
249 |
1/2✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
|
8 | fl.d_.insert({u, depth}); | |
250 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | solved.insert(u); | |
251 | ||||
252 | // Determine any new correctors | |||
253 | 8 | n_found = 0; | ||
254 | 8 | bool in = false; | ||
255 |
3/4✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 8 taken 20 times.
✓ Branch 9 taken 8 times.
|
28 | for (const ZXVert& un : diag.neighbours(u)) { | |
256 |
3/4✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 18 times.
|
20 | if (diag.get_zxtype(un) == ZXType::Input) { | |
257 | 2 | in = true; | ||
258 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | solved.insert(un); | |
259 | 2 | continue; | ||
260 | } | |||
261 |
4/6✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 18 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 8 times.
✓ Branch 8 taken 10 times.
|
18 | if (solved.find(un) == solved.end()) { | |
262 | 8 | ++n_found; | ||
263 | } | |||
264 | // Another neighbour of un has been solved, so check if it can now | |||
265 | // correct something | |||
266 |
1/2✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
|
18 | auto it = past.find(un); | |
267 |
5/6✓ Branch 2 taken 8 times.
✓ Branch 3 taken 10 times.
✓ Branch 5 taken 8 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 8 times.
✓ Branch 8 taken 10 times.
|
18 | if (it != past.end() && it->second > 0) { | |
268 | 8 | --it->second; | ||
269 |
1/4✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
8 | if (it->second == 1) new_correctors.insert(un); | |
270 | } | |||
271 | 8 | } | ||
272 | // u is a new corrector if u notin I and |N(u) cap unsolved| == 1 | |||
273 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
|
8 | if (!in) { | |
274 |
1/2✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
|
6 | past.insert({u, n_found}); | |
275 |
2/4✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
|
6 | if (n_found == 1) new_correctors.insert(u); | |
276 | } | |||
277 | } | |||
278 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | correctors = new_correctors; | |
279 | 6 | ++depth; | ||
280 |
2/2✓ Branch 2 taken 5 times.
✓ Branch 3 taken 1 times.
|
6 | } while (!correctors.empty()); | |
281 |
2/4✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
|
1 | if (solved.size() != diag.n_vertices()) | |
282 | ✗ | throw ZXError("ZXDiagram does not have causal flow"); | ||
283 | 2 | return fl; | ||
284 | 1 | } | ||
285 | ||||
286 | 51 | std::map<ZXVert, ZXVertSeqSet> Flow::gauss_solve_correctors( | ||
287 | const ZXDiagram& diag, const boost::bimap<ZXVert, unsigned>& correctors, | |||
288 | const boost::bimap<ZXVert, unsigned>& preserve, const ZXVertVec& to_solve, | |||
289 | const boost::bimap<ZXVert, unsigned>& ys) { | |||
290 |
1/2✓ Branch 1 taken 51 times.
✗ Branch 2 not taken.
|
51 | unsigned n_correctors = correctors.size(); | |
291 |
1/2✓ Branch 1 taken 51 times.
✗ Branch 2 not taken.
|
51 | unsigned n_preserve = preserve.size(); | |
292 | 51 | unsigned n_to_solve = to_solve.size(); | ||
293 |
1/2✓ Branch 1 taken 51 times.
✗ Branch 2 not taken.
|
51 | unsigned n_ys = ys.size(); | |
294 |
2/4✓ Branch 1 taken 51 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 51 times.
✗ Branch 5 not taken.
|
51 | MatrixXb mat = MatrixXb::Zero(n_preserve + n_ys, n_correctors + n_to_solve); | |
295 | // Build adjacency matrix | |||
296 |
1/2✓ Branch 1 taken 51 times.
✗ Branch 2 not taken.
|
102 | for (boost::bimap<ZXVert, unsigned>::const_iterator it = correctors.begin(), | |
297 |
1/2✓ Branch 1 taken 51 times.
✗ Branch 2 not taken.
|
51 | end = correctors.end(); | |
298 |
4/6✓ Branch 1 taken 288 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 339 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 288 times.
✓ Branch 7 taken 51 times.
|
339 | it != end; ++it) { | |
299 |
4/6✓ Branch 1 taken 288 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 288 times.
✗ Branch 5 not taken.
✓ Branch 11 taken 809 times.
✓ Branch 12 taken 288 times.
|
1097 | for (const ZXVert& n : diag.neighbours(it->left)) { | |
300 |
1/2✓ Branch 1 taken 809 times.
✗ Branch 2 not taken.
|
809 | auto in_past = preserve.left.find(n); | |
301 |
4/6✓ Branch 1 taken 809 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 809 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 302 times.
✓ Branch 7 taken 507 times.
|
809 | if (in_past != preserve.left.end()) { | |
302 |
3/6✓ Branch 1 taken 302 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 302 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 302 times.
✗ Branch 8 not taken.
|
302 | mat(in_past->second, it->right) = true; | |
303 | } else { | |||
304 |
1/2✓ Branch 1 taken 507 times.
✗ Branch 2 not taken.
|
507 | auto in_ys = ys.left.find(n); | |
305 |
4/6✓ Branch 1 taken 507 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 507 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 505 times.
|
507 | if (in_ys != ys.left.end()) { | |
306 |
3/6✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
|
2 | mat(n_preserve + in_ys->second, it->right) = true; | |
307 | } | |||
308 | } | |||
309 | 288 | } | ||
310 | } | |||
311 |
1/2✓ Branch 1 taken 51 times.
✗ Branch 2 not taken.
|
102 | for (boost::bimap<ZXVert, unsigned>::const_iterator it = ys.begin(), | |
312 |
1/2✓ Branch 1 taken 51 times.
✗ Branch 2 not taken.
|
51 | end = ys.end(); | |
313 |
4/6✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 52 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 51 times.
|
52 | it != end; ++it) { | |
314 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | auto found = correctors.left.find(it->left); | |
315 |
3/6✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
|
1 | if (found != correctors.left.end()) | |
316 |
3/6✓ 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.
|
1 | mat(n_preserve + it->right, found->second) = true; | |
317 | } | |||
318 | // Add rhs | |||
319 |
2/2✓ Branch 0 taken 255 times.
✓ Branch 1 taken 51 times.
|
306 | for (unsigned i = 0; i < n_to_solve; ++i) { | |
320 |
1/2✓ Branch 1 taken 255 times.
✗ Branch 2 not taken.
|
255 | ZXVert v = to_solve.at(i); | |
321 |
5/7✓ Branch 1 taken 255 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 219 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 32 times.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
|
255 | switch (diag.get_zxtype(v)) { | |
322 | 219 | case ZXType::XY: | ||
323 | case ZXType::PX: { | |||
324 |
2/4✓ Branch 1 taken 219 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 219 times.
✗ Branch 5 not taken.
|
219 | mat(preserve.left.at(v), n_correctors + i) = true; | |
325 | 219 | break; | ||
326 | } | |||
327 | 3 | case ZXType::XZ: { | ||
328 |
2/4✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
|
3 | mat(preserve.left.at(v), n_correctors + i) = true; | |
329 | } | |||
330 | // fall through | |||
331 | 35 | case ZXType::YZ: | ||
332 | case ZXType::PZ: { | |||
333 |
3/4✓ Branch 1 taken 35 times.
✗ Branch 2 not taken.
✓ Branch 8 taken 83 times.
✓ Branch 9 taken 35 times.
|
118 | for (const ZXVert& n : diag.neighbours(v)) { | |
334 |
1/2✓ Branch 1 taken 83 times.
✗ Branch 2 not taken.
|
83 | auto found = preserve.left.find(n); | |
335 |
4/6✓ Branch 1 taken 83 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 83 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 58 times.
✓ Branch 7 taken 25 times.
|
83 | if (found != preserve.left.end()) | |
336 |
2/4✓ Branch 1 taken 58 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 58 times.
✗ Branch 5 not taken.
|
58 | mat(found->second, n_correctors + i) = true; | |
337 | else { | |||
338 |
1/2✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
|
25 | found = ys.left.find(n); | |
339 |
4/6✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 25 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 24 times.
|
25 | if (found != ys.left.end()) | |
340 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | mat(n_preserve + found->second, n_correctors + i) = true; | |
341 | } | |||
342 | 35 | } | ||
343 | 35 | break; | ||
344 | } | |||
345 | 1 | case ZXType::PY: { | ||
346 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | mat(n_preserve + ys.left.at(v), n_correctors + i) = true; | |
347 | 1 | break; | ||
348 | } | |||
349 | ✗ | default: { | ||
350 | ✗ | throw ZXError( | ||
351 | ✗ | "Internal error in flow identification: non-MBQC vertex found"); | ||
352 | } | |||
353 | } | |||
354 | } | |||
355 | ||||
356 | // Gaussian elimination | |||
357 | std::vector<std::pair<unsigned, unsigned>> row_ops = | |||
358 | gaussian_elimination_row_ops( | |||
359 |
3/6✓ Branch 1 taken 51 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 51 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 51 times.
✗ Branch 8 not taken.
|
102 | mat.block(0, 0, n_preserve + n_ys, n_correctors)); | |
360 |
2/2✓ Branch 5 taken 312 times.
✓ Branch 6 taken 51 times.
|
363 | for (const std::pair<unsigned, unsigned>& op : row_ops) { | |
361 |
2/2✓ Branch 0 taken 3811 times.
✓ Branch 1 taken 312 times.
|
4123 | for (unsigned j = 0; j < n_correctors + n_to_solve; ++j) { | |
362 |
2/4✓ Branch 1 taken 3811 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3811 times.
✗ Branch 5 not taken.
|
3811 | mat(op.second, j) ^= mat(op.first, j); | |
363 | } | |||
364 | } | |||
365 | ||||
366 | // Back substitution | |||
367 | // For each row i, pick a corrector j for which mat(i,j) == true, else | |||
368 | // determine that row i has zero lhs | |||
369 | 102 | std::map<unsigned, ZXVert> row_corrector; | ||
370 |
2/2✓ Branch 0 taken 254 times.
✓ Branch 1 taken 51 times.
|
305 | for (unsigned i = 0; i < n_preserve + n_ys; ++i) { | |
371 |
2/2✓ Branch 0 taken 1132 times.
✓ Branch 1 taken 77 times.
|
1209 | for (unsigned j = 0; j < n_correctors; ++j) { | |
372 |
3/4✓ Branch 1 taken 1132 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 177 times.
✓ Branch 4 taken 955 times.
|
1132 | if (mat(i, j)) { | |
373 |
2/4✓ Branch 1 taken 177 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 177 times.
✗ Branch 6 not taken.
|
177 | row_corrector.insert({i, correctors.right.at(j)}); | |
374 | 177 | break; | ||
375 | } | |||
376 | } | |||
377 | } | |||
378 | // For each past i, scan down column of rhs and for each mat(j,CI+i) == true, | |||
379 | // add corrector from row j or try next i if row j has zero lhs | |||
380 | 51 | std::map<ZXVert, ZXVertSeqSet> solved_flow; | ||
381 |
2/2✓ Branch 0 taken 255 times.
✓ Branch 1 taken 51 times.
|
306 | for (unsigned i = 0; i < n_to_solve; ++i) { | |
382 | 255 | bool fail = false; | ||
383 |
1/2✓ Branch 1 taken 255 times.
✗ Branch 2 not taken.
|
255 | ZXVertSeqSet c_i; | |
384 |
2/2✓ Branch 0 taken 1618 times.
✓ Branch 1 taken 146 times.
|
1764 | for (unsigned j = 0; j < n_preserve + n_ys; ++j) { | |
385 |
3/4✓ Branch 1 taken 1618 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 462 times.
✓ Branch 4 taken 1156 times.
|
1618 | if (mat(j, n_correctors + i)) { | |
386 |
1/2✓ Branch 1 taken 462 times.
✗ Branch 2 not taken.
|
462 | auto found = row_corrector.find(j); | |
387 |
2/2✓ Branch 2 taken 109 times.
✓ Branch 3 taken 353 times.
|
462 | if (found == row_corrector.end()) { | |
388 | 109 | fail = true; | ||
389 | 109 | break; | ||
390 | } else { | |||
391 |
1/2✓ Branch 2 taken 353 times.
✗ Branch 3 not taken.
|
353 | c_i.insert(found->second); | |
392 | } | |||
393 | } | |||
394 | } | |||
395 |
2/2✓ Branch 0 taken 146 times.
✓ Branch 1 taken 109 times.
|
255 | if (!fail) { | |
396 |
1/2✓ Branch 1 taken 146 times.
✗ Branch 2 not taken.
|
146 | ZXVert v = to_solve.at(i); | |
397 |
1/2✓ Branch 1 taken 146 times.
✗ Branch 2 not taken.
|
146 | ZXType vt = diag.get_zxtype(v); | |
398 |
6/6✓ Branch 0 taken 145 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 134 times.
✓ Branch 3 taken 11 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 133 times.
|
146 | if (vt == ZXType::XZ || vt == ZXType::YZ || vt == ZXType::PZ) | |
399 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | c_i.insert(v); | |
400 |
2/4✓ Branch 1 taken 146 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 146 times.
✗ Branch 5 not taken.
|
146 | solved_flow.insert({v, c_i}); | |
401 | } | |||
402 | 255 | } | ||
403 | 102 | return solved_flow; | ||
404 | 51 | } | ||
405 | ||||
406 | 3 | Flow Flow::identify_pauli_flow(const ZXDiagram& diag) { | ||
407 | // Check diagram has the expected form for pauli flow | |||
408 |
2/4✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
|
3 | if (!diag.is_MBQC()) | |
409 | ✗ | throw ZXError("ZXDiagram must be in MBQC form to identify Pauli flow"); | ||
410 | ||||
411 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | ZXVertSeqSet solved; | |
412 | 3 | std::set<ZXVert> inputs; | ||
413 |
1/2✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
|
6 | Flow fl{{}, {}}; | |
414 | ||||
415 | // Tag input measurements | |||
416 |
3/4✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 10 taken 9 times.
✓ Branch 11 taken 3 times.
|
12 | for (const ZXVert& i : diag.get_boundary(ZXType::Input)) { | |
417 |
2/4✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
|
9 | ZXVert ni = diag.neighbours(i).at(0); | |
418 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | inputs.insert(ni); | |
419 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | ZXType nt = diag.get_zxtype(ni); | |
420 |
3/6✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 9 times.
|
9 | if (nt == ZXType::XZ || nt == ZXType::YZ || nt == ZXType::PY) | |
421 | ✗ | throw ZXError( | ||
422 | "Inputs measured in XZ, YZ, or Y cannot be corrected with Pauli " | |||
423 | ✗ | "flow"); | ||
424 | 3 | } | ||
425 | ||||
426 | // Indexing of correctors in binary matrix can be preserved between rounds as | |||
427 | // we will only ever add new correctors | |||
428 |
1/2✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | boost::bimap<ZXVert, unsigned> correctors; | |
429 | 3 | unsigned corrector_i = 0; | ||
430 | ||||
431 |
7/8✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 68 times.
✓ Branch 7 taken 3 times.
✓ Branch 9 taken 68 times.
✓ Branch 10 taken 3 times.
✓ Branch 12 taken 3 times.
✓ Branch 13 taken 3 times.
|
74 | BGL_FORALL_VERTICES(v, *diag.graph, ZXGraph) { | |
432 |
4/5✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
✓ Branch 4 taken 13 times.
✓ Branch 5 taken 44 times.
|
68 | switch (diag.get_zxtype(v)) { | |
433 | 11 | case ZXType::Output: { | ||
434 |
2/4✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 11 times.
✗ Branch 5 not taken.
|
11 | ZXVert n = diag.neighbours(v).at(0); | |
435 | // Outputs are trivially solved | |||
436 |
1/2✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
|
11 | solved.insert(v); | |
437 |
2/4✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
✗ Branch 4 not taken.
|
11 | if (diag.get_zxtype(n) != ZXType::Input) { | |
438 |
1/2✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
|
11 | solved.insert(n); | |
439 |
3/6✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 11 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 11 times.
✗ Branch 8 not taken.
|
11 | fl.c_.insert({n, {}}); | |
440 |
1/2✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
|
11 | fl.d_.insert({n, 0}); | |
441 | } | |||
442 | // n is either an Input or PX, in which case it will be added to the | |||
443 | // correctors in the PX case | |||
444 | 11 | break; | ||
445 | } | |||
446 | 13 | case ZXType::PX: | ||
447 | case ZXType::PY: { | |||
448 | // Can use non-input Xs and Ys to correct | |||
449 |
2/4✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 13 times.
✗ Branch 6 not taken.
|
13 | if (inputs.find(v) == inputs.end()) { | |
450 |
2/4✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
|
13 | correctors.insert({v, corrector_i}); | |
451 | 13 | ++corrector_i; | ||
452 | } | |||
453 | 13 | break; | ||
454 | } | |||
455 | 44 | default: | ||
456 | 44 | break; | ||
457 | } | |||
458 | } | |||
459 | ||||
460 | 3 | unsigned depth = 1; | ||
461 | ||||
462 | 3 | unsigned n_solved = 0; | ||
463 | do { | |||
464 | // Construct Gaussian elimination problem | |||
465 |
1/2✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
|
13 | boost::bimap<ZXVert, unsigned> preserve; | |
466 |
1/2✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
|
13 | boost::bimap<ZXVert, unsigned> unsolved_ys; | |
467 | 13 | ZXVertVec to_solve; | ||
468 |
7/8✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 331 times.
✓ Branch 7 taken 13 times.
✓ Branch 9 taken 331 times.
✓ Branch 10 taken 13 times.
✓ Branch 12 taken 13 times.
✓ Branch 13 taken 13 times.
|
357 | BGL_FORALL_VERTICES(v, *diag.graph, ZXGraph) { | |
469 |
1/2✓ Branch 1 taken 331 times.
✗ Branch 2 not taken.
|
331 | ZXType type = diag.get_zxtype(v); | |
470 |
8/10✓ Branch 4 taken 331 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 331 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 122 times.
✓ Branch 10 taken 209 times.
✓ Branch 11 taken 79 times.
✓ Branch 12 taken 43 times.
✓ Branch 13 taken 79 times.
✓ Branch 14 taken 252 times.
|
331 | if (solved.get<TagKey>().find(v) == solved.get<TagKey>().end() && | |
471 | type != ZXType::Input) { | |||
472 |
1/2✓ Branch 1 taken 79 times.
✗ Branch 2 not taken.
|
79 | to_solve.push_back(v); | |
473 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 78 times.
|
79 | if (type == ZXType::PY) | |
474 |
3/6✓ 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.
|
1 | unsolved_ys.insert({v, (unsigned)unsolved_ys.size()}); | |
475 |
2/2✓ Branch 0 taken 77 times.
✓ Branch 1 taken 1 times.
|
78 | else if (type != ZXType::PZ) | |
476 |
3/6✓ Branch 1 taken 77 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 77 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 77 times.
✗ Branch 8 not taken.
|
77 | preserve.insert({v, (unsigned)preserve.size()}); | |
477 | } | |||
478 | } | |||
479 | ||||
480 | std::map<ZXVert, ZXVertSeqSet> new_corrections = gauss_solve_correctors( | |||
481 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | diag, correctors, preserve, to_solve, unsolved_ys); | |
482 | ||||
483 | 13 | n_solved = new_corrections.size(); | ||
484 | ||||
485 |
2/2✓ Branch 5 taken 37 times.
✓ Branch 6 taken 13 times.
|
50 | for (const std::pair<const ZXVert, ZXVertSeqSet>& nc : new_corrections) { | |
486 |
1/2✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
|
37 | fl.c_.insert(nc); | |
487 |
1/2✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
|
37 | fl.d_.insert({nc.first, depth}); | |
488 |
1/2✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
|
37 | solved.insert(nc.first); | |
489 |
3/4✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 28 times.
✓ Branch 6 taken 9 times.
|
37 | if (inputs.find(nc.first) == inputs.end()) | |
490 |
3/6✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 28 times.
✗ Branch 8 not taken.
|
28 | correctors.insert({nc.first, (unsigned)correctors.size()}); | |
491 | } | |||
492 | ||||
493 | 13 | ++depth; | ||
494 |
2/2✓ Branch 4 taken 10 times.
✓ Branch 5 taken 3 times.
|
13 | } while (n_solved != 0); | |
495 | ||||
496 |
2/4✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
|
3 | if (solved.size() + inputs.size() != diag.n_vertices()) | |
497 | ✗ | throw ZXError("ZXDiagram does not have pauli flow"); | ||
498 | ||||
499 | 6 | return fl; | ||
500 | 3 | } | ||
501 | ||||
502 | 1 | std::set<ZXVertSeqSet> Flow::identify_focussed_sets(const ZXDiagram& diag) { | ||
503 | // Check diagram has the expected form for pauli flow | |||
504 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
|
1 | if (!diag.is_MBQC()) | |
505 | ✗ | throw ZXError("ZXDiagram must be in MBQC form to identify gflow"); | ||
506 | ||||
507 | 1 | std::set<ZXVert> inputs; | ||
508 | 1 | std::set<ZXVert> outputs; | ||
509 | ||||
510 | // Tag input measurements | |||
511 |
3/4✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 10 taken 1 times.
✓ Branch 11 taken 1 times.
|
2 | for (const ZXVert& i : diag.get_boundary(ZXType::Input)) { | |
512 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | ZXVert ni = diag.neighbours(i).at(0); | |
513 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | inputs.insert(ni); | |
514 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | ZXType nt = diag.get_zxtype(ni); | |
515 |
3/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
|
1 | if (nt == ZXType::XZ || nt == ZXType::YZ || nt == ZXType::PY) | |
516 | ✗ | throw ZXError( | ||
517 | "Inputs measured in XZ, YZ, or Y cannot be corrected with Pauli " | |||
518 | ✗ | "flow"); | ||
519 | 1 | } | ||
520 |
3/4✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 10 taken 3 times.
✓ Branch 11 taken 1 times.
|
4 | for (const ZXVert& o : diag.get_boundary(ZXType::Output)) { | |
521 |
2/4✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
|
3 | ZXVert no = diag.neighbours(o).at(0); | |
522 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | outputs.insert(no); | |
523 | 1 | } | ||
524 | ||||
525 | // Build Gaussian elimination problem | |||
526 |
1/2✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | boost::bimap<ZXVert, unsigned> correctors; | |
527 |
1/2✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | boost::bimap<ZXVert, unsigned> preserve; | |
528 |
1/2✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | boost::bimap<ZXVert, unsigned> ys; | |
529 | 1 | unsigned n_correctors = 0; | ||
530 | 1 | unsigned n_preserve = 0; | ||
531 | 1 | unsigned n_ys = 0; | ||
532 | ||||
533 |
7/8✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 16 times.
✓ Branch 7 taken 1 times.
✓ Branch 9 taken 16 times.
✓ Branch 10 taken 1 times.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 1 times.
|
18 | BGL_FORALL_VERTICES(v, *diag.graph, ZXGraph) { | |
534 |
5/6✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 7 times.
|
16 | switch (diag.get_zxtype(v)) { | |
535 | 4 | case ZXType::XY: { | ||
536 |
2/4✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
|
4 | preserve.insert({v, n_preserve}); | |
537 | 4 | ++n_preserve; | ||
538 | // Can use non-input Xs and Ys to correct | |||
539 |
3/4✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 1 times.
|
4 | if (inputs.find(v) == inputs.end()) { | |
540 |
2/4✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
|
3 | correctors.insert({v, n_correctors}); | |
541 | 3 | ++n_correctors; | ||
542 | } | |||
543 | 4 | break; | ||
544 | } | |||
545 | 4 | case ZXType::PX: { | ||
546 | // Nonmeasured vertices also covered by PX | |||
547 | // Only need to preserve measured vertices | |||
548 |
3/4✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 3 times.
|
4 | if (outputs.find(v) == outputs.end()) { | |
549 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | preserve.insert({v, n_preserve}); | |
550 | 1 | ++n_preserve; | ||
551 | } | |||
552 | // Can use non-input Xs and Ys to correct | |||
553 |
2/4✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
|
4 | if (inputs.find(v) == inputs.end()) { | |
554 |
2/4✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
|
4 | correctors.insert({v, n_correctors}); | |
555 | 4 | ++n_correctors; | ||
556 | } | |||
557 | 4 | break; | ||
558 | } | |||
559 | 1 | case ZXType::PY: { | ||
560 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | ys.insert({v, n_ys}); | |
561 | 1 | ++n_ys; | ||
562 | // Can use non-input Xs and Ys to correct | |||
563 |
2/4✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
|
1 | if (inputs.find(v) == inputs.end()) { | |
564 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | correctors.insert({v, n_correctors}); | |
565 | 1 | ++n_correctors; | ||
566 | } | |||
567 | 1 | break; | ||
568 | } | |||
569 | 7 | default: | ||
570 | 7 | break; | ||
571 | } | |||
572 | } | |||
573 | ||||
574 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
2 | MatrixXb mat = MatrixXb::Zero(n_preserve + n_ys, n_correctors); | |
575 | ||||
576 | // Build adjacency matrix | |||
577 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | for (boost::bimap<ZXVert, unsigned>::const_iterator it = correctors.begin(), | |
578 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | end = correctors.end(); | |
579 |
4/6✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 8 times.
✓ Branch 7 taken 1 times.
|
9 | it != end; ++it) { | |
580 |
4/6✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 11 taken 22 times.
✓ Branch 12 taken 8 times.
|
30 | for (const ZXVert& n : diag.neighbours(it->left)) { | |
581 |
1/2✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
|
22 | auto in_preserve = preserve.left.find(n); | |
582 |
4/6✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 22 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 7 times.
✓ Branch 7 taken 15 times.
|
22 | if (in_preserve != preserve.left.end()) { | |
583 |
3/6✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 7 times.
✗ Branch 8 not taken.
|
7 | mat(in_preserve->second, it->right) = true; | |
584 | } else { | |||
585 |
1/2✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
|
15 | auto in_ys = ys.left.find(n); | |
586 |
4/6✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 12 times.
|
15 | if (in_ys != ys.left.end()) { | |
587 |
3/6✓ 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.
|
3 | mat(n_preserve + in_ys->second, it->right) = true; | |
588 | } | |||
589 | } | |||
590 | 8 | } | ||
591 | } | |||
592 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | for (boost::bimap<ZXVert, unsigned>::const_iterator it = ys.begin(), | |
593 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | end = ys.end(); | |
594 |
4/6✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 1 times.
|
2 | it != end; ++it) { | |
595 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | auto found = correctors.left.find(it->left); | |
596 |
3/6✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
|
1 | if (found != correctors.left.end()) | |
597 |
3/6✓ 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.
|
1 | mat(n_preserve + it->right, found->second) = true; | |
598 | } | |||
599 | ||||
600 | // Gaussian elimination | |||
601 | std::vector<std::pair<unsigned, unsigned>> row_ops = | |||
602 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
2 | gaussian_elimination_row_ops(mat); | |
603 |
2/2✓ Branch 5 taken 7 times.
✓ Branch 6 taken 1 times.
|
8 | for (const std::pair<unsigned, unsigned>& op : row_ops) { | |
604 |
2/2✓ Branch 0 taken 56 times.
✓ Branch 1 taken 7 times.
|
63 | for (unsigned j = 0; j < n_correctors; ++j) { | |
605 |
2/4✓ Branch 1 taken 56 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 56 times.
✗ Branch 5 not taken.
|
56 | mat(op.second, j) ^= mat(op.first, j); | |
606 | } | |||
607 | } | |||
608 | ||||
609 | // Back substitution | |||
610 | // For each column j, it either a leading column (the first column for which | |||
611 | // mat(i,j) == true for a given i, so set row_corrector[i] = j; by Gaussian | |||
612 | // Elimination this is the only entry in the column) or it describes the | |||
613 | // focussed set generator {j} + {row_corrector[i] | mat(i,j) == true} | |||
614 | 1 | std::set<ZXVertSeqSet> focussed; | ||
615 | 2 | std::map<unsigned, ZXVert> row_corrector; | ||
616 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | for (boost::bimap<ZXVert, unsigned>::const_iterator it = correctors.begin(), | |
617 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | end = correctors.end(); | |
618 |
4/6✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 8 times.
✓ Branch 7 taken 1 times.
|
9 | it != end; ++it) { | |
619 |
3/6✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 8 times.
✗ Branch 9 not taken.
|
8 | ZXVertSeqSet fset{it->left}; | |
620 | 8 | bool new_row_corrector = false; | ||
621 |
2/2✓ Branch 0 taken 33 times.
✓ Branch 1 taken 2 times.
|
35 | for (unsigned i = 0; i < n_preserve + n_ys; ++i) { | |
622 |
4/6✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 33 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 10 times.
✓ Branch 7 taken 23 times.
|
33 | if (mat(i, it->right)) { | |
623 |
2/4✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 10 times.
✗ Branch 6 not taken.
|
10 | auto inserted = row_corrector.insert({i, it->left}); | |
624 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
|
10 | if (inserted.second) { | |
625 | // New row_corrector, so move to next column | |||
626 | 6 | new_row_corrector = true; | ||
627 | 6 | break; | ||
628 | } else { | |||
629 | // Non-correcting column | |||
630 |
1/2✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | fset.insert(inserted.first->second); | |
631 | } | |||
632 | } | |||
633 | } | |||
634 |
6/10✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✓ Branch 9 taken 2 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
|
10 | if (!new_row_corrector) focussed.insert({fset}); | |
635 | 8 | } | ||
636 | ||||
637 | 2 | return focussed; | ||
638 | 1 | } | ||
639 | ||||
640 | } // namespace zx | |||
641 | ||||
642 | } // namespace tket | |||
643 |