Skip to content

Commit

Permalink
Fix: Rest of failing tests in Target
Browse files Browse the repository at this point in the history
- Modify the `InstructionProperties` python wrapper.
   - InstructionProperties was not assigning properties to rust side.
- Make duration in `InstructionProperties` setable.
- Add `__eq__` method for `PropMap` to compare with other dicts.
- `PropMapKeys` can only be compared with a Set.
- Remove `qargs_for_operation_name` from `target.py`
- Other small tweaks and fixes.
  • Loading branch information
raynelfss committed May 8, 2024
1 parent 1d98941 commit 09cd63d
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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<f64>,
#[pyo3(get, set)]
pub error: Option<f64>,
Expand Down
25 changes: 13 additions & 12 deletions crates/accelerate/src/target_transpiler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ use qargs::{Qargs, QargsSet, QargsTuple};

use self::{
exceptions::{QiskitError, TranspilerError},
property_map::PropsMapKeys,
qargs::QargsOrTuple,
};

Expand All @@ -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<PyAny>) -> PyResult<bool> {
let inspect_module: Bound<PyModule> = py.import_bound("inspect")?;
let is_class_method: Bound<PyAny> = inspect_module.getattr("isclass")?;
is_class_method.call1((object,))?.extract::<bool>()
}

// 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<IndexMap<String, Bound<PyAny>>> {
let inspect_module: Bound<PyModule> =
py.import_bound("qiskit.circuit.library.standard_gates")?;
Expand All @@ -61,6 +62,7 @@ fn get_standard_gate_name_mapping(py: Python<'_>) -> PyResult<IndexMap<String, B
.extract::<IndexMap<String, Bound<PyAny>>>()
}

/// Helper function to obtain the qubit props list from some Target Properties.
fn qubit_props_list_from_props(
py: Python<'_>,
properties: &Bound<PyAny>,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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::<f64>()?))?;
props_.setattr(py, "error", error_prop.extract::<Option<f64>>()?)?;
}
}
}
Expand Down Expand Up @@ -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 {
Expand All @@ -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)
}

/**
Expand All @@ -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<Option<Vec<Option<Qargs>>>> {
fn qargs_for_operation_name(&self, operation: String) -> PyResult<Option<PropsMapKeys>> {
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<Option<Qargs>> = gate_map_oper.map.keys().cloned().collect();
let qargs = gate_map_oper.keys();
Ok(Some(qargs))
} else {
Err(PyKeyError::new_err(format!(
Expand Down
29 changes: 24 additions & 5 deletions crates/accelerate/src/target_transpiler/property_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -61,9 +62,9 @@ impl PropsMapKeys {
Py::new(slf.py(), iter)
}

fn __eq__(slf: PyRef<Self>, other: Bound<PySequence>) -> PyResult<bool> {
for item in other.iter()? {
let qargs = item?
fn __eq__(slf: PyRef<Self>, other: Bound<PySet>) -> PyResult<bool> {
for item in other.iter() {
let qargs = item
.extract::<Option<QargsOrTuple>>()?
.map(|qargs| qargs.parse_qargs());
if !(slf.keys.contains(&qargs)) {
Expand Down Expand Up @@ -122,7 +123,7 @@ impl PropsMap {
PropsMap { map }
}

fn __contains__(&self, key: Bound<PyAny>) -> bool {
fn __contains__(&self, key: &Bound<PyAny>) -> bool {
if let Ok(key) = key.extract::<Option<QargsOrTuple>>() {
let qarg = key.map(|qarg| qarg.parse_qargs());
self.map.contains_key(&qarg)
Expand All @@ -131,6 +132,24 @@ impl PropsMap {
}
}

fn __eq__(slf: PyRef<Self>, other: &Bound<PyAny>) -> PyResult<bool> {
if let Ok(dict) = other.downcast::<PyDict>() {
for key in dict.keys() {
if let Ok(qargs) = key.extract::<Option<QargsOrTuple>>() {
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<QargsOrTuple>) -> PyResult<PyObject> {
let key = key.map(|qargs| qargs.parse_qargs());
if let Some(item) = self.map.get(&key) {
Expand Down
15 changes: 2 additions & 13 deletions qiskit/transpiler/target.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
)

Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 09cd63d

Please sign in to comment.