Skip to content

Commit

Permalink
Add pass to remove labeled ops and label inserted barriers
Browse files Browse the repository at this point in the history
This commit adds a new transpiler pass RemoveLabeledOps which is used to
remove any op nodes that match a given label. This is paired with a new
label option for BarrierBeforeFinalMeasurements. These are combined in
the preset pass managers to ensure we're not always adding a barrier
before output measurements in the output of the transpiler.

Fixes #10321
  • Loading branch information
mtreinish committed Jun 22, 2023
1 parent 924702e commit ef070b1
Show file tree
Hide file tree
Showing 8 changed files with 52 additions and 5 deletions.
2 changes: 2 additions & 0 deletions qiskit/transpiler/passes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@
GatesInBasis
ConvertConditionsToIfOps
UnrollForLoops
RemoveLabeledOps
"""

# layout selection (placement)
Expand Down Expand Up @@ -292,3 +293,4 @@
from .utils import GatesInBasis
from .utils import ConvertConditionsToIfOps
from .utils import UnrollForLoops
from .utils import RemoveLabeledOps
1 change: 1 addition & 0 deletions qiskit/transpiler/passes/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
from .convert_conditions_to_if_ops import ConvertConditionsToIfOps
from .unroll_forloops import UnrollForLoops
from .minimum_point import MinimumPoint
from .remove_labeled_ops import RemoveLabeledOps

# Utility functions
from . import control_flow
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ class BarrierBeforeFinalMeasurements(TransformationPass):
other measurements or barriers.)
"""

def __init__(self, label=None):
super().__init__()
self.label = label

def run(self, dag):
"""Run the BarrierBeforeFinalMeasurements pass on `dag`."""
# Collect DAG nodes which are followed only by barriers or other measures.
Expand Down Expand Up @@ -63,7 +67,9 @@ def run(self, dag):
# from an unmeasured qubit after a measure.
final_qubits = dag.qubits

barrier_layer.apply_operation_back(Barrier(len(final_qubits)), list(final_qubits), [])
barrier_layer.apply_operation_back(
Barrier(len(final_qubits), label=self.label), list(final_qubits), []
)

# Preserve order of final ops collected earlier from the original DAG.
ordered_final_nodes = [
Expand Down
13 changes: 12 additions & 1 deletion qiskit/transpiler/preset_passmanagers/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
from qiskit.transpiler.passes import EnlargeWithAncilla
from qiskit.transpiler.passes import ApplyLayout
from qiskit.transpiler.passes import RemoveResetInZeroState
from qiskit.transpiler.passes import RemoveLabeledOps
from qiskit.transpiler.passes import ValidatePulseGates
from qiskit.transpiler.passes import PadDelay
from qiskit.transpiler.passes import InstructionDurationCheck
Expand Down Expand Up @@ -316,7 +317,15 @@ def _swap_condition(property_set):
return not property_set["routing_not_needed"]

if use_barrier_before_measurement:
routing.append([BarrierBeforeFinalMeasurements(), routing_pass], condition=_swap_condition)
routing.append(
[
BarrierBeforeFinalMeasurements(
label="qiskit.transpiler.internal.routing.protection.barrier"
),
routing_pass,
],
condition=_swap_condition,
)
else:
routing.append([routing_pass], condition=_swap_condition)

Expand All @@ -336,6 +345,8 @@ def _swap_condition(property_set):
)
routing.append(ApplyLayout(), condition=_apply_post_layout_condition)

routing.append([RemoveLabeledOps("qiskit.transpiler.internal.routing.protection.barrier")])

return routing


Expand Down
8 changes: 7 additions & 1 deletion qiskit/transpiler/preset_passmanagers/level1.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,13 @@ def _swap_mapped(property_set):
layout.append(_choose_layout_0, condition=_choose_layout_condition)
layout.append(_choose_layout_1, condition=_layout_not_perfect)
layout.append(
[BarrierBeforeFinalMeasurements(), _improve_layout], condition=_vf2_match_not_found
[
BarrierBeforeFinalMeasurements(
"qiskit.transpiler.internal.routing.protection.barrier"
),
_improve_layout,
],
condition=_vf2_match_not_found,
)
embed = common.generate_embed_passmanager(coupling_map_layout)
layout.append(
Expand Down
8 changes: 7 additions & 1 deletion qiskit/transpiler/preset_passmanagers/level2.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,13 @@ def _swap_mapped(property_set):
layout.append(_given_layout)
layout.append(_choose_layout_0, condition=_choose_layout_condition)
layout.append(
[BarrierBeforeFinalMeasurements(), _choose_layout_1], condition=_vf2_match_not_found
[
BarrierBeforeFinalMeasurements(
"qiskit.transpiler.internal.routing.protection.barrier"
),
_choose_layout_1,
],
condition=_vf2_match_not_found,
)
embed = common.generate_embed_passmanager(coupling_map_layout)
layout.append(
Expand Down
8 changes: 7 additions & 1 deletion qiskit/transpiler/preset_passmanagers/level3.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,13 @@ def _swap_mapped(property_set):
layout.append(_given_layout)
layout.append(_choose_layout_0, condition=_choose_layout_condition)
layout.append(
[BarrierBeforeFinalMeasurements(), _choose_layout_1], condition=_vf2_match_not_found
[
BarrierBeforeFinalMeasurements(
"qiskit.transpiler.internal.routing.protection.barrier"
),
_choose_layout_1,
],
condition=_vf2_match_not_found,
)
embed = common.generate_embed_passmanager(coupling_map_layout)
layout.append(
Expand Down
9 changes: 9 additions & 0 deletions test/python/compiler/test_transpiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -1657,6 +1657,15 @@ def test_paulis_to_constrained_1q_basis(self, opt_level, basis):
self.assertGreaterEqual(set(basis) | {"barrier"}, transpiled.count_ops().keys())
self.assertEqual(Operator(qc), Operator(transpiled))

@data(0, 1, 2, 3)
def test_barrier_not_output(self, opt_level):
"""Test that barriers added as part internal transpiler operations do not leak out."""
qc = QuantumCircuit(2, 2)
qc.cx(0, 1)
qc.measure(range(2), range(2))
tqc = transpile(qc, initial_layout=[1, 4], coupling_map=[[1, 2], [2, 3], [3, 4]], optimization_level=opt_level)
self.assertNotIn("barrier", tqc.count_ops())


@ddt
class TestPostTranspileIntegration(QiskitTestCase):
Expand Down

0 comments on commit ef070b1

Please sign in to comment.