use std::collections::{HashMap, HashSet};
use super::{Components, Scc};
struct Data {
index: u32,
lowlink: u32,
on_stack: bool,
component: usize,
}
pub fn scc<G: ?Sized + Scc>(graph: &G) -> Components<G::Vertex> {
let mut map: HashMap<G::Vertex, Data> = HashMap::new();
let mut stack = Vec::new();
let mut components = Vec::new();
for v in graph.vertices() {
if !map.contains_key(&v) {
strong_connect(graph, 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| {
graph
.successors(*v)
.into_iter()
.map(|sc| *vertex_to_component.get(&sc).unwrap())
})
.collect()
})
.collect();
Components {
vertex_to_component,
list: components,
successors,
}
}
fn strong_connect<G: ?Sized + Scc>(
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
}