Erstellen Sie ein Transpiler-Plugin
Der Code auf dieser Seite wurde unter Berücksichtigung der folgenden Anforderungen entwickelt. Wir empfehlen die Verwendung dieser oder neuerer Versionen.
qiskit[all]~=2.5.2
Die Erstellung eines Transpiler-Plugins ist eine gute Möglichkeit, Ihren Transpilationscode mit der breiteren Qiskit-Gemeinschaft zu teilen, so dass andere Benutzer von der von Ihnen entwickelten Funktionalität profitieren können. Vielen Dank für Ihr Interesse, zur Qiskit-Gemeinschaft beizutragen!
Bevor Sie ein Transpiler-Plugin erstellen, müssen Sie entscheiden, welche Art von Plugin für Ihre Situation geeignet ist. Es gibt drei Arten von Transpiler-Plugins:
- Transpiler-Stufen-Plugin. Wählen Sie diese Option, wenn Sie einen Passmanager definieren, der eine der 6 Stufen eines voreingestellten gestaffelten Passmanagers ersetzen kann.
- Unitarisches Synthese-Plugin. Wählen Sie dies, wenn Ihr Transpilationscode als Eingabe eine unitäre Matrix (dargestellt als Numpy-Array) erhält und eine Beschreibung einer Quantenschaltung ausgibt, die diese unitäre Matrix implementiert.
- High-Level-Synthese-Plugin. Wählen Sie diese Option, wenn Ihr Transpilationscode ein "High-Level-Objekt" wie einen Clifford-Operator oder eine lineare Funktion als Eingabe erhält und eine Beschreibung einer Quantenschaltung ausgibt, die dieses High-Level-Objekt implementiert. Objekte der höheren Ebene werden durch Unterklassen der Klasse Operation dargestellt.
Wenn Sie sich entschieden haben, welche Art von Plugin Sie erstellen möchten, folgen Sie diesen Schritten, um das Plugin zu erstellen:
- Erstellen Sie eine Unterklasse der entsprechenden abstrakten Plugin-Klasse:
- PassManagerStagePlugin für ein Transpiler-Stage-Plugin,
- UnitarySynthesisPlugin für ein unitäres Synthese-Plugin, und
- HighLevelSynthesisPlugin für ein High-Level-Synthese-Plugin.
- Stellen Sie die Klasse als setuptools-Einstiegspunkt in den Paket-Metadaten zur Verfügung, indem Sie typischerweise die Datei
pyproject.toml,setup.cfgodersetup.pyfür Ihr Python -Paket bearbeiten.
Es gibt keine Begrenzung für die Anzahl der Plugins, die ein einzelnes Paket definieren kann, aber jedes Plugin muss einen eindeutigen Namen haben. Das Qiskit SDK selbst enthält eine Reihe von Plugins, deren Namen ebenfalls reserviert sind. Die reservierten Namen sind:
- Transpiler-Stufen-Plugins: Siehe diese Tabelle.
- Unitäre Synthese-Plugins:
default,aqc,sk - High-Level-Synthese-Plugins:
Betriebsklasse | Operationsname | Reservierte Namen |
|---|---|---|
| Clifford | clifford | default, ag, bm, greedy, layers, lnn |
| LinearFunction | linear_function | default, kms, pmh |
| PermutationGate | permutation | default, kms, basic, acg, token_swapper |
In den nächsten Abschnitten zeigen wir Beispiele für diese Schritte für die verschiedenen Arten von Plugins. In diesen Beispielen gehen wir davon aus, dass wir ein Python Paket namens my_qiskit_plugin erstellen. Informationen zur Erstellung von Python Paketen finden Sie in dieser Anleitung auf der Website Python.
Beispiel: Erstellen Sie ein Transpiler-Stage-Plugin
In diesem Beispiel erstellen wir ein Transpilerstufen-Plugin für die Stufe layout (siehe Transpilerstufen für eine Beschreibung der 6 Stufen der in Qiskit integrierten Transpilierungspipeline).
Unser Plugin läuft einfach VF2Layout für eine Anzahl von Versuchen, die von der gewünschten Optimierungsstufe abhängt.
Zunächst erstellen wir eine Unterklasse von PassManagerStagePlugin. Es gibt eine Methode, die wir implementieren müssen, sie heißt pass_manager. Diese Methode nimmt als Eingabe ein PassManagerConfig und gibt den von uns definierten Passmanager zurück. Das PassManagerConfig Objekt speichert Informationen über das Ziel-Backend, wie z.B. seine Kopplungskarte und Basis-Gates.
# This import is needed for python versions prior to 3.10
from __future__ import annotations
from qiskit.transpiler import PassManager
from qiskit.transpiler.passes import VF2Layout
from qiskit.transpiler.passmanager_config import PassManagerConfig
from qiskit.transpiler.preset_passmanagers import common
from qiskit.transpiler.preset_passmanagers.plugin import (
PassManagerStagePlugin,
)
class MyLayoutPlugin(PassManagerStagePlugin):
def pass_manager(
self,
pass_manager_config: PassManagerConfig,
optimization_level: int | None = None,
) -> PassManager:
layout_pm = PassManager(
[
VF2Layout(
coupling_map=pass_manager_config.coupling_map,
properties=pass_manager_config.backend_properties,
max_trials=optimization_level * 10 + 1,
target=pass_manager_config.target,
)
]
)
layout_pm += common.generate_embed_passmanager(
pass_manager_config.coupling_map
)
return layout_pmJetzt machen wir das Plugin bekannt, indem wir einen Eintragspunkt in den Metadaten unseres Python -Pakets hinzufügen.
Hier nehmen wir an, dass die Klasse, die wir definiert haben, in einem Modul namens my_qiskit_plugin exponiert ist, z. B. indem sie in der Datei __init__.py des Moduls my_qiskit_plugin importiert wird.
Wir bearbeiten die Datei pyproject.toml, setup.cfg oder setup.py unseres Pakets (je nachdem, welche Art von Datei Sie für die Speicherung Ihrer Python Projekt-Metadaten gewählt haben):
[project.entry-points."qiskit.transpiler.layout"]
"my_layout" = "my_qiskit_plugin:MyLayoutPlugin"[options.entry_points]
qiskit.transpiler.layout =
my_layout = my_qiskit_plugin:MyLayoutPluginfrom setuptools import setup
setup(
# ...,
entry_points={
'qiskit.transpiler.layout': [
'my_layout = my_qiskit_plugin:MyLayoutPlugin',
]
}
)In der Tabelle der Transpiler-Plugin-Stufen finden Sie die Einstiegspunkte und Erwartungen für jede Transpiler-Stufe.
Um zu überprüfen, ob Ihr Plugin erfolgreich von Qiskit erkannt wird, installieren Sie Ihr Plugin-Paket und folgen Sie den Anweisungen unter Transpiler-Plugins für die Auflistung der installierten Plugins und stellen Sie sicher, dass Ihr Plugin in der Liste erscheint:
from qiskit.transpiler.preset_passmanagers.plugin import list_stage_plugins
list_stage_plugins("layout")Output:
['default', 'dense', 'sabre', 'trivial']
Wenn unser Beispiel-Plugin installiert wäre, würde der Name my_layout in dieser Liste erscheinen.
Wenn Sie eine eingebaute Transpilerstufe als Ausgangspunkt für Ihr Transpilerstufen-Plugin verwenden möchten, können Sie den Passmanager für eine eingebaute Transpilerstufe mit PassManagerStagePluginManager. Die folgende Code-Zelle zeigt, wie man dies tut, um die eingebaute Optimierungsstufe für Optimierungsstufe 3 zu erhalten.
from qiskit.transpiler.preset_passmanagers.plugin import (
PassManagerStagePluginManager,
)
# Initialize the plugin manager
plugin_manager = PassManagerStagePluginManager()
# Here we create a pass manager config to use as an example.
# Instead, you should use the pass manager config that you already received as input
# to the pass_manager method of your PassManagerStagePlugin.
pass_manager_config = PassManagerConfig()
# Obtain the desired built-in transpiler stage
optimization = plugin_manager.get_passmanager_stage(
"optimization", "default", pass_manager_config, optimization_level=3
)Beispiel: Erstellen Sie ein einheitliches Synthese-Plugin
In diesem Beispiel erstellen wir ein unitäres Synthese-Plugin, das einfach den eingebauten UnitarySynthesis transpilationspassus verwendet, um ein Gatter zu synthetisieren. Natürlich wird Ihr eigenes Plugin etwas Interessanteres tun als das.
Die Klasse UnitarySynthesisPlugin klasse definiert die Schnittstelle und den Vertrag für unitäre Synthese plugins. Die wichtigste Methode ist run, die als Eingabe ein Numpy-Array zur Speicherung einer unitären Matrix speichert und einen DAGCircuit zurückgibt, der die aus dieser unitären Matrix synthetisierte Schaltung darstellt.
Neben der Methode run gibt es noch eine Reihe von Eigenschaftsmethoden, die definiert werden müssen.
Siehe UnitarySynthesisPlugin finden Sie eine Dokumentation aller erforderlichen Eigenschaften.
Lassen Sie uns unsere Unterklasse UnitarySynthesisPlugin erstellen:
import numpy as np
from qiskit.circuit import QuantumCircuit, QuantumRegister
from qiskit.converters import circuit_to_dag
from qiskit.dagcircuit.dagcircuit import DAGCircuit
from qiskit.quantum_info import Operator
from qiskit.transpiler.passes import UnitarySynthesis
from qiskit.transpiler.passes.synthesis.plugin import UnitarySynthesisPlugin
class MyUnitarySynthesisPlugin(UnitarySynthesisPlugin):
@property
def supports_basis_gates(self):
# Returns True if the plugin can target a list of basis gates
return True
@property
def supports_coupling_map(self):
# Returns True if the plugin can synthesize for a given coupling map
return False
@property
def supports_natural_direction(self):
# Returns True if the plugin supports a toggle for considering
# directionality of 2-qubit gates
return False
@property
def supports_pulse_optimize(self):
# Returns True if the plugin can optimize pulses during synthesis
return False
@property
def supports_gate_lengths(self):
# Returns True if the plugin can accept information about gate lengths
return False
@property
def supports_gate_errors(self):
# Returns True if the plugin can accept information about gate errors
return False
@property
def supports_gate_lengths_by_qubit(self):
# Returns True if the plugin can accept information about gate lengths
# (The format of the input differs from supports_gate_lengths)
return False
@property
def supports_gate_errors_by_qubit(self):
# Returns True if the plugin can accept information about gate errors
# (The format of the input differs from supports_gate_errors)
return False
@property
def min_qubits(self):
# Returns the minimum number of qubits the plugin supports
return None
@property
def max_qubits(self):
# Returns the maximum number of qubits the plugin supports
return None
@property
def supported_bases(self):
# Returns a dictionary of supported bases for synthesis
return None
def run(self, unitary: np.ndarray, **options) -> DAGCircuit:
basis_gates = options["basis_gates"]
synth_pass = UnitarySynthesis(basis_gates, min_qubits=3)
qubits = QuantumRegister(3)
circuit = QuantumCircuit(qubits)
circuit.append(Operator(unitary).to_instruction(), qubits)
dag_circuit = synth_pass.run(circuit_to_dag(circuit))
return dag_circuitWenn Sie feststellen, dass die verfügbaren Eingänge für run Methode für Ihre Zwecke nicht ausreichen, öffnen Sie bitte ein Problem und erläutern Sie Ihre Anforderungen. Änderungen an der Plugin-Schnittstelle, wie z. B. das Hinzufügen zusätzlicher optionaler Eingaben, werden abwärtskompatibel vorgenommen, so dass sie keine Änderungen an bestehenden Plugins erfordern.
Alle Methoden mit dem Präfix supports_ sind für eine abgeleitete Klasse UnitarySynthesisPlugin als Teil der Schnittstelle reserviert. Sie sollten keine benutzerdefinierten supports_* Methoden in einer Unterklasse definieren, die nicht in der abstrakten Klasse definiert sind.
Jetzt machen wir das Plugin bekannt, indem wir einen Eintragspunkt in den Metadaten unseres Python -Pakets hinzufügen.
Hier nehmen wir an, dass die Klasse, die wir definiert haben, in einem Modul namens my_qiskit_plugin exponiert ist, z. B. indem sie in der Datei __init__.py des Moduls my_qiskit_plugin importiert wird.
Wir bearbeiten die Datei pyproject.toml, setup.cfg, oder setup.py unseres Pakets:
[project.entry-points."qiskit.unitary_synthesis"]
"my_unitary_synthesis" = "my_qiskit_plugin:MyUnitarySynthesisPlugin"[options.entry_points]
qiskit.unitary_synthesis =
my_unitary_synthesis = my_qiskit_plugin:MyUnitarySynthesisPluginfrom setuptools import setup
setup(
# ...,
entry_points={
'qiskit.unitary_synthesis': [
'my_unitary_synthesis = my_qiskit_plugin:MyUnitarySynthesisPlugin',
]
}
)Wenn Ihr Projekt setup.cfg oder setup.py anstelle von pyproject.toml verwendet, lesen Sie in der setuptools-Dokumentation nach, wie Sie diese Zeilen für Ihre Situation anpassen können.
Um zu überprüfen, ob Ihr Plugin erfolgreich von Qiskit erkannt wird, installieren Sie Ihr Plugin-Paket und folgen Sie den Anweisungen unter Transpiler-Plugins für die Auflistung der installierten Plugins und stellen Sie sicher, dass Ihr Plugin in der Liste erscheint:
from qiskit.transpiler.passes.synthesis import unitary_synthesis_plugin_names
unitary_synthesis_plugin_names()Output:
['aqc', 'clifford', 'default', 'gridsynth', 'sk']
Wenn unser Beispiel-Plugin installiert wäre, würde der Name my_unitary_synthesis in dieser Liste erscheinen.
Um einheitliche Synthese-Plugins zu ermöglichen, die mehrere Optionen bereitstellen, hat die Plugin-Schnittstelle eine Option, mit der die Benutzer ein Freiform konfigurationswörterbuch bereitzustellen. Dieser wird an die Methode run übergeben über das Schlüsselwortargument options übergeben. Wenn Ihr Plugin über diese Konfigurationsoptionen verfügt, sollten Sie sie klar dokumentieren.
Beispiel: Erstellen Sie ein Plugin für die High-Level-Synthese
In diesem Beispiel werden wir ein High-Level-Synthese-Plugin erstellen, das einfach die eingebaute Funktion synth_clifford_bm verwendet, um einen Clifford-Operator zu synthetisieren.
Die Klasse HighLevelSynthesisPlugin klasse definiert die Schnittstelle und den Vertrag für High-Level-Synthese-Plugins. Die wichtigste Methode ist run.
Das Positionsargument high_level_object ist eine Operation, die das zu synthetisierende "High-Level"-Objekt darstellt. Es könnte sich zum Beispiel um eine LinearFunction oder ein Clifford.
Die folgenden Schlüsselwortargumente sind vorhanden:
targetspezifiziert das Ziel-Backend, so dass das Plugin auf alle zielspezifischen Informationen zugreifen kann, wie z. B. die Kopplungskarte, das unterstützte Gate-Set uswcoupling_mapgibt nur die Kopplungskarte an und wird nur verwendet, wenntargetnicht angegeben ist.qubitsgibt die Liste der Qubits an, über die das high-Level-Objekt definiert ist, falls die Synthese auf der physischen Schaltung durchgeführt wird. Ein Wert vonNonebedeutet, dass das Layout noch nicht ausgewählt wurde und die physikalischen Qubits in der Ziel- oder Kopplungskarte, auf der diese Operation ausgeführt wird, noch nicht bestimmt wurden.options, ein freies Konfigurationswörterbuch für Plugin-spezifische Optionen. Wenn Ihr Plugin diese Konfigurationsoptionen hat, sollten Sie sollten Sie diese klar dokumentieren.
Die Methode run gibt eine QuantumCircuit zurück, das die aus diesem High-Level-Objekt synthetisierte Schaltung darstellt.
Es ist auch erlaubt, None zurückzugeben, was bedeutet, dass das Plugin nicht in der Lage ist, das angegebene High-Level-Objekt zu synthetisieren.
Die eigentliche Synthese von High-Level-Objekten wird von der HighLevelSynthesis transpiler-Durchgang.
Neben der Methode run gibt es noch eine Reihe von Eigenschaftsmethoden, die definiert werden müssen.
Siehe HighLevelSynthesisPlugin finden Sie eine Dokumentation aller erforderlichen Eigenschaften.
Definieren wir unsere Unterklasse HighLevelSynthesisPlugin :
from qiskit.synthesis import synth_clifford_bm
from qiskit.transpiler.passes.synthesis.plugin import HighLevelSynthesisPlugin
class MyCliffordSynthesisPlugin(HighLevelSynthesisPlugin):
def run(
self,
high_level_object,
coupling_map=None,
target=None,
qubits=None,
**options,
) -> QuantumCircuit:
if high_level_object.num_qubits <= 3:
return synth_clifford_bm(high_level_object)
else:
return NoneDieses Plugin synthetisiert Objekte vom Typ Clifford, die höchstens 3 Qubits haben, unter Verwendung der Methode synth_clifford_bm .
Jetzt machen wir das Plugin bekannt, indem wir einen Eintragspunkt in den Metadaten unseres Python -Pakets hinzufügen.
Hier nehmen wir an, dass die Klasse, die wir definiert haben, in einem Modul namens my_qiskit_plugin exponiert ist, z. B. indem sie in der Datei __init__.py des Moduls my_qiskit_plugin importiert wird.
Wir bearbeiten die Datei pyproject.toml, setup.cfg, oder setup.py unseres Pakets:
[project.entry-points."qiskit.synthesis"]
"clifford.my_clifford_synthesis" = "my_qiskit_plugin:MyCliffordSynthesisPlugin"[options.entry_points]
qiskit.synthesis =
clifford.my_clifford_synthesis = my_qiskit_plugin:MyCliffordSynthesisPluginfrom setuptools import setup
setup(
# ...,
entry_points={
'qiskit.synthesis': [
'clifford.my_clifford_synthesis = my_qiskit_plugin:MyCliffordSynthesisPlugin',
]
}
)Die Website name besteht aus zwei Teilen, die durch einen Punkt getrennt sind (.):
- Der Name des Typs der Operation, die das Plugin synthetisiert (in diesem Fall
clifford). Beachten Sie, dass diese Zeichenkette mit demnameattribut der Klasse Operation entspricht, und nicht dem Namen der Klasse selbst. - Der Name des Plugins (in diesem Fall:
special).
Wenn Ihr Projekt setup.cfg oder setup.py anstelle von pyproject.toml verwendet, lesen Sie in der setuptools-Dokumentation nach, wie Sie diese Zeilen für Ihre Situation anpassen können.
Um zu überprüfen, ob Ihr Plugin erfolgreich von Qiskit erkannt wird, installieren Sie Ihr Plugin-Paket und folgen Sie den Anweisungen unter Transpiler-Plugins für die Auflistung der installierten Plugins und stellen Sie sicher, dass Ihr Plugin in der Liste erscheint:
from qiskit.transpiler.passes.synthesis import (
high_level_synthesis_plugin_names,
)
high_level_synthesis_plugin_names("clifford")Output:
['rb_default', 'ag', 'bm', 'default', 'greedy', 'layers', 'lnn']
Wenn unser Beispiel-Plugin installiert wäre, würde der Name my_clifford_synthesis in dieser Liste erscheinen.
- Senden Sie Ihr Plugin an das Qiskit Ecosystem!
- In den Tutorien finden Sie Beispiele für die Transpilierung und den Betrieb von Quantenschaltungen.