feat+fix!:(RFC) Fewer, tho occasionally more, order edges when inlining#3058
feat+fix!:(RFC) Fewer, tho occasionally more, order edges when inlining#3058acl-cqc wants to merge 5 commits into
Conversation
|
Hey there and thank you for opening this pull request! 👋 We follow the Conventional Commits convention for PR titles. It looks like your title needs some adjustment. The title should have a type prefix, followed by a colon. The most important ones are:
If the PR contains a breaking change, use You may also include a Expand this message for the full list of tags.
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #3058 +/- ##
=======================================
Coverage 81.16% 81.17%
=======================================
Files 240 240
Lines 45030 44975 -55
Branches 38788 38731 -57
=======================================
- Hits 36549 36508 -41
- Misses 6507 6508 +1
+ Partials 1974 1959 -15
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
d7dd9a7 to
1ed60bf
Compare
1ed60bf to
1841d0a
Compare
| * |. / NB. Order edge H_a to nested DFG | ||
| * | . | | ||
| * |. |? NB. Order edge H_a to nested DFG | ||
| * | . |? NB. Optional(o1) Order edge from H_b to nested DFG |
There was a problem hiding this comment.
I am starting to think that perhaps unparametrizing the test - with a fixture returning the Hugr, and all 5 relevant nodes/ops, allowing individual tests to add extra order edges, apply the patch, and test what Order edges are present after, might be clearer. But, a lot longer, I think...
|
Interesting. It isn't clear to me that the existing behaviour is wrong. Doesn't an order edge mean that nothing in the target node should execute until everything in the source node has executed -- even if one or both of those nodes is a DFG? Or am I missing the point? |
Yes and no. Prior to this PR, an order edge indeed means "nothing in the target (of the Order edge) should execute until everything in the source". That is, every DFG includes an implicit order-barrier across the inputs and outputs (not quite a normal barrier: dependencies solely by value edges are not barriered). Note there is no way not to have that barrier! Post this PR, there is no such barrier: Input/Output/DFG are transparent and just forward edges (the edge into the DFG feeds directly to the corresponding output edge(s) from the Input, only). If you want barriers, add them explicitly. Which is why this is "breaking", but I'm not sure (need to make certain about) to what extent the spec actually says the former (and needs updating), or whether the spec is unclear (needs changing, i.e. this is a clarification), or whether this is actually a pure "fix" |
Either way, the spec does need updating to make it clear what an order edge to or from a container node means. I must confess I don't really know what it means if the container node is not atomic with respect to order. (Even if it wasn't made explicit I had always assumed this.) |
Two parts here.
Instead, link only to order successors/predecessors. Thus, treating Order edges as its own edge type, which is kinda consistent with how we treat other edge types.
Is this breaking? This is somewhat debatable. The spec says, at least:
but I haven't been through the whole spec to see if it says anything else as well. The idea that DFGs (and hence Calls, etc.) execute "atomically" has been rather implicit and the question may be, what code is there that assumes this. One definite problem is RemoveRedundantOrderEdges pass, which will need to be updated not to touch order edges whose source/target is Input, Output, or any container node or a Call. Guppy programs should be ok, as they always have neat chains of order edges; Hugrs constructed by other means may not and might be broken by this PR (or might have already been broken before this PR) - where being "broken" means "may lead to wrong program results depending on topsorts taken by the compiler", emphasis on the may.
Possible mitigations?
weakly_ordered=trueenables the new policy, false/absent keeps the old policy. InlineCall needs to merge metadata from Call and callee. Switch guppy to add the metadata. Nice that this gives a fallback, but the long-term strategy to move the metadata to default-true (and then eventually remove it) is unclear.I've had a look at InQuanto's non-guppy code for generating Hugrs. They take a "flat circuit" function from pytket, (Qubit^N,Bool^M) -> (Qubit^N',Bool^M') and wire up N
QAllocs and MConst(false)s to the inputs, and N' QFree's and M'results to the outputs. No order edges...