Skip to content

Commit

Permalink
Add: more methods to Target in target.rs
Browse files Browse the repository at this point in the history
- Add FromPyObject trait to Hashable vec to receive Tuples and transform them directly into this type.
- Add operations_for_qargs for Target class in Rust side and Python.
- Fix return dict keys for `qargs_for_operation_name`.
- Add `timing_constrains` and `operation_from_name` to Python side.
- Other tweaks and fixes.
  • Loading branch information
raynelfss committed Apr 12, 2024
1 parent f58fb09 commit 04bca9f
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 2 deletions.
67 changes: 66 additions & 1 deletion crates/accelerate/src/target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ use std::hash::{Hash, Hasher};

use hashbrown::{HashMap, HashSet};
use pyo3::{
exceptions::PyTypeError,
prelude::*,
pyclass,
types::{PyDict, PyTuple},
types::{PyDict, PyList, PyTuple},
};

#[derive(Eq, PartialEq, Clone, Debug)]
Expand All @@ -40,6 +41,21 @@ impl<T: ToPyObject> IntoPy<PyObject> for HashableVec<T> {
}
}

impl<'a, 'b: 'a, T> FromPyObject<'b> for HashableVec<T>
where
Vec<T>: FromPyObject<'a>,
{
fn extract(ob: &'b PyAny) -> PyResult<Self> {
Ok(Self {
vec: ob.extract::<Vec<T>>()?,
})
}

fn extract_bound(ob: &Bound<'b, PyAny>) -> PyResult<Self> {
Self::extract(ob.clone().into_gil_ref())
}
}

#[pyclass(module = "qiskit._accelerate.target.InstructionProperties")]
pub struct InstructionProperties {
#[pyo3(get)]
Expand Down Expand Up @@ -118,6 +134,7 @@ pub struct Target {
// Maybe convert PyObjects into rust representations of Instruction and Data
#[pyo3(get)]
gate_map: HashMap<String, HashMap<HashableVec<u32>, PyObject>>,
#[pyo3(get)]
gate_name_map: HashMap<String, PyObject>,
global_operations: HashMap<usize, HashSet<String>>,
qarg_gate_map: HashMap<HashableVec<u32>, HashSet<String>>,
Expand Down Expand Up @@ -390,6 +407,54 @@ impl Target {
let qargs: Vec<HashableVec<u32>> = self.gate_map[&operation].clone().into_keys().collect();
Ok(Some(qargs))
}

#[pyo3(text_signature = "(/, operation)")]
fn operations_for_qargs(
&self,
py: Python<'_>,
isclass: &Bound<PyAny>,
qargs: Option<HashableVec<u32>>,
) -> PyResult<PyObject> {
let res = PyList::empty_bound(py);
if let Some(qargs) = qargs.clone() {
if qargs
.vec
.iter()
.any(|x| !(0..(self.num_qubits as u32)).contains(x))
{
// TODO: Throw Python Exception
return Err(PyTypeError::new_err(format!(
"{:?} not in target.",
qargs.vec
)));
}

for x in self.qarg_gate_map[&qargs].clone() {
res.append(self.gate_name_map[&x].clone())?;
}
if let Some(qarg) = self.global_operations.get(&qargs.vec.len()) {
for arg in qarg {
res.append(arg)?;
}
}
}
for op in self.gate_name_map.values() {
if isclass.call1((op,))?.extract::<bool>()? {
res.append(op)?;
}
}
if res.is_empty() {
if let Some(qargs) = qargs {
return Err(PyTypeError::new_err(format!(
"{:?} not in target",
qargs.vec
)));
} else {
return Err(PyTypeError::new_err(format!("{:?} not in target", qargs)));
}
}
Ok(res.to_object(py))
}
}

#[pymodule]
Expand Down
43 changes: 42 additions & 1 deletion qiskit/transpiler/_target.py
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ def qargs_for_operation_name(self, operation):
Returns:
set: The set of qargs the gate instance applies to.
"""
return self._Target.qargs_for_operation_name(operation)
return {x: None for x in self._Target.qargs_for_operation_name(operation)}.keys()

def durations(self):
"""Get an InstructionDurations object from the target
Expand All @@ -444,3 +444,44 @@ def durations(self):
out_durations.append((instruction, list(qarg), properties.duration, "s"))
self._Target.instruction_durations = InstructionDurations(out_durations, dt=self.dt)
return self._Target.instruction_durations

def timing_constraints(self):
"""Get an :class:`~qiskit.transpiler.TimingConstraints` object from the target
Returns:
TimingConstraints: The timing constraints represented in the ``Target``
"""
return TimingConstraints(
self.granularity, self.min_length, self.pulse_alignment, self.acquire_alignment
)

def operation_from_name(self, instruction):
"""Get the operation class object for a given name
Args:
instruction (str): The instruction name to get the
:class:`~qiskit.circuit.Instruction` instance for
Returns:
qiskit.circuit.Instruction: The Instruction instance corresponding to the
name. This also can also be the class for globally defined variable with
operations.
"""
return self._Target.gate_name_map[instruction]

def operation_names_for_qargs(self, qargs):
"""Get the operation names for a specified qargs tuple
Args:
qargs (tuple): A ``qargs`` tuple of the qubits to get the gates that apply
to it. For example, ``(0,)`` will return the set of all
instructions that apply to qubit 0. If set to ``None`` this will
return the names for any globally defined operations in the target.
Returns:
set: The set of operation names that apply to the specified ``qargs``.
Raises:
KeyError: If ``qargs`` is not in target
"""
self._Target.operation_names_for_qargs(inspect.isclass, qargs)


0 comments on commit 04bca9f

Please sign in to comment.