From a344b8a803ec035d702c764fca6655e54cc220d4 Mon Sep 17 00:00:00 2001 From: spline2hg <181270613+spline2hg@users.noreply.github.com> Date: Mon, 23 Jun 2025 18:57:01 +0000 Subject: [PATCH 1/5] Add paramter validation --- bayes_opt/acquisition.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/bayes_opt/acquisition.py b/bayes_opt/acquisition.py index 546ca7be5..3f118bd92 100644 --- a/bayes_opt/acquisition.py +++ b/bayes_opt/acquisition.py @@ -452,6 +452,12 @@ def __init__( if kappa < 0: error_msg = "kappa must be greater than or equal to 0." raise ValueError(error_msg) + if exploration_decay is not None and not (0 < exploration_decay <= 1): + error_msg = "exploration_decay must be greater than 0 and less than or equal to 1." + raise ValueError(error_msg) + if exploration_decay_delay is not None and (not isinstance(exploration_decay_delay, int) or exploration_decay_delay < 0): + error_msg = "exploration_decay_delay must be an integer greater than or equal to 0." + raise ValueError(error_msg) super().__init__(random_state=random_state) self.kappa = kappa @@ -604,6 +610,16 @@ def __init__( exploration_decay_delay: int | None = None, random_state: int | RandomState | None = None, ) -> None: + if xi <= 0: + error_msg = "xi must be greater than 0." + raise ValueError(error_msg) + if exploration_decay is not None and not (0 < exploration_decay <= 1): + error_msg = "exploration_decay must be greater than 0 and less than or equal to 1." + raise ValueError(error_msg) + if exploration_decay_delay is not None and (not isinstance(exploration_decay_delay, int) or exploration_decay_delay < 0): + error_msg = "exploration_decay_delay must be an integer greater than or equal to 0." + raise ValueError(error_msg) + super().__init__(random_state=random_state) self.xi = xi self.exploration_decay = exploration_decay @@ -778,6 +794,16 @@ def __init__( exploration_decay_delay: int | None = None, random_state: int | RandomState | None = None, ) -> None: + if xi <= 0: + error_msg = "xi must be greater than 0." + raise ValueError(error_msg) + if exploration_decay is not None and not (0 < exploration_decay <= 1): + error_msg = "exploration_decay must be greater than 0 and less than or equal to 1." + raise ValueError(error_msg) + if exploration_decay_delay is not None and (not isinstance(exploration_decay_delay, int) or exploration_decay_delay < 0): + error_msg = "exploration_decay_delay must be an integer greater than or equal to 0." + raise ValueError(error_msg) + super().__init__(random_state=random_state) self.xi = xi self.exploration_decay = exploration_decay From 8f70b2d7b83cc18e503acda97d21020be91bf072 Mon Sep 17 00:00:00 2001 From: spline2hg <181270613+spline2hg@users.noreply.github.com> Date: Wed, 25 Jun 2025 00:35:35 +0530 Subject: [PATCH 2/5] fix: pre-commit --- bayes_opt/acquisition.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/bayes_opt/acquisition.py b/bayes_opt/acquisition.py index 3f118bd92..8100add9a 100644 --- a/bayes_opt/acquisition.py +++ b/bayes_opt/acquisition.py @@ -455,7 +455,9 @@ def __init__( if exploration_decay is not None and not (0 < exploration_decay <= 1): error_msg = "exploration_decay must be greater than 0 and less than or equal to 1." raise ValueError(error_msg) - if exploration_decay_delay is not None and (not isinstance(exploration_decay_delay, int) or exploration_decay_delay < 0): + if exploration_decay_delay is not None and ( + not isinstance(exploration_decay_delay, int) or exploration_decay_delay < 0 + ): error_msg = "exploration_decay_delay must be an integer greater than or equal to 0." raise ValueError(error_msg) @@ -616,7 +618,9 @@ def __init__( if exploration_decay is not None and not (0 < exploration_decay <= 1): error_msg = "exploration_decay must be greater than 0 and less than or equal to 1." raise ValueError(error_msg) - if exploration_decay_delay is not None and (not isinstance(exploration_decay_delay, int) or exploration_decay_delay < 0): + if exploration_decay_delay is not None and ( + not isinstance(exploration_decay_delay, int) or exploration_decay_delay < 0 + ): error_msg = "exploration_decay_delay must be an integer greater than or equal to 0." raise ValueError(error_msg) @@ -800,10 +804,12 @@ def __init__( if exploration_decay is not None and not (0 < exploration_decay <= 1): error_msg = "exploration_decay must be greater than 0 and less than or equal to 1." raise ValueError(error_msg) - if exploration_decay_delay is not None and (not isinstance(exploration_decay_delay, int) or exploration_decay_delay < 0): + if exploration_decay_delay is not None and ( + not isinstance(exploration_decay_delay, int) or exploration_decay_delay < 0 + ): error_msg = "exploration_decay_delay must be an integer greater than or equal to 0." raise ValueError(error_msg) - + super().__init__(random_state=random_state) self.xi = xi self.exploration_decay = exploration_decay From 0a3884f81e4f54f6226c056ad7d029f111fffce4 Mon Sep 17 00:00:00 2001 From: spline2hg <181270613+spline2hg@users.noreply.github.com> Date: Fri, 27 Jun 2025 03:16:09 +0530 Subject: [PATCH 3/5] fix: xi --- bayes_opt/acquisition.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bayes_opt/acquisition.py b/bayes_opt/acquisition.py index 8100add9a..73279221a 100644 --- a/bayes_opt/acquisition.py +++ b/bayes_opt/acquisition.py @@ -612,8 +612,8 @@ def __init__( exploration_decay_delay: int | None = None, random_state: int | RandomState | None = None, ) -> None: - if xi <= 0: - error_msg = "xi must be greater than 0." + if xi < 0: + error_msg = "xi must be greater than equal to 0." raise ValueError(error_msg) if exploration_decay is not None and not (0 < exploration_decay <= 1): error_msg = "exploration_decay must be greater than 0 and less than or equal to 1." @@ -798,8 +798,8 @@ def __init__( exploration_decay_delay: int | None = None, random_state: int | RandomState | None = None, ) -> None: - if xi <= 0: - error_msg = "xi must be greater than 0." + if xi < 0: + error_msg = "xi must be greater than equal to 0." raise ValueError(error_msg) if exploration_decay is not None and not (0 < exploration_decay <= 1): error_msg = "exploration_decay must be greater than 0 and less than or equal to 1." From 1169da540f88c9f7a5599e34ca99b237485301cc Mon Sep 17 00:00:00 2001 From: spline2hg <181270613+spline2hg@users.noreply.github.com> Date: Fri, 27 Jun 2025 18:59:55 +0530 Subject: [PATCH 4/5] fix: docstrings --- bayes_opt/acquisition.py | 1 + bayes_opt/bayesian_optimization.py | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/bayes_opt/acquisition.py b/bayes_opt/acquisition.py index 73279221a..d67b18f2b 100644 --- a/bayes_opt/acquisition.py +++ b/bayes_opt/acquisition.py @@ -786,6 +786,7 @@ class ExpectedImprovement(AcquisitionFunction): Decay rate for xi. If None, no decay is applied. exploration_decay_delay : int, default None + Delay for decay. If None, decay is applied from the start. random_state : int, RandomState, default None Set the random state for reproducibility. diff --git a/bayes_opt/bayesian_optimization.py b/bayes_opt/bayesian_optimization.py index 443cdc065..0df53b6d0 100644 --- a/bayes_opt/bayesian_optimization.py +++ b/bayes_opt/bayesian_optimization.py @@ -55,6 +55,11 @@ class BayesianOptimization: Dictionary with parameters names as keys and a tuple with minimum and maximum values. + acquisition_function: AcquisitionFunction, optional(default=None) + The acquisition function to use for suggesting new points to evaluate. + If None, defaults to UpperConfidenceBound for unconstrained problems + and ExpectedImprovement for constrained problems. + constraint: NonlinearConstraint. Note that the names of arguments of the constraint function and of f need to be the same. From 44b57e8af9b69aef1845892cea535af937c0a8e1 Mon Sep 17 00:00:00 2001 From: spline2hg <181270613+spline2hg@users.noreply.github.com> Date: Fri, 27 Jun 2025 19:37:39 +0530 Subject: [PATCH 5/5] add tests --- bayes_opt/acquisition.py | 4 +-- tests/test_acquisition.py | 60 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/bayes_opt/acquisition.py b/bayes_opt/acquisition.py index d67b18f2b..4c8c71911 100644 --- a/bayes_opt/acquisition.py +++ b/bayes_opt/acquisition.py @@ -613,7 +613,7 @@ def __init__( random_state: int | RandomState | None = None, ) -> None: if xi < 0: - error_msg = "xi must be greater than equal to 0." + error_msg = "xi must be greater than or equal to 0." raise ValueError(error_msg) if exploration_decay is not None and not (0 < exploration_decay <= 1): error_msg = "exploration_decay must be greater than 0 and less than or equal to 1." @@ -800,7 +800,7 @@ def __init__( random_state: int | RandomState | None = None, ) -> None: if xi < 0: - error_msg = "xi must be greater than equal to 0." + error_msg = "xi must be greater than or equal to 0." raise ValueError(error_msg) if exploration_decay is not None and not (0 < exploration_decay <= 1): error_msg = "exploration_decay must be greater than 0 and less than or equal to 1." diff --git a/tests/test_acquisition.py b/tests/test_acquisition.py index 30150bcfd..efb7bb5f4 100644 --- a/tests/test_acquisition.py +++ b/tests/test_acquisition.py @@ -377,6 +377,66 @@ def test_upper_confidence_bound_invalid_kappa_error(kappa: float): acquisition.UpperConfidenceBound(kappa=kappa) +@pytest.mark.parametrize("exploration_decay", [-0.1, 0.0, 1.1, 2.0, np.inf]) +def test_upper_confidence_bound_invalid_exploration_decay_error(exploration_decay: float): + with pytest.raises( + ValueError, match="exploration_decay must be greater than 0 and less than or equal to 1." + ): + acquisition.UpperConfidenceBound(kappa=1.0, exploration_decay=exploration_decay) + + +@pytest.mark.parametrize("exploration_decay_delay", [-1, -10, "not_an_int", 1.5]) +def test_upper_confidence_bound_invalid_exploration_decay_delay_error(exploration_decay_delay): + with pytest.raises( + ValueError, match="exploration_decay_delay must be an integer greater than or equal to 0." + ): + acquisition.UpperConfidenceBound(kappa=1.0, exploration_decay_delay=exploration_decay_delay) + + +@pytest.mark.parametrize("xi", [-0.1, -1.0, -np.inf]) +def test_probability_of_improvement_invalid_xi_error(xi: float): + with pytest.raises(ValueError, match="xi must be greater than or equal to 0."): + acquisition.ProbabilityOfImprovement(xi=xi) + + +@pytest.mark.parametrize("exploration_decay", [-0.1, 0.0, 1.1, 2.0, np.inf]) +def test_probability_of_improvement_invalid_exploration_decay_error(exploration_decay: float): + with pytest.raises( + ValueError, match="exploration_decay must be greater than 0 and less than or equal to 1." + ): + acquisition.ProbabilityOfImprovement(xi=0.01, exploration_decay=exploration_decay) + + +@pytest.mark.parametrize("exploration_decay_delay", [-1, -10, "not_an_int", 1.5]) +def test_probability_of_improvement_invalid_exploration_decay_delay_error(exploration_decay_delay): + with pytest.raises( + ValueError, match="exploration_decay_delay must be an integer greater than or equal to 0." + ): + acquisition.ProbabilityOfImprovement(xi=0.01, exploration_decay_delay=exploration_decay_delay) + + +@pytest.mark.parametrize("xi", [-0.1, -1.0, -np.inf]) +def test_expected_improvement_invalid_xi_error(xi: float): + with pytest.raises(ValueError, match="xi must be greater than or equal to 0."): + acquisition.ExpectedImprovement(xi=xi) + + +@pytest.mark.parametrize("exploration_decay", [-0.1, 0.0, 1.1, 2.0, np.inf]) +def test_expected_improvement_invalid_exploration_decay_error(exploration_decay: float): + with pytest.raises( + ValueError, match="exploration_decay must be greater than 0 and less than or equal to 1." + ): + acquisition.ExpectedImprovement(xi=0.01, exploration_decay=exploration_decay) + + +@pytest.mark.parametrize("exploration_decay_delay", [-1, -10, "not_an_int", 1.5]) +def test_expected_improvement_invalid_exploration_decay_delay_error(exploration_decay_delay): + with pytest.raises( + ValueError, match="exploration_decay_delay must be an integer greater than or equal to 0." + ): + acquisition.ExpectedImprovement(xi=0.01, exploration_decay_delay=exploration_decay_delay) + + def verify_optimizers_match(optimizer1, optimizer2): """Helper function to verify two optimizers match.""" assert len(optimizer1.space) == len(optimizer2.space)