Skip to content
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

Add pass to filter ops and label inserted barriers #10323

Merged
merged 14 commits into from
Nov 22, 2023

Conversation

mtreinish
Copy link
Member

@mtreinish mtreinish commented Jun 22, 2023

Summary

This commit adds a new transpiler pass FilterOpNodes which is used to remove operations that match a given filter function. This is paired with a new label option for BarrierBeforeFinalMeasurements which assigns a label to the inserted barrier. These are combined in the preset pass managers to ensure we're not always adding a barrier before output measurements in the output of the transpiler.

Details and comments

Fixes #10321
Fixes #11093

TODO:

  • Add dedicated unit tests for the new pass
  • Release notes
  • Test barrier in circuit input (i.e. .measure_all() case) and likely fix

@mtreinish mtreinish requested a review from a team as a code owner June 22, 2023 16:13
@qiskit-bot
Copy link
Collaborator

One or more of the the following people are requested to review this:

  • @Qiskit/terra-core

This commit adds a new transpiler pass RemoveLabeledOps which is used to
remove any op nodes that match a given label. This is paired with a new
label option for BarrierBeforeFinalMeasurements. These are combined in
the preset pass managers to ensure we're not always adding a barrier
before output measurements in the output of the transpiler.

Fixes Qiskit#10321
@mtreinish mtreinish force-pushed the no-barrier-leakage branch from ef070b1 to caae56f Compare June 22, 2023 16:24
@coveralls
Copy link

Pull Request Test Coverage Report for Build 5347967433

  • 24 of 24 (100.0%) changed or added relevant lines in 5 files are covered.
  • 20 unchanged lines in 5 files lost coverage.
  • Overall coverage increased (+0.009%) to 85.953%

Files with Coverage Reduction New Missed Lines %
qiskit/transpiler/passes/synthesis/unitary_synthesis.py 1 90.39%
crates/qasm2/src/lex.rs 2 91.65%
qiskit/extensions/quantum_initializer/squ.py 2 80.0%
crates/accelerate/src/vf2_layout.rs 3 94.74%
crates/qasm2/src/parse.rs 12 97.11%
Totals Coverage Status
Change from base Build 5334907613: 0.009%
Covered Lines: 71363
Relevant Lines: 83026

💛 - Coveralls

Copy link
Member

@jakelishman jakelishman left a comment

Choose a reason for hiding this comment

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

lol at the entries on the TODO haha. From an implementation perspective, this looks fairly straightforwards to me.

qiskit/transpiler/passes/utils/remove_labeled_ops.py Outdated Show resolved Hide resolved
In the case when a label is set to trigger the removal of the labelled
barrier the merge step would lose the context around which barrier
instruction was transpiler inserted and which was user provided. To
address this issue this commit skips the MergeAdjacentBarrier step so
that the transpiler barrier is kept separate from any user inserted
barriers which need to be preserved.
@coveralls
Copy link

coveralls commented Nov 21, 2023

Pull Request Test Coverage Report for Build 6958650976

  • 30 of 30 (100.0%) changed or added relevant lines in 5 files are covered.
  • 4 unchanged lines in 1 file lost coverage.
  • Overall coverage increased (+0.009%) to 86.47%

Files with Coverage Reduction New Missed Lines %
crates/qasm2/src/lex.rs 4 92.17%
Totals Coverage Status
Change from base Build 6951563267: 0.009%
Covered Lines: 66317
Relevant Lines: 76694

💛 - Coveralls

This commit generalizes the new RemoveLabeledOps pass to be a generic
node filtering pass that given a filter function it will remove any
matching op nodes in the circuit.
@mtreinish mtreinish changed the title [WIP] Add pass to remove labeled ops and label inserted barriers Add pass to remove labeled ops and label inserted barriers Nov 21, 2023
@mtreinish mtreinish added the Changelog: New Feature Include in the "Added" section of the changelog label Nov 21, 2023
@mtreinish mtreinish added this to the 1.0.0pre1 milestone Nov 21, 2023
@mtreinish
Copy link
Member Author

