1use std::collections::{HashMap, HashSet};
14use std::hash::Hash;
15
16pub fn tarjan_sccs<K>(nodes: &[K], graph: &HashMap<K, Vec<K>>) -> Vec<Vec<K>>
19where
20 K: Clone + Eq + Hash + Ord,
21{
22 struct State<K> {
23 index: usize,
24 indices: HashMap<K, usize>,
25 lowlink: HashMap<K, usize>,
26 stack: Vec<K>,
27 on_stack: HashSet<K>,
28 components: Vec<Vec<K>>,
29 }
30
31 fn strong_connect<K>(v: K, graph: &HashMap<K, Vec<K>>, st: &mut State<K>)
32 where
33 K: Clone + Eq + Hash + Ord,
34 {
35 st.indices.insert(v.clone(), st.index);
36 st.lowlink.insert(v.clone(), st.index);
37 st.index += 1;
38 st.stack.push(v.clone());
39 st.on_stack.insert(v.clone());
40
41 if let Some(neighbors) = graph.get(&v) {
42 for w in neighbors {
43 if !st.indices.contains_key(w) {
44 strong_connect(w.clone(), graph, st);
45 let low_v = st.lowlink[&v];
46 let low_w = st.lowlink[w];
47 st.lowlink.insert(v.clone(), low_v.min(low_w));
48 } else if st.on_stack.contains(w) {
49 let low_v = st.lowlink[&v];
50 let idx_w = st.indices[w];
51 st.lowlink.insert(v.clone(), low_v.min(idx_w));
52 }
53 }
54 }
55
56 if st.lowlink[&v] == st.indices[&v] {
57 let mut comp = Vec::new();
58 while let Some(w) = st.stack.pop() {
59 st.on_stack.remove(&w);
60 let done = w == v;
61 comp.push(w);
62 if done {
63 break;
64 }
65 }
66 comp.sort();
67 st.components.push(comp);
68 }
69 }
70
71 let mut sorted_nodes = nodes.to_vec();
72 sorted_nodes.sort();
73 let mut st = State {
74 index: 0,
75 indices: HashMap::new(),
76 lowlink: HashMap::new(),
77 stack: Vec::new(),
78 on_stack: HashSet::new(),
79 components: Vec::new(),
80 };
81 for node in sorted_nodes {
82 if !st.indices.contains_key(&node) {
83 strong_connect(node, graph, &mut st);
84 }
85 }
86 st.components.sort_by(|a, b| a[0].cmp(&b[0]));
87 st.components
88}
89
90pub fn mutually_recursive<K>(nodes: &[K], graph: &HashMap<K, Vec<K>>) -> HashSet<K>
95where
96 K: Clone + Eq + Hash + Ord,
97{
98 tarjan_sccs(nodes, graph)
99 .into_iter()
100 .filter(|c| c.len() > 1)
101 .flatten()
102 .collect()
103}