Coverage for moptipyapps / binpacking2d / bks.py: 48%

359 statements  

« prev     ^ index     » next       coverage.py v7.13.0, created at 2025-12-11 04:40 +0000

1"""In this file, we provide a set of best-known solutions for the 2D-BPP.""" 

2 

3from dataclasses import dataclass 

4from importlib import resources # nosem 

5from math import inf, isfinite 

6from re import Pattern 

7from re import compile as p_compile 

8from statistics import mean 

9from typing import Any, Callable, Final, Iterable, Mapping, cast 

10 

11from pycommons.ds.immutable_map import immutable_mapping 

12from pycommons.io.path import UTF8 

13from pycommons.math.int_math import try_int, try_int_mul 

14from pycommons.strings.chars import WHITESPACE 

15from pycommons.strings.string_tools import replace_regex 

16from pycommons.types import check_int_range 

17 

18from moptipyapps.binpacking2d.instance import Instance 

19from moptipyapps.binpacking2d.packing_result import ( 

20 BIN_COUNT_NAME, 

21 PackingResult, 

22) 

23 

24 

25def __load_references() -> Mapping[str, str]: 

26 """ 

27 Load the references from the BibTeX resource. 

28 

29 This is not a fully-fledged BibTeX parser. It is a very simple and crude 

30 method to extract bibliography keys and data. 

31 

32 :return: the immutable reference dictionary, with keys sorted 

33 alphabetically 

34 """ 

35 current_lines: list[str] = [] 

36 key: str | None = None 

37 mode: int = 0 

38 found: Final[dict[str, str]] = {} 

39 single_ws: Final[Pattern] = p_compile(f"[{WHITESPACE}]") 

40 multi_ws: Final[Pattern] = p_compile(f"[{WHITESPACE}][{WHITESPACE}]+") 

41 with resources.files(__package__).joinpath( 

42 "bks.bib").open("r", encoding=UTF8) as stream: 

43 for rline in stream: 

44 line: str = str.rstrip(rline) 

45 if str.__len__(line) <= 0: 

46 continue 

47 if mode == 0: 

48 line = replace_regex(single_ws, "", line) 

49 if str.startswith(line, "@"): 

50 mode = 1 

51 start_idx: int = line.index("{") 

52 end_idx: int = line.index(",", start_idx + 1) 

53 key = str.strip(line[start_idx + 1:end_idx]) 

54 if str.__len__(key) <= 0: 

55 raise ValueError(f"Invalid key {key!r} in {line!r}.") 

56 current_lines.append(line) 

57 if key in found: 

58 raise ValueError(f"Duplicate key {key!r}.") 

59 elif mode == 1: 

60 if str.strip(line) in {"}", "},"}: 

61 mode = 0 

62 current_lines.append("}") 

63 found[key] = str.strip("\n".join(current_lines)) 

64 current_lines.clear() 

65 else: 

66 current_lines.append(replace_regex(multi_ws, " ", line)) 

67 if dict.__len__(found) <= 0: 

68 raise ValueError("Found no references!") 

69 return immutable_mapping({k: found[k] for k in sorted(found.keys())}) 

70 

71 

72#: the references to literature 

73_REFERENCES: Final[Mapping[str, str]] = __load_references() 

74 

75#: a constant for no reference 

76NO_REF: Final[str] = "{{NO_REF}}" 

77 

78 

79@dataclass(frozen=True, init=False, order=True, eq=True) 

80class Element: 

81 """The algorithm or instance group specification.""" 

82 

83 #: the name or name prefix 

84 name: str 

85 #: the name suffix, if any, and the empty string otherwise 

86 name_suffix: str 

87 #: the reference to the related work 

88 reference: str 

89 

90 def __init__(self, name: str, 

91 name_suffix: str, reference: str = NO_REF) -> None: 

92 """ 

93 Initialize this element. 

94 

95 :param name: the name or name prefix 

96 :param name_suffix: the name suffix, or an empty string 

97 :param reference: the reference 

98 """ 

99 name = str.strip(name) 

100 if str.__len__(name) <= 0: 

101 raise ValueError(f"Invalid name {name!r}.") 

102 object.__setattr__(self, "name", name) 

103 object.__setattr__(self, "name_suffix", str.strip(name_suffix)) 

104 reference = str.strip(reference) 

105 for ref in reference.split(","): 

106 if ref == NO_REF: 

107 continue 

108 if ref not in _REFERENCES: 

109 raise ValueError(f"Invalid reference {ref!r}.") 

110 object.__setattr__(self, "reference", reference) 

111 

112 def get_bibtex(self) -> Iterable[str]: 

113 """ 

114 Get the BibTeX for this element. 

115 

116 :return: the BibTeX string 

117 """ 

118 return (_REFERENCES[r] for r in self.reference.split(",")) 

119 

120 

121#: the BRKGA for 2D bin packing with rotation 

122BRKGA_BPP_2R: Final[Element] = Element( 

123 "BRKGA", "BRKGABPPRTR", "GR2013ABRKGAF2A3BPP") 

124#: the BRKGA for 2D bin packing without rotation 

125BRKGA_BPP_ANB: Final[Element] = Element( 

126 "BRKGA", "BRKGABPPRANB", "GR2013ABRKGAF2A3BPP") 

127#: the grasp/vnd for 2D bin packing without rotation 

128GRASP_VND: Final[Element] = Element( 

129 "GRASPVNDGRASP", "GRASPVNDVND", "PAVOT2010AHGVAFTATDBP") 

130#: the price-and-cut algorithm for 2D bin packing with rotation 

131PAC: Final[Element] = Element("PAC", "", "CGRS2020PACATSMTOOSFT2BPP") 

132#: the HHANO-R algorithm for 2D bin packing with rotation 

133HHANO_R: Final[Element] = Element("HHANO", "HHANOR", "BDC2015RHHAFTOONO2BPP") 

134#: the HHANO-SR algorithm for 2D bin packing with rotation 

135HHANO_SR: Final[Element] = Element("HHANO", "HHANOSR", "BDC2015RHHAFTOONO2BPP") 

136#: the MXGA algorithm for 2D bin packing with rotation 

137MXGA: Final[Element] = Element("MXGA", "", "L2008AGAFTDBPP") 

138#: the LGFi algorithm 

139EALGFI: Final[Element] = Element( 

140 "EALGFIEA", "EALGFILGFI", "BS2013ST2BPPBMOAHEA") 

141 

142#: the small A instances 

143A_SMALL: Final[Element] = Element("a", "small", "MAVdC2010AFMFTTDGCSP") 

144#: the median sized A instances 

145A_MED: Final[Element] = Element("a", "med", "MAVdC2010AFMFTTDGCSP") 

146#: the large A instances 

147A_LARGE: Final[Element] = Element("a", "large", "MAVdC2010AFMFTTDGCSP") 

148#: the asqas 

149ASQAS: Final[Element] = Element("asqas", "", "vdBBMSB2016ASIASSTFI") 

150#: the first part of the Beng instances 

151BENG_1_8: Final[Element] = Element("beng", "1-8", "B1982PRPAHA") 

152#: the second part of the Beng instances 

153BENG_9_10: Final[Element] = Element("beng", "9-10", "B1982PRPAHA") 

154#: the class 1-20 benchmarks 

