scc_trait/
lib.rs

1//! This crate provides the [`Scc`] trait that you can implement on any directed
2//! graph datatype to compute the Strongly Connected Components (SCC) in linear
3//! time, based on [Tarjan's SCC algorithm][1].
4//!
5//! [1]: <https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm>
6//!
7//! # Usage
8//!
9//! First, implement the `Scc` trait on your custom graph type, providing
10//! enough information about the graph structure:
11//! ```
12//! # type Vertex = usize;
13//! struct MyGraphType {
14//!   vertices: Vec<Vertex>,
15//!   edges: HashMap<Vertex, HashSet<Vertex>>
16//! }
17//!
18//! impl Scc for MyGraphType {
19//!   type Vertex = Vertex;
20//!
21//!   fn vertices(&self) -> impl '_ + IntoIterator<Item = Self::Vertex> {
22//!     self.vertices.iter().copied()
23//!   }
24//!
25//!   fn successors(&self, v: Self::Vertex) -> impl '_ + IntoIterator<Item = Self::Vertex> {
26//!     self.edges[&v].iter().copied()
27//!   }
28//! }
29//! ```
30//!
31//! This trait is also implemented for a few default types like
32//! `Vec<HashSet<usize>>` and `HashMap<T, HashSet<T>>`. It provides the
33//! [`strongly_connected_components`](Scc::strongly_connected_components) method
34//! returning the strongly connected [`Components`] of the graph. This type
35//! allows you to iterate through the components, get successors of a component,
36//! order the components by depth, etc.
37//!
38//! ```
39//! # let graph: Vec<HashSet<usize>> = Vec::new();
40//! use scc_trait::Scc;
41//!
42//! // Compute the strongly connected components.
43//! let components = graph.strongly_connected_components();
44//!
45//! // Print vertices grouped by component.
46//! for component in components {
47//!   for vertex in component {
48//!     println!("{vertex}");
49//!   }
50//! }
51//!
52//! // Order components by depth.
53//! for i in components.order_by_depth() {
54//!   let component = components.get_by_index(i).unwrap();
55//!   // ...
56//! }
57//! ```
58use std::{
59	collections::{HashMap, HashSet},
60	hash::Hash,
61};
62
63mod tarjan;
64
65/// Graph on which strongly connected components can be computed.
66pub trait Scc {
67	/// Graph vertex reference type.
68	type Vertex: Copy + Eq + Hash;
69
70	/// Returns an iterator over the vertices of the graph.
71	fn vertices(&self) -> impl '_ + IntoIterator<Item = Self::Vertex>;
72
73	/// Returns an iterator over the successors of the given vertex.
74	fn successors(&self, v: Self::Vertex) -> impl '_ + IntoIterator<Item = Self::Vertex>;
75
76	/// Computes the strongly connected components of the graph.
77	fn strongly_connected_components(&self) -> Components<Self::Vertex> {
78		tarjan::scc(self)
79	}
80}
81
82/// Strongly connected components.
83pub struct Components<V> {
84	/// Components list.
85	list: Vec<Vec<V>>,
86
87	/// Map from vertices to component index.
88	vertex_to_component: HashMap<V, usize>,
89
90	/// Component successors.
91	successors: Vec<HashSet<usize>>,
92}
93
94impl<V> Components<V> {
95	/// Returns the number of strongly connected components.
96	pub fn len(&self) -> usize {
97		self.list.len()
98	}
99
100	/// Checks if there are no components.
101	pub fn is_empty(&self) -> bool {
102		self.list.is_empty()
103	}
104
105	/// Returns an iterator over the strongly connected components.
106	pub fn iter(&self) -> Iter<V> {
107		Iter(self.list.iter())
108	}
109
110	/// Returns the index of the given vertex's strongly connected component.
111	pub fn vertex_component_index(&self, v: &V) -> Option<usize>
112	where
113		V: Eq + Hash,
114	{
115		self.vertex_to_component.get(v).cloned()
116	}
117
118	/// Returns the component with the given index `i`.
119	pub fn get_by_index(&self, i: usize) -> Option<&[V]> {
120		self.list.get(i).map(Vec::as_slice)
121	}
122
123	/// Return the given vertex's strongly connected component.
124	pub fn get(&self, v: &V) -> Option<&[V]>
125	where
126		V: Eq + Hash,
127	{
128		self.get_by_index(self.vertex_component_index(v)?)
129	}
130
131	pub fn successors(&self, i: usize) -> Option<impl '_ + Iterator<Item = usize>> {
132		self.successors.get(i).map(|s| s.iter().cloned())
133	}
134
135	pub fn is_cyclic(&self, i: usize) -> bool {
136		self.successors.get(i).unwrap().contains(&i)
137	}
138
139	fn remove_indirect_successors(&self, result: &mut HashSet<usize>, i: usize) {
140		for j in self.successors(i).unwrap() {
141			result.remove(&j);
142			self.remove_indirect_successors(result, j);
143		}
144	}
145
146	pub fn direct_successors(&self, i: usize) -> Option<HashSet<usize>> {
147		let mut result: HashSet<_> = self.successors(i)?.collect();
148
149		for j in self.successors(i).unwrap() {
150			self.remove_indirect_successors(&mut result, j);
151		}
152
153		Some(result)
154	}
155
156	/// Returns the depth of each component.
157	///
158	/// The depth of a component is the maximum of the depth of its predecessors
159	/// plus 1. A component with no predecessors has depth 0.
160	pub fn depths(&self) -> Vec<usize> {
161		let mut depth = vec![0; self.list.len()];
162		let mut stack: Vec<_> = depth.iter().cloned().enumerate().collect();
163
164		while let Some((i, new_depth)) = stack.pop() {
165			if depth[i] == 0 || new_depth > depth[i] {
166				depth[i] = new_depth;
167				for c in self.successors(i).unwrap() {
168					if c != i {
169						stack.push((c, new_depth + 1))
170					}
171				}
172			}
173		}
174
175		depth
176	}
177
178	pub fn predecessors(&self) -> Vec<HashSet<usize>> {
179		let mut predecessors = Vec::new();
180		predecessors.resize_with(self.list.len(), HashSet::default);
181
182		for (i, successors) in self.successors.iter().enumerate() {
183			for &j in successors {
184				predecessors[j].insert(i);
185			}
186		}
187
188		predecessors
189	}
190
191	/// Order components by depth.
192	///
193	/// The depth of a component is the maximum of the depth of its predecessors
194	/// plus 1. A component with no predecessors has depth 0.
195	pub fn order_by_depth(&self) -> Vec<usize> {
196		let depth = self.depths();
197		let mut ordered_components: Vec<_> = (0..self.list.len()).collect();
198		ordered_components.sort_unstable_by_key(|i| depth[*i]);
199		ordered_components
200	}
201}
202
203pub struct Iter<'a, V>(std::slice::Iter<'a, Vec<V>>);
204
205impl<'a, V> Iterator for Iter<'a, V> {
206	type Item = &'a [V];
207
208	fn next(&mut self) -> Option<Self::Item> {
209		self.0.next().map(Vec::as_slice)
210	}
211}
212
213impl<'a, V> DoubleEndedIterator for Iter<'a, V> {
214	fn next_back(&mut self) -> Option<Self::Item> {
215		self.0.next_back().map(Vec::as_slice)
216	}
217}
218
219impl<'a, V> IntoIterator for &'a Components<V> {
220	type Item = &'a [V];
221	type IntoIter = Iter<'a, V>;
222
223	fn into_iter(self) -> Self::IntoIter {
224		self.iter()
225	}
226}
227
228/// Returns the depth of each component.
229///
230/// The depth of a component is the maximum of the depth of its predecessors
231/// plus 1. A component with no predecessors has depth 0.
232pub fn depths(predecessors: &[HashSet<usize>]) -> Vec<usize> {
233	let mut depth = vec![0; predecessors.len()];
234	let mut stack: Vec<_> = depth.iter().cloned().enumerate().collect();
235
236	while let Some((i, new_depth)) = stack.pop() {
237		if depth[i] == 0 || new_depth > depth[i] {
238			depth[i] = new_depth;
239			for &c in &predecessors[i] {
240				if c != i {
241					stack.push((c, new_depth + 1))
242				}
243			}
244		}
245	}
246
247	depth
248}
249
250impl Scc for Vec<HashSet<usize>> {
251	type Vertex = usize;
252
253	fn vertices(&self) -> impl '_ + IntoIterator<Item = Self::Vertex> {
254		0..self.len()
255	}
256
257	fn successors(&self, v: Self::Vertex) -> impl '_ + IntoIterator<Item = Self::Vertex> {
258		self[v].iter().copied()
259	}
260}
261
262impl<T: Copy + Eq + Hash> Scc for HashMap<T, HashSet<T>> {
263	type Vertex = T;
264
265	fn vertices(&self) -> impl '_ + IntoIterator<Item = Self::Vertex> {
266		self.keys().copied()
267	}
268
269	fn successors(&self, v: Self::Vertex) -> impl '_ + IntoIterator<Item = Self::Vertex> {
270		self[&v].iter().copied()
271	}
272}