From b00c27144f071abb8241845a2b64eba3230d07d5 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Tue, 18 Nov 2025 20:12:57 +0000 Subject: [PATCH 1/9] optimize_guppy_pytket: include NormalizeGuppy --- tket-qsystem/tests/guppy_opt.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tket-qsystem/tests/guppy_opt.rs b/tket-qsystem/tests/guppy_opt.rs index 7a5352764..40f227811 100644 --- a/tket-qsystem/tests/guppy_opt.rs +++ b/tket-qsystem/tests/guppy_opt.rs @@ -92,12 +92,15 @@ fn count_gates(h: &impl HugrView) -> HashMap { ]))] #[should_panic = "xfail"] #[case::false_branch("false_branch", Some(vec![ - ("TKET1.tk1op", 2), ("tket.quantum.QAlloc", 1), ("tket.quantum.MeasureFree", 1) + ("TKET1.tk1op", 1), ("tket.quantum.H", 1), ("tket.quantum.QAlloc", 1), ("tket.quantum.MeasureFree", 1) ]))] #[cfg_attr(miri, ignore)] // Opening files is not supported in (isolated) miri fn optimise_guppy_pytket(#[case] name: &str, #[case] xfail: Option>) { let mut hugr = load_guppy_circuit(name, HugrFileType::Flat) .unwrap_or_else(|_| load_guppy_circuit(name, HugrFileType::Original).unwrap()); + // We don't need NormalizeGuppy to "flatten" control flow here, but we still want + // to get rid of other guppy artifacts. + NormalizeGuppy::default().run(&mut hugr).unwrap(); run_pytket(&mut hugr); let should_xfail = xfail.is_some(); let expected_counts = match xfail { From 14152fdac0d4757766431ffdd9f3fcfa19dced72 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Tue, 18 Nov 2025 20:21:07 +0000 Subject: [PATCH 2/9] Inline...fixes two, and angles breaks in a strange way --- tket-qsystem/tests/guppy_opt.rs | 14 +++++--------- tket/src/passes/guppy.rs | 8 +++++++- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/tket-qsystem/tests/guppy_opt.rs b/tket-qsystem/tests/guppy_opt.rs index 40f227811..175656376 100644 --- a/tket-qsystem/tests/guppy_opt.rs +++ b/tket-qsystem/tests/guppy_opt.rs @@ -74,7 +74,7 @@ fn count_gates(h: &impl HugrView) -> HashMap { /// #[rstest] -#[should_panic = "xfail"] +#[should_panic = "PytketDecodeError { inner: NoMatchingParameter"] #[case::angles("angles", Some(vec![ ("tket.quantum.Rz", 2), ("tket.quantum.MeasureFree", 1), ("tket.quantum.H", 2), ("tket.quantum.QAlloc", 1) ]))] @@ -82,14 +82,10 @@ fn count_gates(h: &impl HugrView) -> HashMap { #[case::simple_cx("simple_cx", Some(vec![ ("tket.quantum.QAlloc", 2), ("tket.quantum.MeasureFree", 2), ]))] -#[should_panic = "xfail"] -#[case::nested("nested", Some(vec![ - ("tket.quantum.CZ", 6), ("tket.quantum.QAlloc", 3), ("tket.quantum.MeasureFree", 3), ("tket.quantum.H", 6) -]))] -#[should_panic = "xfail"] -#[case::ranges("ranges", Some(vec![ - ("tket.quantum.H", 8), ("tket.quantum.MeasureFree", 4), ("tket.quantum.QAlloc", 4), ("tket.quantum.CX", 6) -]))] +//#[should_panic = "xfail"] +#[case::nested("nested", None)] +//#[should_panic = "xfail"] +#[case::ranges("ranges", None)] #[should_panic = "xfail"] #[case::false_branch("false_branch", Some(vec![ ("TKET1.tk1op", 1), ("tket.quantum.H", 1), ("tket.quantum.QAlloc", 1), ("tket.quantum.MeasureFree", 1) diff --git a/tket/src/passes/guppy.rs b/tket/src/passes/guppy.rs index 1ecfee7de..b26d7b000 100644 --- a/tket/src/passes/guppy.rs +++ b/tket/src/passes/guppy.rs @@ -4,7 +4,9 @@ use hugr::algorithms::const_fold::{ConstFoldError, ConstantFoldPass}; use hugr::algorithms::inline_dfgs::InlineDFGsPass; use hugr::algorithms::normalize_cfgs::{NormalizeCFGError, NormalizeCFGPass}; use hugr::algorithms::untuple::{UntupleError, UntupleRecursive}; -use hugr::algorithms::{ComposablePass, RemoveDeadFuncsError, RemoveDeadFuncsPass, UntuplePass}; +use hugr::algorithms::{ + inline_acyclic, ComposablePass, RemoveDeadFuncsError, RemoveDeadFuncsPass, UntuplePass, +}; use hugr::hugr::hugrmut::HugrMut; use hugr::hugr::patch::inline_dfg::InlineDFGError; use hugr::Node; @@ -70,6 +72,10 @@ impl + 'static> ComposablePass for NormalizeGuppy { type Error = NormalizeGuppyErrors; type Result = (); fn run(&self, hugr: &mut H) -> Result { + // We probably shouldn't inline quite as aggressively as this, but + // the results demonstrate how much we need to do at least some of it: + inline_acyclic(hugr, |_, _| true).unwrap(); + if self.simplify_cfgs { NormalizeCFGPass::default().run(hugr)?; } From 1b9c340e57e225ef27c3abe4881240abc99a8202 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Wed, 26 Nov 2025 14:22:16 +0000 Subject: [PATCH 3/9] inline_acyclic only for functions on qubits --- tket/src/passes/guppy.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tket/src/passes/guppy.rs b/tket/src/passes/guppy.rs index 192d428cb..a4c17c06f 100644 --- a/tket/src/passes/guppy.rs +++ b/tket/src/passes/guppy.rs @@ -11,7 +11,7 @@ use hugr::hugr::hugrmut::HugrMut; use hugr::hugr::patch::inline_dfg::InlineDFGError; use hugr::Node; -use crate::passes::BorrowSquashPass; +use crate::passes::{unpack_container::TypeUnpacker, BorrowSquashPass}; /// Normalize the structure of a Guppy-generated circuit into something that can be optimized by tket. /// @@ -84,7 +84,15 @@ impl + 'static> ComposablePass for NormalizeGuppy { fn run(&self, hugr: &mut H) -> Result { // We probably shouldn't inline quite as aggressively as this, but // the results demonstrate how much we need to do at least some of it: - inline_acyclic(hugr, |_, _| true).unwrap(); + let qubit_finder = TypeUnpacker::for_qubits(); + inline_acyclic(hugr, |h, call| { + let inst = &h.get_optype(call).as_call().unwrap().instantiation; + inst.input_types() + .into_iter() + .chain(inst.output_types()) + .any(|ty| qubit_finder.contains_element_type(&ty)) + }) + .unwrap(); if self.simplify_cfgs { NormalizeCFGPass::default().run(hugr)?; From 0209d732364132a57f011df5cd3a898e9c53e3b4 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Wed, 26 Nov 2025 15:52:05 +0000 Subject: [PATCH 4/9] update message --- tket-qsystem/tests/guppy_opt.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tket-qsystem/tests/guppy_opt.rs b/tket-qsystem/tests/guppy_opt.rs index 999149eb6..9c5d5d6dc 100644 --- a/tket-qsystem/tests/guppy_opt.rs +++ b/tket-qsystem/tests/guppy_opt.rs @@ -80,7 +80,7 @@ fn count_gates(h: &impl HugrView) -> HashMap { #[rstest] #[case::nested_array("nested_array", None)] -#[should_panic = "PytketDecodeError { inner: NoMatchingParameter"] +#[should_panic = "UnsupportedSubgraphHasNoRegisters"] #[case::angles("angles", None)] #[should_panic = "xfail"] #[case::simple_cx("simple_cx", Some(vec![ From 9118ff9b46e7714b53cfe9476756c3d58378fd7c Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Wed, 26 Nov 2025 15:56:33 +0000 Subject: [PATCH 5/9] comment --- tket/src/passes/guppy.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tket/src/passes/guppy.rs b/tket/src/passes/guppy.rs index a4c17c06f..99311ea6b 100644 --- a/tket/src/passes/guppy.rs +++ b/tket/src/passes/guppy.rs @@ -86,6 +86,8 @@ impl + 'static> ComposablePass for NormalizeGuppy { // the results demonstrate how much we need to do at least some of it: let qubit_finder = TypeUnpacker::for_qubits(); inline_acyclic(hugr, |h, call| { + // Look for qubits. Use instantiated type so that we inline generic + // (e.g. container) functions as this might enable better qubit tracking. let inst = &h.get_optype(call).as_call().unwrap().instantiation; inst.input_types() .into_iter() From 1f9074c6d4a5edb622933c192ac1e56870308e7e Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Wed, 26 Nov 2025 16:06:03 +0000 Subject: [PATCH 6/9] clippy --- tket/src/passes/guppy.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tket/src/passes/guppy.rs b/tket/src/passes/guppy.rs index 99311ea6b..baed29ad5 100644 --- a/tket/src/passes/guppy.rs +++ b/tket/src/passes/guppy.rs @@ -90,9 +90,9 @@ impl + 'static> ComposablePass for NormalizeGuppy { // (e.g. container) functions as this might enable better qubit tracking. let inst = &h.get_optype(call).as_call().unwrap().instantiation; inst.input_types() - .into_iter() + .iter() .chain(inst.output_types()) - .any(|ty| qubit_finder.contains_element_type(&ty)) + .any(|ty| qubit_finder.contains_element_type(ty)) }) .unwrap(); From ee4f221a0c239211e9003c41429c78fd856306c7 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Wed, 26 Nov 2025 18:08:43 +0000 Subject: [PATCH 7/9] simplify ranges_array --- tket-qsystem/tests/guppy_opt.rs | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/tket-qsystem/tests/guppy_opt.rs b/tket-qsystem/tests/guppy_opt.rs index 9c5d5d6dc..515b9b9fa 100644 --- a/tket-qsystem/tests/guppy_opt.rs +++ b/tket-qsystem/tests/guppy_opt.rs @@ -115,23 +115,9 @@ fn optimize_flattened_guppy(#[case] name: &str, #[case] xfail: Option Date: Fri, 28 Nov 2025 10:05:44 +0000 Subject: [PATCH 8/9] Move RemoveDeadFuncs earlier --- tket/src/passes/guppy.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tket/src/passes/guppy.rs b/tket/src/passes/guppy.rs index baed29ad5..56a547c9b 100644 --- a/tket/src/passes/guppy.rs +++ b/tket/src/passes/guppy.rs @@ -95,6 +95,12 @@ impl + 'static> ComposablePass for NormalizeGuppy { .any(|ty| qubit_finder.contains_element_type(ty)) }) .unwrap(); + // Many functions now unreachable, so remove - this may improve compilation speed, + // although not if all remaining phases operate only beneath the entrypoint. + // Shouldn't be affected by anything else until we start removing untaken branches. + if self.dead_funcs { + RemoveDeadFuncsPass::default().run(hugr)?; + } if self.simplify_cfgs { NormalizeCFGPass::default().run(hugr)?; @@ -107,11 +113,6 @@ impl + 'static> ComposablePass for NormalizeGuppy { if self.constant_fold { ConstantFoldPass::default().run(hugr)?; } - // Only improves compilation speed, not affected by anything else - // until we start removing untaken branches - if self.dead_funcs { - RemoveDeadFuncsPass::default().run(hugr)?; - } // Do earlier? Nothing creates DFGs if self.inline_dfgs { InlineDFGsPass.run(hugr).unwrap_or_else(|e| match e {}) From 79207a5844cc21d0395c319d26df75b9aecba5ae Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Tue, 9 Dec 2025 21:18:42 +0000 Subject: [PATCH 9/9] xfail for angles --- tket-qsystem/tests/guppy_opt.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tket-qsystem/tests/guppy_opt.rs b/tket-qsystem/tests/guppy_opt.rs index 3f966839e..5d87851a2 100644 --- a/tket-qsystem/tests/guppy_opt.rs +++ b/tket-qsystem/tests/guppy_opt.rs @@ -80,8 +80,10 @@ fn count_gates(h: &impl HugrView) -> HashMap { #[rstest] #[case::nested_array("nested_array", None)] -#[should_panic = "UnsupportedSubgraphHasNoRegisters"] -#[case::angles("angles", None)] +#[should_panic = "xfail"] +#[case::angles("angles", Some(vec![ + ("tket.quantum.H", 2), ("tket.quantum.MeasureFree", 1), ("tket.quantum.Rz", 10), ("tket.quantum.QAlloc", 1) +]))] #[should_panic = "xfail"] #[case::simple_cx("simple_cx", Some(vec![ ("tket.quantum.QAlloc", 2), ("tket.quantum.MeasureFree", 2),