Skip to content
This repository was archived by the owner on Nov 10, 2023. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added challenges/PIQUE challenge/quantum_teach.pptx
Binary file not shown.
56 changes: 56 additions & 0 deletions challenges/openqaoa challenge/README.md
Original file line number Diff line number Diff line change
@@ -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.

308 changes: 308 additions & 0 deletions challenges/openqaoa challenge/openqaoa.ipynb
Original file line number Diff line number Diff line change
@@ -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"
]
}
]
}
]
}
Loading