Recocido Cuántico
En este tutorial cubriremos los fundamentos del recocido cuántico y luego mostraremos cómo usar QiliSDK para implementar un algoritmo simple de recocido cuántico.
¿Qué es el Recocido Cuántico?
El recocido cuántico es una técnica de optimización cuántica inspirada en el proceso de recocido en metalurgia, donde un material se calienta y luego se enfría lentamente para eliminar defectos y mejorar sus propiedades.
En el recocido cuántico, comenzamos con un sistema cuántico simple que es fácil de preparar y manipular, y luego lo evolucionamos lentamente hacia un sistema más complejo que codifica la solución al problema que queremos resolver.
Existe un teorema (el teorema adiabático) que establece que si evolucionamos nuestro sistema lo suficientemente despacio, podemos garantizar que permanecerá en su estado fundamental (el estado de menor energía) a lo largo de la evolución. La velocidad que necesitamos está determinada por la brecha de energía entre el estado fundamental y el primer estado excitado, ya que si tenemos una brecha pequeña entre los niveles debemos movernos lentamente para asegurarnos de no saltar accidentalmente al estado excitado.
¿Qué es un Hamiltoniano?
Cuando hablamos de recocido cuántico, a menudo hablamos de Hamiltonianos. Un Hamiltoniano es un objeto matemático que describe la energía de un sistema cuántico.
En el recocido cuántico, típicamente tenemos dos Hamiltonianos: el Hamiltoniano inicial, que es fácil de preparar y manipular, y el Hamiltoniano final, que codifica la solución a nuestro problema. Estos se combinan en un único Hamiltoniano dependiente del tiempo que evoluciona del Hamiltoniano inicial al final a lo largo del tiempo:
donde \(c_i(t)\) y \(c_f(t)\) son coeficientes dependientes del tiempo que controlan cómo se mezclan los dos Hamiltonianos a lo largo del tiempo.
Estos Hamiltonianos se escriben típicamente en términos de los operadores de Pauli: I, X, Y y Z, que son un conjunto de matrices que operan sobre qubits y forman una base para todas las operaciones cuánticas posibles. Por ejemplo, un Hamiltoniano simple de dos qubits podría verse así:
donde el primer término representa una interacción entre los dos qubits, y el segundo término representa un campo local en el primer qubit.
Por simplicidad, el símbolo del producto tensorial (⊗) se omite a menudo, y podemos escribir el Hamiltoniano anterior como:
¿Qué Hacemos Una Vez que Tenemos un Hamiltoniano?
Una vez que tenemos un Hamiltoniano que combina nuestros Hamiltonianos inicial y final, podemos usarlo para evolucionar nuestro sistema cuántico a lo largo del tiempo. Al comenzar nuestro sistema en el estado fundamental del Hamiltoniano inicial y luego evolucionarlo lentamente según el Hamiltoniano dependiente del tiempo, esperamos terminar en el estado fundamental del Hamiltoniano final, que codifica la solución a nuestro problema.
Si nuestro estado fundamental es \(|ψ_0⟩\), podemos representar el estado de nuestro sistema en el siguiente instante \(dt\) como:
Este proceso se repite hasta alcanzar el final de nuestro esquema de recocido. Asumiendo que \(dt\) es suficientemente pequeño, el estado final de nuestro sistema al final del proceso debería estar cerca del estado fundamental del Hamiltoniano final, que codifica la solución a nuestro problema.
¿Cómo Elegimos Nuestros Hamiltonianos?
Determinar cuáles deberían ser nuestros Hamiltonianos inicial y final para un problema de optimización dado es una tarea no trivial, y existen muchas técnicas diferentes para ello. Un enfoque común es representar primero nuestro problema de optimización como un problema de optimización binaria cuadrática sin restricciones (QUBO, por sus siglas en inglés), y luego convertir este problema QUBO en nuestro Hamiltoniano final.
Un Hamiltoniano inicial común es el Hamiltoniano de campo transverso, que viene dado por:
Este Hamiltoniano tiene un estado fundamental simple que es fácil de preparar, lo que lo convierte en una buena elección para el Hamiltoniano inicial en el recocido cuántico.
También existe la elección de cómo se quiere programar el proceso de recocido, que está determinado por las funciones \(c_i(t)\) y \(c_f(t)\). Elegir un buen esquema de programación puede ser importante para el éxito del proceso de recocido, ya que puede ayudar a garantizar que permanezcamos en el estado fundamental durante toda la evolución. La elección más simple es un esquema lineal, cuyos coeficientes son los siguientes:
¿Cómo Podemos Simular el Recocido con QiliSDK?
Nota
Si no tiene QiliSDK instalado y desea ejecutar los siguientes ejemplos usted mismo, puede seguir las instrucciones en la guía de instalación.
Para probar nuestro algoritmo de recocido cuántico, podemos usar QiliSDK para simular el proceso de recocido en un ordenador clásico. Para ello, primero creamos nuestros Hamiltonianos inicial y final usando la clase Hamiltonian, o más específicamente las clases de operadores de Pauli:
from qilisdk.analog import X, Z
initial_hamiltonian = - X(0) - X(1)
final_hamiltonian = Z(0) + Z(1) + 0.5 * Z(0) * Z(1)
We then need to construct our schedule to determine how the mixing will happen over time, which we can do using the Schedule class. The class allows for complete flexibility in how you want to define your schedule, but it also provides some helper functions for common schedules:
from qilisdk.analog import Schedule
schedule = Schedule.linear(initial_hamiltonian, final_hamiltonian, total_time=100, dt=0.1)
Queremos comenzar en el estado fundamental del Hamiltoniano inicial, que es una superposición uniforme de todos los estados posibles del sistema:
from qilisdk.core import QTensor
initial_state = QTensor.uniform(2)
Finalmente, podemos usar QiliSim para simular el proceso de recocido:
from qilisdk.backends import QiliSim
from qilisdk.functionals import AnalogEvolution
from qilisdk.readout import Readout
backend = QiliSim()
result = backend.execute(
AnalogEvolution(schedule=schedule, initial_state=initial_state),
Readout().with_expectation(observables=[Z(0), Z(1), Z(0) * Z(1)])
)
print(result.get_expectation_values())
Esto nos da los valores esperados de los observables que especificamos al final del proceso de recocido, que en este caso son los términos de nuestro Hamiltoniano final:
[-0.9997, -0.9997, +0.9994]
Estos valores esperados están cercanos a los que esperaríamos para el estado fundamental de nuestro Hamiltoniano final, ya que para minimizar la energía del Hamiltoniano final queremos minimizar los valores de \(Z(0)\) y \(Z(1)\), mientras maximizamos el valor de \(Z(0)Z(1)\). Si aumentamos el tiempo total y disminuimos el paso de tiempo, podemos acercar estos valores aún más a 1.0 y -1.0, a costa de aumentar el tiempo de ejecución de nuestra simulación.