Zum Hauptinhalt springen

Quantencomputer für den Transpiler darstellen

Paketversionen

Der Code auf dieser Seite wurde mit den folgenden Anforderungen entwickelt. Wir empfehlen, diese Versionen oder neuere zu verwenden.

qiskit[all]~=2.3.0
qiskit-ibm-runtime~=0.43.1

Um einen abstrakten Circuit in einen ISA-Circuit umzuwandeln, der auf einem bestimmten QPU (Quantenprozessor) laufen kann, benötigt der Transpiler bestimmte Informationen über den QPU. Diese Informationen befinden sich an zwei Stellen: im BackendV2-Objekt (oder dem älteren BackendV1), an das du Jobs übermitteln möchtest, sowie im Target-Attribut des Backends.

  • Das Target enthält alle relevanten Einschränkungen eines Geräts, wie z. B. seine nativen Basis-Gates, die Qubit-Konnektivität sowie Puls- oder Timing-Informationen.
  • Das Backend besitzt standardmäßig ein Target, enthält zusätzliche Informationen — wie die InstructionScheduleMap — und stellt die Schnittstelle zur Übermittlung von Quantum-Circuit-Jobs bereit.

Du kannst dem Transpiler auch explizit Informationen zur Verfügung stellen, zum Beispiel wenn du einen speziellen Anwendungsfall hast oder wenn du glaubst, dass diese Informationen dem Transpiler helfen, einen besser optimierten Circuit zu erzeugen.

Die Genauigkeit, mit der der Transpiler den am besten geeigneten Circuit für bestimmte Hardware erzeugt, hängt davon ab, wie viele Informationen das Target oder das Backend über seine Einschränkungen enthält.

hinweis

Da viele der zugrunde liegenden Transpilationsalgorithmen stochastisch sind, gibt es keine Garantie, dass ein besserer Circuit gefunden wird.

Diese Seite zeigt mehrere Beispiele für die Übergabe von QPU-Informationen an den Transpiler. Diese Beispiele verwenden das Target des Mock-Backends FakeSherbrooke.

Standardkonfiguration

Die einfachste Verwendung des Transpilers besteht darin, alle QPU-Informationen durch Angabe des Backend oder Target bereitzustellen. Um besser zu verstehen, wie der Transpiler funktioniert, erstelle einen Circuit und transpiliere ihn mit verschiedenen Informationen, wie folgt.

Importiere die notwendigen Bibliotheken und instanziiere den QPU: Um einen abstrakten Circuit in einen ISA-Circuit umzuwandeln, der auf einem bestimmten Prozessor laufen kann, benötigt der Transpiler bestimmte Informationen über den Prozessor. Typischerweise sind diese Informationen im Backend oder Target gespeichert, der/das dem Transpiler übergeben wird, und es werden keine weiteren Informationen benötigt. Du kannst dem Transpiler aber auch explizit Informationen zur Verfügung stellen, zum Beispiel wenn du einen speziellen Anwendungsfall hast oder wenn du glaubst, dass diese Informationen dem Transpiler helfen, einen besser optimierten Circuit zu erzeugen.

Dieses Thema zeigt mehrere Beispiele für die Übergabe von Informationen an den Transpiler. Diese Beispiele verwenden das Target des Mock-Backends FakeSherbrooke.

# Added by doQumentation — required packages for this notebook
!pip install -q qiskit qiskit-ibm-runtime
from qiskit_ibm_runtime.fake_provider import FakeSherbrooke

backend = FakeSherbrooke()
target = backend.target

Der Beispiel-Circuit verwendet eine Instanz von efficient_su2 aus Qiskits Circuit-Bibliothek.

from qiskit.circuit.library import efficient_su2

qc = efficient_su2(12, entanglement="circular", reps=1)

qc.draw("mpl")

Ausgabe der vorherigen Code-Zelle

Dieses Beispiel verwendet Standardeinstellungen zum Transpilieren auf das target des backend, das alle Informationen liefert, die benötigt werden, um den Circuit in einen umzuwandeln, der auf dem Backend läuft.

from qiskit.transpiler import generate_preset_pass_manager

pass_manager = generate_preset_pass_manager(
optimization_level=1, target=target, seed_transpiler=12345
)
qc_t_target = pass_manager.run(qc)
qc_t_target.draw("mpl", idle_wires=False, fold=-1)

