Skip to main content
IBM Quantum Platform

Von Sampler zu Executor migrieren

In diesem Leitfaden wird beschrieben, wie Sie Quantum-Sampling-Workloads von der „ IBM Quantum® “-Sampler- Primitive auf die „Executor“-Primitive verlagern können.

Beta-Release

Die Primitive „Executor“ ist Teil des gerichteten Ausführungsmodells. Alle Komponenten des Modells zur gerichteten Ausführung befinden sich derzeit in der Beta-Phase und sind möglicherweise noch nicht stabil. Sie sind herzlich eingeladen, diese zu testen und Feedback zu geben, indem Sie ein Issue in den Repositories „Samplomatic“ oder „qiskit-ibm-runtime“ GitHub eröffnen.


Sollten Sie migrieren?

Nicht jeder sollte von Sampler auf Executor umsteigen. Es gibt viele Unterschiede zwischen den Primitiven, doch die folgenden Hinweise können Ihnen bei der Entscheidung helfen, ob eine Migration sinnvoll ist:

Wechseln Sie zu Executor, wenn Sie als Quanteninformationswissenschaftler Experimente im industriellen Maßstab durchführen und eine detaillierte, reproduzierbare Kontrolle über Techniken wie Pauli-Twirling, das Erlernen und Einbringen von Rauschmodellen sowie Basiswechsel benötigen – oder wenn Sie eine der zusätzlichen Funktionen von Executor benötigen.

Verwenden Sie Sampler weiterhin, wenn Sie eine einfache, übergreifende Schnittstelle wünschen und möchten, dass die Primitive die Fehlerunterdrückung und -minderung für Sie übernimmt.

Einschränkungen und Vorbehalte

Da sich Executor und das Modell der gesteuerten Ausführung noch in der Beta-Phase befinden, sollten Sie Folgendes beachten, bevor Sie sich für eine Migration entscheiden:

  • Noch keine Simulatorunterstützung : Im Gegensatz zu Sampler, das über eine AerSamplerImplementierung für qiskit-aer die lokale Simulation verfügt, gibt es derzeit kein Simulator-Backend für Executor. Simulator Die Unterstützung dafür wird voraussichtlich bald verfügbar sein. In der Zwischenzeit können Sie die Vorlagenschaltung weiterhin lokal prüfen und testen, um Ihren Arbeitsablauf zu validieren, bevor Sie ihn an die Hardware übermitteln.
  • Diese Anleitung bezieht sich ausschließlich auf den Sampler, nicht auf den Estimator. Die Migration von „Estimator“ zu „Executor“ ist wesentlich aufwendiger als die Migration von „Sampler“, da „Estimator“ Erwartungswerte berechnet, anstatt Rohstichproben zurückzugeben. Um das Verhalten von „Estimator“ mit „Executor“ nachzubilden, ist eine zusätzliche Nachbearbeitung erforderlich. Hilfsfunktionen für die Migration von „Estimator“ zu „Executor“ befinden sich noch in der Entwicklung, daher beschreibt diese Anleitung bewusst nur den „Sampler“-Workflow.

Wesentliche Unterschiede zwischen Executor und Sampler

