Skip to content

Commit ced0310

Browse files
authored
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.
1 parent 676a7cd commit ced0310

File tree

1 file changed

+8
-6
lines changed

1 file changed

+8
-6
lines changed

Diff for: src/connectivity/johnson_simple_cycles.rs

+8-6
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ pub struct SimpleCycleIter {
6161
blocked: HashSet<NodeIndex>,
6262
closed: HashSet<NodeIndex>,
6363
block: HashMap<NodeIndex, HashSet<NodeIndex>>,
64-
stack: Vec<(NodeIndex, IndexSet<NodeIndex>)>,
64+
stack: Vec<(NodeIndex, IndexSet<NodeIndex, ahash::RandomState>)>,
6565
start_node: NodeIndex,
6666
node_map: HashMap<NodeIndex, NodeIndex>,
6767
reverse_node_map: HashMap<NodeIndex, NodeIndex>,
@@ -115,7 +115,8 @@ fn unblock(
115115
blocked: &mut HashSet<NodeIndex>,
116116
block: &mut HashMap<NodeIndex, HashSet<NodeIndex>>,
117117
) {
118-
let mut stack: IndexSet<NodeIndex> = IndexSet::new();
118+
let mut stack: IndexSet<NodeIndex, ahash::RandomState> =
119+
IndexSet::with_hasher(ahash::RandomState::new());
119120
stack.insert(node);
120121
while let Some(stack_node) = stack.pop() {
121122
if blocked.remove(&stack_node) {
@@ -141,7 +142,7 @@ fn unblock(
141142
#[allow(clippy::too_many_arguments)]
142143
fn process_stack(
143144
start_node: NodeIndex,
144-
stack: &mut Vec<(NodeIndex, IndexSet<NodeIndex>)>,
145+
stack: &mut Vec<(NodeIndex, IndexSet<NodeIndex, ahash::RandomState>)>,
145146
path: &mut Vec<NodeIndex>,
146147
closed: &mut HashSet<NodeIndex>,
147148
blocked: &mut HashSet<NodeIndex>,
@@ -165,7 +166,7 @@ fn process_stack(
165166
next_node,
166167
subgraph
167168
.neighbors(next_node)
168-
.collect::<IndexSet<NodeIndex>>(),
169+
.collect::<IndexSet<NodeIndex, ahash::RandomState>>(),
169170
));
170171
closed.remove(&next_node);
171172
blocked.insert(next_node);
@@ -206,7 +207,8 @@ impl SimpleCycleIter {
206207
}));
207208
}
208209
// Restore previous state if it exists
209-
let mut stack: Vec<(NodeIndex, IndexSet<NodeIndex>)> = std::mem::take(&mut slf.stack);
210+
let mut stack: Vec<(NodeIndex, IndexSet<NodeIndex, ahash::RandomState>)> =
211+
std::mem::take(&mut slf.stack);
210212
let mut path: Vec<NodeIndex> = std::mem::take(&mut slf.path);
211213
let mut closed: HashSet<NodeIndex> = std::mem::take(&mut slf.closed);
212214
let mut blocked: HashSet<NodeIndex> = std::mem::take(&mut slf.blocked);
@@ -267,7 +269,7 @@ impl SimpleCycleIter {
267269
slf.start_node,
268270
subgraph
269271
.neighbors(slf.start_node)
270-
.collect::<IndexSet<NodeIndex>>(),
272+
.collect::<IndexSet<NodeIndex, ahash::RandomState>>(),
271273
)];
272274
if let Some(res) = process_stack(
273275
slf.start_node,

0 commit comments

Comments
 (0)