GCC Code Coverage Report


Directory: ./
File: Clifford/CliffTableau.cpp
Date: 2022-10-15 05:10:18
Warnings: 4 unchecked decisions!
Exec Total Coverage
Lines: 332 441 75.3%
Functions: 22 24 91.7%
Branches: 365 681 53.6%
Decisions: 80 120 66.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 "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