-
Notifications
You must be signed in to change notification settings - Fork 3k
"swap followed by measure" optimization pass #1890
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
1ucian0
merged 61 commits into
Qiskit:master
from
1ucian0:swap_measure_simplification_pass
Apr 10, 2019
Merged
Changes from 59 commits
Commits
Show all changes
61 commits
Select commit
Hold shift + click to select a range
82e4892
linting
1ucian0 5a8377c
linting
1ucian0 ce08043
initial pass
1ucian0 9a94701
pass
1ucian0 e8da663
off-by-one in collect runs
1ucian0 18a3e4e
Merge branch 'off_by_one_collect_runs' into swap_measure_simplificati…
1ucian0 f4b54e1
stash
1ucian0 7f234b9
successors might not be that long
1ucian0 0e19165
first working version!
1ucian0 90b7648
copyright and import
1ucian0 9d7ab72
count operations pass
1ucian0 9b98f9b
empty dag test
1ucian0 32d58b3
Merge branch 'depth_pass' into swap_measure_simplification_pass
1ucian0 e7b9b25
fixed point
1ucian0 9dcd5ac
test_cannot_optimize
1ucian0 2253295
lint
1ucian0 429186f
Merge branch 'master' into swap_measure_simplification_pass
1ucian0 0294a75
Update qiskit/transpiler/passes/optimize_swap_before_measure.py
ajavadia 6d53535
Update qiskit/transpiler/passes/optimize_swap_before_measure.py
ajavadia d74c8e3
Update qiskit/transpiler/passes/optimize_swap_before_measure.py
ajavadia 1561bf7
Update test/python/transpiler/test_optimize_swap_before_measure.py
ajavadia 464952c
remove_op_node is part of the DAG API
1ucian0 1413b68
lint
1ucian0 a913549
merge
1ucian0 28c7b1c
Merge branch 'swap_measure_simplification_pass' of https://github.com…
1ucian0 1951d60
Merge branch '289' into swap_measure_simplification_pass
1ucian0 0024328
Update qiskit/transpiler/passes/optimize_swap_before_measure.py
ajavadia 06a3660
_basepasses -> basepasses
1ucian0 0afc21b
Merge branch 'swap_measure_simplification_pass' of https://github.com…
1ucian0 dd26f91
dag.successors returns DAGNodes
1ucian0 84e1c6e
docstirng
1ucian0 ed35597
Merge branch '289' into swap_measure_simplification_pass
1ucian0 1faa872
remove_op_node
1ucian0 3da1b77
lint
1ucian0 2d78057
lint
1ucian0 b5aa8aa
Merge branch 'master' into swap_measure_simplification_pass
1ucian0 4a7ad0c
Merge branch 'master' into swap_measure_simplification_pass
1ucian0 00bca79
Merge branch 'master' into swap_measure_simplification_pass
1ucian0 b380e71
Merge branch 'master' into swap_measure_simplification_pass
1ucian0 b0af2d0
Merge branch 'master' into swap_measure_simplification_pass
1ucian0 84f552a
Merge branch 'master' into swap_measure_simplification_pass
1ucian0 8cdc3bf
new measure_layer.apply_operation_back api
1ucian0 fe29f44
fix python.test_dagcircuit.TestDagOperations
1ucian0 58a975f
merge
1ucian0 e2b5d99
Merge branch 'master' of github.com:Qiskit/qiskit-terra into swap_mea…
1ucian0 877d9b0
Merge branch 'master' into swap_measure_simplification_pass
1ucian0 3a6b3e0
Merge branch 'master' into swap_measure_simplification_pass
1ucian0 ad1e64d
adapting test_optimize_swap_before_measure.py
1ucian0 66628e5
Merge branch 'master' into swap_measure_simplification_pass
1ucian0 ec6858b
Merge branch 'master' into swap_measure_simplification_pass
ajavadia 2431311
Merge branch 'master' into swap_measure_simplification_pass
1ucian0 18d157c
Merge branch 'master' into swap_measure_simplification_pass
1ucian0 2365742
delete count_operations
1ucian0 97279f8
base on the dag fixed point instead of counting ops
1ucian0 ef5ab0b
undo this change
1ucian0 1f017f0
Merge branch 'master' into swap_measure_simplification_pass
1ucian0 d814b4a
Merge branch 'master' into swap_measure_simplification_pass
1ucian0 6295bb7
Merge branch 'master' into swap_measure_simplification_pass
1ucian0 671535f
Merge branch 'master' into swap_measure_simplification_pass
1ucian0 f0f151e
Merge branch 'master' into swap_measure_simplification_pass
ajavadia 5e080fe
changelog
1ucian0 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
There are no files selected for viewing
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 |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| # -*- coding: utf-8 -*- | ||
|
|
||
| # Copyright 2019, IBM. | ||
| # | ||
| # This source code is licensed under the Apache License, Version 2.0 found in | ||
| # the LICENSE.txt file in the root directory of this source tree. | ||
|
|
||
|
|
||
| """ | ||
| Transpiler pass to remove swaps in front of measurements by re-targeting the classical bit | ||
| of the measure instruction. | ||
| """ | ||
|
|
||
| from qiskit.circuit import Measure | ||
| from qiskit.extensions.standard import SwapGate | ||
| from qiskit.transpiler.basepasses import TransformationPass | ||
| from qiskit.dagcircuit import DAGCircuit | ||
|
|
||
|
|
||
| class OptimizeSwapBeforeMeasure(TransformationPass): | ||
| """Remove the swaps followed by measurement (and adapt the measurement)""" | ||
|
|
||
| def run(self, dag): | ||
| """Return a new circuit that has been optimized.""" | ||
| swaps = dag.op_nodes(SwapGate) | ||
| for swap in swaps: | ||
| final_successor = [] | ||
| for successor in dag.successors(swap): | ||
| final_successor.append(successor.type == 'out' or (successor.type == 'op' and | ||
| successor.op.name == 'measure')) | ||
| if all(final_successor): | ||
| # the node swap needs to be removed and, if a measure follows, needs to be adapted | ||
| swap_qargs = swap.qargs | ||
| measure_layer = DAGCircuit() | ||
| for qreg in dag.qregs.values(): | ||
| measure_layer.add_qreg(qreg) | ||
| for creg in dag.cregs.values(): | ||
| measure_layer.add_creg(creg) | ||
| for successor in dag.successors(swap): | ||
| if successor.type == 'op' and successor.op.name == 'measure': | ||
| # replace measure node with a new one, where qargs is set with the "other" | ||
| # swap qarg. | ||
| dag.remove_op_node(successor) | ||
| old_measure_qarg = successor.qargs[0] | ||
| new_measure_qarg = swap_qargs[swap_qargs.index(old_measure_qarg) - 1] | ||
| measure_layer.apply_operation_back(Measure(), [new_measure_qarg], | ||
| [successor.cargs[0]]) | ||
| dag.extend_back(measure_layer) | ||
| dag.remove_op_node(swap) | ||
| return dag | ||
154 changes: 154 additions & 0 deletions
154
test/python/transpiler/test_optimize_swap_before_measure.py
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 |
|---|---|---|
| @@ -0,0 +1,154 @@ | ||
| # -*- coding: utf-8 -*- | ||
|
|
||
| # Copyright 2019, IBM. | ||
| # | ||
| # This source code is licensed under the Apache License, Version 2.0 found in | ||
| # the LICENSE.txt file in the root directory of this source tree. | ||
|
|
||
| """Test OptimizeSwapBeforeMeasure pass""" | ||
|
|
||
| import unittest | ||
|
|
||
| from qiskit import QuantumRegister, QuantumCircuit, ClassicalRegister | ||
| from qiskit.transpiler import PassManager, transpile_dag | ||
| from qiskit.transpiler.passes import OptimizeSwapBeforeMeasure, DAGFixedPoint | ||
| from qiskit.converters import circuit_to_dag | ||
| from qiskit.test import QiskitTestCase | ||
|
|
||
|
|
||
| class TestOptimizeSwapBeforeMeasure(QiskitTestCase): | ||
| """ Test swap-followed-by-measure optimizations. """ | ||
|
|
||
| def test_optimize_1swap_1measure(self): | ||
| """ Remove a single swap | ||
| qr0:--X--m-- qr0:---- | ||
| | | | ||
| qr1:--X--|-- ==> qr1:--m- | ||
| | | | ||
| cr0:-----.-- cr0:--.- | ||
| """ | ||
| qr = QuantumRegister(2, 'qr') | ||
| cr = ClassicalRegister(1, 'cr') | ||
| circuit = QuantumCircuit(qr, cr) | ||
| circuit.swap(qr[0], qr[1]) | ||
| circuit.measure(qr[0], cr[0]) | ||
| dag = circuit_to_dag(circuit) | ||
|
|
||
| expected = QuantumCircuit(qr, cr) | ||
| expected.measure(qr[1], cr[0]) | ||
|
|
||
| pass_ = OptimizeSwapBeforeMeasure() | ||
| after = pass_.run(dag) | ||
|
|
||
| self.assertEqual(circuit_to_dag(expected), after) | ||
|
|
||
| def test_optimize_1swap_2measure(self): | ||
| """ Remove a single swap affecting two measurements | ||
| qr0:--X--m-- qr0:--m---- | ||
| | | | | ||
| qr1:--X--|--m ==> qr1:--|--m- | ||
| | | | | | ||
| cr0:-----.--|-- cr0:--|--.- | ||
| cr1:--------.-- cr1:--.---- | ||
| """ | ||
| qr = QuantumRegister(2, 'qr') | ||
| cr = ClassicalRegister(2, 'cr') | ||
| circuit = QuantumCircuit(qr, cr) | ||
| circuit.swap(qr[0], qr[1]) | ||
| circuit.measure(qr[0], cr[0]) | ||
| circuit.measure(qr[1], cr[1]) | ||
| dag = circuit_to_dag(circuit) | ||
|
|
||
| expected = QuantumCircuit(qr, cr) | ||
| expected.measure(qr[1], cr[0]) | ||
| expected.measure(qr[0], cr[1]) | ||
|
|
||
| pass_ = OptimizeSwapBeforeMeasure() | ||
| after = pass_.run(dag) | ||
|
|
||
| self.assertEqual(circuit_to_dag(expected), after) | ||
|
|
||
| def test_cannot_optimize(self): | ||
| """ Cannot optimize when swap is not at the end in all of the successors | ||
| qr0:--X-----m-- | ||
| | | | ||
| qr1:--X-[H]-|-- | ||
| | | ||
| cr0:--------.-- | ||
| """ | ||
| qr = QuantumRegister(2, 'qr') | ||
| cr = ClassicalRegister(1, 'cr') | ||
| circuit = QuantumCircuit(qr, cr) | ||
| circuit.swap(qr[0], qr[1]) | ||
| circuit.h(qr[1]) | ||
| circuit.measure(qr[0], cr[0]) | ||
| dag = circuit_to_dag(circuit) | ||
|
|
||
| pass_ = OptimizeSwapBeforeMeasure() | ||
| after = pass_.run(dag) | ||
|
|
||
| self.assertEqual(circuit_to_dag(circuit), after) | ||
|
|
||
|
|
||
| class TestOptimizeSwapBeforeMeasureFixedPoint(QiskitTestCase): | ||
| """ Test swap-followed-by-measure optimizations in a transpiler, using fixed point. """ | ||
|
|
||
| def test_optimize_undone_swap(self): | ||
| """ Remove redundant swap | ||
| qr0:--X--X--m-- qr0:--m--- | ||
| | | | | | ||
| qr1:--X--X--|-- ==> qr1:--|-- | ||
| | | | ||
| cr0:--------.-- cr0:--.-- | ||
| """ | ||
| qr = QuantumRegister(2, 'qr') | ||
| cr = ClassicalRegister(1, 'cr') | ||
| circuit = QuantumCircuit(qr, cr) | ||
| circuit.swap(qr[0], qr[1]) | ||
| circuit.swap(qr[0], qr[1]) | ||
| circuit.measure(qr[0], cr[0]) | ||
| dag = circuit_to_dag(circuit) | ||
|
|
||
| expected = QuantumCircuit(qr, cr) | ||
| expected.measure(qr[0], cr[0]) | ||
|
|
||
| pass_manager = PassManager() | ||
| pass_manager.append( | ||
| [OptimizeSwapBeforeMeasure(), DAGFixedPoint()], | ||
| do_while=lambda property_set: not property_set['dag_fixed_point']) | ||
| after = transpile_dag(dag, pass_manager=pass_manager) | ||
|
|
||
| self.assertEqual(circuit_to_dag(expected), after) | ||
|
|
||
| def test_optimize_overlap_swap(self): | ||
| """ Remove two swaps that overlap | ||
| qr0:--X-------- qr0:--m-- | ||
| | | | ||
| qr1:--X--X----- qr1:--|-- | ||
| | ==> | | ||
| qr2:-----X--m-- qr2:--|-- | ||
| | | | ||
| cr0:--------.-- cr0:--.-- | ||
| """ | ||
| qr = QuantumRegister(3, 'qr') | ||
| cr = ClassicalRegister(1, 'cr') | ||
| circuit = QuantumCircuit(qr, cr) | ||
| circuit.swap(qr[0], qr[1]) | ||
| circuit.swap(qr[1], qr[2]) | ||
| circuit.measure(qr[2], cr[0]) | ||
| dag = circuit_to_dag(circuit) | ||
|
|
||
| expected = QuantumCircuit(qr, cr) | ||
| expected.measure(qr[0], cr[0]) | ||
|
|
||
| pass_manager = PassManager() | ||
| pass_manager.append( | ||
| [OptimizeSwapBeforeMeasure(), DAGFixedPoint()], | ||
| do_while=lambda property_set: not property_set['dag_fixed_point']) | ||
| after = transpile_dag(dag, pass_manager=pass_manager) | ||
|
|
||
| self.assertEqual(circuit_to_dag(expected), after) | ||
|
|
||
|
|
||
| if __name__ == '__main__': | ||
| unittest.main() |
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.