quantrs2_circuit/routing/
coupling_map.rs1use serde::{Deserialize, Serialize};
7use std::collections::{HashMap, HashSet, VecDeque};
8
9pub type Distance = usize;
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct CouplingMap {
15 num_qubits: usize,
17 edges: Vec<Vec<usize>>,
19 distances: Option<Vec<Vec<Distance>>>,
21}
22
23impl CouplingMap {
24 #[must_use]
26 pub fn new(num_qubits: usize) -> Self {
27 Self {
28 num_qubits,
29 edges: vec![Vec::new(); num_qubits],
30 distances: None,
31 }
32 }
33
34 pub fn add_edge(&mut self, qubit1: usize, qubit2: usize) {
36 if qubit1 < self.num_qubits && qubit2 < self.num_qubits && qubit1 != qubit2 {
37 if !self.edges[qubit1].contains(&qubit2) {
38 self.edges[qubit1].push(qubit2);
39 }
40 if !self.edges[qubit2].contains(&qubit1) {
41 self.edges[qubit2].push(qubit1);
42 }
43 self.distances = None;
45 }
46 }
47
48 #[must_use]
50 pub fn are_connected(&self, qubit1: usize, qubit2: usize) -> bool {
51 if qubit1 < self.num_qubits && qubit2 < self.num_qubits {
52 self.edges[qubit1].contains(&qubit2)
53 } else {
54 false
55 }
56 }
57
58 #[must_use]
60 pub fn neighbors(&self, qubit: usize) -> &[usize] {
61 if qubit < self.num_qubits {
62 &self.edges[qubit]
63 } else {
64 &[]
65 }
66 }
67
68 #[must_use]
70 pub const fn num_qubits(&self) -> usize {
71 self.num_qubits
72 }
73
74 #[must_use]
76 pub fn edges(&self) -> Vec<(usize, usize)> {
77 let mut edges = Vec::new();
78 for (i, neighbors) in self.edges.iter().enumerate() {
79 for &j in neighbors {
80 if i < j {
81 edges.push((i, j));
83 }
84 }
85 }
86 edges
87 }
88
89 #[must_use]
91 pub fn distance(&self, qubit1: usize, qubit2: usize) -> Distance {
92 if qubit1 == qubit2 {
93 return 0;
94 }
95
96 if qubit1 >= self.num_qubits || qubit2 >= self.num_qubits {
97 return Distance::MAX;
98 }
99
100 if let Some(ref distances) = self.distances {
102 return distances[qubit1][qubit2];
103 }
104
105 let mut queue = VecDeque::new();
107 let mut visited = vec![false; self.num_qubits];
108 let mut distances = vec![Distance::MAX; self.num_qubits];
109
110 queue.push_back(qubit1);
111 visited[qubit1] = true;
112 distances[qubit1] = 0;
113
114 while let Some(current) = queue.pop_front() {
115 if current == qubit2 {
116 return distances[current];
117 }
118
119 for &neighbor in &self.edges[current] {
120 if !visited[neighbor] {
121 visited[neighbor] = true;
122 distances[neighbor] = distances[current] + 1;
123 queue.push_back(neighbor);
124 }
125 }
126 }
127
128 Distance::MAX
129 }
130
131 pub fn compute_distances(&mut self) {
133 let mut distances = vec![vec![Distance::MAX; self.num_qubits]; self.num_qubits];
134
135 for i in 0..self.num_qubits {
137 distances[i][i] = 0;
138 for &j in &self.edges[i] {
139 distances[i][j] = 1;
140 }
141 }
142
143 for k in 0..self.num_qubits {
145 for i in 0..self.num_qubits {
146 for j in 0..self.num_qubits {
147 if distances[i][k] != Distance::MAX && distances[k][j] != Distance::MAX {
148 let new_dist = distances[i][k] + distances[k][j];
149 if new_dist < distances[i][j] {
150 distances[i][j] = new_dist;
151 }
152 }
153 }
154 }
155 }
156
157 self.distances = Some(distances);
158 }
159
160 #[must_use]
162 pub fn shortest_path(&self, start: usize, end: usize) -> Option<Vec<usize>> {
163 if start == end {
164 return Some(vec![start]);
165 }
166
167 if start >= self.num_qubits || end >= self.num_qubits {
168 return None;
169 }
170
171 let mut queue = VecDeque::new();
173 let mut visited = vec![false; self.num_qubits];
174 let mut parent = vec![None; self.num_qubits];
175
176 queue.push_back(start);
177 visited[start] = true;
178
179 while let Some(current) = queue.pop_front() {
180 if current == end {
181 let mut path = Vec::new();
183 let mut node = Some(end);
184
185 while let Some(n) = node {
186 path.push(n);
187 node = parent[n];
188 }
189
190 path.reverse();
191 return Some(path);
192 }
193
194 for &neighbor in &self.edges[current] {
195 if !visited[neighbor] {
196 visited[neighbor] = true;
197 parent[neighbor] = Some(current);
198 queue.push_back(neighbor);
199 }
200 }
201 }
202
203 None
204 }
205
206 #[must_use]
208 pub fn is_connected(&self) -> bool {
209 if self.num_qubits <= 1 {
210 return true;
211 }
212
213 let mut visited = vec![false; self.num_qubits];
214 let mut queue = VecDeque::new();
215
216 queue.push_back(0);
218 visited[0] = true;
219 let mut count = 1;
220
221 while let Some(current) = queue.pop_front() {
222 for &neighbor in &self.edges[current] {
223 if !visited[neighbor] {
224 visited[neighbor] = true;
225 queue.push_back(neighbor);
226 count += 1;
227 }
228 }
229 }
230
231 count == self.num_qubits
232 }
233
234 #[must_use]
236 pub fn diameter(&self) -> Distance {
237 let mut max_distance = 0;
238
239 for i in 0..self.num_qubits {
240 for j in (i + 1)..self.num_qubits {
241 let dist = self.distance(i, j);
242 if dist != Distance::MAX {
243 max_distance = max_distance.max(dist);
244 }
245 }
246 }
247
248 max_distance
249 }
250
251 #[must_use]
255 pub fn linear(num_qubits: usize) -> Self {
256 let mut coupling_map = Self::new(num_qubits);
257 for i in 0..(num_qubits.saturating_sub(1)) {
258 coupling_map.add_edge(i, i + 1);
259 }
260 coupling_map.compute_distances();
261 coupling_map
262 }
263
264 #[must_use]
266 pub fn ring(num_qubits: usize) -> Self {
267 let mut coupling_map = Self::linear(num_qubits);
268 if num_qubits > 2 {
269 coupling_map.add_edge(0, num_qubits - 1);
270 }
271 coupling_map.compute_distances();
272 coupling_map
273 }
274
275 #[must_use]
277 pub fn grid(rows: usize, cols: usize) -> Self {
278 let num_qubits = rows * cols;
279 let mut coupling_map = Self::new(num_qubits);
280
281 for row in 0..rows {
282 for col in 0..cols {
283 let qubit = row * cols + col;
284
285 if col + 1 < cols {
287 coupling_map.add_edge(qubit, qubit + 1);
288 }
289
290 if row + 1 < rows {
292 coupling_map.add_edge(qubit, qubit + cols);
293 }
294 }
295 }
296
297 coupling_map.compute_distances();
298 coupling_map
299 }
300
301 #[must_use]
303 pub fn all_to_all(num_qubits: usize) -> Self {
304 let mut coupling_map = Self::new(num_qubits);
305 for i in 0..num_qubits {
306 for j in (i + 1)..num_qubits {
307 coupling_map.add_edge(i, j);
308 }
309 }
310 coupling_map.compute_distances();
311 coupling_map
312 }
313
314 #[must_use]
316 pub fn ibm_lagos() -> Self {
317 let mut coupling_map = Self::new(7);
318
319 let edges = [(0, 1), (1, 2), (1, 4), (2, 3), (3, 6), (4, 5), (5, 6)];
321
322 for (q1, q2) in edges {
323 coupling_map.add_edge(q1, q2);
324 }
325
326 coupling_map.compute_distances();
327 coupling_map
328 }
329
330 #[must_use]
332 pub fn ibm_nairobi() -> Self {
333 let mut coupling_map = Self::new(7);
334
335 let edges = [(0, 1), (1, 2), (1, 3), (3, 5), (4, 5), (5, 6)];
337
338 for (q1, q2) in edges {
339 coupling_map.add_edge(q1, q2);
340 }
341
342 coupling_map.compute_distances();
343 coupling_map
344 }
345
346 #[must_use]
348 pub fn google_sycamore() -> Self {
349 let mut coupling_map = Self::new(12);
350
351 let edges = [
353 (0, 1),
354 (0, 4),
355 (1, 2),
356 (1, 5),
357 (2, 3),
358 (2, 6),
359 (3, 7),
360 (4, 5),
361 (4, 8),
362 (5, 6),
363 (5, 9),
364 (6, 7),
365 (6, 10),
366 (7, 11),
367 (8, 9),
368 (9, 10),
369 (10, 11),
370 ];
371
372 for (q1, q2) in edges {
373 coupling_map.add_edge(q1, q2);
374 }
375
376 coupling_map.compute_distances();
377 coupling_map
378 }
379
380 #[must_use]
382 pub fn from_edges(num_qubits: usize, edges: &[(usize, usize)]) -> Self {
383 let mut coupling_map = Self::new(num_qubits);
384 for &(q1, q2) in edges {
385 coupling_map.add_edge(q1, q2);
386 }
387 coupling_map.compute_distances();
388 coupling_map
389 }
390}
391
392impl Default for CouplingMap {
393 fn default() -> Self {
394 Self::linear(5)
395 }
396}
397
398#[cfg(test)]
399mod tests {
400 use super::*;
401
402 #[test]
403 fn test_linear_coupling_map() {
404 let coupling_map = CouplingMap::linear(5);
405
406 assert_eq!(coupling_map.num_qubits(), 5);
407 assert!(coupling_map.are_connected(0, 1));
408 assert!(coupling_map.are_connected(1, 2));
409 assert!(!coupling_map.are_connected(0, 2));
410
411 assert_eq!(coupling_map.distance(0, 4), 4);
412 assert_eq!(coupling_map.distance(1, 3), 2);
413 }
414
415 #[test]
416 fn test_grid_coupling_map() {
417 let coupling_map = CouplingMap::grid(2, 3);
418
419 assert_eq!(coupling_map.num_qubits(), 6);
420 assert!(coupling_map.are_connected(0, 1));
421 assert!(coupling_map.are_connected(0, 3));
422 assert!(!coupling_map.are_connected(0, 2));
423 }
424
425 #[test]
426 fn test_shortest_path() {
427 let coupling_map = CouplingMap::linear(5);
428
429 let path = coupling_map
430 .shortest_path(0, 4)
431 .expect("shortest_path 0->4 should succeed");
432 assert_eq!(path, vec![0, 1, 2, 3, 4]);
433
434 let path = coupling_map
435 .shortest_path(2, 2)
436 .expect("shortest_path 2->2 should succeed");
437 assert_eq!(path, vec![2]);
438 }
439
440 #[test]
441 fn test_connectivity() {
442 let connected = CouplingMap::linear(5);
443 assert!(connected.is_connected());
444
445 let mut disconnected = CouplingMap::new(5);
446 disconnected.add_edge(0, 1);
447 disconnected.add_edge(2, 3);
448 assert!(!disconnected.is_connected());
449 }
450
451 #[test]
452 fn test_ibm_lagos() {
453 let coupling_map = CouplingMap::ibm_lagos();
454 assert_eq!(coupling_map.num_qubits(), 7);
455 assert!(coupling_map.is_connected());
456 }
457}