Skip to main content
IBM Quantum Platform

Eingaben und Ausgaben des Executors

  • Der Code auf dieser Seite wurde unter Berücksichtigung der folgenden Anforderungen entwickelt. Wir empfehlen, diese Versionen oder neuere zu verwenden.

    qiskit[all]~=2.5.2
    qiskit-ibm-runtime~=0.47.0
    samplomatic~=0.21.0
    

Die Executor-Primitive ist Teil des gerichteten Ausführungsmodells, das mehr Flexibilität bei der Anpassung eines Workflows zur Fehlerbehebung bietet.

Die Ein- und Ausgänge der Executor-Primitive unterscheiden sich erheblich von denen der Sampler- und Estimator -Primitive. QuantumProgramAnstatt beispielsweise eine Liste von PUBs als Eingabe zu verwenden, nimmt Executor ein Objekt entgegen, das eine Liste von QuantumProgramItem Objekten enthält. Diese Containerklassen bieten Ihnen mehr Flexibilität als ein „ PUB “, bei dem es sich um eine einfache Tupel-Datenstruktur handelt.

QuantumProgramItemDie Ausgabe von executor ist ein QuantumProgramResult``Iterable, der für jede Eingabe ein Element enthält.


Eingaben: Quantum-Programme

Wie bereits erwähnt, ist die Eingabe für eine Executor-Primitive ein QuantumProgram, bei dem es sich um eine iterierbare Sammlung von QuantumProgramItem Objekten handelt. Es gibt zwei Arten dieser Objekte:

  • CircuitItem, in der in der Regel eine Schaltung und ihre Parameterwerte (sofern vorhanden) gespeichert sind.
  • SamplexItem, in der in der Regel Folgendes gespeichert wird:
    • Eine Schaltungsvorlage
    • Ein Samplex-Objekt, das dazu dient, zur Laufzeit zufällige Parametersätze zu generieren (beispielsweise um Twirling durchzuführen oder Rauschen einzuspielen)
    • Argumente für den Samplex, die Parameterwerte für die ursprüngliche Schaltung enthalten können

Jeder dieser Punkte stellt eine andere Aufgabe dar, die der Testamentsvollstrecker zu erledigen hat.

Vorbereitende Schritte

Einige der Code-Beispiele auf dieser Seite verwenden samplex, das zum Samplomatic-Paket gehört. Bevor Sie diese Code-Blöcke ausführen, müssen Sie daher Samplomatic installieren, wie im folgenden Code-Block gezeigt. Weitere Informationen finden Sie in der Samplomatic-Dokumentation.

pip install samplomatic

# For visualization support, include the visualization dependencies.
# pip install samplomatic[vis]

Beispiel: Erstellen Sie eine QuantumProgram mit zwei verschiedenen Aufgaben

Initialisieren Sie zunächst Ihr Quantenprogramm und fügen Sie dann Programmelemente hinzu, indem Sie entweder append_circuit_item oder append_samplex_item verwenden (sofern ein Samplex vorhanden ist), wie in den folgenden Beispielen gezeigt.

Die folgende Zelle initialisiert a QuantumProgram und legt fest, dass für jede Konfiguration jedes Elements im Programm 1024 Durchläufe ausgeführt werden sollen.

Note

Im Gegensatz zu Sampler nimmt ein QuantumProgram nur einen einzigen Wert entgegen. QuantumProgramWenn Sie einen anderen Belichtungswert wünschen, benötigen Sie eine separate Aufnahme, was einen separaten Auftrag darstellen würde.

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

# Initialize an empty program
program = QuantumProgram(shots=1024)

# Initialize and transpile a 3-qubit quantum circuit with 2 parameters.
circuit = QuantumCircuit(3)
circuit.h(0)
circuit.cx(0, 1)
circuit.cx(1, 2)
circuit.rz(Parameter("theta"), 0)
circuit.rz(Parameter("phi"), 1)

# `measure_all` adds a 3-bit classical register named "meas"
circuit.measure_all()

# Choose the least busy backend
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)

# Generate a preset pass manager
# This will be used to convert the abstract circuit to an
# equivalent Instruction Set Architecture (ISA) circuit.
preset_pass_manager = generate_preset_pass_manager(
    backend=backend, optimization_level=0
)

# Transpile the circuit
isa_circuit = preset_pass_manager.run(circuit)

Anhängen CircuitItem

Anschließend wird die Zielschaltung, die entsprechend der Befehlssatzarchitektur (ISA) des Backends transpiliert wurde, an die QuantumProgram. Da diese Schaltung zwei Parameter hat, müssen wir auch die Parameterwerte angeben (in diesem Beispiel 10 Sätze). Die Ausführung dieses Befehls CircuitItem ist die erste Aufgabe, die das Programm ausführt.

# Append the transpiled circuit and an array
# containing 10 sets of parameter values to the program
program.append_circuit_item(
    isa_circuit,
    circuit_arguments=np.random.rand(
        10, 2
    ),  # 10 sets of parameter values and 2 parameters
)

Anhängen SamplexItem

Die Elemente der Schleife werden ohne jegliche Zufallsauswahl ausgeführt. Im Gegenteil: Bei Samplex-Elementen können Sie festlegen, wie deren Inhalt zufällig angeordnet werden soll. In der nächsten Zelle werden mithilfe der generate_boxing_pass_manager() Funktion die Logikgatter und Messwerte der Schaltung in Kästchen zusammengefasst und jedem Kästchen eine rotierende Beschriftung hinzugefügt. Anschließend generiert es mithilfe der build() Funktion eine Schaltungsvorlage und ein Samplex-Paar.

