El algoritmo de Deutsch-Jozsa
El algoritmo de Deutsch supera a todos los algoritmos clásicos para un problema de consultas, pero la ventaja es bastante modesta: una consulta frente a dos. El algoritmo de Deutsch-Jozsa amplía esta ventaja — y, de hecho, puede usarse para resolver un par de problemas de consultas distintos.
A continuación se muestra una descripción del algoritmo de Deutsch-Jozsa en forma de circuito cuántico. También puede ser necesario un paso adicional de posprocesamiento clásico, no mostrado en la figura, dependiendo del problema específico que se resuelva.
Por supuesto, todavía no hemos explicado qué problemas resuelve este algoritmo; eso se hace en las dos secciones siguientes.
El problema de Deutsch-Jozsa
Comenzaremos con el problema de consultas que el algoritmo de Deutsch-Jozsa fue diseñado originalmente para resolver, conocido como el problema de Deutsch-Jozsa.
La función de entrada para este problema tiene la forma para un entero positivo arbitrario Al igual que en el problema de Deutsch, la tarea consiste en devolver si es constante y si es balanceada, lo que significa que el número de cadenas de entrada en las que la función toma el valor es igual al número de cadenas de entrada en las que la función toma el valor .
Observa que, cuando es mayor que existen funciones de la forma que no son ni constantes ni balanceadas. Por ejemplo, la función definida como
no pertenece a ninguna de estas dos categorías. Para el problema de Deutsch-Jozsa, simplemente ignoramos funciones como esta — se consideran entradas "irrelevantes". Es decir, para este problema tenemos la promesa de que es constante o balanceada.
El algoritmo de Deutsch-Jozsa, con su única consulta, resuelve este problema en el siguiente sentido: si todos y cada uno de los resultados de medición son entonces la función es constante; de lo contrario, si al menos uno de los resultados de medición es entonces la función es balanceada. Otra forma de expresarlo es que el circuito descrito anteriormente va seguido de un paso de posprocesamiento clásico en el que se calcula el OR de los resultados de medición para producir la salida.
Análisis del algoritmo
Para analizar el rendimiento del algoritmo de Deutsch-Jozsa aplicado al problema de Deutsch-Jozsa, conviene comenzar pensando en la acción de una sola capa de puertas Hadamard. Una operación Hadamard puede expresarse como una matriz de la manera habitual,
pero también podemos expresar esta operación en términos de su acción sobre los estados de la base est ándar:
Estas dos ecuaciones pueden combinarse en una sola fórmula,
que es válida para ambas opciones de
Supongamos ahora que, en lugar de un solo qubit, tenemos qubits y se aplica una operación Hadamard a cada uno. La operación combinada sobre los qubits se describe mediante el producto tensorial ( veces), que escribimos como por concisión y claridad. Usando la fórmula anterior, y luego expandiendo y simplificando, podemos expresar la acción de esta operación combinada sobre los estados de la base estándar de qubits de la siguiente manera:
Nótese que aquí escribimos cadenas binarias de longitud como e siguiendo la convención de indexación de Qiskit.
Esta fórmula nos proporciona una herramienta útil para analizar el circuito cuántico anterior. Tras aplicar la primera capa de puertas Hadamard, el estado de los qubits (incluido el qubit más a la izquierda/inferior, que se trata de forma independiente del resto) es
Al aplicar la operación , este estado se transforma en
exactamente mediante el mismo fenómeno de retroceso de fase que vimos en el análisis del algoritmo de Deutsch.
A continuación se aplica la segunda capa de puertas Hadamard, que (según la fórmula anterior) transforma este estado en
Esta expresión parece algo complicada, y no se puede concluir mucho sobre las probabilidades de obtener distintos resultados de medición sin conocer más sobre la función
Afortunadamente, lo único que necesitamos saber es la probabilidad de que todos los resultados de medición sean — porque esa es la probabilidad de que el algoritmo determine que es constante. Esta probabilidad tiene una fórmula sencilla.
En detalle, si es constante, entonces o bien para toda cadena en cuyo caso el valor de la suma es o bien para toda cadena en cuyo caso el valor de la suma es Al dividir por y tomar el cuadrado del valor absoluto obtenemos
Si, por otro lado, es balanceada, entonces toma el valor en la mitad de las cadenas y el valor en la otra mitad, por lo que los términos y de la suma se cancelan y obtenemos el valor
Concluimos que el algoritmo opera correctamente siempre que se cumpla la promesa.
Dificultad clásica
El algoritmo de Deutsch-Jozsa funciona en todo momento, siempre proporciona la respuesta correcta cuando se cumple la promesa y requiere una única consulta. ¿Cómo se compara esto con los algoritmos de consultas clásicos para el problema de Deutsch-Jozsa?
En primer lugar, cualquier algoritmo clásico determinista que resuelva correctamente el problema de Deutsch-Jozsa debe realizar un número exponencial de consultas: se necesitan consultas en el peor caso. El razonamiento es que, si un algoritmo determinista consulta en o menos cadenas distintas y obtiene el mismo valor de la función en todas ellas, ambas respuestas siguen siendo posibles. La función podría ser constante, o podría ser balanceada pero con mala suerte todas las consultas devuelven el mismo valor de la función.
La segunda posibilidad puede parecer improbable — pero para los algoritmos deterministas no hay aleatoriedad ni incertidumbre, por lo que fallarán sistemáticamente en ciertas funciones. Por lo tanto, tenemos una ventaja significativa de los algoritmos cuánticos sobre los clásicos en este sentido.
Existe, sin embargo, una salvedad: los algoritmos clásicos probabilistas pueden resolver el problema de Deutsch-Jozsa con alta probabilidad usando solo unas pocas consultas. En particular, si simplemente elegimos unas pocas cadenas distintas de longitud al azar y consultamos en esas cadenas, es poco probable que obtengamos el mismo valor de la función para todas ellas cuando es balanceada.
Más concretamente, si elegimos cadenas de entrada de manera uniforme aleatoria, evaluamos y respondemos si todos los valores de la función son iguales y si no, siempre acertaremos cuando es constante, y nos equivocaremos en el caso de que sea balanceada con probabilidad solo Si tomamos por ejemplo, este algoritmo responderá correctamente con probabilidad superior al %.
Por esta razón, seguimos teniendo una ventaja más bien modesta de los algoritmos cuánticos sobre los clásicos — pero es, no obstante, una ventaja cuantificable que representa una mejora respecto al algoritmo de Deutsch.
Deutsch-Jozsa con Qiskit
# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-aer
from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator
import numpy as np
Para implementar el algoritmo de Deutsch-Jozsa en Qiskit, comenzaremos definiendo una función dj_query que genera un circuito cuántico que implementa una puerta de consulta, para una función seleccionada aleatoriamente que satisfaga la promesa del problema de Deutsch-Jozsa.
Con un 50% de probabilidad la función es constante, y con un 50% la función es balanceada.
Para cada una de estas dos posibilidades, la función se selecciona de manera uniforme entre las funciones de ese tipo.
El argumento es el número de bits de entrada de la función.
def dj_query(num_qubits):
# Create a circuit implementing for a query gate for a random function
# satisfying the promise for the Deutsch-Jozsa problem.
qc = QuantumCircuit(num_qubits + 1)
if np.random.randint(0, 2):
# Flip output qubit with 50% chance
qc.x(num_qubits)
if np.random.randint(0, 2):
# return constant circuit with 50% chance
return qc
# Choose half the possible input strings
on_states = np.random.choice(
range(2**num_qubits), # numbers to sample from
2**num_qubits // 2, # number of samples
replace=False, # makes sure states are only sampled once
)
def add_cx(qc, bit_string):
for qubit, bit in enumerate(reversed(bit_string)):
if bit == "1":
qc.x(qubit)
return qc
for state in on_states:
qc.barrier() # Barriers are added to help visualize how the functions are created.
qc = add_cx(qc, f"{state:0b}")
qc.mcx(list(range(num_qubits)), num_qubits)
qc = add_cx(qc, f"{state:0b}")
qc.barrier()
return qc
Podemos visualizar la implementación en circuito cuántico de la puerta de consulta usando el método draw como de costumbre.
display(dj_query(3).draw(output="mpl"))
A continuación definimos una función que crea el circuito de Deutsch-Jozsa, tomando como argumento un circuito cuántico que implementa una puerta de consulta.
def compile_circuit(function: QuantumCircuit):
# Compiles a circuit for use in the Deutsch-Jozsa algorithm.
n = function.num_qubits - 1
qc = QuantumCircuit(n + 1, n)
qc.x(n)
qc.h(range(n + 1))
qc.compose(function, inplace=True)
qc.h(range(n))
qc.measure(range(n), range(n))
return qc
Por último, se define una función que ejecuta el circuito de Deutsch-Jozsa una sola vez.
def dj_algorithm(function: QuantumCircuit):
# Determine if a function is constant or balanced.
qc = compile_circuit(function)
result = AerSimulator().run(qc, shots=1, memory=True).result()
measurements = result.get_memory()
if "1" in measurements[0]:
return "balanced"
return "constant"
Podemos probar nuestra implementación eligiendo una función aleatoriamente, mostrando la implementación en circuito cuántico de una puerta de consulta para dicha función y ejecutando el algoritmo de Deutsch-Jozsa sobre esa función.
f = dj_query(3)
display(f.draw("mpl"))
display(dj_algorithm(f))

