Zum Hauptinhalt springen

Erste Schritte mit Primitives

Neues Ausführungsmodell, jetzt in der Beta-Version

Die Beta-Version eines neuen Ausführungsmodells ist jetzt verfügbar. Das Directed Execution Model bietet mehr Flexibilität bei der Anpassung deines Error-Mitigation-Workflows. Weitere Informationen findest du im Leitfaden Directed execution model.

hinweis

Während diese Dokumentation die Primitives von Qiskit Runtime verwendet, die die Nutzung von IBM®-Backends ermöglichen, können die Primitives mit jedem Anbieter durch Verwendung der Backend-Primitives ausgeführt werden. Zusätzlich kannst du die Referenz-Primitives verwenden, um auf einem lokalen Statevector-Simulator zu laufen. Einzelheiten findest du unter Exact simulation with Qiskit primitives.

Die Schritte in diesem Thema beschreiben, wie du Primitives einrichtest, die Optionen erkundest, die du zur Konfiguration verwenden kannst, und sie in einem Programm aufrufst.

Verwendung fraktionaler Gates

Um die neu unterstützten Fractional Gates zu verwenden, setze use_fractional_gates=True, wenn du ein Backend von einer QiskitRuntimeService-Instanz anforderst. Zum Beispiel:

# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-ibm-runtime
service = QiskitRuntimeService()
fractional_gate_backend = service.least_busy(use_fractional_gates=True)

Beachte, dass dies eine experimentelle Funktion ist und sich in Zukunft ändern kann.

Paketversionen

Der Code auf dieser Seite wurde mit den folgenden Anforderungen entwickelt. Wir empfehlen die Verwendung dieser oder neuerer Versionen.

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

Erste Schritte mit Estimator

1. Initialisiere das Konto

Da Qiskit Runtime Estimator ein verwalteter Dienst ist, musst du zunächst dein Konto initialisieren. Anschließend kannst du die QPU auswählen, die du zur Berechnung des Erwartungswerts verwenden möchtest.

Folge den Schritten im Thema Install and set up topic, wenn du noch kein Konto hast.

from qiskit_ibm_runtime import QiskitRuntimeService

service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=127
)

print(backend.name)
ibm_torino

2. Erstelle einen Circuit und eine Observable

Du benötigst mindestens einen Circuit und eine Observable als Eingaben für das Estimator-Primitive.

from qiskit.circuit.library import qaoa_ansatz
from qiskit.quantum_info import SparsePauliOp

entanglement = [tuple(edge) for edge in backend.coupling_map.get_edges()]
observable = SparsePauliOp.from_sparse_list(
[("ZZ", [i, j], 0.5) for i, j in entanglement],
num_qubits=backend.num_qubits,
)
circuit = qaoa_ansatz(observable, reps=2)
# the circuit is parametrized, so we will define the parameter values for execution
param_values = [0.1, 0.2, 0.3, 0.4]

print(f">>> Observable: {observable.paulis}")
>>> Observable: ['IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...', ...]

Der Circuit und die Observable müssen so transformiert werden, dass sie nur Anweisungen verwenden, die von der QPU unterstützt werden (bezeichnet als Instruction Set Architecture (ISA) Circuits). Wir verwenden den Transpiler, um dies zu tun.

from qiskit.transpiler import generate_preset_pass_manager

pm = generate_preset_pass_manager(optimization_level=1, backend=backend)
isa_circuit = pm.run(circuit)
isa_observable = observable.apply_layout(isa_circuit.layout)
print(f">>> Circuit ops (ISA): {isa_circuit.count_ops()}")
>>> Circuit ops (ISA): OrderedDict([('rz', 3826), ('sx', 1601), ('cz', 968)])

3. Initialisiere Qiskit Runtime Estimator

Wenn du den Estimator initialisierst, verwende den Parameter mode, um den Modus anzugeben, in dem er ausgeführt werden soll. Mögliche Werte sind batch, session oder backend-Objekte für Batch-, Session- und Job-Ausführungsmodus. Weitere Informationen findest du unter Introduction to Qiskit Runtime execution modes.

from qiskit_ibm_runtime import EstimatorV2 as Estimator

estimator = Estimator(mode=backend)

4. Rufe den Estimator auf und erhalte Ergebnisse

Rufe als Nächstes die Methode run() auf, um Erwartungswerte für die Eingabe-Circuits und -Observables zu berechnen. Der Circuit, die Observable und optionale Parameterwertesätze werden als Primitive Unified Bloc (PUB)-Tupel eingegeben.

job = estimator.run([(isa_circuit, isa_observable, param_values)])
print(f">>> Job ID: {job.job_id()}")
print(f">>> Job Status: {job.status()}")
>>> Job ID: d5k96c4jt3vs73ds5smg
>>> Job Status: QUEUED
result = job.result()
print(f">>> {result}")
print(f" > Expectation value: {result[0].data.evs}")
print(f" > Metadata: {result[0].metadata}")
>>> PrimitiveResult([PubResult(data=DataBin(evs=np.ndarray(<shape=(), dtype=float64>), stds=np.ndarray(<shape=(), dtype=float64>), ensemble_standard_error=np.ndarray(<shape=(), dtype=float64>)), metadata={'shots': 4096, 'target_precision': 0.015625, 'circuit_metadata': {}, 'resilience': {}, 'num_randomizations': 32})], metadata={'dynamical_decoupling': {'enable': False, 'sequence_type': 'XX', 'extra_slack_distribution': 'middle', 'scheduling_method': 'alap'}, 'twirling': {'enable_gates': False, 'enable_measure': True, 'num_randomizations': 'auto', 'shots_per_randomization': 'auto', 'interleave_randomizations': True, 'strategy': 'active-accum'}, 'resilience': {'measure_mitigation': True, 'zne_mitigation': False, 'pec_mitigation': False}, 'version': 2})
> Expectation value: 25.8930784649363
> Metadata: {'shots': 4096, 'target_precision': 0.015625, 'circuit_metadata': {}, 'resilience': {}, 'num_randomizations': 32}

