From 6d9c687d701bffbf100b0f7a3e90e6760dd32b54 Mon Sep 17 00:00:00 2001 From: Leon Stichternath <leon@stichternath.net> Date: Fri, 14 May 2021 02:02:54 +0200 Subject: [PATCH] implemented component methods and kernel --- src/graph/graph.rs | 77 +++++++++++++++++++++++++++++++++++++++- src/kernel/component.rs | 78 +++++++++++++++++++++++++++++++++++++++++ src/kernel/mod.rs | 1 + 3 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 src/kernel/component.rs diff --git a/src/graph/graph.rs b/src/graph/graph.rs index 66854b9..16e9318 100644 --- a/src/graph/graph.rs +++ b/src/graph/graph.rs @@ -185,12 +185,51 @@ impl Graph { non_common.remove(&b); non_common } + + /// Returns all nodes of the component that `node` is in. + pub fn component_of_node(&self, node: Node) -> FxHashSet<Node> { + let mut component = crate::new_fxhashset(0); + let mut nodes_to_check = vec![node]; + + while let Some(node) = nodes_to_check.pop() { + component.insert(node); + nodes_to_check.extend(self.neighbors(node).difference(&component)); + } + + component + } + + /// Returns all seperated components of the graph. + pub fn find_all_components(&self) -> Vec<FxHashSet<Node>> { + let mut components = Vec::with_capacity(0); + + for node in self.nodes() { + if components + .iter() + .any(|component: &FxHashSet<_>| component.contains(&node)) + { + continue; + } + components.push(self.component_of_node(node)); + } + + components + } + + /// Returns `true` iff `component` is complete, as in all nodes in `component` are neighboring. + /// + /// This function assumes that `component` is a valid component of the graph. + pub fn is_component_complete(&self, component: &FxHashSet<Node>) -> bool { + component + .iter() + .all(|&node| self.neighbors(node).len() == component.len() - 1) + } } #[cfg(test)] mod tests { - use super::Graph; + use rustc_hash::FxHashSet; #[test] fn with_capacity() { @@ -621,4 +660,40 @@ mod tests { assert_eq!(non_common_13.len(), 0); assert_eq!(non_common_23.len(), 0); } + #[test] + fn component_of_node_one() { + let mut graph = Graph::with_capacity(0); + graph.add_edge(0, 1); + graph.add_edge(0, 2); + graph.add_edge(0, 3); + graph.add_edge(1, 4); + graph.add_edge(2, 4); + + let correct_component = (0..=4).collect::<FxHashSet<_>>(); + let components = (0..=4).map(|node| graph.component_of_node(node)); + + for component in components { + assert_eq!(component, correct_component); + } + } + #[test] + fn component_of_node_two() { + let mut graph = Graph::with_capacity(0); + graph.add_edge(0, 1); + graph.add_edge(0, 2); + graph.add_edge(0, 3); + graph.add_edge(4, 5); + graph.add_edge(4, 6); + + let correct_component_0 = (0..=3).collect::<FxHashSet<_>>(); + let correct_component_1 = (4..=6).collect::<FxHashSet<_>>(); + let components_0 = (0..=3).map(|node| graph.component_of_node(node)); + let components_1 = (4..=6).map(|node| graph.component_of_node(node)); + for component_0 in components_0 { + assert_eq!(component_0, correct_component_0); + } + for component_1 in components_1 { + assert_eq!(component_1, correct_component_1); + } + } } diff --git a/src/kernel/component.rs b/src/kernel/component.rs new file mode 100644 index 0000000..f9b6576 --- /dev/null +++ b/src/kernel/component.rs @@ -0,0 +1,78 @@ +use crate::{context::CepContext, CepResult}; + +impl CepContext { + /// This kernel will delete all seperate complete components. + /// + /// This graph + /// ```text + /// o---o o--o--o + /// \ / | / + /// o o + /// ``` + /// will be turned into this graph. + /// ```text + /// o--o--o + /// | / + /// o + /// ``` + pub fn kernel_complete_components(&mut self) -> CepResult<&mut Self> { + for component in self.graph().find_all_components() { + if !self.graph().is_component_complete(&component) { + continue; + } + for node in component { + self.graph_mut().remove_node(node); + } + } + Ok(self) + } +} + +#[cfg(test)] +mod test { + use crate::{context::CepContext, graph::Graph}; + + #[test] + fn kernel_complete_components_nothing() { + let mut graph = Graph::with_capacity(0); + graph.add_edge(0, 1); + graph.add_edge(0, 2); + graph.add_edge(3, 4); + graph.add_edge(4, 5); + + let mut context = CepContext::new(graph, 0); + context.kernel_complete_components().unwrap(); + + assert!(context.permanent_edges().is_empty()); + assert!(context.forbidden_edges().is_empty()); + assert!(context.edits().is_empty()); + for node in 0..=5 { + assert!(context.graph().node_exists(node)); + } + } + #[test] + fn kernel_complete_components() { + let mut graph = Graph::with_capacity(0); + graph.add_edge(0, 1); + graph.add_edge(0, 2); + graph.add_edge(1, 2); + graph.add_edge(3, 4); + graph.add_edge(4, 5); + graph.add_node(6); + + let mut context = CepContext::new(graph, 0); + context.kernel_complete_components().unwrap(); + + assert!(context.permanent_edges().is_empty()); + assert!(context.forbidden_edges().is_empty()); + assert!(context.edits().is_empty()); + + assert!(!context.graph().node_exists(0)); + assert!(!context.graph().node_exists(1)); + assert!(!context.graph().node_exists(2)); + assert!(context.graph().node_exists(3)); + assert!(context.graph().node_exists(4)); + assert!(context.graph().node_exists(5)); + assert!(!context.graph().node_exists(6)); + } +} diff --git a/src/kernel/mod.rs b/src/kernel/mod.rs index 8ce8b6e..456ea49 100644 --- a/src/kernel/mod.rs +++ b/src/kernel/mod.rs @@ -1 +1,2 @@ mod bridge; +mod component; -- GitLab