2022-04-08 07:27:04 +02:00
|
|
|
// ----------------------------------------------------------------
|
|
|
|
// IMPORTS
|
|
|
|
// ----------------------------------------------------------------
|
|
|
|
|
|
|
|
use std::fmt::Display;
|
|
|
|
use std::hash::Hash;
|
|
|
|
use std::collections::HashMap;
|
|
|
|
|
|
|
|
use crate::core::utils;
|
2022-04-14 05:01:30 +02:00
|
|
|
use crate::core::log::log_debug;
|
2022-04-08 07:27:04 +02:00
|
|
|
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.
|
2022-04-14 05:01:30 +02:00
|
|
|
pub fn tarjan_algorithm<T>(gph: &Graph<T>, debug: bool) -> Vec<Vec<T>>
|
|
|
|
where T: Eq + Hash + Clone + Copy + Display
|
2022-04-08 07:27:04 +02:00
|
|
|
{
|
2022-04-14 05:01:30 +02:00
|
|
|
let mut ctx = Context::new(&gph, debug);
|
2022-04-08 07:27:04 +02:00
|
|
|
|
|
|
|
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<T>(gph: &Graph<T>, v: &T, ctx: &mut Context<T>)
|
2022-04-14 05:01:30 +02:00
|
|
|
where T: Eq + Hash + Clone + Copy + Display
|
2022-04-08 07:27:04 +02:00
|
|
|
{
|
|
|
|
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);
|
2022-04-14 05:16:53 +02:00
|
|
|
ctx.log_info(&v);
|
2022-04-08 07:27:04 +02:00
|
|
|
|
|
|
|
if ctx.get_index(v) == ctx.get_root(v) {
|
|
|
|
let mut component: Vec<T> = Vec::new();
|
|
|
|
loop {
|
|
|
|
let u = ctx.top();
|
|
|
|
ctx.pop();
|
|
|
|
component.push(u.clone());
|
2022-04-14 05:01:30 +02:00
|
|
|
if u == *v { break; }
|
2022-04-08 07:27:04 +02:00
|
|
|
}
|
|
|
|
ctx.components.push(component);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
// AUXILIARY context variables for algorithm
|
|
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
#[derive(Clone, Copy)]
|
2022-04-14 05:01:30 +02:00
|
|
|
struct NodeInformation<T> {
|
|
|
|
node: T,
|
2022-04-08 07:27:04 +02:00
|
|
|
root: usize,
|
|
|
|
index: usize,
|
|
|
|
state: State,
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Context<T> {
|
|
|
|
stack: Stack<T>,
|
|
|
|
max_index: usize,
|
2022-04-14 05:01:30 +02:00
|
|
|
infos: HashMap<T, NodeInformation<T>>,
|
2022-04-08 07:27:04 +02:00
|
|
|
components: Vec<Vec<T>>,
|
2022-04-14 05:01:30 +02:00
|
|
|
debug: bool,
|
2022-04-08 07:27:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> Context<T>
|
2022-04-14 05:01:30 +02:00
|
|
|
where T: Eq + Hash + Clone + Copy + Display
|
2022-04-08 07:27:04 +02:00
|
|
|
{
|
2022-04-14 05:01:30 +02:00
|
|
|
fn new(gph: &Graph<T>, debug: bool) -> Context<T> {
|
|
|
|
let mut infos = HashMap::<T, NodeInformation<T>>::new();
|
2022-04-08 07:27:04 +02:00
|
|
|
for u in gph.nodes.iter() {
|
2022-04-14 05:01:30 +02:00
|
|
|
infos.entry(u.clone()).or_insert(NodeInformation::<T>::new(&u));
|
2022-04-08 07:27:04 +02:00
|
|
|
}
|
|
|
|
return Context {
|
|
|
|
stack: Stack::new(),
|
|
|
|
max_index: 0,
|
|
|
|
infos: infos,
|
|
|
|
components: vec![],
|
2022-04-14 05:01:30 +02:00
|
|
|
debug: debug,
|
2022-04-08 07:27:04 +02:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2022-04-14 05:01:30 +02:00
|
|
|
fn update_infos(self: &mut Self, u: &T, info: NodeInformation<T>) {
|
2022-04-08 07:27:04 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2022-04-14 05:16:53 +02:00
|
|
|
fn get_info(self: &Self, u: &T) -> NodeInformation<T> {
|
2022-04-14 05:01:30 +02:00
|
|
|
return *self.infos.get(u).unwrap();
|
|
|
|
}
|
|
|
|
|
2022-04-14 05:16:53 +02:00
|
|
|
fn get_state(self: &Self, u: &T) -> State {
|
2022-04-14 05:01:30 +02:00
|
|
|
return self.get_info(u).state;
|
2022-04-08 07:27:04 +02:00
|
|
|
}
|
|
|
|
|
2022-04-14 05:16:53 +02:00
|
|
|
fn get_root(self: &Self, u: &T) -> usize {
|
2022-04-14 05:01:30 +02:00
|
|
|
return self.get_info(u).root;
|
2022-04-08 07:27:04 +02:00
|
|
|
}
|
|
|
|
|
2022-04-14 05:16:53 +02:00
|
|
|
fn get_index(self: &Self, u: &T) -> usize {
|
2022-04-14 05:01:30 +02:00
|
|
|
return self.get_info(u).index;
|
2022-04-08 07:27:04 +02:00
|
|
|
}
|
2022-04-14 05:16:53 +02:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
2022-04-08 07:27:04 +02:00
|
|
|
}
|
|
|
|
|
2022-04-14 05:01:30 +02:00
|
|
|
impl<T> NodeInformation<T>
|
|
|
|
where T: Clone + Copy
|
|
|
|
{
|
|
|
|
fn new(node: &T) -> NodeInformation<T> {
|
2022-04-08 07:27:04 +02:00
|
|
|
return NodeInformation {
|
2022-04-14 05:01:30 +02:00
|
|
|
node: node.clone(),
|
2022-04-08 07:27:04 +02:00
|
|
|
root: 0,
|
|
|
|
index: 0,
|
|
|
|
state: State::UNTOUCHED,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|