Skip to content

Commit

Permalink
Docs: Add necessary docstrings to all new rust functions.
Browse files Browse the repository at this point in the history
- Remove duplicate Iterator in GateMap.
- Other small tweaks and fixes.
  • Loading branch information
raynelfss committed May 15, 2024
1 parent 37070b2 commit 7bfb9cd
Show file tree
Hide file tree
Showing 6 changed files with 521 additions and 493 deletions.
56 changes: 41 additions & 15 deletions crates/accelerate/src/target_transpiler/gate_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,32 +22,26 @@ use pyo3::{
};

type GateMapType = IndexMap<String, Py<PropsMap>>;
type GateMapIterType = IntoIter<String>;

// Creates a Key-Like object for the Gate Map keys.
// This is done in an effort to keep the insertion order of the keys.
key_like_set_iterator!(
GateMapKeys,
GateMapKeysIter,
GateMapIter,
keys,
String,
IntoIter<String>,
"",
"gate_map_keys"
);
#[pyclass]
pub struct GateMapIter {
iter: GateMapIterType,
}

#[pymethods]
impl GateMapIter {
fn __iter__(slf: PyRef<'_, Self>) -> PyRef<'_, Self> {
slf
}
fn __next__(mut slf: PyRefMut<'_, Self>) -> Option<String> {
slf.iter.next()
}
}
/**
Mapping of Instruction Names and ``PropsMaps`` (``Qargs``: ``InstructionProperties``) present
on the ``Target``.
This structure keeps track of which qubits an instruction is affecting and the properties of
said instruction on those qubits.
*/
#[pyclass(mapping, module = "qiskit._accelerate.target")]
#[derive(Debug, Clone)]
pub struct GateMap {
Expand All @@ -56,11 +50,13 @@ pub struct GateMap {

#[pymethods]
impl GateMap {
/// Create empty instance of a GateMap.
#[new]
pub fn new() -> Self {
Self::default()
}

/// Checks whether an instruction is present on the ``Target``'s gate map.
pub fn __contains__(&self, key: &Bound<PyAny>) -> bool {
if let Ok(key) = key.extract::<String>() {
self.map.contains_key(&key)
Expand All @@ -69,12 +65,20 @@ impl GateMap {
}
}

/// Check the equality of two gate_maps in the Python space.
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(key) = key.extract::<String>() {
if !slf.map.contains_key(&key) {
return Ok(false);
} else if let (Some(value), Ok(Some(other_value))) =
(slf.map.get(&key), dict.get_item(key))
{
let comparison = other_value.eq(value)?;
if !comparison {
return Ok(false);
}
}
} else {
return Ok(false);
Expand All @@ -86,6 +90,15 @@ impl GateMap {
}
}

/// Access a value in the GateMap using a Key.
///
/// Args:
/// key (str): The instruction name key.
///
/// Return:
/// ``PropsMap`` object at that slot.
/// Raises:
/// KeyError if the ``key`` is not in the ``GateMap``.
pub fn __getitem__(&self, py: Python<'_>, key: String) -> PyResult<Py<PropsMap>> {
if let Some(item) = self.map.get(&key) {
Ok(item.clone_ref(py))
Expand All @@ -97,6 +110,14 @@ impl GateMap {
}
}

/// Access a value in the GateMap using a Key.
///
/// Args:
/// key (str): The instruction name key.
/// default (Option[PyAny]): The default value to be returned.
///
/// Returns:
/// ``PropsMap`` value if found, otherwise returns ``default``.
#[pyo3(signature = (key, default=None))]
fn get(slf: PyRef<Self>, key: String, default: Option<Bound<PyAny>>) -> PyObject {
match slf.__getitem__(slf.py(), key) {
Expand All @@ -108,27 +129,32 @@ impl GateMap {
}
}

/// Returns number of present keys in the GateMap
fn __len__(slf: PyRef<Self>) -> usize {
slf.map.len()
}

/// Returns the iterator of the Keys in the GateMap.
pub fn __iter__(&self, py: Python<'_>) -> PyResult<Py<GateMapIter>> {
let iter = GateMapIter {
iter: self.keys().keys.into_iter(),
};
Py::new(py, iter)
}

/// Returns the Keys in the GateMap as an ordered set of Strings.
pub fn keys(&self) -> GateMapKeys {
GateMapKeys {
keys: self.map.keys().cloned().collect::<IndexSet<String>>(),
}
}

/// Returns the values of the GateMap as a list of ``PropsMap`` objects.
pub fn values(&self) -> Vec<Py<PropsMap>> {
self.map.values().cloned().collect_vec()
}

/// Returns they (keys, values) pairs as a list of (``str``, ``PropsMap``)
pub fn items(&self) -> Vec<(String, Py<PropsMap>)> {
self.map.clone().into_iter().collect_vec()
}
Expand Down
68 changes: 32 additions & 36 deletions crates/accelerate/src/target_transpiler/instruction_properties.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,14 @@ pub struct InstructionProperties {

#[pymethods]
impl InstructionProperties {
/**
Create a new ``InstructionProperties`` object
Args:
duration (Option<f64>): The duration, in seconds, of the instruction on the
specified set of qubits
error (Option<f64>): The average error rate for the instruction on the specified
set of qubits.
calibration (Option<PyObject>): The pulse representation of the instruction.
*/
/// Create a new ``InstructionProperties`` object
///
/// Args:
/// duration (Option<f64>): The duration, in seconds, of the instruction on the
/// specified set of qubits
/// error (Option<f64>): The average error rate for the instruction on the specified
/// set of qubits.
/// calibration (Option<PyObject>): The pulse representation of the instruction.
#[new]
#[pyo3(text_signature = "(/, duration: float | None = None,
error: float | None = None,
Expand All @@ -69,32 +67,30 @@ impl InstructionProperties {
instruction_prop
}

/**
The pulse representation of the instruction.
.. note::
This attribute always returns a Qiskit pulse program, but it is internally
wrapped by the :class:`.CalibrationEntry` to manage unbound parameters
and to uniformly handle different data representation,
for example, un-parsed Pulse Qobj JSON that a backend provider may provide.
This value can be overridden through the property setter in following manner.
When you set either :class:`.Schedule` or :class:`.ScheduleBlock` this is
always treated as a user-defined (custom) calibration and
the transpiler may automatically attach the calibration data to the output circuit.
This calibration data may appear in the wire format as an inline calibration,
which may further update the backend standard instruction set architecture.
If you are a backend provider who provides a default calibration data
that is not needed to be attached to the transpiled quantum circuit,
you can directly set :class:`.CalibrationEntry` instance to this attribute,
in which you should set :code:`user_provided=False` when you define
calibration data for the entry. End users can still intentionally utilize
the calibration data, for example, to run pulse-level simulation of the circuit.
However, such entry doesn't appear in the wire format, and backend must
use own definition to compile the circuit down to the execution format.
*/
/// The pulse representation of the instruction.
///
/// .. note::
///
/// This attribute always returns a Qiskit pulse program, but it is internally
/// wrapped by the :class:`.CalibrationEntry` to manage unbound parameters
/// and to uniformly handle different data representation,
/// for example, un-parsed Pulse Qobj JSON that a backend provider may provide.
///
/// This value can be overridden through the property setter in following manner.
/// When you set either :class:`.Schedule` or :class:`.ScheduleBlock` this is
/// always treated as a user-defined (custom) calibration and
/// the transpiler may automatically attach the calibration data to the output circuit.
/// This calibration data may appear in the wire format as an inline calibration,
/// which may further update the backend standard instruction set architecture.
///
/// If you are a backend provider who provides a default calibration data
/// that is not needed to be attached to the transpiled quantum circuit,
/// you can directly set :class:`.CalibrationEntry` instance to this attribute,
/// in which you should set :code:`user_provided=False` when you define
/// calibration data for the entry. End users can still intentionally utilize
/// the calibration data, for example, to run pulse-level simulation of the circuit.
/// However, such entry doesn't appear in the wire format, and backend must
/// use own definition to compile the circuit down to the execution format.
#[getter]
pub fn get_calibration(&self, py: Python<'_>) -> PyResult<PyObject> {
if !&self._calibration.is_none(py) {
Expand Down
10 changes: 10 additions & 0 deletions crates/accelerate/src/target_transpiler/macro_rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
// copyright notice, and modified files need to carry a notice indicating
// that they have been altered from the originals.

/**
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! key_like_set_iterator {
($name:ident, $iter:ident, $keys:ident, $T:ty, $IterType:ty, $doc:literal, $pyrep:literal) => {
#[doc = $doc]
Expand Down Expand Up @@ -194,6 +198,12 @@ 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]
Expand Down
Loading

0 comments on commit 7bfb9cd

Please sign in to comment.