use crate::graph::Graph;
#[derive(Clone, Copy)]
enum DfsState {
Visit(usize), ProcessNeighbors(usize), Finalize(usize), }
pub struct PathBasedScc {
scc: Vec<usize>,
stack: Vec<usize>, bounds: Vec<usize>, component: usize,
}
impl Default for PathBasedScc {
fn default() -> Self {
Self::new()
}
}
impl PathBasedScc {
pub fn new() -> Self {
Self {
bounds: Vec::new(),
scc: Vec::new(),
stack: Vec::new(),
component: 0,
}
}
pub fn run<T>(&mut self, graph: &(impl Graph<T> + 'static)) -> Vec<usize> {
self.bounds = Vec::new();
self.scc.resize(graph.number_of_nodes(), usize::MAX);
self.stack = Vec::new();
self.component = graph.number_of_nodes();
for v in graph.node_range() {
if self.scc[v] == usize::MAX {
self.dfs_iterative(v, graph);
}
}
self.scc.clone()
}
fn dfs_iterative<T>(&mut self, start: usize, graph: &(impl Graph<T> + 'static)) {
let mut dfs_stack = vec![DfsState::Visit(start)];
let mut edge_indices = vec![0usize; graph.number_of_nodes()];
while let Some(state) = dfs_stack.pop() {
match state {
DfsState::Visit(v) => {
self.stack.push(v);
self.scc[v] = self.stack.len() - 1;
self.bounds.push(self.scc[v]);
dfs_stack.push(DfsState::ProcessNeighbors(v));
}
DfsState::ProcessNeighbors(v) => {
let edges: Vec<_> = graph.edge_range(v).collect();
if edge_indices[v] < edges.len() {
let e = edges[edge_indices[v]];
edge_indices[v] += 1;
dfs_stack.push(DfsState::ProcessNeighbors(v));
let w = graph.target(e);
if self.scc[w] == usize::MAX {
dfs_stack.push(DfsState::Visit(w));
} else {
while let Some(&bound) = self.bounds.last() {
if self.scc[w] < bound {
self.bounds.pop();
} else {
break;
}
}
}
} else {
dfs_stack.push(DfsState::Finalize(v));
}
}
DfsState::Finalize(v) => {
if Some(&self.scc[v]) == self.bounds.last() {
self.bounds.pop();
self.component -= 1;
while let Some(u) = self.stack.pop() {
self.scc[u] = self.component;
if u == v {
break;
}
}
}
}
}
}
}
}
#[cfg(test)]
mod tests {
use crate::edge::InputEdge;
use crate::path_based_scc::PathBasedScc;
use crate::static_graph::StaticGraph;
#[test]
fn scc_wiki1() {
type Graph = StaticGraph<i32>;
let edges = vec![
InputEdge::new(0, 1, 3),
InputEdge::new(1, 2, 3),
InputEdge::new(1, 4, 1),
InputEdge::new(1, 5, 6),
InputEdge::new(2, 3, 2),
InputEdge::new(2, 6, 2),
InputEdge::new(3, 2, 2),
InputEdge::new(3, 7, 2),
InputEdge::new(4, 0, 2),
InputEdge::new(4, 5, 2),
InputEdge::new(5, 6, 2),
InputEdge::new(6, 5, 2),
InputEdge::new(7, 3, 2),
InputEdge::new(7, 6, 2),
];
let graph = Graph::new(edges);
let mut scc = PathBasedScc::new();
assert_eq!(vec![5, 5, 6, 6, 5, 7, 7, 6], scc.run(&graph));
}
#[test]
fn geekforgeeks() {
type Graph = StaticGraph<i32>;
let edges = vec![
InputEdge::new(1, 0, 3),
InputEdge::new(0, 3, 3),
InputEdge::new(0, 2, 1),
InputEdge::new(2, 1, 6),
InputEdge::new(3, 4, 2),
];
let graph = Graph::new(edges);
let mut scc = PathBasedScc::new();
assert_eq!(vec![2, 2, 2, 3, 4], scc.run(&graph));
}
#[test]
fn stanford2() {
type Graph = StaticGraph<i32>;
let edges = vec![
InputEdge::new(0, 6, 3),
InputEdge::new(6, 3, 3),
InputEdge::new(3, 0, 1),
InputEdge::new(6, 8, 6),
InputEdge::new(8, 5, 2),
InputEdge::new(5, 2, 2),
InputEdge::new(2, 8, 2),
InputEdge::new(5, 7, 2),
InputEdge::new(7, 1, 2),
InputEdge::new(4, 7, 2),
InputEdge::new(1, 4, 2),
];
let graph = Graph::new(edges);
let mut scc = PathBasedScc::new();
assert_eq!(vec![6, 8, 7, 6, 8, 7, 6, 8, 7], scc.run(&graph));
}
#[test]
fn web1() {
type Graph = StaticGraph<i32>;
let edges = vec![
InputEdge::new(0, 1, 3),
InputEdge::new(1, 3, 3),
InputEdge::new(1, 4, 1),
InputEdge::new(1, 2, 6),
InputEdge::new(2, 5, 2),
InputEdge::new(4, 1, 2),
InputEdge::new(4, 5, 2),
InputEdge::new(4, 6, 2),
InputEdge::new(5, 7, 2),
InputEdge::new(6, 7, 2),
InputEdge::new(6, 8, 2),
InputEdge::new(7, 9, 2),
InputEdge::new(9, 10, 2),
InputEdge::new(10, 8, 2),
InputEdge::new(8, 11, 2),
InputEdge::new(11, 6, 2),
];
let graph = Graph::new(edges);
let mut scc = PathBasedScc::default();
assert_eq!(
vec![6, 7, 9, 8, 7, 10, 11, 11, 11, 11, 11, 11],
scc.run(&graph)
);
}
}