1use rand::distributions::{Standard, Uniform};
14use rand::prelude::*;
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_entropy(),
165 };
166 let trial_seeds_vec: Vec<u64> =
167 outer_rng.sample_iter(&Standard).take(self.trials).collect();
168
169 CondIterator::new(
170 trial_seeds_vec,
171 self.graph.node_count() >= self.parallel_threshold,
172 )
173 .map(|trial_seed| {
174 self.trial_map(
175 digraph.clone(),
176 sub_digraph.clone(),
177 tokens.clone(),
178 todo_nodes.clone(),
179 trial_seed,
180 )
181 })
182 .min_by_key(|result| match result {
183 Ok(res) => Ok(res.len()),
184 Err(e) => Err(*e),
185 })
186 .unwrap()
187 }
188
189 fn add_token_edges(
190 &self,
191 node: NodeIndex,
192 digraph: &mut StableGraph<(), (), Directed>,
193 sub_digraph: &mut StableGraph<(), (), Directed>,
194 tokens: &mut HashMap<NodeIndex, NodeIndex>,
195 ) -> Result<(), MapNotPossible> {
196 if !tokens.contains_key(&node) {
200 return Ok(());
201 }
202 if tokens[&node] == node {
203 digraph.update_edge(node, node, ());
204 return Ok(());
205 }
206 let id_node = self.rev_node_map[&node];
207 let id_token = self.rev_node_map[&tokens[&node]];
208
209 if self.graph.neighbors(id_node).next().is_none() {
210 return Err(MapNotPossible {});
211 }
212
213 for id_neighbor in self.graph.neighbors(id_node) {
214 let neighbor = self.node_map[&id_neighbor];
215 let dist_neighbor: DictMap<G::NodeId, usize> = dijkstra(
216 &self.graph,
217 id_neighbor,
218 Some(id_token),
219 |_| Ok::<usize, &str>(1),
220 None,
221 )
222 .unwrap();
223
224 let dist_node: DictMap<G::NodeId, usize> = dijkstra(
225 &self.graph,
226 id_node,
227 Some(id_token),
228 |_| Ok::<usize, &str>(1),
229 None,
230 )
231 .unwrap();
232 let neigh_dist = dist_neighbor.get(&id_token);
233 let node_dist = dist_node.get(&id_token);
234 if neigh_dist.is_none() {
235 return Err(MapNotPossible {});
236 }
237 if node_dist.is_none() {
238 return Err(MapNotPossible {});
239 }
240
241 if neigh_dist < node_dist {
242 digraph.update_edge(node, neighbor, ());
243 sub_digraph.update_edge(node, neighbor, ());
244 }
245 }
246 Ok(())
247 }
248
249 fn trial_map(
250 &self,
251 mut digraph: StableGraph<(), (), Directed>,
252 mut sub_digraph: StableGraph<(), (), Directed>,
253 mut tokens: HashMap<NodeIndex, NodeIndex>,
254 mut todo_nodes: Vec<NodeIndex>,
255 trial_seed: u64,
256 ) -> Result<Vec<Swap>, MapNotPossible> {
257 let mut steps = 0;
259 let mut swap_edges: Vec<Swap> = vec![];
260 let mut rng_seed: Pcg64 = Pcg64::seed_from_u64(trial_seed);
261 while !todo_nodes.is_empty() && steps <= 4 * digraph.node_count().pow(2) {
262 let between = Uniform::new(0, todo_nodes.len());
264 let random: usize = between.sample(&mut rng_seed);
265 let todo_node = todo_nodes[random];
266
267 let cycle = find_cycle(&sub_digraph, Some(todo_node));
269 if !cycle.is_empty() {
270 for edge in cycle[1..].iter().rev() {
271 swap_edges.push(*edge);
272 self.swap(
273 edge.0,
274 edge.1,
275 &mut digraph,
276 &mut sub_digraph,
277 &mut tokens,
278 &mut todo_nodes,
279 )?;
280 }
281 steps += cycle.len() - 1;
282 } else {
285 let mut found = false;
286 let sub2 = &sub_digraph.clone();
287 for edge in dfs_edges(sub2, Some(todo_node)) {
288 let new_edge = (NodeIndex::new(edge.0), NodeIndex::new(edge.1));
289 if !tokens.contains_key(&new_edge.1) {
290 swap_edges.push(new_edge);
291 self.swap(
292 new_edge.0,
293 new_edge.1,
294 &mut digraph,
295 &mut sub_digraph,
296 &mut tokens,
297 &mut todo_nodes,
298 )?;
299 steps += 1;
300 found = true;
301 break;
302 }
303 }
304 if !found {
308 let cycle: Vec<Edge> = find_cycle(&digraph, Some(todo_node));
309 let unhappy_node = cycle[0].0;
310 let mut found = false;
311 let di2 = &mut digraph.clone();
312 for predecessor in di2.neighbors_directed(unhappy_node, Incoming) {
313 if predecessor != unhappy_node {
314 swap_edges.push((unhappy_node, predecessor));
315 self.swap(
316 unhappy_node,
317 predecessor,
318 &mut digraph,
319 &mut sub_digraph,
320 &mut tokens,
321 &mut todo_nodes,
322 )?;
323 steps += 1;
324 found = true;
325 break;
326 }
327 }
328 assert!(
329 found,
330 "The token swap process has ended unexpectedly, this points to a bug in rustworkx, please open an issue."
331 );
332 }
333 }
334 }
335 assert!(
336 todo_nodes.is_empty(),
337 "The output final swap map is incomplete, this points to a bug in rustworkx, please open an issue."
338 );
339 Ok(swap_edges)
340 }
341
342 fn swap(
343 &self,
344 node1: NodeIndex,
345 node2: NodeIndex,
346 digraph: &mut StableGraph<(), (), Directed>,
347 sub_digraph: &mut StableGraph<(), (), Directed>,
348 tokens: &mut HashMap<NodeIndex, NodeIndex>,
349 todo_nodes: &mut Vec<NodeIndex>,
350 ) -> Result<(), MapNotPossible> {
351 let token1 = tokens.remove(&node1);
353 let token2 = tokens.remove(&node2);
354
355 if let Some(t2) = token2 {
357 tokens.insert(node1, t2);
358 }
359 if let Some(t1) = token1 {
360 tokens.insert(node2, t1);
361 }
362 for node in [node1, node2] {
365 let edge_nodes: Vec<(NodeIndex, NodeIndex)> = digraph
366 .neighbors_directed(node, Outgoing)
367 .map(|successor| (node, successor))
368 .collect();
369 for (edge_node1, edge_node2) in edge_nodes {
370 let edge = digraph.find_edge(edge_node1, edge_node2).unwrap();
371 digraph.remove_edge(edge);
372 }
373 let edge_nodes: Vec<(NodeIndex, NodeIndex)> = sub_digraph
374 .neighbors_directed(node, Outgoing)
375 .map(|successor| (node, successor))
376 .collect();
377 for (edge_node1, edge_node2) in edge_nodes {
378 let edge = sub_digraph.find_edge(edge_node1, edge_node2).unwrap();
379 sub_digraph.remove_edge(edge);
380 }
381 self.add_token_edges(node, digraph, sub_digraph, tokens)?;
382
383 if tokens.contains_key(&node) && tokens[&node] != node {
385 if !todo_nodes.contains(&node) {
386 todo_nodes.push(node);
387 }
388 } else if todo_nodes.contains(&node) {
390 todo_nodes.swap_remove(todo_nodes.iter().position(|x| *x == node).unwrap());
391 }
392 }
393 Ok(())
394 }
395}
396
397pub fn token_swapper<G>(
441 graph: G,
442 mapping: HashMap<G::NodeId, G::NodeId>,
443 trials: Option<usize>,
444 seed: Option<u64>,
445 parallel_threshold: Option<usize>,
446) -> Result<Vec<Swap>, MapNotPossible>
447where
448 G: NodeCount
449 + EdgeCount
450 + IntoEdges
451 + Visitable
452 + NodeIndexable
453 + IntoNeighborsDirected
454 + IntoNodeIdentifiers
455 + Send
456 + Sync,
457 G::NodeId: Hash + Eq + Send + Sync,
458{
459 let mut swapper = TokenSwapper::new(graph, mapping, trials, seed, parallel_threshold);
460 swapper.map()
461}
462
463#[cfg(test)]
464mod test_token_swapper {
465
466 use crate::petgraph;
467 use crate::token_swapper::token_swapper;
468 use hashbrown::HashMap;
469 use petgraph::graph::NodeIndex;
470
471 fn do_swap(mapping: &mut HashMap<NodeIndex, NodeIndex>, swaps: &Vec<(NodeIndex, NodeIndex)>) {
472 for (swap1, swap2) in swaps {
474 let mut temp_node1: Option<NodeIndex> = None;
476 let mut temp_node2: Option<NodeIndex> = None;
477 if mapping.contains_key(swap1) {
478 temp_node1 = Some(mapping[swap1]);
479 mapping.remove(swap1);
480 }
481 if mapping.contains_key(swap2) {
482 temp_node2 = Some(mapping[swap2]);
483 mapping.remove(swap2);
484 }
485 if let Some(t1) = temp_node1 {
486 mapping.insert(*swap2, t1);
487 }
488 if let Some(t2) = temp_node2 {
489 mapping.insert(*swap1, t2);
490 }
491 }
492 }
493
494 #[test]
495 fn test_simple_swap() {
496 let g = petgraph::graph::UnGraph::<(), ()>::from_edges([(0, 1), (1, 2), (2, 3)]);
498 let mapping = HashMap::from([
499 (NodeIndex::new(0), NodeIndex::new(0)),
500 (NodeIndex::new(1), NodeIndex::new(3)),
501 (NodeIndex::new(3), NodeIndex::new(1)),
502 (NodeIndex::new(2), NodeIndex::new(2)),
503 ]);
504 let swaps = token_swapper(&g, mapping, Some(4), Some(4), Some(50));
505 assert_eq!(3, swaps.expect("swap mapping errored").len());
506 }
507
508 #[test]
509 fn test_small_swap() {
510 let g = petgraph::graph::UnGraph::<(), ()>::from_edges([
512 (0, 1),
513 (1, 2),
514 (2, 3),
515 (3, 4),
516 (4, 5),
517 (5, 6),
518 (6, 7),
519 ]);
520 let mut mapping = HashMap::with_capacity(8);
521 for i in 0..8 {
522 mapping.insert(NodeIndex::new(i), NodeIndex::new(7 - i));
523 }
524 let mut new_map = mapping.clone();
526 let swaps =
527 token_swapper(&g, mapping, Some(4), Some(4), Some(50)).expect("swap mapping errored");
528 do_swap(&mut new_map, &swaps);
529 let mut expected = HashMap::with_capacity(8);
530 for i in 0..8 {
531 expected.insert(NodeIndex::new(i), NodeIndex::new(i));
532 }
533 assert_eq!(expected, new_map);
534 }
535
536 #[test]
537 fn test_happy_swap_chain() {
538 let g = petgraph::graph::UnGraph::<(), ()>::from_edges([
540 (0, 1),
541 (0, 2),
542 (0, 3),
543 (0, 4),
544 (1, 2),
545 (1, 3),
546 (1, 4),
547 (2, 3),
548 (2, 4),
549 (3, 4),
550 (3, 6),
551 ]);
552 let mapping = HashMap::from([
553 (NodeIndex::new(0), NodeIndex::new(4)),
554 (NodeIndex::new(1), NodeIndex::new(0)),
555 (NodeIndex::new(2), NodeIndex::new(3)),
556 (NodeIndex::new(3), NodeIndex::new(6)),
557 (NodeIndex::new(4), NodeIndex::new(2)),
558 (NodeIndex::new(6), NodeIndex::new(1)),
559 ]);
560 let mut new_map = mapping.clone();
562 let swaps =
563 token_swapper(&g, mapping, Some(4), Some(4), Some(50)).expect("swap mapping errored");
564 do_swap(&mut new_map, &swaps);
565 let mut expected = HashMap::with_capacity(6);
566 for i in (0..5).chain(6..7) {
567 expected.insert(NodeIndex::new(i), NodeIndex::new(i));
568 }
569 assert_eq!(expected, new_map);
570 }
571
572 #[test]
573 fn test_partial_simple() {
574 let g = petgraph::graph::UnGraph::<(), ()>::from_edges([(0, 1), (1, 2), (2, 3)]);
576 let mapping = HashMap::from([(NodeIndex::new(0), NodeIndex::new(3))]);
577 let mut new_map = mapping.clone();
578 let swaps =
579 token_swapper(&g, mapping, Some(4), Some(4), Some(1)).expect("swap mapping errored");
580 do_swap(&mut new_map, &swaps);
581 let mut expected = HashMap::with_capacity(4);
582 expected.insert(NodeIndex::new(3), NodeIndex::new(3));
583 assert_eq!(expected, new_map);
584 }
585
586 #[test]
587 fn test_partial_simple_remove_node() {
588 let mut g =
590 petgraph::graph::UnGraph::<(), ()>::from_edges([(0, 1), (1, 2), (2, 3), (3, 4)]);
591 let mapping = HashMap::from([(NodeIndex::new(0), NodeIndex::new(3))]);
592 g.remove_node(NodeIndex::new(2));
593 g.add_edge(NodeIndex::new(1), NodeIndex::new(3), ());
594 let mut new_map = mapping.clone();
595 let swaps =
596 token_swapper(&g, mapping, Some(4), Some(4), Some(1)).expect("swap mapping errored");
597 do_swap(&mut new_map, &swaps);
598 let mut expected = HashMap::with_capacity(4);
599 expected.insert(NodeIndex::new(3), NodeIndex::new(3));
600 assert_eq!(expected, new_map);
601 }
602
603 #[test]
604 fn test_partial_small() {
605 let g = petgraph::graph::UnGraph::<(), ()>::from_edges([(0, 1), (1, 2), (2, 3)]);
607 let mapping = HashMap::from([
608 (NodeIndex::new(0), NodeIndex::new(3)),
609 (NodeIndex::new(1), NodeIndex::new(2)),
610 ]);
611 let mut new_map = mapping.clone();
612 let swaps =
613 token_swapper(&g, mapping, Some(4), Some(4), Some(50)).expect("swap mapping errored");
614 do_swap(&mut new_map, &swaps);
615 let expected = HashMap::from([
616 (NodeIndex::new(2), NodeIndex::new(2)),
617 (NodeIndex::new(3), NodeIndex::new(3)),
618 ]);
619 assert_eq!(5, swaps.len());
620 assert_eq!(expected, new_map);
621 }
622
623 #[test]
624 fn test_large_partial_random() {
625 use crate::generators::gnm_random_graph;
627 use rand::prelude::*;
628 use rand_pcg::Pcg64;
629 use std::iter::zip;
630
631 let mut rng: Pcg64 = Pcg64::seed_from_u64(4);
632
633 let size = 100;
635 let mut g: petgraph::stable_graph::StableGraph<(), ()> =
636 gnm_random_graph(size, size.pow(2) / 10, Some(4), || (), || ()).unwrap();
637
638 let nodes: Vec<_> = g.node_indices().collect();
640 for node in nodes {
641 if let Some(edge) = g.find_edge(node, node) {
642 g.remove_edge(edge);
643 }
644 }
645 for i in 0..(g.node_count() - 1) {
647 g.add_edge(NodeIndex::new(i), NodeIndex::new(i + 1), ());
648 }
649
650 let mut mapped_nodes: Vec<usize> = g.node_indices().map(|node| node.index()).collect();
652 let nodes = mapped_nodes.clone();
653 mapped_nodes.shuffle(&mut rng);
654
655 let mut mapping: Vec<(usize, usize)> = zip(nodes, mapped_nodes).collect();
657 mapping.retain(|(a, _)| a % 2 == 0);
658
659 let mapping: HashMap<NodeIndex, NodeIndex> = mapping
661 .into_iter()
662 .map(|(a, b)| (NodeIndex::new(a), NodeIndex::new(b)))
663 .collect();
664 let mut new_map = mapping.clone();
665 let expected: HashMap<NodeIndex, NodeIndex> =
666 mapping.values().map(|val| (*val, *val)).collect();
667
668 let swaps =
669 token_swapper(&g, mapping, Some(4), Some(4), Some(50)).expect("swap mapping errored");
670 do_swap(&mut new_map, &swaps);
671 assert_eq!(expected, new_map)
672 }
673
674 #[test]
675 fn test_disjoint_graph_works() {
676 let g = petgraph::graph::UnGraph::<(), ()>::from_edges([(0, 1), (2, 3)]);
677 let mapping = HashMap::from([
678 (NodeIndex::new(1), NodeIndex::new(0)),
679 (NodeIndex::new(0), NodeIndex::new(1)),
680 (NodeIndex::new(2), NodeIndex::new(3)),
681 (NodeIndex::new(3), NodeIndex::new(2)),
682 ]);
683 let mut new_map = mapping.clone();
684 let swaps =
685 token_swapper(&g, mapping, Some(10), Some(4), Some(50)).expect("swap mapping errored");
686 do_swap(&mut new_map, &swaps);
687 let expected = HashMap::from([
688 (NodeIndex::new(2), NodeIndex::new(2)),
689 (NodeIndex::new(3), NodeIndex::new(3)),
690 (NodeIndex::new(1), NodeIndex::new(1)),
691 (NodeIndex::new(0), NodeIndex::new(0)),
692 ]);
693 assert_eq!(2, swaps.len());
694 assert_eq!(expected, new_map);
695 }
696
697 #[test]
698 fn test_disjoint_graph_fails() {
699 let g = petgraph::graph::UnGraph::<(), ()>::from_edges([(0, 1), (2, 3)]);
700 let mapping = HashMap::from([
701 (NodeIndex::new(2), NodeIndex::new(0)),
702 (NodeIndex::new(1), NodeIndex::new(1)),
703 (NodeIndex::new(0), NodeIndex::new(2)),
704 (NodeIndex::new(3), NodeIndex::new(3)),
705 ]);
706 assert!(
707 token_swapper(&g, mapping, Some(10), Some(4), Some(50)).is_err(),
708 "This should error"
709 );
710 }
711
712 #[test]
713 fn test_edgeless_graph_fails() {
714 let mut g = petgraph::graph::UnGraph::<(), ()>::new_undirected();
715 let a = g.add_node(());
716 let b = g.add_node(());
717 let c = g.add_node(());
718 let d = g.add_node(());
719 g.add_edge(c, d, ());
720 let mapping = HashMap::from([(a, b), (b, a)]);
721 assert!(
722 token_swapper(&g, mapping, Some(10), Some(4), Some(50)).is_err(),
723 "This should error"
724 );
725 }
726}