diff --git a/qiskit/transpiler/passes/synthesis/high_level_synthesis.py b/qiskit/transpiler/passes/synthesis/high_level_synthesis.py index 34bccf3279fe..c3b56c3bc7cc 100644 --- a/qiskit/transpiler/passes/synthesis/high_level_synthesis.py +++ b/qiskit/transpiler/passes/synthesis/high_level_synthesis.py @@ -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 @@ -189,7 +201,15 @@ 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 name is :``clifford.default`` which can be used as the key on + an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. + """ def run(self, high_level_object, **options): """Run synthesis for the given Clifford.""" @@ -197,8 +217,114 @@ def run(self, high_level_object, **options): return decomposition +class AGSynthesisClifford(HighLevelSynthesisPlugin): + """Clifford synthesis plugin based on the Aaronson-Gottesman method. + + This plugin name is :``clifford.ag`` which can be used as the key on + an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. + """ + + 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 name is :``clifford.bm`` which can be used as the key on + an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. + """ + + 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 name is :``clifford.greedy`` which can be used as the key on + an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. + """ + + 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 name is :``clifford.layers`` which can be used as the key on + an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. + """ + + 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 name is :``clifford.lnn`` which can be used as the key on + an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. + """ + + 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 name is :``linear_function.default`` which can be used as the key on + an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. + """ + + 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 name is :``linear_function.kms`` which can be used as the key on + an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. + """ + + 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 name is :``linear_function.pmh`` which can be used as the key on + an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. + """ def run(self, high_level_object, **options): """Run synthesis for the given LinearFunction.""" @@ -207,7 +333,11 @@ 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 name is :``permutation.kms`` which can be used as the key on + an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. + """ def run(self, high_level_object, **options): """Run synthesis for the given Permutation.""" @@ -216,7 +346,11 @@ 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 name is :``permutation.basic`` which can be used as the key on + an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. + """ def run(self, high_level_object, **options): """Run synthesis for the given Permutation.""" @@ -225,7 +359,11 @@ 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 name is :``permutation.acg`` which can be used as the key on + an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`. + """ def run(self, high_level_object, **options): """Run synthesis for the given Permutation.""" diff --git a/releasenotes/notes/add-hls-plugins-038388970ad43c55.yaml b/releasenotes/notes/add-hls-plugins-038388970ad43c55.yaml new file mode 100644 index 000000000000..ea98eddd2d68 --- /dev/null +++ b/releasenotes/notes/add-hls-plugins-038388970ad43c55.yaml @@ -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()) + + diff --git a/setup.py b/setup.py index 5adeeb9fa2ea..1025480078f7 100755 --- a/setup.py +++ b/setup.py @@ -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",