master > master: code-rust - debugging im Alg

This commit is contained in:
RD 2022-04-14 05:01:30 +02:00
parent d0099eb7f9
commit c17ba0fefb
2 changed files with 34 additions and 24 deletions

View File

@ -7,6 +7,7 @@ use std::hash::Hash;
use std::collections::HashMap; use std::collections::HashMap;
use crate::core::utils; use crate::core::utils;
use crate::core::log::log_debug;
use crate::stacks::stack::Stack; use crate::stacks::stack::Stack;
use crate::graphs::graph::Graph; use crate::graphs::graph::Graph;
@ -28,10 +29,10 @@ enum State {
/// # Tarjan Algorithm # /// # Tarjan Algorithm #
/// Runs the Tarjan-Algorithm to compute the strongly connected components. /// Runs the Tarjan-Algorithm to compute the strongly connected components.
pub fn tarjan_algorithm<T>(gph: &Graph<T>) -> Vec<Vec<T>> pub fn tarjan_algorithm<T>(gph: &Graph<T>, debug: bool) -> Vec<Vec<T>>
where T: Eq + Hash + Clone + Display where T: Eq + Hash + Clone + Copy + Display
{ {
let mut ctx = Context::new(&gph); let mut ctx = Context::new(&gph, debug);
for u in gph.nodes.iter() { for u in gph.nodes.iter() {
tarjan_visit(gph, u, &mut ctx); tarjan_visit(gph, u, &mut ctx);
@ -41,7 +42,7 @@ pub fn tarjan_algorithm<T>(gph: &Graph<T>) -> Vec<Vec<T>>
/// recursive depth-first search algorithm to compute components /// recursive depth-first search algorithm to compute components
fn tarjan_visit<T>(gph: &Graph<T>, v: &T, ctx: &mut Context<T>) fn tarjan_visit<T>(gph: &Graph<T>, v: &T, ctx: &mut Context<T>)
where T: Eq + Hash + Clone + Display where T: Eq + Hash + Clone + Copy + Display
{ {
if !(ctx.get_state(v) == State::UNTOUCHED) { if !(ctx.get_state(v) == State::UNTOUCHED) {
return; return;
@ -66,6 +67,10 @@ fn tarjan_visit<T>(gph: &Graph<T>, v: &T, ctx: &mut Context<T>)
} }
} }
ctx.set_state(v, State::FINISHED); ctx.set_state(v, State::FINISHED);
if ctx.debug {
let info = ctx.get_info(&v);
log_debug!("node, index, component: ({}, {}, {})", info.node, info.index, info.root);
}
if ctx.get_index(v) == ctx.get_root(v) { if ctx.get_index(v) == ctx.get_root(v) {
let mut component: Vec<T> = Vec::new(); let mut component: Vec<T> = Vec::new();
@ -73,9 +78,7 @@ fn tarjan_visit<T>(gph: &Graph<T>, v: &T, ctx: &mut Context<T>)
let u = ctx.top(); let u = ctx.top();
ctx.pop(); ctx.pop();
component.push(u.clone()); component.push(u.clone());
if u == *v { if u == *v { break; }
break;
}
} }
ctx.components.push(component); ctx.components.push(component);
} }
@ -86,7 +89,8 @@ fn tarjan_visit<T>(gph: &Graph<T>, v: &T, ctx: &mut Context<T>)
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
struct NodeInformation { struct NodeInformation<T> {
node: T,
root: usize, root: usize,
index: usize, index: usize,
state: State, state: State,
@ -95,23 +99,25 @@ struct NodeInformation {
struct Context<T> { struct Context<T> {
stack: Stack<T>, stack: Stack<T>,
max_index: usize, max_index: usize,
infos: HashMap<T, NodeInformation>, infos: HashMap<T, NodeInformation<T>>,
components: Vec<Vec<T>>, components: Vec<Vec<T>>,
debug: bool,
} }
impl<T> Context<T> impl<T> Context<T>
where T: Eq + Hash + Clone + Display where T: Eq + Hash + Clone + Copy + Display
{ {
fn new(gph: &Graph<T>) -> Context<T> { fn new(gph: &Graph<T>, debug: bool) -> Context<T> {
let mut infos = HashMap::<T, NodeInformation>::new(); let mut infos = HashMap::<T, NodeInformation<T>>::new();
for u in gph.nodes.iter() { for u in gph.nodes.iter() {
infos.entry(u.clone()).or_insert(NodeInformation::new()); infos.entry(u.clone()).or_insert(NodeInformation::<T>::new(&u));
} }
return Context { return Context {
stack: Stack::new(), stack: Stack::new(),
max_index: 0, max_index: 0,
infos: infos, infos: infos,
components: vec![], components: vec![],
debug: debug,
}; };
} }
@ -127,7 +133,7 @@ impl<T> Context<T>
return self.stack.pop(); return self.stack.pop();
} }
fn update_infos(self: &mut Self, u: &T, info: NodeInformation) { fn update_infos(self: &mut Self, u: &T, info: NodeInformation<T>) {
self.infos.insert(u.clone(), info); self.infos.insert(u.clone(), info);
} }
@ -149,25 +155,29 @@ impl<T> Context<T>
self.update_infos(u, info); self.update_infos(u, info);
} }
fn get_info(self: &mut Self, u: &T) -> NodeInformation<T> {
return *self.infos.get(u).unwrap();
}
fn get_state(self: &mut Self, u: &T) -> State { fn get_state(self: &mut Self, u: &T) -> State {
let info = *self.infos.get(u).unwrap(); return self.get_info(u).state;
return info.state;
} }
fn get_root(self: &mut Self, u: &T) -> usize { fn get_root(self: &mut Self, u: &T) -> usize {
let info = *self.infos.get(u).unwrap(); return self.get_info(u).root;
return info.root;
} }
fn get_index(self: &mut Self, u: &T) -> usize { fn get_index(self: &mut Self, u: &T) -> usize {
let info = *self.infos.get(u).unwrap(); return self.get_info(u).index;
return info.index;
} }
} }
impl NodeInformation { impl<T> NodeInformation<T>
fn new() -> NodeInformation { where T: Clone + Copy
{
fn new(node: &T) -> NodeInformation<T> {
return NodeInformation { return NodeInformation {
node: node.clone(),
root: 0, root: 0,
index: 0, index: 0,
state: State::UNTOUCHED, state: State::UNTOUCHED,

View File

@ -63,9 +63,9 @@ fn fixture_graph3() -> graph::Graph<i32> {
#[case(fixture_graph2(), vec![vec![1], vec![6], vec![7], vec![2,3,4,5]])] #[case(fixture_graph2(), vec![vec![1], vec![6], vec![7], vec![2,3,4,5]])]
#[case(fixture_graph3(), vec![vec![1,2,3,4,5], vec![7], vec![6,8]])] #[case(fixture_graph3(), vec![vec![1,2,3,4,5], vec![7], vec![6,8]])]
fn test_tarjan<T>(#[case] gph: graph::Graph<T>, #[case] expected: Vec<Vec<T>>) fn test_tarjan<T>(#[case] gph: graph::Graph<T>, #[case] expected: Vec<Vec<T>>)
where T: Eq + Hash + Clone + Display where T: Eq + Hash + Clone + Copy + Display
{ {
let components = tarjan::tarjan_algorithm(&gph); let components = tarjan::tarjan_algorithm(&gph, false);
assert_components_eq(&components, &expected) assert_components_eq(&components, &expected)
} }