{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "e1dea188",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Encuentra el conjunto independiente máximo con el optimizador cuántico con restricciones de Aqarios\"\n",
        "description: \"Utilizar el optimizador cuántico con restricciones de Aqarios, basado en el método iterativo de «warm-starting» y en mezcladores XY, para resolver el problema del conjunto máximo independiente en un hardware de IBM Quantum\"\n",
        "---\n",
        "\n",
        "{/* cspell:ignore Aqarios QOBLIB Bucher forall */}\n",
        "\n",
        "<span id=\"find-the-maximum-independent-set-with-the-aqarios-constrained-quantum-optimizer\" />\n",
        "\n",
        "# Encuentra el conjunto independiente máximo con el optimizador cuántico con restricciones de Aqarios\n",
        "\n",
        "<Admonition type=\"note\" title=\"Nota\">\n",
        "  Qiskit Functions Son una función experimental disponible únicamente para los usuarios de los planes « IBM Quantum® Premium Plan », «Flex Plan» y « On-Prem » (a través de la API de IBM Quantum Platform ). Se encuentran en fase de versión preliminar y están sujetas a cambios.\n",
        "</Admonition>\n",
        "\n",
        "*Tiempo de ejecución estimado: 30 segundos en un procesador Heron r2. (NOTA: Se trata únicamente de una estimación. (El tiempo de ejecución puede variar.)*\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "be93797d",
      "metadata": {
        "tags": [
          "version-info"
        ]
      },
      "source": [
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "39ff36f6",
      "metadata": {},
      "source": [
        "<span id=\"background\" />\n",
        "\n",
        "## En segundo plano\n",
        "\n",
        "Este tutorial muestra cómo hallar el conjunto independiente máximo de un grafo utilizando el [optimizador cuántico con restricciones Aqarios](/docs/guides/aqarios-constrained-quantum-optimizer) [\\[1\\]](#references), lo que constituye un problema de optimización combinatoria con restricciones.\n",
        "Se formula una instancia de la biblioteca de pruebas QOBLIB [\\[2\\]](#references) como un problema de programación lineal binaria y se pasa a la función de aplicación del optimizador.\n",
        "El optimizador se encarga internamente de todas las operaciones de reformulación, síntesis de circuitos, transpilación y arranque en caliente iterativo (véase [\\[3\\]](#references) para más detalles).\n",
        "\n",
        "El tutorial abarca los siguientes pasos:\n",
        "\n",
        "1. Define el problema como un programa lineal utilizando el `OptimizationProblem` de [qiskit-addon-opt-mapper](https://github.com/qiskit/qiskit-addon-opt-mapper)\n",
        "2. Ejecuta la optimización cuántica utilizando el optimizador cuántico con restricciones de Aqarios\n",
        "3. Recuperar y visualizar los resultados\n",
        "\n",
        "<span id=\"the-maximum-independent-set-problem\" />\n",
        "\n",
        "### El problema del conjunto independiente máximo\n",
        "\n",
        "El problema del conjunto independiente máximo (MIS) es un reto fundamental en la optimización combinatoria.\n",
        "Formalmente, dado un grafo $G(V, E)$, el objetivo es encontrar el mayor subconjunto de vértices $V_I \\subset V$ tal que no haya dos vértices en $V_I$ conectados por un arco, como se muestra en $\\nexists (u, v) \\in E : v \\in V_I \\wedge u \\in V_I$.\n",
        "A cada vértice se le asigna una variable de decisión binaria $x_i \\in \\{0, 1\\}$, y se introduce una restricción $x_u + x_v \\leq 1$ para cada arco, lo que garantiza que se seleccione como máximo un extremo de cada arco.\n",
        "Por lo tanto, el problema puede formularse como el siguiente problema de maximización:\n",
        "\n",
        "$$\n",
        "\\max_{x_i} \\sum_{i \\in V} x_i \\qquad\\text{(find the largest set)}\\\\\n",
        "\\text{s.t.} \\quad x_u + x_v \\leq 1 \\quad \\forall (u, v) \\in E.\n",
        "$$\n",
        "\n",
        "El MIS tiene una amplia gama de aplicaciones prácticas. En la planificación de redes inalámbricas, un conjunto independiente corresponde a un grupo de transmisores que pueden emitir simultáneamente sin interferir entre sí. En la planificación, modela el conjunto más amplio de tareas que pueden ejecutarse simultáneamente, teniendo en cuenta los conflictos de recursos entre pares. En biología computacional, se utiliza para identificar conjuntos de proteínas que no interactúan entre sí en una red.\n",
        "\n",
        "A pesar de su formulación intuitiva, el MIS es un problema NP-difícil, e incluso en el caso de grafos con unos pocos cientos de nodos, algunas instancias concretas resultan difíciles de resolver, ya sea de forma exacta o heurística [\\[2\\]](#references).\n",
        "El problema da lugar además a estructuras de restricciones dispersas que resultan muy adecuadas para las implementaciones en hardware de la optimización cuántica, lo que lo convierte en un punto de referencia atractivo para los dispositivos cuánticos a corto plazo.\n",
        "\n",
        "<span id=\"aqarios-constrained-quantum-optimizer\" />\n",
        "\n",
        "### Optimizador cuántico con restricciones Aqarios\n",
        "\n",
        "El enfoque estándar para integrar un problema binario con restricciones en la optimización cuántica consiste en transformar el modelo en un formato sin restricciones añadiendo términos de penalización: cada restricción incumplida $x_u + x_v \\leq 1$ contribuye con $2 x_u x_v$ al objetivo de minimización $-\\sum_i x_i$. Esto lo gestiona automáticamente la función «Constrained Quantum Optimizer» de Qiskit.\n",
        "\n",
        "Más allá de esta transformación estándar, el optimizador identifica **cliques** en el grafo de restricciones. Un clúster es un conjunto de nodos $V_C$ en el que cada par de nodos comparte un arco. En consecuencia, las restricciones por pares de « $\\binom{|V_C|}{2}$ » $x_u + x_v \\leq 1 \\;\\forall (u,v) \\in E_C$ pueden sustituirse por una única restricción más estricta $\\sum_{i \\in V_C} x_i \\leq 1$. Al introducir una variable de holgura $y$, esto se convierte en una igualdad $\\sum_i x_i + y = 1$, que adopta la forma de una restricción «one-hot» que puede aplicarse directamente en QAOA utilizando **mezcladores XY** [\\[3\\]](#references). Esto reduce el espacio de búsqueda y evita la necesidad de aplicar términos de penalización para esas restricciones, lo que mejora la calidad de la solución.\n",
        "\n",
        "Además, las variables conectadas únicamente a un único vecino se denominan «nodos **colgantes**» y el algoritmo las fija de forma determinista antes de la ejecución cuántica, lo que reduce aún más el tamaño efectivo del problema.\n",
        "\n",
        "El optimizador cuántico con restricciones emplea un enfoque **iterativo de «arranque en caliente»** compatible con los mezcladores XY [\\[1\\]](#references), que reduce progresivamente el espacio de búsqueda al orientar la distribución del estado cuántico hacia regiones de solución prometedoras a lo largo de las iteraciones. Esto permite utilizar **parámetros QAOA de** ángulo fijo, lo que elimina la necesidad de un entrenamiento variacional de los parámetros. Los requisitos totales de recursos cuánticos dependen exclusivamente del número de iteraciones de «arranque en caliente», lo que significa que el coste cuántico es fácil de controlar.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "01da2a6e",
      "metadata": {
        "lines_to_next_cell": 0
      },
      "source": [
        "<span id=\"requirements\" />\n",
        "\n",
        "## Requisitos\n",
        "\n",
        "Antes de comenzar este tutorial, asegúrate de haber instalado los siguientes requisitos:\n",
        "\n",
        "* Qiskit Runtime (`pip install qiskit-ibm-runtime`)\n",
        "* Qiskit Functions Catalog IBM Cliente (`pip install qiskit-ibm-catalog`)\n",
        "* Mapeador de optimización de complementos de Qiskit (`pip install qiskit-addon-opt-mapper`)\n",
        "* Numpy (`pip install numpy`)\n",
        "* Matplotlib (`pip install matplotlib`)\n",
        "* NetworkX (`pip install networkx`)\n",
        "\n",
        "Si lo deseas, para el [Apéndice](#appendix-problem-statement-with-luna-model) debes instalar\n",
        "\n",
        "* Modelo Luna (`pip install luna-model`)\n",
        "\n",
        "<span id=\"setup\" />\n",
        "\n",
        "## Configuración\n",
        "\n",
        "Importa todas las dependencias necesarias.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "3fe5037e-e02b-40cb-bba7-7349d729df53",
      "metadata": {},
      "outputs": [],
      "source": [
        "import networkx as nx\n",
        "import urllib.request\n",
        "\n",
        "from qiskit_ibm_catalog import QiskitFunctionsCatalog\n",
        "\n",
        "from qiskit_addon_opt_mapper import OptimizationProblem\n",
        "from qiskit_addon_opt_mapper.applications import IndependentSet\n",
        "from qiskit_addon_opt_mapper.translators import to_docplex_mp"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d47802c3",
      "metadata": {},
      "source": [
        "En primer lugar, inicia sesión con tu [clave API de IBM Quantum.](http://quantum.cloud.ibm.com/) A continuación, selecciona la función de Qiskit de la siguiente manera. (Este código da por hecho que ya has [guardado tu cuenta](/docs/guides/functions-get-started#install-qiskit-functions-catalog-client) en tu entorno local.)\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "2e6b3761",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "[QiskitFunction(aqarios/constrained-quantum-optimizer)]"
            ]
          },
          "execution_count": 2,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "catalog = QiskitFunctionsCatalog(channel=\"ibm_quantum_platform\")\n",
        "\n",
        "# Verify that you have access to the function\n",
        "catalog.list()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "2b3688f0",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Load the function\n",
        "optimizer = catalog.load(\"aqarios/constrained-quantum-optimizer\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "bd0fd445",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "[<IBMBackend('ibm_pittsburgh')>,\n",
              " <IBMBackend('ibm_boston')>,\n",
              " <IBMBackend('ibm_phoenix')>,\n",
              " <IBMBackend('ibm_fez')>,\n",
              " <IBMBackend('ibm_miami')>,\n",
              " <IBMBackend('ibm_marrakesh')>,\n",
              " <IBMBackend('ibm_kingston')>]"
            ]
          },
          "execution_count": 4,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Check the list of backends you have access to\n",
        "catalog.backends()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "e50deb54",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Select the backend you want to use\n",
        "backend = catalog.backend(\"ibm_pittsburgh\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5435d391",
      "metadata": {},
      "source": [
        "<span id=\"step-1-map-classical-inputs-to-quantum-problem\" />\n",
        "\n",
        "## Paso 1: Asignar entradas clásicas a un problema cuántico\n",
        "\n",
        "El problema se formula como un **archivo LP**, un formato habitual para problemas de optimización que sirve como entrada para el optimizador cuántico con restricciones Aqarios. Además de los archivos LP, la función también es compatible con **archivos MPS** y representaciones nativas **de Luna Model**.\n",
        "El archivo LP se genera siguiendo estos pasos:\n",
        "\n",
        "1. Obtener una instancia de grafo de la biblioteca QOBLIB [\\[2\\]](#references)\n",
        "2. Formular el problema de optimización\n",
        "3. Generar el archivo LP\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c773d45b",
      "metadata": {},
      "source": [
        "<span id=\"load-the-problem-instance-graph\" />\n",
        "\n",
        "### Cargar el grafo de la instancia del problema\n",
        "\n",
        "Los gráficos se especifican en formato `.gph` DIMACS, un formato basado en líneas en el que las líneas que comienzan por `e` definen aristas, las que comienzan por `p` definen el encabezado del problema y las que comienzan por `c` son comentarios:\n",
        "\n",
        "```\n",
        "c some-comment\n",
        "p edge 3 2\n",
        "e 1 2\n",
        "e 2 3\n",
        "...\n",
        "```\n",
        "\n",
        "El archivo `.gph` se puede descargar del repositorio QOBLIB mediante la siguiente función, que además lo analiza para convertirlo en un gráfico de « NetworkX ». Ten en cuenta que el formato DIMACS utiliza una numeración de nodos que empieza por 1, que aquí se convierte a una indexación que empieza por 0.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "8e09bff6-0d5b-4ce5-869b-449755d7edad",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Loading graph with 186 nodes and 280 edges.\n"
          ]
        }
      ],
      "source": [
        "URL_BASE = \"https://raw.githubusercontent.com/ZIB-AOPT/QOBLIB/refs/heads/main/07-independentset/instances/\"\n",
        "\n",
        "\n",
        "def fetch_qoblib_graph(name: str) -> nx.Graph:\n",
        "    \"\"\"Fetch and parse the QOBLIB graph file.\"\"\"\n",
        "    # Download the .gph file\n",
        "    file, _ = urllib.request.urlretrieve(URL_BASE + f\"{name}.gph\")\n",
        "    with open(file) as f:\n",
        "        # Read the file contents\n",
        "        lines = f.readlines()\n",
        "\n",
        "    # Skip comments\n",
        "    lines = [line for line in lines if not line.startswith(\"c\")]\n",
        "\n",
        "    # Read graph definition\n",
        "    _, _, num_nodes, num_edges = lines[0].split()\n",
        "    print(f\"Loading graph with {num_nodes} nodes and {num_edges} edges.\")\n",
        "\n",
        "    # Parse edge information\n",
        "    # The .gph format starts node labeling with 1; we need 0 here, so we subtract one.\n",
        "    split_edges = (line.split() for line in lines[1:])\n",
        "    edges = [(int(u) - 1, int(v) - 1) for _, u, v in split_edges]\n",
        "\n",
        "    return nx.Graph(edges)\n",
        "\n",
        "\n",
        "graph_name = \"es60fst02\"\n",
        "graph = fetch_qoblib_graph(graph_name)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2851abad",
      "metadata": {},
      "source": [
        "En este ejemplo se utiliza la instancia `es60fst02` de QOBLIB, un grafo con 186 nodos y 280 aristas. Gracias a los pasos de preprocesamiento empleados por el Optimizador Cuántico con Restricciones, esta instancia puede resolverse en dispositivos Heron de 156 qubits. El gráfico se puede visualizar utilizando matplotlib:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "182c672d-bab4-48e7-93c1-5e19dc9226ab",
      "metadata": {
        "lines_to_next_cell": 2
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/find-the-maximum-independent-set-with-aqarios-constrained-quantum-optimizer/extracted-outputs/182c672d-bab4-48e7-93c1-5e19dc9226ab-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "# Keep layout for later reuse\n",
        "layout = nx.spring_layout(graph, seed=1)\n",
        "nx.draw(graph, layout, node_size=40)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "59456755",
      "metadata": {},
      "source": [
        "<span id=\"construct-the-optimization-problem\" />\n",
        "\n",
        "### Formular el problema de optimización\n",
        "\n",
        "El problema del conjunto independiente máximo se puede formular directamente utilizando `OptimizationProblem`. Cada nodo del grafo se convierte en una variable de decisión binaria, y cada arista introduce una restricción que garantiza que se seleccione como máximo uno de sus extremos:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "d5363fd3",
      "metadata": {
        "lines_to_next_cell": 2
      },
      "outputs": [],
      "source": [
        "# Create an OptimizationProblem instance\n",
        "mis_problem = OptimizationProblem(\"MIS\")\n",
        "\n",
        "# Add a binary variable for each node\n",
        "x = mis_problem.binary_var_list(graph.number_of_nodes())\n",
        "\n",
        "# Maximize the sum of all node variables\n",
        "mis_problem.maximize(linear={xi.name: 1 for xi in x})\n",
        "\n",
        "# Add '<= 1' constraints for each edge\n",
        "for u, v in graph.edges:\n",
        "    mis_problem.linear_constraint({x[u].name: 1, x[v].name: 1}, \"<=\", 1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7f9a8247",
      "metadata": {},
      "source": [
        "<span id=\"a-shortcut\" />\n",
        "\n",
        "#### Un atajo\n",
        "\n",
        "El paquete [`qiskit-addon-opt-mapper`](https://qiskit.github.io/qiskit-addon-opt-mapper/) proporciona una clase de aplicación ya implementada para el problema del conjunto independiente máximo, lo que simplifica la formulación anterior a una sola llamada:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "01e2a4e0",
      "metadata": {},
      "outputs": [],
      "source": [
        "mis = IndependentSet(graph)\n",
        "mis_problem = mis.to_optimization_problem()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c6870d4e",
      "metadata": {},
      "source": [
        "<span id=\"translate-the-problem-to-an-lp-file\" />\n",
        "\n",
        "### Convierte el problema en un archivo LP\n",
        "\n",
        "El programa en sí `OptimizationProblem` no admite la exportación de archivos LP, pero es compatible con [DOcplex](https://www.ibm.com/docs/de/icos/22.1.2?topic=docplex-python-modeling-api), que sí lo hace. Para generar el contenido del archivo LP solo se necesitan dos líneas:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "bf4d697a",
      "metadata": {
        "lines_to_next_cell": 0
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "\\ This file has been generated by DOcplex\n",
            "\\ ENCODING=ISO-8859-1\n",
            "\\Problem name: Independent set\n",
            "\n",
            "Maximize\n",
            " obj: x_0 + x_1 + x_2 + x_3 + x_4 + x_5 + x_6 + x_7 + x_8 + x_9 + x_10 + x_11\n",
            "      + x_12 + x_13 + x_14 + x_15 + x_16 + x_17 + x_18 + x_19 + x_20 + x_21\n",
            "      + x_22 + x_23 + x_24 + x_25 + x_26 + x_27 + x_28 + x_29 + x_30 + x_31\n",
            "      + x_32 + x_33 + x_34 + x_35 + x_36 + x_37 + x_38 + x_39 + x_40 + x_41\n",
            "      + x_42 + x_43 + x_44 + x_45 + x_46 + x_47 + x_48 + x_49 + x_50 + x_51\n",
            "      + x_52 + x_53 + x_54 + x_55 + x_56 + x_57 + x_58 + x_59 + x_60 + x_61\n",
            "      + x_62 + x_63 + x_64 + x_65 + x_66 + x_67 + x_68 + x_69 + x_70 + x_71\n",
            "      + x_72 + x_73 + x_74 + x_75 + x_76 + x_77 + x_78 + x_79 + x_80 + x_81\n",
            "      + x_82 + x_83 + x_84 + x_85 + x_86 + x_87 + x_88 + x_89 + x_90 + x_91\n",
            "      + x_92 + x_93 + x_94 + x_95 + x_96 + x_97 + x_98 + x_99 + x_100 + x_101\n",
            "      + x_102 + x_103 + x_104 + x_105 + x_106 + x_107 + x_108 + x_109 + x_110\n",
            "      + x_111 + x_112 + x_113 + x_114 + x_115 + x_116 + x_117 + x_118 + x_119\n",
            "      + x_120 + x_121 + x_122 + x_123 + x_124 + x_125 + x_126 + x_127 + x_128\n",
            "      + x_129 + x_130 + x_131 + x_132 + x_133 + x_134 + x_135 + x_136 + x_137\n",
            "      + x_138 + x_139 + x_140 + x_141 + x_142 + x_143 + x_144 + x_145 + x_146\n",
            "      + x_147 + x_148 + x_149 + x_150 + x_151 + x_152 + x_153 + x_154 + x_155\n",
            "      + x_156 + x_157 + x_158 + x_159 + x_160 + x_161 + x_162 + x_163 + x_164\n",
            "      + x_165 + x_166 + x_167 + x_168 + x_169 + x_170 + x_171 + x_172 + x_173\n",
            "      + x_174 + x_175 + x_176 + x_177 + x_178 + x_179 + x_180 + x_181 + x_182\n",
            "      + x_183 + x_184 + x_185\n",
            "Subject To\n",
            " c0: x_60 + x_61 <= 1\n",
            " c1: x_14 + x_60 <= 1\n",
            " c2: x_7 + x_60 <= 1\n",
            " c3: x_7 + x_61 <= 1\n",
            " c4: x_61 + x_62 <= 1\n",
            " c5: x_61 + x_64 <= 1\n",
            " c6: x_14 + x_62 <= 1\n",
            " c7: x_62 + x_65 <= 1\n",
            " c8: x_23 + x_63 <= 1\n",
            " c9: x_53 + x_63 <= 1\n",
            " c10: x_39 + x_63 <= 1\n",
            " c11: x_7 + x_68 <= 1\n",
            " c12: x_18 + x_68 <= 1\n",
            " c13: x_68 + x_69 <= 1\n",
            " c14: x_68 + x_72 <= 1\n",
            " c15: x_64 + x_65 <= 1\n",
            " c16: x_64 + x_69 <= 1\n",
            " c17: x_65 + x_66 <= 1\n",
            " c18: x_51 + x_53 <= 1\n",
            " c19: x_69 + x_73 <= 1\n",
            " c20: x_66 + x_67 <= 1\n",
            " c21: x_42 + x_66 <= 1\n",
            " c22: x_67 + x_75 <= 1\n",
            " c23: x_43 + x_67 <= 1\n",
            " c24: x_42 + x_75 <= 1\n",
            " c25: x_75 + x_83 <= 1\n",
            " c26: x_12 + x_51 <= 1\n",
            " c27: x_18 + x_70 <= 1\n",
            " c28: x_18 + x_26 <= 1\n",
            " c29: x_70 + x_71 <= 1\n",
            " c30: x_70 + x_76 <= 1\n",
            " c31: x_71 + x_72 <= 1\n",
            " c32: x_72 + x_73 <= 1\n",
            " c33: x_72 + x_78 <= 1\n",
            "...\n"
          ]
        }
      ],
      "source": [
        "mp_model = to_docplex_mp(mis_problem)\n",
        "lp_str = mp_model.export_as_lp_string()\n",
        "\n",
        "print(\"\\n\".join(lp_str.split(\"\\n\")[:60]))\n",
        "print(\"...\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0c6ca33d",
      "metadata": {},
      "source": [
        "Este formato es nativo del optimizador cuántico con restricciones.\n",
        "\n",
        "<span id=\"step-2-optimize-problem-for-quantum-hardware-execution\" />\n",
        "\n",
        "## Paso 2: Optimizar el problema para su ejecución en hardware cuántico\n",
        "\n",
        "Toda la síntesis, optimización y transpilación de circuitos se gestiona de forma nativa mediante esta función. Consulta la [sección](/docs/api/functions/aqarios-constrained-quantum-optimizer#inputs) de entradas de la referencia de la API para conocer los argumentos con los que se debe llamar a la función.\n",
        "\n",
        "Para ajustar el comportamiento del algoritmo, consulta la [lista de opciones](/docs/api/functions/aqarios-constrained-quantum-optimizer#options-list) en la referencia de la API.\n",
        "\n",
        "Para obtener más información, consulta la [guía](/docs/guides/aqarios-constrained-quantum-optimizer) y [la referencia de la API de Aqarios Constrained Quantum Optimizer](/docs/api/functions/aqarios-constrained-quantum-optimizer).\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "241b80a6",
      "metadata": {},
      "source": [
        "<span id=\"step-3-execute-using-qiskit-primitives\" />\n",
        "\n",
        "## Paso 3: Ejecutar con el comando « Qiskit primitives »\n",
        "\n",
        "Ahora se puede enviar el archivo LP al optimizador:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "id": "02469f27-1ea9-4fa2-8412-3e7c5ec1a59f",
      "metadata": {
        "lines_to_next_cell": 0
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Job ID: 87ec08b9-6275-40fa-be94-340a0a916bf1\n"
          ]
        }
      ],
      "source": [
        "job = optimizer.run(model=lp_str, backend_name=backend.name)\n",
        "\n",
        "print(f\"Job ID: {job.job_id}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4804bb92",
      "metadata": {},
      "source": [
        "A nivel interno, el algoritmo sigue las siguientes etapas:\n",
        "\n",
        "1. **Preprocesamiento** :\n",
        "   * Reducir las variables que se pueden modificar\n",
        "   * Encuentra grupos de amigos\n",
        "   * Identificar los tipos de restricciones\n",
        "   * Evaluar los factores de penalización para los términos de penalización\n",
        "   * Aplicar transformaciones con restricciones\n",
        "   * Sintetizar circuitos mediante métodos que garantizan el cumplimiento de las restricciones\n",
        "   * Formulación aproximada del problema y transpilación\n",
        "2. **Cadenas paralelas de bucles iterativos** :\n",
        "   * Muestra de un circuito con parámetros fijos\n",
        "   * Aplicar el posprocesamiento\n",
        "   * Evaluar y establecer nuevas probabilidades de arranque en caliente\n",
        "3. **Posprocesamiento** :\n",
        "   * Busca las mejores muestras y comprueba su viabilidad en relación con el problema planteado\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "25fa45d3",
      "metadata": {},
      "source": [
        "<span id=\"monitor-the-progress\" />\n",
        "\n",
        "### Hacer un seguimiento del progreso\n",
        "\n",
        "Consulta las siguientes secciones de la página «Primeros pasos con Qiskit Functions » para supervisar el progreso de tu trabajo:\n",
        "\n",
        "* [Comprobar estado de trabajo](/docs/guides/functions-get-started#check-job-status)\n",
        "* [Obtener resultados](/docs/guides/functions-get-started#retrieve-results)\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "id": "416cf0c0",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "'QUEUED'"
            ]
          },
          "execution_count": 12,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Monitor the job status\n",
        "job.status()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8378a14f",
      "metadata": {},
      "source": [
        "<span id=\"step-4-post-process-and-return-results-in-desired-classical-format\" />\n",
        "\n",
        "## Paso 4: Realizar el posprocesamiento y presentar los resultados en el formato clásico deseado\n",
        "\n",
        "El resultado es un diccionario cuyos campos se describen en la [sección «Salidas»](/docs/api/functions/aqarios-constrained-quantum-optimizer#outputs) de la referencia de la API.\n",
        "\n",
        "Cuando la lista [`solutions`](/docs/api/functions/aqarios-constrained-quantum-optimizer#output-structure) contiene más de una entrada, se han encontrado varios óptimos degenerados. Aquí solo se tiene en cuenta la primera solución:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "id": "fe8a3b9d",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "The found maximum independent set of es60fst02 contains: 88 nodes and is feasible.\n",
            "{100 103 107 109 111 113 115 118 121 123 124 127 129 130 132 133 138 142 144 148 149 155 156 16 161 162 165 167 169 170 175 28 31 33 35 36 47 50 58 59 60 62 64 66 68 71 73 75 78 79 84 85 87 90 91 93 94 95 39 5 27 23 43 15 22 9 4 56 32 30 53 26 17 54 1 37 41 49 34 11 139 153 12 3 6 57 20 44}\n"
          ]
        }
      ],
      "source": [
        "# Retrieve the job result\n",
        "result = job.result()\n",
        "\n",
        "# Retrieve the first solution from the result\n",
        "solution = result[\"solutions\"][0]\n",
        "\n",
        "print(f\"The found maximum independent set of {graph_name} contains:\", end=\" \")\n",
        "print(\n",
        "    f\"{int(result['obj_value'])} nodes and is {'feasible' if result['feasible'] else 'infeasible'}.\"\n",
        ")\n",
        "print(\"{\" + \" \".join(k[2:] for k, v in solution.items() if v == 1) + \"}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e0ac4233",
      "metadata": {},
      "source": [
        "<span id=\"visualization\" />\n",
        "\n",
        "### Visualización\n",
        "\n",
        "El conjunto independiente identificado se puede visualizar resaltando los nodos seleccionados en el gráfico:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 14,
      "id": "f068c750",
      "metadata": {
        "lines_to_next_cell": 2
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/find-the-maximum-independent-set-with-aqarios-constrained-quantum-optimizer/extracted-outputs/f068c750-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "# Color all selected nodes in orange\n",
        "node_map = {\n",
        "    int(k.split(\"_\")[1]): \"tab:orange\" if v else \"tab:blue\"\n",
        "    for k, v in solution.items()\n",
        "}\n",
        "node_colors = [node_map[k] for k in graph.nodes]\n",
        "\n",
        "# Draw with the same layout used before\n",
        "nx.draw(graph, layout, node_size=40, node_color=node_colors)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "1463b529",
      "metadata": {},
      "source": [
        "<span id=\"appendix-problem-statement-with-luna-model\" />\n",
        "\n",
        "## Apéndice: Planteamiento del problema con el modelo Luna\n",
        "\n",
        "Además del `qiskit-addon-opt-mapper` enfoque mostrado anteriormente, la función Qiskit también admite modelos creados con Luna Model [\\[4\\]](#references), el SDK de modelado de Aqarios.\n",
        "Tras instalar el paquete `luna-model` « PyPI », impórtalo de la siguiente manera:\n",
        "\n",
        "**Configuración:**\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 15,
      "id": "299a6d7c",
      "metadata": {},
      "outputs": [],
      "source": [
        "from luna_model import Model, Sense\n",
        "import numpy as np"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "03a63f0d",
      "metadata": {},
      "source": [
        "A continuación, el modelo se construye a partir del gráfico de la misma forma que en el caso de `qiskit-addon-opt-mapper`:\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "fbf74687",
      "metadata": {},
      "source": [
        "**Crea el modelo:**\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "cf52944f-8908-4b4e-8e65-556fbe3b7a38",
      "metadata": {},
      "outputs": [],
      "source": [
        "edges = np.array(graph.edges)\n",
        "\n",
        "# Create the optimization model with a name\n",
        "model = Model(name=f\"MIS-{graph_name}\", sense=Sense.MAX)\n",
        "# Add binary variables\n",
        "x = model.add_variables(\"x\", graph.number_of_nodes())\n",
        "# Set the objective\n",
        "model.objective = x.sum()\n",
        "\n",
        "# Use numpy like batch generation of constraints\n",
        "model.add_constraints(x[edges].sum(axis=1) <= 1)\n",
        "\n",
        "input_str = model.encode_b64()\n",
        "\n",
        "# optimizer.run(model=input_str, backend_name=\"ibm_fez\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "42730c89",
      "metadata": {},
      "source": [
        "<span id=\"next-steps\" />\n",
        "\n",
        "## Pasos siguientes\n",
        "\n",
        "<Admonition type=\"tip\" title=\"Recomendaciones\">\n",
        "  * Consulta la [guía del optimizador cuántico con restricciones de Aqarios](/docs/guides/aqarios-constrained-quantum-optimizer) para obtener una explicación detallada de todas las funciones.\n",
        "  * Consulta la [referencia de la API](/docs/api/functions/aqarios-constrained-quantum-optimizer) para ver la lista completa de parámetros de entrada y campos de salida.\n",
        "  * Prueba las opciones del algoritmo (`reps`, `num_parallel`, `shots`, `postprocessing`) en tu propio problema de optimización binaria con restricciones para evaluar su impacto en la calidad de la solución y el tiempo de ejecución.\n",
        "</Admonition>\n",
        "\n",
        "<span id=\"references\" />\n",
        "\n",
        "## Referencias\n",
        "\n",
        "1. IBM Quantum : [*Guía del optimizador cuántico con restricciones de Aqarios*](/docs/guides/aqarios-constrained-quantum-optimizer)\n",
        "2. Koch et al. (2026), *«The Quantum Optimization Benchmarking Library»* [10.1038/s43588-026-00991-1](https://doi.org/10.1038/s43588-026-00991-1)\n",
        "3. Bucher et al. (2026), «*Optimización cuántica con restricciones mediante mezcladores XY iterativos con inicio en caliente* » [10.1088/1367-2630/ae8ea2](https://doi.org/10.1088/1367-2630/ae8ea2)\n",
        "4. [*Documentación del modelo Luna de*](https://docs.aqarios.com/luna-model) Aqarios GmbH,\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "id": "a1b8767d",
      "source": "© IBM Corp., 2017-2026"
    }
  ],
  "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"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}