Skip to content

Commit

Permalink
feat: Update pyo3 dep to 0.21
Browse files Browse the repository at this point in the history
  • Loading branch information
aborgna-q committed Apr 16, 2024
1 parent 8576c49 commit 677adab
Show file tree
Hide file tree
Showing 11 changed files with 71 additions and 65 deletions.
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ missing_docs = "warn"
tket2 = { path = "./tket2" }
quantinuum-hugr = "0.2"
portgraph = "0.11"
pyo3 = "0.20"
pyo3 = "0.21.2"
itertools = "0.12.0"
tket-json-rs = "0.3.0"
tket-json-rs = "0.4.0"
tracing = "0.1.37"
portmatching = "0.3.1"
bytemuck = "1.14.0"
Expand Down
22 changes: 11 additions & 11 deletions tket2-py/src/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,25 @@ pub use self::cost::PyCircuitCost;
pub use tket2::{Pauli, Tk2Op};

/// The module definition
pub fn module(py: Python) -> PyResult<&PyModule> {
let m = PyModule::new(py, "_circuit")?;
pub fn module(py: Python<'_>) -> PyResult<Bound<'_, PyModule>> {
let m = PyModule::new_bound(py, "_circuit")?;
m.add_class::<Tk2Circuit>()?;
m.add_class::<PyNode>()?;
m.add_class::<PyCircuitCost>()?;
m.add_class::<Tk2Op>()?;
m.add_class::<Pauli>()?;

m.add_function(wrap_pyfunction!(validate_hugr, m)?)?;
m.add_function(wrap_pyfunction!(to_hugr_dot, m)?)?;
m.add_function(wrap_pyfunction!(validate_hugr, &m)?)?;
m.add_function(wrap_pyfunction!(to_hugr_dot, &m)?)?;

m.add("HugrError", py.get_type::<PyHugrError>())?;
m.add("BuildError", py.get_type::<PyBuildError>())?;
m.add("ValidationError", py.get_type::<PyValidationError>())?;
m.add("HugrError", py.get_type_bound::<PyHugrError>())?;
m.add("BuildError", py.get_type_bound::<PyBuildError>())?;
m.add("ValidationError", py.get_type_bound::<PyValidationError>())?;
m.add(
"HUGRSerializationError",
py.get_type::<PyHUGRSerializationError>(),
py.get_type_bound::<PyHUGRSerializationError>(),
)?;
m.add("OpConvertError", py.get_type::<PyOpConvertError>())?;
m.add("OpConvertError", py.get_type_bound::<PyOpConvertError>())?;

Ok(m)
}
Expand Down Expand Up @@ -76,13 +76,13 @@ create_py_exception!(

/// Run the validation checks on a circuit.
#[pyfunction]
pub fn validate_hugr(c: &PyAny) -> PyResult<()> {
pub fn validate_hugr(c: &Bound<PyAny>) -> PyResult<()> {
try_with_hugr(c, |hugr, _| hugr.validate(&REGISTRY))
}

/// Return a Graphviz DOT string representation of the circuit.
#[pyfunction]
pub fn to_hugr_dot(c: &PyAny) -> PyResult<String> {
pub fn to_hugr_dot(c: &Bound<PyAny>) -> PyResult<String> {
with_hugr(c, |hugr, _| hugr.dot_string())
}

Expand Down
29 changes: 16 additions & 13 deletions tket2-py/src/circuit/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
use hugr::ops::OpType;
use pyo3::exceptions::{PyAttributeError, PyValueError};
use pyo3::{prelude::*, PyTypeInfo};
use pyo3::types::PyAnyMethods;
use pyo3::{
pyclass, pymethods, Bound, FromPyObject, PyAny, PyErr, PyResult, PyTypeInfo, Python, ToPyObject,
};

use derive_more::From;
use hugr::{Hugr, HugrView};
Expand Down Expand Up @@ -50,14 +53,14 @@ pub struct Tk2Circuit {
impl Tk2Circuit {
/// Convert a tket1 circuit to a [`Tk2Circuit`].
#[new]
pub fn from_tket1(circ: &PyAny) -> PyResult<Self> {
pub fn from_tket1(circ: &Bound<PyAny>) -> PyResult<Self> {
Ok(Self {
hugr: with_hugr(circ, |hugr, _| hugr)?,
})
}

/// Convert the [`Tk2Circuit`] to a tket1 circuit.
pub fn to_tket1<'py>(&self, py: Python<'py>) -> PyResult<&'py PyAny> {
pub fn to_tket1<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyAny>> {
SerialCircuit::encode(&self.hugr)
.convert_pyerrs()?
.to_tket1(py)
Expand Down Expand Up @@ -108,7 +111,7 @@ impl Tk2Circuit {
/// `__eq__`, `__int__`, and integer `__div__`.
///
/// :returns: The sum of all operation costs.
pub fn circuit_cost<'py>(&self, cost_fn: &'py PyAny) -> PyResult<&'py PyAny> {
pub fn circuit_cost<'py>(&self, cost_fn: &Bound<'py, PyAny>) -> PyResult<Bound<'py, PyAny>> {
let py = cost_fn.py();
let cost_fn = |op: &OpType| -> PyResult<PyCircuitCost> {
let tk2_op: Tk2Op = op.try_into().map_err(|e| {
Expand All @@ -122,7 +125,7 @@ impl Tk2Circuit {
})
};
let circ_cost = self.hugr.circuit_cost(cost_fn)?;
Ok(circ_cost.cost.into_ref(py))
Ok(circ_cost.cost.into_bound(py))
}

/// Returns a hash of the circuit.
Expand All @@ -141,7 +144,7 @@ impl Tk2Circuit {
}

/// Copy the circuit.
pub fn __deepcopy__(&self, _memo: Py<PyAny>) -> PyResult<Self> {
pub fn __deepcopy__(&self, _memo: Bound<PyAny>) -> PyResult<Self> {
Ok(self.clone())
}
}
Expand All @@ -165,23 +168,23 @@ pub enum CircuitType {

impl CircuitType {
/// Converts a `Hugr` into the format indicated by the flag.
pub fn convert(self, py: Python, hugr: Hugr) -> PyResult<&PyAny> {
pub fn convert(self, py: Python, hugr: Hugr) -> PyResult<Bound<PyAny>> {
match self {
CircuitType::Tket1 => SerialCircuit::encode(&hugr).convert_pyerrs()?.to_tket1(py),
CircuitType::Tket2 => Ok(Py::new(py, Tk2Circuit { hugr })?.into_ref(py)),
CircuitType::Tket2 => Ok(Bound::new(py, Tk2Circuit { hugr })?.into_any()),
}
}
}

/// Apply a fallible function expecting a hugr on a python circuit.
///
/// This method supports both `pytket.Circuit` and `Tk2Circuit` python objects.
pub fn try_with_hugr<T, E, F>(circ: &PyAny, f: F) -> PyResult<T>
pub fn try_with_hugr<T, E, F>(circ: &Bound<PyAny>, f: F) -> PyResult<T>
where
E: ConvertPyErr<Output = PyErr>,
F: FnOnce(Hugr, CircuitType) -> Result<T, E>,
{
let (hugr, typ) = match Tk2Circuit::extract(circ) {
let (hugr, typ) = match Tk2Circuit::extract_bound(circ) {
// hugr circuit
Ok(t2circ) => (t2circ.hugr, CircuitType::Tket2),
// tket1 circuit
Expand All @@ -196,7 +199,7 @@ where
/// Apply a function expecting a hugr on a python circuit.
///
/// This method supports both `pytket.Circuit` and `Tk2Circuit` python objects.
pub fn with_hugr<T, F>(circ: &PyAny, f: F) -> PyResult<T>
pub fn with_hugr<T, F>(circ: &Bound<PyAny>, f: F) -> PyResult<T>
where
F: FnOnce(Hugr, CircuitType) -> T,
{
Expand All @@ -207,7 +210,7 @@ where
///
/// This method supports both `pytket.Circuit` and `Tk2Circuit` python objects.
/// The returned Hugr is converted to the matching python object.
pub fn try_update_hugr<E, F>(circ: &PyAny, f: F) -> PyResult<&PyAny>
pub fn try_update_hugr<'py, E, F>(circ: &Bound<'py, PyAny>, f: F) -> PyResult<Bound<'py, PyAny>>
where
E: ConvertPyErr<Output = PyErr>,
F: FnOnce(Hugr, CircuitType) -> Result<Hugr, E>,
Expand All @@ -223,7 +226,7 @@ where
///
/// This method supports both `pytket.Circuit` and `Tk2Circuit` python objects.
/// The returned Hugr is converted to the matching python object.
pub fn update_hugr<F>(circ: &PyAny, f: F) -> PyResult<&PyAny>
pub fn update_hugr<'py, F>(circ: &Bound<'py, PyAny>, f: F) -> PyResult<Bound<'py, PyAny>>
where
F: FnOnce(Hugr, CircuitType) -> Hugr,
{
Expand Down
6 changes: 3 additions & 3 deletions tket2-py/src/circuit/cost.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ impl PartialEq for PyCircuitCost {
.cost
.call_method1(py, "__eq__", (&other.cost,))
.expect("Could not compare circuit cost objects.");
res.is_true(py)
res.is_truthy(py)
.expect("Could not compare circuit cost objects.")
})
}
Expand All @@ -114,11 +114,11 @@ impl Ord for PyCircuitCost {
fn cmp(&self, other: &Self) -> Ordering {
Python::with_gil(|py| -> PyResult<Ordering> {
let res = self.cost.call_method1(py, "__lt__", (&other.cost,))?;
if res.is_true(py)? {
if res.is_truthy(py)? {
return Ok(Ordering::Less);
}
let res = self.cost.call_method1(py, "__eq__", (&other.cost,))?;
if res.is_true(py)? {
if res.is_truthy(py)? {
return Ok(Ordering::Equal);
}
Ok(Ordering::Greater)
Expand Down
8 changes: 4 additions & 4 deletions tket2-py/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use pyo3::prelude::*;
/// The Python bindings to TKET2.
#[pymodule]
#[pyo3(name = "tket2")]
fn tket2_py(py: Python, m: &PyModule) -> PyResult<()> {
fn tket2_py(py: Python, m: &Bound<PyModule>) -> PyResult<()> {
add_submodule(py, m, circuit::module(py)?)?;
add_submodule(py, m, optimiser::module(py)?)?;
add_submodule(py, m, passes::module(py)?)?;
Expand All @@ -20,16 +20,16 @@ fn tket2_py(py: Python, m: &PyModule) -> PyResult<()> {
Ok(())
}

fn add_submodule(py: Python, parent: &PyModule, submodule: &PyModule) -> PyResult<()> {
parent.add_submodule(submodule)?;
fn add_submodule(py: Python, parent: &Bound<PyModule>, submodule: Bound<PyModule>) -> PyResult<()> {
parent.add_submodule(&submodule)?;

// Add submodule to sys.modules.
// This is required to be able to do `from parent.submodule import ...`.
//
// See [https://github.com/PyO3/pyo3/issues/759]
let parent_name = parent.name()?;
let submodule_name = submodule.name()?;
let modules = py.import("sys")?.getattr("modules")?;
let modules = py.import_bound("sys")?.getattr("modules")?;
modules.set_item(format!("{parent_name}.{submodule_name}"), submodule)?;
Ok(())
}
8 changes: 4 additions & 4 deletions tket2-py/src/optimiser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ use tket2::optimiser::{BadgerLogger, DefaultBadgerOptimiser};
use crate::circuit::update_hugr;

/// The module definition
pub fn module(py: Python) -> PyResult<&PyModule> {
let m = PyModule::new(py, "_optimiser")?;
pub fn module(py: Python<'_>) -> PyResult<Bound<'_, PyModule>> {
let m = PyModule::new_bound(py, "_optimiser")?;
m.add_class::<PyBadgerOptimiser>()?;
Ok(m)
}
Expand Down Expand Up @@ -81,14 +81,14 @@ impl PyBadgerOptimiser {
#[allow(clippy::too_many_arguments)]
pub fn py_optimise<'py>(
&self,
circ: &'py PyAny,
circ: &Bound<'py, PyAny>,
timeout: Option<u64>,
progress_timeout: Option<u64>,
n_threads: Option<NonZeroUsize>,
split_circ: Option<bool>,
queue_size: Option<usize>,
log_progress: Option<PathBuf>,
) -> PyResult<&'py PyAny> {
) -> PyResult<Bound<'py, PyAny>> {
let options = BadgerOptions {
timeout,
progress_timeout,
Expand Down
31 changes: 17 additions & 14 deletions tket2-py/src/passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,23 @@ use crate::{
/// The module definition
///
/// This module is re-exported from the python module with the same name.
pub fn module(py: Python) -> PyResult<&PyModule> {
let m = PyModule::new(py, "_passes")?;
m.add_function(wrap_pyfunction!(greedy_depth_reduce, m)?)?;
m.add_function(wrap_pyfunction!(badger_optimise, m)?)?;
pub fn module(py: Python<'_>) -> PyResult<Bound<'_, PyModule>> {
let m = PyModule::new_bound(py, "_passes")?;
m.add_function(wrap_pyfunction!(greedy_depth_reduce, &m)?)?;
m.add_function(wrap_pyfunction!(badger_optimise, &m)?)?;
m.add_class::<self::chunks::PyCircuitChunks>()?;
m.add_function(wrap_pyfunction!(self::chunks::chunks, m)?)?;
m.add("PullForwardError", py.get_type::<PyPullForwardError>())?;
m.add_function(wrap_pyfunction!(self::chunks::chunks, &m)?)?;
m.add(
"PullForwardError",
py.get_type_bound::<PyPullForwardError>(),
)?;
Ok(m)
}

create_py_exception!(tket2::passes::PullForwardError, PyPullForwardError, "");

#[pyfunction]
fn greedy_depth_reduce(circ: &PyAny) -> PyResult<(&PyAny, u32)> {
fn greedy_depth_reduce<'py>(circ: &Bound<'py, PyAny>) -> PyResult<(Bound<'py, PyAny>, u32)> {
let py = circ.py();
try_with_hugr(circ, |mut h, typ| {
let n_moves = apply_greedy_commutation(&mut h).convert_pyerrs()?;
Expand All @@ -47,14 +50,14 @@ fn greedy_depth_reduce(circ: &PyAny) -> PyResult<(&PyAny, u32)> {
/// from pytket import OpType
/// auto_rebase_pass({OpType.CX, OpType.Rz, OpType.H}).apply(circ)"
// ```
fn rebase_nam(circ: &PyAny) -> PyResult<()> {
fn rebase_nam(circ: &Bound<PyAny>) -> PyResult<()> {
let py = circ.py();
let auto_rebase = py
.import("pytket.passes.auto_rebase")?
.import_bound("pytket.passes.auto_rebase")?
.getattr("auto_rebase_pass")?;
let optype = py.import("pytket")?.getattr("OpType")?;
let locals = [("OpType", &optype)].into_py_dict(py);
let op_set = py.eval("{OpType.CX, OpType.Rz, OpType.H}", None, Some(locals))?;
let optype = py.import_bound("pytket")?.getattr("OpType")?;
let locals = [("OpType", &optype)].into_py_dict_bound(py);
let op_set = py.eval_bound("{OpType.CX, OpType.Rz, OpType.H}", None, Some(&locals))?;
let rebase_pass = auto_rebase.call1((op_set,))?.getattr("apply")?;
rebase_pass.call1((circ,)).map(|_| ())
}
Expand All @@ -75,14 +78,14 @@ fn rebase_nam(circ: &PyAny) -> PyResult<()> {
/// Log files will be written to the directory `log_dir` if specified.
#[pyfunction]
fn badger_optimise<'py>(
circ: &'py PyAny,
circ: &Bound<'py, PyAny>,
optimiser: &PyBadgerOptimiser,
max_threads: Option<NonZeroUsize>,
timeout: Option<u64>,
progress_timeout: Option<u64>,
log_dir: Option<PathBuf>,
rebase: Option<bool>,
) -> PyResult<&'py PyAny> {
) -> PyResult<Bound<'py, PyAny>> {
// Default parameter values
let rebase = rebase.unwrap_or(true);
let max_threads = max_threads.unwrap_or(num_cpus::get().try_into().unwrap());
Expand Down
8 changes: 4 additions & 4 deletions tket2-py/src/passes/chunks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::utils::ConvertPyErr;

/// Split a circuit into chunks of a given size.
#[pyfunction]
pub fn chunks(c: &PyAny, max_chunk_size: usize) -> PyResult<PyCircuitChunks> {
pub fn chunks(c: &Bound<PyAny>, max_chunk_size: usize) -> PyResult<PyCircuitChunks> {
with_hugr(c, |hugr, typ| {
// TODO: Detect if the circuit is in tket1 format or Tk2Circuit.
let chunks = CircuitChunks::split(&hugr, max_chunk_size);
Expand All @@ -38,21 +38,21 @@ pub struct PyCircuitChunks {
#[pymethods]
impl PyCircuitChunks {
/// Reassemble the chunks into a circuit.
fn reassemble<'py>(&self, py: Python<'py>) -> PyResult<&'py PyAny> {
fn reassemble<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyAny>> {
let hugr = self.clone().chunks.reassemble().convert_pyerrs()?;
self.original_type.convert(py, hugr)
}

/// Returns clones of the split circuits.
fn circuits<'py>(&self, py: Python<'py>) -> PyResult<Vec<&'py PyAny>> {
fn circuits<'py>(&self, py: Python<'py>) -> PyResult<Vec<Bound<'py, PyAny>>> {
self.chunks
.iter()
.map(|hugr| self.original_type.convert(py, hugr.clone()))
.collect()
}

/// Replaces a chunk's circuit with an updated version.
fn update_circuit(&mut self, index: usize, new_circ: &PyAny) -> PyResult<()> {
fn update_circuit(&mut self, index: usize, new_circ: &Bound<PyAny>) -> PyResult<()> {
try_with_hugr(new_circ, |hugr, _| {
if hugr.circuit_signature() != self.chunks[index].circuit_signature() {
return Err(PyAttributeError::new_err(
Expand Down
10 changes: 5 additions & 5 deletions tket2-py/src/pattern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ use pyo3::prelude::*;
use tket2::portmatching::{CircuitPattern, PatternMatcher};

/// The module definition
pub fn module(py: Python) -> PyResult<&PyModule> {
let m = PyModule::new(py, "_pattern")?;
pub fn module(py: Python<'_>) -> PyResult<Bound<'_, PyModule>> {
let m = PyModule::new_bound(py, "_pattern")?;
m.add_class::<Rule>()?;
m.add_class::<RuleMatcher>()?;
m.add_class::<self::portmatching::PyCircuitPattern>()?;
Expand All @@ -21,11 +21,11 @@ pub fn module(py: Python) -> PyResult<&PyModule> {

m.add(
"InvalidPatternError",
py.get_type::<PyInvalidPatternError>(),
py.get_type_bound::<PyInvalidPatternError>(),
)?;
m.add(
"InvalidReplacementError",
py.get_type::<PyInvalidReplacementError>(),
py.get_type_bound::<PyInvalidReplacementError>(),
)?;

Ok(m)
Expand All @@ -51,7 +51,7 @@ pub struct Rule(pub [Hugr; 2]);
#[pymethods]
impl Rule {
#[new]
fn new_rule(l: &PyAny, r: &PyAny) -> PyResult<Rule> {
fn new_rule(l: &Bound<PyAny>, r: &Bound<PyAny>) -> PyResult<Rule> {
let l = Tk2Circuit::from_tket1(l)?;
let r = Tk2Circuit::from_tket1(r)?;

Expand Down
Loading

0 comments on commit 677adab

Please sign in to comment.