Erste Schritte mit Sampler

1. Initialisiere das Konto

Da Qiskit Runtime Sampler ein verwalteter Dienst ist, musst du zunächst dein Konto initialisieren. Anschließend kannst du die QPU auswählen, die du zur Berechnung des Erwartungswerts verwenden möchtest.

Folge den Schritten im Thema Install and set up topic, wenn du noch kein Konto eingerichtet hast.

from qiskit_ibm_runtime import QiskitRuntimeService

service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=127
)

2. Erstelle einen Circuit

Du benötigst mindestens einen Circuit als Eingabe für das Sampler-Primitive.

import numpy as np
from qiskit.circuit.library import efficient_su2

circuit = efficient_su2(127, entanglement="linear")
circuit.measure_all()
# The circuit is parametrized, so we will define the parameter values for execution
param_values = np.random.rand(circuit.num_parameters)

Verwende den Transpiler, um einen ISA-Circuit zu erhalten.

from qiskit.transpiler import generate_preset_pass_manager

pm = generate_preset_pass_manager(optimization_level=1, backend=backend)
isa_circuit = pm.run(circuit)
print(f">>> Circuit ops (ISA): {isa_circuit.count_ops()}")
>>> Circuit ops (ISA): OrderedDict([('sx', 3089), ('rz', 3036), ('cz', 1092), ('measure', 127), ('barrier', 1)])

3. Initialisiere den Qiskit Runtime Sampler

Wenn du den Sampler initialisierst, verwende den Parameter mode, um den Modus anzugeben, in dem er ausgeführt werden soll. Mögliche Werte sind batch, session oder backend-Objekte für Batch-, Session- und Job-Ausführungsmodus. Weitere Informationen findest du unter Introduction to Qiskit Runtime execution modes. Beachte, dass Open Plan-Benutzer keine Session-Jobs übermitteln können.

from qiskit_ibm_runtime import SamplerV2 as Sampler

sampler = Sampler(mode=backend)

4. Rufe den Sampler auf und erhalte Ergebnisse

Rufe als Nächstes die Methode run() auf, um die Ausgabe zu generieren. Der Circuit und optionale Parameterwertesätze werden als Primitive Unified Bloc (PUB)-Tupel eingegeben.

job = sampler.run([(isa_circuit, param_values)])
print(f">>> Job ID: {job.job_id()}")
print(f">>> Job Status: {job.status()}")
>>> Job ID: d5k96rsjt3vs73ds5tig
>>> Job Status: QUEUED
result = job.result()

# Get results for the first (and only) PUB
pub_result = result[0]
print(
f"First ten results for the 'meas' output register: {pub_result.data.meas.get_bitstrings()[:10]}"
)
First ten results for the 'meas' output register: ['0101001101010000011001110001011000010010001100001000100110011111011110000010110001101000110011101010000100011011000110101111000', '0100111000000100110001100100000101111000111001101000110111101110110010010100001101001111001010011101010000010011000110000010001', '0101111101111111010011010101000000110100000010000010011101100011100011001100000100100001000101000000100001010101010011001101100', '1100110101111111001110010000010100101010101010001000001100100110011111010000000010001000110111010000010101100000100000110111001', '0010000001111001111010100100010111101000101000100000101100001000011100000100011010110110100011100110001001110110111101010011000', '0101110000001000100100010010100100111000010100000000010010000000010110010010000110000001110110010100000111001110100100111101100', '0100011111101001000111110011011101101101110101110001010111011101111110011101001000000001110000011110000101010000001010000100000', '0001010101011000110100000100111111100001011000111110000011000111001101010000010001001100000110000000100000110101010010101110010', '0100011010001110011110000110100101100100101001001111010100100101010100010000000010100000101010110010000000001000010101011111110', '0000011000000111000001000101111111110110101100110000001100010010011101011100001010000100011010001010001101000000000000010001001']

Erste Schritte mit Backend-Primitives

Im Gegensatz zu anbieterspezifischen Primitives sind Backend-Primitives generische Implementierungen, die mit einem beliebigen backend-Objekt verwendet werden können, solange es die Backend-Schnittstelle implementiert.

Einige Anbieter implementieren Primitives nativ. Einzelheiten findest du auf der Qiskit Ecosystem-Seite.

Beispiel: BackendEstimator

from qiskit.primitives import BackendEstimatorV2
from <some_qiskit_provider> import QiskitProvider

provider = QiskitProvider()
backend = provider.get_backend('backend_name')
estimator = BackendEstimatorV2(backend)

Beispiel: BackendSampler

from qiskit.primitives import BackendSamplerV2
from <some_qiskit_provider> import QiskitProvider

provider = QiskitProvider()
backend = provider.get_backend('backend_name')
sampler = BackendSamplerV2(backend)

Gemeinsamkeiten und Unterschiede zwischen Backend- und Runtime-Primitives

Nächste Schritte

Empfehlungen