From 0dcc97cd6d866d8643ac062181835f0560e1cc98 Mon Sep 17 00:00:00 2001 From: raj_mathe Date: Fri, 8 Apr 2022 07:27:04 +0200 Subject: [PATCH] master > master: code-rust - tarjan alg --- code/rust/src/graphs/tarjan.rs | 176 +++++++++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 code/rust/src/graphs/tarjan.rs diff --git a/code/rust/src/graphs/tarjan.rs b/code/rust/src/graphs/tarjan.rs new file mode 100644 index 0000000..8ee853a --- /dev/null +++ b/code/rust/src/graphs/tarjan.rs @@ -0,0 +1,176 @@ +// ---------------------------------------------------------------- +// IMPORTS +// ---------------------------------------------------------------- + +use std::fmt::Display; +use std::hash::Hash; +use std::collections::HashMap; + +use crate::core::utils; +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) -> Vec> + where T: Eq + Hash + Clone + Display +{ + let mut ctx = Context::new(&gph); + + 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 + Display +{ + if !(ctx.get_state(v) == State::UNTOUCHED) { + return; + } + + 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); + // remains relevant for v, provided u still in Stack: + if ctx.stack.elements.contains(&u) { + let root = utils::min( + ctx.get_root(&u), + ctx.get_root(v) + ); + ctx.set_root(v, root); + } + } + ctx.set_state(v, State::FINISHED); + + 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 { + root: usize, + index: usize, + state: State, +} + +struct Context { + stack: Stack, + max_index: usize, + infos: HashMap, + components: Vec>, +} + +impl Context + where T: Eq + Hash + Clone + Display +{ + fn new(gph: &Graph) -> Context { + let mut infos = HashMap::::new(); + for u in gph.nodes.iter() { + infos.entry(u.clone()).or_insert(NodeInformation::new()); + } + return Context { + stack: Stack::new(), + max_index: 0, + infos: infos, + components: vec![], + }; + } + + 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_state(self: &mut Self, u: &T) -> State { + let info = *self.infos.get(u).unwrap(); + return info.state; + } + + fn get_root(self: &mut Self, u: &T) -> usize { + let info = *self.infos.get(u).unwrap(); + return info.root; + } + + fn get_index(self: &mut Self, u: &T) -> usize { + let info = *self.infos.get(u).unwrap(); + return info.index; + } +} + +impl NodeInformation { + fn new() -> NodeInformation { + return NodeInformation { + root: 0, + index: 0, + state: State::UNTOUCHED, + }; + } +}