I've updated this PR to fix the bug with adjacent barriers and also generalized the filter pass to work for any filter function and not just those that match a given label. This should be ready for review now.

@mtreinish mtreinish modified the milestones: 1.0.0pre1, 1.0.0 Nov 21, 2023
@mtreinish mtreinish changed the title Add pass to remove labeled ops and label inserted barriers Add pass to filter ops and label inserted barriers Nov 22, 2023
jakelishman
jakelishman previously approved these changes Nov 22, 2023
Copy link
Member

@jakelishman jakelishman left a comment

Choose a reason for hiding this comment

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

The new pass seems like a very useful utility pass for sure, and it definitely seems better for us to not leak out the internal detail of the barrier before the final measures.

Happy to approve/merge as-is, but I had a couple of questions that maybe want a change.

qiskit/transpiler/passes/utils/filter_op_nodes.py Outdated Show resolved Hide resolved
qiskit/transpiler/passes/utils/filter_op_nodes.py Outdated Show resolved Hide resolved
Comment on lines 254 to 260
self.assertIsInstance(res, QuantumCircuit)
layout = res._layout.initial_layout
self.assertEqual(
[layout[q] for q in qc.qubits], [22, 7, 2, 12, 1, 5, 14, 4, 11, 0, 16, 15, 3, 10]
[layout[q] for q in qc.qubits], [10, 16, 8, 4, 11, 20, 15, 19, 18, 7, 12, 1, 2, 0]
)


Copy link
Member

Choose a reason for hiding this comment

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

Do we know why this changed? The actual barriers inserted before routing should have been the same, right, so it shouldn't have affected StochasticSwap? It's not really a problem, I just don't understand why it's changed.

Copy link
Member Author

@mtreinish mtreinish Nov 22, 2023

Choose a reason for hiding this comment

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

My assumption was because the input circuit has barriers in it that this was a side effect of not running merge adjacent barriers part of the barrier insertion. (this only changed with 29c1217 ). So, now we have multiple barriers followed by an all qubit barrier instead of it all getting merged into a single barrier. But I didn't look too closely at the internals of what was causing sabre to diverge internally.

Copy link
Member Author

Choose a reason for hiding this comment

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

Just a heads up I did get to the bottom of this, it was basically what I thought. I pushed up #11295 to fix the behavior of Sabre with regards to barriers and had to revert this change in that PR: 93a3241

This commit inverts the predicate usage to be consistent with Python's
built in filter() function. Now if the predicate returns True the dag node
is retained and if it returns false it is removed. This is also
explicitly documented to make it clear how the pass is to be used.
Copy link
Member

@jakelishman jakelishman left a comment

Choose a reason for hiding this comment

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

Looks good to me, thanks!

@jakelishman jakelishman added this pull request to the merge queue Nov 22, 2023
Merged via the queue into Qiskit:main with commit 8a58b3a Nov 22, 2023
14 checks passed
mtreinish added a commit to mtreinish/qiskit-core that referenced this pull request Nov 22, 2023
This commit updates a layout in the:
`TestSabreLayout.test_layout_many_search_trials` test case which was
recently changed in Qiskit#10323. The change in test ouput caused by Qiskit#10323
is what triggered the investigation into this bugfix and now that
barriers are being treated correctly by sabre the layout doesn't change
in the test case anymore and this is reverting the test assertion to use
the original layout before Qiskit#10323 was merged.
@mtreinish mtreinish deleted the no-barrier-leakage branch November 22, 2023 20:39
github-merge-queue bot pushed a commit that referenced this pull request Nov 23, 2023
* Avoid routing 2q barriers in SabreSwap

This commit fixes an oversight in the sabre swap pass where a 2 qubit
barrier would have been treated like a 2 qubit gate and swaps could
potentially be inserted if the sabre algorithm thought it didn't have
connectivity for the qargs to the barrier. However as barrier is just
a compiler directive it is valid on all qubit pairs so this swap
insertion was unnecessary, it was still valid but just not an optimal
output. This commit fixes it by adding context to the sabre dag around
whether a given node is a directive (and valid on all qubits) or not.

