Skip to content

Commit

Permalink
refactor: simplify json encoding using t2op (#78)
Browse files Browse the repository at this point in the history
  • Loading branch information
ss2165 committed Sep 4, 2023
1 parent d457bd0 commit a0a0bcf
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 79 deletions.
109 changes: 43 additions & 66 deletions src/json/op.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
//! circuits by ensuring they always define a signature, and computing the
//! explicit count of qubits and linear bits.

use crate::ops::EXTENSION_ID as QUANTUM_EXTENSION_ID;
use hugr::extension::prelude::QB_T;

use hugr::ops::custom::ExternalOp;
Expand Down Expand Up @@ -189,30 +188,8 @@ impl From<&JsonOp> for OpType {
JsonOpType::T => T2Op::T.into(),
JsonOpType::Tdg => T2Op::Tdg.into(),
JsonOpType::X => T2Op::X.into(),
JsonOpType::Rz => T2Op::RzF64.into(),
JsonOpType::noop => LeafOp::Noop { ty: QB_T }.into(),
// TODO TKET1 measure takes a bit as input, HUGR measure does not
//JsonOpType::Measure => LeafOp::Measure.into(),
// JsonOpType::Reset => LeafOp::Reset.into(),
// JsonOpType::ZZMax => LeafOp::ZZMax.into(),
// JsonOpType::Rz => LeafOp::RzF64.into(),
// JsonOpType::RzF64 => LeafOp::RzF64.into(),
// TODO TKET1 I/O needs some special handling
//JsonOpType::Input => hugr::ops::Input {
// types: json_op.signature().output,
// extensions: Default::default(),
//}
//.into(),
//JsonOpType::Output => hugr::ops::Output {
// types: json_op.signature().input,
// extensions: Default::default(),
//}
//.into(),
// JsonOpType::Z => LeafOp::Z.into(),
// JsonOpType::Y => LeafOp::Y.into(),
// JsonOpType::S => LeafOp::S.into(),
// JsonOpType::Sdg => LeafOp::Sadj.into(),
// JsonOpType::T => LeafOp::T.into(),
// JsonOpType::Tdg => LeafOp::Tadj.into(),
_ => LeafOp::CustomOp(Box::new(json_op.as_opaque_op())).into(),
}
}
Expand All @@ -222,56 +199,56 @@ impl TryFrom<&OpType> for JsonOp {
type Error = OpConvertError;

fn try_from(op: &OpType) -> Result<Self, Self::Error> {
// We only translate operations that have a 1:1 mapping between TKET and HUGR
// We only translate operations that have a 1:1 mapping between TKET and TKET2
//
// Other TKET1 operations are wrapped in an `OpaqueOp`.
//
// Non-supported Hugr operations throw an error.
let err = || OpConvertError::UnsupportedOpSerialization(op.clone());
let OpType::LeafOp(leaf) = op else {
return Err(err());
};

let json_optype: JsonOpType = match op {
OpType::LeafOp(LeafOp::Noop { .. }) => JsonOpType::noop,
OpType::LeafOp(LeafOp::CustomOp(b)) => match (*b).as_ref() {
ExternalOp::Extension(c) if c.def().extension() == &QUANTUM_EXTENSION_ID => {
match &c.def().name()[..] {
"H" => JsonOpType::H,
"CX" => JsonOpType::CX,
_ => return Err(err()),
}
}
ext => {
return try_unwrap_json_op(ext).ok_or_else(err);
} // h_gate() => JsonOpType::H,
// LeafOp::ZZMax => JsonOpType::ZZMax,
// LeafOp::Reset => JsonOpType::Reset,
// //LeafOp::Measure => JsonOpType::Measure,
// LeafOp::T => JsonOpType::T,
// LeafOp::S => JsonOpType::S,
// LeafOp::X => JsonOpType::X,
// LeafOp::Y => JsonOpType::Y,
// LeafOp::Z => JsonOpType::Z,
// LeafOp::Tadj => JsonOpType::Tdg,
// LeafOp::Sadj => JsonOpType::Sdg,
//LeafOp::RzF64 => JsonOpType::Rz, // The angle in RzF64 comes from a constant input
//LeafOp::Xor => todo!(),
//LeafOp::MakeTuple { .. } => todo!(),
//LeafOp::UnpackTuple { .. } => todo!(),
//LeafOp::Tag { .. } => todo!(),
//LeafOp::Lift { .. } => todo!(),
// CustomOp is handled above
},
//OpType::Input(_) => JsonOpType::Input,
//OpType::Output(_) => JsonOpType::Output,
//hugr::ops::OpType::FuncDefn(_) => todo!(),
//hugr::ops::OpType::FuncDecl(_) => todo!(),
//hugr::ops::OpType::Const(_) => todo!(),
//hugr::ops::OpType::Call(_) => todo!(),
//hugr::ops::OpType::CallIndirect(_) => todo!(),
//hugr::ops::OpType::LoadConstant(_) => todo!(),
//hugr::ops::OpType::DFG(_) => JsonOpType::CircBox, // TODO: Requires generating the Operation::op_box
_ => return Err(err()),
let json_optype = if let Ok(t2op) = leaf.clone().try_into() {
match t2op {
T2Op::CX => JsonOpType::CX,
T2Op::H => JsonOpType::H,
T2Op::Measure => JsonOpType::Measure,
T2Op::RzF64 => JsonOpType::RzF64,
_ => return Err(err()),
}
} else if let LeafOp::CustomOp(b) = leaf {
let ext = (*b).as_ref();
return try_unwrap_json_op(ext).ok_or_else(err);
} else {
return Err(err());
};

// let json_optype: JsonOpType = match leaf {
// LeafOp::Noop { .. } => JsonOpType::noop,
// OpType::LeafOp(l) => match l.clone().try_into() {
// Ok(t2op) => match t2op {
// T2Op::CX => JsonOpType::CX,
// T2Op::H => JsonOpType::H,
// T2Op::Measure => JsonOpType::Measure,
// T2Op::RzF64 => JsonOpType::RzF64,
// _ => {
// return Err(err());
// }
// },

// Err(_) => match l {
// LeafOp::CustomOp(b) => {
// let ext = (*b).as_ref();
// return try_unwrap_json_op(ext).ok_or_else(err);
// }

// _ => return Err(err()),
// },
// },
// _ => return Err(err()),
// };

let mut num_qubits = 0;
let mut num_bits = 0;
let mut num_params = 0;
Expand Down
41 changes: 31 additions & 10 deletions src/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use smol_str::SmolStr;
use std::str::FromStr;
use strum::IntoEnumIterator;
use strum_macros::{Display, EnumIter, EnumString, IntoStaticStr};
use thiserror::Error;

/// Name of tket 2 extension.
pub const EXTENSION_ID: ExtensionId = ExtensionId::new_inline("quantum.tket2");
Expand Down Expand Up @@ -68,14 +69,21 @@ pub enum Pauli {
Z,
}

#[derive(Debug, Error, PartialEq, Clone, Copy)]
#[error("Not a T2Op.")]
pub struct NotT2Op;

// this trait could be implemented in Hugr
trait SimpleOpEnum: Into<&'static str> + FromStr + Copy + IntoEnumIterator {
type LoadError: std::error::Error;

fn signature(&self) -> FunctionType;
fn name(&self) -> &str {
(*self).into()
}
fn try_from_op_def(op_def: &OpDef) -> Result<Self, <Self as FromStr>::Err> {
Self::from_str(op_def.name())
fn from_extension_name(extension: &str, op_name: &str) -> Result<Self, Self::LoadError>;
fn try_from_op_def(op_def: &OpDef) -> Result<Self, Self::LoadError> {
Self::from_extension_name(op_def.extension(), op_def.name())
}
fn add_to_extension<'e>(
&self,
Expand All @@ -87,13 +95,21 @@ trait SimpleOpEnum: Into<&'static str> + FromStr + Copy + IntoEnumIterator {
}
}

fn from_extension_name<T: SimpleOpEnum>(extension: &str, op_name: &str) -> Result<T, NotT2Op> {
if extension != EXTENSION_ID {
return Err(NotT2Op);
}
T::from_str(op_name).map_err(|_| NotT2Op)
}

impl Pauli {
/// Check if this pauli commutes with another.
pub fn commutes_with(&self, other: Self) -> bool {
*self == Pauli::I || other == Pauli::I || *self == other
}
}
impl SimpleOpEnum for T2Op {
type LoadError = NotT2Op;
fn signature(&self) -> FunctionType {
use T2Op::*;
let one_qb_row = type_row![QB_T];
Expand Down Expand Up @@ -124,6 +140,13 @@ impl SimpleOpEnum for T2Op {
move |_: &_| Ok(FunctionType::new(input.clone(), output.clone())),
)
}

fn from_extension_name(extension: &str, op_name: &str) -> Result<Self, Self::LoadError> {
if extension != EXTENSION_ID {
return Err(NotT2Op);
}
Self::from_str(op_name).map_err(|_| NotT2Op)
}
}

impl T2Op {
Expand Down Expand Up @@ -193,26 +216,24 @@ impl From<T2Op> for OpType {
}

impl TryFrom<OpType> for T2Op {
type Error = &'static str;
type Error = NotT2Op;

fn try_from(op: OpType) -> Result<Self, Self::Error> {
let leaf: LeafOp = op.try_into().map_err(|_| "not a leaf.")?;
let leaf: LeafOp = op.try_into().map_err(|_| NotT2Op)?;
leaf.try_into()
}
}

impl TryFrom<LeafOp> for T2Op {
type Error = &'static str;
type Error = NotT2Op;

fn try_from(op: LeafOp) -> Result<Self, Self::Error> {
match op {
LeafOp::CustomOp(b) => match *b {
ExternalOp::Extension(e) => {
Self::try_from_op_def(e.def()).map_err(|_| "not a T2Op")
}
ExternalOp::Opaque(_) => todo!(),
ExternalOp::Extension(e) => Self::try_from_op_def(e.def()),
ExternalOp::Opaque(o) => from_extension_name(o.extension(), o.name()),
},
_ => Err("not a custom."),
_ => Err(NotT2Op),
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/portmatching/matcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use thiserror::Error;
#[cfg(feature = "pyo3")]
use pyo3::prelude::*;

use crate::{circuit::Circuit, T2Op};
use crate::{circuit::Circuit, ops::NotT2Op, T2Op};

/// Matchable operations in a circuit.
///
Expand All @@ -45,13 +45,13 @@ impl From<T2Op> for MatchOp {
}

impl TryFrom<OpType> for MatchOp {
type Error = &'static str;
type Error = NotT2Op;

fn try_from(value: OpType) -> Result<Self, Self::Error> {
match value {
OpType::LeafOp(op) => Ok(Self::Op(op.try_into()?)),
OpType::LoadConstant(_) => Ok(Self::LoadConstant),
_ => Err("Unsupported op type"),
_ => Err(NotT2Op),
}
}
}
Expand Down

0 comments on commit a0a0bcf

Please sign in to comment.