From 1c3329b5e4146ec0d83d0fd1f39ece21bbcc4129 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 3 Jan 2026 11:24:37 +0000 Subject: [PATCH 1/5] Initial plan From a24c50368978b6cf79fe126938e44685d7453f4f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 3 Jan 2026 11:31:45 +0000 Subject: [PATCH 2/5] Add ahash dependency and establish baseline Co-authored-by: samueltardieu <44656+samueltardieu@users.noreply.github.com> --- Cargo.lock | 14 ++++++++++++++ Cargo.toml | 1 + 2 files changed, 15 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index cd893650..4a63aa29 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,19 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "getrandom 0.3.3", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.3" @@ -533,6 +546,7 @@ checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" name = "pathfinding" version = "4.14.0" dependencies = [ + "ahash", "codspeed-criterion-compat", "deprecate-until", "iai-callgrind", diff --git a/Cargo.toml b/Cargo.toml index 9ca98786..70304bba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,6 +40,7 @@ iai = [] num-traits = "0.2.19" indexmap = "2.11.4" rustc-hash = "2.1.1" +ahash = "0.8.11" integer-sqrt = "0.1.5" thiserror = "2.0.17" deprecate-until = "0.1.1" From f6b15fa45866d49d64ea272c3c097414b8cf04ff Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 3 Jan 2026 11:36:20 +0000 Subject: [PATCH 3/5] Replace FxHash with AHash in undirected/connected_components.rs Co-authored-by: samueltardieu <44656+samueltardieu@users.noreply.github.com> --- src/directed/count_paths.rs | 7 +++---- src/undirected/connected_components.rs | 7 +++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/directed/count_paths.rs b/src/directed/count_paths.rs index 29b4533f..b1ff76fe 100644 --- a/src/directed/count_paths.rs +++ b/src/directed/count_paths.rs @@ -1,14 +1,13 @@ //! Count the total number of possible paths to reach a destination. +use ahash::AHashMap; use std::hash::Hash; -use rustc_hash::FxHashMap; - fn cached_count_paths( start: T, successors: &mut FN, success: &mut FS, - cache: &mut FxHashMap, + cache: &mut AHashMap, ) -> usize where T: Eq + Hash, @@ -66,6 +65,6 @@ where start, &mut successors, &mut success, - &mut FxHashMap::default(), + &mut AHashMap::default(), ) } diff --git a/src/undirected/connected_components.rs b/src/undirected/connected_components.rs index 1f543d37..70ea7075 100644 --- a/src/undirected/connected_components.rs +++ b/src/undirected/connected_components.rs @@ -1,12 +1,11 @@ //! Separate components of an undirected graph into disjoint sets. +use ahash::{AHashMap, AHashSet}; use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::collections::{HashMap, HashSet}; use std::hash::Hash; use std::marker::PhantomData; -use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet}; - /// A connected component implementation for various generic types. /// /// This structure is only useful if the default collections used by @@ -107,8 +106,8 @@ where let (_, gindices) = Self::separate_components(groups); // Pre-size the hash map to reduce reallocations let estimated_capacity = gindices.iter().filter(|&&n| n != usize::MAX).count(); - let mut gb: FxHashMap> = - FxHashMap::with_capacity_and_hasher(estimated_capacity, FxBuildHasher); + let mut gb: AHashMap> = + AHashMap::with_capacity(estimated_capacity); for (i, n) in gindices .into_iter() .enumerate() From 446386264de0d90fe243c5a3662db5bb0cea9972 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 3 Jan 2026 11:40:21 +0000 Subject: [PATCH 4/5] Replace FxHashSet with AHashSet in noderefs.rs Co-authored-by: samueltardieu <44656+samueltardieu@users.noreply.github.com> --- src/noderefs.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/noderefs.rs b/src/noderefs.rs index b11c7019..7b830f74 100644 --- a/src/noderefs.rs +++ b/src/noderefs.rs @@ -1,4 +1,4 @@ -use rustc_hash::FxHashSet; +use ahash::AHashSet; use std::hash::Hash; use std::iter::FromIterator; use std::ops::Deref; @@ -22,19 +22,19 @@ use std::ops::Deref; /// let refs: NodeRefs = NodeRefs::from_iter([&red, &blue, &green]); /// ``` #[derive(Debug, Clone, PartialEq, Eq)] -pub struct NodeRefs<'a, N>(FxHashSet<&'a N>) +pub struct NodeRefs<'a, N>(AHashSet<&'a N>) where N: Eq + Hash + Clone; impl<'a, N: Eq + Hash + Clone> FromIterator<&'a N> for NodeRefs<'a, N> { fn from_iter>(iter: T) -> Self { - NodeRefs(FxHashSet::from_iter(iter)) + NodeRefs(AHashSet::from_iter(iter)) } } impl<'a, N: Eq + Hash + Clone> From<&'a N> for NodeRefs<'a, N> { fn from(value: &'a N) -> Self { - NodeRefs(FxHashSet::from_iter([value])) + NodeRefs(AHashSet::from_iter([value])) } } @@ -57,7 +57,7 @@ impl<'a, N: Eq + Hash + Clone> IntoIterator for &'a NodeRefs<'a, N> { } impl<'a, N: Eq + Hash + Clone> Deref for NodeRefs<'a, N> { - type Target = FxHashSet<&'a N>; + type Target = AHashSet<&'a N>; fn deref(&self) -> &Self::Target { &self.0 @@ -78,7 +78,7 @@ mod tests { let refs = NodeRefs::from_iter(&nodes); assert_eq!( refs.0, - FxHashSet::from_iter([&nodes[0], &nodes[1], &nodes[2]]) + AHashSet::from_iter([&nodes[0], &nodes[1], &nodes[2]]) ); } @@ -86,7 +86,7 @@ mod tests { fn test_from_single_ref() { let node = Node(42); let refs = NodeRefs::from(&node); - assert_eq!(refs.0, FxHashSet::from_iter([&node])); + assert_eq!(refs.0, AHashSet::from_iter([&node])); } #[test] From 934579b45de92589b6b521760fbab66d30a2f90c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 3 Jan 2026 11:45:21 +0000 Subject: [PATCH 5/5] Final investigation results - keep only improvements Co-authored-by: samueltardieu <44656+samueltardieu@users.noreply.github.com> --- src/undirected/connected_components.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/undirected/connected_components.rs b/src/undirected/connected_components.rs index 70ea7075..57d48e27 100644 --- a/src/undirected/connected_components.rs +++ b/src/undirected/connected_components.rs @@ -106,8 +106,7 @@ where let (_, gindices) = Self::separate_components(groups); // Pre-size the hash map to reduce reallocations let estimated_capacity = gindices.iter().filter(|&&n| n != usize::MAX).count(); - let mut gb: AHashMap> = - AHashMap::with_capacity(estimated_capacity); + let mut gb: AHashMap> = AHashMap::with_capacity(estimated_capacity); for (i, n) in gindices .into_iter() .enumerate()