From 2475338c0b5beb2335ee297ad04fd43a9a31a461 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Sat, 10 Dec 2022 22:31:23 +0100 Subject: [PATCH 1/6] plugin convenience function for getting the entry point object --- .../transpiler/preset_passmanagers/plugin.py | 31 +++++++++++++++++++ .../entry_point_obj-60625d9d797df1d9.yaml | 13 ++++++++ test/python/transpiler/test_stage_plugin.py | 7 +++++ 3 files changed, 51 insertions(+) create mode 100644 releasenotes/notes/entry_point_obj-60625d9d797df1d9.yaml diff --git a/qiskit/transpiler/preset_passmanagers/plugin.py b/qiskit/transpiler/preset_passmanagers/plugin.py index f4d1ae7e4b89..be18986d893c 100644 --- a/qiskit/transpiler/preset_passmanagers/plugin.py +++ b/qiskit/transpiler/preset_passmanagers/plugin.py @@ -161,6 +161,7 @@ def pass_manager(self, pass_manager_config, optimization_level): PassManagerStagePlugin PassManagerStagePluginManager list_stage_plugins + entry_point_obj """ import abc @@ -301,3 +302,33 @@ def list_stage_plugins(stage_name: str) -> List[str]: return plugin_mgr.scheduling_plugins.names() else: raise TranspilerError(f"Invalid stage name: {stage_name}") + + +def entry_point_obj(stage_name: str, plugin_name: str) -> abc.ABCMeta: + """Return the class type of an entry point. + + Args: + stage_name: The stage name to get the entrypoint for + plugin_name: The plugin name to get the entrypoint for + + Returns: + Type: Class of the entrypoint + + Raises: + TranspilerError: If an invalid stage name is specified. + """ + plugin_mgr = PassManagerStagePluginManager() + if stage_name == "init": + return plugin_mgr.init_plugins[plugin_name].obj + elif stage_name == "layout": + return plugin_mgr.layout_plugins[plugin_name].obj + elif stage_name == "routing": + return plugin_mgr.routing_plugins[plugin_name].obj + elif stage_name == "translation": + return plugin_mgr.translation_plugins[plugin_name].obj + elif stage_name == "optimization": + return plugin_mgr.optimization_plugins[plugin_name].obj + elif stage_name == "scheduling": + return plugin_mgr.scheduling_plugins[plugin_name].obj + else: + raise TranspilerError(f"Invalid stage name: {stage_name}") diff --git a/releasenotes/notes/entry_point_obj-60625d9d797df1d9.yaml b/releasenotes/notes/entry_point_obj-60625d9d797df1d9.yaml new file mode 100644 index 000000000000..fea97ed4e375 --- /dev/null +++ b/releasenotes/notes/entry_point_obj-60625d9d797df1d9.yaml @@ -0,0 +1,13 @@ +--- +features: + - | + The function ``entry_point_obj`` in the module + ``qiskit.transpiler.preset_passmanagers.plugin`` was added to obtain the plugin class type. + Given a stage and a plug name, this function will return the plugin class of the entry point, + allowing to identify it and query its documentation. For example:: + + >>> from qiskit.transpiler.preset_passmanagers.plugin import entry_point_obj + >>> entry_point_obj('routing', 'lookahead').__class__ + qiskit.transpiler.preset_passmanagers.builtin_plugins.LookaheadSwapPassManager + + >>> help(entry_point_obj('routing', 'lookahead')) diff --git a/test/python/transpiler/test_stage_plugin.py b/test/python/transpiler/test_stage_plugin.py index 1242905e9f4e..6664641317b1 100644 --- a/test/python/transpiler/test_stage_plugin.py +++ b/test/python/transpiler/test_stage_plugin.py @@ -22,9 +22,11 @@ from qiskit.compiler.transpiler import transpile from qiskit.test import QiskitTestCase from qiskit.transpiler import PassManager, PassManagerConfig, CouplingMap +from qiskit.transpiler.preset_passmanagers.builtin_plugins import BasicSwapPassManager from qiskit.transpiler.preset_passmanagers.plugin import ( PassManagerStagePluginManager, list_stage_plugins, + entry_point_obj, ) from qiskit.transpiler.exceptions import TranspilerError from qiskit.providers.basicaer import QasmSimulatorPy @@ -51,6 +53,11 @@ def test_list_stage_plugins_invalid_stage_name(self): with self.assertRaises(TranspilerError): list_stage_plugins("not_a_stage") + def test_entry_point_obj(self): + """Test entry_point_obj function.""" + basic_obj = entry_point_obj("routing", "basic") + self.assertIsInstance(basic_obj, BasicSwapPassManager) + def test_build_pm_invalid_plugin_name_valid_stage(self): """Test get pm from plugin with invalid plugin name and valid stage.""" plugin_manager = PassManagerStagePluginManager() From b21c62207d0dbb9fbf5378dc31d54aa95c5b850d Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Fri, 10 Mar 2023 21:44:48 +0100 Subject: [PATCH 2/6] simpler code, thanks to Jake Co-authored-by: Jake Lishman --- .../transpiler/preset_passmanagers/plugin.py | 27 +++++++------------ test/python/transpiler/test_stage_plugin.py | 13 ++++++--- 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/qiskit/transpiler/preset_passmanagers/plugin.py b/qiskit/transpiler/preset_passmanagers/plugin.py index be18986d893c..101ca79961fe 100644 --- a/qiskit/transpiler/preset_passmanagers/plugin.py +++ b/qiskit/transpiler/preset_passmanagers/plugin.py @@ -304,31 +304,22 @@ def list_stage_plugins(stage_name: str) -> List[str]: raise TranspilerError(f"Invalid stage name: {stage_name}") -def entry_point_obj(stage_name: str, plugin_name: str) -> abc.ABCMeta: +def passmanager_stage_plugins(stage: str): """Return the class type of an entry point. Args: - stage_name: The stage name to get the entrypoint for - plugin_name: The plugin name to get the entrypoint for + stage: The stage name to get the entrypoint for Returns: - Type: Class of the entrypoint + dict Type: TODO Raises: TranspilerError: If an invalid stage name is specified. """ plugin_mgr = PassManagerStagePluginManager() - if stage_name == "init": - return plugin_mgr.init_plugins[plugin_name].obj - elif stage_name == "layout": - return plugin_mgr.layout_plugins[plugin_name].obj - elif stage_name == "routing": - return plugin_mgr.routing_plugins[plugin_name].obj - elif stage_name == "translation": - return plugin_mgr.translation_plugins[plugin_name].obj - elif stage_name == "optimization": - return plugin_mgr.optimization_plugins[plugin_name].obj - elif stage_name == "scheduling": - return plugin_mgr.scheduling_plugins[plugin_name].obj - else: - raise TranspilerError(f"Invalid stage name: {stage_name}") + try: + manager = getattr(plugin_mgr, f"{stage}_plugins") + except AttributeError as exc: + raise TranspilerError(f"Passmanager stage {stage} not found") from exc + + return {name: manager[name].obj for name in manager.names()} diff --git a/test/python/transpiler/test_stage_plugin.py b/test/python/transpiler/test_stage_plugin.py index 6664641317b1..1279fae467e8 100644 --- a/test/python/transpiler/test_stage_plugin.py +++ b/test/python/transpiler/test_stage_plugin.py @@ -26,7 +26,7 @@ from qiskit.transpiler.preset_passmanagers.plugin import ( PassManagerStagePluginManager, list_stage_plugins, - entry_point_obj, + passmanager_stage_plugins, ) from qiskit.transpiler.exceptions import TranspilerError from qiskit.providers.basicaer import QasmSimulatorPy @@ -53,10 +53,15 @@ def test_list_stage_plugins_invalid_stage_name(self): with self.assertRaises(TranspilerError): list_stage_plugins("not_a_stage") - def test_entry_point_obj(self): + def test_passmanager_stage_plugins(self): """Test entry_point_obj function.""" - basic_obj = entry_point_obj("routing", "basic") - self.assertIsInstance(basic_obj, BasicSwapPassManager) + basic_obj = passmanager_stage_plugins("routing") + self.assertIsInstance(basic_obj["basic"], BasicSwapPassManager) + + def test_passmanager_stage_plugins_not_found(self): + """Test entry_point_obj function with nonexistent stage""" + with self.assertRaises(TranspilerError): + passmanager_stage_plugins("foo_stage") def test_build_pm_invalid_plugin_name_valid_stage(self): """Test get pm from plugin with invalid plugin name and valid stage.""" From 8e8eb112e055d6cf07aa4ebf2c9208d55bc6c111 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Fri, 10 Mar 2023 21:59:59 +0100 Subject: [PATCH 3/6] typehint and docstring --- .../transpiler/preset_passmanagers/plugin.py | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/qiskit/transpiler/preset_passmanagers/plugin.py b/qiskit/transpiler/preset_passmanagers/plugin.py index 101ca79961fe..d500dd3a141d 100644 --- a/qiskit/transpiler/preset_passmanagers/plugin.py +++ b/qiskit/transpiler/preset_passmanagers/plugin.py @@ -165,7 +165,7 @@ def pass_manager(self, pass_manager_config, optimization_level): """ import abc -from typing import List, Optional +from typing import List, Optional, Dict import stevedore @@ -304,14 +304,26 @@ def list_stage_plugins(stage_name: str) -> List[str]: raise TranspilerError(f"Invalid stage name: {stage_name}") -def passmanager_stage_plugins(stage: str): - """Return the class type of an entry point. +def passmanager_stage_plugins(stage: str) -> Dict[str, PassManagerStagePlugin]: + """Return a dict with, for each stage name, the class type of the plugin. + + This function is useful for getting more information about a plugin: + + from qiskit.transpiler.preset_passmanagers.plugin import passmanager_stage_plugins + routing_plugins = passmanager_stage_plugins('routing') + basic_plugin = routing_plugins['basic'] + ?basic_plugin + + Type: BasicSwapPassManager + String form: <...builtin_plugins.BasicSwapPassManager object at 0xdeadbeef> + File: .../qiskit/transpiler/preset_passmanagers/builtin_plugins.py + Docstring: Plugin class for routing stage with :class:`~.BasicSwap` Args: - stage: The stage name to get the entrypoint for + stage: The stage name to get Returns: - dict Type: TODO + dict: the key is the name of the plugin and the value is the class type for each. Raises: TranspilerError: If an invalid stage name is specified. From 524c8861c98bfd7d5c97ab93f102c9fc6911d648 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Fri, 10 Mar 2023 22:05:41 +0100 Subject: [PATCH 4/6] reno update --- .../entry_point_obj-60625d9d797df1d9.yaml | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/releasenotes/notes/entry_point_obj-60625d9d797df1d9.yaml b/releasenotes/notes/entry_point_obj-60625d9d797df1d9.yaml index fea97ed4e375..0494a059c644 100644 --- a/releasenotes/notes/entry_point_obj-60625d9d797df1d9.yaml +++ b/releasenotes/notes/entry_point_obj-60625d9d797df1d9.yaml @@ -1,13 +1,18 @@ --- features: - | - The function ``entry_point_obj`` in the module - ``qiskit.transpiler.preset_passmanagers.plugin`` was added to obtain the plugin class type. - Given a stage and a plug name, this function will return the plugin class of the entry point, - allowing to identify it and query its documentation. For example:: + The function ``passmanager_stage_plugins`` in the module + ``qiskit.transpiler.preset_passmanagers.plugin`` was added to obtain a map between + plugin names and their class type. + This allows to identify and query passmanager plugin documentation. For example:: - >>> from qiskit.transpiler.preset_passmanagers.plugin import entry_point_obj - >>> entry_point_obj('routing', 'lookahead').__class__ + >>> from qiskit.transpiler.preset_passmanagers.plugin import passmanager_stage_plugins + >>> passmanager_stage_plugins('routing')['lookahead'].__class__ qiskit.transpiler.preset_passmanagers.builtin_plugins.LookaheadSwapPassManager - >>> help(entry_point_obj('routing', 'lookahead')) + >>> help(passmanager_stage_plugins('routing')['lookahead']) + Help on BasicSwapPassManager in module qiskit.transpiler.preset_passmanagers.builtin_plugins object: + + class BasicSwapPassManager(qiskit.transpiler.preset_passmanagers.plugin.PassManagerStagePlugin) + | Plugin class for routing stage with :class:`~.BasicSwap` + ... From 6135d9f6c846dcc9f0671ef5a1a1971166975011 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Fri, 24 Mar 2023 20:48:08 +0100 Subject: [PATCH 5/6] thanks Jake --- .../transpiler/preset_passmanagers/plugin.py | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/qiskit/transpiler/preset_passmanagers/plugin.py b/qiskit/transpiler/preset_passmanagers/plugin.py index d500dd3a141d..7bac5c238a83 100644 --- a/qiskit/transpiler/preset_passmanagers/plugin.py +++ b/qiskit/transpiler/preset_passmanagers/plugin.py @@ -161,7 +161,7 @@ def pass_manager(self, pass_manager_config, optimization_level): PassManagerStagePlugin PassManagerStagePluginManager list_stage_plugins - entry_point_obj + passmanager_stage_plugins """ import abc @@ -312,12 +312,19 @@ def passmanager_stage_plugins(stage: str) -> Dict[str, PassManagerStagePlugin]: from qiskit.transpiler.preset_passmanagers.plugin import passmanager_stage_plugins routing_plugins = passmanager_stage_plugins('routing') basic_plugin = routing_plugins['basic'] - ?basic_plugin - - Type: BasicSwapPassManager - String form: <...builtin_plugins.BasicSwapPassManager object at 0xdeadbeef> - File: .../qiskit/transpiler/preset_passmanagers/builtin_plugins.py - Docstring: Plugin class for routing stage with :class:`~.BasicSwap` + help(basic_plugin) + + Help on BasicSwapPassManager in module ...preset_passmanagers.builtin_plugins object: + + class BasicSwapPassManager(...preset_passmanagers.plugin.PassManagerStagePlugin) + | Plugin class for routing stage with :class:`~.BasicSwap` + | + | Method resolution order: + | BasicSwapPassManager + | ...preset_passmanagers.plugin.PassManagerStagePlugin + | abc.ABC + | builtins.object + ... Args: stage: The stage name to get From 216a9b6f2b7ec9cafd4716a33b76492423d11b43 Mon Sep 17 00:00:00 2001 From: Jake Lishman Date: Tue, 18 Apr 2023 00:44:35 +0100 Subject: [PATCH 6/6] Fix docs build --- qiskit/transpiler/preset_passmanagers/plugin.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/qiskit/transpiler/preset_passmanagers/plugin.py b/qiskit/transpiler/preset_passmanagers/plugin.py index 7bac5c238a83..83d66ceae6a2 100644 --- a/qiskit/transpiler/preset_passmanagers/plugin.py +++ b/qiskit/transpiler/preset_passmanagers/plugin.py @@ -309,11 +309,15 @@ def passmanager_stage_plugins(stage: str) -> Dict[str, PassManagerStagePlugin]: This function is useful for getting more information about a plugin: + .. code-block:: python + from qiskit.transpiler.preset_passmanagers.plugin import passmanager_stage_plugins routing_plugins = passmanager_stage_plugins('routing') basic_plugin = routing_plugins['basic'] help(basic_plugin) + .. code-block:: text + Help on BasicSwapPassManager in module ...preset_passmanagers.builtin_plugins object: class BasicSwapPassManager(...preset_passmanagers.plugin.PassManagerStagePlugin)