Iniziare con le primitive
La versione beta di un nuovo modello di esecuzione è ora disponibile. Il modello di esecuzione diretta offre maggiore flessibilità nella personalizzazione del workflow di mitigazione degli errori. Consulta la guida al Modello di esecuzione diretta per ulteriori informazioni.
Sebbene questa documentazione utilizzi le primitive di Qiskit Runtime, che ti permettono di usare i backend IBM®, le primitive possono essere eseguite con qualsiasi provider usando invece le primitive backend. Inoltre, puoi usare le primitive reference per eseguire su un simulatore statevector locale. Consulta Simulazione esatta con le primitive Qiskit per i dettagli.
# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-ibm-runtime
I passi descritti in questo argomento spiegano come configurare le primitive, esplorare le opzioni disponibili per configurarle e invocarle in un programma.
Per usare i fractional gates recentemente supportati, imposta use_fractional_gates=True quando richiedi un backend da un'istanza di QiskitRuntimeService. Per esempio:
service = QiskitRuntimeService()
fractional_gate_backend = service.least_busy(use_fractional_gates=True)
Nota che questa è una funzionalità sperimentale e potrebbe cambiare in futuro.
Versioni dei pacchetti
Il codice in questa pagina è stato sviluppato usando i seguenti requisiti. Si consiglia di usare queste versioni o versioni più recenti.
qiskit[all]~=2.3.0
qiskit-ibm-runtime~=0.43.1
Iniziare con Estimator​
1. Inizializzare l'account​
Poiché Qiskit Runtime Estimator è un servizio gestito, devi prima inizializzare il tuo account. Puoi quindi selezionare il QPU che vuoi usare per calcolare il valore atteso.
Segui i passi nell'argomento Installazione e configurazione se non hai ancora un account.
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. Creare un circuito e un'osservabile​
Hai bisogno di almeno un circuito e un'osservabile come input per la primitiva 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...', ...]
Il circuito e l'osservabile devono essere trasformati in modo da usare solo le istruzioni supportate dal QPU (denominati circuiti con instruction set architecture (ISA)). Useremo il transpiler per farlo.
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. Inizializzare Qiskit Runtime Estimator​
Quando inizializzi Estimator, usa il parametro mode per specificare la modalità in cui vuoi eseguirlo. I valori possibili sono oggetti batch, session o backend per la modalità di esecuzione in batch, in sessione e per singolo job, rispettivamente. Per ulteriori informazioni, consulta Introduzione alle modalità di esecuzione di Qiskit Runtime.
from qiskit_ibm_runtime import EstimatorV2 as Estimator
estimator = Estimator(mode=backend)
4. Invocare Estimator e ottenere i risultati​
Successivamente, invoca il metodo run() per calcolare i valori attesi per i circuiti e le osservabili di input. Il circuito, l'osservabile e gli eventuali set di valori dei parametri vengono passati come tuple 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}
Iniziare con Sampler​
1. Inizializzare l'account​
Poiché Qiskit Runtime Sampler è un servizio gestito, devi prima inizializzare il tuo account. Puoi quindi selezionare il QPU che vuoi usare per calcolare il valore atteso.
Segui i passi nell'argomento Installazione e configurazione se non hai ancora configurato un account.
from qiskit_ibm_runtime import QiskitRuntimeService
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=127
)
2. Creare un circuito​
Hai bisogno di almeno un circuito come input per la primitiva 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)
Usa il transpiler per ottenere un circuito 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. Inizializzare Qiskit Runtime Sampler​
Quando inizializzi Sampler, usa il parametro mode per specificare la modalità in cui vuoi eseguirlo. I valori possibili sono oggetti batch, session o backend per la modalità di esecuzione in batch, in sessione e per singolo job, rispettivamente. Per ulteriori informazioni, consulta Introduzione alle modalità di esecuzione di Qiskit Runtime. Nota che gli utenti del piano Open non possono inviare job in sessione.
from qiskit_ibm_runtime import SamplerV2 as Sampler
sampler = Sampler(mode=backend)
4. Invocare Sampler e ottenere i risultati​
Successivamente, invoca il metodo run() per generare l'output. Il circuito e gli eventuali set di valori dei parametri vengono passati come tuple 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']
Iniziare con le primitive backend​
A differenza delle primitive specifiche per un provider, le primitive backend sono implementazioni generiche che possono essere usate con un qualsiasi oggetto backend, purché implementi l'interfaccia Backend.
- La primitiva Sampler può essere eseguita con qualsiasi provider usando
qiskit.primitives.BackendSamplerV2. - La primitiva Estimator può essere eseguita con qualsiasi provider usando
qiskit.primitives.BackendEstimatorV2.
Alcuni provider implementano le primitive in modo nativo. Consulta la pagina dell'ecosistema Qiskit per i dettagli.
Esempio: BackendEstimator​
from qiskit.primitives import BackendEstimatorV2
from <some_qiskit_provider> import QiskitProvider
provider = QiskitProvider()
backend = provider.get_backend('backend_name')
estimator = BackendEstimatorV2(backend)
Esempio: BackendSampler​
from qiskit.primitives import BackendSamplerV2
from <some_qiskit_provider> import QiskitProvider
provider = QiskitProvider()
backend = provider.get_backend('backend_name')
sampler = BackendSamplerV2(backend)
Somiglianze e differenze tra le primitive backend e quelle Runtime​
-
Gli input e gli output di
qiskit.primitives.BackendSamplerV2eqiskit.primitives.BackendEstimatorV2seguono lo stesso formato PUB delle primitive in Qiskit Runtime. Consulta Input e output delle primitive per i dettagli. Possono tuttavia esserci differenze nei campi dei metadati restituiti. -
La classe
qiskit.primitives.BackendEstimatorV2non offre implementazioni predefinite di mitigazione degli errori di misura o di gate, poiché le primitive backend sono progettate per essere eseguite localmente sul computer dell'utente. -
La classe
qiskit.primitives.BackendSamplerV2richiede un backend che supporti l'opzionememory. -
Le interfacce delle primitive backend espongono
Optionspersonalizzate perSamplerV2edEstimatorV2che differiscono dalle implementazioni Runtime.
Passi successivi​
- Scopri come testare localmente prima di eseguire su computer quantistici.
- Consulta esempi dettagliati sulle primitive.
- Esercitati con le primitive svolgendo la lezione sulla funzione di costo in IBM Quantum Learning.
- Scopri come effettuare il transpiling localmente nella sezione Transpile.
- Prova la guida Confrontare le impostazioni del transpiler.
- Scopri come usare le opzioni delle primitive.
- Visualizza le API per le opzioni di Sampler ed Estimator.
- Leggi Migrazione alle primitive V2.