From d56ef8c49cdeefe4880cdabab43b41d9f2aa92b5 Mon Sep 17 00:00:00 2001 From: Kevin Hartman Date: Tue, 1 Nov 2022 16:16:43 -0400 Subject: [PATCH] Use TOQM routing staged pass manager. (#9042) * Update toqm requirements-dev version. * Remove toqm special casing. * Remove unused imports from preset pass managers. * Add release note. * Apply suggestions from code review Co-authored-by: Jake Lishman Co-authored-by: Jake Lishman Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> --- qiskit/compiler/transpiler.py | 3 +- .../transpiler/preset_passmanagers/common.py | 2 +- .../transpiler/preset_passmanagers/level0.py | 41 ++-------------- .../transpiler/preset_passmanagers/level1.py | 44 +---------------- .../transpiler/preset_passmanagers/level2.py | 49 ++----------------- .../transpiler/preset_passmanagers/level3.py | 48 ++---------------- .../toqm-extra-0.1.0-4fedfa1ff0fedfa0.yaml | 9 ++++ requirements-dev.txt | 2 +- setup.py | 2 +- 9 files changed, 28 insertions(+), 172 deletions(-) create mode 100644 releasenotes/notes/toqm-extra-0.1.0-4fedfa1ff0fedfa0.yaml diff --git a/qiskit/compiler/transpiler.py b/qiskit/compiler/transpiler.py index f4b1836a09b6..4d82214a5e03 100644 --- a/qiskit/compiler/transpiler.py +++ b/qiskit/compiler/transpiler.py @@ -160,8 +160,7 @@ def transpile( You can see a list of installed plugins by using :func:`~.list_stage_plugins` with ``"layout"`` for the ``stage_name`` argument. routing_method: Name of routing pass - ('basic', 'lookahead', 'stochastic', 'sabre', 'toqm', 'none'). Note - that to use method 'toqm', package 'qiskit-toqm' must be installed. + ('basic', 'lookahead', 'stochastic', 'sabre', 'none'). Note This can also be the external plugin name to use for the ``routing`` stage. You can see a list of installed plugins by using :func:`~.list_stage_plugins` with ``"routing"`` for the ``stage_name`` argument. diff --git a/qiskit/transpiler/preset_passmanagers/common.py b/qiskit/transpiler/preset_passmanagers/common.py index 31009b443802..4d460894aab2 100644 --- a/qiskit/transpiler/preset_passmanagers/common.py +++ b/qiskit/transpiler/preset_passmanagers/common.py @@ -64,7 +64,7 @@ working={"trivial", "dense"}, not_working={"sabre", "noise_adaptive"} ), "routing_method": _ControlFlowState( - working={"none", "stochastic"}, not_working={"sabre", "lookahead", "basic", "toqm"} + working={"none", "stochastic"}, not_working={"sabre", "lookahead", "basic"} ), # 'synthesis' is not a supported translation method because of the block-collection passes # involved; we currently don't have a neat way to pass the information about nested blocks - the diff --git a/qiskit/transpiler/preset_passmanagers/level0.py b/qiskit/transpiler/preset_passmanagers/level0.py index 585c727d11c2..78cffd88f24a 100644 --- a/qiskit/transpiler/preset_passmanagers/level0.py +++ b/qiskit/transpiler/preset_passmanagers/level0.py @@ -28,10 +28,7 @@ from qiskit.transpiler.preset_passmanagers import common from qiskit.transpiler.preset_passmanagers.plugin import ( PassManagerStagePluginManager, - list_stage_plugins, ) -from qiskit.transpiler import TranspilerError -from qiskit.utils.optionals import HAS_TOQM def level_0_pass_manager(pass_manager_config: PassManagerConfig) -> StagedPassManager: @@ -91,38 +88,10 @@ def _choose_layout_condition(property_set): coupling_map, max_iterations=1, seed=seed_transpiler, swap_trials=5 ) - toqm_pass = False # Choose routing pass - # TODO: Remove when qiskit-toqm has it's own plugin and we can rely on just the plugin interface - if routing_method == "toqm" and "toqm" not in list_stage_plugins("routing"): - HAS_TOQM.require_now("TOQM-based routing") - from qiskit_toqm import ToqmSwap, ToqmStrategyO0, latencies_from_target - - if initial_layout: - raise TranspilerError("Initial layouts are not supported with TOQM-based routing.") - - toqm_pass = True - # Note: BarrierBeforeFinalMeasurements is skipped intentionally since ToqmSwap - # does not yet support barriers. - routing_pass = ToqmSwap( - coupling_map, - strategy=ToqmStrategyO0( - latencies_from_target( - coupling_map, instruction_durations, basis_gates, backend_properties, target - ) - ), - ) - routing_pm = common.generate_routing_passmanager( - routing_pass, - target, - coupling_map=coupling_map, - seed_transpiler=seed_transpiler, - use_barrier_before_measurement=not toqm_pass, - ) - else: - routing_pm = plugin_manager.get_passmanager_stage( - "routing", routing_method, pass_manager_config, optimization_level=0 - ) + routing_pm = plugin_manager.get_passmanager_stage( + "routing", routing_method, pass_manager_config, optimization_level=0 + ) unroll_3q = None # Build pass manager @@ -164,9 +133,6 @@ def _choose_layout_condition(property_set): unitary_synthesis_plugin_config, hls_config, ) - pre_routing = None - if toqm_pass: - pre_routing = translation if (coupling_map and not coupling_map.is_symmetric) or ( target is not None and target.get_non_global_operation_names(strict_direction=True) @@ -205,7 +171,6 @@ def _choose_layout_condition(property_set): return StagedPassManager( init=init, layout=layout, - pre_routing=pre_routing, routing=routing, translation=translation, pre_optimization=pre_opt, diff --git a/qiskit/transpiler/preset_passmanagers/level1.py b/qiskit/transpiler/preset_passmanagers/level1.py index ac6360862bdc..b3a58fe703d8 100644 --- a/qiskit/transpiler/preset_passmanagers/level1.py +++ b/qiskit/transpiler/preset_passmanagers/level1.py @@ -37,11 +37,8 @@ from qiskit.transpiler.preset_passmanagers import common from qiskit.transpiler.passes.layout.vf2_layout import VF2LayoutStopReason -from qiskit.transpiler import TranspilerError -from qiskit.utils.optionals import HAS_TOQM from qiskit.transpiler.preset_passmanagers.plugin import ( PassManagerStagePluginManager, - list_stage_plugins, ) @@ -149,41 +146,9 @@ def _vf2_match_not_found(property_set): SabreLayout(coupling_map, max_iterations=2, seed=seed_transpiler, swap_trials=5), ).to_flow_controller() - toqm_pass = False + # Choose routing pass routing_pm = None - # TODO: Remove when qiskit-toqm has it's own plugin and we can rely on just the plugin interface - if routing_method == "toqm" and "toqm" not in list_stage_plugins("routing"): - HAS_TOQM.require_now("TOQM-based routing") - from qiskit_toqm import ToqmSwap, ToqmStrategyO1, latencies_from_target - - if initial_layout: - raise TranspilerError("Initial layouts are not supported with TOQM-based routing.") - - toqm_pass = True - # Note: BarrierBeforeFinalMeasurements is skipped intentionally since ToqmSwap - # does not yet support barriers. - routing_pass = ToqmSwap( - coupling_map, - strategy=ToqmStrategyO1( - latencies_from_target( - coupling_map, instruction_durations, basis_gates, backend_properties, target - ) - ), - ) - vf2_call_limit = common.get_vf2_call_limit( - 1, pass_manager_config.layout_method, pass_manager_config.initial_layout - ) - routing_pm = common.generate_routing_passmanager( - routing_pass, - target, - coupling_map, - vf2_call_limit=vf2_call_limit, - backend_properties=backend_properties, - seed_transpiler=seed_transpiler, - check_trivial=True, - use_barrier_before_measurement=not toqm_pass, - ) - elif routing_method is None: + if routing_method is None: _stochastic_routing = plugin_manager.get_passmanager_stage( "routing", "stochastic", @@ -261,10 +226,6 @@ def _opt_control(property_set): hls_config, ) - pre_routing = None - if toqm_pass: - pre_routing = translation - if (coupling_map and not coupling_map.is_symmetric) or ( target is not None and target.get_non_global_operation_names(strict_direction=True) ): @@ -318,7 +279,6 @@ def _unroll_condition(property_set): return StagedPassManager( init=init, layout=layout, - pre_routing=pre_routing, routing=routing, translation=translation, pre_optimization=pre_optimization, diff --git a/qiskit/transpiler/preset_passmanagers/level2.py b/qiskit/transpiler/preset_passmanagers/level2.py index 9597b484a3b7..1edd917c1160 100644 --- a/qiskit/transpiler/preset_passmanagers/level2.py +++ b/qiskit/transpiler/preset_passmanagers/level2.py @@ -37,11 +37,8 @@ from qiskit.transpiler.preset_passmanagers import common from qiskit.transpiler.passes.layout.vf2_layout import VF2LayoutStopReason -from qiskit.transpiler import TranspilerError -from qiskit.utils.optionals import HAS_TOQM from qiskit.transpiler.preset_passmanagers.plugin import ( PassManagerStagePluginManager, - list_stage_plugins, ) @@ -134,43 +131,10 @@ def _vf2_match_not_found(property_set): coupling_map, max_iterations=2, seed=seed_transpiler, swap_trials=10 ) - toqm_pass = False - routing_pm = None - # TODO: Remove when qiskit-toqm has it's own plugin and we can rely on just the plugin interface - if routing_method == "toqm" and "toqm" not in list_stage_plugins("routing"): - HAS_TOQM.require_now("TOQM-based routing") - from qiskit_toqm import ToqmSwap, ToqmStrategyO2, latencies_from_target - - if initial_layout: - raise TranspilerError("Initial layouts are not supported with TOQM-based routing.") - toqm_pass = True - - # Note: BarrierBeforeFinalMeasurements is skipped intentionally since ToqmSwap - # does not yet support barriers. - routing_pass = ToqmSwap( - coupling_map, - strategy=ToqmStrategyO2( - latencies_from_target( - coupling_map, instruction_durations, basis_gates, backend_properties, target - ) - ), - ) - vf2_call_limit = common.get_vf2_call_limit( - 2, pass_manager_config.layout_method, pass_manager_config.initial_layout - ) - routing_pm = common.generate_routing_passmanager( - routing_pass, - target, - coupling_map=coupling_map, - vf2_call_limit=vf2_call_limit, - backend_properties=backend_properties, - seed_transpiler=seed_transpiler, - use_barrier_before_measurement=not toqm_pass, - ) - else: - routing_pm = plugin_manager.get_passmanager_stage( - "routing", routing_method, pass_manager_config, optimization_level=2 - ) + # Choose routing pass + routing_pm = plugin_manager.get_passmanager_stage( + "routing", routing_method, pass_manager_config, optimization_level=2 + ) # Build optimization loop: 1q rotation merge and commutative cancellation iteratively until # no more change in depth @@ -226,9 +190,7 @@ def _opt_control(property_set): unitary_synthesis_plugin_config, hls_config, ) - pre_routing = None - if toqm_pass: - pre_routing = translation + if (coupling_map and not coupling_map.is_symmetric) or ( target is not None and target.get_non_global_operation_names(strict_direction=True) ): @@ -275,7 +237,6 @@ def _unroll_condition(property_set): return StagedPassManager( init=init, layout=layout, - pre_routing=pre_routing, routing=routing, translation=translation, pre_optimization=pre_optimization, diff --git a/qiskit/transpiler/preset_passmanagers/level3.py b/qiskit/transpiler/preset_passmanagers/level3.py index 61080636f357..46cc03e58917 100644 --- a/qiskit/transpiler/preset_passmanagers/level3.py +++ b/qiskit/transpiler/preset_passmanagers/level3.py @@ -45,10 +45,7 @@ from qiskit.transpiler.passes.layout.vf2_layout import VF2LayoutStopReason from qiskit.transpiler.preset_passmanagers.plugin import ( PassManagerStagePluginManager, - list_stage_plugins, ) -from qiskit.transpiler import TranspilerError -from qiskit.utils.optionals import HAS_TOQM def level_3_pass_manager(pass_manager_config: PassManagerConfig) -> StagedPassManager: @@ -140,42 +137,10 @@ def _vf2_match_not_found(property_set): coupling_map, max_iterations=4, seed=seed_transpiler, swap_trials=20 ) - toqm_pass = False - # TODO: Remove when qiskit-toqm has it's own plugin and we can rely on just the plugin interface - if routing_method == "toqm" and "toqm" not in list_stage_plugins("routing"): - HAS_TOQM.require_now("TOQM-based routing") - from qiskit_toqm import ToqmSwap, ToqmStrategyO3, latencies_from_target - - if initial_layout: - raise TranspilerError("Initial layouts are not supported with TOQM-based routing.") - - toqm_pass = True - # Note: BarrierBeforeFinalMeasurements is skipped intentionally since ToqmSwap - # does not yet support barriers. - routing_pass = ToqmSwap( - coupling_map, - strategy=ToqmStrategyO3( - latencies_from_target( - coupling_map, instruction_durations, basis_gates, backend_properties, target - ) - ), - ) - vf2_call_limit = common.get_vf2_call_limit( - 3, pass_manager_config.layout_method, pass_manager_config.initial_layout - ) - routing_pm = common.generate_routing_passmanager( - routing_pass, - target, - coupling_map=coupling_map, - vf2_call_limit=vf2_call_limit, - backend_properties=backend_properties, - seed_transpiler=seed_transpiler, - use_barrier_before_measurement=not toqm_pass, - ) - else: - routing_pm = plugin_manager.get_passmanager_stage( - "routing", routing_method, pass_manager_config, optimization_level=3 - ) + # Choose routing pass + routing_pm = plugin_manager.get_passmanager_stage( + "routing", routing_method, pass_manager_config, optimization_level=3 + ) # 8. Optimize iteratively until no more change in depth. Removes useless gates # after reset and before measure, commutes gates and optimizes contiguous blocks. @@ -252,9 +217,7 @@ def _opt_control(property_set): unitary_synthesis_plugin_config, hls_config, ) - pre_routing = None - if toqm_pass: - pre_routing = translation + if optimization_method is None: optimization = PassManager() unroll = [pass_ for x in translation.passes() for pass_ in x["passes"]] @@ -322,7 +285,6 @@ def _unroll_condition(property_set): return StagedPassManager( init=init, layout=layout, - pre_routing=pre_routing, routing=routing, translation=translation, pre_optimization=pre_optimization, diff --git a/releasenotes/notes/toqm-extra-0.1.0-4fedfa1ff0fedfa0.yaml b/releasenotes/notes/toqm-extra-0.1.0-4fedfa1ff0fedfa0.yaml new file mode 100644 index 000000000000..b6962db3e31e --- /dev/null +++ b/releasenotes/notes/toqm-extra-0.1.0-4fedfa1ff0fedfa0.yaml @@ -0,0 +1,9 @@ +--- +upgrade: + - | + The version requirement for the optional feature package ``qiskit-toqm`` installable via + ``pip install qiskit-terra[toqm]`` has been upgraded from version + ``0.0.4`` to ``0.1.0``. To use the ``toqm`` routing method + with :func:`~.transpile` you must now use qiskit-toqm version + ``0.1.0`` or newer. Older versions are no longer discoverable by + the transpiler. diff --git a/requirements-dev.txt b/requirements-dev.txt index 8d47d49e357e..d85dc5d8365e 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -18,7 +18,7 @@ seaborn>=0.9.0 reno>=3.4.0 Sphinx>=3.0.0 qiskit-sphinx-theme>=1.6 -qiskit-toqm>=0.0.4;platform_machine != 'aarch64' or platform_system != 'Linux' +qiskit-toqm>=0.1.0;platform_machine != 'aarch64' or platform_system != 'Linux' sphinx-autodoc-typehints~=1.18,!=1.19.3 jupyter-sphinx sphinx-design>=0.2.0 diff --git a/setup.py b/setup.py index 74ebd81a0026..cdbfbb67a724 100755 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ ] bip_requirements = ["cplex", "docplex"] csp_requirements = ["python-constraint>=1.4"] -toqm_requirements = ["qiskit-toqm>=0.0.4"] +toqm_requirements = ["qiskit-toqm>=0.1.0"] setup( name="qiskit-terra",