Skip to content

Commit

Permalink
feat!: Update rust hugr dependency to 0.12.0, and python hugr to `0…
Browse files Browse the repository at this point in the history
….8.0` (#568)

The main change is the drop of `CustomOp`s, requiring opaque ops to
always be resolved.

This is a bit of a problem with the current code, as we used `OpaqueOp`s
not backed by a definition to declare operations from python.
For the moment, we leave `PyExtensionOp` unimplemented and disable the
pauli prop tests that depended on it.

https://github.com/CQCL/tket2/blob/473c9f50be90a849ee6378a261e6e953b7145d51/tket2-py/src/ops.rs#L247-L251

https://github.com/CQCL/tket2/blob/473c9f50be90a849ee6378a261e6e953b7145d51/tket2-py/test/test_pauli_prop.py#L96-L100

I'll raise an issue to get them fixed them.


BREAKING CHANGE: Updated to latest hugr version (`hugr-rs 0.12` /
`hugr-py 0.8`). ECCs need to be recompiled.

---------

Co-authored-by: Douglas Wilson <141026920+doug-q@users.noreply.github.com>
  • Loading branch information
aborgna-q and doug-q authored Sep 2, 2024
1 parent 17644ef commit 258a7c5
Show file tree
Hide file tree
Showing 27 changed files with 210 additions and 149 deletions.
47 changes: 37 additions & 10 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ missing_docs = "warn"
[workspace.dependencies]

# Make sure to run `just recompile-eccs` if the hugr serialisation format changes.
hugr = "0.11.0"
hugr-core = "0.8.0"
hugr = "0.12.0"
hugr-core = "0.9.0"
portgraph = "0.12"
pyo3 = "0.21.2"
itertools = "0.13.0"
Expand Down
Binary file modified test_files/eccs/nam_4_2.rwr
Binary file not shown.
Binary file modified test_files/eccs/nam_6_3.rwr
Binary file not shown.
Binary file modified test_files/eccs/small_eccs.rwr
Binary file not shown.
Binary file modified tket2-eccs/src/tket2_eccs/data/nam_6_3.rwr
Binary file not shown.
4 changes: 2 additions & 2 deletions tket2-hseries/src/extension/futures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ impl TryFrom<&OpType> for FutureOpDef {
fn try_from(value: &OpType) -> Result<Self, Self::Error> {
Self::from_op(
value
.as_custom_op()
.as_extension_op()
.ok_or(OpLoadError::NotMember(value.name().into()))?,
)
}
Expand All @@ -208,7 +208,7 @@ impl TryFrom<&OpType> for FutureOp {
fn try_from(value: &OpType) -> Result<Self, Self::Error> {
Self::from_op(
value
.as_custom_op()
.as_extension_op()
.ok_or(OpLoadError::NotMember(value.name().into()))?,
)
}
Expand Down
2 changes: 1 addition & 1 deletion tket2-hseries/src/extension/quantum_lazy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ impl TryFrom<&OpType> for LazyQuantumOp {
fn try_from(value: &OpType) -> Result<Self, Self::Error> {
Self::from_op(
value
.as_custom_op()
.as_extension_op()
.ok_or(OpLoadError::NotMember(value.name().into()))?,
)
}
Expand Down
22 changes: 7 additions & 15 deletions tket2-hseries/src/extension/result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use hugr::{
simple_op::{try_from_name, MakeExtensionOp, MakeOpDef, MakeRegisteredOp, OpLoadError},
ExtensionId, ExtensionRegistry, ExtensionSet, OpDef, SignatureFunc, Version,
},
ops::{CustomOp, NamedOp, OpType},
ops::{NamedOp, OpType},
std_extensions::arithmetic::{
float_types::{
EXTENSION as FLOAT_EXTENSION, EXTENSION_ID as FLOAT_EXTENSION_ID, FLOAT64_TYPE,
Expand Down Expand Up @@ -370,32 +370,24 @@ impl MakeRegisteredOp for ResultOp {
}

impl TryFrom<&OpType> for ResultOpDef {
type Error = ();
type Error = OpLoadError;

fn try_from(value: &OpType) -> Result<Self, Self::Error> {
let Some(custom_op) = value.as_custom_op() else {
Err(())?
let Some(ext) = value.as_extension_op() else {
Err(OpLoadError::NotMember(value.name().into()))?
};
match custom_op {
CustomOp::Extension(ext) => Self::from_extension_op(ext).ok(),
CustomOp::Opaque(opaque) => try_from_name(opaque.name(), &EXTENSION_ID).ok(),
}
.ok_or(())
Self::from_extension_op(ext)
}
}

impl TryFrom<&OpType> for ResultOp {
type Error = OpLoadError;

fn try_from(value: &OpType) -> Result<Self, Self::Error> {
let Some(custom_op) = value.as_custom_op() else {
let Some(ext) = value.as_extension_op() else {
Err(OpLoadError::NotMember(value.name().into()))?
};
match custom_op {
CustomOp::Extension(ext) => Self::from_extension_op(ext),
CustomOp::Opaque(opaque) => try_from_name::<ResultOpDef>(opaque.name(), &EXTENSION_ID)?
.instantiate(opaque.args()),
}
Self::from_extension_op(ext)
}
}

Expand Down
2 changes: 1 addition & 1 deletion tket2-py/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ classifiers = [

dependencies = [
'pytket >= 1.29.2, < 2',
'hugr >= 0.7.0, < 0.8',
'hugr >= 0.8.0, < 0.9',
'tket2_eccs >= 0.1.0, < 0.2',
]

Expand Down
2 changes: 1 addition & 1 deletion tket2-py/src/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use derive_more::{From, Into};
use hugr::extension::prelude::{BOOL_T, QB_T};
use hugr::hugr::IdentList;
use hugr::ops::custom::{ExtensionOp, OpaqueOp};
use hugr::ops::{CustomOp, NamedOp, OpName, OpType};
use hugr::ops::{NamedOp, OpName, OpType};
use hugr::types::{CustomType, Type, TypeBound};
use pyo3::prelude::*;
use std::fmt;
Expand Down
2 changes: 1 addition & 1 deletion tket2-py/src/circuit/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::borrow::Borrow;
use hugr::builder::{CircuitBuilder, DFGBuilder, Dataflow, DataflowHugr};
use hugr::extension::prelude::QB_T;
use hugr::ops::handle::NodeHandle;
use hugr::ops::{CustomOp, OpType};
use hugr::ops::OpType;
use hugr::types::Type;
use itertools::Itertools;
use pyo3::exceptions::{PyAttributeError, PyValueError};
Expand Down
8 changes: 4 additions & 4 deletions tket2-py/src/circuit/tk2circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::borrow::{Borrow, Cow};
use hugr::builder::{CircuitBuilder, DFGBuilder, Dataflow, DataflowHugr};
use hugr::extension::prelude::QB_T;
use hugr::ops::handle::NodeHandle;
use hugr::ops::{CustomOp, OpType};
use hugr::ops::{ExtensionOp, OpType};
use hugr::types::Type;
use itertools::Itertools;
use pyo3::exceptions::{PyAttributeError, PyValueError};
Expand All @@ -26,7 +26,7 @@ use tket2::serialize::TKETDecode;
use tket2::{Circuit, Tk2Op};
use tket_json_rs::circuit_json::SerialCircuit;

use crate::ops::{PyCustomOp, PyTk2Op};
use crate::ops::PyTk2Op;
use crate::rewrite::PyCircuitRewrite;
use crate::types::PyHugrType;
use crate::utils::{into_vec, ConvertPyErr};
Expand Down Expand Up @@ -179,15 +179,15 @@ impl Tk2Circuit {
}

fn node_op(&self, node: PyNode) -> PyResult<Cow<[u8]>> {
let custom: CustomOp = self
let custom: ExtensionOp = self
.circ
.hugr()
.get_optype(node.node)
.clone()
.try_into()
.map_err(|e| {
PyErr::new::<PyValueError, _>(format!(
"Could not convert circuit operation to a `CustomOp`: {e}"
"Could not convert circuit operation to an `ExtensionOp`: {e}"
))
})?;

Expand Down
43 changes: 21 additions & 22 deletions tket2-py/src/ops.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,23 @@
//! Bindings for rust-defined operations
use derive_more::{From, Into};
use hugr::hugr::IdentList;
use hugr::ops::custom::{ExtensionOp, OpaqueOp};
use hugr::types::Signature;
use hugr::ops::custom::ExtensionOp;
use pyo3::prelude::*;
use std::fmt;
use std::str::FromStr;
use strum::IntoEnumIterator;

use hugr::ops::{CustomOp, NamedOp, OpType};
use hugr::ops::{NamedOp, OpType};
use tket2::{Pauli, Tk2Op};

use crate::types::PyHugrType;
use crate::utils::into_vec;

/// The module definition
pub fn module(py: Python<'_>) -> PyResult<Bound<'_, PyModule>> {
let m = PyModule::new_bound(py, "ops")?;
m.add_class::<PyTk2Op>()?;
m.add_class::<PyPauli>()?;
m.add_class::<PyCustomOp>()?;
m.add_class::<PyExtensionOp>()?;
Ok(m)
}

Expand Down Expand Up @@ -68,9 +65,8 @@ impl PyTk2Op {
}

/// Wrap the operation as a custom operation.
pub fn to_custom(&self) -> PyCustomOp {
let custom: ExtensionOp = self.op.into_extension_op();
CustomOp::new_extension(custom).into()
pub fn to_custom(&self) -> PyExtensionOp {
self.op.into_extension_op().into()
}

/// String representation of the operation.
Expand Down Expand Up @@ -224,37 +220,40 @@ impl PyPauliIter {
#[pyo3(name = "CustomOp")]
#[repr(transparent)]
#[derive(From, Into, PartialEq, Clone)]
pub struct PyCustomOp(CustomOp);
pub struct PyExtensionOp(ExtensionOp);

impl fmt::Debug for PyCustomOp {
impl fmt::Debug for PyExtensionOp {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}

impl From<PyCustomOp> for OpType {
fn from(op: PyCustomOp) -> Self {
impl From<PyExtensionOp> for OpType {
fn from(op: PyExtensionOp) -> Self {
op.0.into()
}
}

#[pymethods]
impl PyCustomOp {
impl PyExtensionOp {
#[new]
#[allow(unused)]
fn new(
extension: &str,
op_name: &str,
input_types: Vec<PyHugrType>,
output_types: Vec<PyHugrType>,
) -> PyResult<Self> {
Ok(CustomOp::new_opaque(OpaqueOp::new(
IdentList::new(extension).unwrap(),
op_name,
Default::default(),
[],
Signature::new(into_vec(input_types), into_vec(output_types)),
))
.into())
// FIXME: Broken during the update to hugr 0.12
// Operations must now always be backed by an opDef, so the old way
// of creating `PyOpaqueOp`s on the fly is no longer possible.
unimplemented!("Python Extension Ops need an operation definition")
//let opdef = todo!();
//Ok(ExtensionOp::new(
// opdef,
// [],
// Signature::new(into_vec(input_types), into_vec(output_types)),
//))
}

fn to_custom(&self) -> Self {
Expand Down
Loading

0 comments on commit 258a7c5

Please sign in to comment.