Vai al contenuto principale

Simulazione esatta e rumorosa con le primitive di Qiskit Aer

Versioni dei pacchetti

Il codice in questa pagina è stato sviluppato utilizzando i seguenti requisiti. Si consiglia di usare queste versioni o versioni più recenti.

qiskit[all]~=2.3.0
qiskit-aer~=0.17

La simulazione esatta con le primitive di Qiskit mostra come usare le primitive di riferimento incluse in Qiskit per eseguire la simulazione esatta di circuiti quantistici. I processori quantistici attualmente esistenti sono soggetti a errori, o rumore, quindi i risultati di una simulazione esatta non riflettono necessariamente i risultati che ti aspetteresti eseguendo i circuiti su hardware reale. Mentre le primitive di riferimento in Qiskit non supportano la modellazione del rumore, Qiskit Aer include implementazioni delle primitive che supportano la modellazione del rumore. Qiskit Aer è un simulatore di circuiti quantistici ad alte prestazioni che puoi usare al posto delle primitive di riferimento per ottenere prestazioni migliori e più funzionalità. Fa parte del Qiskit Ecosystem. In questo articolo, dimostriamo l'uso delle primitive di Qiskit Aer per la simulazione esatta e rumorosa.

Note
  • È richiesta la versione qiskit-aer v0.14 o successiva.
  • Sebbene le primitive di Qiskit Aer implementino le interfacce primitive, non forniscono le stesse opzioni delle primitive di Qiskit Runtime. Il livello di resilienza, ad esempio, non è disponibile con le primitive di Qiskit Aer.
  • Consulta la documentazione di AerSimulator per i dettagli sulle opzioni del metodo di simulazione supportate da Aer.

Per esplorare la simulazione esatta e rumorosa, crea un circuito di esempio su otto qubit:

# Added by doQumentation — required packages for this notebook
!pip install -q qiskit qiskit-aer
from qiskit.circuit.library import efficient_su2

n_qubits = 8
circuit = efficient_su2(n_qubits)
circuit.draw("mpl")

Output della cella di codice precedente

Questo circuito contiene parametri per rappresentare gli angoli di rotazione dei gate RyR_y e RzR_z. Quando si simula questo circuito, è necessario specificare valori espliciti per questi parametri. Nella cella successiva, specifichiamo alcuni valori per questi parametri e usiamo la primitiva Estimator di Qiskit Aer per calcolare il valore di aspettazione esatto dell'osservabile ZZZZZ \cdots Z.

from qiskit.quantum_info import SparsePauliOp
from qiskit.transpiler import generate_preset_pass_manager
from qiskit_aer import AerSimulator
from qiskit_aer.primitives import EstimatorV2 as Estimator

observable = SparsePauliOp("Z" * n_qubits)
params = [0.1] * circuit.num_parameters

exact_estimator = Estimator()
# The circuit needs to be transpiled to the AerSimulator target
pass_manager = generate_preset_pass_manager(3, AerSimulator())
isa_circuit = pass_manager.run(circuit)
pub = (isa_circuit, observable, params)
job = exact_estimator.run([pub])
result = job.result()
pub_result = result[0]
exact_value = float(pub_result.data.evs)
exact_value
0.8870140234256602

Adesso, inizializziamo un modello di rumore che include un errore di depolarizzazione del 2% su ogni gate CX. In pratica, l'errore derivante dai gate a due qubit — che qui sono gate CX — è la fonte di errore dominante quando si esegue un circuito. Consulta Costruire modelli di rumore per una panoramica sulla costruzione di modelli di rumore in Qiskit Aer.

Nella cella successiva, costruiamo un Estimator che incorpora questo modello di rumore e lo usiamo per calcolare il valore di aspettazione dell'osservabile.

from qiskit_aer.noise import NoiseModel, depolarizing_error

noise_model = NoiseModel()
cx_depolarizing_prob = 0.02
noise_model.add_all_qubit_quantum_error(
depolarizing_error(cx_depolarizing_prob, 2), ["cx"]
)

noisy_estimator = Estimator(
options=dict(backend_options=dict(noise_model=noise_model))
)
job = noisy_estimator.run([pub])
result = job.result()
pub_result = result[0]
noisy_value = float(pub_result.data.evs)
noisy_value
0.7247404214143528

Come puoi vedere, il valore di aspettazione in presenza del rumore è abbastanza lontano dal valore corretto. In pratica, puoi impiegare una varietà di tecniche di mitigazione degli errori per contrastare gli effetti del rumore, ma la discussione di queste tecniche va oltre lo scopo di questo articolo.

Per avere un'idea molto approssimativa di come il rumore influisce sul risultato finale, considera il nostro modello di rumore, che aggiunge un errore di depolarizzazione del 2% a ogni gate CX. L'errore di depolarizzazione con probabilità pp è definito come un canale quantistico EE che ha la seguente azione su una matrice densità ρ\rho:

E(ρ)=(1p)ρ+pI2nE(\rho) = (1 - p) \rho + p\frac{I}{2^n}

dove nn è il numero di qubit, in questo caso 2. Ovvero, con probabilità pp, lo stato viene sostituito con lo stato completamente misto, e lo stato viene preservato con probabilità 1p1 - p. Dopo mm applicazioni del canale di depolarizzazione, la probabilità che lo stato venga preservato sarebbe (1p)m(1 - p)^m. Pertanto, ci aspettiamo che la probabilità di conservare lo stato corretto alla fine della simulazione diminuisca esponenzialmente con il numero di gate CX nel nostro circuito.

Contiamo il numero di gate CX nel nostro circuito e calcoliamo (1p)m(1 - p)^m. Chiamiamo count_ops per ottenere un dizionario che mappa i nomi dei gate ai conteggi, e recuperiamo la voce per il gate CX.

cx_count = circuit.count_ops()["cx"]
(1 - cx_depolarizing_prob) ** cx_count
0.6542558123199923

Questo valore, 65%, fornisce una stima approssimativa della probabilità che il nostro stato finale sia corretto. È una stima conservativa perché non tiene conto dello stato iniziale della simulazione.

La seguente cella di codice mostra come usare la primitiva Sampler di Qiskit Aer per campionare dal circuito rumoroso. Dobbiamo aggiungere le misurazioni al circuito prima di eseguirlo con la primitiva Sampler.

from qiskit_aer.primitives import SamplerV2 as Sampler

measured_circuit = circuit.copy()
measured_circuit.measure_all()

noisy_sampler = Sampler(
options=dict(backend_options=dict(noise_model=noise_model))
)
# The circuit needs to be transpiled to the AerSimulator target
pass_manager = generate_preset_pass_manager(3, AerSimulator())
isa_circuit = pass_manager.run(measured_circuit)
pub = (isa_circuit, params, 100)
job = noisy_sampler.run([pub])
result = job.result()
pub_result = result[0]
pub_result.data.meas.get_counts()
{'00100000': 1,
'00000000': 65,
'10101000': 1,
'10000000': 5,
'00001000': 1,
'00000110': 2,
'11110010': 1,
'00000011': 3,
'01010000': 3,
'11000000': 3,
'01111000': 1,
'01000000': 2,
'00000010': 1,
'01100000': 1,
'00011000': 1,
'00111100': 1,
'00010100': 1,
'00001111': 1,
'00110000': 1,
'01100101': 1,
'00000100': 1,
'10100000': 1,
'00000001': 1,
'11010000': 1}

Passi successivi

Raccomandazioni