diff --git a/.clippy.toml b/.clippy.toml index 3487b230a9c1..e0998e9a860f 100644 --- a/.clippy.toml +++ b/.clippy.toml @@ -3,4 +3,6 @@ disallowed-types = [ "std::collections::HashMap", "ahash::HashSet", "ahash::HashMap", + "indexmap::IndexMap", + "indexmap::IndexSet", ] diff --git a/Cargo.lock b/Cargo.lock index f5dc11a00b68..c58229851bd1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -823,6 +823,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "gemm" version = "0.19.0" @@ -1163,7 +1169,7 @@ checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ "allocator-api2", "equivalent", - "foldhash", + "foldhash 0.1.5", "rayon", "serde", ] @@ -2267,19 +2273,17 @@ dependencies = [ "anyhow", "cbindgen", "clap", - "indexmap", "qiskit-bindgen", "qiskit-cext-vtable", + "qiskit-util", ] [[package]] name = "qiskit-cext" version = "2.5.0-dev" dependencies = [ - "ahash 0.8.12", "anyhow", "hashbrown 0.15.5", - "indexmap", "mimalloc", "nalgebra 0.34.2", "ndarray", @@ -2289,6 +2293,7 @@ dependencies = [ "qiskit-circuit-library", "qiskit-quantum-info", "qiskit-transpiler", + "qiskit-util", "rand 0.10.1", "rand_pcg 0.10.2", "smallvec", @@ -2311,8 +2316,8 @@ dependencies = [ "bitfield-struct", "bytemuck", "crossterm", + "foldhash 0.2.0", "hashbrown 0.15.5", - "indexmap", "itertools 0.14.0", "lexical-core", "lexical-write-float", @@ -2401,14 +2406,14 @@ dependencies = [ name = "qiskit-qasm3" version = "2.5.0-dev" dependencies = [ - "ahash 0.8.12", + "foldhash 0.2.0", "hashbrown 0.15.5", - "indexmap", "lazy_static", "oq3_semantics", "oq3_syntax", "pyo3", "qiskit-circuit", + "qiskit-util", "regex", "thiserror 2.0.18", ] @@ -2417,11 +2422,9 @@ dependencies = [ name = "qiskit-qpy" version = "2.5.0-dev" dependencies = [ - "ahash 0.8.12", "binrw", "bytemuck", "hashbrown 0.15.5", - "indexmap", "num-bigint", "num-complex", "num-traits", @@ -2430,6 +2433,7 @@ dependencies = [ "pyo3", "qiskit-circuit", "qiskit-quantum-info", + "qiskit-util", "smallvec", "thiserror 2.0.18", "uuid", @@ -2439,12 +2443,11 @@ dependencies = [ name = "qiskit-quantum-info" version = "2.5.0-dev" dependencies = [ - "ahash 0.8.12", "approx", "bytemuck", "fixedbitset 0.5.7", + "foldhash 0.2.0", "hashbrown 0.15.5", - "indexmap", "itertools 0.14.0", "nalgebra 0.34.2", "ndarray", @@ -2467,14 +2470,12 @@ dependencies = [ name = "qiskit-synthesis" version = "2.5.0-dev" dependencies = [ - "ahash 0.8.12", "approx", "binrw", "bytemuck", "faer", "fixedbitset 0.5.7", "hashbrown 0.15.5", - "indexmap", "itertools 0.14.0", "nalgebra 0.34.2", "ndarray", @@ -2501,11 +2502,11 @@ dependencies = [ name = "qiskit-transpiler" version = "2.5.0-dev" dependencies = [ - "ahash 0.8.12", "anyhow", "approx", "bytemuck", "fixedbitset 0.5.7", + "foldhash 0.2.0", "hashbrown 0.15.5", "indexmap", "itertools 0.14.0", @@ -2532,6 +2533,8 @@ dependencies = [ name = "qiskit-util" version = "2.5.0-dev" dependencies = [ + "foldhash 0.2.0", + "indexmap", "num-complex", "pyo3", "thiserror 2.0.18", @@ -2870,7 +2873,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aaeee6f84153fd6f62507fc22bfe9499c8485075b44186dcbb918166ef75116f" dependencies = [ "fixedbitset 0.5.7", - "foldhash", + "foldhash 0.1.5", "hashbrown 0.15.5", "indexmap", "ndarray", diff --git a/Cargo.toml b/Cargo.toml index 8f523478cd9e..adf46dd75ec5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,7 +30,7 @@ rustworkx-core = "0.17" fixedbitset = "0.5.7" approx = "0.5" itertools = "0.14.0" -ahash = "0.8.12" +foldhash = "0.2.0" rayon = "1.12" nom = "8.0" nom-unicode = "0.4" diff --git a/crates/bindgen-c/Cargo.toml b/crates/bindgen-c/Cargo.toml index a3f5dab1e2c9..141725b4d689 100644 --- a/crates/bindgen-c/Cargo.toml +++ b/crates/bindgen-c/Cargo.toml @@ -15,6 +15,6 @@ name = "qiskit-bindgen-c" qiskit-bindgen.workspace = true qiskit-cext-vtable = { workspace = true, features = ["python_binding"] } anyhow.workspace = true -indexmap.workspace = true +qiskit-util.workspace = true cbindgen.workspace = true clap = { version = "4.6", features = ["derive"] } diff --git a/crates/bindgen-c/src/abi.rs b/crates/bindgen-c/src/abi.rs index e0e890383dcf..8b958f452abc 100644 --- a/crates/bindgen-c/src/abi.rs +++ b/crates/bindgen-c/src/abi.rs @@ -10,8 +10,8 @@ // copyright notice, and modified files need to carry a notice indicating // that they have been altered from the originals. -use indexmap::IndexMap; use qiskit_cext_vtable::ExportedFunction; +use qiskit_util::IndexMap; pub struct SlotsLists { pub slots: IndexMap, diff --git a/crates/bindgen-c/src/lint.rs b/crates/bindgen-c/src/lint.rs index 76d6e3e1bdd5..a3150a40a3f8 100644 --- a/crates/bindgen-c/src/lint.rs +++ b/crates/bindgen-c/src/lint.rs @@ -11,8 +11,8 @@ // that they have been altered from the originals. use crate::SlotsLists; -use indexmap::IndexMap; use qiskit_bindgen::fn_attrs; +use qiskit_util::IndexMap; use std::fmt::Write; /// Tracked failures from the linting of a resolved vtable listing against a set of extracted @@ -68,8 +68,8 @@ pub fn lint( bindings: &cbindgen::Bindings, slots: &SlotsLists, ) -> anyhow::Result> { - let mut seen = IndexMap::<&str, (&str, usize)>::new(); - let mut duplicates = IndexMap::>::new(); + let mut seen = IndexMap::<&str, (&str, usize)>::default(); + let mut duplicates = IndexMap::>::default(); for (api_name, list) in slots.slots.iter() { for (slot, export) in list.iter_names() { if let Some((prev_api, prev_slot)) = seen.insert(export, (api_name, slot)) { @@ -82,7 +82,7 @@ pub fn lint( } } } - let mut skipped_but_exported = IndexMap::new(); + let mut skipped_but_exported = IndexMap::default(); let mut missing = Vec::new(); for func in bindings.functions.iter() { let fname = func.path.name(); diff --git a/crates/cext/Cargo.toml b/crates/cext/Cargo.toml index fe05556eccb4..e950dbc2c0fc 100644 --- a/crates/cext/Cargo.toml +++ b/crates/cext/Cargo.toml @@ -21,8 +21,7 @@ qiskit-circuit.workspace = true qiskit-circuit-library.workspace = true qiskit-transpiler.workspace = true pyo3 = { workspace = true, optional = true } -indexmap.workspace = true -ahash.workspace = true +qiskit-util.workspace = true smallvec.workspace = true ndarray.workspace = true nalgebra.workspace = true diff --git a/crates/cext/src/transpiler/neighbors.rs b/crates/cext/src/transpiler/neighbors.rs index ea83ff5de9b0..44ea23576c71 100644 --- a/crates/cext/src/transpiler/neighbors.rs +++ b/crates/cext/src/transpiler/neighbors.rs @@ -203,10 +203,10 @@ pub unsafe extern "C" fn qk_neighbors_clear(neighbors: *mut CNeighbors) { mod test { use super::*; - use indexmap::IndexMap; use qiskit_circuit::PhysicalQubit; use qiskit_circuit::operations::StandardGate; use qiskit_transpiler::target::{Qargs, Target}; + use qiskit_util::IndexMap; // This is mostly for Miri. #[test] @@ -224,7 +224,7 @@ mod test { None, ) .unwrap(); - let mut line: IndexMap<_, _, _> = Default::default(); + let mut line: IndexMap<_, _> = Default::default(); for qubit in 0..num_qubits - 1 { line.insert(Qargs::from([qubit, qubit + 1].map(PhysicalQubit)), None); } @@ -268,7 +268,7 @@ mod test { None, ) .unwrap(); - let mut line: IndexMap<_, _, _> = Default::default(); + let mut line: IndexMap<_, _> = Default::default(); line.insert(Qargs::Global, None); target .add_instruction(StandardGate::CZ.into(), None, None, Some(line)) diff --git a/crates/cext/src/transpiler/target.rs b/crates/cext/src/transpiler/target.rs index 77e57d4e0918..30bd7df8f1d5 100644 --- a/crates/cext/src/transpiler/target.rs +++ b/crates/cext/src/transpiler/target.rs @@ -17,7 +17,6 @@ use std::sync::Arc; use crate::dag::COperationKind; use crate::exit_codes::{CInputError, ExitCode}; use crate::pointers::{check_ptr, const_ptr_as_ref, mut_ptr_as_ref}; -use indexmap::IndexMap; use qiskit_circuit::PhysicalQubit; use qiskit_circuit::instruction::{Instruction, Parameters}; use qiskit_circuit::operations::StandardInstruction; @@ -26,6 +25,7 @@ use qiskit_circuit::packed_instruction::PackedOperation; use qiskit_circuit::parameter::parameter_expression::ParameterExpression; use qiskit_circuit::parameter::symbol_expr::Symbol; use qiskit_transpiler::target::{InstructionProperties, Qargs, Target, TargetOperation}; +use qiskit_util::IndexMap; use smallvec::{SmallVec, smallvec}; /// @ingroup QkTarget @@ -497,7 +497,7 @@ impl From for PackedOperation { pub struct TargetEntry { operation: StandardOperation, params: Option>, - map: IndexMap, ahash::RandomState>, + map: IndexMap>, name: Option, } @@ -1009,8 +1009,8 @@ pub unsafe extern "C" fn qk_target_num_instructions(target: *const Target) -> us /// qk_target_instruction_supported(target, "crx", (uint32_t []){0, 1}, params); /// /// // Free the pointers -/// qk_param_free(params[0]); -/// qk_target_free(target); +/// qk_param_free(params[0]); +/// qk_target_free(target); /// ``` /// /// # Safety @@ -1220,8 +1220,8 @@ pub unsafe extern "C" fn qk_target_op_qargs_index( /// Retrieve the qargs for the operation by index. /// /// @param target A pointer to the ``QkTarget``. -/// @param op_idx The index at which the gate is stored. -/// @param qarg_idx The index at which the qargs are stored. +/// @param op_idx The index at which the gate is stored. +/// @param qarg_idx The index at which the qargs are stored. /// @param qargs_out An out pointer to an array qubits. If ``op_idx`` refers to a a global /// operation, a null pointer will be written. The written pointer is borrowed from the /// target and must not be freed. A zero-qargs instruction will write out a non-null pointer, @@ -1522,7 +1522,7 @@ pub unsafe extern "C" fn qk_target_op_get( /// /// QkTargetOp op; /// qk_target_op_get(target, 0, &op); -/// +/// /// // Check if the operation is a gate; /// if (op.op_type == QkOperationKind_Gate) { /// QkGate gate = qk_target_op_gate(target, 0); diff --git a/crates/circuit/Cargo.toml b/crates/circuit/Cargo.toml index c953bab3c8a9..b958ce1d3848 100644 --- a/crates/circuit/Cargo.toml +++ b/crates/circuit/Cargo.toml @@ -16,7 +16,7 @@ workspace = true qiskit-util = { workspace = true, features = ["py"] } qiskit-quantum-info.workspace = true rayon.workspace = true -ahash.workspace = true +foldhash.workspace = true rustworkx-core.workspace = true bytemuck = {workspace = true, features = ["derive"]} bitfield-struct.workspace = true @@ -32,6 +32,7 @@ nom-unicode.workspace = true nom-language.workspace = true crossterm = "0.29.0" unicode-width = "0.2" +ahash = "0.8.12" unicode-segmentation = "1.13" lexical-core = "1.0.6" lexical-write-float = "1.0.6" @@ -52,10 +53,6 @@ features = ["rayon", "approx"] workspace = true features = ["rayon"] -[dependencies.indexmap] -workspace = true -features = ["rayon"] - [dependencies.smallvec] workspace = true features = ["union", "const_generics"] diff --git a/crates/circuit/src/bit_locator.rs b/crates/circuit/src/bit_locator.rs index 3b4d9f8ed16b..355bcd149bd2 100644 --- a/crates/circuit/src/bit_locator.rs +++ b/crates/circuit/src/bit_locator.rs @@ -13,15 +13,15 @@ use std::{fmt::Debug, hash::Hash, sync::OnceLock}; use crate::bit::{BitLocations, Register}; -use indexmap::IndexMap; use pyo3::prelude::*; use pyo3::types::{IntoPyDict, PyDict}; +use qiskit_util::IndexMap; /// Structure that keeps a mapping of bits and their locations within /// the circuit. #[derive(Debug)] pub struct BitLocator { - bit_locations: IndexMap, ::ahash::RandomState>, + bit_locations: IndexMap>, cached: OnceLock>, } diff --git a/crates/circuit/src/circuit_data.rs b/crates/circuit/src/circuit_data.rs index a27a7f85fb3a..8d60ecaa4e70 100644 --- a/crates/circuit/src/circuit_data.rs +++ b/crates/circuit/src/circuit_data.rs @@ -56,7 +56,7 @@ use pyo3::types::{IntoPyDict, PyDict, PyList, PySet, PyTuple, PyType}; use pyo3::{PyTraverseError, PyVisit, import_exception, intern}; use hashbrown::{HashMap, HashSet}; -use indexmap::IndexMap; +use qiskit_util::IndexMap; use smallvec::SmallVec; use thiserror::Error; @@ -1751,8 +1751,8 @@ impl CircuitData { /// /// # Returns /// An IndexMap containing the operation names as keys and their respective counts as values. - pub fn count_ops(&self) -> IndexMap<&str, usize, ::ahash::RandomState> { - let mut ops_count: IndexMap<&str, usize, ::ahash::RandomState> = IndexMap::default(); + pub fn count_ops(&self) -> IndexMap<&str, usize> { + let mut ops_count: IndexMap<&str, usize> = IndexMap::default(); for instruction in &self.data { *ops_count.entry(instruction.op.name()).or_insert(0) += 1; } @@ -2897,7 +2897,7 @@ impl PyCircuitData { /// /// # Returns /// An IndexMap containing the operation names as keys and their respective counts as values. - pub fn count_ops(&self) -> IndexMap<&str, usize, ::ahash::RandomState> { + pub fn count_ops(&self) -> IndexMap<&str, usize> { self.inner.count_ops() } diff --git a/crates/circuit/src/dag_circuit.rs b/crates/circuit/src/dag_circuit.rs index 900a2ac99cbf..4ad5ca011a88 100644 --- a/crates/circuit/src/dag_circuit.rs +++ b/crates/circuit/src/dag_circuit.rs @@ -14,7 +14,7 @@ use std::cmp::Ordering; use std::hash::Hash; use std::sync::Arc; -use ahash::RandomState; +use foldhash::fast::RandomState; use smallvec::SmallVec; use crate::bit::{ @@ -48,8 +48,8 @@ use crate::{ use qiskit_util::py::{PySequenceIndex, SequenceIndex}; use hashbrown::{HashMap, HashSet}; -use indexmap::{IndexMap, IndexSet}; use itertools::{EitherOrBoth, Itertools}; +use qiskit_util::{IndexMap, IndexSet}; use pyo3::IntoPyObjectExt; use pyo3::exceptions::{ @@ -248,7 +248,7 @@ pub struct DAGCircuit { var_io_map: Vec<[NodeIndex; 2]>, /// Operation kind to count - op_names: IndexMap, + op_names: IndexMap, } #[derive(Clone, Debug)] @@ -668,18 +668,18 @@ impl DAGCircuit { let dict_state = state.cast_bound::(py)?; self.name = dict_state.get_item("name")?.unwrap().extract()?; self.metadata = dict_state.get_item("metadata")?.unwrap().extract()?; - self.qregs = - RegisterData::from_mapping(dict_state.get_item("qregs")?.unwrap().extract::>()?); - self.cregs = - RegisterData::from_mapping(dict_state.get_item("cregs")?.unwrap().extract::>()?); + self.qregs = RegisterData::from_mapping( + dict_state + .get_item("qregs")? + .unwrap() + .extract::>()?, + ); + self.cregs = RegisterData::from_mapping( + dict_state + .get_item("cregs")? + .unwrap() + .extract::>()?, + ); self.global_phase = dict_state.get_item("global_phase")?.unwrap().extract()?; self.op_names = dict_state.get_item("op_name")?.unwrap().extract()?; let binding = dict_state.get_item("qubits")?.unwrap(); @@ -5806,7 +5806,7 @@ impl DAGCircuit { }; // Put the new node in-between the previously "last" nodes on each wire // and the terminal map. - let termini: IndexSet = self + let termini: IndexSet = self .qargs_interner .get(qubits_id) .iter() @@ -5862,7 +5862,7 @@ impl DAGCircuit { ) -> PyResult<(Vec, Option>)> { let (all_clbits, vars): (Vec, Option>) = { if self.may_have_additional_wires(instr) { - let mut clbits: IndexSet = + let mut clbits: IndexSet = IndexSet::from_iter(self.cargs_interner.get(instr.clbits).iter().copied()); let (additional_clbits, additional_vars) = Python::attach(|py| self.additional_wires(py, instr))?; @@ -6607,7 +6607,7 @@ impl DAGCircuit { clbit_map: Option<&HashMap>, var_map: Option<&HashMap>, block_map: Option<&HashMap>, - ) -> PyResult> { + ) -> PyResult> { if self.dag.node_weight(node_index).is_none() { return Err(PyIndexError::new_err(format!( "Specified node {} is not in this graph", @@ -6776,7 +6776,7 @@ impl DAGCircuit { clbit_map: &HashMap, var_map: &HashMap, block_map: &HashMap, - ) -> PyResult> { + ) -> PyResult> { if self.dag.node_weight(node).is_none() { return Err(PyIndexError::new_err(format!( "Specified node {} is not in this graph", @@ -6866,7 +6866,7 @@ impl DAGCircuit { let reverse_var_map: HashMap<&expr::Var, &expr::Var> = var_map.iter().map(|(x, y)| (y, x)).collect(); // Copy nodes from other to self - let mut out_map: IndexMap = + let mut out_map: IndexMap = IndexMap::with_capacity_and_hasher(other.dag.node_count(), RandomState::default()); for old_index in other.dag.node_indices() { if !node_filter(old_index) { @@ -7323,14 +7323,11 @@ impl DAGCircuit { /// Args: /// py: The python token necessary for control flow recursion /// recurse: Whether to recurse into control flow ops or not - pub fn count_ops(&self, recurse: bool) -> PyResult> { + pub fn count_ops(&self, recurse: bool) -> PyResult> { if !recurse || !self.has_control_flow() { Ok(self.op_names.clone()) } else { - fn inner( - dag: &DAGCircuit, - counts: &mut IndexMap, - ) -> PyResult<()> { + fn inner(dag: &DAGCircuit, counts: &mut IndexMap) -> PyResult<()> { for (key, value) in dag.op_names.iter() { counts .entry(key.clone()) @@ -7360,7 +7357,7 @@ impl DAGCircuit { /// and it returns a reference instead of an owned copy. If you don't need to work with /// control flow or ownership of the counts this is a more efficient alternative to /// `DAGCircuit::count_ops(py, false)` - pub fn get_op_counts(&self) -> &IndexMap { + pub fn get_op_counts(&self) -> &IndexMap { &self.op_names } @@ -8429,7 +8426,7 @@ pub(crate) fn add_global_phase(phase: &Param, other: &Param) -> Param { /// is separate to allow safe borrow checking of instructions that are in-place in the DAG. fn track_instruction( inst: &PackedInstruction, - op_names: &mut IndexMap, + op_names: &mut IndexMap, blocks: &mut ControlFlowBlocks, ) { let name = inst.op.name(); @@ -8451,7 +8448,7 @@ fn track_instruction( /// is separate to allow safe borrow checking of instructions that are in-place in the DAG. fn untrack_instruction( inst: &PackedInstruction, - op_names: &mut IndexMap, + op_names: &mut IndexMap, blocks: &mut ControlFlowBlocks, ) { let name = inst.op.name(); diff --git a/crates/circuit/src/interner.rs b/crates/circuit/src/interner.rs index d89cac89a5a7..befe822c25bf 100644 --- a/crates/circuit/src/interner.rs +++ b/crates/circuit/src/interner.rs @@ -15,7 +15,7 @@ use std::fmt; use std::hash::Hash; use std::marker::PhantomData; -use indexmap::IndexSet; +use qiskit_util::IndexSet; use smallvec::SmallVec; /// A key to retrieve a value (by reference) from an interner of the same type. This is narrower @@ -207,7 +207,7 @@ mod interned_map { /// assert_eq!(interner.get(key), &[0, 1, 2, 3, 4]); /// ``` #[derive(Default)] -pub struct Interner(IndexSet<::Owned, ::ahash::RandomState>); +pub struct Interner(IndexSet<::Owned>); // `Clone` and `Debug` can't use the derivation mechanism because the values that are actually // stored are of type `::Owned`, which the derive system doesn't reason about. @@ -286,7 +286,8 @@ where /// Note that the default item of the interner is always allocated and given a key immediately, /// which will use one slot of the capacity. pub fn with_capacity(capacity: usize) -> Self { - let mut set = IndexSet::with_capacity_and_hasher(capacity, ::ahash::RandomState::new()); + let mut set = + IndexSet::with_capacity_and_hasher(capacity, ::foldhash::fast::RandomState::default()); set.insert(Default::default()); Self(set) } diff --git a/crates/circuit/src/parameter/parameter_expression.rs b/crates/circuit/src/parameter/parameter_expression.rs index dc01114318c0..7f3aeea51f2b 100644 --- a/crates/circuit/src/parameter/parameter_expression.rs +++ b/crates/circuit/src/parameter/parameter_expression.rs @@ -12,10 +12,10 @@ use hashbrown::hash_map::Entry; use hashbrown::{HashMap, HashSet}; -use indexmap::IndexSet; use num_complex::Complex64; use pyo3::exceptions::{PyRuntimeError, PyTypeError, PyValueError, PyZeroDivisionError}; use pyo3::types::{IntoPyDict, PyComplex, PyFloat, PyInt, PyNotImplemented, PySet, PyString}; +use qiskit_util::IndexSet; use std::sync::Arc; use thiserror::Error; use uuid::Uuid; @@ -135,7 +135,7 @@ impl fmt::Display for ParameterExpression { impl ParameterExpression { pub fn qpy_replay(&self) -> Vec { let mut replay = Vec::new(); - let mut unused: IndexSet<_, ahash::RandomState> = self.name_map.values().cloned().collect(); + let mut unused: IndexSet<_> = self.name_map.values().cloned().collect(); // The recursive inner `qpy_replay_inner` assumes it starts from a containing operation, so // fails to build a complete replay in the case it starts from a single symbol or value. match &self.expr { @@ -2077,7 +2077,7 @@ fn qpy_replay_inner( expr: &ParameterExpression, name_map: &HashMap, replay: &mut Vec, - unused: &mut IndexSet, + unused: &mut IndexSet, ) { match &expr.expr { // This function is written under the assumption that the top-level expression involves an diff --git a/crates/circuit/src/var_stretch_container.rs b/crates/circuit/src/var_stretch_container.rs index b80eb2fb3245..f6178e4f0686 100644 --- a/crates/circuit/src/var_stretch_container.rs +++ b/crates/circuit/src/var_stretch_container.rs @@ -13,7 +13,7 @@ use crate::classical::expr; use crate::object_registry::ObjectRegistry; use crate::{Stretch, Var}; -use indexmap::IndexMap; +use qiskit_util::IndexMap; use thiserror::Error; use pyo3::exceptions::PyValueError; @@ -103,7 +103,10 @@ impl VarStretchContainer { VarStretchContainer { vars: ObjectRegistry::with_capacity(num_vars), stretches: ObjectRegistry::with_capacity(num_stretches), - identifier_info: IndexMap::with_capacity(num_vars + num_stretches), + identifier_info: IndexMap::with_capacity_and_hasher( + num_vars + num_stretches, + foldhash::fast::RandomState::default(), + ), var_indices: [Vec::new(), Vec::new(), Vec::new()], stretch_indices: [Vec::new(), Vec::new()], } @@ -114,7 +117,10 @@ impl VarStretchContainer { let mut res = VarStretchContainer { vars: ObjectRegistry::with_capacity(self.vars.len()), stretches: ObjectRegistry::with_capacity(self.stretches.len()), - identifier_info: IndexMap::with_capacity(self.identifier_info.len()), + identifier_info: IndexMap::with_capacity_and_hasher( + self.identifier_info.len(), + foldhash::fast::RandomState::default(), + ), var_indices: [Vec::new(), Vec::with_capacity(self.vars.len()), Vec::new()], stretch_indices: [Vec::with_capacity(self.stretches.len()), Vec::new()], }; diff --git a/crates/circuit/src/vf2.rs b/crates/circuit/src/vf2.rs index 752b6f1635ac..5b261302d4c4 100644 --- a/crates/circuit/src/vf2.rs +++ b/crates/circuit/src/vf2.rs @@ -28,7 +28,7 @@ use std::marker; use std::num::NonZero; use hashbrown::{HashMap, hash_map::Entry}; -use indexmap::IndexMap; +use qiskit_util::IndexMap; use smallvec::SmallVec; use rustworkx_core::petgraph::data::Create; @@ -896,10 +896,7 @@ where ES: Semantics, { type Item = Result< - ( - IndexMap, - NS::Score, - ), + (IndexMap, NS::Score), IsIsomorphicError, >; type IntoIter = Vf2IntoIter; @@ -1250,7 +1247,7 @@ where NS: Semantics, ES: Semantics, { - fn mapping(&self) -> IndexMap { + fn mapping(&self) -> IndexMap { self.needle .mapping .iter() @@ -1823,10 +1820,7 @@ where NS: Semantics, ES: Semantics, { - type Item = Result< - (IndexMap, NS::Score), - IsIsomorphicError, - >; + type Item = Result<(IndexMap, NS::Score), IsIsomorphicError>; fn next(&mut self) -> Option { // The overall strategy is a nested loop, where the "outer" loop is over unmapped nodes in diff --git a/crates/qasm3/Cargo.toml b/crates/qasm3/Cargo.toml index 60f2bb0961c2..e274636dec89 100644 --- a/crates/qasm3/Cargo.toml +++ b/crates/qasm3/Cargo.toml @@ -13,12 +13,12 @@ doctest = false workspace = true [dependencies] -indexmap.workspace = true +qiskit-util.workspace = true hashbrown.workspace = true oq3_semantics = "0.7.0" oq3_syntax = "0.7.0" qiskit-circuit.workspace = true -ahash.workspace = true +foldhash.workspace = true regex = "1.12" lazy_static = "1.5" thiserror.workspace = true diff --git a/crates/qasm3/src/build.rs b/crates/qasm3/src/build.rs index 845a4ee25b6e..cd35ed10c6f1 100644 --- a/crates/qasm3/src/build.rs +++ b/crates/qasm3/src/build.rs @@ -13,10 +13,10 @@ use pyo3::prelude::*; use pyo3::types::{PySequence, PyTuple}; -use ahash::RandomState; +use foldhash::fast::RandomState; use hashbrown::HashMap; -use indexmap::IndexMap; +use qiskit_util::IndexMap; use oq3_semantics::asg; use oq3_semantics::symbols::{SymbolId, SymbolTable, SymbolType}; @@ -191,10 +191,11 @@ 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, RandomState>::with_capacity_and_hasher( - asg_qubits.len(), - RandomState::default() - ); + let mut qubits = + IndexMap::<*const ::pyo3::ffi::PyObject, Py>::with_capacity_and_hasher( + asg_qubits.len(), + RandomState::default(), + ); for qarg in asg_qubits.iter() { let qarg = expr::expect_gate_operand(qarg)?; match expr::eval_qarg(py, &self.symbols, ast_symbols, qarg)? { diff --git a/crates/qasm3/src/exporter.rs b/crates/qasm3/src/exporter.rs index 83393ed87cc3..fc9eaa5925b9 100644 --- a/crates/qasm3/src/exporter.rs +++ b/crates/qasm3/src/exporter.rs @@ -24,7 +24,6 @@ use std::io::Write; use crate::printer::BasicPrinter; use hashbrown::{HashMap, HashSet}; -use indexmap::IndexMap; use pyo3::Python; use pyo3::prelude::*; use qiskit_circuit::bit::{ @@ -36,6 +35,7 @@ use qiskit_circuit::operations::{Operation, Param}; use qiskit_circuit::packed_instruction::PackedInstruction; use qiskit_circuit::parameter::parameter_expression::ParameterExpression; use qiskit_circuit::parameter::symbol_expr; +use qiskit_util::IndexMap; use thiserror::Error; use lazy_static::lazy_static; @@ -263,7 +263,7 @@ impl SymbolTable { symbols, bitinfo, reginfo, - gates: IndexMap::new(), + gates: IndexMap::default(), stdgates: HashSet::new(), _counter: Counter::new(), } diff --git a/crates/qpy/Cargo.toml b/crates/qpy/Cargo.toml index 9f197498ce75..3d4d025a5366 100644 --- a/crates/qpy/Cargo.toml +++ b/crates/qpy/Cargo.toml @@ -13,10 +13,9 @@ doctest = false workspace = true [dependencies] -indexmap.workspace = true +qiskit-util.workspace = true hashbrown.workspace = true oq3_semantics = "0.7.0" -ahash.workspace = true qiskit-circuit.workspace = true qiskit-quantum-info.workspace = true num-bigint.workspace = true diff --git a/crates/qpy/src/circuit_writer.rs b/crates/qpy/src/circuit_writer.rs index 2a941492ad26..9ee40fa02ffa 100644 --- a/crates/qpy/src/circuit_writer.rs +++ b/crates/qpy/src/circuit_writer.rs @@ -20,10 +20,10 @@ // `write` method into a `Cursor` buffer, but there might be exceptions. use binrw::Endian; use hashbrown::{HashMap, HashSet}; -use indexmap::IndexSet; use num_bigint::BigUint; use num_traits::ToPrimitive; use numpy::ToPyArray; +use qiskit_util::IndexSet; use pyo3::prelude::*; use pyo3::types::{PyAny, PyDict, PyTuple}; @@ -674,7 +674,7 @@ fn pack_quantum_registers(circuit_data: &CircuitData) -> Vec = // circuit_data.qregs().iter().cloned().collect(); let mut in_circ_lookup: HashSet = HashSet::new(); - let mut registers_to_pack: IndexSet = IndexSet::new(); + let mut registers_to_pack: IndexSet = IndexSet::default(); circuit_data.qregs().iter().for_each(|qreg| { in_circ_lookup.insert(qreg.clone()); registers_to_pack.insert(qreg.clone()); diff --git a/crates/quantum_info/Cargo.toml b/crates/quantum_info/Cargo.toml index 7fb5daa34a08..08251dd8e066 100644 --- a/crates/quantum_info/Cargo.toml +++ b/crates/quantum_info/Cargo.toml @@ -20,7 +20,7 @@ rustworkx-core.workspace = true thiserror.workspace = true rayon.workspace = true bytemuck.workspace = true -ahash.workspace = true +foldhash.workspace = true ndarray-einsum = "0.8.0" rand.workspace = true rand_pcg.workspace = true @@ -39,10 +39,6 @@ features = ["num-complex"] workspace = true features = ["rayon"] -[dependencies.indexmap] -workspace = true -features = ["rayon"] - [dependencies.pyo3] workspace = true features = ["hashbrown", "indexmap", "num-complex", "num-bigint", "smallvec"] diff --git a/crates/quantum_info/src/sparse_observable/mod.rs b/crates/quantum_info/src/sparse_observable/mod.rs index 4c890867e61b..1eff9e5ea72e 100644 --- a/crates/quantum_info/src/sparse_observable/mod.rs +++ b/crates/quantum_info/src/sparse_observable/mod.rs @@ -13,7 +13,6 @@ mod lookup; use hashbrown::HashSet; -use indexmap::IndexSet; use itertools::Itertools; use lookup::conjugate_bitterm; use ndarray::Array2; @@ -31,6 +30,7 @@ use pyo3::{ sync::PyOnceLock, types::{IntoPyDict, PyList, PyString, PyTuple, PyType}, }; +use qiskit_util::IndexSet; use std::{ cmp::Ordering, collections::btree_map, @@ -3662,7 +3662,7 @@ impl PySparseObservable { let order = order .try_iter()? .map(|obj| obj.and_then(|obj| obj.extract::())) - .collect::>>()?; + .collect::>>()?; if order.len() != in_length { return Err(PyValueError::new_err("duplicate indices in qargs")); } diff --git a/crates/quantum_info/src/sparse_pauli_op.rs b/crates/quantum_info/src/sparse_pauli_op.rs index 38b8e5675a0b..8f6d91fe94cf 100644 --- a/crates/quantum_info/src/sparse_pauli_op.rs +++ b/crates/quantum_info/src/sparse_pauli_op.rs @@ -10,7 +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 foldhash::fast::RandomState; use pyo3::Python; use pyo3::exceptions::{PyRuntimeError, PyValueError}; use pyo3::prelude::*; @@ -21,10 +21,10 @@ use numpy::prelude::*; use numpy::{PyArray1, PyArray2, PyReadonlyArray1, PyReadonlyArray2, PyUntypedArrayMethods}; use hashbrown::HashMap; -use indexmap::IndexMap; use ndarray::{Array2, ArrayView1, ArrayView2, Axis, s}; use num_complex::Complex64; use num_traits::Zero; +use qiskit_util::IndexMap; use rayon::prelude::*; use thiserror::Error; @@ -334,11 +334,10 @@ impl MatrixCompressedPaulis { /// explicitly stored operations, if there are duplicates. After the summation, any terms that /// have become zero are dropped. pub fn combine(&mut self) { - let mut hash_table = - IndexMap::<(u64, u64), Complex64, RandomState>::with_capacity_and_hasher( - self.coeffs.len(), - RandomState::new(), - ); + let mut hash_table = IndexMap::<(u64, u64), Complex64>::with_capacity_and_hasher( + self.coeffs.len(), + RandomState::default(), + ); for (key, coeff) in self .x_like .drain(..) diff --git a/crates/synthesis/Cargo.toml b/crates/synthesis/Cargo.toml index 6d23106f070e..cc34ba873720 100644 --- a/crates/synthesis/Cargo.toml +++ b/crates/synthesis/Cargo.toml @@ -19,7 +19,6 @@ qiskit-util.workspace = true bytemuck.workspace = true num-complex.workspace = true nalgebra.workspace = true -ahash.workspace = true itertools.workspace = true numpy.workspace = true rayon.workspace = true @@ -56,10 +55,6 @@ features = ["num-complex"] workspace = true features = ["rayon", "serde"] -[dependencies.indexmap] -workspace = true -features = ["rayon"] - [dev-dependencies] pyo3 = { workspace = true, features = ["auto-initialize"] } diff --git a/crates/synthesis/src/clifford/greedy_synthesis.rs b/crates/synthesis/src/clifford/greedy_synthesis.rs index 40e43946f1cf..68e9905e6a57 100644 --- a/crates/synthesis/src/clifford/greedy_synthesis.rs +++ b/crates/synthesis/src/clifford/greedy_synthesis.rs @@ -10,9 +10,8 @@ // 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::{Array2, ArrayView2, s}; +use qiskit_util::IndexSet; use smallvec::smallvec; use crate::clifford::utils::{ @@ -105,7 +104,7 @@ pub struct GreedyCliffordSynthesis<'a> { symplectic_matrix: SymplecticMatrix, /// Unprocessed qubits. - unprocessed_qubits: IndexSet, + unprocessed_qubits: IndexSet, } impl GreedyCliffordSynthesis<'_> { @@ -198,10 +197,10 @@ impl GreedyCliffordSynthesis<'_> { gate_seq: &mut CliffordGatesVec, min_qubit: usize, ) -> Result<(), String> { - let mut a_qubits: IndexSet<_, ::ahash::RandomState> = IndexSet::default(); - let mut b_qubits: IndexSet<_, ::ahash::RandomState> = IndexSet::default(); - let mut c_qubits: IndexSet<_, ::ahash::RandomState> = IndexSet::default(); - let mut d_qubits: IndexSet<_, ::ahash::RandomState> = IndexSet::default(); + let mut a_qubits: IndexSet<_> = IndexSet::default(); + let mut b_qubits: IndexSet<_> = IndexSet::default(); + let mut c_qubits: IndexSet<_> = IndexSet::default(); + let mut d_qubits: IndexSet<_> = IndexSet::default(); for qubit in &self.unprocessed_qubits { let pauli_pair_index = pauli_pair_to_index( diff --git a/crates/synthesis/src/evolution/suzuki_trotter.rs b/crates/synthesis/src/evolution/suzuki_trotter.rs index 0c49d412dcdf..2b1c7a7a7350 100644 --- a/crates/synthesis/src/evolution/suzuki_trotter.rs +++ b/crates/synthesis/src/evolution/suzuki_trotter.rs @@ -11,9 +11,9 @@ // that they have been altered from the originals. use hashbrown::HashSet; -use indexmap::IndexMap; use itertools::Itertools; use qiskit_quantum_info::sparse_observable::SparseTermView; +use qiskit_util::IndexMap; use rustworkx_core::coloring::{ColoringStrategy, greedy_node_color_with_coloring_strategy}; use rustworkx_core::petgraph::graph::NodeIndex; use rustworkx_core::petgraph::{Graph, Undirected}; @@ -82,7 +82,7 @@ pub fn reorder_terms<'a>( let callback = |_: NodeIndex| -> Result, Infallible> { Ok(None) }; match greedy_node_color_with_coloring_strategy(&graph, callback, ColoringStrategy::Saturation) { Ok(colors) => { - let mut colors_map: IndexMap> = IndexMap::new(); + let mut colors_map: IndexMap> = IndexMap::default(); for (node_index, color) in colors.iter().sorted() { if !colors_map.contains_key(color) { diff --git a/crates/transpiler/Cargo.toml b/crates/transpiler/Cargo.toml index 6221abb5f06b..696f46d7cc43 100644 --- a/crates/transpiler/Cargo.toml +++ b/crates/transpiler/Cargo.toml @@ -16,7 +16,7 @@ workspace = true rayon.workspace = true rayon-cond = "0.4.0" numpy.workspace = true -ahash.workspace = true +foldhash.workspace = true itertools.workspace = true nalgebra.workspace = true rand.workspace = true diff --git a/crates/transpiler/src/equivalence.rs b/crates/transpiler/src/equivalence.rs index 7d06fba5d5ca..88d187bf97fd 100644 --- a/crates/transpiler/src/equivalence.rs +++ b/crates/transpiler/src/equivalence.rs @@ -27,10 +27,9 @@ use std::{error::Error, fmt::Display}; use exceptions::CircuitError; -use ahash::RandomState; -use indexmap::{IndexMap, IndexSet}; use pyo3::prelude::*; use pyo3::types::{PyDict, PyList, PyString}; +use qiskit_util::{IndexMap, IndexSet}; use rustworkx_core::petgraph::{ graph::{EdgeIndex, NodeIndex}, @@ -371,7 +370,7 @@ impl<'a, 'py> FromPyObject<'a, 'py> for CircuitFromPython { // Custom Types type GraphType = StableDiGraph>; -type KTIType = IndexMap; +type KTIType = IndexMap; /// A library providing a one-way mapping of gates to their equivalent /// implementations as :class:`.QuantumCircuit` instances. @@ -612,7 +611,7 @@ impl EquivalenceLibrary { slf.key_to_node_index = state .get_item("key_to_node_index")? .unwrap() - .extract::>()? + .extract::>()? .into_iter() .map(|(key, val)| (key, NodeIndex::new(val))) .collect(); @@ -644,7 +643,7 @@ impl EquivalenceLibrary { if let Some(node) = self.graph.node_weight_mut(target) { node.equivs.push(equiv.clone()); } - let sources: IndexSet = IndexSet::from_iter( + let sources: IndexSet = IndexSet::from_iter( equivalent_circuit .iter() .map(|inst| Key::from_operation(&inst.op)), @@ -793,23 +792,22 @@ fn raise_if_shape_mismatch( fn rebind_equiv(equiv: Equivalence, query_params: &[Param]) -> PyResult { let (equiv_params, mut equiv_circuit) = (equiv.params, equiv.circuit); - let param_mapping: PyResult> = - equiv_params - .iter() - .zip(query_params.iter()) - .filter_map(|(param_x, param_y)| match param_x { - Param::ParameterExpression(param) => { - // we know this expression represents a symbol - let symbol = match param.try_to_symbol() { - Ok(symbol) => symbol, - Err(e) => return Some(Err(PyErr::from(e))), - }; - let uuid = ParameterUuid::from_symbol(&symbol); - Some(Ok((uuid, param_y))) - } - _ => None, - }) - .collect(); + let param_mapping: PyResult> = equiv_params + .iter() + .zip(query_params.iter()) + .filter_map(|(param_x, param_y)| match param_x { + Param::ParameterExpression(param) => { + // we know this expression represents a symbol + let symbol = match param.try_to_symbol() { + Ok(symbol) => symbol, + Err(e) => return Some(Err(PyErr::from(e))), + }; + let uuid = ParameterUuid::from_symbol(&symbol); + Some(Ok((uuid, param_y))) + } + _ => None, + }) + .collect(); equiv_circuit.assign_parameters_from_mapping(param_mapping?)?; Ok(equiv_circuit) } diff --git a/crates/transpiler/src/passes/basis_translator/basis_search.rs b/crates/transpiler/src/passes/basis_translator/basis_search.rs index c1053d6c1907..d3dea8bb1018 100644 --- a/crates/transpiler/src/passes/basis_translator/basis_search.rs +++ b/crates/transpiler/src/passes/basis_translator/basis_search.rs @@ -12,7 +12,7 @@ use std::cell::RefCell; -use indexmap::{IndexMap, IndexSet}; +use qiskit_util::{IndexMap, IndexSet}; use crate::equivalence::{EdgeData, Equivalence, EquivalenceLibrary, Key, NodeData}; use qiskit_circuit::operations::Operation; @@ -33,22 +33,20 @@ type BasisTransforms = Vec<(GateIdentifier, BasisTransformIn)>; /// basis` are reached. pub(crate) fn basis_search( equiv_lib: &mut EquivalenceLibrary, - source_basis: &IndexSet, - target_basis: &IndexSet<&str, ahash::RandomState>, + source_basis: &IndexSet, + target_basis: &IndexSet<&str>, ) -> Option { // Build the visitor attributes: - let mut num_gates_remaining_for_rule: IndexMap = - IndexMap::default(); - let predecessors: RefCell> = - RefCell::new(IndexMap::default()); - let opt_cost_map: RefCell> = + let mut num_gates_remaining_for_rule: IndexMap = IndexMap::default(); + let predecessors: RefCell> = RefCell::new(IndexMap::default()); + let opt_cost_map: RefCell> = RefCell::new(IndexMap::default()); let mut basis_transforms: Vec<(GateIdentifier, BasisTransformIn)> = vec![]; // Initialize visitor attributes: initialize_num_gates_remain_for_rule(equiv_lib.graph(), &mut num_gates_remaining_for_rule); - let mut source_basis_remain: IndexSet = source_basis + let mut source_basis_remain: IndexSet = source_basis .iter() .filter_map(|(gate_name, gate_num_qubits)| { if !target_basis.contains(gate_name.as_str()) { @@ -180,7 +178,7 @@ pub(crate) fn basis_search( fn initialize_num_gates_remain_for_rule( graph: &StableDiGraph>, - source: &mut IndexMap, + source: &mut IndexMap, ) { let mut save_index = usize::MAX; // When iterating over the edges, ignore any none-valued ones by calling `flatten` diff --git a/crates/transpiler/src/passes/basis_translator/compose_transforms.rs b/crates/transpiler/src/passes/basis_translator/compose_transforms.rs index d2cbdf0c9a84..23608dc38dab 100644 --- a/crates/transpiler/src/passes/basis_translator/compose_transforms.rs +++ b/crates/transpiler/src/passes/basis_translator/compose_transforms.rs @@ -12,7 +12,6 @@ use super::errors::BasisTranslatorError; use hashbrown::HashMap; -use indexmap::{IndexMap, IndexSet}; use pyo3::prelude::*; use qiskit_circuit::bit::QuantumRegister; use qiskit_circuit::circuit_data::CircuitData; @@ -29,6 +28,7 @@ use qiskit_circuit::{ dag_circuit::DAGCircuit, operations::{Operation, Param}, }; +use qiskit_util::{IndexMap, IndexSet}; use smallvec::SmallVec; use std::sync::OnceLock; @@ -42,14 +42,12 @@ static STD_INST_SET: [&str; 4] = ["barrier", "delay", "measure", "reset"]; pub(super) fn compose_transforms<'a>( basis_transforms: &'a [(GateIdentifier, BasisTransformIn)], - source_basis: &'a IndexSet, + source_basis: &'a IndexSet, source_dag: &'a DAGCircuit, -) -> Result, BasisTranslatorError> { - let mut gate_param_counts: IndexMap = - IndexMap::default(); +) -> Result, BasisTranslatorError> { + let mut gate_param_counts: IndexMap = IndexMap::default(); get_gates_num_params(source_dag, &mut gate_param_counts); - let mut mapped_instructions: IndexMap = - IndexMap::with_hasher(ahash::RandomState::default()); + let mut mapped_instructions: IndexMap = IndexMap::default(); for (gate_name, gate_num_qubits) in source_basis.iter().cloned() { let num_params = gate_param_counts[&(gate_name.clone(), gate_num_qubits)]; @@ -118,18 +116,17 @@ pub(super) fn compose_transforms<'a>( }) .collect::>(); for (node, params) in nodes_to_replace { - let param_mapping: IndexMap = - equiv_params - .iter() - .map(|x| match x { - Param::ParameterExpression(parameter_expression) => { - let symbol = parameter_expression.try_to_symbol().unwrap(); - ParameterUuid::from_symbol(&symbol) - } - _ => unreachable!("A non parameter-expression has snuck in"), - }) - .zip(params) - .collect(); + let param_mapping: IndexMap = equiv_params + .iter() + .map(|x| match x { + Param::ParameterExpression(parameter_expression) => { + let symbol = parameter_expression.try_to_symbol().unwrap(); + ParameterUuid::from_symbol(&symbol) + } + _ => unreachable!("A non parameter-expression has snuck in"), + }) + .zip(params) + .collect(); let mut replacement = equiv.clone(); replacement .assign_parameters_from_mapping(param_mapping) @@ -188,10 +185,7 @@ fn name_to_packed_operation(name: &str, num_qubits: u32) -> Option, -) { +fn get_gates_num_params(dag: &DAGCircuit, example_gates: &mut IndexMap) { for (_, inst) in dag.op_nodes(true) { if let Some(control_flow) = dag.try_view_control_flow(inst) { example_gates.insert( diff --git a/crates/transpiler/src/passes/basis_translator/mod.rs b/crates/transpiler/src/passes/basis_translator/mod.rs index 0d056b657fb7..2fecd74991c5 100644 --- a/crates/transpiler/src/passes/basis_translator/mod.rs +++ b/crates/transpiler/src/passes/basis_translator/mod.rs @@ -18,8 +18,8 @@ use basis_search::basis_search; use compose_transforms::compose_transforms; use errors::BasisTranslatorError; use hashbrown::{HashMap, HashSet}; -use indexmap::{IndexMap, IndexSet}; use pyo3::prelude::*; +use qiskit_util::{IndexMap, IndexSet}; mod basis_search; mod compose_transforms; @@ -46,8 +46,8 @@ use crate::target::Qargs; use crate::target::QargsRef; use crate::target::Target; -type AhashIndexMap = IndexMap; -type AhashIndexSet = IndexSet; +type AhashIndexMap = IndexMap; +type AhashIndexSet = IndexSet; type InstMap = AhashIndexMap; type ExtraInstructionMap<'a> = AhashIndexMap<&'a PhysicalQargs, InstMap>; type PhysicalQargs = SmallVec<[PhysicalQubit; 2]>; diff --git a/crates/transpiler/src/passes/commutation_analysis.rs b/crates/transpiler/src/passes/commutation_analysis.rs index beb0d7818869..9a8c46ba2838 100644 --- a/crates/transpiler/src/passes/commutation_analysis.rs +++ b/crates/transpiler/src/passes/commutation_analysis.rs @@ -16,7 +16,7 @@ use pyo3::prelude::*; use pyo3::types::{PyDict, PyList}; use pyo3::{Bound, PyResult, Python, pyfunction, wrap_pyfunction}; -use indexmap::IndexMap; +use qiskit_util::IndexMap; use rustworkx_core::petgraph::stable_graph::NodeIndex; use crate::commutation_checker::CommutationChecker; @@ -25,8 +25,8 @@ use qiskit_circuit::dag_circuit::{DAGCircuit, NodeType, Wire}; // Custom types to store the commutation sets and node indices, // see the docstring below for more information. -type CommutationSet = IndexMap>, ::ahash::RandomState>; -type NodeIndices = IndexMap<(NodeIndex, Wire), usize, ::ahash::RandomState>; +type CommutationSet = IndexMap>>; +type NodeIndices = IndexMap<(NodeIndex, Wire), usize>; // the maximum number of qubits we check commutativity for const MAX_NUM_QUBITS: u32 = 3; diff --git a/crates/transpiler/src/passes/commutation_cancellation.rs b/crates/transpiler/src/passes/commutation_cancellation.rs index 670d14a4f4ee..10fe22411f52 100644 --- a/crates/transpiler/src/passes/commutation_cancellation.rs +++ b/crates/transpiler/src/passes/commutation_cancellation.rs @@ -16,7 +16,7 @@ use pyo3::exceptions::PyRuntimeError; use pyo3::prelude::*; use pyo3::{Bound, PyResult, pyfunction, wrap_pyfunction}; -use indexmap::IndexMap; +use qiskit_util::IndexMap; use smallvec::{SmallVec, smallvec}; use super::analyze_commutations; @@ -125,7 +125,7 @@ pub fn cancel_commutations( */ let (commutation_set, node_indices) = analyze_commutations(dag, commutation_checker, approximation_degree)?; - let mut cancellation_sets = IndexMap::with_hasher(::ahash::RandomState::new()); + let mut cancellation_sets = IndexMap::with_hasher(::foldhash::fast::RandomState::default()); (0..dag.num_qubits() as u32).for_each(|qubit| { let wire = Qubit(qubit); diff --git a/crates/transpiler/src/passes/consolidate_blocks.rs b/crates/transpiler/src/passes/consolidate_blocks.rs index 50c5b6178a9f..1416a24f7c83 100644 --- a/crates/transpiler/src/passes/consolidate_blocks.rs +++ b/crates/transpiler/src/passes/consolidate_blocks.rs @@ -616,7 +616,7 @@ pub fn consolidate_blocks_mod(m: &Bound) -> PyResult<()> { #[cfg(all(test, not(miri)))] mod test_consolidate_blocks { - use indexmap::IndexMap; + use qiskit_util::IndexMap; use qiskit_circuit::{ PhysicalQubit, Qubit, circuit_data::CircuitData, dag_circuit::DAGCircuit, diff --git a/crates/transpiler/src/passes/constrained_reschedule.rs b/crates/transpiler/src/passes/constrained_reschedule.rs index 54bbabafa6bb..c6dd710e5588 100644 --- a/crates/transpiler/src/passes/constrained_reschedule.rs +++ b/crates/transpiler/src/passes/constrained_reschedule.rs @@ -14,8 +14,6 @@ use crate::TranspilerError; use crate::passes::schedule_analysis::{NodeDurations, PyNodeDurations}; use crate::target::Target; use ::hashbrown::HashSet; -use ahash::RandomState; -use indexmap::IndexMap; use pyo3::exceptions::PyValueError; use pyo3::prelude::*; use pyo3::{Bound, PyResult, pyfunction, wrap_pyfunction}; @@ -23,6 +21,7 @@ use qiskit_circuit::PhysicalQubit; use qiskit_circuit::dag_circuit::{DAGCircuit, NodeType}; use qiskit_circuit::operations::Param; use qiskit_circuit::operations::{Operation, OperationRef, StandardInstruction}; +use qiskit_util::IndexMap; use rustworkx_core::petgraph::stable_graph::NodeIndex; /// Returns the immediate successor operation nodes of a given node in the DAG. @@ -63,7 +62,7 @@ fn get_next_gate(dag: &DAGCircuit, node_index: NodeIndex) -> impl Iterator, u64, RandomState>, + node_start_time: &mut IndexMap, u64>, clbit_write_latency: u32, pulse_align: u32, acquire_align: u32, @@ -268,7 +267,7 @@ pub fn py_run_constrained_reschedule( pub fn run_constrained_reschedule( dag: &DAGCircuit, - node_start_time: &mut IndexMap, u64, RandomState>, + node_start_time: &mut IndexMap, u64>, clbit_write_latency: u32, acquire_align: u32, pulse_align: u32, diff --git a/crates/transpiler/src/passes/dense_layout.rs b/crates/transpiler/src/passes/dense_layout.rs index a94c07cde4c5..398a09fa4d11 100644 --- a/crates/transpiler/src/passes/dense_layout.rs +++ b/crates/transpiler/src/passes/dense_layout.rs @@ -11,12 +11,11 @@ // that they have been altered from the originals. #![allow(clippy::too_many_arguments)] -use ahash::RandomState; use hashbrown::{HashMap, HashSet}; -use indexmap::IndexSet; use ndarray::prelude::*; use numpy::IntoPyArray; use numpy::PyReadonlyArray2; +use qiskit_util::IndexSet; use rayon::prelude::*; use pyo3::Python; @@ -35,14 +34,13 @@ struct SubsetResult { fn bfs_sort(adj_matrix: ArrayView2, start: usize, num_qubits: usize) -> Vec { let n = adj_matrix.shape()[0]; - let mut next_level: IndexSet = - IndexSet::with_hasher(RandomState::default()); + let mut next_level: IndexSet = IndexSet::default(); let mut bfs_order = Vec::with_capacity(num_qubits); let mut seen: HashSet = HashSet::with_capacity(n); next_level.insert(start); while !next_level.is_empty() { let this_level = next_level; - next_level = IndexSet::with_hasher(RandomState::default()); + next_level = IndexSet::default(); let mut found: Vec = Vec::new(); for v in this_level { if !seen.contains(&v) { diff --git a/crates/transpiler/src/passes/inverse_cancellation.rs b/crates/transpiler/src/passes/inverse_cancellation.rs index dd5be9068983..09a714e5ea83 100644 --- a/crates/transpiler/src/passes/inverse_cancellation.rs +++ b/crates/transpiler/src/passes/inverse_cancellation.rs @@ -10,10 +10,9 @@ // copyright notice, and modified files need to carry a notice indicating // that they have been altered from the originals. -use ahash::RandomState; use hashbrown::HashSet; -use indexmap::IndexMap; use pyo3::prelude::*; +use qiskit_util::IndexMap; use rustworkx_core::petgraph::stable_graph::NodeIndex; use qiskit_circuit::NoBlocks; @@ -44,7 +43,7 @@ fn gate_eq(gate_a: &PackedInstruction, gate_b: &OperationFromPython) - fn run_on_self_inverse( dag: &mut DAGCircuit, - op_counts: &IndexMap, + op_counts: &IndexMap, self_inverse_gate_names: HashSet, self_inverse_gates: Vec>, ) -> PyResult<()> { @@ -108,7 +107,7 @@ fn run_on_self_inverse( } fn run_on_inverse_pairs( dag: &mut DAGCircuit, - op_counts: &IndexMap, + op_counts: &IndexMap, inverse_gate_names: HashSet, inverse_gates: Vec<[OperationFromPython; 2]>, ) -> PyResult<()> { diff --git a/crates/transpiler/src/passes/sabre/layer.rs b/crates/transpiler/src/passes/sabre/layer.rs index 8b5dd6f4e2d6..6f6257aa9442 100644 --- a/crates/transpiler/src/passes/sabre/layer.rs +++ b/crates/transpiler/src/passes/sabre/layer.rs @@ -10,8 +10,8 @@ // copyright notice, and modified files need to carry a notice indicating // that they have been altered from the originals. -use indexmap::IndexMap; use ndarray::prelude::*; +use qiskit_util::IndexMap; use rustworkx_core::petgraph::prelude::*; use qiskit_circuit::PhysicalQubit; @@ -33,7 +33,7 @@ use super::vec_map::VecMap; #[derive(Clone, Debug)] pub struct Layer { /// Map of the (index to the) node to the qubits it acts on. - nodes: IndexMap, + nodes: IndexMap, /// Map of each qubit to the node that acts on it and the other qubit that node acts on, if this /// qubit is active (otherwise `None`). qubits: VecMap>, @@ -46,7 +46,7 @@ impl Layer { // and can only have one gate in the layer. nodes: IndexMap::with_capacity_and_hasher( num_qubits as usize / 2, - ::ahash::RandomState::default(), + ::foldhash::fast::RandomState::default(), ), qubits: vec![None; num_qubits as usize].into(), } @@ -73,7 +73,7 @@ impl Layer { /// Remove a node from the layer. pub fn remove(&mut self, index: &NodeIndex) { - // The actual order in the indexmap doesn't matter as long as it's reproducible. + // The actual order in the qiskit_util doesn't matter as long as it's reproducible. // Swap-remove is more efficient than a full shift-remove. let [a, b] = self .nodes diff --git a/crates/transpiler/src/passes/sabre/route.rs b/crates/transpiler/src/passes/sabre/route.rs index 879b4c0c7c53..751bc6259a24 100644 --- a/crates/transpiler/src/passes/sabre/route.rs +++ b/crates/transpiler/src/passes/sabre/route.rs @@ -22,8 +22,8 @@ use pyo3::prelude::*; use pyo3::types::PyDict; use hashbrown::HashSet; -use indexmap::IndexMap; use ndarray::Array2; +use qiskit_util::IndexMap; use rand::prelude::*; use rand::rngs::SysRng; use rand_pcg::Pcg64Mcg; @@ -624,8 +624,8 @@ impl State { fn populate_extended_set(&mut self, problem: RoutingProblem) { let mut next_visit = self.front_layer.iter_nodes().copied().collect::>(); let mut to_visit = Vec::new(); - let mut decremented: IndexMap = - IndexMap::with_hasher(ahash::RandomState::default()); + let mut decremented: IndexMap = + IndexMap::with_hasher(foldhash::fast::RandomState::default()); for layer in self.lookahead_layers.iter_mut() { for node in next_visit.drain(..) { for edge in problem.sabre.dag.edges_directed(node, Direction::Outgoing) { diff --git a/crates/transpiler/src/passes/schedule_analysis/alap_schedule_analysis.rs b/crates/transpiler/src/passes/schedule_analysis/alap_schedule_analysis.rs index 7c2beddef996..dadcbd9a4baf 100644 --- a/crates/transpiler/src/passes/schedule_analysis/alap_schedule_analysis.rs +++ b/crates/transpiler/src/passes/schedule_analysis/alap_schedule_analysis.rs @@ -13,27 +13,26 @@ use super::TimeOps; use crate::TranspilerError; use crate::passes::schedule_analysis::{NodeDurations, PyNodeDurations}; -use ahash::RandomState; use hashbrown::HashMap; -use indexmap::IndexMap; use pyo3::prelude::*; use qiskit_circuit::dag_circuit::{DAGCircuit, Wire}; use qiskit_circuit::operations::{OperationRef, StandardInstruction}; use qiskit_circuit::{Clbit, Qubit}; +use qiskit_util::IndexMap; use rustworkx_core::petgraph::prelude::NodeIndex; pub fn run_alap_schedule_analysis( dag: &DAGCircuit, clbit_write_latency: T, - node_durations: &IndexMap, -) -> PyResult> { + node_durations: &IndexMap, +) -> PyResult> { if dag.qregs().len() != 1 || !dag.qregs_data().contains_key("q") { return Err(TranspilerError::new_err( "ALAP schedule runs on physical circuits only", )); } - let mut node_start_time: IndexMap = IndexMap::default(); + let mut node_start_time: IndexMap = IndexMap::default(); let mut idle_before: HashMap = HashMap::new(); let zero = T::zero(); @@ -132,7 +131,7 @@ pub fn run_alap_schedule_analysis( // Note that ALAP pass is inversely scheduled, thus // t0 is computed by subtracting t1 from the entire circuit duration. - let mut result: IndexMap = IndexMap::default(); + let mut result: IndexMap = IndexMap::default(); for (node_idx, t1) in node_start_time { let final_time = *circuit_duration - t1; result.insert(node_idx, final_time); diff --git a/crates/transpiler/src/passes/schedule_analysis/asap_schedule_analysis.rs b/crates/transpiler/src/passes/schedule_analysis/asap_schedule_analysis.rs index 22cc4a449a21..48edcc44cbdc 100644 --- a/crates/transpiler/src/passes/schedule_analysis/asap_schedule_analysis.rs +++ b/crates/transpiler/src/passes/schedule_analysis/asap_schedule_analysis.rs @@ -12,27 +12,26 @@ use crate::TranspilerError; use crate::passes::schedule_analysis::{NodeDurations, PyNodeDurations, TimeOps}; -use ahash::RandomState; use hashbrown::HashMap; -use indexmap::IndexMap; use pyo3::prelude::*; use qiskit_circuit::dag_circuit::{DAGCircuit, Wire}; use qiskit_circuit::operations::{OperationRef, StandardInstruction}; use qiskit_circuit::{Clbit, Qubit}; +use qiskit_util::IndexMap; use rustworkx_core::petgraph::prelude::NodeIndex; pub fn run_asap_schedule_analysis( dag: &DAGCircuit, clbit_write_latency: T, - node_durations: &IndexMap, -) -> PyResult> { + node_durations: &IndexMap, +) -> PyResult> { if dag.qregs().len() != 1 || !dag.qregs_data().contains_key("q") { return Err(TranspilerError::new_err( "ASAP schedule runs on physical circuits only", )); } - let mut node_start_time: IndexMap = IndexMap::default(); + let mut node_start_time: IndexMap = IndexMap::default(); let mut idle_after: HashMap = HashMap::new(); let zero = T::zero(); diff --git a/crates/transpiler/src/passes/schedule_analysis/mod.rs b/crates/transpiler/src/passes/schedule_analysis/mod.rs index 88e0599ec268..5131ce2dcc63 100644 --- a/crates/transpiler/src/passes/schedule_analysis/mod.rs +++ b/crates/transpiler/src/passes/schedule_analysis/mod.rs @@ -17,9 +17,7 @@ use std::ops::{ Add, AddAssign, Deref, DerefMut, Div, DivAssign, Mul, MulAssign, Rem, RemAssign, Sub, SubAssign, }; -use ahash::RandomState; use hashbrown::HashMap; -use indexmap::IndexMap; use pyo3::{ IntoPyObjectExt, exceptions::{PyKeyError, PyTypeError}, @@ -30,6 +28,7 @@ use qiskit_circuit::{ dag_circuit::DAGCircuit, dag_node::{DAGNode, DAGOpNode}, }; +use qiskit_util::IndexMap; use rustworkx_core::petgraph::graph::NodeIndex; use crate::TranspilerError; @@ -403,8 +402,8 @@ impl PyNodeDurations { /// representing by an `f64`. #[derive(Debug, Clone, PartialEq)] pub enum NodeDurations { - Dt(IndexMap, u64, RandomState>), - Seconds(IndexMap, f64, RandomState>), + Dt(IndexMap, u64>), + Seconds(IndexMap, f64>), } impl NodeDurations { @@ -424,14 +423,14 @@ impl NodeDurations { } } -impl From, u64, RandomState>> for NodeDurations { - fn from(value: IndexMap, u64, RandomState>) -> Self { +impl From, u64>> for NodeDurations { + fn from(value: IndexMap, u64>) -> Self { Self::Dt(value) } } -impl From, f64, RandomState>> for NodeDurations { - fn from(value: IndexMap, f64, RandomState>) -> Self { +impl From, f64>> for NodeDurations { + fn from(value: IndexMap, f64>) -> Self { Self::Seconds(value) } } diff --git a/crates/transpiler/src/passes/unitary_synthesis/decomposers.rs b/crates/transpiler/src/passes/unitary_synthesis/decomposers.rs index b16d527dcd13..4e348fbdbaaf 100644 --- a/crates/transpiler/src/passes/unitary_synthesis/decomposers.rs +++ b/crates/transpiler/src/passes/unitary_synthesis/decomposers.rs @@ -23,9 +23,9 @@ use std::sync::LazyLock; use approx::relative_eq; use hashbrown::{HashMap, HashSet, hash_map}; -use indexmap::{IndexMap, IndexSet}; use ndarray::{ArrayView2, CowArray, Ix2}; use num_complex::Complex64; +use qiskit_util::{IndexMap, IndexSet}; use smallvec::{SmallVec, smallvec}; use numpy::convert::ToPyArray; @@ -309,9 +309,7 @@ impl Decomposer2q { /// /// This exists mostly just to attach methods to and to shorten a bunch of type signatures. #[derive(Clone, Debug, Default)] -struct Decomposer2qCacheInner( - IndexMap, ::ahash::RandomState>, -); +struct Decomposer2qCacheInner(IndexMap>); impl Decomposer2qCacheInner { /// Get a decomposer by known-good index. /// @@ -628,7 +626,7 @@ fn get_2q_decomposers( let euler_bases = euler_bases_from_target(target, qubits[0]); let candidates_2q = get_candidate_2q_operations(target, qubits, config.decomposition_direction_2q); - let mut decomposers = IndexSet::new(); + let mut decomposers = IndexSet::default(); // Ising-like gates. for candidate in candidates_2q.iter() { diff --git a/crates/transpiler/src/passes/unitary_synthesis/mod.rs b/crates/transpiler/src/passes/unitary_synthesis/mod.rs index 5021009b9d24..888e31c3e27e 100644 --- a/crates/transpiler/src/passes/unitary_synthesis/mod.rs +++ b/crates/transpiler/src/passes/unitary_synthesis/mod.rs @@ -13,10 +13,10 @@ mod decomposers; use hashbrown::HashSet; -use indexmap::IndexSet; use nalgebra::Matrix2; use ndarray::prelude::*; use num_complex::Complex64; +use qiskit_util::IndexSet; use std::hash; use numpy::PyReadonlyArray2; @@ -114,7 +114,7 @@ impl Approximation { pub enum QpuConstraint<'a> { Target(&'a Target), Loose { - basis_gates: &'a IndexSet<&'a str, ::ahash::RandomState>, + basis_gates: &'a IndexSet<&'a str>, coupling: &'a HashSet<[PhysicalQubit; 2]>, }, } @@ -674,7 +674,7 @@ pub fn py_unitary_synthesis( run_python_decomposers: true, }; let mut state = UnitarySynthesisState::new(config); - let mut basis_gates_set: IndexSet<&str, ::ahash::RandomState>; + let mut basis_gates_set: IndexSet<&str>; let constraint = match target { Some(target) => QpuConstraint::Target(target), None => { @@ -718,7 +718,7 @@ pub fn py_synthesize_unitary_matrix( run_python_decomposers: true, }; let mut state = UnitarySynthesisState::new(config); - let mut basis_gates_set: IndexSet<&str, ::ahash::RandomState>; + let mut basis_gates_set: IndexSet<&str>; let constraint = match target { Some(target) => QpuConstraint::Target(target), None => { diff --git a/crates/transpiler/src/passes/vf2/vf2_layout.rs b/crates/transpiler/src/passes/vf2/vf2_layout.rs index 200ccafd5edc..6ae652a3fb29 100644 --- a/crates/transpiler/src/passes/vf2/vf2_layout.rs +++ b/crates/transpiler/src/passes/vf2/vf2_layout.rs @@ -14,7 +14,7 @@ use std::convert::Infallible; use std::time::Instant; use hashbrown::HashMap; -use indexmap::{IndexMap, IndexSet}; +use qiskit_util::{IndexMap, IndexSet}; use rand::prelude::*; use rand::rngs::SysRng; use rand_pcg::Pcg64Mcg; @@ -637,7 +637,7 @@ fn map_free_qubits( fn minimize_vf2( vf2: vf2::Vf2, config: &Vf2PassConfiguration, -) -> Option> +) -> Option> where N: vf2::alias::IntoVf2Graph, H: vf2::alias::IntoVf2Graph, diff --git a/crates/transpiler/src/target/mod.rs b/crates/transpiler/src/target/mod.rs index 65916834c23a..d4a80f6921a2 100644 --- a/crates/transpiler/src/target/mod.rs +++ b/crates/transpiler/src/target/mod.rs @@ -25,10 +25,8 @@ pub use qubit_properties::QubitProperties; use std::{ops::Index, sync::OnceLock}; -use ahash::RandomState; use hashbrown::HashMap; use hashbrown::HashSet; -use indexmap::IndexMap; use itertools::Itertools; use pyo3::{ IntoPyObjectExt, @@ -37,6 +35,7 @@ use pyo3::{ pyclass, types::{PyDict, PyList, PySet}, }; +use qiskit_util::IndexMap; use rustworkx_core::petgraph::prelude::*; use smallvec::SmallVec; use thiserror::Error; @@ -52,8 +51,8 @@ use crate::TranspilerError; use bounds::AngleBound; // Custom types -type GateMap = IndexMap; -type PropsMap = IndexMap, RandomState>; +type GateMap = IndexMap; +type PropsMap = IndexMap>; /// Represents a Qiskit `Gate` object or a Variadic instruction. /// Keeps a reference to its Python instance for caching purposes. @@ -221,9 +220,9 @@ pub struct Target { pub concurrent_measurements: Option>>, gate_map: GateMap, #[pyo3(get)] - _gate_name_map: IndexMap, - global_operations: IndexMap, RandomState>, - qarg_gate_map: IndexMap, RandomState>, + _gate_name_map: IndexMap, + global_operations: IndexMap>, + qarg_gate_map: IndexMap>, angle_bounds: HashMap, } @@ -837,11 +836,11 @@ impl Target { self._gate_name_map = state .get_item("gate_name_map")? .unwrap() - .extract::>()?; + .extract::>()?; self.global_operations = state .get_item("global_operations")? .unwrap() - .extract::, RandomState>>()?; + .extract::>>()?; self.qarg_gate_map = IndexMap::from_iter( state .get_item("qarg_gate_map")? @@ -1052,7 +1051,7 @@ impl Target { /// use qiskit_transpiler::target::{Target, InstructionProperties, Qargs}; /// use qiskit_circuit::operations::StandardGate; /// use qiskit_circuit::PhysicalQubit; - /// use indexmap::IndexMap; + /// use qiskit_util::IndexMap; /// /// let mut target = Target::default(); /// target.add_instruction( @@ -1203,7 +1202,7 @@ impl Target { } } let mut incomplete_basis_gates: Vec<&str> = Vec::new(); - let mut size_dict: IndexMap = IndexMap::default(); + let mut size_dict: IndexMap = IndexMap::default(); *size_dict .entry(1) .or_insert(self.num_qubits.unwrap_or_default()) = self.num_qubits.unwrap_or_default(); diff --git a/crates/util/Cargo.toml b/crates/util/Cargo.toml index a20745815294..e4a3e35b7661 100644 --- a/crates/util/Cargo.toml +++ b/crates/util/Cargo.toml @@ -19,3 +19,5 @@ workspace = true num-complex.workspace = true pyo3 = { workspace = true, optional = true } thiserror.workspace = true +indexmap.workspace = true +foldhash.workspace = true diff --git a/crates/util/src/lib.rs b/crates/util/src/lib.rs index 704a1bdfc526..210731f7f85c 100644 --- a/crates/util/src/lib.rs +++ b/crates/util/src/lib.rs @@ -15,6 +15,18 @@ use std::env; #[cfg(feature = "py")] pub mod py; +/// A common type alias to use IndexMap with Qiskit's default hasher all +/// internal crate usage of IndexMap should use this instead of the indexmap +/// crate directly. +#[allow(clippy::disallowed_types)] +pub type IndexMap = indexmap::IndexMap; + +/// A common type alias to use IndexSet with Qiskit's default hasher all +/// internal crate usage of IndexSet should use this instead of the indexmap +/// crate directly. +#[allow(clippy::disallowed_types)] +pub type IndexSet = indexmap::IndexSet; + pub mod complex { use num_complex::Complex64; diff --git a/releasenotes/notes/use-foldhash-b63e18338950a9c8.yaml b/releasenotes/notes/use-foldhash-b63e18338950a9c8.yaml new file mode 100644 index 000000000000..6ae68e0dd901 --- /dev/null +++ b/releasenotes/notes/use-foldhash-b63e18338950a9c8.yaml @@ -0,0 +1,7 @@ +--- +performance: + - The internal hashing algorithm used for Rust `indexmap `__ types + has been changed to use `foldhash `__ instead of the previously used + `ahash `__ library. This has led up to speedups for some of the + functionality that heavily uses indexmap internally. See + `#15920 `__ for more details.