Die Ausführung dieser Aufgabe SamplexItem ist die zweite Aufgabe, die das Programm ausführt.

Ausführliche Informationen zu samplex und seinen Argumenten finden Sie in der Sam plomatic-API-Dokumentation. Informationen zur Verwendung der generate_boxing_pass_manager() Funktion finden Sie im Sam plomatic-Transpiler-Handbuch.

# Transpile the circuit, additionally grouping gates and measurements into annotated boxes
preset_pass_manager = generate_preset_pass_manager(
    backend=backend, optimization_level=0
)

# Use the boxing pass manager to group gates
# and measurements into boxes and add
# a`Twirl` annotation.
preset_pass_manager.post_scheduling = generate_boxing_pass_manager(
    # Add gate twirling
    enable_gates=True,
    # Add measurement twirling
    enable_measures=True,
)
boxed_circuit = preset_pass_manager.run(circuit)

# Build the template circuit and the samplex.  The template circuit has parametric gates
# without fixed values and the samplex randomly generates the parameter
# values on the server side at runtime to perform twirling.
template_circuit, samplex = build(boxed_circuit)

# Determine what arguments are required by the samplex.
# Input the arguments in samplex_arguments.
print(samplex.inputs())

Output:

TensorInterface(<
  - 'parameter_values' <float64[2]>: Input parameter values to use during sampling.
>)
# Append the template circuit and samplex as a samplex item
program.append_samplex_item(
    template_circuit,
    samplex=samplex,
    samplex_arguments={
        # the arguments required by the samplex.sample method
        "parameter_values": np.random.rand(10, 2),
    },
    shape=(28, 10),  # 28 randomizations and 10 sets of parameter values
)
# Initialize an Executor with the default options
executor = Executor(mode=backend)

# Submit the job
job = executor.run(program)

# Retrieve the result
result = job.result()

Ausgaben

Die Ausgabe von Executor ist ein QuantumProgramResult, das iterierbar ist. Es enthält einen Eintrag pro Eingabe QuantumProgramItem in derselben Reihenfolge wie die Eingabeelemente. Jedes dieser Ausgabeelemente ist ein Wörterbuch, dessen Schlüssel Zeichenfolgen sind, die (unter anderem) den Namen der klassischen Register in den Eingangsschaltungen entsprechen, sodass du dir diese Namen nicht mehr merken musst, wie es beim Sampler-Ausgang der Fall war. Die Werte des Wörterbuchs sind vom Typ np.ndarray.

Das Ergebnis des vorangegangenen Beispiels enthält folgende Elemente:

CircuitItem Ergebnis

CircuitItemDer erste Eintrag enthält die Ergebnisse der Ausführung der ersten Aufgabe (a) im Programm. Es enthält einen einzigen Schlüssel, meas, der den Namen des klassischen Registers in der Eingangsschaltung angibt. (parameter sets, shots, register bits)Der Wert dieses Schlüssels wird einem Array np.ndarray der Form zugeordnet, die im obigen Beispiel (10, 1024, 3) lautet.

Der folgende Code zeigt, wie man auf diese Informationen zugreifen kann:

# Access the results of the classical register of task #0, a CircuitItem
result_0 = result[0]["meas"]
print(f"Result shape: {result_0.shape}")

Output:

Result shape: (10, 1024, 3)

Die Achse ganz rechts von result_0 läuft über klassische Bits in Little-Endian-Reihenfolge. Somit enthält der Index 0 den Wert des klassischen Bits 0, also des niedrigstwertigen Bits.

SamplexItem Ergebnis

Der zweite Eintrag enthält die Ergebnisse der Ausführung der zweiten Aufgabe (a SamplexItem) im Programm. Dieser Eintrag enthält mehrere Schlüssel. Der Schlüssel meas , bei dem es sich um den Namen des klassischen Registers der Eingangsschaltung handelt, wird auf das Ergebnisarray dieses Registers abgebildet. Dieses Array hat die Form (randomizations, parameter sets, shots, classical bits), in diesem Beispiel also (28, 10, 1024, 3).

Zudem enthält die Ausgabe einen Schlüssel measurement_flips.meas , bei dem es sich um die Bit-Flip-Korrekturen handelt, mit denen die Messabweichung für das Register meas rückgängig gemacht wird. In unserem Beispiel ergibt sich daraus die Ausgabestruktur (28, 10, 1, 3), da für die Bitumkehr nur ein Durchlauf erforderlich ist.

Beachten Sie, dass die Achse ganz rechts über klassische Bits in Little-Endian-Reihenfolge verläuft result_1 .

# Access the results of the classical register of task #1
result_1 = result[1]["meas"]
print(f"Result shape: {result_1.shape}")

# Access the bit-flip corrections
flips_1 = result[1]["measurement_flips.meas"]
print(f"Bit-flip corrections shape: {flips_1.shape}")

# Undo the bit flips via classical XOR
unflipped_result_1 = result_1 ^ flips_1

Output:

Result shape: (28, 10, 1024, 3)
Bit-flip corrections shape: (28, 10, 1, 3)

Nächste Schritte

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