La correzione degli errori quantistici, nota anche come QEC, è una delle aree di ricerca più attive nell’informatica quantistica odierna. L’obiettivo della QEC è proteggere le fragili informazioni quantistiche, memorizzate nei qubit, dal rumore e dalla decoerenza.
La misura dell’affidabilità di un qubit si basa sulla probabilità di errore, e i qubit fisici odierni sono in grado di raggiungere un ordine di grandezza di circa 1 errore ogni 10.000 (\(10^{-4}\)) operazioni di gate. Tuttavia, per essere pienamente efficiente, il tasso di errore dei gate deve essere in grado di raggiungere almeno 1 su 1 miliardo (\(10^{-9}\)), o addirittura uno su un trilione (\(10^{-12}\)).

Questo promemoria si propone di fornire una guida leggera e concisa alla comprensione della correzione degli errori quantistici (QEC) da una prospettiva implementativa. La prima sezione offre una panoramica dei diversi metodi di calcolo per la correzione degli errori necessari alla creazione di qubit logici. La seconda sezione esamina la potenziale implementazione di operazioni di gate su qubit logicamente corretti. Infine, l’ultima sezione introduce il framework Cuda-QEC e il suo approccio programmatico per la creazione di sistemi di correzione degli errori quantistici.
Quali problemi si propone di risolvere QEC e in che modo? Link to heading
La sfida per la correzione degli errori quantistici (QEC) è, a prima vista, semplice: innanzitutto rilevare quando si è verificato un errore e poi correggerlo. Solo che questo deve avvenire senza mai misurare o far collassare gli stati quantistici dei qubit. È qui che entra in gioco il concetto di qubit ausiliari entangled:
Invece di memorizzare le informazioni in un singolo qubit, QEC codifica un qubit logico su più qubit fisici, suddivisi in due categorie: qubit dati e qubit ausiliari (noti anche come qubit di misura). Il gruppo di qubit forma uno stato entangled tale da rendere possibile la lettura dei qubit ausiliari senza far collassare lo stato del qubit dati. Nell’immagine sottostante, la linea rossa mostra diverse possibili mappature dei qubit logici al qubit fisico.

