Skip to content

Replace event based logging #557

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Apr 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions bayes_opt/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
import importlib.metadata

from bayes_opt import acquisition
from bayes_opt.bayesian_optimization import BayesianOptimization, Events
from bayes_opt.bayesian_optimization import BayesianOptimization
from bayes_opt.constraint import ConstraintModel
from bayes_opt.domain_reduction import SequentialDomainReductionTransformer
from bayes_opt.logger import JSONLogger, ScreenLogger
from bayes_opt.logger import ScreenLogger
from bayes_opt.target_space import TargetSpace

__version__ = importlib.metadata.version("bayesian-optimization")
Expand All @@ -19,8 +19,6 @@
"BayesianOptimization",
"TargetSpace",
"ConstraintModel",
"Events",
"ScreenLogger",
"JSONLogger",
"SequentialDomainReductionTransformer",
]
63 changes: 18 additions & 45 deletions bayes_opt/bayesian_optimization.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,13 @@
from bayes_opt import acquisition
from bayes_opt.constraint import ConstraintModel
from bayes_opt.domain_reduction import DomainTransformer
from bayes_opt.event import DEFAULT_EVENTS, Events
from bayes_opt.logger import _get_default_logger
from bayes_opt.logger import ScreenLogger
from bayes_opt.parameter import wrap_kernel
from bayes_opt.target_space import TargetSpace
from bayes_opt.util import ensure_rng

if TYPE_CHECKING:
from collections.abc import Callable, Iterable, Mapping
from collections.abc import Callable, Mapping

from numpy.random import RandomState
from numpy.typing import NDArray
Expand All @@ -41,35 +40,7 @@
Float = np.floating[Any]


class Observable:
"""Inspired by https://www.protechtraining.com/blog/post/879#simple-observer."""

def __init__(self, events: Iterable[Any]) -> None:
# maps event names to subscribers
# str -> dict
self._events = {event: dict() for event in events}

def get_subscribers(self, event: Any) -> Any:
"""Return the subscribers of an event."""
return self._events[event]

def subscribe(self, event: Any, subscriber: Any, callback: Callable[..., Any] | None = None) -> None:
"""Add subscriber to an event."""
if callback is None:
callback = subscriber.update
self.get_subscribers(event)[subscriber] = callback

def unsubscribe(self, event: Any, subscriber: Any) -> None:
"""Remove a subscriber for a particular event."""
del self.get_subscribers(event)[subscriber]

def dispatch(self, event: Any) -> None:
"""Trigger callbacks for subscribers of an event."""
for callback in self.get_subscribers(event).values():
callback(event, self)


class BayesianOptimization(Observable):
class BayesianOptimization:
"""Handle optimization of a target function over a specific target space.

This class takes the function to optimize as well as the parameters bounds
Expand Down Expand Up @@ -173,7 +144,9 @@ def __init__(
self._bounds_transformer.initialize(self._space)

self._sorting_warning_already_shown = False # TODO: remove in future version
super().__init__(events=DEFAULT_EVENTS)

# Initialize logger
self.logger = ScreenLogger(verbose=self._verbose, is_constrained=self.is_constrained)

@property
def space(self) -> TargetSpace:
Expand Down Expand Up @@ -236,7 +209,9 @@ def register(
warn(msg, stacklevel=1)
self._sorting_warning_already_shown = True
self._space.register(params, target, constraint_value)
self.dispatch(Events.OPTIMIZATION_STEP)
self.logger.log_optimization_step(
self._space.keys, self._space.res()[-1], self._space.params_config, self.max
)

def probe(self, params: ParamsType, lazy: bool = True) -> None:
"""Evaluate the function at the given points.
Expand Down Expand Up @@ -268,7 +243,9 @@ def probe(self, params: ParamsType, lazy: bool = True) -> None:
self._queue.append(params)
else:
self._space.probe(params)
self.dispatch(Events.OPTIMIZATION_STEP)
self.logger.log_optimization_step(
self._space.keys, self._space.res()[-1], self._space.params_config, self.max
)

def suggest(self) -> dict[str, float | NDArray[Float]]:
"""Suggest a promising point to probe next."""
Expand All @@ -295,13 +272,6 @@ def _prime_queue(self, init_points: int) -> None:
sample = self._space.random_sample(random_state=self._random_state)
self._queue.append(self._space.array_to_params(sample))

def _prime_subscriptions(self) -> None:
if not any([len(subs) for subs in self._events.values()]):
_logger = _get_default_logger(self._verbose, self.is_constrained)
self.subscribe(Events.OPTIMIZATION_START, _logger)
self.subscribe(Events.OPTIMIZATION_STEP, _logger)
self.subscribe(Events.OPTIMIZATION_END, _logger)

def maximize(self, init_points: int = 5, n_iter: int = 25) -> None:
r"""
Maximize the given function over the target space.
Expand All @@ -324,8 +294,10 @@ def maximize(self, init_points: int = 5, n_iter: int = 25) -> None:
optimization routine, make sure to fit it manually, e.g. by calling
``optimizer._gp.fit(optimizer.space.params, optimizer.space.target)``.
"""
self._prime_subscriptions()
self.dispatch(Events.OPTIMIZATION_START)
# Log optimization start
self.logger.log_optimization_start(self._space.keys)

# Prime the queue with random points
self._prime_queue(init_points)

iteration = 0
Expand All @@ -342,7 +314,8 @@ def maximize(self, init_points: int = 5, n_iter: int = 25) -> None:
# the init_points points (only for the true iterations)
self.set_bounds(self._bounds_transformer.transform(self._space))

self.dispatch(Events.OPTIMIZATION_END)
# Log optimization end
self.logger.log_optimization_end()

def set_bounds(self, new_bounds: BoundsMapping) -> None:
"""Modify the bounds of the search space.
Expand Down
17 changes: 0 additions & 17 deletions bayes_opt/event.py

This file was deleted.

Loading