mirror of https://github.com/Qiskit/qiskit.git
Add support for custom backend transpiler stages (#8648)
* Add support for custom backend transpiler stages This commit adds initial support to the transpiler and backend interfaces for backends to specify custom transpiler stages. There are often specific hardware compilation requirements that a general purpose transpiler's preset pass manager can't account for. While we strive to provide interfaces to outline all the hardware constraints via the Target class and general purposes passes to fit and optimize an input circuit to the target backend there are some constraints that aren't easily addressed in a general purpose way. For such cases having an interface for a specific backend which has the necessary context of its own constraints to provide custom compilation steps to integrate into the pipeline is a necessary feature. The two initial examples of this are custom basis gate translation and custom scheduling. This commit adds two new hook point methods for BackendV2 objects, get_post_translation_stage() and get_scheduling_stage(). These allow for backends to specify custom PassManager objects that will run after the translation stage and for the scheduling stage by default when compilation is targetting the backend. This should enable backends with custom hardware specific requirements to influence the compilation process so that any required custom steps to ensure the output circuit is executable. In the future we may add additional hook points in a similar manner to enable backends to assert more hardware-specific compilation where the need arises. Closes #8329 * Remove stray optimization level args from pm config * Fix tests * Apply suggestions from code review Co-authored-by: Jake Lishman <jake@binhbar.com> * Pivot backend transpiler hook points to leverage plugins Since in qiskit-terra 0.22.0 we're adding a plugin interface for transpiler stages already, the more natural fit for enabling backends to inject custom passes into a pass maanger is via that plugin interface. This commit updates the hook points to return a plugin method name that a backend should use by default. This will provide the same level of flexibility but also export any custom stages as standalone methods that users can call into if they need to and also advertise the custom stage methods along with all other installed methods. * Apply suggestions from code review Co-authored-by: Kevin Krsulich <kevin@krsulich.net> * Update qiskit/providers/__init__.py Co-authored-by: Kevin Krsulich <kevin@krsulich.net> * Update release note * Update qiskit/providers/backend.py Co-authored-by: John Lapeyre <jlapeyre@users.noreply.github.com> * Rename transpile() option and reword doc * Rename hook methods backend_ * Update qiskit/compiler/transpiler.py Co-authored-by: John Lapeyre <jlapeyre@users.noreply.github.com> Co-authored-by: Jake Lishman <jake@binhbar.com> Co-authored-by: Kevin Krsulich <kevin@krsulich.net> Co-authored-by: John Lapeyre <jlapeyre@users.noreply.github.com>
This commit is contained in:
parent
53e215c31c
commit
86fb555871
|
@ -84,6 +84,7 @@ def transpile(
|
|||
hls_config: Optional[HLSConfig] = None,
|
||||
init_method: str = None,
|
||||
optimization_method: str = None,
|
||||
ignore_backend_supplied_default_methods: bool = False,
|
||||
) -> Union[QuantumCircuit, List[QuantumCircuit]]:
|
||||
"""Transpile one or more circuits, according to some desired transpilation targets.
|
||||
|
||||
|
@ -276,6 +277,11 @@ def transpile(
|
|||
plugin is not used. You can see a list of installed plugins by
|
||||
using :func:`~.list_stage_plugins` with ``"optimization"`` for the
|
||||
``stage_name`` argument.
|
||||
ignore_backend_supplied_default_methods: If set to ``True`` any default methods specified by
|
||||
a backend will be ignored. Some backends specify alternative default methods
|
||||
to support custom compilation target-specific passes/plugins which support
|
||||
backend-specific compilation techniques. If you'd prefer that these defaults were
|
||||
not used this option is used to disable those backend-specific defaults.
|
||||
|
||||
Returns:
|
||||
The transpiled circuit(s).
|
||||
|
@ -344,6 +350,7 @@ def transpile(
|
|||
hls_config,
|
||||
init_method,
|
||||
optimization_method,
|
||||
ignore_backend_supplied_default_methods,
|
||||
)
|
||||
# Get transpile_args to configure the circuit transpilation job(s)
|
||||
if coupling_map in unique_transpile_args:
|
||||
|
@ -426,7 +433,7 @@ def _log_transpile_time(start_time, end_time):
|
|||
def _combine_args(shared_transpiler_args, unique_config):
|
||||
# Pop optimization_level to exclude it from the kwargs when building a
|
||||
# PassManagerConfig
|
||||
level = shared_transpiler_args.get("optimization_level")
|
||||
level = shared_transpiler_args.pop("optimization_level")
|
||||
pass_manager_config = shared_transpiler_args
|
||||
pass_manager_config.update(unique_config.pop("pass_manager_config"))
|
||||
pass_manager_config = PassManagerConfig(**pass_manager_config)
|
||||
|
@ -597,6 +604,7 @@ def _parse_transpile_args(
|
|||
hls_config,
|
||||
init_method,
|
||||
optimization_method,
|
||||
ignore_backend_supplied_default_methods,
|
||||
) -> Tuple[List[Dict], Dict]:
|
||||
"""Resolve the various types of args allowed to the transpile() function through
|
||||
duck typing, overriding args, etc. Refer to the transpile() docstring for details on
|
||||
|
@ -669,6 +677,12 @@ def _parse_transpile_args(
|
|||
}
|
||||
|
||||
list_transpile_args = []
|
||||
if not ignore_backend_supplied_default_methods:
|
||||
if scheduling_method is None and hasattr(backend, "get_scheduling_stage_plugin"):
|
||||
scheduling_method = backend.get_scheduling_stage_plugin()
|
||||
if translation_method is None and hasattr(backend, "get_translation_stage_plugin"):
|
||||
translation_method = backend.get_translation_stage_plugin()
|
||||
|
||||
for key, value in {
|
||||
"inst_map": inst_map,
|
||||
"coupling_map": coupling_map,
|
||||
|
|
|
@ -406,6 +406,53 @@ Custom Basis Gates
|
|||
transpiler will ensure that it continues to be well supported by Qiskit
|
||||
moving forward.
|
||||
|
||||
.. _custom_transpiler_backend:
|
||||
|
||||
Custom Transpiler Passes
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
The transpiler supports the ability for backends to provide custom transpiler
|
||||
stage implementations to facilitate hardware specific optimizations and
|
||||
circuit transformations. Currently there are two stages supported,
|
||||
``get_translation_stage_plugin()`` and ``get_scheduling_stage_plugin()``
|
||||
which allow a backend to specify string plugin names to be used as the default
|
||||
translation and scheduling stages, respectively. These
|
||||
hook points in a :class:`~.BackendV2` class can be used if your
|
||||
backend has requirements for compilation that are not met by the
|
||||
current backend/:class:`~.Target` interface. Please also consider
|
||||
submitting a Github issue describing your use case as there is interest
|
||||
in improving these interfaces to be able to describe more hardware
|
||||
architectures in greater depth.
|
||||
|
||||
To leverage these hook points you just need to add the methods to your
|
||||
:class:`~.BackendV2` implementation and have them return a string plugin name.
|
||||
For example::
|
||||
|
||||
|
||||
class Mybackend(BackendV2):
|
||||
|
||||
def get_scheduling_stage_plugin(self):
|
||||
return "SpecialDD"
|
||||
|
||||
def get_translation_stage_plugin(self):
|
||||
return "BasisTranslatorWithCustom1qOptimization"
|
||||
|
||||
This snippet of a backend implementation will now have the :func:`~.transpile`
|
||||
function use the ``SpecialDD`` plugin for the scheduling stage and
|
||||
the ``BasisTranslatorWithCustom1qOptimization`` plugin for the translation
|
||||
stage by default when the target is set to ``Mybackend``. Note that users may override these choices
|
||||
by explicitly selecting a different plugin name. For this interface to work though transpiler
|
||||
stage plugins must be implemented for the returned plugin name. You can refer
|
||||
to :mod:`qiskit.transpiler.preset_passmanagers.plugin` module documentation for
|
||||
details on how to implement plugins. The typical expectation is that if your backend
|
||||
requires custom passes as part of a compilation stage the provider package will
|
||||
include the transpiler stage plugins that use those passes. However, this is not
|
||||
required and any valid method (from a built-in method or external plugin) can
|
||||
be used.
|
||||
|
||||
This way if these two compilation steps are **required** for running or providing
|
||||
efficient output on ``Mybackend`` the transpiler will be able to perform these
|
||||
custom steps without any manual user input.
|
||||
|
||||
Run Method
|
||||
----------
|
||||
|
||||
|
|
|
@ -287,6 +287,26 @@ class BackendV2(Backend, ABC):
|
|||
will build a :class:`~qiskit.providers.models.BackendConfiguration` object
|
||||
and :class:`~qiskit.providers.models.BackendProperties` from the attributes
|
||||
defined in this class for backwards compatibility.
|
||||
|
||||
A backend object can optionally contain methods named
|
||||
``get_translation_stage_plugin`` and ``get_scheduling_stage_plugin``. If these
|
||||
methods are present on a backend object and this object is used for
|
||||
:func:`~.transpile` or :func:`~.generate_preset_pass_manager` the
|
||||
transpilation process will default to using the output from those methods
|
||||
as the scheduling stage and the translation compilation stage. This
|
||||
enables a backend which has custom requirements for compilation to specify a
|
||||
stage plugin for these stages to enable custom transformation of
|
||||
the circuit to ensure it is runnable on the backend. These hooks are enabled
|
||||
by default and should only be used to enable extra compilation steps
|
||||
if they are **required** to ensure a circuit is executable on the backend or
|
||||
have the expected level of performance. These methods are passed no input
|
||||
arguments and are expected to return a ``str`` representing the method name
|
||||
which should be a stage plugin (see: :mod:`qiskit.transpiler.preset_passmanagers.plugin`
|
||||
for more details on plugins). The typical expected use case is for a backend
|
||||
provider to implement a stage plugin for ``translation`` or ``scheduling``
|
||||
that contains the custom compilation passes and then for the hook methods on
|
||||
the backend object to return the plugin name so that :func:`~.transpile` will
|
||||
use it by default when targetting the backend.
|
||||
"""
|
||||
|
||||
version = 2
|
||||
|
|
|
@ -42,7 +42,6 @@ class PassManagerConfig:
|
|||
hls_config=None,
|
||||
init_method=None,
|
||||
optimization_method=None,
|
||||
optimization_level=None,
|
||||
):
|
||||
"""Initialize a PassManagerConfig object
|
||||
|
||||
|
@ -84,7 +83,6 @@ class PassManagerConfig:
|
|||
init_method (str): The plugin name for the init stage plugin to use
|
||||
optimization_method (str): The plugin name for the optimization stage plugin
|
||||
to use.
|
||||
optimization_level (int): The optimization level being used for compilation.
|
||||
"""
|
||||
self.initial_layout = initial_layout
|
||||
self.basis_gates = basis_gates
|
||||
|
@ -105,7 +103,6 @@ class PassManagerConfig:
|
|||
self.unitary_synthesis_plugin_config = unitary_synthesis_plugin_config
|
||||
self.target = target
|
||||
self.hls_config = hls_config
|
||||
self.optimization_level = optimization_level
|
||||
|
||||
@classmethod
|
||||
def from_backend(cls, backend, **pass_manager_options):
|
||||
|
@ -157,6 +154,10 @@ class PassManagerConfig:
|
|||
if res.target is None:
|
||||
if backend_version >= 2:
|
||||
res.target = backend.target
|
||||
if res.scheduling_method is None and hasattr(backend, "get_scheduling_stage_plugin"):
|
||||
res.scheduling_method = backend.get_scheduling_stage_plugin()
|
||||
if res.translation_method is None and hasattr(backend, "get_translation_stage_plugin"):
|
||||
res.translation_method = backend.get_translation_stage_plugin()
|
||||
return res
|
||||
|
||||
def __str__(self):
|
||||
|
|
|
@ -205,7 +205,6 @@ def generate_preset_pass_manager(
|
|||
hls_config=hls_config,
|
||||
init_method=init_method,
|
||||
optimization_method=optimization_method,
|
||||
optimization_level=optimization_level,
|
||||
)
|
||||
|
||||
if backend is not None:
|
||||
|
|
|
@ -94,11 +94,6 @@ def level_3_pass_manager(pass_manager_config: PassManagerConfig) -> StagedPassMa
|
|||
unitary_synthesis_plugin_config = pass_manager_config.unitary_synthesis_plugin_config
|
||||
target = pass_manager_config.target
|
||||
hls_config = pass_manager_config.hls_config
|
||||
# Override an unset optimization_level for stage plugin use.
|
||||
# it will be restored to None before this is returned
|
||||
optimization_level = pass_manager_config.optimization_level
|
||||
if optimization_level is None:
|
||||
pass_manager_config.optimization_level = 3
|
||||
|
||||
# Layout on good qubits if calibration info available, otherwise on dense links
|
||||
_given_layout = SetLayout(initial_layout)
|
||||
|
@ -314,14 +309,13 @@ def level_3_pass_manager(pass_manager_config: PassManagerConfig) -> StagedPassMa
|
|||
sched = common.generate_scheduling(
|
||||
instruction_durations, scheduling_method, timing_constraints, inst_map
|
||||
)
|
||||
elif isinstance(scheduling_method, PassManager):
|
||||
sched = scheduling_method
|
||||
else:
|
||||
sched = plugin_manager.get_passmanager_stage(
|
||||
"scheduling", scheduling_method, pass_manager_config, optimization_level=3
|
||||
)
|
||||
|
||||
# Restore PassManagerConfig optimization_level override
|
||||
pass_manager_config.optimization_level = optimization_level
|
||||
|
||||
return StagedPassManager(
|
||||
init=init,
|
||||
layout=layout,
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
---
|
||||
features:
|
||||
- |
|
||||
The :class:`~.BackendV2` class now has support for two new optional hook
|
||||
points enabling backends to inject custom compilation steps as part of
|
||||
:func:`~.transpile` and :func:`~.generate_preset_pass_manager`. If a
|
||||
:class:`~.BackendV2` implementation includes the methods
|
||||
``get_scheduling_stage_plugin()`` or ``get_translation_stage_plugin()`` the
|
||||
transpiler will use the returned string as the default value for
|
||||
the ``scheduling_method`` and ``translation_method`` arguments. This enables
|
||||
backends to run additional custom transpiler passes when targetting that
|
||||
backend by leveraging the transpiler stage
|
||||
:mod:`~qiskit.transpiler.preset_passmanagers.plugin` interface.
|
||||
For more details on how to use this see :ref:`custom_transpiler_backend`.
|
||||
- |
|
||||
Added a new keyword argument, ``ignore_backend_supplied_default_methods``, to the
|
||||
:func:`~.transpile` function can be used to disable a backend's custom
|
||||
default method if the target backend has one set.
|
|
@ -21,12 +21,9 @@ features:
|
|||
``optimization_method`` which are used to specify alternative plugins to
|
||||
use for the ``init`` stage and ``optimization`` stages respectively.
|
||||
- |
|
||||
The :class:`~.PassManagerConfig` class has 3 new attributes,
|
||||
:attr:`~.PassManagerConfig.init_method`,
|
||||
:attr:`~.PassManagerConfig.optimization_method`, and
|
||||
:attr:`~.PassManagerConfig.optimization_level` along with matching keyword
|
||||
arguments on the constructor methods. The first two attributes represent
|
||||
The :class:`~.PassManagerConfig` class has 2 new attributes,
|
||||
:attr:`~.PassManagerConfig.init_method` and
|
||||
:attr:`~.PassManagerConfig.optimization_method`
|
||||
along with matching keyword arguments on the constructor methods. These represent
|
||||
the user specified ``init`` and ``optimization`` plugins to use for
|
||||
compilation. The :attr:`~.PassManagerConfig.optimization_level` attribute
|
||||
represents the compilations optimization level if specified which can
|
||||
be used to inform stage plugin behavior.
|
||||
compilation.
|
||||
|
|
|
@ -23,7 +23,12 @@ from qiskit import QuantumCircuit, ClassicalRegister, QuantumRegister
|
|||
from qiskit.circuit import Qubit
|
||||
from qiskit.compiler import transpile, assemble
|
||||
from qiskit.transpiler import CouplingMap, Layout, PassManager, TranspilerError
|
||||
from qiskit.circuit.library import U2Gate, U3Gate, QuantumVolume
|
||||
from qiskit.transpiler.passes import (
|
||||
ALAPScheduleAnalysis,
|
||||
PadDynamicalDecoupling,
|
||||
RemoveResetInZeroState,
|
||||
)
|
||||
from qiskit.circuit.library import U2Gate, U3Gate, XGate, QuantumVolume
|
||||
from qiskit.test import QiskitTestCase
|
||||
from qiskit.providers.fake_provider import (
|
||||
FakeBelem,
|
||||
|
@ -41,10 +46,37 @@ from qiskit.converters import circuit_to_dag
|
|||
from qiskit.circuit.library import GraphState
|
||||
from qiskit.quantum_info import random_unitary
|
||||
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
|
||||
from qiskit.transpiler.preset_passmanagers import level0, level1, level2, level3
|
||||
from qiskit.utils.optionals import HAS_TOQM
|
||||
from qiskit.transpiler.passes import Collect2qBlocks, GatesInBasis
|
||||
|
||||
|
||||
def mock_get_passmanager_stage(
|
||||
stage_name,
|
||||
plugin_name,
|
||||
pm_config,
|
||||
optimization_level=None, # pylint: disable=unused-argument
|
||||
) -> PassManager:
|
||||
"""Mock function for get_passmanager_stage."""
|
||||
if stage_name == "translation" and plugin_name == "custom_stage_for_test":
|
||||
pm = PassManager([RemoveResetInZeroState()])
|
||||
return pm
|
||||
|
||||
elif stage_name == "scheduling" and plugin_name == "custom_stage_for_test":
|
||||
dd_sequence = [XGate(), XGate()]
|
||||
pm = PassManager(
|
||||
[
|
||||
ALAPScheduleAnalysis(pm_config.instruction_durations),
|
||||
PadDynamicalDecoupling(pm_config.instruction_durations, dd_sequence),
|
||||
]
|
||||
)
|
||||
return pm
|
||||
elif stage_name == "routing":
|
||||
return PassManager([])
|
||||
else:
|
||||
raise Exception("Failure, unexpected stage plugin combo for test")
|
||||
|
||||
|
||||
def emptycircuit():
|
||||
"""Empty circuit"""
|
||||
return QuantumCircuit()
|
||||
|
@ -431,6 +463,36 @@ class TestPassesInspection(QiskitTestCase):
|
|||
Layout.from_qubit_list([ancilla[0], ancilla[1], qr[1], ancilla[2], qr[0]]),
|
||||
)
|
||||
|
||||
@unittest.mock.patch.object(
|
||||
level0.PassManagerStagePluginManager,
|
||||
"get_passmanager_stage",
|
||||
wraps=mock_get_passmanager_stage,
|
||||
)
|
||||
def test_backend_with_custom_stages(self, _plugin_manager_mock):
|
||||
"""Test transpile() executes backend specific custom stage."""
|
||||
optimization_level = 1
|
||||
|
||||
class TargetBackend(FakeLagosV2):
|
||||
"""Fake lagos subclass with custom transpiler stages."""
|
||||
|
||||
def get_scheduling_stage_plugin(self):
|
||||
"""Custom scheduling stage."""
|
||||
return "custom_stage_for_test"
|
||||
|
||||
def get_translation_stage_plugin(self):
|
||||
"""Custom post translation stage."""
|
||||
return "custom_stage_for_test"
|
||||
|
||||
target = TargetBackend()
|
||||
qr = QuantumRegister(2, "q")
|
||||
qc = QuantumCircuit(qr)
|
||||
qc.h(qr[0])
|
||||
qc.cx(qr[0], qr[1])
|
||||
_ = transpile(qc, target, optimization_level=optimization_level, callback=self.callback)
|
||||
self.assertIn("ALAPScheduleAnalysis", self.passes)
|
||||
self.assertIn("PadDynamicalDecoupling", self.passes)
|
||||
self.assertIn("RemoveResetInZeroState", self.passes)
|
||||
|
||||
|
||||
@ddt
|
||||
class TestInitialLayouts(QiskitTestCase):
|
||||
|
@ -1029,3 +1091,139 @@ class TestGeenratePresetPassManagers(QiskitTestCase):
|
|||
"""Assert we fail with an invalid optimization_level."""
|
||||
with self.assertRaises(ValueError):
|
||||
generate_preset_pass_manager(42)
|
||||
|
||||
@unittest.mock.patch.object(
|
||||
level2.PassManagerStagePluginManager,
|
||||
"get_passmanager_stage",
|
||||
wraps=mock_get_passmanager_stage,
|
||||
)
|
||||
def test_backend_with_custom_stages_level2(self, _plugin_manager_mock):
|
||||
"""Test generated preset pass manager includes backend specific custom stages."""
|
||||
optimization_level = 2
|
||||
|
||||
class TargetBackend(FakeLagosV2):
|
||||
"""Fake lagos subclass with custom transpiler stages."""
|
||||
|
||||
def get_scheduling_stage_plugin(self):
|
||||
"""Custom scheduling stage."""
|
||||
return "custom_stage_for_test"
|
||||
|
||||
def get_translation_stage_plugin(self):
|
||||
"""Custom post translation stage."""
|
||||
return "custom_stage_for_test"
|
||||
|
||||
target = TargetBackend()
|
||||
pm = generate_preset_pass_manager(optimization_level, backend=target)
|
||||
self.assertIsInstance(pm, PassManager)
|
||||
|
||||
pass_list = [y.__class__.__name__ for x in pm.passes() for y in x["passes"]]
|
||||
self.assertIn("PadDynamicalDecoupling", pass_list)
|
||||
self.assertIn("ALAPScheduleAnalysis", pass_list)
|
||||
post_translation_pass_list = [
|
||||
y.__class__.__name__
|
||||
for x in pm.translation.passes() # pylint: disable=no-member
|
||||
for y in x["passes"]
|
||||
]
|
||||
self.assertIn("RemoveResetInZeroState", post_translation_pass_list)
|
||||
|
||||
@unittest.mock.patch.object(
|
||||
level1.PassManagerStagePluginManager,
|
||||
"get_passmanager_stage",
|
||||
wraps=mock_get_passmanager_stage,
|
||||
)
|
||||
def test_backend_with_custom_stages_level1(self, _plugin_manager_mock):
|
||||
"""Test generated preset pass manager includes backend specific custom stages."""
|
||||
optimization_level = 1
|
||||
|
||||
class TargetBackend(FakeLagosV2):
|
||||
"""Fake lagos subclass with custom transpiler stages."""
|
||||
|
||||
def get_scheduling_stage_plugin(self):
|
||||
"""Custom scheduling stage."""
|
||||
return "custom_stage_for_test"
|
||||
|
||||
def get_translation_stage_plugin(self):
|
||||
"""Custom post translation stage."""
|
||||
return "custom_stage_for_test"
|
||||
|
||||
target = TargetBackend()
|
||||
pm = generate_preset_pass_manager(optimization_level, backend=target)
|
||||
self.assertIsInstance(pm, PassManager)
|
||||
|
||||
pass_list = [y.__class__.__name__ for x in pm.passes() for y in x["passes"]]
|
||||
self.assertIn("PadDynamicalDecoupling", pass_list)
|
||||
self.assertIn("ALAPScheduleAnalysis", pass_list)
|
||||
post_translation_pass_list = [
|
||||
y.__class__.__name__
|
||||
for x in pm.translation.passes() # pylint: disable=no-member
|
||||
for y in x["passes"]
|
||||
]
|
||||
self.assertIn("RemoveResetInZeroState", post_translation_pass_list)
|
||||
|
||||
@unittest.mock.patch.object(
|
||||
level3.PassManagerStagePluginManager,
|
||||
"get_passmanager_stage",
|
||||
wraps=mock_get_passmanager_stage,
|
||||
)
|
||||
def test_backend_with_custom_stages_level3(self, _plugin_manager_mock):
|
||||
"""Test generated preset pass manager includes backend specific custom stages."""
|
||||
optimization_level = 3
|
||||
|
||||
class TargetBackend(FakeLagosV2):
|
||||
"""Fake lagos subclass with custom transpiler stages."""
|
||||
|
||||
def get_scheduling_stage_plugin(self):
|
||||
"""Custom scheduling stage."""
|
||||
return "custom_stage_for_test"
|
||||
|
||||
def get_translation_stage_plugin(self):
|
||||
"""Custom post translation stage."""
|
||||
return "custom_stage_for_test"
|
||||
|
||||
target = TargetBackend()
|
||||
pm = generate_preset_pass_manager(optimization_level, backend=target)
|
||||
self.assertIsInstance(pm, PassManager)
|
||||
|
||||
pass_list = [y.__class__.__name__ for x in pm.passes() for y in x["passes"]]
|
||||
self.assertIn("PadDynamicalDecoupling", pass_list)
|
||||
self.assertIn("ALAPScheduleAnalysis", pass_list)
|
||||
post_translation_pass_list = [
|
||||
y.__class__.__name__
|
||||
for x in pm.translation.passes() # pylint: disable=no-member
|
||||
for y in x["passes"]
|
||||
]
|
||||
self.assertIn("RemoveResetInZeroState", post_translation_pass_list)
|
||||
|
||||
@unittest.mock.patch.object(
|
||||
level0.PassManagerStagePluginManager,
|
||||
"get_passmanager_stage",
|
||||
wraps=mock_get_passmanager_stage,
|
||||
)
|
||||
def test_backend_with_custom_stages_level0(self, _plugin_manager_mock):
|
||||
"""Test generated preset pass manager includes backend specific custom stages."""
|
||||
optimization_level = 0
|
||||
|
||||
class TargetBackend(FakeLagosV2):
|
||||
"""Fake lagos subclass with custom transpiler stages."""
|
||||
|
||||
def get_scheduling_stage_plugin(self):
|
||||
"""Custom scheduling stage."""
|
||||
return "custom_stage_for_test"
|
||||
|
||||
def get_translation_stage_plugin(self):
|
||||
"""Custom post translation stage."""
|
||||
return "custom_stage_for_test"
|
||||
|
||||
target = TargetBackend()
|
||||
pm = generate_preset_pass_manager(optimization_level, backend=target)
|
||||
self.assertIsInstance(pm, PassManager)
|
||||
|
||||
pass_list = [y.__class__.__name__ for x in pm.passes() for y in x["passes"]]
|
||||
self.assertIn("PadDynamicalDecoupling", pass_list)
|
||||
self.assertIn("ALAPScheduleAnalysis", pass_list)
|
||||
post_translation_pass_list = [
|
||||
y.__class__.__name__
|
||||
for x in pm.translation.passes() # pylint: disable=no-member
|
||||
for y in x["passes"]
|
||||
]
|
||||
self.assertIn("RemoveResetInZeroState", post_translation_pass_list)
|
||||
|
|
Loading…
Reference in New Issue