Skip to content

Commit

Permalink
Fixed bug in OptimizeSwapBeforeMeasure (#11413)
Browse files Browse the repository at this point in the history
* fixed bug in OptimizeSwapBeforeMeasure #11195

* fix lint issue

(cherry picked from commit 3551c7c)
  • Loading branch information
border-b authored and mergify[bot] committed Dec 14, 2023
1 parent ef21b50 commit 8428277
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def run(self, dag):
if getattr(swap.op, "condition", None) is not None:
continue
final_successor = []
for successor in dag.successors(swap):
for successor in dag.descendants(swap):
final_successor.append(
isinstance(successor, DAGOutNode)
or (isinstance(successor, DAGOpNode) and isinstance(successor.op, Measure))
Expand All @@ -56,7 +56,7 @@ def run(self, dag):
measure_layer.add_qreg(qreg)
for creg in dag.cregs.values():
measure_layer.add_creg(creg)
for successor in list(dag.successors(swap)):
for successor in list(dag.descendants(swap)):
if isinstance(successor, DAGOpNode) and isinstance(successor.op, Measure):
# replace measure node with a new one, where qargs is set with the "other"
# swap qarg.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
fixes:
- |
Fixed an issue with the :class:`~.OptimizeSwapBeforeMeasure` pass where
it would incorrectly optimize circuits involving swap and measure
instructions. This commit fixes the bug by changing `DAGCircuit.successors`
to `DAGCircuit.descendants`. Also, added a couple of extra tests to ensure
that the bug is fixed. For example::
from qiskit import QuantumCircuit
from qiskit.transpiler.passes import OptimizeSwapBeforeMeasure
pass_ = OptimizeSwapBeforeMeasure()
qc = QuantumCircuit(2, 1)
qc.swap(0, 1)
qc.measure(0, 0)
qc.measure(0, 0)
print(qc.draw())
print(pass_(qc).draw())
would previously print::
┌─┐┌─┐
q_0: ─X─┤M├┤M├
│ └╥┘└╥┘
q_1: ─X──╫──╫─
║ ║
c: 1/════╩══╩═
0 0
┌─┐
q_0: ┤M├───
└╥┘┌─┐
q_1: ─╫─┤M├
║ └╥┘
c: 1/═╩══╩═
0 0
and now the second ciruit is correctly optimized to::
q_0: ──────
┌─┐┌─┐
q_1: ┤M├┤M├
└╥┘└╥┘
c: 1/═╩══╩═
0 0
71 changes: 71 additions & 0 deletions test/python/transpiler/test_optimize_swap_before_measure.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,38 @@ def test_optimize_1swap_2measure(self):

self.assertEqual(circuit_to_dag(expected), after)

def test_optimize_3swap_3measure(self):
"""Remove three swaps affecting three measurements
┌─┐ ┌─┐ ┌─┐
q_0: ─X─┤M├────X──X─┤M├ q_0: ───┤M├───
│ └╥┘┌─┐ │ │ └╥┘ ┌─┐└╥┘┌─┐
q_1: ─X──╫─┤M├─┼──┼──╫─ q_1: ┤M├─╫─┤M├
║ └╥┘ │ │ ║ ==> └╥┘ ║ └╥┘
q_2: ────╫──╫──X──X──╫─ q_2: ─╫──╫──╫─
║ ║ ║ ║ ║ ║
c: 2/════╩══╩════════╩═ c: 2/═╩══╩══╩═
0 1 0 0 1 0
"""

qc = QuantumCircuit(3, 2)
qc.swap(0, 1)
qc.measure(0, 0)
qc.swap(0, 2)
qc.measure(1, 1)
qc.swap(0, 2)
qc.measure(0, 0)
dag = circuit_to_dag(qc)

expected = QuantumCircuit(3, 2)
expected.measure(1, 0)
expected.measure(0, 1)
expected.measure(1, 0)

pass_ = OptimizeSwapBeforeMeasure()
after = pass_.run(dag)

self.assertEqual(circuit_to_dag(expected), after)

def test_optimize_nswap_nmeasure(self):
"""Remove severals swap affecting multiple measurements
┌─┐ ┌─┐
Expand Down Expand Up @@ -139,6 +171,45 @@ def test_optimize_nswap_nmeasure(self):

self.assertEqual(circuit_to_dag(expected), after)

def test_optimize_nswap_nmeasure_2(self):
"""Remove multiple swaps affecting multiple measurements
┌─┐┌─┐ ┌─┐┌─┐┌─┐┌─┐┌─┐
q_0: ─X──X─┤M├┤M├─X──────────────X─ q_0: ┤M├┤M├┤M├┤M├┤M├
│ │ └╥┘└╥┘ │ ┌─┐ │ └╥┘└╥┘└╥┘└╥┘└╥┘
q_1: ─X──X──╫──╫──┼─────X─┤M├─X──X─ q_1: ─╫──╫──╫──╫──╫─
║ ║ │ ┌─┐ │ └╥┘ │ ┌─┐ ==> ║ ║ ║ ║ ║
q_2: ───────╫──╫──X─┤M├─X──╫──X─┤M├ q_2: ─╫──╫──╫──╫──╫─
║ ║ └╥┘ ║ └╥┘ ║ ║ ║ ║ ║
c: 1/═══════╩══╩═════╩═════╩═════╩═ c: 1/═╩══╩══╩══╩══╩═
0 0 0 0 0 0 0 0 0 0
"""

qc = QuantumCircuit(3, 1)
qc.swap(0, 1)
qc.swap(0, 1)
qc.measure(0, 0)
qc.measure(0, 0)
qc.swap(2, 0)
qc.measure(2, 0)
qc.swap(1, 2)
qc.measure(1, 0)
qc.swap(1, 2)
qc.swap(0, 1)
qc.measure(2, 0)
dag = circuit_to_dag(qc)

expected = QuantumCircuit(3, 1)
expected.measure(0, 0)
expected.measure(0, 0)
expected.measure(0, 0)
expected.measure(0, 0)
expected.measure(0, 0)

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--
Expand Down

0 comments on commit 8428277

Please sign in to comment.