Vai al contenuto principale

Simulazione efficiente di circuiti stabilizzatori con le primitive di Qiskit Aer

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-aer~=0.17

Questa pagina mostra come usare le primitive di Qiskit Aer per simulare in modo efficiente circuiti stabilizzatori, inclusi quelli soggetti a rumore di Pauli.

I circuiti stabilizzatori, noti anche come circuiti di Clifford, sono un'importante classe ristretta di circuiti quantistici che possono essere simulati in modo efficiente su hardware classico. Esistono diversi modi equivalenti per definire i circuiti stabilizzatori. Una definizione è che un circuito stabilizzatore è un circuito quantistico composto esclusivamente dai seguenti gate:

Nota che usando Hadamard e S è possibile costruire qualsiasi gate di rotazione di Pauli (RxR_x, RyR_y e RzR_z) con un angolo appartenente all'insieme {0,π2,π,3π2}\{0, \frac{\pi}{2}, \pi, \frac{3\pi}{2}\} (a meno di una fase globale), quindi è possibile includere questi gate nella definizione.

I circuiti stabilizzatori sono fondamentali per lo studio della correzione degli errori quantistici. La loro simulabilità classica li rende inoltre utili per verificare l'output dei computer quantistici. Supponiamo, per esempio, di voler eseguire su un computer quantistico un circuito che usa 100 qubit. Come possiamo sapere che il computer quantistico si sta comportando correttamente? Un circuito quantistico su 100 qubit è al di là delle capacità della simulazione classica per forza bruta. Modificando il circuito in modo che diventi un circuito stabilizzatore, puoi eseguire circuiti sul computer quantistico con una struttura simile al circuito desiderato, ma che puoi simulare su un computer classico. Verificando l'output del computer quantistico sui circuiti stabilizzatori, puoi acquistare fiducia nel fatto che si stia comportando correttamente anche sui circuiti non stabilizzatori. Vedi Evidence for the utility of quantum computing before fault tolerance per un esempio pratico di questa idea.

Simulazione esatta e rumorosa con le primitive di Qiskit Aer mostra come usare Qiskit Aer per eseguire simulazioni esatte e rumorose di circuiti quantistici generici. Considera il circuito di esempio usato in quell'articolo, un circuito a 8 qubit costruito con efficient_su2:

# Added by doQumentation — required packages for this notebook
!pip install -q numpy 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

Con Qiskit Aer siamo riusciti a simulare questo circuito facilmente. Supponiamo ora di impostare il numero di qubit a 500:

n_qubits = 500
circuit = efficient_su2(n_qubits)
# don't try to draw the circuit because it's too large

Poiché il costo della simulazione di circuiti quantistici cresce esponenzialmente con il numero di qubit, un circuito così grande supererebbe generalmente le capacità persino di un simulatore ad alte prestazioni come Qiskit Aer. La simulazione classica di circuiti quantistici generici diventa impraticabile quando il numero di qubit supera approssimativamente 50-100 qubit. Nota però che il circuito efficient_su2 è parametrizzato da angoli sui gate RyR_y e RzR_z. Se tutti questi angoli appartengono all'insieme {0,π2,π,3π2}\{0, \frac{\pi}{2}, \pi, \frac{3\pi}{2}\}, allora il circuito è un circuito stabilizzatore e può essere simulato in modo efficiente!

Nella cella seguente, eseguiamo il circuito con la primitiva Sampler supportata dal simulatore di circuiti stabilizzatori, usando parametri scelti casualmente in modo che il circuito sia garantito essere un circuito stabilizzatore.

import numpy as np
from qiskit.transpiler import generate_preset_pass_manager
from qiskit_aer import AerSimulator
from qiskit_aer.primitives import SamplerV2 as Sampler

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

rng = np.random.default_rng(1234)
params = rng.choice(
[0, np.pi / 2, np.pi, 3 * np.pi / 2],
size=circuit.num_parameters,
)

# Initialize a Sampler backed by the stabilizer circuit simulator
exact_sampler = Sampler(
options=dict(backend_options=dict(method="stabilizer"))
)
# The circuit needs to be transpiled to the AerSimulator target
pass_manager = generate_preset_pass_manager(
1, AerSimulator(method="stabilizer")
)
isa_circuit = pass_manager.run(measured_circuit)
pub = (isa_circuit, params)
job = exact_sampler.run([pub])
result = job.result()
pub_result = result[0]
counts = pub_result.data.meas.get_counts()

Il simulatore di circuiti stabilizzatori supporta anche la simulazione rumorosa, ma solo per una classe ristretta di modelli di rumore. In particolare, qualsiasi rumore quantistico deve essere caratterizzato da un canale di errore di Pauli. L'errore depolarizzante rientra in questa categoria, quindi può essere simulato anch'esso. Possono essere simulati anche i canali di rumore classici come l'errore di readout.

La cella di codice seguente esegue la stessa simulazione di prima, ma questa volta specificando un modello di rumore che aggiunge un errore depolarizzante del 2% a ogni gate CX, oltre a un errore di readout che ribalta ogni bit misurato con probabilità del 5%.

from qiskit_aer.noise import NoiseModel, depolarizing_error, ReadoutError

noise_model = NoiseModel()
cx_depolarizing_prob = 0.02
bit_flip_prob = 0.05
noise_model.add_all_qubit_quantum_error(
depolarizing_error(cx_depolarizing_prob, 2), ["cx"]
)
noise_model.add_all_qubit_readout_error(
ReadoutError(
[
[1 - bit_flip_prob, bit_flip_prob],
[bit_flip_prob, 1 - bit_flip_prob],
]
)
)

noisy_sampler = Sampler(
options=dict(
backend_options=dict(method="stabilizer", noise_model=noise_model)
)
)
job = noisy_sampler.run([pub])
result = job.result()
pub_result = result[0]
counts = pub_result.data.meas.get_counts()

Ora, usiamo la primitiva Estimator supportata dal simulatore stabilizzatore per calcolare il valore di aspettazione dell'osservabile ZZ⋯ZZZ \cdots Z. Grazie alla struttura speciale dei circuiti stabilizzatori, il risultato sarà molto probabilmente 0.

from qiskit.quantum_info import SparsePauliOp
from qiskit_aer.primitives import EstimatorV2 as Estimator

observable = SparsePauliOp("Z" * n_qubits)

exact_estimator = Estimator(
options=dict(backend_options=dict(method="stabilizer")),
)
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.0

Passi successivi​

Raccomandazioni