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 StagedPassManager class for pass manager with defined stages #6403

Merged
merged 43 commits into from
Jun 21, 2022
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
e45b115
Add FullPassManager class for pass manager with defined stages
mtreinish May 12, 2021
90c242c
Add docs
mtreinish May 12, 2021
c9a0ab4
Merge branch 'main' into transpiler-phases
mtreinish Jun 1, 2021
53f34ba
Deduplicate preset passmanager construction
mtreinish Jun 2, 2021
1bebc51
Update docs
mtreinish Jun 2, 2021
76ffb74
Merge branch 'main' into transpiler-phases
mtreinish Jun 2, 2021
c86a7fb
Merge remote-tracking branch 'origin/main' into transpiler-phases
mtreinish Sep 10, 2021
f177d5f
Add dedicated scheduling stage to FullPassManager
mtreinish Sep 10, 2021
cc3c4fd
Add missing new UnitarySynthesis kwargs after rebase
mtreinish Sep 10, 2021
1937354
Use basis_translator as default method instead of basis
mtreinish Oct 18, 2021
b392a45
Merge remote-tracking branch 'origin/main' into transpiler-phases
mtreinish Oct 18, 2021
f30ee80
Rename FullPassManager StructuredPassManager
mtreinish Oct 18, 2021
f336a34
Rename generate_scheduling_post_opt() generate_scheduling()
mtreinish Oct 18, 2021
8637fa1
Merge remote-tracking branch 'origin/main' into transpiler-phases
mtreinish May 23, 2022
06582d4
Fix missing and incorrect arguments
mtreinish May 23, 2022
35a8db9
Fix more rebase issues
mtreinish May 23, 2022
10f543d
Fix even more rebase issues
mtreinish May 24, 2022
ff55b06
Merge remote-tracking branch 'origin/main' into transpiler-phases
mtreinish May 25, 2022
5e5657e
Only run unroll3q on level 0-2 if coupling map is set
mtreinish May 25, 2022
aa1db1f
Rework StructuredPassManager as a more dynamic StagedPassManager
mtreinish May 25, 2022
d654b94
Merge branch 'main' into transpiler-phases
mtreinish May 25, 2022
c51518f
Fix docs
mtreinish May 26, 2022
f6cbb55
Update internal pass set on each access
mtreinish May 26, 2022
445fdfb
Rename phases attribute to stages
mtreinish May 26, 2022
e34cbb8
Fix lint
mtreinish May 26, 2022
5e007f3
Explicitly set name in qpy compat tests
mtreinish May 26, 2022
14494db
Merge remote-tracking branch 'origin/main' into transpiler-phases
mtreinish May 26, 2022
897678c
Merge branch 'main' into transpiler-phases
mtreinish Jun 14, 2022
8414533
Merge remote-tracking branch 'origin/main' into transpiler-phases
mtreinish Jun 14, 2022
75e3d41
Apply suggestions from code review
mtreinish Jun 16, 2022
7c14a6e
Merge remote-tracking branch 'origin/main' into transpiler-phases
mtreinish Jun 16, 2022
37ad778
Run black
mtreinish Jun 16, 2022
a2472f2
Update type hint
mtreinish Jun 16, 2022
c5ac5f6
Remove out of date docstring note
mtreinish Jun 16, 2022
af9e244
Update copyright header date in qiskit/transpiler/preset_passmanagers…
mtreinish Jun 16, 2022
5a446a0
Add check for invalid stage names
mtreinish Jun 17, 2022
2205e3e
Merge branch 'main' into transpiler-phases
mtreinish Jun 17, 2022
7b225ff
Merge branch 'main' into transpiler-phases
mtreinish Jun 17, 2022
0329fb3
Merge remote-tracking branch 'origin/main' into transpiler-phases
mtreinish Jun 20, 2022
5325217
Add backwards compatibility note
mtreinish Jun 20, 2022
8b27565
Add docs on using StagedPassManager features with preset passmanagers
mtreinish Jun 20, 2022
7a8a675
Merge branch 'main' into transpiler-phases
1ucian0 Jun 21, 2022
4063b13
Merge branch 'main' into transpiler-phases
mergify[bot] Jun 21, 2022
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/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,7 @@
.. autosummary::
:toctree: ../stubs/

FullPassManager
PassManager
PassManagerConfig
PropertySet
Expand Down Expand Up @@ -417,6 +418,7 @@
from .runningpassmanager import FlowController
from .passmanager import PassManager
from .passmanager_config import PassManagerConfig
from .passmanager import FullPassManager
from .propertyset import PropertySet
from .exceptions import TranspilerError, TranspilerAccessError
from .fencedobjs import FencedDAGCircuit, FencedPropertySet
Expand Down
158 changes: 158 additions & 0 deletions qiskit/transpiler/passmanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,3 +312,161 @@ def passes(self) -> List[Dict[str, BasePass]]:
item["flow_controllers"] = {}
ret.append(item)
return ret