* Update rust tests too

* Skip directives in extended set generation too

Co-authored-by: Kevin Hartman <[email protected]>

* Add release note

* Update test layout in test_layout_many_search_trials

This commit updates a layout in the:
`TestSabreLayout.test_layout_many_search_trials` test case which was
recently changed in #10323. The change in test ouput caused by #10323
is what triggered the investigation into this bugfix and now that
barriers are being treated correctly by sabre the layout doesn't change
in the test case anymore and this is reverting the test assertion to use
the original layout before #10323 was merged.

---------

Co-authored-by: Kevin Hartman <[email protected]>
gluonhiggs pushed a commit to gluonhiggs/qiskit that referenced this pull request Nov 23, 2023
* Avoid routing 2q barriers in SabreSwap

This commit fixes an oversight in the sabre swap pass where a 2 qubit
barrier would have been treated like a 2 qubit gate and swaps could
potentially be inserted if the sabre algorithm thought it didn't have
connectivity for the qargs to the barrier. However as barrier is just
a compiler directive it is valid on all qubit pairs so this swap
insertion was unnecessary, it was still valid but just not an optimal
output. This commit fixes it by adding context to the sabre dag around
whether a given node is a directive (and valid on all qubits) or not.

* Update rust tests too

* Skip directives in extended set generation too

Co-authored-by: Kevin Hartman <[email protected]>

* Add release note

* Update test layout in test_layout_many_search_trials

This commit updates a layout in the:
`TestSabreLayout.test_layout_many_search_trials` test case which was
recently changed in Qiskit#10323. The change in test ouput caused by Qiskit#10323
is what triggered the investigation into this bugfix and now that
barriers are being treated correctly by sabre the layout doesn't change
in the test case anymore and this is reverting the test assertion to use
the original layout before Qiskit#10323 was merged.

---------

Co-authored-by: Kevin Hartman <[email protected]>
FabianBrings pushed a commit to FabianBrings/qiskit that referenced this pull request Nov 27, 2023
* Add pass to remove labeled ops and label inserted barriers

This commit adds a new transpiler pass RemoveLabeledOps which is used to
remove any op nodes that match a given label. This is paired with a new
label option for BarrierBeforeFinalMeasurements. These are combined in
the preset pass managers to ensure we're not always adding a barrier
before output measurements in the output of the transpiler.

Fixes Qiskit#10321

* Fix rebase issues

* Handle pre-existing adjacent barriers

In the case when a label is set to trigger the removal of the labelled
barrier the merge step would lose the context around which barrier
instruction was transpiler inserted and which was user provided. To
address this issue this commit skips the MergeAdjacentBarrier step so
that the transpiler barrier is kept separate from any user inserted
barriers which need to be preserved.

* Generalize RemoveLabeledOps to FilterOpNodes

This commit generalizes the new RemoveLabeledOps pass to be a generic
node filtering pass that given a filter function it will remove any
matching op nodes in the circuit.

* Add release note

* Add tests for new pass

* Add release note for new barrier pass kwarg

* Fix type hint

* Fix docs typo

* Invert predicate usage

This commit inverts the predicate usage to be consistent with Python's
built in filter() function. Now if the predicate returns True the dag node
is retained and if it returns false it is removed. This is also
explicitly documented to make it clear how the pass is to be used.

* Update pass manager drawer reference images
FabianBrings pushed a commit to FabianBrings/qiskit that referenced this pull request Nov 27, 2023
* Avoid routing 2q barriers in SabreSwap

This commit fixes an oversight in the sabre swap pass where a 2 qubit
barrier would have been treated like a 2 qubit gate and swaps could
potentially be inserted if the sabre algorithm thought it didn't have
connectivity for the qargs to the barrier. However as barrier is just
a compiler directive it is valid on all qubit pairs so this swap
insertion was unnecessary, it was still valid but just not an optimal
output. This commit fixes it by adding context to the sabre dag around
whether a given node is a directive (and valid on all qubits) or not.

* Update rust tests too

* Skip directives in extended set generation too

Co-authored-by: Kevin Hartman <[email protected]>

