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

Adding HLS plugins for linear functions and cliffords #9399

Merged
merged 7 commits into from
Apr 5, 2023
Merged
Show file tree
Hide file tree
Changes from 6 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
144 changes: 135 additions & 9 deletions qiskit/transpiler/passes/synthesis/high_level_synthesis.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,25 @@


from qiskit.converters import circuit_to_dag
from qiskit.synthesis import synth_permutation_basic, synth_permutation_acg
from qiskit.transpiler.basepasses import TransformationPass
from qiskit.dagcircuit.dagcircuit import DAGCircuit
from qiskit.transpiler.exceptions import TranspilerError
from qiskit.synthesis import synth_clifford_full
from qiskit.synthesis.linear import synth_cnot_count_full_pmh
from qiskit.synthesis.permutation import synth_permutation_depth_lnn_kms

from qiskit.synthesis.clifford import (
synth_clifford_full,
synth_clifford_layers,
synth_clifford_depth_lnn,
synth_clifford_greedy,
synth_clifford_ag,
synth_clifford_bm,
)
from qiskit.synthesis.linear import synth_cnot_count_full_pmh, synth_cnot_depth_line_kms
from qiskit.synthesis.permutation import (
synth_permutation_basic,
synth_permutation_acg,
synth_permutation_depth_lnn_kms,
)

from .plugin import HighLevelSynthesisPluginManager, HighLevelSynthesisPlugin


Expand Down Expand Up @@ -189,16 +201,121 @@ def run(self, dag: DAGCircuit) -> DAGCircuit:


class DefaultSynthesisClifford(HighLevelSynthesisPlugin):
"""The default clifford synthesis plugin."""
"""The default clifford synthesis plugin.

For N <= 3 qubits this is the optimal CX cost decomposition by Bravyi, Maslov.
For N > 3 qubits this is done using the general non-optimal greedy compilation
routine from reference by Bravyi, Hu, Maslov, Shaydulin.

This plugin is called ``clifford.default`` in ``setup.py``.
"""

def run(self, high_level_object, **options):
"""Run synthesis for the given Clifford."""
decomposition = synth_clifford_full(high_level_object)
return decomposition


class AGSynthesisClifford(HighLevelSynthesisPlugin):
"""Clifford synthesis plugin based on the Aaronson-Gottesman method.

This plugin is called ``clifford.ag`` in ``setup.py``.
mtreinish marked this conversation as resolved.
Show resolved Hide resolved
"""

def run(self, high_level_object, **options):
"""Run synthesis for the given Clifford."""
decomposition = synth_clifford_ag(high_level_object)
return decomposition


class BMSynthesisClifford(HighLevelSynthesisPlugin):
"""Clifford synthesis plugin based on the Bravyi-Maslov method.
The plugin is named

The method only works on Cliffords with at most 3 qubits, for which it
constructs the optimal CX cost decomposition.

This plugin is called ``clifford.bm`` in ``setup.py``.
"""

def run(self, high_level_object, **options):
"""Run synthesis for the given Clifford."""
if high_level_object.num_qubits <= 3:
decomposition = synth_clifford_bm(high_level_object)
else:
decomposition = None
return decomposition


class GreedySynthesisClifford(HighLevelSynthesisPlugin):
"""Clifford synthesis plugin based on the greedy synthesis
Bravyi-Hu-Maslov-Shaydulin method.

This plugin is called ``clifford.greedy`` in ``setup.py``.
"""

def run(self, high_level_object, **options):
"""Run synthesis for the given Clifford."""
decomposition = synth_clifford_greedy(high_level_object)
return decomposition


class LayerSynthesisClifford(HighLevelSynthesisPlugin):
"""Clifford synthesis plugin based on the Bravyi-Maslov method
to synthesize Cliffords into layers.

This plugin is called ``clifford.layers`` in ``setup.py``.
"""

def run(self, high_level_object, **options):
"""Run synthesis for the given Clifford."""
decomposition = synth_clifford_layers(high_level_object)
return decomposition


class LayerLnnSynthesisClifford(HighLevelSynthesisPlugin):
"""Clifford synthesis plugin based on the Bravyi-Maslov method
to synthesize Cliffords into layers, with each layer synthesized
adhering to LNN connectivity.

This plugin is called ``clifford.lnn`` in ``setup.py``.
"""

def run(self, high_level_object, **options):
"""Run synthesis for the given Clifford."""
decomposition = synth_clifford_depth_lnn(high_level_object)
return decomposition


class DefaultSynthesisLinearFunction(HighLevelSynthesisPlugin):
"""The default linear function synthesis plugin."""
"""The default linear function synthesis plugin.

This plugin is called ``linear_function.default`` in ``setup.py``.
"""

def run(self, high_level_object, **options):
"""Run synthesis for the given LinearFunction."""
decomposition = synth_cnot_count_full_pmh(high_level_object.linear)
return decomposition


class KMSSynthesisLinearFunction(HighLevelSynthesisPlugin):
"""Linear function synthesis plugin based on the Kutin-Moulton-Smithline method.

This plugin is called ``linear_function.kms`` in ``setup.py``.
"""

def run(self, high_level_object, **options):
"""Run synthesis for the given LinearFunction."""
decomposition = synth_cnot_depth_line_kms(high_level_object.linear)
return decomposition


class PMHSynthesisLinearFunction(HighLevelSynthesisPlugin):
"""Linear function synthesis plugin based on the Patel-Markov-Hayes method.

This plugin is called ``linear_function.pmh`` in ``setup.py``.
"""