class FullPassManager(PassManager):
"""A full Pass manager pipeline for a backend

Instances of FullPassManager define a full compilation pipeline from a abstract virtual
circuit to one that is optimized and capable of running on the specified backend. It is
built using predefined stages:

1. Init - any initial passes that are run before we start embedding the circuit to the backend
2. Layout - This stage runs layout and maps the virtual qubits in the
circuit to the physical qubits on a backend
3. Routing - This stage runs after a layout has been run and will insert any
necessary gates to move the qubit states around until it can be run on
backend's compuling map.
4. Translation - Perform the basis gate translation, in other words translate the gates
in the circuit to the target backend's basis set
5. Pre-Optimization - Any passes to run before the main optimization loop
6. Optimization - The main optimization loop, this will typically run in a loop trying to optimize
the circuit until a condtion (such as fixed depth) is reached.
7. Post-Optimization - Any passes to run after the main optimization loop

These stages will be executed in order and any stage set to ``None`` will be skipped. If
a :class:`~qiskit.transpiler.PassManager` input is being used for more than 1 stage here
(for example in the case of a Pass that covers both Layout and Routing) you will want to set
that to the earliest stage in sequence that it covers.
"""

phases = [
"init",
"layout",
"routing",
"translation",
"pre_optimization",
"optimization",
"post_optimization",
]

def __init__(
self,
init=None,
layout=None,
routing=None,
translation=None,
pre_optimization=None,
optimization=None,
post_optimization=None,
):
"""Initialize a new FullPassManager object

Args:
init (PassManager): A passmanager to run for the initial stage of the
compilation.
layout (PassManager): A passmanager to run for the layout stage of the
compilation.
routing (PassManager): A pass manager to run for the routing stage
of the compilation
translation (PassManager): A pass manager to run for the translation
stage of the compilation
pre_opt (PassManager): A pass manager to run before the optimization
loop
optimization (PassManager): A pass manager to run for the
optimization loop stage
post_opt (PassManager): A pass manager to run after the optimization
loop
"""
super().__init__()
self._init = init
self._layout = layout
self._routing = routing
self._translation = translation
self._pre_optimization = pre_optimization
self._optimization = optimization
self._post_optimization = post_optimization
self._update_passmanager()

def _update_passmanager(self):
self._pass_sets = []
if self._init:
self._pass_sets.extend(self._init._pass_sets)
if self._layout:
self._pass_sets.extend(self._layout._pass_sets)
if self._routing:
self._pass_sets.extend(self._routing._pass_sets)
if self._translation:
self._pass_sets.extend(self._translation._pass_sets)
if self._pre_optimization:
self._pass_sets.extend(self._pre_optimization._pass_sets)
if self._optimization:
self._pass_sets.extend(self._optimization._pass_sets)
if self._post_optimization:
self._pass_sets.extend(self._post_optimization._pass_sets)

@property
def init(self):
"""Get the :class:`~qiskit.transpiler.PassManager` for the init stage."""
return self._init

@init.setter
def init(self, value):
"""Set the :class:`~qiskit.transpiler.PassManager` for the init stage."""
self._init = value
self._update_passmanager()

@property
def layout(self):
"""Get the :class:`~qiskit.transpiler.PassManager` for the layout stage."""
return self._layout

@layout.setter
def layout(self, value):
"""Set the :class:`~qiskit.transpiler.PassManager` for the layout stage."""
self._layout = value
self._update_passmanager()

@property
def routing(self):
"""Get the :class:`~qiskit.transpiler.PassManager` for the routing stage."""
return self._routing

@routing.setter
def routing(self, value):
"""Set the :class:`~qiskit.transpiler.PassManager` for the routing stage."""
self._routing = value
self._update_passmanager()

@property
def pre_optimization(self):
"""Get the :class:`~qiskit.transpiler.PassManager` for the pre_optimization stage."""
return self._pre_optimization

@pre_optimization.setter
def pre_optimization(self, value):
"""Set the :class:`~qiskit.transpiler.PassManager` for the pre_optimization stage."""
self._pre_optimization = value
self._update_passmanager()

@property
def optimization(self):
"""Get the :class:`~qiskit.transpiler.PassManager` for the optimization stage."""
return self._optimization

@optimization.setter
def optimization(self, value):
"""Set the :class:`~qiskit.transpiler.PassManager` for the optimization stage."""
self._optimization = value
self._update_passmanager()

@property
def post_optimization(self):
"""Get the :class:`~qiskit.transpiler.PassManager` for the post_optimization stage."""
return self._post_optimization

@post_optimization.setter
def post_optimization(self, value):
"""Set the :class:`~qiskit.transpiler.PassManager` for the post_optimization stage."""
self._post_optimization = value
self._update_passmanager()
160 changes: 160 additions & 0 deletions qiskit/transpiler/preset_passmanagers/common.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2017, 2018.
#
# 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.

# pylint: disable=invalid-name

"""Common preset passmanager generators."""

from qiskit.circuit.equivalence_library import SessionEquivalenceLibrary as sel

