// ---------------------------------------------------------------- // IMPORTS // ---------------------------------------------------------------- use std::fmt::Display; use std::hash::Hash; use std::collections::HashMap; use crate::value_min; use crate::core::log::log_debug; use crate::stacks::stack::Stack; use crate::graphs::graph::Graph; // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CONSTANTS // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #[derive(Clone, Copy, PartialEq)] enum State { UNTOUCHED, PENDING, FINISHED, } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // METHOD Tarjan Algorithm // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /// # Tarjan Algorithm # /// Runs the Tarjan-Algorithm to compute the strongly connected components. pub fn tarjan_algorithm(gph: &Graph, debug: bool) -> Vec> where T: Eq + Hash + Clone + Copy + Display { let mut ctx = Context::new(&gph, debug); for u in gph.nodes.iter() { tarjan_visit(gph, u, &mut ctx); } return ctx.components; } /// recursive depth-first search algorithm to compute components fn tarjan_visit(gph: &Graph, v: &T, ctx: &mut Context) where T: Eq + Hash + Clone + Copy + Display { // do nothing, if v already visited if !(ctx.get_state(v) == State::UNTOUCHED) { return; } /**************** * First visit of v. * - Place v on stack. * - Initialise visit-index + component-index. * - After each rekursiv call, only those all ****************/ ctx.max_index += 1; ctx.push(v); ctx.set_root(v, ctx.max_index); ctx.set_index(v, ctx.max_index); ctx.set_state(v, State::PENDING); // depth first search: for u in gph.successors(&v) { tarjan_visit(gph, &u, ctx); /**** * u is in the same component as v, if and only if u is still on the stack. * In this case, update the associated component-index of v: ****/ if ctx.stack.contains(&u) { ctx.set_root(v, value_min!(ctx.get_root(v), ctx.get_root(&u))); } } ctx.set_state(v, State::FINISHED); ctx.log_info(&v); if ctx.get_index(v) == ctx.get_root(v) { let mut component: Vec = Vec::new(); loop { let u = ctx.top(); ctx.pop(); component.push(u.clone()); if u == *v { break; } } ctx.components.push(component); } } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // AUXILIARY context variables for algorithm // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #[derive(Clone, Copy)] struct NodeInformation { node: T, root: usize, index: usize, state: State, } struct Context { stack: Stack, max_index: usize, infos: HashMap>, components: Vec>, debug: bool, } impl Context where T: Eq + Hash + Clone + Copy + Display { fn new(gph: &Graph, debug: bool) -> Context { let mut infos = HashMap::>::new(); for u in gph.nodes.iter() { infos.entry(u.clone()).or_insert(NodeInformation::::new(&u)); } return Context { stack: Stack::new(), max_index: 0, infos: infos, components: vec![], debug: debug, }; } fn push(self: &mut Self, u: &T) { self.stack.push(u.clone()); } fn top(self: &mut Self) -> T { return self.stack.top(); } fn pop(self: &mut Self) -> T { return self.stack.pop(); } fn update_infos(self: &mut Self, u: &T, info: NodeInformation) { self.infos.insert(u.clone(), info); } fn set_state(self: &mut Self, u: &T, state: State) { let mut info = *self.infos.get(u).unwrap(); info.state = state; self.update_infos(u, info); } fn set_root(self: &mut Self, u: &T, root: usize) { let mut info = *self.infos.get(u).unwrap(); info.root = root; self.update_infos(u, info); } fn set_index(self: &mut Self, u: &T, index: usize) { let mut info = *self.infos.get(u).unwrap(); info.index = index; self.update_infos(u, info); } fn get_info(self: &Self, u: &T) -> NodeInformation { return *self.infos.get(u).unwrap(); } fn get_state(self: &Self, u: &T) -> State { return self.get_info(u).state; } fn get_root(self: &Self, u: &T) -> usize { return self.get_info(u).root; } fn get_index(self: &Self, u: &T) -> usize { return self.get_info(u).index; } fn log_info(self: &Self, u: &T) { let info = self.get_info(&u); if !self.debug { return; } log_debug!("node, index, component: ({}, {}, {})", info.node, info.index, info.root); } } impl NodeInformation where T: Clone + Copy { fn new(node: &T) -> NodeInformation { return NodeInformation { node: node.clone(), root: 0, index: 0, state: State::UNTOUCHED, }; } }