From 623ed7241673a53bec4e499b020db7e2b2f63441 Mon Sep 17 00:00:00 2001 From: Raynel Sanchez Date: Wed, 7 Aug 2024 15:05:19 -0400 Subject: [PATCH 1/3] Initial: Introduce a gate name interner to avoid duplicating `String` instances. - Remove `variable_operation_class`, use enum nature to discriminate. - Hide `gate_name_map` from Python, use `operation_from_name`. - Other small tweaks and fixes. --- .../accelerate/src/target_transpiler/mod.rs | 328 ++++++++++++------ qiskit/transpiler/target.py | 4 +- 2 files changed, 233 insertions(+), 99 deletions(-) diff --git a/crates/accelerate/src/target_transpiler/mod.rs b/crates/accelerate/src/target_transpiler/mod.rs index bb0ec166c07e..332670603885 100644 --- a/crates/accelerate/src/target_transpiler/mod.rs +++ b/crates/accelerate/src/target_transpiler/mod.rs @@ -16,11 +16,13 @@ mod errors; mod instruction_properties; mod nullable_index_map; +use std::hash::Hash; use std::ops::Index; use ahash::RandomState; use ahash::HashSet; +use indexmap::Equivalent; use indexmap::{IndexMap, IndexSet}; use itertools::Itertools; use nullable_index_map::NullableIndexMap; @@ -51,9 +53,9 @@ mod exceptions { // Custom types type Qargs = SmallVec<[PhysicalQubit; 2]>; -type GateMap = IndexMap; +type GateMap = IndexMap; type PropsMap = NullableIndexMap>; -type GateMapState = Vec<(String, Vec<(Option, Option)>)>; +type GateMapState = Vec<(usize, Vec<(Option, Option)>)>; /// Represents a Qiskit `Gate` object or a Variadic instruction. /// Keeps a reference to its Python instance for caching purposes. @@ -131,6 +133,67 @@ impl ToPyObject for NormalOperation { } } +/** +Creates an interner instance to keep only one copy of the gate names. +The interned version is an instance of u32 which uses `Copy`. + */ +#[derive(Debug, Clone, Default)] +struct TargetInterner +where + T: Hash + Clone + Eq, +{ + gate_name_map: IndexSet, +} + +impl TargetInterner +where + T: Hash + Clone + Eq, +{ + /// Internalizes a gate name + pub fn intern_item(&mut self, item: T) -> usize { + if let Some(index) = self.gate_name_map.get_index_of(&item) { + index + } else { + let new_index = self.gate_name_map.len(); + self.gate_name_map.insert(item); + new_index + } + } + + /// Get an existent gates + pub fn get_item(&self, item: &Q) -> Option + where + Q: ?Sized + Hash + Equivalent, + { + self.gate_name_map.get_index_of(item) + } + + /// Decodes the gate + pub fn intern_index(&self, gate_index: usize) -> Option<&T> { + self.gate_name_map.get_index(gate_index) + } + + pub fn reduce(&self) -> Vec { + self.gate_name_map.iter().cloned().collect() + } + + pub fn from_reduced(reduced: I) -> Self + where + I: IntoIterator, + { + Self { + gate_name_map: IndexSet::from_iter(reduced), + } + } + + pub fn contains(&self, item: &Q) -> bool + where + Q: ?Sized + Hash + Equivalent, + { + self.gate_name_map.contains(item) + } +} + /** The base class for a Python ``Target`` object. Contains data representing the constraints of a particular backend. @@ -170,13 +233,13 @@ pub(crate) struct Target { #[pyo3(get, set)] pub concurrent_measurements: Option>>, gate_map: GateMap, - #[pyo3(get)] - _gate_name_map: IndexMap, - global_operations: IndexMap, RandomState>, - variable_class_operations: IndexSet, - qarg_gate_map: NullableIndexMap>>, - non_global_strict_basis: Option>, - non_global_basis: Option>, + gate_name_map: IndexMap, + gate_interner: TargetInterner, + qarg_interner: TargetInterner>, + global_operations: IndexMap, RandomState>, + qarg_gate_map: NullableIndexMap>>, + non_global_strict_basis: Option>, + non_global_basis: Option>, } #[pymethods] @@ -268,12 +331,13 @@ impl Target { qubit_properties, concurrent_measurements, gate_map: GateMap::default(), - _gate_name_map: IndexMap::default(), - variable_class_operations: IndexSet::default(), + gate_name_map: IndexMap::default(), global_operations: IndexMap::default(), qarg_gate_map: NullableIndexMap::default(), non_global_basis: None, non_global_strict_basis: None, + gate_interner: TargetInterner::default(), + qarg_interner: TargetInterner::default(), }) } @@ -295,18 +359,18 @@ impl Target { name: &str, properties: Option, ) -> PyResult<()> { - if self.gate_map.contains_key(name) { + if self.contains_key(name) { return Err(PyAttributeError::new_err(format!( "Instruction {:?} is already in the target", name ))); } let mut qargs_val: PropsMap; + let gate_index = self.gate_interner.intern_item(name.to_string()); match instruction { TargetOperation::Variadic(_) => { qargs_val = PropsMap::with_capacity(1); qargs_val.extend([(None, None)].into_iter()); - self.variable_class_operations.insert(name.to_string()); } TargetOperation::Normal(_) => { if let Some(mut properties) = properties { @@ -316,9 +380,9 @@ impl Target { self.global_operations .entry(inst_num_qubits) .and_modify(|e| { - e.insert(name.to_string()); + e.insert(gate_index); }) - .or_insert(HashSet::from_iter([name.to_string()])); + .or_insert(HashSet::from_iter([gate_index])); } let property_keys: Vec> = properties.keys().map(|qargs| qargs.cloned()).collect(); @@ -345,10 +409,10 @@ impl Target { let inst_properties = properties.swap_remove(qarg.as_ref()).unwrap(); qargs_val.insert(qarg.clone(), inst_properties); if let Some(Some(value)) = self.qarg_gate_map.get_mut(qarg.as_ref()) { - value.insert(name.to_string()); + value.insert(gate_index); } else { self.qarg_gate_map - .insert(qarg, Some(HashSet::from_iter([name.to_string()]))); + .insert(qarg, Some(HashSet::from_iter([gate_index]))); } } } else { @@ -356,8 +420,8 @@ impl Target { } } } - self._gate_name_map.insert(name.to_string(), instruction); - self.gate_map.insert(name.to_string(), qargs_val); + self.gate_name_map.insert(gate_index, instruction); + self.gate_map.insert(gate_index, qargs_val); self.non_global_basis = None; self.non_global_strict_basis = None; Ok(()) @@ -374,17 +438,17 @@ impl Target { #[pyo3(text_signature = "(instruction, qargs, properties, /,)")] fn update_instruction_properties( &mut self, - instruction: String, + instruction: &str, qargs: Option, properties: Option, ) -> PyResult<()> { - if !self.contains_key(&instruction) { + if !self.contains_key(instruction) { return Err(PyKeyError::new_err(format!( "Provided instruction: '{:?}' not in this Target.", &instruction ))); }; - let mut prop_map = self[&instruction].clone(); + let mut prop_map = self[instruction].clone(); if !(prop_map.contains_key(qargs.as_ref())) { return Err(PyKeyError::new_err(format!( "Provided qarg {:?} not in this Target for {:?}.", @@ -396,7 +460,7 @@ impl Target { *e = properties; } self.gate_map - .entry(instruction) + .entry(self.gate_interner.get_item(instruction).unwrap()) .and_modify(|e| *e = prop_map); Ok(()) } @@ -460,9 +524,10 @@ impl Target { ) -> PyResult> { // Move to rust native once Gates are in rust Ok(self - .py_operation_names_for_qargs(qargs)? + .operation_index_for_qargs(qargs.as_ref()) + .map_err(|err| PyKeyError::new_err(err.message))? .into_iter() - .map(|x| self._gate_name_map[x].to_object(py)) + .map(|x| self.gate_name_map[x].to_object(py)) .collect()) } @@ -559,7 +624,7 @@ impl Target { qargs = None; } if let Some(_operation_class) = operation_class { - for (op_name, obj) in self._gate_name_map.iter() { + for (op_name, obj) in self.gate_name_map.iter() { match obj { TargetOperation::Variadic(variable) => { if !_operation_class.eq(variable)? { @@ -595,7 +660,7 @@ impl Target { } if gate_map_name.contains_key(None) { let qubit_comparison = - self._gate_name_map[op_name].num_qubits(); + self.gate_name_map[op_name].num_qubits(); return Ok(qubit_comparison == _qargs.len() as u32 && _qargs.iter().all(|x| { x.index() < self.num_qubits.unwrap_or_default() @@ -617,9 +682,12 @@ impl Target { } Ok(false) } else if let Some(operation_name) = operation_name { + let Some(operation_index) = self.gate_interner.get_item(&operation_name) else { + return Ok(self.instruction_supported(&operation_name, qargs.as_ref())) + }; if let Some(parameters) = parameters { - if let Some(obj) = self._gate_name_map.get(&operation_name) { - if self.variable_class_operations.contains(&operation_name) { + if let Some(obj) = self.gate_name_map.get(&operation_index) { + if matches!(obj, TargetOperation::Variadic(_)) { if let Some(_qargs) = qargs { let qarg_set: HashSet = _qargs.iter().cloned().collect(); return Ok(_qargs @@ -778,7 +846,7 @@ impl Target { #[getter] #[pyo3(name = "operations")] fn py_operations(&self, py: Python<'_>) -> Py { - PyList::new_bound(py, self._gate_name_map.values()).unbind() + PyList::new_bound(py, self.gate_name_map.values()).unbind() } /// Returns a sorted list of physical qubits. @@ -824,7 +892,7 @@ impl Target { .collect::() .into_py(py), )?; - result_list.set_item("gate_name_map", self._gate_name_map.to_object(py))?; + result_list.set_item("gate_name_map", self.gate_name_map.to_object(py))?; result_list.set_item("global_operations", self.global_operations.clone())?; result_list.set_item( "qarg_gate_map", @@ -835,6 +903,8 @@ impl Target { "non_global_strict_basis", self.non_global_strict_basis.clone(), )?; + result_list.set_item("gate_names", self.gate_interner.reduce())?; + result_list.set_item("qargs", self.qarg_interner.reduce())?; Ok(result_list.unbind()) } @@ -874,28 +944,40 @@ impl Target { .into_iter() .map(|(name, prop_map)| (name, PropsMap::from_iter(prop_map.into_iter()))), ); - self._gate_name_map = state + 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::, RandomState>>()?; self.qarg_gate_map = NullableIndexMap::from_iter( state .get_item("qarg_gate_map")? .unwrap() - .extract::, Option>)>>()?, + .extract::, Option>)>>()?, ); self.non_global_basis = state .get_item("non_global_basis")? .unwrap() - .extract::>>()?; + .extract::>>()?; self.non_global_strict_basis = state .get_item("non_global_strict_basis")? .unwrap() - .extract::>>()?; + .extract::>>()?; + self.gate_interner = TargetInterner::from_reduced( + state + .get_item("gate_names")? + .unwrap() + .extract::>()?, + ); + self.qarg_interner = TargetInterner::from_reduced( + state + .get_item("qargs")? + .unwrap() + .extract::>>()?, + ); Ok(()) } } @@ -920,21 +1002,26 @@ impl Target { self.gate_map.iter().flat_map(move |(op, props_map)| { props_map .keys() - .map(move |qargs| (&self._gate_name_map[op], qargs)) + .map(move |qargs| (&self.gate_name_map[op], qargs)) }) } /// Returns an iterator over the operation names in the target. // TODO: Remove once `Target` is being consumed. #[allow(dead_code)] pub fn operation_names(&self) -> impl ExactSizeIterator { - self.gate_map.keys().map(|x| x.as_str()) + self.gate_map.keys().map(|x| { + self.gate_interner + .intern_index(*x) + .map(|gate| gate.as_str()) + .unwrap() + }) } /// Get the `OperationType` objects present in the target. // TODO: Remove once `Target` is being consumed. #[allow(dead_code)] pub fn operations(&self) -> impl Iterator { - return self._gate_name_map.values().filter_map(|oper| match oper { + return self.gate_name_map.values().filter_map(|oper| match oper { TargetOperation::Normal(oper) => Some(oper), _ => None, }); @@ -946,7 +1033,7 @@ impl Target { } /// Generate non global operations if missing - fn generate_non_global_op_names(&mut self, strict_direction: bool) -> &[String] { + fn generate_non_global_op_names(&mut self, strict_direction: bool) -> Vec<&str> { let mut search_set: HashSet = HashSet::default(); if strict_direction { // Build search set @@ -960,7 +1047,7 @@ impl Target { } } } - let mut incomplete_basis_gates: Vec = vec![]; + let mut incomplete_basis_gates: Vec = vec![]; let mut size_dict: IndexMap = IndexMap::default(); *size_dict .entry(1) @@ -991,39 +1078,66 @@ impl Target { } if let Some(qarg_sample) = qarg_sample { if qarg_len != *size_dict.entry(qarg_sample.len()).or_insert(0) { - incomplete_basis_gates.push(inst.clone()); + incomplete_basis_gates.push(*inst); } } } } if strict_direction { - self.non_global_strict_basis = Some(incomplete_basis_gates); - self.non_global_strict_basis.as_ref().unwrap() + self.non_global_strict_basis = Some(incomplete_basis_gates.to_vec()); } else { - self.non_global_basis = Some(incomplete_basis_gates.clone()); - self.non_global_basis.as_ref().unwrap() + self.non_global_basis = Some(incomplete_basis_gates.to_vec()); } + incomplete_basis_gates + .iter() + .map(|gate_index| { + self.gate_interner + .intern_index(*gate_index) + .unwrap() + .as_str() + }) + .collect() } /// Get all non_global operation names. - pub fn get_non_global_operation_names(&mut self, strict_direction: bool) -> Option<&[String]> { + pub fn get_non_global_operation_names(&mut self, strict_direction: bool) -> Option> { if strict_direction { if self.non_global_strict_basis.is_some() { - return self.non_global_strict_basis.as_deref(); + return self.non_global_strict_basis.as_ref().map(|strict| { + strict + .iter() + .map(|gate_index| { + self.gate_interner + .intern_index(*gate_index) + .unwrap() + .as_str() + }) + .collect() + }); } } else if self.non_global_basis.is_some() { - return self.non_global_basis.as_deref(); + return self.non_global_basis.as_ref().map(|basis| { + basis + .iter() + .map(|gate_index| { + self.gate_interner + .intern_index(*gate_index) + .unwrap() + .as_str() + }) + .collect() + }); } return Some(self.generate_non_global_op_names(strict_direction)); } - /// Gets all the operation names that use these qargs. Rust native equivalent of ``BaseTarget.operation_names_for_qargs()`` - pub fn operation_names_for_qargs( + /// Gets all the interned operation_names that use these qargs. Rust native equivalent of ``BaseTarget.operation_names_for_qargs()`` + fn operation_index_for_qargs( &self, qargs: Option<&Qargs>, - ) -> Result, TargetKeyError> { + ) -> Result, TargetKeyError> { // When num_qubits == 0 we return globally defined operators - let mut res: HashSet<&str> = HashSet::default(); + let mut res: HashSet = HashSet::default(); let mut qargs = qargs; if self.num_qubits.unwrap_or_default() == 0 || self.num_qubits.is_none() { qargs = None; @@ -1040,16 +1154,16 @@ impl Target { } } if let Some(Some(qarg_gate_map_arg)) = self.qarg_gate_map.get(qargs).as_ref() { - res.extend(qarg_gate_map_arg.iter().map(|key| key.as_str())); + res.extend(qarg_gate_map_arg.iter()); } - for name in self._gate_name_map.keys() { - if self.variable_class_operations.contains(name) { - res.insert(name); + for (index, oper) in self.gate_name_map.iter() { + if matches!(oper, TargetOperation::Variadic(_)) { + res.insert(*index); } } if let Some(qargs) = qargs.as_ref() { if let Some(global_gates) = self.global_operations.get(&(qargs.len() as u32)) { - res.extend(global_gates.iter().map(|key| key.as_str())) + res.extend(global_gates.iter()) } } if res.is_empty() { @@ -1061,6 +1175,19 @@ impl Target { Ok(res) } + /// Gets all the operation names that use these qargs. Rust native equivalent of ``BaseTarget.operation_names_for_qargs()`` + pub fn operation_names_for_qargs( + &self, + qargs: Option<&Qargs>, + ) -> Result, TargetKeyError> { + self.operation_index_for_qargs(qargs).map(|result| { + result + .iter() + .map(|x| self.gate_interner.intern_index(*x).unwrap().as_str()) + .collect() + }) + } + /// Returns an iterator of `OperationType` instances and parameters present in the Target that affect the provided qargs. // TODO: Remove once `Target` is being consumed. #[allow(dead_code)] @@ -1068,10 +1195,10 @@ impl Target { &self, qargs: Option<&Qargs>, ) -> Result, TargetKeyError> { - self.operation_names_for_qargs(qargs).map(|operations| { + self.operation_index_for_qargs(qargs).map(|operations| { operations .into_iter() - .filter_map(|oper| match &self._gate_name_map[oper] { + .filter_map(|oper| match &self.gate_name_map[oper] { TargetOperation::Normal(normal) => Some(normal), _ => None, }) @@ -1085,17 +1212,15 @@ impl Target { &self, operation: &str, ) -> Result>, TargetKeyError> { - if let Some(gate_map_oper) = self.gate_map.get(operation) { - if gate_map_oper.contains_key(None) { - return Ok(None); - } - let qargs = gate_map_oper.keys().flatten(); - Ok(Some(qargs)) - } else { - Err(TargetKeyError::new_err(format!( - "Operation: {operation} not in Target." - ))) + let Some(gate_index) = self.gate_interner.get_item(operation) else { return Err(TargetKeyError::new_err(format!( + "Operation: {operation} not in Target." + )))}; + let gate_map_oper = &self.gate_map[gate_index]; + if gate_map_oper.contains_key(None) { + return Ok(None); } + let qargs = gate_map_oper.keys().flatten(); + Ok(Some(qargs)) } /// Gets a tuple of Operation object and Parameters based on the operation name if present in the Target. @@ -1117,8 +1242,8 @@ impl Target { /// Gets the instruction object based on the operation name fn _operation_from_name(&self, instruction: &str) -> Result<&TargetOperation, TargetKeyError> { - if let Some(gate_obj) = self._gate_name_map.get(instruction) { - Ok(gate_obj) + if let Some(gate_obj) = self.gate_interner.get_item(instruction) { + Ok(&self.gate_name_map[gate_obj]) } else { Err(TargetKeyError::new_err(format!( "Instruction {:?} not in target", @@ -1140,43 +1265,49 @@ impl Target { /// Checks whether an instruction is supported by the Target based on instruction name and qargs. pub fn instruction_supported(&self, operation_name: &str, qargs: Option<&Qargs>) -> bool { - if self.gate_map.contains_key(operation_name) { + if let Some(gate_index) = self.gate_interner.get_item(operation_name) { if let Some(_qargs) = qargs { let qarg_set: HashSet<&PhysicalQubit> = _qargs.iter().collect(); - if let Some(gate_prop_name) = self.gate_map.get(operation_name) { + if let Some(gate_prop_name) = self.gate_map.get(&gate_index) { if gate_prop_name.contains_key(qargs) { return true; } if gate_prop_name.contains_key(None) { - let obj = &self._gate_name_map[operation_name]; - if self.variable_class_operations.contains(operation_name) { + let obj = &self.gate_name_map[gate_index]; + match obj { + TargetOperation::Variadic(_) => { + return qargs.is_none() + || _qargs.iter().all(|qarg| { + qarg.index() <= self.num_qubits.unwrap_or_default() + }) && qarg_set.len() == _qargs.len(); + } + TargetOperation::Normal(obj) => { + let qubit_comparison = obj.operation.view().num_qubits(); + return qubit_comparison == _qargs.len() as u32 + && _qargs.iter().all(|qarg| { + qarg.index() < self.num_qubits.unwrap_or_default() + }); + } + } + } + } else { + // Duplicate case is if it contains none + let gate_obj = &self.gate_name_map[gate_index]; + match gate_obj { + TargetOperation::Variadic(_) => { return qargs.is_none() || _qargs.iter().all(|qarg| { qarg.index() <= self.num_qubits.unwrap_or_default() }) && qarg_set.len() == _qargs.len(); - } else { - let qubit_comparison = obj.num_qubits(); + } + TargetOperation::Normal(obj) => { + let qubit_comparison = obj.operation.view().num_qubits(); return qubit_comparison == _qargs.len() as u32 && _qargs.iter().all(|qarg| { qarg.index() < self.num_qubits.unwrap_or_default() }); } } - } else { - // Duplicate case is if it contains none - if self.variable_class_operations.contains(operation_name) { - return qargs.is_none() - || _qargs - .iter() - .all(|qarg| qarg.index() <= self.num_qubits.unwrap_or_default()) - && qarg_set.len() == _qargs.len(); - } else { - let qubit_comparison = self._gate_name_map[operation_name].num_qubits(); - return qubit_comparison == _qargs.len() as u32 - && _qargs - .iter() - .all(|qarg| qarg.index() < self.num_qubits.unwrap_or_default()); - } } } else { return true; @@ -1191,7 +1322,9 @@ impl Target { // TODO: Remove once `Target` is being consumed. #[allow(dead_code)] pub fn keys(&self) -> impl Iterator { - self.gate_map.keys().map(|x| x.as_str()) + self.gate_map + .keys() + .map(|x| self.gate_interner.intern_index(*x).unwrap().as_str()) } /// Retrieves an iterator over the property maps stored within the Target @@ -1203,7 +1336,7 @@ impl Target { /// Checks if a key exists in the Target pub fn contains_key(&self, key: &str) -> bool { - self.gate_map.contains_key(key) + self.gate_interner.contains(key) } } @@ -1211,7 +1344,8 @@ impl Target { impl Index<&str> for Target { type Output = PropsMap; fn index(&self, index: &str) -> &Self::Output { - self.gate_map.index(index) + self.gate_map + .index(self.gate_interner.get_item(index).unwrap()) } } diff --git a/qiskit/transpiler/target.py b/qiskit/transpiler/target.py index da4a44a8ee02..455af07efa4d 100644 --- a/qiskit/transpiler/target.py +++ b/qiskit/transpiler/target.py @@ -690,7 +690,7 @@ def instructions(self): is globally defined. """ return [ - (self._gate_name_map[op], qarg) + (self.operation_from_name(op), qarg) for op, qargs in self._gate_map.items() for qarg in qargs ] @@ -741,7 +741,7 @@ def _build_coupling_graph(self): self._coupling_graph.add_nodes_from([{} for _ in range(self.num_qubits)]) for gate, qarg_map in self._gate_map.items(): if qarg_map is None: - if self._gate_name_map[gate].num_qubits == 2: + if self.operation_from_name(gate).num_qubits == 2: self._coupling_graph = None # pylint: disable=attribute-defined-outside-init return continue From ae52ec32bdeb8dc996d931b2f11fc826c877fa0f Mon Sep 17 00:00:00 2001 From: Raynel Sanchez Date: Tue, 13 Aug 2024 13:22:24 -0400 Subject: [PATCH 2/3] Fix: Use u16 as default index for Interner --- .../accelerate/src/target_transpiler/mod.rs | 76 +++++++++---------- 1 file changed, 37 insertions(+), 39 deletions(-) diff --git a/crates/accelerate/src/target_transpiler/mod.rs b/crates/accelerate/src/target_transpiler/mod.rs index ac7f7885321c..53668d76751c 100644 --- a/crates/accelerate/src/target_transpiler/mod.rs +++ b/crates/accelerate/src/target_transpiler/mod.rs @@ -53,9 +53,9 @@ mod exceptions { // Custom types type Qargs = SmallVec<[PhysicalQubit; 2]>; -type GateMap = IndexMap; +type GateMap = IndexMap; type PropsMap = NullableIndexMap>; -type GateMapState = Vec<(usize, Vec<(Option, Option)>)>; +type GateMapState = Vec<(u16, Vec<(Option, Option)>)>; /// Represents a Qiskit `Gate` object or a Variadic instruction. /// Keeps a reference to its Python instance for caching purposes. @@ -149,28 +149,35 @@ impl TargetInterner where T: Hash + Clone + Eq, { + /// Creates a new interner instance. + pub fn new() -> Self { + Self { + gate_name_map: IndexSet::default(), + } + } + /// Internalizes a gate name - pub fn intern_item(&mut self, item: T) -> usize { + pub fn intern_item(&mut self, item: T) -> u16 { if let Some(index) = self.gate_name_map.get_index_of(&item) { - index + index as u16 } else { let new_index = self.gate_name_map.len(); self.gate_name_map.insert(item); - new_index + new_index as u16 } } /// Get an existent gates - pub fn get_item(&self, item: &Q) -> Option + pub fn get_item(&self, item: &Q) -> Option where Q: ?Sized + Hash + Equivalent, { - self.gate_name_map.get_index_of(item) + self.gate_name_map.get_index_of(item).map(|x| x as u16) } /// Decodes the gate - pub fn intern_index(&self, gate_index: usize) -> Option<&T> { - self.gate_name_map.get_index(gate_index) + pub fn intern_index(&self, gate_index: u16) -> Option<&T> { + self.gate_name_map.get_index(gate_index as usize) } pub fn reduce(&self) -> Vec { @@ -233,13 +240,12 @@ pub(crate) struct Target { #[pyo3(get, set)] pub concurrent_measurements: Option>>, gate_map: GateMap, - gate_name_map: IndexMap, + gate_name_map: IndexMap, gate_interner: TargetInterner, - qarg_interner: TargetInterner>, - global_operations: IndexMap, RandomState>, - qarg_gate_map: NullableIndexMap>>, - non_global_strict_basis: Option>, - non_global_basis: Option>, + global_operations: IndexMap, RandomState>, + qarg_gate_map: NullableIndexMap>>, + non_global_strict_basis: Option>, + non_global_basis: Option>, } #[pymethods] @@ -336,8 +342,7 @@ impl Target { qarg_gate_map: NullableIndexMap::default(), non_global_basis: None, non_global_strict_basis: None, - gate_interner: TargetInterner::default(), - qarg_interner: TargetInterner::default(), + gate_interner: TargetInterner::new(), }) } @@ -527,7 +532,7 @@ impl Target { .operation_index_for_qargs(qargs.as_ref()) .map_err(|err| PyKeyError::new_err(err.message))? .into_iter() - .map(|x| self.gate_name_map[x].to_object(py)) + .map(|x| self.gate_name_map[&x].to_object(py)) .collect()) } @@ -904,7 +909,6 @@ impl Target { self.non_global_strict_basis.clone(), )?; result_list.set_item("gate_names", self.gate_interner.reduce())?; - result_list.set_item("qargs", self.qarg_interner.reduce())?; Ok(result_list.unbind()) } @@ -947,37 +951,31 @@ 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::, RandomState>>()?; self.qarg_gate_map = NullableIndexMap::from_iter( state .get_item("qarg_gate_map")? .unwrap() - .extract::, Option>)>>()?, + .extract::, Option>)>>()?, ); self.non_global_basis = state .get_item("non_global_basis")? .unwrap() - .extract::>>()?; + .extract::>>()?; self.non_global_strict_basis = state .get_item("non_global_strict_basis")? .unwrap() - .extract::>>()?; + .extract::>>()?; self.gate_interner = TargetInterner::from_reduced( state .get_item("gate_names")? .unwrap() .extract::>()?, ); - self.qarg_interner = TargetInterner::from_reduced( - state - .get_item("qargs")? - .unwrap() - .extract::>>()?, - ); Ok(()) } } @@ -1047,7 +1045,7 @@ impl Target { } } } - let mut incomplete_basis_gates: Vec = vec![]; + let mut incomplete_basis_gates: Vec = vec![]; let mut size_dict: IndexMap = IndexMap::default(); *size_dict .entry(1) @@ -1135,9 +1133,9 @@ impl Target { fn operation_index_for_qargs( &self, qargs: Option<&Qargs>, - ) -> Result, TargetKeyError> { + ) -> Result, TargetKeyError> { // When num_qubits == 0 we return globally defined operators - let mut res: HashSet = HashSet::default(); + let mut res: HashSet = HashSet::default(); let mut qargs = qargs; if self.num_qubits.unwrap_or_default() == 0 || self.num_qubits.is_none() { qargs = None; @@ -1198,7 +1196,7 @@ impl Target { self.operation_index_for_qargs(qargs).map(|operations| { operations .into_iter() - .filter_map(|oper| match &self.gate_name_map[oper] { + .filter_map(|oper| match &self.gate_name_map[&oper] { TargetOperation::Normal(normal) => Some(normal), _ => None, }) @@ -1215,7 +1213,7 @@ impl Target { let Some(gate_index) = self.gate_interner.get_item(operation) else { return Err(TargetKeyError::new_err(format!( "Operation: {operation} not in Target." )))}; - let gate_map_oper = &self.gate_map[gate_index]; + let gate_map_oper = &self.gate_map[&gate_index]; if gate_map_oper.contains_key(None) { return Ok(None); } @@ -1243,7 +1241,7 @@ impl Target { /// Gets the instruction object based on the operation name fn _operation_from_name(&self, instruction: &str) -> Result<&TargetOperation, TargetKeyError> { if let Some(gate_obj) = self.gate_interner.get_item(instruction) { - Ok(&self.gate_name_map[gate_obj]) + Ok(&self.gate_name_map[&gate_obj]) } else { Err(TargetKeyError::new_err(format!( "Instruction {:?} not in target", @@ -1273,7 +1271,7 @@ impl Target { return true; } if gate_prop_name.contains_key(None) { - let obj = &self.gate_name_map[gate_index]; + let obj = &self.gate_name_map[&gate_index]; match obj { TargetOperation::Variadic(_) => { return qargs.is_none() @@ -1292,7 +1290,7 @@ impl Target { } } else { // Duplicate case is if it contains none - let gate_obj = &self.gate_name_map[gate_index]; + let gate_obj = &self.gate_name_map[&gate_index]; match gate_obj { TargetOperation::Variadic(_) => { return qargs.is_none() @@ -1345,7 +1343,7 @@ impl Index<&str> for Target { type Output = PropsMap; fn index(&self, index: &str) -> &Self::Output { self.gate_map - .index(self.gate_interner.get_item(index).unwrap()) + .index(self.gate_interner.get_item(index).unwrap() as usize) } } From b8eeccc4182a4da97f87d54c09882e73d419424c Mon Sep 17 00:00:00 2001 From: Raynel Sanchez Date: Tue, 13 Aug 2024 14:07:08 -0400 Subject: [PATCH 3/3] Refactor: Rename interner set `inner_set`. --- .../accelerate/src/target_transpiler/mod.rs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/crates/accelerate/src/target_transpiler/mod.rs b/crates/accelerate/src/target_transpiler/mod.rs index a2013c071e86..eef5c5a5c3b3 100644 --- a/crates/accelerate/src/target_transpiler/mod.rs +++ b/crates/accelerate/src/target_transpiler/mod.rs @@ -142,7 +142,7 @@ struct TargetInterner where T: Hash + Clone + Eq, { - gate_name_map: IndexSet, + inner_set: IndexSet, } impl TargetInterner @@ -152,17 +152,17 @@ where /// Creates a new interner instance. pub fn new() -> Self { Self { - gate_name_map: IndexSet::default(), + inner_set: IndexSet::default(), } } /// Internalizes a gate name pub fn intern_item(&mut self, item: T) -> u16 { - if let Some(index) = self.gate_name_map.get_index_of(&item) { + if let Some(index) = self.inner_set.get_index_of(&item) { index as u16 } else { - let new_index = self.gate_name_map.len(); - self.gate_name_map.insert(item); + let new_index = self.inner_set.len(); + self.inner_set.insert(item); new_index as u16 } } @@ -172,16 +172,16 @@ where where Q: ?Sized + Hash + Equivalent, { - self.gate_name_map.get_index_of(item).map(|x| x as u16) + self.inner_set.get_index_of(item).map(|x| x as u16) } /// Decodes the gate pub fn intern_index(&self, gate_index: u16) -> Option<&T> { - self.gate_name_map.get_index(gate_index as usize) + self.inner_set.get_index(gate_index as usize) } pub fn reduce(&self) -> Vec { - self.gate_name_map.iter().cloned().collect() + self.inner_set.iter().cloned().collect() } pub fn from_reduced(reduced: I) -> Self @@ -189,7 +189,7 @@ where I: IntoIterator, { Self { - gate_name_map: IndexSet::from_iter(reduced), + inner_set: IndexSet::from_iter(reduced), } } @@ -197,7 +197,7 @@ where where Q: ?Sized + Hash + Equivalent, { - self.gate_name_map.contains(item) + self.inner_set.contains(item) } }