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

1""" 

2A combination of the errors and the hardness objective. 

3 

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. 

11 

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. 

28 

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 

32 

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 

40 

41>>> obj.evaluate(orig) 

420.9275907603155895 

43""" 

44from typing import Callable, Final, Iterable 

45 

46from moptipy.api.execution import Execution 

47from moptipy.api.objective import Objective 

48from moptipy.utils.logger import KeyValueLogSection 

49 

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 

59 

60 

61class ErrorsAndHardness(Objective): 

62 """Compute the errors and hardness.""" 

63 

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. 

71 

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) 

83 

84 def evaluate(self, x: list[Instance] | Instance) -> float: 

85 """ 

86 Compute the combination of hardness and errors. 

87 

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)) 

93 

94 def lower_bound(self) -> float: 

95 """ 

96 Get the lower bound of the instance error and hardness. 

97 

98 :returns 0.0: always 

99 """ 

100 return 0.0 

101 

102 def upper_bound(self) -> float: 

103 """ 

104 Get the upper bound of the instance error and hardness. 

105 

106 :returns 1.0: always 

107 """ 

108 return 1.0 

109 

110 def is_always_integer(self) -> bool: 

111 """ 

112 Return `False` because the hardness function returns `float`. 

113 

114 :retval False: always 

115 """ 

116 return False 

117 

118 def __str__(self) -> str: 

119 """ 

120 Get the name of the errors objective function. 

121 

122 :return: `errorsAndHardness` 

123 :retval "errorsAndHardness": always 

124 """ 

125 return "errorsAndHardness" 

126 

127 def log_parameters_to(self, logger: KeyValueLogSection) -> None: 

128 """ 

129 Log the parameters of this instance. 

130 

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)