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 |