Coverage for moptipyapps / binpacking2d / instgen / errors_and_hardness.py: 100%
29 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"""
2A combination of the errors and the hardness objective.
4>>> orig = Instance.from_resource("a04")
5>>> space = InstanceSpace(orig)
6>>> print(f"{space.inst_name!r} with {space.n_different_items}/"
7... f"{space.n_items} items with area {space.total_item_area} "
8... f"in {space.min_bins} bins of "
9... f"size {space.bin_width}*{space.bin_height}.")
10'a04n' with 2/16 items with area 7305688 in 3 bins of size 2750*1220.
12>>> from moptipyapps.binpacking2d.instgen.inst_decoding import InstanceDecoder
13>>> decoder = InstanceDecoder(space)
14>>> import numpy as np
15>>> x = np.array([ 0.0, 0.2, -0.1, 0.3, 0.5, -0.6, -0.7, 0.9,
16... 0.0, 0.2, -0.1, 0.3, 0.5, -0.6, -0.7, 0.9,
17... 0.0, 0.2, -0.1, 0.3, 0.5, -0.6, -0.7, 0.9,
18... 0.0, 0.2, ])
19>>> y = space.create()
20>>> decoder.decode(x, y)
21>>> space.validate(y)
22>>> res: Instance = y[0]
23>>> print(f"{res.name!r} with {res.n_different_items}/"
24... f"{res.n_items} items with area {res.total_item_area} "
25... f"in {res.lower_bound_bins} bins of "
26... f"size {res.bin_width}*{res.bin_height}.")
27'a04n' with 15/16 items with area 10065000 in 3 bins of size 2750*1220.
29>>> print(space.to_str(y))
30a04n;15;2750;1220;1101,1098;2750,244;2750,98;1101,171;1649,171;2750,976;\
31441,122;1649,122;2750,10;2750,1,2;2750,3;1649,1098;2750,878;2750,58;660,122
33>>> obj = ErrorsAndHardness(space, max_fes=100)
34>>> obj.lower_bound()
350.0
36>>> obj.upper_bound()
371.0
38>>> obj.evaluate(y)
390.5439113595945743
41>>> obj.evaluate(orig)
420.9275907603155895
43"""
44from typing import Callable, Final, Iterable
46from moptipy.api.execution import Execution
47from moptipy.api.objective import Objective
48from moptipy.utils.logger import KeyValueLogSection
50from moptipyapps.binpacking2d.instance import (
51 Instance,
52)
53from moptipyapps.binpacking2d.instgen.errors import Errors
54from moptipyapps.binpacking2d.instgen.hardness import (
55 DEFAULT_EXECUTORS,
56 Hardness,
57)
58from moptipyapps.binpacking2d.instgen.instance_space import InstanceSpace
61class ErrorsAndHardness(Objective):
62 """Compute the errors and hardness."""
64 def __init__(self, space: InstanceSpace,
65 max_fes: int = 1_000_000, n_runs: int = 3,
66 executors: Iterable[
67 Callable[[Instance], tuple[
68 Execution, Objective]]] = DEFAULT_EXECUTORS) -> None:
69 """
70 Initialize the errors objective function.
72 :param space: the instance space
73 :param max_fes: the maximum FEs
74 :param n_runs: the maximum runs
75 :param executors: the functions creating the executions
76 """
77 super().__init__()
78 #: the errors objective
79 self.errors: Final[Errors] = Errors(space)
80 #: the hardness objective function
81 self.hardness: Final[Hardness] = Hardness(
82 max_fes, n_runs, executors)
84 def evaluate(self, x: list[Instance] | Instance) -> float:
85 """
86 Compute the combination of hardness and errors.
88 :param x: the instance
89 :return: the hardness and errors
90 """
91 return max(0.0, min(1.0, ((self.hardness.evaluate(
92 x) * 1000.0) + self.errors.evaluate(x)) / 1001.0))
94 def lower_bound(self) -> float:
95 """
96 Get the lower bound of the instance error and hardness.
98 :returns 0.0: always
99 """
100 return 0.0
102 def upper_bound(self) -> float:
103 """
104 Get the upper bound of the instance error and hardness.
106 :returns 1.0: always
107 """
108 return 1.0
110 def is_always_integer(self) -> bool:
111 """
112 Return `False` because the hardness function returns `float`.
114 :retval False: always
115 """
116 return False
118 def __str__(self) -> str:
119 """
120 Get the name of the errors objective function.
122 :return: `errorsAndHardness`
123 :retval "errorsAndHardness": always
124 """
125 return "errorsAndHardness"
127 def log_parameters_to(self, logger: KeyValueLogSection) -> None:
128 """
129 Log the parameters of this instance.
131 :param logger: the logger
132 """
133 super().log_parameters_to(logger)
134 with logger.scope("err") as err:
135 self.errors.log_parameters_to(err)
136 with logger.scope("hard") as hard:
137 self.hardness.log_parameters_to(hard)