-
Notifications
You must be signed in to change notification settings - Fork 11
feat: Add KAK Commit Factory #954
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
base: dan-commit-factory-base
Are you sure you want to change the base?
Changes from 1 commit
b7d1588
2ba9957
b55d4d2
3c88bfb
8ba2ab4
7a82cdc
01c41e3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,255 @@ | ||||||||||||||||||||||||||||||
| //! KAKResynthesis explorer for rewrite space exploration. | ||||||||||||||||||||||||||||||
| use hugr::{ | ||||||||||||||||||||||||||||||
| builder::{ | ||||||||||||||||||||||||||||||
| endo_sig, DFGBuilder, Dataflow, DataflowHugr | ||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||
| extension::{prelude::qb_t, simple_op::MakeExtensionOp}, | ||||||||||||||||||||||||||||||
| Hugr, HugrView, IncomingPort, OutgoingPort | ||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||
| use hugr::Direction; | ||||||||||||||||||||||||||||||
| use tket2::{ | ||||||||||||||||||||||||||||||
| portmatching::PatternMatch, rewrite_space::{ | ||||||||||||||||||||||||||||||
| CommitFactory, IterMatchedWires, PersistentHugr, Walker | ||||||||||||||||||||||||||||||
| }, Tk2Op | ||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||
| use hugr::persistent::{PersistentWire, PatchNode}; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| pub struct KAKResynthesis{ | ||||||||||||||||||||||||||||||
| wires: Vec<PersistentWire> | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| impl IterMatchedWires for KAKResynthesis { | ||||||||||||||||||||||||||||||
| fn matched_wires(&self) -> impl Iterator<Item = &PersistentWire> + '_ { | ||||||||||||||||||||||||||||||
| self.wires[0].iter().chain(self.wires[1].iter()) | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| pub struct KAKFactory; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| struct SearchingWalker <'w> { | ||||||||||||||||||||||||||||||
| walker: Walker <'w>, // Initial state of walker. | ||||||||||||||||||||||||||||||
| frontier_wires: Vec<PersistentWire>, // Wires to be expanded. | ||||||||||||||||||||||||||||||
| pattern: KAKResynthesis, // Current pattern. | ||||||||||||||||||||||||||||||
| two_qubit_node: Option<PatchNode>, // If a 2q gate has been found along one wire, | ||||||||||||||||||||||||||||||
| // but not yet the other, then it is stored here. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
| walker: Walker <'w>, // Initial state of walker. | |
| frontier_wires: Vec<PersistentWire>, // Wires to be expanded. | |
| pattern: KAKResynthesis, // Current pattern. | |
| two_qubit_node: Option<PatchNode>, // If a 2q gate has been found along one wire, | |
| // but not yet the other, then it is stored here. | |
| /// Initial state of walker. | |
| walker: Walker <'w>, | |
| /// Wires to be expanded. | |
| frontier_wires: Vec<PersistentWire>, | |
| /// Current pattern. | |
| pattern: KAKResynthesis, | |
| /// If a 2q gate has been found along one wire, | |
| /// but not yet the other, then it is stored here. | |
| two_qubit_node: Option<PatchNode>, |
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you are traversing wires backwards here: you are getting an incoming port, and traversing it to get the next outgoing port. It should be the opposite:
| let (frontier_node, _) = searching_walker.walker.wire_pinned_inports(&wire_to_search).next().expect("error"); | |
| // Expand the wire into the future | |
| for expanded_walker in searching_walker.walker.expand(&wire_to_search, Direction::Outgoing) { | |
| let (frontier_node, _) = searching_walker.walker.wire_pinned_outports(&wire_to_search).next().expect("error"); | |
| // Expand the wire into the future | |
| for expanded_walker in searching_walker.walker.expand(&wire_to_search, Direction::Incoming) { |
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this will always be port 0? Also, if you change the above direction, you will need to change it here too.
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wouldn't error if it is not a TKET2 (it could be an input/output node). Instead you could write
| let tket2_op = Tk2Op::from_extension_op(ext_op).expect("Not TKET2 OP"); | |
| let Ok(tket2_op) = Tk2Op::from_extension_op(ext_op) else { | |
| continue; | |
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See also comment below about adding searching_walker back to the queue in this case.
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, both here and just above in the suggestion I made about ignoring non-tket2 ops: you need to make sure that in this case you still add the existing match to the list of completed matches to be returned.
Probably the simplest way to do this would be to add searching_walker back to the queue.
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suspect the compiler must be complaining here about using searching_walker.pattern and searching_walker.walker in more than one place (more specifically, it will say "use of moved value" further below). You must clone the data:
| matches.push((searching_walker.pattern, searching_walker.walker)); | |
| matches.push((searching_walker.pattern.clone(), searching_walker.walker.clone())); |
That being said, this will add all possible subcircuits (not just the maximal ones). Is this what you want? Might indeed be the right way to go provided we don't get far too many matches.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
Adding all matches was indeed what I was going for as a first try.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a Hugr with more CZ and more than one match to test on. E.g.:
fn three_cz_hugr() -> Hugr {
let mut builder = DFGBuilder::new(endo_sig(vec![qb_t(); 3])).unwrap();
let [q0, q1, q2] = builder.input_wires_arr();
let cz1 = builder.add_dataflow_op(Tk2Op::CZ, vec![q0, q1]).unwrap();
let [q0, q1] = cz1.outputs_arr();
let cz2 = builder.add_dataflow_op(Tk2Op::CZ, vec![q0, q1]).unwrap();
let [q0, q1] = cz2.outputs_arr();
let cz3 = builder.add_dataflow_op(Tk2Op::CZ, vec![q0, q2]).unwrap();
let [q0, q2] = cz3.outputs_arr();
builder.finish_hugr_with_outputs(vec![q0, q1, q2]).unwrap()
}
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not important but useful to know:
if you replace #[test] with #[rstest] (you need to import it with use rstest::rstest) and you add #[fixture] (also imported from rstest) in front of your helper function one_cz_2qb_hugr, then you can write the test as
#[rstest]
fn test_kak_resynthesis_init(one_cz_2qb_hugr: Hugr) { ... }It's just syntactic sugar to move the construction of the Hugr from a function call in your function body as you have it now, to something that looks like an argument passed to the test.
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add an assertion to check this does what you expect.
The simplest would be to add a variable let mut n_matches = 0 before the loop, and then count the number of matches you find:
n_matches += factory.find_pattern_matches(node, walker).count();After the loop, you would write assert_eq(n_matches, 1).
A stronger test would involve looking into the matches obtained and checking it contains the gates you expect.
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's something weird here: the way this is written worked for
wires: [Vec<PersistentWire>; 2], but it looks like you've changed it to a simpleVec<_>. In this case,self.wires.iter()should be all you need here.