Coverage for moptipyapps / binpacking2d / instgen / instance_space.py: 61%
59 statements
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-11 04:40 +0000
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-11 04:40 +0000
1"""An encoding that is inspired by a given instance."""
2from typing import Final
4from moptipy.api.space import Space
5from moptipy.utils.logger import KeyValueLogSection
6from pycommons.types import check_int_range, type_error
8from moptipyapps.binpacking2d.instance import IDX_HEIGHT, IDX_WIDTH, Instance
11class InstanceSpace(Space):
12 """An space structure for the instance generation problem and space."""
14 def __init__(self, source: Instance) -> None:
15 """
16 Create the space structure for the instance generation problem.
18 :param source: the source instances whose date we take as an example
19 """
20 super().__init__()
21 #: the instance name
22 self.inst_name: Final[str] = str.strip(source.name) + "n"
23 #: the target number of unique items
24 self.n_different_items: Final[int] = check_int_range(
25 source.n_different_items, "n_different_items",
26 1, 100_000)
27 #: the target number of items (including repetitions)
28 self.n_items: Final[int] = check_int_range(
29 source.n_items, "n_items", source.n_different_items,
30 1_000_000_000)
31 #: the bin width
32 self.bin_width: Final[int] = check_int_range(
33 source.bin_width, "bin_width", 1, 1_000_000_000)
34 #: the bin height
35 self.bin_height: Final[int] = check_int_range(
36 source.bin_height, "bin_height", 1, 1_000_000_000)
37 #: the minimum number of bins that this instance requires
38 self.min_bins: Final[int] = check_int_range(
39 min(source.lower_bound_bins, self.n_items), "min_bins",
40 1, 1_000_000_000)
41 #: the minimum item width
42 self.item_width_min: Final[int] = check_int_range(int(min(
43 source[:, IDX_WIDTH])), "item_width_min", 1, self.bin_width)
44 #: the maximum item width
45 self.item_width_max: Final[int] = check_int_range(int(max(
46 source[:, IDX_WIDTH])), "item_width_max", self.item_width_min,
47 self.bin_width)
48 #: the minimum item height
49 self.item_height_min: Final[int] = check_int_range(int(min(
50 source[:, IDX_HEIGHT])), "item_height_min", 1, self.bin_height)
51 #: the maximum item height
52 self.item_height_max: Final[int] = check_int_range(int(max(
53 source[:, IDX_HEIGHT])), "item_height_max", self.item_height_min,
54 self.bin_height)
55 #: the total item area
56 self.total_item_area: Final[int] = check_int_range(
57 source.total_item_area, "total_item_area", 1, 1_000_000_000)
59 def log_parameters_to(self, logger: KeyValueLogSection) -> None:
60 """
61 Log the parameters of this instance.
63 :param logger: the logger
64 """
65 super().log_parameters_to(logger)
66 logger.key_value("instName", self.inst_name)
67 logger.key_value("nItems", self.n_items)
68 logger.key_value("nDifferentItems", self.n_different_items)
69 logger.key_value("binWidth", self.bin_width)
70 logger.key_value("binHeight", self.bin_height)
71 logger.key_value("minBins", self.min_bins)
72 logger.key_value("itemWidthMin", self.item_width_min)
73 logger.key_value("itemWidthMax", self.item_width_max)
74 logger.key_value("itemHeightMin", self.item_height_min)
75 logger.key_value("itemHeightMax", self.item_height_max)
76 logger.key_value("totalItemArea", self.total_item_area)
78 def create(self) -> list[Instance]:
79 """
80 Generate a list for receiving an instance.
82 :return: the new instance list
83 """
84 return []
86 def copy(self, dest: list[Instance], source: list[Instance]) -> None:
87 """
88 Copy the instance list.
90 :param dest: the destination instance list
91 :param source: the source instance list
92 """
93 dest.clear()
94 dest.extend(source)
96 def to_str(self, x: list[Instance]) -> str: # +book
97 """
98 Convert an instance list to a string.
100 :param x: the instance list
101 :return: the string representation of x
102 """
103 return x[0].to_compact_str()
105 def from_str(self, text: str) -> list[Instance]:
106 """
107 Convert an instance string to a list with an instance.
109 :param text: the input string
110 :return: the element in the space corresponding to `text`
111 """
112 return [Instance.from_compact_str(text)]
114 def is_equal(self, x1: list[Instance], x2: list[Instance]) -> bool:
115 """
116 Check if the contents of two instances of the data structure are equal.
118 :param x1: the first instance
119 :param x2: the second instance
120 :return: `True` if the contents are equal, `False` otherwise
121 """
122 return x1 == x2
124 def validate(self, x: list[Instance]) -> None:
125 """
126 Check whether a given point in the space is valid.
128 :param x: the point
129 :raises TypeError: if the point `x` (or one of its elements, if
130 applicable) has the wrong data type
131 :raises ValueError: if the point `x` is invalid and/or simply is not
132 an element of this space
133 """
134 if list.__len__(x) != 1:
135 raise ValueError("There must be exactly one instance in x.")
136 inst: Instance = x[0]
137 if not isinstance(inst, Instance):
138 raise type_error(inst, "x[0]", Instance)
139 if inst.name != self.inst_name:
140 raise ValueError(
141 f"instance name {inst.name!r} != {self.inst_name!r}.")
142 if inst.bin_width != self.bin_width:
143 raise ValueError(
144 f"instance bin width={inst.bin_width} != {self.bin_width}.")
145 if inst.bin_height != self.bin_height:
146 raise ValueError(
147 "instance bin height="
148 f"{inst.bin_height} != {self.bin_height}.")
149 if inst.n_items != self.n_items:
150 raise ValueError(
151 f"instance n_items={inst.n_items} != {self.n_items}.")
153 def n_points(self) -> int:
154 """
155 Get the approximate number of different elements in the space.
157 :return: the approximate scale of the space
158 """
159 return (self.bin_height * self.bin_width) ** self.n_items