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}