// ---------------------------------------------------------------- // 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() { if ctx.get_state(&u) == State::UNTOUCHED { tarjan_visit(gph, &u, &mut ctx); } } return ctx.components; } /// Recursive depth-first search algorithm to compute strongly components of a graph. fn tarjan_visit(gph: &Graph, &u: &T, ctx: &mut Context) where T: Eq + Hash + Clone + Copy + Display { // Place node on stack + initialise visit-index + component-index. ctx.max_index += 1; ctx.stack_push(&u); ctx.set_root(&u, ctx.max_index); ctx.set_index(&u, ctx.max_index); ctx.set_state(&u, State::PENDING); /**************** * Compute strongly connected components of each child node. * NOTE: Child nodes remain on stack, if and only if parent is in same component. ****************/ for v in gph.successors(&u) { // Visit child node only if untouched: if ctx.get_state(&v) == State::UNTOUCHED { tarjan_visit(gph, &v, ctx); } // Update associated component-index of parent node, if in same component as child: if ctx.stack_contains(&v) { ctx.set_root(&u, value_min!(ctx.get_root(&u), ctx.get_root(&v))); } } ctx.set_state(&u, State::FINISHED); ctx.log_info(&u); // If at root of component pop everything from stack up to root and add component: if ctx.get_index(&u) == ctx.get_root(&u) { let mut component: Vec = Vec::new(); loop { let v = ctx.stack_top(); ctx.stack_pop(); component.push(v.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 stack_push(self: &mut Self, u: &T) { self.stack.push(u.clone()); } fn stack_top(self: &mut Self) -> T { return self.stack.top(); } fn stack_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 stack_contains(self: &Self, u: &T) -> bool { return self.stack.contains(u); } 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) { if !self.debug { return; } let info = self.get_info(&u); 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, }; } }