oxihuman_core/
strongly_connected.rs1#![allow(dead_code)]
4
5pub struct SccGraph {
9 pub n: usize,
10 pub adj: Vec<Vec<usize>>,
11}
12
13impl SccGraph {
14 pub fn new(n: usize) -> Self {
15 SccGraph {
16 n,
17 adj: vec![Vec::new(); n],
18 }
19 }
20}
21
22pub fn new_scc_graph(n: usize) -> SccGraph {
24 SccGraph::new(n)
25}
26
27pub fn scc_add_edge(g: &mut SccGraph, u: usize, v: usize) {
29 if u < g.n && v < g.n {
30 g.adj[u].push(v);
31 }
32}
33
34pub fn tarjan_scc(g: &SccGraph) -> Vec<Vec<usize>> {
36 let n = g.n;
37 let mut index = vec![usize::MAX; n];
38 let mut lowlink = vec![0usize; n];
39 let mut on_stack = vec![false; n];
40 let mut stack: Vec<usize> = Vec::new();
41 let mut sccs: Vec<Vec<usize>> = Vec::new();
42 let mut counter = 0usize;
43
44 for start in 0..n {
45 if index[start] == usize::MAX {
46 let mut dfs_stack: Vec<(usize, usize)> = vec![(start, 0)];
48 index[start] = counter;
49 lowlink[start] = counter;
50 counter += 1;
51 on_stack[start] = true;
52 stack.push(start);
53
54 while let Some((v, ei)) = dfs_stack.last_mut() {
55 let v = *v;
56 let neighbors = &g.adj[v];
57 if *ei < neighbors.len() {
58 let w = neighbors[*ei];
59 *ei += 1;
60 if index[w] == usize::MAX {
61 index[w] = counter;
62 lowlink[w] = counter;
63 counter += 1;
64 on_stack[w] = true;
65 stack.push(w);
66 dfs_stack.push((w, 0));
67 } else if on_stack[w] {
68 let lv = lowlink[v];
69 lowlink[v] = lv.min(index[w]);
70 }
71 } else {
72 dfs_stack.pop();
74 if let Some(&(parent, _)) = dfs_stack.last() {
75 let lv = lowlink[parent];
76 lowlink[parent] = lv.min(lowlink[v]);
77 }
78 if lowlink[v] == index[v] {
79 let mut scc = Vec::new();
81 #[allow(clippy::while_let_loop)]
82 loop {
83 let Some(w) = stack.pop() else { break };
84 on_stack[w] = false;
85 scc.push(w);
86 if w == v {
87 break;
88 }
89 }
90 scc.sort_unstable();
91 sccs.push(scc);
92 }
93 }
94 }
95 }
96 }
97 sccs
98}
99
100pub fn scc_count(g: &SccGraph) -> usize {
102 tarjan_scc(g).len()
103}
104
105pub fn is_strongly_connected(g: &SccGraph) -> bool {
107 if g.n == 0 {
108 return true;
109 }
110 let sccs = tarjan_scc(g);
111 sccs.len() == 1
112}
113
114pub fn largest_scc(g: &SccGraph) -> Vec<usize> {
116 tarjan_scc(g)
117 .into_iter()
118 .max_by_key(|s| s.len())
119 .unwrap_or_default()
120}
121
122#[cfg(test)]
123mod tests {
124 use super::*;
125
126 #[test]
127 fn test_single_node_scc() {
128 let g = new_scc_graph(1);
130 let sccs = tarjan_scc(&g);
131 assert_eq!(sccs.len(), 1);
132 assert_eq!(sccs[0], vec![0]);
133 }
134
135 #[test]
136 fn test_two_node_cycle() {
137 let mut g = new_scc_graph(2);
139 scc_add_edge(&mut g, 0, 1);
140 scc_add_edge(&mut g, 1, 0);
141 assert_eq!(scc_count(&g), 1);
142 }
143
144 #[test]
145 fn test_dag_three_sccs() {
146 let mut g = new_scc_graph(3);
148 scc_add_edge(&mut g, 0, 1);
149 scc_add_edge(&mut g, 1, 2);
150 assert_eq!(scc_count(&g), 3);
151 }
152
153 #[test]
154 fn test_strongly_connected_true() {
155 let mut g = new_scc_graph(3);
156 scc_add_edge(&mut g, 0, 1);
157 scc_add_edge(&mut g, 1, 2);
158 scc_add_edge(&mut g, 2, 0);
159 assert!(is_strongly_connected(&g));
160 }
161
162 #[test]
163 fn test_strongly_connected_false() {
164 let mut g = new_scc_graph(3);
165 scc_add_edge(&mut g, 0, 1);
166 scc_add_edge(&mut g, 1, 2);
167 assert!(!is_strongly_connected(&g));
168 }
169
170 #[test]
171 fn test_empty_graph() {
172 let g = new_scc_graph(0);
173 assert!(is_strongly_connected(&g));
174 }
175
176 #[test]
177 fn test_largest_scc() {
178 let mut g = new_scc_graph(4);
180 scc_add_edge(&mut g, 0, 1);
181 scc_add_edge(&mut g, 1, 2);
182 scc_add_edge(&mut g, 2, 0);
183 scc_add_edge(&mut g, 2, 3);
184 let big = largest_scc(&g);
185 assert_eq!(big.len(), 3);
186 }
187
188 #[test]
189 fn test_self_loop_scc() {
190 let mut g = new_scc_graph(2);
191 scc_add_edge(&mut g, 0, 0); scc_add_edge(&mut g, 1, 1);
193 assert_eq!(scc_count(&g), 2);
194 }
195
196 #[test]
197 fn test_complex_graph() {
198 let mut g = new_scc_graph(8);
200 let edges = [
201 (0, 1),
202 (1, 2),
203 (2, 0),
204 (3, 1),
205 (3, 2),
206 (3, 4),
207 (4, 3),
208 (4, 5),
209 (5, 6),
210 (6, 4),
211 (7, 6),
212 (7, 7),
213 ];
214 for (u, v) in edges {
215 scc_add_edge(&mut g, u, v);
216 }
217 let count = scc_count(&g);
218 assert!(count >= 3);
219 }
220}