def run(self, high_level_object, **options):
"""Run synthesis for the given LinearFunction."""
Expand All @@ -207,7 +324,10 @@ def run(self, high_level_object, **options):


class KMSSynthesisPermutation(HighLevelSynthesisPlugin):
"""The permutation synthesis plugin based on the Kutin, Moulton, Smithline method."""
"""The permutation synthesis plugin based on the Kutin, Moulton, Smithline method.

This plugin is called ``permutation.kms`` in ``setup.py``.
"""

def run(self, high_level_object, **options):
"""Run synthesis for the given Permutation."""
Expand All @@ -216,7 +336,10 @@ def run(self, high_level_object, **options):


class BasicSynthesisPermutation(HighLevelSynthesisPlugin):
"""The permutation synthesis plugin based on sorting."""
"""The permutation synthesis plugin based on sorting.

This plugin is called ``permutation.basic`` in ``setup.py``.
"""

def run(self, high_level_object, **options):
"""Run synthesis for the given Permutation."""
Expand All @@ -225,7 +348,10 @@ def run(self, high_level_object, **options):


class ACGSynthesisPermutation(HighLevelSynthesisPlugin):
"""The permutation synthesis plugin based on the Alon, Chung, Graham method."""
"""The permutation synthesis plugin based on the Alon, Chung, Graham method.

This plugin is called ``permutation.acg`` in ``setup.py``.
"""

def run(self, high_level_object, **options):
"""Run synthesis for the given Permutation."""
Expand Down
75 changes: 75 additions & 0 deletions releasenotes/notes/add-hls-plugins-038388970ad43c55.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
---
features:
- |
Added high-level-synthesis plugins for :class:`.LinearFunction` and for
:class:`qiskit.quantum_info.Clifford`, extending the set of synthesis
methods that can be called from :class:`~qiskit.transpiler.passes.HighLevelSynthesis`
transpiler pass.

For :class:`.LinearFunction` the available plugins are listed below:

.. list-table::
:header-rows: 1

* - Plugin name
- High-level synthesis plugin
* - ``default``
- :class:`.DefaultSynthesisLinearFunction`
* - ``kms``
- :class:`.KMSSynthesisLinearFunction`
* - ``pmh``
- :class:`.PMHSynthesisLinearFunction`

For :class:`qiskit.quantum_info.Clifford` the available plugins are listed below:

.. list-table::
:header-rows: 1

* - Plugin name
- High-level synthesis plugin
* - ``default``
- :class:`.DefaultSynthesisClifford`
* - ``ag``
- :class:`.AGSynthesisClifford`
* - ``bm``
- :class:`.BMSynthesisClifford`
* - ``greedy``
- :class:`.GreedySynthesisClifford`
* - ``layers``
- :class:`.LayerSynthesisClifford`
* - ``lnn``
- :class:`.LayerLnnSynthesisClifford`

Please refer to :mod:`qiskit.synthesis` documentation for more information
about each individual method.

The following example illustrates some of the new plugins::

from qiskit.circuit import QuantumCircuit
from qiskit.circuit.library import LinearFunction
from qiskit.quantum_info import Clifford
from qiskit.transpiler.passes.synthesis.high_level_synthesis import HLSConfig, HighLevelSynthesis

# Create a quantum circuit with one linear function and one clifford
qc1 = QuantumCircuit(3)
qc1.cx(0, 1)
qc1.swap(0, 2)
lin_fun = LinearFunction(qc1)

qc2 = QuantumCircuit(3)
qc2.h(0)
qc2.cx(0, 2)
cliff = Clifford(qc2)

qc = QuantumCircuit(4)
qc.append(lin_fun, [0, 1, 2])
qc.append(cliff, [1, 2, 3])

# Choose synthesis methods that adhere to linear-nearest-neighbour connectivity
hls_config = HLSConfig(linear_function=["kms"], clifford=["lnn"])

# Synthesize
qct = HighLevelSynthesis(hls_config)(qc)
print(qct.decompose())


7 changes: 7 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,14 @@
],
"qiskit.synthesis": [
"clifford.default = qiskit.transpiler.passes.synthesis.high_level_synthesis:DefaultSynthesisClifford",
"clifford.ag = qiskit.transpiler.passes.synthesis.high_level_synthesis:AGSynthesisClifford",
"clifford.bm = qiskit.transpiler.passes.synthesis.high_level_synthesis:BMSynthesisClifford",
"clifford.greedy = qiskit.transpiler.passes.synthesis.high_level_synthesis:GreedySynthesisClifford",
"clifford.layers = qiskit.transpiler.passes.synthesis.high_level_synthesis:LayerSynthesisClifford",
"clifford.lnn = qiskit.transpiler.passes.synthesis.high_level_synthesis:LayerLnnSynthesisClifford",
"linear_function.default = qiskit.transpiler.passes.synthesis.high_level_synthesis:DefaultSynthesisLinearFunction",
"linear_function.kms = qiskit.transpiler.passes.synthesis.high_level_synthesis:KMSSynthesisLinearFunction",
"linear_function.pmh = qiskit.transpiler.passes.synthesis.high_level_synthesis:PMHSynthesisLinearFunction",
"permutation.default = qiskit.transpiler.passes.synthesis.high_level_synthesis:BasicSynthesisPermutation",
"permutation.kms = qiskit.transpiler.passes.synthesis.high_level_synthesis:KMSSynthesisPermutation",
"permutation.basic = qiskit.transpiler.passes.synthesis.high_level_synthesis:BasicSynthesisPermutation",
Expand Down