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

24 statements  

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

1"""Minimize the sum of the work times of all machines in `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@numba.njit(nogil=True, cache=True) 

13def worktime(x: Gantt) -> int: 

14 """ 

15 Get the work time of all machines in a given `Gantt` chart. 

16 

17 We assume that a machine is turned on when its first job/operation begins 

18 and is turned off when the last job/operation on it ends. 

19 During all the time inbetween, the machine is on and a worker needs to be 

20 present. 

21 The work time therefore corresponds to the sum of the time units when the 

22 machines can be turned off minus the time units at which they are turned 

23 on. 

24 

25 :param x: the Gantt chart. 

26 :return: the end times minus the start times 

27 """ 

28 return int(x[:, -1, 2].sum()) - int(x[:, 0, 2].sum()) 

29 

30 

31class Worktime(Objective): 

32 """Compute the work time of a `Gantt` chart (for minimization).""" 

33 

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

35 """ 

36 Initialize the worktime objective function. 

37 

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

39 """ 

40 super().__init__() 

41 if not isinstance(instance, Instance): 

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

43 #: the internal instance reference 

44 self.__instance: Final[Instance] = instance 

45 #: The fast call forwarding to the worktime function. # +book 

46 self.evaluate = worktime # type: ignore # +book 

47 

48 def lower_bound(self) -> int: 

49 """ 

50 Get the lower bound of the worktime. 

51 

52 :return: the lower bound 

53 """ 

54 return self.__instance.makespan_lower_bound \ 

55 + self.__instance.machines - 1 

56 

57 def is_always_integer(self) -> bool: 

58 """ 

59 Return `True` because :func:`worktime` always returns `int` values. 

60 

61 :retval True: always 

62 """ 

63 return True 

64 

65 def upper_bound(self) -> int: 

66 """ 

67 Get the upper bound of the worktime. 

68 

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

70 """ 

71 return self.__instance.makespan_upper_bound * self.__instance.machines 

72 

73 def __str__(self) -> str: 

74 """ 

75 Get the name of the worktime objective function. 

76 

77 :return: `worktime` 

78 :retval "worktime": always 

79 """ 

80 return "worktime"