Ausgabe der vorherigen Code-Zelle

Dieses Beispiel wird in späteren Abschnitten dieses Themas verwendet, um zu verdeutlichen, dass die Coupling Map und die Basis-Gates die wesentlichen Informationsstücke sind, die dem Transpiler für eine optimale Circuit-Konstruktion übergeben werden müssen. Der QPU kann in der Regel Standardeinstellungen für andere nicht übergebene Informationen wählen, wie z. B. Timing und Scheduling.

Coupling Map

Die Coupling Map ist ein Graph, der anzeigt, welche Qubits miteinander verbunden sind und somit Zwei-Qubit-Gates zwischen ihnen haben. Manchmal ist dieser Graph gerichtet, was bedeutet, dass die Zwei-Qubit-Gates nur in eine Richtung verlaufen können. Der Transpiler kann jedoch jederzeit die Richtung eines Gates umkehren, indem er zusätzliche Einzel-Qubit-Gates hinzufügt. Ein abstrakter Quantum-Circuit kann immer auf diesem Graphen dargestellt werden, selbst wenn seine Konnektivität begrenzt ist, indem SWAP-Gates eingeführt werden, um die Quanteninformation zu verschieben.

Die Qubits unserer abstrakten Circuits werden virtuelle Qubits genannt und die auf der Coupling Map physikalische Qubits. Der Transpiler stellt ein Mapping zwischen virtuellen und physikalischen Qubits bereit. Einer der ersten Schritte bei der Transpilation, die Layout-Phase, führt dieses Mapping durch.

hinweis

Obwohl die Routing-Phase mit der Layout-Phase verknüpft ist — die die tatsächlichen Qubits auswählt — behandelt dieses Thema sie der Einfachheit halber standardmäßig als separate Phasen. Die Kombination aus Routing und Layout wird Qubit-Mapping genannt. Weitere Informationen zu diesen Phasen findest du im Thema Transpiler-Phasen.

Übergib das Schlüsselwortargument coupling_map, um seine Auswirkung auf den Transpiler zu sehen:

coupling_map = target.build_coupling_map()

pass_manager = generate_preset_pass_manager(
optimization_level=0, coupling_map=coupling_map, seed_transpiler=12345
)
qc_t_cm_lv0 = pass_manager.run(qc)
qc_t_cm_lv0.draw("mpl", idle_wires=False, fold=-1)

Ausgabe der vorherigen Code-Zelle

Wie oben gezeigt, wurden mehrere SWAP-Gates eingefügt (jeweils bestehend aus drei CX-Gates), was auf aktuellen Geräten viele Fehler verursachen wird. Um zu sehen, welche Qubits auf der tatsächlichen Qubit-Topologie ausgewählt werden, verwende plot_circuit_layout aus den Qiskit-Visualisierungen:

from qiskit.visualization import plot_circuit_layout

plot_circuit_layout(qc_t_cm_lv0, backend, view="physical")

Ausgabe der vorherigen Code-Zelle

Dies zeigt, dass unsere virtuellen Qubits 0–11 trivialerweise auf die Linie der physikalischen Qubits 0–11 abgebildet wurden. Kehren wir zur Standardeinstellung (optimization_level=1) zurück, die VF2Layout verwendet, wenn Routing erforderlich ist.

pass_manager = generate_preset_pass_manager(
optimization_level=1, coupling_map=coupling_map, seed_transpiler=12345
)
qc_t_cm_lv1 = pass_manager.run(qc)
qc_t_cm_lv1.draw("mpl", idle_wires=False, fold=-1)

Ausgabe der vorherigen Code-Zelle

Jetzt werden keine SWAP-Gates mehr eingefügt und die ausgewählten physikalischen Qubits sind dieselben wie bei Verwendung der target-Klasse.

from qiskit.visualization import plot_circuit_layout

plot_circuit_layout(qc_t_cm_lv1, backend, view="physical")

Ausgabe der vorherigen Code-Zelle

Jetzt liegt das Layout in einem Ring. Da dieses Layout die Konnektivität des Circuits respektiert, gibt es keine SWAP-Gates, was einen wesentlich besseren Circuit für die Ausführung liefert.

Basis-Gates

