From 6aa933cc0627d0d64cfcda53055db4f460f21b28 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Fri, 9 Aug 2024 18:21:29 -0400 Subject: [PATCH] Use ahash for IndexMap and IndexSet hasher (#12935) The ahash hasher offers better performace as a drop in replacement for the stdlib hash algorithm. This is a large reason we use the hashbrown crate for our HashMap type in Qiskit (along with rayon support). The indexmap crate doesn't use ahash by default however, so we typically switch to it anywhere we use IndexMap or IndexSet to match the lookup performance of hashbrown in places where we need to preserve insertion order. However, there were a couple of spots where we missed this in the rust code, this commit corrects these oversights. --- Cargo.lock | 1 + Cargo.toml | 1 + crates/accelerate/Cargo.toml | 2 +- crates/accelerate/src/synthesis/clifford/greedy_synthesis.rs | 5 +++-- crates/qasm3/Cargo.toml | 1 + crates/qasm3/src/build.rs | 5 ++++- 6 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4858af1971e9..5b2ee803ee4a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1222,6 +1222,7 @@ dependencies = [ name = "qiskit-qasm3" version = "1.3.0" dependencies = [ + "ahash 0.8.11", "hashbrown 0.14.5", "indexmap", "oq3_semantics", diff --git a/Cargo.toml b/Cargo.toml index a505a4e7c22b..5fffe8ff4dd7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,7 @@ ndarray = "^0.15.6" numpy = "0.21.0" smallvec = "1.13" thiserror = "1.0" +ahash = "0.8.11" # Most of the crates don't need the feature `extension-module`, since only `qiskit-pyext` builds an # actual C extension (the feature disables linking in `libpython`, which is forbidden in Python diff --git a/crates/accelerate/Cargo.toml b/crates/accelerate/Cargo.toml index 0b23cf08743e..854c1ed05706 100644 --- a/crates/accelerate/Cargo.toml +++ b/crates/accelerate/Cargo.toml @@ -15,7 +15,7 @@ numpy.workspace = true rand = "0.8" rand_pcg = "0.3" rand_distr = "0.4.3" -ahash = "0.8.11" +ahash.workspace = true num-traits = "0.2" num-complex.workspace = true num-bigint.workspace = true diff --git a/crates/accelerate/src/synthesis/clifford/greedy_synthesis.rs b/crates/accelerate/src/synthesis/clifford/greedy_synthesis.rs index e53e25282005..81ddfb1d6503 100644 --- a/crates/accelerate/src/synthesis/clifford/greedy_synthesis.rs +++ b/crates/accelerate/src/synthesis/clifford/greedy_synthesis.rs @@ -10,6 +10,7 @@ // copyright notice, and modified files need to carry a notice indicating // that they have been altered from the originals. +use ahash::RandomState; use indexmap::IndexSet; use ndarray::{s, ArrayView2}; use smallvec::smallvec; @@ -102,7 +103,7 @@ pub struct GreedyCliffordSynthesis<'a> { symplectic_matrix: SymplecticMatrix, /// Unprocessed qubits. - unprocessed_qubits: IndexSet, + unprocessed_qubits: IndexSet, } impl GreedyCliffordSynthesis<'_> { @@ -121,7 +122,7 @@ impl GreedyCliffordSynthesis<'_> { smat: tableau.slice(s![.., 0..2 * num_qubits]).to_owned(), }; - let unprocessed_qubits: IndexSet = (0..num_qubits).collect(); + let unprocessed_qubits = (0..num_qubits).collect(); Ok(GreedyCliffordSynthesis { tableau, diff --git a/crates/qasm3/Cargo.toml b/crates/qasm3/Cargo.toml index 4dd0d977786e..8e42f3f0701b 100644 --- a/crates/qasm3/Cargo.toml +++ b/crates/qasm3/Cargo.toml @@ -14,3 +14,4 @@ pyo3.workspace = true indexmap.workspace = true hashbrown.workspace = true oq3_semantics = "0.6.0" +ahash.workspace = true diff --git a/crates/qasm3/src/build.rs b/crates/qasm3/src/build.rs index f5cf2fd4efca..912066df839e 100644 --- a/crates/qasm3/src/build.rs +++ b/crates/qasm3/src/build.rs @@ -13,6 +13,8 @@ use pyo3::prelude::*; use pyo3::types::{PySequence, PyString, PyTuple}; +use ahash::RandomState; + use hashbrown::HashMap; use indexmap::IndexMap; @@ -190,8 +192,9 @@ impl BuilderState { let qubits = if let Some(asg_qubits) = barrier.qubits().as_ref() { // We want any deterministic order for easier circuit reproducibility in Python space, // and to include each seen qubit once. This simply maintains insertion order. - let mut qubits = IndexMap::<*const ::pyo3::ffi::PyObject, Py>::with_capacity( + let mut qubits = IndexMap::<*const ::pyo3::ffi::PyObject, Py, RandomState>::with_capacity_and_hasher( asg_qubits.len(), + RandomState::default() ); for qarg in asg_qubits.iter() { let qarg = expr::expect_gate_operand(qarg)?;