Skip to content

Commit

Permalink
Added the "Almost Squares in Almost Squares" 2D Bin Packing Instances
Browse files Browse the repository at this point in the history
All of these instances have the optimum 1 bin.
  • Loading branch information
thomasWeise committed Dec 20, 2023
1 parent 67eaf12 commit 3ab6b82
Show file tree
Hide file tree
Showing 9 changed files with 199 additions and 133 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ In the package [`moptipyapps.binpacking2d`](https://thomasweise.github.io/moptip
Bin packing is a classical domain from Operations Research.
The goal is to pack objects into containers, the so-called bins.
We address [two-dimensional rectangular bin packing](https://thomasweise.github.io/moptipyapps/moptipyapps.binpacking2d.html#module-moptipyapps.binpacking2d).
We provide the bin packing [instances](https://thomasweise.github.io/moptipyapps/moptipyapps.binpacking2d.html#module-moptipyapps.binpacking2d.instance) from [2DPackLib](https://site.unibo.it/operations-research/en/research/2dpacklib) as [resources](https://thomasweise.github.io/moptipyapps/moptipyapps.binpacking2d.html#moptipyapps.binpacking2d.instance.Instance.from_resource) together with [this package](https://thomasweise.github.io/moptipyapps/moptipyapps.binpacking2d.html#module-moptipyapps.binpacking2d).
We provide the bin packing [instances](https://thomasweise.github.io/moptipyapps/moptipyapps.binpacking2d.html#module-moptipyapps.binpacking2d.instance) from [2DPackLib](https://site.unibo.it/operations-research/en/research/2dpacklib) as [resources](https://thomasweise.github.io/moptipyapps/moptipyapps.binpacking2d.html#moptipyapps.binpacking2d.instance.Instance.from_resource) together with [this package](https://thomasweise.github.io/moptipyapps/moptipyapps.binpacking2d.html#module-moptipyapps.binpacking2d) as well as the four non-trivial "[Almost Squares in Almost Squares](https://hdl.handle.net/11245/1.545914)" instances.
Each such instances defines a set of `n_different_items` objects `Oi` with `i` from `1..n_different_objects`.
Each object `Oi` is a rectangle with a given width and height.
The object occur is a given multiplicity `repetitions(O_i)`, i.e., either only once or multiple times.
Expand Down
242 changes: 131 additions & 111 deletions moptipyapps/binpacking2d/instance.py

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ a40;40;2750;1220;250,250,4;350,150,4;400,150,4;450,150,15;450,440;486,433,2;500,
a41;32;2750;1220;76,486,2;76,986;228,210,7;253,386;390,781,2;486,433,2;720,781,5;770,705;980,1031,2;987,705,2;1236,143,4;1263,486;1263,736,2;1467,781,2;1486,143,2;1486,303,9;1647,873;1707,531,2;1707,781;1736,310;1806,310,2;1897,473;1897,973;1903,486,6;1906,150,2;2117,725,2;2192,475;2192,992;2357,313;2357,423;2357,753,2;2357,992
a42;8;2750;1220;703,486;706,516,2;1120,486;1120,986,3;1940,320;2117,775,2;2117,875;2357,875,2
a43;11;2750;1220;228,210,2;623,426;986,433,4;987,705;1120,486,2;1181,733,4;1236,143,2;1780,740;1903,486,2;2040,320;2357,935,2
asqas03;3;5;4;2,1;3,2;4,3
asqas08;8;16;15;2,1;3,2;4,3;5,4;6,5;7,6;8,7;9,8
asqas20;20;56;55;2,1;3,2;4,3;5,4;6,5;7,6;8,7;9,8;10,9;11,10;12,11;13,12;14,13;15,14;16,15;17,16;18,17;19,18;20,19;21,20
asqas34;34;120;119;2,1;3,2;4,3;5,4;6,5;7,6;8,7;9,8;10,9;11,10;12,11;13,12;14,13;15,14;16,15;17,16;18,17;19,18;20,19;21,20;22,21;23,22;24,23;25,24;26,25;27,26;28,27;29,28;30,29;31,30;32,31;33,32;34,33;35,34
beng01;20;25;10;1,3;1,7;3,6;3,8;4,3;4,7;7,8;8,6;8,6;9,1;9,1;9,8;10,3;11,1;11,3;11,4;11,5;11,6;12,6;12,8
beng02;40;25;10;1,1;1,2;1,3;1,7;2,7;2,8;3,4;3,6;3,8;3,8;4,1;4,3;4,7;5,6;7,3;7,8;8,3;8,4;8,4;8,6;8,6;8,8;9,1;9,1;9,8;10,3;10,3;10,3;11,1;11,3;11,4;11,5;11,5;11,6;12,3;12,6;12,7;12,7;12,7;12,8
beng03;60;25;10;1,1;1,2;1,3;1,7;2,3;2,7;2,8;3,2;3,3;3,4;3,6;3,8;3,8;4,1;4,3;4,7;4,7;4,8;5,4;5,4;5,6;6,2;6,5;7,2;7,3;7,7;7,8;8,1;8,3;8,3;8,4;8,4;8,5;8,6;8,6;8,7;8,8;8,8;9,1;9,1;9,8;10,3;10,3;10,3;10,5;10,7;11,1;11,3;11,4;11,4;11,5;11,5;11,6;11,8;12,3;12,6;12,7;12,7;12,7;12,8
Expand Down
68 changes: 55 additions & 13 deletions moptipyapps/binpacking2d/make_instances.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@

import zipfile
from io import BytesIO
from math import isqrt
from os.path import dirname, exists
from typing import Callable, Final, Iterable
from typing import Any, Callable, Final, Iterable

# noinspection PyPackageRequirements
import certifi # type: ignore
Expand All @@ -34,10 +35,13 @@
Instance,
)

#: the base url for 2DPackLib
__BASE_URL: str = \
"https://site.unibo.it/operations-research/en/research/2dpacklib"

#: The base URLs of the relevant 2DPackLib instances.
__BASE_URLS: Final[Iterable[str]] = tuple(
("https://site.unibo.it/operations-research/en"
f"/research/2dpacklib/{f}.zip") for f in ["a", "beng", "class"])
f"{__BASE_URL}/{f}.zip" for f in ["a", "beng", "class"])


def download_2dpacklib_instances(
Expand Down Expand Up @@ -107,30 +111,55 @@ def __normalize_2dpacklib_inst_name(instname: str) -> str:
return instname


def join_2dpacklib_instances_to_compact(
files: Iterable[str], dest_file: str,
def append_almost_squares_strings(collector: Callable[[
tuple[str, str]], Any]) -> None:
"""
Append the strings of the almost squares instances.
:param collector: the instance collector
:return: the strings
"""
objects: list[list[int]] = [[2, 1, 1]]
size: int = 2
for small_side in range(2, 36):
big_side = small_side + 1
objects.append([big_side, small_side, 1])
size += small_side * big_side

bin_small = isqrt(size)
bin_big = bin_small + 1
if (bin_big * bin_small) == size:
iname: str = str(small_side)
iname = f"asqas{iname}" if len(iname) >= 2 else f"asqas0{iname}"
collector((iname, Instance(
iname, bin_big, bin_small, objects).to_compact_str()))


def join_instances_to_compact(
binpacklib2d_files: Iterable[str], dest_file: str,
normalizer: Callable[[str], str] = __normalize_2dpacklib_inst_name) \
-> tuple[Path, Iterable[str]]:
"""
Join all instances from a set of 2DPackLib files to one compact file.
:param files: the iterable of 2DPackLib file paths
:param binpacklib2d_files: the iterable of 2DPackLib file paths
:param dest_file: the destination file
:param normalizer: the name normalizer, i.e., a function that processes
and/or transforms an instance name
:return: the canonical destination path and the list of instance names
stored
"""
if not isinstance(files, Iterable):
raise type_error(files, "files", Iterable)
if not isinstance(binpacklib2d_files, Iterable):
raise type_error(binpacklib2d_files, "files", Iterable)
if not callable(normalizer):
raise type_error(normalizer, "normalizer", call=True)
dest_path = Path.path(dest_file)
data: Final[list[tuple[str, str]]] = []
for f in files:
inst: Instance = Instance.from_2dpacklib(Path.file(f))
for file in binpacklib2d_files:
inst: Instance = Instance.from_2dpacklib(Path.file(file))
inst.name = normalizer(inst.name)
data.append((inst.name, inst.to_compact_str()))
append_almost_squares_strings(data.append) # add the asquas instances
data.sort()
dest_path.write_all([content for _, content in data])
dest_path.enforce_file()
Expand Down Expand Up @@ -158,7 +187,7 @@ def make_2dpacklib_resource(
with TempDir.create() as temp:
files: Iterable[Path] = download_2dpacklib_instances(
dest_dir=temp, source_urls=source_urls)
return join_2dpacklib_instances_to_compact(
return join_instances_to_compact(
files, dest_path, normalizer)


Expand All @@ -178,7 +207,20 @@ def make_2dpacklib_resource(
has_space = False
rows.append(current[:-1] + ")")

print( # noqa
"#: the list of instance names of the 2DPackLib bin packing set")
cmt_strs: list[str] = (
"the the list of instance names of the 2DPackLib bin "
f"packing set downloaded from {__BASE_URL} ('a*',"
"'beng*', 'cl*') as well as the four non-trivial "
"'Almost Squares in Almost Squares' instances ('asqas*').").split()
cmt_str = "#:"
for word in cmt_strs:
if len(word) + 1 + len(cmt_str) <= 79:
cmt_str = f"{cmt_str} {word}"
else:
print(cmt_str) # noqa
cmt_str = f"#: {word}"
if len(cmt_str) > 2:
print(cmt_str) # noqa

for s in rows:
print(s) # noqa
6 changes: 3 additions & 3 deletions moptipyapps/ttp/plan_length.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@
3. if the current location != own hometown, add the travel distance back
from the current location to the hometown to the total travel length.
As penalty for the `bye` situation where no game is scheduled, we use the
twice the maximum distance between any two teams plus 1.
As penalty for the `bye` situation where no game is scheduled, we use twice
the maximum distance between any two teams plus 1.
The logic is that if a `bye` (i.e., a `0`) inserted into a game plan, it
replaces one game. Since it replaces one game, it affects up to two travels,
namely from the previous location to the game location and from the game
Expand Down Expand Up @@ -189,7 +189,7 @@ def is_always_integer(self) -> bool:

def __str__(self) -> str:
"""Get the name of this objective function."""
return "gameLength"
return "planLength"

def log_parameters_to(self, logger: KeyValueLogSection) -> None:
"""
Expand Down
2 changes: 1 addition & 1 deletion moptipyapps/version.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""An internal file with the version of the `moptipyapps` package."""
from typing import Final

__version__: Final[str] = "0.8.40"
__version__: Final[str] = "0.8.41"
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

# `moptipy` provides the basic optimization infrastructure and the spaces and
# tools that we use for optimization.
moptipy == 0.9.100
moptipy == 0.9.101

# `numpy` is needed for its efficient data structures.
numpy == 1.26.1
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ include_package_data = True
install_requires =
certifi >= 2023.7.22
defusedxml >= 0.7.1
moptipy >= 0.9.100
moptipy >= 0.9.101
numpy >= 1.26.1
numba >= 0.58.1
matplotlib >= 3.8.0
Expand Down
4 changes: 2 additions & 2 deletions tests/binpacking2d/test_binpacking2d_instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ def test_load_all_from_resources() -> None:
for name in Instance.list_resources():
check_instance(Instance.from_resource(name), name)
count += 1
if count != 553:
raise ValueError(f"Excepted 553 instances, got {count}.")
if count != 557:
raise ValueError(f"Excepted 557 instances, got {count}.")


#: These are known lower bounds for the oriented 2D Bin Packing Problem.
Expand Down

0 comments on commit 3ab6b82

Please sign in to comment.