22. Introducción.#
En este notebook, vamos a mostrar un ejemplo sobre cómo mejorar el rendimiento de la programación hecha con Ocean a la hora de resolver un problema de programación lineal. Al mismo tiempo vamos a ver una serie de pautas que el lector puede seguir a la hora de resolver otro enfoque del problema de la mochila que ya se ha visto en otros ejemplos.
Para ello vamos a resolver el típico problema de tipo bin packing
que básicamente consiste en distribuir de forma óptima una serie de paquetes, con unos determinados pesos en unos contenedores con una limitación de capacidad dada. La referencia a este problema se puede ver en https://en.wikipedia.org/wiki/Bin_packing_problem.
Inicialmente lo resolvemos como se indica en este enlace: https://docs.ocean.dwavesys.com/en/stable/examples/hybrid_cqm_binpacking.html.
La función objetivo en este caso va a consistir en minimizar el número de contenedores (bins) utilizados. Puesto que un contenedor puede ser utilizado o no, podemos denotar esa situación mediante una variable de tipo binario, por lo tanto la variable bin_used_<j>
indicará si el contenedor \(b_j\) va a ser utilizado o no. Vamos a definir inicialmente una serie de valores para este problema
import numpy as np
num_items = 15 # Es el número de items para cargar que vamos a utilizar
item_weight_range = [3, 7] # Rango de pesos
weights = list(np.random.randint(*item_weight_range, num_items))
bin_capacity = int(10 * np.mean(weights)) # Capacidad de los bins
print("Problem: pack a total weight of {} into bins of capacity {}.".format(
sum(weights), bin_capacity))
Problem: pack a total weight of 73 into bins of capacity 48.
# Veamos los pesos que obtenemos
weights
[6, 6, 3, 3, 6, 6, 4, 5, 4, 6, 6, 5, 3, 4, 6]
Como estamos en presencia de un problema de optimización lineal con restricciones, utilizamos un modelo de tipo ConstrainedQuadraticModel
conocido también como CQM
from dimod import ConstrainedQuadraticModel
cqm = ConstrainedQuadraticModel()
23. Función objetivo.#
Tal y como hemos explicado anteriormente, vamos a definir la variable \(b_j\) de tipo binario e indicativo si se utiliza o no el contenedor j de la siguiente manera
from dimod import Binary
bin_used = [Binary(f'bin_used_{j}') for j in range(num_items)]
Veamos cual es el contenido de las variables que acabamos de generar
bin_used
[BinaryQuadraticModel({'bin_used_0': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'bin_used_1': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'bin_used_2': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'bin_used_3': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'bin_used_4': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'bin_used_5': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'bin_used_6': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'bin_used_7': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'bin_used_8': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'bin_used_9': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'bin_used_10': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'bin_used_11': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'bin_used_12': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'bin_used_13': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'bin_used_14': 1.0}, {}, 0.0, 'BINARY')]
La función objetivo tendrá el siguiente formato:
Es decir:
cqm.set_objective(sum(bin_used))
Como hemos visto anteriormente las variables generadas son del tipo BinaryQuadraticModel
, pero veamos qué ocurre si a estas variables les multiplicamos por una determinada cantidad
4.5*bin_used[0]
BinaryQuadraticModel({'bin_used_0': 4.5}, {}, 0.0, 'BINARY')
o incluso si multiplicamos dos de esta variables
4.5*bin_used[0]*bin_used[1]
BinaryQuadraticModel({'bin_used_0': 0.0, 'bin_used_1': 0.0}, {('bin_used_1', 'bin_used_0'): 4.5}, 0.0, 'BINARY')
Si multiplicamos tres variables tendriamos un error porque no sería un término cuadrático
4.5*bin_used[0]*bin_used[1]*bin_used[3]
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[9], line 1
----> 1 4.5*bin_used[0]*bin_used[1]*bin_used[3]
File c:\users\francisco\desktop\dwaveocean\ocean\lib\site-packages\dimod\binary\binary_quadratic_model.py:345, in BinaryQuadraticModel.__mul__(self, other)
343 if isinstance(other, BinaryQuadraticModel):
344 if not (self.is_linear() and other.is_linear()):
--> 345 raise TypeError(
346 "cannot multiply BQMs with interactions")
347 elif other.num_variables and other.vartype != self.vartype:
348 # promote self
349 return QuadraticModel.from_bqm(self) * other
TypeError: cannot multiply BQMs with interactions
24. Restricciones.#
A continuación procedemos a implementar las restricciones que deben tenerse en cuenta en este modelo.
En primer lugar se debe cargar cada item en un sólo bin o contenedor. Entonces si designamos por \(x_{i,j}\) la variable binaria relativa a que el objeto o item i va en el contenedor j, entonces para cada i la suma en j de estas variables debe ser 1. Es decir:
Definamos estas variables \(x_{i,j}\)
item_in_bin = [[Binary(f'item_{i}_in_bin_{j}') for j in range(num_items)]
for i in range(num_items)]
item_in_bin
[[BinaryQuadraticModel({'item_0_in_bin_0': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_0_in_bin_1': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_0_in_bin_2': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_0_in_bin_3': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_0_in_bin_4': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_0_in_bin_5': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_0_in_bin_6': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_0_in_bin_7': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_0_in_bin_8': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_0_in_bin_9': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_0_in_bin_10': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_0_in_bin_11': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_0_in_bin_12': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_0_in_bin_13': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_0_in_bin_14': 1.0}, {}, 0.0, 'BINARY')],
[BinaryQuadraticModel({'item_1_in_bin_0': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_1_in_bin_1': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_1_in_bin_2': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_1_in_bin_3': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_1_in_bin_4': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_1_in_bin_5': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_1_in_bin_6': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_1_in_bin_7': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_1_in_bin_8': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_1_in_bin_9': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_1_in_bin_10': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_1_in_bin_11': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_1_in_bin_12': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_1_in_bin_13': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_1_in_bin_14': 1.0}, {}, 0.0, 'BINARY')],
[BinaryQuadraticModel({'item_2_in_bin_0': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_2_in_bin_1': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_2_in_bin_2': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_2_in_bin_3': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_2_in_bin_4': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_2_in_bin_5': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_2_in_bin_6': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_2_in_bin_7': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_2_in_bin_8': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_2_in_bin_9': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_2_in_bin_10': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_2_in_bin_11': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_2_in_bin_12': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_2_in_bin_13': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_2_in_bin_14': 1.0}, {}, 0.0, 'BINARY')],
[BinaryQuadraticModel({'item_3_in_bin_0': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_3_in_bin_1': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_3_in_bin_2': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_3_in_bin_3': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_3_in_bin_4': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_3_in_bin_5': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_3_in_bin_6': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_3_in_bin_7': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_3_in_bin_8': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_3_in_bin_9': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_3_in_bin_10': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_3_in_bin_11': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_3_in_bin_12': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_3_in_bin_13': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_3_in_bin_14': 1.0}, {}, 0.0, 'BINARY')],
[BinaryQuadraticModel({'item_4_in_bin_0': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_4_in_bin_1': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_4_in_bin_2': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_4_in_bin_3': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_4_in_bin_4': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_4_in_bin_5': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_4_in_bin_6': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_4_in_bin_7': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_4_in_bin_8': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_4_in_bin_9': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_4_in_bin_10': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_4_in_bin_11': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_4_in_bin_12': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_4_in_bin_13': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_4_in_bin_14': 1.0}, {}, 0.0, 'BINARY')],
[BinaryQuadraticModel({'item_5_in_bin_0': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_5_in_bin_1': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_5_in_bin_2': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_5_in_bin_3': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_5_in_bin_4': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_5_in_bin_5': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_5_in_bin_6': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_5_in_bin_7': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_5_in_bin_8': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_5_in_bin_9': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_5_in_bin_10': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_5_in_bin_11': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_5_in_bin_12': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_5_in_bin_13': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_5_in_bin_14': 1.0}, {}, 0.0, 'BINARY')],
[BinaryQuadraticModel({'item_6_in_bin_0': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_6_in_bin_1': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_6_in_bin_2': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_6_in_bin_3': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_6_in_bin_4': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_6_in_bin_5': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_6_in_bin_6': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_6_in_bin_7': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_6_in_bin_8': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_6_in_bin_9': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_6_in_bin_10': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_6_in_bin_11': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_6_in_bin_12': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_6_in_bin_13': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_6_in_bin_14': 1.0}, {}, 0.0, 'BINARY')],
[BinaryQuadraticModel({'item_7_in_bin_0': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_7_in_bin_1': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_7_in_bin_2': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_7_in_bin_3': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_7_in_bin_4': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_7_in_bin_5': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_7_in_bin_6': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_7_in_bin_7': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_7_in_bin_8': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_7_in_bin_9': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_7_in_bin_10': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_7_in_bin_11': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_7_in_bin_12': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_7_in_bin_13': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_7_in_bin_14': 1.0}, {}, 0.0, 'BINARY')],
[BinaryQuadraticModel({'item_8_in_bin_0': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_8_in_bin_1': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_8_in_bin_2': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_8_in_bin_3': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_8_in_bin_4': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_8_in_bin_5': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_8_in_bin_6': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_8_in_bin_7': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_8_in_bin_8': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_8_in_bin_9': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_8_in_bin_10': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_8_in_bin_11': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_8_in_bin_12': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_8_in_bin_13': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_8_in_bin_14': 1.0}, {}, 0.0, 'BINARY')],
[BinaryQuadraticModel({'item_9_in_bin_0': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_9_in_bin_1': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_9_in_bin_2': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_9_in_bin_3': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_9_in_bin_4': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_9_in_bin_5': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_9_in_bin_6': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_9_in_bin_7': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_9_in_bin_8': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_9_in_bin_9': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_9_in_bin_10': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_9_in_bin_11': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_9_in_bin_12': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_9_in_bin_13': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_9_in_bin_14': 1.0}, {}, 0.0, 'BINARY')],
[BinaryQuadraticModel({'item_10_in_bin_0': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_10_in_bin_1': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_10_in_bin_2': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_10_in_bin_3': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_10_in_bin_4': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_10_in_bin_5': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_10_in_bin_6': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_10_in_bin_7': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_10_in_bin_8': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_10_in_bin_9': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_10_in_bin_10': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_10_in_bin_11': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_10_in_bin_12': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_10_in_bin_13': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_10_in_bin_14': 1.0}, {}, 0.0, 'BINARY')],
[BinaryQuadraticModel({'item_11_in_bin_0': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_11_in_bin_1': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_11_in_bin_2': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_11_in_bin_3': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_11_in_bin_4': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_11_in_bin_5': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_11_in_bin_6': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_11_in_bin_7': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_11_in_bin_8': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_11_in_bin_9': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_11_in_bin_10': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_11_in_bin_11': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_11_in_bin_12': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_11_in_bin_13': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_11_in_bin_14': 1.0}, {}, 0.0, 'BINARY')],
[BinaryQuadraticModel({'item_12_in_bin_0': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_12_in_bin_1': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_12_in_bin_2': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_12_in_bin_3': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_12_in_bin_4': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_12_in_bin_5': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_12_in_bin_6': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_12_in_bin_7': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_12_in_bin_8': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_12_in_bin_9': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_12_in_bin_10': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_12_in_bin_11': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_12_in_bin_12': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_12_in_bin_13': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_12_in_bin_14': 1.0}, {}, 0.0, 'BINARY')],
[BinaryQuadraticModel({'item_13_in_bin_0': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_13_in_bin_1': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_13_in_bin_2': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_13_in_bin_3': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_13_in_bin_4': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_13_in_bin_5': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_13_in_bin_6': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_13_in_bin_7': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_13_in_bin_8': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_13_in_bin_9': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_13_in_bin_10': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_13_in_bin_11': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_13_in_bin_12': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_13_in_bin_13': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_13_in_bin_14': 1.0}, {}, 0.0, 'BINARY')],
[BinaryQuadraticModel({'item_14_in_bin_0': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_14_in_bin_1': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_14_in_bin_2': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_14_in_bin_3': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_14_in_bin_4': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_14_in_bin_5': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_14_in_bin_6': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_14_in_bin_7': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_14_in_bin_8': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_14_in_bin_9': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_14_in_bin_10': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_14_in_bin_11': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_14_in_bin_12': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_14_in_bin_13': 1.0}, {}, 0.0, 'BINARY'),
BinaryQuadraticModel({'item_14_in_bin_14': 1.0}, {}, 0.0, 'BINARY')]]
Ahora añadimos la restricción anterior para cada uno de los i_es
for i in range(num_items):
one_bin_per_item = cqm.add_constraint(sum(item_in_bin[i]) == 1, label=f'item_placing_{i}')
Otra restricción a tener en cuenta es que la capacidad de cada contenedor o bin es limitada y entonces para cada j se tiene que se debe cumplir:
es decir:
for j in range(num_items):
bin_up_to_capacity = cqm.add_constraint(
sum(weights[i] * item_in_bin[i][j] for i in range(num_items)) - bin_used[j] * bin_capacity <= 0,
label=f'capacity_bin_{j}')
len(cqm.variables)
240
25. Resolución del problema.#
from dwave.system import LeapHybridCQMSampler
sampler = LeapHybridCQMSampler()
sampleset = sampler.sample_cqm(cqm,
time_limit=180,
label="SDK Examples - Bin Packing")
# Nos quedamos con las soluciones factibles
feasible_sampleset = sampleset.filter(lambda row: row.is_feasible)
if len(feasible_sampleset):
best = feasible_sampleset.first
print("{} feasible solutions of {}.".format(
len(feasible_sampleset), len(sampleset)))
127 feasible solutions of 131.
best
Sample(sample={'bin_used_0': 0.0, 'bin_used_1': 0.0, 'bin_used_10': 0.0, 'bin_used_11': 1.0, 'bin_used_12': 0.0, 'bin_used_13': 0.0, 'bin_used_14': 0.0, 'bin_used_2': 0.0, 'bin_used_3': 0.0, 'bin_used_4': 0.0, 'bin_used_5': 1.0, 'bin_used_6': 0.0, 'bin_used_7': 0.0, 'bin_used_8': 0.0, 'bin_used_9': 0.0, 'item_0_in_bin_0': 0.0, 'item_0_in_bin_1': 0.0, 'item_0_in_bin_10': 0.0, 'item_0_in_bin_11': 1.0, 'item_0_in_bin_12': 0.0, 'item_0_in_bin_13': 0.0, 'item_0_in_bin_14': 0.0, 'item_0_in_bin_2': 0.0, 'item_0_in_bin_3': 0.0, 'item_0_in_bin_4': 0.0, 'item_0_in_bin_5': 0.0, 'item_0_in_bin_6': 0.0, 'item_0_in_bin_7': 0.0, 'item_0_in_bin_8': 0.0, 'item_0_in_bin_9': 0.0, 'item_10_in_bin_0': 0.0, 'item_10_in_bin_1': 0.0, 'item_10_in_bin_10': 0.0, 'item_10_in_bin_11': 0.0, 'item_10_in_bin_12': 0.0, 'item_10_in_bin_13': 0.0, 'item_10_in_bin_14': 0.0, 'item_10_in_bin_2': 0.0, 'item_10_in_bin_3': 0.0, 'item_10_in_bin_4': 0.0, 'item_10_in_bin_5': 1.0, 'item_10_in_bin_6': 0.0, 'item_10_in_bin_7': 0.0, 'item_10_in_bin_8': 0.0, 'item_10_in_bin_9': 0.0, 'item_11_in_bin_0': 0.0, 'item_11_in_bin_1': 0.0, 'item_11_in_bin_10': 0.0, 'item_11_in_bin_11': 0.0, 'item_11_in_bin_12': 0.0, 'item_11_in_bin_13': 0.0, 'item_11_in_bin_14': 0.0, 'item_11_in_bin_2': 0.0, 'item_11_in_bin_3': 0.0, 'item_11_in_bin_4': 0.0, 'item_11_in_bin_5': 1.0, 'item_11_in_bin_6': 0.0, 'item_11_in_bin_7': 0.0, 'item_11_in_bin_8': 0.0, 'item_11_in_bin_9': 0.0, 'item_12_in_bin_0': 0.0, 'item_12_in_bin_1': 0.0, 'item_12_in_bin_10': 0.0, 'item_12_in_bin_11': 0.0, 'item_12_in_bin_12': 0.0, 'item_12_in_bin_13': 0.0, 'item_12_in_bin_14': 0.0, 'item_12_in_bin_2': 0.0, 'item_12_in_bin_3': 0.0, 'item_12_in_bin_4': 0.0, 'item_12_in_bin_5': 1.0, 'item_12_in_bin_6': 0.0, 'item_12_in_bin_7': 0.0, 'item_12_in_bin_8': 0.0, 'item_12_in_bin_9': 0.0, 'item_13_in_bin_0': 0.0, 'item_13_in_bin_1': 0.0, 'item_13_in_bin_10': 0.0, 'item_13_in_bin_11': 1.0, 'item_13_in_bin_12': 0.0, 'item_13_in_bin_13': 0.0, 'item_13_in_bin_14': 0.0, 'item_13_in_bin_2': 0.0, 'item_13_in_bin_3': 0.0, 'item_13_in_bin_4': 0.0, 'item_13_in_bin_5': 0.0, 'item_13_in_bin_6': 0.0, 'item_13_in_bin_7': 0.0, 'item_13_in_bin_8': 0.0, 'item_13_in_bin_9': 0.0, 'item_14_in_bin_0': 0.0, 'item_14_in_bin_1': 0.0, 'item_14_in_bin_10': 0.0, 'item_14_in_bin_11': 1.0, 'item_14_in_bin_12': 0.0, 'item_14_in_bin_13': 0.0, 'item_14_in_bin_14': 0.0, 'item_14_in_bin_2': 0.0, 'item_14_in_bin_3': 0.0, 'item_14_in_bin_4': 0.0, 'item_14_in_bin_5': 0.0, 'item_14_in_bin_6': 0.0, 'item_14_in_bin_7': 0.0, 'item_14_in_bin_8': 0.0, 'item_14_in_bin_9': 0.0, 'item_1_in_bin_0': 0.0, 'item_1_in_bin_1': 0.0, 'item_1_in_bin_10': 0.0, 'item_1_in_bin_11': 0.0, 'item_1_in_bin_12': 0.0, 'item_1_in_bin_13': 0.0, 'item_1_in_bin_14': 0.0, 'item_1_in_bin_2': 0.0, 'item_1_in_bin_3': 0.0, 'item_1_in_bin_4': 0.0, 'item_1_in_bin_5': 1.0, 'item_1_in_bin_6': 0.0, 'item_1_in_bin_7': 0.0, 'item_1_in_bin_8': 0.0, 'item_1_in_bin_9': 0.0, 'item_2_in_bin_0': 0.0, 'item_2_in_bin_1': 0.0, 'item_2_in_bin_10': 0.0, 'item_2_in_bin_11': 1.0, 'item_2_in_bin_12': 0.0, 'item_2_in_bin_13': 0.0, 'item_2_in_bin_14': 0.0, 'item_2_in_bin_2': 0.0, 'item_2_in_bin_3': 0.0, 'item_2_in_bin_4': 0.0, 'item_2_in_bin_5': 0.0, 'item_2_in_bin_6': 0.0, 'item_2_in_bin_7': 0.0, 'item_2_in_bin_8': 0.0, 'item_2_in_bin_9': 0.0, 'item_3_in_bin_0': 0.0, 'item_3_in_bin_1': 0.0, 'item_3_in_bin_10': 0.0, 'item_3_in_bin_11': 1.0, 'item_3_in_bin_12': 0.0, 'item_3_in_bin_13': 0.0, 'item_3_in_bin_14': 0.0, 'item_3_in_bin_2': 0.0, 'item_3_in_bin_3': 0.0, 'item_3_in_bin_4': 0.0, 'item_3_in_bin_5': 0.0, 'item_3_in_bin_6': 0.0, 'item_3_in_bin_7': 0.0, 'item_3_in_bin_8': 0.0, 'item_3_in_bin_9': 0.0, 'item_4_in_bin_0': 0.0, 'item_4_in_bin_1': 0.0, 'item_4_in_bin_10': 0.0, 'item_4_in_bin_11': 0.0, 'item_4_in_bin_12': 0.0, 'item_4_in_bin_13': 0.0, 'item_4_in_bin_14': 0.0, 'item_4_in_bin_2': 0.0, 'item_4_in_bin_3': 0.0, 'item_4_in_bin_4': 0.0, 'item_4_in_bin_5': 1.0, 'item_4_in_bin_6': 0.0, 'item_4_in_bin_7': 0.0, 'item_4_in_bin_8': 0.0, 'item_4_in_bin_9': 0.0, 'item_5_in_bin_0': 0.0, 'item_5_in_bin_1': 0.0, 'item_5_in_bin_10': 0.0, 'item_5_in_bin_11': 0.0, 'item_5_in_bin_12': 0.0, 'item_5_in_bin_13': 0.0, 'item_5_in_bin_14': 0.0, 'item_5_in_bin_2': 0.0, 'item_5_in_bin_3': 0.0, 'item_5_in_bin_4': 0.0, 'item_5_in_bin_5': 1.0, 'item_5_in_bin_6': 0.0, 'item_5_in_bin_7': 0.0, 'item_5_in_bin_8': 0.0, 'item_5_in_bin_9': 0.0, 'item_6_in_bin_0': 0.0, 'item_6_in_bin_1': 0.0, 'item_6_in_bin_10': 0.0, 'item_6_in_bin_11': 0.0, 'item_6_in_bin_12': 0.0, 'item_6_in_bin_13': 0.0, 'item_6_in_bin_14': 0.0, 'item_6_in_bin_2': 0.0, 'item_6_in_bin_3': 0.0, 'item_6_in_bin_4': 0.0, 'item_6_in_bin_5': 1.0, 'item_6_in_bin_6': 0.0, 'item_6_in_bin_7': 0.0, 'item_6_in_bin_8': 0.0, 'item_6_in_bin_9': 0.0, 'item_7_in_bin_0': 0.0, 'item_7_in_bin_1': 0.0, 'item_7_in_bin_10': 0.0, 'item_7_in_bin_11': 1.0, 'item_7_in_bin_12': 0.0, 'item_7_in_bin_13': 0.0, 'item_7_in_bin_14': 0.0, 'item_7_in_bin_2': 0.0, 'item_7_in_bin_3': 0.0, 'item_7_in_bin_4': 0.0, 'item_7_in_bin_5': 0.0, 'item_7_in_bin_6': 0.0, 'item_7_in_bin_7': 0.0, 'item_7_in_bin_8': 0.0, 'item_7_in_bin_9': 0.0, 'item_8_in_bin_0': 0.0, 'item_8_in_bin_1': 0.0, 'item_8_in_bin_10': 0.0, 'item_8_in_bin_11': 0.0, 'item_8_in_bin_12': 0.0, 'item_8_in_bin_13': 0.0, 'item_8_in_bin_14': 0.0, 'item_8_in_bin_2': 0.0, 'item_8_in_bin_3': 0.0, 'item_8_in_bin_4': 0.0, 'item_8_in_bin_5': 1.0, 'item_8_in_bin_6': 0.0, 'item_8_in_bin_7': 0.0, 'item_8_in_bin_8': 0.0, 'item_8_in_bin_9': 0.0, 'item_9_in_bin_0': 0.0, 'item_9_in_bin_1': 0.0, 'item_9_in_bin_10': 0.0, 'item_9_in_bin_11': 1.0, 'item_9_in_bin_12': 0.0, 'item_9_in_bin_13': 0.0, 'item_9_in_bin_14': 0.0, 'item_9_in_bin_2': 0.0, 'item_9_in_bin_3': 0.0, 'item_9_in_bin_4': 0.0, 'item_9_in_bin_5': 0.0, 'item_9_in_bin_6': 0.0, 'item_9_in_bin_7': 0.0, 'item_9_in_bin_8': 0.0, 'item_9_in_bin_9': 0.0}, energy=2.0, num_occurrences=1, is_satisfied=array([ True, True, True, True, True, True, True, True, True,
True, True, True, True, True, True, True, True, True,
True, True, True, True, True, True, True, True, True,
True, True, True]), is_feasible=True)
best.sample.items()
dict_items([('bin_used_0', 0.0), ('bin_used_1', 0.0), ('bin_used_10', 0.0), ('bin_used_11', 1.0), ('bin_used_12', 0.0), ('bin_used_13', 0.0), ('bin_used_14', 0.0), ('bin_used_2', 0.0), ('bin_used_3', 0.0), ('bin_used_4', 0.0), ('bin_used_5', 1.0), ('bin_used_6', 0.0), ('bin_used_7', 0.0), ('bin_used_8', 0.0), ('bin_used_9', 0.0), ('item_0_in_bin_0', 0.0), ('item_0_in_bin_1', 0.0), ('item_0_in_bin_10', 0.0), ('item_0_in_bin_11', 1.0), ('item_0_in_bin_12', 0.0), ('item_0_in_bin_13', 0.0), ('item_0_in_bin_14', 0.0), ('item_0_in_bin_2', 0.0), ('item_0_in_bin_3', 0.0), ('item_0_in_bin_4', 0.0), ('item_0_in_bin_5', 0.0), ('item_0_in_bin_6', 0.0), ('item_0_in_bin_7', 0.0), ('item_0_in_bin_8', 0.0), ('item_0_in_bin_9', 0.0), ('item_10_in_bin_0', 0.0), ('item_10_in_bin_1', 0.0), ('item_10_in_bin_10', 0.0), ('item_10_in_bin_11', 0.0), ('item_10_in_bin_12', 0.0), ('item_10_in_bin_13', 0.0), ('item_10_in_bin_14', 0.0), ('item_10_in_bin_2', 0.0), ('item_10_in_bin_3', 0.0), ('item_10_in_bin_4', 0.0), ('item_10_in_bin_5', 1.0), ('item_10_in_bin_6', 0.0), ('item_10_in_bin_7', 0.0), ('item_10_in_bin_8', 0.0), ('item_10_in_bin_9', 0.0), ('item_11_in_bin_0', 0.0), ('item_11_in_bin_1', 0.0), ('item_11_in_bin_10', 0.0), ('item_11_in_bin_11', 0.0), ('item_11_in_bin_12', 0.0), ('item_11_in_bin_13', 0.0), ('item_11_in_bin_14', 0.0), ('item_11_in_bin_2', 0.0), ('item_11_in_bin_3', 0.0), ('item_11_in_bin_4', 0.0), ('item_11_in_bin_5', 1.0), ('item_11_in_bin_6', 0.0), ('item_11_in_bin_7', 0.0), ('item_11_in_bin_8', 0.0), ('item_11_in_bin_9', 0.0), ('item_12_in_bin_0', 0.0), ('item_12_in_bin_1', 0.0), ('item_12_in_bin_10', 0.0), ('item_12_in_bin_11', 0.0), ('item_12_in_bin_12', 0.0), ('item_12_in_bin_13', 0.0), ('item_12_in_bin_14', 0.0), ('item_12_in_bin_2', 0.0), ('item_12_in_bin_3', 0.0), ('item_12_in_bin_4', 0.0), ('item_12_in_bin_5', 1.0), ('item_12_in_bin_6', 0.0), ('item_12_in_bin_7', 0.0), ('item_12_in_bin_8', 0.0), ('item_12_in_bin_9', 0.0), ('item_13_in_bin_0', 0.0), ('item_13_in_bin_1', 0.0), ('item_13_in_bin_10', 0.0), ('item_13_in_bin_11', 1.0), ('item_13_in_bin_12', 0.0), ('item_13_in_bin_13', 0.0), ('item_13_in_bin_14', 0.0), ('item_13_in_bin_2', 0.0), ('item_13_in_bin_3', 0.0), ('item_13_in_bin_4', 0.0), ('item_13_in_bin_5', 0.0), ('item_13_in_bin_6', 0.0), ('item_13_in_bin_7', 0.0), ('item_13_in_bin_8', 0.0), ('item_13_in_bin_9', 0.0), ('item_14_in_bin_0', 0.0), ('item_14_in_bin_1', 0.0), ('item_14_in_bin_10', 0.0), ('item_14_in_bin_11', 1.0), ('item_14_in_bin_12', 0.0), ('item_14_in_bin_13', 0.0), ('item_14_in_bin_14', 0.0), ('item_14_in_bin_2', 0.0), ('item_14_in_bin_3', 0.0), ('item_14_in_bin_4', 0.0), ('item_14_in_bin_5', 0.0), ('item_14_in_bin_6', 0.0), ('item_14_in_bin_7', 0.0), ('item_14_in_bin_8', 0.0), ('item_14_in_bin_9', 0.0), ('item_1_in_bin_0', 0.0), ('item_1_in_bin_1', 0.0), ('item_1_in_bin_10', 0.0), ('item_1_in_bin_11', 0.0), ('item_1_in_bin_12', 0.0), ('item_1_in_bin_13', 0.0), ('item_1_in_bin_14', 0.0), ('item_1_in_bin_2', 0.0), ('item_1_in_bin_3', 0.0), ('item_1_in_bin_4', 0.0), ('item_1_in_bin_5', 1.0), ('item_1_in_bin_6', 0.0), ('item_1_in_bin_7', 0.0), ('item_1_in_bin_8', 0.0), ('item_1_in_bin_9', 0.0), ('item_2_in_bin_0', 0.0), ('item_2_in_bin_1', 0.0), ('item_2_in_bin_10', 0.0), ('item_2_in_bin_11', 1.0), ('item_2_in_bin_12', 0.0), ('item_2_in_bin_13', 0.0), ('item_2_in_bin_14', 0.0), ('item_2_in_bin_2', 0.0), ('item_2_in_bin_3', 0.0), ('item_2_in_bin_4', 0.0), ('item_2_in_bin_5', 0.0), ('item_2_in_bin_6', 0.0), ('item_2_in_bin_7', 0.0), ('item_2_in_bin_8', 0.0), ('item_2_in_bin_9', 0.0), ('item_3_in_bin_0', 0.0), ('item_3_in_bin_1', 0.0), ('item_3_in_bin_10', 0.0), ('item_3_in_bin_11', 1.0), ('item_3_in_bin_12', 0.0), ('item_3_in_bin_13', 0.0), ('item_3_in_bin_14', 0.0), ('item_3_in_bin_2', 0.0), ('item_3_in_bin_3', 0.0), ('item_3_in_bin_4', 0.0), ('item_3_in_bin_5', 0.0), ('item_3_in_bin_6', 0.0), ('item_3_in_bin_7', 0.0), ('item_3_in_bin_8', 0.0), ('item_3_in_bin_9', 0.0), ('item_4_in_bin_0', 0.0), ('item_4_in_bin_1', 0.0), ('item_4_in_bin_10', 0.0), ('item_4_in_bin_11', 0.0), ('item_4_in_bin_12', 0.0), ('item_4_in_bin_13', 0.0), ('item_4_in_bin_14', 0.0), ('item_4_in_bin_2', 0.0), ('item_4_in_bin_3', 0.0), ('item_4_in_bin_4', 0.0), ('item_4_in_bin_5', 1.0), ('item_4_in_bin_6', 0.0), ('item_4_in_bin_7', 0.0), ('item_4_in_bin_8', 0.0), ('item_4_in_bin_9', 0.0), ('item_5_in_bin_0', 0.0), ('item_5_in_bin_1', 0.0), ('item_5_in_bin_10', 0.0), ('item_5_in_bin_11', 0.0), ('item_5_in_bin_12', 0.0), ('item_5_in_bin_13', 0.0), ('item_5_in_bin_14', 0.0), ('item_5_in_bin_2', 0.0), ('item_5_in_bin_3', 0.0), ('item_5_in_bin_4', 0.0), ('item_5_in_bin_5', 1.0), ('item_5_in_bin_6', 0.0), ('item_5_in_bin_7', 0.0), ('item_5_in_bin_8', 0.0), ('item_5_in_bin_9', 0.0), ('item_6_in_bin_0', 0.0), ('item_6_in_bin_1', 0.0), ('item_6_in_bin_10', 0.0), ('item_6_in_bin_11', 0.0), ('item_6_in_bin_12', 0.0), ('item_6_in_bin_13', 0.0), ('item_6_in_bin_14', 0.0), ('item_6_in_bin_2', 0.0), ('item_6_in_bin_3', 0.0), ('item_6_in_bin_4', 0.0), ('item_6_in_bin_5', 1.0), ('item_6_in_bin_6', 0.0), ('item_6_in_bin_7', 0.0), ('item_6_in_bin_8', 0.0), ('item_6_in_bin_9', 0.0), ('item_7_in_bin_0', 0.0), ('item_7_in_bin_1', 0.0), ('item_7_in_bin_10', 0.0), ('item_7_in_bin_11', 1.0), ('item_7_in_bin_12', 0.0), ('item_7_in_bin_13', 0.0), ('item_7_in_bin_14', 0.0), ('item_7_in_bin_2', 0.0), ('item_7_in_bin_3', 0.0), ('item_7_in_bin_4', 0.0), ('item_7_in_bin_5', 0.0), ('item_7_in_bin_6', 0.0), ('item_7_in_bin_7', 0.0), ('item_7_in_bin_8', 0.0), ('item_7_in_bin_9', 0.0), ('item_8_in_bin_0', 0.0), ('item_8_in_bin_1', 0.0), ('item_8_in_bin_10', 0.0), ('item_8_in_bin_11', 0.0), ('item_8_in_bin_12', 0.0), ('item_8_in_bin_13', 0.0), ('item_8_in_bin_14', 0.0), ('item_8_in_bin_2', 0.0), ('item_8_in_bin_3', 0.0), ('item_8_in_bin_4', 0.0), ('item_8_in_bin_5', 1.0), ('item_8_in_bin_6', 0.0), ('item_8_in_bin_7', 0.0), ('item_8_in_bin_8', 0.0), ('item_8_in_bin_9', 0.0), ('item_9_in_bin_0', 0.0), ('item_9_in_bin_1', 0.0), ('item_9_in_bin_10', 0.0), ('item_9_in_bin_11', 1.0), ('item_9_in_bin_12', 0.0), ('item_9_in_bin_13', 0.0), ('item_9_in_bin_14', 0.0), ('item_9_in_bin_2', 0.0), ('item_9_in_bin_3', 0.0), ('item_9_in_bin_4', 0.0), ('item_9_in_bin_5', 0.0), ('item_9_in_bin_6', 0.0), ('item_9_in_bin_7', 0.0), ('item_9_in_bin_8', 0.0), ('item_9_in_bin_9', 0.0)])
selected_bins = [key for key, val in best.sample.items() if 'bin_used' in key and val]
print("{} bins are used.".format(len(selected_bins)))
2 bins are used.
def get_indices(name):
return [int(digs) for digs in name.split('_') if digs.isdigit()]
for bin in selected_bins:
in_bin = [key for key, val in best.sample.items() if
"_in_bin" in key and
get_indices(key)[1] == get_indices(bin)[0]
and val]
b = get_indices(in_bin[0])[1]
w = [weights[get_indices(item)[0]] for item in in_bin]
print("Bin {} tiene pesos {} que suman un total de {}.".format(b, w, sum(w)))
Bin 11 tiene pesos [4, 6, 4, 5, 3, 4, 4] que suman un total de 30.
Bin 5 tiene pesos [4, 6, 6, 3, 4, 6, 6, 6] que suman un total de 41.
26. Optimizando Código#
En este apartado vamos a ver cómo podríamos mejorar el código anterior para obtener una mejora importante en el rendimiento de esas instrucciones.
Por simplicidad, pero sin pérdida de generalidad, vamos a suponer que cada contenedor o bin,tiene una capacidad de 1. Un problema de estas características con n items, se convierte en un CQM de n*(n+1) variables binarias. Comenzamos definiendo el número de items y los pesos
import numpy as np
num_items = 100 # results in 10100 binary variables
weights = np.random.default_rng(42).random(num_items)
Entonces la primera implementación de problema, sería la siguiente:
import typing
import dimod
def bin_packing(weights: typing.Sequence[float]) -> dimod.ConstrainedQuadraticModel:
"""Generate a bin packing problem as a constrained quadratic model."""
n = len(weights)
# y_j indicates that bin j is used
y = [dimod.Binary(f'y_{j}') for j in range(n)]
# x_i,j indicates that item i is put in bin j
x = [[dimod.Binary(f'x_{i},{j}') for j in range(n)] for i in range(n)]
cqm = dimod.ConstrainedQuadraticModel()
# minimize the number of bins used
cqm.set_objective(sum(y))
# each item can go in only one bin
for i in range(n):
cqm.add_constraint(sum(x[i]) == 1, label=f'item_placing_{i}')
# each bin has a capacity that must be respected
for j in range(n):
cqm.add_constraint(sum(weights[i] * x[i][j] for i in range(n)) - y[j] <= 0,
label=f'capacity_bin_{j}')
return cqm
%timeit bin_packing(weights)
793 ms ± 30.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
Lo anterior es la implementación con la función sum(), que suele ser más lenta que si se utiliza quicksum()
import typing
import dimod
def bin_packing(weights: typing.Sequence[float]) -> dimod.ConstrainedQuadraticModel:
"""Generate a bin packing problem as a constrained quadratic model."""
n = len(weights)
# y_j indicates that bin j is used
y = [dimod.Binary(f'y_{j}') for j in range(n)]
# x_i,j indicates that item i is put in bin j
x = [[dimod.Binary(f'x_{i},{j}') for j in range(n)] for i in range(n)]
cqm = dimod.ConstrainedQuadraticModel()
# minimize the number of bins used
cqm.set_objective(dimod.quicksum(y))
# each item can only go in one bin
for i in range(n):
cqm.add_constraint(dimod.quicksum(x[i]) == 1, label=f'item_placing_{i}')
# each bin has a capacity that must be respected
for j in range(n):
cqm.add_constraint(dimod.quicksum(weights[i] * x[i][j] for i in range(n)) - y[j] <= 0,
label=f'capacity_bin_{j}')
return cqm
%timeit bin_packing(weights)
552 ms ± 6.76 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
Puede conseguir una mejora aún mayor si omite por completo la construcción simbólica y trabaja directamente con etiquetas de variables y un único objeto BQM.
El siguiente pequeño ejemplo demuestra la diferencia de rendimiento
import dimod
def make_bqm_symbolic(num_variables: int) -> dimod.BinaryQuadraticModel:
return dimod.quicksum(2*dimod.Binary(v) for v in range(num_variables))
def make_bqm_labels(num_variables: int) -> dimod.BinaryQuadraticModel:
bqm = dimod.BinaryQuadraticModel('BINARY')
bqm.add_linear_from((v, 2) for v in range(num_variables))
return bqm
%timeit make_bqm_symbolic(1000)
31.9 ms ± 2.52 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit make_bqm_labels(1000)
390 µs ± 2.03 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
Aplicamos esta misma construcción de modelo al ejemplo de binpacking:
import typing
import dimod
def bin_packing(weights: typing.Sequence[float]) -> dimod.ConstrainedQuadraticModel:
"""Generate a bin packing problem as a constrained quadratic model."""
n = len(weights)
# y_j indicates that bin j is used
y_labels = [f'y_{j}' for j in range(n)]
# x_i,j indicates that item i is put in bin j
x_labels = [[f'x_{i},{j}' for j in range(n)] for i in range(n)]
cqm = dimod.ConstrainedQuadraticModel()
# minimize the number of bins used
objective = dimod.QuadraticModel()
objective.add_linear_from(((v, 1) for v in y_labels), default_vartype='BINARY')
#objective.add_linear(((v, 1) for v in y_labels), default_vartype='BINARY')
cqm.set_objective(objective)
# each item can only go in one bin
for i in range(n):
lhs = dimod.QuadraticModel()
lhs.add_linear_from(((v, 1) for v in x_labels[i]), default_vartype='BINARY')
#lhs.add_linear(((v, 1) for v in x_labels[i]), default_vartype='BINARY')
cqm.add_constraint_from_model(lhs, rhs=1, sense='==', label=f'item_placing_{i}')
# each bin has a capacity that must be respected
for j in range(n):
lhs = dimod.QuadraticModel()
lhs.add_linear_from(((x_labels[i][j], weights[i]) for i in range(n)), default_vartype='BINARY')
#lhs.add_linear(((x_labels[i][j], weights[i]) for i in range(n)), default_vartype='BINARY')
lhs.add_linear(y_labels[j], -1, default_vartype='BINARY')
cqm.add_constraint_from_model(lhs, rhs=0, sense='<=', label=f'capacity_bin_{j}')
return cqm
%timeit bin_packing(weights)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
~\AppData\Local\Temp\ipykernel_15812\14838865.py in <module>
----> 1 get_ipython().run_line_magic('timeit', 'bin_packing(weights)')
d:\mistrabajos\dwaveocean\ocean\lib\site-packages\IPython\core\interactiveshell.py in run_line_magic(self, magic_name, line, _stack_depth)
2362 kwargs['local_ns'] = self.get_local_scope(stack_depth)
2363 with self.builtin_trap:
-> 2364 result = fn(*args, **kwargs)
2365 return result
2366
d:\mistrabajos\dwaveocean\ocean\lib\site-packages\decorator.py in fun(*args, **kw)
230 if not kwsyntax:
231 args, kw = fix(args, kw, sig)
--> 232 return caller(func, *(extras + args), **kw)
233 fun.__name__ = func.__name__
234 fun.__doc__ = func.__doc__
d:\mistrabajos\dwaveocean\ocean\lib\site-packages\IPython\core\magic.py in <lambda>(f, *a, **k)
185 # but it's overkill for just that one bit of state.
186 def magic_deco(arg):
--> 187 call = lambda f, *a, **k: f(*a, **k)
188
189 if callable(arg):
d:\mistrabajos\dwaveocean\ocean\lib\site-packages\IPython\core\magics\execution.py in timeit(self, line, cell, local_ns)
1178 for index in range(0, 10):
1179 number = 10 ** index
-> 1180 time_number = timer.timeit(number)
1181 if time_number >= 0.2:
1182 break
d:\mistrabajos\dwaveocean\ocean\lib\site-packages\IPython\core\magics\execution.py in timeit(self, number)
167 gc.disable()
168 try:
--> 169 timing = self.inner(it, self.timer)
170 finally:
171 if gcold:
<magic-timeit> in inner(_it, _timer)
~\AppData\Local\Temp\ipykernel_15812\1737132310.py in bin_packing(weights)
19 # minimize the number of bins used
20 objective = dimod.QuadraticModel()
---> 21 objective.add_linear_from(((v, 1) for v in y_labels), default_vartype='BINARY')
22 #objective.add_linear(((v, 1) for v in y_labels), default_vartype='BINARY')
23 cqm.set_objective(objective)
TypeError: add_linear_from() got an unexpected keyword argument 'default_vartype'
Como