GCC Code Coverage Report


Directory: ./
File: Gate/GateUnitaryMatrixUtils.cpp
Date: 2022-10-15 05:10:18
Warnings: 2 unchecked decisions!
Exec Total Coverage
Lines: 61 83 73.5%
Functions: 7 7 100.0%
Branches: 70 206 34.0%
Decisions: 15 26 57.7%

Line Branch Decision Exec Source
1 // Copyright 2019-2022 Cambridge Quantum Computing
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "GateUnitaryMatrixUtils.hpp"
16
17 #include <sstream>
18
19 #include "Gate/Gate.hpp"
20 #include "GateUnitaryMatrixError.hpp"
21
22 namespace tket {
23 namespace internal {
24
25 8375 Eigen::Matrix4cd GateUnitaryMatrixUtils::get_controlled_gate_unitary(
26 const Eigen::Matrix2cd& u) {
27
1/2
✓ Branch 2 taken 8375 times.
✗ Branch 3 not taken.
8375 Eigen::Matrix4cd matr = Eigen::Matrix4cd::Identity();
28
1/2
✓ Branch 2 taken 8375 times.
✗ Branch 3 not taken.
8375 matr.block(2, 2, 2, 2) = u;
29 8375 return matr;
30 }
31
32 Eigen::MatrixXcd
33 86 GateUnitaryMatrixUtils::get_multi_controlled_gate_dense_unitary(
34 const Eigen::MatrixXcd& u, unsigned int number_of_qubits) {
35 unsigned int size;
36 try {
37
1/2
✓ Branch 1 taken 86 times.
✗ Branch 2 not taken.
86 size = get_matrix_size(number_of_qubits);
38 } catch (const std::exception& e) {
39 throw GateUnitaryMatrixError(
40 e.what(), GateUnitaryMatrixError::Cause::TOO_MANY_QUBITS);
41 }
42 8 const auto throw_with_message = [&](const std::string& message) {
43
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 std::stringstream ss;
44
2/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
8 ss << "multi_controlled_gate with " << number_of_qubits
45 << " qubits "
46
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 "(final matrix size "
47
3/6
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 8 times.
✗ Branch 8 not taken.
8 << size << "x" << size
48 << "), "
49
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 "for unitary matrix U with "
50
5/10
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 8 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 8 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 8 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 8 times.
✗ Branch 16 not taken.
8 << u.cols() << " cols, " << u.rows() << ": " << message;
51
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 throw GateUnitaryMatrixError(
52
1/2
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
16 ss.str(), GateUnitaryMatrixError::Cause::INPUT_ERROR);
53 8 };
54
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 86 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 86 times.
86 if (u.cols() != u.rows()) {
55 throw_with_message("matrix U not square");
56 }
57
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 86 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 86 times.
86 if (u.cols() == 0) {
58 throw_with_message("zero size matrix U");
59 }
60
3/4
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 78 times.
2/2
✓ Decision 'true' taken 24 times.
✓ Decision 'false' taken 62 times.
86 if (!(number_of_qubits >= 1 && size >= 2)) {
61
2/4
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 8 times.
24 throw_with_message("must have at least 1 qubit");
62 }
63
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 78 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 78 times.
78 if (!(size >= u.cols())) {
64
0/1
? Decision couldn't be analyzed.
throw_with_message("input U is too large for the final number of qubits");
65 }
66 // A trick: we should check that U is of size 2^k * 2^k.
67 // But actually, we know the full size is 2^N * 2^N for N >= k,
68 // so we just check for factors.
69 78 const unsigned int ratio = size / u.cols();
70
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 78 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 78 times.
78 if (ratio * u.cols() != size) {
71 std::stringstream ss;
72 ss << "input U number of columns is not a power of 2 (" << u.cols()
73 << " doesn't divide " << size << ")";
74 throw_with_message(ss.str());
75 }
76
2/4
✓ Branch 1 taken 78 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 78 times.
✗ Branch 5 not taken.
78 Eigen::MatrixXcd matr = Eigen::MatrixXcd::Identity(size, size);
77
2/4
✓ Branch 5 taken 78 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 78 times.
✗ Branch 9 not taken.
78 matr.block(size - u.cols(), size - u.cols(), u.cols(), u.cols()) = u;
78 156 return matr;
79 }
80
81 2198 std::string GateUnitaryMatrixUtils::get_error_prefix(
82 const std::string& name, unsigned number_of_qubits,
83 const std::vector<double>& parameters) {
84
1/2
✓ Branch 1 taken 2198 times.
✗ Branch 2 not taken.
2198 std::stringstream ss;
85
4/8
✓ Branch 1 taken 2198 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2198 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2198 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 2198 times.
✗ Branch 11 not taken.
0/1
? Decision couldn't be analyzed.
2198 ss << "GateUnitaryMatrix for op " << name << " acting on " << number_of_qubits
86
3/6
✓ Branch 1 taken 2198 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 2198 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 2198 times.
✗ Branch 9 not taken.
2198 << " qubits, taking " << parameters.size() << " parameters:\n";
87
88
2/2
✓ Branch 1 taken 5678 times.
✓ Branch 2 taken 2198 times.
2/2
✓ Decision 'true' taken 5678 times.
✓ Decision 'false' taken 2198 times.
7876 for (unsigned nn = 0; nn < parameters.size(); ++nn) {
89
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5678 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 5678 times.
5678 if (nn >= 10) {
90 ss << "...";
91 break;
92 }
93
5/10
✓ Branch 1 taken 5678 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5678 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 5678 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 5678 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 5678 times.
✗ Branch 15 not taken.
5678 ss << "param[" << nn << "] = " << parameters[nn] << "\n";
94 }
95
1/2
✓ Branch 1 taken 2198 times.
✗ Branch 2 not taken.
4396 return ss.str();
96 2198 }
97
98 2198 std::string GateUnitaryMatrixUtils::get_error_prefix(
99 OpType op_type, unsigned number_of_qubits,
100 const std::vector<double>& parameters) {
101
1/2
✓ Branch 1 taken 2198 times.
✗ Branch 2 not taken.
2198 const OpDesc desc(op_type);
102
2/4
✓ Branch 1 taken 2198 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2198 times.
✗ Branch 5 not taken.
6594 return get_error_prefix(desc.name(), number_of_qubits, parameters);
103 2198 }
104
105 196544 void GateUnitaryMatrixUtils::check_and_throw_upon_wrong_number_of_parameters(
106 OpType op_type, unsigned number_of_qubits,
107 const std::vector<double>& parameters,
108 unsigned expected_number_of_parameters) {
109
2/2
✓ Branch 1 taken 195014 times.
✓ Branch 2 taken 1530 times.
2/2
✓ Decision 'true' taken 195014 times.
✓ Decision 'false' taken 1530 times.
196544 if (parameters.size() == expected_number_of_parameters) {
110 195014 return;
111 }
112
1/2
✓ Branch 1 taken 1530 times.
✗ Branch 2 not taken.
1530 std::stringstream ss;
113
1/2
✓ Branch 1 taken 1530 times.
✗ Branch 2 not taken.
3060 ss << get_error_prefix(op_type, number_of_qubits, parameters)
114
3/6
✓ Branch 1 taken 1530 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1530 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1530 times.
✗ Branch 8 not taken.
1530 << "wrong number of parameters (expected " << expected_number_of_parameters
115
1/2
✓ Branch 1 taken 1530 times.
✗ Branch 2 not taken.
1530 << ")";
116
1/2
✓ Branch 1 taken 1530 times.
✗ Branch 2 not taken.
1530 throw GateUnitaryMatrixError(
117
1/2
✓ Branch 2 taken 1530 times.
✗ Branch 3 not taken.
3060 ss.str(), GateUnitaryMatrixError::Cause::INPUT_ERROR);
118 1530 }
119
120 194434 std::vector<double> GateUnitaryMatrixUtils::get_checked_parameters(
121 const Gate& gate) {
122
1/2
✓ Branch 1 taken 194434 times.
✗ Branch 2 not taken.
194434 const std::vector<Expr> parameter_expressions = gate.get_params();
123
1/2
✓ Branch 1 taken 194434 times.
✗ Branch 2 not taken.
194434 const unsigned int number_of_qubits = gate.n_qubits();
124
1/2
✓ Branch 3 taken 194434 times.
✗ Branch 4 not taken.
194434 std::vector<double> parameters(parameter_expressions.size());
125
2/2
✓ Branch 1 taken 136482 times.
✓ Branch 2 taken 194434 times.
2/2
✓ Decision 'true' taken 136482 times.
✓ Decision 'false' taken 194434 times.
330916 for (unsigned nn = 0; nn < parameters.size(); ++nn) {
126
1/2
✓ Branch 2 taken 136482 times.
✗ Branch 3 not taken.
136482 const auto optional_value = eval_expr(parameter_expressions[nn]);
127
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 136482 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 136482 times.
136482 if (!optional_value) {
128 std::stringstream ss;
129 ss << get_error_prefix(gate.get_name(), number_of_qubits, parameters)
130 << "parameter[" << nn << "] is symbolic";
131 throw GateUnitaryMatrixError(
132 ss.str(), GateUnitaryMatrixError::Cause::SYMBOLIC_PARAMETERS);
133 }
134
1/2
✓ Branch 1 taken 136482 times.
✗ Branch 2 not taken.
136482 const double value = optional_value.value();
135
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 136482 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 136482 times.
136482 if (!std::isfinite(value)) {
136 std::stringstream ss;
137 ss << get_error_prefix(gate.get_name(), number_of_qubits, parameters)
138 << "parameter[" << nn << "] has non-finite value " << value;
139 throw GateUnitaryMatrixError(
140 ss.str(), GateUnitaryMatrixError::Cause::NON_FINITE_PARAMETER);
141 }
142 136482 parameters[nn] = value;
143 }
144 388868 return parameters;
145 194434 }
146
147 } // namespace internal
148 } // namespace tket
149