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 "CliffTableau.hpp" | |||
16 | ||||
17 | #include <stdexcept> | |||
18 | ||||
19 | #include "OpType/OpType.hpp" | |||
20 | #include "OpType/OpTypeInfo.hpp" | |||
21 | #include "Utils/MatrixAnalysis.hpp" | |||
22 | #include "tkassert/Assert.hpp" | |||
23 | ||||
24 | namespace tket { | |||
25 | ||||
26 | const std::map< | |||
27 | std::pair<CliffTableau::BoolPauli, CliffTableau::BoolPauli>, | |||
28 | std::pair<CliffTableau::BoolPauli, Complex>> | |||
29 | CliffTableau::mult_lut = { | |||
30 | // {{{x1,z1},{x2,z2}}, {{x,z},ph}} | |||
31 | {{{false, false}, {false, false}}, {{false, false}, 1.}}, | |||
32 | {{{false, false}, {false, true}}, {{false, true}, 1.}}, | |||
33 | {{{false, false}, {true, false}}, {{true, false}, 1.}}, | |||
34 | {{{false, false}, {true, true}}, {{true, true}, 1.}}, | |||
35 | {{{false, true}, {false, false}}, {{false, true}, 1.}}, | |||
36 | {{{false, true}, {false, true}}, {{false, false}, 1.}}, | |||
37 | {{{false, true}, {true, false}}, {{true, true}, i_}}, | |||
38 | {{{false, true}, {true, true}}, {{true, false}, -i_}}, | |||
39 | {{{true, false}, {false, false}}, {{true, false}, 1.}}, | |||
40 | {{{true, false}, {false, true}}, {{true, true}, -i_}}, | |||
41 | {{{true, false}, {true, false}}, {{false, false}, 1.}}, | |||
42 | {{{true, false}, {true, true}}, {{false, true}, i_}}, | |||
43 | {{{true, true}, {false, false}}, {{true, true}, 1.}}, | |||
44 | {{{true, true}, {false, true}}, {{true, false}, i_}}, | |||
45 | {{{true, true}, {true, false}}, {{false, true}, -i_}}, | |||
46 | {{{true, true}, {true, true}}, {{false, false}, 1.}}}; | |||
47 | ||||
48 |
6/12✓ Branch 2 taken 53 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 53 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 53 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 53 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 53 times.
✗ Branch 15 not taken.
✓ Branch 18 taken 53 times.
✗ Branch 19 not taken.
|
53 | CliffTableau::CliffTableau(unsigned n) : size_(n) { | |
49 |
2/4✓ Branch 1 taken 53 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 53 times.
✗ Branch 5 not taken.
|
53 | xpauli_x = MatrixXb::Identity(n, n); | |
50 |
2/4✓ Branch 1 taken 53 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 53 times.
✗ Branch 5 not taken.
|
53 | xpauli_z = MatrixXb::Zero(n, n); | |
51 |
2/4✓ Branch 1 taken 53 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 53 times.
✗ Branch 5 not taken.
|
53 | xpauli_phase = VectorXb::Zero(n); | |
52 |
2/4✓ Branch 1 taken 53 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 53 times.
✗ Branch 5 not taken.
|
53 | zpauli_x = MatrixXb::Zero(n, n); | |
53 |
2/4✓ Branch 1 taken 53 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 53 times.
✗ Branch 5 not taken.
|
53 | zpauli_z = MatrixXb::Identity(n, n); | |
54 |
2/4✓ Branch 1 taken 53 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 53 times.
✗ Branch 5 not taken.
|
53 | zpauli_phase = VectorXb::Zero(n); | |
55 |
2/2✓ Branch 0 taken 241 times.
✓ Branch 1 taken 53 times.
|
2/2✓ Decision 'true' taken 241 times.
✓ Decision 'false' taken 53 times.
|
294 | for (unsigned i = 0; i < n; i++) { |
56 |
4/8✓ Branch 1 taken 241 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 241 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 241 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 241 times.
✗ Branch 11 not taken.
|
241 | qubits_.insert({Qubit(q_default_reg(), i), i}); | |
57 | } | |||
58 | 53 | } | ||
59 | ||||
60 |
6/12✓ Branch 3 taken 110 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 110 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 110 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 110 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 110 times.
✗ Branch 16 not taken.
✓ Branch 19 taken 110 times.
✗ Branch 20 not taken.
|
110 | CliffTableau::CliffTableau(const qubit_vector_t &qbs) : size_(qbs.size()) { | |
61 | 110 | const unsigned n = size_; | ||
62 |
2/4✓ Branch 1 taken 110 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 110 times.
✗ Branch 5 not taken.
|
110 | xpauli_x = MatrixXb::Identity(n, n); | |
63 |
2/4✓ Branch 1 taken 110 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 110 times.
✗ Branch 5 not taken.
|
110 | xpauli_z = MatrixXb::Zero(n, n); | |
64 |
2/4✓ Branch 1 taken 110 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 110 times.
✗ Branch 5 not taken.
|
110 | xpauli_phase = VectorXb::Zero(n); | |
65 |
2/4✓ Branch 1 taken 110 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 110 times.
✗ Branch 5 not taken.
|
110 | zpauli_x = MatrixXb::Zero(n, n); | |
66 |
2/4✓ Branch 1 taken 110 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 110 times.
✗ Branch 5 not taken.
|
110 | zpauli_z = MatrixXb::Identity(n, n); | |
67 |
2/4✓ Branch 1 taken 110 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 110 times.
✗ Branch 5 not taken.
|
110 | zpauli_phase = VectorXb::Zero(n); | |
68 | ||||
69 | 110 | unsigned i = 0; | ||
70 |
2/2✓ Branch 4 taken 356 times.
✓ Branch 5 taken 110 times.
|
2/2✓ Decision 'true' taken 356 times.
✓ Decision 'false' taken 110 times.
|
466 | for (const Qubit &q : qbs) { |
71 |
2/4✓ Branch 1 taken 356 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 356 times.
✗ Branch 5 not taken.
|
356 | qubits_.insert({q, i}); | |
72 | 356 | i++; | ||
73 | } | |||
74 | 110 | } | ||
75 | ||||
76 | 943 | static QubitPauliTensor get_pauli( | ||
77 | const Qubit &qb, const boost::bimap<Qubit, unsigned> &qubits_, | |||
78 | const MatrixXb &pauli_x, const MatrixXb &pauli_z, | |||
79 | const VectorXb &pauli_phase) { | |||
80 |
1/2✓ Branch 1 taken 943 times.
✗ Branch 2 not taken.
|
943 | unsigned uqb = qubits_.left.at(qb); | |
81 | 943 | Complex phase = 1.; | ||
82 |
3/4✓ Branch 1 taken 943 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 28 times.
✓ Branch 4 taken 915 times.
|
1/2✓ Decision 'true' taken 943 times.
✗ Decision 'false' not taken.
|
943 | if (pauli_phase(uqb)) phase = -1.; |
83 | 943 | QubitPauliTensor res(phase); | ||
84 |
1/2✓ Branch 1 taken 943 times.
✗ Branch 2 not taken.
|
1/2✓ Decision 'true' taken 943 times.
✗ Decision 'false' not taken.
|
1886 | for (boost::bimap<Qubit, unsigned>::const_iterator iter = qubits_.begin(), |
85 |
1/2✓ Branch 1 taken 943 times.
✗ Branch 2 not taken.
|
943 | iend = qubits_.end(); | |
86 |
4/6✓ Branch 1 taken 3463 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4406 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3463 times.
✓ Branch 7 taken 943 times.
|
4406 | iter != iend; ++iter) { | |
87 |
1/2✓ Branch 1 taken 3463 times.
✗ Branch 2 not taken.
|
3463 | unsigned origin = iter->right; | |
88 |
3/4✓ Branch 1 taken 3463 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 716 times.
✓ Branch 4 taken 2747 times.
|
2/2✓ Decision 'true' taken 716 times.
✓ Decision 'false' taken 2747 times.
|
3463 | if (pauli_x(uqb, origin)) { |
89 |
3/4✓ Branch 1 taken 716 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 126 times.
✓ Branch 4 taken 590 times.
|
2/2✓ Decision 'true' taken 126 times.
✓ Decision 'false' taken 590 times.
|
716 | if (pauli_z(uqb, origin)) { |
90 |
3/6✓ Branch 1 taken 126 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 126 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 126 times.
✗ Branch 8 not taken.
|
126 | res = res * QubitPauliTensor(iter->left, Pauli::Y); | |
91 | } else { | |||
92 |
3/6✓ Branch 1 taken 590 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 590 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 590 times.
✗ Branch 8 not taken.
|
590 | res = res * QubitPauliTensor(iter->left, Pauli::X); | |
93 | } | |||
94 |
3/4✓ Branch 1 taken 2747 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 480 times.
✓ Branch 4 taken 2267 times.
|
2/2✓ Decision 'true' taken 480 times.
✓ Decision 'false' taken 2267 times.
|
2747 | } else if (pauli_z(uqb, origin)) { |
95 |
3/6✓ Branch 1 taken 480 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 480 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 480 times.
✗ Branch 8 not taken.
|
480 | res = res * QubitPauliTensor(iter->left, Pauli::Z); | |
96 | } | |||
97 | } | |||
98 | 1886 | return res; | ||
99 | } | |||
100 | ||||
101 | 550 | QubitPauliTensor CliffTableau::get_zpauli(const Qubit &qb) const { | ||
102 | 550 | return get_pauli(qb, qubits_, zpauli_x, zpauli_z, zpauli_phase); | ||
103 | } | |||
104 | ||||
105 | 393 | QubitPauliTensor CliffTableau::get_xpauli(const Qubit &qb) const { | ||
106 | 393 | return get_pauli(qb, qubits_, xpauli_x, xpauli_z, xpauli_phase); | ||
107 | } | |||
108 | ||||
109 | 80 | std::set<Qubit> CliffTableau::get_qubits() const { | ||
110 | 80 | std::set<Qubit> result; | ||
111 |
1/2✓ Branch 1 taken 80 times.
✗ Branch 2 not taken.
|
1/2✓ Decision 'true' taken 80 times.
✗ Decision 'false' not taken.
|
160 | for (boost::bimap<Qubit, unsigned>::const_iterator iter = qubits_.begin(), |
112 |
1/2✓ Branch 1 taken 80 times.
✗ Branch 2 not taken.
|
80 | iend = qubits_.end(); | |
113 |
4/6✓ Branch 1 taken 277 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 357 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 277 times.
✓ Branch 7 taken 80 times.
|
357 | iter != iend; ++iter) { | |
114 |
2/4✓ Branch 1 taken 277 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 277 times.
✗ Branch 5 not taken.
|
277 | result.insert(iter->left); | |
115 | } | |||
116 | 80 | return result; | ||
117 | } | |||
118 | ||||
119 | 1486 | void CliffTableau::row_mult( | ||
120 | const MatrixXb::RowXpr &xa, const MatrixXb::RowXpr &za, const bool &pa, | |||
121 | const MatrixXb::RowXpr &xb, const MatrixXb::RowXpr &zb, const bool &pb, | |||
122 | Complex phase, MatrixXb::RowXpr &xw, MatrixXb::RowXpr &zw, bool &pw) { | |||
123 |
2/2✓ Branch 0 taken 286 times.
✓ Branch 1 taken 1200 times.
|
1/2✓ Decision 'true' taken 1486 times.
✗ Decision 'false' not taken.
|
1486 | if (pa) phase *= -1; |
124 |
2/2✓ Branch 0 taken 354 times.
✓ Branch 1 taken 1132 times.
|
0/1? Decision couldn't be analyzed.
|
1486 | if (pb) phase *= -1; |
125 |
2/2✓ Branch 0 taken 6298 times.
✓ Branch 1 taken 1486 times.
|
2/2✓ Decision 'true' taken 6298 times.
✓ Decision 'false' taken 1486 times.
|
7784 | for (unsigned i = 0; i < size_; i++) { |
126 | std::pair<BoolPauli, Complex> res = | |||
127 |
5/10✓ Branch 1 taken 6298 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6298 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 6298 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 6298 times.
✗ Branch 11 not taken.
✓ Branch 14 taken 6298 times.
✗ Branch 15 not taken.
|
6298 | mult_lut.at({{xa(i), za(i)}, {xb(i), zb(i)}}); | |
128 |
1/2✓ Branch 1 taken 6298 times.
✗ Branch 2 not taken.
|
6298 | xw(i) = res.first.x; | |
129 |
1/2✓ Branch 1 taken 6298 times.
✗ Branch 2 not taken.
|
6298 | zw(i) = res.first.z; | |
130 | 6298 | phase *= res.second; | ||
131 | } | |||
132 | 1486 | pw = (phase == -1.); | ||
133 | 1486 | } | ||
134 | ||||
135 | 3164 | void CliffTableau::col_mult( | ||
136 | const MatrixXb::ColXpr &a, const MatrixXb::ColXpr &b, bool flip, | |||
137 | MatrixXb::ColXpr &w, VectorXb &pw) { | |||
138 |
2/2✓ Branch 0 taken 11024 times.
✓ Branch 1 taken 3164 times.
|
2/2✓ Decision 'true' taken 11024 times.
✓ Decision 'false' taken 3164 times.
|
14188 | for (unsigned i = 0; i < size_; i++) { |
139 |
4/4✓ Branch 2 taken 2461 times.
✓ Branch 3 taken 8563 times.
✓ Branch 5 taken 1110 times.
✓ Branch 6 taken 1351 times.
|
11024 | pw(i) = pw(i) ^ (a(i) && (b(i) ^ flip)); | |
140 | 11024 | w(i) = a(i) ^ b(i); | ||
141 | } | |||
142 | 3164 | } | ||
143 | ||||
144 | 1063 | void CliffTableau::apply_S_at_front(unsigned qb) { | ||
145 |
1/2✓ Branch 1 taken 1063 times.
✗ Branch 2 not taken.
|
1063 | MatrixXb::ColXpr xx = xpauli_x.col(qb); | |
146 |
1/2✓ Branch 1 taken 1063 times.
✗ Branch 2 not taken.
|
1063 | MatrixXb::ColXpr xz = xpauli_z.col(qb); | |
147 |
1/2✓ Branch 1 taken 1063 times.
✗ Branch 2 not taken.
|
1063 | MatrixXb::ColXpr zx = zpauli_x.col(qb); | |
148 |
1/2✓ Branch 1 taken 1063 times.
✗ Branch 2 not taken.
|
1063 | MatrixXb::ColXpr zz = zpauli_z.col(qb); | |
149 |
1/2✓ Branch 1 taken 1063 times.
✗ Branch 2 not taken.
|
1063 | col_mult(xx, xz, true, xz, xpauli_phase); | |
150 |
1/2✓ Branch 1 taken 1063 times.
✗ Branch 2 not taken.
|
1063 | col_mult(zx, zz, true, zz, zpauli_phase); | |
151 | 1063 | } | ||
152 | ||||
153 | 349 | void CliffTableau::apply_S_at_end(unsigned qb) { | ||
154 |
1/2✓ Branch 1 taken 349 times.
✗ Branch 2 not taken.
|
349 | MatrixXb::RowXpr xx = xpauli_x.row(qb); | |
155 |
1/2✓ Branch 1 taken 349 times.
✗ Branch 2 not taken.
|
349 | MatrixXb::RowXpr xz = xpauli_z.row(qb); | |
156 |
1/2✓ Branch 1 taken 349 times.
✗ Branch 2 not taken.
|
349 | MatrixXb::RowXpr zx = zpauli_x.row(qb); | |
157 |
1/2✓ Branch 1 taken 349 times.
✗ Branch 2 not taken.
|
349 | MatrixXb::RowXpr zz = zpauli_z.row(qb); | |
158 | 349 | row_mult( | ||
159 |
2/4✓ Branch 1 taken 349 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 349 times.
✗ Branch 5 not taken.
|
349 | zx, zz, zpauli_phase(qb), xx, xz, xpauli_phase(qb), i_, xx, xz, | |
160 |
2/4✓ Branch 1 taken 349 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 349 times.
✗ Branch 5 not taken.
|
349 | xpauli_phase(qb)); | |
161 | 349 | } | ||
162 | ||||
163 | 519 | void CliffTableau::apply_V_at_front(unsigned qb) { | ||
164 |
1/2✓ Branch 1 taken 519 times.
✗ Branch 2 not taken.
|
519 | MatrixXb::ColXpr xx = xpauli_x.col(qb); | |
165 |
1/2✓ Branch 1 taken 519 times.
✗ Branch 2 not taken.
|
519 | MatrixXb::ColXpr xz = xpauli_z.col(qb); | |
166 |
1/2✓ Branch 1 taken 519 times.
✗ Branch 2 not taken.
|
519 | MatrixXb::ColXpr zx = zpauli_x.col(qb); | |
167 |
1/2✓ Branch 1 taken 519 times.
✗ Branch 2 not taken.
|
519 | MatrixXb::ColXpr zz = zpauli_z.col(qb); | |
168 |
1/2✓ Branch 1 taken 519 times.
✗ Branch 2 not taken.
|
519 | col_mult(xx, xz, false, xx, xpauli_phase); | |
169 |
1/2✓ Branch 1 taken 519 times.
✗ Branch 2 not taken.
|
519 | col_mult(zx, zz, false, zx, zpauli_phase); | |
170 | 519 | } | ||
171 | ||||
172 | 487 | void CliffTableau::apply_V_at_end(unsigned qb) { | ||
173 |
1/2✓ Branch 1 taken 487 times.
✗ Branch 2 not taken.
|
487 | MatrixXb::RowXpr xx = xpauli_x.row(qb); | |
174 |
1/2✓ Branch 1 taken 487 times.
✗ Branch 2 not taken.
|
487 | MatrixXb::RowXpr xz = xpauli_z.row(qb); | |
175 |
1/2✓ Branch 1 taken 487 times.
✗ Branch 2 not taken.
|
487 | MatrixXb::RowXpr zx = zpauli_x.row(qb); | |
176 |
1/2✓ Branch 1 taken 487 times.
✗ Branch 2 not taken.
|
487 | MatrixXb::RowXpr zz = zpauli_z.row(qb); | |
177 | 487 | row_mult( | ||
178 |
2/4✓ Branch 1 taken 487 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 487 times.
✗ Branch 5 not taken.
|
487 | xx, xz, xpauli_phase(qb), zx, zz, zpauli_phase(qb), i_, zx, zz, | |
179 |
2/4✓ Branch 1 taken 487 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 487 times.
✗ Branch 5 not taken.
|
487 | zpauli_phase(qb)); | |
180 | 487 | } | ||
181 | ||||
182 | 67 | void CliffTableau::apply_CX_at_front(unsigned control, unsigned target) { | ||
183 |
2/2✓ Branch 0 taken 261 times.
✓ Branch 1 taken 67 times.
|
2/2✓ Decision 'true' taken 261 times.
✓ Decision 'false' taken 67 times.
|
328 | for (unsigned i = 0; i < size_; i++) { |
184 | 522 | xpauli_phase(i) = | ||
185 |
4/4✓ Branch 2 taken 107 times.
✓ Branch 3 taken 154 times.
✓ Branch 5 taken 14 times.
✓ Branch 6 taken 93 times.
|
275 | xpauli_phase(i) ^ (xpauli_x(i, control) && xpauli_z(i, target) && | |
186 |
2/2✓ Branch 2 taken 12 times.
✓ Branch 3 taken 2 times.
|
14 | !(xpauli_x(i, target) ^ xpauli_z(i, control))); | |
187 | 261 | xpauli_x(i, target) = xpauli_x(i, control) ^ xpauli_x(i, target); | ||
188 | 261 | xpauli_z(i, control) = xpauli_z(i, control) ^ xpauli_z(i, target); | ||
189 | 522 | zpauli_phase(i) = | ||
190 |
4/4✓ Branch 2 taken 53 times.
✓ Branch 3 taken 208 times.
✓ Branch 5 taken 29 times.
✓ Branch 6 taken 24 times.
|
290 | zpauli_phase(i) ^ (zpauli_x(i, control) && zpauli_z(i, target) && | |
191 |
2/2✓ Branch 2 taken 16 times.
✓ Branch 3 taken 13 times.
|
29 | !(zpauli_x(i, target) ^ zpauli_z(i, control))); | |
192 | 261 | zpauli_x(i, target) = zpauli_x(i, control) ^ zpauli_x(i, target); | ||
193 | 261 | zpauli_z(i, control) = zpauli_z(i, control) ^ zpauli_z(i, target); | ||
194 | } | |||
195 | 67 | } | ||
196 | ||||
197 | 282 | void CliffTableau::apply_CX_at_end(unsigned control, unsigned target) { | ||
198 |
1/2✓ Branch 1 taken 282 times.
✗ Branch 2 not taken.
|
282 | MatrixXb::RowXpr xxc = xpauli_x.row(control); | |
199 |
1/2✓ Branch 1 taken 282 times.
✗ Branch 2 not taken.
|
282 | MatrixXb::RowXpr xzc = xpauli_z.row(control); | |
200 |
1/2✓ Branch 1 taken 282 times.
✗ Branch 2 not taken.
|
282 | MatrixXb::RowXpr zxt = zpauli_x.row(target); | |
201 |
1/2✓ Branch 1 taken 282 times.
✗ Branch 2 not taken.
|
282 | MatrixXb::RowXpr zzt = zpauli_z.row(target); | |
202 | ✗ | row_mult( | ||
203 |
3/6✓ Branch 1 taken 282 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 282 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 282 times.
✗ Branch 8 not taken.
|
282 | xxc, xzc, xpauli_phase(control), xpauli_x.row(target), | |
204 |
2/4✓ Branch 1 taken 282 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 282 times.
✗ Branch 5 not taken.
|
282 | xpauli_z.row(target), xpauli_phase(target), 1., xxc, xzc, | |
205 |
1/2✓ Branch 1 taken 282 times.
✗ Branch 2 not taken.
|
282 | xpauli_phase(control)); | |
206 |
1/2✓ Branch 1 taken 282 times.
✗ Branch 2 not taken.
|
282 | row_mult( | |
207 |
2/4✓ Branch 1 taken 282 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 282 times.
✗ Branch 5 not taken.
|
282 | zpauli_x.row(control), zpauli_z.row(control), zpauli_phase(control), zxt, | |
208 |
3/6✓ Branch 1 taken 282 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 282 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 282 times.
✗ Branch 9 not taken.
|
282 | zzt, zpauli_phase(target), 1., zxt, zzt, zpauli_phase(target)); | |
209 | 282 | } | ||
210 | ||||
211 | 14 | void CliffTableau::apply_gate_at_front( | ||
212 | OpType type, const std::vector<unsigned> &qbs) { | |||
213 |
5/15✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 8 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 1 times.
|
14 | switch (type) { | |
214 |
0/1✗ Decision 'true' not taken.
|
✗ | case OpType::Z: { | |
215 | ✗ | apply_S_at_front(qbs.at(0)); | ||
216 | ✗ | apply_S_at_front(qbs.at(0)); | ||
217 | ✗ | break; | ||
218 | } | |||
219 |
0/1✗ Decision 'true' not taken.
|
✗ | case OpType::X: { | |
220 | ✗ | apply_V_at_front(qbs.at(0)); | ||
221 | ✗ | apply_V_at_front(qbs.at(0)); | ||
222 | ✗ | break; | ||
223 | } | |||
224 |
0/1✗ Decision 'true' not taken.
|
✗ | case OpType::Y: { | |
225 | ✗ | apply_S_at_front(qbs.at(0)); | ||
226 | ✗ | apply_S_at_front(qbs.at(0)); | ||
227 | ✗ | apply_V_at_front(qbs.at(0)); | ||
228 | ✗ | apply_V_at_front(qbs.at(0)); | ||
229 | ✗ | break; | ||
230 | } | |||
231 |
1/1✓ Decision 'true' taken 2 times.
|
2 | case OpType::S: { | |
232 | 2 | apply_S_at_front(qbs.at(0)); | ||
233 | 2 | break; | ||
234 | } | |||
235 |
0/1✗ Decision 'true' not taken.
|
✗ | case OpType::Sdg: { | |
236 | ✗ | apply_S_at_front(qbs.at(0)); | ||
237 | ✗ | apply_S_at_front(qbs.at(0)); | ||
238 | ✗ | apply_S_at_front(qbs.at(0)); | ||
239 | ✗ | break; | ||
240 | } | |||
241 |
0/1✗ Decision 'true' not taken.
|
✗ | case OpType::V: { | |
242 | ✗ | apply_V_at_front(qbs.at(0)); | ||
243 | ✗ | break; | ||
244 | } | |||
245 |
1/1✓ Decision 'true' taken 2 times.
|
2 | case OpType::Vdg: { | |
246 | 2 | apply_V_at_front(qbs.at(0)); | ||
247 | 2 | apply_V_at_front(qbs.at(0)); | ||
248 | 2 | apply_V_at_front(qbs.at(0)); | ||
249 | 2 | break; | ||
250 | } | |||
251 |
1/1✓ Decision 'true' taken 1 times.
|
1 | case OpType::H: { | |
252 | 1 | apply_S_at_front(qbs.at(0)); | ||
253 | 1 | apply_V_at_front(qbs.at(0)); | ||
254 | 1 | apply_S_at_front(qbs.at(0)); | ||
255 | 1 | break; | ||
256 | } | |||
257 |
1/1✓ Decision 'true' taken 8 times.
|
8 | case OpType::CX: { | |
258 | 8 | apply_CX_at_front(qbs.at(0), qbs.at(1)); | ||
259 | 8 | break; | ||
260 | } | |||
261 |
0/1✗ Decision 'true' not taken.
|
✗ | case OpType::CY: { | |
262 | ✗ | apply_V_at_front(qbs.at(1)); | ||
263 | ✗ | apply_V_at_front(qbs.at(1)); | ||
264 | ✗ | apply_V_at_front(qbs.at(1)); | ||
265 | ✗ | apply_CX_at_front(qbs.at(0), qbs.at(1)); | ||
266 | ✗ | apply_V_at_front(qbs.at(1)); | ||
267 | ✗ | break; | ||
268 | } | |||
269 |
0/1✗ Decision 'true' not taken.
|
✗ | case OpType::CZ: { | |
270 | ✗ | apply_S_at_front(qbs.at(1)); | ||
271 | ✗ | apply_V_at_front(qbs.at(1)); | ||
272 | ✗ | apply_S_at_front(qbs.at(1)); | ||
273 | ✗ | apply_CX_at_front(qbs.at(0), qbs.at(1)); | ||
274 | ✗ | apply_S_at_front(qbs.at(1)); | ||
275 | ✗ | apply_V_at_front(qbs.at(1)); | ||
276 | ✗ | apply_S_at_front(qbs.at(1)); | ||
277 | ✗ | break; | ||
278 | } | |||
279 |
0/1✗ Decision 'true' not taken.
|
✗ | case OpType::SWAP: { | |
280 | ✗ | apply_CX_at_front(qbs.at(0), qbs.at(1)); | ||
281 | ✗ | apply_CX_at_front(qbs.at(1), qbs.at(0)); | ||
282 | ✗ | apply_CX_at_front(qbs.at(0), qbs.at(1)); | ||
283 | ✗ | break; | ||
284 | } | |||
285 |
0/1✗ Decision 'true' not taken.
|
✗ | case OpType::BRIDGE: { | |
286 | ✗ | apply_CX_at_front(qbs.at(0), qbs.at(2)); | ||
287 | ✗ | break; | ||
288 | } | |||
289 | ✗ | case OpType::noop: | ||
290 | case OpType::Phase: { | |||
291 | ✗ | break; | ||
292 | } | |||
293 |
1/1✓ Decision 'true' taken 1 times.
|
1 | default: { | |
294 |
2/4✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
|
1 | throw BadOpType("Not a Clifford gate", type); | |
295 | } | |||
296 | } | |||
297 | 13 | } | ||
298 | ||||
299 | ✗ | void CliffTableau::apply_gate_at_front(OpType type, const qubit_vector_t &qbs) { | ||
300 | ✗ | std::vector<unsigned> uqbs; | ||
301 |
0/2✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
|
✗ | for (const Qubit &qb : qbs) { | |
302 | ✗ | uqbs.push_back(qubits_.left.at(qb)); | ||
303 | } | |||
304 | ✗ | apply_gate_at_front(type, uqbs); | ||
305 | } | |||
306 | ||||
307 | 747 | void CliffTableau::apply_gate_at_end( | ||
308 | OpType type, const std::vector<unsigned> &qbs) { | |||
309 |
9/15✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 26 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 251 times.
✓ Branch 6 taken 14 times.
✓ Branch 7 taken 154 times.
✓ Branch 8 taken 279 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 2 times.
|
747 | switch (type) { | |
310 |
0/1✗ Decision 'true' not taken.
|
✗ | case OpType::Z: { | |
311 | ✗ | apply_S_at_end(qbs.at(0)); | ||
312 | ✗ | apply_S_at_end(qbs.at(0)); | ||
313 | ✗ | break; | ||
314 | } | |||
315 |
1/1✓ Decision 'true' taken 17 times.
|
17 | case OpType::X: { | |
316 | 17 | apply_V_at_end(qbs.at(0)); | ||
317 | 17 | apply_V_at_end(qbs.at(0)); | ||
318 | 17 | break; | ||
319 | } | |||
320 |
0/1✗ Decision 'true' not taken.
|
✗ | case OpType::Y: { | |
321 | ✗ | apply_S_at_end(qbs.at(0)); | ||
322 | ✗ | apply_S_at_end(qbs.at(0)); | ||
323 | ✗ | apply_V_at_end(qbs.at(0)); | ||
324 | ✗ | apply_V_at_end(qbs.at(0)); | ||
325 | ✗ | break; | ||
326 | } | |||
327 |
1/1✓ Decision 'true' taken 26 times.
|
26 | case OpType::S: { | |
328 | 26 | apply_S_at_end(qbs.at(0)); | ||
329 | 26 | break; | ||
330 | } | |||
331 |
1/1✓ Decision 'true' taken 1 times.
|
1 | case OpType::Sdg: { | |
332 | 1 | apply_S_at_end(qbs.at(0)); | ||
333 | 1 | apply_S_at_end(qbs.at(0)); | ||
334 | 1 | apply_S_at_end(qbs.at(0)); | ||
335 | 1 | break; | ||
336 | } | |||
337 |
1/1✓ Decision 'true' taken 251 times.
|
251 | case OpType::V: { | |
338 | 251 | apply_V_at_end(qbs.at(0)); | ||
339 | 251 | break; | ||
340 | } | |||
341 |
1/1✓ Decision 'true' taken 14 times.
|
14 | case OpType::Vdg: { | |
342 | 14 | apply_V_at_end(qbs.at(0)); | ||
343 | 14 | apply_V_at_end(qbs.at(0)); | ||
344 | 14 | apply_V_at_end(qbs.at(0)); | ||
345 | 14 | break; | ||
346 | } | |||
347 |
1/1✓ Decision 'true' taken 154 times.
|
154 | case OpType::H: { | |
348 | 154 | apply_S_at_end(qbs.at(0)); | ||
349 | 154 | apply_V_at_end(qbs.at(0)); | ||
350 | 154 | apply_S_at_end(qbs.at(0)); | ||
351 | 154 | break; | ||
352 | } | |||
353 |
1/1✓ Decision 'true' taken 279 times.
|
279 | case OpType::CX: { | |
354 | 279 | apply_CX_at_end(qbs.at(0), qbs.at(1)); | ||
355 | 279 | break; | ||
356 | } | |||
357 |
0/1✗ Decision 'true' not taken.
|
✗ | case OpType::CY: { | |
358 | ✗ | apply_V_at_end(qbs.at(1)); | ||
359 | ✗ | apply_V_at_end(qbs.at(1)); | ||
360 | ✗ | apply_V_at_end(qbs.at(1)); | ||
361 | ✗ | apply_CX_at_end(qbs.at(0), qbs.at(1)); | ||
362 | ✗ | apply_V_at_end(qbs.at(1)); | ||
363 | ✗ | break; | ||
364 | } | |||
365 |
1/1✓ Decision 'true' taken 3 times.
|
3 | case OpType::CZ: { | |
366 | 3 | apply_S_at_end(qbs.at(1)); | ||
367 | 3 | apply_V_at_end(qbs.at(1)); | ||
368 | 3 | apply_S_at_end(qbs.at(1)); | ||
369 | 3 | apply_CX_at_end(qbs.at(0), qbs.at(1)); | ||
370 | 3 | apply_S_at_end(qbs.at(1)); | ||
371 | 3 | apply_V_at_end(qbs.at(1)); | ||
372 | 3 | apply_S_at_end(qbs.at(1)); | ||
373 | 3 | break; | ||
374 | } | |||
375 |
0/1✗ Decision 'true' not taken.
|
✗ | case OpType::SWAP: { | |
376 | ✗ | apply_CX_at_end(qbs.at(0), qbs.at(1)); | ||
377 | ✗ | apply_CX_at_end(qbs.at(1), qbs.at(0)); | ||
378 | ✗ | apply_CX_at_end(qbs.at(0), qbs.at(1)); | ||
379 | ✗ | break; | ||
380 | } | |||
381 |
0/1✗ Decision 'true' not taken.
|
✗ | case OpType::BRIDGE: { | |
382 | ✗ | apply_CX_at_end(qbs.at(0), qbs.at(2)); | ||
383 | ✗ | break; | ||
384 | } | |||
385 | ✗ | case OpType::noop: | ||
386 | case OpType::Phase: { | |||
387 | ✗ | break; | ||
388 | } | |||
389 |
1/1✓ Decision 'true' taken 2 times.
|
2 | default: { | |
390 |
2/4✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
|
2 | throw BadOpType("Not a Clifford gate", type); | |
391 | } | |||
392 | } | |||
393 | 745 | } | ||
394 | ||||
395 | 489 | void CliffTableau::apply_gate_at_end(OpType type, const qubit_vector_t &qbs) { | ||
396 | 489 | std::vector<unsigned> uqbs; | ||
397 |
2/2✓ Branch 5 taken 676 times.
✓ Branch 6 taken 489 times.
|
2/2✓ Decision 'true' taken 676 times.
✓ Decision 'false' taken 489 times.
|
1165 | for (const Qubit &qb : qbs) { |
398 |
2/4✓ Branch 1 taken 676 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 676 times.
✗ Branch 5 not taken.
|
676 | uqbs.push_back(qubits_.left.at(qb)); | |
399 | } | |||
400 |
1/2✓ Branch 1 taken 489 times.
✗ Branch 2 not taken.
|
489 | apply_gate_at_end(type, uqbs); | |
401 | 489 | } | ||
402 | ||||
403 | 22 | void CliffTableau::apply_pauli_at_front( | ||
404 | const QubitPauliTensor &pauli, unsigned half_pis) { | |||
405 |
1/2✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
|
22 | CliffTableau pauli_tab(size_); | |
406 |
1/2✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
|
22 | pauli_tab.qubits_ = this->qubits_; | |
407 |
1/2✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
|
22 | pauli_tab.apply_pauli_at_end(pauli, half_pis); | |
408 |
1/2✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
|
22 | CliffTableau product = CliffTableau::compose(pauli_tab, *this); | |
409 |
1/2✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
|
22 | this->xpauli_x = product.xpauli_x; | |
410 |
1/2✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
|
22 | this->xpauli_z = product.xpauli_z; | |
411 |
1/2✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
|
22 | this->xpauli_phase = product.xpauli_phase; | |
412 |
1/2✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
|
22 | this->zpauli_x = product.zpauli_x; | |
413 |
1/2✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
|
22 | this->zpauli_z = product.zpauli_z; | |
414 |
1/2✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
|
22 | this->zpauli_phase = product.zpauli_phase; | |
415 | 22 | } | ||
416 | ||||
417 | 23 | void CliffTableau::apply_pauli_at_end( | ||
418 | const QubitPauliTensor &pauli, unsigned half_pis) { | |||
419 | 23 | half_pis = half_pis % 4; | ||
420 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
1/2✓ Decision 'true' taken 23 times.
✗ Decision 'false' not taken.
|
23 | if (half_pis == 0) return; // Identity |
421 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 23 times.
|
23 | if (half_pis == 2) { // Degenerates to product of PI rotations |
422 |
0/2✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
|
✗ | for (const std::pair<const Qubit, Pauli> &term : pauli.string.map) { | |
423 | ✗ | switch (term.second) { | ||
424 |
0/1✗ Decision 'true' not taken.
|
✗ | case Pauli::I: { | |
425 | ✗ | break; | ||
426 | } | |||
427 |
0/1✗ Decision 'true' not taken.
|
✗ | case Pauli::X: { | |
428 | ✗ | apply_gate_at_end(OpType::X, {term.first}); | ||
429 | ✗ | break; | ||
430 | } | |||
431 |
0/1✗ Decision 'true' not taken.
|
✗ | case Pauli::Y: { | |
432 | ✗ | apply_gate_at_end(OpType::Y, {term.first}); | ||
433 | ✗ | break; | ||
434 | } | |||
435 |
0/1✗ Decision 'true' not taken.
|
✗ | case Pauli::Z: { | |
436 | ✗ | apply_gate_at_end(OpType::Z, {term.first}); | ||
437 | ✗ | break; | ||
438 | } | |||
439 | } | |||
440 | } | |||
441 | ✗ | return; | ||
442 | } | |||
443 | ||||
444 | // From here, half_pis == 1 or 3 | |||
445 | // They act the same except for a phase flip on the product term | |||
446 |
2/4✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
46 | MatrixXb product_x = MatrixXb::Zero(1, size_); | |
447 |
2/4✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
46 | MatrixXb product_z = MatrixXb::Zero(1, size_); | |
448 |
1/2✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
|
23 | MatrixXb::RowXpr px = product_x.row(0); | |
449 |
1/2✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
|
23 | MatrixXb::RowXpr pz = product_z.row(0); | |
450 |
4/6✓ Branch 1 taken 5 times.
✓ Branch 2 taken 18 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 5 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 23 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 23 times.
|
23 | if (pauli.coeff != 1. && pauli.coeff != -1.) |
451 | ✗ | throw std::invalid_argument( | ||
452 | "Can only apply Paulis with real unit coefficients to " | |||
453 | ✗ | "CliffTableaus"); | ||
454 | 23 | bool phase = (pauli.coeff == -1.) ^ (half_pis == 3); | ||
455 | ||||
456 | // Collect the product term | |||
457 |
2/2✓ Branch 5 taken 38 times.
✓ Branch 6 taken 23 times.
|
2/2✓ Decision 'true' taken 38 times.
✓ Decision 'false' taken 23 times.
|
61 | for (const std::pair<const Qubit, Pauli> &term : pauli.string.map) { |
458 |
1/2✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
|
38 | unsigned uqb = qubits_.left.at(term.first); | |
459 |
3/5✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
|
38 | switch (term.second) { | |
460 |
0/1✗ Decision 'true' not taken.
|
✗ | case Pauli::I: { | |
461 | ✗ | break; | ||
462 | } | |||
463 |
1/1✓ Decision 'true' taken 40 times.
|
20 | case Pauli::X: { | |
464 |
1/2✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
|
40 | row_mult( | |
465 |
3/6✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 20 times.
✗ Branch 8 not taken.
|
20 | xpauli_x.row(uqb), xpauli_z.row(uqb), xpauli_phase(uqb), px, pz, | |
466 | phase, 1., px, pz, phase); | |||
467 | 20 | break; | ||
468 | } | |||
469 |
1/1✓ Decision 'true' taken 10 times.
|
5 | case Pauli::Y: { | |
470 |
1/2✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
10 | row_mult( | |
471 |
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 | zpauli_x.row(uqb), zpauli_z.row(uqb), zpauli_phase(uqb), px, pz, | |
472 | phase, 1., px, pz, phase); | |||
473 |
1/2✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
|
5 | row_mult( | |
474 |
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 | xpauli_x.row(uqb), xpauli_z.row(uqb), xpauli_phase(uqb), px, pz, | |
475 | phase, i_, px, pz, phase); | |||
476 | 5 | break; | ||
477 | } | |||
478 |
1/1✓ Decision 'true' taken 26 times.
|
13 | case Pauli::Z: { | |
479 |
1/2✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
|
26 | row_mult( | |
480 |
3/6✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 13 times.
✗ Branch 8 not taken.
|
13 | zpauli_x.row(uqb), zpauli_z.row(uqb), zpauli_phase(uqb), px, pz, | |
481 | phase, 1., px, pz, phase); | |||
482 | 13 | break; | ||
483 | } | |||
484 | } | |||
485 | } | |||
486 | ||||
487 | // Apply the product term on the anti-commuting rows | |||
488 |
2/2✓ Branch 5 taken 38 times.
✓ Branch 6 taken 23 times.
|
2/2✓ Decision 'true' taken 38 times.
✓ Decision 'false' taken 23 times.
|
61 | for (const std::pair<const Qubit, Pauli> &term : pauli.string.map) { |
489 |
1/2✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
|
38 | unsigned uqb = qubits_.left.at(term.first); | |
490 |
1/2✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
|
38 | MatrixXb::RowXpr xx = xpauli_x.row(uqb); | |
491 |
1/2✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
|
38 | MatrixXb::RowXpr xz = xpauli_z.row(uqb); | |
492 |
1/2✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
|
38 | MatrixXb::RowXpr zx = zpauli_x.row(uqb); | |
493 |
1/2✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
|
38 | MatrixXb::RowXpr zz = zpauli_z.row(uqb); | |
494 |
3/5✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
|
38 | switch (term.second) { | |
495 |
0/1✗ Decision 'true' not taken.
|
✗ | case Pauli::I: { | |
496 | ✗ | break; | ||
497 | } | |||
498 |
1/1✓ Decision 'true' taken 20 times.
|
20 | case Pauli::X: { | |
499 | 20 | row_mult( | ||
500 |
1/2✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
|
20 | px, pz, phase, zx, zz, zpauli_phase(uqb), i_, zx, zz, | |
501 |
2/4✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
|
20 | zpauli_phase(uqb)); | |
502 | 20 | break; | ||
503 | } | |||
504 |
1/1✓ Decision 'true' taken 5 times.
|
5 | case Pauli::Y: { | |
505 | 5 | row_mult( | ||
506 |
1/2✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
|
5 | px, pz, phase, zx, zz, zpauli_phase(uqb), i_, zx, zz, | |
507 |
2/4✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
|
5 | zpauli_phase(uqb)); | |
508 | 5 | row_mult( | ||
509 |
1/2✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
|
5 | px, pz, phase, xx, xz, xpauli_phase(uqb), i_, xx, xz, | |
510 |
2/4✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
|
5 | xpauli_phase(uqb)); | |
511 | 5 | break; | ||
512 | } | |||
513 |
1/1✓ Decision 'true' taken 13 times.
|
13 | case Pauli::Z: { | |
514 | 13 | row_mult( | ||
515 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | px, pz, phase, xx, xz, xpauli_phase(uqb), i_, xx, xz, | |
516 |
2/4✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
|
13 | xpauli_phase(uqb)); | |
517 | 13 | break; | ||
518 | } | |||
519 | } | |||
520 | } | |||
521 | } | |||
522 | ||||
523 | ✗ | std::ostream &operator<<(std::ostream &os, CliffTableau const &tab) { | ||
524 | ✗ | MatrixXb full(2 * tab.size_, 2 * tab.size_ + 1); | ||
525 | ✗ | full << tab.xpauli_x, tab.xpauli_z, tab.xpauli_phase, tab.zpauli_x, | ||
526 | ✗ | tab.zpauli_z, tab.zpauli_phase; | ||
527 | ✗ | os << full; | ||
528 | ✗ | return os; | ||
529 | } | |||
530 | ||||
531 | 10 | bool CliffTableau::operator==(const CliffTableau &other) const { | ||
532 | 10 | bool same = this->size_ == other.size_; | ||
533 | 10 | same &= this->qubits_ == other.qubits_; | ||
534 | 10 | same &= this->xpauli_x == other.xpauli_x; | ||
535 | 10 | same &= this->xpauli_z == other.xpauli_z; | ||
536 | 10 | same &= this->xpauli_phase == other.xpauli_phase; | ||
537 | 10 | same &= this->zpauli_x == other.zpauli_x; | ||
538 | 10 | same &= this->zpauli_z == other.zpauli_z; | ||
539 | 10 | same &= this->zpauli_phase == other.zpauli_phase; | ||
540 | 10 | return same; | ||
541 | } | |||
542 | ||||
543 | 138 | static std::vector<Complex> cphase_from_tableau( | ||
544 | const MatrixXb &pauli_x, const MatrixXb &pauli_z, | |||
545 | const VectorXb &pauli_phase) { | |||
546 | 138 | std::vector<Complex> cphase; | ||
547 | 138 | const unsigned n = pauli_phase.size(); | ||
548 |
2/2✓ Branch 0 taken 666 times.
✓ Branch 1 taken 138 times.
|
2/2✓ Decision 'true' taken 666 times.
✓ Decision 'false' taken 138 times.
|
804 | for (unsigned i = 0; i < n; i++) { |
549 |
3/4✓ Branch 1 taken 666 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 100 times.
✓ Branch 4 taken 566 times.
|
666 | Complex cp = pauli_phase(i) ? -1. : 1.; | |
550 |
2/2✓ Branch 0 taken 3258 times.
✓ Branch 1 taken 666 times.
|
2/2✓ Decision 'true' taken 3258 times.
✓ Decision 'false' taken 666 times.
|
3924 | for (unsigned j = 0; j < n; j++) { |
551 |
8/10✓ Branch 1 taken 3258 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 522 times.
✓ Branch 4 taken 2736 times.
✓ Branch 6 taken 522 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 143 times.
✓ Branch 9 taken 379 times.
✓ Branch 10 taken 143 times.
✓ Branch 11 taken 3115 times.
|
2/2✓ Decision 'true' taken 666 times.
✓ Decision 'false' taken 2592 times.
|
3258 | if (pauli_x(i, j) && pauli_z(i, j)) cp *= i_; |
552 | } | |||
553 |
1/2✓ Branch 1 taken 666 times.
✗ Branch 2 not taken.
|
666 | cphase.push_back(cp); | |
554 | } | |||
555 | 138 | return cphase; | ||
556 | } | |||
557 | ||||
558 | 23 | CliffTableau CliffTableau::compose( | ||
559 | const CliffTableau &first, const CliffTableau &second) { | |||
560 |
2/4✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 23 times.
|
23 | if (first.qubits_ != second.qubits_) |
561 | ✗ | throw std::logic_error( | ||
562 | ✗ | "Cannot compose Clifford Tableaus with different qubit maps"); | ||
563 | 23 | const unsigned n = first.size_; | ||
564 | std::vector<Complex> first_x_cphase = | |||
565 |
1/2✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
|
23 | cphase_from_tableau(first.xpauli_x, first.xpauli_z, first.xpauli_phase); | |
566 | std::vector<Complex> first_z_cphase = | |||
567 |
1/2✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
|
23 | cphase_from_tableau(first.zpauli_x, first.zpauli_z, first.zpauli_phase); | |
568 | std::vector<Complex> second_x_cphase = cphase_from_tableau( | |||
569 |
1/2✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
|
23 | second.xpauli_x, second.xpauli_z, second.xpauli_phase); | |
570 | std::vector<Complex> second_z_cphase = cphase_from_tableau( | |||
571 |
1/2✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
|
23 | second.zpauli_x, second.zpauli_z, second.zpauli_phase); | |
572 | ||||
573 |
1/2✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
|
23 | CliffTableau result(n); | |
574 |
1/2✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
|
23 | result.xpauli_x.setZero(); | |
575 |
1/2✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
|
23 | result.xpauli_z.setZero(); | |
576 |
1/2✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
|
23 | result.zpauli_x.setZero(); | |
577 |
1/2✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
|
23 | result.zpauli_z.setZero(); | |
578 |
1/2✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
|
23 | result.qubits_ = first.qubits_; | |
579 | ||||
580 | // Target cphases | |||
581 |
1/2✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | std::vector<Complex> xpauli_cphase(n); | |
582 |
1/2✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | std::vector<Complex> zpauli_cphase(n); | |
583 | ||||
584 | // Calculate xpauli rows | |||
585 |
2/2✓ Branch 0 taken 111 times.
✓ Branch 1 taken 23 times.
|
2/2✓ Decision 'true' taken 111 times.
✓ Decision 'false' taken 23 times.
|
134 | for (unsigned i = 0; i < n; i++) { // row in second |
586 | // Sum rows from first according to second.xpauli | |||
587 | 111 | xpauli_cphase[i] = second_x_cphase[i]; | ||
588 | 111 | bool phase_flip = false; | ||
589 |
2/2✓ Branch 0 taken 543 times.
✓ Branch 1 taken 111 times.
|
2/2✓ Decision 'true' taken 543 times.
✓ Decision 'false' taken 111 times.
|
654 | for (unsigned j = 0; j < n; j++) { // col in second |
590 |
3/4✓ Branch 1 taken 543 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 80 times.
✓ Branch 4 taken 463 times.
|
2/2✓ Decision 'true' taken 460 times.
✓ Decision 'false' taken 83 times.
|
543 | if (second.xpauli_x(i, j)) { |
591 | // add first.xpauli to xpauli | |||
592 |
2/2✓ Branch 0 taken 380 times.
✓ Branch 1 taken 80 times.
|
2/2✓ Decision 'true' taken 380 times.
✓ Decision 'false' taken 80 times.
|
460 | for (unsigned k = 0; k < n; k++) { |
593 |
6/8✓ Branch 1 taken 380 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 28 times.
✓ Branch 4 taken 352 times.
✓ Branch 6 taken 28 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 9 times.
✓ Branch 9 taken 19 times.
|
380 | phase_flip ^= result.xpauli_z(i, k) && first.xpauli_x(j, k); | |
594 |
3/6✓ Branch 1 taken 380 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 380 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 380 times.
✗ Branch 8 not taken.
|
380 | result.xpauli_x(i, k) = result.xpauli_x(i, k) != first.xpauli_x(j, k); | |
595 |
3/6✓ Branch 1 taken 380 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 380 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 380 times.
✗ Branch 8 not taken.
|
380 | result.xpauli_z(i, k) = result.xpauli_z(i, k) != first.xpauli_z(j, k); | |
596 | } | |||
597 | 80 | xpauli_cphase[i] *= first_x_cphase[j]; | ||
598 | } | |||
599 |
3/4✓ Branch 1 taken 543 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 111 times.
✓ Branch 4 taken 432 times.
|
0/1? Decision couldn't be analyzed.
|
543 | if (second.xpauli_z(i, j)) { |
600 | // add first.zpauli to xpauli | |||
601 |
2/2✓ Branch 0 taken 543 times.
✓ Branch 1 taken 111 times.
|
2/2✓ Decision 'true' taken 543 times.
✓ Decision 'false' taken 111 times.
|
654 | for (unsigned k = 0; k < n; k++) { |
602 |
6/8✓ Branch 1 taken 543 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 38 times.
✓ Branch 4 taken 505 times.
✓ Branch 6 taken 38 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 11 times.
✓ Branch 9 taken 27 times.
|
543 | phase_flip ^= result.xpauli_z(i, k) && first.zpauli_x(j, k); | |
603 |
3/6✓ Branch 1 taken 543 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 543 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 543 times.
✗ Branch 8 not taken.
|
543 | result.xpauli_x(i, k) = result.xpauli_x(i, k) != first.zpauli_x(j, k); | |
604 |
3/6✓ Branch 1 taken 543 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 543 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 543 times.
✗ Branch 8 not taken.
|
543 | result.xpauli_z(i, k) = result.xpauli_z(i, k) != first.zpauli_z(j, k); | |
605 | } | |||
606 | 111 | xpauli_cphase[i] *= first_z_cphase[j]; | ||
607 | } | |||
608 | } | |||
609 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 99 times.
|
0/1? Decision couldn't be analyzed.
|
111 | if (phase_flip) xpauli_cphase[i] *= -1.; |
610 | } | |||
611 | ||||
612 | // Calculate zpauli rows | |||
613 |
2/2✓ Branch 0 taken 111 times.
✓ Branch 1 taken 23 times.
|
2/2✓ Decision 'true' taken 111 times.
✓ Decision 'false' taken 23 times.
|
134 | for (unsigned i = 0; i < n; i++) { // row in second |
614 | // Sum rows from first according to second.zpauli | |||
615 | 111 | zpauli_cphase[i] = second_z_cphase[i]; | ||
616 | 111 | bool phase_flip = false; | ||
617 |
2/2✓ Branch 0 taken 543 times.
✓ Branch 1 taken 111 times.
|
2/2✓ Decision 'true' taken 543 times.
✓ Decision 'false' taken 111 times.
|
654 | for (unsigned j = 0; j < n; j++) { // col in second |
618 |
3/4✓ Branch 1 taken 543 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 95 times.
✓ Branch 4 taken 448 times.
|
0/1? Decision couldn't be analyzed.
|
543 | if (second.zpauli_x(i, j)) { |
619 | // add first.xpauli to zpauli | |||
620 |
2/2✓ Branch 0 taken 459 times.
✓ Branch 1 taken 95 times.
|
2/2✓ Decision 'true' taken 459 times.
✓ Decision 'false' taken 95 times.
|
554 | for (unsigned k = 0; k < n; k++) { |
621 |
6/8✓ Branch 1 taken 459 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 29 times.
✓ Branch 4 taken 430 times.
✓ Branch 6 taken 29 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 11 times.
✓ Branch 9 taken 18 times.
|
459 | phase_flip ^= result.zpauli_z(i, k) && first.xpauli_x(j, k); | |
622 |
3/6✓ Branch 1 taken 459 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 459 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 459 times.
✗ Branch 8 not taken.
|
459 | result.zpauli_x(i, k) = result.zpauli_x(i, k) != first.xpauli_x(j, k); | |
623 |
3/6✓ Branch 1 taken 459 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 459 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 459 times.
✗ Branch 8 not taken.
|
459 | result.zpauli_z(i, k) = result.zpauli_z(i, k) != first.xpauli_z(j, k); | |
624 | } | |||
625 | 95 | zpauli_cphase[i] *= first_x_cphase[j]; | ||
626 | } | |||
627 |
3/4✓ Branch 1 taken 543 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 89 times.
✓ Branch 4 taken 454 times.
|
2/2✓ Decision 'true' taken 518 times.
✓ Decision 'false' taken 25 times.
|
543 | if (second.zpauli_z(i, j)) { |
628 | // add first.zpauli to zpauli | |||
629 |
2/2✓ Branch 0 taken 429 times.
✓ Branch 1 taken 89 times.
|
2/2✓ Decision 'true' taken 429 times.
✓ Decision 'false' taken 89 times.
|
518 | for (unsigned k = 0; k < n; k++) { |
630 |
6/8✓ Branch 1 taken 429 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 24 times.
✓ Branch 4 taken 405 times.
✓ Branch 6 taken 24 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 8 times.
✓ Branch 9 taken 16 times.
|
429 | phase_flip ^= result.zpauli_z(i, k) && first.zpauli_x(j, k); | |
631 |
3/6✓ Branch 1 taken 429 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 429 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 429 times.
✗ Branch 8 not taken.
|
429 | result.zpauli_x(i, k) = result.zpauli_x(i, k) != first.zpauli_x(j, k); | |
632 |
3/6✓ Branch 1 taken 429 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 429 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 429 times.
✗ Branch 8 not taken.
|
429 | result.zpauli_z(i, k) = result.zpauli_z(i, k) != first.zpauli_z(j, k); | |
633 | } | |||
634 | 89 | zpauli_cphase[i] *= first_z_cphase[j]; | ||
635 | } | |||
636 | } | |||
637 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 110 times.
|
2/2✓ Decision 'true' taken 23 times.
✓ Decision 'false' taken 88 times.
|
111 | if (phase_flip) zpauli_cphase[i] *= -1.; |
638 | } | |||
639 | ||||
640 | std::vector<Complex> current_x_cphase = cphase_from_tableau( | |||
641 |
1/2✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
|
23 | result.xpauli_x, result.xpauli_z, result.xpauli_phase); | |
642 | std::vector<Complex> current_z_cphase = cphase_from_tableau( | |||
643 |
1/2✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
|
23 | result.zpauli_x, result.zpauli_z, result.zpauli_phase); | |
644 | ||||
645 |
2/2✓ Branch 0 taken 111 times.
✓ Branch 1 taken 23 times.
|
2/2✓ Decision 'true' taken 111 times.
✓ Decision 'false' taken 23 times.
|
134 | for (unsigned i = 0; i < n; i++) { |
646 | TKET_ASSERT((current_x_cphase[i] * xpauli_cphase[i]).imag() == 0); | |||
647 |
1/2✓ Branch 5 taken 111 times.
✗ Branch 6 not taken.
|
111 | result.xpauli_phase(i) = (current_x_cphase[i] == -xpauli_cphase[i]); | |
648 | TKET_ASSERT((current_z_cphase[i] * zpauli_cphase[i]).imag() == 0); | |||
649 |
1/2✓ Branch 5 taken 111 times.
✗ Branch 6 not taken.
|
111 | result.zpauli_phase(i) = (current_z_cphase[i] == -zpauli_cphase[i]); | |
650 | } | |||
651 | ||||
652 | 46 | return result; | ||
653 | 23 | } | ||
654 | ||||
655 | } // namespace tket | |||
656 |