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

Document how to use high level synthesis plugins #11389

Merged
merged 8 commits into from
Dec 15, 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
2 changes: 2 additions & 0 deletions qiskit/transpiler/passes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@
LinearFunctionsSynthesis
LinearFunctionsToPermutations
HighLevelSynthesis
HLSConfig
SolovayKitaev
SolovayKitaevSynthesis

Expand Down Expand Up @@ -253,6 +254,7 @@
from .synthesis import LinearFunctionsSynthesis
from .synthesis import LinearFunctionsToPermutations
from .synthesis import HighLevelSynthesis
from .synthesis import HLSConfig
from .synthesis import SolovayKitaev
from .synthesis import SolovayKitaevSynthesis

Expand Down
37 changes: 23 additions & 14 deletions qiskit/transpiler/passes/synthesis/high_level_synthesis.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,23 @@
class HLSConfig:
"""The high-level-synthesis config allows to specify a list of "methods" used by
:class:`~.HighLevelSynthesis` transformation pass to synthesize different types
of higher-level-objects. A higher-level object is an object of type
:class:`~.Operation` (e.g., "clifford", "linear_function", etc.), and the list
of applicable synthesis methods is strictly tied to the name of the operation.
In the config, each method is specified as a tuple consisting of the name of the
synthesis algorithm and of a dictionary providing additional arguments for this
algorithm. Additionally, a synthesis method can be specified as a tuple consisting
of an instance of :class:`.HighLevelSynthesisPlugin` and additional arguments.
Moreover, when there are no additional arguments, a synthesis
method can be specified simply by name or by an instance
of :class:`.HighLevelSynthesisPlugin`. The following example illustrates different
ways how a config file can be created::
of higher-level objects.

A higher-level object is an object of type :class:`~.Operation` (e.g., :class:`.Clifford` or
:class:`.LinearFunction`). Each object is referred to by its :attr:`~.Operation.name` field
(e.g., ``"clifford"`` for :class:`.Clifford` objects), and the applicable synthesis methods are
tied to this name.

In the config, each method is specified in one of several ways:

1. a tuple consisting of the name of a known synthesis plugin and a dictionary providing
additional arguments for the algorithm.
2. a tuple consisting of an instance of :class:`.HighLevelSynthesisPlugin` and additional
arguments for the algorithm.
3. a single string of a known synthesis plugin
4. a single instance of :class:`.HighLevelSynthesisPlugin`.

The following example illustrates different ways how a config file can be created::

from qiskit.transpiler.passes.synthesis.high_level_synthesis import HLSConfig
from qiskit.transpiler.passes.synthesis.high_level_synthesis import ACGSynthesisPermutation
Expand All @@ -74,7 +80,7 @@ class HLSConfig:
hls_config = HLSConfig(permutation=[(ACGSynthesisPermutation(), {})])
hls_config = HLSConfig(permutation=[ACGSynthesisPermutation()])

The names of the synthesis algorithms should be declared in ``entry-points`` table for
The names of the synthesis plugins should be declared in ``entry-points`` table for
``qiskit.synthesis`` in ``pyproject.toml``, in the form
<higher-level-object-name>.<synthesis-method-name>.

Expand All @@ -84,8 +90,11 @@ class HLSConfig:

To avoid synthesizing a given higher-level-object, one can give it an empty list of methods.

For an explicit example of using such config files, refer to the
documentation for :class:`~.HighLevelSynthesis`.
For an explicit example of using such config files, refer to the documentation for
:class:`~.HighLevelSynthesis`.

For an overview of the complete process of using high-level synthesis, see
:ref:`using-high-level-synthesis-plugins`.
"""

def __init__(self, use_default_on_unspecified=True, **kwargs):
Expand Down
62 changes: 62 additions & 0 deletions qiskit/transpiler/passes/synthesis/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,9 @@ def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **
Using Plugins
=============

Unitary Synthesis Plugins
-------------------------

To use a plugin all you need to do is install the package that includes a
synthesis plugin. Then Qiskit will automatically discover the installed
plugins and expose them as valid options for the appropriate
Expand All @@ -243,6 +246,44 @@ def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **
:func:`qiskit.transpiler.passes.synthesis.plugin.unitary_synthesis_plugin_names`
function.

.. _using-high-level-synthesis-plugins:

High-level Synthesis Plugins
----------------------------

To use a high-level synthesis plugin, you first instantiate an :class:`.HLSConfig` to
store the names of the plugins to use for various high-level objects.
For example::

HLSConfig(permutation=["acg"], clifford=["layers"], linear_function=["pmh"])
kevinsung marked this conversation as resolved.
Show resolved Hide resolved

creates a high-level synthesis configuration that uses the ``acg`` plugin
for synthesizing :class:`.PermutationGate` objects, the ``layers`` plugin
for synthesizing :class:`.Clifford` objects, and the ``pmh`` plugin for synthesizing
:class:`.LinearFunction` objects. The keyword arguments are the :attr:`.Operation.name` fields of
the relevant objects. For example, all :class:`.Clifford` operations have the
:attr:`~.Operation.name` ``clifford``, so this is used as the keyword argument. You can specify
any keyword argument here that you have installed plugins to handle, including custom user objects
if you have plugins installed for them. See :class:`.HLSConfig` for more detail on alternate
formats for configuring the plugins within each argument.

For each high-level object, the list of given plugins are tried in sequence until one of them
succeeds (in the example above, each list only contains a single plugin). In addition to specifying
a plugin by its name, you can instead pass a ``(name, options)`` tuple, where the second element of
the tuple is a dictionary containing options for the plugin.

Once created you then pass this :class:`.HLSConfig` object into the
``hls_config`` argument for :func:`.transpile` or :func:`.generate_preset_pass_manager`
which will use the specified plugins as part of the larger compilation workflow.

To get a list of installed high level synthesis plugins for any given :attr:`.Operation.name`, you
can use the :func:`.high_level_synthesis_plugin_names` function, passing the desired ``name`` as the
argument::

high_level_synthesis_plugin_names("clifford")

will return a list of all the installed Clifford synthesis plugins.

Plugin API
==========

Expand All @@ -264,10 +305,12 @@ def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **

HighLevelSynthesisPlugin
HighLevelSynthesisPluginManager
high_level_synthesis_plugin_names

"""

import abc
from typing import List

import stevedore

Expand Down Expand Up @@ -595,3 +638,22 @@ def method(self, op_name, method_name):
"""Returns the plugin for ``op_name`` and ``method_name``."""
plugin_name = op_name + "." + method_name
return self.plugins[plugin_name].obj


def high_level_synthesis_plugin_names(op_name: str) -> List[str]:
"""Return a list of plugin names installed for a given high level object name

Args:
op_name: The operation name to find the installed plugins for. For example,
if you provide ``"clifford"`` as the input it will find all the installed
clifford synthesis plugins that can synthesize :class:`.Clifford` objects.
The name refers to the :attr:`.Operation.name` attribute of the relevant objects.

Returns:
A list of installed plugin names for the specified high level operation

"""
# NOTE: This is not a shared global instance to avoid an import cycle
# at load time for the default plugins.
plugin_manager = HighLevelSynthesisPluginManager()
return plugin_manager.method_names(op_name)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
features:
- |
Added a new function, :func:`.high_level_synthesis_plugin_names` that is
used to get the list of installed high level synthesis plugins for a given
operation name.