-
Notifications
You must be signed in to change notification settings - Fork 11
test: run pytket on guppy_opt tests, measure (very limited) success #1250
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 2 commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
68c22b4
QSystem guppy_opt.rs tests call out to tket1-passes
acl-cqc b9b004b
more/explicit tests
acl-cqc a3902c6
fmt differently
acl-cqc 1dfadbb
move should_panic
acl-cqc 40988dc
Merge remote-tracking branch 'origin/main' into acl/guppy_opt_tests
acl-cqc c0cca11
Switched to enum HugrFileType {Original, Flat, Optimized}
acl-cqc bc57a69
Add separate optimize_guppy_pytket / flatten_guppy steps
acl-cqc 50bdfe2
Drop some other tests, keep optimise_guppy(_full=>)
acl-cqc 0ebc1b7
remove unused fixtures
acl-cqc File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| //! Tests optimizing Guppy-generated programs. | ||
|
|
||
| use rayon::iter::ParallelIterator; | ||
| use smol_str::SmolStr; | ||
| use std::collections::HashMap; | ||
| use std::fs; | ||
|
|
@@ -11,40 +12,62 @@ use hugr::algorithms::ComposablePass; | |
| use hugr::{Hugr, HugrView}; | ||
| use rstest::{fixture, rstest}; | ||
| use tket::passes::NormalizeGuppy; | ||
| use tket::serialize::pytket::{EncodeOptions, EncodedCircuit}; | ||
| use tket::Circuit; | ||
|
|
||
| use tket1_passes::Tket1Circuit; | ||
| use tket_qsystem::QSystemPass; | ||
|
|
||
| const GUPPY_EXAMPLES_DIR: &str = "../test_files/guppy_optimization"; | ||
|
|
||
| fn load_guppy_circuit(name: &str) -> Hugr { | ||
| let file = Path::new(GUPPY_EXAMPLES_DIR).join(format!("{name}/{name}.hugr")); | ||
| let reader = fs::File::open(file).unwrap(); | ||
| fn load_guppy_circuit(path: &str) -> std::io::Result<Hugr> { | ||
| let file = Path::new(GUPPY_EXAMPLES_DIR).join(format!("{path}.hugr")); | ||
| let reader = fs::File::open(file)?; | ||
| let reader = BufReader::new(reader); | ||
| Hugr::load(reader, None).unwrap() | ||
| Ok(Hugr::load(reader, None).unwrap()) | ||
| } | ||
|
|
||
| #[fixture] | ||
| fn guppy_angles() -> Hugr { | ||
| load_guppy_circuit("angles") | ||
| load_guppy_circuit("angles/angles").unwrap() | ||
| } | ||
|
|
||
| #[fixture] | ||
| fn guppy_false_branch() -> Hugr { | ||
| load_guppy_circuit("false_branch") | ||
| load_guppy_circuit("false_branch/false_branch").unwrap() | ||
| } | ||
|
|
||
| #[fixture] | ||
| fn guppy_nested() -> Hugr { | ||
| load_guppy_circuit("nested") | ||
| load_guppy_circuit("nested/nested").unwrap() | ||
| } | ||
|
|
||
| #[fixture] | ||
| fn guppy_ranges() -> Hugr { | ||
| load_guppy_circuit("ranges") | ||
| load_guppy_circuit("ranges/ranges").unwrap() | ||
| } | ||
|
|
||
| #[fixture] | ||
| fn guppy_simple_cx() -> Hugr { | ||
| load_guppy_circuit("simple_cx") | ||
| load_guppy_circuit("simple_cx/simple_cx").unwrap() | ||
| } | ||
|
|
||
| fn run_pytket(h: &mut Hugr) { | ||
| let circ = Circuit::new(h); | ||
| let mut encoded = | ||
| EncodedCircuit::new(&circ, EncodeOptions::new().with_subcircuits(true)).unwrap(); | ||
|
|
||
| encoded | ||
| .par_iter_mut() | ||
| .for_each(|(_region, serial_circuit)| { | ||
| let mut circuit_ptr = Tket1Circuit::from_serial_circuit(serial_circuit).unwrap(); | ||
| circuit_ptr | ||
| .clifford_simp(tket_json_rs::OpType::CX, true) | ||
| .unwrap(); | ||
| *serial_circuit = circuit_ptr.to_serial_circuit().unwrap(); | ||
| }); | ||
|
|
||
| encoded.reassemble_inplace(circ.into_hugr(), None).unwrap(); | ||
| } | ||
|
|
||
| fn count_gates(h: &impl HugrView) -> HashMap<SmolStr, usize> { | ||
|
|
@@ -63,37 +86,72 @@ fn count_gates(h: &impl HugrView) -> HashMap<SmolStr, usize> { | |
| /// | ||
| /// This test is intended to check the current status of the Guppy optimization passes. | ||
| /// | ||
|
|
||
| #[rstest] | ||
| #[case::angles(guppy_angles(), [ | ||
| ("tket.quantum.H", 2), ("tket.quantum.QAlloc", 1), ("tket.quantum.Rz", 2), ("tket.quantum.MeasureFree", 1) | ||
| ])] | ||
| #[case::false_branch(guppy_false_branch(), [ | ||
| ("tket.quantum.H", 2), ("tket.quantum.QAlloc", 1), ("tket.quantum.MeasureFree", 1) | ||
| ])] | ||
| #[case::nested(guppy_nested(), [ | ||
| ("tket.quantum.CZ", 1), ("tket.quantum.H", 2), ("tket.quantum.QAlloc", 3), ("tket.quantum.MeasureFree", 3) | ||
| ])] | ||
| #[case::ranges(guppy_ranges(), [ | ||
| ("tket.quantum.QAlloc", 4), ("tket.quantum.MeasureFree", 4), ("tket.quantum.H", 2), ("tket.quantum.CX", 2) | ||
| ], [ | ||
| ("TKET1.tk1op", 1), ("tket.quantum.QAlloc", 1), ("tket.quantum.H", 1), ("tket.quantum.MeasureFree", 1) | ||
|
||
| ])] | ||
| #[case::simple_cx(guppy_simple_cx(), [ | ||
| ("tket.quantum.QAlloc", 2), ("tket.quantum.CX", 2), ("tket.quantum.MeasureFree", 2) | ||
| ], [ | ||
| ("tket.quantum.MeasureFree", 2), ("tket.quantum.QAlloc", 2) | ||
aborgna-q marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| ])] | ||
| #[cfg_attr(miri, ignore)] // Opening files is not supported in (isolated) miri | ||
| fn optimise_guppy<'a>( | ||
| fn optimise_guppy( | ||
| #[case] mut hugr: Hugr, | ||
| #[case] before: impl IntoIterator<Item = (&'a str, usize)>, | ||
| #[case] before: impl IntoIterator<Item = (impl Into<SmolStr>, usize)>, | ||
| #[case] after: impl IntoIterator<Item = (impl Into<SmolStr>, usize)>, | ||
| ) { | ||
| NormalizeGuppy::default().run(&mut hugr).unwrap(); | ||
| let before = before.into_iter().map(|(k, v)| (k.into(), v)).collect(); | ||
| assert_eq!(count_gates(&hugr), before); | ||
|
|
||
| // TODO: Run pytket passes here, and check that the circuit is as optimized as possible at this point. | ||
| // | ||
| // Most example circuits optimize to identity functions, so it may be possible to check for that. | ||
| run_pytket(&mut hugr); | ||
|
|
||
| let after = after.into_iter().map(|(k, v)| (k.into(), v)).collect(); | ||
| assert_eq!(count_gates(&hugr), after); | ||
|
|
||
| // Lower to QSystem. This may blow up the HUGR size. | ||
| QSystemPass::default().run(&mut hugr).unwrap(); | ||
|
|
||
| hugr.validate().unwrap_or_else(|e| panic!("{e}")); | ||
| } | ||
|
|
||
| /// Checks that pytket does nothing for these examples. | ||
| /// We include gate counts for after the NormalizeGuppy step | ||
| /// as our flattening is not sufficient to match the .flat.hugr | ||
| #[rstest] | ||
| #[case::angles(guppy_angles(), [ | ||
| ("tket.quantum.H", 2), ("tket.quantum.QAlloc", 1), ("tket.quantum.Rz", 2), ("tket.quantum.MeasureFree", 1) | ||
| ])] | ||
| #[case::nested(guppy_nested(), [ | ||
| ("tket.quantum.CZ", 1), ("tket.quantum.H", 2), ("tket.quantum.QAlloc", 3), ("tket.quantum.MeasureFree", 3) | ||
| ])] | ||
| #[case::ranges(guppy_ranges(), [ | ||
| ("tket.quantum.QAlloc", 4), ("tket.quantum.MeasureFree", 4), ("tket.quantum.H", 2), ("tket.quantum.CX", 2) | ||
| ])] | ||
| #[cfg_attr(miri, ignore)] // Opening files is not supported in (isolated) miri | ||
| fn no_optimise_guppy<'a>( | ||
| #[case] hugr: Hugr, | ||
| #[case] before_after: impl IntoIterator<Item = (&'a str, usize)> + Clone, | ||
| ) { | ||
| optimise_guppy(hugr, before_after.clone(), before_after); | ||
| } | ||
|
|
||
| /// Check that each example optimizes to the full extent given by the .opt (and .flat) .hugr files. | ||
| #[should_panic] /// This does not yet pass for any case! | ||
| #[rstest] | ||
| #[case::angles("angles")] | ||
| #[case::false_branch("false_branch")] | ||
| #[case::simple_cx("simple_cx")] | ||
| #[case::nested("nested")] | ||
| #[case::ranges("ranges")] | ||
| fn optimise_guppy_full(#[case] name: &str) { | ||
| let hugr = load_guppy_circuit(&format!("{name}/{name}")).unwrap(); | ||
| let flat = load_guppy_circuit(&format!("{name}/{name}.flat")).unwrap_or(hugr.clone()); | ||
aborgna-q marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| let opt = load_guppy_circuit(&format!("{name}/{name}.opt")).unwrap(); | ||
|
|
||
| optimise_guppy(hugr, count_gates(&flat), count_gates(&opt)) | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.