Aller au contenu principal

Débuter avec les primitives

Nouveau modèle d'exécution, maintenant en version bêta

La version bêta d'un nouveau modèle d'exécution est désormais disponible. Le modèle d'exécution dirigée offre plus de flexibilité pour personnaliser ton workflow d'atténuation des erreurs. Consulte le guide Modèle d'exécution dirigée pour plus d'informations.

remarque

Bien que cette documentation utilise les primitives de Qiskit Runtime, qui te permettent d'utiliser les backends IBM®, les primitives peuvent être exécutées avec n'importe quel fournisseur en utilisant les primitives backend à la place. De plus, tu peux utiliser les primitives de référence pour exécuter sur un simulateur statevector local. Consulte Simulation exacte avec les primitives Qiskit pour les détails.

# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-ibm-runtime

Les étapes décrites dans ce sujet expliquent comment configurer les primitives, explorer les options disponibles pour les paramétrer, et les invoquer dans un programme.

Utiliser les portes fractionnelles

Pour utiliser les portes fractionnelles nouvellement prises en charge, définis use_fractional_gates=True lors de la demande d'un backend à partir d'une instance QiskitRuntimeService. Par exemple :

service = QiskitRuntimeService()
fractional_gate_backend = service.least_busy(use_fractional_gates=True)

Note que cette fonctionnalité est expérimentale et pourrait changer à l'avenir.

Versions des packages

Le code sur cette page a été développé avec les dépendances suivantes. Nous recommandons d'utiliser ces versions ou des versions plus récentes.

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

Débuter avec Estimator

1. Initialiser le compte

Comme Qiskit Runtime Estimator est un service géré, tu dois d'abord initialiser ton compte. Tu peux ensuite sélectionner le QPU que tu souhaites utiliser pour calculer la valeur d'espérance.

Suis les étapes du sujet Installation et configuration si tu n'as pas encore de compte.

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. Créer un circuit et un observable

Tu as besoin d'au moins un circuit et un observable comme entrées pour la primitive Estimator.

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...', ...]

Le circuit et l'observable doivent être transformés pour n'utiliser que les instructions prises en charge par le QPU (appelées circuits à architecture d'ensemble d'instructions (ISA)). Nous allons utiliser le transpileur pour ce faire.

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. Initialiser Qiskit Runtime Estimator

Lors de l'initialisation d'Estimator, utilise le paramètre mode pour spécifier le mode dans lequel tu souhaites l'exécuter. Les valeurs possibles sont des objets batch, session ou backend pour les modes d'exécution par lot, session et job, respectivement. Pour plus d'informations, consulte Introduction aux modes d'exécution de Qiskit Runtime.

from qiskit_ibm_runtime import EstimatorV2 as Estimator

estimator = Estimator(mode=backend)

4. Invoquer Estimator et obtenir les résultats

Ensuite, invoque la méthode run() pour calculer les valeurs d'espérance pour les circuits d'entrée et les observables. Le circuit, l'observable et les ensembles de valeurs de paramètres optionnels sont fournis sous forme de tuples primitive unified bloc (PUB).

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}

Débuter avec Sampler

1. Initialiser le compte

Comme Qiskit Runtime Sampler est un service géré, tu dois d'abord initialiser ton compte. Tu peux ensuite sélectionner le QPU que tu souhaites utiliser pour calculer la valeur d'espérance.

Suis les étapes du sujet Installation et configuration si tu n'as pas encore de compte configuré.

from qiskit_ibm_runtime import QiskitRuntimeService

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

2. Créer un circuit

Tu as besoin d'au moins un circuit comme entrée pour la primitive Sampler.

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)

Utilise le transpileur pour obtenir un circuit ISA.

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. Initialiser le Qiskit Runtime Sampler

Lors de l'initialisation du Sampler, utilise le paramètre mode pour spécifier le mode dans lequel tu souhaites l'exécuter. Les valeurs possibles sont des objets batch, session ou backend pour les modes d'exécution par lot, session et job, respectivement. Pour plus d'informations, consulte Introduction aux modes d'exécution de Qiskit Runtime. Note que les utilisateurs du plan Open ne peuvent pas soumettre de jobs de session.

from qiskit_ibm_runtime import SamplerV2 as Sampler

sampler = Sampler(mode=backend)

4. Invoquer le Sampler et obtenir les résultats

Ensuite, invoque la méthode run() pour générer la sortie. Le circuit et les ensembles de valeurs de paramètres optionnels sont fournis sous forme de tuples primitive unified bloc (PUB).

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']

Débuter avec les primitives backend

Contrairement aux primitives propres à un fournisseur, les primitives backend sont des implémentations génériques utilisables avec n'importe quel objet backend, à condition qu'il implémente l'interface Backend.

Certains fournisseurs implémentent les primitives nativement. Consulte la page de l'écosystème Qiskit pour les détails.

Exemple : BackendEstimator

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

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

Exemple : BackendSampler

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

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

Similitudes et différences entre les primitives backend et Runtime

Prochaines étapes

Recommandations