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 |