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 "Mapping/LexiRoute.hpp" | |||
16 | ||||
17 | #include "Mapping/MappingFrontier.hpp" | |||
18 | #include "Utils/Json.hpp" | |||
19 | ||||
20 | namespace tket { | |||
21 | ||||
22 | 5725 | LexiRoute::LexiRoute( | ||
23 | const ArchitecturePtr& _architecture, | |||
24 | 5725 | MappingFrontier_ptr& _mapping_frontier) | ||
25 | 5725 | : architecture_(_architecture), mapping_frontier_(_mapping_frontier) { | ||
26 | // set initial logical->physical labelling | |||
27 |
3/4✓ Branch 2 taken 5725 times.
✗ Branch 3 not taken.
✓ Branch 9 taken 114004 times.
✓ Branch 10 taken 5725 times.
|
0/1? Decision couldn't be analyzed.
|
119729 | for (const Qubit& qb : this->mapping_frontier_->circuit_.all_qubits()) { |
28 |
1/2✓ Branch 2 taken 114004 times.
✗ Branch 3 not taken.
|
114004 | this->labelling_.insert({qb, qb}); | |
29 |
1/2✓ Branch 1 taken 114004 times.
✗ Branch 2 not taken.
|
114004 | Node n(qb); | |
30 | // store which Node have been asigned to Circuit already | |||
31 |
3/4✓ Branch 2 taken 114004 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 99969 times.
✓ Branch 5 taken 14035 times.
|
2/2✓ Decision 'true' taken 99969 times.
✓ Decision 'false' taken 14035 times.
|
114004 | if (this->architecture_->node_exists(n)) { |
32 |
1/2✓ Branch 1 taken 99969 times.
✗ Branch 2 not taken.
|
99969 | this->assigned_nodes_.insert(n); | |
33 | } | |||
34 | 119729 | } | ||
35 | 5725 | } | ||
36 | ||||
37 | 408 | bool LexiRoute::assign_at_distance( | ||
38 | const UnitID& assignee, const Node& root, unsigned distances) { | |||
39 | 408 | node_set_t valid_nodes; | ||
40 | 408 | for (const Node& neighbour : | ||
41 |
3/4✓ Branch 2 taken 408 times.
✗ Branch 3 not taken.
✓ Branch 9 taken 1230 times.
✓ Branch 10 taken 408 times.
|
2046 | this->architecture_->nodes_at_distance(root, distances)) { | |
42 | // A node is unassigned if it's empty or holding an ancilla | |||
43 |
3/4✓ Branch 2 taken 1230 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 844 times.
✓ Branch 6 taken 386 times.
|
2/2✓ Decision 'true' taken 401 times.
✓ Decision 'false' taken 1673 times.
|
2074 | if (this->assigned_nodes_.find(neighbour) == this->assigned_nodes_.end() || |
44 |
3/4✓ Branch 2 taken 844 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15 times.
✓ Branch 5 taken 829 times.
|
1688 | this->mapping_frontier_->ancilla_nodes_.find(neighbour) != | |
45 |
2/2✓ Branch 3 taken 401 times.
✓ Branch 4 taken 829 times.
|
2918 | this->mapping_frontier_->ancilla_nodes_.end()) { | |
46 |
1/2✓ Branch 1 taken 401 times.
✗ Branch 2 not taken.
|
401 | valid_nodes.insert(neighbour); | |
47 | } | |||
48 | 408 | } | ||
49 |
2/2✓ Branch 1 taken 139 times.
✓ Branch 2 taken 269 times.
|
2/2✓ Decision 'true' taken 139 times.
✓ Decision 'false' taken 269 times.
|
408 | if (valid_nodes.size() == 1) { |
50 | 139 | auto it = valid_nodes.begin(); | ||
51 | // If the node to be assigned holds an ancilla | |||
52 |
1/2✓ Branch 3 taken 139 times.
✗ Branch 4 not taken.
|
2/2✓ Decision 'true' taken 5 times.
✓ Decision 'false' taken 134 times.
|
139 | if (this->mapping_frontier_->ancilla_nodes_.find(*it) != |
53 |
2/2✓ Branch 3 taken 5 times.
✓ Branch 4 taken 134 times.
|
278 | this->mapping_frontier_->ancilla_nodes_.end()) { | |
54 | // => node *it is already present in circuit, but as an ancilla | |||
55 | // Merge the logical qubit to the end of the ancilla. | |||
56 | // notice that the merge_ancilla updates the qubit maps. | |||
57 |
1/2✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
|
5 | this->mapping_frontier_->merge_ancilla(assignee, *it); | |
58 |
1/2✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
|
5 | this->mapping_frontier_->ancilla_nodes_.erase(*it); | |
59 |
1/2✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | this->labelling_.erase(*it); | |
60 |
1/2✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | this->labelling_[assignee] = *it; | |
61 | } else { | |||
62 |
1/2✓ Branch 2 taken 134 times.
✗ Branch 3 not taken.
|
134 | this->labelling_[assignee] = *it; | |
63 |
1/2✓ Branch 2 taken 134 times.
✗ Branch 3 not taken.
|
134 | this->assigned_nodes_.insert(*it); | |
64 | // Assignee is a UnitID obtained from the circuit | |||
65 | // so we need to use the initial map to find the associated qubit. | |||
66 |
1/2✓ Branch 3 taken 134 times.
✗ Branch 4 not taken.
|
536 | this->mapping_frontier_->update_bimaps( | |
67 |
1/2✓ Branch 3 taken 134 times.
✗ Branch 4 not taken.
|
402 | this->mapping_frontier_->get_qubit_from_circuit_uid(assignee), *it); | |
68 | } | |||
69 | 139 | return true; | ||
70 | } | |||
71 |
2/2✓ Branch 1 taken 103 times.
✓ Branch 2 taken 166 times.
|
2/2✓ Decision 'true' taken 103 times.
✓ Decision 'false' taken 166 times.
|
269 | if (valid_nodes.size() > 1) { |
72 | 103 | auto it = valid_nodes.begin(); | ||
73 | lexicographical_distances_t winning_distances = | |||
74 |
2/4✓ Branch 3 taken 103 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 103 times.
✗ Branch 7 not taken.
|
103 | this->architecture_->get_distances(*it); | |
75 | 103 | Node preserved_node = *it; | ||
76 | 103 | ++it; | ||
77 |
2/2✓ Branch 3 taken 159 times.
✓ Branch 4 taken 103 times.
|
2/2✓ Decision 'true' taken 159 times.
✓ Decision 'false' taken 103 times.
|
262 | for (; it != valid_nodes.end(); ++it) { |
78 | lexicographical_distances_t comparison_distances = | |||
79 |
2/4✓ Branch 3 taken 159 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 159 times.
✗ Branch 7 not taken.
|
159 | this->architecture_->get_distances(*it); | |
80 |
3/4✓ Branch 2 taken 159 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 21 times.
✓ Branch 6 taken 138 times.
|
2/2✓ Decision 'true' taken 21 times.
✓ Decision 'false' taken 138 times.
|
159 | if (comparison_distances < winning_distances) { |
81 | 21 | preserved_node = *it; | ||
82 |
1/2✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
|
21 | winning_distances = comparison_distances; | |
83 | } | |||
84 | 159 | } | ||
85 |
1/2✓ Branch 2 taken 103 times.
✗ Branch 3 not taken.
|
2/2✓ Decision 'true' taken 8 times.
✓ Decision 'false' taken 95 times.
|
103 | if (this->mapping_frontier_->ancilla_nodes_.find(preserved_node) != |
86 |
2/2✓ Branch 3 taken 8 times.
✓ Branch 4 taken 95 times.
|
206 | this->mapping_frontier_->ancilla_nodes_.end()) { | |
87 | // => node *it is already present in circuit, but as an ancilla | |||
88 | // Merge the logical qubit to the end of the ancilla. | |||
89 |
1/2✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
|
8 | this->mapping_frontier_->merge_ancilla(assignee, preserved_node); | |
90 |
1/2✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
|
8 | this->mapping_frontier_->ancilla_nodes_.erase(preserved_node); | |
91 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | this->labelling_.erase(preserved_node); | |
92 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | this->labelling_[assignee] = preserved_node; | |
93 | } else { | |||
94 | // add ancilla case | |||
95 |
1/2✓ Branch 1 taken 95 times.
✗ Branch 2 not taken.
|
95 | this->labelling_[assignee] = preserved_node; | |
96 |
1/2✓ Branch 1 taken 95 times.
✗ Branch 2 not taken.
|
95 | this->assigned_nodes_.insert(preserved_node); | |
97 |
1/2✓ Branch 3 taken 95 times.
✗ Branch 4 not taken.
|
285 | this->mapping_frontier_->update_bimaps( | |
98 |
1/2✓ Branch 2 taken 95 times.
✗ Branch 3 not taken.
|
190 | this->mapping_frontier_->get_qubit_from_circuit_uid(assignee), | |
99 | preserved_node); | |||
100 | } | |||
101 | 103 | return true; | ||
102 | 103 | } | ||
103 | 166 | return false; | ||
104 | 408 | } | ||
105 | ||||
106 | 218 | bool LexiRoute::update_labelling() { | ||
107 | // iterate through interacting qubits, assigning them to an Architecture Node | |||
108 | // if they aren't already | |||
109 | 218 | bool relabelled = false; | ||
110 |
2/2✓ Branch 5 taken 845 times.
✓ Branch 6 taken 215 times.
|
2/2✓ Decision 'true' taken 845 times.
✓ Decision 'false' taken 215 times.
|
1060 | for (const auto& pair : this->interacting_uids_) { |
111 | bool uid_0_exist = | |||
112 |
3/6✓ Branch 2 taken 845 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 845 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 845 times.
✗ Branch 9 not taken.
|
845 | this->architecture_->node_exists(Node(this->labelling_[pair.first])); | |
113 | bool uid_1_exist = | |||
114 |
3/6✓ Branch 2 taken 845 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 845 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 845 times.
✗ Branch 9 not taken.
|
845 | this->architecture_->node_exists(Node(this->labelling_[pair.second])); | |
115 |
4/4✓ Branch 0 taken 775 times.
✓ Branch 1 taken 70 times.
✓ Branch 2 taken 164 times.
✓ Branch 3 taken 611 times.
|
2/2✓ Decision 'true' taken 234 times.
✓ Decision 'false' taken 611 times.
|
845 | if (!uid_0_exist || !uid_1_exist) { |
116 | 234 | relabelled = true; | ||
117 | } | |||
118 |
4/4✓ Branch 0 taken 70 times.
✓ Branch 1 taken 775 times.
✓ Branch 2 taken 32 times.
✓ Branch 3 taken 38 times.
|
2/2✓ Decision 'true' taken 32 times.
✓ Decision 'false' taken 813 times.
|
845 | if (!uid_0_exist && !uid_1_exist) { |
119 | // Place one on free unassigned qubit | |||
120 | // Then place second later | |||
121 | // condition => No ancilla qubits assigned, so don't check | |||
122 |
2/2✓ Branch 1 taken 20 times.
✓ Branch 2 taken 12 times.
|
2/2✓ Decision 'true' taken 20 times.
✓ Decision 'false' taken 12 times.
|
32 | if (this->assigned_nodes_.size() == 0) { |
123 | // find nodes with best averaged distance to other nodes | |||
124 | // place it there... | |||
125 | std::set<Node> max_degree_nodes = | |||
126 |
1/2✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
|
20 | this->architecture_->max_degree_nodes(); | |
127 | 20 | auto it = max_degree_nodes.begin(); | ||
128 | lexicographical_distances_t winning_distances = | |||
129 |
2/4✓ Branch 3 taken 20 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 20 times.
✗ Branch 7 not taken.
|
20 | this->architecture_->get_distances(*it); | |
130 | 20 | Node preserved_node = Node(*it); | ||
131 | 20 | ++it; | ||
132 |
2/2✓ Branch 3 taken 111 times.
✓ Branch 4 taken 20 times.
|
2/2✓ Decision 'true' taken 111 times.
✓ Decision 'false' taken 20 times.
|
131 | for (; it != max_degree_nodes.end(); ++it) { |
133 | lexicographical_distances_t comparison_distances = | |||
134 |
2/4✓ Branch 3 taken 111 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 111 times.
✗ Branch 7 not taken.
|
111 | this->architecture_->get_distances(*it); | |
135 |
3/4✓ Branch 2 taken 111 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 108 times.
|
2/2✓ Decision 'true' taken 3 times.
✓ Decision 'false' taken 108 times.
|
111 | if (comparison_distances < winning_distances) { |
136 | 3 | preserved_node = Node(*it); | ||
137 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | winning_distances = comparison_distances; | |
138 | } | |||
139 | 111 | } | ||
140 |
1/2✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
|
20 | this->labelling_[pair.first] = preserved_node; | |
141 |
1/2✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
|
20 | this->assigned_nodes_.insert(preserved_node); | |
142 | // Update bimaps | |||
143 |
1/2✓ Branch 3 taken 20 times.
✗ Branch 4 not taken.
|
40 | this->mapping_frontier_->update_bimaps( | |
144 |
1/2✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
|
40 | this->mapping_frontier_->get_qubit_from_circuit_uid(pair.first), | |
145 | preserved_node); | |||
146 | 20 | uid_0_exist = true; | ||
147 | // given best node, do something | |||
148 | 20 | } else { | ||
149 | // Assign uid_0 to an unassigned node that is | |||
150 | // 1. adjacent to the already assigned nodes | |||
151 | // 2. has an unassigned neighbour | |||
152 | 12 | auto root_it = this->assigned_nodes_.begin(); | ||
153 |
6/6✓ Branch 0 taken 30 times.
✓ Branch 1 taken 11 times.
✓ Branch 4 taken 29 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 29 times.
✓ Branch 7 taken 12 times.
|
0/1? Decision couldn't be analyzed.
|
41 | while (!uid_0_exist && root_it != this->assigned_nodes_.end()) { |
154 | 29 | Node root = *root_it; | ||
155 |
1/2✓ Branch 1 taken 29 times.
✗ Branch 2 not taken.
|
29 | uid_0_exist = this->assign_at_distance(pair.first, root, 1); | |
156 | 29 | ++root_it; | ||
157 | 29 | } | ||
158 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 11 times.
|
2/2✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 11 times.
|
12 | if (!uid_0_exist) { |
159 |
2/4✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
|
1 | throw LexiRouteError( | |
160 | 2 | "Unable to assign physical qubit - no free qubits remaining."); | ||
161 | } | |||
162 | } | |||
163 | } | |||
164 |
3/4✓ Branch 0 taken 38 times.
✓ Branch 1 taken 806 times.
✓ Branch 2 taken 38 times.
✗ Branch 3 not taken.
|
2/2✓ Decision 'true' taken 38 times.
✓ Decision 'false' taken 806 times.
|
844 | if (!uid_0_exist && uid_1_exist) { |
165 |
2/4✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 38 times.
✗ Branch 5 not taken.
|
38 | Node root(this->labelling_[pair.second]); | |
166 |
3/4✓ Branch 2 taken 72 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 70 times.
✓ Branch 5 taken 2 times.
|
0/1? Decision couldn't be analyzed.
|
72 | for (unsigned k = 1; k <= this->architecture_->get_diameter(); k++) { |
167 |
1/2✓ Branch 1 taken 70 times.
✗ Branch 2 not taken.
|
70 | uid_0_exist = this->assign_at_distance(pair.first, root, k); | |
168 |
2/2✓ Branch 0 taken 36 times.
✓ Branch 1 taken 34 times.
|
2/2✓ Decision 'true' taken 36 times.
✓ Decision 'false' taken 34 times.
|
70 | if (uid_0_exist) { |
169 | 36 | break; | ||
170 | } | |||
171 | } | |||
172 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 36 times.
|
2/2✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 36 times.
|
38 | if (!uid_0_exist) { |
173 |
2/4✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
|
2 | throw LexiRouteError( | |
174 | 4 | "Unable to assign physical qubit - no free qubits remaining."); | ||
175 | } | |||
176 | 38 | } | ||
177 |
3/4✓ Branch 0 taken 842 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 195 times.
✓ Branch 3 taken 647 times.
|
2/2✓ Decision 'true' taken 195 times.
✓ Decision 'false' taken 647 times.
|
842 | if (uid_0_exist && !uid_1_exist) { |
178 |
2/4✓ Branch 1 taken 195 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 195 times.
✗ Branch 5 not taken.
|
195 | Node root(this->labelling_[pair.first]); | |
179 |
2/4✓ Branch 2 taken 309 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 309 times.
✗ Branch 5 not taken.
|
0/1? Decision couldn't be analyzed.
|
309 | for (unsigned k = 1; k <= this->architecture_->get_diameter(); k++) { |
180 |
1/2✓ Branch 1 taken 309 times.
✗ Branch 2 not taken.
|
309 | uid_1_exist = this->assign_at_distance(pair.second, root, k); | |
181 |
2/2✓ Branch 0 taken 195 times.
✓ Branch 1 taken 114 times.
|
2/2✓ Decision 'true' taken 195 times.
✓ Decision 'false' taken 114 times.
|
309 | if (uid_1_exist) { |
182 | 195 | break; | ||
183 | } | |||
184 | } | |||
185 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 195 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 195 times.
|
195 | if (!uid_1_exist) { |
186 | ✗ | throw LexiRouteError( | ||
187 | ✗ | "Unable to assign physical qubit - no free qubits remaining."); | ||
188 | } | |||
189 | 195 | } | ||
190 | } | |||
191 | 215 | return relabelled; | ||
192 | } | |||
193 | ||||
194 | /** | |||
195 | * LexiRoute::set_interacting_uids | |||
196 | * Updates this->interacting_uids_ with all "interacting" pairs | |||
197 | * of UnitID in this->mapping_frontier_ | |||
198 | */ | |||
199 | 31278 | bool LexiRoute::set_interacting_uids( | ||
200 | AssignedOnly assigned_only, CheckRoutingValidity route_check, | |||
201 | CheckLabellingValidity label_check) { | |||
202 | // return types | |||
203 | 31278 | this->interacting_uids_.clear(); | ||
204 | 31278 | bool all_placed = true; | ||
205 | 31278 | for (auto it = | ||
206 | 31278 | this->mapping_frontier_->linear_boundary->get<TagKey>().begin(); | ||
207 |
3/4✓ Branch 5 taken 1110296 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1079021 times.
✓ Branch 8 taken 31275 times.
|
1110296 | it != this->mapping_frontier_->linear_boundary->get<TagKey>().end(); | |
208 |
1/2✓ Branch 1 taken 1079018 times.
✗ Branch 2 not taken.
|
1079018 | ++it) { | |
209 | 1079021 | Edge e0 = this->mapping_frontier_->circuit_.get_nth_out_edge( | ||
210 |
3/6✓ Branch 1 taken 1079021 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1079021 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1079021 times.
✗ Branch 8 not taken.
|
1079021 | it->second.first, it->second.second); | |
211 |
1/2✓ Branch 2 taken 1079021 times.
✗ Branch 3 not taken.
|
1079021 | Vertex v0 = this->mapping_frontier_->circuit_.target(e0); | |
212 | // should never be input vertex, so can always use in_edges | |||
213 |
1/2✓ Branch 2 taken 1079021 times.
✗ Branch 3 not taken.
|
1079021 | Op_ptr op = this->mapping_frontier_->circuit_.get_Op_ptr_from_Vertex(v0); | |
214 |
1/2✓ Branch 2 taken 1079021 times.
✗ Branch 3 not taken.
|
1/2✓ Decision 'true' taken 1079021 times.
✗ Decision 'false' not taken.
|
1079021 | if (op->get_type() != OpType::Barrier) { |
215 |
1/2✓ Branch 2 taken 1079021 times.
✗ Branch 3 not taken.
|
1079021 | int n_edges = this->mapping_frontier_->circuit_.n_in_edges_of_type( | |
216 | 1079021 | v0, EdgeType::Quantum); | ||
217 | // make forwards = backwards | |||
218 |
2/2✓ Branch 0 taken 629571 times.
✓ Branch 1 taken 449450 times.
|
2/2✓ Decision 'true' taken 629571 times.
✓ Decision 'false' taken 449450 times.
|
1079021 | if (n_edges == 2) { |
219 | 629571 | auto jt = it; | ||
220 |
1/2✓ Branch 1 taken 629571 times.
✗ Branch 2 not taken.
|
629571 | ++jt; | |
221 |
1/2✓ Branch 1 taken 8737435 times.
✗ Branch 2 not taken.
|
1/2✓ Decision 'true' taken 8737435 times.
✗ Decision 'false' not taken.
|
9367006 | while (jt != |
222 |
2/2✓ Branch 4 taken 8107867 times.
✓ Branch 5 taken 629568 times.
|
17474870 | this->mapping_frontier_->linear_boundary->get<TagKey>().end()) { | |
223 | // i.e. if vertices match | |||
224 | 8107867 | Edge e1 = this->mapping_frontier_->circuit_.get_nth_out_edge( | ||
225 |
3/6✓ Branch 1 taken 8107867 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8107867 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 8107867 times.
✗ Branch 8 not taken.
|
8107867 | jt->second.first, jt->second.second); | |
226 |
1/2✓ Branch 2 taken 8107867 times.
✗ Branch 3 not taken.
|
8107867 | Vertex v1 = this->mapping_frontier_->circuit_.target(e1); | |
227 |
2/2✓ Branch 0 taken 43599 times.
✓ Branch 1 taken 8064268 times.
|
2/2✓ Decision 'true' taken 43599 times.
✓ Decision 'false' taken 8064268 times.
|
8107867 | if (v0 == v1) { |
228 | // we can assume a qubit will only be in one interaction | |||
229 | // we can assume from how we iterate through pairs that each qubit | |||
230 | // will only be found in one match | |||
231 | bool node0_exists = | |||
232 |
3/6✓ Branch 2 taken 43599 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 43599 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 43599 times.
✗ Branch 9 not taken.
|
43599 | this->architecture_->node_exists(Node(it->first)); | |
233 | bool node1_exists = | |||
234 |
3/6✓ Branch 2 taken 43599 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 43599 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 43599 times.
✗ Branch 9 not taken.
|
43599 | this->architecture_->node_exists(Node(jt->first)); | |
235 |
12/16✓ Branch 0 taken 43499 times.
✓ Branch 1 taken 100 times.
✓ Branch 2 taken 43076 times.
✓ Branch 3 taken 423 times.
✓ Branch 6 taken 43076 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 43076 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 7 times.
✓ Branch 12 taken 43069 times.
✓ Branch 13 taken 43076 times.
✓ Branch 14 taken 523 times.
✓ Branch 16 taken 530 times.
✓ Branch 17 taken 43069 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
|
2/2✓ Decision 'true' taken 530 times.
✓ Decision 'false' taken 43069 times.
|
43599 | if (!node0_exists || !node1_exists || op->get_desc().is_box()) { |
236 | 530 | all_placed = false; | ||
237 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 527 times.
|
0/1? Decision couldn't be analyzed.
|
530 | if (route_check == CheckRoutingValidity::Yes) return false; |
238 | } | |||
239 | ||||
240 |
4/4✓ Branch 0 taken 28593 times.
✓ Branch 1 taken 15003 times.
✓ Branch 2 taken 28563 times.
✓ Branch 3 taken 30 times.
|
2/2✓ Decision 'true' taken 43307 times.
✓ Decision 'false' taken 289 times.
|
43596 | if (assigned_only == AssignedOnly::No || |
241 |
2/2✓ Branch 0 taken 28304 times.
✓ Branch 1 taken 259 times.
|
28563 | (node0_exists && node1_exists)) { | |
242 |
3/6✓ Branch 1 taken 43307 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 43307 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 43307 times.
✗ Branch 9 not taken.
|
43307 | interacting_uids_.insert({it->first, jt->first}); | |
243 |
3/6✓ Branch 1 taken 43307 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 43307 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 43307 times.
✗ Branch 9 not taken.
|
43307 | interacting_uids_.insert({jt->first, it->first}); | |
244 | } | |||
245 | } | |||
246 |
1/2✓ Branch 1 taken 8107864 times.
✗ Branch 2 not taken.
|
8107864 | ++jt; | |
247 | } | |||
248 | } | |||
249 | } | |||
250 |
2/2✓ Branch 1 taken 1079018 times.
✓ Branch 2 taken 3 times.
|
1079021 | } | |
251 | ||||
252 | // conditions for proceeding with labelling | |||
253 |
2/2✓ Branch 0 taken 2965 times.
✓ Branch 1 taken 28310 times.
|
2/2✓ Decision 'true' taken 2965 times.
✓ Decision 'false' taken 28310 times.
|
31275 | if (label_check == CheckLabellingValidity::Yes) { |
254 |
2/2✓ Branch 0 taken 2747 times.
✓ Branch 1 taken 218 times.
|
2/2✓ Decision 'true' taken 2747 times.
✓ Decision 'false' taken 218 times.
|
2965 | if (all_placed) { |
255 | 2747 | return true; | ||
256 | } else { | |||
257 | 218 | return false; | ||
258 | } | |||
259 | } | |||
260 | // this should have left early when first found | |||
261 |
2/2✓ Branch 0 taken 2757 times.
✓ Branch 1 taken 25553 times.
|
2/2✓ Decision 'true' taken 2757 times.
✓ Decision 'false' taken 25553 times.
|
28310 | if (route_check == CheckRoutingValidity::Yes) { |
262 |
1/2✓ Branch 0 taken 2757 times.
✗ Branch 1 not taken.
|
1/2✓ Decision 'true' taken 2757 times.
✗ Decision 'false' not taken.
|
2757 | if (all_placed) { |
263 |
1/2✓ Branch 1 taken 2757 times.
✗ Branch 2 not taken.
|
1/2✓ Decision 'true' taken 2757 times.
✗ Decision 'false' not taken.
|
2757 | if (interacting_uids_.size() > 0) { |
264 | 2757 | return true; | ||
265 | } | |||
266 | ✗ | return false; | ||
267 | } else { | |||
268 | ✗ | return false; | ||
269 | } | |||
270 | } | |||
271 | // => either route_check true and all_placed so valid | |||
272 | // or !route_check and !label_check so return true and discard | |||
273 | 25553 | return true; | ||
274 | } | |||
275 | ||||
276 | 2757 | swap_set_t LexiRoute::get_candidate_swaps() { | ||
277 | 2757 | swap_set_t candidate_swaps; | ||
278 |
2/2✓ Branch 5 taken 9480 times.
✓ Branch 6 taken 2757 times.
|
2/2✓ Decision 'true' taken 9480 times.
✓ Decision 'false' taken 2757 times.
|
12237 | for (const auto& interaction : this->interacting_uids_) { |
279 |
2/4✓ Branch 1 taken 9480 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9480 times.
✗ Branch 5 not taken.
|
9480 | Node assigned_first = Node(this->labelling_[interaction.first]); | |
280 | std::vector<Node> adjacent_uids_0 = | |||
281 |
1/2✓ Branch 2 taken 9480 times.
✗ Branch 3 not taken.
|
9480 | this->architecture_->nodes_at_distance(assigned_first, 1); | |
282 | TKET_ASSERT(adjacent_uids_0.size() != 0); | |||
283 |
2/2✓ Branch 5 taken 22246 times.
✓ Branch 6 taken 9480 times.
|
2/2✓ Decision 'true' taken 22246 times.
✓ Decision 'false' taken 9480 times.
|
31726 | for (const Node& neighbour : adjacent_uids_0) { |
284 |
1/2✓ Branch 2 taken 22246 times.
✗ Branch 3 not taken.
|
2/2✓ Decision 'true' taken 20091 times.
✓ Decision 'false' taken 2155 times.
|
22246 | if (candidate_swaps.find({neighbour, assigned_first}) == |
285 |
2/2✓ Branch 1 taken 20091 times.
✓ Branch 2 taken 2155 times.
|
44492 | candidate_swaps.end()) { | |
286 |
1/2✓ Branch 2 taken 20091 times.
✗ Branch 3 not taken.
|
20091 | candidate_swaps.insert({assigned_first, neighbour}); | |
287 | } | |||
288 | } | |||
289 |
2/4✓ Branch 1 taken 9480 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9480 times.
✗ Branch 5 not taken.
|
9480 | Node assigned_second = Node(this->labelling_[interaction.second]); | |
290 | std::vector<Node> adjacent_uids_1 = | |||
291 |
1/2✓ Branch 2 taken 9480 times.
✗ Branch 3 not taken.
|
9480 | this->architecture_->nodes_at_distance(assigned_second, 1); | |
292 | TKET_ASSERT(adjacent_uids_1.size() != 0); | |||
293 |
2/2✓ Branch 5 taken 22246 times.
✓ Branch 6 taken 9480 times.
|
2/2✓ Decision 'true' taken 22246 times.
✓ Decision 'false' taken 9480 times.
|
31726 | for (const Node& neighbour : adjacent_uids_1) { |
294 |
1/2✓ Branch 2 taken 22246 times.
✗ Branch 3 not taken.
|
2/2✓ Decision 'true' taken 20091 times.
✓ Decision 'false' taken 2155 times.
|
22246 | if (candidate_swaps.find({neighbour, assigned_second}) == |
295 |
2/2✓ Branch 1 taken 20091 times.
✓ Branch 2 taken 2155 times.
|
44492 | candidate_swaps.end()) { | |
296 |
1/2✓ Branch 2 taken 20091 times.
✗ Branch 3 not taken.
|
20091 | candidate_swaps.insert({assigned_second, neighbour}); | |
297 | } | |||
298 | } | |||
299 | 9480 | } | ||
300 | 2757 | return candidate_swaps; | ||
301 | } | |||
302 | ||||
303 | 1959 | bool is_vertex_CX(const Circuit& circ_, const Vertex& v) { | ||
304 | 1959 | OpType ot = circ_.get_OpType_from_Vertex(v); | ||
305 |
2/2✓ Branch 0 taken 201 times.
✓ Branch 1 taken 1758 times.
|
2/2✓ Decision 'true' taken 201 times.
✓ Decision 'false' taken 1758 times.
|
1959 | if (ot != OpType::CX) { |
306 |
2/2✓ Branch 0 taken 99 times.
✓ Branch 1 taken 102 times.
|
2/2✓ Decision 'true' taken 99 times.
✓ Decision 'false' taken 102 times.
|
201 | if (ot == OpType::Conditional) { |
307 | const Conditional& b = | |||
308 | 99 | static_cast<const Conditional&>(*circ_.get_Op_ptr_from_Vertex(v)); | ||
309 |
2/2✓ Branch 4 taken 33 times.
✓ Branch 5 taken 66 times.
|
2/2✓ Decision 'true' taken 33 times.
✓ Decision 'false' taken 66 times.
|
99 | if (b.get_op()->get_type() != OpType::CX) { |
310 | 33 | return false; | ||
311 | } | |||
312 | } else { | |||
313 | 102 | return false; | ||
314 | } | |||
315 | } | |||
316 | 1824 | return true; | ||
317 | } | |||
318 | ||||
319 | 2757 | std::pair<bool, bool> LexiRoute::check_bridge( | ||
320 | const std::pair<Node, Node>& swap, unsigned lookahead) { | |||
321 | 2757 | std::pair<bool, bool> output = {false, false}; | ||
322 | // first confirm whether it even has an interaction | |||
323 |
1/2✓ Branch 1 taken 2757 times.
✗ Branch 2 not taken.
|
2757 | auto it = this->interacting_uids_.find(swap.first); | |
324 |
1/2✓ Branch 2 taken 2757 times.
✗ Branch 3 not taken.
|
1/2✓ Decision 'true' taken 2757 times.
✗ Decision 'false' not taken.
|
2757 | if (it != this->interacting_uids_.end()) { // => in interaction |
325 |
4/6✓ Branch 3 taken 2757 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2757 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1576 times.
✓ Branch 10 taken 1181 times.
|
2757 | if (this->architecture_->get_distance(swap.first, Node(it->second)) == | |
326 | 2) { // => could be bridge | |||
327 | // below should always return correct object given prior checks | |||
328 | VertPort vp = | |||
329 |
2/4✓ Branch 3 taken 1576 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1576 times.
✗ Branch 7 not taken.
|
1576 | (*this->mapping_frontier_->linear_boundary->find(swap.first)).second; | |
330 |
1/2✓ Branch 2 taken 1576 times.
✗ Branch 3 not taken.
|
1576 | Edge out_edge = this->mapping_frontier_->circuit_.get_nth_out_edge( | |
331 | vp.first, vp.second); | |||
332 | 3152 | output.first = is_vertex_CX( | ||
333 |
1/2✓ Branch 1 taken 1576 times.
✗ Branch 2 not taken.
|
1576 | this->mapping_frontier_->circuit_, | |
334 |
1/2✓ Branch 2 taken 1576 times.
✗ Branch 3 not taken.
|
3152 | this->mapping_frontier_->circuit_.target(out_edge)); | |
335 | } | |||
336 | } | |||
337 | // repeat for second swap | |||
338 |
1/2✓ Branch 1 taken 2757 times.
✗ Branch 2 not taken.
|
2757 | it = this->interacting_uids_.find(swap.second); | |
339 |
2/2✓ Branch 2 taken 427 times.
✓ Branch 3 taken 2330 times.
|
2757 | if (it != this->interacting_uids_.end()) { | |
340 |
4/6✓ Branch 3 taken 427 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 427 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 383 times.
✓ Branch 10 taken 44 times.
|
427 | if (this->architecture_->get_distance(swap.second, Node(it->second)) == 2) { | |
341 | VertPort vp = | |||
342 |
2/4✓ Branch 3 taken 383 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 383 times.
✗ Branch 7 not taken.
|
383 | (*this->mapping_frontier_->linear_boundary->find(swap.second)).second; | |
343 |
1/2✓ Branch 2 taken 383 times.
✗ Branch 3 not taken.
|
383 | Edge out_edge = this->mapping_frontier_->circuit_.get_nth_out_edge( | |
344 | vp.first, vp.second); | |||
345 | 766 | output.second = is_vertex_CX( | ||
346 |
1/2✓ Branch 1 taken 383 times.
✗ Branch 2 not taken.
|
383 | this->mapping_frontier_->circuit_, | |
347 |
1/2✓ Branch 2 taken 383 times.
✗ Branch 3 not taken.
|
766 | this->mapping_frontier_->circuit_.target(out_edge)); | |
348 | } | |||
349 | } | |||
350 |
8/8✓ Branch 0 taken 1464 times.
✓ Branch 1 taken 1293 times.
✓ Branch 2 taken 1142 times.
✓ Branch 3 taken 322 times.
✓ Branch 4 taken 1293 times.
✓ Branch 5 taken 1142 times.
✓ Branch 6 taken 1255 times.
✓ Branch 7 taken 38 times.
|
2757 | if ((output.first && output.second) || (!output.first && !output.second)) { | |
351 | 1577 | return {0, 0}; | ||
352 | } | |||
353 | // implies conditions are set to at least check if BRIDGE is better | |||
354 | swap_set_t candidate_swaps = { | |||
355 | swap, | |||
356 | 1180 | {swap.first, | ||
357 |
1/2✓ Branch 4 taken 1180 times.
✗ Branch 5 not taken.
|
4720 | swap.first}}; // second swap here will just compare the base case | |
358 | ||||
359 | // as with best swap finder, we create a set of candidate swap gates and | |||
360 | // then find best, except with only 2 swap (best swap and no swap) | |||
361 |
2/2✓ Branch 1 taken 4485 times.
✓ Branch 2 taken 1180 times.
|
5665 | while (candidate_swaps.size() > 1 /*some lookahead parameter*/) { | |
362 |
1/2✓ Branch 2 taken 4485 times.
✗ Branch 3 not taken.
|
4485 | this->mapping_frontier_->advance_next_2qb_slice(lookahead); | |
363 | // true bool means it only sets interacting uids if both uids are in | |||
364 | // architecture | |||
365 |
1/2✓ Branch 1 taken 4485 times.
✗ Branch 2 not taken.
|
4485 | this->set_interacting_uids( | |
366 | AssignedOnly::Yes, CheckRoutingValidity::No, | |||
367 | CheckLabellingValidity::No); | |||
368 | // if 0, just take first swap rather than place | |||
369 |
2/2✓ Branch 1 taken 62 times.
✓ Branch 2 taken 4423 times.
|
4485 | if (this->interacting_uids_.size() == 0) { | |
370 |
3/6✓ Branch 4 taken 62 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 62 times.
✓ Branch 7 taken 62 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
|
124 | candidate_swaps = {*candidate_swaps.begin()}; | |
371 | } else { | |||
372 | 4423 | interacting_nodes_t convert_uids; | ||
373 |
2/2✓ Branch 4 taken 11908 times.
✓ Branch 5 taken 4423 times.
|
16331 | for (const auto& p : this->interacting_uids_) { | |
374 |
1/2✓ Branch 2 taken 11908 times.
✗ Branch 3 not taken.
|
11908 | convert_uids.insert( | |
375 |
2/4✓ Branch 1 taken 11908 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 11908 times.
✗ Branch 5 not taken.
|
23816 | {Node(this->labelling_[p.first]), | |
376 |
2/4✓ Branch 1 taken 11908 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 11908 times.
✗ Branch 5 not taken.
|
23816 | Node(this->labelling_[p.second])}); | |
377 | } | |||
378 |
1/2✓ Branch 1 taken 4423 times.
✗ Branch 2 not taken.
|
4423 | LexicographicalComparison lookahead_lc(this->architecture_, convert_uids); | |
379 |
1/2✓ Branch 1 taken 4423 times.
✗ Branch 2 not taken.
|
4423 | lookahead_lc.remove_swaps_lexicographical(candidate_swaps); | |
380 | 4423 | } | ||
381 | } | |||
382 | // condition implies bridge is chosen | |||
383 | // if both remained then lexicographically equivalent under given conditions | |||
384 | // so either can be added with same consequences (for given hyper | |||
385 | // parameters) | |||
386 |
3/4✓ Branch 3 taken 1180 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 878 times.
✓ Branch 6 taken 302 times.
|
1180 | if (*candidate_swaps.begin() == swap) { | |
387 | 878 | output = {0, 0}; | ||
388 | } | |||
389 | 1180 | return output; | ||
390 | 1180 | } | ||
391 | ||||
392 | // Returns the distance between n1 and p1 and the distance between n2 and p2, | |||
393 | // distance ordered (greatest first) | |||
394 | 40176 | const std::pair<size_t, size_t> LexiRoute::pair_distances( | ||
395 | const Node& p0_first, const Node& p0_second, const Node& p1_first, | |||
396 | const Node& p1_second) const { | |||
397 | { | |||
398 |
1/2✓ Branch 2 taken 40176 times.
✗ Branch 3 not taken.
|
40176 | const bool valid = this->architecture_->node_exists(p0_first) && | |
399 |
2/4✓ Branch 2 taken 40176 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 40176 times.
✗ Branch 5 not taken.
|
40176 | this->architecture_->node_exists(p0_second) && | |
400 |
3/6✓ Branch 0 taken 40176 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 40176 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 40176 times.
✗ Branch 7 not taken.
|
120528 | this->architecture_->node_exists(p1_first) && | |
401 |
2/4✓ Branch 2 taken 40176 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 40176 times.
✗ Branch 5 not taken.
|
40176 | this->architecture_->node_exists(p1_second); | |
402 | TKET_ASSERT(valid); | |||
403 | } | |||
404 |
1/2✓ Branch 2 taken 40176 times.
✗ Branch 3 not taken.
|
40176 | size_t curr_dist1 = this->architecture_->get_distance(p0_first, p0_second); | |
405 |
1/2✓ Branch 2 taken 40176 times.
✗ Branch 3 not taken.
|
40176 | size_t curr_dist2 = this->architecture_->get_distance(p1_first, p1_second); | |
406 |
1/2✓ Branch 1 taken 31248 times.
✗ Branch 2 not taken.
|
31248 | return (curr_dist1 > curr_dist2) ? std::make_pair(curr_dist1, curr_dist2) | |
407 |
3/4✓ Branch 0 taken 31248 times.
✓ Branch 1 taken 8928 times.
✓ Branch 3 taken 8928 times.
✗ Branch 4 not taken.
|
80352 | : std::make_pair(curr_dist2, curr_dist1); | |
408 | } | |||
409 | ||||
410 | 2757 | void LexiRoute::remove_swaps_decreasing(swap_set_t& swaps) { | ||
411 | 2757 | swap_set_t remaining_swaps; | ||
412 |
2/4✓ Branch 1 taken 2757 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2757 times.
✗ Branch 5 not taken.
|
2757 | Node pair_first, pair_second; | |
413 |
2/2✓ Branch 5 taken 20091 times.
✓ Branch 6 taken 2757 times.
|
22848 | for (const auto& swap : swaps) { | |
414 |
1/2✓ Branch 1 taken 20091 times.
✗ Branch 2 not taken.
|
20091 | auto it = this->interacting_uids_.find(swap.first); | |
415 | // => swap.first is in interaction | |||
416 |
1/2✓ Branch 2 taken 20091 times.
✗ Branch 3 not taken.
|
20091 | if (it != this->interacting_uids_.end()) { | |
417 | // find its pair | |||
418 |
1/2✓ Branch 2 taken 20091 times.
✗ Branch 3 not taken.
|
20091 | pair_first = Node(it->second); | |
419 | } else { | |||
420 | // => not interacting, assign pair to self (will give lexicographic | |||
421 | // distance 0) | |||
422 | ✗ | pair_first = swap.first; | ||
423 | } | |||
424 | // => UnitID in SWAP are interacting | |||
425 |
3/4✓ Branch 1 taken 20091 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 20088 times.
|
20091 | if (pair_first == swap.second) { | |
426 | 11450 | continue; | ||
427 | } | |||
428 |
1/2✓ Branch 1 taken 20088 times.
✗ Branch 2 not taken.
|
20088 | auto jt = this->interacting_uids_.find(swap.second); | |
429 | // => swap.second is in interaction | |||
430 |
2/2✓ Branch 2 taken 2152 times.
✓ Branch 3 taken 17936 times.
|
20088 | if (jt != this->interacting_uids_.end()) { | |
431 |
1/2✓ Branch 2 taken 2152 times.
✗ Branch 3 not taken.
|
2152 | pair_second = Node(jt->second); | |
432 | } else { | |||
433 | 17936 | pair_second = swap.second; | ||
434 | } | |||
435 | // => UnitID in SWAP are interacting | |||
436 | // Check should alrady be done with earlier continue | |||
437 | TKET_ASSERT(pair_second != swap.first); | |||
438 | ||||
439 | const std::pair<size_t, size_t>& curr_dists = | |||
440 |
1/2✓ Branch 1 taken 20088 times.
✗ Branch 2 not taken.
|
20088 | this->pair_distances(swap.first, pair_first, swap.second, pair_second); | |
441 | const std::pair<size_t, size_t>& news_dists = | |||
442 |
1/2✓ Branch 1 taken 20088 times.
✗ Branch 2 not taken.
|
20088 | this->pair_distances(swap.second, pair_first, swap.first, pair_second); | |
443 |
2/2✓ Branch 3 taken 11447 times.
✓ Branch 4 taken 8641 times.
|
20088 | if (news_dists >= curr_dists) { | |
444 | 11447 | continue; | ||
445 | } | |||
446 |
1/2✓ Branch 1 taken 8641 times.
✗ Branch 2 not taken.
|
8641 | remaining_swaps.insert(swap); | |
447 | } | |||
448 | 2757 | } | ||
449 | ||||
450 | 2965 | bool LexiRoute::solve_labelling() { | ||
451 | 2965 | bool all_labelled = this->set_interacting_uids( | ||
452 | AssignedOnly::No, CheckRoutingValidity::No, CheckLabellingValidity::Yes); | |||
453 |
2/2✓ Branch 0 taken 218 times.
✓ Branch 1 taken 2747 times.
|
2965 | if (!all_labelled) { | |
454 | 218 | this->update_labelling(); | ||
455 | 215 | this->mapping_frontier_->update_linear_boundary_uids(this->labelling_); | ||
456 | 215 | return true; | ||
457 | } | |||
458 | 2747 | return false; | ||
459 | } | |||
460 | ||||
461 | 2760 | bool LexiRoute::solve(unsigned lookahead) { | ||
462 | // work out if valid | |||
463 | ||||
464 |
1/2✓ Branch 1 taken 2760 times.
✗ Branch 2 not taken.
|
2760 | bool all_labelled = this->set_interacting_uids( | |
465 | AssignedOnly::No, CheckRoutingValidity::Yes, CheckLabellingValidity::No); | |||
466 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2757 times.
|
2760 | if (!all_labelled) { | |
467 | 3 | return false; | ||
468 | } | |||
469 | ||||
470 | // store a copy of the original this->mapping_frontier_->quantum_boundray | |||
471 | // this object will be updated and reset throughout the swap picking procedure | |||
472 | // so need to return it to original setting at end | |||
473 |
1/2✓ Branch 1 taken 2757 times.
✗ Branch 2 not taken.
|
2757 | unit_vertport_frontier_t copy; | |
474 | 2757 | for (const std::pair<UnitID, VertPort>& pair : | ||
475 |
4/6✓ Branch 6 taken 55569 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 58326 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 55569 times.
✓ Branch 12 taken 2757 times.
|
61083 | this->mapping_frontier_->linear_boundary->get<TagKey>()) { | |
476 |
2/4✓ Branch 2 taken 55569 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 55569 times.
✗ Branch 7 not taken.
|
55569 | copy.insert({pair.first, pair.second}); | |
477 | } | |||
478 |
1/2✓ Branch 1 taken 2757 times.
✗ Branch 2 not taken.
|
2757 | swap_set_t candidate_swaps = this->get_candidate_swaps(); | |
479 |
1/2✓ Branch 1 taken 2757 times.
✗ Branch 2 not taken.
|
2757 | this->remove_swaps_decreasing(candidate_swaps); | |
480 | TKET_ASSERT(candidate_swaps.size() != 0); | |||
481 | // Only want to substitute a single swap | |||
482 | // check next layer of interacting qubits and remove swaps until only one | |||
483 | // lexicographically superior swap is left | |||
484 | 2757 | unsigned counter = 0; | ||
485 |
6/6✓ Branch 1 taken 18220 times.
✓ Branch 2 taken 2539 times.
✓ Branch 3 taken 18100 times.
✓ Branch 4 taken 120 times.
✓ Branch 5 taken 18100 times.
✓ Branch 6 taken 2659 times.
|
20759 | while (candidate_swaps.size() > 1 && counter < lookahead) { | |
486 | // if 0, just take first swap rather than place | |||
487 |
2/2✓ Branch 1 taken 98 times.
✓ Branch 2 taken 18002 times.
|
18100 | if (this->interacting_uids_.size() == 0) { | |
488 | 98 | break; | ||
489 | } else { | |||
490 | 18002 | interacting_nodes_t convert_uids; | ||
491 |
2/2✓ Branch 4 taken 45228 times.
✓ Branch 5 taken 18002 times.
|
63230 | for (const auto& p : this->interacting_uids_) { | |
492 |
1/2✓ Branch 2 taken 45228 times.
✗ Branch 3 not taken.
|
45228 | convert_uids.insert( | |
493 |
2/4✓ Branch 1 taken 45228 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 45228 times.
✗ Branch 5 not taken.
|
90456 | {Node(this->labelling_[p.first]), | |
494 |
2/4✓ Branch 1 taken 45228 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 45228 times.
✗ Branch 5 not taken.
|
90456 | Node(this->labelling_[p.second])}); | |
495 | } | |||
496 |
1/2✓ Branch 1 taken 18002 times.
✗ Branch 2 not taken.
|
18002 | LexicographicalComparison lookahead_lc(this->architecture_, convert_uids); | |
497 |
1/2✓ Branch 1 taken 18002 times.
✗ Branch 2 not taken.
|
18002 | lookahead_lc.remove_swaps_lexicographical(candidate_swaps); | |
498 | 18002 | } | ||
499 | 18002 | counter++; | ||
500 |
1/2✓ Branch 2 taken 18002 times.
✗ Branch 3 not taken.
|
18002 | this->mapping_frontier_->advance_next_2qb_slice(lookahead); | |
501 | // true bool means it only sets interacting uids if both uids are in | |||
502 | // architecture | |||
503 |
1/2✓ Branch 1 taken 18002 times.
✗ Branch 2 not taken.
|
18002 | this->set_interacting_uids( | |
504 | AssignedOnly::Yes, CheckRoutingValidity::No, | |||
505 | CheckLabellingValidity::No); | |||
506 | } | |||
507 | // find best swap | |||
508 | 2757 | auto it = candidate_swaps.end(); | ||
509 | 2757 | --it; | ||
510 | ||||
511 | 2757 | std::pair<Node, Node> chosen_swap = *it; | ||
512 |
1/2✓ Branch 2 taken 2757 times.
✗ Branch 3 not taken.
|
2757 | this->mapping_frontier_->set_linear_boundary(copy); | |
513 | ||||
514 |
1/2✓ Branch 1 taken 2757 times.
✗ Branch 2 not taken.
|
2757 | this->set_interacting_uids( | |
515 | AssignedOnly::No, CheckRoutingValidity::No, CheckLabellingValidity::No); | |||
516 |
1/2✓ Branch 1 taken 2757 times.
✗ Branch 2 not taken.
|
2757 | std::pair<bool, bool> check = this->check_bridge(chosen_swap, lookahead); | |
517 | // set for final time, to allow gates to be correctly inserted, but then leave | |||
518 | // as is | |||
519 | // insert gates | |||
520 |
1/2✓ Branch 2 taken 2757 times.
✗ Branch 3 not taken.
|
2757 | this->mapping_frontier_->set_linear_boundary(copy); | |
521 |
4/4✓ Branch 0 taken 2473 times.
✓ Branch 1 taken 284 times.
✓ Branch 2 taken 2455 times.
✓ Branch 3 taken 18 times.
|
2757 | if (!check.first && !check.second) { | |
522 | // update circuit with new swap | |||
523 | // final_labelling is initial labelling permuted by single swap | |||
524 | ||||
525 | // if false, SWAP is identical to last SWAP added without any gates realised | |||
526 |
3/4✓ Branch 2 taken 2455 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✓ Branch 5 taken 2448 times.
|
2455 | if (!this->mapping_frontier_->add_swap( | |
527 | chosen_swap.first, chosen_swap.second)) { | |||
528 | // only need to reset in bridge case | |||
529 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | this->set_interacting_uids( | |
530 | AssignedOnly::No, CheckRoutingValidity::No, | |||
531 | CheckLabellingValidity::No); | |||
532 | // if SWAP has both Nodes in interaction default takes first | |||
533 | // this could be inefficient compared to other SWAP, however | |||
534 | // this failsafe is expected to be called extremely rarely (once in | |||
535 | // thousands) on very dense circuits for very symmetrical architectures so | |||
536 | // doesn't largely matter | |||
537 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | auto it = this->interacting_uids_.find(chosen_swap.first); | |
538 | 24 | auto add_path_swaps = [this](const Node& source, const Node& target) { | ||
539 |
1/2✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
|
7 | auto path = this->architecture_->get_path(source, target); | |
540 | 7 | auto path_it_0 = path.begin() + 1; | ||
541 | 7 | auto path_it_1 = path.begin(); | ||
542 | // adds a SWAP between each pair of adjacent nodes on path | |||
543 |
2/2✓ Branch 2 taken 17 times.
✓ Branch 3 taken 7 times.
|
24 | while (path_it_0 != path.end()) { | |
544 |
1/2✓ Branch 4 taken 17 times.
✗ Branch 5 not taken.
|
17 | this->mapping_frontier_->add_swap(*path_it_0, *path_it_1); | |
545 | 17 | ++path_it_0; | ||
546 | 17 | ++path_it_1; | ||
547 | } | |||
548 | 7 | }; | ||
549 |
1/2✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
|
7 | if (it != this->interacting_uids_.end()) { | |
550 |
2/4✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 7 times.
✗ Branch 6 not taken.
|
7 | add_path_swaps(chosen_swap.first, Node(it->second)); | |
551 | } else { | |||
552 | ✗ | it = this->interacting_uids_.find(chosen_swap.second); | ||
553 | TKET_ASSERT(it != this->interacting_uids_.end()); | |||
554 | ✗ | add_path_swaps(chosen_swap.second, Node(it->second)); | ||
555 | } | |||
556 | } | |||
557 | ||||
558 | 2455 | } else { | ||
559 | // only need to reset in bridge case | |||
560 |
1/2✓ Branch 1 taken 302 times.
✗ Branch 2 not taken.
|
302 | this->set_interacting_uids( | |
561 | AssignedOnly::No, CheckRoutingValidity::No, CheckLabellingValidity::No); | |||
562 | ||||
563 | 302 | auto add_ordered_bridge = [&](const Node& n) { | ||
564 |
1/2✓ Branch 3 taken 302 times.
✗ Branch 4 not taken.
|
302 | auto it0 = this->mapping_frontier_->linear_boundary->find(n); | |
565 | // this should implicitly be the case if this logic is reached | |||
566 | TKET_ASSERT(it0 != this->mapping_frontier_->linear_boundary->end()); | |||
567 | ||||
568 |
2/4✓ Branch 1 taken 302 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 302 times.
✗ Branch 5 not taken.
|
302 | Node other_node = Node(this->interacting_uids_[n]); | |
569 |
1/2✓ Branch 3 taken 302 times.
✗ Branch 4 not taken.
|
302 | auto it1 = this->mapping_frontier_->linear_boundary->find(other_node); | |
570 | // this should implicitly be the case if this logic is reached | |||
571 | TKET_ASSERT(it1 != this->mapping_frontier_->linear_boundary->end()); | |||
572 | ||||
573 |
1/2✓ Branch 2 taken 302 times.
✗ Branch 3 not taken.
|
302 | auto path = this->architecture_->get_path(n, other_node); | |
574 | 302 | Node central = Node(path[1]); | ||
575 | ||||
576 | 302 | Edge n_edge = this->mapping_frontier_->circuit_.get_nth_out_edge( | ||
577 |
3/6✓ Branch 1 taken 302 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 302 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 302 times.
✗ Branch 8 not taken.
|
302 | it0->second.first, it0->second.second); | |
578 | 302 | Edge other_edge = this->mapping_frontier_->circuit_.get_nth_out_edge( | ||
579 |
3/6✓ Branch 1 taken 302 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 302 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 302 times.
✗ Branch 8 not taken.
|
302 | it1->second.first, it1->second.second); | |
580 | ||||
581 | unsigned port0 = | |||
582 |
1/2✓ Branch 2 taken 302 times.
✗ Branch 3 not taken.
|
302 | this->mapping_frontier_->circuit_.get_target_port(n_edge); | |
583 | unsigned port1 = | |||
584 |
1/2✓ Branch 2 taken 302 times.
✗ Branch 3 not taken.
|
302 | this->mapping_frontier_->circuit_.get_target_port(other_edge); | |
585 | // compare port ordering to get control vs target | |||
586 | TKET_ASSERT(port0 != port1); | |||
587 |
2/2✓ Branch 0 taken 142 times.
✓ Branch 1 taken 160 times.
|
302 | if (port0 < port1) { | |
588 |
1/2✓ Branch 2 taken 142 times.
✗ Branch 3 not taken.
|
142 | this->mapping_frontier_->add_bridge(n, central, other_node); | |
589 | } else { | |||
590 |
1/2✓ Branch 2 taken 160 times.
✗ Branch 3 not taken.
|
160 | this->mapping_frontier_->add_bridge(other_node, central, n); | |
591 | } | |||
592 | 302 | }; | ||
593 | ||||
594 |
2/2✓ Branch 0 taken 284 times.
✓ Branch 1 taken 18 times.
|
302 | if (check.first) { | |
595 |
1/2✓ Branch 1 taken 284 times.
✗ Branch 2 not taken.
|
284 | add_ordered_bridge(chosen_swap.first); | |
596 | } | |||
597 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 284 times.
|
302 | if (check.second) { | |
598 |
1/2✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
|
18 | add_ordered_bridge(chosen_swap.second); | |
599 | } | |||
600 | } | |||
601 | 2757 | return true; | ||
602 | 2757 | } | ||
603 | ||||
604 | } // namespace tket | |||
605 |