Skip to content

Commit

Permalink
Add RemoveFinalReset pass (#11266)
Browse files Browse the repository at this point in the history
* Add RemoveFinalReset pass

* Fix lint

* Look at predecessors of `output_map`

Suggested at #11266 (comment)

Co-authored-by: Matthew Treinish <mtreinish@kortar.org>

* Remove `RemoveFinalReset` from preset passmanagers

This pass modifies the quantum output state of the circuit, so it
should not be run by default.

* Update remove-final-reset-488247c01c4e147d.yaml

It's no longer run by default at any optimization level.

* Fix `QiskitTestCase` import

* Update to use `DoWhileController`

---------

Co-authored-by: Matthew Treinish <mtreinish@kortar.org>
  • Loading branch information
garrison and mtreinish committed Mar 19, 2024
1 parent 194cc8f commit 494a32e
Show file tree
Hide file tree
Showing 7 changed files with 194 additions and 1 deletion.
2 changes: 2 additions & 0 deletions qiskit/transpiler/passes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
Optimize1qGatesSimpleCommutation
RemoveDiagonalGatesBeforeMeasure
RemoveResetInZeroState
RemoveFinalReset
HoareOptimizer
TemplateOptimization
EchoRZXWeylDecomposition
Expand Down Expand Up @@ -225,6 +226,7 @@
from .optimization import Optimize1qGatesSimpleCommutation
from .optimization import OptimizeSwapBeforeMeasure
from .optimization import RemoveResetInZeroState
from .optimization import RemoveFinalReset
from .optimization import RemoveDiagonalGatesBeforeMeasure
from .optimization import HoareOptimizer
from .optimization import TemplateOptimization
Expand Down
1 change: 1 addition & 0 deletions qiskit/transpiler/passes/optimization/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from .optimize_1q_commutation import Optimize1qGatesSimpleCommutation
from .optimize_swap_before_measure import OptimizeSwapBeforeMeasure
from .remove_reset_in_zero_state import RemoveResetInZeroState
from .remove_final_reset import RemoveFinalReset
from .remove_diagonal_gates_before_measure import RemoveDiagonalGatesBeforeMeasure
from .hoare_opt import HoareOptimizer
from .template_optimization import TemplateOptimization
Expand Down
37 changes: 37 additions & 0 deletions qiskit/transpiler/passes/optimization/remove_final_reset.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2017, 2023.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""Remove reset when it is the final instruction on a qubit."""

from qiskit.circuit import Reset, Qubit
from qiskit.dagcircuit import DAGOpNode
from qiskit.transpiler.basepasses import TransformationPass


class RemoveFinalReset(TransformationPass):
"""Remove reset when it is the final instruction on a qubit wire."""

def run(self, dag):
"""Run the RemoveFinalReset pass on `dag`.
Args:
dag (DAGCircuit): the DAG to be optimized.
Returns:
DAGCircuit: the optimized DAG.
"""
for output_node in dag.output_map.values():
if isinstance(output_node.wire, Qubit):
pred = next(dag.predecessors(output_node))
if isinstance(pred, DAGOpNode) and isinstance(pred.op, Reset):
dag.remove_op_node(pred)
return dag
35 changes: 35 additions & 0 deletions releasenotes/notes/remove-final-reset-488247c01c4e147d.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
features:
- |
Added a new transpiler pass, :class:`.RemoveFinalReset`, which
will remove any :class:`.Reset` operation which is the final
instruction on a qubit wire. For example, taking a circuit with
final :class:`.Reset`\ s:
.. plot::
from qiskit.circuit import QuantumCircuit
qc = QuantumCircuit(3, 1)
qc.reset(0)
qc.h(range(3))
qc.cx(1, 0)
qc.measure(0, 0)
qc.reset(range(3))
qc.draw("mpl")
will remove the final resets when the pass is run:
.. plot::
:include-source:
from qiskit.transpiler.passes import RemoveFinalReset
from qiskit.circuit import QuantumCircuit
qc = QuantumCircuit(3, 1)
qc.reset(0)
qc.h(range(3))
qc.cx(1, 0)
qc.measure(0, 0)
qc.reset(range(3))
RemoveFinalReset()(qc).draw("mpl")
1 change: 1 addition & 0 deletions test/python/compiler/test_transpiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -925,6 +925,7 @@ def test_init_resets_kept_preset_passmanagers(self, optimization_level):
num_qubits = 5
qc = QuantumCircuit(num_qubits)
qc.reset(range(num_qubits))
qc.h(range(num_qubits))

num_resets = transpile(qc, optimization_level=optimization_level).count_ops()["reset"]
self.assertEqual(num_resets, num_qubits)
Expand Down
117 changes: 117 additions & 0 deletions test/python/transpiler/test_remove_final_reset.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2017, 2023.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""Test RemoveFinalReset pass"""

import unittest

from qiskit import QuantumRegister, QuantumCircuit
from qiskit.passmanager.flow_controllers import DoWhileController
from qiskit.transpiler import PassManager
from qiskit.transpiler.passes import RemoveFinalReset, DAGFixedPoint
from qiskit.converters import circuit_to_dag
from test import QiskitTestCase # pylint: disable=wrong-import-order


class TestRemoveFinalReset(QiskitTestCase):
"""Test remove-reset-in-zero-state optimizations."""

def test_optimize_single_reset(self):
"""Remove a single final reset
qr0:--[H]--|0>-- ==> qr0:--[H]--
"""
qr = QuantumRegister(1, "qr")
circuit = QuantumCircuit(qr)
circuit.h(0)
circuit.reset(qr)
dag = circuit_to_dag(circuit)

expected = QuantumCircuit(qr)
expected.h(0)

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

self.assertEqual(circuit_to_dag(expected), after)

def test_dont_optimize_non_final_reset(self):
"""Do not remove reset if not final instruction
qr0:--|0>--[H]-- ==> qr0:--|0>--[H]--
"""
qr = QuantumRegister(1, "qr")
circuit = QuantumCircuit(qr)
circuit.reset(qr)
circuit.h(qr)
dag = circuit_to_dag(circuit)

expected = QuantumCircuit(qr)
expected.reset(qr)
expected.h(qr)

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

self.assertEqual(circuit_to_dag(expected), after)

def test_optimize_single_reset_in_diff_qubits(self):
"""Remove a single final reset in different qubits
qr0:--[H]--|0>-- qr0:--[H]--
==>
qr1:--[X]--|0>-- qr1:--[X]----
"""
qr = QuantumRegister(2, "qr")
circuit = QuantumCircuit(qr)
circuit.h(0)
circuit.x(1)
circuit.reset(qr)
dag = circuit_to_dag(circuit)

expected = QuantumCircuit(qr)
expected.h(0)
expected.x(1)

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

self.assertEqual(circuit_to_dag(expected), after)


class TestRemoveFinalResetFixedPoint(QiskitTestCase):
"""Test RemoveFinalReset in a transpiler, using fixed point."""

def test_two_resets(self):
"""Remove two final resets
qr0:--[H]-|0>-|0>-- ==> qr0:--[H]--
"""
qr = QuantumRegister(1, "qr")
circuit = QuantumCircuit(qr)
circuit.h(qr[0])
circuit.reset(qr[0])
circuit.reset(qr[0])

expected = QuantumCircuit(qr)
expected.h(qr[0])

pass_manager = PassManager()
pass_manager.append(
DoWhileController(
[RemoveFinalReset(), DAGFixedPoint()],
do_while=lambda property_set: not property_set["dag_fixed_point"],
)
)
after = pass_manager.run(circuit)

self.assertEqual(expected, after)


if __name__ == "__main__":
unittest.main()
2 changes: 1 addition & 1 deletion test/python/transpiler/test_remove_reset_in_zero_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@


class TestRemoveResetInZeroState(QiskitTestCase):
"""Test swap-followed-by-measure optimizations."""
"""Test remove-reset-in-zero-state optimizations."""

def test_optimize_single_reset(self):
"""Remove a single reset
Expand Down

0 comments on commit 494a32e

Please sign in to comment.