GCC Code Coverage Report


Directory: ./
File: Circuit/CircUtils.cpp
Date: 2022-10-15 05:10:18
Warnings: 1 unchecked decisions!
Exec Total Coverage
Lines: 750 838 89.5%
Functions: 27 27 100.0%
Branches: 1202 2281 52.7%
Decisions: 267 316 84.5%

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 "CircUtils.hpp"
16
17 #include <cmath>
18 #include <complex>
19 #include <vector>
20
21 #include "CircPool.hpp"
22 #include "Circuit/Circuit.hpp"
23 #include "Gate/GatePtr.hpp"
24 #include "Gate/GateUnitaryMatrixImplementations.hpp"
25 #include "Gate/Rotation.hpp"
26 #include "OpType/OpType.hpp"
27 #include "Ops/Op.hpp"
28 #include "Utils/EigenConfig.hpp"
29 #include "Utils/Expression.hpp"
30 #include "Utils/MatrixAnalysis.hpp"
31 #include "Utils/UnitID.hpp"
32
33 namespace tket {
34
35 211 Eigen::Matrix2cd get_matrix(const Circuit &circ, const Vertex &vert) {
36
1/2
✓ Branch 1 taken 211 times.
✗ Branch 2 not taken.
211 const Op_ptr op = circ.get_Op_ptr_from_Vertex(vert);
37
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 211 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 211 times.
211 if (op->get_type() != OpType::TK1) {
38 throw BadOpType("Cannot compute matrix from gate", op->get_type());
39 }
40
1/2
✓ Branch 2 taken 211 times.
✗ Branch 3 not taken.
211 std::vector<Expr> ps = op->get_params();
41
2/4
✓ Branch 1 taken 211 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 211 times.
✗ Branch 5 not taken.
211 ps.push_back(0);
42
2/4
✓ Branch 1 taken 211 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 211 times.
✗ Branch 5 not taken.
422 return get_matrix_from_tk1_angles(ps);
43 211 }
44
45 131 Eigen::Matrix2cd get_matrix_from_circ(const Circuit &circ) {
46
2/4
✓ Branch 1 taken 131 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 131 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 131 times.
131 if (circ.n_qubits() != 1)
47 throw CircuitInvalidity(
48 "Getting Matrix: expected 1 qubit circuit, found " +
49 std::to_string(circ.n_qubits()));
50
3/6
✓ Branch 1 taken 131 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 131 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 131 times.
✗ Branch 8 not taken.
131 Complex factor = std::exp(i_ * PI * eval_expr(circ.get_phase()).value());
51
2/4
✓ Branch 1 taken 131 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 131 times.
✗ Branch 6 not taken.
131 VertexVec qpath = circ.qubit_path_vertices(circ.all_qubits()[0]);
52 131 unsigned N = qpath.size();
53
5/8
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 127 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 4 times.
✗ Branch 10 not taken.
2/2
✓ Decision 'true' taken 127 times.
✓ Decision 'false' taken 8 times.
135 if (N == 2) return factor * Eigen::Matrix2cd::Identity();
54
1/2
✓ Branch 2 taken 127 times.
✗ Branch 3 not taken.
127 Eigen::Matrix2cd m = get_matrix(circ, qpath[N - 2]);
55
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 127 times.
2/2
✓ Decision 'true' taken 84 times.
✓ Decision 'false' taken 127 times.
211 for (unsigned x = N - 3; x >= 1; --x) {
56
3/6
✓ Branch 2 taken 84 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 84 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 84 times.
✗ Branch 9 not taken.
84 m = m * get_matrix(circ, qpath[x]);
57 }
58
2/4
✓ Branch 1 taken 127 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 127 times.
✗ Branch 5 not taken.
254 return factor * m;
59 131 }
60
61 6599 Eigen::Matrix4cd get_matrix_from_2qb_circ(const Circuit &circ) {
62
1/2
✓ Branch 1 taken 6599 times.
✗ Branch 2 not taken.
6599 std::vector<QPathDetailed> all_paths = circ.all_qubit_paths();
63 6599 std::map<Vertex, Eigen::Matrix4cd> v_to_op;
64
3/6
✓ Branch 1 taken 6599 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6599 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 6599 times.
✗ Branch 8 not taken.
6599 Eigen::Matrix4cd cnot, tonc, swap;
65 // clang-format off
66
4/8
✓ Branch 2 taken 6599 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 6599 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 6599 times.
✗ Branch 11 not taken.
✓ Branch 14 taken 6599 times.
✗ Branch 15 not taken.
6599 cnot << 1, 0, 0, 0,
67
4/8
✓ Branch 2 taken 6599 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 6599 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 6599 times.
✗ Branch 11 not taken.
✓ Branch 14 taken 6599 times.
✗ Branch 15 not taken.
6599 0, 1, 0, 0,
68
4/8
✓ Branch 2 taken 6599 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 6599 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 6599 times.
✗ Branch 11 not taken.
✓ Branch 14 taken 6599 times.
✗ Branch 15 not taken.
6599 0, 0, 0, 1,
69
4/8
✓ Branch 2 taken 6599 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 6599 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 6599 times.
✗ Branch 11 not taken.
✓ Branch 14 taken 6599 times.
✗ Branch 15 not taken.
6599 0, 0, 1, 0;
70
4/8
✓ Branch 2 taken 6599 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 6599 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 6599 times.
✗ Branch 11 not taken.
✓ Branch 14 taken 6599 times.
✗ Branch 15 not taken.
6599 tonc << 1, 0, 0, 0,
71
4/8
✓ Branch 2 taken 6599 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 6599 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 6599 times.
✗ Branch 11 not taken.
✓ Branch 14 taken 6599 times.
✗ Branch 15 not taken.
6599 0, 0, 0, 1,
72
4/8
✓ Branch 2 taken 6599 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 6599 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 6599 times.
✗ Branch 11 not taken.
✓ Branch 14 taken 6599 times.
✗ Branch 15 not taken.
6599 0, 0, 1, 0,
73
4/8
✓ Branch 2 taken 6599 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 6599 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 6599 times.
✗ Branch 11 not taken.
✓ Branch 14 taken 6599 times.
✗ Branch 15 not taken.
6599 0, 1, 0, 0;
74
4/8
✓ Branch 2 taken 6599 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 6599 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 6599 times.
✗ Branch 11 not taken.
✓ Branch 14 taken 6599 times.
✗ Branch 15 not taken.
6599 swap << 1, 0, 0, 0,
75
4/8
✓ Branch 2 taken 6599 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 6599 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 6599 times.
✗ Branch 11 not taken.
✓ Branch 14 taken 6599 times.
✗ Branch 15 not taken.
6599 0, 0, 1, 0,
76
4/8
✓ Branch 2 taken 6599 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 6599 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 6599 times.
✗ Branch 11 not taken.
✓ Branch 14 taken 6599 times.
✗ Branch 15 not taken.
6599 0, 1, 0, 0,
77
4/8
✓ Branch 2 taken 6599 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 6599 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 6599 times.
✗ Branch 11 not taken.
✓ Branch 14 taken 6599 times.
✗ Branch 15 not taken.
6599 0, 0, 0, 1;
78 // clang-format on
79
80
2/2
✓ Branch 0 taken 13198 times.
✓ Branch 1 taken 6599 times.
2/2
✓ Decision 'true' taken 13198 times.
✓ Decision 'false' taken 6599 times.
19797 for (unsigned uqb = 0; uqb < 2; uqb++) {
81 13198 for (QPathDetailed::iterator it = all_paths[uqb].begin();
82
2/2
✓ Branch 4 taken 91000 times.
✓ Branch 5 taken 13198 times.
104198 it != all_paths[uqb].end(); ++it) {
83
1/2
✓ Branch 2 taken 91000 times.
✗ Branch 3 not taken.
91000 const Op_ptr o = circ.get_Op_ptr_from_Vertex(it->first);
84
5/5
✓ Branch 2 taken 26396 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 16640 times.
✓ Branch 5 taken 4286 times.
✓ Branch 6 taken 43676 times.
91000 switch (o->get_type()) {
85 26396 case OpType::Input:
86 case OpType::Create:
87 case OpType::Output:
88 case OpType::Discard: {
89
3/6
✓ Branch 1 taken 26396 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 26396 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 26396 times.
✗ Branch 9 not taken.
26396 v_to_op[it->first] = Eigen::Matrix4cd::Identity();
90 26396 break;
91 }
92
1/1
✓ Decision 'true' taken 2 times.
2 case OpType::SWAP: {
93
4/6
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
1/2
✓ Decision 'true' taken 2 times.
✗ Decision 'false' not taken.
2 if (uqb == 0) v_to_op[it->first] = swap;
94 2 break;
95 }
96
1/1
✓ Decision 'true' taken 16640 times.
16640 case OpType::CX: {
97
2/2
✓ Branch 0 taken 8320 times.
✓ Branch 1 taken 8320 times.
2/2
✓ Decision 'true' taken 8320 times.
✓ Decision 'false' taken 8320 times.
16640 if (uqb == 0) {
98
2/2
✓ Branch 1 taken 8300 times.
✓ Branch 2 taken 20 times.
2/2
✓ Decision 'true' taken 8300 times.
✓ Decision 'false' taken 20 times.
8320 if (it->second == 0) {
99
2/4
✓ Branch 2 taken 8300 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 8300 times.
✗ Branch 6 not taken.
8300 v_to_op[it->first] = cnot;
100 } else {
101
2/4
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 20 times.
✗ Branch 6 not taken.
20 v_to_op[it->first] = tonc;
102 }
103 }
104 16640 break;
105 }
106
1/1
✓ Decision 'true' taken 4286 times.
4286 case OpType::TK2: {
107
1/2
✓ Branch 2 taken 4286 times.
✗ Branch 3 not taken.
4286 auto params = o->get_params();
108 TKET_ASSERT(params.size() == 3);
109
1/2
✓ Branch 2 taken 4286 times.
✗ Branch 3 not taken.
4286 v_to_op[it->first] =
110
2/4
✓ Branch 1 taken 4286 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4286 times.
✗ Branch 5 not taken.
8572 get_matrix_from_2qb_circ(CircPool::normalised_TK2_using_CX(
111 8572 params[0], params[1], params[2]));
112 4286 break;
113 4286 }
114
1/1
✓ Decision 'true' taken 87352 times.
43676 default: {
115
7/16
✓ Branch 2 taken 43676 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 43676 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 43676 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 43676 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 43676 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 43676 times.
✗ Branch 16 not taken.
✓ Branch 18 taken 43676 times.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
2/2
✓ Decision 'true' taken 43676 times.
✓ Decision 'false' taken 43676 times.
87352 if (o->get_desc().is_gate() && circ.n_in_edges(it->first) == 1 &&
116
2/4
✓ Branch 2 taken 43676 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 43676 times.
✗ Branch 5 not taken.
43676 circ.n_out_edges(it->first) == 1) {
117 43676 const Op_ptr g = o;
118
2/4
✓ Branch 2 taken 43676 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 43676 times.
✗ Branch 7 not taken.
87352 std::vector<Expr> ps = as_gate_ptr(g)->get_tk1_angles();
119
2/4
✓ Branch 1 taken 43676 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 43676 times.
✗ Branch 5 not taken.
43676 Eigen::Matrix2cd mat = get_matrix_from_tk1_angles(ps);
120
2/2
✓ Branch 0 taken 23918 times.
✓ Branch 1 taken 19758 times.
2/2
✓ Decision 'true' taken 23918 times.
✓ Decision 'false' taken 19758 times.
43676 if (uqb == 0) {
121
1/2
✓ Branch 2 taken 23918 times.
✗ Branch 3 not taken.
23918 v_to_op[it->first] =
122
3/6
✓ Branch 1 taken 23918 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 23918 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 23918 times.
✗ Branch 8 not taken.
47836 Eigen::kroneckerProduct(mat, Eigen::Matrix2cd::Identity());
123 } else {
124
1/2
✓ Branch 2 taken 19758 times.
✗ Branch 3 not taken.
19758 v_to_op[it->first] =
125
3/6
✓ Branch 1 taken 19758 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 19758 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 19758 times.
✗ Branch 8 not taken.
39516 Eigen::kroneckerProduct(Eigen::Matrix2cd::Identity(), mat);
126 }
127 43676 } else
128 throw BadOpType("Cannot obtain matrix from op", o->get_type());
129 }
130 }
131 91000 }
132 }
133
2/4
✓ Branch 1 taken 6599 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6599 times.
✗ Branch 5 not taken.
6599 Eigen::Matrix4cd m = Eigen::Matrix4cd::Identity();
134
1/2
✓ Branch 1 taken 6599 times.
✗ Branch 2 not taken.
6599 SliceVec slices = circ.get_slices();
135
2/2
✓ Branch 5 taken 35511 times.
✓ Branch 6 taken 6599 times.
2/2
✓ Decision 'true' taken 35511 times.
✓ Decision 'false' taken 6599 times.
42110 for (const Slice &s : slices) {
136
2/2
✓ Branch 4 taken 54140 times.
✓ Branch 5 taken 35511 times.
2/2
✓ Decision 'true' taken 54140 times.
✓ Decision 'false' taken 35511 times.
89651 for (const Vertex &v : s) {
137
3/6
✓ Branch 1 taken 54140 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 54140 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 54140 times.
✗ Branch 8 not taken.
54140 m = v_to_op[v] * m;
138 }
139 }
140
5/10
✓ Branch 1 taken 6599 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6599 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 6599 times.
✗ Branch 8 not taken.
✓ Branch 13 taken 6599 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 6599 times.
✗ Branch 17 not taken.
19797 return std::exp(i_ * PI * eval_expr(circ.get_phase()).value()) * m;
141 6599 }
142
143 2106 Circuit two_qubit_canonical(const Eigen::Matrix4cd &U, OpType target_2qb_gate) {
144
3/6
✓ Branch 1 taken 2106 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2106 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 2106 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 2106 times.
2106 if (!is_unitary(U)) {
145 throw std::invalid_argument(
146 "Non-unitary matrix passed to two_qubit_canonical");
147 }
148
149
1/2
✓ Branch 1 taken 2106 times.
✗ Branch 2 not taken.
2106 auto [K1, A, K2] = get_information_content(U);
150
151
3/6
✓ Branch 1 taken 2106 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2106 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2106 times.
✗ Branch 8 not taken.
2106 K1 /= pow(K1.determinant(), 0.25);
152
3/6
✓ Branch 1 taken 2106 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2106 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2106 times.
✗ Branch 8 not taken.
2106 K2 /= pow(K2.determinant(), 0.25);
153 2106 auto [a, b, c] = A;
154
155 // Decompose single qubits
156
1/2
✓ Branch 1 taken 2106 times.
✗ Branch 2 not taken.
2106 auto [K1a, K1b] = kronecker_decomposition(K1);
157
1/2
✓ Branch 1 taken 2106 times.
✗ Branch 2 not taken.
2106 auto [K2a, K2b] = kronecker_decomposition(K2);
158
159
1/2
✓ Branch 2 taken 2106 times.
✗ Branch 3 not taken.
2106 Circuit result(2);
160
161
1/2
✓ Branch 1 taken 2106 times.
✗ Branch 2 not taken.
2106 std::vector<double> angles_q0 = tk1_angles_from_unitary(K2a);
162
1/2
✓ Branch 1 taken 2106 times.
✗ Branch 2 not taken.
2106 std::vector<double> angles_q1 = tk1_angles_from_unitary(K2b);
163
3/6
✓ Branch 3 taken 2106 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 2106 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 2106 times.
✗ Branch 11 not taken.
6318 result.add_op<unsigned>(
164 4212 OpType::TK1, {angles_q0.begin(), angles_q0.end() - 1}, {0});
165
3/6
✓ Branch 3 taken 2106 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 2106 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 2106 times.
✗ Branch 11 not taken.
6318 result.add_op<unsigned>(
166 4212 OpType::TK1, {angles_q1.begin(), angles_q1.end() - 1}, {1});
167
168
2/3
✓ Branch 0 taken 1740 times.
✓ Branch 1 taken 366 times.
✗ Branch 2 not taken.
2106 switch (target_2qb_gate) {
169
1/1
✓ Decision 'true' taken 1740 times.
1740 case OpType::TK2:
170
5/10
✓ Branch 1 taken 1740 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1740 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1740 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1740 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1740 times.
✗ Branch 14 not taken.
1740 result.append(CircPool::TK2_using_normalised_TK2(a, b, c));
171 1740 break;
172
1/1
✓ Decision 'true' taken 366 times.
366 case OpType::CX:
173
5/10
✓ Branch 1 taken 366 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 366 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 366 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 366 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 366 times.
✗ Branch 14 not taken.
366 result.append(CircPool::TK2_using_CX(a, b, c));
174 366 break;
175
0/1
✗ Decision 'true' not taken.
default:
176 throw std::invalid_argument("target_2qb_gate must be CX or TK2.");
177 }
178
179
1/2
✓ Branch 1 taken 2106 times.
✗ Branch 2 not taken.
2106 angles_q0 = tk1_angles_from_unitary(K1a);
180
1/2
✓ Branch 1 taken 2106 times.
✗ Branch 2 not taken.
2106 angles_q1 = tk1_angles_from_unitary(K1b);
181
3/6
✓ Branch 3 taken 2106 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 2106 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 2106 times.
✗ Branch 11 not taken.
6318 result.add_op<unsigned>(
182 4212 OpType::TK1, {angles_q0.begin(), angles_q0.end() - 1}, {0});
183
3/6
✓ Branch 3 taken 2106 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 2106 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 2106 times.
✗ Branch 11 not taken.
6318 result.add_op<unsigned>(
184 4212 OpType::TK1, {angles_q1.begin(), angles_q1.end() - 1}, {1});
185
186 // this fixes phase if decomposition is exact
187
4/8
✓ Branch 1 taken 2106 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2106 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2106 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 2106 times.
✗ Branch 11 not taken.
2106 Eigen::Matrix4cd reminder = get_matrix_from_2qb_circ(result).adjoint() * U;
188
1/2
✓ Branch 1 taken 2106 times.
✗ Branch 2 not taken.
2106 const Complex phase = reminder(0, 0); // reminder = phase * I
189
2/4
✓ Branch 2 taken 2106 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2106 times.
✗ Branch 6 not taken.
2106 result.add_phase(arg(phase) / PI);
190 4212 return result;
191 2106 }
192
193 // Factorize U as VD where V corresponds to a 2-CX circuit and
194 // D = diag(z, z*, z*, z). Return V and z.
195 1348 static std::pair<Eigen::Matrix4cd, Complex> decompose_VD(
196 const Eigen::Matrix4cd &U) {
197
3/6
✓ Branch 1 taken 1348 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1348 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 1348 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 1348 times.
1348 if (!is_unitary(U)) {
198 throw std::invalid_argument("Non-unitary matrix passed to decompose_VD");
199 }
200
201 // The calculations below are derived from the proof of Proposition V.2 in
202 // https://arxiv.org/abs/quant-ph/0308033.
203
204
4/8
✓ Branch 1 taken 1348 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1348 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1348 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1348 times.
✗ Branch 11 not taken.
1348 Eigen::Matrix4cd u = U / pow(U.determinant(), 0.25);
205
11/22
✓ Branch 1 taken 1348 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1348 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1348 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1348 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1348 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 1348 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 1348 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 1348 times.
✗ Branch 23 not taken.
✓ Branch 25 taken 1348 times.
✗ Branch 26 not taken.
✓ Branch 28 taken 1348 times.
✗ Branch 29 not taken.
✓ Branch 31 taken 1348 times.
✗ Branch 32 not taken.
1348 Complex a = u(3, 0) * u(0, 3) - u(2, 0) * u(1, 3) - u(1, 0) * u(2, 3) +
206
4/8
✓ Branch 1 taken 1348 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1348 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1348 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1348 times.
✗ Branch 11 not taken.
2696 u(0, 0) * u(3, 3);
207
11/22
✓ Branch 1 taken 1348 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1348 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1348 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1348 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1348 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 1348 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 1348 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 1348 times.
✗ Branch 23 not taken.
✓ Branch 25 taken 1348 times.
✗ Branch 26 not taken.
✓ Branch 28 taken 1348 times.
✗ Branch 29 not taken.
✓ Branch 31 taken 1348 times.
✗ Branch 32 not taken.
1348 Complex b = u(3, 1) * u(0, 2) - u(2, 1) * u(1, 2) - u(1, 1) * u(2, 2) +
208
4/8
✓ Branch 1 taken 1348 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1348 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1348 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1348 times.
✗ Branch 11 not taken.
2696 u(0, 1) * u(3, 2);
209 // Now we want to find z such that |z|=1 and (az* - bz) is real.
210 // The numerical stability of this function is a concern when a is close to
211 // -b*. This problem can be demonstrated in artificially constructed
212 // examples (passing unitaries very close to, but not quite, the identity to
213 // the functions below). In these cases the product VD (or DV) may not
214 // approximate U to within Eigen's default tolerance. Is there a way to
215 // dodge this issue?
216
1/2
✓ Branch 2 taken 1348 times.
✗ Branch 3 not taken.
1348 Complex w = a + std::conj(b);
217 1348 double d = std::abs(w);
218 // If w = 0 then we can set z = 1.
219
2/2
✓ Branch 0 taken 659 times.
✓ Branch 1 taken 689 times.
1348 Complex z = (d < EPS) ? 1. : w / d;
220 1348 Complex z0 = sqrt(z);
221 1348 Complex z1 = std::conj(z0);
222
1/2
✓ Branch 1 taken 1348 times.
✗ Branch 2 not taken.
1348 Eigen::Matrix4cd V = U;
223
2/4
✓ Branch 1 taken 1348 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1348 times.
✗ Branch 5 not taken.
1348 V.col(0) *= z1;
224
2/4
✓ Branch 1 taken 1348 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1348 times.
✗ Branch 5 not taken.
1348 V.col(1) *= z0;
225
2/4
✓ Branch 1 taken 1348 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1348 times.
✗ Branch 5 not taken.
1348 V.col(2) *= z0;
226
2/4
✓ Branch 1 taken 1348 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1348 times.
✗ Branch 5 not taken.
1348 V.col(3) *= z1;
227
1/2
✓ Branch 1 taken 1348 times.
✗ Branch 2 not taken.
2696 return {V, z0};
228 }
229
230 1348 static void replace_TK2_2CX(Circuit &circ) {
231 1348 VertexList bin;
232
7/8
✓ Branch 1 taken 1348 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 30052 times.
✓ Branch 6 taken 1348 times.
✓ Branch 8 taken 30052 times.
✓ Branch 9 taken 1348 times.
✓ Branch 11 taken 1348 times.
✓ Branch 12 taken 1348 times.
32748 BGL_FORALL_VERTICES(v, circ.dag, DAG) {
233
3/4
✓ Branch 1 taken 30052 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 28704 times.
✓ Branch 4 taken 1348 times.
2/2
✓ Decision 'true' taken 1348 times.
✓ Decision 'false' taken 28704 times.
30052 if (circ.get_OpType_from_Vertex(v) != OpType::TK2) continue;
234
2/4
✓ Branch 1 taken 1348 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1348 times.
✗ Branch 6 not taken.
1348 auto params = circ.get_Op_ptr_from_Vertex(v)->get_params();
235 TKET_ASSERT(params.size() == 3);
236 // We need to have a fairly high tolerance in the assertion below, since in
237 // practice rounding errors can accumulate:
238 TKET_ASSERT(equiv_0(params[2], 4, 1e-6));
239
1/2
✓ Branch 3 taken 1348 times.
✗ Branch 4 not taken.
1348 Circuit sub = CircPool::approx_TK2_using_2xCX(params[0], params[1]);
240
1/2
✓ Branch 1 taken 1348 times.
✗ Branch 2 not taken.
1348 bin.push_back(v);
241
1/2
✓ Branch 1 taken 1348 times.
✗ Branch 2 not taken.
1348 circ.substitute(sub, v, Circuit::VertexDeletion::No);
242 1348 }
243 TKET_ASSERT(bin.size() == 1);
244
1/2
✓ Branch 1 taken 1348 times.
✗ Branch 2 not taken.
1348 circ.remove_vertices(
245 bin, Circuit::GraphRewiring::No, Circuit::VertexDeletion::Yes);
246 1348 }
247
248 125 std::pair<Circuit, Complex> decompose_2cx_VD(const Eigen::Matrix4cd &U) {
249
1/2
✓ Branch 1 taken 125 times.
✗ Branch 2 not taken.
125 auto [V, z0] = decompose_VD(U);
250
1/2
✓ Branch 1 taken 125 times.
✗ Branch 2 not taken.
125 Circuit circ = two_qubit_canonical(V);
251
1/2
✓ Branch 1 taken 125 times.
✗ Branch 2 not taken.
125 replace_TK2_2CX(circ);
252
1/2
✓ Branch 1 taken 125 times.
✗ Branch 2 not taken.
250 return {circ, z0};
253 125 }
254
255 1223 std::pair<Circuit, Complex> decompose_2cx_DV(const Eigen::Matrix4cd &U) {
256
3/6
✓ Branch 1 taken 1223 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1223 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1223 times.
✗ Branch 8 not taken.
1223 auto [V, z0] = decompose_VD(U.adjoint());
257
1/2
✓ Branch 1 taken 1223 times.
✗ Branch 2 not taken.
1223 V.adjointInPlace();
258
1/2
✓ Branch 1 taken 1223 times.
✗ Branch 2 not taken.
1223 Circuit circ = two_qubit_canonical(V);
259
1/2
✓ Branch 1 taken 1223 times.
✗ Branch 2 not taken.
1223 replace_TK2_2CX(circ);
260
1/2
✓ Branch 2 taken 1223 times.
✗ Branch 3 not taken.
2446 return {circ, std::conj(z0)};
261 1223 }
262
263 586 Circuit phase_gadget(unsigned n_qubits, const Expr &t, CXConfigType cx_config) {
264 // Handle n_qubits==0 as a special case, or the calculations below
265 // go badly wrong.
266
1/2
✓ Branch 2 taken 586 times.
✗ Branch 3 not taken.
586 Circuit new_circ(n_qubits);
267
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 586 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 586 times.
586 if (n_qubits == 0) {
268 new_circ.add_phase(-t / 2);
269 return new_circ;
270 }
271
4/5
✓ Branch 0 taken 526 times.
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 20 times.
✓ Branch 3 taken 20 times.
✗ Branch 4 not taken.
586 switch (cx_config) {
272
1/1
✓ Decision 'true' taken 945 times.
526 case CXConfigType::Snake: {
273
2/2
✓ Branch 0 taken 419 times.
✓ Branch 1 taken 526 times.
2/2
✓ Decision 'true' taken 419 times.
✓ Decision 'false' taken 526 times.
945 for (unsigned i = n_qubits - 1; i != 0; --i) {
274 419 unsigned j = i - 1;
275
2/4
✓ Branch 3 taken 419 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 419 times.
✗ Branch 7 not taken.
419 new_circ.add_op<unsigned>(OpType::CX, {i, j});
276 }
277
2/4
✓ Branch 3 taken 526 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 526 times.
✗ Branch 7 not taken.
526 new_circ.add_op<unsigned>(OpType::Rz, t, {0});
278
2/2
✓ Branch 0 taken 419 times.
✓ Branch 1 taken 526 times.
2/2
✓ Decision 'true' taken 419 times.
✓ Decision 'false' taken 526 times.
945 for (unsigned i = 0; i != n_qubits - 1; ++i) {
279 419 unsigned j = i + 1;
280
2/4
✓ Branch 3 taken 419 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 419 times.
✗ Branch 7 not taken.
419 new_circ.add_op<unsigned>(OpType::CX, {j, i});
281 }
282 526 break;
283 }
284
1/1
✓ Decision 'true' taken 47 times.
20 case CXConfigType::Star: {
285
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 20 times.
2/2
✓ Decision 'true' taken 27 times.
✓ Decision 'false' taken 20 times.
47 for (unsigned i = n_qubits - 1; i != 0; --i) {
286
2/4
✓ Branch 3 taken 27 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 27 times.
✗ Branch 7 not taken.
27 new_circ.add_op<unsigned>(OpType::CX, {i, 0});
287 }
288
2/4
✓ Branch 3 taken 20 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 20 times.
✗ Branch 7 not taken.
20 new_circ.add_op<unsigned>(OpType::Rz, t, {0});
289
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 20 times.
2/2
✓ Decision 'true' taken 27 times.
✓ Decision 'false' taken 20 times.
47 for (unsigned i = 1; i != n_qubits; ++i) {
290
2/4
✓ Branch 3 taken 27 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 27 times.
✗ Branch 7 not taken.
27 new_circ.add_op<unsigned>(OpType::CX, {i, 0});
291 }
292 20 break;
293 }
294
1/1
✓ Decision 'true' taken 20 times.
20 case CXConfigType::Tree: {
295 20 unsigned complete_layers = floor(log2(n_qubits));
296 20 unsigned dense_end = pow(2, complete_layers);
297
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 20 times.
2/2
✓ Decision 'true' taken 3 times.
✓ Decision 'false' taken 20 times.
23 for (unsigned i = 0; i < n_qubits - dense_end; i++)
298
2/4
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
6 new_circ.add_op<unsigned>(
299 3 OpType::CX, {dense_end + i, dense_end - 1 - i});
300
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 20 times.
2/2
✓ Decision 'true' taken 18 times.
✓ Decision 'false' taken 20 times.
38 for (unsigned step_size = 1; step_size < dense_end; step_size *= 2) {
301
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 18 times.
2/2
✓ Decision 'true' taken 24 times.
✓ Decision 'false' taken 18 times.
42 for (unsigned i = 0; i < dense_end; i += 2 * step_size)
302
2/4
✓ Branch 3 taken 24 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 24 times.
✗ Branch 7 not taken.
24 new_circ.add_op<unsigned>(OpType::CX, {i + step_size, i});
303 }
304
2/4
✓ Branch 3 taken 20 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 20 times.
✗ Branch 7 not taken.
20 new_circ.add_op<unsigned>(OpType::Rz, t, {0});
305
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 20 times.
2/2
✓ Decision 'true' taken 18 times.
✓ Decision 'false' taken 20 times.
38 for (unsigned step_size = dense_end / 2; step_size >= 1; step_size /= 2) {
306
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 18 times.
2/2
✓ Decision 'true' taken 24 times.
✓ Decision 'false' taken 18 times.
42 for (unsigned i = 0; i < dense_end; i += 2 * step_size)
307
2/4
✓ Branch 3 taken 24 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 24 times.
✗ Branch 7 not taken.
24 new_circ.add_op<unsigned>(OpType::CX, {i + step_size, i});
308 }
309
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 20 times.
2/2
✓ Decision 'true' taken 3 times.
✓ Decision 'false' taken 20 times.
23 for (unsigned i = 0; i < n_qubits - dense_end; i++)
310
2/4
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
6 new_circ.add_op<unsigned>(
311 3 OpType::CX, {dense_end + i, dense_end - 1 - i});
312 20 break;
313 }
314
1/1
✓ Decision 'true' taken 20 times.
20 case CXConfigType::MultiQGate: {
315 20 std::vector<std::vector<unsigned>> conjugations;
316 20 int sign_correction = 1;
317
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 20 times.
2/2
✓ Decision 'true' taken 17 times.
✓ Decision 'false' taken 20 times.
37 for (int q = n_qubits - 1; q > 0; q -= 2) {
318
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 6 times.
2/2
✓ Decision 'true' taken 11 times.
✓ Decision 'false' taken 6 times.
17 if (q - 1 > 0) {
319 11 unsigned i = q, j = q - 1;
320 // this is only equal to the CX decompositions above
321 // up to phase, but phase differences are cancelled out by
322 // its dagger XXPhase(-1/2) below.
323
2/4
✓ Branch 3 taken 11 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 11 times.
✗ Branch 7 not taken.
11 new_circ.add_op<unsigned>(OpType::H, {i});
324
2/4
✓ Branch 3 taken 11 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 11 times.
✗ Branch 7 not taken.
11 new_circ.add_op<unsigned>(OpType::H, {j});
325
3/6
✓ Branch 3 taken 11 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 11 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 11 times.
✗ Branch 10 not taken.
11 new_circ.add_op<unsigned>(OpType::XXPhase3, 0.5, {i, j, 0});
326 11 sign_correction *= -1;
327
2/4
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 11 times.
✗ Branch 6 not taken.
11 conjugations.push_back({i, j, 0});
328 } else {
329 6 unsigned i = q;
330
2/4
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
6 new_circ.add_op<unsigned>(OpType::CX, {i, 0});
331
2/4
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 6 times.
✗ Branch 6 not taken.
6 conjugations.push_back({i, 0});
332 }
333 }
334
4/8
✓ Branch 3 taken 20 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 20 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 20 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 20 times.
✗ Branch 13 not taken.
20 new_circ.add_op<unsigned>(OpType::Rz, sign_correction * t, {0});
335
2/2
✓ Branch 5 taken 17 times.
✓ Branch 6 taken 20 times.
2/2
✓ Decision 'true' taken 17 times.
✓ Decision 'false' taken 20 times.
37 for (const auto &conj : conjugations) {
336
2/2
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 11 times.
2/2
✓ Decision 'true' taken 6 times.
✓ Decision 'false' taken 11 times.
17 if (conj.size() == 2) {
337
1/2
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 new_circ.add_op<unsigned>(OpType::CX, conj);
338 } else {
339 TKET_ASSERT(conj.size() == 3);
340
2/4
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 11 times.
✗ Branch 6 not taken.
11 new_circ.add_op<unsigned>(OpType::XXPhase3, -0.5, conj);
341
2/4
✓ Branch 4 taken 11 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 11 times.
✗ Branch 8 not taken.
11 new_circ.add_op<unsigned>(OpType::H, {conj[0]});
342
2/4
✓ Branch 4 taken 11 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 11 times.
✗ Branch 8 not taken.
11 new_circ.add_op<unsigned>(OpType::H, {conj[1]});
343 }
344 }
345 20 break;
346 20 }
347 }
348 586 return new_circ;
349 }
350
351 568 Circuit pauli_gadget(
352 const std::vector<Pauli> &paulis, const Expr &t, CXConfigType cx_config) {
353 568 unsigned n = paulis.size();
354
1/2
✓ Branch 2 taken 568 times.
✗ Branch 3 not taken.
568 Circuit circ(n);
355 568 std::vector<unsigned> qubits;
356
2/2
✓ Branch 0 taken 1141 times.
✓ Branch 1 taken 568 times.
2/2
✓ Decision 'true' taken 1141 times.
✓ Decision 'false' taken 568 times.
1709 for (unsigned i = 0; i < n; i++) {
357
4/5
✓ Branch 1 taken 194 times.
✓ Branch 2 taken 274 times.
✓ Branch 3 taken 167 times.
✓ Branch 4 taken 506 times.
✗ Branch 5 not taken.
1141 switch (paulis[i]) {
358
1/1
✓ Decision 'true' taken 194 times.
194 case Pauli::I:
359 194 break;
360
1/1
✓ Decision 'true' taken 274 times.
274 case Pauli::X:
361
2/4
✓ Branch 3 taken 274 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 274 times.
✗ Branch 7 not taken.
274 circ.add_op<unsigned>(OpType::H, {i});
362
1/2
✓ Branch 1 taken 274 times.
✗ Branch 2 not taken.
274 qubits.push_back(i);
363 274 break;
364
1/1
✓ Decision 'true' taken 167 times.
167 case Pauli::Y:
365
2/4
✓ Branch 3 taken 167 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 167 times.
✗ Branch 7 not taken.
167 circ.add_op<unsigned>(OpType::V, {i});
366
1/2
✓ Branch 1 taken 167 times.
✗ Branch 2 not taken.
167 qubits.push_back(i);
367 167 break;
368
1/1
✓ Decision 'true' taken 506 times.
506 case Pauli::Z:
369
1/2
✓ Branch 1 taken 506 times.
✗ Branch 2 not taken.
506 qubits.push_back(i);
370 506 break;
371 }
372 }
373
2/2
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 551 times.
2/2
✓ Decision 'true' taken 17 times.
✓ Decision 'false' taken 551 times.
568 if (qubits.empty()) {
374
4/8
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 17 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 17 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 17 times.
✗ Branch 11 not taken.
17 circ.add_phase(-t / 2);
375 } else {
376
1/2
✓ Branch 2 taken 551 times.
✗ Branch 3 not taken.
551 Vertex v = circ.add_op<unsigned>(OpType::PhaseGadget, t, qubits);
377
2/4
✓ Branch 1 taken 551 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 551 times.
✗ Branch 5 not taken.
551 Circuit cx_gadget = phase_gadget(circ.n_in_edges(v), t, cx_config);
378
4/8
✓ Branch 1 taken 551 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 551 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 551 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 551 times.
✗ Branch 12 not taken.
1102 Subcircuit sub = {circ.get_in_edges(v), circ.get_all_out_edges(v), {v}};
379
1/2
✓ Branch 1 taken 551 times.
✗ Branch 2 not taken.
551 circ.substitute(cx_gadget, sub, Circuit::VertexDeletion::Yes);
380
2/2
✓ Branch 0 taken 1109 times.
✓ Branch 1 taken 551 times.
2/2
✓ Decision 'true' taken 1109 times.
✓ Decision 'false' taken 551 times.
1660 for (unsigned i = 0; i < n; i++) {
381
4/5
✓ Branch 1 taken 162 times.
✓ Branch 2 taken 274 times.
✓ Branch 3 taken 167 times.
✓ Branch 4 taken 506 times.
✗ Branch 5 not taken.
1109 switch (paulis[i]) {
382
1/1
✓ Decision 'true' taken 162 times.
162 case Pauli::I:
383 162 break;
384
1/1
✓ Decision 'true' taken 274 times.
274 case Pauli::X:
385
2/4
✓ Branch 3 taken 274 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 274 times.
✗ Branch 7 not taken.
274 circ.add_op<unsigned>(OpType::H, {i});
386 274 break;
387
1/1
✓ Decision 'true' taken 167 times.
167 case Pauli::Y:
388
2/4
✓ Branch 3 taken 167 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 167 times.
✗ Branch 7 not taken.
167 circ.add_op<unsigned>(OpType::Vdg, {i});
389 167 break;
390
1/1
✓ Decision 'true' taken 506 times.
506 case Pauli::Z:
391 506 break;
392 }
393 }
394 551 }
395 1136 return circ;
396 568 }
397
398 4 void replace_CX_with_TK2(Circuit &c) {
399
4/8
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
4 static const Op_ptr cx = std::make_shared<Gate>(OpType::CX);
400
2/4
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
4 c.substitute_all(CircPool::CX_using_TK2(), cx);
401 4 }
402
403 1112 Circuit with_TK2(Gate_ptr op) {
404
1/2
✓ Branch 2 taken 1112 times.
✗ Branch 3 not taken.
1112 std::vector<Expr> params = op->get_params();
405
1/2
✓ Branch 2 taken 1112 times.
✗ Branch 3 not taken.
1112 unsigned n = op->n_qubits();
406
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1112 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 1112 times.
1112 if (n == 0) {
407 Circuit c(0);
408
0/2
✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
if (op->get_type() == OpType::Phase) {
409 c.add_phase(op->get_params()[0]);
410 }
411 return c;
412
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1112 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 1112 times.
1112 } else if (n == 1) {
413 Circuit c(1);
414 c.add_op(op, std::vector<unsigned>{0});
415 return c;
416
9/12
✓ Branch 1 taken 1107 times.
✓ Branch 2 taken 5 times.
✓ Branch 5 taken 1107 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1095 times.
✓ Branch 9 taken 12 times.
✓ Branch 10 taken 1107 times.
✓ Branch 11 taken 5 times.
✓ Branch 13 taken 1095 times.
✓ Branch 14 taken 17 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
2/2
✓ Decision 'true' taken 1095 times.
✓ Decision 'false' taken 17 times.
1112 } else if (n == 2 && op->free_symbols().empty()) {
417
2/4
✓ Branch 2 taken 1095 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1095 times.
✗ Branch 6 not taken.
1095 Eigen::Matrix4cd U = op->get_unitary();
418
1/2
✓ Branch 1 taken 1095 times.
✗ Branch 2 not taken.
1095 auto [K1, A, K2] = get_information_content(U);
419 // Decompose single qubits
420
1/2
✓ Branch 1 taken 1095 times.
✗ Branch 2 not taken.
1095 auto [K1a, K1b] = kronecker_decomposition(K1);
421
1/2
✓ Branch 1 taken 1095 times.
✗ Branch 2 not taken.
1095 auto [K2a, K2b] = kronecker_decomposition(K2);
422
1/2
✓ Branch 2 taken 1095 times.
✗ Branch 3 not taken.
1095 Circuit c(2);
423
1/2
✓ Branch 1 taken 1095 times.
✗ Branch 2 not taken.
1095 std::vector<double> angles_K1a = tk1_angles_from_unitary(K1a);
424
1/2
✓ Branch 1 taken 1095 times.
✗ Branch 2 not taken.
1095 std::vector<double> angles_K1b = tk1_angles_from_unitary(K1b);
425
1/2
✓ Branch 1 taken 1095 times.
✗ Branch 2 not taken.
1095 std::vector<double> angles_K2a = tk1_angles_from_unitary(K2a);
426
1/2
✓ Branch 1 taken 1095 times.
✗ Branch 2 not taken.
1095 std::vector<double> angles_K2b = tk1_angles_from_unitary(K2b);
427
3/6
✓ Branch 3 taken 1095 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 1095 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1095 times.
✗ Branch 11 not taken.
3285 c.add_op<unsigned>(
428 2190 OpType::TK1, {angles_K2a.begin(), angles_K2a.end() - 1}, {0});
429
3/6
✓ Branch 3 taken 1095 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 1095 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1095 times.
✗ Branch 11 not taken.
3285 c.add_op<unsigned>(
430 2190 OpType::TK1, {angles_K2b.begin(), angles_K2b.end() - 1}, {1});
431 1095 double alpha = std::get<0>(A);
432 1095 double beta = std::get<1>(A);
433 1095 double gamma = std::get<2>(A);
434
435
5/10
✓ Branch 1 taken 1095 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1095 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1095 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1095 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1095 times.
✗ Branch 14 not taken.
1095 c.append(CircPool::TK2_using_normalised_TK2(alpha, beta, gamma));
436
437
3/6
✓ Branch 3 taken 1095 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 1095 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1095 times.
✗ Branch 11 not taken.
3285 c.add_op<unsigned>(
438 2190 OpType::TK1, {angles_K1a.begin(), angles_K1a.end() - 1}, {0});
439
3/6
✓ Branch 3 taken 1095 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 1095 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1095 times.
✗ Branch 11 not taken.
3285 c.add_op<unsigned>(
440 2190 OpType::TK1, {angles_K1b.begin(), angles_K1b.end() - 1}, {1});
441
442 // Correct phase by computing the unitary and comparing with U:
443
1/2
✓ Branch 1 taken 1095 times.
✗ Branch 2 not taken.
1095 Eigen::Matrix4cd V_K1 = Eigen::KroneckerProduct(
444
8/16
✓ Branch 1 taken 1095 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1095 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1095 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1095 times.
✗ Branch 11 not taken.
✓ Branch 14 taken 1095 times.
✗ Branch 15 not taken.
✓ Branch 17 taken 1095 times.
✗ Branch 18 not taken.
✓ Branch 21 taken 4380 times.
✓ Branch 22 taken 1095 times.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
8760 get_matrix_from_tk1_angles(
445 3285 {angles_K1a[0], angles_K1a[1], angles_K1a[2], 0}),
446
8/16
✓ Branch 1 taken 1095 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1095 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1095 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1095 times.
✗ Branch 11 not taken.
✓ Branch 14 taken 1095 times.
✗ Branch 15 not taken.
✓ Branch 17 taken 1095 times.
✗ Branch 18 not taken.
✓ Branch 21 taken 4380 times.
✓ Branch 22 taken 1095 times.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
8760 get_matrix_from_tk1_angles(
447
1/2
✓ Branch 4 taken 1095 times.
✗ Branch 5 not taken.
4380 {angles_K1b[0], angles_K1b[1], angles_K1b[2], 0}));
448 Eigen::Matrix4cd V_A =
449
1/2
✓ Branch 1 taken 1095 times.
✗ Branch 2 not taken.
1095 internal::GateUnitaryMatrixImplementations::TK2(alpha, beta, gamma);
450
1/2
✓ Branch 1 taken 1095 times.
✗ Branch 2 not taken.
1095 Eigen::Matrix4cd V_K2 = Eigen::KroneckerProduct(
451
8/16
✓ Branch 1 taken 1095 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1095 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1095 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1095 times.
✗ Branch 11 not taken.
✓ Branch 14 taken 1095 times.
✗ Branch 15 not taken.
✓ Branch 17 taken 1095 times.
✗ Branch 18 not taken.
✓ Branch 21 taken 4380 times.
✓ Branch 22 taken 1095 times.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
8760 get_matrix_from_tk1_angles(
452 3285 {angles_K2a[0], angles_K2a[1], angles_K2a[2], 0}),
453
8/16
✓ Branch 1 taken 1095 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1095 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1095 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1095 times.
✗ Branch 11 not taken.
✓ Branch 14 taken 1095 times.
✗ Branch 15 not taken.
✓ Branch 17 taken 1095 times.
✗ Branch 18 not taken.
✓ Branch 21 taken 4380 times.
✓ Branch 22 taken 1095 times.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
8760 get_matrix_from_tk1_angles(
454
1/2
✓ Branch 4 taken 1095 times.
✗ Branch 5 not taken.
4380 {angles_K2b[0], angles_K2b[1], angles_K2b[2], 0}));
455
3/6
✓ Branch 1 taken 1095 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1095 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1095 times.
✗ Branch 8 not taken.
1095 Eigen::Matrix4cd V = V_K1 * V_A * V_K2;
456
3/6
✓ Branch 1 taken 1095 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1095 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1095 times.
✗ Branch 8 not taken.
1095 Eigen::Matrix4cd R = V.adjoint() * U;
457
1/2
✓ Branch 1 taken 1095 times.
✗ Branch 2 not taken.
1095 const Complex phase = R(0, 0); // R = phase * I
458
2/4
✓ Branch 2 taken 1095 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1095 times.
✗ Branch 6 not taken.
1095 c.add_phase(arg(phase) / PI);
459
460
1/2
✓ Branch 1 taken 1095 times.
✗ Branch 2 not taken.
1095 return c;
461 1095 }
462 // Now the non-trivial cases.
463
14/15
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 1 times.
✓ Branch 9 taken 1 times.
✓ Branch 10 taken 1 times.
✓ Branch 11 taken 1 times.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 1 times.
✓ Branch 14 taken 1 times.
✓ Branch 15 taken 4 times.
✗ Branch 16 not taken.
17 switch (op->get_type()) {
464
1/1
✓ Decision 'true' taken 1 times.
1 case OpType::ISWAP:
465
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 return CircPool::ISWAP_using_TK2(params[0]);
466
1/1
✓ Decision 'true' taken 1 times.
1 case OpType::PhasedISWAP:
467
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 return CircPool::PhasedISWAP_using_TK2(params[0], params[1]);
468
1/1
✓ Decision 'true' taken 1 times.
1 case OpType::XXPhase:
469
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 return CircPool::XXPhase_using_TK2(params[0]);
470
1/1
✓ Decision 'true' taken 1 times.
1 case OpType::YYPhase:
471
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 return CircPool::YYPhase_using_TK2(params[0]);
472
1/1
✓ Decision 'true' taken 1 times.
1 case OpType::ZZPhase:
473
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 return CircPool::ZZPhase_using_TK2(params[0]);
474
1/1
✓ Decision 'true' taken 1 times.
1 case OpType::NPhasedX:
475
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 return CircPool::NPhasedX_using_PhasedX(n, params[0], params[1]);
476
1/1
✓ Decision 'true' taken 1 times.
1 case OpType::ESWAP:
477
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 return CircPool::ESWAP_using_TK2(params[0]);
478
1/1
✓ Decision 'true' taken 1 times.
1 case OpType::FSim:
479
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 return CircPool::FSim_using_TK2(params[0], params[1]);
480
1/1
✓ Decision 'true' taken 1 times.
1 case OpType::CRx:
481
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 return CircPool::CRx_using_TK2(params[0]);
482
1/1
✓ Decision 'true' taken 1 times.
1 case OpType::CRy:
483
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 return CircPool::CRy_using_TK2(params[0]);
484
1/1
✓ Decision 'true' taken 1 times.
1 case OpType::CRz:
485
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 return CircPool::CRz_using_TK2(params[0]);
486
1/1
✓ Decision 'true' taken 1 times.
1 case OpType::CU1:
487
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 return CircPool::CU1_using_TK2(params[0]);
488
1/1
✓ Decision 'true' taken 1 times.
1 case OpType::XXPhase3:
489
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 return CircPool::XXPhase3_using_TK2(params[0]);
490 4 case OpType::CCX:
491 case OpType::CSWAP:
492 case OpType::BRIDGE:
493 case OpType::CU3:
494 case OpType::PhaseGadget: {
495 // As a first, inefficient, solution, decompose these into CX and then
496 // replace each CX with a TK2 (and some single-qubit gates).
497 // TODO Find more efficient decompositions for these gates.
498
1/2
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 Circuit c = with_CX(op);
499
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 replace_CX_with_TK2(c);
500
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 return c;
501 4 }
502
0/1
✗ Decision 'true' not taken.
default:
503 throw CircuitInvalidity("Cannot decompose " + op->get_name());
504 }
505 1112 }
506
507 21885 Circuit with_CX(Gate_ptr op) {
508 21885 OpType optype = op->get_type();
509
1/2
✓ Branch 2 taken 21885 times.
✗ Branch 3 not taken.
21885 std::vector<Expr> params = op->get_params();
510
1/2
✓ Branch 2 taken 21885 times.
✗ Branch 3 not taken.
21885 unsigned n = op->n_qubits();
511
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 21884 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 21884 times.
21885 if (n == 0) {
512
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 Circuit c(0);
513
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1/2
✓ Decision 'true' taken 1 times.
✗ Decision 'false' not taken.
1 if (op->get_type() == OpType::Phase) {
514
3/6
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
1 c.add_phase(op->get_params()[0]);
515 }
516
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 return c;
517
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 21884 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 21885 times.
21885 } else if (n == 1) {
518 Circuit c(1);
519 c.add_op(op, std::vector<unsigned>{0});
520 return c;
521 }
522
31/33
✗ Branch 0 not taken.
✓ Branch 1 taken 212 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 150 times.
✓ Branch 4 taken 10 times.
✓ Branch 5 taken 6 times.
✓ Branch 6 taken 4 times.
✓ Branch 7 taken 6 times.
✓ Branch 8 taken 4 times.
✓ Branch 9 taken 4107 times.
✓ Branch 10 taken 4256 times.
✓ Branch 11 taken 4380 times.
✓ Branch 12 taken 4331 times.
✓ Branch 13 taken 4137 times.
✓ Branch 14 taken 7 times.
✓ Branch 15 taken 5 times.
✓ Branch 16 taken 4 times.
✓ Branch 17 taken 2 times.
✓ Branch 18 taken 18 times.
✓ Branch 19 taken 3 times.
✓ Branch 20 taken 171 times.
✓ Branch 21 taken 9 times.
✓ Branch 22 taken 3 times.
✓ Branch 23 taken 9 times.
✓ Branch 24 taken 30 times.
✓ Branch 25 taken 3 times.
✓ Branch 26 taken 1 times.
✓ Branch 27 taken 1 times.
✓ Branch 28 taken 3 times.
✓ Branch 29 taken 2 times.
✓ Branch 30 taken 3 times.
✓ Branch 31 taken 1 times.
✗ Branch 32 not taken.
21884 switch (optype) {
523
0/1
✗ Decision 'true' not taken.
case OpType::CX: {
524 Circuit c(2);
525 c.add_op(op, std::vector<unsigned>{0, 1});
526 return c;
527 }
528
1/1
✓ Decision 'true' taken 212 times.
212 case OpType::CCX:
529
2/4
✓ Branch 1 taken 212 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 212 times.
✗ Branch 5 not taken.
212 return CircPool::CCX_normal_decomp();
530
1/1
✓ Decision 'true' taken 6 times.
6 case OpType::CY:
531
2/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
6 return CircPool::CY_using_CX();
532
1/1
✓ Decision 'true' taken 150 times.
150 case OpType::CZ:
533
2/4
✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 150 times.
✗ Branch 5 not taken.
150 return CircPool::CZ_using_CX();
534
1/1
✓ Decision 'true' taken 10 times.
10 case OpType::CH:
535
2/4
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
10 return CircPool::CH_using_CX();
536
1/1
✓ Decision 'true' taken 6 times.
6 case OpType::CV:
537
2/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
6 return CircPool::CV_using_CX();
538
1/1
✓ Decision 'true' taken 4 times.
4 case OpType::CVdg:
539
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
4 return CircPool::CVdg_using_CX();
540
1/1
✓ Decision 'true' taken 6 times.
6 case OpType::CSX:
541
2/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
6 return CircPool::CSX_using_CX();
542
1/1
✓ Decision 'true' taken 4 times.
4 case OpType::CSXdg:
543
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
4 return CircPool::CSXdg_using_CX();
544
1/1
✓ Decision 'true' taken 4107 times.
4107 case OpType::CRz:
545
1/2
✓ Branch 2 taken 4107 times.
✗ Branch 3 not taken.
4107 return CircPool::CRz_using_CX(params[0]);
546
1/1
✓ Decision 'true' taken 4256 times.
4256 case OpType::CRx:
547
1/2
✓ Branch 2 taken 4256 times.
✗ Branch 3 not taken.
4256 return CircPool::CRx_using_CX(params[0]);
548
1/1
✓ Decision 'true' taken 4380 times.
4380 case OpType::CRy:
549
1/2
✓ Branch 2 taken 4380 times.
✗ Branch 3 not taken.
4380 return CircPool::CRy_using_CX(params[0]);
550
1/1
✓ Decision 'true' taken 4331 times.
4331 case OpType::CU1:
551
1/2
✓ Branch 2 taken 4331 times.
✗ Branch 3 not taken.
4331 return CircPool::CU1_using_CX(params[0]);
552
1/1
✓ Decision 'true' taken 4137 times.
4137 case OpType::CU3:
553
1/2
✓ Branch 4 taken 4137 times.
✗ Branch 5 not taken.
4137 return CircPool::CU3_using_CX(params[0], params[1], params[2]);
554
1/1
✓ Decision 'true' taken 7 times.
7 case OpType::PhaseGadget:
555
1/2
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
7 return phase_gadget(n, params[0], CXConfigType::Snake);
556
1/1
✓ Decision 'true' taken 5 times.
5 case OpType::SWAP:
557
2/4
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
5 return CircPool::SWAP_using_CX_0();
558
1/1
✓ Decision 'true' taken 4 times.
4 case OpType::CSWAP:
559
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
4 return CircPool::CSWAP_using_CX();
560
1/1
✓ Decision 'true' taken 2 times.
2 case OpType::BRIDGE:
561
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
2 return CircPool::BRIDGE_using_CX_0();
562
1/1
✓ Decision 'true' taken 18 times.
18 case OpType::ECR:
563
2/4
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
18 return CircPool::ECR_using_CX();
564
1/1
✓ Decision 'true' taken 3 times.
3 case OpType::ISWAP:
565
1/2
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 return CircPool::ISWAP_using_CX(params[0]);
566
1/1
✓ Decision 'true' taken 171 times.
171 case OpType::ZZMax:
567
2/4
✓ Branch 1 taken 171 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 171 times.
✗ Branch 5 not taken.
171 return CircPool::ZZMax_using_CX();
568
1/1
✓ Decision 'true' taken 9 times.
9 case OpType::XXPhase:
569
1/2
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
9 return CircPool::XXPhase_using_CX(params[0]);
570
1/1
✓ Decision 'true' taken 3 times.
3 case OpType::YYPhase:
571
1/2
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 return CircPool::YYPhase_using_CX(params[0]);
572
1/1
✓ Decision 'true' taken 9 times.
9 case OpType::ZZPhase:
573
1/2
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
9 return CircPool::ZZPhase_using_CX(params[0]);
574
1/1
✓ Decision 'true' taken 30 times.
30 case OpType::TK2:
575
1/2
✓ Branch 4 taken 30 times.
✗ Branch 5 not taken.
30 return CircPool::TK2_using_CX(params[0], params[1], params[2]);
576
1/1
✓ Decision 'true' taken 3 times.
3 case OpType::XXPhase3:
577
1/2
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 return CircPool::XXPhase3_using_CX(params[0]);
578
1/1
✓ Decision 'true' taken 1 times.
1 case OpType::ESWAP:
579
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 return CircPool::ESWAP_using_CX(params[0]);
580
1/1
✓ Decision 'true' taken 1 times.
1 case OpType::FSim:
581
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 return CircPool::FSim_using_CX(params[0], params[1]);
582
1/1
✓ Decision 'true' taken 3 times.
3 case OpType::Sycamore:
583
3/6
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
3 return CircPool::FSim_using_CX(1. / 2., 1. / 6.);
584
1/1
✓ Decision 'true' taken 2 times.
2 case OpType::ISWAPMax:
585
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
2 return CircPool::ISWAP_using_CX(1.);
586
1/1
✓ Decision 'true' taken 3 times.
3 case OpType::PhasedISWAP:
587
1/2
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
3 return CircPool::PhasedISWAP_using_CX(params[0], params[1]);
588
1/1
✓ Decision 'true' taken 1 times.
1 case OpType::NPhasedX:
589
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 return CircPool::NPhasedX_using_PhasedX(n, params[0], params[1]);
590
0/1
✗ Decision 'true' not taken.
default:
591 throw CircuitInvalidity("Cannot decompose " + op->get_name());
592 }
593 21885 }
594
595 #define CNXTYPE(n) \
596 (((n) == 2) ? OpType::CX : ((n) == 3) ? OpType::CCX : OpType::CnX)
597 #define CNZTYPE(n) (((n) == 2) ? OpType::CZ : OpType::CnZ)
598 #define CNYTYPE(n) (((n) == 2) ? OpType::CY : OpType::CnY)
599 #define CNRYTYPE(n) (((n) == 2) ? OpType::CRy : OpType::CnRy)
600 /**
601 * Construct a circuit representing CnU1.
602 */
603 8 static Circuit CnU1(unsigned n_controls, Expr lambda) {
604
2/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
8 Gate_ptr u1_gate = as_gate_ptr(get_op_ptr(OpType::U1, lambda));
605 // Use the gray code method if lambda contains symbols
606 // The gray code decomp also produces less CXs when n_controls is 3 or 4
607
5/10
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 8 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 8 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 8 times.
8 if (eval_expr(lambda) == std::nullopt || n_controls == 3 || n_controls == 4) {
608 return CircPool::CnU_gray_code_decomp(n_controls, u1_gate);
609 } else {
610 return CircPool::CnU_linear_depth_decomp(
611
3/6
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 8 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 8 times.
✗ Branch 9 not taken.
8 n_controls, u1_gate->get_unitary());
612 }
613 8 }
614
615 1 static Circuit with_controls_symbolic(const Circuit &c, unsigned n_controls) {
616
5/10
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 1 times.
1 if (c.n_bits() != 0 || !c.is_simple()) {
617 throw CircuitInvalidity("Only default qubit register allowed");
618 }
619
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 1 times.
1 if (c.has_implicit_wireswaps()) {
620 throw CircuitInvalidity("Circuit has implicit wireswaps");
621 }
622
623 // Dispose of the trivial case
624
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 1 times.
1 if (n_controls == 0) {
625 return c;
626 }
627
628 static const OpTypeSet multiq_gate_set = {
629 OpType::CX, OpType::CCX, OpType::CnX, OpType::CRy, OpType::CnRy,
630
3/8
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
1 OpType::CZ, OpType::CnZ, OpType::CY, OpType::CnY};
631
632
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 unsigned c_n_qubits = c.n_qubits();
633
634 // 1. Rebase to {CX, CCX, CnX, CnRy} and single-qubit gates
635
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 Circuit c1(c);
636 1 VertexList bin;
637
7/8
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 1 times.
✓ Branch 8 taken 3 times.
✓ Branch 9 taken 1 times.
✓ Branch 11 taken 1 times.
✓ Branch 12 taken 1 times.
5 BGL_FORALL_VERTICES(v, c1.dag, DAG) {
638
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 Op_ptr op = c1.get_Op_ptr_from_Vertex(v);
639 3 OpType optype = op->get_type();
640
3/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 2 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 2 times.
3 if (is_gate_type(optype)) {
641
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 1 times.
1 if (is_projective_type(optype)) {
642 throw CircuitInvalidity("Projective operations present");
643 }
644
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 1 times.
1 if (is_box_type(optype)) {
645 throw CircuitInvalidity("Undecomposed boxes present");
646 }
647
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1/2
✓ Decision 'true' taken 1 times.
✗ Decision 'false' not taken.
1 if (is_single_qubit_type(optype)) {
648 1 continue;
649 }
650
0/2
✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
if (multiq_gate_set.find(optype) != multiq_gate_set.end()) {
651 continue;
652 }
653 Circuit replacement = with_CX(as_gate_ptr(op));
654 c1.substitute(replacement, v, Circuit::VertexDeletion::No);
655 bin.push_back(v);
656 }
657
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
3 }
658
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 c1.remove_vertices(
659 bin, Circuit::GraphRewiring::No, Circuit::VertexDeletion::Yes);
660
661 // Capture the phase. We may adjust this during replacements below.
662
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 Expr a = c1.get_phase();
663
664 // 2. Replace all gates with controlled versions
665
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 Circuit c2(n_controls + c_n_qubits);
666
5/8
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 1 times.
✓ Branch 12 taken 1 times.
0/1
? Decision couldn't be analyzed.
2 for (Circuit::CommandIterator cit = c1.begin(); cit != c1.end(); ++cit) {
667 1 Op_ptr op = cit->get_op_ptr();
668
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 unit_vector_t args = cit->get_args();
669 1 unsigned n_args = args.size();
670 1 unsigned n_new_args = n_controls + n_args;
671
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 qubit_vector_t new_args(n_new_args);
672
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 1 times.
2 for (unsigned i = 0; i < n_controls; i++) {
673
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 new_args[i] = Qubit(i);
674 }
675
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 1 times.
2 for (unsigned i = 0; i < n_args; i++) {
676
2/4
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
1 new_args[n_controls + i] = Qubit(n_controls + args[i].index()[0]);
677 }
678 1 OpType optype = op->get_type();
679
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 std::vector<Expr> params = op->get_params();
680
1/6
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
1 switch (optype) {
681
0/1
✗ Decision 'true' not taken.
case OpType::noop:
682 break;
683 case OpType::X:
684 case OpType::CX:
685 case OpType::CCX:
686 case OpType::CnX:
687 c2.add_op<Qubit>(CNXTYPE(n_new_args), new_args);
688 break;
689 case OpType::Ry:
690 case OpType::CRy:
691 case OpType::CnRy:
692 c2.add_op<Qubit>(CNRYTYPE(n_new_args), params, new_args);
693 break;
694 case OpType::Z:
695 case OpType::CZ:
696 case OpType::CnZ:
697 c2.add_op<Qubit>(CNZTYPE(n_new_args), new_args);
698 break;
699 case OpType::Y:
700 case OpType::CY:
701 case OpType::CnY:
702 c2.add_op<Qubit>(CNYTYPE(n_new_args), new_args);
703 break;
704
1/1
✓ Decision 'true' taken 2 times.
1 default: {
705
2/4
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
2 std::vector<Expr> tk1_angles = as_gate_ptr(op)->get_tk1_angles();
706
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 Expr theta = tk1_angles[1];
707
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
1 Expr phi = tk1_angles[0] - 0.5;
708
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
1 Expr lambda = tk1_angles[2] + 0.5;
709
4/8
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
2 Expr t = tk1_angles[3] - 0.5 * (tk1_angles[0] + tk1_angles[2]);
710 // Operation is U3(theta, phi, lambda) + phase t.
711 // First absorb t in the overall phase.
712
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 a += t;
713 // Construct a multi-controlled U3, by extending the standard
714 // CU3-to-CX decomposition.
715 1 Qubit target = new_args[n_controls];
716
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.
2 Circuit cnu1 = CnU1(n_controls - 1, 0.5 * (lambda + phi));
717
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 c2.append(cnu1);
718
7/14
✓ 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.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 1 times.
✗ Branch 17 not taken.
✓ Branch 23 taken 1 times.
✓ Branch 24 taken 1 times.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
2 c2.add_op<Qubit>(OpType::U1, 0.5 * (lambda - phi), {target});
719
2/6
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
1 c2.add_op<Qubit>(CNXTYPE(n_new_args), new_args);
720
12/24
✓ 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.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 1 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 1 times.
✗ Branch 20 not taken.
✓ Branch 23 taken 1 times.
✗ Branch 24 not taken.
✓ Branch 26 taken 1 times.
✗ Branch 27 not taken.
✓ Branch 30 taken 3 times.
✓ Branch 31 taken 1 times.
✓ Branch 36 taken 1 times.
✓ Branch 37 taken 1 times.
✗ Branch 42 not taken.
✗ Branch 43 not taken.
✗ Branch 49 not taken.
✗ Branch 50 not taken.
7 c2.add_op<Qubit>(
721
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 OpType::U3, {-0.5 * theta, 0, -0.5 * (lambda + phi)}, {target});
722
2/6
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
1 c2.add_op<Qubit>(CNXTYPE(n_new_args), new_args);
723
11/22
✓ 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.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 1 times.
✗ Branch 17 not taken.
✓ Branch 20 taken 1 times.
✗ Branch 21 not taken.
✓ Branch 23 taken 1 times.
✗ Branch 24 not taken.
✓ Branch 27 taken 3 times.
✓ Branch 28 taken 1 times.
✓ Branch 33 taken 1 times.
✓ Branch 34 taken 1 times.
✗ Branch 39 not taken.
✗ Branch 40 not taken.
✗ Branch 45 not taken.
✗ Branch 46 not taken.
5 c2.add_op<Qubit>(OpType::U3, {0.5 * theta, phi, 0}, {target});
724 1 } break;
725 }
726 2 }
727
728 // 3. Account for phase by appending a CnU1 to the control qubits.
729
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 1 times.
1 if (!equiv_0(a)) {
730 Circuit cnu1 = CnU1(n_controls - 1, a);
731 c2.append(cnu1);
732 }
733
734
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 c2.remove_noops();
735
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 return c2;
736 1 }
737
738 // Return the target unitary given a Cn* gate where n >= 0
739 81 static Eigen::Matrix2cd get_target_op_matrix(const Op_ptr &op) {
740 81 OpType optype = op->get_type();
741
1/2
✓ Branch 1 taken 81 times.
✗ Branch 2 not taken.
81 Eigen::Matrix2cd m;
742
6/14
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 4 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 2 times.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 55 times.
81 switch (optype) {
743 18 case OpType::CX:
744 case OpType::CCX:
745 case OpType::CnX:
746
3/6
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 18 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 18 times.
✗ Branch 9 not taken.
36 return Gate(OpType::X, {}, 1).get_unitary();
747
0/1
✗ Decision 'true' not taken.
case OpType::CSX:
748 return Gate(OpType::SX, {}, 1).get_unitary();
749
0/1
✗ Decision 'true' not taken.
case OpType::CSXdg:
750 return Gate(OpType::SXdg, {}, 1).get_unitary();
751
0/1
✗ Decision 'true' not taken.
case OpType::CV:
752 return Gate(OpType::V, {}, 1).get_unitary();
753
0/1
✗ Decision 'true' not taken.
case OpType::CVdg:
754 return Gate(OpType::Vdg, {}, 1).get_unitary();
755
0/1
✗ Decision 'true' not taken.
case OpType::CRx:
756 return Gate(OpType::Rx, op->get_params(), 1).get_unitary();
757 case OpType::CnRy:
758 case OpType::CRy:
759 return Gate(OpType::Ry, op->get_params(), 1).get_unitary();
760 1 case OpType::CY:
761 case OpType::CnY:
762
3/6
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
2 return Gate(OpType::Y, {}, 1).get_unitary();
763
0/1
✗ Decision 'true' not taken.
case OpType::CRz:
764 return Gate(OpType::Rz, op->get_params(), 1).get_unitary();
765 4 case OpType::CZ:
766 case OpType::CnZ:
767
3/6
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 4 times.
✗ Branch 9 not taken.
8 return Gate(OpType::Z, {}, 1).get_unitary();
768
0/1
✗ Decision 'true' not taken.
case OpType::CH:
769 return Gate(OpType::H, {}, 1).get_unitary();
770
1/1
✓ Decision 'true' taken 4 times.
2 case OpType::CU1:
771
4/8
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 2 times.
✗ Branch 12 not taken.
4 return Gate(OpType::U1, op->get_params(), 1).get_unitary();
772
1/1
✓ Decision 'true' taken 2 times.
1 case OpType::CU3:
773
4/8
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 1 times.
✗ Branch 12 not taken.
2 return Gate(OpType::U3, op->get_params(), 1).get_unitary();
774
1/1
✓ Decision 'true' taken 55 times.
55 default:
775
5/10
✓ Branch 1 taken 55 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 55 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 55 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 55 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 55 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 55 times.
55 if (!is_gate_type(optype) || op->n_qubits() != 1) {
776 throw CircuitInvalidity(
777 "Cannot get the target unitary of " + op->get_name());
778 }
779
3/6
✓ Branch 2 taken 55 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 55 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 55 times.
✗ Branch 10 not taken.
110 return as_gate_ptr(op)->get_unitary();
780 }
781 }
782
783 // A gate block containing Cn* gates that can be merged as a single CnU gate
784 struct CnGateBlock {
785 enum class MergeMode { append, prepend };
786 81 CnGateBlock(const Command &command) {
787 // Assumes the color of the target is not identity
788 81 Op_ptr op = command.get_op_ptr();
789
1/2
✓ Branch 1 taken 81 times.
✗ Branch 2 not taken.
81 ops.push_back(op);
790
1/2
✓ Branch 1 taken 81 times.
✗ Branch 2 not taken.
81 unit_vector_t args = command.get_args();
791 TKET_ASSERT(!args.empty());
792
2/2
✓ Branch 1 taken 34 times.
✓ Branch 2 taken 81 times.
2/2
✓ Decision 'true' taken 34 times.
✓ Decision 'false' taken 81 times.
115 for (unsigned i = 0; i < args.size() - 1; i++) {
793
2/4
✓ Branch 2 taken 34 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 34 times.
✗ Branch 7 not taken.
34 control_qubits.insert(args[i].index()[0]);
794 }
795
1/2
✓ Branch 2 taken 81 times.
✗ Branch 3 not taken.
81 target_qubit = args.back().index()[0];
796 81 is_symmetric =
797
6/6
✓ Branch 2 taken 78 times.
✓ Branch 3 taken 3 times.
✓ Branch 6 taken 77 times.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 2 times.
✓ Branch 9 taken 75 times.
158 (op->get_type() == OpType::CZ || op->get_type() == OpType::CnZ ||
798 77 op->get_type() == OpType::CU1);
799
2/4
✓ Branch 2 taken 81 times.
✗ Branch 3 not taken.
✓ Branch 7 taken 81 times.
✗ Branch 8 not taken.
81 color = as_gate_ptr(op)->commuting_basis(args.size() - 1);
800
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 81 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 81 times.
81 if (color == Pauli::I) {
801 throw std::invalid_argument(
802 "CnGateBlock doesn't accept multi-controlled identity gate.");
803 }
804 81 }
805
806 // Check whether commute with another CnGateBlock
807 115 bool commutes_with(const CnGateBlock &other) {
808
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 82 times.
2/2
✓ Decision 'true' taken 33 times.
✓ Decision 'false' taken 82 times.
115 if (target_qubit == other.target_qubit) {
809
4/4
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 24 times.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 1 times.
33 return (color == other.color && color != std::nullopt);
810 }
811
5/6
✓ Branch 1 taken 82 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 21 times.
✓ Branch 4 taken 61 times.
✓ Branch 5 taken 13 times.
✓ Branch 6 taken 8 times.
2/2
✓ Decision 'true' taken 13 times.
✓ Decision 'false' taken 90 times.
103 if (control_qubits.contains(other.target_qubit) &&
812
2/2
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 69 times.
103 other.color != Pauli::Z) {
813 13 return false;
814 }
815
7/8
✓ Branch 1 taken 69 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 27 times.
✓ Branch 4 taken 42 times.
✓ Branch 6 taken 18 times.
✓ Branch 7 taken 9 times.
✓ Branch 8 taken 18 times.
✓ Branch 9 taken 51 times.
2/2
✓ Decision 'true' taken 18 times.
✓ Decision 'false' taken 51 times.
69 if (other.control_qubits.contains(target_qubit) && color != Pauli::Z) {
816 18 return false;
817 }
818 51 return true;
819 }
820
821 // Check whether can be merged with another CnGateBlock
822 138 bool is_mergeable_with(const CnGateBlock &other) {
823 // check if sizes match
824
2/2
✓ Branch 2 taken 79 times.
✓ Branch 3 taken 59 times.
2/2
✓ Decision 'true' taken 79 times.
✓ Decision 'false' taken 59 times.
138 if (control_qubits.size() != other.control_qubits.size()) {
825 79 return false;
826 }
827 // check if they act on the same set of qubits
828
1/2
✓ Branch 1 taken 59 times.
✗ Branch 2 not taken.
59 std::set<unsigned> args_a = control_qubits;
829
1/2
✓ Branch 1 taken 59 times.
✗ Branch 2 not taken.
59 args_a.insert(target_qubit);
830
1/2
✓ Branch 1 taken 59 times.
✗ Branch 2 not taken.
59 std::set<unsigned> args_b = other.control_qubits;
831
1/2
✓ Branch 1 taken 59 times.
✗ Branch 2 not taken.
59 args_b.insert(other.target_qubit);
832
3/4
✓ Branch 1 taken 59 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 34 times.
✓ Branch 4 taken 25 times.
2/2
✓ Decision 'true' taken 34 times.
✓ Decision 'false' taken 25 times.
59 if (args_a != args_b) {
833 34 return false;
834 }
835 // false if target don't match and none of them is symmetric
836
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 21 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 1 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 23 times.
25 if (target_qubit != other.target_qubit && !is_symmetric &&
837
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 !other.is_symmetric) {
838 2 return false;
839 }
840 23 return true;
841 59 }
842
843 // Merge with another CnGateBlock
844 23 void merge(CnGateBlock &other, const MergeMode &mode) {
845
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 19 times.
2/2
✓ Decision 'true' taken 4 times.
✓ Decision 'false' taken 19 times.
23 if (mode == MergeMode::append) {
846
1/2
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
4 ops.insert(ops.end(), other.ops.begin(), other.ops.end());
847 } else {
848
1/2
✓ Branch 5 taken 19 times.
✗ Branch 6 not taken.
19 ops.insert(ops.begin(), other.ops.begin(), other.ops.end());
849 }
850
2/2
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 12 times.
23 color = (color != other.color) ? std::nullopt : color;
851
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 19 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 1 times.
2/2
✓ Decision 'true' taken 3 times.
✓ Decision 'false' taken 20 times.
23 if (is_symmetric && !other.is_symmetric) {
852 3 control_qubits = other.control_qubits;
853 3 target_qubit = other.target_qubit;
854 3 is_symmetric = false;
855 }
856 // empty the other CnGateBlock
857 23 other.ops.clear();
858 23 }
859
860 58 Eigen::Matrix2cd get_target_unitary() const {
861
1/2
✓ Branch 2 taken 58 times.
✗ Branch 3 not taken.
58 Eigen::Matrix2cd m = Eigen::Matrix2cd::Identity();
862
2/2
✓ Branch 4 taken 81 times.
✓ Branch 5 taken 58 times.
2/2
✓ Decision 'true' taken 81 times.
✓ Decision 'false' taken 58 times.
139 for (const Op_ptr &op : ops) {
863
3/6
✓ Branch 1 taken 81 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 81 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 81 times.
✗ Branch 8 not taken.
81 m = get_target_op_matrix(op) * m;
864 }
865 58 return m;
866 }
867
868 // ops in the block
869 std::vector<Op_ptr> ops;
870 // target qubit index
871 unsigned target_qubit;
872 // control indices
873 std::set<unsigned> control_qubits;
874 // whether the target can act on any of its qubits
875 bool is_symmetric;
876 // color of the target qubit
877 std::optional<Pauli> color;
878 };
879
880 // Construct a controlled version of a given circuit
881 // with the assumption that the circuit does not have symbols.
882 27 static Circuit with_controls_numerical(const Circuit &c, unsigned n_controls) {
883
5/10
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 27 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 27 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 27 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 27 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 27 times.
27 if (c.n_bits() != 0 || !c.is_simple()) {
884 throw CircuitInvalidity("Only default qubit register allowed");
885 }
886
2/4
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 27 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 27 times.
27 if (c.has_implicit_wireswaps()) {
887 throw CircuitInvalidity("Circuit has implicit wireswaps");
888 }
889
890 // Dispose of the trivial case
891
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 27 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 27 times.
27 if (n_controls == 0) {
892 return c;
893 }
894 // 1. Rebase to Cn* gates (n=0 for single qubit gates)
895
1/2
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
27 Circuit c1(c);
896 27 VertexList bin;
897
7/8
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 188 times.
✓ Branch 6 taken 27 times.
✓ Branch 8 taken 188 times.
✓ Branch 9 taken 27 times.
✓ Branch 11 taken 27 times.
✓ Branch 12 taken 27 times.
242 BGL_FORALL_VERTICES(v, c1.dag, DAG) {
898
1/2
✓ Branch 1 taken 188 times.
✗ Branch 2 not taken.
188 Op_ptr op = c1.get_Op_ptr_from_Vertex(v);
899 188 OpType optype = op->get_type();
900
3/4
✓ Branch 1 taken 188 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 86 times.
✓ Branch 4 taken 102 times.
2/2
✓ Decision 'true' taken 86 times.
✓ Decision 'false' taken 102 times.
188 if (is_gate_type(optype)) {
901
2/4
✓ Branch 1 taken 86 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 86 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 86 times.
86 if (is_projective_type(optype)) {
902 throw CircuitInvalidity("Projective operations present");
903 }
904
2/4
✓ Branch 1 taken 86 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 86 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 86 times.
86 if (is_box_type(optype)) {
905 throw CircuitInvalidity("Undecomposed boxes present");
906 }
907
8/10
✓ Branch 1 taken 86 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 31 times.
✓ Branch 4 taken 55 times.
✓ Branch 6 taken 31 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 26 times.
✓ Branch 9 taken 5 times.
✓ Branch 10 taken 81 times.
✓ Branch 11 taken 5 times.
2/2
✓ Decision 'true' taken 81 times.
✓ Decision 'false' taken 5 times.
86 if (is_single_qubit_type(optype) || is_controlled_gate_type(optype)) {
908 81 continue;
909 }
910
2/4
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 5 times.
✗ Branch 6 not taken.
10 Circuit replacement = with_CX(as_gate_ptr(op));
911
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 c1.substitute(replacement, v, Circuit::VertexDeletion::No);
912
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 bin.push_back(v);
913
3/4
✓ Branch 1 taken 51 times.
✓ Branch 2 taken 51 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 51 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 107 times.
107 } else if (optype != OpType::Input && optype != OpType::Output) {
914 throw CircuitInvalidity(
915 "Cannot construct the controlled version of " + op->get_name());
916 }
917
2/2
✓ Branch 1 taken 107 times.
✓ Branch 2 taken 81 times.
188 }
918
1/2
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
27 c1.remove_vertices(
919 bin, Circuit::GraphRewiring::No, Circuit::VertexDeletion::Yes);
920
921 // 2. try to partition the circuit into blocks of Cn* gates such that
922 // the gates in each block can be merged into a single CnU gate
923
1/2
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
27 std::vector<Command> commands = c1.get_commands();
924 27 std::vector<CnGateBlock> blocks;
925
926
2/2
✓ Branch 5 taken 81 times.
✓ Branch 6 taken 27 times.
2/2
✓ Decision 'true' taken 81 times.
✓ Decision 'false' taken 27 times.
108 for (const Command &c : commands) {
927
1/2
✓ Branch 4 taken 81 times.
✗ Branch 5 not taken.
1/2
✓ Decision 'true' taken 81 times.
✗ Decision 'false' not taken.
81 if (c.get_op_ptr()->get_type() != OpType::noop) {
928
2/4
✓ Branch 1 taken 81 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 81 times.
✗ Branch 5 not taken.
81 blocks.push_back(CnGateBlock(c));
929 }
930 }
931
932 // iterate the blocks from left to right
933
2/2
✓ Branch 1 taken 56 times.
✓ Branch 2 taken 27 times.
2/2
✓ Decision 'true' taken 56 times.
✓ Decision 'false' taken 27 times.
83 for (unsigned i = 0; i + 1 < blocks.size(); i++) {
934 56 CnGateBlock &b = blocks[i];
935
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 56 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 56 times.
56 if (b.ops.empty()) {
936 continue;
937 }
938 // try to merge b to a block on the right
939
2/2
✓ Branch 1 taken 87 times.
✓ Branch 2 taken 9 times.
2/2
✓ Decision 'true' taken 87 times.
✓ Decision 'false' taken 9 times.
96 for (unsigned j = i + 1; j < blocks.size(); j++) {
940 87 CnGateBlock &candidate = blocks[j];
941
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 87 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 87 times.
87 if (candidate.ops.empty()) {
942 continue;
943 }
944
3/4
✓ Branch 1 taken 87 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 19 times.
✓ Branch 4 taken 68 times.
2/2
✓ Decision 'true' taken 19 times.
✓ Decision 'false' taken 68 times.
87 if (b.is_mergeable_with(candidate)) {
945
1/2
✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
19 candidate.merge(b, CnGateBlock::MergeMode::prepend);
946 19 break;
947 }
948
3/4
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 28 times.
✓ Branch 4 taken 40 times.
2/2
✓ Decision 'true' taken 28 times.
✓ Decision 'false' taken 40 times.
68 if (!b.commutes_with(candidate)) {
949 28 break;
950 }
951 }
952 }
953
954 // iterate the blocks from right to left
955
2/2
✓ Branch 1 taken 56 times.
✓ Branch 2 taken 27 times.
2/2
✓ Decision 'true' taken 56 times.
✓ Decision 'false' taken 27 times.
83 for (unsigned i = blocks.size(); i-- > 1;) {
956 56 CnGateBlock &b = blocks[i];
957
2/2
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 42 times.
2/2
✓ Decision 'true' taken 14 times.
✓ Decision 'false' taken 42 times.
56 if (b.ops.empty()) {
958 14 continue;
959 }
960 // try to merge b to a block on the left
961 // iterate from i-1 to 0
962
2/2
✓ Branch 0 taken 89 times.
✓ Branch 1 taken 10 times.
2/2
✓ Decision 'true' taken 89 times.
✓ Decision 'false' taken 10 times.
99 for (unsigned j = i; j-- > 0;) {
963 89 CnGateBlock &candidate = blocks[j];
964
2/2
✓ Branch 1 taken 38 times.
✓ Branch 2 taken 51 times.
2/2
✓ Decision 'true' taken 38 times.
✓ Decision 'false' taken 51 times.
89 if (candidate.ops.empty()) {
965 38 continue;
966 }
967
3/4
✓ Branch 1 taken 51 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 47 times.
2/2
✓ Decision 'true' taken 4 times.
✓ Decision 'false' taken 47 times.
51 if (b.is_mergeable_with(candidate)) {
968
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 candidate.merge(b, CnGateBlock::MergeMode::append);
969 4 break;
970 }
971
3/4
✓ Branch 1 taken 47 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 28 times.
✓ Branch 4 taken 19 times.
2/2
✓ Decision 'true' taken 28 times.
✓ Decision 'false' taken 19 times.
47 if (!b.commutes_with(candidate)) {
972 28 break;
973 }
974 }
975 }
976 // 3. Add each block to c2 either as a CnX, CnZ, CnY or a CnU decomposition
977
2/4
✓ Branch 2 taken 27 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 27 times.
✗ Branch 6 not taken.
27 Circuit c2(n_controls + c1.n_qubits());
978
6/12
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 26 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
27 const static Eigen::Matrix2cd X = Gate(OpType::X, {}, 1).get_unitary();
979
6/12
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 26 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
27 const static Eigen::Matrix2cd Y = Gate(OpType::Y, {}, 1).get_unitary();
980
6/12
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 26 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
27 const static Eigen::Matrix2cd Z = Gate(OpType::Z, {}, 1).get_unitary();
981
982
2/2
✓ Branch 5 taken 81 times.
✓ Branch 6 taken 27 times.
2/2
✓ Decision 'true' taken 81 times.
✓ Decision 'false' taken 27 times.
108 for (const CnGateBlock &b : blocks) {
983
2/2
✓ Branch 1 taken 23 times.
✓ Branch 2 taken 58 times.
2/2
✓ Decision 'true' taken 45 times.
✓ Decision 'false' taken 36 times.
81 if (b.ops.empty()) {
984 45 continue;
985 }
986 // Computes the target unitary
987
1/2
✓ Branch 1 taken 58 times.
✗ Branch 2 not taken.
58 Eigen::Matrix2cd m = b.get_target_unitary();
988
4/6
✓ Branch 1 taken 58 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 58 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 5 times.
✓ Branch 7 taken 53 times.
2/2
✓ Decision 'true' taken 5 times.
✓ Decision 'false' taken 53 times.
58 if (m.isApprox(Eigen::Matrix2cd::Identity(), EPS)) {
989 5 continue;
990 }
991 17 std::function<qubit_vector_t()> get_args = [&]() {
992 17 qubit_vector_t new_args;
993
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 17 times.
2/2
✓ Decision 'true' taken 19 times.
✓ Decision 'false' taken 17 times.
36 for (unsigned i = 0; i < n_controls; i++) {
994
2/4
✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 19 times.
✗ Branch 5 not taken.
19 new_args.push_back(Qubit(i));
995 }
996
2/2
✓ Branch 4 taken 23 times.
✓ Branch 5 taken 17 times.
2/2
✓ Decision 'true' taken 23 times.
✓ Decision 'false' taken 17 times.
40 for (const unsigned i : b.control_qubits) {
997
2/4
✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
23 new_args.push_back(Qubit(i + n_controls));
998 }
999
2/4
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 17 times.
✗ Branch 5 not taken.
17 new_args.push_back(Qubit(b.target_qubit + n_controls));
1000 17 return new_args;
1001 53 };
1002
3/4
✓ Branch 1 taken 53 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 15 times.
✓ Branch 4 taken 38 times.
2/2
✓ Decision 'true' taken 15 times.
✓ Decision 'false' taken 38 times.
53 if (m.isApprox(X, EPS)) {
1003
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 qubit_vector_t new_args = get_args();
1004
5/6
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 1 times.
✓ Branch 5 taken 10 times.
✓ Branch 6 taken 4 times.
✓ Branch 8 taken 15 times.
✗ Branch 9 not taken.
15 c2.add_op<Qubit>(CNXTYPE(new_args.size()), new_args);
1005 15 continue;
1006 15 }
1007
3/4
✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 37 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 37 times.
38 if (m.isApprox(Y, EPS)) {
1008
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 qubit_vector_t new_args = get_args();
1009
2/4
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
1 c2.add_op<Qubit>(CNYTYPE(new_args.size()), new_args);
1010 1 continue;
1011 1 }
1012
3/4
✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 36 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 36 times.
37 if (m.isApprox(Z, EPS)) {
1013
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 qubit_vector_t new_args = get_args();
1014
2/4
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
1 c2.add_op<Qubit>(CNZTYPE(new_args.size()), new_args);
1015 1 continue;
1016 1 }
1017 36 unit_map_t unit_map;
1018
2/2
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 36 times.
2/2
✓ Decision 'true' taken 56 times.
✓ Decision 'false' taken 36 times.
92 for (unsigned i = 0; i < n_controls; i++) {
1019
3/6
✓ Branch 1 taken 56 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 56 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 56 times.
✗ Branch 9 not taken.
56 unit_map.insert({Qubit(i), Qubit(i)});
1020 }
1021 36 unsigned control_index = n_controls;
1022
2/2
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 36 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 36 times.
38 for (const unsigned i : b.control_qubits) {
1023
3/6
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
2 unit_map.insert({Qubit(control_index++), Qubit(i + n_controls)});
1024 }
1025
3/6
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 36 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 36 times.
✗ Branch 9 not taken.
36 unit_map.insert({Qubit(control_index), Qubit(b.target_qubit + n_controls)});
1026
1027 36 unsigned total_controls = b.control_qubits.size() + n_controls;
1028
1029
1/2
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
36 Circuit replacement;
1030
1031 // Check if the matrix is SU(2)
1032
3/4
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 24 times.
2/2
✓ Decision 'true' taken 12 times.
✓ Decision 'false' taken 24 times.
36 if (m.determinant() == 1.) {
1033 // We have three functions that can decompose a multi-controlled SU(2).
1034 // The choice is based on the average number of CXs they produce for a
1035 // random n-controlled SU(2) gate.
1036
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 12 times.
12 if (total_controls > 2 && total_controls < 5) {
1037 replacement = CircPool::CnU_gray_code_decomp(total_controls, m);
1038
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 11 times.
12 } else if (total_controls >= 5 && total_controls < 9) {
1039
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 replacement = CircPool::CnU_linear_depth_decomp(total_controls, m);
1040 } else {
1041 // Compute the SU(2) angles from the TK1 angles
1042
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 std::vector<double> angles = tk1_angles_from_unitary(m);
1043
4/6
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 11 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 2 times.
✓ Branch 9 taken 9 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 9 times.
11 if (equiv_val(angles[3], 1., 2)) {
1044 // if the phase is odd, it can be absorbed into the first Rz rotation
1045 2 angles[0] = angles[0] + 2;
1046 } else {
1047 // because it's SU(2), the phase must be integers
1048 TKET_ASSERT(equiv_0(angles[3], 2));
1049 }
1050 // convert tk1 angles to zyz angles
1051 std::vector<double> zyz_angles = {
1052
1/2
✓ Branch 5 taken 11 times.
✗ Branch 6 not taken.
11 angles[0] - 0.5, angles[1], angles[2] + 0.5};
1053
4/8
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 11 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 11 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 11 times.
✗ Branch 11 not taken.
44 replacement = CircPool::CnSU2_linear_decomp(
1054
1/2
✓ Branch 4 taken 11 times.
✗ Branch 5 not taken.
44 total_controls, zyz_angles[0], zyz_angles[1], zyz_angles[2]);
1055 11 }
1056 } else {
1057 // The gray code method produces less CXs when total_controls is 3 or 4
1058
2/4
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 24 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 24 times.
24 if (total_controls == 3 || total_controls == 4) {
1059 replacement = CircPool::CnU_gray_code_decomp(total_controls, m);
1060 } else {
1061
2/4
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 24 times.
✗ Branch 5 not taken.
24 replacement = CircPool::CnU_linear_depth_decomp(total_controls, m);
1062 }
1063 }
1064
1/2
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
36 c2.append_with_map(replacement, unit_map);
1065
2/2
✓ Branch 3 taken 36 times.
✓ Branch 4 taken 17 times.
53 }
1066
1067 // 4. implement the conditional phase as a CnU1 gate
1068
4/6
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 27 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 7 times.
✓ Branch 8 taken 20 times.
2/2
✓ Decision 'true' taken 7 times.
✓ Decision 'false' taken 20 times.
27 if (!equiv_0(c1.get_phase())) {
1069
2/4
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
7 Circuit cnu1_circ = CnU1(n_controls - 1, c1.get_phase());
1070
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 c2.append(cnu1_circ);
1071 7 }
1072
1/2
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
27 return c2;
1073 27 }
1074
1075 28 Circuit with_controls(const Circuit &c, unsigned n_controls) {
1076
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 27 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 27 times.
28 if (c.is_symbolic()) {
1077 1 return with_controls_symbolic(c, n_controls);
1078 } else {
1079 27 return with_controls_numerical(c, n_controls);
1080 }
1081 }
1082
1083 #undef CNXTYPE
1084 #undef CNZTYPE
1085 #undef CNYTYPE
1086 #undef CNRYTYPE
1087
1088 3609 std::tuple<Circuit, std::array<Expr, 3>, Circuit> normalise_TK2_angles(
1089 Expr a, Expr b, Expr c) {
1090
1/2
✓ Branch 1 taken 3609 times.
✗ Branch 2 not taken.
3609 std::optional<double> a_eval = eval_expr_mod(a, 4);
1091
1/2
✓ Branch 1 taken 3609 times.
✗ Branch 2 not taken.
3609 std::optional<double> b_eval = eval_expr_mod(b, 4);
1092
1/2
✓ Branch 1 taken 3609 times.
✗ Branch 2 not taken.
3609 std::optional<double> c_eval = eval_expr_mod(c, 4);
1093
1094
2/4
✓ Branch 2 taken 3609 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 3609 times.
✗ Branch 7 not taken.
7218 Circuit pre(2), post(2);
1095
1096 // Add ot.dagger() at beggining and ot at end.
1097 10855 auto conj = [&pre, &post](OpType ot) {
1098
1/2
✓ Branch 2 taken 2171 times.
✗ Branch 3 not taken.
2171 Op_ptr op = get_op_ptr(ot);
1099
1/2
✓ Branch 2 taken 2171 times.
✗ Branch 3 not taken.
2171 Op_ptr opdg = op->dagger();
1100
2/4
✓ Branch 3 taken 2171 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2171 times.
✗ Branch 7 not taken.
2171 pre.add_op<unsigned>(opdg, {0});
1101
2/4
✓ Branch 3 taken 2171 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2171 times.
✗ Branch 7 not taken.
2171 pre.add_op<unsigned>(opdg, {1});
1102 // These get undaggered at the end
1103
2/4
✓ Branch 3 taken 2171 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2171 times.
✗ Branch 7 not taken.
2171 post.add_op<unsigned>(opdg, {0});
1104
2/4
✓ Branch 3 taken 2171 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2171 times.
✗ Branch 7 not taken.
2171 post.add_op<unsigned>(opdg, {1});
1105 2171 };
1106
1107 // Step 1: For non-symbolic: a, b, c ∈ [0, 1] ∪ [3, 4].
1108
8/8
✓ Branch 1 taken 3586 times.
✓ Branch 2 taken 23 times.
✓ Branch 4 taken 268 times.
✓ Branch 5 taken 3318 times.
✓ Branch 7 taken 222 times.
✓ Branch 8 taken 46 times.
✓ Branch 9 taken 222 times.
✓ Branch 10 taken 3387 times.
2/2
✓ Decision 'true' taken 222 times.
✓ Decision 'false' taken 3387 times.
3609 if (a_eval && *a_eval > 1. && *a_eval <= 3.) {
1109
2/4
✓ Branch 1 taken 222 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 222 times.
✗ Branch 5 not taken.
222 a -= 2;
1110 222 *a_eval -= 2;
1111
2/4
✓ Branch 1 taken 222 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 222 times.
✗ Branch 5 not taken.
222 pre.add_phase(1);
1112
1/2
✓ Branch 2 taken 222 times.
✗ Branch 3 not taken.
222 *a_eval = fmodn(*a_eval, 4);
1113 }
1114
8/8
✓ Branch 1 taken 3601 times.
✓ Branch 2 taken 8 times.
✓ Branch 4 taken 508 times.
✓ Branch 5 taken 3093 times.
✓ Branch 7 taken 3 times.
✓ Branch 8 taken 505 times.
✓ Branch 9 taken 3 times.
✓ Branch 10 taken 3606 times.
2/2
✓ Decision 'true' taken 3 times.
✓ Decision 'false' taken 3606 times.
3609 if (b_eval && *b_eval > 1. && *b_eval <= 3.) {
1115
2/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
3 b -= 2;
1116 3 *b_eval -= 2;
1117
2/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
3 pre.add_phase(1);
1118
1/2
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 *b_eval = fmodn(*b_eval, 4);
1119 }
1120
8/8
✓ Branch 1 taken 3601 times.
✓ Branch 2 taken 8 times.
✓ Branch 4 taken 110 times.
✓ Branch 5 taken 3491 times.
✓ Branch 7 taken 5 times.
✓ Branch 8 taken 105 times.
✓ Branch 9 taken 5 times.
✓ Branch 10 taken 3604 times.
2/2
✓ Decision 'true' taken 5 times.
✓ Decision 'false' taken 3604 times.
3609 if (c_eval && *c_eval > 1. && *c_eval <= 3.) {
1121
2/4
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
5 c -= 2;
1122 5 *c_eval -= 2;
1123
2/4
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
5 pre.add_phase(1);
1124
1/2
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
5 *c_eval = fmodn(*c_eval, 4);
1125 }
1126
1127 // Step 2: Make sure that symbolic expressions come before non-symbolics.
1128
6/6
✓ Branch 1 taken 3586 times.
✓ Branch 2 taken 23 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 3584 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 3607 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 3607 times.
3609 if (a_eval && !b_eval) {
1129 // Swap XX and YY.
1130
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 conj(OpType::S);
1131 2 std::swap(a, b);
1132 2 std::swap(a_eval, b_eval);
1133
6/6
✓ Branch 1 taken 3584 times.
✓ Branch 2 taken 23 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 3583 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 3606 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 3606 times.
3607 } else if (a_eval && !c_eval) {
1134 // Swap XX and ZZ.
1135
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 conj(OpType::H);
1136 1 std::swap(a, c);
1137 1 std::swap(a_eval, c_eval);
1138 }
1139
6/6
✓ Branch 1 taken 3603 times.
✓ Branch 2 taken 6 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 3601 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 3607 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 3607 times.
3609 if (b_eval && !c_eval) {
1140 // Swap YY and ZZ.
1141
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 conj(OpType::V);
1142 2 std::swap(b, c);
1143 2 std::swap(b_eval, c_eval);
1144 }
1145
1146 // Step 3: Order non-symbolic expressions in decreasing order.
1147 21534 auto val_in_weyl = [](double r) {
1148 // Value of r once projected into Weyl chamber.
1149
1/2
✓ Branch 2 taken 21534 times.
✗ Branch 3 not taken.
21534 return std::min(fmodn(r, 1), 1 - fmodn(r, 1));
1150 };
1151
9/12
✓ Branch 1 taken 3583 times.
✓ Branch 2 taken 26 times.
✓ Branch 4 taken 3583 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 3583 times.
✗ Branch 9 not taken.
✓ Branch 12 taken 3583 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 602 times.
✓ Branch 15 taken 2981 times.
✓ Branch 16 taken 602 times.
✓ Branch 17 taken 3007 times.
2/2
✓ Decision 'true' taken 602 times.
✓ Decision 'false' taken 3007 times.
3609 if (a_eval && b_eval && val_in_weyl(*a_eval) < val_in_weyl(*b_eval)) {
1152 // Swap XX and YY.
1153
1/2
✓ Branch 1 taken 602 times.
✗ Branch 2 not taken.
602 conj(OpType::S);
1154 602 std::swap(a, b);
1155 602 std::swap(a_eval, b_eval);
1156 }
1157
9/12
✓ Branch 1 taken 3601 times.
✓ Branch 2 taken 8 times.
✓ Branch 4 taken 3601 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 3601 times.
✗ Branch 9 not taken.
✓ Branch 12 taken 3601 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 1504 times.
✓ Branch 15 taken 2097 times.
✓ Branch 16 taken 1504 times.
✓ Branch 17 taken 2105 times.
2/2
✓ Decision 'true' taken 1504 times.
✓ Decision 'false' taken 2105 times.
3609 if (b_eval && c_eval && val_in_weyl(*b_eval) < val_in_weyl(*c_eval)) {
1158 // Swap YY and ZZ.
1159
1/2
✓ Branch 1 taken 1504 times.
✗ Branch 2 not taken.
1504 conj(OpType::V);
1160 1504 std::swap(b, c);
1161 1504 std::swap(b_eval, c_eval);
1162 }
1163
9/12
✓ Branch 1 taken 3583 times.
✓ Branch 2 taken 26 times.
✓ Branch 4 taken 3583 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 3583 times.
✗ Branch 9 not taken.
✓ Branch 12 taken 3583 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 60 times.
✓ Branch 15 taken 3523 times.
✓ Branch 16 taken 60 times.
✓ Branch 17 taken 3549 times.
2/2
✓ Decision 'true' taken 60 times.
✓ Decision 'false' taken 3549 times.
3609 if (a_eval && b_eval && val_in_weyl(*a_eval) < val_in_weyl(*b_eval)) {
1164 // Swap XX and YY.
1165
1/2
✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
60 conj(OpType::S);
1166 60 std::swap(a, b);
1167 60 std::swap(a_eval, b_eval);
1168 }
1169
1170 // Step 4: Project into Weyl chamber.
1171
6/6
✓ Branch 1 taken 3583 times.
✓ Branch 2 taken 26 times.
✓ Branch 4 taken 316 times.
✓ Branch 5 taken 3267 times.
✓ Branch 6 taken 316 times.
✓ Branch 7 taken 3293 times.
2/2
✓ Decision 'true' taken 316 times.
✓ Decision 'false' taken 3293 times.
3609 if (a_eval && *a_eval > 1.) {
1172
2/4
✓ Branch 1 taken 316 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 316 times.
✗ Branch 5 not taken.
316 a -= 3.;
1173 316 *a_eval -= 3;
1174
2/4
✓ Branch 3 taken 316 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 316 times.
✗ Branch 7 not taken.
316 post.add_op<unsigned>(OpType::X, {0});
1175
2/4
✓ Branch 3 taken 316 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 316 times.
✗ Branch 7 not taken.
316 post.add_op<unsigned>(OpType::X, {1});
1176
2/4
✓ Branch 1 taken 316 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 316 times.
✗ Branch 5 not taken.
316 pre.add_phase(0.5);
1177 }
1178
6/6
✓ Branch 1 taken 3601 times.
✓ Branch 2 taken 8 times.
✓ Branch 4 taken 233 times.
✓ Branch 5 taken 3368 times.
✓ Branch 6 taken 233 times.
✓ Branch 7 taken 3376 times.
2/2
✓ Decision 'true' taken 233 times.
✓ Decision 'false' taken 3376 times.
3609 if (b_eval && *b_eval > 1.) {
1179
2/4
✓ Branch 1 taken 233 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 233 times.
✗ Branch 5 not taken.
233 b -= 3.;
1180 233 *b_eval -= 3;
1181
2/4
✓ Branch 3 taken 233 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 233 times.
✗ Branch 7 not taken.
233 post.add_op<unsigned>(OpType::Y, {0});
1182
2/4
✓ Branch 3 taken 233 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 233 times.
✗ Branch 7 not taken.
233 post.add_op<unsigned>(OpType::Y, {1});
1183
2/4
✓ Branch 1 taken 233 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 233 times.
✗ Branch 5 not taken.
233 pre.add_phase(0.5);
1184 }
1185
6/6
✓ Branch 1 taken 3604 times.
✓ Branch 2 taken 5 times.
✓ Branch 4 taken 113 times.
✓ Branch 5 taken 3491 times.
✓ Branch 6 taken 113 times.
✓ Branch 7 taken 3496 times.
2/2
✓ Decision 'true' taken 113 times.
✓ Decision 'false' taken 3496 times.
3609 if (c_eval && *c_eval > 1.) {
1186
2/4
✓ Branch 1 taken 113 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 113 times.
✗ Branch 5 not taken.
113 c -= 3.;
1187 113 *c_eval -= 3;
1188
2/4
✓ Branch 3 taken 113 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 113 times.
✗ Branch 7 not taken.
113 post.add_op<unsigned>(OpType::Z, {0});
1189
2/4
✓ Branch 3 taken 113 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 113 times.
✗ Branch 7 not taken.
113 post.add_op<unsigned>(OpType::Z, {1});
1190
2/4
✓ Branch 1 taken 113 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 113 times.
✗ Branch 5 not taken.
113 pre.add_phase(0.5);
1191 }
1192
6/6
✓ Branch 1 taken 3583 times.
✓ Branch 2 taken 26 times.
✓ Branch 4 taken 485 times.
✓ Branch 5 taken 3098 times.
✓ Branch 6 taken 485 times.
✓ Branch 7 taken 3124 times.
2/2
✓ Decision 'true' taken 485 times.
✓ Decision 'false' taken 3124 times.
3609 if (a_eval && *a_eval > .5) {
1193
2/4
✓ Branch 1 taken 485 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 485 times.
✗ Branch 5 not taken.
485 a = 1. - a;
1194 485 *a_eval = 1. - *a_eval;
1195
2/4
✓ Branch 1 taken 485 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 485 times.
✗ Branch 5 not taken.
485 b = 1. - b;
1196 485 *b_eval = 1. - *b_eval;
1197
2/4
✓ Branch 3 taken 485 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 485 times.
✗ Branch 7 not taken.
485 pre.add_op<unsigned>(OpType::Z, {0});
1198
2/4
✓ Branch 3 taken 485 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 485 times.
✗ Branch 7 not taken.
485 post.add_op<unsigned>(OpType::Z, {1});
1199 }
1200
6/6
✓ Branch 1 taken 3601 times.
✓ Branch 2 taken 8 times.
✓ Branch 4 taken 651 times.
✓ Branch 5 taken 2950 times.
✓ Branch 6 taken 651 times.
✓ Branch 7 taken 2958 times.
2/2
✓ Decision 'true' taken 651 times.
✓ Decision 'false' taken 2958 times.
3609 if (b_eval && (*b_eval > .5)) {
1201
2/4
✓ Branch 1 taken 651 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 651 times.
✗ Branch 5 not taken.
651 b = 1 - b;
1202 651 *b_eval = 1. - *b_eval;
1203
2/4
✓ Branch 1 taken 651 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 651 times.
✗ Branch 5 not taken.
651 c = 1 - c;
1204 651 *c_eval = 1. - *c_eval;
1205
2/4
✓ Branch 3 taken 651 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 651 times.
✗ Branch 7 not taken.
651 pre.add_op<unsigned>(OpType::X, {0});
1206
2/4
✓ Branch 3 taken 651 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 651 times.
✗ Branch 7 not taken.
651 post.add_op<unsigned>(OpType::X, {1});
1207 }
1208
6/6
✓ Branch 1 taken 3604 times.
✓ Branch 2 taken 5 times.
✓ Branch 4 taken 941 times.
✓ Branch 5 taken 2663 times.
✓ Branch 6 taken 941 times.
✓ Branch 7 taken 2668 times.
2/2
✓ Decision 'true' taken 941 times.
✓ Decision 'false' taken 2668 times.
3609 if (c_eval && *c_eval > .5) {
1209
2/4
✓ Branch 1 taken 941 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 941 times.
✗ Branch 5 not taken.
941 c -= 1;
1210 941 *c_eval -= 1.;
1211
2/4
✓ Branch 3 taken 941 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 941 times.
✗ Branch 7 not taken.
941 post.add_op<unsigned>(OpType::Z, {0});
1212
2/4
✓ Branch 3 taken 941 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 941 times.
✗ Branch 7 not taken.
941 post.add_op<unsigned>(OpType::Z, {1});
1213
2/4
✓ Branch 1 taken 941 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 941 times.
✗ Branch 5 not taken.
941 pre.add_phase(-0.5);
1214 }
1215 // Cheeky way of reversing order of ops.
1216
2/4
✓ Branch 1 taken 3609 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3609 times.
✗ Branch 5 not taken.
3609 post = post.dagger();
1217
1218
4/8
✓ Branch 1 taken 3609 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3609 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3609 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 3609 times.
✗ Branch 11 not taken.
7218 return {pre, {a, b, c}, post};
1219 3609 }
1220
1221 } // namespace tket
1222