
Del bit al cúbit: el cambio de modelo mental que necesita un ingeniero de software
Puedo decir que comencé a interesarme por la computación cuántica cuando en un libro de Michiu Kaku leí por primera vez algo sobre el concepto de cúbit, en contraposición al bit de toda la vida…
Quizá porque, como ingeniero de software, estaba demasiado acostumbrado a pensar en bits, variables, estados y valores perfectamente definidos, porque como bien sabemos, un bit vale 0 o vale 1. Podemos almacenarlo, leerlo, copiarlo, cambiarlo y volver a consultarlo tantas veces como queramos. Gran parte de nuestra intuición como programadores se ha construido, en realidad, sobre ideas tan sencillas como ésta.
Y de repente aparece en escena un concepto nuevo, el cúbit, que, como veremos, tiene propiedades muy diferentes a las del bit clásico, por llamarlo de alguna manera.
Y me temo que aquí comienzan los malentendidos, porque lo primero que solemos escuchar es que puede ser 0 y 1 «al mismo tiempo».
Esta explicación puede ser útil para despertar nuestra curiosidad, pero me parece insuficiente para comprender qué significa realmente programar un computador cuántico. Incluso puede conducirnos a construir un modelo mental equivocado.
Un cúbit no es simplemente un bit que ha aprendido algún truco nuevo. Es otra forma de representar y manipular información, con propiedades de la mecánica cuántica que le permiten realizar operaciones, digamos, de otro modo totalmente diferente.
En este artículo voy a hacer una introducción rápida al cúbit.
Del valor al estado
Comencemos por aquello que conocemos bien. El estado de un bit clásico pertenece al conjunto:
Y ya está.
Podemos tener millones de bits y construir con ellos estructuras extraordinariamente complejas, pero cada bit individual, en un instante determinado, tiene uno de esos dos valores. Esto parece una obviedad, al menos para quienes llevamos programando desde pequeños, aunque seguramente hasta esto en su día nos podría parecer algo extraño o exótico.
Un cúbit se describe de otra forma. Su estado puro puede escribirse mediante la notación de Dirac como:
, donde y son números complejos denominados amplitudes y deben cumplir:
(Por no complicar las cosas, diremos que la notación de Dirac es el lenguaje matemático utilizado en mecánica cuántica para representar estados y operaciones cuánticas de forma más compacta).
Aquí se encuentra uno de los primeros cambios importantes de mentalidad para un programador: puesto que 0 y 1 ya no son los dos únicos estados posibles, sino los vectores de una base, normalmente denominada base computacional. El estado del cúbit es un vector normalizado dentro de un espacio vectorial complejo de dimensión dos.
Esto significa que existen infinitos estados posibles entre y , aunque al medir en la base computacional solamente podamos obtener uno de esos dos resultados, y, de paso, cuando llegamos a este punto, nos damos cuenta de que la computación cuántica utilizar álgebra lineal para representar los estados de cualquier algoritmo cuántico.
No podemos pensar, por tanto, que y almacenan dos valores clásicos simultáneamente. Son amplitudes que forman parte de la descripción matemática del estado.
Las amplitudes no son probabilidades
Comprender este punto es especialmente importante.
Si tenemos:
y realizamos una medición en la base computacional, obtenemos:
Uno puede pensar entonces que el cúbit no es más que una especie de bit probabilístico. Pero tampoco es eso. ¿Te das cuenta de cómo todo esto es diferente al bit clásico?
Las amplitudes y son números complejos, y conservan información que una probabilidad por sí sola no representa: la fase, sí, esos mismos números complejos que seguramente estudiaste el primer año de universidad.
Imagina dos estados:
y
Si medimos cualquiera de ellos directamente en la base computacional, obtenemos 0 o 1 con una probabilidad del 50 %.
Desde el punto de vista de esas probabilidades parecen idénticos, y, sin embargo, los estados no son iguales.
El signo introduce una diferencia de fase relativa y ésta importa porque las amplitudes pueden interferir. Operaciones cuánticas posteriores pueden convertir esa diferencia aparentemente invisible en resultados de medición completamente diferentes. Es más, la manipular la fase es la clave en la mayoría de los algoritmos de computación cuántica.
Éste es, en mi opinión, uno de los puntos donde el programador tiene que abandonar definitivamente la intuición clásica: conocer únicamente las probabilidades de salida no significa conocer el estado cuántico.
Otra diferencia: medir no equivale a leer una variable
Hay otra costumbre profundamente arraigada entre quienes programamos: observar el estado de nuestro programa.
Podemos detener una aplicación en un breakpoint y comprobar tranquilamente:
counter = 7
enabled = true
status = READY
, o algo por el estilo. Incluso podemos inspeccionar varias veces una variable sin que el hecho de leerla modifique su valor.
Con un cúbit ocurre algo sustancialmente diferente, radicalmente distinto.
Si preparamos:
y lo medimos en la base computacional, obtendremos 0 o 1, cada uno con probabilidad . Tras una medición proyectiva ideal, el estado queda asociado al resultado obtenido.
Por eso medir un cúbit no es equivalente a consultar una variable.
Esta diferencia tiene consecuencias inmediatas para la forma en que diseñamos y depuramos programas de algoritmos cuánticos. No podemos inspeccionar arbitrariamente un estado desconocido durante la ejecución, leer sus amplitudes y continuar como si nada hubiese ocurrido. De hecho, lenguajes específicamente diseñados para programación cuántica reflejan esta limitación: Q#, por ejemplo, no permite acceder directamente al estado interno de un cúbit.
Desde el punto de vista del desarrollador, esto resulta bastante desconcertante al principio.
Adivino que muchos desarrolladores, cuando se interesan por la computación cuántica y llegan a este punto, cierto galimatías de conceptos que tienen un origen en la mecánica cuántica, tiran la toalla y se olvidan de esto.
Estamos acostumbrados a que observar el estado forme parte natural del proceso de depuración. En computación cuántica tenemos que razonar más sobre transformaciones, probabilidades, invariantes y resultados estadísticos obtenidos mediante múltiples ejecuciones.
¿Por qué? Por que la naturaleza, a un nivel cuántico, es esencialmente probabilística.
La esfera de Bloch
Afortunadamente tenemos una representación extraordinariamente útil para adquirir intuición: la esfera de Bloch. El estado puro de un único cúbit puede escribirse, ignorando una fase global físicamente irrelevante, como:
Los parámetros y permiten representar el estado como un punto sobre la superficie de una esfera.
En uno de los polos tenemos y en el opuesto . Los demás puntos representan las diferentes superposiciones posibles.
Esta representación me parece especialmente interesante para alguien que viene del desarrollo de software, porque permite dejar de imaginar el cúbit como un extraño interruptor que está «encendido y apagado al mismo tiempo».