Sowohl „Sampler“ als auch „Executor“ lesen die Ausgaberegister von Quantenschaltungen aus, richten sich jedoch an unterschiedliche Nutzer:

  • „Sampler“ ist eine Abstraktion auf hoher Ebene. Es weist folgende Merkmale auf:
    • Es verfügt über eine integrierte Fehlerunterdrückung (dynamische Entkopplung und Twirling).
    • Es trifft implizit Entscheidungen für dich.
    • Es ist so konzipiert, dass sich Algorithmusentwickler auf Innovationen statt auf Daten konzentrieren können. Umwandlung.
  • „Executor“ ist Teil des Modells der gerichteten Ausführung. Es unterscheidet sich in vielerlei Hinsicht von Sampler und weist die folgenden Merkmale auf:
    • Es verfügt über keine integrierte Fehlerunterdrückung oder -minderung. Stattdessen halten Sie Ihre Entwurfsabsicht auf der Client-Seite fest (mithilfe von Schaltungsanmerkungen und einem Samplex ), und die rechenintensive Generierung von Schaltungsvarianten wird auf die Serverseite verlagert.

    • Es trifft keine impliziten Entscheidungen. Es hält sich genau an Ihre Anweisungen und bietet Ihnen volle Kontrolle und Transparenz.

    • Executor und Samplomatic bieten gemeinsam zusätzliche Funktionen, die Sampler nicht bietet, darunter (unter anderem) die folgenden:

      • Weitere Twirling-Gruppen: Mit „Samplomatic“ können Sie für jedes Feld selbst auswählen, welche Twirling-Gruppe angewendet werden soll, anstatt auf die einzige Strategie beschränkt zu sein, die „Sampler“ automatisch für Sie anwendet. Es unterstützt auch andere Twirling-Gruppen als die Pauli-Gruppe, wie beispielsweise die "local_c1" Twirling- Gruppe.
      • Kernel- und klassifizierte Messungen zusammen: Die Einstellung QuantumProgram.meas_level = "both" (hinzugefügt unter v0.48.0qiskit-ibm-runtime ) sieht vor, dass sowohl klassifizierte als auch Kernel-Messungen in den Ergebnissen enthalten sind, anstatt pro Auftrag einen einzigen Messungstyp auszuwählen.
      • Twirling für Schaltungen mit fraktionalen Gatter: Executor kann Twirling auf Schaltungen anwenden, die fraktionale Gatter enthalten.
      • Fein abgestimmte, kombinierbare Fehlerminderung: Beispielsweise die Auswahl der Schaltungsebenen, auf denen eine Fehlerminderung erfolgen soll, sowie die Anpassung der in die Schaltung eingespeisten Rauschraten.
      Hinweise
      • Zukünftige neue Funktionen werden voraussichtlich zunächst für Executor veröffentlicht und möglicherweise nicht auf Sampler portiert. Wenn Sie Wert auf den Zugriff auf die neuesten Funktionen legen, ist Executor die zukunftssicherere Wahl.
      • Das Qiskit-Basispaket bietet noch keine Basisklasse für die Executor-Primitive (für andere Primitive ist dies jedoch der FallSamplerV2).

Konzeptionelle Kartierung

Die folgende Tabelle veranschaulicht, wie die Sampler-Konzepte dem Executor zugeordnet werden.

Konzept
Stichprobenfunktion
Steuerprogramm
Importierenfrom qiskit_ibm_runtime import SamplerV2from qiskit_ibm_runtime import Executor
EingabeListe der PUBs (Tupel)Eine Anzahl von QuantumProgram Objekten QuantumProgramItem
Schaltung und Parameter(circuit, params, shots) Tupelprogram.append_circuit_item(circuit, circuit_arguments=...)
WirbelnTwirlingOptionsDeutlich erkennbar durch beschriftete Kästchen und ein Samplex (append_samplex_item)
Anruf ausführensampler.run([pub, ...])executor.run(program)
ErgebnistypPrimitiveResultvonSamplerPubResultQuantumProgramResult (iterierbar)
Datenzugriffresult[0].data.<register> (BitArray)result[0]["<register>"] (np.ndarray)
Lärm bewältigenIntegrierte OptionenMuss manuell zusammengestellt werden (Anmerkungen, Samplex, NoiseLearnerV3)

Übersicht über die Migrationsschritte

  1. Installieren Sie Samplomatic.
  2. Ändere die Importe.
  3. PUB -Tupel ersetzen.
  4. Ändere die Art und Weise, wie Schüsse dargestellt werden.
  5. Passen Sie gegebenenfalls weitere Optionen an.
  6. Aktualisieren Sie den Befehl run .
  7. Aktualisierung der Ergebnisauswertung.
  8. Das Drehen rückgängig machen.

Schritt 1. Installieren Sie die erforderlichen Pakete

Für „Executor“ und das Modell der gerichteten Ausführung ist das folgende Paket samplomatic erforderlich:

pip install qiskit qiskit-ibm-runtime samplomatic

# For visualization support:
# pip install samplomatic[vis]
Versionshinweise
  • qiskit-ibm-runtime v0.48.0 wird empfohlen, da dadurch die Option meas_level = "both" und die local_c1 Twirling-Gruppe hinzugefügt werden.
  • qiskit >= 2.3.0 ist erforderlich.
  • samplomatic >= 0.18.0 ist erforderlich.

Schritt 2. Ändere die Importe

Auszug:

from qiskit_ibm_runtime import SamplerV2 as Sampler

Testamentsvollstrecker:

from qiskit_ibm_runtime import Executor, QuantumProgram

Schritt 3. Ersetze die Tupel „ PUB “ durch ein QuantumProgram

Anstatt eine Liste von Tupeln (PUBs) zu übergeben, erstellt man bei der Verwendung von Executor ein und QuantumProgram fügt Elemente daran an.

