use super::Sccs;
use dsi_progress_logger::ProgressLog;
use std::ops::ControlFlow::{Break, Continue};
use sux::bits::BitVec;
use sux::traits::BitVecOpsMut;
use webgraph::traits::RandomAccessGraph;
use webgraph::visits::{Sequential, StoppedWhenDone, depth_first::*};
pub fn tarjan(graph: impl RandomAccessGraph, pl: &mut impl ProgressLog) -> Sccs {
let num_nodes = graph.num_nodes();
pl.item_name("node");
pl.expected_updates(Some(num_nodes));
pl.start("Computing strongly connected components...");
let mut visit = SeqPred::new(&graph);
let mut lead = BitVec::with_capacity(128);
lead.push(true);
let mut component_stack = Vec::with_capacity(16);
let mut high_link = vec![0; num_nodes].into_boxed_slice();
let mut index = num_nodes;
let mut root_low_link = 0;
let mut number_of_components = 0;
if visit
.visit(0..num_nodes, |event| {
match event {
EventPred::Init { .. } => {
root_low_link = index;
}
EventPred::Previsit { node: curr, .. } => {
pl.light_update();
high_link[curr] = index; index -= 1;
lead.push(true);
}
EventPred::Revisit { node, pred, .. } => {
if high_link[pred] < high_link[node] {
lead.set(lead.len() - 1, false);
high_link[pred] = high_link[node];
if high_link[pred] == root_low_link && index == 0 {
high_link[pred] = number_of_components;
for &node in component_stack.iter() {
high_link[node] = number_of_components;
}
return Break(StoppedWhenDone {});
}
}
}
EventPred::Postvisit {
node, parent: pred, ..
} => {
if lead.pop().unwrap() {
while let Some(comp_node) = component_stack.pop() {
if high_link[node] < high_link[comp_node] {
component_stack.push(comp_node);
break;
}
index += 1;
high_link[comp_node] = number_of_components;
}
high_link[node] = number_of_components;
index += 1;
number_of_components += 1;
} else {
component_stack.push(node);
if high_link[pred] < high_link[node] {
lead.set(lead.len() - 1, false);
high_link[pred] = high_link[node];
}
}
}
_ => {}
}
Continue(())
})
.is_break()
{
for node in visit.stack() {
high_link[node] = number_of_components;
}
number_of_components += 1;
}
pl.done();
Sccs::new(number_of_components, high_link)
}