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 RemoveFinalReset pass #11266

Merged
merged 8 commits into from
Mar 19, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
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
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
37 changes: 37 additions & 0 deletions releasenotes/notes/remove-final-reset-488247c01c4e147d.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
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")

This new pass is enabled at optimization levels 1 and higher.
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
114 changes: 114 additions & 0 deletions test/python/transpiler/test_remove_final_reset.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# 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.transpiler import PassManager
from qiskit.transpiler.passes import RemoveFinalReset, DAGFixedPoint
from qiskit.converters import circuit_to_dag
from qiskit.test import QiskitTestCase


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(
[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()
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
Loading