La corrección de errores cuánticos, también conocida como QEC, es una de las áreas de investigación más activas en la computación cuántica actual. El objetivo de la QEC es proteger la información cuántica, frágil y almacenada en los cúbits, del ruido y la decoherencia.

La fiabilidad de un cúbit se mide en función de la probabilidad de error, y los cúbits físicos actuales pueden alcanzar un orden de magnitud de aproximadamente 1 error en 10 000 operaciones de puerta (10⁻⁴). Sin embargo, para ser totalmente eficientes, la tasa de error de puerta debe ser de al menos 1 en 1000 millones (10⁻⁹), o incluso 1 en un billón (10⁻¹²).

Este documento pretende ofrecer una guía concisa y clara para comprender la corrección de errores cuánticos (QEC) desde una perspectiva de implementación. La primera sección presenta una descripción general de los diferentes métodos de cálculo de corrección de errores necesarios para crear cúbits lógicos. La segunda sección examina la posible implementación de operaciones de compuerta en cúbits corregidos lógicamente. Finalmente, la última sección introduce el marco Cuda-QEC y su enfoque programático para crear sistemas de corrección de errores cuánticos.

¿Qué problema intenta resolver QEC y cómo? Link to heading

El desafío para QEC es, a primera vista, simple: primero detectar cuándo se ha producido un error y luego corregirlo. Excepto que esto debe ocurrir sin medir ni colapsar los estados cuánticos del cúbit. Aquí es donde entra en juego el concepto de cúbits ancilla entrelazados:

En lugar de almacenar información en un solo cúbit, QEC codifica un cúbit lógico en varios cúbits físicos, divididos en dos categorías: cúbits de datos y cúbits auxiliares (también conocidos como cúbits de medición). El grupo de cúbits forma un estado entrelazado que permite leer los cúbits auxiliares sin que se colapse el estado del cúbit de datos. En la imagen inferior, la línea roja muestra varias posibles asignaciones de cúbits lógicos al cúbit físico.

Modus Operandi Link to heading

Supongamos que queremos corregir un cúbit lógico, que está codificado en varios cúbits físicos. Cuando se produce un error, uno de los cúbits físicos puede cambiar de estado, ya sea mediante un cambio de bit (X), un cambio de fase (Z) o ambos (Y).

Para comprobar si existe un cambio de estado, QEC realiza mediciones periódicas de síndromes, que consisten en medir cúbits auxiliares específicos que interactúan con los cúbits de datos. El cúbit auxiliar se entrelaza primero con el cúbit de datos y, a continuación, se realiza la lectura. El entrelazamiento se lleva a cabo durante un breve periodo, el tiempo justo para que se pueda realizar la lectura. En el caso de Google, este entrelazamiento se consigue mediante puertas CZ (control-Z), que, a su vez, también utilizan el entrelazamiento.

Medición del cúbito Ancilla> (Fuente de la imagen: Google Quantum AI - Implementación de cúbitos lógicos de código de superficie)

Una vez identificados los síndromes, se procede a la corrección. Para ello, un algoritmo clásico determina el posible error ocurrido. A continuación, el sistema aplica la corrección correspondiente (puerta X, Y o Z). En el caso de Google, se utiliza un desacoplamiento dinámico (DD) adicional para mitigar los errores de desfase (T2?).

Códigos cuánticos Link to heading

Los cúbits de datos y medición se distribuyen de forma no local, de manera que un error en uno o dos cúbits no destruye la consistencia del grupo. Esta distribución se denomina código cuántico. Los sistemas reales utilizan códigos más grandes y sofisticados.

  • Código Shor (9 qubits): corrige errores de inversión de bits y de inversión de fase.

  • Código Steane (7 qubits): primer código de corrección de errores totalmente cuántico.

  • Códigos de superficie (\(2n^2-1\) cúbits)— Organiza los cúbits en una cuadrícula 2D. La distancia del código de superficie \(n\) se refiere a cuántos errores se pueden corregir al mismo tiempo.

En la práctica, cada cúbit de medición se encarga de medir proyectivamente un operador estabilizador, que se utiliza para la lógica de decisión del algoritmo clásico. Un código estabilizador es la generalización cuántica de los códigos lineales en la corrección de errores clásica, que utiliza comprobaciones de paridad para detectar errores en los bits de ruido.

¿Cómo ejecutar un algoritmo cuántico en cúbits lógicos? Link to heading

Ejecutar un algoritmo cuántico en cúbits físicos implica operar compuertas (o puertas lógicas) en dichos cúbits. Pero, ¿qué ocurre al trabajar con cúbits lógicos? Aunque parezca una pregunta sencilla, la respuesta no es tan directa, y existen diversas maneras de abordar las compuertas lógicas de cúbits. Comencemos con las compuertas de un solo cúbit y, posteriormente, con las de múltiples cúbits.

Aplicación de compuertas de un solo cúbit a cúbits lógicos Link to heading

Tipos de implementaciones de compuertas lógicas:

Una puerta lógica para cúbits equivale a aplicar la misma puerta a cada uno de los n cúbits físicos. Por ejemplo, con el código Steane de 7 cúbits, una puerta lógica de Hadamard se implementa aplicando una puerta física H a cada uno de los 7 cúbits físicos.

En los códigos de superficie, los cúbits lógicos se codifican como grandes parches de cúbits físicos. Las operaciones lógicas se implementan fusionando y dividiendo parches o entrelazando defectos, lo que modifica la topología del código.

La imagen de la derecha, procedente de arxiv.2505.15907, muestra una operación de cirugía reticular que consiste en unir dos fragmentos de código a lo largo del borde. Esta operación requiere O(d) rondas para lograr la tolerancia a fallos.

