{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "e1dea188",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Encontre o Conjunto Independente Máximo com o Otimizador Quântico Restrito Aqarios\"\n",
        "description: \"Utilize o Otimizador Quântico Restrito Aqarios, baseado em warm-starting iterativo e misturadores XY, para resolver o problema do Conjunto Independente Máximo em um hardware d 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",
        "# Encontre o Conjunto Independente Máximo com o Otimizador Quântico Restrito Aqarios\n",
        "\n",
        "<Admonition type=\"note\" title=\"Nota\">\n",
        "  Qiskit Functions são um recurso experimental disponível apenas para usuários dos planos “ IBM Quantum® Premium Plan ”, “Flex Plan” e “ On-Prem ” (por meio da API do IBM Quantum Platform ). Elas estão em fase de pré-lançamento e estão sujeitas a alterações.\n",
        "</Admonition>\n",
        "\n",
        "Estimativa de *tempo de execução: 30 segundos em um processador Heron r2. (OBSERVAÇÃO: Trata-se apenas de uma estimativa. (O tempo de execução pode 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",
        "## Segundo plano\n",
        "\n",
        "Este tutorial demonstra como encontrar o conjunto independente máximo de um grafo utilizando o [Otimizador Quântico com Restrições Aqarios](/docs/guides/aqarios-constrained-quantum-optimizer) [\\[1\\]](#references), um problema de otimização combinatória com restrições.\n",
        "Uma instância da biblioteca de benchmark QOBLIB [\\[2\\]](#references) é formulada como um programa linear binário e passada para a Função de Aplicação do Otimizador.\n",
        "O otimizador realiza internamente toda a reformulação, síntese de circuitos, transpilagem e inicialização iterativa (consulte [\\[3\\]](#references) para obter mais detalhes).\n",
        "\n",
        "O tutorial aborda as seguintes etapas:\n",
        "\n",
        "1. Defina o problema como um programa linear utilizando o `OptimizationProblem` do [qiskit-addon-opt-mapper](https://github.com/qiskit/qiskit-addon-opt-mapper)\n",
        "2. Execute a otimização quântica utilizando o Aqarios Constrained Quantum Optimizer\n",
        "3. Recuperar e visualizar os resultados\n",
        "\n",
        "<span id=\"the-maximum-independent-set-problem\" />\n",
        "\n",
        "### O problema do Conjunto Independente Máximo\n",
        "\n",
        "O problema do Conjunto Independente Máximo (MIS) é um desafio fundamental na otimização combinatória.\n",
        "Formalmente, dado um grafo $G(V, E)$, o objetivo é encontrar o maior subconjunto de vértices $V_I \\subset V$ tal que nenhum par de vértices em $V_I$ esteja conectado por uma aresta, conforme ilustrado em $\\nexists (u, v) \\in E : v \\in V_I \\wedge u \\in V_I$.\n",
        "A cada vértice é atribuída uma variável de decisão binária $x_i \\in \\{0, 1\\}$, e uma restrição $x_u + x_v \\leq 1$ é introduzida para cada aresta, garantindo que, no máximo, uma das extremidades de cada aresta seja selecionada.\n",
        "O problema pode, portanto, ser formulado como o seguinte problema de maximização:\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",
        "O MIS possui uma ampla gama de aplicações práticas. No planejamento de redes sem fio, um conjunto independente corresponde a um grupo de transmissores que podem transmitir simultaneamente sem causar interferência mútua. No planejamento de horários, ele modela o maior conjunto de tarefas que podem ser executadas simultaneamente, levando em conta os conflitos de recursos entre pares. Na biologia computacional, ele identifica conjuntos de proteínas que não interagem entre si em uma rede.\n",
        "\n",
        "Apesar de sua formulação intuitiva, o MIS é NP-difícil e, mesmo para grafos com algumas centenas de nós, instâncias específicas tornam-se difíceis de resolver exatamente ou de forma heurística [\\[2\\]](#references).\n",
        "O problema também dá origem a estruturas de restrições esparsas que são adequadas para implementações em hardware de otimização quântica, tornando-o um benchmark atraente para dispositivos quânticos no curto prazo.\n",
        "\n",
        "<span id=\"aqarios-constrained-quantum-optimizer\" />\n",
        "\n",
        "### Otimizador Quântico com Restrições Aqarios\n",
        "\n",
        "A abordagem padrão para incorporar um problema binário com restrições à otimização quântica transforma o modelo em um formato sem restrições por meio da adição de termos de penalidade: cada restrição violada $x_u + x_v \\leq 1$ contribui com $2 x_u x_v$ para o objetivo de minimização $-\\sum_i x_i$. Isso é tratado automaticamente pela função Constrained Quantum Optimizer do Qiskit.\n",
        "\n",
        "Além dessa transformação padrão, o otimizador identifica **cliques** no grafo de restrições. Um clique é um conjunto de vértices $V_C$ em que cada par de vértices é conectado por uma aresta. Consequentemente, as restrições em pares $\\binom{|V_C|}{2}$ $x_u + x_v \\leq 1 \\;\\forall (u,v) \\in E_C$ podem ser substituídas por uma única restrição mais restritiva $\\sum_{i \\in V_C} x_i \\leq 1$. A introdução de uma variável de folga $y$ transforma isso em uma igualdade $\\sum_i x_i + y = 1$, que assume a forma de uma restrição “one-hot” que pode ser aplicada diretamente no QAOA usando **misturadores XY** [\\[3\\]](#references). Isso reduz o espaço de busca e evita a necessidade de termos de penalidade para essas restrições, melhorando a qualidade da solução.\n",
        "\n",
        "Além disso, as variáveis conectadas a apenas um único vizinho são chamadas de nós **pendentes** e são definidas de forma determinística pelo algoritmo antes da execução quântica, reduzindo ainda mais o tamanho efetivo do problema.\n",
        "\n",
        "O Otimizador Quântico Restrito emprega uma abordagem **iterativa de “warm-starting”** compatível com misturadores XY [\\[1\\]](#references), que reduz progressivamente o espaço de busca ao direcionar a distribuição do estado quântico para regiões de solução promissoras ao longo das iterações. Isso permite o uso de **parâmetros QAOA de ângulo fixo**, eliminando a necessidade de treinamento de parâmetros variacionais. Os requisitos totais de recursos quânticos são determinados exclusivamente pelo número de iterações de inicialização a quente, o que significa que o custo quântico é 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 iniciar este tutorial, certifique-se de ter instalado os seguintes pré-requisitos:\n",
        "\n",
        "* Qiskit Runtime (`pip install qiskit-ibm-runtime`)\n",
        "* Qiskit Functions Catalog IBM Cliente (`pip install qiskit-ibm-catalog`)\n",
        "* Mapeador de otimização do complemento do Qiskit (`pip install qiskit-addon-opt-mapper`)\n",
        "* Numpy (`pip install numpy`)\n",
        "* Matplotlib (`pip install matplotlib`)\n",
        "* NetworkX (`pip install networkx`)\n",
        "\n",
        "Opcionalmente, para o [Apêndice,](#appendix-problem-statement-with-luna-model) é necessário instalar\n",
        "\n",
        "* Modelo Luna (`pip install luna-model`)\n",
        "\n",
        "<span id=\"setup\" />\n",
        "\n",
        "## Instalação\n",
        "\n",
        "Importe todas as dependências necessárias.\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": [
        "Primeiro, faça a autenticação usando sua [chave de API do IBM Quantum.](http://quantum.cloud.ibm.com/) Em seguida, selecione a função do Qiskit da seguinte maneira. (Este código pressupõe que você já tenha [salvo sua conta](/docs/guides/functions-get-started#install-qiskit-functions-catalog-client) no seu ambiente 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",
        "## Etapa 1: Mapeamento de entradas clássicas para o problema quântico\n",
        "\n",
        "O problema é formulado como um **arquivo LP**, um formato comum para problemas de otimização que serve como entrada para o Aqarios Constrained Quantum Optimizer. Além dos arquivos LP, a função também suporta **arquivos MPS** e representações nativas **do Luna Model**.\n",
        "O arquivo LP é gerado por meio das seguintes etapas:\n",
        "\n",
        "1. Buscar uma instância de grafo da biblioteca QOBLIB [\\[2\\]](#references)\n",
        "2. Modelar o problema de otimização\n",
        "3. Gerar o arquivo LP\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c773d45b",
      "metadata": {},
      "source": [
        "<span id=\"load-the-problem-instance-graph\" />\n",
        "\n",
        "### Carregar o gráfico da instância do problema\n",
        "\n",
        "Os gráficos são especificados no formato `.gph` DIMACS, um formato baseado em linhas em que as linhas que começam com `e` definem arestas, as linhas que começam com `p` definem o cabeçalho do problema e as linhas que começam com `c` são comentários:\n",
        "\n",
        "```\n",
        "c some-comment\n",
        "p edge 3 2\n",
        "e 1 2\n",
        "e 2 3\n",
        "...\n",
        "```\n",
        "\n",
        "O arquivo `.gph` pode ser baixado do repositório QOBLIB por meio da seguinte função, que também o analisa para gerar um gráfico do tipo “ NetworkX ”. Observe que o formato DIMACS utiliza numeração de nós a partir de 1, que é convertida aqui para indexação a partir de 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": [
        "Este exemplo utiliza a `es60fst02` instância da QOBLIB, um grafo com 186 nós e 280 arestas. Graças às etapas de pré-processamento empregadas pelo Otimizador Quântico Restrito, esta instância pode ser resolvida em dispositivos Heron de 156 qubits. O gráfico pode ser visualizado usando o 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",
        "### Formule o problema de otimização\n",
        "\n",
        "O problema do Conjunto Independente Máximo pode ser formulado diretamente usando `OptimizationProblem`. Cada nó do grafo se torna uma variável de decisão binária, e cada aresta introduz uma restrição que garante que, no máximo, uma de suas extremidades seja selecionada:\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",
        "#### Um atalho\n",
        "\n",
        "O [`qiskit-addon-opt-mapper`](https://qiskit.github.io/qiskit-addon-opt-mapper/) pacote oferece uma classe de aplicação pré-implementada para o problema do Conjunto Independente Máximo, o que simplifica a formulação acima em uma única chamada:\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",
        "### Converta o problema em um arquivo LP\n",
        "\n",
        "O próprio `OptimizationProblem` programa não oferece suporte à exportação de arquivos LP, mas é compatível com [o DOcplex](https://www.ibm.com/docs/de/icos/22.1.2?topic=docplex-python-modeling-api), que oferece esse recurso. Para gerar o conteúdo do arquivo LP, bastam duas linhas:\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": [
        "Esse formato é nativo do Constrained Quantum Optimizer.\n",
        "\n",
        "<span id=\"step-2-optimize-problem-for-quantum-hardware-execution\" />\n",
        "\n",
        "## Etapa 2: Otimizar o problema para execução em hardware quântico\n",
        "\n",
        "Toda a síntese, otimização e transpilagem de circuitos são realizadas de forma nativa pela função. Consulte a [seção de entradas](/docs/api/functions/aqarios-constrained-quantum-optimizer#inputs) na referência da API para conhecer os argumentos com os quais se deve chamar a função.\n",
        "\n",
        "Para ajustar o comportamento do algoritmo, consulte a [lista de opções](/docs/api/functions/aqarios-constrained-quantum-optimizer#options-list) na referência da API.\n",
        "\n",
        "Para obter mais informações, consulte o [guia](/docs/guides/aqarios-constrained-quantum-optimizer) e [a referência da API do 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",
        "## Etapa 3: Executar usando o comando `Qiskit primitives`\n",
        "\n",
        "Agora, o arquivo LP pode ser enviado ao otimizador:\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": [
        "Internamente, o algoritmo passa pelas seguintes etapas:\n",
        "\n",
        "1. **Pré-processamento** :\n",
        "   * Reduzir variáveis que podem ser fixadas\n",
        "   * Encontre grupos\n",
        "   * Identificar tipos de restrições\n",
        "   * Avaliar os fatores de penalidade para os termos de penalidade\n",
        "   * Aplicar transformações de restrição\n",
        "   * Sintetizar circuitos com métodos de imposição de restrições\n",
        "   * Aproximação do problema e transpilagem\n",
        "2. **Cadeias paralelas de loops iterativos** :\n",
        "   * Amostra de circuito com parâmetros fixos\n",
        "   * Aplicar pós-processamento\n",
        "   * Avaliar e definir novas probabilidades de partida a quente\n",
        "3. **Pós-processamento** :\n",
        "   * Encontre as melhores amostras e verifique a viabilidade em relação ao problema de entrada\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "25fa45d3",
      "metadata": {},
      "source": [
        "<span id=\"monitor-the-progress\" />\n",
        "\n",
        "### Acompanhar o andamento\n",
        "\n",
        "Consulte as seções a seguir na página “Introdução ao Qiskit Functions ” para acompanhar o andamento do seu trabalho:\n",
        "\n",
        "* [Verificar o status do trabalho](/docs/guides/functions-get-started#check-job-status)\n",
        "* [Recuperar 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",
        "## Etapa 4: Realizar o pós-processamento e apresentar os resultados no formato clássico desejado\n",
        "\n",
        "O resultado retornado é um dicionário, cujos campos estão descritos na [seção “Saídas”](/docs/api/functions/aqarios-constrained-quantum-optimizer#outputs) da referência da API.\n",
        "\n",
        "Quando a lista [`solutions`](/docs/api/functions/aqarios-constrained-quantum-optimizer#output-structure) contém mais de um item, foram encontrados vários ótimos degenerados. Aqui, considera-se apenas a primeira solução:\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",
        "### Visualização\n",
        "\n",
        "O conjunto independente identificado pode ser visualizado destacando-se os nós selecionados no 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: Formulação do problema com o Modelo Luna\n",
        "\n",
        "Além da `qiskit-addon-opt-mapper` abordagem apresentada acima, a função do Qiskit também aceita modelos criados com o Luna Model [\\[4\\]](#references), o SDK de modelagem da Aqarios.\n",
        "Após a instalação do `luna-model` pacote PyPI, importe-o da seguinte forma:\n",
        "\n",
        "**Configuração:**\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": [
        "O modelo é então construído a partir do gráfico da mesma forma que em `qiskit-addon-opt-mapper`:\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "fbf74687",
      "metadata": {},
      "source": [
        "**Construa o 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",
        "## Próximos passos\n",
        "\n",
        "<Admonition type=\"tip\" title=\"Recomendações\">\n",
        "  * Consulte o [guia do](/docs/guides/aqarios-constrained-quantum-optimizer) Aqarios Constrained Quantum Optimizer para obter um passo a passo detalhado de todos os recursos da função.\n",
        "  * Consulte a [referência da](/docs/api/functions/aqarios-constrained-quantum-optimizer) API para obter a lista completa de parâmetros de entrada e campos de saída.\n",
        "  * Experimente as opções do algoritmo (`reps`, `num_parallel`, `shots`, `postprocessing`) em seu próprio problema de otimização binária com restrições para avaliar o impacto delas na qualidade da solução e no tempo de execução.\n",
        "</Admonition>\n",
        "\n",
        "<span id=\"references\" />\n",
        "\n",
        "## Referências\n",
        "\n",
        "1. IBM Quantum, [*Guia do Otimizador Quântico Restrito do 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), \\*Otimização quântica com restrições por meio de misturadores XY iterativos com inicialização a quente \\*[10.1088/1367-2630/ae8ea2](https://doi.org/10.1088/1367-2630/ae8ea2)\n",
        "4. [*Documentação do modelo Luna da*](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
}