use crate::{
graph::{GraphPred, GraphSucc, indexgraph::IndexGraph, node_map::NodeMap},
index::vec::IndexVec,
index_type,
};
fn scc_dfs<G: GraphSucc>(
graph: G,
vis: &mut NodeMap<G, bool>,
items: &mut Vec<G::Node>,
node: G::Node,
) {
debug_assert!(!vis[node]);
vis[node] = true;
for node in graph.succ_of(node) {
if !vis[node] {
scc_dfs(graph, vis, items, node);
}
}
items.push(node);
}
fn scc_dfs_rev<G: GraphPred>(
graph: G,
vis: &mut NodeMap<G, bool>,
items: &mut Vec<G::Node>,
node: G::Node,
) {
debug_assert!(!vis[node]);
vis[node] = true;
for node in graph.pred_of(node) {
if !vis[node] {
scc_dfs_rev(graph, vis, items, node);
}
}
items.push(node);
}
index_type!(pub CondensedNode<Id>);
pub fn scc<G: GraphPred + GraphSucc>(
graph: G,
) -> (NodeMap<G, CondensedNode<G>>, IndexGraph<CondensedNode<G>>) {
let mut order = vec![];
let mut dfs_vis = NodeMap::new_with(graph, |_| false);
for node in graph.nodes() {
if !dfs_vis[node] {
scc_dfs(graph, &mut dfs_vis, &mut order, node);
}
}
order.reverse();
dfs_vis.clear(graph);
let mut condensed_lut = NodeMap::new_with(graph, |_| CondensedNode::ZERO);
let mut components = vec![];
let mut index_graph = IndexVec::new();
for &node in &order {
if dfs_vis[node] {
continue;
}
scc_dfs_rev(graph, &mut dfs_vis, &mut components, node);
let con_node = index_graph.push(vec![]);
for c in components.drain(..) {
condensed_lut[c] = con_node;
}
}
for &node in &order {
let src = condensed_lut[node];
for succ in graph.succ_of(node) {
let dst = condensed_lut[succ];
if src != dst {
index_graph[src].push(dst);
}
}
}
for (_, set) in &mut index_graph {
set.sort_unstable();
set.dedup();
}
(condensed_lut, index_graph.into())
}