From ced03100d0a4bd29da122deb13d970d87f97e911 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Mon, 26 Sep 2022 14:06:17 -0400 Subject: [PATCH] Use ahash with IndexSet in simple_cycles() (#688) We recently merged a new simple_cycles() function in #633 that added an implementation of johnson's algorithm for finding all the simple cycles in a directed graph. In that function we used IndexSet to have a set with O(1) lookup with a deterministic ordering. As part of that we used the default hashing algorithm from the Rust stdlib. This leaves some performance on the table as the stdlib hashing algorithm is slower in order to have proven resistance to HashDoS attacks. Since this is relevant for the internal usage in Johnson's algorithm this commit switches the hasing algorithm to ahash (which is the default hashbrown uses) which offers better performance. --- src/connectivity/johnson_simple_cycles.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/connectivity/johnson_simple_cycles.rs b/src/connectivity/johnson_simple_cycles.rs index bef2a01b4..42ac5f865 100644 --- a/src/connectivity/johnson_simple_cycles.rs +++ b/src/connectivity/johnson_simple_cycles.rs @@ -61,7 +61,7 @@ pub struct SimpleCycleIter { blocked: HashSet, closed: HashSet, block: HashMap>, - stack: Vec<(NodeIndex, IndexSet)>, + stack: Vec<(NodeIndex, IndexSet)>, start_node: NodeIndex, node_map: HashMap, reverse_node_map: HashMap, @@ -115,7 +115,8 @@ fn unblock( blocked: &mut HashSet, block: &mut HashMap>, ) { - let mut stack: IndexSet = IndexSet::new(); + let mut stack: IndexSet = + IndexSet::with_hasher(ahash::RandomState::new()); stack.insert(node); while let Some(stack_node) = stack.pop() { if blocked.remove(&stack_node) { @@ -141,7 +142,7 @@ fn unblock( #[allow(clippy::too_many_arguments)] fn process_stack( start_node: NodeIndex, - stack: &mut Vec<(NodeIndex, IndexSet)>, + stack: &mut Vec<(NodeIndex, IndexSet)>, path: &mut Vec, closed: &mut HashSet, blocked: &mut HashSet, @@ -165,7 +166,7 @@ fn process_stack( next_node, subgraph .neighbors(next_node) - .collect::>(), + .collect::>(), )); closed.remove(&next_node); blocked.insert(next_node); @@ -206,7 +207,8 @@ impl SimpleCycleIter { })); } // Restore previous state if it exists - let mut stack: Vec<(NodeIndex, IndexSet)> = std::mem::take(&mut slf.stack); + let mut stack: Vec<(NodeIndex, IndexSet)> = + std::mem::take(&mut slf.stack); let mut path: Vec = std::mem::take(&mut slf.path); let mut closed: HashSet = std::mem::take(&mut slf.closed); let mut blocked: HashSet = std::mem::take(&mut slf.blocked); @@ -267,7 +269,7 @@ impl SimpleCycleIter { slf.start_node, subgraph .neighbors(slf.start_node) - .collect::>(), + .collect::>(), )]; if let Some(res) = process_stack( slf.start_node,