From ee9fcc5fdf2a845aadb98d58ba27fd6195f51e17 Mon Sep 17 00:00:00 2001 From: ljeub-pometry <97447091+ljeub-pometry@users.noreply.github.com> Date: Thu, 2 Jan 2025 18:05:10 +0100 Subject: [PATCH] Fix in- and out-component distance calculations (#1904) * add multi-path to test * fix out_components distances * add test for in-component * fix distances in in-component algorithm --- .../algorithms/components/in_components.rs | 42 ++++++++++++------- .../algorithms/components/out_components.rs | 42 ++++++++++++------- 2 files changed, 54 insertions(+), 30 deletions(-) diff --git a/raphtory/src/algorithms/components/in_components.rs b/raphtory/src/algorithms/components/in_components.rs index 74833fcc3..b5dfc6d89 100644 --- a/raphtory/src/algorithms/components/in_components.rs +++ b/raphtory/src/algorithms/components/in_components.rs @@ -20,7 +20,7 @@ use crate::{ prelude::GraphViewOps, }; use itertools::Itertools; -use std::collections::{hash_map::Entry, HashMap, HashSet}; +use std::collections::{hash_map::Entry, HashMap, HashSet, VecDeque}; #[derive(Clone, Debug, Default)] struct InState { @@ -111,20 +111,20 @@ pub fn in_component<'graph, G: GraphViewOps<'graph>>( node: NodeView, ) -> NodeState<'graph, usize, G> { let mut in_components = HashMap::new(); - let mut to_check_stack = Vec::new(); + let mut to_check_stack = VecDeque::new(); node.in_neighbours().iter().for_each(|node| { let id = node.node; in_components.insert(id, 1usize); - to_check_stack.push((id, 1usize)); + to_check_stack.push_back((id, 1usize)); }); - while let Some((neighbour_id, d)) = to_check_stack.pop() { + while let Some((neighbour_id, d)) = to_check_stack.pop_front() { let d = d + 1; if let Some(neighbour) = &node.graph.node(neighbour_id) { neighbour.in_neighbours().iter().for_each(|node| { let id = node.node; if let Entry::Vacant(entry) = in_components.entry(id) { entry.insert(d); - to_check_stack.push((id, d)); + to_check_stack.push_back((id, d)); } }); } @@ -145,6 +145,16 @@ mod components_test { use crate::{db::api::mutation::AdditionOps, prelude::*, test_storage}; use std::collections::HashMap; + fn check_node(graph: &Graph, node_id: u64, mut correct: Vec<(u64, usize)>) { + let mut results: Vec<_> = in_component(graph.node(node_id).unwrap()) + .iter() + .map(|(n, d)| (n.id().as_u64().unwrap(), *d)) + .collect(); + results.sort(); + correct.sort(); + assert_eq!(results, correct); + } + #[test] fn in_component_test() { let graph = Graph::new(); @@ -163,16 +173,6 @@ mod components_test { graph.add_edge(ts, src, dst, NO_PROPS, None).unwrap(); } - fn check_node(graph: &Graph, node_id: u64, mut correct: Vec<(u64, usize)>) { - let mut results: Vec<_> = in_component(graph.node(node_id).unwrap()) - .iter() - .map(|(n, d)| (n.id().as_u64().unwrap(), *d)) - .collect(); - results.sort(); - correct.sort(); - assert_eq!(results, correct); - } - check_node(&graph, 1, vec![]); check_node(&graph, 2, vec![(1, 1)]); check_node(&graph, 3, vec![(1, 1)]); @@ -183,6 +183,18 @@ mod components_test { check_node(&graph, 8, vec![(1, 3), (2, 2), (5, 1)]); } + #[test] + fn test_distances() { + let graph = Graph::new(); + graph.add_edge(0, 1, 2, NO_PROPS, None).unwrap(); + graph.add_edge(0, 2, 3, NO_PROPS, None).unwrap(); + graph.add_edge(0, 1, 4, NO_PROPS, None).unwrap(); + graph.add_edge(0, 4, 5, NO_PROPS, None).unwrap(); + graph.add_edge(0, 5, 3, NO_PROPS, None).unwrap(); + + check_node(&graph, 3, vec![(1, 2), (2, 1), (4, 2), (5, 1)]); + } + #[test] fn in_components_test() { let graph = Graph::new(); diff --git a/raphtory/src/algorithms/components/out_components.rs b/raphtory/src/algorithms/components/out_components.rs index ed7d11982..26a76a8a8 100644 --- a/raphtory/src/algorithms/components/out_components.rs +++ b/raphtory/src/algorithms/components/out_components.rs @@ -19,7 +19,7 @@ use crate::{ use itertools::Itertools; use raphtory_api::core::entities::GID; use rayon::prelude::*; -use std::collections::{hash_map::Entry, HashMap, HashSet}; +use std::collections::{hash_map::Entry, HashMap, HashSet, VecDeque}; #[derive(Clone, Debug, Default)] struct OutState { @@ -114,20 +114,20 @@ pub fn out_component<'graph, G: GraphViewOps<'graph>>( node: NodeView, ) -> NodeState<'graph, usize, G> { let mut out_components = HashMap::new(); - let mut to_check_stack = Vec::new(); + let mut to_check_stack = VecDeque::new(); node.out_neighbours().iter().for_each(|node| { let id = node.node; out_components.insert(id, 1usize); - to_check_stack.push((id, 1usize)); + to_check_stack.push_back((id, 1usize)); }); - while let Some((neighbour_id, d)) = to_check_stack.pop() { + while let Some((neighbour_id, d)) = to_check_stack.pop_front() { let d = d + 1; if let Some(neighbour) = &node.graph.node(neighbour_id) { neighbour.out_neighbours().iter().for_each(|node| { let id = node.node; if let Entry::Vacant(entry) = out_components.entry(id) { entry.insert(d); - to_check_stack.push((id, d)); + to_check_stack.push_back((id, d)); } }); } @@ -148,6 +148,16 @@ mod components_test { use crate::{db::api::mutation::AdditionOps, prelude::*, test_storage}; use std::collections::HashMap; + fn check_node(graph: &Graph, node_id: u64, mut correct: Vec<(u64, usize)>) { + let mut results: Vec<_> = out_component(graph.node(node_id).unwrap()) + .iter() + .map(|(n, d)| (n.id().as_u64().unwrap(), *d)) + .collect(); + results.sort(); + correct.sort(); + assert_eq!(results, correct); + } + #[test] fn out_component_test() { let graph = Graph::new(); @@ -166,16 +176,6 @@ mod components_test { graph.add_edge(ts, src, dst, NO_PROPS, None).unwrap(); } - fn check_node(graph: &Graph, node_id: u64, mut correct: Vec<(u64, usize)>) { - let mut results: Vec<_> = out_component(graph.node(node_id).unwrap()) - .iter() - .map(|(n, d)| (n.id().as_u64().unwrap(), *d)) - .collect(); - results.sort(); - correct.sort(); - assert_eq!(results, correct); - } - check_node( &graph, 1, @@ -190,6 +190,18 @@ mod components_test { check_node(&graph, 8, vec![]); } + #[test] + fn test_distances() { + let graph = Graph::new(); + graph.add_edge(0, 1, 2, NO_PROPS, None).unwrap(); + graph.add_edge(0, 2, 3, NO_PROPS, None).unwrap(); + graph.add_edge(0, 1, 4, NO_PROPS, None).unwrap(); + graph.add_edge(0, 4, 5, NO_PROPS, None).unwrap(); + graph.add_edge(0, 5, 3, NO_PROPS, None).unwrap(); + + check_node(&graph, 1, vec![(2, 1), (3, 2), (4, 1), (5, 2)]); + } + #[test] fn out_components_test() { let graph = Graph::new();