22
33from __future__ import annotations
44
5- import json
6- from contextlib import suppress
7- from pathlib import Path
5+ from datetime import datetime
86from typing import TYPE_CHECKING , Any
97
108import numpy as np
119from colorama import Fore , just_fix_windows_console
1210
13- from bayes_opt .event import Events
14- from bayes_opt .observer import _Tracker
15-
1611if TYPE_CHECKING :
17- from os import PathLike
18-
1912 from bayes_opt .bayesian_optimization import BayesianOptimization
2013
2114just_fix_windows_console ()
2215
2316
24- def _get_default_logger (verbose : int , is_constrained : bool ) -> ScreenLogger :
25- """
26- Return the default logger.
27-
28- Parameters
29- ----------
30- verbose : int
31- Verbosity level of the logger.
32-
33- is_constrained : bool
34- Whether the underlying optimizer uses constraints (this requires
35- an additional column in the output).
36-
37- Returns
38- -------
39- ScreenLogger
40- The default logger.
41-
42- """
43- return ScreenLogger (verbose = verbose , is_constrained = is_constrained )
44-
45-
46- class ScreenLogger (_Tracker ):
17+ class ScreenLogger :
4718 """Logger that outputs text, e.g. to log to a terminal.
4819
4920 Parameters
@@ -66,7 +37,11 @@ def __init__(self, verbose: int = 2, is_constrained: bool = False) -> None:
6637 self ._verbose = verbose
6738 self ._is_constrained = is_constrained
6839 self ._header_length = None
69- super ().__init__ ()
40+ self ._iterations = 0
41+ self ._previous_max = None
42+ self ._previous_max_params = None
43+ self ._start_time = None
44+ self ._previous_time = None
7045
7146 @property
7247 def verbose (self ) -> int :
@@ -221,84 +196,76 @@ def _is_new_max(self, instance: BayesianOptimization) -> bool:
221196 self ._previous_max = instance .max ["target" ]
222197 return instance .max ["target" ] > self ._previous_max
223198
224- def update (self , event : str , instance : BayesianOptimization ) -> None :
225- """Handle incoming events .
199+ def _update_tracker (self , instance : BayesianOptimization ) -> None :
200+ """Update the tracker .
226201
227202 Parameters
228203 ----------
229- event : str
230- One of the values associated with `Events.OPTIMIZATION_START`,
231- `Events.OPTIMIZATION_STEP` or `Events.OPTIMIZATION_END`.
232-
233204 instance : bayesian_optimization.BayesianOptimization
234205 The instance associated with the step.
235206 """
236- line = ""
237- if event == Events .OPTIMIZATION_START :
238- line = self ._header (instance ) + "\n "
239- elif event == Events .OPTIMIZATION_STEP :
240- is_new_max = self ._is_new_max (instance )
241- if self ._verbose != 1 or is_new_max :
242- colour = self ._colour_new_max if is_new_max else self ._colour_regular_message
243- line = self ._step (instance , colour = colour ) + "\n "
244- elif event == Events .OPTIMIZATION_END :
245- line = "=" * self ._header_length + "\n "
207+ self ._iterations += 1
246208
247- if self ._verbose :
248- print (line , end = "" )
249- self ._update_tracker (event , instance )
250-
251-
252- class JSONLogger (_Tracker ):
253- """
254- Logger that outputs steps in JSON format.
209+ if instance .max is None :
210+ return
255211
256- The resulting file can be used to restart the optimization from an earlier state.
212+ current_max = instance . max
257213
258- Parameters
259- ----------
260- path : str or os.PathLike
261- Path to the file to write to.
214+ if self ._previous_max is None or current_max ["target" ] > self ._previous_max :
215+ self ._previous_max = current_max ["target" ]
216+ self ._previous_max_params = current_max ["params" ]
262217
263- reset : bool
264- Whether to overwrite the file if it already exists.
218+ def _time_metrics (self ) -> tuple [str , float , float ]:
219+ """Return time passed since last call."""
220+ now = datetime .now () # noqa: DTZ005
221+ if self ._start_time is None :
222+ self ._start_time = now
223+ if self ._previous_time is None :
224+ self ._previous_time = now
265225
266- """
226+ time_elapsed = now - self ._start_time
227+ time_delta = now - self ._previous_time
267228
268- def __init__ (self , path : str | PathLike [str ], reset : bool = True ):
269- self ._path = Path (path )
270- if reset :
271- with suppress (OSError ):
272- self ._path .unlink (missing_ok = True )
273- super ().__init__ ()
229+ self ._previous_time = now
230+ return (now .strftime ("%Y-%m-%d %H:%M:%S" ), time_elapsed .total_seconds (), time_delta .total_seconds ())
274231
275- def update (self , event : str , instance : BayesianOptimization ) -> None :
276- """
277- Handle incoming events.
232+ def log_optimization_start (self , instance : BayesianOptimization ) -> None :
233+ """Log the start of the optimization process.
278234
279235 Parameters
280236 ----------
281- event : str
282- One of the values associated with `Events.OPTIMIZATION_START`,
283- `Events.OPTIMIZATION_STEP` or `Events.OPTIMIZATION_END`.
284-
285- instance : bayesian_optimization.BayesianOptimization
286- The instance associated with the step.
287-
237+ instance : BayesianOptimization
238+ The instance associated with the event.
288239 """
289- if event == Events .OPTIMIZATION_STEP :
290- data = dict (instance .res [- 1 ])
240+ if self ._verbose :
241+ line = self ._header (instance ) + "\n "
242+ print (line , end = "" )
291243
292- now , time_elapsed , time_delta = self . _time_metrics ()
293- data [ "datetime" ] = { "datetime" : now , "elapsed" : time_elapsed , "delta" : time_delta }
244+ def log_optimization_step ( self , instance : BayesianOptimization ) -> None :
245+ """Log an optimization step.
294246
295- if "allowed" in data : # fix: github.com/fmfn/BayesianOptimization/issues/361
296- data ["allowed" ] = bool (data ["allowed" ])
247+ Parameters
248+ ----------
249+ instance : BayesianOptimization
250+ The instance associated with the event.
251+ """
252+ is_new_max = self ._is_new_max (instance )
253+ self ._update_tracker (instance )
297254
298- if "constraint" in data and isinstance (data ["constraint" ], np .ndarray ):
299- data ["constraint" ] = data ["constraint" ].tolist ()
255+ if self ._verbose != 1 or is_new_max :
256+ colour = self ._colour_new_max if is_new_max else self ._colour_regular_message
257+ line = self ._step (instance , colour = colour ) + "\n "
258+ if self ._verbose :
259+ print (line , end = "" )
300260
301- with self . _path . open ( "a" ) as f :
302- f . write ( json . dumps ( data ) + " \n " )
261+ def log_optimization_end ( self , instance : BayesianOptimization ) -> None :
262+ """Log the end of the optimization process.
303263
304- self ._update_tracker (event , instance )
264+ Parameters
265+ ----------
266+ instance : BayesianOptimization
267+ The instance associated with the event.
268+ """
269+ if self ._verbose and self ._header_length is not None :
270+ line = "=" * self ._header_length + "\n "
271+ print (line , end = "" )
0 commit comments