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 "GateUnitaryMatrix.hpp" | |||
16 | ||||
17 | #include <cmath> | |||
18 | #include <sstream> | |||
19 | #include <tkassert/Assert.hpp> | |||
20 | ||||
21 | #include "Gate/Gate.hpp" | |||
22 | #include "GateUnitaryMatrixError.hpp" | |||
23 | #include "GateUnitaryMatrixImplementations.hpp" | |||
24 | #include "GateUnitaryMatrixUtils.hpp" | |||
25 | #include "GateUnitaryMatrixVariableQubits.hpp" | |||
26 | #include "GateUnitarySparseMatrix.hpp" | |||
27 | #include "OpType/OpTypeInfo.hpp" | |||
28 | ||||
29 | // This is just for the main Gate -> matrix function, so the only part | |||
30 | // which actually uses the rest of tket. This is nothing but a wrapper around | |||
31 | // the basic named functions like x(), etc. (with extra error checks). | |||
32 | ||||
33 | // NOTE: MatrixXcd objects are returned by a series of functions; | |||
34 | // if the OpType is unrecognised, it returns a 0x0 matrix. | |||
35 | // Eventually, when it is recognised, a nonempty matrix will be returned, | |||
36 | // or an error thrown if nothing recognises it. | |||
37 | ||||
38 | namespace tket { | |||
39 | ||||
40 | using internal::GateUnitaryMatrixImplementations; | |||
41 | using internal::GateUnitaryMatrixUtils; | |||
42 | ||||
43 | #ifdef CASE_RETURN_0P | |||
44 | #error "Macro already defined!" | |||
45 | #endif | |||
46 | #define CASE_RETURN_0P(function_name) \ | |||
47 | case OpType::function_name: \ | |||
48 | GateUnitaryMatrixUtils::check_and_throw_upon_wrong_number_of_parameters( \ | |||
49 | OpType::function_name, number_of_qubits, parameters, 0); \ | |||
50 | return GateUnitaryMatrixImplementations::function_name(); | |||
51 | ||||
52 | #ifdef CASE_RETURN_1P | |||
53 | #error "Macro already defined!" | |||
54 | #endif | |||
55 | #define CASE_RETURN_1P(function_name) \ | |||
56 | case OpType::function_name: \ | |||
57 | GateUnitaryMatrixUtils::check_and_throw_upon_wrong_number_of_parameters( \ | |||
58 | OpType::function_name, number_of_qubits, parameters, 1); \ | |||
59 | return GateUnitaryMatrixImplementations::function_name(parameters[0]); | |||
60 | ||||
61 | #ifdef CASE_RETURN_2P | |||
62 | #error "Macro already defined!" | |||
63 | #endif | |||
64 | #define CASE_RETURN_2P(function_name) \ | |||
65 | case OpType::function_name: \ | |||
66 | GateUnitaryMatrixUtils::check_and_throw_upon_wrong_number_of_parameters( \ | |||
67 | OpType::function_name, number_of_qubits, parameters, 2); \ | |||
68 | return GateUnitaryMatrixImplementations::function_name( \ | |||
69 | parameters[0], parameters[1]); | |||
70 | ||||
71 | #ifdef CASE_RETURN_3P | |||
72 | #error "Macro already defined!" | |||
73 | #endif | |||
74 | #define CASE_RETURN_3P(function_name) \ | |||
75 | case OpType::function_name: \ | |||
76 | GateUnitaryMatrixUtils::check_and_throw_upon_wrong_number_of_parameters( \ | |||
77 | OpType::function_name, number_of_qubits, parameters, 3); \ | |||
78 | return GateUnitaryMatrixImplementations::function_name( \ | |||
79 | parameters[0], parameters[1], parameters[2]); | |||
80 | ||||
81 | // Only for op types with a fixed, known number of qubits; | |||
82 | // throws if the number of parameters is wrong. | |||
83 | // However, does NOT check the number of qubits. | |||
84 | 196507 | static Eigen::MatrixXcd get_unitary_or_throw( | ||
85 | OpType op_type, unsigned number_of_qubits, | |||
86 | const std::vector<double>& parameters) { | |||
87 |
53/53✓ Branch 0 taken 1405 times.
✓ Branch 1 taken 532 times.
✓ Branch 2 taken 1208 times.
✓ Branch 3 taken 733 times.
✓ Branch 4 taken 372 times.
✓ Branch 5 taken 918 times.
✓ Branch 6 taken 676 times.
✓ Branch 7 taken 1125 times.
✓ Branch 8 taken 839 times.
✓ Branch 9 taken 19957 times.
✓ Branch 10 taken 44 times.
✓ Branch 11 taken 43 times.
✓ Branch 12 taken 50 times.
✓ Branch 13 taken 136 times.
✓ Branch 14 taken 49 times.
✓ Branch 15 taken 40 times.
✓ Branch 16 taken 39 times.
✓ Branch 17 taken 74474 times.
✓ Branch 18 taken 54 times.
✓ Branch 19 taken 414 times.
✓ Branch 20 taken 52 times.
✓ Branch 21 taken 48 times.
✓ Branch 22 taken 46 times.
✓ Branch 23 taken 48 times.
✓ Branch 24 taken 46 times.
✓ Branch 25 taken 79 times.
✓ Branch 26 taken 128 times.
✓ Branch 27 taken 45 times.
✓ Branch 28 taken 45 times.
✓ Branch 29 taken 1 times.
✓ Branch 30 taken 10205 times.
✓ Branch 31 taken 11277 times.
✓ Branch 32 taken 12387 times.
✓ Branch 33 taken 29532 times.
✓ Branch 34 taken 5413 times.
✓ Branch 35 taken 237 times.
✓ Branch 36 taken 213 times.
✓ Branch 37 taken 158 times.
✓ Branch 38 taken 56 times.
✓ Branch 39 taken 130 times.
✓ Branch 40 taken 117 times.
✓ Branch 41 taken 151 times.
✓ Branch 42 taken 127 times.
✓ Branch 43 taken 113 times.
✓ Branch 44 taken 247 times.
✓ Branch 45 taken 172 times.
✓ Branch 46 taken 116 times.
✓ Branch 47 taken 118 times.
✓ Branch 48 taken 2496 times.
✓ Branch 49 taken 8917 times.
✓ Branch 50 taken 9270 times.
✓ Branch 51 taken 1386 times.
✓ Branch 52 taken 23 times.
|
196507 | switch (op_type) { | |
88 | 1405 | CASE_RETURN_0P(X) | ||
89 | 532 | CASE_RETURN_0P(Y) | ||
90 | 1208 | CASE_RETURN_0P(Z) | ||
91 | 733 | CASE_RETURN_0P(S) | ||
92 | 372 | CASE_RETURN_0P(Sdg) | ||
93 | 918 | CASE_RETURN_0P(T) | ||
94 | 676 | CASE_RETURN_0P(Tdg) | ||
95 | 1125 | CASE_RETURN_0P(V) | ||
96 | 839 | CASE_RETURN_0P(Vdg) | ||
97 | 19957 | CASE_RETURN_0P(H) | ||
98 | 44 | CASE_RETURN_0P(BRIDGE) | ||
99 | 43 | CASE_RETURN_0P(noop) | ||
100 | 50 | CASE_RETURN_0P(ECR) | ||
101 | 136 | CASE_RETURN_0P(SX) | ||
102 | 49 | CASE_RETURN_0P(SXdg) | ||
103 | 40 | CASE_RETURN_0P(CSWAP) | ||
104 | 39 | CASE_RETURN_0P(CCX) | ||
105 | 74474 | CASE_RETURN_0P(CX) | ||
106 | 54 | CASE_RETURN_0P(CY) | ||
107 | 414 | CASE_RETURN_0P(CZ) | ||
108 | 52 | CASE_RETURN_0P(CH) | ||
109 | 48 | CASE_RETURN_0P(CV) | ||
110 | 46 | CASE_RETURN_0P(CVdg) | ||
111 | 48 | CASE_RETURN_0P(CSX) | ||
112 | 46 | CASE_RETURN_0P(CSXdg) | ||
113 | 79 | CASE_RETURN_0P(SWAP) | ||
114 | 128 | CASE_RETURN_0P(ZZMax) | ||
115 | 45 | CASE_RETURN_0P(Sycamore) | ||
116 | 45 | CASE_RETURN_0P(ISWAPMax) | ||
117 | #undef CASE_RETURN_0P | |||
118 |
1/2✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
2 | CASE_RETURN_1P(Phase) | |
119 |
1/2✓ Branch 4 taken 10175 times.
✗ Branch 5 not taken.
|
20380 | CASE_RETURN_1P(Rx) | |
120 |
1/2✓ Branch 4 taken 11247 times.
✗ Branch 5 not taken.
|
22524 | CASE_RETURN_1P(Ry) | |
121 |
1/2✓ Branch 4 taken 12357 times.
✗ Branch 5 not taken.
|
24744 | CASE_RETURN_1P(Rz) | |
122 |
1/2✓ Branch 4 taken 29502 times.
✗ Branch 5 not taken.
|
59034 | CASE_RETURN_1P(U1) | |
123 |
1/2✓ Branch 4 taken 5383 times.
✗ Branch 5 not taken.
|
10796 | CASE_RETURN_1P(CRx) | |
124 |
1/2✓ Branch 4 taken 207 times.
✗ Branch 5 not taken.
|
444 | CASE_RETURN_1P(CRy) | |
125 |
1/2✓ Branch 4 taken 183 times.
✗ Branch 5 not taken.
|
396 | CASE_RETURN_1P(CRz) | |
126 |
1/2✓ Branch 4 taken 128 times.
✗ Branch 5 not taken.
|
286 | CASE_RETURN_1P(CU1) | |
127 |
1/2✓ Branch 4 taken 26 times.
✗ Branch 5 not taken.
|
82 | CASE_RETURN_1P(ISWAP) | |
128 |
1/2✓ Branch 4 taken 100 times.
✗ Branch 5 not taken.
|
230 | CASE_RETURN_1P(XXPhase) | |
129 |
1/2✓ Branch 4 taken 87 times.
✗ Branch 5 not taken.
|
204 | CASE_RETURN_1P(YYPhase) | |
130 |
1/2✓ Branch 4 taken 121 times.
✗ Branch 5 not taken.
|
272 | CASE_RETURN_1P(ZZPhase) | |
131 |
1/2✓ Branch 4 taken 97 times.
✗ Branch 5 not taken.
|
224 | CASE_RETURN_1P(XXPhase3) | |
132 |
1/2✓ Branch 4 taken 83 times.
✗ Branch 5 not taken.
|
196 | CASE_RETURN_1P(ESWAP) | |
133 | #undef CASE_RETURN_1P | |||
134 |
1/2✓ Branch 5 taken 217 times.
✗ Branch 6 not taken.
|
464 | CASE_RETURN_2P(U2) | |
135 |
1/2✓ Branch 5 taken 142 times.
✗ Branch 6 not taken.
|
314 | CASE_RETURN_2P(PhasedX) | |
136 |
1/2✓ Branch 5 taken 86 times.
✗ Branch 6 not taken.
|
202 | CASE_RETURN_2P(PhasedISWAP) | |
137 |
1/2✓ Branch 5 taken 88 times.
✗ Branch 6 not taken.
|
206 | CASE_RETURN_2P(FSim) | |
138 | #undef CASE_RETURN_2P | |||
139 |
1/2✓ Branch 6 taken 2466 times.
✗ Branch 7 not taken.
|
4962 | CASE_RETURN_3P(CU3) | |
140 |
1/2✓ Branch 6 taken 8887 times.
✗ Branch 7 not taken.
|
17804 | CASE_RETURN_3P(U3) | |
141 |
1/2✓ Branch 6 taken 9240 times.
✗ Branch 7 not taken.
|
18510 | CASE_RETURN_3P(TK1) | |
142 |
1/2✓ Branch 6 taken 1356 times.
✗ Branch 7 not taken.
|
2742 | CASE_RETURN_3P(TK2) | |
143 | #undef CASE_RETURN_3P | |||
144 |
1/1✓ Decision 'true' taken 23 times.
|
23 | default: { | |
145 |
1/2✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
|
23 | std::stringstream ss; | |
146 |
1/2✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
|
46 | ss << GateUnitaryMatrixUtils::get_error_prefix( | |
147 | op_type, number_of_qubits, parameters) | |||
148 |
2/4✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | << "unrecognised Op type"; | |
149 |
2/4✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 23 times.
✗ Branch 6 not taken.
|
23 | throw BadOpType(ss.str(), op_type); | |
150 | 23 | } | ||
151 | } | |||
152 | } | |||
153 | ||||
154 | // It's already been checked not to be one of the special cases | |||
155 | // having a variable number of qubits. | |||
156 | 196507 | static Eigen::MatrixXcd get_unitary_for_ordinary_fixed_size_case( | ||
157 | OpType op_type, unsigned number_of_qubits, | |||
158 | const std::vector<double>& parameters) { | |||
159 | const Eigen::MatrixXcd matr = | |||
160 |
2/2✓ Branch 1 taken 194954 times.
✓ Branch 2 taken 1553 times.
|
196507 | get_unitary_or_throw(op_type, number_of_qubits, parameters); | |
161 | ||||
162 | TKET_ASSERT(matr.cols() == matr.rows()); | |||
163 |
1/2✓ Branch 2 taken 194954 times.
✗ Branch 3 not taken.
|
194954 | const auto expected_number_of_qubits = get_number_of_qubits(matr.cols()); | |
164 |
2/2✓ Branch 0 taken 194699 times.
✓ Branch 1 taken 255 times.
|
0/1? Decision couldn't be analyzed.
|
194954 | if (expected_number_of_qubits == number_of_qubits) { |
165 | 389398 | return matr; | ||
166 | } | |||
167 |
1/2✓ Branch 1 taken 255 times.
✗ Branch 2 not taken.
|
255 | std::stringstream ss; | |
168 |
1/2✓ Branch 1 taken 255 times.
✗ Branch 2 not taken.
|
510 | ss << GateUnitaryMatrixUtils::get_error_prefix( | |
169 | op_type, number_of_qubits, parameters) | |||
170 |
4/8✓ Branch 1 taken 255 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 255 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 255 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 255 times.
✗ Branch 11 not taken.
|
255 | << "wrong number of qubits (expected " << expected_number_of_qubits << ")"; | |
171 |
1/2✓ Branch 1 taken 255 times.
✗ Branch 2 not taken.
|
255 | throw GateUnitaryMatrixError( | |
172 |
1/2✓ Branch 2 taken 255 times.
✗ Branch 3 not taken.
|
510 | ss.str(), GateUnitaryMatrixError::Cause::INPUT_ERROR); | |
173 | 510 | } | ||
174 | ||||
175 | 197293 | Eigen::MatrixXcd GateUnitaryMatrix::get_unitary( | ||
176 | OpType op_type, unsigned number_of_qubits, | |||
177 | const std::vector<double>& parameters) { | |||
178 |
1/2✓ Branch 1 taken 197293 times.
✗ Branch 2 not taken.
|
197293 | const internal::GateUnitaryMatrixVariableQubits variable_qubits_data(op_type); | |
179 |
3/4✓ Branch 1 taken 197293 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 196507 times.
✓ Branch 4 taken 786 times.
|
2/2✓ Decision 'true' taken 196507 times.
✓ Decision 'false' taken 786 times.
|
197293 | if (!variable_qubits_data.is_known_type()) { |
180 | return get_unitary_for_ordinary_fixed_size_case( | |||
181 |
2/2✓ Branch 1 taken 194699 times.
✓ Branch 2 taken 1808 times.
|
196507 | op_type, number_of_qubits, parameters); | |
182 | } | |||
183 | const auto expected_number_of_parameters = | |||
184 |
1/2✓ Branch 1 taken 786 times.
✗ Branch 2 not taken.
|
786 | variable_qubits_data.get_number_of_parameters(); | |
185 |
2/2✓ Branch 1 taken 396 times.
✓ Branch 2 taken 390 times.
|
2/2✓ Decision 'true' taken 396 times.
✓ Decision 'false' taken 390 times.
|
786 | if (parameters.size() == expected_number_of_parameters) { |
186 |
2/2✓ Branch 1 taken 388 times.
✓ Branch 2 taken 8 times.
|
396 | return variable_qubits_data.get_dense_unitary(number_of_qubits, parameters); | |
187 | } | |||
188 |
1/2✓ Branch 1 taken 390 times.
✗ Branch 2 not taken.
|
390 | std::stringstream ss; | |
189 |
1/2✓ Branch 1 taken 390 times.
✗ Branch 2 not taken.
|
780 | ss << GateUnitaryMatrixUtils::get_error_prefix( | |
190 | op_type, number_of_qubits, parameters) | |||
191 |
3/6✓ Branch 1 taken 390 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 390 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 390 times.
✗ Branch 8 not taken.
|
390 | << "wrong number of parameters (expected " << expected_number_of_parameters | |
192 |
1/2✓ Branch 1 taken 390 times.
✗ Branch 2 not taken.
|
390 | << ")"; | |
193 |
1/2✓ Branch 1 taken 390 times.
✗ Branch 2 not taken.
|
390 | throw GateUnitaryMatrixError( | |
194 |
1/2✓ Branch 2 taken 390 times.
✗ Branch 3 not taken.
|
780 | ss.str(), GateUnitaryMatrixError::Cause::INPUT_ERROR); | |
195 | 390 | } | ||
196 | ||||
197 | 194374 | Eigen::MatrixXcd GateUnitaryMatrix::get_unitary(const Gate& gate) { | ||
198 |
1/2✓ Branch 1 taken 194374 times.
✗ Branch 2 not taken.
|
194374 | const auto parameters = GateUnitaryMatrixUtils::get_checked_parameters(gate); | |
199 |
3/4✓ Branch 1 taken 194374 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 194371 times.
✓ Branch 6 taken 3 times.
|
388745 | return get_unitary(gate.get_type(), gate.n_qubits(), parameters); | |
200 | 194374 | } | ||
201 | ||||
202 | 191456 | std::vector<TripletCd> GateUnitaryMatrix::get_unitary_triplets( | ||
203 | const Gate& gate, double abs_epsilon) { | |||
204 | auto triplets = internal::GateUnitarySparseMatrix::get_unitary_triplets( | |||
205 | 191456 | gate, abs_epsilon); | ||
206 |
2/2✓ Branch 1 taken 191262 times.
✓ Branch 2 taken 194 times.
|
2/2✓ Decision 'true' taken 191262 times.
✓ Decision 'false' taken 194 times.
|
191456 | if (triplets.empty()) { |
207 | // Not recognised as a specific sparse type, so just get the dense matrix | |||
208 |
1/2✓ Branch 1 taken 191262 times.
✗ Branch 2 not taken.
|
191262 | const auto unitary_matr = get_unitary(gate); | |
209 |
1/2✓ Branch 1 taken 191262 times.
✗ Branch 2 not taken.
|
191262 | triplets = get_triplets(unitary_matr, abs_epsilon); | |
210 | 191262 | } | ||
211 | 191456 | return triplets; | ||
212 | } | |||
213 | ||||
214 | } // namespace tket | |||
215 |