-
Notifications
You must be signed in to change notification settings - Fork 2
/
optimize_result.py
179 lines (155 loc) · 5.89 KB
/
optimize_result.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
import copy
from importlib.metadata import version, PackageNotFoundError
import logging
import numpy as np
class OptimizeResult(dict):
"""
It represents the optimization result.
The class is based on ``scipy.optimize.OptimizeResult``.
See also: https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.OptimizeResult.html.
Attributes:
- fun: callable
- The objective function to be minimized.
- non_box_cons: callable
- Non-box constraints function (if any).
- x0: np.ndarray
- Initial starting point.
- x: np.ndarray
- The solution of the optimization.
- fval: float
- Value of objective function at solution.
- fsd: float
- Standard deviation of objective function at solution (0 if noiseless).
- yval_vec: np.ndarray
- Final sampled observations at the solution.
- ysd_vec: np.ndarray
- Standard deviations of the final sampled observations (``"yval_vec"``).
- mesh_size: float
- Final mesh size.
- func_count: int
- Number of evaluations of the objective functions.
- iterations: int
- Number of iterations performed by the optimizer.
- message: str
- Termination message.
- problem_type: str
- Type of problem (unconstrained, bound constraints, non-box constraints).
- total_time: float
- Total time taken by the optimizer.
- overhead: float
- Fractional overhead taken by the optimizer, compared to function time.
- random_seed: int
- Random seed used by the optimizer (``None`` if not set).
- version: str
- Version of the optimizer.
Parameters:
bads: pybads.BADS
- An Instance of the BADS class. It is used to set the attributes of the optimization result.
"""
_keys = [
"x",
"x0", # Initial starting point
"success",
"status",
"message",
"fun",
"func_count", # Number of evaluations of the objective functions
"iterations", # Number of iterations performed by the optimizer.
"target_type",
"problem_type",
"mesh_size",
"non_box_cons", # non_box_constraint function
"yval_vec",
"ysd_vec",
"fval",
"fsd",
"total_time",
"overhead",
"random_seed",
"algorithm",
"version",
]
def __init__(self, bads=None):
super().__init__()
if bads is not None:
self.set_attributes(bads)
def set_attributes(self, bads):
"""Set the attributes of the dictionary.
Parameters:
- bads: pybads.BADS
An Instance of the BADS class. It is used to set the attributes of the optimization result.
"""
self["fun"] = bads.function_logger.fun
self["non_box_cons"] = bads.non_box_cons
if bads.optim_state["uncertainty_handling_level"] > 0:
if bads.options["specify_target_noise"]:
self["target_type"] = "stochastic (specified noise)"
else:
self["target_type"] = "stochastic"
else:
self["target_type"] = "deterministic"
if (
np.all(np.isinf(bads.lower_bounds))
and np.all(np.isinf(bads.upper_bounds))
and bads.non_box_cons is None
):
self["problem_type"] = "unconstrained"
elif bads.non_box_cons is None:
self["problem_type"] = "bound constraints"
else:
self["problem_type"] = "non-box constraints"
self["iterations"] = bads.optim_state["iter"]
self["func_count"] = bads.function_logger.func_count
self["mesh_size"] = bads.mesh_size
self["overhead"] = bads.optim_state["overhead"]
self["algorithm"] = "Bayesian adaptive direct search"
if (
bads.optim_state["uncertainty_handling_level"] > 0
and bads.options["noise_final_samples"] > 0
):
self["yval_vec"] = bads.optim_state["yval_vec"].copy()
else:
self["yval_vec"] = None
if (
bads.options["specify_target_noise"]
and bads.options["noise_final_samples"] > 0
):
self["ysd_vec"] = bads.optim_state["ysd_vec"]
else:
self["ysd_vec"] = None
self["x0"] = bads.x0.copy()
self["x"] = bads.x.copy()
self["fval"] = bads.fval
self["fsd"] = bads.fsd
self["total_time"] = bads.optim_state["total_time"]
self["random_seed"] = bads.optim_state["random_seed"]
try:
__version__ = version("pybads")
except PackageNotFoundError:
# package is not installed
__version__ = None
logger = logging.getLogger("BADS")
logger.warning("Cannot read version number from package metadata.")
self["version"] = __version__
self[
"success"
] = True # TODO: In our case when an error occurs, the application just stops.
self["message"] = bads.optim_state["termination_msg"]
def __getattr__(self, name):
try:
return self[name]
except KeyError as e:
raise AttributeError(name) from e
def __getitem__(self, key):
return dict.__getitem__(self, key)
def __iter__(self):
yield from sorted(dict.__iter__(self))
def __len__(self):
return dict.__len__(self)
def __delitem__(self, key):
return dict.__delitem__(self, key)
def __setitem__(self, key: str, val: object):
if key not in OptimizeResult._keys:
raise ValueError("""The key is not part of OptimizeResult._keys""")
else:
dict.__setitem__(self, key, copy.deepcopy(val))