GCC Code Coverage Report


Directory: ./
File: ZX/Flow.cpp
Date: 2022-10-15 05:10:18
Warnings: 17 unchecked decisions!
Exec Total Coverage
Lines: 397 420 94.5%
Functions: 10 10 100.0%
Branches: 704 1177 59.8%
Decisions: 57 97 58.8%

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