Modus Operandi Link to heading
Supponiamo di voler correggere un errore in un qubit logico, codificato in più qubit fisici. Quando si verifica un errore, uno dei qubit fisici potrebbe subire un’inversione, sia sotto forma di inversione di bit (X), sia sotto forma di inversione di fase (Z), o entrambe (Y).
Per verificare la presenza di inversioni di stato, QEC esegue misurazioni periodiche della sindrome, che prevedono la misurazione di specifici qubit ausiliari che interagiscono con i qubit dati. Il qubit ausiliario viene prima entangled con il qubit dati, e poi viene effettuata la lettura. L’entanglement dura per un breve periodo, giusto il tempo necessario per eseguire la lettura. Nel caso di Google, questo entanglement viene ottenuto utilizzando porte CZ (control-Z), che a loro volta utilizzano anch’esse l’entanglement.
(fonte immagine: Google Quantum AI - Implementazione di qubit logici a codice di superficie)
Una volta ottenute le sindromi, è possibile eseguire la correzione; a tal fine, un algoritmo classico determina il probabile errore che si è verificato. Il sistema applica quindi la correzione appropriata (porta X, Y o Z). Nel caso di Google, viene utilizzato un ulteriore disaccoppiamento dinamico (DD) per attenuare gli errori di defasamento (T2?).
Codici quantistici Link to heading
I qubit di dati e di misura sono distribuiti in modo non locale, in maniera tale che un errore su uno o due qubit non comprometta la coerenza del gruppo. Questa distribuzione è definita codice quantistico. I sistemi reali utilizzano codici più grandi e sofisticati:
Codice Shor (9 qubit): corregge sia gli errori di inversione di bit che quelli di inversione di fase.
Codice Steane (7 qubit): il primo codice di correzione degli errori completamente quantistico.
Codici di superficie (\(2n^2-1\) qubit)— Dispone i qubit su una griglia 2D. La distanza del codice di superficie \(n\) si riferisce a quanti errori possono essere corretti contemporaneamente
In pratica, ogni qubit di misura è responsabile della misurazione proiettiva di un operatore stabilizzatore, utilizzato per la logica decisionale dell’algoritmo classico. Un codice stabilizzatore è la generalizzazione quantistica dei codici lineari nella correzione degli errori classica, che utilizza controlli di parità per rilevare errori sui bit di rumore.
Come eseguire un algoritmo quantistico su qubit logici? Link to heading
Eseguire un algoritmo quantistico su qubit fisici significa operare dei gate su qubit fisici. Ma cosa succede quando si ha a che fare con i qubit logici? Questa potrebbe sembrare una domanda semplice, ma la risposta non è così scontata, e ci sono diversi modi per affrontare i gate sui qubit logici. Iniziamo con i gate a singolo qubit e in seguito affronteremo la sfida dei gate a più qubit.
Applicazione di porte a singolo qubit ai qubit logici Link to heading
Tipi di implementazione delle porte logiche:
- porte trasversali: Una porta trasversale agisce indipendentemente su ciascun qubit fisico.
Una porta logica per qubit equivale ad applicare la stessa porta a ciascuno degli n qubit fisici. Ad esempio, con il codice di Steane a 7 qubit, una porta logica di Hadamard viene implementata applicando una porta fisica H a ciascuno dei 7 qubit fisici.
Nei codici di superficie, i qubit logici sono codificati come grandi porzioni di qubit fisici. Le operazioni logiche vengono implementate unendo e dividendo le porzioni o intrecciando i difetti, il che modifica la topologia del codice.
L’immagine a destra, tratta da arxiv.2505.15907, mostra un’operazione di chirurgia reticolare eseguita unendo due patch di codice lungo il bordo. Questa operazione richiede O(d) iterazioni per ottenere la tolleranza ai guasti.
Applicazione di porte multi-qubit ai qubit logici Link to heading
- Porte multi-qubit trasversali : molti codici quantistici (ad esempio, Steane, Bacon-Shor), CNOT logico possono essere eseguiti trasversalmente: \( CNOT_L=\sum_{i=1}^n CNOT(a_i,b_i) \)
Ovvero, per ogni qubit fisico \(a_i\) nel blocco di controllo, applicare un CNOT fisico al qubit corrispondente \( b_i \) nel blocco di destinazione.
- Porte logiche multi-qubit basate su qubit ausiliari : Quando un’implementazione trasversale non è possibile, le porte logiche multi-qubit possono essere realizzate tramite qubit ausiliari e circuiti di teletrasporto.
Ad esempio, la porta CCNOT (Toffoli) non può essere implementata trasversalmente nella maggior parte dei codici (*). Viene invece implementata creando stati magici, che sono stati “teletrasportati” in modo condizionale, ad esempio con un CNOT. Si noti che in tal caso, la porta di teletrasporto è un’operazione logica.
- Porte multi-qubit logiche nei codici di superficie : nei codici topologici come il codice di superficie, le porte multi-qubit vengono implementate in modo diverso a seconda della porta.
Ad esempio, CNOT tramite Lattice Surgery e CZ tramite Braiding.
Riepilogo Link to heading
L’applicazione di porte multi-qubit ai qubit logici avviene operando sui qubit fisici codificati secondo la struttura del codice:
Trasversale: Porte a coppie tra qubit fisici di blocchi logici.
Basato su ancilla: Utilizzare metodi di teletrasporto o di stato magico.
Topologico: Eseguire operazioni geometriche come intrecci o chirurgia reticolare.
Devo scusarmi con il lettore che ha avuto il coraggio di arrivare fin qui: questa sezione è un po’ superficiale e troppo vicina alla superficie, anziché un’analisi approfondita. Ciò che è necessario sapere per ora è che non esiste un’unica soluzione per la porta a singolo/multiplo qubit di un qubit logico, ma una serie di procedure applicabili a ciascuna porta e tipo di codice quantistico.
Approccio programmatico: il framework Cuda-QX QEC Link to heading