Jeder Quantencomputer unterstützt einen begrenzten Befehlssatz, der als Basis-Gates bezeichnet wird. Jedes Gate im Circuit muss in die Elemente dieses Satzes übersetzt werden. Dieser Satz sollte aus Einzel- und Zwei-Qubit-Gates bestehen, die einen universellen Gate-Satz bilden, was bedeutet, dass jede Quantenoperation in diese Gates zerlegt werden kann. Dies geschieht durch den BasisTranslator, und die Basis-Gates können dem Transpiler als Schlüsselwortargument übergeben werden, um diese Informationen bereitzustellen.

basis_gates = list(target.operation_names)
print(basis_gates)
['sx', 'switch_case', 'x', 'if_else', 'measure', 'for_loop', 'delay', 'ecr', 'id', 'reset', 'rz']

Die Standard-Einzel-Qubit-Gates auf ibm_sherbrooke sind rz, x und sx, und das Standard-Zwei-Qubit-Gate ist ecr (echoed cross-resonance). CX-Gates werden aus ecr-Gates konstruiert, daher ist auf manchen QPUs ecr als Zwei-Qubit-Basis-Gate angegeben, während auf anderen cx der Standard ist. Das ecr-Gate ist der verschränkende Teil des cx-Gates. Neben den Steuer-Gates gibt es auch delay- und measurement-Befehle.

hinweis

QPUs haben Standard-Basis-Gates, aber du kannst beliebige Gates wählen, solange du die Anweisung bereitstellst oder Puls-Gates hinzufügst (siehe Transpiler-Passes erstellen.). Die Standard-Basis-Gates sind diejenigen, für die Kalibrierungen auf dem QPU durchgeführt wurden, sodass keine weiteren Anweisungs-/Puls-Gates bereitgestellt werden müssen. Zum Beispiel ist auf manchen QPUs cx das Standard-Zwei-Qubit-Gate und auf anderen ecr. Weitere Details findest du in der Liste der möglichen nativen Gates und Operationen.

pass_manager = generate_preset_pass_manager(
optimization_level=1,
coupling_map=coupling_map,
basis_gates=basis_gates,
seed_transpiler=12345,
)
qc_t_cm_bg = pass_manager.run(qc)
qc_t_cm_bg.draw("mpl", idle_wires=False, fold=-1)

Ausgabe der vorherigen Code-Zelle

Beachte, dass die CXGate-Objekte in ecr-Gates und Einzel-Qubit-Basis-Gates zerlegt wurden.

Geräte-Fehlerraten

Die Target-Klasse kann Informationen über die Fehlerraten für Operationen auf dem Gerät enthalten. Zum Beispiel ruft der folgende Code die Eigenschaften für das echoed cross-resonance (ECR) Gate zwischen Qubit 1 und 0 ab (beachte, dass das ECR-Gate gerichtet ist):

target["ecr"][(1, 0)]
InstructionProperties(duration=5.333333333333332e-07, error=0.007494257741828603)

Die Ausgabe zeigt die Dauer des Gates (in Sekunden) und seine Fehlerrate. Um dem Transpiler Fehlerinformationen bereitzustellen, erstelle ein Target-Modell mit den basis_gates und der coupling_map von oben und befülle es mit Fehlerwerten aus dem Backend FakeSherbrooke.

from qiskit.transpiler import Target
from qiskit.circuit.controlflow import IfElseOp, SwitchCaseOp, ForLoopOp

err_targ = Target.from_configuration(
basis_gates=basis_gates,
coupling_map=coupling_map,
num_qubits=target.num_qubits,
custom_name_mapping={
"if_else": IfElseOp,
"switch_case": SwitchCaseOp,
"for_loop": ForLoopOp,
},
)

for i, (op, qargs) in enumerate(target.instructions):
if op.name in basis_gates:
err_targ[op.name][qargs] = target.instruction_properties(i)

Transpiliere mit unserem neuen Target err_targ als Ziel:

pass_manager = generate_preset_pass_manager(
optimization_level=1, target=err_targ, seed_transpiler=12345
)
qc_t_cm_bg_et = pass_manager.run(qc)
qc_t_cm_bg_et.draw("mpl", idle_wires=False, fold=-1)

Ausgabe der vorherigen Code-Zelle

Da das Target Fehlerinformationen enthält, versucht der VF2PostLayout-Pass, die optimalen Qubits zu finden, was zu demselben Circuit führt, der ursprünglich mit denselben physikalischen Qubits gefunden wurde.

Nächste Schritte