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