from qiskit.transpiler.passmanager import PassManager
from qiskit.transpiler.passes import Unroller
from qiskit.transpiler.passes import BasisTranslator
from qiskit.transpiler.passes import UnrollCustomDefinitions
from qiskit.transpiler.passes import Unroll3qOrMore
from qiskit.transpiler.passes import Collect2qBlocks
from qiskit.transpiler.passes import ConsolidateBlocks
from qiskit.transpiler.passes import UnitarySynthesis
from qiskit.transpiler.passes import CheckMap
from qiskit.transpiler.passes import GateDirection
from qiskit.transpiler.passes import BarrierBeforeFinalMeasurements
from qiskit.transpiler.passes import CheckGateDirection
from qiskit.transpiler.passes import TimeUnitConversion
from qiskit.transpiler.passes import ALAPSchedule
from qiskit.transpiler.passes import ASAPSchedule
from qiskit.transpiler.passes import FullAncillaAllocation
from qiskit.transpiler.passes import EnlargeWithAncilla
from qiskit.transpiler.passes import ApplyLayout
from qiskit.transpiler.passes import RemoveResetInZeroState
from qiskit.transpiler.exceptions import TranspilerError


def generate_embed_passmanager(coupling_map):
Copy link
Member

@chriseclectic chriseclectic Feb 15, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think better names for these sort of functions would be default_*_passmanager

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

"""Generate a layout embedding :class:`~qiskit.transpiler.PassManager`

This is used to generate a :class:`~qiskit.transpiler.PassManager` object
that can be used to expand and apply an initial layout to a circuit

Args:
coupling_map (CouplingMap): The coupling map for the backend to embed
the circuit to.
Returns:
PassManager: The embedding passmanager that assumes the layout property
set has been set in earlier stages
"""
return PassManager([FullAncillaAllocation(coupling_map), EnlargeWithAncilla(), ApplyLayout()])


def generate_routing_passmanager(routing_pass, coupling_map):
"""Generate a routing :class:`~qiskit.transpiler.PassManager`

Args:
routing_pass (TransformationPass): The pass which will perform the
routing
coupling_map (CouplingMap): The coupling map of the backend to route
for
Returns:
PassManager: The routing pass manager
"""
routing = PassManager()
routing.append(Unroll3qOrMore())
routing.append(CheckMap(coupling_map))

def _swap_condition(property_set):
return not property_set["is_swap_mapped"]

routing.append([BarrierBeforeFinalMeasurements(), routing_pass], condition=_swap_condition)
return routing


def generate_pre_op_passmanager(coupling_map=None, remove_reset_in_zero=False):
"""Generate a pre-optimization loop :class:`~qiskit.transpiler.PassManager`

This pass manager will check to ensure that directionality from the coupling
map is respected

Args:
coupling_map (CouplingMap): The coupling map to use
remove_reset_in_zero (bool): If ``True`` include the remove reset in
zero pass in the generated PassManager
Returns:
PassManager: The pass manager

"""
pre_opt = PassManager()
if coupling_map:
pre_opt.append(CheckGateDirection(coupling_map))

def _direction_condition(property_set):
return not property_set["is_direction_mapped"]

pre_opt.append([GateDirection(coupling_map)], condition=_direction_condition)
if remove_reset_in_zero:
pre_opt.append(RemoveResetInZeroState())
return pre_opt


def generate_translation_passmanager(basis_gates, method="basis", approximation_degree=None):
"""Generate a basis translation :class:`~qiskit.transpiler.PassManager`

Args:
basis_gates (list): A list
method (str): The basis translation method to use
approximation_degree (float): The heuristic approximation degree to
use. Can be between 0 and 1.

Returns:
PassManager: The basis translation pass manager

Raises:
TranspilerError: If the ``method`` kwarg is not a valid value
"""
if method == "unroller":
unroll = [Unroller(basis_gates)]
elif method == "translator":
unroll = [UnrollCustomDefinitions(sel, basis_gates), BasisTranslator(sel, basis_gates)]
elif method == "synthesis":
unroll = [
Unroll3qOrMore(),
Collect2qBlocks(),
ConsolidateBlocks(basis_gates=basis_gates),
UnitarySynthesis(basis_gates, approximation_degree=approximation_degree),
]
else:
raise TranspilerError("Invalid translation method %s." % method)
return PassManager(unroll)


def generate_scheduling_post_opt(instruction_durations, scheduling_method):
"""Generate a post optimization scheduling :class:`~qiskit.transpiler.PassManager`

Args:
instruction_durations (dict): The dictionary of instruction durations
scheduling_method (str): The scheduling method to use, can either be
``'asap'``/``'as_soon_as_possible'`` or
``'alap'``/``'as_late_as_possible'``

Returns:
PassManager: The scheduling pass manager

Raises:
TranspilerError: If the ``scheduling_method`` kwarg is not a valid value
"""
scheduling = PassManager([TimeUnitConversion(instruction_durations)])
if scheduling_method:
if scheduling_method in {"alap", "as_late_as_possible"}:
scheduling.append(ALAPSchedule(instruction_durations))
elif scheduling_method in {"asap", "as_soon_as_possible"}:
scheduling.append(ASAPSchedule(instruction_durations))
else:
raise TranspilerError("Invalid scheduling method %s." % scheduling_method)
return scheduling
Loading