Aplicación de puertas multicúbit a cúbits lógicos Link to heading

  • Puertas Multiqubit Transversales : Muchos de los códigos cuánticos (por ejemplo, Steane, Bacon-Shor), CNOT lógico se pueden realizar transversalmente: \( CNOT_L​=\sum_{i=1}^n ​CNOT(a_i​,b_i​) \)

Es decir, para cada cúbit físico \(a_i\) en el bloque de control, aplicar un CNOT físico al cúbit correspondiente \(b_i\) en el bloque de destino.

Por ejemplo, la puerta CCNOT (Toffoli) no se puede implementar transversalmente en la mayoría de los códigos (*). En su lugar, se implementa creando estados mágicos, que son estados “teletransportados” condicionalmente, por ejemplo, con una CNOT. Cabe destacar que, en ese caso, la puerta de teletransporte es una operación de puerta lógica.

Por ejemplo, CNOT mediante cirugía reticular y CZ mediante trenzado.

Resumen Link to heading

La aplicación de compuertas multiqubit a qubits lógicos se realiza operando sobre sus qubits físicos codificados de acuerdo con la estructura del código:

  • Transversal: Compuertas por pares entre cúbits físicos de bloques lógicos.

  • Basado en Ancilla: Utiliza métodos de teletransportación o estado mágico.

  • Topológico: Realizar operaciones geométricas como trenzado o cirugía de celosía.

Pido disculpas al lector que haya tenido el valor de leer hasta aquí: esta sección es un tanto superficial y se queda demasiado en la superficie, en lugar de profundizar en el tema. Lo que hay que saber por ahora es que no existe una única solución para la puerta lógica de uno o varios cúbits, sino un conjunto de métodos que se pueden aplicar a cada tipo de puerta y código cuántico.

Enfoque programático: El marco QEC de Cuda-QX Link to heading

En 2024, el equipo de Quantum en Nvidia presentó CUDA-QX, como una extensión de la plataforma de código abierto CUDA-Q, que proporciona bibliotecas optimizadas para desarrolladores cuánticos. Dos de las bibliotecas incluidas en CUDA-QX son CUDA-Q QEC (primitivas y decodificadores de corrección de errores cuánticos) y CUDA-Q Solvers (VQE/ADAPT-VQE, asistentes QAOA).

Veamos brevemente su enfoque para exponer una API programática para la implementación personalizada de la lógica clásica del operador estabilizador. A continuación, se muestra un ejemplo mínimo que implementa el decodificador más simple, utilizado para detectar errores de inversión de bits de un solo cúbit. El decodificador funciona comprobando si el síndrome coincide con una sola columna de la matriz de paridad Hz; en ese caso, se detecta que el cúbit está invertido:

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 nLogicalErrors

La parte importante del algoritmo anterior es que la matriz de paridad y las observables predichas se obtienen del código cuántico de Stean predefinido. Un decodificador simple se puede implementar de esta manera:

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 prediction

Una vez instalado el decodificador, ya es posible ejecutar el algoritmo.

nShots = 1000
nLogicalErrors = run_simple_code_capacity(nShots)
print(f"Shots = {nShots}, Logical error rate ≈ {nLogicalErrors/nShots:.4f}")

Como se puede observar, el QEC de CUDA se basa fundamentalmente en proporcionar herramientas y bibliotecas eficientes para implementar la lógica de computación clásica del QEC. La pregunta que queda es cómo se puede conectar este QEC de CUDA a una pila cuántica real, y especialmente cómo se comunican los síndromes desde la pila de control al decodificador del QEC, y cómo los decodificadores informan a la pila de control, a su vez, sobre las puertas correctivas que se deben aplicar. Aquí es donde entra en juego el fascinante framework Cuda-Q, ¡pero dejaré esta investigación para un informe futuro!

Conclusión Link to heading

¡Voilà! Es evidente que profundizar en el mundo de la corrección de errores cuánticos requiere dedicación a tiempo completo, por lo que tendré que mantenerme a un nivel bastante alto para seguir avanzando en la arquitectura de la máquina de computación cuántica. Por ahora, me pregunto si debería hablar de una máquina de computación cuántica “lógicamente correcta” o simplemente de una “máquina de computación cuántica fiable”. En el primer caso, el énfasis recae en el modelo que garantiza la corrección de la máquina, mientras que en el segundo, el énfasis está en su comportamiento.

Tampoco me queda claro, como ya mencioné en una publicación anterior, si el QEC debería aplicarse como un adorno al algoritmo cuántico, es decir, si el compilador encargado de traducir la secuencia de puertas cuánticas en algo ejecutable por la pila de control también es responsable de “inlinear” las operaciones de las puertas para obtener la lectura del código de superficie. ¿O debería realizarse como una operación en segundo plano de la “máquina de computación cuántica confiable”?


Notas Link to heading

  1. Si te preguntas si se debe usar Ancillary o Auxiliary, entonces la palabra correcta es Ancillary (del latín ancilla: sirvienta), cuyo significado es “proporcionar el apoyo necesario a una función principal”, mientras que Auxiliary (del latín auxilium: ayuda), cuyo significado es “proporcionar ayuda adicional o apoyo de reserva”.

Esta nota se ha añadido después de que se redactara el memorándum inicial:

  1. Hay un tutorial interesante sobre “Integración estrecha de GPU y QPU para corrección de errores cuánticos y control óptimo” de IEEE QCE24, con una grabación de video disponible aquí, que parece brindar muchas respuestas y perspectivas a las preguntas abiertas anteriores. Procesaré este tutorial en un memorando futuro. Por ahora, la idea es que un circuito puede ser reescrito para ajustarse a un código cuántico dado, reducido para ajustarse a una topología de nivel superficial y posprocesado para puertas que lo permitan (puertas Clifford).

Algoritmo de Shor combinado con QEC


Referencias Link to heading