strongly_connected_components/lib.rs
1//! Decomposes a graph into [Strongly Connected Components](https://en.wikipedia.org/wiki/Strongly_connected_component)
2//! and to sorts them in [topological order](https://en.wikipedia.org/wiki/Topological_sorting).
3//!
4//! ## Usage
5//!
6//! 1. Define the [`Graph`] structure:
7//! ```
8//! // ┌───┐ ┌───┐ ┌───┐
9//! // │ a ├─►│ b ├─►│ c │
10//! // └───┘ └─▲─┘ └─┬─┘
11//! // └──────┘
12//! # use strongly_connected_components::Node;
13//! # use strongly_connected_components::Graph;
14//! let mut graph = Graph::new();
15//! let a: Node = graph.new_node();
16//! let b: Node = graph.new_node();
17//! let c: Node = graph.new_node();
18//! graph.new_edge(a, b);
19//! graph.new_edge(b, c);
20//! graph.new_edge(c, b);
21//! ```
22//! 2. Run the algorithm and create the [`SccDecomposition`]:
23//! ```
24//! # use strongly_connected_components::Graph;
25//! # use strongly_connected_components::SccDecomposition;
26//! # let mut graph = Graph::new();
27//! # let a = graph.new_node();
28//! # let b = graph.new_node();
29//! # let c = graph.new_node();
30//! # graph.new_edge(a, b);
31//! # graph.new_edge(b, c);
32//! # graph.new_edge(c, b);
33//! let decomp: SccDecomposition = graph.find_sccs();
34//! // There are 2 SCCs in the example graph: `[a]` and `[b, c]`.
35//! assert_eq!(decomp.len(), 2);
36//! ```
37//! 3. Check whether two nodes belong to the same [`Scc`]:
38//! ```
39//! # use strongly_connected_components::Graph;
40//! # use strongly_connected_components::Scc;
41//! # use strongly_connected_components::SccDecomposition;
42//! # let mut graph = Graph::new();
43//! # let a = graph.new_node();
44//! # let b = graph.new_node();
45//! # let c = graph.new_node();
46//! # graph.new_edge(a, b);
47//! # graph.new_edge(b, c);
48//! # graph.new_edge(c, b);
49//! # let decomp = graph.find_sccs();
50//! let a_scc: &Scc = decomp.scc_of_node(a);
51//! let b_scc: &Scc = decomp.scc_of_node(b);
52//! let c_scc: &Scc = decomp.scc_of_node(c);
53//!
54//! // Node `a` belongs to a different SCC than `b` and `c`.
55//! assert_ne!(a_scc, b_scc);
56//! assert_ne!(a_scc, c_scc);
57//!
58//! // Nodes `b` and `c` belong to the same SCC.
59//! assert_eq!(b_scc, c_scc);
60//! ```
61//! 4. List all nodes belonging to [`Scc`]:
62//! ```
63//! # use strongly_connected_components::Node;
64//! # use strongly_connected_components::Graph;
65//! # let mut graph = Graph::new();
66//! # let a = graph.new_node();
67//! # let b = graph.new_node();
68//! # let c = graph.new_node();
69//! # graph.new_edge(a, b);
70//! # graph.new_edge(b, c);
71//! # graph.new_edge(c, b);
72//! # let decomp = graph.find_sccs();
73//! # let a_scc = decomp.scc_of_node(a);
74//! # let b_scc = decomp.scc_of_node(b);
75//! assert_eq!(a_scc.len(), 1);
76//! let a_scc_all: Vec<Node> = a_scc.iter_nodes().collect();
77//! assert_eq!(a_scc_all, vec![a]);
78//!
79//! assert_eq!(b_scc.len(), 2);
80//! let b_scc_all: Vec<Node> = b_scc.iter_nodes().collect();
81//! assert_eq!(b_scc_all, vec![b, c]);
82//! ```
83//! 5. List [`Scc`]s in topological order:
84//! ```
85//! # use strongly_connected_components::Node;
86//! # use strongly_connected_components::Graph;
87//! # use strongly_connected_components::Scc;
88//! # use strongly_connected_components::SccDecomposition;
89//! # let mut graph = Graph::new();
90//! # let a = graph.new_node();
91//! # let b = graph.new_node();
92//! # let c = graph.new_node();
93//! # graph.new_edge(a, b);
94//! # graph.new_edge(b, c);
95//! # graph.new_edge(c, b);
96//! # let decomp = graph.find_sccs();
97//! # let a_scc: &Scc = decomp.scc_of_node(a);
98//! # let b_scc: &Scc = decomp.scc_of_node(b);
99//! let sccs: Vec<&Scc> = decomp.iter_sccs().collect();
100//! assert_eq!(sccs, vec![b_scc, a_scc]);
101//! ```
102//! 6. List [`Node`]s in topological order (with arbitrary order within [`Scc`]s):
103//! ```
104//! # use strongly_connected_components::Node;
105//! # use strongly_connected_components::Graph;
106//! # use strongly_connected_components::Scc;
107//! # use strongly_connected_components::SccDecomposition;
108//! # let mut graph = Graph::new();
109//! # let a = graph.new_node();
110//! # let b = graph.new_node();
111//! # let c = graph.new_node();
112//! # graph.new_edge(a, b);
113//! # graph.new_edge(b, c);
114//! # graph.new_edge(c, b);
115//! # let decomp = graph.find_sccs();
116//! # let a_scc: &Scc = decomp.scc_of_node(a);
117//! # let b_scc: &Scc = decomp.scc_of_node(b);
118//! let nodes: Vec<Node> = decomp.iter_nodes().collect();
119//! // Either of those would be a valid order,
120//! // because `b` and `c` belong to the same SCC.
121//! assert!(nodes == vec![c, b, a] || nodes == vec![b, c, a]);
122//! ```
123mod internal;
124
125pub use internal::graph::Graph;
126pub use internal::node::Node;
127pub use internal::scc::Scc;
128pub use internal::scc_decomposition::SccDecomposition;
129
130#[cfg(test)]
131mod tests {
132 use rstest::*;
133 use std::collections::HashMap;
134 use std::ops::Range;
135
136 use rand::Rng;
137 use rand::SeedableRng;
138 use rand_chacha::ChaCha8Rng;
139
140 use super::*;
141
142 #[test]
143 fn empty_graph() {
144 let graph = Graph::default();
145 let decomp = graph.find_sccs();
146 assert!(decomp.is_empty());
147 assert_eq!(decomp.len(), 0);
148 }
149
150 #[test]
151 fn single_node_no_edges() {
152 let mut graph = Graph::new();
153 let node = graph.new_node();
154 let decomp = graph.find_sccs();
155 assert!(!decomp.is_empty());
156 assert_eq!(decomp.len(), 1);
157 let scc: Vec<Node> = decomp.iter_nodes().collect();
158 assert_eq!(scc, vec![node]);
159 }
160
161 #[test]
162 fn single_node_and_edges() {
163 let mut graph = Graph::new();
164 let node = graph.new_node();
165 graph.new_edge(node, node);
166 graph.new_edge(node, node);
167 graph.new_edge(node, node);
168 graph.new_edge(node, node);
169 let decomp = graph.find_sccs();
170 assert!(!decomp.is_empty());
171 assert_eq!(decomp.len(), 1);
172 let scc: Vec<Node> = decomp.iter_nodes().collect();
173 assert_eq!(scc, vec![node]);
174 }
175
176 #[test]
177 fn separate_nodes() {
178 let mut graph = Graph::new();
179 let a = graph.new_node();
180 let b = graph.new_node();
181 let c = graph.new_node();
182 graph.new_edge(a, a);
183 graph.new_edge(c, c);
184 let decomp = graph.find_sccs();
185 assert!(!decomp.is_empty());
186 assert_eq!(decomp.len(), 3);
187 let a_scc: Vec<Node> = decomp.scc_of_node(a).iter_nodes().collect();
188 let b_scc: Vec<Node> = decomp.scc_of_node(b).iter_nodes().collect();
189 let c_scc: Vec<Node> = decomp.scc_of_node(c).iter_nodes().collect();
190 assert_eq!(a_scc, vec![a]);
191 assert_eq!(b_scc, vec![b]);
192 assert_eq!(c_scc, vec![c]);
193 }
194
195 #[test]
196 fn manual_example() {
197 // Tests the following graph:
198 // ╔══════════════════════╗
199 // ║ ┌───┐ ┌───┐ ┌───┐ ║ ╔════════╗
200 // ┌────────╫─►│ 1 ├─►│ 9 ├─►│ 6 │─╫──┐ ║ ┌─┐ ║
201 // ╔═══╪═══╗ ║ └─▲─┘ └───┘ └─┬─┘ ║ │ ║ ┌┴─▼┐ ║
202 // ║ ┌─┴─┐ ║ ║ └─────────────┘ ║ └──╫─►│ 2 │ ║
203 // ║ │ 4 │ ║ ╚══════════════════════╝ ║ └▲─┬┘ ║
204 // ║ └─┬─┘ ║ ╔═════════════════════════════╗ ║ │ │ ║
205 // ╚═══╪═══╝ ║ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ║ ║ ┌┴─▼┐ ║
206 // └─────╫─►│ 0 ├─►│ 3 ├─►│ 7 ├─►│ 8 │─╫─╫─►│ 5 │ ║
207 // ║ └─▲─┘ └┬─▲┘ └───┘ └─┬─┘ ║ ║ └───┘ ║
208 // ║ └─────┘ └────────────┘ ║ ╚════════╝
209 // ╚═════════════════════════════╝
210 let mut graph = Graph::new();
211 let v0 = graph.new_node();
212 let v1 = graph.new_node();
213 let v2 = graph.new_node();
214 let v3 = graph.new_node();
215 let v4 = graph.new_node();
216 let v5 = graph.new_node();
217 let v6 = graph.new_node();
218 let v7 = graph.new_node();
219 let v8 = graph.new_node();
220 let v9 = graph.new_node();
221 graph.new_edge(v4, v1);
222 graph.new_edge(v1, v9);
223 graph.new_edge(v9, v6);
224 graph.new_edge(v6, v1);
225 graph.new_edge(v4, v0);
226 graph.new_edge(v0, v3);
227 graph.new_edge(v3, v0);
228 graph.new_edge(v3, v7);
229 graph.new_edge(v7, v8);
230 graph.new_edge(v8, v3);
231 graph.new_edge(v6, v2);
232 graph.new_edge(v8, v5);
233 graph.new_edge(v2, v2);
234 graph.new_edge(v2, v5);
235 graph.new_edge(v5, v2);
236 let decomp = graph.find_sccs();
237
238 assert_eq!(decomp.len(), 4);
239
240 // Class [4]
241 assert_eq!(decomp.scc_of_node(v4).len(), 1);
242 let scc_v4: Vec<Node> = decomp.scc_of_node(v4).iter_nodes().collect();
243 assert_eq!(scc_v4, vec![v4]);
244
245 // Class [1, 9, 6]
246 assert_eq!(decomp.scc_of_node(v1).len(), 3);
247 assert_eq!(decomp.scc_of_node(v1), decomp.scc_of_node(v9));
248 assert_eq!(decomp.scc_of_node(v1), decomp.scc_of_node(v6));
249 let scc_v9: Vec<Node> = decomp.scc_of_node(v9).iter_nodes().collect();
250 assert_eq!(scc_v9, vec![v1, v6, v9]);
251
252 // Class [0, 3, 7, 8]
253 assert_eq!(decomp.scc_of_node(v0).len(), 4);
254 assert_eq!(decomp.scc_of_node(v0), decomp.scc_of_node(v3));
255 assert_eq!(decomp.scc_of_node(v0), decomp.scc_of_node(v7));
256 assert_eq!(decomp.scc_of_node(v0), decomp.scc_of_node(v8));
257 let scc_v8: Vec<Node> = decomp.scc_of_node(v8).iter_nodes().collect();
258 assert_eq!(scc_v8, vec![v0, v7, v3, v8]);
259
260 // Class [2, 5]
261 assert_eq!(decomp.scc_of_node(v2).len(), 2);
262 assert_eq!(decomp.scc_of_node(v2), decomp.scc_of_node(v5));
263 let scc_v2: Vec<Node> = decomp.scc_of_node(v2).iter_nodes().collect();
264 assert_eq!(scc_v2, vec![v5, v2]);
265 }
266
267 struct Bruteforce {
268 n: usize,
269 graph: Graph,
270 node_to_id: HashMap<Node, usize>,
271 matrix: Vec<Vec<bool>>,
272 }
273
274 impl Bruteforce {
275 fn new(graph: Graph) -> Self {
276 let n = graph.len();
277 let node_to_id: HashMap<Node, usize> = graph
278 .iter_nodes()
279 .enumerate()
280 .map(|(id, node)| (node, id))
281 .collect();
282 let mut bruteforce = Self {
283 n,
284 graph,
285 node_to_id,
286 matrix: vec![vec![false; n]; n],
287 };
288 bruteforce.compute_matrix();
289 bruteforce
290 }
291
292 fn compute_matrix(&mut self) {
293 for (node, id) in &self.node_to_id {
294 self.matrix[*id][*id] = true;
295 for successor in self.graph.iter_successors(*node) {
296 self.matrix[*id][self.node_to_id[&successor]] = true;
297 }
298 }
299 for k in 0..self.n {
300 for i in 0..self.n {
301 for j in 0..self.n {
302 if self.matrix[i][k] && self.matrix[k][j] {
303 self.matrix[i][j] = true;
304 }
305 }
306 }
307 }
308 }
309
310 fn are_same_scc(&self, a: Node, b: Node) -> bool {
311 let a_id = self.node_to_id[&a];
312 let b_id = self.node_to_id[&b];
313 return self.matrix[a_id][b_id] && self.matrix[b_id][a_id];
314 }
315
316 fn is_a_before_b(&self, a: Node, b: Node) -> bool {
317 let a_id = self.node_to_id[&a];
318 let b_id = self.node_to_id[&b];
319 return !self.matrix[a_id][b_id] && self.matrix[b_id][a_id];
320 }
321 }
322
323 struct SccDecompositionVerifier {
324 bruteforce: Bruteforce,
325 decomposition: SccDecomposition,
326 node_to_position: HashMap<Node, usize>,
327 }
328
329 impl SccDecompositionVerifier {
330 fn new(graph: Graph) -> Self {
331 let decomposition = graph.find_sccs();
332 let node_to_position: HashMap<Node, usize> = decomposition
333 .iter_nodes()
334 .enumerate()
335 .map(|(id, node)| (node, id))
336 .collect();
337 Self {
338 bruteforce: Bruteforce::new(graph),
339 decomposition,
340 node_to_position,
341 }
342 }
343
344 fn verify(&self) {
345 for (a, _) in &self.bruteforce.node_to_id {
346 for (b, _) in &self.bruteforce.node_to_id {
347 assert_eq!(
348 self.bruteforce.are_same_scc(*a, *b),
349 self.decomposition.scc_of_node(*a) == self.decomposition.scc_of_node(*b)
350 );
351 if self.bruteforce.is_a_before_b(*a, *b) {
352 assert!(self.node_to_position[a] < self.node_to_position[b]);
353 }
354 }
355 }
356 }
357 }
358
359 struct RandomGraphGenerator {
360 rng: ChaCha8Rng,
361 }
362
363 impl RandomGraphGenerator {
364 fn new(seed: u64) -> Self {
365 Self {
366 rng: ChaCha8Rng::seed_from_u64(seed),
367 }
368 }
369
370 fn generate_graph(&mut self, n: Range<usize>, edge_probability: f64) -> Graph {
371 let mut graph = Graph::new();
372 let n: usize = self.rng.random_range(n);
373 let nodes: Vec<Node> = std::iter::repeat_n((), n)
374 .map(|_| graph.new_node())
375 .collect();
376 for i in 0..n {
377 for j in 0..n {
378 if self.rng.random_bool(edge_probability) {
379 graph.new_edge(nodes[i], nodes[j]);
380 }
381 }
382 }
383 graph
384 }
385 }
386
387 #[rstest]
388 #[case(0x1111111, 10_000, 0..10, 0.5)]
389 #[case(0x2222222, 100, 10..100, 0.05)]
390 #[case(0x3333333, 1, 0..1000, 0.01)]
391 fn test_random_graph(
392 #[case] start_seed: u64,
393 #[case] count: usize,
394 #[case] n: Range<usize>,
395 #[case] edge_probability: f64,
396 ) {
397 for i in 0..count {
398 println!("Iteration {}", i);
399 let graph = RandomGraphGenerator::new(start_seed + (i as u64))
400 .generate_graph(n.clone(), edge_probability);
401 let edges_len: usize = graph
402 .iter_nodes()
403 .map(|node| graph.iter_successors(node).count())
404 .sum();
405 println!("Graph generated with n={} edges={}", graph.len(), edges_len);
406 let verifier = SccDecompositionVerifier::new(graph);
407 verifier.verify();
408 }
409 }
410}