Coverage for moptipy / api / mo_process.py: 89%

19 statements  

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

1""" 

2Processes offer data to both the user and the optimization algorithm. 

3 

4They provide the information about the optimization process and its current 

5state as handed to the optimization algorithm and, after the algorithm has 

6finished, to the user. 

7This is the multi-objective version of the :class:`~moptipy.api.process.\ 

8Process`-API. 

9It supports having multiple objective functions. 

10It also provides a single core objective value, which is the scalarized 

11result of several objective values. 

12""" 

13from typing import Any, Callable, Iterable 

14 

15import numpy as np 

16 

17from moptipy.api.mo_archive import MORecord 

18from moptipy.api.mo_problem import MOProblem 

19from moptipy.api.process import Process 

20 

21 

22class MOProcess(MOProblem, Process): 

23 """ 

24 A multi-objective :class:`~moptipy.api.process.Process` API variant. 

25 

26 This class encapsulates an optimization process using multiple objective 

27 functions. It inherits all of its methods from the single-objective 

28 process :class:`~moptipy.api.process.Process` and extends its API towards 

29 multi-objective optimization by providing the functionality of the class 

30 :class:`~moptipy.api.mo_problem.MOProblem`. 

31 """ 

32 

33 def register(self, x, f: int | float) -> None: 

34 """Unavailable during multi-objective optimization.""" 

35 raise ValueError( 

36 "register is not available during multi-objective optimization.") 

37 

38 def get_archive(self) -> list[MORecord]: 

39 """ 

40 Get the archive of non-dominated solutions. 

41 

42 :returns: a list containing all non-dominated solutions currently in 

43 the archive 

44 """ 

45 

46 def check_in(self, x: Any, fs: np.ndarray, 

47 prune_if_necessary: bool = False) -> bool: 

48 """ 

49 Check a solution into the archive. 

50 

51 This method is intended for being invoked after the optimization 

52 algorithm has finished its work. The algorithm should, by itself, 

53 maintain the set of interesting solutions during its course. Once 

54 it has completed all of its computations, it should flush these 

55 solutions to the process using this method. All the non-dominated 

56 solutions preserved in the archive will then become available via 

57 :meth:`get_archive` to the code starting the optimization procedure. 

58 

59 If you have a sequence of :class:`~moptipy.api.mo_archive.MORecord` 

60 instances that you want to flush into the archive, you can use the 

61 convenience method :meth:`~check_in_all` for that purpose. 

62 

63 :param x: the point in the search space 

64 :param fs: the vector of objective values 

65 :param prune_if_necessary: should we prune the archive if it becomes 

66 too large? `False` means that the archive may grow unbounded 

67 :returns: `True` if the solution was non-dominated and has actually 

68 entered the archive, `False` if it has not entered the archive 

69 """ 

70 

71 def check_in_all(self, recs: Iterable[MORecord], 

72 prune_if_necessary: bool = False) -> None: 

73 """ 

74 Check in all the elements of an `Iterable` of `MORecord` instances. 

75 

76 This is a convenience wrapper around :meth:`~check_in`. 

77 

78 :param recs: an iterable sequence of solution + quality vector records 

79 :param prune_if_necessary: should we prune the archive if it becomes 

80 too large? `False` means that the archive may grow unbounded 

81 """ 

82 sci: Callable[[Any, np.ndarray, bool], bool] = self.check_in 

83 for r in recs: 

84 sci(r.x, r.fs, prune_if_necessary) 

85 

86 def get_copy_of_best_fs(self, fs: np.ndarray) -> None: 

87 """ 

88 Get a copy of the objective vector of the current best solution. 

89 

90 This always corresponds to the best-so-far solution based on the 

91 scalarization of the objective vector. It is the best solution that 

92 the process has seen *so far*, the current best solution. 

93 

94 You should only call this method if you are either sure that you 

95 have invoked :meth:`~moptipy.api.process.Process.evaluate`, have 

96 invoked :meth:`~moptipy.api.mo_problem.MOProblem.f_evaluate`, or 

97 have called :meth:`~moptipy.api.process.Process.has_best` before 

98 and it returned `True`. 

99 

100 :param fs: the destination vector to be overwritten 

101 

102 See Also 

103 - :meth:`~moptipy.api.process.Process.has_best` 

104 - :meth:`~moptipy.api.process.Process.get_best_f` 

105 - :meth:`~moptipy.api.process.Process.get_copy_of_best_x` 

106 - :meth:`~moptipy.api.process.Process.get_copy_of_best_y` 

107 - :meth:`~moptipy.api.mo_problem.MOProblem.f_evaluate` 

108 """ 

109 

110 def __str__(self) -> str: 

111 """ 

112 Get the name of this process implementation. 

113 

114 :return: "mo_process" 

115 """ 

116 return "mo_process" 

117 

118 def __enter__(self) -> "MOProcess": 

119 """ 

120 Begin a `with` statement. 

121 

122 :return: this process itself 

123 """ 

124 return self