{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "b6d1e3ec",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Optimización binaria de alto nivel con el solucionador de optimización de Q-CTRL\"\n",
        "description: \"Resuelve un problema de optimización cuántica a escala industrial utilizando el solucionador de optimización, una función Qiskit de Q-CTRL Fire Opal\"\n",
        "---\n",
        "\n",
        "{/* cspell:ignore nrows ncols lambdify ILOG histtype stepfilled */}\n",
        "\n",
        "<span id=\"higher-order-binary-optimization-with-q-ctrls-optimization-solver\" />\n",
        "\n",
        "# Optimización binaria de alto nivel con el solucionador de optimización de Q-CTRL\n",
        "\n"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "a6f69b77",
      "metadata": {},
      "source": [
        "<Admonition type=\"note\" title=\"Nota\">\n",
        "  Las funciones Qiskit 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 IBM Quantum Platform API). Se trata de versiones preliminares sujetas a cambios.\n",
        "</Admonition>\n",
        "\n",
        "*Estimación de uso: 24 minutos en un procesador Heron r2. (NOTA: Esto es sólo una estimación. Su tiempo de ejecución puede variar)*\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8bf80006",
      "metadata": {},
      "source": [
        "<span id=\"background\" />\n",
        "\n",
        "## En segundo plano\n",
        "\n",
        "Este tutorial muestra cómo resolver un problema de optimización binaria de orden superior (HOBO) utilizando el [Optimization Solver, una función Qiskit de Q-CTRL Fire Opal](/docs/guides/q-ctrl-optimization-solver). El ejemplo que se muestra en este tutorial es un problema de optimización diseñado para encontrar la energía del estado base de un modelo Ising de 156 qubits de enlace aleatorio que posee términos cúbicos. El Optimization Solver puede utilizarse para problemas generales de optimización que pueden definirse como una función objetivo.\n",
        "\n",
        "La optimización automatiza completamente los pasos de implementación conscientes del hardware para resolver problemas de optimización en hardware cuántico y, al aprovechar [la gestión del rendimiento](/docs/guides/q-ctrl-performance-management) para la ejecución cuántica, consigue soluciones precisas a escala de utilidad. Para obtener un resumen detallado del flujo de trabajo completo del Optimization Solver y los resultados de la evaluación comparativa, consulte [el manuscrito publicado](https://arxiv.org/abs/2406.01743).\n",
        "\n",
        "Este tutorial explica los siguientes pasos:\n",
        "\n",
        "1. Definir el problema como una función objetivo\n",
        "2. Ejecute el algoritmo híbrido con el solucionador de optimización Fire Opal\n",
        "3. Evaluar los resultados\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "55b94021",
      "metadata": {},
      "source": [
        "<span id=\"requirements\" />\n",
        "\n",
        "## Requisitos\n",
        "\n",
        "Antes de empezar este tutorial, asegúrate de que tienes instalado lo siguiente:\n",
        "\n",
        "* Funciones Qiskit (`pip install qiskit-ibm-catalog`)\n",
        "* SymPy (`pip install sympy`)\n",
        "\n",
        "También necesitará acceder a la función Optimization Solver. Rellene [el formulario](/functions?id=q-ctrl-optimization-solver) para solicitar acceso.\n",
        "\n"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "7db2e559",
      "metadata": {},
      "source": [
        "<span id=\"setup\" />\n",
        "\n",
        "## Configuración\n",
        "\n",
        "En primer lugar, importa los paquetes y herramientas necesarios.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "c262cb27",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Qiskit Functions Catalog\n",
        "from qiskit_ibm_catalog import QiskitFunctionsCatalog\n",
        "\n",
        "# SymPy tools for constructing objective function\n",
        "from sympy import Poly\n",
        "from sympy import symbols, srepr\n",
        "\n",
        "# Tools for plotting and evaluating results\n",
        "import numpy as np\n",
        "import matplotlib.pyplot as plt\n",
        "from sympy import lambdify"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "df157bba",
      "metadata": {},
      "source": [
        "Defina sus credenciales de [IBM Quantum Platform](/), que se utilizarán a lo largo del tutorial para autenticarse en Qiskit Runtime y Qiskit Functions.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "b92bd67d",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Credentials\n",
        "\n",
        "# For `token`, use the 44-character API_KEY you created\n",
        "# and saved from the IBM Quantum Platform Home dashboard\n",
        "token = \"<YOUR-API_KEY>\"\n",
        "instance = \"<YOUR_CRN>\""
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "988ee237",
      "metadata": {},
      "source": [
        "<span id=\"step-1-define-the-problem-as-an-objective-function\" />\n",
        "\n",
        "## Paso 1: Definir el problema como una función objetivo\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6c9bffae",
      "metadata": {},
      "source": [
        "El solucionador de optimización acepta como entrada una función objetivo o un gráfico. En este tutorial, el problema de minimización del cristal de espín de Ising se define como una función objetivo, y se ha adaptado para la topología heavy-hex de los dispositivos IBM®.\n",
        "\n",
        "Como esta función objetivo contiene términos cúbicos, cuadráticos y lineales, pertenece a la clase de problemas HOBO, conocidos por ser considerablemente más complicados de resolver que los problemas convencionales de optimización binaria cuadrática sin restricciones (QUBO).\n",
        "\n",
        "Para un análisis detallado de la construcción de la definición del problema y de los resultados anteriores obtenidos con el Optimization Solver, consulte [este manuscrito técnico](https://arxiv.org/abs/2406.01743). El problema se definió y evaluó originalmente como parte de un [artículo publicado por el Laboratorio Nacional de Los Álamos](https://arxiv.org/abs/2312.00997), y se ha adaptado para aprovechar todo el ancho de dispositivo de los procesadores IBM Quantum Heron de 156 qubits.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 42,
      "id": "0ad66539",
      "metadata": {},
      "outputs": [],
      "source": [
        "qubit_count = 156\n",
        "\n",
        "# Create symbolic variables to represent qubits\n",
        "x = symbols([f\"x[{i}]\" for i in range(qubit_count)])\n",
        "\n",
        "# # Define a polynomial representing a spin glass model\n",
        "spin_glass_poly = Poly(\n",
        "    -4 * x[0] * x[1]\n",
        "    - 8 * x[1] * x[2] * x[3]\n",
        "    + 8 * x[1] * x[2]\n",
        "    + 4 * x[1] * x[3]\n",
        "    - 4 * x[2]\n",
        "    + 8 * x[3] * x[4] * x[5]\n",
        "    - 4 * x[3] * x[5]\n",
        "    - 8 * x[3] * x[16] * x[23]\n",
        "    + 4 * x[3] * x[23]\n",
        "    - 2 * x[3]\n",
        "    - 4 * x[4]\n",
        "    - 8 * x[5] * x[6] * x[7]\n",
        "    + 8 * x[5] * x[6]\n",
        "    + 4 * x[5] * x[7]\n",
        "    - 2 * x[5]\n",
        "    + 8 * x[6] * x[7]\n",
        "    - 4 * x[6]\n",
        "    - 8 * x[7] * x[8] * x[9]\n",
        "    + 4 * x[7] * x[9]\n",
        "    - 8 * x[7] * x[17] * x[27]\n",
        "    + 4 * x[7] * x[27]\n",
        "    - 6 * x[7]\n",
        "    + 8 * x[8] * x[9]\n",
        "    + 8 * x[9] * x[10] * x[11]\n",
        "    - 4 * x[9] * x[11]\n",
        "    - 2 * x[9]\n",
        "    - 8 * x[10] * x[11]\n",
        "    + 4 * x[10]\n",
        "    - 8 * x[11] * x[12] * x[13]\n",
        "    + 4 * x[11] * x[13]\n",
        "    - 8 * x[11] * x[18] * x[31]\n",
        "    + 8 * x[11] * x[18]\n",
        "    + 4 * x[11] * x[31]\n",
        "    - 2 * x[11]\n",
        "    + 8 * x[12] * x[13]\n",
        "    + 8 * x[13] * x[14] * x[15]\n",
        "    - 4 * x[13] * x[15]\n",
        "    - 2 * x[13]\n",
        "    - 8 * x[14] * x[15]\n",
        "    + 4 * x[14]\n",
        "    - 8 * x[15] * x[19] * x[35]\n",
        "    + 8 * x[15] * x[19]\n",
        "    + 4 * x[15] * x[35]\n",
        "    - 2 * x[15]\n",
        "    + 8 * x[16] * x[23]\n",
        "    + 8 * x[17] * x[27]\n",
        "    - 4 * x[17]\n",
        "    + 8 * x[18] * x[31]\n",
        "    - 8 * x[18]\n",
        "    + 8 * x[19] * x[35]\n",
        "    - 8 * x[19]\n",
        "    + 4 * x[20] * x[21]\n",
        "    - 4 * x[20]\n",
        "    - 8 * x[21] * x[22] * x[23]\n",
        "    + 8 * x[21] * x[22]\n",
        "    + 4 * x[21] * x[23]\n",
        "    - 8 * x[21] * x[36] * x[41]\n",
        "    + 4 * x[21] * x[41]\n",
        "    - 4 * x[21]\n",
        "    + 8 * x[22] * x[23]\n",
        "    - 8 * x[22]\n",
        "    + 8 * x[23] * x[24] * x[25]\n",
        "    - 4 * x[23] * x[25]\n",
        "    - 10 * x[23]\n",
        "    - 8 * x[24] * x[25]\n",
        "    + 8 * x[25] * x[26] * x[27]\n",
        "    - 8 * x[25] * x[26]\n",
        "    - 4 * x[25] * x[27]\n",
        "    + 8 * x[25] * x[37] * x[45]\n",
        "    - 8 * x[25] * x[37]\n",
        "    - 4 * x[25] * x[45]\n",
        "    + 14 * x[25]\n",
        "    - 8 * x[26] * x[27]\n",
        "    + 4 * x[26]\n",
        "    + 8 * x[27] * x[28] * x[29]\n",
        "    - 4 * x[27] * x[29]\n",
        "    - 2 * x[27]\n",
        "    - 8 * x[28] * x[29]\n",
        "    - 8 * x[29] * x[30] * x[31]\n",
        "    + 4 * x[29] * x[31]\n",
        "    + 8 * x[29] * x[38] * x[49]\n",
        "    - 8 * x[29] * x[38]\n",
        "    - 4 * x[29] * x[49]\n",
        "    + 6 * x[29]\n",
        "    + 8 * x[30] * x[31]\n",
        "    - 4 * x[30]\n",
        "    - 8 * x[31] * x[32] * x[33]\n",
        "    + 4 * x[31] * x[33]\n",
        "    - 6 * x[31]\n",
        "    + 8 * x[33] * x[34] * x[35]\n",
        "    - 4 * x[33] * x[35]\n",
        "    - 8 * x[33] * x[39] * x[53]\n",
        "    + 8 * x[33] * x[39]\n",
        "    + 4 * x[33] * x[53]\n",
        "    - 6 * x[33]\n",
        "    - 8 * x[34] * x[35]\n",
        "    + 2 * x[35]\n",
        "    + 8 * x[36] * x[41]\n",
        "    - 8 * x[37] * x[45]\n",
        "    + 4 * x[37]\n",
        "    - 8 * x[38] * x[49]\n",
        "    + 4 * x[38]\n",
        "    + 4 * x[40] * x[41]\n",
        "    - 8 * x[41] * x[42] * x[43]\n",
        "    + 4 * x[41] * x[43]\n",
        "    - 8 * x[41]\n",
        "    + 8 * x[42] * x[43]\n",
        "    - 4 * x[42]\n",
        "    - 8 * x[43] * x[44] * x[45]\n",
        "    + 8 * x[43] * x[44]\n",
        "    + 4 * x[43] * x[45]\n",
        "    - 8 * x[43] * x[56] * x[63]\n",
        "    + 4 * x[43] * x[63]\n",
        "    - 6 * x[43]\n",
        "    - 4 * x[44]\n",
        "    - 8 * x[45] * x[46] * x[47]\n",
        "    + 4 * x[45] * x[47]\n",
        "    + 2 * x[45]\n",
        "    + 4 * x[46]\n",
        "    - 8 * x[47] * x[48] * x[49]\n",
        "    + 8 * x[47] * x[48]\n",
        "    + 4 * x[47] * x[49]\n",
        "    - 8 * x[47] * x[57] * x[67]\n",
        "    + 4 * x[47] * x[67]\n",
        "    - 2 * x[47]\n",
        "    - 4 * x[48]\n",
        "    - 8 * x[49] * x[50] * x[51]\n",
        "    + 8 * x[49] * x[50]\n",
        "    + 4 * x[49] * x[51]\n",
        "    - 2 * x[49]\n",
        "    + 8 * x[50] * x[51]\n",
        "    - 8 * x[50]\n",
        "    - 8 * x[51] * x[52] * x[53]\n",
        "    + 8 * x[51] * x[52]\n",
        "    + 4 * x[51] * x[53]\n",
        "    - 8 * x[51] * x[58] * x[71]\n",
        "    + 4 * x[51] * x[71]\n",
        "    - 6 * x[51]\n",
        "    + 8 * x[52] * x[53]\n",
        "    - 8 * x[52]\n",
        "    + 8 * x[53] * x[54] * x[55]\n",
        "    - 8 * x[53] * x[54]\n",
        "    - 4 * x[53] * x[55]\n",
        "    - 2 * x[53]\n",
        "    + 4 * x[54]\n",
        "    - 8 * x[55] * x[59] * x[75]\n",
        "    + 4 * x[55] * x[75]\n",
        "    - 2 * x[55]\n",
        "    + 8 * x[56] * x[63]\n",
        "    + 8 * x[57] * x[67]\n",
        "    - 4 * x[57]\n",
        "    + 8 * x[58] * x[71]\n",
        "    + 8 * x[59] * x[75]\n",
        "    - 4 * x[59]\n",
        "    + 4 * x[60] * x[61]\n",
        "    + 8 * x[61] * x[62] * x[63]\n",
        "    - 4 * x[61] * x[63]\n",
        "    + 8 * x[61] * x[76] * x[81]\n",
        "    - 8 * x[61] * x[76]\n",
        "    - 4 * x[61] * x[81]\n",
        "    - 8 * x[63] * x[64] * x[65]\n",
        "    + 8 * x[63] * x[64]\n",
        "    + 4 * x[63] * x[65]\n",
        "    - 6 * x[63]\n",
        "    + 8 * x[65] * x[66] * x[67]\n",
        "    - 8 * x[65] * x[66]\n",
        "    - 4 * x[65] * x[67]\n",
        "    - 8 * x[65] * x[77] * x[85]\n",
        "    + 4 * x[65] * x[85]\n",
        "    + 2 * x[65]\n",
        "    + 4 * x[66]\n",
        "    - 8 * x[67] * x[68] * x[69]\n",
        "    + 8 * x[67] * x[68]\n",
        "    + 4 * x[67] * x[69]\n",
        "    - 10 * x[67]\n",
        "    + 8 * x[68] * x[69]\n",
        "    - 4 * x[68]\n",
        "    + 8 * x[69] * x[70] * x[71]\n",
        "    - 4 * x[69] * x[71]\n",
        "    - 8 * x[69] * x[78] * x[89]\n",
        "    + 4 * x[69] * x[89]\n",
        "    - 6 * x[69]\n",
        "    + 8 * x[71] * x[72] * x[73]\n",
        "    - 8 * x[71] * x[72]\n",
        "    - 4 * x[71] * x[73]\n",
        "    + 2 * x[71]\n",
        "    - 8 * x[72] * x[73]\n",
        "    + 8 * x[72]\n",
        "    - 8 * x[73] * x[74] * x[75]\n",
        "    + 8 * x[73] * x[74]\n",
        "    + 4 * x[73] * x[75]\n",
        "    - 8 * x[73] * x[79] * x[93]\n",
        "    + 8 * x[73] * x[79]\n",
        "    + 4 * x[73] * x[93]\n",
        "    - 6 * x[73]\n",
        "    + 8 * x[74] * x[75]\n",
        "    - 4 * x[74]\n",
        "    - 10 * x[75]\n",
        "    + 4 * x[76]\n",
        "    + 8 * x[78] * x[89]\n",
        "    - 4 * x[78]\n",
        "    - 4 * x[79]\n",
        "    - 4 * x[80] * x[81]\n",
        "    + 4 * x[80]\n",
        "    - 8 * x[81] * x[82] * x[83]\n",
        "    + 8 * x[81] * x[82]\n",
        "    + 4 * x[81] * x[83]\n",
        "    + 8 * x[82] * x[83]\n",
        "    - 8 * x[82]\n",
        "    - 8 * x[83] * x[84] * x[85]\n",
        "    + 4 * x[83] * x[85]\n",
        "    - 8 * x[83] * x[96] * x[103]\n",
        "    + 4 * x[83] * x[103]\n",
        "    - 2 * x[83]\n",
        "    - 8 * x[85] * x[86] * x[87]\n",
        "    + 8 * x[85] * x[86]\n",
        "    + 4 * x[85] * x[87]\n",
        "    - 6 * x[85]\n",
        "    + 8 * x[86] * x[87]\n",
        "    - 4 * x[86]\n",
        "    - 8 * x[87] * x[88] * x[89]\n",
        "    + 4 * x[87] * x[89]\n",
        "    + 8 * x[87] * x[97] * x[107]\n",
        "    - 8 * x[87] * x[97]\n",
        "    - 4 * x[87] * x[107]\n",
        "    + 2 * x[87]\n",
        "    + 4 * x[88]\n",
        "    - 8 * x[89] * x[90] * x[91]\n",
        "    + 8 * x[89] * x[90]\n",
        "    + 4 * x[89] * x[91]\n",
        "    - 10 * x[89]\n",
        "    + 8 * x[90] * x[91]\n",
        "    - 8 * x[90]\n",
        "    - 8 * x[91] * x[92] * x[93]\n",
        "    + 4 * x[91] * x[93]\n",
        "    - 8 * x[91] * x[98] * x[111]\n",
        "    + 8 * x[91] * x[98]\n",
        "    + 4 * x[91] * x[111]\n",
        "    - 10 * x[91]\n",
        "    + 8 * x[92] * x[93]\n",
        "    - 4 * x[92]\n",
        "    - 8 * x[93] * x[94] * x[95]\n",
        "    + 4 * x[93] * x[95]\n",
        "    - 6 * x[93]\n",
        "    + 8 * x[95] * x[99] * x[115]\n",
        "    - 8 * x[95] * x[99]\n",
        "    - 4 * x[95] * x[115]\n",
        "    + 2 * x[95]\n",
        "    + 4 * x[96]\n",
        "    - 8 * x[97] * x[107]\n",
        "    + 4 * x[97]\n",
        "    - 4 * x[98]\n",
        "    - 8 * x[99] * x[115]\n",
        "    + 4 * x[99]\n",
        "    - 4 * x[100] * x[101]\n",
        "    + 8 * x[101] * x[102] * x[103]\n",
        "    - 8 * x[101] * x[102]\n",
        "    - 4 * x[101] * x[103]\n",
        "    - 8 * x[101] * x[116] * x[121]\n",
        "    + 8 * x[101] * x[116]\n",
        "    + 4 * x[101] * x[121]\n",
        "    + 4 * x[101]\n",
        "    - 8 * x[103] * x[104] * x[105]\n",
        "    + 4 * x[103] * x[105]\n",
        "    + 2 * x[103]\n",
        "    + 8 * x[105] * x[106] * x[107]\n",
        "    - 4 * x[105] * x[107]\n",
        "    - 8 * x[105] * x[117] * x[125]\n",
        "    + 4 * x[105] * x[125]\n",
        "    + 2 * x[105]\n",
        "    - 8 * x[106] * x[107]\n",
        "    + 4 * x[106]\n",
        "    + 8 * x[107] * x[108] * x[109]\n",
        "    - 4 * x[107] * x[109]\n",
        "    + 6 * x[107]\n",
        "    - 4 * x[108]\n",
        "    + 8 * x[109] * x[110] * x[111]\n",
        "    - 4 * x[109] * x[111]\n",
        "    - 8 * x[109] * x[118] * x[129]\n",
        "    + 4 * x[109] * x[129]\n",
        "    + 2 * x[109]\n",
        "    - 8 * x[110] * x[111]\n",
        "    + 4 * x[110]\n",
        "    - 8 * x[111] * x[112] * x[113]\n",
        "    + 8 * x[111] * x[112]\n",
        "    + 4 * x[111] * x[113]\n",
        "    + 2 * x[111]\n",
        "    + 8 * x[112] * x[113]\n",
        "    - 8 * x[112]\n",
        "    - 8 * x[113] * x[114] * x[115]\n",
        "    + 4 * x[113] * x[115]\n",
        "    - 8 * x[113] * x[119] * x[133]\n",
        "    + 4 * x[113] * x[133]\n",
        "    - 2 * x[113]\n",
        "    + 6 * x[115]\n",
        "    - 4 * x[116]\n",
        "    + 4 * x[118]\n",
        "    + 4 * x[119]\n",
        "    + 4 * x[120] * x[121]\n",
        "    - 8 * x[121] * x[122] * x[123]\n",
        "    + 4 * x[121] * x[123]\n",
        "    - 4 * x[121]\n",
        "    + 4 * x[122]\n",
        "    - 8 * x[123] * x[124] * x[125]\n",
        "    + 4 * x[123] * x[125]\n",
        "    - 8 * x[123] * x[136] * x[143]\n",
        "    + 4 * x[123] * x[143]\n",
        "    - 2 * x[123]\n",
        "    + 8 * x[124] * x[125]\n",
        "    - 4 * x[124]\n",
        "    + 8 * x[125] * x[126] * x[127]\n",
        "    - 8 * x[125] * x[126]\n",
        "    - 4 * x[125] * x[127]\n",
        "    + 2 * x[125]\n",
        "    - 8 * x[127] * x[128] * x[129]\n",
        "    + 8 * x[127] * x[128]\n",
        "    + 4 * x[127] * x[129]\n",
        "    + 8 * x[127] * x[137] * x[147]\n",
        "    - 8 * x[127] * x[137]\n",
        "    - 4 * x[127] * x[147]\n",
        "    - 2 * x[127]\n",
        "    + 8 * x[129] * x[130] * x[131]\n",
        "    - 4 * x[129] * x[131]\n",
        "    + 2 * x[129]\n",
        "    - 4 * x[130]\n",
        "    - 8 * x[131] * x[132] * x[133]\n",
        "    + 4 * x[131] * x[133]\n",
        "    - 8 * x[131] * x[138] * x[151]\n",
        "    + 4 * x[131] * x[151]\n",
        "    - 2 * x[131]\n",
        "    + 8 * x[133] * x[134] * x[135]\n",
        "    - 4 * x[133] * x[135]\n",
        "    + 2 * x[133]\n",
        "    - 8 * x[134] * x[135]\n",
        "    + 4 * x[134]\n",
        "    - 8 * x[135] * x[139] * x[155]\n",
        "    + 8 * x[135] * x[139]\n",
        "    + 4 * x[135] * x[155]\n",
        "    + 2 * x[135]\n",
        "    + 8 * x[136] * x[143]\n",
        "    - 4 * x[136]\n",
        "    + 4 * x[138]\n",
        "    + 8 * x[139] * x[155]\n",
        "    - 4 * x[139]\n",
        "    - 4 * x[140] * x[141]\n",
        "    - 8 * x[141] * x[142] * x[143]\n",
        "    + 8 * x[141] * x[142]\n",
        "    + 4 * x[141] * x[143]\n",
        "    + 8 * x[142] * x[143]\n",
        "    - 8 * x[142]\n",
        "    - 8 * x[143] * x[144] * x[145]\n",
        "    + 8 * x[143] * x[144]\n",
        "    + 4 * x[143] * x[145]\n",
        "    - 14 * x[143]\n",
        "    + 8 * x[144] * x[145]\n",
        "    - 8 * x[144]\n",
        "    - 8 * x[145] * x[146] * x[147]\n",
        "    + 8 * x[145] * x[146]\n",
        "    + 4 * x[145] * x[147]\n",
        "    - 6 * x[145]\n",
        "    + 8 * x[146] * x[147]\n",
        "    - 4 * x[146]\n",
        "    - 8 * x[147] * x[148] * x[149]\n",
        "    + 8 * x[147] * x[148]\n",
        "    + 4 * x[147] * x[149]\n",
        "    - 6 * x[147]\n",
        "    - 4 * x[148]\n",
        "    - 8 * x[149] * x[150] * x[151]\n",
        "    + 8 * x[149] * x[150]\n",
        "    + 4 * x[149] * x[151]\n",
        "    - 6 * x[149]\n",
        "    + 8 * x[151] * x[152] * x[153]\n",
        "    - 4 * x[151] * x[153]\n",
        "    + 2 * x[151]\n",
        "    + 8 * x[153] * x[154] * x[155]\n",
        "    - 8 * x[153] * x[154]\n",
        "    - 4 * x[153] * x[155]\n",
        "    + 2 * x[153]\n",
        "    - 8 * x[154] * x[155]\n",
        "    + 4 * x[154]\n",
        "    - 2 * x[155]\n",
        "    + 46,\n",
        "    x,\n",
        "    domain=\"ZZ\",\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ac6f36e3",
      "metadata": {},
      "source": [
        "<span id=\"step-2-run-the-hybrid-algorithm-using-the-fire-opal-optimization-solver\" />\n",
        "\n",
        "## Paso 2: Ejecute el algoritmo híbrido utilizando el solucionador de optimización Fire Opal\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "13ba6d0c",
      "metadata": {},
      "source": [
        "Ahora utilice el Optimization Solver Qiskit Function para ejecutar el algoritmo. Entre bastidores, el solucionador de optimización se encarga de asignar el problema a un algoritmo cuántico híbrido, ejecutar los circuitos cuánticos con supresión de errores y realizar la optimización clásica.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "bd38bb1e",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Authenticate to the Qiskit Functions Catalog\n",
        "catalog = QiskitFunctionsCatalog(\n",
        "    token=token,\n",
        "    instance=instance,\n",
        ")\n",
        "\n",
        "# Load the function\n",
        "solver = catalog.load(\"q-ctrl/optimization_solver\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "12cfe6f5",
      "metadata": {},
      "source": [
        "Comprueba que el dispositivo elegido tiene al menos 156 qubits.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "a27adab7",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Specify the target backend name\n",
        "backend_name = \"<CHOOSE_A_BACKEND>\""
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ffbe9f79",
      "metadata": {},
      "source": [
        "El Solver acepta una representación de cadena de la función objetivo.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 43,
      "id": "1834cb22",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Convert the objective function to string format\n",
        "spin_glass_poly_as_str = srepr(spin_glass_poly)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "98213fe9",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Run the problem\n",
        "spin_glass_job = solver.run(\n",
        "    problem=spin_glass_poly_as_str,\n",
        "    run_options={\"backend_name\": backend_name},\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d25caa83",
      "metadata": {},
      "source": [
        "Puede utilizar las conocidas [API sin servidor de Qiskit](/docs/guides/serverless) para comprobar el estado de la carga de trabajo de Qiskit Function:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "77a8ded0",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Get job status\n",
        "spin_glass_job.status()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7cd96271",
      "metadata": {},
      "source": [
        "El solucionador devuelve un diccionario con la solución y los metadatos asociados, como la cadena de bits de la solución, el número de iteraciones y la asignación de variables a la cadena de bits. Para una definición completa de las entradas y salidas del Solver, consulte la [documentación]().\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "bd8bd878",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Poll for results\n",
        "result = spin_glass_job.result()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 54,
      "id": "2bddbcbc",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Get the final bitstring distribution and set the number of shots\n",
        "distribution = result[\"final_bitstring_distribution\"]"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "50b94af2",
      "metadata": {},
      "source": [
        "<span id=\"step-3-evaluate-results\" />\n",
        "\n",
        "## Paso 3: Evaluar los resultados\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 31,
      "id": "f6f6e93a",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Minimum ground state energy: -242.0\n"
          ]
        }
      ],
      "source": [
        "# Get the solution ground state energy\n",
        "print(f\"Minimum ground state energy: {result[\"solution_bitstring_cost\"]}\")"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "733431ad",
      "metadata": {},
      "source": [
        "El Solver encontró la solución correcta, que fue validada mediante un software de optimización clásico. La complejidad de este problema a gran escala requiere un software de optimización avanzado para su resolución clásica, como [IBM ILOG CPLEX Optimization Studio (CPLEX)](https://www.ibm.com/products/ilog-cplex-optimization-studio) o [Gurobi Optimization](https://www.gurobi.com/).\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "40406a33",
      "metadata": {},
      "source": [
        "Como análisis visual de la calidad de los resultados, puede trazar los resultados calculando los valores de coste a partir de las cadenas de bits y sus probabilidades. Para comparar, trace los resultados junto a una distribución de cadenas de bits muestreadas aleatoriamente, lo que equivale a una solución clásica de \"fuerza bruta\". Si el algoritmo encuentra sistemáticamente costes más bajos, sugiere que el algoritmo cuántico está resolviendo eficazmente el problema de optimización.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "a481c257",
      "metadata": {},
      "outputs": [],
      "source": [
        "def plot_cost_histogram(\n",
        "    costs, probabilities, distribution, qubit_count, bitstring_cost\n",
        "):\n",
        "    \"\"\"Plots a histogram comparing the cost distributions of\n",
        "    Q-CTRL Solver and random sampling.\"\"\"\n",
        "\n",
        "    # Set figure DPI for higher resolution and font size for labels\n",
        "    plt.rcParams[\"figure.dpi\"] = 300\n",
        "    plt.rcParams.update({\"font.size\": 6})  # Set default font size to 6\n",
        "\n",
        "    # Define labels and colors for the plot\n",
        "    labels = [\"Q-CTRL Solver\", \"Random Sampling\"]\n",
        "    colors = [\"#680CE9\", \"#E04542\"]\n",
        "\n",
        "    # Calculate total shots (total number of bitstrings in the distribution)\n",
        "    shots = sum(distribution.values())\n",
        "\n",
        "    # Generate random bitstrings for comparison (random sampling)\n",
        "    rng = np.random.default_rng(seed=0)\n",
        "    random_array = rng.integers(\n",
        "        0, 2, size=(shots, qubit_count)\n",
        "    )  # Generate random bitstrings (0 or 1 for each qubit)\n",
        "    random_bitstrings = [\"\".join(row.astype(str)) for row in random_array]\n",
        "\n",
        "    # Compute the cost for each random bitstring\n",
        "    random_costs = [bitstring_cost(k) for k in random_bitstrings]\n",
        "\n",
        "    # Set uniform probabilities for the random sampling\n",
        "    random_probabilities = (\n",
        "        np.ones(shape=(shots,)) / shots\n",
        "    )  # Equal probability for each random bitstring\n",
        "\n",
        "    # Find the minimum and maximum costs for binning the histogram\n",
        "    min_cost = np.min(costs)\n",
        "    max_cost = np.max(random_costs)\n",
        "\n",
        "    # Create a histogram plot with a smaller figure size (4x2 inches)\n",
        "    fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(4, 2))\n",
        "\n",
        "    # Plot histograms for the Q-CTRL solver and random sampling costs\n",
        "    _, _, _ = ax.hist(\n",
        "        [costs, random_costs],  # Data for the two histograms\n",
        "        np.arange(min_cost, max_cost, 2),  # Bins for the histogram\n",
        "        weights=[\n",
        "            probabilities,\n",
        "            random_probabilities,\n",
        "        ],  # Probabilities for each data set\n",
        "        label=labels,  # Labels for the legend\n",
        "        color=colors,  # Colors for each histogram\n",
        "        histtype=\"stepfilled\",  # Filled step histogram\n",
        "        align=\"mid\",  # Align bars to the bin center\n",
        "        alpha=0.8,  # Transparency\n",
        "    )\n",
        "\n",
        "    # Set the x and y labels for the plot\n",
        "    ax.set_xlabel(\"Cost\")\n",
        "    ax.set_ylabel(\"Probability\")\n",
        "\n",
        "    # Add the legend to the plot\n",
        "    ax.legend()\n",
        "\n",
        "    # Show the plot\n",
        "    plt.show()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 59,
      "id": "a2fe3966",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/solve-higher-order-binary-optimization-problems-with-q-ctrls-optimization-solver/extracted-outputs/a2fe3966-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "# Convert spin_glass_poly into a NumPy-compatible function\n",
        "poly_as_numpy_function = lambdify(x, spin_glass_poly.as_expr(), \"numpy\")\n",
        "\n",
        "\n",
        "# Function to compute the cost of a given bitstring using spin_glass_poly\n",
        "def bitstring_cost(bitstring: str) -> float:\n",
        "    # Convert bitstring to a reversed list of integers (0s and 1s)\n",
        "    return float(\n",
        "        poly_as_numpy_function(*[int(b) for b in str(bitstring[::-1])])\n",
        "    )\n",
        "\n",
        "\n",
        "# Calculate the cost of each bitstring in the distribution\n",
        "costs = [bitstring_cost(k) for k, _ in distribution.items()]\n",
        "\n",
        "# Extract probabilities from the bitstring distribution\n",
        "probabilities = np.array([v for _, v in distribution.items()])\n",
        "probabilities = probabilities / sum(\n",
        "    probabilities\n",
        ")  # Normalize to get probabilities\n",
        "\n",
        "plot_cost_histogram(\n",
        "    costs, probabilities, distribution, qubit_count, bitstring_cost\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "15e35cff",
      "metadata": {},
      "source": [
        "Dado que el objetivo de este algoritmo de optimización es encontrar el estado fundamental mínimo del modelo de Ising, los valores más bajos indican mejores soluciones. Por tanto, es evidente que las soluciones generadas por el solucionador de optimización Fire Opal superan con creces a la selección aleatoria.\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"
    },
    "hours": 1,
    "qpuSeconds": 1440
  },
  "nbformat": 4,
  "nbformat_minor": 5
}