GCC Code Coverage Report


Directory: ./
File: Gate/GateUnitarySparseMatrix.cpp
Date: 2022-10-15 05:10:18
Warnings: 1 unchecked decisions!
Exec Total Coverage
Lines: 69 70 98.6%
Functions: 7 7 100.0%
Branches: 49 81 60.5%
Decisions: 18 21 85.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 "GateUnitarySparseMatrix.hpp"
16
17 #include <tkassert/Assert.hpp>
18
19 #include "Gate/Gate.hpp"
20 #include "GateUnitaryMatrix.hpp"
21 #include "GateUnitaryMatrixError.hpp"
22 #include "GateUnitaryMatrixImplementations.hpp"
23 #include "GateUnitaryMatrixUtils.hpp"
24
25 namespace tket {
26 namespace internal {
27
28 // Given a controlled type, which can be written as
29 // a number of control qubits applied to a more primitive type,
30 // return the primitive type. (e.g. CnX returns X).
31 // Returns "noop" if it's not a controlled type we know how to deal with.
32 // We are excluding things like, e.g., CX, which are only 4x4 and too small
33 // to be worth dealing with specially.
34 191456 static OpType get_primitive_type(OpType type_without_controls) {
35
5/5
✓ Branch 0 taken 93 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 25 times.
✓ Branch 4 taken 191322 times.
191456 switch (type_without_controls) {
36
0/1
✗ Decision 'true' not taken.
93 case OpType::CnX:
37 // fall through
38 case OpType::CCX:
39 93 return OpType::X;
40
41
1/1
✓ Decision 'true' taken 8 times.
8 case OpType::CnZ:
42 8 return OpType::Z;
43
44
1/1
✓ Decision 'true' taken 8 times.
8 case OpType::CnY:
45 8 return OpType::Y;
46
47
1/1
✓ Decision 'true' taken 25 times.
25 case OpType::CnRy:
48 25 return OpType::Ry;
49
50
1/1
✓ Decision 'true' taken 191322 times.
191322 default:
51 191322 return OpType::noop;
52 }
53 }
54
55 // We have a type acting on 1 qubit.
56 // Convert this to a type acting on n qubits (given by the Gate object)
57 // by adding controls.
58 static std::vector<TripletCd>
59 134 convert_1qb_type_to_controlled_type_and_get_triplets(
60 const Gate& gate, OpType one_qubit_type, double abs_epsilon) {
61
2/4
✓ Branch 1 taken 134 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 134 times.
✗ Branch 5 not taken.
134 const Gate new_gate(one_qubit_type, gate.get_params(), 1);
62
1/2
✓ Branch 1 taken 134 times.
✗ Branch 2 not taken.
134 const auto small_unitary = GateUnitaryMatrix::get_unitary(new_gate);
63
1/2
✓ Branch 1 taken 134 times.
✗ Branch 2 not taken.
134 auto triplets = get_triplets(small_unitary, abs_epsilon);
64
65 // e.g., if CnX or CnRy for n=3, then U is 2x2, but we are embedding into
66 // the bottom right corner of an 8x8 identity matrix
67
2/4
✓ Branch 1 taken 134 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 134 times.
✗ Branch 5 not taken.
134 unsigned full_matr_size = get_matrix_size(gate.n_qubits());
68 134 unsigned translation = full_matr_size - small_unitary.rows();
69
1/2
✓ Branch 0 taken 134 times.
✗ Branch 1 not taken.
0/1
? Decision couldn't be analyzed.
134 if (translation > 0) {
70
2/2
✓ Branch 4 taken 318 times.
✓ Branch 5 taken 134 times.
2/2
✓ Decision 'true' taken 318 times.
✓ Decision 'false' taken 134 times.
452 for (auto& triplet : triplets) {
71 318 triplet = TripletCd(
72 318 triplet.row() + translation, triplet.col() + translation,
73 triplet.value());
74 }
75
1/2
✓ Branch 2 taken 134 times.
✗ Branch 3 not taken.
134 triplets.reserve(triplets.size() + translation);
76
2/2
✓ Branch 0 taken 1056 times.
✓ Branch 1 taken 134 times.
2/2
✓ Decision 'true' taken 1056 times.
✓ Decision 'false' taken 134 times.
1190 for (unsigned ii = 0; ii < translation; ++ii) {
77
1/2
✓ Branch 1 taken 1056 times.
✗ Branch 2 not taken.
1056 triplets.emplace_back(ii, ii, 1.0);
78 }
79 }
80 268 return triplets;
81 134 }
82
83 namespace {
84 struct FixedTripletsWithNoParameters {
85 std::vector<TripletCd> bridge_triplets;
86 std::vector<TripletCd> cswap_triplets;
87
88 FixedTripletsWithNoParameters();
89
90 // It just so happens that these gates all take
91 // the same number of qubits and parameters.
92 // Therefore, test the gate for this, as well as
93 // returning the const data for use.
94 static const FixedTripletsWithNoParameters& get(const Gate& gate);
95 };
96
97 1 FixedTripletsWithNoParameters::FixedTripletsWithNoParameters() {
98
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 bridge_triplets.reserve(8);
99
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 cswap_triplets.reserve(8);
100 const auto& bridge_cols =
101
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 GateUnitaryMatrixImplementations::get_bridge_columns();
102 const auto& cswap_cols =
103
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 GateUnitaryMatrixImplementations::get_cswap_columns();
104
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
2/2
✓ Decision 'true' taken 8 times.
✓ Decision 'false' taken 1 times.
9 for (unsigned ii = 0; ii < 8; ++ii) {
105
1/2
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
8 bridge_triplets.emplace_back(ii, bridge_cols[ii], 1.0);
106
1/2
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
8 cswap_triplets.emplace_back(ii, cswap_cols[ii], 1.0);
107 }
108 1 }
109
110 19 const FixedTripletsWithNoParameters& FixedTripletsWithNoParameters::get(
111 const Gate& gate) {
112
4/8
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 18 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
19 static const FixedTripletsWithNoParameters data;
113
114
1/2
✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
19 GateUnitaryMatrixUtils::check_and_throw_upon_wrong_number_of_parameters(
115
1/2
✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
19 gate.get_type(), gate.n_qubits(),
116 38 GateUnitaryMatrixUtils::get_checked_parameters(gate), 0);
117 TKET_ASSERT(gate.n_qubits() == 3);
118 19 return data;
119 }
120 } // namespace
121
122 41 static std::vector<TripletCd> get_phase_gadget_triplets(
123 unsigned number_of_qubits, double param) {
124 // All diagonal entries have abs value 1,
125 // so no point in abs_epsilon.
126 const auto entries =
127 GateUnitaryMatrixImplementations::PhaseGadget_diagonal_entries(
128
1/2
✓ Branch 1 taken 41 times.
✗ Branch 2 not taken.
41 number_of_qubits, param);
129
1/2
✓ Branch 3 taken 41 times.
✗ Branch 4 not taken.
41 std::vector<TripletCd> triplets(entries.rows());
130
2/2
✓ Branch 1 taken 294 times.
✓ Branch 2 taken 41 times.
2/2
✓ Decision 'true' taken 294 times.
✓ Decision 'false' taken 41 times.
335 for (unsigned ii = 0; ii < entries.rows(); ++ii) {
131
1/2
✓ Branch 1 taken 294 times.
✗ Branch 2 not taken.
294 triplets[ii] = TripletCd(ii, ii, entries(ii));
132 }
133 82 return triplets;
134 41 }
135
136 191322 static std::vector<TripletCd> get_triplets_for_noncontrolled_gate(
137 const Gate& gate) {
138
4/4
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 41 times.
✓ Branch 4 taken 191262 times.
191322 switch (gate.get_type()) {
139
1/1
✓ Decision 'true' taken 5 times.
5 case OpType::CSWAP:
140 5 return FixedTripletsWithNoParameters::get(gate).cswap_triplets;
141
1/1
✓ Decision 'true' taken 14 times.
14 case OpType::BRIDGE:
142 14 return FixedTripletsWithNoParameters::get(gate).bridge_triplets;
143
1/1
✓ Decision 'true' taken 41 times.
41 case OpType::PhaseGadget: {
144
1/2
✓ Branch 1 taken 41 times.
✗ Branch 2 not taken.
41 const auto params = GateUnitaryMatrixUtils::get_checked_parameters(gate);
145
1/2
✓ Branch 2 taken 41 times.
✗ Branch 3 not taken.
41 GateUnitaryMatrixUtils::check_and_throw_upon_wrong_number_of_parameters(
146
1/2
✓ Branch 1 taken 41 times.
✗ Branch 2 not taken.
41 gate.get_type(), gate.n_qubits(), params, 1);
147
2/4
✓ Branch 2 taken 41 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 41 times.
✗ Branch 6 not taken.
41 return get_phase_gadget_triplets(gate.n_qubits(), params[0]);
148 41 }
149
1/1
✓ Decision 'true' taken 191262 times.
191262 default:
150 191262 return {};
151 }
152 }
153
154 191456 std::vector<TripletCd> GateUnitarySparseMatrix::get_unitary_triplets(
155 const Gate& gate, double abs_epsilon) {
156 191456 const auto type = gate.get_type();
157 191456 const auto primitive_type = get_primitive_type(type);
158
2/2
✓ Branch 0 taken 134 times.
✓ Branch 1 taken 191322 times.
2/2
✓ Decision 'true' taken 134 times.
✓ Decision 'false' taken 191322 times.
191456 if (primitive_type != OpType::noop) {
159 try {
160 return convert_1qb_type_to_controlled_type_and_get_triplets(
161
1/2
✓ Branch 1 taken 134 times.
✗ Branch 2 not taken.
134 gate, primitive_type, abs_epsilon);
162 } catch (const GateUnitaryMatrixError& e) {
163 // GCOVR_EXCL_START
164 TKET_ASSERT(
165 AssertMessage()
166 << "Converting " << gate.get_name()
167 << " to sparse unitary, via adding controls to gate type "
168 << OpDesc(primitive_type).name() << ": " << e.what());
169 // GCOVR_EXCL_STOP
170 }
171 }
172 191322 return get_triplets_for_noncontrolled_gate(gate);
173 }
174
175 } // namespace internal
176 } // namespace tket
177