Es más útil visualizarlo como un estado que podemos transformar mediante operaciones.
Las puertas cuánticas de un solo cúbit pueden interpretarse, salvo una fase global, como rotaciones de este estado. Aplicar una puerta cambia su posición en la esfera y, con ello, las amplitudes y fases que determinarán cómo se comportará en operaciones posteriores y qué podremos obtener al medirlo.
Pero conviene introducir aquí una precaución: la esfera de Bloch es una representación extraordinaria para un solo cúbit. No debemos extrapolarla ingenuamente a un sistema arbitrario de muchos cúbits, cuyo espacio de estados crece exponencialmente (otro concepto difícil de digerir).
En computación cuántica, programamos transformaciones, no valores
Aquí aparece, quizá, el cambio conceptual que más nos interesa como ingenieros de software. En programación clásica escribimos continuamente instrucciones como:
x = 0
x = 1
if x == 1:
...
Pensamos en variables que contienen valores.
En programación cuántica es más apropiado pensar en preparar un estado, transformarlo y finalmente medirlo.
Como ejmplo, una puerta Hadamard aplicada sobre , por ejemplo, genera una transformación al estado de un cúbit, y produce:
Si inmediatamente medimos este estado muchas veces en la base computacional, observaremos aproximadamente la mitad de resultados 0 y la mitad 1.
Pero lo verdaderamente interesante no consiste en conseguir un generador de bits aleatorios extraordinariamente sofisticado, sino que empieza cuando seguimos operando sobre las amplitudes antes de medir.
El trabajo, por tanto, al implementar un algoritmo cuántico, consiste en modificar las fases de sus cúbits y conseguir que diferentes caminos computacionales interfieran constructiva o destructivamente. Un algoritmo cuántico trata precisamente de controlar estas transformaciones para que, al final del cálculo, la distribución de resultados obtenida contenga información útil sobre el problema que estamos intentando resolver.
De ahí la famosa explicación de que un computador cuántico «prueba todas las soluciones a la vez» debe manejarse con muchísimo cuidado. De nuevo, un fenómeno puramente cuántico, es difícil traducirlo a nuestro lenguaje humano (que, precisamente, está definido para un mundo material, digamos, newtoniano, salvando las distancias y perdón por esta comparación tan burda). Una superposición no nos permite leer simultáneamente todos sus componentes.
La potencia de los algoritmos cuánticos, cuando existe una ventaja demostrable, procede de algo bastante más sutil que un supuesto paralelismo gratuito.
También cambia nuestra forma de depurar
Todo esto nos obliga a revisar otro de nuestros hábitos como programadores: la depuración.
En un simulador podemos inspeccionar un vector de estado porque estamos representándolo utilizando memoria clásica. Herramientas como la librería Qiskit permiten visualizar statevectors, matrices de densidad y esferas de Bloch precisamente con fines de análisis y aprendizaje.
No obstante, no debemos confundir esta comodidad del simulador con el comportamiento del hardware cuántico real.
Un programa clásico puede depurarse observando directamente gran parte de su estado interno. Un programa cuántico debe analizarse teniendo en cuenta preparaciones, puertas, bases de medición y distribuciones estadísticas. Además, en sistemas reales aparecen ruido, decoherencia y errores de operación y medida que complican todavía más esta tarea.
Es otro oficio que tendremos que aprender y que cambia radicalmente la forma en que hemos programado en computación clásica.
Un cúbit no es un bit mejor
Si tuviera que quedarme con una única idea, sería ésta: Un cúbit no es una versión más potente de un bit, como he llegado a leer por ahí, ni tampoco almacena simplemente más información clásica que éste.
Es la unidad básica de información de un modelo computacional diferente, cuyo estado se representa mediante amplitudes complejas (son números complejos) y cuya evolución explota propiedades como la superposición, la fase, la interferencia y, cuando trabajamos con varios cúbits, el entrelazamiento, fenómenos puramente cuánticos.
Para quienes llevamos muchos años desarrollando software, quizá la principal dificultad de comenzar con computación cuántica no sea aprender nuevas puertas, memorizar circuitos o utilizar un SDK diferente. Todo eso puede aprenderse.
Lo complicado es dejar atrás determinadas intuiciones y hábitos en la forma de resolver problemas, de ahí que afirme que esto es un nuevo paradigma de computación.
Tenemos que aceptar que observar puede modificar aquello que estamos observando, que una fase que no aparece directamente en una medición puede ser decisiva unas operaciones después, que no podemos copiar alegremente un estado cuántico desconocido y que nuestro programa ya no consiste únicamente en mover valores conocidos entre posiciones de memoria, en esencial.
Hay que aprender a pensar en estados, transformaciones, amplitudes e interferencia, con toda la base matemática que esto conlleva.
El cúbit fue uno de los conceptos que despertó mi interés por la computación cuántica precisamente por esto. Tras muchos años acostumbrado a pensar en software clásico, descubrir que la propia unidad mínima de información obligaba a replantear ideas que parecían evidentes me resultó especialmente sugerente, pero muy chocante al principio.
Y creo que ése es un buen punto de partida para cualquier desarrollador que quiera introducirse en esta disciplina.
Antes de intentar comprender algoritmos como Grover, Shor o QAOA, conviene detenerse aquí el tiempo suficiente, porque es la base para todo lo que venga a continuación.
Primero hay que aprender qué significa realmente un cúbit.
Y, sobre todo, dejar de pensar que es un bit extraño.