Skip to content

Commit

Permalink
feat: Support tuple unpacking with multiple unpacks (#470)
Browse files Browse the repository at this point in the history
This was already implemented, but blocked by a bug in hugr
(CQCL/hugr#1191).

drive-by: Added a test case for #416, the last missing case for tuple
unpacking

---------

Co-authored-by: Douglas Wilson <[email protected]>
  • Loading branch information
aborgna-q and doug-q authored Jul 11, 2024
1 parent 88e9010 commit 34836c3
Showing 1 changed file with 35 additions and 9 deletions.
44 changes: 35 additions & 9 deletions tket2/src/passes/tuple_unpack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,6 @@ fn make_rewrite<T: HugrView>(circ: &Circuit<T>, cmd: Command<T>) -> Option<Circu
return None;
}

// TODO: SimpleReplacement fails when replacements have multiports.
// We only support matching a single unpack for now.
//
// This can be removed once https://github.com/CQCL/hugr/pull/1191 gets released.
if unpack_nodes.len() > 1 {
return None;
}

// Remove all unpack operations, but only remove the pack operation if all neighbours are unpacks.
match links.len() == unpack_nodes.len() {
true => Some(remove_pack_unpack(
Expand Down Expand Up @@ -136,6 +128,9 @@ mod test {
use hugr::types::FunctionType;
use rstest::{fixture, rstest};

/// A simple pack operation followed by an unpack operation.
///
/// These can be removed entirely.
#[fixture]
fn simple_pack_unpack() -> Circuit {
let mut h = DFGBuilder::new(FunctionType::new_endo(type_row![QB_T, BOOL_T])).unwrap();
Expand All @@ -154,6 +149,9 @@ mod test {
.into()
}

/// A pack operation followed by two unpack operations from the same tuple.
///
/// These can be removed entirely.
#[fixture]
fn multi_unpack() -> Circuit {
let mut h = DFGBuilder::new(FunctionType::new(
Expand All @@ -179,9 +177,37 @@ mod test {
.into()
}

/// A pack operation followed by an unpack operation, where the tuple is also returned.
///
/// The unpack operation can be removed, but the pack operation cannot.
#[fixture]
fn partial_unpack() -> Circuit {
let mut h = DFGBuilder::new(FunctionType::new(
type_row![BOOL_T, BOOL_T],
vec![BOOL_T, BOOL_T, Type::new_tuple(type_row![BOOL_T, BOOL_T])],
))
.unwrap();
let mut inps = h.input_wires();
let b1 = inps.next().unwrap();
let b2 = inps.next().unwrap();

let op = MakeTuple::new(type_row![BOOL_T, BOOL_T]);
let [tuple] = h.add_dataflow_op(op, [b1, b2]).unwrap().outputs_arr();

let op = UnpackTuple::new(type_row![BOOL_T, BOOL_T]);
let [b1, b2] = h.add_dataflow_op(op, [tuple]).unwrap().outputs_arr();

h.finish_prelude_hugr_with_outputs([b1, b2, tuple])
.unwrap()
.into()
}

#[rstest]
#[case::simple(simple_pack_unpack(), 1, 0)]
#[case::multi(multi_unpack(), 0, 3)]
#[case::multi(multi_unpack(), 1, 0)]
// TODO: Partial unpack is not currently supported.
#[ignore = "Unimplemented."]
#[case::partial(partial_unpack(), 1, 1)]
fn test_pack_unpack(
#[case] mut circ: Circuit,
#[case] expected_rewrites: usize,
Expand Down

0 comments on commit 34836c3

Please sign in to comment.