A QuantumProgram Akzeptiert Schaltungselemente und Samplex- Elemente:

  • append_circuit_item: Fügt ein „ CircuitItem,“ hinzu, das für eine Schaltung steht, sowie (optional) deren Parameterwerte. Es wird unverändert und ohne jegliche Zufallsauswahl ausgeführt.

    Verwenden Sie diese Option, wenn Sie lediglich eine Schaltung abtasten möchten – genau so, wie es „Sampler“ bei einem „ PUB “ ohne Twirling tun würde; beispielsweise beim Einreichen eines einfachen Abtastauftrags oder wenn Sie bereits manuell alle gewünschten Varianten hinzugefügt haben.

  • append_samplex_item: Fügt ein „ samplexItem,“ hinzu, bei dem es sich um eine Vorlagenschaltung plus ein „Samplex“ handelt, das serverseitig zufällige Parametersätze generiert.

    Verwenden Sie diese Option, wenn Sie möchten, dass der Inhalt der Schaltung zufällig angeordnet wird. Der Hauptfall betrifft das Twirling (Gate oder Messung) oder die Rauscheinjektion. Diese Funktion ersetzt die in Sampler integrierte Twirling-Funktion.

Ein einzelnes QuantumProgram kann beide Elementtypen akzeptieren; jedes angehängte Element wird als eigenständige Aufgabe ausgeführt und erzeugt einen eigenen Eintrag in den Ergebnissen. Verwenden Sie im Allgemeinen, wenn append_circuit_item Ihre Schaltung nicht randomisiert werden muss. Andernfalls verwenden Sie append_samplex_item.

In den folgenden Abschnitten werden nacheinander folgende Themen behandelt: parametrisierte Schaltungen, die … verwenden append_circuit_item, sowie die Migration von Twirling unter Verwendung von append_samplex_item…

In den folgenden Code-Beispielen bezieht isa_circuit sich auf die Schaltung, die so transpiliert wurde, dass sie der Befehlssatzarchitektur (ISA) des Ziel-Backends entspricht. Dies enthält isa_circuit zwei Parameter.

Schritt 3a. Parametrisierte Schaltungen migrieren

Bei „Sampler“ sind die Parameterwerte das zweite Element des Tupels „ PUB “. Bei Executor übergeben Sie diese als circuit_arguments an append_circuit_item.

Auszug:

params = np.random.rand(10, circuit.num_parameters)  # 10 parameter sets
pubs = (isa_circuit, params)

Steuerprogramm

program = QuantumProgram(shots=1024)
program.append_circuit_item(
    isa_circuit,
    circuit_arguments=np.random.rand(10, circuit.num_parameters),  # 10 sets
)

# CircuitItem result shape: (parameter_sets, shots, register_bits) -> (10, 1024, 2)
result_0 = result[0]["meas"]

Schritt 3b. Integrierte Twirling-Funktionen in explizite Annotationen migrieren

Das ist die wichtigste Änderung. Sampler wendet mithilfe verschiedener Optionen den „Twirling“-Effekt für Sie an. Mit Executor bringst du diese Absicht explizit zum Ausdruck, indem du annotierte Felder und ein Samplex (von Samplomatic ) verwendest.

Beispiel (mit den Optionen drehen):

sampler = Sampler(mode=backend)
sampler.options.twirling.enable_gates = True
sampler.options.twirling.enable_measure = True

Ausführender (Wirbel mit Kisten und einem Samplex):

from samplomatic import build
from samplomatic.transpiler import generate_boxing_pass_manager

# 1. Group gates and measurements into annotated boxes with twirling annotations
boxes_pm = generate_boxing_pass_manager(
    enable_gates=True,     # gate twirling
    enable_measures=True,  # measurement twirling
)
boxed_circuit = boxes_pm.run(isa_circuit)

# 2. Build the (template circuit, samplex) pair.
#    The template circuit's single-qubit gates are replaced by parameterized gates;
#    the samplex encodes how to generate the randomized parameters at runtime.
template_circuit, samplex = build(boxed_circuit)

# 3. Append as a samplex item, specifying the number of randomizations
program = QuantumProgram(shots=1024)
program.append_samplex_item(
    template_circuit,
    samplex=samplex,
    samplex_arguments={
        "parameter_values": np.random.rand(10, 2),  # original circuit params
    },
    shape=(28, 10),  # 28 randomizations x 10 parameter sets
)

Da die Vorlagenschaltung und der Samplex auf der Client-Seite erstellt werden, können Sie diese lokal überprüfen und abtasten, um die Ausgabe zu verifizieren, bevor Sie Daten an die Hardware senden.

Überprüfung: Testen Sie die Vorlagenschaltung lokal

