"""
Plot a 2-dimensional packing.
Here we try out the two different variants of the improved-bottom-left
encoding. `ImprovedBottomLeftEncoding1` inserts objects one by one and moves
on to a new bin once an object doesn't fit into the current bin. It will then
never consider the filled bin again. `ImprovedBottomLeftEncoding2` always
tries all bins for any object.
We try both encodings for instance `a10` and fixed (but randomly chosen)
signed permutation as input string.
You will see that `ImprovedBottomLeftEncoding1` needs four bins, whereas
`ImprovedBottomLeftEncoding2` needs three.
In the file `binpacking2d_rls.py`, we plug `ImprovedBottomLeftEncoding2` into
a simple randomized local search. This search runs for 1024 steps and finds a
packing that only needs two bins.
"""
from time import sleep
from webbrowser import open_new_tab
import numpy as np
from moptipy.utils.nputils import rand_generator
from moptipy.utils.plot_utils import save_figure
from pycommons.io.temp import temp_dir
from pycommons.processes.caller import is_build
from moptipyapps.binpacking2d.encodings.ibl_encoding_1 import (
ImprovedBottomLeftEncoding1,
)
from moptipyapps.binpacking2d.encodings.ibl_encoding_2 import (
ImprovedBottomLeftEncoding2,
)
from moptipyapps.binpacking2d.instance import Instance
from moptipyapps.binpacking2d.packing_space import PackingSpace
from moptipyapps.binpacking2d.plot_packing import plot_packing
random = rand_generator(3) # get a random number generator
instance = Instance.from_resource("a10") # pick instance a10
space = PackingSpace(instance) # create the packing space
# We test two versions of the Improved Bottom Left Encoding
encodings = [ImprovedBottomLeftEncoding1(instance), # the 1st encoding
ImprovedBottomLeftEncoding2(instance)] # the 2nd encoding
# The data that the encoding can convert to a packing is an array with
# the same length as the total number n_items of objects to pack. Now a
# packing instance has n_different_items different items, each of which
# can occur multiple times, i.e., may occur repeatedly.
# So we include each of n_different_items item IDs exactly as often as
# it should be repeated. We sometimes include it directly and sometimes
# in the negated form, which is interpreted as a 90deg rotation by the
# encoding.
# Then, we convert the list of item IDs to a numpy array and, finally, shuffle
# the array. The encoding then inserts the items in the same sequence they
# appear in the array into bins.
# generate the data for a random packing
x_data = instance.get_standard_item_sequence()
for i, e in enumerate(x_data):
if random.integers(2) != 0:
x_data[i] = -e
x = np.array(x_data, instance.dtype) # convert the data to a numpy array
random.shuffle(x) # shuffle the data, i.e., the insertion sequence
# The packing is a two-dimensional matrix of items.
# Each row corresponds to one item. It stores the item ID, the ID of the bin
# into which the item is to be inserted, as well as the left-x, bottom-y,
# right-x, and top-y coordinates of the item.
# We now allocate one packing record for each encoding and apply the
# encodings.
ys = []
for encoding in encodings:
y = space.create() # allocate the packing
encoding.decode(x, y) # perform the encoding
space.validate(y) # check
ys.append(y)
# We can now plot the packing. We create the figures in a temp directory.
# To keep the figures, you would put an existing directory path into `td` by
# doing `from pycommons.io.path import Path; td = Path("mydir")` and not use
# the `with` block.
with temp_dir() as td: # create temporary directory `td`
files = [] # the collection of files
# Plot the packings. The default plotting includes the item ID into each
# rectangle. If enough space is there, it will also include the index of the
# item in the bin (starting at 1), and, if then there is still enough space,
# also the overall index of the item in the encoding (starting at 1).
for i, y in enumerate(ys):
fig = plot_packing(y, max_bins_per_row=2, max_rows=2)
# Save the image as svg and png.
files.extend(save_figure(
fig=fig, # store fig to a file
file_name=f"packing_plot_a10_ibl{i + 1}", # base name
dir_name=td, # store graphic in temp directory
formats=("svg", "png"))) # file types: svg and png
del fig # dispose figure
# OK, we have now generated and saved the plot in a file.
# We will open it in the web browser if we are not in a make build.
if not is_build():
for file in files: # for each file we generated
open_new_tab(f"file://{file}") # open a browser tab
sleep(10) # sleep 10 seconds (enough time for the browser to load)
# The temp directory is deleted as soon as we leave the `with` block.
# Hence, all the figures generated above as well as the experimental results
# now have disappeared.