Skip to content
Merged
Show file tree
Hide file tree
Changes from 59 commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
82e4892
linting
1ucian0 Feb 28, 2019
5a8377c
linting
1ucian0 Feb 28, 2019
ce08043
initial pass
1ucian0 Feb 28, 2019
9a94701
pass
1ucian0 Feb 28, 2019
e8da663
off-by-one in collect runs
1ucian0 Feb 28, 2019
18a3e4e
Merge branch 'off_by_one_collect_runs' into swap_measure_simplificati…
1ucian0 Feb 28, 2019
f4b54e1
stash
1ucian0 Feb 28, 2019
7f234b9
successors might not be that long
1ucian0 Mar 1, 2019
0e19165
first working version!
1ucian0 Mar 4, 2019
90b7648
copyright and import
1ucian0 Mar 4, 2019
9d7ab72
count operations pass
1ucian0 Mar 4, 2019
9b98f9b
empty dag test
1ucian0 Mar 4, 2019
32d58b3
Merge branch 'depth_pass' into swap_measure_simplification_pass
1ucian0 Mar 4, 2019
e7b9b25
fixed point
1ucian0 Mar 4, 2019
9dcd5ac
test_cannot_optimize
1ucian0 Mar 4, 2019
2253295
lint
1ucian0 Mar 5, 2019
429186f
Merge branch 'master' into swap_measure_simplification_pass
1ucian0 Mar 8, 2019
0294a75
Update qiskit/transpiler/passes/optimize_swap_before_measure.py
ajavadia Mar 12, 2019
6d53535
Update qiskit/transpiler/passes/optimize_swap_before_measure.py
ajavadia Mar 12, 2019
d74c8e3
Update qiskit/transpiler/passes/optimize_swap_before_measure.py
ajavadia Mar 12, 2019
1561bf7
Update test/python/transpiler/test_optimize_swap_before_measure.py
ajavadia Mar 12, 2019
464952c
remove_op_node is part of the DAG API
1ucian0 Mar 26, 2019
1413b68
lint
1ucian0 Mar 26, 2019
a913549
merge
1ucian0 Mar 26, 2019
28c7b1c
Merge branch 'swap_measure_simplification_pass' of https://github.com…
1ucian0 Mar 26, 2019
1951d60
Merge branch '289' into swap_measure_simplification_pass
1ucian0 Mar 26, 2019
0024328
Update qiskit/transpiler/passes/optimize_swap_before_measure.py
ajavadia Mar 26, 2019
06a3660
_basepasses -> basepasses
1ucian0 Mar 26, 2019
0afc21b
Merge branch 'swap_measure_simplification_pass' of https://github.com…
1ucian0 Mar 26, 2019
dd26f91
dag.successors returns DAGNodes
1ucian0 Mar 26, 2019
84e1c6e
docstirng
1ucian0 Mar 26, 2019
ed35597
Merge branch '289' into swap_measure_simplification_pass
1ucian0 Mar 26, 2019
1faa872
remove_op_node
1ucian0 Mar 26, 2019
3da1b77
lint
1ucian0 Mar 26, 2019
2d78057
lint
1ucian0 Mar 26, 2019
b5aa8aa
Merge branch 'master' into swap_measure_simplification_pass
1ucian0 Mar 27, 2019
4a7ad0c
Merge branch 'master' into swap_measure_simplification_pass
1ucian0 Mar 27, 2019
00bca79
Merge branch 'master' into swap_measure_simplification_pass
1ucian0 Mar 28, 2019
b380e71
Merge branch 'master' into swap_measure_simplification_pass
1ucian0 Apr 3, 2019
b0af2d0
Merge branch 'master' into swap_measure_simplification_pass
1ucian0 Apr 3, 2019
84f552a
Merge branch 'master' into swap_measure_simplification_pass
1ucian0 Apr 4, 2019
8cdc3bf
new measure_layer.apply_operation_back api
1ucian0 Apr 4, 2019
fe29f44
fix python.test_dagcircuit.TestDagOperations
1ucian0 Apr 4, 2019
58a975f
merge
1ucian0 Apr 5, 2019
e2b5d99
Merge branch 'master' of github.com:Qiskit/qiskit-terra into swap_mea…
1ucian0 Apr 5, 2019
877d9b0
Merge branch 'master' into swap_measure_simplification_pass
1ucian0 Apr 5, 2019
3a6b3e0
Merge branch 'master' into swap_measure_simplification_pass
1ucian0 Apr 5, 2019
ad1e64d
adapting test_optimize_swap_before_measure.py
1ucian0 Apr 5, 2019
66628e5
Merge branch 'master' into swap_measure_simplification_pass
1ucian0 Apr 5, 2019
ec6858b
Merge branch 'master' into swap_measure_simplification_pass
ajavadia Apr 7, 2019
2431311
Merge branch 'master' into swap_measure_simplification_pass
1ucian0 Apr 8, 2019
18d157c
Merge branch 'master' into swap_measure_simplification_pass
1ucian0 Apr 8, 2019
2365742
delete count_operations
1ucian0 Apr 8, 2019
97279f8
base on the dag fixed point instead of counting ops
1ucian0 Apr 8, 2019
ef5ab0b
undo this change
1ucian0 Apr 8, 2019
1f017f0
Merge branch 'master' into swap_measure_simplification_pass
1ucian0 Apr 8, 2019
d814b4a
Merge branch 'master' into swap_measure_simplification_pass
1ucian0 Apr 8, 2019
6295bb7
Merge branch 'master' into swap_measure_simplification_pass
1ucian0 Apr 9, 2019
671535f
Merge branch 'master' into swap_measure_simplification_pass
1ucian0 Apr 9, 2019
f0f151e
Merge branch 'master' into swap_measure_simplification_pass
ajavadia Apr 10, 2019
5e080fe
changelog
1ucian0 Apr 10, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions qiskit/transpiler/passes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from .decompose import Decompose
from .unroll_3q_or_more import Unroll3qOrMore
from .commutation_analysis import CommutationAnalysis
from .optimize_swap_before_measure import OptimizeSwapBeforeMeasure
from .mapping.barrier_before_final_measurements import BarrierBeforeFinalMeasurements
from .mapping.check_map import CheckMap
from .mapping.check_cnot_direction import CheckCnotDirection
Expand Down
50 changes: 50 additions & 0 deletions qiskit/transpiler/passes/optimize_swap_before_measure.py
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)
Comment thread
1ucian0 marked this conversation as resolved.
dag.remove_op_node(swap)
return dag
154 changes: 154 additions & 0 deletions test/python/transpiler/test_optimize_swap_before_measure.py
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()