Sie können Zufallswerte aus dem Samplex ziehen und diese an die Schaltungsvorlage binden, um zu überprüfen, ob der Samplex die von Ihnen erwarteten Parameterwerte liefert. Die von zurückgegebenen Parameterwerte sind samplex.sample direkt kompatibel mit den Parametern der Vorlagenschaltung.

# Check which inputs the samplex requires (for the twirling example above,
# this is just the original circuit's parameter values).
print(samplex.inputs())

# Bind the required inputs, then draw a few randomizations locally.
inputs = samplex.inputs().bind(
    parameter_values=np.random.rand(2),  # one set of the original circuit's params
)
outputs = samplex.sample(inputs, num_randomizations=3)

# Assign one randomization's parameter values to the template circuit and inspect it.
bound_template = template_circuit.assign_parameters(outputs["parameter_values"][0])
bound_template.draw("mpl", idle_wires=False)

Um noch einen Schritt weiter zu gehen, kann man überprüfen, ob jede Randomisierung logisch äquivalent zur ursprünglichen Schaltung ist, indem man beispielsweise beide in Operator Objekte umwandelt und ihre unitären Implementierungen vergleicht (nach Berücksichtigung der Korrekturen outputs["measurement_flips.<register>"] , die das „Measurement Twirling“ rückgängig machen) oder indem man die Erwartungswerte aus einem lokalen StatevectorSampler bzw. Lauf StatevectorEstimator vergleicht. Eine vollständige Anleitung finden Sie im Handbuch zu den Ein- und Ausgängen des Samplomatic Samplex.

Schritt 4. Ändern Sie die Art und Weise, wie Aufnahmen angefordert werden

Bilder von der „ PUB “ nach QuantumProgram(shots=...)… verschieben. In Executor gilt shots dies für den gesamten Auftrag. Reichen Sie mehrere Aufträge ein, wenn Sie unterschiedliche Bildanzahlen benötigen.

Auszug:

# Run — shots are passed to run()
sampler = Sampler(mode=backend)
job = sampler.run([(isa_circuit, None, 25)])

Testamentsvollstrecker:

# Build a QuantumProgram — shots are on the program
program = QuantumProgram(shots=25)
program.append_circuit_item(isa_circuit)

Schritt 5. Aktualisieren Sie die Optionen nach Bedarf

Executor bietet weniger Optionen als Sampler, da die Einstellungen zur Fehlerminderung nun in Ihren Annotationen und in „samplex“ statt in den Optionen zu finden sind.

Außerdem gibt es einen strukturellen Unterschied hinsichtlich der Speicherorte der Einstellungen.

  • Bei Sampler wird alles – einschließlich der Einstellungen, die sich auf die Nachbearbeitung der Ergebnisse auswirken – über die Optionen der Primitive oder im „ PUB “ konfiguriert.

  • Bei Executor werden die Einstellungen, die Einfluss darauf haben, wie die Auftragsergebnisse gestaltet und nachbearbeitet werden, auf der Seite festgelegt QuantumProgram, nicht auf ExecutorOptions.

Beispiele:

Stichprobenfunktion
Steuerprogramm
shotsQuantumProgram(shots=...)
meas_typeQuantumProgram(meas_level=...)

ExecutorOptions enthält lediglich Ausführungs- und Umgebungseinstellungen auf niedrigerer Ebene, die die Struktur der zurückgegebenen Daten nicht verändern. Es umfasst drei Gruppen auf oberster Ebene:

Insbesondere gibt es die Optionen dynamical_decoupling und twirling im Sampler, nicht jedoch im Executor. Stattdessen werden diese Optionswerte über das gerichtete Ausführungsmodell ausgedrückt.

Beispiel:

from qiskit_ibm_runtime import Executor, ExecutorOptions

options = ExecutorOptions(
    environment={"log_level": "INFO"},
    execution={"init_qubits": True},
)
# or mutate after construction:
options = ExecutorOptions()
options.environment.log_level = "INFO"
options.execution.init_qubits = True

executor = Executor(mode=backend, options=options)

Schritt 6. Den Befehl run aktualisieren

Als Eingabe für einen Executor-Job dient das Programm anstelle von PUBs.

Auszug:

# Submit a job
sampler.run([(isa_circuit, parameter_values)])

Testamentsvollstrecker:

# Submit a job
executor.run(program)

Schritt 7. Ändern Sie die Art und Weise, wie Sie auf Ergebnisse zugreifen

In Executor sind die Ergebnisse „ NumPy “-Arrays und keine BitArray Objekte. Verwende die Zeichenkette als Index (result[0]["meas"]) und erhalte ein zurück np.ndarray . Man muss sich den Pfad des Attributs .data.<register> nicht merken.

