use std::{
collections::{HashMap, HashSet},
hash::Hash,
};
struct Data {
index: u32,
lowlink: u32,
on_stack: bool,
component: usize,
}
pub trait SccGraph {
type Vertex: Copy + Eq + Hash;
type Vertices<'a>: 'a + IntoIterator<Item = Self::Vertex>
where
Self: 'a;
type Successors<'a>: 'a + IntoIterator<Item = Self::Vertex>
where
Self: 'a;
fn vertices(&self) -> Self::Vertices<'_>;
fn successors(&self, v: Self::Vertex) -> Self::Successors<'_>;
fn strongly_connected_components(&self) -> Components<Self::Vertex> {
let mut map: HashMap<Self::Vertex, Data> = HashMap::new();
let mut stack = Vec::new();
let mut components = Vec::new();
for v in self.vertices() {
if !map.contains_key(&v) {
strong_connect(self, v, &mut stack, &mut map, &mut components);
}
}
let vertex_to_component: HashMap<_, _> = map
.into_iter()
.map(|(v, data)| (v, data.component))
.collect();
let successors: Vec<HashSet<_>> = components
.iter()
.map(|component| {
component
.iter()
.flat_map(|v| {
self.successors(*v)
.into_iter()
.map(|sc| *vertex_to_component.get(&sc).unwrap())
})
.collect()
})
.collect();
Components {
vertex_to_component,
components,
successors,
}
}
}
pub struct Components<V> {
vertex_to_component: HashMap<V, usize>,
components: Vec<Vec<V>>,
successors: Vec<HashSet<usize>>,
}
impl<V> Components<V> {
pub fn len(&self) -> usize {
self.components.len()
}
pub fn vertex_component(&self, v: &V) -> Option<usize>
where
V: Eq + Hash,
{
self.vertex_to_component.get(v).cloned()
}
pub fn get(&self, i: usize) -> Option<&[V]> {
self.components.get(i).map(Vec::as_slice)
}
pub fn successors(&self, i: usize) -> Option<impl '_ + Iterator<Item = usize>> {
self.successors.get(i).map(|s| s.iter().cloned())
}
}
fn strong_connect<G: ?Sized + SccGraph>(
graph: &G,
v: G::Vertex,
stack: &mut Vec<G::Vertex>,
map: &mut HashMap<G::Vertex, Data>,
components: &mut Vec<Vec<G::Vertex>>,
) -> u32 {
let index = map.len() as u32;
stack.push(v);
map.insert(
v,
Data {
index,
lowlink: index,
on_stack: true,
component: 0,
},
);
for w in graph.successors(v) {
let new_v_lowlink = match map.get(&w) {
None => {
let w_lowlink = strong_connect(graph, w, stack, map, components);
Some(std::cmp::min(map[&v].lowlink, w_lowlink))
}
Some(w_data) => {
if w_data.on_stack {
Some(std::cmp::min(map[&v].lowlink, w_data.index))
} else {
None
}
}
};
if let Some(new_v_lowlink) = new_v_lowlink {
map.get_mut(&v).unwrap().lowlink = new_v_lowlink;
}
}
let lowlink = map[&v].lowlink;
if lowlink == map[&v].index {
let mut component = Vec::new();
loop {
let w = stack.pop().unwrap();
let w_data = map.get_mut(&w).unwrap();
w_data.on_stack = false;
w_data.component = components.len();
component.push(w);
if w == v {
break;
}
}
components.push(component)
}
lowlink
}