GCC Code Coverage Report


Directory: ./
File: Architecture/Architecture.cpp
Date: 2022-10-15 05:10:18
Warnings: 1 unchecked decisions!
Exec Total Coverage
Lines: 155 183 84.7%
Functions: 16 20 80.0%
Branches: 158 306 51.6%
Decisions: 16 34 47.1%

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 "Architecture/Architecture.hpp"
16
17 #include <boost/graph/biconnected_components.hpp>
18 #include <unordered_set>
19 #include <vector>
20
21 #include "Graphs/ArticulationPoints.hpp"
22 #include "Utils/Json.hpp"
23 #include "Utils/UnitID.hpp"
24
25 namespace tket {
26
27 bool Architecture::valid_operation(const std::vector<Node>& uids) const {
28
0/2
✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
for (Node n : uids) {
29
0/2
✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
if (!this->node_exists(Node(n))) return false;
30 }
31
0/2
✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
if (uids.size() == 1) {
32 return true;
33
0/2
✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
} else if (uids.size() == 2) {
34
0/2
✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
if (this->bidirectional_edge_exists(uids[0], uids[1])) {
35 return true;
36 }
37 }
38 return false;
39 }
40
41 Architecture Architecture::create_subarch(
42 const std::vector<Node>& subarc_nodes) const {
43 Architecture subarc(subarc_nodes);
44
0/1
? Decision couldn't be analyzed.
for (auto [u1, u2] : get_all_edges_vec()) {
45
0/2
✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
if (subarc.node_exists(u1) && subarc.node_exists(u2)) {
46 subarc.add_connection(u1, u2);
47 }
48 }
49 return subarc;
50 }
51
52 // Given a vector of lengths of lines, returns a vector of lines of these sizes
53 // comprised of architecture nodes
54 8 std::vector<node_vector_t> Architecture::get_lines(
55 std::vector<unsigned> required_lengths) const {
56 // check total length doesn't exceed number of nodes
57
1/2
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 16 times.
16 if (std::accumulate(required_lengths.begin(), required_lengths.end(), 0u) >
58 8 n_nodes()) {
59 throw ArchitectureInvalidity(
60 "Not enough nodes to satisfy required lengths.");
61 }
62
1/2
✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
8 std::sort(
63 required_lengths.begin(), required_lengths.end(),
64 std::greater<unsigned>());
65
66
2/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
8 UndirectedConnGraph curr_graph(get_undirected_connectivity());
67 8 std::vector<node_vector_t> found_lines;
68
2/2
✓ Branch 5 taken 8 times.
✓ Branch 6 taken 8 times.
2/2
✓ Decision 'true' taken 8 times.
✓ Decision 'false' taken 8 times.
16 for (unsigned length : required_lengths) {
69 std::vector<Vertex> longest(
70
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 graphs::longest_simple_path(curr_graph, length));
71
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
1/2
✓ Decision 'true' taken 8 times.
✗ Decision 'false' not taken.
8 if (longest.size() >= length) {
72
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 longest.resize(length);
73 // convert Vertex to Node
74 8 node_vector_t to_add;
75
2/2
✓ Branch 5 taken 27 times.
✓ Branch 6 taken 8 times.
2/2
✓ Decision 'true' taken 27 times.
✓ Decision 'false' taken 8 times.
35 for (Vertex v : longest) {
76
2/4
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 27 times.
✗ Branch 5 not taken.
27 to_add.push_back(curr_graph[v]);
77 }
78
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 found_lines.push_back(to_add);
79
2/2
✓ Branch 5 taken 27 times.
✓ Branch 6 taken 8 times.
2/2
✓ Decision 'true' taken 27 times.
✓ Decision 'false' taken 8 times.
35 for (Vertex v : longest) {
80
1/2
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
27 boost::clear_vertex(v, curr_graph);
81 }
82 8 }
83 8 }
84 16 return found_lines;
85 8 }
86
87 std::set<Node> Architecture::get_articulation_points(
88 const Architecture& subarc) const {
89 return graphs::get_subgraph_aps<Node>(
90 get_undirected_connectivity(), subarc.get_undirected_connectivity());
91 }
92
93 452 std::set<Node> Architecture::get_articulation_points() const {
94 452 std::set<Vertex> aps;
95
2/4
✓ Branch 1 taken 452 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 452 times.
✗ Branch 5 not taken.
452 UndirectedConnGraph undir_g = get_undirected_connectivity();
96
2/4
✓ Branch 2 taken 452 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 452 times.
✗ Branch 6 not taken.
452 boost::articulation_points(undir_g, std::inserter(aps, aps.begin()));
97 452 std::set<Node> ret;
98
2/2
✓ Branch 5 taken 33091 times.
✓ Branch 6 taken 452 times.
2/2
✓ Decision 'true' taken 33091 times.
✓ Decision 'false' taken 452 times.
33543 for (Vertex ap : aps) {
99
2/4
✓ Branch 1 taken 33091 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 33091 times.
✗ Branch 5 not taken.
33091 ret.insert(undir_g[ap]);
100 }
101 904 return ret;
102 452 }
103
104 446 static bool lexicographical_comparison(
105 const std::vector<size_t>& dist1, const std::vector<size_t>& dist2) {
106 446 return std::lexicographical_compare(
107 446 dist1.begin(), dist1.end(), dist2.begin(), dist2.end());
108 }
109
110 446 std::optional<Node> Architecture::find_worst_node(
111 const Architecture& original_arch) {
112
1/2
✓ Branch 1 taken 446 times.
✗ Branch 2 not taken.
446 node_set_t ap = get_articulation_points();
113
1/2
✓ Branch 1 taken 446 times.
✗ Branch 2 not taken.
446 node_set_t min_nodes = min_degree_nodes();
114
115 446 std::set<Node> bad_nodes;
116
2/4
✓ Branch 2 taken 446 times.
✗ Branch 3 not taken.
✓ Branch 9 taken 446 times.
✗ Branch 10 not taken.
446 std::set_difference(
117 min_nodes.cbegin(), min_nodes.cend(), ap.cbegin(), ap.cend(),
118 std::inserter(bad_nodes, bad_nodes.begin()));
119
120
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 446 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 446 times.
446 if (bad_nodes.empty()) {
121 return std::nullopt;
122 }
123
124 446 std::vector<size_t> worst_distances, temp_distances;
125 446 Node worst_node = *bad_nodes.begin();
126
2/4
✓ Branch 1 taken 446 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 446 times.
✗ Branch 5 not taken.
446 worst_distances = get_distances(worst_node);
127
2/2
✓ Branch 6 taken 893 times.
✓ Branch 7 taken 446 times.
2/2
✓ Decision 'true' taken 893 times.
✓ Decision 'false' taken 446 times.
1339 for (Node temp_node : bad_nodes) {
128
2/4
✓ Branch 1 taken 893 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 893 times.
✗ Branch 5 not taken.
893 temp_distances = get_distances(temp_node);
129
130 int distance_comp =
131
1/2
✓ Branch 1 taken 893 times.
✗ Branch 2 not taken.
893 tri_lexicographical_comparison(temp_distances, worst_distances);
132
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 893 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 893 times.
893 if (distance_comp == 1) {
133 worst_node = temp_node;
134 worst_distances = temp_distances;
135
2/2
✓ Branch 0 taken 446 times.
✓ Branch 1 taken 447 times.
2/2
✓ Decision 'true' taken 446 times.
✓ Decision 'false' taken 447 times.
893 } else if (distance_comp == -1) {
136 std::vector<size_t> temp_distances_full =
137
2/4
✓ Branch 1 taken 446 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 446 times.
✗ Branch 5 not taken.
446 original_arch.get_distances(temp_node);
138 std::vector<size_t> worst_distances_full =
139
2/4
✓ Branch 1 taken 446 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 446 times.
✗ Branch 5 not taken.
446 original_arch.get_distances(worst_node);
140
2/4
✓ Branch 1 taken 446 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 446 times.
446 if (lexicographical_comparison(
141 temp_distances_full, worst_distances_full)) {
142 worst_node = temp_node;
143 worst_distances = temp_distances;
144 }
145 446 }
146 893 }
147 446 return worst_node;
148 446 }
149
150 8 node_set_t Architecture::remove_worst_nodes(unsigned num) {
151 8 node_set_t out;
152
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 Architecture original_arch(*this);
153
2/2
✓ Branch 0 taken 446 times.
✓ Branch 1 taken 8 times.
454 for (unsigned k = 0; k < num; k++) {
154
1/2
✓ Branch 1 taken 446 times.
✗ Branch 2 not taken.
446 std::optional<Node> v = find_worst_node(original_arch);
155
1/2
✓ Branch 1 taken 446 times.
✗ Branch 2 not taken.
446 if (v.has_value()) {
156
2/4
✓ Branch 1 taken 446 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 446 times.
✗ Branch 5 not taken.
446 remove_node(v.value());
157
2/4
✓ Branch 1 taken 446 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 446 times.
✗ Branch 5 not taken.
446 out.insert(v.value());
158 }
159 446 }
160 16 return out;
161 8 }
162
163 893 int tri_lexicographical_comparison(
164 const std::vector<std::size_t>& dist1,
165 const std::vector<std::size_t>& dist2) {
166 // add assertion that these are the same size distance vectors
167 893 auto start_dist1 = dist1.cbegin();
168 893 auto start_dist2 = dist2.cbegin();
169
170
2/2
✓ Branch 2 taken 34427 times.
✓ Branch 3 taken 446 times.
34873 while (start_dist1 != dist1.cend()) {
171
5/6
✓ Branch 2 taken 34427 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 447 times.
✓ Branch 7 taken 33980 times.
✓ Branch 8 taken 447 times.
✓ Branch 9 taken 33980 times.
34427 if (start_dist2 == dist2.cend() || *start_dist2 < *start_dist1) {
172 447 return 0;
173
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 33980 times.
33980 } else if (*start_dist1 < *start_dist2) {
174 return 1;
175 }
176 33980 ++start_dist1;
177 33980 ++start_dist2;
178 }
179 446 return -1;
180 }
181
182 165 MatrixXb Architecture::get_connectivity() const {
183 165 unsigned n = n_nodes();
184
1/2
✓ Branch 1 taken 165 times.
✗ Branch 2 not taken.
165 MatrixXb connectivity = MatrixXb(n, n);
185
2/2
✓ Branch 0 taken 1021 times.
✓ Branch 1 taken 165 times.
1186 for (unsigned i = 0; i != n; ++i) {
186
2/2
✓ Branch 0 taken 8583 times.
✓ Branch 1 taken 1021 times.
9604 for (unsigned j = 0; j != n; ++j) {
187
1/2
✓ Branch 1 taken 8583 times.
✗ Branch 2 not taken.
8583 connectivity(i, j) =
188
16/32
✓ Branch 1 taken 8583 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8583 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 8583 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 7682 times.
✓ Branch 10 taken 901 times.
✓ Branch 12 taken 7682 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 7682 times.
✗ Branch 16 not taken.
✓ Branch 18 taken 7682 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 901 times.
✓ Branch 21 taken 6781 times.
✓ Branch 22 taken 7682 times.
✓ Branch 23 taken 901 times.
✓ Branch 25 taken 7682 times.
✓ Branch 26 taken 901 times.
✓ Branch 28 taken 8583 times.
✗ Branch 29 not taken.
✓ Branch 31 taken 8583 times.
✗ Branch 32 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✗ Branch 43 not taken.
✗ Branch 44 not taken.
17166 edge_exists(Node(i), Node(j)) || edge_exists(Node(j), Node(i));
189 }
190 }
191 330 return connectivity;
192 }
193
194 2368 void to_json(nlohmann::json& j, const Architecture::Connection& link) {
195
1/2
✓ Branch 2 taken 2368 times.
✗ Branch 3 not taken.
2368 j.push_back(link.first);
196
1/2
✓ Branch 2 taken 2368 times.
✗ Branch 3 not taken.
2368 j.push_back(link.second);
197 2368 }
198
199 void from_json(const nlohmann::json& j, Architecture::Connection& link) {
200 link.first = j.at(0).get<Node>();
201 link.second = j.at(1).get<Node>();
202 }
203
204 134 void to_json(nlohmann::json& j, const Architecture& ar) {
205 // Preserve the internal order of ids since Placement depends on this
206
1/2
✓ Branch 2 taken 134 times.
✗ Branch 3 not taken.
134 auto uid_its = ar.nodes();
207
1/2
✓ Branch 4 taken 134 times.
✗ Branch 5 not taken.
134 std::vector<Node> nodes{uid_its.begin(), uid_its.end()};
208
2/4
✓ Branch 1 taken 134 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 134 times.
✗ Branch 5 not taken.
134 j["nodes"] = nodes;
209
210 134 nlohmann::json links;
211
3/4
✓ Branch 1 taken 134 times.
✗ Branch 2 not taken.
✓ Branch 8 taken 2358 times.
✓ Branch 9 taken 134 times.
2492 for (const Architecture::Connection& con : ar.get_all_edges_vec()) {
212 2358 nlohmann::json entry;
213
2/4
✓ Branch 1 taken 2358 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2358 times.
✗ Branch 5 not taken.
2358 entry["link"] = con;
214
2/4
✓ Branch 1 taken 2358 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 2358 times.
✗ Branch 6 not taken.
2358 entry["weight"] = ar.get_connection_weight(con.first, con.second);
215
1/2
✓ Branch 1 taken 2358 times.
✗ Branch 2 not taken.
2358 links.push_back(entry);
216 2492 }
217
2/4
✓ Branch 1 taken 134 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 134 times.
✗ Branch 5 not taken.
134 j["links"] = links;
218 134 }
219
220 15 void from_json(const nlohmann::json& j, Architecture& ar) {
221
4/6
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
✓ Branch 11 taken 191 times.
✓ Branch 12 taken 15 times.
206 for (const Node& n : j.at("nodes").get<node_vector_t>()) {
222
1/2
✓ Branch 1 taken 191 times.
✗ Branch 2 not taken.
191 ar.add_node(n);
223 15 }
224
6/10
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 323 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 323 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 338 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 323 times.
✓ Branch 15 taken 15 times.
338 for (const auto& j_entry : j.at("links")) {
225 Architecture::Connection l =
226
2/4
✓ Branch 1 taken 323 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 323 times.
✗ Branch 5 not taken.
323 j_entry.at("link").get<Architecture::Connection>();
227
2/4
✓ Branch 1 taken 323 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 323 times.
✗ Branch 5 not taken.
323 unsigned w = j_entry.at("weight").get<unsigned>();
228
1/2
✓ Branch 1 taken 323 times.
✗ Branch 2 not taken.
323 ar.add_connection(l.first, l.second, w);
229 323 }
230 15 }
231
232 2 void to_json(nlohmann::json& j, const FullyConnected& ar) {
233
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 auto uid_its = ar.nodes();
234
1/2
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
2 std::vector<Node> nodes{uid_its.begin(), uid_its.end()};
235
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
2 j["nodes"] = nodes;
236 2 }
237
238 1 void from_json(const nlohmann::json& j, FullyConnected& ar) {
239
4/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 11 taken 4 times.
✓ Branch 12 taken 1 times.
5 for (const Node& n : j.at("nodes").get<node_vector_t>()) {
240
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 ar.add_node(n);
241 1 }
242 1 }
243
244 //////////////////////////////////////
245 // Architecture subclasses //
246 //////////////////////////////////////
247
248 25 RingArch::RingArch(unsigned numberOfNodes)
249
1/2
✓ Branch 2 taken 25 times.
✗ Branch 3 not taken.
25 : Architecture(get_edges(numberOfNodes)) {}
250
251 25 std::vector<Architecture::Connection> RingArch::get_edges(
252 unsigned numberOfNodes) {
253 25 std::vector<Connection> edges;
254
2/2
✓ Branch 0 taken 212 times.
✓ Branch 1 taken 25 times.
237 for (unsigned i = 0; i < numberOfNodes; i++) {
255
2/4
✓ Branch 2 taken 212 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 212 times.
✗ Branch 6 not taken.
424 Node n1("ringNode", i);
256
2/4
✓ Branch 2 taken 212 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 212 times.
✗ Branch 6 not taken.
424 Node n2("ringNode", (i + 1) % numberOfNodes);
257
1/2
✓ Branch 2 taken 212 times.
✗ Branch 3 not taken.
212 edges.push_back({n1, n2});
258 212 }
259 25 return edges;
260 }
261
262 76 SquareGrid::SquareGrid(
263 76 const unsigned dim_r, const unsigned dim_c, const unsigned _layers)
264 76 : Architecture(get_edges(dim_r, dim_c, _layers)),
265 76 dimension_r{dim_r},
266 76 dimension_c{dim_c},
267
1/2
✓ Branch 2 taken 76 times.
✗ Branch 3 not taken.
152 layers{_layers} {}
268
269 76 std::vector<Architecture::Connection> SquareGrid::get_edges(
270 const unsigned dim_r, const unsigned dim_c, const unsigned layers) {
271 76 std::vector<Connection> edges;
272
2/2
✓ Branch 0 taken 130 times.
✓ Branch 1 taken 76 times.
206 for (unsigned l = 0; l < layers; l++) {
273
2/2
✓ Branch 0 taken 320 times.
✓ Branch 1 taken 130 times.
450 for (unsigned ver = 0; ver < dim_r; ver++) {
274
2/2
✓ Branch 0 taken 1626 times.
✓ Branch 1 taken 320 times.
1946 for (unsigned hor = 0; hor < dim_c; hor++) {
275
2/4
✓ Branch 2 taken 1626 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1626 times.
✗ Branch 6 not taken.
3252 Node n("gridNode", ver, hor, l);
276
2/2
✓ Branch 0 taken 1306 times.
✓ Branch 1 taken 320 times.
1626 if (hor != dim_c - 1) {
277
2/4
✓ Branch 2 taken 1306 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1306 times.
✗ Branch 6 not taken.
2612 Node h_neighbour("gridNode", ver, hor + 1, l);
278
1/2
✓ Branch 2 taken 1306 times.
✗ Branch 3 not taken.
1306 edges.push_back({n, h_neighbour});
279 1306 }
280
2/2
✓ Branch 0 taken 1069 times.
✓ Branch 1 taken 557 times.
1626 if (ver != dim_r - 1) {
281
2/4
✓ Branch 2 taken 1069 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1069 times.
✗ Branch 6 not taken.
2138 Node v_neighbour("gridNode", ver + 1, hor, l);
282
1/2
✓ Branch 2 taken 1069 times.
✗ Branch 3 not taken.
1069 edges.push_back({n, v_neighbour});
283 1069 }
284
2/2
✓ Branch 0 taken 821 times.
✓ Branch 1 taken 805 times.
1626 if (l != layers - 1) {
285
2/4
✓ Branch 2 taken 821 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 821 times.
✗ Branch 6 not taken.
1642 Node l_neighbour("gridNode", ver, hor, l + 1);
286
1/2
✓ Branch 2 taken 821 times.
✗ Branch 3 not taken.
821 edges.push_back({n, l_neighbour});
287 821 }
288 1626 }
289 }
290 }
291 76 return edges;
292 }
293
294 } // namespace tket
295