* Add release note

* Update test layout in test_layout_many_search_trials

This commit updates a layout in the:
`TestSabreLayout.test_layout_many_search_trials` test case which was
recently changed in Qiskit#10323. The change in test ouput caused by Qiskit#10323
is what triggered the investigation into this bugfix and now that
barriers are being treated correctly by sabre the layout doesn't change
in the test case anymore and this is reverting the test assertion to use
the original layout before Qiskit#10323 was merged.

---------

Co-authored-by: Kevin Hartman <[email protected]>
mtreinish added a commit to mtreinish/qiskit-core that referenced this pull request Jan 26, 2024
This commit fixes an issue in the disjoint layout processing caused by a
shared reference from the input dag to a layout pass to the internal
transformations the layout processing performs. As part of the disjoint
layout processing the input dag needs to be split into smaller dags
for each connected component in the circuit. To enable this any barriers
present in the circuit need to be split up prior to analyzing the
connected components in the dag. A multiqubit barrier doesn't represent
a real connectivity requirement so they need to be split prior to
analysis to ensure they don't factor into the connected component
computation. To faciliate not losing the semantic meaning of the barrier
for the layout analysis of each connected component, the barrier split is
done by first taking an n-qubit barrier and converting it into n parallel
1q barriers with a uuid label applied to it. Then after we split the
circuit into the separate connected components the uuid is used to
identify any components of the same barrier and combine them together.

There were two issues with this approach the first is that the splitting
of the barriers was done on the input dag without copying first. This
causes the input dag to be modified and because in most cases it's a
shared instance which would leak out the barrier splitting if the input
dag was returned verbatim from the pass, which in most cases it would
be. This issue is fixed by ensuring that we re-combine any split
barriers after we've split the dag into it's connected components.
The second issue is the uuid label assignment would overwrite any
existing labels on barriers. While setting labels on barriers is
uncommon for users to do (but still completely valid) this is causing a
bigger issues since Qiskit#10323 because the transpiler is assigning labels to
barriers it creates internally so they can be removed before the circuit
is returned. This is also fixed in this commit by appending a uuid to
the existing label instead of overwriting it, so we're able to restore
the original label when we recombine barriers.

Fixes Qiskit#11649
github-merge-queue bot pushed a commit that referenced this pull request Jan 30, 2024
* Fix split barriers leaking during disjoint layout processing

This commit fixes an issue in the disjoint layout processing caused by a
shared reference from the input dag to a layout pass to the internal
transformations the layout processing performs. As part of the disjoint
layout processing the input dag needs to be split into smaller dags
for each connected component in the circuit. To enable this any barriers
present in the circuit need to be split up prior to analyzing the
connected components in the dag. A multiqubit barrier doesn't represent
a real connectivity requirement so they need to be split prior to
analysis to ensure they don't factor into the connected component
computation. To faciliate not losing the semantic meaning of the barrier
for the layout analysis of each connected component, the barrier split is
done by first taking an n-qubit barrier and converting it into n parallel
1q barriers with a uuid label applied to it. Then after we split the
circuit into the separate connected components the uuid is used to
identify any components of the same barrier and combine them together.

There were two issues with this approach the first is that the splitting
of the barriers was done on the input dag without copying first. This
causes the input dag to be modified and because in most cases it's a
shared instance which would leak out the barrier splitting if the input
dag was returned verbatim from the pass, which in most cases it would
be. This issue is fixed by ensuring that we re-combine any split
barriers after we've split the dag into it's connected components.
The second issue is the uuid label assignment would overwrite any
existing labels on barriers. While setting labels on barriers is
uncommon for users to do (but still completely valid) this is causing a
bigger issues since #10323 because the transpiler is assigning labels to
barriers it creates internally so they can be removed before the circuit
is returned. This is also fixed in this commit by appending a uuid to
the existing label instead of overwriting it, so we're able to restore
the original label when we recombine barriers.

Fixes #11649

* Always use string uuid

* Add release note
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Changelog: New Feature Include in the "Added" section of the changelog
Projects
None yet
4 participants