Skip to content

Commit

Permalink
Resolve qasm3 warnings.
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinhartman committed Apr 2, 2024
1 parent 2cbdecd commit fe0bb69
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 62 deletions.
4 changes: 2 additions & 2 deletions crates/qasm3/src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ impl BuilderState {
let gate = self.symbols.gates.get(gate_id).ok_or_else(|| {
QASM3ImporterError::new_err(format!("internal error: unknown gate {:?}", gate_id))
})?;
let params = PyTuple::new(
let params = PyTuple::new_bound(
py,
call.params()
.as_ref()
Expand Down Expand Up @@ -206,7 +206,7 @@ impl BuilderState {
}
}
}
PyTuple::new(py, qubits.values())
PyTuple::new_bound(py, qubits.values())
} else {
// If there's no qargs (represented in the ASG with a `None` rather than an empty
// vector), it's a barrier over all in-scope qubits, which is all qubits, unless we're
Expand Down
65 changes: 35 additions & 30 deletions crates/qasm3/src/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub trait PyRegister {
// or at a minimum
// fn iter<'a>(&'a self, py: Python<'a>) -> ::pyo3::types::iter::PyListIterator<'a>;
// but we can't use the former before Rust 1.75 and the latter before PyO3 0.21.
fn bit_list<'a>(&'a self, py: Python<'a>) -> &'a PyList;
fn bit_list<'a>(&'a self, py: Python<'a>) -> &Bound<'a, PyList>;
}

macro_rules! register_type {
Expand All @@ -43,13 +43,13 @@ macro_rules! register_type {
fn bit(&self, py: Python, index: usize) -> PyResult<Py<PyAny>> {
// Unfortunately, `PyList::get_item_unchecked` isn't usable with the stable ABI.
self.items
.as_ref(py)
.bind(py)
.get_item(index)
.map(|item| item.into_py(py))
}

fn bit_list<'a>(&'a self, py: Python<'a>) -> &'a PyList {
self.items.as_ref(py)
fn bit_list<'a>(&'a self, py: Python<'a>) -> &Bound<'a, PyList> {
self.items.bind(py)
}
}

Expand Down Expand Up @@ -106,9 +106,9 @@ impl PyGate {
A: IntoPy<Py<PyTuple>>,
{
let args = args.into_py(py);
let received_num_params = args.as_ref(py).len();
let received_num_params = args.bind(py).len();
if received_num_params == self.num_params {
self.constructor.call1(py, args.as_ref(py))
self.constructor.call1(py, args.bind(py))
} else {
Err(QASM3ImporterError::new_err(format!(
"internal error: wrong number of params for {} (got {}, expected {})",
Expand Down Expand Up @@ -143,11 +143,11 @@ impl PyGate {
}
}

fn __repr__<'py>(&self, py: Python<'py>) -> PyResult<&'py PyAny> {
PyString::new(py, "CustomGate(name={!r}, num_params={}, num_qubits={})").call_method1(
fn __repr__<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyAny>> {
PyString::new_bound(py, "CustomGate(name={!r}, num_params={}, num_qubits={})").call_method1(
"format",
(
PyString::new(py, &self.name),
PyString::new_bound(py, &self.name),
self.num_params,
self.num_qubits,
),
Expand All @@ -156,7 +156,7 @@ impl PyGate {

fn __reduce__(&self, py: Python) -> Py<PyTuple> {
(
PyType::new::<PyGate>(py),
PyType::new_bound::<PyGate>(py),
(
self.constructor.clone_ref(py),
&self.name,
Expand Down Expand Up @@ -188,27 +188,30 @@ pub struct PyCircuitModule {
impl PyCircuitModule {
/// Import the necessary components from `qiskit.circuit`.
pub fn import(py: Python) -> PyResult<Self> {
let module = PyModule::import(py, "qiskit.circuit")?;
let module = PyModule::import_bound(py, "qiskit.circuit")?;
Ok(Self {
circuit: module
.getattr("QuantumCircuit")?
.downcast::<PyType>()?
.into_py(py),
.downcast_into::<PyType>()?
.unbind(),
qreg: module
.getattr("QuantumRegister")?
.downcast::<PyType>()?
.into_py(py),
qubit: module.getattr("Qubit")?.downcast::<PyType>()?.into_py(py),
.downcast_into::<PyType>()?
.unbind(),
qubit: module.getattr("Qubit")?.downcast_into::<PyType>()?.unbind(),
creg: module
.getattr("ClassicalRegister")?
.downcast::<PyType>()?
.into_py(py),
clbit: module.getattr("Clbit")?.downcast::<PyType>()?.into_py(py),
.downcast_into::<PyType>()?
.unbind(),
clbit: module.getattr("Clbit")?.downcast_into::<PyType>()?.unbind(),
circuit_instruction: module
.getattr("CircuitInstruction")?
.downcast::<PyType>()?
.into_py(py),
barrier: module.getattr("Barrier")?.downcast::<PyType>()?.into_py(py),
.downcast_into::<PyType>()?
.unbind(),
barrier: module
.getattr("Barrier")?
.downcast_into::<PyType>()?
.unbind(),
// Measure is a singleton, so just store the object.
measure: module.getattr("Measure")?.call0()?.into_py(py),
})
Expand All @@ -227,9 +230,10 @@ impl PyCircuitModule {
let qreg = self.qreg.call1(py, (size, name.into_py(py)))?;
Ok(PyQuantumRegister {
items: qreg
.getattr(py, "_bits")?
.downcast::<PyList>(py)?
.into_py(py),
.bind(py)
.getattr("_bits")?
.downcast_into::<PyList>()?
.unbind(),
object: qreg,
})
}
Expand All @@ -247,9 +251,10 @@ impl PyCircuitModule {
let creg = self.creg.call1(py, (size, name.into_py(py)))?;
Ok(PyClassicalRegister {
items: creg
.getattr(py, "_bits")?
.downcast::<PyList>(py)?
.into_py(py),
.bind(py)
.getattr("_bits")?
.downcast_into::<PyList>()?
.unbind(),
object: creg,
})
}
Expand Down Expand Up @@ -291,8 +296,8 @@ pub struct PyCircuit(Py<PyAny>);

impl PyCircuit {
/// Untyped access to the inner Python object.
pub fn inner<'a>(&'a self, py: Python<'a>) -> &'a PyAny {
self.0.as_ref(py)
pub fn inner<'a>(&'a self, py: Python<'a>) -> &Bound<'a, PyAny> {
self.0.bind(py)
}

pub fn add_qreg(&self, py: Python, qreg: &PyQuantumRegister) -> PyResult<()> {
Expand Down
17 changes: 10 additions & 7 deletions crates/qasm3/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ struct BroadcastQubitsIter<'py> {
}

impl<'py> Iterator for BroadcastQubitsIter<'py> {
type Item = &'py PyTuple;
type Item = Bound<'py, PyTuple>;

fn next(&mut self) -> Option<Self::Item> {
if self.offset >= self.len {
Expand All @@ -122,7 +122,10 @@ impl<'py> Iterator for BroadcastQubitsIter<'py> {
BroadcastItem::Register(bits) => bits[offset].clone_ref(self.py),
};
self.offset += 1;
Some(PyTuple::new(self.py, self.items.iter().map(to_scalar)))
Some(PyTuple::new_bound(
self.py,
self.items.iter().map(to_scalar),
))
}

fn size_hint(&self) -> (usize, Option<usize>) {
Expand All @@ -140,7 +143,7 @@ struct BroadcastMeasureIter<'a, 'py> {
}

impl<'a, 'py> Iterator for BroadcastMeasureIter<'a, 'py> {
type Item = (&'py PyTuple, &'py PyTuple);
type Item = (Bound<'py, PyTuple>, Bound<'py, PyTuple>);

fn next(&mut self) -> Option<Self::Item> {
if self.offset >= self.len {
Expand All @@ -153,8 +156,8 @@ impl<'a, 'py> Iterator for BroadcastMeasureIter<'a, 'py> {
};
self.offset += 1;
Some((
PyTuple::new(self.py, &[to_scalar(self.qarg)]),
PyTuple::new(self.py, &[to_scalar(self.carg)]),
PyTuple::new_bound(self.py, &[to_scalar(self.qarg)]),
PyTuple::new_bound(self.py, &[to_scalar(self.carg)]),
))
}

Expand Down Expand Up @@ -321,7 +324,7 @@ pub fn broadcast_qubits<'a, 'py, T>(
our_symbols: &PySymbolTable,
ast_symbols: &SymbolTable,
qargs: T,
) -> PyResult<impl Iterator<Item = &'py PyTuple>>
) -> PyResult<impl Iterator<Item = Bound<'py, PyTuple>>>
where
T: IntoIterator<Item = &'a asg::TExpr> + 'a,
{
Expand Down Expand Up @@ -358,7 +361,7 @@ pub fn broadcast_measure<'a, 'py>(
py: Python<'py>,
qarg: &'a BroadcastItem,
carg: &'a BroadcastItem,
) -> PyResult<impl Iterator<Item = (&'py PyTuple, &'py PyTuple)> + 'a>
) -> PyResult<impl Iterator<Item = (Bound<'py, PyTuple>, Bound<'py, PyTuple>)> + 'a>
where
'py: 'a,
{
Expand Down
53 changes: 30 additions & 23 deletions crates/qasm3/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ mod error;
mod expr;

use std::ffi::OsString;
use std::ops::Deref;
use std::path::{Path, PathBuf};

use hashbrown::HashMap;
Expand All @@ -24,6 +25,7 @@ use pyo3::prelude::*;
use pyo3::types::{PyModule, PyTuple};

use oq3_semantics::syntax_to_semantics::parse_source_string;
use pyo3::pybacked::PyBackedStr;

use crate::error::QASM3ImporterError;

Expand Down Expand Up @@ -58,14 +60,15 @@ const STDGATES_INC_CUSTOM_GATES_ATTR: &str = "STDGATES_INC_GATES";
#[pyfunction]
#[pyo3(pass_module, signature = (source, /, *, custom_gates=None, include_path=None))]
pub fn loads(
module: &PyModule,
module: Bound<PyModule>,
py: Python,
source: String,
custom_gates: Option<Vec<circuit::PyGate>>,
include_path: Option<Vec<OsString>>,
) -> PyResult<circuit::PyCircuit> {
let default_include_path = || -> PyResult<Vec<OsString>> {
Ok(vec![Path::new(module.filename()?)
let filename: PyBackedStr = module.filename()?.try_into()?;
Ok(vec![Path::new(filename.deref())
.parent()
.unwrap()
.join(["qasm", "libs", "dummy"].iter().collect::<PathBuf>())
Expand Down Expand Up @@ -130,34 +133,35 @@ pub fn loads(
signature = (pathlike_or_filelike, /, *, custom_gates=None, include_path=None),
)]
pub fn load(
module: &PyModule,
module: Bound<PyModule>,
py: Python,
pathlike_or_filelike: &PyAny,
pathlike_or_filelike: Bound<PyAny>,
custom_gates: Option<Vec<circuit::PyGate>>,
include_path: Option<Vec<OsString>>,
) -> PyResult<circuit::PyCircuit> {
let source =
if pathlike_or_filelike.is_instance(PyModule::import(py, "io")?.getattr("TextIOBase")?)? {
pathlike_or_filelike
.call_method0("read")?
.extract::<String>()?
} else {
let path = PyModule::import(py, "os")?
.getattr("fspath")?
.call1((pathlike_or_filelike,))?
.extract::<OsString>()?;
::std::fs::read_to_string(&path).map_err(|err| {
QASM3ImporterError::new_err(format!("failed to read file '{:?}': {:?}", &path, err))
})?
};
let source = if pathlike_or_filelike
.is_instance(&PyModule::import_bound(py, "io")?.getattr("TextIOBase")?)?
{
pathlike_or_filelike
.call_method0("read")?
.extract::<String>()?
} else {
let path = PyModule::import_bound(py, "os")?
.getattr("fspath")?
.call1((pathlike_or_filelike,))?
.extract::<OsString>()?;
::std::fs::read_to_string(&path).map_err(|err| {
QASM3ImporterError::new_err(format!("failed to read file '{:?}': {:?}", &path, err))
})?
};
loads(module, py, source, custom_gates, include_path)
}

/// Create a suitable sequence for use with the ``custom_gates`` of :func:`load` and :func:`loads`,
/// as a Python object on the Python heap, so we can re-use it, and potentially expose it has a
/// data attribute to users.
fn stdgates_inc_gates(py: Python) -> PyResult<&PyTuple> {
let library = PyModule::import(py, "qiskit.circuit.library")?;
fn stdgates_inc_gates(py: Python) -> PyResult<Bound<PyTuple>> {
let library = PyModule::import_bound(py, "qiskit.circuit.library")?;
let stdlib_gate = |qiskit_class, name, num_params, num_qubits| -> PyResult<Py<PyAny>> {
Ok(circuit::PyGate::new(
py,
Expand All @@ -168,7 +172,7 @@ fn stdgates_inc_gates(py: Python) -> PyResult<&PyTuple> {
)
.into_py(py))
};
Ok(PyTuple::new(
Ok(PyTuple::new_bound(
py,
vec![
stdlib_gate("PhaseGate", "p", 1, 1)?,
Expand Down Expand Up @@ -210,10 +214,13 @@ fn stdgates_inc_gates(py: Python) -> PyResult<&PyTuple> {
/// Internal module supplying the OpenQASM 3 import capabilities. The entries in it should largely
/// be re-exposed directly to public Python space.
#[pymodule]
fn _qasm3(py: Python<'_>, module: &PyModule) -> PyResult<()> {
fn _qasm3(module: &Bound<PyModule>) -> PyResult<()> {
module.add_function(wrap_pyfunction!(loads, module)?)?;
module.add_function(wrap_pyfunction!(load, module)?)?;
module.add_class::<circuit::PyGate>()?;
module.add(STDGATES_INC_CUSTOM_GATES_ATTR, stdgates_inc_gates(py)?)?;
module.add(
STDGATES_INC_CUSTOM_GATES_ATTR,
stdgates_inc_gates(module.py())?,
)?;
Ok(())
}

0 comments on commit fe0bb69

Please sign in to comment.