'balanced'
El problema de Bernstein-Vazirani
A continuación, hablaremos de un problema conocido como el problema de Bernstein-Vazirani. También se llama problema de muestreo de Fourier, aunque existen formulaciones más generales de este problema que también llevan ese nombre.
Primero, introduzcamos algo de notación. Para cualesquiera dos cadenas binarias e de longitud definimos
Llamaremos a esta operación el producto punto binario. Una forma alternativa de definirlo es la siguiente.
Observa que esta es una operación simétrica, lo que significa que el resultado no cambia si intercambiamos e así que podemos hacerlo cuando nos resulte conveniente. A veces es útil pensar en el producto punto binario como la paridad de los bits de en las posiciones donde la cadena tiene un o de forma equivalente, la paridad de los bits de en las posiciones donde la cadena tiene un
Con esta notación ya podemos definir el problema de Bernstein-Vazirani.
En realidad no necesitamos un nuevo algoritmo cuántico para este problema; el algoritmo de Deutsch-Jozsa lo resuelve. Para mayor claridad, llamemos circuito de Deutsch-Jozsa al circuito cuántico descrito anteriormente, que no incluye el paso de posprocesamiento clásico de calcular la OR.
Análisis del algoritmo
Para analizar cómo funciona el circuito de Deutsch-Jozsa con una función que satisface la promesa del problema de Bernstein-Vazirani, comenzaremos con una observación rápida. Usando el producto punto binario, podemos describir de forma alternativa la acción de puertas Hadamard sobre los estados de la base estándar de qubits así:
De forma similar a lo que vimos al analizar el algoritmo de Deutsch, esto se debe a que el valor para cualquier entero depende únicamente de si es par o impar.
Volviendo al circuito de Deutsch-Jozsa, después de que se aplica la primera capa de puertas Hadamard, el estado de los qubits es
A continuación se aplica la puerta de consulta, que (mediante el fenómeno de retroceso de fase) transforma el estado en
Usando nuestra fórmula para la acción de una capa de puertas Hadamard, vemos que la segunda capa de puertas Hadamard transforma este estado en
Ahora podemos hacer algunas simplificaciones en el exponente de dentro de la suma. Se nos promete que para alguna cadena por lo que podemos expresar el estado como
Dado que y son valores binarios, podemos reemplazar la suma por la OR exclusiva — de nuevo porque lo único que importa para un entero en el exponente de es si es par o impar. Haciendo uso de la simetría del producto punto binario, obtenemos esta expresión para el estado:
(Se han añadido paréntesis para mayor claridad, aunque no son estrictamente necesarios porque por convención el producto punto binario tiene mayor precedencia que la OR exclusiva.)
En este punto haremos uso de la siguiente fórmula.
Podemos obtener la fórmula a partir de una fórmula análoga para bits,
junto con una expansión del producto punto binario y la OR exclusiva bit a bit:
Esto nos permite expresar el estado del circuito justo antes de las mediciones así:
El último paso es hacer uso de otra fórmula más, que es válida para toda cadena binaria
Aquí usamos una notación sencilla para cadenas que utilizaremos varias veces más en la lección: es la cadena de todos ceros de longitud
Una forma simple de argumentar que esta fórmula es correcta es considerar los dos casos por separado. Si entonces para toda cadena por lo que el valor de cada término de la suma es y al sumar y dividir entre obtenemos Por otro lado, si alguno de los bits de es igual a entonces el producto punto binario es igual a para exactamente la mitad de las posibles elecciones de e igual a para la otra mitad — porque el valor del producto punto binario cambia (de a o de a ) si invertimos cualquier bit de en una posición donde tiene un
Si ahora aplicamos esta fórmula para simplificar el estado del circuito antes de las mediciones, obtenemos
dado que si y solo si Así, las mediciones revelan exactamente la cadena que buscamos.
Dificultad clásica
Mientras que el circuito de Deutsch-Jozsa resuelve el problema de Bernstein-Vazirani con una sola consulta, cualquier algoritmo de consulta clásico debe realizar al menos consultas para resolver este problema.
Esto puede razonarse mediante un argumento denominado teórico-informacional, que es muy sencillo en este caso. Cada consulta clásica revela un solo bit de información sobre la solución, y hay bits de información que deben descubrirse — por lo tanto, se necesitan al menos consultas.
De hecho, es posible resolver el problema de Bernstein-Vazirani de forma clásica consultando la función en cada una de las cadenas que tienen un único en cada posición posible y en todos los demás bits, lo que revela los bits de de uno en uno. Por lo tanto, la ventaja de los algoritmos cuánticos sobre los clásicos para este problema es de consulta frente a consultas.
Bernstein-Vazirani con Qiskit
Ya hemos implementado el circuito de Deutsch-Jozsa anteriormente, y aquí lo usaremos para resolver el problema de Bernstein-Vazirani. Primero definiremos una función que implementa una puerta de consulta para el problema de Bernstein-Vazirani dada cualquier cadena binaria
def bv_query(s):
# Create a quantum circuit implementing a query gate for the
# Bernstein-Vazirani problem.
qc = QuantumCircuit(len(s) + 1)
for index, bit in enumerate(reversed(s)):
if bit == "1":
qc.cx(index, len(s))
return qc
display(bv_query("1011").draw(output="mpl"))
Ahora podemos crear una función que ejecute el circuito de Deutsch-Jozsa sobre la función, usando la función compile_circuit que se definió anteriormente.
def bv_algorithm(function: QuantumCircuit):
qc = compile_circuit(function)
result = AerSimulator().run(qc, shots=1, memory=True).result()
return result.get_memory()[0]
display(bv_algorithm(bv_query("1011")))
'1011'
Observación sobre la nomenclatura
En el contexto del problema de Bernstein-Vazirani, es habitual que el algoritmo de Deutsch-Jozsa se denomine "algoritmo de Bernstein-Vazirani." Esto es algo engañoso, porque el algoritmo es el algoritmo de Deutsch-Jozsa, tal y como Bernstein y Vazirani dejaron muy claro en su trabajo.
Lo que hicieron Bernstein y Vazirani tras demostrar que el algoritmo de Deutsch-Jozsa resuelve el problema de Bernstein-Vazirani (tal como se enuncia más arriba) fue definir un problema mucho más complicado, conocido como el problema de muestreo de Fourier recursivo. Se trata de un problema muy artificial en el que las soluciones a diferentes instancias del problema desbloquean efectivamente nuevos niveles del problema, organizados en una estructura de árbol. El problema de Bernstein-Vazirani es esencialmente el caso base de este problema más complicado.
El problema de muestreo de Fourier recursivo fue el primer ejemplo conocido de un problema de consulta en el que los algoritmos cuánticos tienen una ventaja llamada superpolinomial sobre los algoritmos probabilísticos, superando así la ventaja cuántica sobre la clásica que ofrece el algoritmo de Deutsch-Jozsa. Intuitivamente, la versión recursiva del problema amplifica la ventaja de frente a de los algoritmos cuánticos hasta algo mucho mayor.
El aspecto más desafiante del análisis matemático que establece esta ventaja es demostrar que los algoritmos de consulta clásicos no pueden resolver el problema sin realizar muchas consultas. Esto es bastante típico; para muchos problemas puede ser muy difícil descartar enfoques clásicos creativos que los resuelvan de manera eficiente.
El problema de Simon, y el algoritmo para resolverlo descrito en la siguiente sección, sí proporciona un ejemplo mucho más sencillo de una ventaja superpolinomial (y, de hecho, exponencial) de los algoritmos cuánticos sobre los clásicos, por lo que el problema de muestreo de Fourier recursivo se discute con menos frecuencia. No obstante, sigue siendo un problema computacional interesante por derecho propio.