Vai al contenuto principale

Iniziare con le primitive

Nuovo modello di esecuzione, ora in versione beta

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.

nota

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.

Utilizzo dei Fractional Gates

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.

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​

Passi successivi​

Raccomandazioni