Coverage for moptipy / examples / jssp / makespan.py: 92%

24 statements  

« prev     ^ index     » next       coverage.py v7.12.0, created at 2025-11-24 08:49 +0000

1"""An objective function for minimizing the makespan of `Gantt` charts.""" 

2from typing import Final 

3 

4import numba # type: ignore 

5from pycommons.types import type_error 

6 

7from moptipy.api.objective import Objective 

8from moptipy.examples.jssp.gantt import Gantt 

9from moptipy.examples.jssp.instance import Instance 

10 

11 

12# start book 

13@numba.njit(nogil=True, cache=True) 

14def makespan(x: Gantt) -> int: 

15 """ 

16 Get the makespan corresponding to a given `Gantt` chart. 

17 

18 The makespan corresponds to the maximum of the end times of the 

19 last operation on each machine. This is jitted for performance. 

20 

21 :param x: the Gantt chart. 

22 :return: the maximum of any end time stored in the chart 

23 """ 

24 return int(x[:, -1, 2].max()) # maximum of end time of last op 

25 # end book 

26 

27 

28# start book 

29class Makespan(Objective): 

30 """Compute the makespan of a `Gantt` chart (for minimization).""" 

31 

32# end book 

33 def __init__(self, instance: Instance) -> None: # +book 

34 """ 

35 Initialize the makespan objective function. 

36 

37 :param instance: the instance to load the bounds from 

38 """ 

39 super().__init__() 

40 if not isinstance(instance, Instance): 

41 raise type_error(instance, "instance", Instance) 

42 #: the internal instance reference 

43 self.__instance: Final[Instance] = instance 

44 #: The fast call forwarding to the makespan function. # +book 

45 self.evaluate = makespan # type: ignore # +book 

46 

47 def lower_bound(self) -> int: 

48 """ 

49 Get the lower bound of the makespan. 

50 

51 :return: the lower bound 

52 """ 

53 return self.__instance.makespan_lower_bound 

54 

55 def is_always_integer(self) -> bool: 

56 """ 

57 Return `True` because :func:`makespan` always returns `int` values. 

58 

59 :retval True: always 

60 """ 

61 return True 

62 

63 def upper_bound(self) -> int: 

64 """ 

65 Get the upper bound of the makespan. 

66 

67 :return: the sum of all job execution times. 

68 """ 

69 return self.__instance.makespan_upper_bound 

70 

71 def __str__(self) -> str: 

72 """ 

73 Get the name of the makespan objective function. 

74 

75 :return: `makespan` 

76 :retval "makespan": always 

77 """ 

78 return "makespan"