GCC Code Coverage Report


Directory: ./
File: Converters/PhasePoly.cpp
Date: 2022-10-15 05:10:18
Warnings: 16 unchecked decisions!
Exec Total Coverage
Lines: 368 396 92.9%
Functions: 17 19 89.5%
Branches: 487 844 57.7%
Decisions: 87 132 65.9%

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 "PhasePoly.hpp"
16
17 #include <algorithm>
18 #include <stdexcept>
19 #include <string>
20 #include <tklog/TketLog.hpp>
21 #include <vector>
22
23 #include "Circuit/Boxes.hpp"
24 #include "Circuit/Circuit.hpp"
25 #include "Converters/Gauss.hpp"
26 #include "OpType/OpType.hpp"
27 #include "Ops/MetaOp.hpp"
28 #include "Ops/OpJsonFactory.hpp"
29 #include "Ops/OpPtr.hpp"
30 #include "Utils/GraphHeaders.hpp"
31 #include "Utils/Json.hpp"
32
33 namespace tket {
34
35 /* Used only for gray_synth */
36 struct SynthStruct {
37 std::list<phase_term_t> terms;
38 std::set<unsigned> remaining_indices;
39 std::optional<unsigned> target;
40 };
41
42 // update the phase gadgets when adding a CNOT
43 585 static void adjust_vectors(
44 unsigned ctrl, unsigned tgt, std::list<SynthStruct>& Q) {
45
2/2
✓ Branch 5 taken 445 times.
✓ Branch 6 taken 585 times.
2/2
✓ Decision 'true' taken 445 times.
✓ Decision 'false' taken 585 times.
1030 for (SynthStruct& S : Q) {
46
2/2
✓ Branch 4 taken 478 times.
✓ Branch 5 taken 445 times.
2/2
✓ Decision 'true' taken 478 times.
✓ Decision 'false' taken 445 times.
923 for (std::pair<std::vector<bool>, Expr>& term : S.terms) {
47 478 std::vector<bool>& vec = term.first;
48
3/6
✓ Branch 1 taken 478 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 478 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 478 times.
✗ Branch 10 not taken.
478 vec[ctrl] = vec[ctrl] ^ vec[tgt];
49 }
50 }
51 585 }
52
53 // see https://arxiv.org/pdf/1712.01859.pdf p12, line 18
54 // get qubit with either greatest or least hamming weight
55 1008 static unsigned find_best_split(
56 const std::list<phase_term_t>& terms, const std::set<unsigned>& indices) {
57 1008 int max = -1;
58 1008 int max_i = -1;
59
2/2
✓ Branch 5 taken 4488 times.
✓ Branch 6 taken 1008 times.
2/2
✓ Decision 'true' taken 4488 times.
✓ Decision 'false' taken 1008 times.
5496 for (unsigned i : indices) {
60
1/2
✓ Branch 3 taken 4488 times.
✗ Branch 4 not taken.
4488 int num_ones = std::count_if(
61 terms.begin(), terms.end(),
62 17803 [=](const std::pair<std::vector<bool>, Expr>& term) {
63 17803 return term.first[i];
64 4488 });
65 4488 int num_zeros = terms.size() - num_ones;
66
67
4/4
✓ Branch 0 taken 3217 times.
✓ Branch 1 taken 1271 times.
✓ Branch 2 taken 57 times.
✓ Branch 3 taken 3160 times.
2/2
✓ Decision 'true' taken 1328 times.
✓ Decision 'false' taken 3160 times.
4488 if (num_zeros > max || num_ones > max) {
68
2/2
✓ Branch 0 taken 622 times.
✓ Branch 1 taken 706 times.
1328 max = num_zeros > num_ones ? num_zeros : num_ones;
69 1328 max_i = i;
70 }
71 }
72
73 1008 return (unsigned)max_i;
74 }
75
76 // divide into S0 and S1 based on value at qubit j
77 1008 static std::pair<std::list<phase_term_t>, std::list<phase_term_t>> split(
78 std::list<phase_term_t>& terms, int j) {
79 1008 std::list<phase_term_t> zeros;
80 1008 std::list<phase_term_t> ones;
81
82
2/2
✓ Branch 1 taken 3240 times.
✓ Branch 2 taken 1008 times.
2/2
✓ Decision 'true' taken 3240 times.
✓ Decision 'false' taken 1008 times.
4248 while (!terms.empty()) {
83
3/4
✓ Branch 2 taken 3240 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1271 times.
✓ Branch 6 taken 1969 times.
2/2
✓ Decision 'true' taken 1271 times.
✓ Decision 'false' taken 1969 times.
3240 if (terms.front().first[j])
84 1271 ones.splice(ones.end(), terms, terms.begin());
85 else
86 1969 zeros.splice(zeros.end(), terms, terms.begin());
87 }
88
89
1/2
✓ Branch 1 taken 1008 times.
✗ Branch 2 not taken.
2016 return std::make_pair(zeros, ones);
90 1008 }
91
92 /* see: arXiv:1712.01859 */
93 265 Circuit gray_synth(
94 unsigned n_qubits, const std::list<phase_term_t>& parities,
95 const MatrixXb& linear_transformation) {
96
1/2
✓ Branch 1 taken 265 times.
✗ Branch 2 not taken.
265 MatrixXb A = linear_transformation;
97
1/2
✓ Branch 2 taken 265 times.
✗ Branch 3 not taken.
265 Circuit circ(n_qubits);
98 265 std::list<SynthStruct> Q; // used to recur over
99 std::set<unsigned>
100 265 indices; // correspond to qubits which have to be recurred over
101
3/4
✓ Branch 1 taken 1600 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1600 times.
✓ Branch 4 taken 265 times.
0/1
? Decision couldn't be analyzed.
1865 for (unsigned i = 0; i < n_qubits; ++i) indices.insert(i);
102
3/6
✓ Branch 1 taken 265 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 265 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 265 times.
✗ Branch 8 not taken.
265 Q.push_front({parities, indices, std::nullopt});
103
104
2/2
✓ Branch 1 taken 2281 times.
✓ Branch 2 taken 265 times.
2/2
✓ Decision 'true' taken 2281 times.
✓ Decision 'false' taken 265 times.
2546 while (!Q.empty()) {
105
1/2
✓ Branch 2 taken 2281 times.
✗ Branch 3 not taken.
2281 SynthStruct S = Q.front();
106 2281 Q.pop_front();
107
108
2/2
✓ Branch 1 taken 612 times.
✓ Branch 2 taken 1669 times.
2/2
✓ Decision 'true' taken 1669 times.
✓ Decision 'false' taken 612 times.
2281 if (S.terms.size() == 0) continue;
109 // only one column in GraySynth matrix being recurred over
110
6/6
✓ Branch 1 taken 832 times.
✓ Branch 2 taken 837 times.
✓ Branch 4 taken 661 times.
✓ Branch 5 taken 171 times.
✓ Branch 6 taken 661 times.
✓ Branch 7 taken 1008 times.
2/2
✓ Decision 'true' taken 661 times.
✓ Decision 'false' taken 1008 times.
1669 else if (S.terms.size() == 1 && S.target) {
111 // special case to avoid doing extra recursion
112 661 unsigned tgt = *(S.target);
113 661 auto& [vec, angle] = S.terms.front();
114
2/2
✓ Branch 1 taken 4492 times.
✓ Branch 2 taken 661 times.
2/2
✓ Decision 'true' taken 4492 times.
✓ Decision 'false' taken 661 times.
5153 for (unsigned ctrl = 0; ctrl < vec.size(); ++ctrl) {
115
7/8
✓ Branch 0 taken 3831 times.
✓ Branch 1 taken 661 times.
✓ Branch 3 taken 3831 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 585 times.
✓ Branch 7 taken 3246 times.
✓ Branch 8 taken 585 times.
✓ Branch 9 taken 3907 times.
2/2
✓ Decision 'true' taken 585 times.
✓ Decision 'false' taken 3907 times.
4492 if (ctrl != tgt && vec[ctrl]) {
116
2/4
✓ Branch 3 taken 585 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 585 times.
✗ Branch 7 not taken.
585 circ.add_op<unsigned>(OpType::CX, {ctrl, tgt});
117
1/2
✓ Branch 1 taken 585 times.
✗ Branch 2 not taken.
585 adjust_vectors(ctrl, tgt, Q);
118
2/2
✓ Branch 1 taken 4609 times.
✓ Branch 2 taken 585 times.
2/2
✓ Decision 'true' taken 4609 times.
✓ Decision 'false' taken 585 times.
5194 for (unsigned i = 0; i < A.rows(); i++) {
119 // do column operation on linear
120 // transformation
121 // this will allow us to correct for the CXs
122 // we produce here using Gaussian elim
123
2/4
✓ Branch 1 taken 4609 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4609 times.
✗ Branch 5 not taken.
4609 A(i, ctrl) ^= A(i, tgt);
124 }
125 }
126 }
127
2/4
✓ Branch 3 taken 661 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 661 times.
✗ Branch 7 not taken.
661 circ.add_op<unsigned>(OpType::Rz, angle, {tgt});
128
1/2
✓ Branch 1 taken 1008 times.
✗ Branch 2 not taken.
1/2
✓ Decision 'true' taken 1008 times.
✗ Decision 'false' not taken.
1008 } else if (!S.remaining_indices.empty()) {
129
1/2
✓ Branch 1 taken 1008 times.
✗ Branch 2 not taken.
1008 unsigned i = find_best_split(S.terms, S.remaining_indices);
130
1/2
✓ Branch 1 taken 1008 times.
✗ Branch 2 not taken.
1008 auto [S0, S1] = split(S.terms, i);
131
132
1/2
✓ Branch 1 taken 1008 times.
✗ Branch 2 not taken.
1008 S.remaining_indices.erase(i);
133
134
2/2
✓ Branch 1 taken 297 times.
✓ Branch 2 taken 711 times.
2/2
✓ Decision 'true' taken 297 times.
✓ Decision 'false' taken 711 times.
1008 if (S.target) {
135
3/6
✓ Branch 1 taken 297 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 297 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 297 times.
✗ Branch 8 not taken.
297 Q.push_front({S1, S.remaining_indices, S.target});
136 } else {
137
3/6
✓ Branch 1 taken 711 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 711 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 711 times.
✗ Branch 9 not taken.
711 Q.push_front({S1, S.remaining_indices, i});
138 }
139
3/6
✓ Branch 1 taken 1008 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1008 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1008 times.
✗ Branch 8 not taken.
1008 Q.push_front({S0, S.remaining_indices, S.target});
140 1008 }
141
2/2
✓ Branch 1 taken 1669 times.
✓ Branch 2 taken 612 times.
2281 }
142
1/2
✓ Branch 1 taken 265 times.
✗ Branch 2 not taken.
265 DiagMatrix m(A);
143
1/2
✓ Branch 1 taken 265 times.
✗ Branch 2 not taken.
265 CXMaker cxmaker(n_qubits, false);
144
1/2
✓ Branch 1 taken 265 times.
✗ Branch 2 not taken.
265 m.gauss(cxmaker);
145
2/4
✓ Branch 1 taken 265 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 265 times.
✗ Branch 5 not taken.
265 circ.append(cxmaker._circ.dagger());
146 530 return circ;
147 265 }
148
149 391 PhasePolyBox::PhasePolyBox(const Circuit& circ)
150
4/8
✓ Branch 2 taken 391 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 391 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 391 times.
✗ Branch 11 not taken.
✓ Branch 15 taken 391 times.
✗ Branch 16 not taken.
391 : Box(OpType::PhasePolyBox), n_qubits_(circ.n_qubits()) {
151
1/2
✓ Branch 1 taken 391 times.
✗ Branch 2 not taken.
391 Circuit newcirc(circ);
152
153 // check for classical bits
154
2/4
✓ Branch 1 taken 391 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 391 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 391 times.
391 if (newcirc.n_bits() != 0)
155 throw std::invalid_argument(
156 "Cannot construct phase polynomial from classical controlled "
157 "gates");
158
159 // check the gateset of the circuit
160
6/10
✓ Branch 1 taken 391 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 391 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3407 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 3407 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 3407 times.
✓ Branch 14 taken 391 times.
0/1
? Decision couldn't be analyzed.
3798 for (const Command& com : newcirc) {
161 3407 OpType ot = com.get_op_ptr()->get_type();
162
163
2/3
✓ Branch 0 taken 2492 times.
✓ Branch 1 taken 915 times.
✗ Branch 2 not taken.
3407 switch (ot) {
164
1/1
✓ Decision 'true' taken 2492 times.
2492 case OpType::CX: {
165 2492 break;
166 }
167
1/1
✓ Decision 'true' taken 915 times.
915 case OpType::Rz: {
168 915 break;
169 }
170
0/1
✗ Decision 'true' not taken.
default: {
171 throw BadOpType("Only CXs and Rzs allowed in Phase Polynomials", ot);
172 }
173 }
174 3798 }
175
176 // replace wireswaps with three CX
177
3/4
✓ Branch 1 taken 399 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 391 times.
0/1
? Decision couldn't be analyzed.
399 while (newcirc.has_implicit_wireswaps()) {
178 8 bool foundswap = false;
179
180
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 qubit_map_t perm = newcirc.implicit_qubit_permutation();
181
2/2
✓ Branch 5 taken 37 times.
✓ Branch 6 taken 8 times.
2/2
✓ Decision 'true' taken 37 times.
✓ Decision 'false' taken 8 times.
45 for (const std::pair<const Qubit, Qubit>& pair : perm) {
182
3/4
✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 25 times.
✓ Branch 4 taken 12 times.
2/2
✓ Decision 'true' taken 25 times.
✓ Decision 'false' taken 12 times.
37 if (pair.first != pair.second) {
183
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 17 times.
2/2
✓ Decision 'true' taken 8 times.
✓ Decision 'false' taken 17 times.
25 if (!foundswap) {
184
1/2
✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
8 newcirc.replace_implicit_wire_swap(pair.first, pair.second);
185 8 foundswap = true;
186 }
187 }
188 }
189 8 }
190
191 // generate box
192
1/2
✓ Branch 2 taken 391 times.
✗ Branch 3 not taken.
391 signature_ = op_signature_t(n_qubits_, EdgeType::Quantum);
193 391 unsigned i = 0;
194
3/4
✓ Branch 1 taken 391 times.
✗ Branch 2 not taken.
✓ Branch 7 taken 2218 times.
✓ Branch 8 taken 391 times.
0/1
? Decision couldn't be analyzed.
2609 for (const Qubit& qb : newcirc.all_qubits()) {
195
2/4
✓ Branch 1 taken 2218 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2218 times.
✗ Branch 5 not taken.
2218 qubit_indices_.insert({qb, i});
196 2218 ++i;
197 391 }
198
2/4
✓ Branch 1 taken 391 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 391 times.
✗ Branch 5 not taken.
391 linear_transformation_ = MatrixXb::Identity(n_qubits_, n_qubits_);
199
6/10
✓ Branch 1 taken 391 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 391 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3431 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 3431 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 3431 times.
✓ Branch 14 taken 391 times.
0/1
? Decision couldn't be analyzed.
3822 for (const Command& com : newcirc) {
200 3431 OpType ot = com.get_op_ptr()->get_type();
201
1/2
✓ Branch 1 taken 3431 times.
✗ Branch 2 not taken.
3431 unit_vector_t qbs = com.get_args();
202
2/2
✓ Branch 0 taken 2516 times.
✓ Branch 1 taken 915 times.
2/2
✓ Decision 'true' taken 2516 times.
✓ Decision 'false' taken 915 times.
3431 if (ot == OpType::CX) {
203
2/4
✓ Branch 2 taken 2516 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2516 times.
✗ Branch 6 not taken.
2516 unsigned ctrl = qubit_indices_.left.at(Qubit(qbs[0]));
204
2/4
✓ Branch 2 taken 2516 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2516 times.
✗ Branch 6 not taken.
2516 unsigned target = qubit_indices_.left.at(Qubit(qbs[1]));
205
2/2
✓ Branch 0 taken 19261 times.
✓ Branch 1 taken 2516 times.
2/2
✓ Decision 'true' taken 19261 times.
✓ Decision 'false' taken 2516 times.
21777 for (unsigned j = 0; j < n_qubits_; ++j) {
206
1/2
✓ Branch 1 taken 19261 times.
✗ Branch 2 not taken.
19261 linear_transformation_.row(target)[j] ^=
207
3/6
✓ Branch 1 taken 19261 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 19261 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 19261 times.
✗ Branch 8 not taken.
38522 linear_transformation_.row(ctrl)[j];
208 }
209
1/2
✓ Branch 0 taken 915 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 915 times.
✗ Decision 'false' not taken.
915 } else if (ot == OpType::Rz) {
210
2/4
✓ Branch 2 taken 915 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 915 times.
✗ Branch 6 not taken.
915 unsigned qb = qubit_indices_.left.at(Qubit(qbs[0]));
211
1/2
✓ Branch 2 taken 915 times.
✗ Branch 3 not taken.
915 std::vector<bool> boolvec(n_qubits_);
212
2/2
✓ Branch 0 taken 5733 times.
✓ Branch 1 taken 915 times.
2/2
✓ Decision 'true' taken 5733 times.
✓ Decision 'false' taken 915 times.
6648 for (unsigned j = 0; j < n_qubits_; ++j) {
213
3/6
✓ Branch 1 taken 5733 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5733 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 5733 times.
✗ Branch 8 not taken.
5733 boolvec[j] = linear_transformation_.row(qb)[j];
214 }
215
1/2
✓ Branch 1 taken 915 times.
✗ Branch 2 not taken.
915 PhasePolynomial::iterator pp_it = phase_polynomial_.find(boolvec);
216
2/2
✓ Branch 2 taken 895 times.
✓ Branch 3 taken 20 times.
2/2
✓ Decision 'true' taken 895 times.
✓ Decision 'false' taken 20 times.
915 if (pp_it == phase_polynomial_.end())
217
4/8
✓ Branch 3 taken 895 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 895 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 895 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 895 times.
✗ Branch 13 not taken.
895 phase_polynomial_[boolvec] = com.get_op_ptr()->get_params().at(0);
218 else
219
3/6
✓ Branch 3 taken 20 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 20 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 20 times.
✗ Branch 11 not taken.
20 pp_it->second += com.get_op_ptr()->get_params().at(0);
220 915 } else
221 TKET_ASSERT(!"Only CXs and Rzs allowed in Phase Polynomials");
222 3822 }
223 391 }
224
225 6 PhasePolyBox::PhasePolyBox(
226 unsigned n_qubits, const boost::bimap<Qubit, unsigned>& qubit_indices,
227 const PhasePolynomial& phase_polynomial,
228 6 const MatrixXb& linear_transformation)
229 : Box(OpType::PhasePolyBox),
230 6 n_qubits_(n_qubits),
231 6 qubit_indices_(qubit_indices),
232
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 phase_polynomial_(phase_polynomial),
233
3/6
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 6 times.
✗ Branch 10 not taken.
12 linear_transformation_(linear_transformation) {
234
7/12
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 13 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 11 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 17 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 13 times.
✓ Branch 16 taken 4 times.
0/1
? Decision couldn't be analyzed.
17 for (const auto& pair : qubit_indices_) {
235
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 11 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 11 times.
13 if (pair.right >= n_qubits) {
236
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 throw std::invalid_argument(
237 "The creation of a phasepolybox failed: index in qubit "
238 4 "list is out of range");
239 }
240 }
241
242
2/2
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 1 times.
2/2
✓ Decision 'true' taken 4 times.
✓ Decision 'false' taken 1 times.
5 for (auto const& ps : phase_polynomial_) {
243
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 3 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 3 times.
4 if (ps.first.size() != n_qubits_) {
244
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 throw std::invalid_argument(
245 "The creation of a phasepolybox failed: PhasePolynomial "
246 2 "does not match the given number of qubits");
247 }
248
249
3/4
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 1 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 1 times.
3 if (std::none_of(
250 5 ps.first.begin(), ps.first.end(), [](bool x) { return x; })) {
251
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 throw std::invalid_argument(
252 "The creation of a phasepolybox failed: PhasePolynomial "
253 4 "contains invalid element");
254 }
255 }
256
257
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 1 times.
1 if (linear_transformation_.rows() != n_qubits) {
258 throw std::invalid_argument(
259 "The creation of a phasepolybox failed: row size of the "
260 "linear transformation does not match the number of qubits");
261 }
262
263
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 1 times.
1 if (linear_transformation_.cols() != n_qubits) {
264 throw std::invalid_argument(
265 "The creation of a phasepolybox failed: cols size of the "
266 "linear transformation does not match the number of qubits");
267 }
268
269
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 signature_ = op_signature_t(n_qubits_, EdgeType::Quantum);
270 21 }
271
272 265 void PhasePolyBox::generate_circuit() const {
273 265 std::list<phase_term_t> phases;
274
4/6
✓ Branch 4 taken 661 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 661 times.
✗ Branch 8 not taken.
✓ Branch 12 taken 661 times.
✓ Branch 13 taken 265 times.
0/1
? Decision couldn't be analyzed.
926 for (phase_term_t phase : phase_polynomial_) phases.push_back(phase);
275
1/2
✓ Branch 1 taken 265 times.
✗ Branch 2 not taken.
265 Circuit circ = gray_synth(n_qubits_, phases, linear_transformation_);
276 265 unit_map_t qmap;
277
6/10
✓ Branch 1 taken 265 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 265 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1600 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1865 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1600 times.
✓ Branch 13 taken 265 times.
0/1
? Decision couldn't be analyzed.
1865 for (const auto& pair : qubit_indices_.right) {
278
4/8
✓ Branch 1 taken 1600 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1600 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 1600 times.
✗ Branch 9 not taken.
✓ Branch 13 taken 1600 times.
✗ Branch 14 not taken.
1600 qmap.insert({Qubit(q_default_reg(), pair.first), pair.second});
279 }
280
1/2
✓ Branch 1 taken 265 times.
✗ Branch 2 not taken.
265 circ.rename_units(qmap);
281
1/2
✓ Branch 1 taken 265 times.
✗ Branch 2 not taken.
265 circ_ = std::make_shared<Circuit>(circ);
282 265 }
283
284 133 PhasePolyBox::PhasePolyBox(const PhasePolyBox& other)
285 : Box(other),
286 133 n_qubits_(other.n_qubits_),
287 133 qubit_indices_(other.qubit_indices_),
288
1/2
✓ Branch 1 taken 133 times.
✗ Branch 2 not taken.
133 phase_polynomial_(other.phase_polynomial_),
289
2/4
✓ Branch 2 taken 133 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 133 times.
✗ Branch 6 not taken.
266 linear_transformation_(other.linear_transformation_) {}
290
291 Op_ptr PhasePolyBox::symbol_substitution(
292 const SymEngine::map_basic_basic& sub_map) const {
293 Circuit new_circ(*to_circuit());
294 new_circ.symbol_substitution(sub_map);
295 return std::make_shared<PhasePolyBox>(new_circ);
296 }
297
298 SymSet PhasePolyBox::free_symbols() const {
299 return to_circuit()->free_symbols();
300 }
301
302 // Dynamic Eigen matrix requires special treatment to load, to allocate memory
303 template <typename T>
304 1 Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> load_dynamic_matrix(
305 const nlohmann::json& j, size_t rows, size_t cols) {
306 1 Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> mat(rows, cols);
307
308
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 1 times.
3 for (size_t row = 0; row < j.size(); ++row) {
309
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 const auto& j_row = j.at(row);
310
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 2 times.
2/2
✓ Decision 'true' taken 4 times.
✓ Decision 'false' taken 2 times.
6 for (size_t col = 0; col < j_row.size(); ++col) {
311
3/6
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
4 mat(row, col) = j_row.at(col).get<T>();
312 }
313 }
314 1 return mat;
315 }
316
317 1 nlohmann::json PhasePolyBox::to_json(const Op_ptr& op) {
318 1 const auto& box = static_cast<const PhasePolyBox&>(*op);
319 1 nlohmann::json j = core_box_json(box);
320
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 j["n_qubits"] = box.get_n_qubits();
321
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 j["qubit_indices"] = nlohmann::json::array();
322
7/12
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 2 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 3 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 2 times.
✓ Branch 17 taken 1 times.
0/1
? Decision couldn't be analyzed.
3 for (const auto& pair : box.get_qubit_indices()) {
323 2 nlohmann::json ind_j;
324
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
2 ind_j.push_back(pair.left);
325
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 ind_j.push_back(pair.right);
326
327
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
2 j["qubit_indices"].push_back(ind_j);
328 2 }
329
330
2/4
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
1 j["phase_polynomial"] = box.get_phase_polynomial();
331
2/4
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
1 j["linear_transformation"] = box.get_linear_transformation();
332 1 return j;
333 }
334
335 1 Op_ptr PhasePolyBox::from_json(const nlohmann::json& j) {
336
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 boost::bimap<Qubit, unsigned> q_ind;
337
5/8
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 3 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 2 times.
✓ Branch 12 taken 1 times.
0/1
? Decision couldn't be analyzed.
3 for (const auto& j_ar : j.at("qubit_indices")) {
338
7/14
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 2 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 2 times.
✗ Branch 17 not taken.
✓ Branch 21 taken 2 times.
✗ Branch 22 not taken.
2 q_ind.insert({j_ar.at(0), j_ar.at(1)});
339 }
340
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 const unsigned n_qb = j.at("n_qubits").get<unsigned>();
341 const MatrixXb& lin_trans =
342
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 load_dynamic_matrix<bool>(j.at("linear_transformation"), n_qb, n_qb);
343
344 PhasePolyBox box = PhasePolyBox(
345
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 n_qb, q_ind, j.at("phase_polynomial").get<PhasePolynomial>(), lin_trans);
346 return set_box_id(
347 box,
348
4/8
✓ 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.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
3 boost::lexical_cast<boost::uuids::uuid>(j.at("id").get<std::string>()));
349 1 }
350
351 REGISTER_OPFACTORY(PhasePolyBox, PhasePolyBox)
352
353 37 CircToPhasePolyConversion::CircToPhasePolyConversion(
354
5/10
✓ Branch 5 taken 37 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 37 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 37 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 37 times.
✗ Branch 15 not taken.
✓ Branch 17 taken 37 times.
✗ Branch 18 not taken.
37 const Circuit& circ, unsigned min_size) {
355 37 min_size_ = min_size;
356
1/2
✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
37 circ_ = circ;
357 37 box_size_ = 0;
358
359
1/2
✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
37 nq_ = circ_.n_qubits();
360
1/2
✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
37 nb_ = circ_.n_bits();
361
362
1/2
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
37 qubit_types_ = std::vector<QubitType>(nq_, QubitType::pre);
363
364 37 unsigned i = 0;
365
3/4
✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
✓ Branch 7 taken 157 times.
✓ Branch 8 taken 37 times.
0/1
? Decision couldn't be analyzed.
194 for (const Qubit& qb : circ_.all_qubits()) {
366
1/2
✓ Branch 2 taken 157 times.
✗ Branch 3 not taken.
157 qubit_indices_.insert({qb, i});
367 157 ++i;
368 37 }
369
370 37 i = 0;
371
3/4
✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
✓ Branch 7 taken 10 times.
✓ Branch 8 taken 37 times.
0/1
? Decision couldn't be analyzed.
47 for (const Bit& b : circ_.all_bits()) {
372
1/2
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
10 bit_indices_.insert({b, i});
373 10 ++i;
374 37 }
375
376
2/4
✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 37 times.
✗ Branch 5 not taken.
37 empty_circ_ = Circuit(circ_);
377
378 37 VertexList bin;
379
380
7/8
✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1528 times.
✓ Branch 6 taken 37 times.
✓ Branch 8 taken 1528 times.
✓ Branch 9 taken 37 times.
✓ Branch 11 taken 37 times.
✓ Branch 12 taken 37 times.
1602 BGL_FORALL_VERTICES(v, empty_circ_.dag, DAG) {
381
3/4
✓ Branch 1 taken 1528 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1194 times.
✓ Branch 4 taken 334 times.
2/2
✓ Decision 'true' taken 1194 times.
✓ Decision 'false' taken 334 times.
1528 if (!empty_circ_.detect_boundary_Op(v)) {
382
1/2
✓ Branch 1 taken 1194 times.
✗ Branch 2 not taken.
1194 bin.push_back(v);
383 }
384 }
385
386
1/2
✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
37 empty_circ_.remove_vertices(
387 bin, Circuit::GraphRewiring::Yes, Circuit::VertexDeletion::Yes);
388
389
2/4
✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 37 times.
✗ Branch 5 not taken.
37 input_circ_ = Circuit(empty_circ_);
390
2/4
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 37 times.
✗ Branch 6 not taken.
37 box_circ_ = Circuit(nq_);
391
2/4
✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 37 times.
✗ Branch 5 not taken.
37 post_circ_ = Circuit(empty_circ_);
392
393
1/2
✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
37 all_qu_ = circ_.all_qubits();
394 37 }
395
396 120 void CircToPhasePolyConversion::add_phase_poly_box() {
397
1/2
✓ Branch 1 taken 120 times.
✗ Branch 2 not taken.
120 qubit_types_.assign(nq_, QubitType::pre);
398
399
2/2
✓ Branch 0 taken 114 times.
✓ Branch 1 taken 6 times.
2/2
✓ Decision 'true' taken 114 times.
✓ Decision 'false' taken 6 times.
120 if (box_size_ >= min_size_) {
400
1/2
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
114 PhasePolyBox ppbox(box_circ_);
401
1/2
✓ Branch 2 taken 114 times.
✗ Branch 3 not taken.
114 circ_.add_box(ppbox, all_qu_);
402 114 } else {
403
6/10
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 20 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 20 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 20 times.
✓ Branch 14 taken 6 times.
0/1
? Decision couldn't be analyzed.
26 for (const Command& com : box_circ_) {
404 20 OpType ot = com.get_op_ptr()->get_type();
405
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
20 unit_vector_t qbs = com.get_args();
406
2/3
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
20 switch (ot) {
407
1/1
✓ Decision 'true' taken 12 times.
12 case OpType::CX: {
408
2/4
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 12 times.
✗ Branch 6 not taken.
12 unsigned ctrl = qubit_indices_.at(Qubit(qbs[0]));
409
2/4
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 12 times.
✗ Branch 6 not taken.
12 unsigned target = qubit_indices_.at(Qubit(qbs[1]));
410
2/4
✓ Branch 3 taken 12 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 12 times.
✗ Branch 7 not taken.
12 circ_.add_op<unsigned>(ot, {ctrl, target});
411 12 break;
412 }
413
1/1
✓ Decision 'true' taken 8 times.
8 case OpType::Rz: {
414
2/4
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 8 times.
✗ Branch 6 not taken.
8 unsigned qb = qubit_indices_.at(Qubit(qbs[0]));
415
3/6
✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 8 times.
✗ Branch 10 not taken.
16 auto angle = com.get_op_ptr()->get_params().at(0);
416
2/4
✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
8 circ_.add_op<unsigned>(ot, angle, {qb});
417 8 break;
418 8 }
419
0/1
✗ Decision 'true' not taken.
default: {
420 // no other types should be in this circuit
421 TKET_ASSERT(!"invalid op type in phase poly box construction");
422 }
423 }
424 26 }
425 }
426
427
6/10
✓ Branch 1 taken 120 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 120 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 358 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 358 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 358 times.
✓ Branch 14 taken 120 times.
0/1
? Decision couldn't be analyzed.
478 for (const Command& post_com : post_circ_) {
428 358 OpType post_ot = post_com.get_op_ptr()->get_type();
429 // no other type should be in this list
430
4/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
11 bool expected = (post_ot == OpType::H) || (post_ot == OpType::Measure) ||
431
3/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 347 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
369 (post_ot == OpType::Collapse) || (post_ot == OpType::Reset);
432 TKET_ASSERT(expected);
433
1/2
✓ Branch 1 taken 358 times.
✗ Branch 2 not taken.
358 unit_vector_t qbs = post_com.get_args();
434
2/4
✓ Branch 2 taken 358 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 358 times.
✗ Branch 6 not taken.
358 unsigned qb = qubit_indices_.at(Qubit(qbs[0]));
435
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 349 times.
2/2
✓ Decision 'true' taken 9 times.
✓ Decision 'false' taken 349 times.
358 if (post_ot == OpType::Measure) {
436
2/4
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 9 times.
✗ Branch 6 not taken.
9 unsigned b = bit_indices_.at(Bit(qbs[1]));
437
2/4
✓ Branch 3 taken 9 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 9 times.
✗ Branch 7 not taken.
9 circ_.add_op<unsigned>(post_ot, {qb, b});
438 } else {
439
2/4
✓ Branch 3 taken 349 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 349 times.
✗ Branch 7 not taken.
349 circ_.add_op<unsigned>(post_ot, {qb});
440 }
441 478 }
442
443
1/2
✓ Branch 2 taken 120 times.
✗ Branch 3 not taken.
120 post_circ_ = Circuit(empty_circ_);
444
2/4
✓ Branch 2 taken 120 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 120 times.
✗ Branch 6 not taken.
120 box_circ_ = Circuit(nq_);
445 120 box_size_ = 0;
446 120 }
447
448 37 void CircToPhasePolyConversion::convert() {
449
6/10
✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 37 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1194 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1194 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1194 times.
✓ Branch 14 taken 37 times.
0/1
? Decision couldn't be analyzed.
1231 for (const Command& com : circ_) {
450 1194 OpType ot = com.get_op_ptr()->get_type();
451
1/2
✓ Branch 1 taken 1194 times.
✗ Branch 2 not taken.
1194 unit_vector_t qbs = com.get_args();
452
5/6
✓ Branch 0 taken 294 times.
✓ Branch 1 taken 402 times.
✓ Branch 2 taken 486 times.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
1194 switch (ot) {
453
1/1
✓ Decision 'true' taken 294 times.
294 case OpType::CX: {
454
2/4
✓ Branch 2 taken 294 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 294 times.
✗ Branch 6 not taken.
294 unsigned ctrl = qubit_indices_.at(Qubit(qbs[0]));
455
2/4
✓ Branch 2 taken 294 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 294 times.
✗ Branch 6 not taken.
294 unsigned target = qubit_indices_.at(Qubit(qbs[1]));
456
2/4
✓ Branch 3 taken 294 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 294 times.
✗ Branch 7 not taken.
294 input_circ_.add_op<unsigned>(ot, {ctrl, target});
457 294 break;
458 }
459
1/1
✓ Decision 'true' taken 402 times.
402 case OpType::Rz: {
460
2/4
✓ Branch 2 taken 402 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 402 times.
✗ Branch 6 not taken.
402 unsigned qb = qubit_indices_.at(Qubit(qbs[0]));
461
3/6
✓ Branch 3 taken 402 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 402 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 402 times.
✗ Branch 10 not taken.
804 auto angle = com.get_op_ptr()->get_params().at(0);
462
2/4
✓ Branch 3 taken 402 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 402 times.
✗ Branch 7 not taken.
402 input_circ_.add_op<unsigned>(ot, angle, {qb});
463 402 break;
464 402 }
465 486 case OpType::H:
466 case OpType::Collapse:
467 case OpType::Reset: {
468
2/4
✓ Branch 2 taken 486 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 486 times.
✗ Branch 6 not taken.
486 unsigned qb = qubit_indices_.at(Qubit(qbs[0]));
469
2/4
✓ Branch 3 taken 486 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 486 times.
✗ Branch 7 not taken.
486 input_circ_.add_op<unsigned>(ot, {qb});
470 486 break;
471 }
472
1/1
✓ Decision 'true' taken 9 times.
9 case OpType::Measure: {
473
2/4
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 9 times.
✗ Branch 6 not taken.
9 unsigned qb = qubit_indices_.at(Qubit(qbs[0]));
474
2/4
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 9 times.
✗ Branch 6 not taken.
9 unsigned b = bit_indices_.at(Bit(qbs[1]));
475
2/4
✓ Branch 3 taken 9 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 9 times.
✗ Branch 7 not taken.
9 input_circ_.add_op<unsigned>(ot, {qb, b});
476 9 break;
477 }
478
1/1
✓ Decision 'true' taken 3 times.
3 case OpType::Barrier: {
479
2/4
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
3 input_circ_.add_barrier(qbs);
480 3 break;
481 }
482
0/1
✗ Decision 'true' not taken.
default: {
483 throw BadOpType(
484 "Please rebase with the compiler pass RebaseUFR to only CX, Rz, H, "
485 "measure, reset, collapse, barrier gates. Found gate of different "
486 "type",
487 ot);
488 }
489 }
490 1231 }
491
492 74 VertexList bin;
493
494
7/8
✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1528 times.
✓ Branch 6 taken 37 times.
✓ Branch 8 taken 1528 times.
✓ Branch 9 taken 37 times.
✓ Branch 11 taken 37 times.
✓ Branch 12 taken 37 times.
1602 BGL_FORALL_VERTICES(v, circ_.dag, DAG) {
495
3/4
✓ Branch 1 taken 1528 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1194 times.
✓ Branch 4 taken 334 times.
2/2
✓ Decision 'true' taken 1194 times.
✓ Decision 'false' taken 334 times.
1528 if (!circ_.detect_boundary_Op(v)) {
496
1/2
✓ Branch 1 taken 1194 times.
✗ Branch 2 not taken.
1194 bin.push_back(v);
497 }
498 }
499
500
1/2
✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
37 circ_.remove_vertices(
501 bin, Circuit::GraphRewiring::Yes, Circuit::VertexDeletion::Yes);
502
503 /*
504 this for loop checks all gates in the circuits and try to
505 find the biggest possible sub circuits which contains only
506 CX+Rz Gates. This is done in a way that all qubits get
507 marked if they are currently outside before (pre), in (in)
508 or outside after (post) of a currently constructed box. If
509 a qubit is in the pre state and a gate, which is no valid
510 type in a box should be added, the type is not changed and
511 the gate is added. If a CX or Rz gate should be added to
512 this qubit the type is changes to in and the gate is added
513 to the box. If another gate should be added to a qubit in
514 state, the state stays the same for CX and Rz and they are
515 added to the box. If the added gate has a different type
516 the type of the qubit is changed to post and the gate is
517 added after the box. If a CX or Rz gate should be added to
518 a qubit in the post state, the current box is added and a
519 new box is started to which the current gate is added. All
520 qubits states are reset to pre.
521 */
522
6/10
✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 37 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1194 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1194 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1194 times.
✓ Branch 14 taken 37 times.
0/1
? Decision couldn't be analyzed.
1231 for (const Command& com : input_circ_) {
523 1194 OpType ot = com.get_op_ptr()->get_type();
524
1/2
✓ Branch 1 taken 1194 times.
✗ Branch 2 not taken.
1194 unit_vector_t qbs = com.get_args();
525
5/6
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 294 times.
✓ Branch 2 taken 402 times.
✓ Branch 3 taken 486 times.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
1194 switch (ot) {
526
1/1
✓ Decision 'true' taken 3 times.
3 case OpType::Barrier: {
527
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 add_phase_poly_box();
528
529
2/4
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
3 circ_.add_barrier(qbs);
530 3 break;
531 }
532
1/1
✓ Decision 'true' taken 294 times.
294 case OpType::CX: {
533
2/4
✓ Branch 2 taken 294 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 294 times.
✗ Branch 6 not taken.
294 unsigned ctrl = qubit_indices_.at(Qubit(qbs[0]));
534
2/4
✓ Branch 2 taken 294 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 294 times.
✗ Branch 6 not taken.
294 unsigned target = qubit_indices_.at(Qubit(qbs[1]));
535
4/4
✓ Branch 1 taken 164 times.
✓ Branch 2 taken 130 times.
✓ Branch 3 taken 127 times.
✓ Branch 4 taken 167 times.
2/2
✓ Decision 'true' taken 127 times.
✓ Decision 'false' taken 331 times.
458 if ((qubit_types_[ctrl] == QubitType::in) &&
536
2/2
✓ Branch 1 taken 127 times.
✓ Branch 2 taken 37 times.
164 (qubit_types_[target] == QubitType::in)) {
537
2/4
✓ Branch 3 taken 127 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 127 times.
✗ Branch 7 not taken.
127 box_circ_.add_op<unsigned>(OpType::CX, {ctrl, target});
538 167 } else if (
539
4/4
✓ Branch 1 taken 121 times.
✓ Branch 2 taken 46 times.
✓ Branch 3 taken 88 times.
✓ Branch 4 taken 79 times.
288 (qubit_types_[ctrl] == QubitType::pre) &&
540
2/2
✓ Branch 1 taken 88 times.
✓ Branch 2 taken 33 times.
121 (qubit_types_[target] == QubitType::in)) {
541 88 qubit_types_[ctrl] = QubitType::in;
542
2/4
✓ Branch 3 taken 88 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 88 times.
✗ Branch 7 not taken.
88 box_circ_.add_op<unsigned>(OpType::CX, {ctrl, target});
543 79 } else if (
544
4/4
✓ Branch 1 taken 37 times.
✓ Branch 2 taken 42 times.
✓ Branch 3 taken 32 times.
✓ Branch 4 taken 47 times.
116 (qubit_types_[ctrl] == QubitType::in) &&
545
2/2
✓ Branch 1 taken 32 times.
✓ Branch 2 taken 5 times.
37 (qubit_types_[target] == QubitType::pre)) {
546 32 qubit_types_[target] = QubitType::in;
547
2/4
✓ Branch 3 taken 32 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 32 times.
✗ Branch 7 not taken.
32 box_circ_.add_op<unsigned>(OpType::CX, {ctrl, target});
548 47 } else if (
549
4/4
✓ Branch 1 taken 33 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 32 times.
✓ Branch 4 taken 15 times.
80 (qubit_types_[ctrl] == QubitType::pre) &&
550
2/2
✓ Branch 1 taken 32 times.
✓ Branch 2 taken 1 times.
33 (qubit_types_[target] == QubitType::pre)) {
551 32 qubit_types_[ctrl] = QubitType::in;
552 32 qubit_types_[target] = QubitType::in;
553
2/4
✓ Branch 3 taken 32 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 32 times.
✗ Branch 7 not taken.
32 box_circ_.add_op<unsigned>(OpType::CX, {ctrl, target});
554 15 } else if (
555
3/4
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 15 times.
✗ Branch 4 not taken.
21 (qubit_types_[ctrl] == QubitType::post) ||
556
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 (qubit_types_[target] == QubitType::post)) {
557
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 add_phase_poly_box();
558
559 15 qubit_types_[ctrl] = QubitType::in;
560 15 qubit_types_[target] = QubitType::in;
561
2/4
✓ Branch 3 taken 15 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 15 times.
✗ Branch 7 not taken.
15 box_circ_.add_op<unsigned>(OpType::CX, {ctrl, target});
562 } else {
563 // no other types should be in this list
564 TKET_ASSERT(!"Invalid Qubit Type in Phase Poly Box creation");
565 }
566 294 ++box_size_;
567 294 break;
568 }
569
1/1
✓ Decision 'true' taken 402 times.
402 case OpType::Rz: {
570
2/4
✓ Branch 2 taken 402 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 402 times.
✗ Branch 6 not taken.
402 unsigned qb = qubit_indices_.at(Qubit(qbs[0]));
571
3/6
✓ Branch 3 taken 402 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 402 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 402 times.
✗ Branch 10 not taken.
804 auto angle = com.get_op_ptr()->get_params().at(0);
572
3/4
✓ Branch 1 taken 204 times.
✓ Branch 2 taken 133 times.
✓ Branch 3 taken 65 times.
✗ Branch 4 not taken.
402 switch (qubit_types_[qb]) {
573
1/1
✓ Decision 'true' taken 204 times.
204 case QubitType::pre: {
574
2/4
✓ Branch 3 taken 204 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 204 times.
✗ Branch 7 not taken.
204 box_circ_.add_op<unsigned>(OpType::Rz, angle, {qb});
575 204 qubit_types_[qb] = QubitType::in;
576 204 break;
577 }
578
1/1
✓ Decision 'true' taken 133 times.
133 case QubitType::in: {
579
2/4
✓ Branch 3 taken 133 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 133 times.
✗ Branch 7 not taken.
133 box_circ_.add_op<unsigned>(OpType::Rz, angle, {qb});
580 133 break;
581 }
582
1/1
✓ Decision 'true' taken 65 times.
65 case QubitType::post: {
583
1/2
✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
65 add_phase_poly_box();
584
585 65 qubit_types_[qb] = QubitType::in;
586
2/4
✓ Branch 3 taken 65 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 65 times.
✗ Branch 7 not taken.
65 box_circ_.add_op<unsigned>(OpType::Rz, angle, {qb});
587 65 break;
588 }
589
0/1
✗ Decision 'true' not taken.
default: {
590 // no other types should be in this list
591 TKET_ASSERT(!"Invalid Qubit Type in Phase Poly Box creation");
592 }
593 }
594 402 break;
595 402 }
596 486 case OpType::H:
597 case OpType::Collapse:
598 case OpType::Reset: {
599
2/4
✓ Branch 2 taken 486 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 486 times.
✗ Branch 6 not taken.
486 unsigned qb = qubit_indices_.at(Qubit(qbs[0]));
600
3/4
✓ Branch 1 taken 137 times.
✓ Branch 2 taken 319 times.
✓ Branch 3 taken 30 times.
✗ Branch 4 not taken.
486 switch (qubit_types_[qb]) {
601
1/1
✓ Decision 'true' taken 137 times.
137 case QubitType::pre: {
602
2/4
✓ Branch 3 taken 137 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 137 times.
✗ Branch 7 not taken.
137 circ_.add_op<unsigned>(ot, {qb});
603 137 break;
604 }
605
1/1
✓ Decision 'true' taken 319 times.
319 case QubitType::in: {
606
2/4
✓ Branch 3 taken 319 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 319 times.
✗ Branch 7 not taken.
319 post_circ_.add_op<unsigned>(ot, {qb});
607 319 qubit_types_[qb] = QubitType::post;
608 319 break;
609 }
610
1/1
✓ Decision 'true' taken 30 times.
30 case QubitType::post: {
611
2/4
✓ Branch 3 taken 30 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 30 times.
✗ Branch 7 not taken.
30 post_circ_.add_op<unsigned>(ot, {qb});
612 30 break;
613 }
614
0/1
✗ Decision 'true' not taken.
default: {
615 // no other types should be in this list
616 TKET_ASSERT(!"Invalid Qubit Type in Phase Poly Box creation");
617 }
618 }
619 486 break;
620 }
621
1/1
✓ Decision 'true' taken 9 times.
9 case OpType::Measure: {
622
2/4
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 9 times.
✗ Branch 6 not taken.
9 unsigned qb = qubit_indices_.at(Qubit(qbs[0]));
623
2/4
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 9 times.
✗ Branch 6 not taken.
9 unsigned b = bit_indices_.at(Bit(qbs[1]));
624
625
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
9 switch (qubit_types_[qb]) {
626
0/1
✗ Decision 'true' not taken.
case QubitType::pre: {
627 circ_.add_op<unsigned>(ot, {qb, b});
628 break;
629 }
630
1/1
✓ Decision 'true' taken 1 times.
1 case QubitType::in: {
631
2/4
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
1 post_circ_.add_op<unsigned>(ot, {qb, b});
632 1 qubit_types_[qb] = QubitType::post;
633 1 break;
634 }
635
1/1
✓ Decision 'true' taken 8 times.
8 case QubitType::post: {
636
2/4
✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
8 post_circ_.add_op<unsigned>(ot, {qb, b});
637 8 break;
638 }
639
0/1
✗ Decision 'true' not taken.
default: {
640 // no other types should be in this list
641 TKET_ASSERT(!"Invalid Qubit Type in Phase Poly Box creation");
642 }
643 }
644 9 break;
645 }
646
0/1
✗ Decision 'true' not taken.
default: {
647 throw BadOpType(
648 "Please rebase with the compiler pass RebaseUFR to only CX, Rz, H, "
649 "measure, reset, collapse, barrier gates. Found gate of different "
650 "type",
651 ot);
652 }
653 }
654 1231 }
655
656 // add the last box to the circuit
657
1/2
✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
37 add_phase_poly_box();
658 37 }
659
660 37 Circuit CircToPhasePolyConversion::get_circuit() const { return circ_; }
661
662 } // namespace tket
663