From 3660dc994eeab722a397a32680382da614468184 Mon Sep 17 00:00:00 2001 From: ktz03 <2484593937@qq.com> Date: Sun, 11 Oct 2026 14:30:12 +0800 Subject: [PATCH 1/2] Fix load-state parameter key validation --- bayes_opt/bayesian_optimization.py | 4 ++++ tests/test_bayesian_optimization.py | 23 +++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/bayes_opt/bayesian_optimization.py b/bayes_opt/bayesian_optimization.py index 828bff27..737cb0e8 100644 --- a/bayes_opt/bayesian_optimization.py +++ b/bayes_opt/bayesian_optimization.py @@ -456,6 +456,10 @@ def _load_state_dict(self, state: dict[str, Any]) -> None: state : dict Dictionary containing the optimizer state. """ + if state["keys"] != self._space.keys: + msg = "Saved state must have the same parameter keys in the same order as the optimizer." + raise ValueError(msg) + params_array = np.asarray(state["params"], dtype=np.float64) target_array = np.asarray(state["target"], dtype=np.float64) constraint_array = ( diff --git a/tests/test_bayesian_optimization.py b/tests/test_bayesian_optimization.py index 7fb9f4de..90f01056 100644 --- a/tests/test_bayesian_optimization.py +++ b/tests/test_bayesian_optimization.py @@ -368,6 +368,29 @@ def test_save_load_state(tmp_path): np.testing.assert_array_equal(optimizer.space.target, new_optimizer.space.target) +@pytest.mark.parametrize("saved_points", [False, True]) +@pytest.mark.parametrize("existing_points", [False, True]) +@pytest.mark.parametrize("pbounds", [{"p2": (0, 10), "p1": (0, 10)}, {"width": (0, 10), "height": (0, 10)}]) +def test_load_state_rejects_incompatible_keys(tmp_path, saved_points, existing_points, pbounds): + original = BayesianOptimization(target_func, PBOUNDS, random_state=1, verbose=0) + if saved_points: + original.probe({"p1": 1, "p2": 2}, lazy=False) + state_path = tmp_path / "optimizer_state.json" + original.save_state(state_path) + + restored = BayesianOptimization(target_func, pbounds, random_state=7, verbose=0) + if existing_points: + restored.probe(dict.fromkeys(pbounds, 0), lazy=False) + before = restored.res + + with pytest.raises(ValueError, match="parameter keys.*same order"): + restored.load_state(state_path) + + assert restored.res == before + control = BayesianOptimization(target_func, pbounds, random_state=7, verbose=0) + assert restored.random_sample(2) == control.random_sample(2) + + def test_save_load_w_categorical_params(tmp_path): """Test saving and loading optimizer state with categorical parameters.""" From e47d1a3fc583fe4bc4836c8c5deace16e99d2ccf Mon Sep 17 00:00:00 2001 From: ktz03 <2484593937@qq.com> Date: Sun, 11 Oct 2026 14:43:17 +0800 Subject: [PATCH 2/2] Document incompatible-state regression coverage --- tests/test_bayesian_optimization.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_bayesian_optimization.py b/tests/test_bayesian_optimization.py index 90f01056..2788e192 100644 --- a/tests/test_bayesian_optimization.py +++ b/tests/test_bayesian_optimization.py @@ -372,6 +372,7 @@ def test_save_load_state(tmp_path): @pytest.mark.parametrize("existing_points", [False, True]) @pytest.mark.parametrize("pbounds", [{"p2": (0, 10), "p1": (0, 10)}, {"width": (0, 10), "height": (0, 10)}]) def test_load_state_rejects_incompatible_keys(tmp_path, saved_points, existing_points, pbounds): + """Reject incompatible keys without changing results or random-state progression.""" original = BayesianOptimization(target_func, PBOUNDS, random_state=1, verbose=0) if saved_points: original.probe({"p1": 1, "p2": 2}, lazy=False)