1use rand::prelude::*;
14use rand_distr::{StandardUniform, Uniform};
15use rand_pcg::Pcg64;
16use std::error::Error;
17use std::fmt;
18use std::hash::Hash;
19
20use hashbrown::HashMap;
21use petgraph::stable_graph::{NodeIndex, StableGraph};
22use petgraph::visit::{
23 EdgeCount, GraphBase, IntoEdges, IntoNeighborsDirected, IntoNodeIdentifiers, NodeCount,
24 NodeIndexable, Visitable,
25};
26use petgraph::Directed;
27use petgraph::Direction::{Incoming, Outgoing};
28use rayon::prelude::*;
29use rayon_cond::CondIterator;
30
31use crate::connectivity::find_cycle;
32use crate::dictmap::*;
33use crate::shortest_path::dijkstra;
34use crate::traversal::dfs_edges;
35
36type Swap = (NodeIndex, NodeIndex);
37type Edge = (NodeIndex, NodeIndex);
38
39#[derive(Debug, PartialEq, Eq, Ord, PartialOrd, Copy, Clone)]
42pub struct MapNotPossible;
43
44impl Error for MapNotPossible {}
45impl fmt::Display for MapNotPossible {
46 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
47 write!(f, "No mapping possible.")
48 }
49}
50
51struct TokenSwapper<G: GraphBase>
52where
53 G::NodeId: Eq + Hash,
54{
55 graph: G,
57 mapping: HashMap<G::NodeId, G::NodeId>,
59 trials: usize,
61 seed: Option<u64>,
63 parallel_threshold: usize,
65 node_map: HashMap<G::NodeId, NodeIndex>,
67 rev_node_map: HashMap<NodeIndex, G::NodeId>,
69}
70
71impl<G> TokenSwapper<G>
72where
73 G: NodeCount
74 + EdgeCount
75 + IntoEdges
76 + Visitable
77 + NodeIndexable
78 + IntoNeighborsDirected
79 + IntoNodeIdentifiers
80 + Send
81 + Sync,
82 G::NodeId: Hash + Eq + Send + Sync,
83{
84 fn new(
85 graph: G,
86 mapping: HashMap<G::NodeId, G::NodeId>,
87 trials: Option<usize>,
88 seed: Option<u64>,
89 parallel_threshold: Option<usize>,
90 ) -> Self {
91 TokenSwapper {
92 graph,
93 mapping,
94 trials: trials.unwrap_or(4),
95 seed,
96 parallel_threshold: parallel_threshold.unwrap_or(50),
97 node_map: HashMap::with_capacity(graph.node_count()),
98 rev_node_map: HashMap::with_capacity(graph.node_count()),
99 }
100 }
101
102 fn map(&mut self) -> Result<Vec<Swap>, MapNotPossible> {
103 let num_nodes = self.graph.node_bound();
104 let num_edges = self.graph.edge_count();
105
106 let mut digraph = StableGraph::with_capacity(num_nodes, num_edges);
109
110 for _ in 0..self.graph.node_bound() {
113 digraph.add_node(());
114 }
115 let mut count: usize = 0;
116 for gnode in self.graph.node_identifiers() {
117 let gidx = self.graph.to_index(gnode);
118 if gidx != count {
119 for idx in count..gidx {
120 digraph.remove_node(NodeIndex::new(idx));
121 }
122 count = gidx;
123 }
124 count += 1;
125 }
126
127 for node in self.graph.node_identifiers() {
129 self.node_map
130 .insert(node, NodeIndex::new(self.graph.to_index(node)));
131 self.rev_node_map
132 .insert(NodeIndex::new(self.graph.to_index(node)), node);
133 }
134 let mut sub_digraph = digraph.clone();
136
137 let mut tokens: HashMap<NodeIndex, NodeIndex> = self
139 .mapping
140 .iter()
141 .map(|(k, v)| (self.node_map[k], self.node_map[v]))
142 .collect();
143
144 let mut todo_nodes: Vec<NodeIndex> = tokens
146 .iter()
147 .filter_map(|(node, dest)| if node != dest { Some(*node) } else { None })
148 .collect();
149 todo_nodes.par_sort();
150
151 for node in self.graph.node_identifiers() {
153 self.add_token_edges(
154 self.node_map[&node],
155 &mut digraph,
156 &mut sub_digraph,
157 &mut tokens,
158 )?;
159 }
160 let outer_rng: Pcg64 = match self.seed {
163 Some(rng_seed) => Pcg64::seed_from_u64(rng_seed),
164 None => Pcg64::from_os_rng(),
165 };
166 let trial_seeds_vec: Vec<u64> = outer_rng
167 .sample_iter(&StandardUniform)
168 .take(self.trials)
169 .collect();
170
171 CondIterator::new(
172 trial_seeds_vec,
173 self.graph.node_count() >= self.parallel_threshold,
174 )
175 .map(|trial_seed| {
176 self.trial_map(
177 digraph.clone(),
178 sub_digraph.clone(),
179 tokens.clone(),
180 todo_nodes.clone(),
181 trial_seed,
182 )
183 })
184 .min_by_key(|result| match result {
185 Ok(res) => Ok(res.len()),
186 Err(e) => Err(*e),
187 })
188 .unwrap()
189 }
190
191 fn add_token_edges(
192 &self,
193 node: NodeIndex,
194 digraph: &mut StableGraph<(), (), Directed>,
195 sub_digraph: &mut StableGraph<(), (), Directed>,
196 tokens: &mut HashMap<NodeIndex, NodeIndex>,
197 ) -> Result<(), MapNotPossible> {
198 if !tokens.contains_key(&node) {
202 return Ok(());
203 }
204 if tokens[&node] == node {
205 digraph.update_edge(node, node, ());
206 return Ok(());
207 }
208 let id_node = self.rev_node_map[&node];
209 let id_token = self.rev_node_map[&tokens[&node]];
210
211 if self.graph.neighbors(id_node).next().is_none() {
212 return Err(MapNotPossible {});
213 }
214
215 for id_neighbor in self.graph.neighbors(id_node) {
216 let neighbor = self.node_map[&id_neighbor];
217 let dist_neighbor: DictMap<G::NodeId, usize> = dijkstra(
218 &self.graph,
219 id_neighbor,
220 Some(id_token),
221 |_| Ok::<usize, &str>(1),
222 None,
223 )
224 .unwrap();
225
226 let dist_node: DictMap<G::NodeId, usize> = dijkstra(
227 &self.graph,
228 id_node,
229 Some(id_token),
230 |_| Ok::<usize, &str>(1),
231 None,
232 )
233 .unwrap();
234 let neigh_dist = dist_neighbor.get(&id_token);
235 let node_dist = dist_node.get(&id_token);
236 if neigh_dist.is_none() {
237 return Err(MapNotPossible {});
238 }
239 if node_dist.is_none() {
240 return Err(MapNotPossible {});
241 }
242
243 if neigh_dist < node_dist {
244 digraph.update_edge(node, neighbor, ());
245 sub_digraph.update_edge(node, neighbor, ());
246 }
247 }
248 Ok(())
249 }
250
251 fn trial_map(
252 &self,
253 mut digraph: StableGraph<(), (), Directed>,
254 mut sub_digraph: StableGraph<(), (), Directed>,
255 mut tokens: HashMap<NodeIndex, NodeIndex>,
256 mut todo_nodes: Vec<NodeIndex>,
257 trial_seed: u64,
258 ) -> Result<Vec<Swap>, MapNotPossible> {
259 let mut steps = 0;
261 let mut swap_edges: Vec<Swap> = vec![];
262 let mut rng_seed: Pcg64 = Pcg64::seed_from_u64(trial_seed);
263 while !todo_nodes.is_empty() && steps <= 4 * digraph.node_count().pow(2) {
264 let between = Uniform::new(0, todo_nodes.len()).map_err(|_| MapNotPossible {})?;
266 let random: usize = between.sample(&mut rng_seed);
267 let todo_node = todo_nodes[random];
268
269 let cycle = find_cycle(&sub_digraph, Some(todo_node));
271 if !cycle.is_empty() {
272 for edge in cycle[1..].iter().rev() {
273 swap_edges.push(*edge);
274 self.swap(
275 edge.0,
276 edge.1,
277 &mut digraph,
278 &mut sub_digraph,
279 &mut tokens,
280 &mut todo_nodes,
281 )?;
282 }
283 steps += cycle.len() - 1;
284 } else {
287 let mut found = false;
288 let sub2 = &sub_digraph.clone();
289 for edge in dfs_edges(sub2, Some(todo_node)) {
290 let new_edge = (NodeIndex::new(edge.0), NodeIndex::new(edge.1));
291 if !tokens.contains_key(&new_edge.1) {
292 swap_edges.push(new_edge);
293 self.swap(
294 new_edge.0,
295 new_edge.1,
296 &mut digraph,
297 &mut sub_digraph,
298 &mut tokens,
299 &mut todo_nodes,
300 )?;
301 steps += 1;
302 found = true;
303 break;
304 }
305 }
306 if !found {
310 let cycle: Vec<Edge> = find_cycle(&digraph, Some(todo_node));
311 let unhappy_node = cycle[0].0;
312 let mut found = false;
313 let di2 = &mut digraph.clone();
314 for predecessor in di2.neighbors_directed(unhappy_node, Incoming) {
315 if predecessor != unhappy_node {
316 swap_edges.push((unhappy_node, predecessor));
317 self.swap(
318 unhappy_node,
319 predecessor,
320 &mut digraph,
321 &mut sub_digraph,
322 &mut tokens,
323 &mut todo_nodes,
324 )?;
325 steps += 1;
326 found = true;
327 break;
328 }
329 }
330 assert!(
331 found,
332 "The token swap process has ended unexpectedly, this points to a bug in rustworkx, please open an issue."
333 );
334 }
335 }
336 }
337 assert!(
338 todo_nodes.is_empty(),
339 "The output final swap map is incomplete, this points to a bug in rustworkx, please open an issue."
340 );
341 Ok(swap_edges)
342 }
343
344 fn swap(
345 &self,
346 node1: NodeIndex,
347 node2: NodeIndex,
348 digraph: &mut StableGraph<(), (), Directed>,
349 sub_digraph: &mut StableGraph<(), (), Directed>,
350 tokens: &mut HashMap<NodeIndex, NodeIndex>,
351 todo_nodes: &mut Vec<NodeIndex>,
352 ) -> Result<(), MapNotPossible> {
353 let token1 = tokens.remove(&node1);
355 let token2 = tokens.remove(&node2);
356
357 if let Some(t2) = token2 {
359 tokens.insert(node1, t2);
360 }
361 if let Some(t1) = token1 {
362 tokens.insert(node2, t1);
363 }
364 for node in [node1, node2] {
367 let edge_nodes: Vec<(NodeIndex, NodeIndex)> = digraph
368 .neighbors_directed(node, Outgoing)
369 .map(|successor| (node, successor))
370 .collect();
371 for (edge_node1, edge_node2) in edge_nodes {
372 let edge = digraph.find_edge(edge_node1, edge_node2).unwrap();
373 digraph.remove_edge(edge);
374 }
375 let edge_nodes: Vec<(NodeIndex, NodeIndex)> = sub_digraph
376 .neighbors_directed(node, Outgoing)
377 .map(|successor| (node, successor))
378 .collect();
379 for (edge_node1, edge_node2) in edge_nodes {
380 let edge = sub_digraph.find_edge(edge_node1, edge_node2).unwrap();
381 sub_digraph.remove_edge(edge);
382 }
383 self.add_token_edges(node, digraph, sub_digraph, tokens)?;
384
385 if tokens.contains_key(&node) && tokens[&node] != node {
387 if !todo_nodes.contains(&node) {
388 todo_nodes.push(node);
389 }
390 } else if todo_nodes.contains(&node) {
392 todo_nodes.swap_remove(todo_nodes.iter().position(|x| *x == node).unwrap());
393 }
394 }
395 Ok(())
396 }
397}
398
399pub fn token_swapper<G>(
443 graph: G,
444 mapping: HashMap<G::NodeId, G::NodeId>,
445 trials: Option<usize>,
446 seed: Option<u64>,
447 parallel_threshold: Option<usize>,
448) -> Result<Vec<Swap>, MapNotPossible>
449where
450 G: NodeCount
451 + EdgeCount
452 + IntoEdges
453 + Visitable
454 + NodeIndexable
455 + IntoNeighborsDirected
456 + IntoNodeIdentifiers
457 + Send
458 + Sync,
459 G::NodeId: Hash + Eq + Send + Sync,
460{
461 let mut swapper = TokenSwapper::new(graph, mapping, trials, seed, parallel_threshold);
462 swapper.map()
463}
464
465#[cfg(test)]
466mod test_token_swapper {
467
468 use crate::petgraph;
469 use crate::token_swapper::token_swapper;
470 use hashbrown::HashMap;
471 use petgraph::graph::NodeIndex;
472
473 fn do_swap(mapping: &mut HashMap<NodeIndex, NodeIndex>, swaps: &Vec<(NodeIndex, NodeIndex)>) {
474 for (swap1, swap2) in swaps {
476 let mut temp_node1: Option<NodeIndex> = None;
478 let mut temp_node2: Option<NodeIndex> = None;
479 if mapping.contains_key(swap1) {
480 temp_node1 = Some(mapping[swap1]);
481 mapping.remove(swap1);
482 }
483 if mapping.contains_key(swap2) {
484 temp_node2 = Some(mapping[swap2]);
485 mapping.remove(swap2);
486 }
487 if let Some(t1) = temp_node1 {
488 mapping.insert(*swap2, t1);
489 }
490 if let Some(t2) = temp_node2 {
491 mapping.insert(*swap1, t2);
492 }
493 }
494 }
495
496 #[test]
497 fn test_simple_swap() {
498 let g = petgraph::graph::UnGraph::<(), ()>::from_edges([(0, 1), (1, 2), (2, 3)]);
500 let mapping = HashMap::from([
501 (NodeIndex::new(0), NodeIndex::new(0)),
502 (NodeIndex::new(1), NodeIndex::new(3)),
503 (NodeIndex::new(3), NodeIndex::new(1)),
504 (NodeIndex::new(2), NodeIndex::new(2)),
505 ]);
506 let swaps = token_swapper(&g, mapping, Some(4), Some(4), Some(50));
507 assert_eq!(3, swaps.expect("swap mapping errored").len());
508 }
509
510 #[test]
511 fn test_small_swap() {
512 let g = petgraph::graph::UnGraph::<(), ()>::from_edges([
514 (0, 1),
515 (1, 2),
516 (2, 3),
517 (3, 4),
518 (4, 5),
519 (5, 6),
520 (6, 7),
521 ]);
522 let mut mapping = HashMap::with_capacity(8);
523 for i in 0..8 {
524 mapping.insert(NodeIndex::new(i), NodeIndex::new(7 - i));
525 }
526 let mut new_map = mapping.clone();
528 let swaps =
529 token_swapper(&g, mapping, Some(4), Some(4), Some(50)).expect("swap mapping errored");
530 do_swap(&mut new_map, &swaps);
531 let mut expected = HashMap::with_capacity(8);
532 for i in 0..8 {
533 expected.insert(NodeIndex::new(i), NodeIndex::new(i));
534 }
535 assert_eq!(expected, new_map);
536 }
537
538 #[test]
539 fn test_happy_swap_chain() {
540 let g = petgraph::graph::UnGraph::<(), ()>::from_edges([
542 (0, 1),
543 (0, 2),
544 (0, 3),
545 (0, 4),
546 (1, 2),
547 (1, 3),
548 (1, 4),
549 (2, 3),
550 (2, 4),
551 (3, 4),
552 (3, 6),
553 ]);
554 let mapping = HashMap::from([
555 (NodeIndex::new(0), NodeIndex::new(4)),
556 (NodeIndex::new(1), NodeIndex::new(0)),
557 (NodeIndex::new(2), NodeIndex::new(3)),
558 (NodeIndex::new(3), NodeIndex::new(6)),
559 (NodeIndex::new(4), NodeIndex::new(2)),
560 (NodeIndex::new(6), NodeIndex::new(1)),
561 ]);
562 let mut new_map = mapping.clone();
564 let swaps =
565 token_swapper(&g, mapping, Some(4), Some(4), Some(50)).expect("swap mapping errored");
566 do_swap(&mut new_map, &swaps);
567 let mut expected = HashMap::with_capacity(6);
568 for i in (0..5).chain(6..7) {
569 expected.insert(NodeIndex::new(i), NodeIndex::new(i));
570 }
571 assert_eq!(expected, new_map);
572 }
573
574 #[test]
575 fn test_partial_simple() {
576 let g = petgraph::graph::UnGraph::<(), ()>::from_edges([(0, 1), (1, 2), (2, 3)]);
578 let mapping = HashMap::from([(NodeIndex::new(0), NodeIndex::new(3))]);
579 let mut new_map = mapping.clone();
580 let swaps =
581 token_swapper(&g, mapping, Some(4), Some(4), Some(1)).expect("swap mapping errored");
582 do_swap(&mut new_map, &swaps);
583 let mut expected = HashMap::with_capacity(4);
584 expected.insert(NodeIndex::new(3), NodeIndex::new(3));
585 assert_eq!(expected, new_map);
586 }
587
588 #[test]
589 fn test_partial_simple_remove_node() {
590 let mut g =
592 petgraph::graph::UnGraph::<(), ()>::from_edges([(0, 1), (1, 2), (2, 3), (3, 4)]);
593 let mapping = HashMap::from([(NodeIndex::new(0), NodeIndex::new(3))]);
594 g.remove_node(NodeIndex::new(2));
595 g.add_edge(NodeIndex::new(1), NodeIndex::new(3), ());
596 let mut new_map = mapping.clone();
597 let swaps =
598 token_swapper(&g, mapping, Some(4), Some(4), Some(1)).expect("swap mapping errored");
599 do_swap(&mut new_map, &swaps);
600 let mut expected = HashMap::with_capacity(4);
601 expected.insert(NodeIndex::new(3), NodeIndex::new(3));
602 assert_eq!(expected, new_map);
603 }
604
605 #[test]
606 fn test_partial_small() {
607 let g = petgraph::graph::UnGraph::<(), ()>::from_edges([(0, 1), (1, 2), (2, 3)]);
609 let mapping = HashMap::from([
610 (NodeIndex::new(0), NodeIndex::new(3)),
611 (NodeIndex::new(1), NodeIndex::new(2)),
612 ]);
613 let mut new_map = mapping.clone();
614 let swaps =
615 token_swapper(&g, mapping, Some(4), Some(4), Some(50)).expect("swap mapping errored");
616 do_swap(&mut new_map, &swaps);
617 let expected = HashMap::from([
618 (NodeIndex::new(2), NodeIndex::new(2)),
619 (NodeIndex::new(3), NodeIndex::new(3)),
620 ]);
621 assert_eq!(5, swaps.len());
622 assert_eq!(expected, new_map);
623 }
624
625 #[test]
626 fn test_large_partial_random() {
627 use crate::generators::gnm_random_graph;
629 use rand::prelude::*;
630 use rand_pcg::Pcg64;
631 use std::iter::zip;
632
633 let mut rng: Pcg64 = Pcg64::seed_from_u64(4);
634
635 let size = 100;
637 let mut g: petgraph::stable_graph::StableGraph<(), ()> =
638 gnm_random_graph(size, size.pow(2) / 10, Some(4), || (), || ()).unwrap();
639
640 let nodes: Vec<_> = g.node_indices().collect();
642 for node in nodes {
643 if let Some(edge) = g.find_edge(node, node) {
644 g.remove_edge(edge);
645 }
646 }
647 for i in 0..(g.node_count() - 1) {
649 g.add_edge(NodeIndex::new(i), NodeIndex::new(i + 1), ());
650 }
651
652 let mut mapped_nodes: Vec<usize> = g.node_indices().map(|node| node.index()).collect();
654 let nodes = mapped_nodes.clone();
655 mapped_nodes.shuffle(&mut rng);
656
657 let mut mapping: Vec<(usize, usize)> = zip(nodes, mapped_nodes).collect();
659 mapping.retain(|(a, _)| a % 2 == 0);
660
661 let mapping: HashMap<NodeIndex, NodeIndex> = mapping
663 .into_iter()
664 .map(|(a, b)| (NodeIndex::new(a), NodeIndex::new(b)))
665 .collect();
666 let mut new_map = mapping.clone();
667 let expected: HashMap<NodeIndex, NodeIndex> =
668 mapping.values().map(|val| (*val, *val)).collect();
669
670 let swaps =
671 token_swapper(&g, mapping, Some(4), Some(4), Some(50)).expect("swap mapping errored");
672 do_swap(&mut new_map, &swaps);
673 assert_eq!(expected, new_map)
674 }
675
676 #[test]
677 fn test_disjoint_graph_works() {
678 let g = petgraph::graph::UnGraph::<(), ()>::from_edges([(0, 1), (2, 3)]);
679 let mapping = HashMap::from([
680 (NodeIndex::new(1), NodeIndex::new(0)),
681 (NodeIndex::new(0), NodeIndex::new(1)),
682 (NodeIndex::new(2), NodeIndex::new(3)),
683 (NodeIndex::new(3), NodeIndex::new(2)),
684 ]);
685 let mut new_map = mapping.clone();
686 let swaps =
687 token_swapper(&g, mapping, Some(10), Some(4), Some(50)).expect("swap mapping errored");
688 do_swap(&mut new_map, &swaps);
689 let expected = HashMap::from([
690 (NodeIndex::new(2), NodeIndex::new(2)),
691 (NodeIndex::new(3), NodeIndex::new(3)),
692 (NodeIndex::new(1), NodeIndex::new(1)),
693 (NodeIndex::new(0), NodeIndex::new(0)),
694 ]);
695 assert_eq!(2, swaps.len());
696 assert_eq!(expected, new_map);
697 }
698
699 #[test]
700 fn test_disjoint_graph_fails() {
701 let g = petgraph::graph::UnGraph::<(), ()>::from_edges([(0, 1), (2, 3)]);
702 let mapping = HashMap::from([
703 (NodeIndex::new(2), NodeIndex::new(0)),
704 (NodeIndex::new(1), NodeIndex::new(1)),
705 (NodeIndex::new(0), NodeIndex::new(2)),
706 (NodeIndex::new(3), NodeIndex::new(3)),
707 ]);
708 assert!(
709 token_swapper(&g, mapping, Some(10), Some(4), Some(50)).is_err(),
710 "This should error"
711 );
712 }
713
714 #[test]
715 fn test_edgeless_graph_fails() {
716 let mut g = petgraph::graph::UnGraph::<(), ()>::new_undirected();
717 let a = g.add_node(());
718 let b = g.add_node(());
719 let c = g.add_node(());
720 let d = g.add_node(());
721 g.add_edge(c, d, ());
722 let mapping = HashMap::from([(a, b), (b, a)]);
723 assert!(
724 token_swapper(&g, mapping, Some(10), Some(4), Some(50)).is_err(),
725 "This should error"
726 );
727 }
728}