diff --git a/crates/accelerate/src/target_transpiler/instruction_properties.rs b/crates/accelerate/src/target_transpiler/instruction_properties.rs index 6b0f68ba4eb1..28462042648a 100644 --- a/crates/accelerate/src/target_transpiler/instruction_properties.rs +++ b/crates/accelerate/src/target_transpiler/instruction_properties.rs @@ -28,7 +28,7 @@ custom attributes for those custom/additional properties by the backend. #[pyclass(subclass, module = "qiskit._accelerate.target")] #[derive(Clone, Debug)] pub struct InstructionProperties { - #[pyo3(get)] + #[pyo3(get, set)] pub duration: Option, #[pyo3(get, set)] pub error: Option, diff --git a/crates/accelerate/src/target_transpiler/mod.rs b/crates/accelerate/src/target_transpiler/mod.rs index 555e9e079a2d..a61ed67939a9 100644 --- a/crates/accelerate/src/target_transpiler/mod.rs +++ b/crates/accelerate/src/target_transpiler/mod.rs @@ -35,6 +35,7 @@ use qargs::{Qargs, QargsSet, QargsTuple}; use self::{ exceptions::{QiskitError, TranspilerError}, + property_map::PropsMapKeys, qargs::QargsOrTuple, }; @@ -44,14 +45,14 @@ mod exceptions { import_exception_bound! {qiskit.transpiler.exceptions, TranspilerError} } -// Helper function to import inspect.isclass from python. +/// Helper function to import inspect.isclass from python. fn isclass(py: Python<'_>, object: &Bound) -> PyResult { let inspect_module: Bound = py.import_bound("inspect")?; let is_class_method: Bound = inspect_module.getattr("isclass")?; is_class_method.call1((object,))?.extract::() } -// Helper function to import standard gate name mapping from python. +/// Helper function to import standard gate name mapping from python. fn get_standard_gate_name_mapping(py: Python<'_>) -> PyResult>> { let inspect_module: Bound = py.import_bound("qiskit.circuit.library.standard_gates")?; @@ -61,6 +62,7 @@ fn get_standard_gate_name_mapping(py: Python<'_>) -> PyResult>>() } +/// Helper function to obtain the qubit props list from some Target Properties. fn qubit_props_list_from_props( py: Python<'_>, properties: &Bound, @@ -491,9 +493,7 @@ impl Target { ))); } if let Some(q_vals) = self.gate_map.get_mut(&instruction) { - if let Some(q_vals) = q_vals.map.get_mut(&qargs) { - *q_vals = properties; - } + q_vals.map.insert(qargs, properties); } self.instruction_durations = None; self.instruction_schedule_map = None; @@ -600,7 +600,7 @@ impl Target { if let (Some(error_prop), Some(props_)) = (error_dict_name.get(&qargs_), props.as_mut()) { - props_.setattr(py, "error", Some(error_prop.extract::()?))?; + props_.setattr(py, "error", error_prop.extract::>()?)?; } } } @@ -728,8 +728,8 @@ impl Target { let inst_sched_map_module = py.import_bound("qiskit.pulse.instruction_schedule_map")?; let inst_sched_map_class = inst_sched_map_module.getattr("InstructionScheduleMap")?; let out_inst_schedule_map = inst_sched_map_class.call0()?; - for (instruction, qargs) in self.gate_map.iter() { - for (qarg, properties) in qargs.map.iter() { + for (instruction, props_map) in self.gate_map.iter() { + for (qarg, properties) in props_map.map.iter() { // Directly getting calibration entry to invoke .get_schedule(). // This keeps PulseQobjDef unparsed. if let Some(properties) = properties { @@ -741,8 +741,9 @@ impl Target { } } } - self.instruction_schedule_map = Some(out_inst_schedule_map.clone().unbind()); - Ok(out_inst_schedule_map.unbind()) + let out_inst_schedule_map = out_inst_schedule_map.unbind(); + self.instruction_schedule_map = Some(out_inst_schedule_map.clone()); + Ok(out_inst_schedule_map) } /** @@ -754,12 +755,12 @@ impl Target { set: The set of qargs the gate instance applies to. */ #[pyo3(text_signature = "(operation, /,)")] - fn qargs_for_operation_name(&self, operation: String) -> PyResult>>> { + fn qargs_for_operation_name(&self, operation: String) -> PyResult> { if let Some(gate_map_oper) = self.gate_map.get(&operation) { if gate_map_oper.map.contains_key(&None) { return Ok(None); } - let qargs: Vec> = gate_map_oper.map.keys().cloned().collect(); + let qargs = gate_map_oper.keys(); Ok(Some(qargs)) } else { Err(PyKeyError::new_err(format!( diff --git a/crates/accelerate/src/target_transpiler/property_map.rs b/crates/accelerate/src/target_transpiler/property_map.rs index 6c728a4bb97d..0639a8e93d2c 100644 --- a/crates/accelerate/src/target_transpiler/property_map.rs +++ b/crates/accelerate/src/target_transpiler/property_map.rs @@ -13,7 +13,8 @@ use hashbrown::{hash_set::IntoIter as HashSetIntoIter, HashSet}; use indexmap::{map::IntoKeys, IndexMap}; use itertools::Itertools; -use pyo3::{exceptions::PyKeyError, prelude::*, pyclass, types::PySequence}; +use pyo3::types::{PyDict, PySet}; +use pyo3::{exceptions::PyKeyError, prelude::*, pyclass}; use super::instruction_properties::InstructionProperties; use super::qargs::{Qargs, QargsOrTuple}; @@ -61,9 +62,9 @@ impl PropsMapKeys { Py::new(slf.py(), iter) } - fn __eq__(slf: PyRef, other: Bound) -> PyResult { - for item in other.iter()? { - let qargs = item? + fn __eq__(slf: PyRef, other: Bound) -> PyResult { + for item in other.iter() { + let qargs = item .extract::>()? .map(|qargs| qargs.parse_qargs()); if !(slf.keys.contains(&qargs)) { @@ -122,7 +123,7 @@ impl PropsMap { PropsMap { map } } - fn __contains__(&self, key: Bound) -> bool { + fn __contains__(&self, key: &Bound) -> bool { if let Ok(key) = key.extract::>() { let qarg = key.map(|qarg| qarg.parse_qargs()); self.map.contains_key(&qarg) @@ -131,6 +132,24 @@ impl PropsMap { } } + fn __eq__(slf: PyRef, other: &Bound) -> PyResult { + if let Ok(dict) = other.downcast::() { + for key in dict.keys() { + if let Ok(qargs) = key.extract::>() { + let qargs = qargs.map(|qargs| qargs.parse_qargs()); + if !slf.map.contains_key(&qargs) { + return Ok(false); + } + } else { + return Ok(false); + } + } + Ok(true) + } else { + Ok(false) + } + } + fn __getitem__(&self, py: Python<'_>, key: Option) -> PyResult { let key = key.map(|qargs| qargs.parse_qargs()); if let Some(item) = self.map.get(&key) { diff --git a/qiskit/transpiler/target.py b/qiskit/transpiler/target.py index 787c83b3a72b..b487cb79f995 100644 --- a/qiskit/transpiler/target.py +++ b/qiskit/transpiler/target.py @@ -62,13 +62,13 @@ class InstructionProperties(InstructionProperties2): def __new__( cls, - *args, # pylint: disable=unused-argument duration=None, error=None, calibration=None, + *args, # pylint: disable=unused-argument **kwargs, # pylint: disable=unused-argument ): - return super(InstructionProperties, cls).__new__( + return InstructionProperties2.__new__( cls, duration=duration, error=error, calibration=calibration ) @@ -259,17 +259,6 @@ def operation_names(self): """Get the operation names in the target.""" return {x: None for x in super().operation_names}.keys() - def qargs_for_operation_name(self, operation): - """Get the qargs for a given operation name - - Args: - operation (str): The operation name to get qargs for - Returns: - set: The set of qargs the gate instance applies to. - """ - qargs = super().qargs_for_operation_name(operation) - return {x: None for x in qargs}.keys() if qargs else qargs - def _build_coupling_graph(self): self.coupling_graph = rx.PyDiGraph( # pylint: disable=attribute-defined-outside-init multigraph=False