{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "dde95705",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Optimizador cuántico con restricciones: una función de Qiskit desarrollada por Aqarios\"\n",
        "description: \"Resuelve problemas de optimización binaria con restricciones en hardware de tipo « IBM Quantum » utilizando el método iterativo QAOA con «warm-starting» y mezcladores XY de Aqarios.\"\n",
        "---\n",
        "\n",
        "{/* cspell:ignore Aqarios QOBLIB Bucher docplex forall Zachary quicksum */}\n",
        "\n",
        "<span id=\"constrained-quantum-optimizer---a-qiskit-function-by-aqarios\" />\n",
        "\n",
        "# Optimizador cuántico con restricciones: una función de Qiskit desarrollada por Aqarios\n",
        "\n",
        "*Consulta la [referencia de la API](/docs/api/functions/aqarios-constrained-quantum-optimizer)*\n",
        "\n",
        "<Admonition type=\"note\">\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",
        "<span id=\"overview\" />\n",
        "\n",
        "## Visión general\n",
        "\n",
        "Con el «Constrained Quantum Optimizer» de Aqarios, puedes resolver problemas de optimización binaria con restricciones en hardware cuántico d IBM®, sin necesidad de reformulación manual ni mapeo de circuitos. Solo tienes que proporcionar un problema en formato de archivo LP, MPS o [Luna Model](https://docs.aqarios.com/luna-model). La función se encarga automáticamente de la reformulación, la síntesis de circuitos, la transpilación y la ejecución en hardware. El solucionador utiliza el método iterativo de «warm-starting» [\\[1\\]](#references) del algoritmo « [FlexQAOA](https://docs.aqarios.com/luna-solve/algorithms/quantum-gate/flexqaoa/) », una extensión nativa de restricciones del algoritmo cuántico de optimización aproximada (QAOA).\n",
        "\n",
        "El optimizador está diseñado para resolver problemas binarios con restricciones. En concreto, las restricciones «one-hot» y las restricciones de empaquetamiento de conjuntos pueden aplicarse de forma nativa mediante el uso de mezcladores XY. Otros tipos de restricciones se reformulan automáticamente como términos de penalización.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e9f4110b",
      "metadata": {
        "tags": [
          "version-info"
        ]
      },
      "source": [
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8bcd63ea",
      "metadata": {},
      "source": [
        "<span id=\"description\" />\n",
        "\n",
        "## Descripción\n",
        "\n",
        "<Admonition type=\"caution\" title=\"Declaración de limitación de responsabilidad\">\n",
        "  El rendimiento puede depender tanto de la instancia del problema como de los pasos de procesamiento posteriores. En algunos casos, las muestras clásicas y las generadas cuánticamente podrían alcanzar una calidad final de solución similar tras un posprocesamiento equivalente. Por lo tanto, la evaluación debería tener en cuenta todo el flujo de trabajo de optimización.\n",
        "</Admonition>\n",
        "\n",
        "El optimizador cuántico con restricciones implementa el algoritmo QAOA con mezclador XY iterativo y arranque en caliente (IWS-QAOA) [\\[1\\]](#references). El algoritmo ejecuta circuitos QAOA de ángulo fijo en hardware cuántico y actualiza las probabilidades iniciales de «warm-start» de cada circuito utilizando los resultados de las mediciones de la iteración anterior. No es necesario entrenar ningún parámetro variacional; en su lugar, se elige una parametrización de rampa lineal fija.\n",
        "\n",
        "Al utilizar mezcladores XY para aplicar restricciones «one-hot», se puede mejorar drásticamente la calidad de la solución en problemas con restricciones, ya que el espacio de búsqueda se reduce prácticamente a un subespacio factible más pequeño, sin que se introduzca ninguna complejidad adicional —debida a los términos de penalización— en el paisaje de optimización.\n",
        "\n",
        "<span id=\"workflow\" />\n",
        "\n",
        "### Flujo de trabajo\n",
        "\n",
        "A continuación se describe el flujo de trabajo de la función:\n",
        "\n",
        "1. **Preprocesamiento** : Antes de la síntesis del circuito, el optimizador analiza la estructura de restricciones del problema de entrada:\n",
        "   * *Preprocesamiento de grafos:* cuando resulta aplicable al problema, este se analiza como un grafo, en el que las aristas determinan la relación entre las variables. Este análisis de gráficos permite introducir dos mejoras en el tratamiento previo de los problemas. En primer lugar, las restricciones individuales pueden agruparse en una sola restricción de mayor envergadura mediante la fusión de cliques, de modo que queden representadas por un único mezclador XY. En segundo lugar, las variables que solo tienen un vecino pueden fijarse de forma determinista, lo que reduce el tamaño y la complejidad del problema.\n",
        "   * *Resolución de restricciones:* El preprocesador gestiona cada restricción por separado: si la restricción es del tipo «one-hot», puede aplicarse mediante mezcladores XY. Si se trata de una restricción de empaquetamiento de conjuntos, primero se transformará en una restricción de tipo «one-hot». Las restricciones de igualdad se gestionan mediante penalizaciones cuadráticas, y las restricciones de desigualdad, mediante [penalización desequilibrada](https://doi.org/10.1088/2058-9565/ad35e4).\n",
        "   * *Derivación de la penalización:* Las restricciones que no pueden expresarse como restricciones de igualdad «one-hot» se convierten en términos de penalización. El optimizador deduce automáticamente la intensidad de la penalización a partir de la estructura del problema.\n",
        "2. **Inicio en caliente iterativo** : el optimizador ejecuta varias *cadenas de inicio en caliente en paralelo*. Cada cadena contiene una distribución de probabilidad sobre las asignaciones de variables, que se utiliza como probabilidad inicial del circuito QAOA (estado de arranque en caliente). En cada iteración, una cadena toma muestras del circuito cuántico, aplica un posprocesamiento clásico y actualiza su distribución en función de la aparición de las muestras. A lo largo de las iteraciones, esto centra la búsqueda en soluciones de alta calidad sin necesidad de un bucle de optimización variacional.\n",
        "\n",
        "El número de cadenas (`num_parallel`), el presupuesto total de disparos por cadena (`total_shots`) y el número de repeticiones de QAOA (`reps`) son los principales parámetros que permiten equilibrar la calidad de la solución y el tiempo de ejecución.\n",
        "\n",
        "![Diagrama de flujo del optimizador cuántico con restricciones](https://quantum.cloud.ibm.com/docs/images/guides/aqarios-constrained-quantum-optimizer/cqo-diagram.svg)\n",
        "\n",
        "<span id=\"benchmarks\" />\n",
        "\n",
        "## Referencias comparativas\n",
        "\n",
        "Las pruebas comparativas que se muestran a continuación demuestran que la función «Constrained Quantum Optimizer» de Qiskit es capaz de encontrar soluciones viables y de alta calidad para problemas de optimización con restricciones que cuentan con más de 100 variables binarias. La precisión es la relación entre el valor objetivo obtenido y el valor óptimo conocido. El tiempo de ejecución es el tiempo real transcurrido desde la invocación de la función hasta la entrega del resultado. El uso de la QPU es el tiempo de computación cuántica facturable.\n",
        "\n",
        "Se analizaron dos problemas: el problema [del conjunto independiente máximo](/docs/tutorials/find-the-maximum-independent-set-with-aqarios-constrained-quantum-optimizer) (MIS) y el «Max- $k$ -Cut», que es una extensión del conocido problema « MaxCut » a más de dos categorías. El problema de «Max- $k$ -Cut» es también el problema de optimización equivalente al problema de decisión de coloración de grafos (cuando se cortan todas las aristas, el grafo es « $k$ -colorable»).\n",
        "\n",
        "| Problema                 | Variables | Restricciones | Qubits | Precisión | Viabilidad | Tiempo total de ejecución (s) | Uso de la CPU (s) | Total de tiros |\n",
        "| ------------------------ | --------- | ------------- | ------ | --------- | ---------- | ----------------------------- | ----------------- | -------------- |\n",
        "| MIS es60fst02            | 186       | 280           | 124    | 100.0%    | Sí         | 940.2                         | 147.0             | 25.0k          |\n",
        "| MIS sloane\\_2dc\\_128     | 128       | 5173          | 74     | 100.0%    | Sí         | 347.6                         | 106.0             | 12.5k          |\n",
        "| Max-3-Cut Club de kárate | 99        | 33            | 99     | 98.7%     | Sí         | 279.5                         | 166.0             | 25.0k          |\n",
        "| Max-4-Cut Club de kárate | 132       | 33            | 132    | 100.0%    | Sí         | 258.3                         | 200.0             | 25.0k          |\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5f761442",
      "metadata": {},
      "source": [
        "<span id=\"benchmark-notes\" />\n",
        "\n",
        "### Notas sobre las pruebas de referencia\n",
        "\n",
        "* Los resultados anteriores se obtuvieron en el procesador Heron `ibm_marrakesh` r2 con las opciones predeterminadas y la función `use_session` activada. Por ejemplo `sloane_2dc_128` , `total_shots=12500` se utilizó.\n",
        "* El menor número de qubits en los casos de MIS (74 y 124 frente a 128 y 186 variables) se debe a la fijación de variables en el preprocesamiento.\n",
        "* Las instancias de problemas para MIS proceden de la [Biblioteca de Referencia de Optimización Cuántica](https://doi.org/10.1038/s43588-026-00991-1). - La instancia para el problema del corte «Max- $k$ -Cut» es el [grafo del Club de Kárate Zachary](https://en.wikipedia.org/wiki/Zachary%27s_karate_club), que tiene un número cromático de 5.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "73390a19",
      "metadata": {},
      "source": [
        "<span id=\"get-started\" />\n",
        "\n",
        "## Cómo empezar\n",
        "\n",
        "Esta guía explica el funcionamiento básico del «Constrained Quantum Optimizer», mostrando cómo cargar la función y resolver problemas sencillos. Si deseas un tutorial más detallado, consulta «[Cómo hallar el conjunto independiente máximo con el optimizador cuántico con restricciones de Aqarios](/docs/tutorials/find-the-maximum-independent-set-with-aqarios-constrained-quantum-optimizer) ».\n",
        "\n",
        "Inicia sesión con tu clave API de IBM Quantum y tu instancia CRN; a continuación, carga la función desde el catálogo.\n",
        "\n",
        "<Admonition type=\"note\">\n",
        "  El siguiente código da por hecho que ya has guardado tus credenciales. Para configurarlas, sigue las instrucciones que figuran en «[Guarda las credenciales de tu cuenta de IBM Cloud](/docs/guides/functions-get-started#install-qiskit-functions-catalog-client) ».\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "95a715d2",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "[QiskitFunction(aqarios/constrained-quantum-optimizer)]"
            ]
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit_ibm_catalog import QiskitFunctionsCatalog\n",
        "\n",
        "catalog = QiskitFunctionsCatalog(channel=\"ibm_quantum_platform\")\n",
        "\n",
        "# Verify that you have access to the function\n",
        "catalog.list()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "fe865158",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Load the function\n",
        "optimizer = catalog.load(\"aqarios/constrained-quantum-optimizer\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "d976e101",
      "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": 3,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Check the list of backends you have access to\n",
        "catalog.backends()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "6b0f5c79",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Select the backend you want to use\n",
        "backend = catalog.backend(\"ibm_phoenix\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e4445979",
      "metadata": {},
      "source": [
        "<span id=\"example-1-a-simple-constrained-problem\" />\n",
        "\n",
        "## Ejemplo 1: Un problema sencillo con restricciones\n",
        "\n",
        "El primer ejemplo muestra cómo utilizar la función con [archivos LP](https://www.ibm.com/docs/en/icos/22.1.1?topic=cplex-lp-file-format-algebraic-representation), un formato habitual para especificar problemas de optimización en la investigación operativa. Deberás formular el siguiente problema de optimización arbitrario de cinco variables binarias $x_i \\in \\{0,1\\}$, sujeto a dos restricciones:\n",
        "\n",
        "$$\n",
        "    \\min x_1 x_2 + 2 x_2 x_3 - x_3 x_4 - 2 x_4 x_5 - 2 x_1 x_3 - 4 x_2 x_5 \\\\\n",
        "    \\text{s.t.}\\quad x_1 + x_2 + x_3 \\leq 1 \\\\\n",
        "    \\quad x_3 - x_4 + x_5 = 0\n",
        "$$\n",
        "\n",
        "<span id=\"1-formulate-the-problem\" />\n",
        "\n",
        "### 1. Plantear el problema\n",
        "\n",
        "Expresa directamente la expresión matemática en el siguiente formato de cadena LP:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "7c3af25d",
      "metadata": {
        "lines_to_next_cell": 0
      },
      "outputs": [],
      "source": [
        "lp_str = \"\"\"\\\\Problem name: Example\n",
        "Minimize\n",
        "  obj: [ 2 x_1 x_2 + 4 x_2 x_3 - 2 x_3 x_4 - 4 x_4 x_5 - 4 x_1 x_3 - 8 x_2 x_5 ] / 2\n",
        "Subject To\n",
        "  c1: x_1 + x_2 + x_3 <= 1\n",
        "  c2: x_3 - x_4 + x_5 = 0\n",
        "Binaries\n",
        "  x_1 x_2 x_3 x_4 x_5\n",
        "End\n",
        "\"\"\""
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f6c75f9d",
      "metadata": {},
      "source": [
        "Ten en cuenta que `[...] / 2` es una notación obligatoria para los objetivos cuadráticos según la norma del PL.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "003a933c",
      "metadata": {},
      "source": [
        "<span id=\"2-run-the-optimizer\" />\n",
        "\n",
        "### 2. Ejecuta el optimizador\n",
        "\n",
        "Resuelve el problema con el optimizador.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "242f1f89",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Job ID: 2e06a3a8-7c29-4c76-94d7-194293363f4a\n"
          ]
        }
      ],
      "source": [
        "# Set up low-resource options for the simple problem\n",
        "options = {\"total_shots\": 2000, \"num_parallel\": 5, \"use_session\": True}\n",
        "\n",
        "# Dispatch the job\n",
        "job_1 = optimizer.run(\n",
        "    model=lp_str, backend_name=backend.name, options=options\n",
        ")\n",
        "\n",
        "print(f\"Job ID: {job_1.job_id}\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "4bd4790a",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "'RUNNING: WAITING_FOR_QPU'"
            ]
          },
          "execution_count": 7,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Monitor the job status\n",
        "job_1.status()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "acff0671",
      "metadata": {
        "lines_to_next_cell": 0
      },
      "source": [
        "<span id=\"3-retrieve-the-result\" />\n",
        "\n",
        "### 3. Obtener el resultado\n",
        "\n",
        "La solución, que consiste en asignar los nombres de las variables a las asignaciones correspondientes, se obtiene del resultado.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "6a121188",
      "metadata": {
        "lines_to_next_cell": 0
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "{'solutions': [{'x_1': 0, 'x_2': 1, 'x_3': 0, 'x_4': 1, 'x_5': 1}],\n",
              " 'raw_energy': -6.0,\n",
              " 'obj_value': -6.0,\n",
              " 'feasible': True,\n",
              " 'metadata': {'resource_usage': {'RUNNING: MAPPING': {'CPU': 5.405},\n",
              "   'RUNNING: OPTIMIZING_FOR_HARDWARE': {'CPU': 9.902},\n",
              "   'RUNNING: WAITING_FOR_QPU': {'CPU': 25.456},\n",
              "   'RUNNING: EXECUTING_QPU': {'CPU': 25.202},\n",
              "   'RUNNING: POST_PROCESSING': {'CPU': 6.481}},\n",
              "  'circuit_metrics': {'depth': 100.95,\n",
              "   '2Q-depth': 33.0,\n",
              "   'sx': 122.25,\n",
              "   'rz': 78.85,\n",
              "   'cz': 48.0,\n",
              "   'x': 0.4}}}"
            ]
          },
          "execution_count": 8,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "result = job_1.result()\n",
        "\n",
        "result"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e8837f5f",
      "metadata": {},
      "source": [
        "El `solutions` campo del diccionario de retorno contiene todas las mejores soluciones degeneradas encontradas. Junto con los datos de la solución, `metadata` se proporcionan el `obj_value`, un indicador `feasible` y adicionales.\n",
        "\n",
        "<span id=\"example-2-maximum-independent-set\" />\n",
        "\n",
        "## Ejemplo 2: Conjunto independiente máximo\n",
        "\n",
        "El problema del conjunto independiente máximo (MIS) consiste en hallar el mayor subconjunto de vértices de un grafo tal que ningún par de vértices del subconjunto comparta un arco. Este ejemplo resuelve el problema MIS en un grafo regular de 12 nodos. Para obtener más información sobre el problema y ver un ejemplo más extenso, consulta el [tutorial](/docs/tutorials/find-the-maximum-independent-set-with-aqarios-constrained-quantum-optimizer).\n",
        "\n",
        "El problema se ha creado con [qiskit-addon-opt-mapper](https://github.com/qiskit/qiskit-addon-opt-mapper).\n",
        "Instala los paquetes necesarios si es preciso:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "a1e2f301",
      "metadata": {},
      "outputs": [],
      "source": [
        "# %pip install networkx qiskit-addon-opt-mapper"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d56e1440",
      "metadata": {},
      "source": [
        "<span id=\"step-1-define-the-problem\" />\n",
        "\n",
        "### Paso 1: Definir el problema\n",
        "\n",
        "Crea un grafo aleatorio de 3-regular y formula el problema de optimización del MIS. Cada nodo del grafo se convierte en una variable binaria, y cada arista introduce una restricción que garantiza que se seleccione, como máximo, un extremo.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "03998691",
      "metadata": {},
      "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",
            "Subject To\n",
            " c0: x_0 + x_4 <= 1\n",
            " c1: x_0 + x_9 <= 1\n",
            " c2: x_0 + x_8 <= 1\n",
            " c3: x_1 + x_2 <= 1\n",
            " c4: x_1 + x_7 <= 1\n",
            " c5: x_1 + x_3 <= 1\n",
            " c6: x_2 + x_4 <= 1\n",
            " c7: x_2 + x_11 <= 1\n",
            " c8: x_3 + x_10 <= 1\n",
            " c9: x_3 + x_11 <= 1\n",
            " c10: x_4 + x_5 <= 1\n",
            " c11: x_5 + x_10 <= 1\n",
            " c12: x_5 + x_6 <= 1\n",
            " c13: x_6 + x_8 <= 1\n",
            " c14: x_6 + x_7 <= 1\n",
            " c15: x_7 + x_9 <= 1\n",
            " c16: x_8 + x_11 <= 1\n",
            " c17: x_9 + x_10 <= 1\n",
            "\n",
            "Bounds\n",
            " 0 <= x_0 <= 1\n",
            " 0 <= x_1 <= 1\n",
            " 0 <= x_2 <= 1\n",
            " 0 <= x_3 <= 1\n",
            " 0 <= x_4 <= 1\n",
            " 0 <= x_5 <= 1\n",
            " 0 <= x_6 <= 1\n",
            " 0 <= x_7 <= 1\n",
            " 0 <= x_8 <= 1\n",
            " 0 <= x_9 <= 1\n",
            " 0 <= x_10 <= 1\n",
            " 0 <= x_11 <= 1\n",
            "\n",
            "Binaries\n",
            " 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",
            "End\n",
            "\n"
          ]
        }
      ],
      "source": [
        "import networkx as nx\n",
        "from qiskit_addon_opt_mapper.applications import IndependentSet\n",
        "from qiskit_addon_opt_mapper.translators import to_docplex_mp\n",
        "\n",
        "# 12-node random 3-regular graph\n",
        "G = nx.random_regular_graph(3, 12, seed=7)\n",
        "\n",
        "# Build MIS problem and export as LP string\n",
        "mis = IndependentSet(G)\n",
        "mis_problem = mis.to_optimization_problem()\n",
        "lp_str = to_docplex_mp(mis_problem).export_as_lp_string()\n",
        "\n",
        "print(lp_str)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e6f7a8b9",
      "metadata": {
        "lines_to_next_cell": 0
      },
      "source": [
        "<span id=\"step-2-run-the-optimizer\" />\n",
        "\n",
        "### Paso 2: Ejecuta el optimizador\n",
        "\n",
        "Resuelve el problema con el optimizador.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "04236c83",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Job ID: f041431c-b42e-4627-afe5-522fea61faf6\n"
          ]
        }
      ],
      "source": [
        "options = {\"total_shots\": 2000, \"use_session\": True}\n",
        "\n",
        "# Dispatch the job\n",
        "job_2 = optimizer.run(\n",
        "    model=lp_str, backend_name=backend.name, options=options\n",
        ")\n",
        "\n",
        "print(f\"Job ID: {job_2.job_id}\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "id": "079ebc2f",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "'QUEUED'"
            ]
          },
          "execution_count": 11,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Monitor the job status\n",
        "job_2.status()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "90c6de7c",
      "metadata": {},
      "source": [
        "<span id=\"step-3-retrieve-and-interpret-results\" />\n",
        "\n",
        "### Paso 3: Obtener e interpretar los resultados\n",
        "\n",
        "Por último, recuperamos la solución y comprobamos que sea correcta.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "id": "f1a2b3c4",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Feasible: True\n",
            "Independent set size: 5\n",
            "Selected nodes: [1, 4, 6, 9, 11]\n",
            "Edge conflicts: []\n"
          ]
        }
      ],
      "source": [
        "result = job_2.result()\n",
        "\n",
        "print(f\"Feasible: {result['feasible']}\")\n",
        "print(f\"Independent set size: {int(result['obj_value'])}\")\n",
        "\n",
        "# Extract the selected nodes\n",
        "solution = result[\"solutions\"][0]\n",
        "independent_set = [\n",
        "    int(k.split(\"_\")[1]) for k, v in solution.items() if v == 1\n",
        "]\n",
        "print(f\"Selected nodes: {sorted(independent_set)}\")\n",
        "\n",
        "# Verify no two selected nodes share an edge\n",
        "conflicts = [\n",
        "    (u, v)\n",
        "    for u, v in G.edges()\n",
        "    if u in independent_set and v in independent_set\n",
        "]\n",
        "print(f\"Edge conflicts: {conflicts}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a2b3c4d5",
      "metadata": {},
      "source": [
        "<span id=\"example-3-graph-3-coloring-max-3-cut\" />\n",
        "\n",
        "## Ejemplo 3: Coloreado de grafos de 3 colores ( Max-3-Cut )\n",
        "\n",
        "El problema «Max- $k$ -Cut» divide los vértices de un grafo en grupos « $k$ » con el fin de maximizar el número de aristas cuyos extremos pertenecen a grupos diferentes. Para $k = 3$, esto equivale a encontrar una coloración de 3 colores que maximice el número de aristas de colores cruzados.\n",
        "\n",
        "Formalmente, se asigna cada nodo $i \\in V$ a uno de los grupos $k$ con variables binarias $x_{i,c}$ para el color $c \\in \\{1, \\ldots, k\\}$. La restricción «one-hot» $\\sum_c x_{i,c} = 1$ para cada nodo garantiza una asignación única. El objetivo maximiza los enlaces entre grupos:\n",
        "\n",
        "$$\n",
        "\\min \\sum_{(u,v) \\in E} \\sum_c x_{u,c} \\, x_{v,c}\\\\\n",
        "\\text{s.t.} \\sum_{c} x_{i,c} = 1 \\quad \\forall i \\in  V\n",
        "$$\n",
        "\n",
        "Las restricciones «one-hot» son ideales para los mezcladores XY, que el optimizador gestiona de forma nativa.\n",
        "\n",
        "En este ejemplo se utiliza el [grafo del](https://en.wikipedia.org/wiki/Zachary%27s_karate_club) Zachary Karate Club (34 nodos, 78 aristas) y se construye el modelo con [Luna Model](https://docs.aqarios.com/luna-model/).\n",
        "Instala los paquetes necesarios si es preciso:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "b3c4d5e6",
      "metadata": {},
      "outputs": [],
      "source": [
        "# %pip install networkx matplotlib luna-model"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c4d5e6f7",
      "metadata": {},
      "source": [
        "<span id=\"step-1-define-the-problem\" />\n",
        "\n",
        "### Paso 1: Definir el problema\n",
        "\n",
        "En primer lugar, genera las variables binarias con el paquete `luna-model` . A continuación, define el objetivo e incorpora las restricciones al modelo.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "id": "d5e6f7a8",
      "metadata": {},
      "outputs": [],
      "source": [
        "import networkx as nx\n",
        "from luna_model import Model, quicksum\n",
        "\n",
        "k = 3\n",
        "G = nx.karate_club_graph()\n",
        "\n",
        "# Instantiate the Model object\n",
        "model = Model(name=\"Max-3-Cut\")\n",
        "\n",
        "# Add binary variables\n",
        "x = model.add_variables(\"x\", shape=(G.number_of_nodes(), k))\n",
        "\n",
        "# Add the objective by using the numpy dot abstraction\n",
        "model.objective = quicksum(x[i].dot(x[j]) for i, j in G.edges)\n",
        "\n",
        "# Bulk-add the one-hot constraints\n",
        "model.add_constraints(x.sum(axis=1) == 1)\n",
        "\n",
        "# Encode the model to send via API\n",
        "model_enc = model.encode_b64()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "263ccb5d",
      "metadata": {
        "lines_to_next_cell": 0
      },
      "source": [
        "<span id=\"step-2-run-the-optimizer\" />\n",
        "\n",
        "### Paso 2: Ejecuta el optimizador\n",
        "\n",
        "Resuelve el problema con el optimizador.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "f7a8b9c0",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Job ID: df911d83-9df7-44a1-bfad-5d66e08676c3\n"
          ]
        }
      ],
      "source": [
        "options = {\"use_session\": True}\n",
        "\n",
        "# Dispatch the job\n",
        "job_3 = optimizer.run(\n",
        "    model=model_enc, backend_name=backend.name, options=options\n",
        ")\n",
        "\n",
        "print(f\"Job ID: {job_3.job_id}\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 15,
      "id": "e2ff9b51",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "'RUNNING: WAITING_FOR_QPU'"
            ]
          },
          "execution_count": 15,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Monitor the job status\n",
        "job_3.status()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a8b9c0d1",
      "metadata": {},
      "source": [
        "<span id=\"step-3-retrieve-and-visualize-results\" />\n",
        "\n",
        "### Paso 3: Obtener y visualizar los resultados\n",
        "\n",
        "Recupera y visualiza los resultados.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 16,
      "id": "b9c0d1e2",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Feasible: True\n",
            "Violations: 4\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/aqarios-constrained-quantum-optimizer/extracted-outputs/b9c0d1e2-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "result = job_3.result()\n",
        "solution = result[\"solutions\"][0]\n",
        "\n",
        "# Map each node to its assigned color group\n",
        "node_group = {}\n",
        "for i in G.nodes:\n",
        "    for c in range(k):\n",
        "        if solution[f\"x{i},{c}\"] == 1:\n",
        "            node_group[i] = c\n",
        "\n",
        "print(f\"Feasible: {result['feasible']}\")\n",
        "print(f\"Violations: {int(result['obj_value'])}\")\n",
        "\n",
        "# Visualize the partition\n",
        "colors = [\"tab:blue\", \"tab:orange\", \"tab:green\"]\n",
        "node_colors = [colors[node_group[i]] for i in G.nodes()]\n",
        "nx.draw(G, nx.kamada_kawai_layout(G), node_color=node_colors, node_size=200)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e9ec2e67",
      "metadata": {},
      "source": [
        "<span id=\"get-support\" />\n",
        "\n",
        "## Obtener soporte\n",
        "\n",
        "Si tienes alguna pregunta o problema, ponte en contacto con [support@aqarios.com](mailto:support@aqarios.com) indicando tu número de referencia.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5a6a25c8",
      "metadata": {
        "jp-MarkdownHeadingCollapsed": true
      },
      "source": [
        "<span id=\"next-steps\" />\n",
        "\n",
        "## Próximos pasos\n",
        "\n",
        "<Admonition type=\"tip\" title=\"Recomendaciones\">\n",
        "  * [Solicita acceso al «Constrained Quantum Optimizer» de Aqarios](https://aqarios.com/qiskit-function-access/).\n",
        "  * Consulta la [referencia de la API](/docs/api/functions/aqarios-constrained-quantum-optimizer) para obtener la documentación completa sobre los parámetros y los resultados.\n",
        "  * Prueba el tutorial [«Encontrar el conjunto independiente máximo con el optimizador cuántico con restricciones de Aqarios»](/docs/tutorials/find-the-maximum-independent-set-with-aqarios-constrained-quantum-optimizer) para profundizar en una instancia real del banco de pruebas QOBLIB.\n",
        "  * Consulta la publicación «[Optimización cuántica con restricciones mediante mezcladores XY iterativos con arranque en caliente](https://doi.org/10.1088/1367-2630/ae8ea2) ».\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6c0a20cb",
      "metadata": {},
      "source": [
        "<span id=\"references\" />\n",
        "\n",
        "## Referencias\n",
        "\n",
        "1. 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",
        "\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
}