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

Migrate init stage to plugins #10689

Merged
merged 2 commits into from
Aug 22, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
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,
)
Comment on lines +67 to +74
Copy link
Member

Choose a reason for hiding this comment

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

Pre-existing, but is this definitely an "initialisation" action and not just a shared requirement of most of our routing plugins?

Copy link
Member Author

Choose a reason for hiding this comment

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

It is, since almost all layout and routing stages only work with 1 and 2 qubit gates this is why it's in the default. You could argue it's a better fit for the pre_layout stage, but I think init works better here because it allows for plugins to override it. So in a hypothetical case where there is a layout and routing pass for hardware that has native 3q gates they can have users do something like transpile(..., routing_method="toffoli", init_method="only_opt").

I guess there is an argument that the init stage should be more granular. We do have an issue for adding a dedicated synthesis stage #8936. But, at the end of the day there isn't very much in there and I worry about having too many stages that all only do one or two passes.

Copy link
Member

@jakelishman jakelishman Aug 22, 2023

Choose a reason for hiding this comment

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

Yeah, that's fine. I'd originally written "layout" in my comment, then mistakenly changed it because I thought it was only Sabre that really had a problem (which is via Sabre routing anyway - the Sabre layout logic itself doesn't care), but that's not true - noise aware, CSP and VF2 all have issues with 3q.

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(
Copy link
Member

Choose a reason for hiding this comment

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

The whole concept of a pre-initialisation stage is funny to me, but this does seem like an ok compromise.

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