155CLASS_1_20: Final[Element] = Element( 

156 "class 1", "20", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

157#: the class 1-40 benchmarks 

158CLASS_1_40: Final[Element] = Element( 

159 "class 1", "40", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

160#: the class 1-60 benchmarks 

161CLASS_1_60: Final[Element] = Element( 

162 "class 1", "60", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

163#: the class 1-80 benchmarks 

164CLASS_1_80: Final[Element] = Element( 

165 "class 1", "80", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

166#: the class 1-100 benchmarks 

167CLASS_1_100: Final[Element] = Element( 

168 "class 1", "100", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

169 

170#: the class 2-20 benchmarks 

171CLASS_2_20: Final[Element] = Element( 

172 "class 2", "20", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

173#: the class 2-40 benchmarks 

174CLASS_2_40: Final[Element] = Element( 

175 "class 2", "40", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

176#: the class 2-60 benchmarks 

177CLASS_2_60: Final[Element] = Element( 

178 "class 2", "60", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

179#: the class 2-80 benchmarks 

180CLASS_2_80: Final[Element] = Element( 

181 "class 2", "80", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

182#: the class 1-100 benchmarks 

183CLASS_2_100: Final[Element] = Element( 

184 "class 2", "100", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

185 

186#: the class 3-20 benchmarks 

187CLASS_3_20: Final[Element] = Element( 

188 "class 3", "20", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

189#: the class 1-40 benchmarks 

190CLASS_3_40: Final[Element] = Element( 

191 "class 3", "40", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

192#: the class 3-60 benchmarks 

193CLASS_3_60: Final[Element] = Element( 

194 "class 3", "60", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

195#: the class 3-80 benchmarks 

196CLASS_3_80: Final[Element] = Element( 

197 "class 3", "80", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

198#: the class 3-100 benchmarks 

199CLASS_3_100: Final[Element] = Element( 

200 "class 3", "100", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

201 

202#: the class 4-20 benchmarks 

203CLASS_4_20: Final[Element] = Element( 

204 "class 4", "20", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

205#: the class 4-40 benchmarks 

206CLASS_4_40: Final[Element] = Element( 

207 "class 4", "40", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

208#: the class 4-60 benchmarks 

209CLASS_4_60: Final[Element] = Element( 

210 "class 4", "60", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

211#: the class 4-80 benchmarks 

212CLASS_4_80: Final[Element] = Element( 

213 "class 4", "80", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

214#: the class 4-100 benchmarks 

215CLASS_4_100: Final[Element] = Element( 

216 "class 4", "100", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

217 

218#: the class 5-20 benchmarks 

219CLASS_5_20: Final[Element] = Element( 

220 "class 5", "20", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

221#: the class 5-40 benchmarks 

222CLASS_5_40: Final[Element] = Element( 

223 "class 5", "40", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

224#: the class 5-60 benchmarks 

225CLASS_5_60: Final[Element] = Element( 

226 "class 5", "60", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

227#: the class 5-80 benchmarks 

228CLASS_5_80: Final[Element] = Element( 

229 "class 5", "80", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

230#: the class 5-100 benchmarks 

231CLASS_5_100: Final[Element] = Element( 

232 "class 5", "100", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

233 

234#: the class 6-20 benchmarks 

235CLASS_6_20: Final[Element] = Element( 

236 "class 6", "20", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

237#: the class 6-40 benchmarks 

238CLASS_6_40: Final[Element] = Element( 

239 "class 6", "40", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

240#: the class 6-60 benchmarks 

241CLASS_6_60: Final[Element] = Element( 

242 "class 6", "60", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

243#: the class 6-80 benchmarks 

244CLASS_6_80: Final[Element] = Element( 

245 "class 6", "80", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

246#: the class 6-100 benchmarks 

247CLASS_6_100: Final[Element] = Element( 

248 "class 6", "100", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

249 

250#: the class 7-20 benchmarks 

251CLASS_7_20: Final[Element] = Element( 

252 "class 7", "20", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

253#: the class 7-40 benchmarks 

254CLASS_7_40: Final[Element] = Element( 

255 "class 7", "40", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

256#: the class 7-60 benchmarks 

257CLASS_7_60: Final[Element] = Element( 

258 "class 7", "60", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

259#: the class 7-80 benchmarks 

260CLASS_7_80: Final[Element] = Element( 

261 "class 7", "80", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

262#: the class 7-100 benchmarks 

263CLASS_7_100: Final[Element] = Element( 

264 "class 7", "100", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

265 

266#: the class 8-20 benchmarks 

267CLASS_8_20: Final[Element] = Element( 

268 "class 8", "20", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

269#: the class 8-40 benchmarks 

270CLASS_8_40: Final[Element] = Element( 

271 "class 8", "40", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

272#: the class 8-60 benchmarks 

273CLASS_8_60: Final[Element] = Element( 

274 "class 8", "60", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

275#: the class 8-80 benchmarks 

276CLASS_8_80: Final[Element] = Element( 

277 "class 8", "80", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

278#: the class 8-100 benchmarks 

279CLASS_8_100: Final[Element] = Element( 

280 "class 8", "100", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

281 

282#: the class 9-20 benchmarks 

283CLASS_9_20: Final[Element] = Element( 

284 "class 9", "20", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

285#: the class 9-40 benchmarks 

286CLASS_9_40: Final[Element] = Element( 

287 "class 9", "40", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

288#: the class 9-60 benchmarks 

289CLASS_9_60: Final[Element] = Element( 

290 "class 9", "60", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

291#: the class 9-80 benchmarks 

292CLASS_9_80: Final[Element] = Element( 

293 "class 9", "80", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

294#: the class 9-100 benchmarks 

295CLASS_9_100: Final[Element] = Element( 

296 "class 9", "100", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

297 

298#: the class 10-20 benchmarks 

299CLASS_10_20: Final[Element] = Element( 

300 "class 10", "20", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

301#: the class 10-40 benchmarks 

302CLASS_10_40: Final[Element] = Element( 

303 "class 10", "40", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

304#: the class 10-60 benchmarks 

305CLASS_10_60: Final[Element] = Element( 

306 "class 10", "60", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

307#: the class 10-80 benchmarks 

308CLASS_10_80: Final[Element] = Element( 

309 "class 10", "80", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

310#: the class 6-100 benchmarks 

311CLASS_10_100: Final[Element] = Element( 

312 "class 10", "100", "BW1987TDFBPA,MV1998ESOTTDFBPP") 

313 

314 

315def __sort_key(txt: str) -> list[str]: 

316 """ 

317 Get a sort key from a string. 

318 

319 :param txt: the string 

320 :return: the sort key 

321 """ 

322 kys: list[str] = [] 

323 for v in txt.split(","): 

324 for vv in v.split("-"): 

325 for vvv in vv.split("_"): 

326 for vvvv in vvv.split(" "): 

327 if vvvv == "small": 

328 kys.append("1_small") 

329 elif vvvv == "med": 

330 kys.append("2_med") 

331 elif vvvv == "large": 

332 kys.append("3_large") 

333 elif vvvv.startswith("asqas"): 

334 kys.append(f"zzzzzzzzzzzzzzzzzz{vvvv}") 

335 else: 

336 kys.append(vvvv.rjust(10, "0") 

337 if vvvv.isdigit() else vvvv) 

338 return kys 

339 

340 

341#: The set of class and beng instance groups 

342CLASS_AND_BENG: Final[tuple[Element, ...]] = ( 

343 BENG_1_8, BENG_9_10, CLASS_1_20, CLASS_1_40, CLASS_1_60, CLASS_1_80, 

344 CLASS_1_100, CLASS_2_20, CLASS_2_40, CLASS_2_60, CLASS_2_80, 

345 CLASS_2_100, CLASS_3_20, CLASS_3_40, CLASS_3_60, CLASS_3_80, 

346 CLASS_3_100, CLASS_4_20, CLASS_4_40, CLASS_4_60, CLASS_4_80, 

347 CLASS_4_100, CLASS_5_20, CLASS_5_40, CLASS_5_60, CLASS_5_80, 

348 CLASS_5_100, CLASS_6_20, CLASS_6_40, CLASS_6_60, CLASS_6_80, 

349 CLASS_6_100, CLASS_7_20, CLASS_7_40, CLASS_7_60, CLASS_7_80, 

350 CLASS_7_100, CLASS_8_20, CLASS_8_40, CLASS_8_60, CLASS_8_80, 

351 CLASS_8_100, CLASS_9_20, CLASS_9_40, CLASS_9_60, CLASS_9_80, 

352 CLASS_9_100, CLASS_10_20, CLASS_10_40, CLASS_10_60, CLASS_10_80, 

353 CLASS_10_100, 

354) 

355 

356 

357def __make_instance_map() -> Mapping[Element, tuple[str, ...]]: 

358 """ 

359 Make an instance map. 

360 

361 :return: the instance map. 

362 """ 

363 groups: Final[list[Element]] = [ 

364 A_SMALL, A_MED, A_LARGE, ASQAS, 

365 BENG_1_8, BENG_9_10, CLASS_1_20, CLASS_1_40, CLASS_1_60, CLASS_1_80, 

366 CLASS_1_100, CLASS_2_20, CLASS_2_40, CLASS_2_60, CLASS_2_80, 

367 CLASS_2_100, CLASS_3_20, CLASS_3_40, CLASS_3_60, CLASS_3_80, 

368 CLASS_3_100, CLASS_4_20, CLASS_4_40, CLASS_4_60, CLASS_4_80, 

369 CLASS_4_100, CLASS_5_20, CLASS_5_40, CLASS_5_60, CLASS_5_80, 

370 CLASS_5_100, CLASS_6_20, CLASS_6_40, CLASS_6_60, CLASS_6_80, 

371 CLASS_6_100, CLASS_7_20, CLASS_7_40, CLASS_7_60, CLASS_7_80, 

372 CLASS_7_100, CLASS_8_20, CLASS_8_40, CLASS_8_60, CLASS_8_80, 

373 CLASS_8_100, CLASS_9_20, CLASS_9_40, CLASS_9_60, CLASS_9_80, 

374 CLASS_9_100, CLASS_10_20, CLASS_10_40, CLASS_10_60, CLASS_10_80, 

375 CLASS_10_100] 

376 

377 data: dict[Element, tuple[str, ...]] = {} 

378 for group in Instance.list_resources_groups(): 

379 prefix: str = group[0] 

380 suffix: str = "" if group[1] is None else group[1] 

381 insts: tuple[str, ...] = group[2] 

382 found: bool = False 

383 for ggg in groups: 

384 if (ggg.name == prefix) and (ggg.name_suffix == suffix): 

385 if ggg in data: 

386 raise ValueError(f"Encountered {ggg} twice?") 

387 data[ggg] = insts 

388 found = True 

389 break 

390 if not found: 

391 raise ValueError(f"Did not find {group!r}.") 

392 

393 return immutable_mapping({k: data[k] for k in sorted( 

394 data.keys(), key=lambda e: __sort_key(f"{e.name} {e.name_suffix}"))}) 

395 

396 

397#: a mapping of instance groups to instances 

398GROUPS_TO_INSTANCES: Final[Mapping[Element, tuple[ 

399 str, ...]]] = __make_instance_map() 

400 

401#: A sort key function for instance groups 

402INST_GROUP_SORT_KEY: Final[Callable[[Element], int]] \ 

403 = list(GROUPS_TO_INSTANCES.keys()).index 

404 

405 

406def __make_instance_to_groups() -> Mapping[str, Element]: 

407 """ 

408 Make a mapping of instances to groups. 

409 

410 :return: the mapping of instances to groups. 

411 """ 

412 data: list[tuple[str, Element]] = [( 

413 v, k) for k, vv in GROUPS_TO_INSTANCES.items() for v in vv] 

414 data.sort(key=lambda x: __sort_key(x[0])) 

415 return immutable_mapping(dict(data)) 

416 

417 

418#: a mapping of instances to instance groups 

419INSTANCES_TO_GROUPS: Final[Mapping[str, Element]] = \ 

420 __make_instance_to_groups() 

421 

422 

423def __lb_avg_denormalize( 

424 with_rotation: bool, algo: Element, group: Element, 

425 value: "int | float", min_result: int = -1_000_000) -> tuple[ 

426 bool, Element, Element, int]: 

427 """ 

428 De-normalize using the maximum of the Dell'Amico and geometric bound. 

429 

430 :param with_rotation: is this a result with or without rotation? 

431 :param algo: the algorithm used 

432 :param group: the instance group 

433 :param value: the value 

434 :param min_result: the minimum denormalized result 

435 :return: de-normalized average 

436 """ 

437 return (with_rotation, algo, group, max( 

438 min_result, round(try_int_mul(sum(Instance.from_resource( 

439 ins).lower_bound_bins for ins in GROUPS_TO_INSTANCES[group]), 

440 value)))) 

441 

442 

443#: the related works with rotation averaged 

444__RW__AVERAGE: Final[tuple[tuple[ 

445 bool, Element, Element, int], ...]] = ( 

446 (True, BRKGA_BPP_2R, CLASS_1_20, 66), 

447 (False, BRKGA_BPP_ANB, CLASS_1_20, 71), 

448 (True, BRKGA_BPP_2R, CLASS_1_40, 128), 

449 (False, BRKGA_BPP_ANB, CLASS_1_40, 134), 

450 (True, BRKGA_BPP_2R, CLASS_1_60, 195), 

451 (False, BRKGA_BPP_ANB, CLASS_1_60, 200), 

452 (True, BRKGA_BPP_2R, CLASS_1_80, 270), 

453 (False, BRKGA_BPP_ANB, CLASS_1_80, 275), 

454 (True, BRKGA_BPP_2R, CLASS_1_100, 313), 

455 (False, BRKGA_BPP_ANB, CLASS_1_100, 317), 

456 (True, BRKGA_BPP_2R, CLASS_2_20, 10), 

457 (False, BRKGA_BPP_ANB, CLASS_2_20, 10), 

458 (True, BRKGA_BPP_2R, CLASS_2_40, 19), 

459 (False, BRKGA_BPP_ANB, CLASS_2_40, 19), 

460 (True, BRKGA_BPP_2R, CLASS_2_60, 25), 

461 (False, BRKGA_BPP_ANB, CLASS_2_60, 25), 

462 (True, BRKGA_BPP_2R, CLASS_2_80, 31), 

463 (False, BRKGA_BPP_ANB, CLASS_2_80, 31), 

464 (True, BRKGA_BPP_2R, CLASS_2_100, 39), 

465 (False, BRKGA_BPP_ANB, CLASS_2_100, 39), 

466 (True, BRKGA_BPP_2R, CLASS_3_20, 47), 

467 (False, BRKGA_BPP_ANB, CLASS_3_20, 51), 

468 (True, BRKGA_BPP_2R, CLASS_3_40, 92), 

469 (False, BRKGA_BPP_ANB, CLASS_3_40, 94), 

470 (True, BRKGA_BPP_2R, CLASS_3_60, 134), 

471 (False, BRKGA_BPP_ANB, CLASS_3_60, 139), 

472 (True, BRKGA_BPP_2R, CLASS_3_80, 182), 

473 (False, BRKGA_BPP_ANB, CLASS_3_80, 189), 

474 (True, BRKGA_BPP_2R, CLASS_3_100, 220), 

475 (False, BRKGA_BPP_ANB, CLASS_3_100, 223), 

476 (True, BRKGA_BPP_2R, CLASS_4_20, 10), 

477 (False, BRKGA_BPP_ANB, CLASS_4_20, 10), 

478 (True, BRKGA_BPP_2R, CLASS_4_40, 19), 

479 (False, BRKGA_BPP_ANB, CLASS_4_40, 19), 

480 (True, BRKGA_BPP_2R, CLASS_4_60, 23), 

481 (False, BRKGA_BPP_ANB, CLASS_4_60, 25), 

482 (True, BRKGA_BPP_2R, CLASS_4_80, 31), 

483 (False, BRKGA_BPP_ANB, CLASS_4_80, 31), 

484 (True, BRKGA_BPP_2R, CLASS_4_100, 37), 

485 (False, BRKGA_BPP_ANB, CLASS_4_100, 37), 

486 (True, BRKGA_BPP_2R, CLASS_5_20, 59), 

487 (False, BRKGA_BPP_ANB, CLASS_5_20, 65), 

488 (True, BRKGA_BPP_2R, CLASS_5_40, 114), 

489 (False, BRKGA_BPP_ANB, CLASS_5_40, 119), 

490 (True, BRKGA_BPP_2R, CLASS_5_60, 172), 

491 (False, BRKGA_BPP_ANB, CLASS_5_60, 180), 

492 (True, BRKGA_BPP_2R, CLASS_5_80, 239), 

493 (False, BRKGA_BPP_ANB, CLASS_5_80, 247), 

494 (True, BRKGA_BPP_2R, CLASS_5_100, 277), 

495 (False, BRKGA_BPP_ANB, CLASS_5_100, 281), 

496 (True, BRKGA_BPP_2R, CLASS_6_20, 10), 

497 (False, BRKGA_BPP_ANB, CLASS_6_20, 10), 

498 (True, BRKGA_BPP_2R, CLASS_6_40, 16), 

499 (False, BRKGA_BPP_ANB, CLASS_6_40, 16), 

500 (True, BRKGA_BPP_2R, CLASS_6_60, 21), 

501 (False, BRKGA_BPP_ANB, CLASS_6_60, 21), 

502 (True, BRKGA_BPP_2R, CLASS_6_80, 30), 

503 (False, BRKGA_BPP_ANB, CLASS_6_80, 30), 

504 (True, BRKGA_BPP_2R, CLASS_6_100, 32), 

505 (False, BRKGA_BPP_ANB, CLASS_6_100, 33), 

506 (True, BRKGA_BPP_2R, CLASS_7_20, 52), 

507 (False, BRKGA_BPP_ANB, CLASS_7_20, 55), 

508 (True, BRKGA_BPP_2R, CLASS_7_40, 102), 

509 (False, BRKGA_BPP_ANB, CLASS_7_40, 111), 

510 (True, BRKGA_BPP_2R, CLASS_7_60, 146), 

511 (False, BRKGA_BPP_ANB, CLASS_7_60, 158), 

512 (True, BRKGA_BPP_2R, CLASS_7_80, 208), 

513 (False, BRKGA_BPP_ANB, CLASS_7_80, 232), 

514 (True, BRKGA_BPP_2R, CLASS_7_100, 250), 

515 (False, BRKGA_BPP_ANB, CLASS_7_100, 271), 

516 (True, BRKGA_BPP_2R, CLASS_8_20, 53), 

517 (False, BRKGA_BPP_ANB, CLASS_8_20, 58), 

518 (True, BRKGA_BPP_2R, CLASS_8_40, 103), 

519 (False, BRKGA_BPP_ANB, CLASS_8_40, 113), 

520 (True, BRKGA_BPP_2R, CLASS_8_60, 147), 

521 (False, BRKGA_BPP_ANB, CLASS_8_60, 161), 

522 (True, BRKGA_BPP_2R, CLASS_8_80, 204), 

523 (False, BRKGA_BPP_ANB, CLASS_8_80, 224), 

524 (True, BRKGA_BPP_2R, CLASS_8_100, 252), 

525 (False, BRKGA_BPP_ANB, CLASS_8_100, 278), 

526 (True, BRKGA_BPP_2R, CLASS_9_20, 143), 

527 (False, BRKGA_BPP_ANB, CLASS_9_20, 143), 

528 (True, BRKGA_BPP_2R, CLASS_9_40, 275), 

529 (False, BRKGA_BPP_ANB, CLASS_9_40, 278), 

530 (True, BRKGA_BPP_2R, CLASS_9_60, 435), 

531 (False, BRKGA_BPP_ANB, CLASS_9_60, 437), 

532 (True, BRKGA_BPP_2R, CLASS_9_80, 573), 

533 (False, BRKGA_BPP_ANB, CLASS_9_80, 577), 

534 (True, BRKGA_BPP_2R, CLASS_9_100, 693), 

535 (False, BRKGA_BPP_ANB, CLASS_9_100, 695), 

536 (True, BRKGA_BPP_2R, CLASS_10_20, 41), 

537 (False, BRKGA_BPP_ANB, CLASS_10_20, 42), 

538 (True, BRKGA_BPP_2R, CLASS_10_40, 72), 

539 (False, BRKGA_BPP_ANB, CLASS_10_40, 74), 

540 (True, BRKGA_BPP_2R, CLASS_10_60, 99), 

541 (False, BRKGA_BPP_ANB, CLASS_10_60, 100), 

542 (True, BRKGA_BPP_2R, CLASS_10_80, 125), 

543 (False, BRKGA_BPP_ANB, CLASS_10_80, 128), 

544 (True, BRKGA_BPP_2R, CLASS_10_100, 154), 

545 (False, BRKGA_BPP_ANB, CLASS_10_100, 158), 

546 (True, BRKGA_BPP_2R, BENG_1_8, 54), 

547 (False, BRKGA_BPP_ANB, BENG_1_8, 54), 

548 (True, BRKGA_BPP_2R, BENG_9_10, 13), 

549 (False, BRKGA_BPP_ANB, BENG_9_10, 13), 

550 (False, PAC, CLASS_1_20, 71), 

551 (False, PAC, CLASS_1_40, 134), 

552 (False, PAC, CLASS_1_60, 200), 

553 (False, PAC, CLASS_1_80, 275), 

554 (False, PAC, CLASS_1_100, 317), 

555 (False, PAC, CLASS_2_20, 10), 

556 (False, PAC, CLASS_2_40, 19), 

557 (False, PAC, CLASS_2_60, 25), 

558 (False, PAC, CLASS_2_80, 31), 

559 (False, PAC, CLASS_2_100, 39), 

560 (False, PAC, CLASS_3_20, 51), 

561 (False, PAC, BENG_1_8, 54), 

562 (False, PAC, BENG_9_10, 13), 

563 (True, PAC, CLASS_1_20, 66), 

564 (True, PAC, CLASS_1_40, 128), 

565 (True, PAC, CLASS_1_60, 195), 

566 (True, PAC, CLASS_1_80, 270), 

567 (True, PAC, CLASS_1_100, 313), 

568 (True, PAC, CLASS_2_20, 10), 

569 (True, PAC, CLASS_2_40, 19), 

570 (True, PAC, CLASS_2_60, 25), 

571 (True, PAC, CLASS_2_80, 31), 

572 (True, PAC, CLASS_2_100, 39), 

573 (True, PAC, CLASS_3_20, 47), 

574 (True, PAC, BENG_1_8, 54), 

575 (True, PAC, BENG_9_10, 13), 

576 (True, HHANO_R, CLASS_1_20, 66), 

577 (True, HHANO_SR, CLASS_1_20, 66), 

578 (True, HHANO_R, CLASS_1_40, 131), 

579 (True, HHANO_SR, CLASS_1_40, 129), 

580 (True, HHANO_R, CLASS_1_60, 196), 

581 (True, HHANO_SR, CLASS_1_60, 195), 

582 (True, HHANO_R, CLASS_1_80, 270), 

583 (True, HHANO_SR, CLASS_1_80, 270), 

584 (True, HHANO_R, CLASS_1_100, 314), 

585 (True, HHANO_SR, CLASS_1_100, 313), 

586 (True, HHANO_R, CLASS_2_20, 10), 

587 (True, HHANO_SR, CLASS_2_20, 10), 

588 (True, HHANO_R, CLASS_2_40, 20), 

589 (True, HHANO_SR, CLASS_2_40, 19), 

590 (True, HHANO_R, CLASS_2_60, 25), 

591 (True, HHANO_SR, CLASS_2_60, 25), 

592 (True, HHANO_R, CLASS_2_80, 31), 

593 (True, HHANO_SR, CLASS_2_80, 31), 

594 (True, HHANO_R, CLASS_2_100, 39), 

595 (True, HHANO_SR, CLASS_2_100, 39), 

596 (True, HHANO_R, CLASS_3_20, 48), 

597 (True, HHANO_SR, CLASS_3_20, 48), 

598 (True, HHANO_R, CLASS_3_40, 95), 

599 (True, HHANO_SR, CLASS_3_40, 95), 

600 (True, HHANO_R, CLASS_3_60, 137), 

601 (True, HHANO_SR, CLASS_3_60, 137), 

602 (True, HHANO_R, CLASS_3_80, 186), 

603 (True, HHANO_SR, CLASS_3_80, 187), 

604 (True, HHANO_R, CLASS_3_100, 225), 

605 (True, HHANO_SR, CLASS_3_100, 225), 

606 (True, HHANO_R, CLASS_4_20, 10), 

607 (True, HHANO_SR, CLASS_4_20, 10), 

608 (True, HHANO_R, CLASS_4_40, 19), 

609 (True, HHANO_SR, CLASS_4_40, 19), 

610 (True, HHANO_R, CLASS_4_60, 25), 

611 (True, HHANO_SR, CLASS_4_60, 25), 

612 (True, HHANO_R, CLASS_4_80, 32), 

613 (True, HHANO_SR, CLASS_4_80, 33), 

614 (True, HHANO_R, CLASS_4_100, 38), 

615 (True, HHANO_SR, CLASS_4_100, 38), 

616 (True, HHANO_R, CLASS_5_20, 59), 

617 (True, HHANO_SR, CLASS_5_20, 59), 

618 (True, HHANO_R, CLASS_5_40, 116), 

619 (True, HHANO_SR, CLASS_5_40, 115), 

620 (True, HHANO_R, CLASS_5_60, 175), 

621 (True, HHANO_SR, CLASS_5_60, 176), 

622 (True, HHANO_R, CLASS_5_80, 240), 

623 (True, HHANO_SR, CLASS_5_80, 241), 

624 (True, HHANO_R, CLASS_5_100, 284), 

625 (True, HHANO_SR, CLASS_5_100, 284), 

626 (True, HHANO_R, CLASS_6_20, 10), 

627 (True, HHANO_SR, CLASS_6_20, 10), 

628 (True, HHANO_R, CLASS_6_40, 18), 

629 (True, HHANO_SR, CLASS_6_40, 17), 

630 (True, HHANO_R, CLASS_6_60, 22), 

631 (True, HHANO_SR, CLASS_6_60, 22), 

632 (True, HHANO_R, CLASS_6_80, 30), 

633 (True, HHANO_SR, CLASS_6_80, 30), 

634 (True, HHANO_R, CLASS_6_100, 34), 

635 (True, HHANO_SR, CLASS_6_100, 34), 

636 (True, HHANO_R, CLASS_7_20, 52), 

637 (True, HHANO_SR, CLASS_7_20, 52), 

638 (True, HHANO_R, CLASS_7_40, 106), 

639 (True, HHANO_SR, CLASS_7_40, 107), 

640 (True, HHANO_R, CLASS_7_60, 152), 

641 (True, HHANO_SR, CLASS_7_60, 153), 

642 (True, HHANO_R, CLASS_7_80, 216), 

643 (True, HHANO_SR, CLASS_7_80, 217), 

644 (True, HHANO_R, CLASS_7_100, 260), 

645 (True, HHANO_SR, CLASS_7_100, 259), 

646 (True, HHANO_R, CLASS_8_20, 53), 

647 (True, HHANO_SR, CLASS_8_20, 53), 

648 (True, HHANO_R, CLASS_8_40, 106), 

649 (True, HHANO_SR, CLASS_8_40, 105), 

650 (True, HHANO_R, CLASS_8_60, 155), 

651 (True, HHANO_SR, CLASS_8_60, 154), 

652 (True, HHANO_R, CLASS_8_80, 213), 

653 (True, HHANO_SR, CLASS_8_80, 214), 

654 (True, HHANO_R, CLASS_8_100, 261), 

655 (True, HHANO_SR, CLASS_8_100, 262), 

656 (True, HHANO_R, CLASS_9_20, 143), 

657 (True, HHANO_SR, CLASS_9_20, 143), 

658 (True, HHANO_R, CLASS_9_40, 275), 

659 (True, HHANO_SR, CLASS_9_40, 275), 

660 (True, HHANO_R, CLASS_9_60, 435), 

661 (True, HHANO_SR, CLASS_9_60, 435), 

662 (True, HHANO_R, CLASS_9_80, 573), 

663 (True, HHANO_SR, CLASS_9_80, 573), 

664 (True, HHANO_R, CLASS_9_100, 693), 

665 (True, HHANO_SR, CLASS_9_100, 693), 

666 (True, HHANO_R, CLASS_10_20, 41), 

667 (True, HHANO_SR, CLASS_10_20, 41), 

668 (True, HHANO_R, CLASS_10_40, 73), 

669 (True, HHANO_SR, CLASS_10_40, 73), 

670 (True, HHANO_R, CLASS_10_60, 101), 

671 (True, HHANO_SR, CLASS_10_60, 101), 

672 (True, HHANO_R, CLASS_10_80, 129), 

673 (True, HHANO_SR, CLASS_10_80, 130), 

674 (True, HHANO_R, CLASS_10_100, 161), 

675 (True, HHANO_SR, CLASS_10_100, 162), 

676 __lb_avg_denormalize(True, MXGA, CLASS_1_20, 1.03), 

677 __lb_avg_denormalize(True, MXGA, CLASS_1_40, 1.04), 

678 __lb_avg_denormalize(True, MXGA, CLASS_1_60, 1.04, 195), # 19.4 

679 __lb_avg_denormalize(True, MXGA, CLASS_1_80, 1.06), 

680 __lb_avg_denormalize(True, MXGA, CLASS_1_100, 1.02, 313), # 31.2 

681 __lb_avg_denormalize(True, MXGA, CLASS_2_20, 1.0), 

682 __lb_avg_denormalize(True, MXGA, CLASS_2_40, 1.1), 

683 __lb_avg_denormalize(True, MXGA, CLASS_2_60, 1.0), 

684 __lb_avg_denormalize(True, MXGA, CLASS_2_80, 1.0), 

685 __lb_avg_denormalize(True, MXGA, CLASS_2_100, 1.0), 

686 __lb_avg_denormalize(True, MXGA, CLASS_3_20, 1.04), 

687 __lb_avg_denormalize(True, MXGA, CLASS_3_40, 1.09), 

688 __lb_avg_denormalize(True, MXGA, CLASS_3_60, 1.08), 

689 __lb_avg_denormalize(True, MXGA, CLASS_3_80, 1.06), 

690 __lb_avg_denormalize(True, MXGA, CLASS_3_100, 1.06), 

691 __lb_avg_denormalize(True, MXGA, CLASS_4_20, 1.0), 

692 __lb_avg_denormalize(True, MXGA, CLASS_4_40, 1.0), 

693 __lb_avg_denormalize(True, MXGA, CLASS_4_60, 1.10), 

694 __lb_avg_denormalize(True, MXGA, CLASS_4_80, 1.07), 

695 __lb_avg_denormalize(True, MXGA, CLASS_4_100, 1.03), 

696 __lb_avg_denormalize(True, MXGA, CLASS_5_20, 1.04), 

697 __lb_avg_denormalize(True, MXGA, CLASS_5_40, 1.06), 

698 __lb_avg_denormalize(True, MXGA, CLASS_5_60, 1.07), 

699 __lb_avg_denormalize(True, MXGA, CLASS_5_80, 1.07), 

700 __lb_avg_denormalize(True, MXGA, CLASS_5_100, 1.05), 

701 __lb_avg_denormalize(True, MXGA, CLASS_6_20, 1.0), 

702 __lb_avg_denormalize(True, MXGA, CLASS_6_40, 1.4), 

703 __lb_avg_denormalize(True, MXGA, CLASS_6_60, 1.0), 

704 __lb_avg_denormalize(True, MXGA, CLASS_6_80, 1.0), 

705 __lb_avg_denormalize(True, MXGA, CLASS_6_100, 1.07), 

706 __lb_avg_denormalize(True, MXGA, CLASS_7_20, 1.11), 

707 __lb_avg_denormalize(True, MXGA, CLASS_7_40, 1.07), 

708 __lb_avg_denormalize(True, MXGA, CLASS_7_60, 1.05), 

709 __lb_avg_denormalize(True, MXGA, CLASS_7_80, 1.08), 

710 __lb_avg_denormalize(True, MXGA, CLASS_7_100, 1.07), 

711 __lb_avg_denormalize(True, MXGA, CLASS_8_20, 1.10), 

712 __lb_avg_denormalize(True, MXGA, CLASS_8_40, 1.09), 

713 __lb_avg_denormalize(True, MXGA, CLASS_8_60, 1.06), 

714 __lb_avg_denormalize(True, MXGA, CLASS_8_80, 1.07), 

715 __lb_avg_denormalize(True, MXGA, CLASS_8_100, 1.06), 

716 __lb_avg_denormalize(True, MXGA, CLASS_9_20, 1.0), 

717 __lb_avg_denormalize(True, MXGA, CLASS_9_40, 1.01), 

718 __lb_avg_denormalize(True, MXGA, CLASS_9_60, 1.01), 

719 __lb_avg_denormalize(True, MXGA, CLASS_9_80, 1.01), 

720 __lb_avg_denormalize(True, MXGA, CLASS_9_100, 1.01), 

721 __lb_avg_denormalize(True, MXGA, CLASS_10_20, 1.13), 

722 __lb_avg_denormalize(True, MXGA, CLASS_10_40, 1.06), 

723 __lb_avg_denormalize(True, MXGA, CLASS_10_60, 1.07), 

724 __lb_avg_denormalize(True, MXGA, CLASS_10_80, 1.06), 

725 __lb_avg_denormalize(True, MXGA, CLASS_10_100, 1.04), 

726 (False, EALGFI, CLASS_1_20, 71), 

727 (False, EALGFI, CLASS_1_40, 134), 

728 (False, EALGFI, CLASS_1_60, 200), 

729 (False, EALGFI, CLASS_1_80, 275), 

730 (False, EALGFI, CLASS_1_100, 317), 

731 (False, EALGFI, CLASS_2_20, 10), 

732 (False, EALGFI, CLASS_2_40, 19), 

733 (False, EALGFI, CLASS_2_60, 25), 

734 (False, EALGFI, CLASS_2_80, 31), 

735 (False, EALGFI, CLASS_2_100, 39), 

736 (False, EALGFI, CLASS_3_20, 51), 

737 (False, EALGFI, CLASS_3_40, 94), 

738 (False, EALGFI, CLASS_3_60, 139), 

739 (False, EALGFI, CLASS_3_80, 189), 

740 (False, EALGFI, CLASS_3_100, 224), 

741 (False, EALGFI, CLASS_4_20, 10), 

742 (False, EALGFI, CLASS_4_40, 19), 

743 (False, EALGFI, CLASS_4_60, 23), 

744 (False, EALGFI, CLASS_4_80, 31), 

745 (False, EALGFI, CLASS_4_100, 37), 

746 (False, EALGFI, CLASS_5_20, 65), 

747 (False, EALGFI, CLASS_5_40, 119), 

748 (False, EALGFI, CLASS_5_60, 180), 

749 (False, EALGFI, CLASS_5_80, 247), 

750 (False, EALGFI, CLASS_5_100, 284), 

751 (False, EALGFI, CLASS_6_20, 10), 

752 (False, EALGFI, CLASS_6_40, 17), 

753 (False, EALGFI, CLASS_6_60, 21), 

754 (False, EALGFI, CLASS_6_80, 30), 

755 (False, EALGFI, CLASS_6_100, 32), 

756 (False, EALGFI, CLASS_7_20, 55), 

757 (False, EALGFI, CLASS_7_40, 111), 

758 (False, EALGFI, CLASS_7_60, 159), 

759 (False, EALGFI, CLASS_7_80, 232), 

760 (False, EALGFI, CLASS_7_100, 271), 

761 (False, EALGFI, CLASS_8_20, 58), 

762 (False, EALGFI, CLASS_8_40, 113), 

763 (False, EALGFI, CLASS_8_60, 161), 

764 (False, EALGFI, CLASS_8_80, 224), 

765 (False, EALGFI, CLASS_8_100, 277), 

766 (False, EALGFI, CLASS_9_20, 143), 

767 (False, EALGFI, CLASS_9_40, 278), 

768 (False, EALGFI, CLASS_9_60, 437), 

769 (False, EALGFI, CLASS_9_80, 577), 

770 (False, EALGFI, CLASS_9_100, 695), 

771 (False, EALGFI, CLASS_10_20, 42), 

772 (False, EALGFI, CLASS_10_40, 74), 

773 (False, EALGFI, CLASS_10_60, 101), 

774 (False, EALGFI, CLASS_10_80, 128), 

775 (False, EALGFI, CLASS_10_100, 160), 

776 (False, GRASP_VND, CLASS_1_20, 71), 

777 (False, GRASP_VND, CLASS_1_40, 134), 

778 (False, GRASP_VND, CLASS_1_60, 200), 

779 (False, GRASP_VND, CLASS_1_80, 275), 

780 (False, GRASP_VND, CLASS_1_100, 317), 

781 (False, GRASP_VND, CLASS_2_20, 10), 

782 (False, GRASP_VND, CLASS_2_40, 19), 

783 (False, GRASP_VND, CLASS_2_60, 25), 

784 (False, GRASP_VND, CLASS_2_80, 31), 

785 (False, GRASP_VND, CLASS_2_100, 39), 

786 (False, GRASP_VND, CLASS_3_20, 51), 

787 (False, GRASP_VND, CLASS_3_40, 94), 

788 (False, GRASP_VND, CLASS_3_60, 139), 

789 (False, GRASP_VND, CLASS_3_80, 189), 

790 (False, GRASP_VND, CLASS_3_100, 223), 

791 (False, GRASP_VND, CLASS_4_20, 10), 

792 (False, GRASP_VND, CLASS_4_40, 19), 

793 (False, GRASP_VND, CLASS_4_60, 25), 

794 (False, GRASP_VND, CLASS_4_80, 31), 

795 (False, GRASP_VND, CLASS_4_100, 38), 

796 (False, GRASP_VND, CLASS_5_20, 65), 

797 (False, GRASP_VND, CLASS_5_40, 119), 

798 (False, GRASP_VND, CLASS_5_60, 180), 

799 (False, GRASP_VND, CLASS_5_80, 247), 

800 (False, GRASP_VND, CLASS_5_100, 282), 

801 (False, GRASP_VND, CLASS_6_20, 10), 

802 (False, GRASP_VND, CLASS_6_40, 17), 

803 (False, GRASP_VND, CLASS_6_60, 21), 

804 (False, GRASP_VND, CLASS_6_80, 30), 

805 (False, GRASP_VND, CLASS_6_100, 34), 

806 (False, GRASP_VND, CLASS_7_20, 55), 

807 (False, GRASP_VND, CLASS_7_40, 111), 

808 (False, GRASP_VND, CLASS_7_60, 159), 

809 (False, GRASP_VND, CLASS_7_80, 232), 

810 (False, GRASP_VND, CLASS_7_100, 271), 

811 (False, GRASP_VND, CLASS_8_20, 58), 

812 (False, GRASP_VND, CLASS_8_40, 113), 

813 (False, GRASP_VND, CLASS_8_60, 161), 

814 (False, GRASP_VND, CLASS_8_80, 224), 

815 (False, GRASP_VND, CLASS_8_100, 278), 

816 (False, GRASP_VND, CLASS_9_20, 143), 

817 (False, GRASP_VND, CLASS_9_40, 278), 

818 (False, GRASP_VND, CLASS_9_60, 437), 

819 (False, GRASP_VND, CLASS_9_80, 577), 

820 (False, GRASP_VND, CLASS_9_100, 695), 

821 (False, GRASP_VND, CLASS_10_20, 42), 

822 (False, GRASP_VND, CLASS_10_40, 74), 

823 (False, GRASP_VND, CLASS_10_60, 100), 

824 (False, GRASP_VND, CLASS_10_80, 129), 

825 (False, GRASP_VND, CLASS_10_100, 159), 

826 (False, GRASP_VND, BENG_1_8, 54), 

827 (False, GRASP_VND, BENG_9_10, 13), 

828) 

829 

830 

831def get_related_work( 

832 with_rotation: bool | None = None, 

833 without_rotation: bool | None = None, 

834 algo_select: Callable[[Element], bool] = 

835 lambda _: True, 

836 inst_group_select: Callable[[Element], bool] = 

837 lambda _: True) -> tuple[ 

838 tuple[bool, Element, Element, int], ...]: 

839 """ 

840 Get the related work of a given type. 

841 

842 :param with_rotation: include the data with rotation 

843 :param without_rotation: include the data without rotation 

844 :param algo_select: the algorithm selector 

845 :param inst_group_select: the instance group selector 

846 :return: An iterable with the related works 

847 """ 

848 res: Iterable[tuple[bool, Element, Element, int]] 

849 if (with_rotation is None) and (without_rotation is None): 

850 res = __RW__AVERAGE 

851 else: 

852 if with_rotation is None: 

853 with_rotation = not without_rotation 

854 if without_rotation is None: 

855 without_rotation = not with_rotation 

856 

857 if without_rotation and with_rotation: 

858 res = __RW__AVERAGE 

859 elif with_rotation: 

860 res = (x for x in __RW__AVERAGE if x[0]) 

861 elif without_rotation: 

862 res = (x for x in __RW__AVERAGE if not x[0]) 

863 else: 

864 return () 

865 return tuple(sorted(filter( 

866 lambda x: algo_select(x[1]) and inst_group_select(x[2]), res), 

867 key=lambda v: (v[0], INST_GROUP_SORT_KEY(v[2]), v[1], v[3]))) 

868 

869 

870def make_comparison_table_data( 

871 data: Iterable[PackingResult], 

872 with_rotation: bool, 

873 algo_from_pr: Callable[[PackingResult], Element] = lambda x: Element( 

874 x.end_result.algorithm, x.end_result.objective), 

875 algo_sort_key: Callable[[Element], Any] = lambda x: ( 

876 -1 if (x.reference == NO_REF) else 1, x), 

877 rw_algo_selector: Callable[[Element], bool] = lambda _: True, 

878 aggregator: Callable[[Iterable[int | float]], int | float] = mean, 

879 additional: Callable[[Element], Iterable[tuple[ 

880 Element, Callable[[Iterable[int | float]], int | float]]]] = 

881 lambda _: ()) -> tuple[tuple[Element, ...], tuple[tuple[ 

882 Element, tuple[int | float | None, ...]], ...]]: 

883 """ 

884 Create the data for an end result comparison table. 

885 

886 :param data: the source data 

887 :param with_rotation: are we doing stuff with rotation? 

888 :param algo_from_pr: convert a packing result to an algorithm 

889 :param algo_sort_key: the algorithm sort key 

890 :param rw_algo_selector: the related work algorithm selector 

891 :param aggregator: the routine for per-instance averaging of bins 

892 :param additional: an additional column constructor 

893 

894 :return: the table data: the title row columns followed by the data 

895 row-by-row, each row leading with an instance group identifier 

896 """ 

897 per_algo_data: dict[Element, tuple[Callable[[ 

898 Iterable[int | float]], int | float], dict[str, list[int]]]] = {} 

899 for pr in data: 

900 algo: Element = algo_from_pr(pr) 

901 inst_dict: dict[str, list[int]] 

902 if algo in per_algo_data: 

903 inst_dict = per_algo_data[algo][1] 

904 else: 

905 inst_dict = {} 

906 per_algo_data[algo] = aggregator, inst_dict 

907 inst: str = pr.end_result.instance 

908 val: int = check_int_range( 

909 pr.objectives[BIN_COUNT_NAME], BIN_COUNT_NAME, 1, 1_000_000_000) 

910 if inst in inst_dict: 

911 inst_dict[inst].append(val) 

912 else: 

913 inst_dict[inst] = [val] 

914 

915 groups: Final[list[Element]] = sorted({ 

916 INSTANCES_TO_GROUPS[k] for kk in per_algo_data.values() 

917 for k in kk[1]}, key=INST_GROUP_SORT_KEY) 

918 

919 # get the averages 

920 algo_per_group_data: Final[dict[Element, dict[Element, int | float]]] = {} 

921 for algo, inst_dict_and_avg in per_algo_data.items(): 

922 dothis: list[tuple[Element, Callable[[ 

923 Iterable[int | float]], int | float]]] = [ 

924 (algo, inst_dict_and_avg[0])] 

925 dothis.extend(additional(algo)) 

926 

927 for xyz in dothis: 

928 avg: Callable[[Iterable[int | float]], int | float] = xyz[1] 

929 inst_dict = inst_dict_and_avg[1] 

930 ag: dict[Element, int | float] = {} 

931 algo_per_group_data[xyz[0]] = ag 

932 algo_runs: int | None = None 

933 for g in groups: 

934 gis: tuple[str, ...] = GROUPS_TO_INSTANCES[g] 

935 gisd: list[list[int | float]] = [] 

936 ok: bool = True 

937 for inst in gis: 

938 if inst not in inst_dict: 

939 ok = False 

940 gisd.append(cast("list[int | float]", inst_dict[inst])) 

941 if ok: 

942 if list.__len__(gisd) <= 0: 

943 raise ValueError(f"Empty group {g!r} for {algo!r}?") 

944 if list.__len__(gisd) != tuple.__len__(gis): 

945 raise ValueError( 

946 f"Some data missing in {g!r} for {algo!r}?") 

947 ll = list.__len__(gisd[0]) 

948 if algo_runs is None: 

949 algo_runs = ll 

950 elif algo_runs != ll: 

951 raise ValueError( 

952 f"Inconsistent number of runs for {algo!r}: " 

953 f"{ll} in {gis[0]!r} vs. {algo_runs}.") 

954 if not all(list.__len__(xxx) == ll for xxx in gisd): 

955 raise ValueError( 

956 f"Inconsistent run numbers in {g!r} for {algo!r}.") 

957 ag[g] = round(sum(cast("Iterable", ( 

958 try_int(avg(v)) for v in gisd)))) 

959 elif len(gisd) > 0: 

960 raise ValueError(f"Incomplete group {g!r} for {algo!r}.") 

961 

962 rw: tuple[tuple[bool, Element, Element, float], ...] = get_related_work( 

963 with_rotation=with_rotation, without_rotation=not with_rotation, 

964 algo_select=rw_algo_selector, inst_group_select=groups.__contains__) 

965 

966 algorithms: list[Element] = list({rww[1] for rww in rw}) 

967 algorithms.sort(key=algo_sort_key) 

968 our_algorithms = sorted(algo_per_group_data.keys(), key=algo_sort_key) 

969 

970 rows: list[tuple[Element, tuple[int | float | None, ...]]] = [] 

971 for g in groups: 

972 xdata: list[int | float | None] = [] 

973 for algo in algorithms: 

974 found: bool = False 

975 for zz in rw: 

976 if zz[1] != algo: 

977 continue 

978 if zz[2] != g: 

979 continue 

980 found = True 

981 xdata.append(zz[3]) 

982 break 

983 if found: 

984 continue 

985 xdata.append(None) 

986 for algo in our_algorithms: 

987 agz: dict[Element, int | float] = algo_per_group_data[algo] 

988 if g not in agz: 

989 xdata.append(None) 

990 continue 

991 xdata.append(agz[g]) 

992 rows.append((g, tuple(xdata))) 

993 

994 algorithms.extend(our_algorithms) 

995 return tuple(algorithms), tuple(rows) 

996 

997 

998def make_comparison_table( 

999 dest: Callable[[str], Any], 

1000 data: tuple[tuple[Element, ...], tuple[tuple[Element, tuple[ 

1001 int | float | None, ...]], ...]], 

1002 name_to_strs: Callable[[Element], tuple[str, str]] = lambda s: ( 

1003 s.name.split("_")[0], s.name_suffix), 

1004 format_best: Callable[[str], str] = 

1005 lambda s: f"\\textbf{{{s}}}", 

1006 count_best_over: Iterable[tuple[Iterable[Element], str]] = ()) -> None: 

1007 """ 

1008 Make a comparison table in LaTeX. 

1009 

1010 :param dest: the destination 

1011 :param data: the source data 

1012 :param name_to_strs: the converter of names to strings 

1013 :param format_best: the formatter for best values 

1014 :param count_best_over: a set of instances to include in the best counting 

1015 and a corresponding label 

1016 """ 

1017 inst_names: Final[list[tuple[str, str]]] = [ 

1018 name_to_strs(d[0]) for d in data[1]] 

1019 inst_cols: int = 2 if any( 

1020 str.__len__(n[1]) > 0 for n in inst_names) else 1 

1021 

1022 dest("% begin auto-generated LaTeX table comparing " 

1023 "end results with related work.%") 

1024 writer: list[str] = [r"\begin{tabular}{@{}r"] 

1025 if inst_cols > 1: 

1026 writer.append("@{}l") 

1027 writer.extend("r" for _ in range(tuple.__len__(data[0]))) 

1028 writer.append("@{}}%") 

1029 dest("".join(writer)) 

1030 writer.clear() 

1031 dest(r"\hline%") 

1032 

1033 head_names: Final[list[tuple[str, str]]] = [ 

1034 name_to_strs(d) for d in data[0]] 

1035 head_names.insert(0, ("instance", "group")) 

1036 if inst_cols > 1: 

1037 head_names.insert(0, ("instance", "group")) 

1038 head_count: Final[int] = list.__len__(head_names) 

1039 

1040 for dim in (0, 1): 

1041 i = 0 

1042 while i < head_count: 

1043 head = head_names[i] 

1044 next_i = i + 1 

1045 while (next_i < head_count) and ( 

1046 head_names[next_i][dim] == head[dim]): 

1047 next_i += 1 

1048 

1049 col_txt: str = f"\\multicolumn{{{next_i - i}}}{{" 

1050 if i <= 0: 

1051 col_txt = f"{col_txt}@{{}}" 

1052 col_txt = f"{col_txt}c" 

1053 if next_i >= head_count: 

1054 col_txt = f"{col_txt}@{{}}" 

1055 col_txt = f"{col_txt}}}{{{head[dim]}}}" 

1056 if next_i >= head_count: 

1057 col_txt = f"{col_txt}\\\\%" 

1058 writer.append(col_txt) 

1059 i = next_i 

1060 dest("&".join(writer)) 

1061 writer.clear() 

1062 last_first_name = "" 

1063 

1064 count_best: list[tuple[str, list[int]]] = [] 

1065 count_as: dict[Element, list[list[int]]] = {} 

1066 for count_this, title in count_best_over: 

1067 lst: list[int] = [0] * tuple.__len__(data[0]) 

1068 count_best.append((title, lst)) 

1069 for k in count_this: 

1070 if k in count_as: 

1071 count_as[k].append(lst) 

1072 else: 

1073 count_as[k] = [lst] 

1074 

1075 for i, data_row in enumerate(data[1]): 

1076 inst_name: tuple[str, str] = inst_names[i] 

1077 if inst_name[0] != last_first_name: 

1078 last_first_name = inst_name[0] 

1079 dest(r"\hline%") 

1080 writer.append(last_first_name) 

1081 if inst_cols > 1: 

1082 in1: str = str.strip(inst_name[1]) 

1083 if str.__len__(in1) > 0: 

1084 in1 = str.strip(f"/{in1}") 

1085 if str.__len__(in1) <= 1: 

1086 in1 = "" 

1087 writer.append(in1) 

1088 

1089 row_data: tuple[int | float | None, ...] = data_row[1] 

1090 minimum: int | float = inf 

1091 for ddd in row_data: 

1092 if (ddd is not None) and (ddd < minimum): 

1093 minimum = ddd 

1094 if not isfinite(minimum): 

1095 raise ValueError(f"Huuhhh? {inst_name} has non-finite min?") 

1096 instance: Element = data_row[0] 

1097 for iij, ddd in enumerate(row_data): 

1098 if ddd is None: 

1099 writer.append("") 

1100 continue 

1101 writer.append( 

1102 format_best(str(ddd)) if ddd <= minimum else str(ddd)) 

1103 if (ddd <= minimum) and (instance in count_as): 

1104 for lst in count_as[instance]: 

1105 lst[iij] += 1 

1106 dest(f"{'&'.join(writer)}\\\\%") 

1107 writer.clear() 

1108 

1109 dest(r"\hline%") 

1110 if list.__len__(count_best) > 0: 

1111 for brow in count_best: 

1112 writer.append( 

1113 f"\\multicolumn{{{inst_cols}}}{{@{{}}r}}{{{brow[0]}}}") 

1114 writer.extend(map(str, brow[1])) 

1115 writer[-1] = f"{writer[-1]}\\\\%" 

1116 dest("&".join(writer)) 

1117 dest(r"\hline%") 

1118 dest(r"\end{tabular}%") 

1119 dest("% end auto-generated LaTeX table comparing " 

1120 "end results with related work.%")