Skip to content

Commit

Permalink
feat(tket2-hseries)!: Add HSeriesPass (#487)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: rename `FutureOp` -> `FutureOpDef`, and replace the
placeholder `prepare_ngrte` with `HSeriesPass`
  • Loading branch information
doug-q authored Jul 31, 2024
1 parent 3e67379 commit bd06805
Show file tree
Hide file tree
Showing 6 changed files with 296 additions and 88 deletions.
3 changes: 3 additions & 0 deletions Cargo.lock

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

3 changes: 3 additions & 0 deletions tket2-hseries/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,12 @@ serde_json.workspace = true
smol_str.workspace = true
strum.workspace = true
strum_macros.workspace = true
thiserror.workspace = true
itertools.workspace = true

[dev-dependencies]
cool_asserts.workspace = true
petgraph.workspace = true

[lints]
workspace = true
143 changes: 81 additions & 62 deletions tket2-hseries/src/extension/futures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@
use hugr::{
builder::{BuildError, Dataflow},
extension::{
simple_op::{try_from_name, MakeExtensionOp, MakeOpDef, MakeRegisteredOp, OpLoadError},
ExtensionBuildError, ExtensionId, ExtensionRegistry, OpDef, SignatureFunc, TypeDef,
simple_op::{
try_from_name, HasConcrete, HasDef, MakeExtensionOp, MakeOpDef, MakeRegisteredOp,
OpLoadError,
},
ExtensionBuildError, ExtensionId, ExtensionRegistry, OpDef, SignatureError, SignatureFunc,
TypeDef,
},
ops::{custom::ExtensionOp, CustomOp, OpType},
ops::{custom::ExtensionOp, NamedOp, OpType},
types::{type_param::TypeParam, CustomType, PolyFuncType, Signature, Type, TypeArg, TypeBound},
Extension, Wire,
};
Expand All @@ -27,7 +31,7 @@ lazy_static! {
let mut ext = Extension::new(EXTENSION_ID);
let _ = add_future_type_def(&mut ext).unwrap();

FutureOp::load_all_ops(&mut ext).unwrap();
FutureOpDef::load_all_ops(&mut ext).unwrap();
ext
};

Expand Down Expand Up @@ -82,27 +86,27 @@ pub fn future_type(t: Type) -> Type {
#[allow(missing_docs)]
#[non_exhaustive]
/// Simple enum of "tket2.futures" operations.
pub enum FutureOp {
pub enum FutureOpDef {
Read,
Dup,
Free,
}

impl MakeOpDef for FutureOp {
impl MakeOpDef for FutureOpDef {
fn signature(&self) -> SignatureFunc {
let t_param = TypeParam::from(TypeBound::Any);
let t_type = Type::new_var_use(0, TypeBound::Any);
let future_type = future_type(t_type.clone());
match self {
FutureOp::Read => {
FutureOpDef::Read => {
PolyFuncType::new([t_param], Signature::new(future_type, t_type)).into()
}
FutureOp::Dup => PolyFuncType::new(
FutureOpDef::Dup => PolyFuncType::new(
[t_param],
Signature::new(future_type.clone(), vec![future_type.clone(), future_type]),
)
.into(),
FutureOp::Free => {
FutureOpDef::Free => {
PolyFuncType::new([t_param], Signature::new(future_type.clone(), vec![])).into()
}
}
Expand All @@ -118,57 +122,59 @@ impl MakeOpDef for FutureOp {

fn description(&self) -> String {
match self {
FutureOp::Read => "Read a value from a Future, consuming it".into(),
FutureOp::Dup => {
FutureOpDef::Read => "Read a value from a Future, consuming it".into(),
FutureOpDef::Dup => {
"Duplicate a Future. The original Future is consumed and two Futures are returned"
.into()
}
FutureOp::Free => "Consume a future without reading it.".into(),
FutureOpDef::Free => "Consume a future without reading it.".into(),
}
}
}

impl<'a> From<&'a ConcreteFutureOp> for &'static str {
fn from(value: &ConcreteFutureOp) -> Self {
value.op.into()
impl HasConcrete for FutureOpDef {
type Concrete = FutureOp;

fn instantiate(&self, type_args: &[TypeArg]) -> Result<Self::Concrete, OpLoadError> {
match type_args {
[TypeArg::Type { ty }] => Ok(FutureOp {
op: *self,
typ: ty.clone(),
}),
_ => Err(SignatureError::InvalidTypeArgs.into()),
}
}
}

/// Concrete "tket2.futures" operations with type set.
struct ConcreteFutureOp {
op: FutureOp,
typ: Type,
impl<'a> From<&'a FutureOp> for &'static str {
fn from(value: &FutureOp) -> Self {
value.op.into()
}
}

fn concrete_future_op_type_args(
args: &[TypeArg],
) -> Result<Type, hugr::extension::simple_op::OpLoadError> {
match args {
[TypeArg::Type { ty }] => Ok(ty.clone()),
_ => Err(OpLoadError::InvalidArgs(
hugr::extension::SignatureError::InvalidTypeArgs,
)),
}
/// Concrete "tket2.futures" operations with type set.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct FutureOp {
/// The `FutureOpDef` that defines this operation.
pub op: FutureOpDef,
/// The inner type of the `Future` this op acts on.
pub typ: Type,
}

impl MakeExtensionOp for ConcreteFutureOp {
fn from_extension_op(
ext_op: &ExtensionOp,
) -> Result<Self, hugr::extension::simple_op::OpLoadError>
impl MakeExtensionOp for FutureOp {
fn from_extension_op(ext_op: &ExtensionOp) -> Result<Self, OpLoadError>
where
Self: Sized,
{
let op = FutureOp::from_def(ext_op.def())?;
let typ = concrete_future_op_type_args(ext_op.args())?;
Ok(Self { op, typ })
FutureOpDef::from_def(ext_op.def())?.instantiate(ext_op.args())
}

fn type_args(&self) -> Vec<hugr::types::TypeArg> {
vec![self.typ.clone().into()]
}
}

impl MakeRegisteredOp for ConcreteFutureOp {
impl MakeRegisteredOp for FutureOp {
fn extension_id(&self) -> ExtensionId {
EXTENSION_ID
}
Expand All @@ -178,31 +184,31 @@ impl MakeRegisteredOp for ConcreteFutureOp {
}
}

impl TryFrom<&OpType> for FutureOp {
type Error = ();
impl HasDef for FutureOp {
type Def = FutureOpDef;
}

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

fn try_from(value: &OpType) -> Result<Self, Self::Error> {
let Some(custom_op) = value.as_custom_op() else {
Err(())?
};
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_op(
value
.as_custom_op()
.ok_or(OpLoadError::NotMember(value.name().into()))?,
)
}
}

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

fn try_from(value: &OpType) -> Result<Self, Self::Error> {
(|| {
let op = value.try_into().ok()?;
let typ = concrete_future_op_type_args(value.as_custom_op()?.args()).ok()?;
Some(Self { op, typ })
})()
.ok_or(())
Self::from_op(
value
.as_custom_op()
.ok_or(OpLoadError::NotMember(value.name().into()))?,
)
}
}

Expand All @@ -213,8 +219,8 @@ pub trait FutureOpBuilder: Dataflow {
fn add_read(&mut self, lifted: Wire, typ: Type) -> Result<[Wire; 1], BuildError> {
Ok(self
.add_dataflow_op(
ConcreteFutureOp {
op: FutureOp::Read,
FutureOp {
op: FutureOpDef::Read,
typ,
},
[lifted],
Expand All @@ -226,8 +232,8 @@ pub trait FutureOpBuilder: Dataflow {
fn add_dup(&mut self, lifted: Wire, typ: Type) -> Result<[Wire; 2], BuildError> {
Ok(self
.add_dataflow_op(
ConcreteFutureOp {
op: FutureOp::Dup,
FutureOp {
op: FutureOpDef::Dup,
typ,
},
[lifted],
Expand All @@ -238,8 +244,8 @@ pub trait FutureOpBuilder: Dataflow {
/// Add a "tket2.futures.Free" op.
fn add_free(&mut self, lifted: Wire, typ: Type) -> Result<(), BuildError> {
let op = self.add_dataflow_op(
ConcreteFutureOp {
op: FutureOp::Free,
FutureOp {
op: FutureOpDef::Free,
typ,
},
[lifted],
Expand Down Expand Up @@ -271,11 +277,24 @@ pub(crate) mod test {
fn create_extension() {
assert_eq!(EXTENSION.name(), &EXTENSION_ID);

for o in FutureOp::iter() {
assert_eq!(FutureOp::from_def(get_opdef(o).unwrap()), Ok(o));
for o in FutureOpDef::iter() {
assert_eq!(FutureOpDef::from_def(get_opdef(o).unwrap()), Ok(o));
}
}

#[test]
fn future_op_from_def() {
let typ = Type::UNIT;

assert_eq!(
FutureOp {
op: FutureOpDef::Free,
typ: typ.clone()
},
FutureOpDef::Free.instantiate(&[typ.into()]).unwrap()
)
}

#[test]
fn circuit() {
let t_param = TypeParam::from(TypeBound::Any);
Expand Down
19 changes: 8 additions & 11 deletions tket2-hseries/src/extension/quantum_lazy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ use hugr::{
builder::{BuildError, Dataflow},
extension::{
prelude::{BOOL_T, QB_T},
simple_op::{try_from_name, MakeExtensionOp, MakeOpDef, MakeRegisteredOp},
simple_op::{try_from_name, MakeOpDef, MakeRegisteredOp, OpLoadError},
ExtensionId, ExtensionRegistry, OpDef, SignatureFunc, PRELUDE,
},
ops::{CustomOp, OpType},
ops::{NamedOp as _, OpType},
types::Signature,
Extension, Wire,
};
Expand Down Expand Up @@ -90,16 +90,13 @@ impl MakeRegisteredOp for LazyQuantumOp {
}

impl TryFrom<&OpType> for LazyQuantumOp {
type Error = ();
type Error = OpLoadError;
fn try_from(value: &OpType) -> Result<Self, Self::Error> {
let Some(custom_op) = value.as_custom_op() else {
Err(())?
};
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_op(
value
.as_custom_op()
.ok_or(OpLoadError::NotMember(value.name().into()))?,
)
}
}

Expand Down
Loading

0 comments on commit bd06805

Please sign in to comment.