Skip to main content
IBM Quantum Platform

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:

  1. Erstellen Sie eine Unterklasse der entsprechenden abstrakten Plugin-Klasse:
  2. Stellen Sie die Klasse als setuptools-Einstiegspunkt in den Paket-Metadaten zur Verfügung, indem Sie typischerweise die Datei pyproject.toml, setup.cfg oder setup.py fü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
Cliffordclifforddefault, ag, bm, greedy, layers, lnn
LinearFunctionlinear_functiondefault, kms, pmh
PermutationGatepermutationdefault, 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_pm

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 (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"

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_circuit

Wenn 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.

Anmerkung

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"

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:

  • target spezifiziert das Ziel-Backend, so dass das Plugin auf alle zielspezifischen Informationen zugreifen kann, wie z. B. die Kopplungskarte, das unterstützte Gate-Set usw
  • coupling_map gibt nur die Kopplungskarte an und wird nur verwendet, wenn target nicht angegeben ist.
  • qubits gibt 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 von None bedeutet, 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 None

Dieses 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"

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 dem name attribut 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.

Empfehlung
War diese Seite hilfreich?
Melden Sie auf GitHub einen Fehler, einen Tippfehler oder fordern Sie Inhalte an.