Skip to content

Commit

Permalink
Add FullPassManager class for pass manager with defined stages
Browse files Browse the repository at this point in the history
This commit adds a new PassManager subclass, FullPassManager. This class
is used to have a PassManager with a defined structure and stages for
the normal transpile workflow. The preset pass managers are then updated
to be FullPassManager objects they conform to the fixed structure. Having
a class with defined phases gives us flexibility in the future for making
the transpiler pluggable with external plugins (similar to what's done in
PR Qiskit#6124) and also have backend hook points before or after different
phases of the transpile.

Fixes Qiskit#5978
  • Loading branch information
mtreinish committed May 12, 2021
1 parent 9b78934 commit e45b115
Show file tree
Hide file tree
Showing 6 changed files with 297 additions and 65 deletions.
154 changes: 154 additions & 0 deletions qiskit/transpiler/passmanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,3 +312,157 @@ 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
"""

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()
41 changes: 27 additions & 14 deletions qiskit/transpiler/preset_passmanagers/level0.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

from qiskit.transpiler.passmanager_config import PassManagerConfig
from qiskit.transpiler.passmanager import PassManager
from qiskit.transpiler.passmanager import FullPassManager

from qiskit.transpiler.passes import Unroller
from qiskit.transpiler.passes import BasisTranslator
Expand Down Expand Up @@ -49,7 +50,7 @@
from qiskit.transpiler import TranspilerError


def level_0_pass_manager(pass_manager_config: PassManagerConfig) -> PassManager:
def level_0_pass_manager(pass_manager_config: PassManagerConfig) -> FullPassManager:
"""Level 0 pass manager: no explicit optimization other than mapping to backend.
This pass manager applies the user-given initial layout. If none is given, a trivial
Expand Down Expand Up @@ -170,18 +171,30 @@ def _direction_condition(property_set):
raise TranspilerError("Invalid scheduling method %s." % scheduling_method)

# Build pass manager
pm0 = PassManager()
if coupling_map or initial_layout:
pm0.append(_given_layout)
pm0.append(_choose_layout, condition=_choose_layout_condition)
pm0.append(_embed)
pm0.append(_unroll3q)
pm0.append(_swap_check)
pm0.append(_swap, condition=_swap_condition)
pm0.append(_unroll)
layout = PassManager()
layout.append(_given_layout)
layout.append(_choose_layout, condition=_choose_layout_condition)
layout.append(_embed)
routing = PassManager()
routing.append(_unroll3q)
routing.append(_swap_check)
routing.append(_swap, condition=_swap_condition)
else:
layout = None
routing = None
translation = PassManager(_unroll)
if coupling_map and not coupling_map.is_symmetric:
pm0.append(_direction_check)
pm0.append(_direction, condition=_direction_condition)
pm0.append(_unroll)
pm0.append(_scheduling)
return pm0
pre_opt = PassManager(_direction_check)
pre_opt.append(_direction, condition=_direction_condition)
pre_opt.append(_unroll)
else:
pre_opt = None
post_opt = PassManager(_scheduling)
return FullPassManager(
layout=layout,
routing=routing,
translation=translation,
pre_optimization=pre_opt,
post_optimization=post_opt,
)
47 changes: 31 additions & 16 deletions qiskit/transpiler/preset_passmanagers/level1.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

from qiskit.transpiler.passmanager_config import PassManagerConfig
from qiskit.transpiler.passmanager import PassManager
from qiskit.transpiler.passmanager import FullPassManager

from qiskit.transpiler.passes import Unroller
from qiskit.transpiler.passes import BasisTranslator
Expand Down Expand Up @@ -201,21 +202,35 @@ def _opt_control(property_set):
raise TranspilerError("Invalid scheduling method %s." % scheduling_method)

# Build pass manager
pm1 = PassManager()

if coupling_map or initial_layout:
pm1.append(_given_layout)
pm1.append(_choose_layout_and_score, condition=_choose_layout_condition)
pm1.append(_improve_layout, condition=_not_perfect_yet)
pm1.append(_embed)
pm1.append(_unroll3q)
pm1.append(_swap_check)
pm1.append(_swap, condition=_swap_condition)
pm1.append(_unroll)
layout = PassManager()
layout.append(_given_layout)
layout.append(_choose_layout_and_score, condition=_choose_layout_condition)
layout.append(_improve_layout, condition=_not_perfect_yet)
layout.append(_embed)
routing = PassManager()
routing.append(_unroll3q)
routing.append(_swap_check)
routing.append(_swap, condition=_swap_condition)
else:
layout = None
routing = None
translation = PassManager(_unroll)
pre_optimization = PassManager()
if coupling_map and not coupling_map.is_symmetric:
pm1.append(_direction_check)
pm1.append(_direction, condition=_direction_condition)
pm1.append(_reset)
pm1.append(_depth_check + _opt + _unroll, do_while=_opt_control)
pm1.append(_scheduling)

return pm1
pre_optimization.append(_direction_check)
pre_optimization.append(_direction, condition=_direction_condition)
pre_optimization.append(_reset)
optimization = PassManager()
optimization.append(_depth_check + _opt + _unroll, do_while=_opt_control)
post_optimization = PassManager(_scheduling)

return FullPassManager(
layout=layout,
routing=routing,
translation=translation,
pre_optimization=pre_optimization,
optimization=optimization,
post_optimization=post_optimization,
)
49 changes: 32 additions & 17 deletions qiskit/transpiler/preset_passmanagers/level2.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

from qiskit.transpiler.passmanager_config import PassManagerConfig
from qiskit.transpiler.passmanager import PassManager
from qiskit.transpiler.passmanager import FullPassManager


from qiskit.transpiler.passes import Unroller
from qiskit.transpiler.passes import BasisTranslator
Expand Down Expand Up @@ -238,22 +240,35 @@ def _opt_control(property_set):
raise TranspilerError("Invalid scheduling method %s." % scheduling_method)

# Build pass manager
pm2 = PassManager()
if coupling_map or initial_layout:
pm2.append(_given_layout)
pm2.append(_choose_layout_0, condition=_choose_layout_condition)
pm2.append(_choose_layout_1, condition=_trivial_not_perfect)
pm2.append(_choose_layout_2, condition=_csp_not_found_match)
pm2.append(_embed)
pm2.append(_unroll3q)
pm2.append(_swap_check)
pm2.append(_swap, condition=_swap_condition)
pm2.append(_unroll)
layout = PassManager()
layout.append(_given_layout)
layout.append(_choose_layout_0, condition=_choose_layout_condition)
layout.append(_choose_layout_1, condition=_trivial_not_perfect)
layout.append(_choose_layout_2, condition=_csp_not_found_match)
layout.append(_embed)
routing = PassManager()
routing.append(_unroll3q)
routing.append(_swap_check)
routing.append(_swap, condition=_swap_condition)
else:
layout = None
routing = None
translation = PassManager(_unroll)
pre_optimization = PassManager()
if coupling_map and not coupling_map.is_symmetric:
pm2.append(_direction_check)
pm2.append(_direction, condition=_direction_condition)
pm2.append(_reset)
pm2.append(_depth_check + _opt + _unroll, do_while=_opt_control)
pm2.append(_scheduling)

return pm2
pre_optimization.append(_direction_check)
pre_optimization.append(_direction, condition=_direction_condition)
pre_optimization.append(_reset)
optimization = PassManager()
optimization.append(_depth_check + _opt + _unroll, do_while=_opt_control)
post_optimization = PassManager(_scheduling)

return FullPassManager(
layout=layout,
routing=routing,
translation=translation,
pre_optimization=pre_optimization,
optimization=optimization,
post_optimization=post_optimization,
)
Loading

0 comments on commit e45b115

Please sign in to comment.