Skip to content

Commit

Permalink
Migrate init stage to plugins (Qiskit#10689)
Browse files Browse the repository at this point in the history
This commit updates the preset pass manager construction to only use
plugins for the init stage. To accomplish this the previously hard
coded built-in pass manager used for each optimization level are
refactored to be in a plugin named "default". One thing that is changed
in this PR is that the use of `generate_control_flow_options_check()`
is moved to the `pre_init` stage. The reason for this is because the way
the init stage was being constructed in the preset pass managers was to
do initial checking of any methods, and this was unconditionally being
run. This is a more logical fit for pre_init stage because it should run
before any specified plugin.

Fixes: Qiskit#10687
Fixes: Qiskit#8661
  • Loading branch information
mtreinish authored and SamD-1998 committed Sep 7, 2023
1 parent 40bbe3c commit 7cc3fd8
Show file tree
Hide file tree
Showing 9 changed files with 73 additions and 95 deletions.
42 changes: 42 additions & 0 deletions qiskit/transpiler/preset_passmanagers/builtin_plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
from qiskit.transpiler.passes import NoiseAdaptiveLayout
from qiskit.transpiler.passes import CheckMap
from qiskit.transpiler.passes import BarrierBeforeFinalMeasurements
from qiskit.transpiler.passes import RemoveResetInZeroState
from qiskit.transpiler.passes import OptimizeSwapBeforeMeasure
from qiskit.transpiler.passes import RemoveDiagonalGatesBeforeMeasure
from qiskit.transpiler.preset_passmanagers import common
from qiskit.transpiler.preset_passmanagers.plugin import (
PassManagerStagePlugin,
Expand All @@ -47,6 +50,45 @@
from qiskit.transpiler.passes.layout.vf2_layout import VF2LayoutStopReason


class DefaultInitPassManager(PassManagerStagePlugin):
"""Plugin class for default init stage."""

def pass_manager(self, pass_manager_config, optimization_level=None) -> PassManager:
if optimization_level in {1, 2, 0}:
init = None
if (
pass_manager_config.initial_layout
or pass_manager_config.coupling_map
or (
pass_manager_config.target is not None
and pass_manager_config.target.build_coupling_map() is not None
)
):
init = common.generate_unroll_3q(
pass_manager_config.target,
pass_manager_config.basis_gates,
pass_manager_config.approximation_degree,
pass_manager_config.unitary_synthesis_method,
pass_manager_config.unitary_synthesis_plugin_config,
pass_manager_config.hls_config,
)
elif optimization_level == 3:
init = common.generate_unroll_3q(
pass_manager_config.target,
pass_manager_config.basis_gates,
pass_manager_config.approximation_degree,
pass_manager_config.unitary_synthesis_method,
pass_manager_config.unitary_synthesis_plugin_config,
pass_manager_config.hls_config,
)
init.append(RemoveResetInZeroState())
init.append(OptimizeSwapBeforeMeasure())
init.append(RemoveDiagonalGatesBeforeMeasure())
else:
return TranspilerError(f"Invalid optimization level {optimization_level}")
return init


class BasisTranslatorPassManager(PassManagerStagePlugin):
"""Plugin class for translation stage with :class:`~.BasisTranslator`"""

Expand Down
27 changes: 6 additions & 21 deletions qiskit/transpiler/preset_passmanagers/level0.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,34 +46,21 @@ def level_0_pass_manager(pass_manager_config: PassManagerConfig) -> StagedPassMa
basis_gates = pass_manager_config.basis_gates
coupling_map = pass_manager_config.coupling_map
initial_layout = pass_manager_config.initial_layout
init_method = pass_manager_config.init_method
init_method = pass_manager_config.init_method or "default"
layout_method = pass_manager_config.layout_method or "default"
routing_method = pass_manager_config.routing_method or "stochastic"
translation_method = pass_manager_config.translation_method or "translator"
optimization_method = pass_manager_config.optimization_method or "default"
scheduling_method = pass_manager_config.scheduling_method or "default"
approximation_degree = pass_manager_config.approximation_degree
unitary_synthesis_method = pass_manager_config.unitary_synthesis_method
unitary_synthesis_plugin_config = pass_manager_config.unitary_synthesis_plugin_config
target = pass_manager_config.target
hls_config = pass_manager_config.hls_config

# Choose routing pass
routing_pm = plugin_manager.get_passmanager_stage(
"routing", routing_method, pass_manager_config, optimization_level=0
)

unroll_3q = None
# Build pass manager
if coupling_map or initial_layout:
unroll_3q = common.generate_unroll_3q(
target,
basis_gates,
approximation_degree,
unitary_synthesis_method,
unitary_synthesis_plugin_config,
hls_config,
)
layout = plugin_manager.get_passmanager_stage(
"layout", layout_method, pass_manager_config, optimization_level=0
)
Expand All @@ -98,7 +85,7 @@ def level_0_pass_manager(pass_manager_config: PassManagerConfig) -> StagedPassMa
"scheduling", scheduling_method, pass_manager_config, optimization_level=0
)

init = common.generate_control_flow_options_check(
pre_init = common.generate_control_flow_options_check(
layout_method=layout_method,
routing_method=routing_method,
translation_method=translation_method,
Expand All @@ -107,17 +94,15 @@ def level_0_pass_manager(pass_manager_config: PassManagerConfig) -> StagedPassMa
basis_gates=basis_gates,
target=target,
)
if init_method is not None:
init += plugin_manager.get_passmanager_stage(
"init", init_method, pass_manager_config, optimization_level=0
)
elif unroll_3q is not None:
init += unroll_3q
init = plugin_manager.get_passmanager_stage(
"init", init_method, pass_manager_config, optimization_level=0
)
optimization = plugin_manager.get_passmanager_stage(
"optimization", optimization_method, pass_manager_config, optimization_level=0
)

return StagedPassManager(
pre_init=pre_init,
init=init,
layout=layout,
routing=routing,
Expand Down
27 changes: 6 additions & 21 deletions qiskit/transpiler/preset_passmanagers/level1.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,36 +48,23 @@ def level_1_pass_manager(pass_manager_config: PassManagerConfig) -> StagedPassMa
basis_gates = pass_manager_config.basis_gates
coupling_map = pass_manager_config.coupling_map
initial_layout = pass_manager_config.initial_layout
init_method = pass_manager_config.init_method
init_method = pass_manager_config.init_method or "default"
# Unlike other presets, the layout and routing defaults aren't set here because they change
# based on whether the input circuit has control flow.
layout_method = pass_manager_config.layout_method or "default"
routing_method = pass_manager_config.routing_method or "sabre"
translation_method = pass_manager_config.translation_method or "translator"
optimization_method = pass_manager_config.optimization_method or "default"
scheduling_method = pass_manager_config.scheduling_method or "default"
approximation_degree = pass_manager_config.approximation_degree
unitary_synthesis_method = pass_manager_config.unitary_synthesis_method
unitary_synthesis_plugin_config = pass_manager_config.unitary_synthesis_plugin_config
target = pass_manager_config.target
hls_config = pass_manager_config.hls_config

# Choose routing pass
routing_pm = plugin_manager.get_passmanager_stage(
"routing", routing_method, pass_manager_config, optimization_level=1
)

unroll_3q = None
# Build full pass manager
if coupling_map or initial_layout:
unroll_3q = common.generate_unroll_3q(
target,
basis_gates,
approximation_degree,
unitary_synthesis_method,
unitary_synthesis_plugin_config,
hls_config,
)
layout = plugin_manager.get_passmanager_stage(
"layout", layout_method, pass_manager_config, optimization_level=1
)
Expand Down Expand Up @@ -108,7 +95,7 @@ def level_1_pass_manager(pass_manager_config: PassManagerConfig) -> StagedPassMa
"scheduling", scheduling_method, pass_manager_config, optimization_level=1
)

init = common.generate_control_flow_options_check(
pre_init = common.generate_control_flow_options_check(
layout_method=layout_method,
routing_method=routing_method,
translation_method=translation_method,
Expand All @@ -117,14 +104,12 @@ def level_1_pass_manager(pass_manager_config: PassManagerConfig) -> StagedPassMa
basis_gates=basis_gates,
target=target,
)
if init_method is not None:
init += plugin_manager.get_passmanager_stage(
"init", init_method, pass_manager_config, optimization_level=1
)
elif unroll_3q is not None:
init += unroll_3q
init = plugin_manager.get_passmanager_stage(
"init", init_method, pass_manager_config, optimization_level=1
)

return StagedPassManager(
pre_init=pre_init,
init=init,
layout=layout,
routing=routing,
Expand Down
27 changes: 6 additions & 21 deletions qiskit/transpiler/preset_passmanagers/level2.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,34 +51,21 @@ def level_2_pass_manager(pass_manager_config: PassManagerConfig) -> StagedPassMa
basis_gates = pass_manager_config.basis_gates
coupling_map = pass_manager_config.coupling_map
initial_layout = pass_manager_config.initial_layout
init_method = pass_manager_config.init_method
init_method = pass_manager_config.init_method or "default"
layout_method = pass_manager_config.layout_method or "default"
routing_method = pass_manager_config.routing_method or "sabre"
translation_method = pass_manager_config.translation_method or "translator"
optimization_method = pass_manager_config.optimization_method or "default"
scheduling_method = pass_manager_config.scheduling_method or "default"
approximation_degree = pass_manager_config.approximation_degree
unitary_synthesis_method = pass_manager_config.unitary_synthesis_method
unitary_synthesis_plugin_config = pass_manager_config.unitary_synthesis_plugin_config
target = pass_manager_config.target
hls_config = pass_manager_config.hls_config

# Choose routing pass
routing_pm = plugin_manager.get_passmanager_stage(
"routing", routing_method, pass_manager_config, optimization_level=2
)

unroll_3q = None
# Build pass manager
if coupling_map or initial_layout:
unroll_3q = common.generate_unroll_3q(
target,
basis_gates,
approximation_degree,
unitary_synthesis_method,
unitary_synthesis_plugin_config,
hls_config,
)
layout = plugin_manager.get_passmanager_stage(
"layout", layout_method, pass_manager_config, optimization_level=2
)
Expand All @@ -105,7 +92,7 @@ def level_2_pass_manager(pass_manager_config: PassManagerConfig) -> StagedPassMa
"scheduling", scheduling_method, pass_manager_config, optimization_level=2
)

init = common.generate_control_flow_options_check(
pre_init = common.generate_control_flow_options_check(
layout_method=layout_method,
routing_method=routing_method,
translation_method=translation_method,
Expand All @@ -114,14 +101,12 @@ def level_2_pass_manager(pass_manager_config: PassManagerConfig) -> StagedPassMa
basis_gates=basis_gates,
target=target,
)
if init_method is not None:
init += plugin_manager.get_passmanager_stage(
"init", init_method, pass_manager_config, optimization_level=2
)
elif unroll_3q is not None:
init += unroll_3q
init = plugin_manager.get_passmanager_stage(
"init", init_method, pass_manager_config, optimization_level=2
)

return StagedPassManager(
pre_init=pre_init,
init=init,
layout=layout,
routing=routing,
Expand Down
36 changes: 6 additions & 30 deletions qiskit/transpiler/preset_passmanagers/level3.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@
from __future__ import annotations
from qiskit.transpiler.passmanager_config import PassManagerConfig
from qiskit.transpiler.passmanager import StagedPassManager
from qiskit.transpiler.passes import RemoveResetInZeroState
from qiskit.transpiler.passes import OptimizeSwapBeforeMeasure
from qiskit.transpiler.passes import RemoveDiagonalGatesBeforeMeasure
from qiskit.transpiler.preset_passmanagers import common
from qiskit.transpiler.preset_passmanagers.plugin import (
PassManagerStagePluginManager,
Expand Down Expand Up @@ -54,26 +51,22 @@ def level_3_pass_manager(pass_manager_config: PassManagerConfig) -> StagedPassMa
basis_gates = pass_manager_config.basis_gates
coupling_map = pass_manager_config.coupling_map
initial_layout = pass_manager_config.initial_layout
init_method = pass_manager_config.init_method
init_method = pass_manager_config.init_method or "default"
layout_method = pass_manager_config.layout_method or "default"
routing_method = pass_manager_config.routing_method or "sabre"
translation_method = pass_manager_config.translation_method or "translator"
scheduling_method = pass_manager_config.scheduling_method
optimization_method = pass_manager_config.optimization_method or "default"
scheduling_method = pass_manager_config.scheduling_method or "default"
approximation_degree = pass_manager_config.approximation_degree
unitary_synthesis_method = pass_manager_config.unitary_synthesis_method
unitary_synthesis_plugin_config = pass_manager_config.unitary_synthesis_plugin_config
target = pass_manager_config.target
hls_config = pass_manager_config.hls_config

# Choose routing pass
routing_pm = plugin_manager.get_passmanager_stage(
"routing", routing_method, pass_manager_config, optimization_level=3
)

# Build pass manager
init = common.generate_control_flow_options_check(
pre_init = common.generate_control_flow_options_check(
layout_method=layout_method,
routing_method=routing_method,
translation_method=translation_method,
Expand All @@ -82,22 +75,9 @@ def level_3_pass_manager(pass_manager_config: PassManagerConfig) -> StagedPassMa
basis_gates=basis_gates,
target=target,
)
if init_method is not None:
init += plugin_manager.get_passmanager_stage(
"init", init_method, pass_manager_config, optimization_level=2
)
else:
init += common.generate_unroll_3q(
target,
basis_gates,
approximation_degree,
unitary_synthesis_method,
unitary_synthesis_plugin_config,
hls_config,
)
init.append(RemoveResetInZeroState())
init.append(OptimizeSwapBeforeMeasure())
init.append(RemoveDiagonalGatesBeforeMeasure())
init = plugin_manager.get_passmanager_stage(
"init", init_method, pass_manager_config, optimization_level=3
)
if coupling_map or initial_layout:
layout = plugin_manager.get_passmanager_stage(
"layout", layout_method, pass_manager_config, optimization_level=3
Expand All @@ -118,11 +98,6 @@ def level_3_pass_manager(pass_manager_config: PassManagerConfig) -> StagedPassMa
target is not None and target.get_non_global_operation_names(strict_direction=True)
):
pre_optimization = common.generate_pre_op_passmanager(target, coupling_map, True)
_direction = [
pass_
for x in common.generate_pre_op_passmanager(target, coupling_map).passes()
for pass_ in x["passes"]
]
else:
pre_optimization = common.generate_pre_op_passmanager(remove_reset_in_zero=True)

Expand All @@ -131,6 +106,7 @@ def level_3_pass_manager(pass_manager_config: PassManagerConfig) -> StagedPassMa
)

return StagedPassManager(
pre_init=pre_init,
init=init,
layout=layout,
routing=routing,
Expand Down
2 changes: 1 addition & 1 deletion qiskit/transpiler/preset_passmanagers/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
- Description and expectations
* - ``init``
- ``qiskit.transpiler.init``
- No reserved names
- ``default``
- This stage runs first and is typically used for any initial logical optimization. Because most
layout and routing algorithms are only designed to work with 1 and 2 qubit gates, this stage
is also used to translate any gates that operate on more than 2 qubits into gates that only
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
upgrade:
- |
The plugin name ``default`` is reserved for the :ref:`stage_table`
``layout``, ``optimization``, and ``scheduling``. These stages previously
``init``, ``layout``, ``optimization``, and ``scheduling``. These stages previously
did not reserve this plugin name, but the ``default`` name is now used to
represent Qiskit's built-in default method for these stages. If you were
using these names for plugins on these stages these will conflict with
Expand Down
3 changes: 3 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,9 @@
"permutation.basic = qiskit.transpiler.passes.synthesis.high_level_synthesis:BasicSynthesisPermutation",
"permutation.acg = qiskit.transpiler.passes.synthesis.high_level_synthesis:ACGSynthesisPermutation",
],
"qiskit.transpiler.init": [
"default = qiskit.transpiler.preset_passmanagers.builtin_plugins:DefaultInitPassManager",
],
"qiskit.transpiler.translation": [
"translator = qiskit.transpiler.preset_passmanagers.builtin_plugins:BasisTranslatorPassManager",
"unroller = qiskit.transpiler.preset_passmanagers.builtin_plugins:UnrollerPassManager",
Expand Down
2 changes: 2 additions & 0 deletions test/python/transpiler/test_preset_passmanagers.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ def mock_get_passmanager_stage(
]
)
return pm
elif stage_name == "init":
return PassManager([])
elif stage_name == "routing":
return PassManager([])
elif stage_name == "optimization":
Expand Down

0 comments on commit 7cc3fd8

Please sign in to comment.