GCC Code Coverage Report


Directory: ./
File: Clifford/SymplecticTableau.cpp
Date: 2022-10-15 05:10:18
Warnings: 2 unchecked decisions!
Exec Total Coverage
Lines: 237 256 92.6%
Functions: 21 22 95.5%
Branches: 235 364 64.6%
Decisions: 72 83 86.7%

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 "SymplecticTableau.hpp"
16
17 #include <stdexcept>
18
19 #include "OpType/OpTypeInfo.hpp"
20 #include "Utils/EigenConfig.hpp"
21
22 namespace tket {
23
24 4286 bool BoolPauli::operator<(const BoolPauli &other) const {
25
2/2
✓ Branch 0 taken 3656 times.
✓ Branch 1 taken 630 times.
2/2
✓ Decision 'true' taken 3656 times.
✓ Decision 'false' taken 630 times.
4286 if (x == other.x) {
26 3656 return z < other.z;
27 }
28 630 return x < other.x;
29 }
30
31 228 Pauli BoolPauli::to_pauli() const {
32
2/2
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 140 times.
2/2
✓ Decision 'true' taken 88 times.
✓ Decision 'false' taken 140 times.
228 if (x) {
33
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 66 times.
2/2
✓ Decision 'true' taken 22 times.
✓ Decision 'false' taken 66 times.
88 if (z)
34 22 return Pauli::Y;
35 else
36 66 return Pauli::X;
37
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 86 times.
2/2
✓ Decision 'true' taken 54 times.
✓ Decision 'false' taken 86 times.
140 } else if (z)
38 54 return Pauli::Z;
39 else
40 86 return Pauli::I;
41 }
42
43 const std::map<std::pair<BoolPauli, BoolPauli>, std::pair<BoolPauli, Complex>>
44 BoolPauli::mult_lut = {
45 // {{{x1,z1},{x2,z2}}, {{x,z},ph}}
46 {{{false, false}, {false, false}}, {{false, false}, 1.}},
47 {{{false, false}, {false, true}}, {{false, true}, 1.}},
48 {{{false, false}, {true, false}}, {{true, false}, 1.}},
49 {{{false, false}, {true, true}}, {{true, true}, 1.}},
50 {{{false, true}, {false, false}}, {{false, true}, 1.}},
51 {{{false, true}, {false, true}}, {{false, false}, 1.}},
52 {{{false, true}, {true, false}}, {{true, true}, i_}},
53 {{{false, true}, {true, true}}, {{true, false}, -i_}},
54 {{{true, false}, {false, false}}, {{true, false}, 1.}},
55 {{{true, false}, {false, true}}, {{true, true}, -i_}},
56 {{{true, false}, {true, false}}, {{false, false}, 1.}},
57 {{{true, false}, {true, true}}, {{false, true}, i_}},
58 {{{true, true}, {false, false}}, {{true, true}, 1.}},
59 {{{true, true}, {false, true}}, {{true, false}, i_}},
60 {{{true, true}, {true, false}}, {{false, true}, -i_}},
61 {{{true, true}, {true, true}}, {{false, false}, 1.}}};
62
63 34 SymplecticTableau::SymplecticTableau(
64 34 const MatrixXb &xmat, const MatrixXb &zmat, const VectorXb &phase)
65 34 : n_rows_(xmat.rows()),
66 34 n_qubits_(xmat.cols()),
67 34 xmat_(xmat),
68
1/2
✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
34 zmat_(zmat),
69
1/2
✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
34 phase_(phase) {
70
3/6
✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 34 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 34 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 34 times.
34 if (zmat.rows() != n_rows_ || phase_.size() != n_rows_)
71 throw std::invalid_argument(
72 "Tableau must have the same number of rows in each component.");
73
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 34 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 34 times.
34 if (zmat.cols() != n_qubits_)
74 throw std::invalid_argument(
75 "Tableau must have the same number of columns in x and z components.");
76 34 }
77
78
2/4
✓ Branch 2 taken 35 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 35 times.
✗ Branch 6 not taken.
35 SymplecticTableau::SymplecticTableau(const PauliStabiliserList &rows) {
79 35 n_rows_ = rows.size();
80
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 2 times.
2/2
✓ Decision 'true' taken 33 times.
✓ Decision 'false' taken 2 times.
35 if (n_rows_ == 0)
81 33 n_qubits_ = 0;
82 else
83 2 n_qubits_ = rows[0].string.size();
84
2/4
✓ Branch 1 taken 35 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 35 times.
✗ Branch 5 not taken.
35 xmat_ = MatrixXb::Zero(n_rows_, n_qubits_);
85
2/4
✓ Branch 1 taken 35 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 35 times.
✗ Branch 5 not taken.
35 zmat_ = MatrixXb::Zero(n_rows_, n_qubits_);
86
2/4
✓ Branch 1 taken 35 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 35 times.
✗ Branch 5 not taken.
35 phase_ = VectorXb::Zero(n_rows_);
87
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 35 times.
2/2
✓ Decision 'true' taken 9 times.
✓ Decision 'false' taken 35 times.
44 for (unsigned i = 0; i < n_rows_; ++i) {
88 9 const PauliStabiliser &stab = rows[i];
89
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 9 times.
9 if (stab.string.size() != n_qubits_)
90 throw std::invalid_argument(
91 "Tableau must have the same number of qubits in each row.");
92
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 9 times.
2/2
✓ Decision 'true' taken 27 times.
✓ Decision 'false' taken 9 times.
36 for (unsigned q = 0; q < n_qubits_; ++q) {
93 27 const Pauli &p = stab.string[q];
94
5/6
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 18 times.
✓ Branch 5 taken 27 times.
✗ Branch 6 not taken.
27 xmat_(i, q) = (p == Pauli::X) || (p == Pauli::Y);
95
5/6
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 15 times.
✓ Branch 5 taken 27 times.
✗ Branch 6 not taken.
27 zmat_(i, q) = (p == Pauli::Z) || (p == Pauli::Y);
96 }
97
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 phase_(i) = !stab.coeff;
98 }
99 35 }
100
101 1 unsigned SymplecticTableau::get_n_rows() const { return n_rows_; }
102 6 unsigned SymplecticTableau::get_n_qubits() const { return n_qubits_; }
103
104 76 PauliStabiliser SymplecticTableau::get_pauli(unsigned i) const {
105
1/2
✓ Branch 2 taken 76 times.
✗ Branch 3 not taken.
76 std::vector<Pauli> str(n_qubits_);
106
2/2
✓ Branch 0 taken 228 times.
✓ Branch 1 taken 76 times.
2/2
✓ Decision 'true' taken 228 times.
✓ Decision 'false' taken 76 times.
304 for (unsigned q = 0; q < n_qubits_; ++q) {
107
3/6
✓ Branch 1 taken 228 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 228 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 228 times.
✗ Branch 8 not taken.
228 str[q] = BoolPauli{xmat_(i, q), zmat_(i, q)}.to_pauli();
108 }
109
3/6
✓ Branch 1 taken 76 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 76 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 76 times.
✗ Branch 8 not taken.
152 return PauliStabiliser(str, !phase_(i));
110 76 }
111
112 1 std::ostream &operator<<(std::ostream &os, const SymplecticTableau &tab) {
113
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
2/2
✓ Decision 'true' taken 3 times.
✓ Decision 'false' taken 1 times.
4 for (unsigned i = 0; i < tab.n_rows_; ++i) {
114
7/14
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 3 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 3 times.
✗ Branch 15 not taken.
✓ Branch 17 taken 3 times.
✗ Branch 18 not taken.
✓ Branch 20 taken 3 times.
✗ Branch 21 not taken.
6 os << tab.xmat_.row(i) << " " << tab.zmat_.row(i) << " " << tab.phase_(i)
115
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 << std::endl;
116 }
117 1 return os;
118 }
119
120 bool SymplecticTableau::operator==(const SymplecticTableau &other) const {
121 bool same = this->n_rows_ == other.n_rows_;
122 same &= this->n_qubits_ == other.n_qubits_;
123 same &= this->xmat_ == other.xmat_;
124 same &= this->zmat_ == other.zmat_;
125 same &= this->phase_ == other.phase_;
126 return same;
127 }
128
129 69 void SymplecticTableau::row_mult(unsigned ra, unsigned rw, Complex coeff) {
130
1/2
✓ Branch 1 taken 69 times.
✗ Branch 2 not taken.
69 MatrixXb::RowXpr xa = xmat_.row(ra);
131
1/2
✓ Branch 1 taken 69 times.
✗ Branch 2 not taken.
69 MatrixXb::RowXpr za = zmat_.row(ra);
132
1/2
✓ Branch 1 taken 69 times.
✗ Branch 2 not taken.
69 MatrixXb::RowXpr xw = xmat_.row(rw);
133
1/2
✓ Branch 1 taken 69 times.
✗ Branch 2 not taken.
69 MatrixXb::RowXpr zw = zmat_.row(rw);
134
4/8
✓ Branch 1 taken 69 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 69 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 69 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 69 times.
✗ Branch 11 not taken.
69 row_mult(xa, za, phase_(ra), xw, zw, phase_(rw), coeff, xw, zw, phase_(rw));
135 69 }
136
137 198 void SymplecticTableau::apply_S(unsigned qb) {
138
1/2
✓ Branch 1 taken 198 times.
✗ Branch 2 not taken.
198 MatrixXb::ColXpr xcol = xmat_.col(qb);
139
1/2
✓ Branch 1 taken 198 times.
✗ Branch 2 not taken.
198 MatrixXb::ColXpr zcol = zmat_.col(qb);
140
1/2
✓ Branch 1 taken 198 times.
✗ Branch 2 not taken.
198 col_mult(xcol, zcol, true, zcol, phase_);
141 198 }
142
143 111 void SymplecticTableau::apply_V(unsigned qb) {
144
1/2
✓ Branch 1 taken 111 times.
✗ Branch 2 not taken.
111 MatrixXb::ColXpr xcol = xmat_.col(qb);
145
1/2
✓ Branch 1 taken 111 times.
✗ Branch 2 not taken.
111 MatrixXb::ColXpr zcol = zmat_.col(qb);
146
1/2
✓ Branch 1 taken 111 times.
✗ Branch 2 not taken.
111 col_mult(xcol, zcol, false, xcol, phase_);
147 111 }
148
149 110 void SymplecticTableau::apply_CX(unsigned qc, unsigned qt) {
150
2/2
✓ Branch 0 taken 642 times.
✓ Branch 1 taken 110 times.
2/2
✓ Decision 'true' taken 642 times.
✓ Decision 'false' taken 110 times.
752 for (unsigned i = 0; i < n_rows_; ++i) {
151
4/4
✓ Branch 2 taken 224 times.
✓ Branch 3 taken 418 times.
✓ Branch 5 taken 89 times.
✓ Branch 6 taken 135 times.
731 phase_(i) = phase_(i) ^ (xmat_(i, qc) && zmat_(i, qt) &&
152
2/2
✓ Branch 2 taken 51 times.
✓ Branch 3 taken 38 times.
89 !(xmat_(i, qt) ^ zmat_(i, qc)));
153 642 xmat_(i, qt) = xmat_(i, qc) ^ xmat_(i, qt);
154 642 zmat_(i, qc) = zmat_(i, qc) ^ zmat_(i, qt);
155 }
156 110 }
157
158 137 void SymplecticTableau::apply_gate(
159 OpType type, const std::vector<unsigned> &qbs) {
160
14/15
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 20 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 6 times.
✓ Branch 6 taken 14 times.
✓ Branch 7 taken 12 times.
✓ Branch 8 taken 69 times.
✓ Branch 9 taken 1 times.
✓ Branch 10 taken 1 times.
✓ Branch 11 taken 1 times.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 2 times.
137 switch (type) {
161
1/1
✓ Decision 'true' taken 5 times.
5 case OpType::Z: {
162 5 apply_S(qbs.at(0));
163 5 apply_S(qbs.at(0));
164 5 break;
165 }
166
1/1
✓ Decision 'true' taken 2 times.
2 case OpType::X: {
167 2 apply_V(qbs.at(0));
168 2 apply_V(qbs.at(0));
169 2 break;
170 }
171
1/1
✓ Decision 'true' taken 2 times.
2 case OpType::Y: {
172 2 apply_S(qbs.at(0));
173 2 apply_S(qbs.at(0));
174 2 apply_V(qbs.at(0));
175 2 apply_V(qbs.at(0));
176 2 break;
177 }
178
1/1
✓ Decision 'true' taken 20 times.
20 case OpType::S: {
179 20 apply_S(qbs.at(0));
180 20 break;
181 }
182
1/1
✓ Decision 'true' taken 1 times.
1 case OpType::Sdg: {
183 1 apply_S(qbs.at(0));
184 1 apply_S(qbs.at(0));
185 1 apply_S(qbs.at(0));
186 1 break;
187 }
188
1/1
✓ Decision 'true' taken 6 times.
6 case OpType::V: {
189 6 apply_V(qbs.at(0));
190 6 break;
191 }
192
1/1
✓ Decision 'true' taken 14 times.
14 case OpType::Vdg: {
193 14 apply_V(qbs.at(0));
194 14 apply_V(qbs.at(0));
195 14 apply_V(qbs.at(0));
196 14 break;
197 }
198
1/1
✓ Decision 'true' taken 12 times.
12 case OpType::H: {
199 12 apply_S(qbs.at(0));
200 12 apply_V(qbs.at(0));
201 12 apply_S(qbs.at(0));
202 12 break;
203 }
204
1/1
✓ Decision 'true' taken 69 times.
69 case OpType::CX: {
205 69 apply_CX(qbs.at(0), qbs.at(1));
206 69 break;
207 }
208
1/1
✓ Decision 'true' taken 1 times.
1 case OpType::CY: {
209 1 apply_S(qbs.at(1));
210 1 apply_S(qbs.at(1));
211 1 apply_S(qbs.at(1));
212 1 apply_CX(qbs.at(0), qbs.at(1));
213 1 apply_S(qbs.at(1));
214 1 break;
215 }
216
1/1
✓ Decision 'true' taken 1 times.
1 case OpType::CZ: {
217 1 apply_S(qbs.at(1));
218 1 apply_V(qbs.at(1));
219 1 apply_S(qbs.at(1));
220 1 apply_CX(qbs.at(0), qbs.at(1));
221 1 apply_S(qbs.at(1));
222 1 apply_V(qbs.at(1));
223 1 apply_S(qbs.at(1));
224 1 break;
225 }
226
1/1
✓ Decision 'true' taken 1 times.
1 case OpType::SWAP: {
227 1 apply_CX(qbs.at(0), qbs.at(1));
228 1 apply_CX(qbs.at(1), qbs.at(0));
229 1 apply_CX(qbs.at(0), qbs.at(1));
230 1 break;
231 }
232
1/1
✓ Decision 'true' taken 1 times.
1 case OpType::BRIDGE: {
233 1 apply_CX(qbs.at(0), qbs.at(2));
234 1 break;
235 }
236
0/1
✗ Decision 'true' not taken.
case OpType::noop: {
237 break;
238 }
239
1/1
✓ Decision 'true' taken 2 times.
2 default: {
240
2/4
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
2 throw BadOpType(
241 "Cannot be applied to a SymplecticTableau: not a Clifford gate",
242 4 type);
243 }
244 }
245 135 }
246
247 2 void SymplecticTableau::apply_pauli_gadget(
248 const PauliStabiliser &pauli, unsigned half_pis) {
249
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 2 times.
2 if (pauli.string.size() != n_qubits_) {
250 throw std::invalid_argument(
251 "Cannot apply pauli gadget to SymplecticTableau; string and tableau "
252 "have different numbers of qubits");
253 }
254 2 half_pis = half_pis % 4;
255
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 1 times.
3 if (half_pis == 0) return; // Identity
256
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
0/1
? Decision couldn't be analyzed.
2 if (half_pis == 2) { // Degenerates to product of PI rotations
257
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 times.
2/2
✓ Decision 'true' taken 3 times.
✓ Decision 'false' taken 1 times.
4 for (unsigned i = 0; i < pauli.string.size(); ++i) {
258
4/7
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
3 switch (pauli.string.at(i)) {
259
0/1
✗ Decision 'true' not taken.
case Pauli::I: {
260 break;
261 }
262
1/1
✓ Decision 'true' taken 1 times.
1 case Pauli::X: {
263
2/4
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
1 apply_gate(OpType::X, {i});
264 1 break;
265 }
266
1/1
✓ Decision 'true' taken 1 times.
1 case Pauli::Y: {
267
2/4
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
1 apply_gate(OpType::Y, {i});
268 1 break;
269 }
270
1/1
✓ Decision 'true' taken 1 times.
1 case Pauli::Z: {
271
2/4
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
1 apply_gate(OpType::Z, {i});
272 1 break;
273 }
274 }
275 }
276 1 return;
277 }
278
279 // From here, half_pis == 1 or 3
280 // They act the same except for a phase flip on the product term
281
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 MatrixXb pauli_xrow = MatrixXb::Zero(1, n_qubits_);
282
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 MatrixXb pauli_zrow = MatrixXb::Zero(1, n_qubits_);
283
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
2/2
✓ Decision 'true' taken 3 times.
✓ Decision 'false' taken 1 times.
4 for (unsigned i = 0; i < n_qubits_; ++i) {
284
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 Pauli p = pauli.string.at(i);
285
5/6
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
3 pauli_xrow(i) = (p == Pauli::X) || (p == Pauli::Y);
286
5/6
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
3 pauli_zrow(i) = (p == Pauli::Z) || (p == Pauli::Y);
287 }
288 1 bool phase = (!pauli.coeff) ^ (half_pis == 3);
289
290
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1 times.
2/2
✓ Decision 'true' taken 6 times.
✓ Decision 'false' taken 1 times.
7 for (unsigned i = 0; i < n_rows_; ++i) {
291 6 bool anti = false;
292
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 MatrixXb::RowXpr xr = xmat_.row(i);
293
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 MatrixXb::RowXpr zr = zmat_.row(i);
294
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 6 times.
2/2
✓ Decision 'true' taken 18 times.
✓ Decision 'false' taken 6 times.
24 for (unsigned q = 0; q < n_qubits_; ++q) {
295
6/8
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 11 times.
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 5 times.
✓ Branch 9 taken 2 times.
18 anti ^= (xr(q) && pauli_zrow(q));
296
6/8
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 11 times.
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 6 times.
✓ Branch 9 taken 1 times.
18 anti ^= (zr(q) && pauli_xrow(q));
297 }
298
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 5 times.
6 if (anti) {
299 1 row_mult(
300
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 xr, zr, phase_(i), pauli_xrow.row(0), pauli_zrow.row(0), phase, i_,
301
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 xr, zr, phase_(i));
302 }
303 }
304 }
305
306 4 MatrixXb SymplecticTableau::anticommuting_rows() const {
307
1/2
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 MatrixXb res = MatrixXb::Zero(n_rows_, n_rows_);
308
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 4 times.
2/2
✓ Decision 'true' taken 24 times.
✓ Decision 'false' taken 4 times.
28 for (unsigned i = 0; i < n_rows_; ++i) {
309
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 24 times.
2/2
✓ Decision 'true' taken 60 times.
✓ Decision 'false' taken 24 times.
84 for (unsigned j = 0; j < i; ++j) {
310 60 bool anti = false;
311
2/2
✓ Branch 0 taken 180 times.
✓ Branch 1 taken 60 times.
2/2
✓ Decision 'true' taken 180 times.
✓ Decision 'false' taken 60 times.
240 for (unsigned q = 0; q < n_qubits_; ++q) {
312
6/8
✓ Branch 1 taken 180 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 52 times.
✓ Branch 4 taken 128 times.
✓ Branch 6 taken 52 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 8 times.
✓ Branch 9 taken 44 times.
180 anti ^= (xmat_(i, q) && zmat_(j, q));
313
6/8
✓ Branch 1 taken 180 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 88 times.
✓ Branch 4 taken 92 times.
✓ Branch 6 taken 88 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 28 times.
✓ Branch 9 taken 60 times.
180 anti ^= (xmat_(j, q) && zmat_(i, q));
314 }
315
1/2
✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
60 res(i, j) = anti;
316
1/2
✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
60 res(j, i) = anti;
317 }
318 }
319 4 return res;
320 }
321
322 4 unsigned SymplecticTableau::rank() const {
323
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 MatrixXb fullmat(n_rows_, 2 * n_qubits_);
324
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
4 fullmat << xmat_, zmat_;
325 Eigen::FullPivLU<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>> lu(
326
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
4 fullmat.cast<double>());
327
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
8 return lu.rank();
328 4 }
329
330 1 SymplecticTableau SymplecticTableau::conjugate() const {
331 1 SymplecticTableau conj(*this);
332
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1 times.
2/2
✓ Decision 'true' taken 6 times.
✓ Decision 'false' taken 1 times.
7 for (unsigned i = 0; i < n_rows_; ++i) {
333 6 unsigned sum = 0;
334
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 6 times.
2/2
✓ Decision 'true' taken 18 times.
✓ Decision 'false' taken 6 times.
24 for (unsigned j = 0; j < n_qubits_; ++j) {
335
8/10
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 9 times.
✓ Branch 6 taken 9 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✓ Branch 9 taken 8 times.
✓ Branch 10 taken 1 times.
✓ Branch 11 taken 17 times.
2/2
✓ Decision 'true' taken 6 times.
✓ Decision 'false' taken 12 times.
18 if (xmat_(i, j) && zmat_(i, j)) ++sum;
336 }
337
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 5 times.
6 if (sum % 2 == 1) conj.phase_(i) ^= true;
338 }
339 1 return conj;
340 }
341
342 78 void SymplecticTableau::row_mult(
343 const MatrixXb::RowXpr &xa, const MatrixXb::RowXpr &za, const bool &pa,
344 const MatrixXb::RowXpr &xb, const MatrixXb::RowXpr &zb, const bool &pb,
345 Complex phase, MatrixXb::RowXpr &xw, MatrixXb::RowXpr &zw, bool &pw) {
346
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 61 times.
1/2
✓ Decision 'true' taken 78 times.
✗ Decision 'false' not taken.
78 if (pa) phase *= -1;
347
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 52 times.
0/1
? Decision couldn't be analyzed.
78 if (pb) phase *= -1;
348
2/2
✓ Branch 0 taken 234 times.
✓ Branch 1 taken 78 times.
2/2
✓ Decision 'true' taken 234 times.
✓ Decision 'false' taken 78 times.
312 for (unsigned i = 0; i < n_qubits_; i++) {
349 std::pair<BoolPauli, Complex> res =
350
5/10
✓ Branch 1 taken 234 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 234 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 234 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 234 times.
✗ Branch 11 not taken.
✓ Branch 14 taken 234 times.
✗ Branch 15 not taken.
234 BoolPauli::mult_lut.at({{xa(i), za(i)}, {xb(i), zb(i)}});
351
1/2
✓ Branch 1 taken 234 times.
✗ Branch 2 not taken.
234 xw(i) = res.first.x;
352
1/2
✓ Branch 1 taken 234 times.
✗ Branch 2 not taken.
234 zw(i) = res.first.z;
353 234 phase *= res.second;
354 }
355 78 pw = (phase == -1.);
356 78 }
357
358 309 void SymplecticTableau::col_mult(
359 const MatrixXb::ColXpr &a, const MatrixXb::ColXpr &b, bool flip,
360 MatrixXb::ColXpr &w, VectorXb &pw) {
361
2/2
✓ Branch 0 taken 1776 times.
✓ Branch 1 taken 309 times.
2/2
✓ Decision 'true' taken 1776 times.
✓ Decision 'false' taken 309 times.
2085 for (unsigned i = 0; i < n_rows_; i++) {
362
4/4
✓ Branch 2 taken 525 times.
✓ Branch 3 taken 1251 times.
✓ Branch 5 taken 289 times.
✓ Branch 6 taken 236 times.
1776 pw(i) = pw(i) ^ (a(i) && (b(i) ^ flip));
363 1776 w(i) = a(i) ^ b(i);
364 }
365 309 }
366
367 1 void to_json(nlohmann::json &j, const SymplecticTableau &tab) {
368
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 j["nrows"] = tab.n_rows_;
369
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 j["nqubits"] = tab.n_qubits_;
370
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 j["xmat"] = tab.xmat_;
371
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 j["zmat"] = tab.zmat_;
372
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 j["phase"] = tab.phase_;
373 1 }
374
375 1 void from_json(const nlohmann::json &j, SymplecticTableau &tab) {
376
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 unsigned n_rows = j.at("nrows").get<unsigned>();
377
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 unsigned n_qbs = j.at("nqubits").get<unsigned>();
378
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 MatrixXb xmat(n_rows, n_qbs);
379
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 MatrixXb zmat(n_rows, n_qbs);
380
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 VectorXb phase(n_rows);
381
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 from_json(j.at("xmat"), xmat);
382
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 from_json(j.at("zmat"), zmat);
383
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 from_json(j.at("phase"), phase);
384
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 tab = SymplecticTableau(xmat, zmat, phase);
385 1 }
386
387 } // namespace tket
388