quantrs2_circuit/routing/
swap_network.rs1use crate::routing::CouplingMap;
7use quantrs2_core::{error::QuantRS2Result, gate::multi::SWAP, qubit::QubitId};
8use std::collections::{HashMap, HashSet, VecDeque};
9
10#[derive(Debug, Clone)]
12pub struct SwapLayer {
13 pub swaps: Vec<(usize, usize)>,
15 pub depth: usize,
17}
18
19impl SwapLayer {
20 #[must_use]
22 pub const fn new(depth: usize) -> Self {
23 Self {
24 swaps: Vec::new(),
25 depth,
26 }
27 }
28
29 pub fn add_swap(&mut self, qubit1: usize, qubit2: usize) {
31 self.swaps.push((qubit1, qubit2));
32 }
33
34 #[must_use]
36 pub fn involves_qubits(&self, qubit1: usize, qubit2: usize) -> bool {
37 self.swaps
38 .iter()
39 .any(|&(q1, q2)| (q1 == qubit1 || q1 == qubit2) || (q2 == qubit1 || q2 == qubit2))
40 }
41
42 #[must_use]
44 pub fn qubits(&self) -> HashSet<usize> {
45 let mut qubits = HashSet::new();
46 for &(q1, q2) in &self.swaps {
47 qubits.insert(q1);
48 qubits.insert(q2);
49 }
50 qubits
51 }
52
53 #[must_use]
55 pub fn can_add_swap(&self, qubit1: usize, qubit2: usize) -> bool {
56 !self.involves_qubits(qubit1, qubit2)
57 }
58}
59
60#[derive(Debug, Clone)]
62pub struct SwapNetwork {
63 pub layers: Vec<SwapLayer>,
65 coupling_map: CouplingMap,
67}
68
69impl SwapNetwork {
70 #[must_use]
72 pub const fn new(coupling_map: CouplingMap) -> Self {
73 Self {
74 layers: Vec::new(),
75 coupling_map,
76 }
77 }
78
79 pub fn add_layer(&mut self, layer: SwapLayer) {
81 self.layers.push(layer);
82 }
83
84 pub fn generate_routing_network(
86 &mut self,
87 initial_mapping: &HashMap<usize, usize>,
88 target_mapping: &HashMap<usize, usize>,
89 ) -> QuantRS2Result<()> {
90 let mut current_perm = self.mapping_to_permutation(initial_mapping);
92 let target_perm = self.mapping_to_permutation(target_mapping);
93
94 let mut depth = 0;
95
96 while current_perm != target_perm {
97 let mut layer = SwapLayer::new(depth);
98 let mut swaps_added = false;
99
100 for i in 0..current_perm.len() {
102 if current_perm[i] != target_perm[i] {
103 if let Some(j) = current_perm.iter().position(|&x| x == target_perm[i]) {
105 if i != j
106 && self.coupling_map.are_connected(i, j)
107 && layer.can_add_swap(i, j)
108 {
109 layer.add_swap(i, j);
110 current_perm.swap(i, j);
111 swaps_added = true;
112 }
113 }
114 }
115 }
116
117 if !swaps_added {
119 if let Some((i, j)) = self.find_routing_swap(¤t_perm, &target_perm, &layer) {
120 layer.add_swap(i, j);
121 current_perm.swap(i, j);
122 swaps_added = true;
123 }
124 }
125
126 if swaps_added {
127 self.add_layer(layer);
128 depth += 1;
129 } else {
130 break; }
132
133 if depth > current_perm.len() * 2 {
135 break;
136 }
137 }
138
139 Ok(())
140 }
141
142 fn mapping_to_permutation(&self, mapping: &HashMap<usize, usize>) -> Vec<usize> {
144 let mut perm = vec![0; self.coupling_map.num_qubits()];
145
146 for (&logical, &physical) in mapping {
147 if physical < perm.len() {
148 perm[physical] = logical;
149 }
150 }
151
152 perm
153 }
154
155 fn find_routing_swap(
157 &self,
158 current: &[usize],
159 target: &[usize],
160 layer: &SwapLayer,
161 ) -> Option<(usize, usize)> {
162 let mut best_swap = None;
163 let mut best_score = -1;
164
165 for i in 0..current.len() {
166 for &j in self.coupling_map.neighbors(i) {
167 if i < j && layer.can_add_swap(i, j) {
168 let score = self.evaluate_swap_progress(current, target, i, j);
169 if score > best_score {
170 best_score = score;
171 best_swap = Some((i, j));
172 }
173 }
174 }
175 }
176
177 best_swap
178 }
179
180 fn evaluate_swap_progress(
182 &self,
183 current: &[usize],
184 target: &[usize],
185 i: usize,
186 j: usize,
187 ) -> i32 {
188 let mut score = 0;
189
190 let target_pos_i = target.iter().position(|&x| x == current[i]);
192 let target_pos_j = target.iter().position(|&x| x == current[j]);
193
194 if let Some(target_i) = target_pos_i {
195 let dist_before = self.coupling_map.distance(i, target_i);
196 let dist_after = self.coupling_map.distance(j, target_i);
197 if dist_after < dist_before {
198 score += dist_before as i32 - dist_after as i32;
199 }
200 }
201
202 if let Some(target_j) = target_pos_j {
203 let dist_before = self.coupling_map.distance(j, target_j);
204 let dist_after = self.coupling_map.distance(i, target_j);
205 if dist_after < dist_before {
206 score += dist_before as i32 - dist_after as i32;
207 }
208 }
209
210 score
211 }
212
213 pub fn optimize(&mut self) {
215 self.remove_redundant_swaps();
216 self.merge_consecutive_layers();
217 self.reorder_swaps_for_parallelism();
218 }
219
220 fn remove_redundant_swaps(&mut self) {
222 let mut net_swaps: HashMap<(usize, usize), usize> = HashMap::new();
224
225 for layer in &self.layers {
226 for &(q1, q2) in &layer.swaps {
227 let key = (q1.min(q2), q1.max(q2));
228 *net_swaps.entry(key).or_insert(0) += 1;
229 }
230 }
231
232 let cancelled_swaps: HashSet<(usize, usize)> = net_swaps
234 .iter()
235 .filter(|(_, &count)| count % 2 == 0)
236 .map(|(&key, _)| key)
237 .collect();
238
239 for layer in &mut self.layers {
240 layer.swaps.retain(|&(q1, q2)| {
241 let key = (q1.min(q2), q1.max(q2));
242 !cancelled_swaps.contains(&key)
243 });
244 }
245
246 self.layers.retain(|layer| !layer.swaps.is_empty());
248 }
249
250 fn merge_consecutive_layers(&mut self) {
252 let mut i = 0;
253 while i + 1 < self.layers.len() {
254 let can_merge = {
255 let layer1_qubits = self.layers[i].qubits();
256 let layer2_qubits = self.layers[i + 1].qubits();
257 layer1_qubits.is_disjoint(&layer2_qubits)
258 };
259
260 if can_merge {
261 let mut layer2 = self.layers.remove(i + 1);
263 self.layers[i].swaps.append(&mut layer2.swaps);
264 } else {
265 i += 1;
266 }
267 }
268 }
269
270 fn reorder_swaps_for_parallelism(&mut self) {
272 for layer in &mut self.layers {
273 layer.swaps.sort_by_key(|&(q1, q2)| q1.min(q2));
275 }
276 }
277
278 #[must_use]
280 pub fn to_swap_gates(&self) -> Vec<SWAP> {
281 let mut gates = Vec::new();
282
283 for layer in &self.layers {
284 for &(q1, q2) in &layer.swaps {
285 gates.push(SWAP {
286 qubit1: QubitId::new(q1 as u32),
287 qubit2: QubitId::new(q2 as u32),
288 });
289 }
290 }
291
292 gates
293 }
294
295 #[must_use]
297 pub fn total_swaps(&self) -> usize {
298 self.layers.iter().map(|layer| layer.swaps.len()).sum()
299 }
300
301 #[must_use]
303 pub fn depth(&self) -> usize {
304 self.layers.len()
305 }
306
307 #[must_use]
309 pub fn is_empty(&self) -> bool {
310 self.layers.is_empty() || self.layers.iter().all(|layer| layer.swaps.is_empty())
311 }
312
313 pub fn bubble_sort_network(
315 &mut self,
316 initial_mapping: &HashMap<usize, usize>,
317 target_mapping: &HashMap<usize, usize>,
318 ) -> QuantRS2Result<()> {
319 let mut current_perm = self.mapping_to_permutation(initial_mapping);
320 let target_perm = self.mapping_to_permutation(target_mapping);
321
322 let mut depth = 0;
323 let mut changed = true;
324
325 while changed && current_perm != target_perm {
326 changed = false;
327 let mut layer = SwapLayer::new(depth);
328
329 for i in 0..current_perm.len().saturating_sub(1) {
330 if current_perm[i] != target_perm[i] {
331 if self.coupling_map.are_connected(i, i + 1) && layer.can_add_swap(i, i + 1) {
333 if self.should_swap_for_target(¤t_perm, &target_perm, i, i + 1) {
335 layer.add_swap(i, i + 1);
336 current_perm.swap(i, i + 1);
337 changed = true;
338 }
339 }
340 }
341 }
342
343 if !layer.swaps.is_empty() {
344 self.add_layer(layer);
345 depth += 1;
346 }
347 }
348
349 Ok(())
350 }
351
352 fn should_swap_for_target(
354 &self,
355 current: &[usize],
356 target: &[usize],
357 i: usize,
358 j: usize,
359 ) -> bool {
360 if i >= current.len() || j >= current.len() || i >= target.len() || j >= target.len() {
361 return false;
362 }
363
364 (current[i] == target[i] && current[j] != target[j])
366 || (current[j] == target[j] && current[i] != target[i])
367 }
368}
369
370pub mod networks {
372 use super::{CouplingMap, HashMap, QuantRS2Result, SwapLayer, SwapNetwork};
373
374 pub fn linear_reversal(num_qubits: usize) -> SwapNetwork {
376 let coupling_map = CouplingMap::linear(num_qubits);
377 let mut network = SwapNetwork::new(coupling_map);
378
379 for layer_idx in 0..num_qubits {
381 let mut layer = SwapLayer::new(layer_idx);
382
383 for i in (layer_idx..num_qubits - 1).step_by(2) {
384 layer.add_swap(i, i + 1);
385 }
386
387 if !layer.swaps.is_empty() {
388 network.add_layer(layer);
389 }
390 }
391
392 network
393 }
394
395 pub fn circular_rotation(num_qubits: usize, steps: usize) -> SwapNetwork {
397 let coupling_map = CouplingMap::ring(num_qubits);
398 let mut network = SwapNetwork::new(coupling_map);
399
400 let effective_steps = steps % num_qubits;
401
402 for step in 0..effective_steps {
403 let mut layer = SwapLayer::new(step);
404
405 for i in 0..num_qubits - 1 {
407 layer.add_swap(i, i + 1);
408 }
409
410 network.add_layer(layer);
411 }
412
413 network
414 }
415
416 pub fn random_permutation(
418 coupling_map: CouplingMap,
419 initial: &HashMap<usize, usize>,
420 target: &HashMap<usize, usize>,
421 ) -> QuantRS2Result<SwapNetwork> {
422 let mut network = SwapNetwork::new(coupling_map);
423 network.generate_routing_network(initial, target)?;
424 network.optimize();
425 Ok(network)
426 }
427}
428
429#[cfg(test)]
430mod tests {
431 use super::*;
432
433 #[test]
434 fn test_swap_layer() {
435 let mut layer = SwapLayer::new(0);
436
437 assert!(layer.can_add_swap(0, 1));
438 layer.add_swap(0, 1);
439 assert!(!layer.can_add_swap(0, 2)); assert!(layer.can_add_swap(2, 3));
441
442 let qubits = layer.qubits();
443 assert!(qubits.contains(&0));
444 assert!(qubits.contains(&1));
445 }
446
447 #[test]
448 fn test_swap_network_generation() {
449 let coupling_map = CouplingMap::linear(4);
450 let mut network = SwapNetwork::new(coupling_map);
451
452 let initial: HashMap<usize, usize> =
453 [(0, 0), (1, 1), (2, 2), (3, 3)].iter().copied().collect();
454 let target: HashMap<usize, usize> =
455 [(0, 3), (1, 2), (2, 1), (3, 0)].iter().copied().collect();
456
457 let result = network.generate_routing_network(&initial, &target);
458 assert!(result.is_ok());
459 assert!(!network.is_empty());
460 }
461
462 #[test]
463 fn test_linear_reversal_network() {
464 let network = networks::linear_reversal(4);
465 assert!(!network.is_empty());
466 assert!(network.total_swaps() > 0);
467 }
468
469 #[test]
470 fn test_network_optimization() {
471 let coupling_map = CouplingMap::linear(3);
472 let mut network = SwapNetwork::new(coupling_map);
473
474 let mut layer1 = SwapLayer::new(0);
476 layer1.add_swap(0, 1);
477 network.add_layer(layer1);
478
479 let mut layer2 = SwapLayer::new(1);
480 layer2.add_swap(0, 1); network.add_layer(layer2);
482
483 network.optimize();
484 assert!(network.is_empty()); }
486}