Coverage for moptipyapps/prodsched/objectives/worst_service_level.py: 41%

17 statements  

« prev     ^ index     » next       coverage.py v7.16.0, created at 2026-09-12 08:11 +0000

1""" 

2Maximize the worst-case service level. 

3 

4This objective function tries to find solutions which have very robust fill 

5rates. 

6The service level is the fraction of customers that can get served directly, 

7i.e., the fraction of customers that do not need to wait. 

8This means that it is the fraction of customers whose demands can directly be 

9satisfied from the stock. 

10 

11Service levels are between 0 and 1. 

12Of course, high service levels are good and should therefore be subject to 

13maximization. 

14However, since we can only *minimize*, we minimize "1 - service level". 

15 

16Now, the question is: 

17What is a *robust* service level / solution? 

18Well, we simulate the solutions (such as re-order points) over multiple 

19instances. 

20A robust good service level would be high on the worst instance. 

21In other words, the smallest service level measured on any instance should 

22be as high as possible. 

23This means that the largest value "1 - service level" should be as small as 

24possible. 

25So we use this as result of our objective function. 

26""" 

27 

28 

29from moptipy.api.objective import Objective 

30 

31from moptipyapps.prodsched.multistatistics import MultiStatistics 

32 

33 

34class WorstFillRate(Objective): 

35 """Compute the worst service level and return `1 -` of it.""" 

36 

37 def evaluate(self, x: MultiStatistics) -> int | float: 

38 """ 

39 Get the negated worst service level. 

40 

41 :param x: the multi-statistics 

42 :return: the worst stock level 

43 """ 

44 min_imm: int | float = 1 

45 for stat in x.per_instance: 

46 for sl in stat.service_levels: 

47 if (sl is None) or not (0 < sl <= 1): 

48 return 1 

49 min_imm = min(min_imm, sl) 

50 return 1 - min_imm 

51 

52 def lower_bound(self) -> int: 

53 """ 

54 Get the lower bound of the inverted minimum service level. 

55 

56 :retval 0: always 

57 """ 

58 return 0 

59 

60 def upper_bound(self) -> int: 

61 """ 

62 Get the upper bound of the inverted minimum service level. 

63 

64 :retval 1: always 

65 """ 

66 return 1 

67 

68 def __str__(self) -> str: 

69 """ 

70 Get the name of the objective function. 

71 

72 :return: `worstFillRate` 

73 :retval "worstFillRate": always 

74 """ 

75 return "worstFillRate"