Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move QuantumCircuit.assign_parameters to Rust (backport #12794) #12878

Merged
merged 1 commit into from
Aug 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
676 changes: 402 additions & 274 deletions crates/circuit/src/circuit_data.rs

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions crates/circuit/src/imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,12 @@ pub static SINGLETON_CONTROLLED_GATE: ImportOnceCell =
ImportOnceCell::new("qiskit.circuit.singleton", "SingletonControlledGate");
pub static CONTROLLED_GATE: ImportOnceCell =
ImportOnceCell::new("qiskit.circuit", "ControlledGate");
pub static ANNOTATED_OPERATION: ImportOnceCell =
ImportOnceCell::new("qiskit.circuit", "AnnotatedOperation");
pub static DEEPCOPY: ImportOnceCell = ImportOnceCell::new("copy", "deepcopy");
pub static QI_OPERATOR: ImportOnceCell = ImportOnceCell::new("qiskit.quantum_info", "Operator");
pub static WARNINGS_WARN: ImportOnceCell = ImportOnceCell::new("warnings", "warn");
pub static UUID: ImportOnceCell = ImportOnceCell::new("uuid", "UUID");

/// A mapping from the enum variant in crate::operations::StandardGate to the python
/// module path and class name to import it. This is used to populate the conversion table
Expand Down
66 changes: 54 additions & 12 deletions crates/circuit/src/operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use smallvec::smallvec;
use numpy::IntoPyArray;
use numpy::PyReadonlyArray2;
use pyo3::prelude::*;
use pyo3::types::{IntoPyDict, PyTuple};
use pyo3::types::{IntoPyDict, PyFloat, PyIterator, PyTuple};
use pyo3::{intern, IntoPy, Python};

#[derive(Clone, Debug)]
Expand All @@ -37,17 +37,13 @@ pub enum Param {

impl<'py> FromPyObject<'py> for Param {
fn extract_bound(b: &Bound<'py, PyAny>) -> Result<Self, PyErr> {
Ok(
if b.is_instance(PARAMETER_EXPRESSION.get_bound(b.py()))?
|| b.is_instance(QUANTUM_CIRCUIT.get_bound(b.py()))?
{
Param::ParameterExpression(b.clone().unbind())
} else if let Ok(val) = b.extract::<f64>() {
Param::Float(val)
} else {
Param::Obj(b.clone().unbind())
},
)
Ok(if b.is_instance(PARAMETER_EXPRESSION.get_bound(b.py()))? {
Param::ParameterExpression(b.clone().unbind())
} else if let Ok(val) = b.extract::<f64>() {
Param::Float(val)
} else {
Param::Obj(b.clone().unbind())
})
}
}

Expand All @@ -71,6 +67,52 @@ impl ToPyObject for Param {
}
}

impl Param {
/// Get an iterator over any Python-space `Parameter` instances tracked within this `Param`.
pub fn iter_parameters<'py>(&self, py: Python<'py>) -> PyResult<ParamParameterIter<'py>> {
let parameters_attr = intern!(py, "parameters");
match self {
Param::Float(_) => Ok(ParamParameterIter(None)),
Param::ParameterExpression(expr) => Ok(ParamParameterIter(Some(
expr.bind(py).getattr(parameters_attr)?.iter()?,
))),
Param::Obj(obj) => {
let obj = obj.bind(py);
if obj.is_instance(QUANTUM_CIRCUIT.get_bound(py))? {
Ok(ParamParameterIter(Some(
obj.getattr(parameters_attr)?.iter()?,
)))
} else {
Ok(ParamParameterIter(None))
}
}
}
}

/// Extract from a Python object without numeric coercion to float. The default conversion will
/// coerce integers into floats, but in things like `assign_parameters`, this is not always
/// desirable.
pub fn extract_no_coerce(ob: &Bound<PyAny>) -> PyResult<Self> {
Ok(if ob.is_instance_of::<PyFloat>() {
Param::Float(ob.extract()?)
} else if ob.is_instance(PARAMETER_EXPRESSION.get_bound(ob.py()))? {
Param::ParameterExpression(ob.clone().unbind())
} else {
Param::Obj(ob.clone().unbind())
})
}
}

/// Struct to provide iteration over Python-space `Parameter` instances within a `Param`.
pub struct ParamParameterIter<'py>(Option<Bound<'py, PyIterator>>);
impl<'py> Iterator for ParamParameterIter<'py> {
type Item = PyResult<Bound<'py, PyAny>>;

fn next(&mut self) -> Option<Self::Item> {
self.0.as_mut().and_then(|iter| iter.next())
}
}

/// Trait for generic circuit operations these define the common attributes
/// needed for something to be addable to the circuit struct
pub trait Operation {
Expand Down
Loading
Loading