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

1"""An encoding that is inspired by a given instance.""" 

2from typing import Final 

3 

4from moptipy.api.space import Space 

5from moptipy.utils.logger import KeyValueLogSection 

6from pycommons.types import check_int_range, type_error 

7 

8from moptipyapps.binpacking2d.instance import IDX_HEIGHT, IDX_WIDTH, Instance 

9 

10 

11class InstanceSpace(Space): 

12 """An space structure for the instance generation problem and space.""" 

13 

14 def __init__(self, source: Instance) -> None: 

15 """ 

16 Create the space structure for the instance generation problem. 

17 

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) 

58 

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

60 """ 

61 Log the parameters of this instance. 

62 

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) 

77 

78 def create(self) -> list[Instance]: 

79 """ 

80 Generate a list for receiving an instance. 

81 

82 :return: the new instance list 

83 """ 

84 return [] 

85 

86 def copy(self, dest: list[Instance], source: list[Instance]) -> None: 

87 """ 

88 Copy the instance list. 

89 

90 :param dest: the destination instance list 

91 :param source: the source instance list 

92 """ 

93 dest.clear() 

94 dest.extend(source) 

95 

96 def to_str(self, x: list[Instance]) -> str: # +book 

97 """ 

98 Convert an instance list to a string. 

99 

100 :param x: the instance list 

101 :return: the string representation of x 

102 """ 

103 return x[0].to_compact_str() 

104 

105 def from_str(self, text: str) -> list[Instance]: 

106 """ 

107 Convert an instance string to a list with an instance. 

108 

109 :param text: the input string 

110 :return: the element in the space corresponding to `text` 

111 """ 

112 return [Instance.from_compact_str(text)] 

113 

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. 

117 

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 

123 

124 def validate(self, x: list[Instance]) -> None: 

125 """ 

126 Check whether a given point in the space is valid. 

127 

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}.") 

152 

153 def n_points(self) -> int: 

154 """ 

155 Get the approximate number of different elements in the space. 

156 

157 :return: the approximate scale of the space 

158 """ 

159 return (self.bin_height * self.bin_width) ** self.n_items