diff --git a/challenges/PIQUE challenge/quantum_teach.pptx b/challenges/PIQUE challenge/quantum_teach.pptx new file mode 100644 index 0000000..4412b12 Binary files /dev/null and b/challenges/PIQUE challenge/quantum_teach.pptx differ diff --git a/challenges/openqaoa challenge/README.md b/challenges/openqaoa challenge/README.md new file mode 100644 index 0000000..a816e7c --- /dev/null +++ b/challenges/openqaoa challenge/README.md @@ -0,0 +1,56 @@ +## Planteamiento del problema + +Una asociación sin ánimo de lucro de asistencia a personas con dependencia o movilidad reducida, presta todos los días servicio de cuidados y atención por las mañanas de 08:00 a 14:00. + +Gracias a una extensa red de voluntarios que se ofrecen a realizar el servicio según las necesidades de los usuarios, el servicio está garantizado. + +Cada día, para conocer las necesidades y lo disoponible, los usuarios solicitan el servicio de cuidados y los voluntarios marcan su disponibilidad. + +A las 7:00 de la mañana los voluntarios reciben un mensaje con los datos de la persona que deben de atender ese día. + +Simplificando el problema, el coste para prestar este servicio para la ONG se puede dividir en gastos fijos (Alquiler, luz, agua, material fungible, etc...) y gastos variables (pago de dietas y desplazamiento del voluntariado). + +Quitando la parte del coste fijo y de las dietas que depende del número de usuarios que solicitan el servicio, el único concepto que pueden gestionar es el gasto en desplazamientos. + +El objetivo es encontrar la asignación del personal voluntariado más económica. + +## Modelización QUBO del problema +Para modelizar el problema como un problema de tipo QUBO, llamamos: +* $u_i$ a cada uno de los usuarios. +* $v_i$ a cada voluntario. +* $d_{ij}$ la distancia que recorre el voluntario $v_i$ para llegar a casa del usuario $u_j$. +* $x_{ij}$ es la variable del problema e indica si el usuario $u_i$ ha acudido a atender al usuario $u_j$. + +Los valores que pueden tener cada uno de los parámetros y la variable es: +* $u_i$: 1 si el usuario ha solicitado atención y 0 en caso contrario. +* $v_i$: 1 si el voluntario ha indicado su disponibilidad y 0 en caso contrario. +* $x_{ij}$: 1 si el voluntario $v_i$ ha ido a atender al usuario $u_j$ y 0 en caso contrario. + +De esta forma la función a optimizar es la distancia recorrida por todos los voluntarios, que en un día se calcula por + +$\sum_{i=1}\ \sum_{j=1}\ d_{ij}\ u_i\ v_j\ x_{ij}$ + +Con las siguiente restriciones: +* Un voluntario solo puede atender a un usuario + $\sum_{j=1}\ x_{ij}\ =\ v_i$ +* Un usuario solo puede recibir a un voluntario + $\sum_{i=1}\ x_{ij}\ =\ u_j$ + +De esta manera la función QUBO a minimizar es +$f(x)= \sum_{i=1}\ \sum_{j=1}\ d_{ij}\ u_i\ v_j\ x_{ij} + \lambda (\sum_{j=1}\ x_{ij}\ -\ v_i)^2 + \lambda (\sum_{i=1}\ x_{ij}\ -\ u_j)^2$ + +Donde $\lambda$ es el coeficiente de Lagrange, que para este evento y para simplificar los cálculos, como las restricciones tienen la misma importancia que el objetivo a minimizar vamos a considerar con un valor de $\lambda = 1$. + +Desarrollamos la expresión y apartando los términos constantes obtenemos +$f(x)= \sum_{i=1}\ \sum_{j=1}\ d_{ij}\ u_i\ v_j\ x_{ij} + \sum_{j=1}\ (1-2v_i) x_{ij} + \sum_{i\neq j}\ x_{ij} x_{ik} + \sum_{j=1}\ (1-2u_i) x_{ij} + \sum_{i\neq j}\ x_{ij} x_{ik}=\sum_{i=1}\ \sum_{j=1}\ (d_{ij}\ u_i\ v_j-2v_i-2u_i) x_{ij} + \sum_{i\neq j}\ 2x_{ij} x_{ik}$ + +## Modelización ISING del problema +Una vez obtenida la función a minimizar como una función QUBO, pasarlo a ISING es hacer el cambio de variable $x_{ij}=\frac{1-z_{ij}}{2}$. Por lo tanto +$f(x)= \sum_{i=1}\ \sum_{j=1}\ (d_{ij}\ u_i\ v_j-2v_i-2u_i) \frac{1-z_{ij}}{2} + \sum_{i\neq j}\ 2 \frac{1-z_{ij}}{2} \frac{1-z_{ik}}{2}=-\sum_{i=1}\ \sum_{j=1}\ \frac{d_{ij}\ u_i\ v_j-2v_i-2u_i-2}{2}z_{ij} + \sum_{i\neq j}\ \frac{z_{ij}z_{ik}}{2}$ + +## Construcción del circuito +Una vez tenemos la función a minimizar bajo el concepto de función ISING, pasarlo a circuito usando el algoritmo QAOA consiste en construir dos circuitos. El primer circuito asociado a los coeficientes de los términos de la diagonal de la función, y el segundo creado con el resto de los coeficientes. + +* Primer circuito llamado U_B en el ejercicio. Se forma usando la puerta rotacional $R_Z$. +* Segundo circuito llamado U_C en el ejercicio. Se forma usando la puerta rotacional $R_Z$ entre dos puertas CCNOT. + diff --git a/challenges/openqaoa challenge/openqaoa.ipynb b/challenges/openqaoa challenge/openqaoa.ipynb new file mode 100644 index 0000000..004e68e --- /dev/null +++ b/challenges/openqaoa challenge/openqaoa.ipynb @@ -0,0 +1,308 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "7WUZL7Rg9Upp" + }, + "outputs": [], + "source": [ + "!pip install pennylane" + ] + }, + { + "cell_type": "code", + "source": [ + "import pennylane as qml\n", + "from pennylane import numpy as np\n", + "import matplotlib.pyplot as plt" + ], + "metadata": { + "id": "pij3jS-Z98sP" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "#Definimos el tamaño del problema\n", + "numeroUsuarios = 4\n", + "numeroVoluntarios = 5\n", + "rango = max(numeroUsuarios, numeroVoluntarios)\n", + "nqubits = numeroVoluntarios * numeroUsuarios\n", + "distancia = [[0 for i in range(rango)] for j in range(rango)]\n", + "peticionUsuarios = np.random.randint(0, 2, numeroUsuarios)\n", + "peticionVoluntarios = np.random.randint(0, 2, numeroVoluntarios)\n", + "for i in range(numeroVoluntarios):\n", + " for j in range(numeroUsuarios):\n", + " distancia[i][j] = np.random.randint(5, 500)" + ], + "metadata": { + "id": "L5m8N7Ls9kXz" + }, + "execution_count": 88, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "def toLineal(i, j):\n", + " return i*numeroUsuarios + j" + ], + "metadata": { + "id": "v4Mfho3VGMi3" + }, + "execution_count": 112, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "def fromLineal(n):\n", + " return n//numeroUsuarios, n%numeroUsuarios" + ], + "metadata": { + "id": "mO1d9G5eUb7V" + }, + "execution_count": 113, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "print(peticionUsuarios)\n", + "print(peticionVoluntarios)\n", + "print(distancia)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "-IOQnQRBGVlA", + "outputId": "af3cbab0-106b-46c8-d60e-b40af00711d0" + }, + "execution_count": 89, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "[1 1 1 0]\n", + "[1 1 0 0 1]\n", + "[[238, 232, 346, 73, 0], [257, 256, 236, 292, 0], [483, 306, 269, 461, 0], [217, 366, 307, 390, 0], [291, 454, 313, 253, 0]]\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "def matrizObjetivo():\n", + " objetivo = [[0 for i in range(nqubits)] for j in range(nqubits)]\n", + " for i in range(nqubits):\n", + " for j in range(nqubits):\n", + " v1,u1 = fromLineal(i)\n", + " v2,u2 = fromLineal(j)\n", + " if i == j:\n", + " objetivo[i][j] = (distancia[v1][u1] * peticionVoluntarios[v1] * peticionUsuarios[u1] - (2 * peticionVoluntarios[v1]) - (2 * peticionUsuarios[u1]) - 2)/2\n", + " else:\n", + " objetivo[i][j] = 0.5 * peticionVoluntarios[v1] * peticionUsuarios[u1]* peticionVoluntarios[v2] * peticionUsuarios[u2]\n", + " return objetivo" + ], + "metadata": { + "id": "_LRX8wgc-0GY" + }, + "execution_count": 122, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "dev = qml.device(\"default.qubit\", wires = range(nqubits))" + ], + "metadata": { + "id": "eKUui196HTcB" + }, + "execution_count": 15, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "def U_C(gamma, h, n):\n", + " for i in range(n):\n", + " for j in range(n):\n", + " if (j != i):\n", + " qml.CNOT(wires = [i, j])\n", + " qml.RZ(-2 * (-h[i][j] * h[i][j]) * gamma, wires = j)\n", + " qml.CNOT(wires = [i, j])" + ], + "metadata": { + "id": "fZDpTURcHfBN" + }, + "execution_count": 10, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "def U_B(beta, h, n):\n", + " for k in range(n):\n", + " qml.RX(-2 * beta * h[k][k], wires = k)" + ], + "metadata": { + "id": "DMphZolSHhkV" + }, + "execution_count": 11, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "@qml.qnode(dev)\n", + "def circuito(gamma, beta, h, n, capas):\n", + " for k in range(n):\n", + " qml.Hadamard(wires = k)\n", + " for k in range(capas):\n", + " U_C(gamma, h, n)\n", + " U_B(beta, h, n)\n", + " return qml.probs(wires = range(n))" + ], + "metadata": { + "id": "wWAjEqSjHkk1" + }, + "execution_count": 17, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "gamma = 0.15\n", + "beta = 0.15\n", + "capas = 3" + ], + "metadata": { + "id": "RA-k70t9HpnH" + }, + "execution_count": 13, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "resultados = circuito(gamma, beta, matrizObjetivo(), nqubits, capas)" + ], + "metadata": { + "id": "TI-Dk_i2IBe5" + }, + "execution_count": 123, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "def getMaxKey(valores):\n", + " maxValue = max(valores)\n", + " for i in range(2**nqubits):\n", + " if valores[i] == maxValue:\n", + " return i" + ], + "metadata": { + "id": "nHt_GL5zVKWC" + }, + "execution_count": 27, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "ganador=getMaxKey(resultados)\n", + "print(ganador)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "LGdxZwuCNdz5", + "outputId": "4d23ed90-a834-4581-b961-1dba27dd077f" + }, + "execution_count": 124, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "434178\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "def decimalToBinary(n):\n", + " return bin(n).replace(\"0b\", \"\")" + ], + "metadata": { + "id": "4ocKMJikOjeu" + }, + "execution_count": 35, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "estadoGanador = decimalToBinary(ganador)" + ], + "metadata": { + "id": "B46_tp-vOKAx" + }, + "execution_count": 125, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "for i in range(len(str(estadoGanador))):\n", + " if (estadoGanador[i] == '1'):\n", + " u, v = fromLineal(i)\n", + " print(f\"El voluntario %1d debe acudir a visitar al usuario %1d\" % (u+1, v+1))" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "0k2XlICwPTXB", + "outputId": "f2045b28-4c96-4b62-ed60-e1863e87f63c" + }, + "execution_count": 127, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "El voluntario 1 debe acudir a visitar al usuario 1\n", + "El voluntario 2 debe acudir a visitar al usuario 2\n", + "El voluntario 5 debe acudir a visitar al usuario 3\n" + ] + } + ] + } + ] +} diff --git a/challenges/xanadu challenge/Examples/Pennylane_Challenge_tests.ipynb b/challenges/xanadu challenge/Examples/Pennylane_Challenge_tests.ipynb new file mode 100644 index 0000000..8a46c62 --- /dev/null +++ b/challenges/xanadu challenge/Examples/Pennylane_Challenge_tests.ipynb @@ -0,0 +1,146 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "import pennylane as qml\n", + "from pennylane import numpy as np" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "WIRES = 2 # Número de hilos o qubits\n", + "LAYERS = 5 # Número de capas en el circuito\n", + "NUM_PARAMETERS = LAYERS * WIRES * 3 # Número total de parámetros en el circuito" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "# Definiendo el circuito cuántico variacional dado por Pennylane\n", + "def variational_circuit(params, hamiltonian):\n", + " # Reestructurando los parámetros para que coincidan con el número de capas y qubits\n", + " parameters = params.reshape((LAYERS, WIRES, 3))\n", + " # Aplicando capas de entrelazamiento fuerte (StronglyEntanglingLayers) al circuito\n", + " qml.templates.StronglyEntanglingLayers(parameters, wires=range(WIRES))\n", + " # Retornando el valor esperado del hamiltoniano\n", + " return qml.expval(qml.Hermitian(hamiltonian, wires=[0, 1]))" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "# Función para optimizar el circuito cuántico dado un hamiltoniano\n", + "def optimize_circuit(hamiltonian):\n", + " # Convirtiendo el hamiltoniano en un array y asegurando que no requiere gradiente\n", + " hamiltonian = np.array(hamiltonian, requires_grad=False)\n", + " # Reestructurando el hamiltoniano para que tenga la forma adecuada (4x4 en este caso)\n", + " hamiltonian = np.array(hamiltonian, float).reshape((2 ** WIRES), (2 ** WIRES))\n", + " # Definiendo el dispositivo cuántico\n", + " dev = qml.device('default.qubit', wires=WIRES)\n", + " # Creando el nodo cuántico del circuito\n", + " circuit = qml.QNode(variational_circuit, dev)\n", + " # Inicializando parámetros aleatoriamente para el circuito\n", + " init_params = np.random.randn(NUM_PARAMETERS)\n", + " # Función de costo que queremos minimizar (valor esperado del hamiltoniano)\n", + " def cost(params):\n", + " return circuit(params, hamiltonian)\n", + " # Definiendo el optimizador (Descenso de Gradiente)\n", + " optimizer = qml.GradientDescentOptimizer(stepsize=0.4)\n", + " num_steps = 200 # Número de pasos de optimización\n", + " params = init_params # Iniciando con los parámetros aleatorios\n", + " # Loop de optimización\n", + " for _ in range(num_steps):\n", + " params = optimizer.step(cost, params)\n", + " # Retornando el valor del costo optimizado\n", + " return cost(params)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Optimized expectation value: 0.6174534093371777\n" + ] + } + ], + "source": [ + "min_value = float('inf')\n", + "# Definiendo un ejemplo de hamiltoniano\n", + "hamiltonian_example = np.array(\n", + " [0.863327072347624,0.0167108057202516,0.07991447085492759,0.0854049026262154,\n", + " 0.0167108057202516,0.8237963773906136,-0.07695947154193797,0.03131548733285282,\n", + " 0.07991447085492759,-0.07695947154193795,0.8355417021014687,-0.11345916130631205,\n", + " 0.08540490262621539,0.03131548733285283,-0.11345916130631205,0.758156886827099])\n", + "# Optimiza el circuito con el hamiltoniano \n", + "optimized_value = optimize_circuit(hamiltonian_example)\n", + "print(\"Optimized expectation value:\", optimized_value)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Optimized expectation value: 0.0024648812008860738\n" + ] + } + ], + "source": [ + "min_value = float('inf')\n", + "# Definiendo un ejemplo de hamiltoniano\n", + "hamiltonian_example = np.array(\n", + " [0.32158897156285354,-0.20689268438270836,0.12366748295758379,-0.11737425017261123,\n", + " -0.20689268438270836,0.7747346055276305,-0.05159966365446514,0.08215539696259792,\n", + " 0.12366748295758379,-0.05159966365446514,0.5769050487087416,0.3853362904758938,\n", + " -0.11737425017261123,0.08215539696259792,0.3853362904758938,0.3986256655167206])\n", + "# Optimiza el circuito con el hamiltoniano \n", + "optimized_value = optimize_circuit(hamiltonian_example)\n", + "print(\"Optimized expectation value:\", optimized_value)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.2" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/challenges/xanadu challenge/Experiments/Pennylane_Challenge.py b/challenges/xanadu challenge/Experiments/Pennylane_Challenge.py new file mode 100644 index 0000000..5290d94 --- /dev/null +++ b/challenges/xanadu challenge/Experiments/Pennylane_Challenge.py @@ -0,0 +1,48 @@ +import pennylane as qml +from pennylane import numpy as np +WIRES = 2 +LAYERS = 5 +NUM_PARAMETERS = LAYERS * WIRES * 3 + +def variational_circuit(params, hamiltonian): + parameters = params.reshape((LAYERS, WIRES, 3)) + qml.templates.StronglyEntanglingLayers(parameters, wires=range(WIRES)) + return qml.expval(qml.Hermitian(hamiltonian, wires=[0, 1])) + +def optimize_circuit(hamiltonian,stepsizee,num_stepss): + hamiltonian = np.array(hamiltonian, requires_grad=False) + hamiltonian = np.array(hamiltonian, float).reshape((2 ** WIRES), (2 ** WIRES)) + + dev = qml.device('default.qubit', wires=WIRES) + circuit = qml.QNode(variational_circuit, dev) + init_params = np.random.randn(NUM_PARAMETERS) + def cost(params): + return circuit(params, hamiltonian) + optimizer = qml.GradientDescentOptimizer(stepsize=0.4) + num_steps = 200 + params = init_params + for _ in range(num_steps): + params = optimizer.step(cost, params) + return cost(params) + +if __name__ == "__main__": + min_value = float('inf') + best_stepsizee = None + best_num_stepss = None + hamiltonian_example = np.array( + [0.32158897156285354,-0.20689268438270836,0.12366748295758379,-0.11737425017261123, + -0.20689268438270836,0.7747346055276305,-0.05159966365446514,0.08215539696259792, + 0.12366748295758379,-0.05159966365446514,0.5769050487087416,0.3853362904758938, + -0.11737425017261123,0.08215539696259792,0.3853362904758938,0.3986256655167206]) + for _ in range(1000): + stepsizee = np.random.uniform(0.1,0.5) + num_stepss = np.random.randint(100,500) + optimized_value = optimize_circuit(hamiltonian_example,stepsizee,num_stepss) + if optimized_value < min_value: + min_value = optimized_value + best_stepsizee = stepsizee + best_num_stepss = num_stepss + + print("Optimized expectation value:", min_value) + print("Best stepsize:", best_stepsizee) + print("Best num_steps:", best_num_stepss) diff --git a/challenges/xanadu challenge/Principal Code/Pennylane_Challenge.ipynb b/challenges/xanadu challenge/Principal Code/Pennylane_Challenge.ipynb new file mode 100644 index 0000000..cdfb9ff --- /dev/null +++ b/challenges/xanadu challenge/Principal Code/Pennylane_Challenge.ipynb @@ -0,0 +1,120 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "import pennylane as qml\n", + "from pennylane import numpy as np" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [], + "source": [ + "WIRES = 2 # Número de hilos o qubits\n", + "LAYERS = 5 # Número de capas en el circuito\n", + "NUM_PARAMETERS = LAYERS * WIRES * 3 # Número total de parámetros en el circuito" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [], + "source": [ + "# Definiendo el circuito cuántico variacional dado por Pennylane\n", + "def variational_circuit(params, hamiltonian):\n", + " # Reestructurando los parámetros para que coincidan con el número de capas y qubits\n", + " parameters = params.reshape((LAYERS, WIRES, 3))\n", + " # Aplicando capas de entrelazamiento fuerte (StronglyEntanglingLayers) al circuito\n", + " qml.templates.StronglyEntanglingLayers(parameters, wires=range(WIRES))\n", + " # Retornando el valor esperado del hamiltoniano\n", + " return qml.expval(qml.Hermitian(hamiltonian, wires=[0, 1]))" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [], + "source": [ + "# Función para optimizar el circuito cuántico dado un hamiltoniano\n", + "def optimize_circuit(hamiltonian):\n", + " # Convirtiendo el hamiltoniano en un array y asegurando que no requiere gradiente\n", + " hamiltonian = np.array(hamiltonian, requires_grad=False)\n", + " # Reestructurando el hamiltoniano para que tenga la forma adecuada (4x4 en este caso)\n", + " hamiltonian = np.array(hamiltonian, float).reshape((2 ** WIRES), (2 ** WIRES))\n", + " # Definiendo el dispositivo cuántico\n", + " dev = qml.device('default.qubit', wires=WIRES)\n", + " # Creando el nodo cuántico del circuito\n", + " circuit = qml.QNode(variational_circuit, dev)\n", + " # Inicializando parámetros aleatoriamente para el circuito\n", + " init_params = np.random.randn(NUM_PARAMETERS)\n", + " # Función de costo que queremos minimizar (valor esperado del hamiltoniano)\n", + " def cost(params):\n", + " return circuit(params, hamiltonian)\n", + " # Definiendo el optimizador (Descenso de Gradiente)\n", + " optimizer = qml.GradientDescentOptimizer(stepsize=0.4)\n", + " num_steps = 200 # Número de pasos de optimización\n", + " params = init_params # Iniciando con los parámetros aleatorios\n", + " # Loop de optimización\n", + " for _ in range(num_steps):\n", + " params = optimizer.step(cost, params)\n", + " # Retornando el valor del costo optimizado\n", + " return cost(params)" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Optimized expectation value: 0.0024648812008865612\n" + ] + } + ], + "source": [ + "min_value = float('inf')\n", + "# Definiendo un ejemplo de hamiltoniano\n", + "hamiltonian_example = np.array(\n", + " [0.32158897156285354,-0.20689268438270836,0.12366748295758379,-0.11737425017261123,\n", + " -0.20689268438270836,0.7747346055276305,-0.05159966365446514,0.08215539696259792,\n", + " 0.12366748295758379,-0.05159966365446514,0.5769050487087416,0.3853362904758938,\n", + " -0.11737425017261123,0.08215539696259792,0.3853362904758938,0.3986256655167206])\n", + "# Optimiza el circuito con el hamiltoniano \n", + "optimized_value = optimize_circuit(hamiltonian_example)\n", + "print(\"Optimized expectation value:\", optimized_value)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.2" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/challenges/xanadu challenge/README.md b/challenges/xanadu challenge/README.md new file mode 100644 index 0000000..de6bf9f --- /dev/null +++ b/challenges/xanadu challenge/README.md @@ -0,0 +1,197 @@ + +# Quantum Circuit Optimizer with PennyLane + +This project implements a variational quantum circuit optimizer using the PennyLane +quantum computing library. The goal is to minimize the expected value of a fixed +measurement by adjusting the parameters of a variational quantum circuit, which represents +a QNode in PennyLane. This optimization process is crucial for tasks such as quantum state +preparation and solving energy problems in physical systems modeled by specific +Hamiltonians. + +The project demonstrates how to convert a quantum circuit into an executable QNode and how to apply optimizers to find the parameters that result in the minimum expected value of an unknown observable. Concrete examples are provided, and the effectiveness of the optimizer is shown using different Hamiltonians as test cases. + + + + +## Installation + +Install Pennylane + +To install PennyLane and run the quantum circuit optimizer, follow these steps: + +- Ensure you have Python installed on your system. +- Install PennyLane using pip with the following command: + +```bash + pip install pennylane +``` + +## Dependencies + +**PennyLane:** A Python library that simplifies the simulation and optimization of quantum circuits. It is the only dependency required to run this project. + + + + +## Usage + +To use the code, you need to download the Pennylane_Challenge.ipynb file, meet the dependencies (Python and Pennylane), and start running the project step by step from top to bottom. + +To test different Hamiltonians, simply modify the line of code: + +```bash + hamiltonian_example = np.array( + [0.32158897156285354,-0.20689268438270836,0.12366748295758379,-0.11737425017261123, + -0.20689268438270836,0.7747346055276305,-0.05159966365446514,0.08215539696259792, + 0.12366748295758379,-0.05159966365446514,0.5769050487087416,0.3853362904758938, + -0.11737425017261123,0.08215539696259792,0.3853362904758938,0.3986256655167206]) +``` + +Pennylane examples: + +```bash + [0.863327072347624,0.0167108057202516,0.07991447085492759,0.0854049026262154, + 0.0167108057202516,0.8237963773906136,-0.07695947154193797,0.03131548733285282, + 0.07991447085492759,-0.07695947154193795,0.8355417021014687,-0.11345916130631205, + 0.08540490262621539,0.03131548733285283,-0.11345916130631205,0.758156886827099] +``` +- expected_output: `0.61745341` +```bash + [0.32158897156285354,-0.20689268438270836,0.12366748295758379,-0.11737425017261123, + -0.20689268438270836,0.7747346055276305,-0.05159966365446514,0.08215539696259792, + 0.12366748295758379,-0.05159966365446514,0.5769050487087416,0.3853362904758938, + -0.11737425017261123,0.08215539696259792,0.3853362904758938,0.3986256655167206] +``` +- expected_output: `0.00246488` + +## Physic context of the problem + + +Let $\hat{H}$ be a hamiltonian in a quantum Hilbert space $\mathcal{H}$, then for its ground state: + + +
+ $\hat{H} \ket{\Psi_0} = E_0 \ket{\Psi _0}$ +
+ +with $E_0$ its eigenvalue, then the expected value: + ++$\braket{H}_{\Psi_0} = \bra {\Psi _0} \hat{H} \ket{\Psi_0} =E_0\braket{\Psi | \Psi} = E_0$ +
+ + +For an arbitrary $\ket{\Psi} \in \mathcal{H}$, it can be showed: + + ++$\bra{\Psi _0} \hat{H} \ket{\Psi_0} \leq \bra{\Psi} \hat{H} \ket{\Psi} \Rightarrow \braket{H}_{\Psi_0} \leq \braket{H}_{\Psi}$ +
+ +Given $\hat{H}$, if we want to obtain the ground state we can propouse a parametrized state (an ansatz): + + ++ $\ket{\Psi (θ)} = \hat{W}_\theta \ket{0}^{\otimes n}$ +
+ + +and so we can attempt to find the parameters that characterize the ground state: + + ++$\ket{\Psi_0} = \hat{W}_θ \ket{0}^{\otimes n}$ +
+ + +then ,due the expected value of the hamiltonian in the ground states is less or equal to the expected value for an arbitrary state, for the ground state we must find the parameters of the operator $\hat{W}$(θ) that minimize the expected value for the Hamiltonian $\hat{H}$ in $\hat{W}$(θ) $\ket{0}^{\otimes n}$ , i,e $\braket{H}$ $_{\Psi(θ)}$ + + +We can encode our minimization problem of a cost function, the expected value, with a Variational Quantum Algorithm and use tools like PennyLane! + +## Screenshots and Code explanation + +For the development of this code, we started with the template provided by PennyLane. The only necessary library is PennyLane, and initially, we begin with the definition of what will be our number of wires or qubits, our number of layers in the circuit, and our total number of parameters. + + + +The function "variational_circuit" aims to construct a variational quantum circuit (VQC), which is a type of parameterized quantum circuit frequently used in quantum algorithms, especially in the fields of quantum optimization and quantum machine learning. + +Parameter Reshaping: The function starts by taking an argument called params, which is an array of numerical values. These values are the variational parameters that will control certain quantum operations (gates) in the circuit. The params array is reshaped to match the number of layers (LAYERS) and the number of qubits (WIRES) in the circuit. Each qubit in each layer will have three associated parameters. + +Construction of Entangling Layers: It uses a template called StronglyEntanglingLayers from the quantum computing library. This template applies a series of quantum gates that strongly entangle the qubits, thereby creating quantum entanglement between them. Entanglement is a key resource in quantum computing that allows qubits to be correlated in a way that is not possible in classical systems. + +StronglyEntanglingLayers: StronglyEntanglingLayers is one of the templates provided by PennyLane. This template creates a sequence of layers where each layer consists of single-qubit rotation gates and two-qubit entangling gates. The single-qubit rotations are typically applied to each qubit and are parametrized by the input parameters. The two-qubit entangling gates are CNOTs or other entangling gates that link the qubits together, creating quantum entanglement between them. + + + +Expectation Value Evaluation: Finally, the function calculates the expected value of a given Hamiltonian operator (hamiltonian). In quantum mechanics, the expectation value of a Hamiltonian with respect to a quantum state gives the average energy of that state. In this case, the Hamiltonian is applied to the first two qubits of the circuit. The expected value is a critical measure in VQCs, as it is often sought to minimize this value through a variational optimization process, by adjusting the circuit parameters to find the state of lowest energy, which is the optimal solution to the problem at hand. + + + +This code defines a function named optimize_circuit that aims to optimize a variational quantum circuit given a Hamiltonian. Here's a breakdown of the function and the rationale behind each part: + +Hamiltonian Conversion: The function starts by converting the hamiltonian input into a NumPy array and ensuring that it does not require a gradient. This is necessary because the optimization process involves computing gradients, and the Hamiltonian's own gradient is not relevant to this process. + +Hamiltonian Reshaping: The Hamiltonian is reshaped into a square matrix of size 4x4, which is suitable for a system with two qubits (since $2^2$ = 4). This is because the Hamiltonian must be a matrix where the dimensions are equal to the number of possible states of the system. + +Quantum Device Definition: A quantum device is instantiated using PennyLane's default.qubit simulator, setting the number of wires (qubits) it will use. This device will simulate the quantum circuit. + +Quantum Node Creation: A quantum node (QNode) is created with the variational_circuit function previously discussed, and the quantum device dev. A QNode wraps a quantum function (the circuit) for execution on a specific device. + +Parameter Initialization: The circuit parameters are initialized to random values. This is a common practice in optimization, as starting from different random points can help in avoiding local minima and finding a better global solution. + +Cost Function: The cost function is defined to be the expected value of the Hamiltonian, which is what we seek to minimize. It uses the circuit to compute this expected value given the current parameters. + +Optimizer Definition: A gradient descent optimizer is initialized with a specified step size. Gradient descent is an optimization algorithm that iteratively adjusts parameters to minimize the cost function. + +Optimization Loop: The optimization process is carried out for a predefined number of steps (num_steps). In each step, the optimizer adjusts the parameters to minimize the cost function. + +Return Optimized Cost: After the optimization loop, the function returns the optimized cost, which is the lowest expected value of the Hamiltonian found by the optimization process. + + + +min_value Initialization: The variable min_value is initialized to float('inf'), which is a way of setting it to "infinity" in Python. This value serves as a comparison baseline for finding the minimum expectation value as the optimization proceeds. + +Hamiltonian Definition: hamiltonian_example is defined as a NumPy array representing a Hamiltonian, which is a matrix associated with the total energy of the quantum system. In quantum computing, we often seek to find the ground state (the state of lowest energy) of such a system. + +Optimization Call: The optimize_circuit function is called with the defined Hamiltonian. Although the function itself is not shown in the snippet, we can infer that it involves setting up a variational quantum circuit, initializing parameters, defining a cost function (usually the expectation value of the Hamiltonian), and using an optimizer to adjust the parameters to minimize the cost. + +Print Optimized Value: After the optimization routine completes, the optimized expectation value (presumably the lowest found by the optimizer) is printed out. This value represents the energy of the system in the state dictated by the optimized parameters of the variational quantum circuit. + + +## Test cases + +For this project, two Hamiltonians provided by PennyLane were used to verify the code's functionality. + +- input: +```bash + [0.863327072347624,0.0167108057202516,0.07991447085492759,0.0854049026262154, + 0.0167108057202516,0.8237963773906136,-0.07695947154193797,0.03131548733285282, + 0.07991447085492759,-0.07695947154193795,0.8355417021014687,-0.11345916130631205, + 0.08540490262621539,0.03131548733285283,-0.11345916130631205,0.758156886827099] +``` +- expected_output: `0.61745341` +- proyect_output: `0.6174534088312781` + +- input: +```bash + [0.32158897156285354,-0.20689268438270836,0.12366748295758379,-0.11737425017261123, + -0.20689268438270836,0.7747346055276305,-0.05159966365446514,0.08215539696259792, + 0.12366748295758379,-0.05159966365446514,0.5769050487087416,0.3853362904758938, + -0.11737425017261123,0.08215539696259792,0.3853362904758938,0.3986256655167206] +``` +- expected_output: `0.00246488` +- proyect_output: `0.0024648812008860755` + + +## Authors + +#### Quantum Codebreakers + +- [@Arnoldo Valdez](https://www.github.com/arnoldodany44) +- [@Alejandro Monroy](https://www.github.com/AzpMon) +- [@Francisco Costa](https://www.github.com/podxboq) +- [@Sofía Salazar](https://www.github.com/nsalazard) +- [@Julio Moreno](https://www.github.com/pyspdev) +