Revert "fix(IPsecUtil): Delete keywords no longer used"
[csit.git] / resources / libraries / python / MLRsearch / config.py
1 # Copyright (c) 2023 Cisco and/or its affiliates.
2 # Licensed under the Apache License, Version 2.0 (the "License");
3 # you may not use this file except in compliance with the License.
4 # You may obtain a copy of the License at:
5 #
6 #     http://www.apache.org/licenses/LICENSE-2.0
7 #
8 # Unless required by applicable law or agreed to in writing, software
9 # distributed under the License is distributed on an "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 # See the License for the specific language governing permissions and
12 # limitations under the License.
13
14 """Module defining Config class."""
15
16 from collections.abc import Iterable
17 from dataclasses import dataclass
18 from typing import Optional
19
20 from .dataclass import DataclassProperty
21 from .search_goal import SearchGoal
22 from .search_goal_tuple import SearchGoalTuple
23
24
25 @dataclass
26 class Config:
27     """Structure containing several static config items.
28
29     The main MLRsearch algorithm uses multiple customizable values.
30     Pylint complains if the values appear as long argument lists
31     or multiple local variables.
32
33     This class offers a storage for values which do not contain
34     internally mutable state and are set at an unknown time
35     before the search starts. This way users can override only some values,
36     and do it over multiple calls.
37     All "official" user inputs are contained here.
38
39     Properties are defined to enforce the requirements on allowed values.
40     All fields have default values, so instances can be created without any.
41     It is still recommended to set all values after instantiation,
42     as the defaults may change in the next version.
43
44     As some relations between values of different fields are required,
45     users must take care to set them in the correct order.
46
47     For example, min_load has to be set to a value smaller
48     than the current value of max_load.
49     """
50
51     # Externally visible "fields" (but in fact redefined as properties).
52     goals: SearchGoalTuple = SearchGoalTuple((SearchGoal(),))
53     """Container holding search goals."""
54     min_load: float = 9001.0
55     """Each trial measurement must have intended load at least this [tps]."""
56     max_load: float = 1e9
57     """Each trial measurement must have intended load at most this [tps]."""
58     search_duration_max: float = 1200.0
59     """The search will end as a failure this long [s] after it is started."""
60     warmup_duration: float = 1.0
61     """If specified, one trial at max load and this duration is performed
62     before the usual search starts. None converts to zero and means no warmup.
63     The results of that one trial are ignored."""
64
65     @DataclassProperty
66     def goals(self) -> SearchGoalTuple:
67         """Return the reference to the current container of goals.
68
69         :returns: The current container instance.
70         :rtype: SearchGoalTuple
71         """
72         return self._goals
73
74     @goals.setter
75     def goals(self, goals: Iterable[SearchGoal]) -> None:
76         """Create and store the goal container.
77
78         :param goals: Search goals to add to the container to store.
79         :type goals: Iterable[SearchGoal]
80         :raises ValueError: If there are no goals.
81         :raises TypeError: If any of the goals is not a SearchGoal.
82         """
83         self._goals = SearchGoalTuple(goals)
84
85     @DataclassProperty
86     def min_load(self) -> float:
87         """Getter for min load, no logic here.
88
89         :returns: Currently set minimal intended load [tps].
90         :rtype: float
91         """
92         return self._min_load
93
94     @min_load.setter
95     def min_load(self, load: float) -> None:
96         """Set min load after converting type and checking value.
97
98         :param load: Minimal intended load [tps] to set.
99         :type load: float
100         :raises ValueError: If the argument is found invalid.
101         """
102         load = float(load)
103         if load <= 0.0:
104             raise ValueError(f"Min load {load} must be positive.")
105         # At the time init is first called, _max_load is not set yet.
106         if hasattr(self, "_max_load") and load >= self.max_load:
107             raise ValueError(f"Min load {load} must be smaller.")
108         self._min_load = load
109
110     @DataclassProperty
111     def max_load(self) -> float:
112         """Getter for max load, no logic here.
113
114         :returns: Currently set maximal intended load [tps].
115         :rtype: float
116         """
117         return self._max_load
118
119     @max_load.setter
120     def max_load(self, load: float) -> None:
121         """Set max load after converting type and checking value.
122
123         :param load: Minimal intended load [tps] to set.
124         :type load: float
125         :raises ValueError: If the argument is found invalid.
126         """
127         load = float(load)
128         if load <= self.min_load:
129             raise ValueError(f"Max load {load} must be bigger.")
130         self._max_load = load
131
132     @DataclassProperty
133     def search_duration_max(self) -> float:
134         """Getter for max search duration, no logic here.
135
136         :returns: Currently set max search duration [s].
137         :rtype: float
138         """
139         return self._search_duration_max
140
141     @search_duration_max.setter
142     def search_duration_max(self, duration: float) -> None:
143         """Set max search duration after converting and checking value.
144
145         :param duration: Search duration maximum [s] to set.
146         :type duration: float
147         :raises ValueError: If the argument is found invalid.
148         """
149         duration = float(duration)
150         if duration <= 0.0:
151             raise ValueError(f"Search duration max too small: {duration}")
152         self._search_duration_max = duration
153
154     @DataclassProperty
155     def warmup_duration(self) -> float:
156         """Getter for warmup duration, no logic here.
157
158         :returns: Currently set max search duration [s].
159         :rtype: float
160         """
161         return self._warmup_duration
162
163     @warmup_duration.setter
164     def warmup_duration(self, duration: Optional[float]) -> None:
165         """Set warmup duration after converting and checking value.
166
167         Zero duration is treated as None, meaning no warmup trial.
168
169         :param duration: Warmup duration [s] to set.
170         :type duration: Optional(float)
171         :raises ValueError: If the argument is found invalid.
172         """
173         if duration:
174             duration = float(duration)
175             if duration < 0.0:
176                 raise ValueError(f"Warmup duration too small: {duration}")
177         else:
178             duration = 0.0
179         self._warmup_duration = duration