Um von „Sampler“ auf „Executor“ umzustellen, ändern Sie result[i].data.<reg> (BitArray) in result[i]["<reg>"] (np.ndarray)und schreiben Sie die get_counts-basierte Nachbearbeitung als „ NumPy “-Operationen um.

Aufgabe
Stichprobenfunktion
Steuerprogramm
Registerdaten abrufenresult[0].data.measresult[0]["meas"]
DatentypBitArraynp.ndarray
Zählwörterbuchresult[0].data.meas.get_counts()Das Array manuell nachbearbeiten
Mehrere Registerresult[0].data.<name> pro Registerresult[0]["<name>"] pro Register
CircuitItem Array-Form-(parameter_sets, shots, register_bits)
SamplexItem Array-Form-(randomizations, parameter_sets, shots, register_bits)
Messung rückgängig machenAutomatischresult[i]["measurement_flips.<name>"] + XOR
Note

Sampler's BitArray bietet Hilfsmittel (get_counts, slice_bits, slice_shots, expectation_values, sowie Masken zur Nachauswahl) an. Der Executor gibt „ NumPy “-Arrays im Rohformat zurück, sodass Sie diese Nachbearbeitung mit Standardoperationen von „ NumPy “ durchführen können.

Schritt 8. Behandlung von durch Drehung verursachten Ergebnissen (Korrekturen bei Bit-Flips)

Wenn Sie eine Messung mittels „Twirling“ durch ein anwenden SamplexItem, gibt „Executor“ die Rohwerte (die durch „Twirling“ bearbeiteten Messwerte) sowie die Bit-Flip-Korrekturen zurück, die erforderlich sind, um das „Twirling“ rückgängig zu machen. Sie müssen sie manuell anwenden; es erfolgt keine automatische Korrektur.

Wenn Sie Executor verwenden, heben Sie das Twirling explizit mithilfe der Korrekturen measurement_flips.<reg> und einer XOR-Operation auf, wie im folgenden Beispiel gezeigt:

# SamplexItem result shape: (randomizations, parameter_sets, shots, register_bits)
result_1 = result[1]["meas"]                       # example: (28, 10, 1024, 2)

# Bit-flip corrections to undo measurement twirling
flips_1 = result[1]["measurement_flips.meas"]      # example: (28, 10, 1, 2)

# Undo the twirling through classical XOR (broadcasts over the shots axis)
unflipped_result_1 = result_1 ^ flips_1

In Sampler gibt es keinen entsprechenden Schritt, da dort das Ausblenden automatisch rückgängig gemacht wird.


Vollständiges Beispiel: Migration eines einfachen Abtastauftrags

Stichprobenfunktion

import numpy as np
from qiskit.circuit import QuantumCircuit
from qiskit.transpiler import generate_preset_pass_manager
from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2 as Sampler

# 1. Account + backend
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)

# 2. Circuit
circuit = QuantumCircuit(2)
circuit.h(0)
circuit.h(1)
circuit.cz(0, 1)
circuit.h(1)
circuit.measure_all()

# 3. Transpile to ISA
pm = generate_preset_pass_manager(optimization_level=1, backend=backend)
isa_circuit = pm.run(circuit)

# 4. Run — shots are passed to run()
sampler = Sampler(mode=backend)
job = sampler.run([(isa_circuit,)], shots=25)
result = job.result()

# 5. Access results: a BitArray keyed by register name
counts = result[0].data.meas.get_counts()

Steuerprogramm

import numpy as np
from qiskit.circuit import QuantumCircuit
from qiskit.transpiler import generate_preset_pass_manager
from qiskit_ibm_runtime import QiskitRuntimeService, Executor
from qiskit_ibm_runtime.quantum_program import QuantumProgram

# 1. Account + backend (unchanged)
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)

# 2. Circuit (unchanged)
circuit = QuantumCircuit(2)
circuit.h(0)
circuit.h(1)
circuit.cz(0, 1)
circuit.h(1)
circuit.measure_all()

# 3. Transpile to ISA (unchanged)
pm = generate_preset_pass_manager(optimization_level=1, backend=backend)
isa_circuit = pm.run(circuit)

# 4. Build a QuantumProgram — shots are on the program
program = QuantumProgram(shots=25)
program.append_circuit_item(isa_circuit)

# 5. Run
executor = Executor(mode=backend)
job = executor.run(program)
result = job.result()

# 6. Access results: a plain np.ndarray keyed by register name
#    shape = (shots, register_bits)
meas = result[0]["meas"]

Nächste Schritte

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