Skip to content
34 changes: 6 additions & 28 deletions tket-qsystem/tests/guppy_opt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,22 +80,14 @@ fn count_gates(h: &impl HugrView) -> HashMap<SmolStr, usize> {

#[rstest]
#[case::nested_array("nested_array", None)]
#[should_panic = "xfail"]
#[case::angles("angles", Some(vec![
("tket.quantum.Rz", 2), ("tket.quantum.MeasureFree", 1), ("tket.quantum.H", 2), ("tket.quantum.QAlloc", 1)
]))]
#[should_panic = "UnsupportedSubgraphHasNoRegisters"]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm gonna investigate this as a distinct bug, I have the hugr for which run_pytket fails, expect to link to an issue here

#[case::angles("angles", None)]
#[should_panic = "xfail"]
#[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)
]))]
#[case::nested("nested", None)]
#[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)
Expand Down Expand Up @@ -123,23 +115,9 @@ fn optimize_flattened_guppy(#[case] name: &str, #[case] xfail: Option<Vec<(&str,
#[cfg_attr(miri, ignore)] // Opening files is not supported in (isolated) miri
fn optimize_guppy_ranges_array() {
// Demonstrates we can fully optimize the array operations in ranges
// (after control flow is flattened) if we play around with the entrypoint.
use hugr::algorithms::const_fold::ConstantFoldPass;
use hugr::hugr::hugrmut::HugrMut;
use tket::passes::BorrowSquashPass;
// (starting with a Hugr where only control flow has been flattened, not arrays)
let mut hugr = load_guppy_example("ranges/ranges.flat.array.hugr").unwrap();

let f = hugr
.children(hugr.module_root())
.find(|n| {
hugr.get_optype(*n)
.as_func_defn()
.is_some_and(|fd| fd.func_name() == "f")
})
.unwrap();
hugr.set_entrypoint(f);
ConstantFoldPass::default().run(&mut hugr).unwrap();
BorrowSquashPass::default().run(&mut hugr).unwrap();
NormalizeGuppy::default().run(&mut hugr).unwrap();
run_pytket(&mut hugr);
let expected_counts =
count_gates(&load_guppy_circuit("ranges", HugrFileType::Optimized).unwrap());
Expand Down
31 changes: 24 additions & 7 deletions tket/src/passes/guppy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ 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;

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.
///
Expand Down Expand Up @@ -80,6 +82,26 @@ impl<H: HugrMut<Node = Node> + 'static> ComposablePass<H> for NormalizeGuppy {
type Error = NormalizeGuppyErrors;
type Result = ();
fn run(&self, hugr: &mut H) -> Result<Self::Result, Self::Error> {
// 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:
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()
.iter()
.chain(inst.output_types())
.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)?;
}
Expand All @@ -91,11 +113,6 @@ impl<H: HugrMut<Node = Node> + 'static> ComposablePass<H> 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 {})
Expand Down
Loading