Skip to content

Commit

Permalink
Fix: Use GILOneCell and remove Qargs
Browse files Browse the repository at this point in the history
- Use `GILOneCell` to import python modules only once at initialization.
- Remove the custom data structure `Qargs` to avoid conversion overhead.
- `Qargs` does not use `PhysicalQubits`, `u32` is used instead.
- Fix `__setstate__ `and `__getstate__` methods for `PropsMap`, `GateMap`, and `key_like_set_iterator` macro_rule.
- Update code to use the new structures.
- TODO: Fix broken tests.
  • Loading branch information
raynelfss committed May 20, 2024
1 parent a957406 commit a3fcd78
Show file tree
Hide file tree
Showing 8 changed files with 355 additions and 699 deletions.
10 changes: 5 additions & 5 deletions crates/accelerate/src/target_transpiler/gate_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ impl GateMap {
return Ok(false);
}
}
Ok(true)
Ok(slf.map.len() == dict.len())
} else {
Ok(false)
}
Expand Down Expand Up @@ -159,13 +159,13 @@ impl GateMap {
self.map.clone().into_iter().collect_vec()
}

fn __setstate__(&mut self, state: (GateMapType,)) -> PyResult<()> {
self.map = state.0;
pub fn __setstate__(&mut self, state: Vec<(String, Py<PropsMap>)>) -> PyResult<()> {
self.map = IndexMap::from_iter(state);
Ok(())
}

fn __getstate__(&self) -> (GateMapType,) {
(self.map.clone(),)
pub fn __getstate__(&self) -> Vec<(String, Py<PropsMap>)> {
self.items()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pub struct InstructionProperties {
#[pyo3(get, set)]
pub error: Option<f64>,
#[pyo3(get)]
_calibration: PyObject,
pub _calibration: PyObject,
}

#[pymethods]
Expand Down
230 changes: 0 additions & 230 deletions crates/accelerate/src/target_transpiler/macro_rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,13 +151,6 @@ macro_rules! key_like_set_iterator {
Ok(slf.$keys.contains(&obj))
}

fn __repr__(slf: PyRef<Self>) -> String {
let mut output = format!("{}([", $pyrep);
output.push_str(slf.$keys.iter().join(", ").as_str());
output.push_str("])");
output
}

fn __getstate__(&self) -> (HashSet<$T>,) {
return (self.$keys.clone().into_iter().collect::<HashSet<$T>>(),);
}
Expand Down Expand Up @@ -198,227 +191,4 @@ macro_rules! key_like_set_iterator {
};
}

/**
Qargs oriented variant of the ``key_like_set_iterator`` macro.
Creates an ordered set key-like collection that will be preserve insertion order in Python
while keeping the convenience of the ``set`` data structure.
*/
macro_rules! qargs_key_like_set_iterator {
($name:ident, $iter:ident, $keys:ident, $IterType:ty, $doc:literal, $pyrep:literal) => {
#[doc = $doc]
#[pyclass(sequence, module = "qiskit._accelerate.target")]
#[derive(Debug, Clone)]
pub struct $name {
pub $keys: IndexSet<Option<Qargs>>,
}

#[pymethods]
impl $name {
#[new]
fn new() -> Self {
Self::default()
}

fn __iter__(slf: PyRef<Self>) -> PyResult<Py<$iter>> {
let iter = $iter {
iter: slf.$keys.clone().into_iter(),
};
Py::new(slf.py(), iter)
}

fn __eq__(slf: PyRef<Self>, other: Bound<PyAny>) -> PyResult<bool> {
if let Ok(set) = other.downcast::<PySet>() {
for item in set.iter() {
let key = item
.extract::<Option<QargsOrTuple>>()?
.map(|qargs| qargs.parse_qargs());
if !(slf.$keys.contains(&key)) {
return Ok(false);
}
}
} else if let Ok(self_like) = other.extract::<Self>() {
for item in self_like.$keys.iter() {
if !(slf.$keys.contains(item)) {
return Ok(false);
}
}
}

Ok(true)
}

fn __len__(slf: PyRef<Self>) -> usize {
slf.$keys.len()
}

fn __sub__(&self, other: &Bound<PyAny>) -> PyResult<Self> {
self.difference(other)
}

fn union(&self, other: &Bound<PyAny>) -> PyResult<Self> {
if let Ok(set) = other.extract::<Self>() {
Ok(Self {
$keys: self.$keys.union(&set.$keys).cloned().collect(),
})
} else if let Ok(set) = other.extract::<HashSet<Option<QargsOrTuple>>>() {
let set: HashSet<Option<Qargs>> = set
.into_iter()
.map(|x| x.map(|y| y.parse_qargs()))
.collect();
Ok(Self {
$keys: self
.$keys
.iter()
.cloned()
.collect::<HashSet<Option<Qargs>>>()
.union(&set)
.cloned()
.collect(),
})
} else {
Err(PyKeyError::new_err(
"Could not perform union, Wrong Key Types",
))
}
}

fn intersection(&self, other: &Bound<PyAny>) -> PyResult<Self> {
if let Ok(set) = other.extract::<Self>() {
Ok(Self {
$keys: self.$keys.intersection(&set.$keys).cloned().collect(),
})
} else if let Ok(set) = other.extract::<HashSet<Option<QargsOrTuple>>>() {
let set: HashSet<Option<Qargs>> = set
.into_iter()
.map(|x| x.map(|y| y.parse_qargs()))
.collect();
Ok(Self {
$keys: self
.$keys
.iter()
.cloned()
.collect::<HashSet<Option<Qargs>>>()
.intersection(&set)
.cloned()
.collect(),
})
} else {
Err(PyKeyError::new_err(
"Could not perform intersection, Wrong Key Types",
))
}
}

fn difference(&self, other: &Bound<PyAny>) -> PyResult<Self> {
if let Ok(set) = other.extract::<Self>() {
Ok(Self {
$keys: self.$keys.difference(&set.$keys).cloned().collect(),
})
} else if let Ok(set) = other.extract::<HashSet<Option<QargsOrTuple>>>() {
let set: HashSet<Option<Qargs>> = set
.into_iter()
.map(|x| x.map(|y| y.parse_qargs()))
.collect();
Ok(Self {
$keys: self
.$keys
.iter()
.cloned()
.collect::<HashSet<Option<Qargs>>>()
.difference(&set)
.cloned()
.collect(),
})
} else {
Err(PyKeyError::new_err(
"Could not perform difference, Wrong Key Types",
))
}
}

fn __ior__(&mut self, other: &Bound<PyAny>) -> PyResult<()> {
self.$keys = self.union(other)?.$keys;
Ok(())
}

fn __iand__(&mut self, other: &Bound<PyAny>) -> PyResult<()> {
self.$keys = self.intersection(other)?.$keys;
Ok(())
}

fn __isub__(&mut self, other: &Bound<PyAny>) -> PyResult<()> {
self.$keys = self.difference(other)?.$keys;
Ok(())
}

fn __contains__(slf: PyRef<Self>, obj: Option<QargsOrTuple>) -> PyResult<bool> {
let obj = obj.map(|obj| obj.parse_qargs());
Ok(slf.$keys.contains(&obj))
}

fn __repr__(slf: PyRef<Self>) -> String {
let mut output = format!("{}[(", $pyrep);
output.push_str(
slf.$keys
.iter()
.map(|x| {
if let Some(x) = x {
x.to_string()
} else {
"None".to_owned()
}
})
.join(", ")
.as_str(),
);
output.push(']');
output
}

fn __getstate__(&self) -> (HashSet<Option<Qargs>>,) {
return (self
.$keys
.clone()
.into_iter()
.collect::<HashSet<Option<Qargs>>>(),);
}

fn __setstate__(&mut self, state: (HashSet<Option<Qargs>>,)) -> PyResult<()> {
self.$keys = state.0.into_iter().collect::<IndexSet<Option<Qargs>>>();
Ok(())
}
}

impl Default for $name {
fn default() -> Self {
Self {
$keys: IndexSet::new(),
}
}
}

#[pyclass]
pub struct $iter {
pub iter: $IterType,
}

#[pymethods]
impl $iter {
fn __next__(mut slf: PyRefMut<Self>) -> Option<Option<Qargs>> {
slf.iter.next()
}

fn __iter__(slf: PyRef<Self>) -> PyRef<Self> {
slf
}

fn __length_hint__(slf: PyRef<Self>) -> usize {
slf.iter.len()
}
}
};
}

pub(crate) use key_like_set_iterator;
pub(crate) use qargs_key_like_set_iterator;
Loading

0 comments on commit a3fcd78

Please sign in to comment.