{ "cells": [ { "cell_type": "markdown", "id": "fc40105a-11b7-49ed-9428-f2675643ac0b", "metadata": {}, "source": [ "(primeros_pasos)=\n", "# Introducción.\n", "\n", "En este apartado vamos a proceder a exponer diversos ejemplos fáciles de implementar, con la finalidad que el usuario se vaya familiarizando con las ideas que subyacen a este tipo de técnica de computación cuántica.\n", "\n", "En este apartado vamoa a aprender a construir modelos de tipo [QUBO](modelo_qubo) y de tipo [ISING](modelo_ising), así como su solución utilizando diferentes samplers.\n", "\n", "\n", "Recordemos que un **modelo de tipo ISING** va tratar las variables como binarias pero que pueden tomar los valores -1 y +1. Entonces utilizando este modelo la función objetivo se va a definir de la siguiente manera:\n", "\n", "$$\n", "E=-\\sum_{i}h_{i}S_{i}+\\sum_{i,j}J_{ij}S_{i}S_{j}\\qquad donde\\:S_{i}\\in\\{-1,+1\\}\n", "$$\n", "\n", "La variable se representa en este modelo por S ya que es la inicial de *Spin*.Los valores de h's y J's son constantes para ajustar por el modelo, una h para cada Spin y una J para cada interacción de los pares de Spines.\n", "\n", "El **modelo de tipo QUBO**, se describe de la siguiente manera:\n", "\n", "$$\n", "Obj(c,a_{i},b_{ij},q_{i})=c+\\sum_{i}a_{i}q_{i}+\\sum_{i Classical Solvers . Se puede utilizar un solucionador clásico mientras se desarrolla un código o en una versión pequeña de un problema para verificar el código.Con este tipo de Solvers, la solución se obtiene utilizando el equipo propio con el que trabaja el investigador.\n", "\n", "* Solvers Híbridos . Este tipo de solvers utiliza recursos clásicos y cuánticos para resolver los problemas.\n", "\n", "* Solvers cuánticos .Este sistema utiliza sólo medios cuánticos para resolver los problemas planteados.Este solver es denominado DWaveSampler que normalmente es utilizado junto a EmbeddingComposite .\n", "\n", "Vamos a comenzar en esta sección a crear con diversos métodos un modelo BQM o ISING y como se resuelve utiliozando diferentes solvers. Comenzamos con el solver más sencillo, el denominado ExactSolver del paquete dimod.\n", "\n", "```{index} BinaryQuadraticModel\n", "```\n", "Importaremos primero la clase *BinaryQuadraticModel()*. annslator" ] }, { "cell_type": "code", "execution_count": 1, "id": "61c37b29-c805-4f36-8f2d-2c86b70957b9", "metadata": {}, "outputs": [], "source": [ "from dimod import BinaryQuadraticModel" ] }, { "cell_type": "markdown", "id": "8f931c45-8494-44e2-b2fc-54a1ea74c21b", "metadata": {}, "source": [ "También se puede importar de la siguiente manera" ] }, { "cell_type": "code", "execution_count": 2, "id": "bed67f32-67e9-42b2-b521-c049357882fe", "metadata": {}, "outputs": [], "source": [ "from dimod import BQM" ] }, { "cell_type": "markdown", "id": "bc356bb9-68d9-4660-ab5a-a00790a50219", "metadata": {}, "source": [ "En principio hay que tener en cuenta que todos los samplers de Ocean heredan de la clase abstracta *Sampler* , para ver el contenido de esta clase, se pueden utilizar las siguientes instrucciones." ] }, { "cell_type": "code", "execution_count": 3, "id": "ee7e65b7-6660-403c-aff9-543de2e1d940", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\u001b[1;31mInit signature:\u001b[0m \u001b[0mSampler\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;31mDocstring:\u001b[0m \n", "Abstract base class for dimod samplers.\n", "\n", "Provides all methods :meth:`~.Sampler.sample`, :meth:`~.Sampler.sample_ising`,\n", ":meth:`~.Sampler.sample_qubo` assuming at least one is implemented.\n", "\n", "Also includes utility method :meth:`~.Sampler.remove_unknown_kwargs`,\n", "which may be used in sample methods to handle unknown kwargs.\n", "\u001b[1;31mFile:\u001b[0m c:\\users\\francisco\\desktop\\dwaveocean\\ocean\\lib\\site-packages\\dimod\\core\\sampler.py\n", "\u001b[1;31mType:\u001b[0m SamplerABCMeta\n", "\u001b[1;31mSubclasses:\u001b[0m ComposedSampler, StructureComposite, ExactSolver, IdentitySampler, NullSampler, RandomSampler, SimulatedAnnealingSampler" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from dimod import Sampler\n", "\n", "Sampler?" ] }, { "cell_type": "markdown", "id": "60b1ddc1-3a03-46b1-a935-4d72a6c8fc36", "metadata": {}, "source": [ "Diferentes Samplers que podemos utilizar los podemos ver en el siguiente cuadro:\n", "\n", "![Samplers Ocean](../img/samplers.PNG)\n", "\n", "Vamos a mostrar a continuación código para generar un problema de tipo ISING, que posteriormente resolveremos con diferentes solvers.\n", "\n", "Procedemos a continuación a crear el modelo ISING" ] }, { "cell_type": "code", "execution_count": 10, "id": "7489af8e-96c4-401f-bfcf-2fbc88d1dbe7", "metadata": {}, "outputs": [], "source": [ "from dimod import BinaryQuadraticModel, to_networkx_graph\n", "bqm = BinaryQuadraticModel('SPIN')\n", "bqm.add_variable(0, -1)\n", "bqm.add_variable(1, -1)\n", "bqm.add_variable(4, -1)\n", "bqm.add_variable(5, -1)\n", "# bqm.add_variable(6,-1) # lo añadí yo de prueba\n", "bqm.add_interaction(0, 4, 1.0)\n", "bqm.add_interaction(0, 5, 1.0)\n", "bqm.add_interaction(1, 4, 1.0)\n", "bqm.add_interaction(1, 5, 1.0)\n", "# bqm.add_interaction(0, 1, 1.0) # lo añadí so de prueba\n" ] }, { "cell_type": "markdown", "id": "4b37ca57-af09-46ab-ba9e-8d601337cd3c", "metadata": {}, "source": [ "El modelo anterior, representado con uan formulación matemática, sería el siguiente:\n", "\n", "$$-1\\cdot x_{0}-1\\cdot x_{1}-1\\cdot x_{4}-1\\cdot x_{5}+1\\cdot x_{0}\\cdot x_{4}+1\\cdot x_{0}\\cdot x_{5}+1\\cdot x_{1}\\cdot x_{4}+1\\cdot x_{1}\\cdot x_{4}$$\r\n", "Y además el modelo sería de tipo SPIN, es decir que las variables, sólo podrían tomar valores de 1 ó -1.\n", "\n", "```{index} to_networkx_graph\r\n", "```\n", "\n", "\n", "Un modelo BQM, se representa en los ordenadores de D_Wave mediante un grafo, dondelos nodos son los coeficientes lineales de la ecuación anterior, y los arcos soerían los coeficientes de los términos cuadráticos. Vamos a representar mediante un grafo el modelo crado anteriormenmte: " ] }, { "cell_type": "code", "execution_count": 11, "id": "66d29c78-16ca-48fe-a89a-f3a99de751b2", "metadata": {}, "outputs": [ { "data": { "image/png": "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hw8fVlhYmIYPH64vvvjCdBy/VlRUpFWrVsnhcGj69Ok6efKkWrZsKavVKovFottvv910RAAo9yiUQCmwWCxavnx58T198A75+flasmSJ7Ha7Zs6cqZycHN15552yWq0aOXKkGjdubDoiAJRLFErAwxYsWKABAwZo6tSpstlspuOgBLm5uZo3b54cDofmzZunvLw8devWTRaLRSNGjNCNN95oOiIAlBsUSsCDcnNzFRERodtvv12LFy/mPr1y4vTp05o1a5YcDocWL14sSerdu7esVquGDBmiWrVqmQ0IAF6OQgl40Msvv6z3339fKSkp3JtXTh0/flzTp0+Xw+HQd999pwoVKmjAgAGyWCwaNGiQqlSpYjoiAHgdCiXgITt27FBkZKTGjh2rUaNGmY4DD/j55581bdo0ORwObdiwQVWrVtXgwYNltVp17733shUUAPwHhRLwAKfTqS5duujs2bPaunWrQkJCTEeCh/3000/FG6inpqaqVq1aGjZsmCwWi3r27MkG6gD8GoUS8IBJkybp8ccf1+rVq3X33XebjoNSlpqaWryB+k8//aT69etrxIgRslqt6tSpkwIDA01HBIAyRaEE3HTw4EGFh4crOjpa//rXv0zHQRlyuVzatGmTHA6H4uPj9fPPP6tJkyaKjo6W1WpVu3btGMwC4BcolICbRo4cqVWrVikzM1M33HCD6TgwxOl06vvvv5fdbldCQoKys7MVGhoqi8Uii8WisLAw0xEBoNRQKAE3zJs3TwMHDlRcXJysVqvpOPASBQUFWrZsmRwOh5KSknTmzBm1a9euuFzecsstpiMCgEdRKIHrlJOTo4iICIWGhmrhwoVc2sQlXbhwQQsWLJDD4dCcOXN0/vx5de7cWVarVSNGjFCDBg1MRwQAt1Eogev04osv6qOPPlJaWppuvfVW03FQDpw9e1Zz5syR3W7XokWLVFRUpJ49e8pisSgqKopjOgGUWxRK4Dps27ZN7du31+uvv66XX37ZdByUQydOnFBiYqIcDodWrFihoKAg3XfffbJYLHrggQdUrVo10xEB4KpRKIFrVFRUpC5duig3N1dbtmxRhQoVTEdCOXf48GElJCTIbrdr7dq1qly5sgYOHCir1ar+/furUqVKpiMCwGVRKIFr9PHHH+vJJ59UcnKyunTpYjoOfMzevXsVHx8vh8Ohbdu2qUaNGho6dKgsFot69+7NLzAAvBKFErgGP//8s8LDw2Wz2TRp0iTTceDjMjMz5XA4ZLfb9cMPP6hu3boaPny4rFar7r77bjZQB+A1KJTANRg+fLi+//57ZWZmqlatWqbjwE+4XC5t27ZNdrtdDodD+/fvV6NGjRQdHS2LxaL27duzywAAoyiUwFWaM2eOBg8eLIfDoejoaNNx4KecTqfWrVsnu92uadOm6ejRo7rttttksVhktVoVERFhOiIAP0ShBK7CuXPnFBERoYiICM2bN4/VIHiFwsJCrVy5Ug6HQzNmzNCpU6fUqlUrWa1WRUdH67bbbjMdEYCfoFACV+H555/XpEmTlJaWpmbNmpmOA/xGXl6eFi9eLLvdrlmzZik3N1cdOnSQxWLRyJEj1ahRI9MRAfgwCiVwBVu3blX79u31j3/8Qy+99JLpOMAV5eTkaO7cuXI4HJo/f74KCgrUvXt3WSwWDR8+XHXr1jUdEYCPoVACl1FUVKROnTopPz9fmzZtYssWlDunTp3SzJkzZbfbtWzZMklS3759ZbVaNWTIENWoUcNwQgC+gEIJXMYHH3ygZ555RmvWrFGnTp1MxwHccvToUc2YMUN2u12rV69WxYoVdf/998tisWjgwIGqXLmy6YgAyikKJVCCAwcOKDw8XP/zP/+jjz/+2HQcwKP279+vadOmyW63a/PmzapWrZoeeOABWa1W9e3bVyEhIaYjAihHKJRACaKiorR27VplZmaqZs2apuMApWbXrl2Kj4+X3W5Xenq6ateurWHDhslisahHjx4KCgoyHRGAl6NQApcwa9YsDRkyRNOmTdOIESNMxwHKhMvlUmpqavEG6nv27FGDBg00cuRIWa1WdezYkS2zAFwShRL4L2fPnlXLli3Vtm1bzZkzhw9Q+CWXy6UNGzbI4XAoPj5ehw4dUtOmTWWxWGSxWNSmTRt+NgAUo1AC/+XZZ5/Vv/71L6Wlpalp06am4wDGFRUVafXq1bLb7Zo+fbpOnDihsLAwWa1WWSwWtWjRwnREAIZRKIFf2Lx5szp06KA333xTL7zwguk4gNcpKCjQkiVL5HA4lJSUpHPnzikyMlIWi0XR0dFq0qSJ6YgADKBQAv9RWFiojh07qqioSJs2bVJwcLDpSIBXO3/+vObPny+Hw6G5c+fqwoUL6tq1q6xWq4YPH6769eubjgigjFAogf9477339Nxzz2ndunXq0KGD6ThAuXLmzBnNnj1bdrtdixcvltPpVO/evWWxWBQVFaVatWqZjgigFFEoAf17T77w8HA99NBD+vDDD03HAcq148ePKzExUQ6HQytXrlSFChXUr18/Wa1WDRo0SFWrVjUdEYCHUSjh91wul4YMGaJNmzYpIyODo+gADzp48KASEhJkt9u1fv16ValSRYMGDZLValW/fv1UsWJF0xEBeACFEn4vKSlJUVFRmjFjhqKiokzHAXzWnj175HA45HA4tGPHDtWsWVNRUVGyWCzq1asX9y0D5RiFEn7tzJkzatmypSIjIzVr1iz21QPKSHp6uhwOh+x2u3788UfdeOONGjFihKxWq7p06aLAwEDTEQFcAwol/NrTTz+tL7/8Uunp6Wx3Ahjgcrm0ZcsW2e12xcfH68CBA2rcuLGio6NlsVgUGRnJL3pAOUChhN/auHGjOnbsqLffflvPPvus6TiA33M6nUpOTpbD4VBCQoKOHTum5s2by2KxyGq1Kjw83HREACWgUMIvFRYW6q677lJAQIA2bNjAvVuAlyksLNTy5cvlcDiUmJio06dPq02bNrJarYqOjlazZs1MRwTwCxRK+KV33nlHL774otavX6/27dubjgPgMvLy8rRw4ULZ7XbNnj1b58+fV6dOnWSxWDRy5EjddNNNpiMCfo9CCb+zb98+tWzZUn/84x/1/vvvm44D4BqcO3dOc+bMkcPh0IIFC1RYWKh77rlHFotFw4YNU506dUxHBPwShRJ+xeVyadCgQdq2bZsyMjJUvXp105EAXKeTJ08qKSlJdrtdy5cvV2BgoO69915ZrVY98MAD/HwDZYhCCb8yY8YMDR8+XElJSRoyZIjpOAA85MiRI0pISJDD4VBycrIqVaqkgQMHymKxaMCAAapcubLpiIBPo1DCb5w+fVrh4eHq0KGDZs6caToOgFKSlZWl+Ph42e12bd26VdWrV9eQIUNktVrVp08fVahQwXREwOdQKOE3nnzySX399ddKT09X48aNTccBUAZ27txZvIH6zp07VadOHQ0fPlwWi0XdunVTUFCQ6YiAT6BQwi+sX79enTt31rvvvqunn37adBwAZczlcmnHjh2y2+1yOBzat2+fGjZsqJEjR8pisahDhw5soA64gUIJn1dQUKD27durQoUKWr9+PSsSgJ9zuVxa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ulUhISGmIwEA4JaioiJ16NBBTqdTGzduVHAw62zXi785XJVPP/1U69ev1+rVqymTAACf8Mknn2jr1q1au3YtZdJNrFDiig4ePKjw8HBZLBZ99tlnpuMAAOC2Q4cOKSwsTFarVZ9++qnpOOUehRJXNHLkSK1atUqZmZm64YYbTMcBAMBtVqtVy5Yt086dO/ls8wDWd3FZ8+bNU0JCguLi4viBAwD4hCVLlsjhcOjrr7/ms81DWKFEiXJyctSyZUuFhYVp4cKFbBMEACj38vLy1Lp1a910001auXIln20ewgolSjRmzBgdPXpUK1as4AcOAOATJkyYoD179igpKYnPNg+iUOKStm3bpnfffVevv/66br31VtNxAABw208//aTx48fr+eefV0REhOk4PoVL3viNoqIide7cWefPn9eWLVtUoUIF05EAAHCLy+XSgAEDlJGRobS0NFWtWtV0JJ/CCiV+Y9KkSdq4caPWrFlDmQQA+IQZM2Zo4cKFmjVrFmWyFLBCiV/5+eefFR4eLpvNpkmTJpmOAwCA286ePavw8HDdeeedmjVrluk4PolCiV8ZNmyYkpOTlZmZqVq1apmOAwCA25577jl99tlnSk9P1y233GI6jk/ikjeKzZ49W4mJiXI4HJRJAIBP2L59uz744AONHz+eMlmKWKGEJOncuXNq2bKlWrVqpXnz5rGVAgCg3HM6nbr77rt1+vRpbd26VSEhIaYj+SxWKCFJGj16tI4fP66PP/6YMgkA8AmTJ0/W2rVrtWrVKspkKWOFEtqyZYvuuusu/eMf/9BLL71kOg4AAG47fvy4QkNDNXDgQH399dem4/g8CqWfKyoqUseOHVVQUKBNmzaxTRAAwCc8/PDDmjlzpjIzM1WvXj3TcXwel7z93Mcff6wtW7aw5yQAwGd8//33mjJlij799FPKZBlhhdKPHThwQOHh4fqf//kfffzxx6bjAADgtoKCAkVGRqpq1apas2aNAgMDTUfyC6xQ+rGnnnpK1atX1xtvvGE6CgAAHvHee+8pPT1dmzZtokyWIQqln5o5c6ZmzpyphIQE1axZ03QcAADclpWVpTFjxuipp57SHXfcYTqOX+GStx86e/asWrZsqbZt22rOnDlsEwQA8AlDhw7Vhg0blJGRoRo1apiO41dYofRDr776qk6cOKGPPvqIMgkA8Alz587VzJkzFR8fT5k0gBVKP7Np0yZ17NhREyZM0PPPP286DgAAbsvNzVVERIRatGihhQsXslhiAIXSjxQWFqpjx44qKirSpk2bFBzMAjUAoPx75ZVX9PbbbyslJUXNmzc3Hccv0Sj8yEcffaStW7dq3bp1lEkAgE/IyMjQxIkTNWrUKMqkQaxQ+omsrCy1bNlSDz30kD788EPTcQAAcJvL5VKvXr104MABpaSkqFKlSqYj+S2WqfyAy+XSk08+qZo1a2r8+PGm4wAA4BGxsbFauXKlFi1aRJk0jBVKP5CUlKSoqCjNmDFDUVFRpuMAAOC2kydPKiwsTPfcc4/i4+NNx/F7FEofd+bMGbVs2VKRkZGaNWsWk28AAJ/w+OOPa+rUqcrMzFTDhg1Nx/F7XPL2cX/729906tQp9pwEAPiMDRs26NNPP9W7775LmfQSrFD6sI0bN6pjx456++239eyzz5qOAwCA24qKitShQwc5nU5t3LiRXUu8BIXSRxUWFuquu+5SQECANmzYwA8cAMAnfPTRR/rLX/6iNWvWqFOnTqbj4D9oGT7q/fff144dO7R+/XrKJADAJxw6dEivvPKKHn30Ucqkl2GF0gft27dPLVu21KOPPqr33nvPdBwAADwiJiZGS5cuVWZmpmrXrm06Dn6BQuljXC6XBg0apG3btikjI0PVq1c3HQkAALctXbpUffv21VdffaXf//73puPgv1Aofcz06dM1YsQIJSUlaciQIabjAADgtry8PLVp00YNGjTQypUr2bXEC3FznQ85ffq0/vKXv+iBBx6gTAIAfMaECRO0e/duJSYmUia9VKDpAPCcV155RWfPnuWsbgCAz/jpp580fvx4Pf/884qIiDAdByXgkrePWL9+vTp37qx3331XTz/9tOk4AAC4zeVyacCAAcrIyFBaWpqqVq1qOhJKQKH0AQUFBWrfvr0qVKig9evXKygoyHQkAADcNmPGDA0fPlyzZs3S4MGDTcfBZXAPpQ947733lJqaqo0bN1ImAQA+4ezZs3r66ac1aNAgymQ5wD2U5dzevXs1evRoPf3004qMjDQdBwAAjxgzZoxOnDihDz74wHQUXAUueZdjLpdL999/v1JTU5Wenq5q1aqZjgQAgNt27NihyMhIvf7663r55ZdNx8FVoFCWY9OmTVN0dDT3lgAAfIbT6dTdd9+t06dPa+vWrQoJCTEdCVeBeyjLqVOnTunpp59WVFQUZRIA4DMmT56stWvXauXKlZTJcoQVynLq8ccf19SpU5WRkaFGjRqZjgMAgNuOHz+u0NBQDRw4UF9//bXpOLgGrFCWQ2vXrtWnn36q999/nzIJAPAZL730klwulyZOnGg6Cq4RK5TlTEFBgSIjI1W5cmWtXbuWbYIAAD7h+++/V7du3fTpp5/qz3/+s+k4uEYUynLmzTff1CuvvKJNmzapXbt2puMAAOC2i4slVapU0dq1axUYyK6G5Q2XvMuR3bt36+9//7ueeeYZyiQAwGe8//77Sk9P16ZNmyiT5RQrlOWEy+VS//79i88zZc9JAIAv2L9/v8LDw/XII4/o/fffNx0H14kVynIiPj5eixYt0pw5cyiTAACf8fTTT6tGjRoaN26c6ShwAyuU5cDJkycVHh6ubt26KSEhwXQcAAA8Yt68eRo4cKAcDoeio6NNx4EbKJTlwJ///GfZ7XZlZmaqYcOGpuMAAOC23NxcRUREqHnz5lq0aJECAgJMR4IbuOTt5ZKTk/Wvf/1LH330EWUSAOAzxo8fr0OHDmnx4sWUSR/ACqUXy8/PV2RkpKpVq6bk5GT2nAQA+ISMjAy1bdtWo0aN0pgxY0zHgQewQunF3nrrLWVmZmrz5s2USQCAT3C5XHr88cd1yy236OWXXzYdBx5CofRSP/74o8aNG6fnnntObdu2NR0HAACPiIuL08qVK7Vo0SJVqlTJdBx4CJe8vZDL5dJ9992nXbt2KTU1VVWrVjUdCQAAt506dUqhoaHq0aOHpk2bZjoOPIgVSi9kt9u1ZMkSzZ8/nzIJAPAZr7zyinJzc/Xuu++ajgIPY4XSy5w4cUJhYWHq2bOn4uPjTccBAMAjNm7cqI4dO+qdd97RM888YzoOPIxC6WUeffRRJSQkKCMjQzfddJPpOAAAuK2oqEgdO3ZUUVGRNm7cqOBgLpD6Gv6NepHVq1friy++0KRJkyiTAACfMWnSJG3ZskVr1qyhTPooVii9RH5+vtq1a6eaNWsqOTlZgYGBpiMBAOC2Q4cOKSwsTBaLRZ999pnpOCgl/JrgJSZMmKBdu3Zpy5YtlEkAgM94/vnnVbFiRf3jH/8wHQWliELpBXbt2qXXX39dL7zwglq3bm06DgAAHrFs2TLZ7XZ99dVXql27tuk4KEVc8jbM5XKpb9++2r17t1JTU1WlShXTkQAAcFteXp7atGmj+vXra9WqVZzX7eNYoTRs6tSpWrZsmRYsWECZBAD4jIkTJ2r37t1KTEykTPoBVigNys7OVlhYmPr06SO73W46DgAAHrF7925FREToL3/5i958803TcVAGKJQGPfLII0pMTFRGRoYaNGhgOg4AAG5zuVy6//77lZaWpvT0dE588xNc8jZk1apVmjx5sj777DPKJADAZyQmJmrBggWaOXMmZdKPsEJpQF5entq2bau6devqu+++Y5sgAIBPOHv2rMLDwxUZGanZs2ebjoMyxAqlAW+++aZ++uknzZgxgzIJAPAZY8aM0YkTJ/TBBx+YjoIyRqEsYz/88IPGjx+vl156SREREabjAADgETt27ND777+v119/XU2bNjUdB2WMS95lyOVyqXfv3tq3b59SU1NVuXJl05EAAHCb0+lUt27ddPLkSW3btk0hISGmI6GMsUJZhr755hutWLFCixcvpkwCAHzGlClTtGbNGq1YsYIy6adYoSwjx48fV1hYmPr166epU6eajgMAgEccP35coaGhuv/++/XNN9+YjgNDmAgpIy+++KKcTqfeeecd01EAAPCY//u//5PT6dRbb71lOgoM4pJ3GVixYoW++uorff7556pXr57pOAAAeERycrImT56sSZMm8fnm57jkXcouXLigtm3bql69elq1ahXbBAEAfEJBQYEiIyNVpUoVrV27ls83P8cKZSn75z//qT179igpKYkfNgCAz3j//feVnp6uTZs28fkGVihLU2Zmptq2bauXXnpJ48aNMx0HAACP2L9/v8LDw/XII4/o/fffNx0HXoBCWUpcLpfuueceHTx4UDt27GCbIACAz4iKitK6deuUmZmpGjVqmI4DL8Al71Ly1Vdf6bvvvtPSpUspkwAAnzFv3jwlJSXJ4XBQJlGMFcpScOzYMYWFhbEnFwDAp+Tm5qpVq1a67bbbtHjxYgUEBJiOBC/BCmUpeP755yVJb7/9tuEkAAB4zhtvvKGff/5ZCxcupEziVyiUHrZs2TJ9++23+vLLL3XjjTeajgMAgEdkZmZqwoQJ+utf/6oWLVqYjgMvwyVvD7pw4YJat26thg0bauXKlfz2BgDwCS6XS71791ZWVpZSU1NVqVIl05HgZVih9KDx48dr3759mjNnDmUSAOAz4uLitGLFCi1c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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "\n", "import networkx as nx\n", "red = to_networkx_graph(bqm)\n", "nx.draw(red, with_labels = True)\n" ] }, { "cell_type": "markdown", "id": "4ee8a7a2-4679-40e4-bbb6-8606a8c63729", "metadata": {}, "source": [ "Veamos que efectivamente los arcos son los términos cuadráticos de la ecuación" ] }, { "cell_type": "code", "execution_count": 9, "id": "e2101e31-4077-415f-8ec3-ca1a2ab18eca", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "EdgeDataView([(0, 4, {'bias': 1.0}), (0, 5, {'bias': 1.0}), (1, 4, {'bias': 1.0}), (1, 5, {'bias': 1.0})])" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "red.edges().data()" ] }, { "cell_type": "markdown", "id": "6eb4d1a5-38be-462c-babb-5c508c12b472", "metadata": {}, "source": [ "Veamos a continuación el modelo que realmente se ha construido:" ] }, { "cell_type": "code", "execution_count": 5, "id": "1c0c4215-82aa-4bcd-b931-d1781cf37794", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "BinaryQuadraticModel({0: -1.0, 1: -1.0, 4: -1.0, 5: -1.0}, {(4, 0): 1.0, (4, 1): 1.0, (5, 0): 1.0, (5, 1): 1.0}, 0.0, 'SPIN')" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "bqm" ] }, { "cell_type": "code", "execution_count": 12, "id": "54bb87e0-7678-4e86-8b25-343720bfb553", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{0: -1.0, 1: -1.0, 4: -1.0, 5: -1.0}" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Estos serían los términos lineales\n", "bqm.linear" ] }, { "cell_type": "code", "execution_count": 13, "id": "c9f42209-cf52-4402-aff8-84ee9c81a1c7", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{(4, 0): 1.0, (4, 1): 1.0, (5, 0): 1.0, (5, 1): 1.0}" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# estos los términos cuadráticos\n", "bqm.quadratic" ] }, { "cell_type": "markdown", "id": "c053cf31-c290-4bf5-98ce-317691d14694", "metadata": {}, "source": [ "Vamos a resolver el problema anterior, con el Solver *ExactSolver*." ] }, { "cell_type": "code", "execution_count": 14, "id": "beb5c07d-0b80-469f-b777-ec5d7262b58a", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " 0 1 4 5 energy num_oc.\n", "0 +1 +1 -1 -1 -4.0 1\n", "1 -1 -1 +1 +1 -4.0 1\n", "2 +1 +1 +1 -1 -2.0 1\n", "3 +1 -1 +1 +1 -2.0 1\n", "4 -1 +1 +1 +1 -2.0 1\n", "5 +1 +1 -1 +1 -2.0 1\n", "6 -1 +1 +1 -1 0.0 1\n", "7 +1 -1 +1 -1 0.0 1\n", "8 +1 +1 +1 +1 0.0 1\n", "9 -1 +1 -1 +1 0.0 1\n", "['SPIN', 10 rows, 10 samples, 4 variables]\n" ] } ], "source": [ "from dimod import ExactSolver\n", "# Creamos una instancia de este Solver\n", "solver = ExactSolver()\n", "response = solver.sample(bqm)\n", "# Sólo sacamos las primeras 10 soluciones (ordenadas de menos a más energía )\n", "print(response.truncate(10))" ] }, { "cell_type": "markdown", "id": "4f526b71-871f-4343-a881-bd0798606b8a", "metadata": {}, "source": [ "Como el modelo se le ha declarado de tipo SPIN los únicos valores que toman las variables son 1 y -1 y un mínimo de la función antyerior, lo podemos encontrar con la primera solución indicada que es la que tiene menor energía, aunque también podría servir la siguiente, la que ocupa la segunda línea de la solución.\n", "\n", "## DWave_neal.\n", "```{index} SimulatedAnnealingSampler,LeapHybridSampler,DWaveSampler\r\n", "```\n", "Es de advertir que este módulo está *deprecated* desde dwave-ocean-sdk.6.1.0 en favor del módulo dwave_samplers, y será eliminado en la versión dwave-ocean-sdk.8.0.0." ] }, { "cell_type": "code", "execution_count": 16, "id": "4bcf89fd-fb0c-4312-b33f-a48ed3b05ba1", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " 0 1 4 5 energy num_oc.\n", "0 -1 -1 +1 +1 -4.0 1\n", "1 +1 +1 -1 -1 -4.0 1\n", "2 +1 +1 -1 -1 -4.0 1\n", "3 +1 +1 -1 -1 -4.0 1\n", "4 -1 -1 +1 +1 -4.0 1\n", "5 +1 +1 -1 -1 -4.0 1\n", "6 +1 +1 -1 -1 -4.0 1\n", "7 +1 +1 -1 -1 -4.0 1\n", "8 +1 +1 -1 -1 -4.0 1\n", "9 +1 +1 -1 -1 -4.0 1\n", "['SPIN', 10 rows, 10 samples, 4 variables]\n" ] } ], "source": [ "from neal import SimulatedAnnealingSampler \n", "\n", "sampler = SimulatedAnnealingSampler()\n", "\n", "response = sampler.sample(bqm, num_reads=10,\n", " num_sweeps=1000,\n", " initial_states=None,\n", " beta_range=[10, 100])\n", "print(response)" ] }, { "cell_type": "markdown", "id": "e9c73076-5d08-4d0f-bb28-9773608fa9a1", "metadata": {}, "source": [ "Utilizamos a continuación un solvers completamente cuántico, nos referimos a *DWaveSampler*. Veamos un ejemplo" ] }, { "cell_type": "code", "execution_count": null, "id": "5ef523e0-0d6a-4bd5-bbf1-ca4e4eaa2acf", "metadata": {}, "outputs": [], "source": [ "from dwave.system import DWaveSampler\n", "\n", "sampler = DWaveSampler(solver=dict(topology__type='chimera'))\n", "\n", "response = sampler.sample(\n", " bqm, num_reads=10,\n", " annealing_time=10,\n", " auto_scale=False,\n", " answer_mode='raw',\n", " label='Prueba_DWaveSampler'\n", " )\n", "print(response)" ] }, { "cell_type": "markdown", "id": "8879b436-0875-4ec5-b2bb-018d9867133e", "metadata": {}, "source": [ "Por último usamos *LeapHybridSampler*, un solver híbrido muy flexibles y utilizado" ] }, { "cell_type": "code", "execution_count": null, "id": "76f48453-28a8-4095-86a4-c27541bff7ca", "metadata": {}, "outputs": [], "source": [ "from dwave.system import LeapHybridSampler\n", "\n", "sampler = LeapHybridSampler()\n", "print(\"Propiedades de este Sampler:\\n\")\n", "print(sampler.properties)\n", "\n", "response = sampler.sample(\n", " bqm, time_limit=3,\n", " label = \"Prueba con LeapHybridSampler\"\n", " )\n", "print(\"\\nla respuesta es la siguiente.\\n\")\n", "print(response)" ] }, { "cell_type": "markdown", "id": "9d2cdeae-1b8f-43af-a082-f1682d283532", "metadata": {}, "source": [ "## Otro ejemplo.\n", "\n", "Con el fin de afianzar estos conceptos, fáciles pero muy importante de dominar pues son los pilares de estos métodos de optimización, a continuación procedemos a resolver otro problema similar al anterior. Implementamos el código para el problema" ] }, { "cell_type": "code", "execution_count": 17, "id": "770ed750-3f20-4dbc-ab45-82b5ba70b91a", "metadata": {}, "outputs": [], "source": [ "bqm = BinaryQuadraticModel('SPIN')\n", "bqm.add_variable('x',1)\n", "bqm.add_variable('y',1)\n", "bqm.add_variable('z',1)\n", "bqm.add_interaction('x','y',-2)\n", "bqm.add_interaction('x','z',-2)\n", "bqm.add_interaction('y','z',-2)" ] }, { "cell_type": "markdown", "id": "62667610-b61f-4706-9f0f-8f92b77ecf0a", "metadata": {}, "source": [ "La función objetivo en este caso sería la siguiente:\n", "\n", "$$H = x + y + z - 2xy - 2xz - 2yz$$" ] }, { "cell_type": "code", "execution_count": 18, "id": "5c95b3a0-e58a-4c81-bad5-99a51f2216dc", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "BinaryQuadraticModel({'x': 1.0, 'y': 1.0, 'z': 1.0}, {('y', 'x'): -2.0, ('z', 'x'): -2.0, ('z', 'y'): -2.0}, 0.0, 'SPIN')" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Veamos el modelo\n", "bqm" ] }, { "cell_type": "markdown", "id": "2751fb7c-326d-423d-9369-4e106fd0db20", "metadata": {}, "source": [ "El anterior modelo también se puede construir, desde un diccionario de python de la siguiente manera" ] }, { "cell_type": "code", "execution_count": 25, "id": "5428c0b8-e1be-480b-9d5e-1d9a35d2f229", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "BinaryQuadraticModel({'x': 1.0, 'y': 1.0, 'z': 1.0}, {('y', 'x'): -2.0, ('z', 'x'): -2.0, ('z', 'y'): -2.0}, 0.0, 'SPIN')" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# el diccionario h contendrá los términos lineales\n", "h1={}\n", "# El diccionario j contendra los terminos cuadráticos\n", "j1={}\n", "\n", "# Ahora definimos los términos lineales\n", "h1['x']=1\n", "h1['y']=1\n", "h1['z']=1\n", "\n", "#Definimos los términos cuadráticos\n", "\n", "j1['x','y'] =-2\n", "j1['x','z'] = -2\n", "j1['y','z'] = -2\n", "\n", "model = BinaryQuadraticModel.from_ising(h=h1,J=j1)\n", "model" ] }, { "cell_type": "markdown", "id": "6a486aa3-9cc7-4b06-b4bb-102199463768", "metadata": {}, "source": [ "Como podemos observar con los dos procedimientos obtenemos el mismo modelo. Veamos algunas de las características del modelo construido:" ] }, { "cell_type": "code", "execution_count": 26, "id": "bc930a32-4e29-45d0-9c50-58ba5d4f1269", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "model.vartype" ] }, { "cell_type": "code", "execution_count": 27, "id": "7d3f1240-2411-436d-83fe-730b361222af", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Variables(['x', 'y', 'z'])" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "model.variables" ] }, { "cell_type": "markdown", "id": "96ec3bc5-0184-4306-8b5f-6a9639be1e05", "metadata": {}, "source": [ "Resolvemos con ExactSolver" ] }, { "cell_type": "code", "execution_count": 28, "id": "227d90c3-a777-4245-a26c-17f05b5e9ac0", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " x y z energy num_oc.\n", "0 -1 -1 -1 -9.0 1\n", "1 +1 +1 +1 -3.0 1\n", "2 +1 -1 -1 1.0 1\n", "3 -1 +1 -1 1.0 1\n", "4 -1 -1 +1 1.0 1\n", "5 +1 +1 -1 3.0 1\n", "6 -1 +1 +1 3.0 1\n", "7 +1 -1 +1 3.0 1\n", "['SPIN', 8 rows, 8 samples, 3 variables]\n" ] } ], "source": [ "from dimod import ExactSolver\n", "\n", "solver = ExactSolver()\n", "response = solver.sample(bqm)\n", "print(response.truncate(10))" ] }, { "cell_type": "code", "execution_count": 29, "id": "6170e776-d349-4f75-a0fc-a83031b59816", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "dimod.sampleset.SampleSet" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(response)" ] }, { "cell_type": "markdown", "id": "dc30d209-0540-422b-8562-1afab494ae59", "metadata": {}, "source": [ "Como podemos observar el objeto que se nos devuelve es de tipo SampleSet y su documentación la podemos ver en este enlace ." ] }, { "cell_type": "code", "execution_count": 30, "id": "7fef1d4d-f51e-4649-94d0-367029537c59", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "response.data" ] }, { "cell_type": "markdown", "id": "c1d5ec0f-dbf3-497f-a2de-75a6d3536bb5", "metadata": {}, "source": [ "Podemos quedarnos con parte de los datos de la respuesta de la siguiente manera:" ] }, { "cell_type": "code", "execution_count": 31, "id": "47dbda03-aad5-46c8-9400-3b0596edbd8f", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'x': -1, 'y': -1, 'z': -1} -9.0\n", "{'x': 1, 'y': 1, 'z': 1} -3.0\n", "{'x': 1, 'y': -1, 'z': -1} 1.0\n", "{'x': -1, 'y': 1, 'z': -1} 1.0\n", "{'x': -1, 'y': -1, 'z': 1} 1.0\n", "{'x': 1, 'y': 1, 'z': -1} 3.0\n", "{'x': -1, 'y': 1, 'z': 1} 3.0\n", "{'x': 1, 'y': -1, 'z': 1} 3.0\n", "___________________\n", "{'x': -1, 'y': -1, 'z': -1} 1\n", "{'x': 1, 'y': 1, 'z': 1} 1\n", "{'x': 1, 'y': -1, 'z': -1} 1\n", "{'x': -1, 'y': 1, 'z': -1} 1\n", "{'x': -1, 'y': -1, 'z': 1} 1\n", "{'x': 1, 'y': 1, 'z': -1} 1\n", "{'x': -1, 'y': 1, 'z': 1} 1\n", "{'x': 1, 'y': -1, 'z': 1} 1\n" ] } ], "source": [ "for sample, energy in response.data(['sample','energy']):\n", " print(sample, energy)\n", "print(\"___________________\")\n", "\n", "\n", "for sample, num_oc in response.data(['sample','num_occurrences']):\n", " print(sample, num_oc)" ] }, { "cell_type": "code", "execution_count": 32, "id": "f100dde0-8a84-4628-a6dc-25ec32b4dac1", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Sample(sample={'x': -1, 'y': -1, 'z': -1}, energy=-9.0, num_occurrences=1)\n" ] } ], "source": [ "# Sacamos la primera solución\n", "print(response.first)" ] }, { "cell_type": "markdown", "id": "d145a97c-f77b-4b5b-a4f7-e275ecdfa5a8", "metadata": {}, "source": [ "## Utilización de FixedVariableComposite.\n", "```{index} FixedVariableComposite\r\n", "```\n", "En ocasiones quizá pueda ser aconsejable fijar el valor de una variables al resolver problemas de optimización. Para conseguir esto Ocean SDK pone a nuestra disposición el clase FixedVariableComposite .\n", "\n", "Para ver cómo podemos utilzar esto, vamos a añadir al modelo anterior una nueva variable denominada w con un *bias* igual a -1. Esta variable no va a estar conectada a ninguna otra variable y la vamos a fijar con un valor igual a 1.\n", "\n", "Todo esto lo hacemos con el siguiente código\n" ] }, { "cell_type": "code", "execution_count": 33, "id": "adf3dbe1-575a-4b20-a7e7-e2caa4888e4f", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " w x y z energy num_oc.\n", "0 +1 -1 -1 -1 -10.0 1\n", "5 +1 +1 +1 +1 -4.0 1\n", "1 +1 +1 -1 -1 0.0 1\n", "3 +1 -1 +1 -1 0.0 1\n", "7 +1 -1 -1 +1 0.0 1\n", "2 +1 +1 +1 -1 2.0 1\n", "4 +1 -1 +1 +1 2.0 1\n", "6 +1 +1 -1 +1 2.0 1\n", "['SPIN', 8 rows, 8 samples, 4 variables]\n" ] } ], "source": [ "# He importado FixVariablesComposite porque FixedVariableComposite estaba decrepated\n", "from dwave.preprocessing.composites import FixVariablesComposite\n", "#bqm.add_variable('w',-1)\n", "composite_sampler = FixVariablesComposite(solver)\n", "# añadimos la variable w al modelo, con un valor de bias de -1\n", "bqm.add_variable('w',-1) \n", "# Ahora fijo el valor de la variable w a 1\n", "respuesta = composite_sampler.sample(bqm,fixed_variables={'w':1})\n", "print(respuesta)" ] }, { "cell_type": "markdown", "id": "46b367b0-1c67-4917-a395-9087cd73bd46", "metadata": {}, "source": [ "## Convertir un modelo QUBO en ISING.\n", "\n", "En el siguiente ejemplo, vamos a ver como pasar de un modelo tipo QUBO a otro ISING" ] }, { "cell_type": "code", "execution_count": 34, "id": "ec95e8dc-f182-4952-a834-6280683ff6cf", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "BinaryQuadraticModel({'B': 1.0, 'K': 1.0, 'A': 0.0, 'C': 0.0}, {('A', 'K'): -2.0, ('C', 'B'): -2.0, ('C', 'A'): 2.0}, 0.0, 'BINARY')" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Importamos los paquetes necesario\n", "from dwave.system import EmbeddingComposite, DWaveSampler\n", "from dimod import BinaryQuadraticModel\n", "\n", "# Definimos el problema mediante un diccionario\n", "Q = {('B','B'): 1,\n", " ('K','K'): 1,\n", " ('A','C'): 2,\n", " ('A','K'): -2,\n", " ('B','C'): -2}\n", "\n", "# Generamos el modelo QUBO\n", "bqm = BinaryQuadraticModel.from_qubo(Q)\n", "\n", "bqm" ] }, { "cell_type": "markdown", "id": "aebf945b-8ce2-47b5-8f86-f4d1150c5e1e", "metadata": {}, "source": [ "Ahora cambiamos el tipo de modelo" ] }, { "cell_type": "code", "execution_count": 35, "id": "9c3d92fe-e122-4e99-ac24-cc5e70c20ca5", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "({'B': 0.0, 'K': 0.0, 'A': 0.0, 'C': 0.0},\n", " {('A', 'K'): -0.5, ('C', 'B'): -0.5, ('C', 'A'): 0.5},\n", " 0.5)" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Convertimos el bqm to a un modelo Ising\n", "ising_model = bqm.to_ising()\n", "ising_model" ] }, { "cell_type": "markdown", "id": "e3d41b3d-15ce-49fc-924f-9d7d4e4bdcb5", "metadata": {}, "source": [ "Veamos la diferentes partes que se han generado" ] }, { "cell_type": "code", "execution_count": 36, "id": "33d2d206-a5d0-422a-9045-bad7d24cedb2", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'B': 0.0, 'K': 0.0, 'A': 0.0, 'C': 0.0}" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ising_model[0]" ] }, { "cell_type": "code", "execution_count": 37, "id": "edac4673-adff-48cc-9c85-18992e7f6764", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{('A', 'K'): -0.5, ('C', 'B'): -0.5, ('C', 'A'): 0.5}" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ising_model[1]" ] }, { "cell_type": "code", "execution_count": null, "id": "7026490c-5c04-40f6-98b5-359778407a4a", "metadata": {}, "outputs": [], "source": [ "\n", "# Definimos el Sampler a utilizar en el problema\n", "sampler = EmbeddingComposite(DWaveSampler())\n", "\n", "# Ejecutamos el Sampler definido antes e imprimimos el resultado\n", "sampleset = sampler.sample_ising(\n", " h = ising_model[0],\n", " J = ising_model[1],\n", " num_reads = 10,\n", " label='Example - Simple Ocean Programs: Conversion')\n", "\n", "print(sampleset)" ] }, { "cell_type": "markdown", "id": "f4097099-be68-4e7c-8932-cbfd01282104", "metadata": {}, "source": [ "Otra manera de hacer lo anterior sería mediante el siguiente formato de código" ] }, { "cell_type": "code", "execution_count": null, "id": "0f776c25-28c0-4712-a6e4-16140a6e4d71", "metadata": {}, "outputs": [], "source": [ "from dwave.system import EmbeddingComposite, DWaveSampler\n", "from dimod import BinaryQuadraticModel\n", "\n", "# Definimos el problema utilizando un diccionario\n", "Q = {('B','B'): 1,\n", " ('K','K'): 1,\n", " ('A','C'): 2,\n", " ('A','K'): -2,\n", " ('B','C'): -2}\n", "# Creamos el objeto BQM y le damos un offset (el término constante) de 1\n", "bqm = BinaryQuadraticModel.from_qubo(Q, offset=1.0)\n", "\n", "# Definimos el Sampler a utilizar\n", "sampler = EmbeddingComposite(DWaveSampler())\n", "\n", "# Ejecutamos el SAmpler anterior e imprimimos resultados\n", "sampleset = sampler.sample(bqm,\n", " num_reads = 10,\n", " label='Example - Simple Ocean Programs: Offsets')\n", "print(\"QUBO samples:\")\n", "print(sampleset)\n", "\n", "# Convertinos el modelo a ISING y ejecutamos en el mismo sampler.\n", "bqm.change_vartype('SPIN')\n", "sampleset = sampler.sample(bqm,\n", " num_reads = 10,\n", " label='Example - Simple Ocean Programs: Offsets')\n", "print(\"\\nIsing samples:\")\n", "print(sampleset)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "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.8.3" } }, "nbformat": 4, "nbformat_minor": 5 }