Nel 2024, il team Qutum di Nvidia ha introdotto CUDA-QX, come estensione della piattaforma open-source CUDA-Q, fornendo librerie ottimizzate per gli sviluppatori quantistici. Due delle librerie incluse in CUDA-QX sono CUDA-Q QEC (primitive e decodificatori per la correzione degli errori quantistici) e CUDA-Q Solvers (funzioni di supporto per VQE/ADAPT-VQE e QAOA).
Diamo un’occhiata rapida al loro approccio per esporre un’API programmatica per l’implementazione personalizzata della logica classica dell’operatore stabilizzatore. Di seguito è riportato un esempio minimo che implementa il decodificatore più semplice, utilizzato per rilevare errori di inversione di bit su un singolo qubit. Il decodificatore funziona verificando se la sindrome corrisponde a una singola colonna della matrice di parità Hz, nel qual caso il qubit viene rilevato come invertito:
import cudaq_qec as qec
def run_simple_code_capacity( nShots=1000, errorProbability=0.1 ):
steane = qec.get_code("steane") # get built-in Steane code from CUDA-Q QEC
parity_check_matrix = steane.get_parity_z() # parity-check matrix for Z (bit-flip) errors
observable = steane.get_observables_z() # Get the Pauli Z observables of the code
decoder = MyCustomDecoder(Hz) # instantiate custom decoder
nLogicalErrors = 0
for _ in range(nShots):
# Generate noisy data
data = qec.generate_random_bit_flips(Hz.shape[1], errorProbability)
# Calculate which syndromes are flagged.
syndrome = (parity_check_matrix @ data) % 2
# Decode the syndrome to predict what happened to the data
result = decoder.decode(syndrome)
data_prediction = np.array(result.result, dtype=np.uint8)
# See if this prediction flipped the observable
predicted_observable = (observable @ data_prediction) % 2
# See if the observable was actually flipped
actual_observable = observable @ data % 2
if (predicted_observable != actual_observable):
nLogicalErrors += 1
return nLogicalErrorsLa parte importante dell’algoritmo sopra descritto è che la matrice di parità e gli osservabili predetti vengono ottenuti dal codice quantistico steano predefinito. Un semplice decodificatore può quindi essere implementato in questo modo:
class SingleColumnMatchDecoder:
def __init__(self, Hz): # Hz is a parity-check matrix shape (nChecks, nDataQubits)
self.Hz = np.array(Hz) % 2
self.n_qubits = self.Hz.shape[1]
class SimpleDecoderResult:
def __init__(self):
self.result = np.zeros(self.n_qubits, dtype=np.uint8)
def flipped(self, q):
self.result[q]=1
return self
def decode(self, syndrome):
# ensure syndrome is 1D numpy array of length nChecks
s = np.asarray(syndrome).flatten() % 2
# Initialize the flip prediction list
prediction = SimpleDecoderResult()
# Compare to each column of Hz: if any column equals the syndrome, pick that qubit
for q in range(self.n_qubits):
col = self.Hz[:, q] % 2
if np.array_equal(col, s):
return prediction.flipped(q)
# no single-column match -> predict no flips (all zeros)
return predictionCon il decodificatore installato, è ora possibile eseguire l’algoritmo.
nShots = 1000
nLogicalErrors = run_simple_code_capacity(nShots)
print(f"Shots = {nShots}, Logical error rate ≈ {nLogicalErrors/nShots:.4f}")Come si può notare, il QEC di CUDA è essenzialmente guidato dalla fornitura di strumenti e librerie efficienti per implementare la logica di calcolo classica del QEC. La questione che rimane aperta è come questo QEC di CUDA possa essere connesso a un vero stack quantistico, e in particolare come i sindromi vengano comunicati dallo stack di controllo al decodificatore QEC, e come i decodificatori, a loro volta, informino lo stack di controllo sui gate correttivi da applicare. È qui che entra in gioco l’affascinante framework Cuda-Q, ma rimanderò questa indagine a una nota futura!
Conclusion Link to heading
Ecco, è chiaro che addentrarsi nel mondo della correzione degli errori quantistici è un lavoro a tempo pieno, quindi dovrò rimanere a un livello piuttosto elevato per non perdere slancio nell’architettura delle macchine per il calcolo quantistico. Per ora, mi chiedo se dovrei parlare di una macchina per il calcolo quantistico “logicamente corretta” o semplicemente di una “macchina per il calcolo quantistico affidabile”? Nel primo caso, l’enfasi è sul modello che rende la macchina corretta, mentre nel secondo, l’enfasi è sul comportamento.
Non mi è chiaro, come già accennato in un post precedente, se il QEC debba essere applicato come un’aggiunta all’algoritmo quantistico, ovvero se il compilatore incaricato di tradurre la sequenza di porte quantistiche in qualcosa di eseguibile dallo stack di controllo sia anche responsabile dell’“inlining” delle operazioni delle porte per ottenere la lettura del codice di superficie. Oppure se debba essere eseguito come un’operazione “in background” della “macchina di calcolo quantistico affidabile”?
Note Link to heading
- Se ti chiedi se si debba usare Ancillary o Auxiliary, allora il termine corretto è Ancillary (dal latino ancilla: serva), il cui significato è “fornire il supporto necessario a una funzione primaria”, mentre Auxiliary (dal latino auxilium: aiuto), il cui significato è “fornire ulteriore aiuto o supporto di riserva”.
Questa nota è stata aggiunta dopo la stesura del promemoria iniziale:
- Esiste un interessante tutorial su “Integrazione stretta di GPU e QPU per la correzione degli errori quantistici e il controllo ottimale” dell’IEEE QCE24, con una registrazione video disponibile qui, che sembra fornire molte risposte e spunti di riflessione alle domande aperte di cui sopra. Tratterò questo tutorial in una nota successiva. Per ora, l’idea è che un circuito possa essere riscritto per adattarsi a un dato codice quantistico, abbassato per adattarsi a una topologia a livello di superficie e post-elaborato per i gate che lo consentono (gate di Clifford).

References Link to heading
- Suppressing quantum errors by scaling a surface code logical qubit (video)
- Suppressing quantum errors by scaling a surface code logical qubit (article)
- Resource Analysis of Low-Overhead Transversal Architectures for Reconfigurable Atom Arrays
- How Tensor Network Simulators Can Contribute To Practical Quantum Error Correction
- A bird’s-eye view of quantum error correction and fault tolerance
- Making Quantum Error Correction practical
- Quantum Error Correction For Dummies
