55import numpy as np
66import pytest
77from scipy .spatial .distance import pdist
8+ from scipy .optimize import NonlinearConstraint
89from sklearn .gaussian_process import GaussianProcessRegressor
910
10- from bayes_opt import acquisition , exception
11+ from bayes_opt import acquisition , exception , BayesianOptimization
1112from bayes_opt .constraint import ConstraintModel
1213from bayes_opt .target_space import TargetSpace
14+ from bayes_opt .acquisition import (
15+ UpperConfidenceBound ,
16+ ProbabilityOfImprovement ,
17+ ExpectedImprovement ,
18+ ConstantLiar ,
19+ GPHedge
20+ )
21+
22+ # Test fixtures
23+ @pytest .fixture
24+ def target_func_x_and_y ():
25+ return lambda x , y : - (x - 1 )** 2 - (y - 2 )** 2
26+
27+
28+ @pytest .fixture
29+ def pbounds ():
30+ return {"x" : (- 5 , 5 ), "y" : (- 5 , 5 )}
31+
1332
33+ @pytest .fixture
34+ def constraint (constraint_func ):
35+ return NonlinearConstraint (
36+ fun = constraint_func ,
37+ lb = - 1.0 ,
38+ ub = 4.0
39+ )
1440
1541@pytest .fixture
1642def target_func ():
@@ -32,6 +58,11 @@ def target_space(target_func):
3258 return TargetSpace (target_func = target_func , pbounds = {"x" : (1 , 4 ), "y" : (0 , 3.0 )})
3359
3460
61+ @pytest .fixture
62+ def constraint_func ():
63+ return lambda x , y : x + y
64+
65+
3566@pytest .fixture
3667def constrained_target_space (target_func ):
3768 constraint_model = ConstraintModel (fun = lambda params : params ["x" ] + params ["y" ], lb = 0.0 , ub = 1.0 )
@@ -357,3 +388,218 @@ def test_gphedge_integration(gp, target_space, random_state):
357388def test_upper_confidence_bound_invalid_kappa_error (kappa : float ):
358389 with pytest .raises (ValueError , match = "kappa must be greater than or equal to 0." ):
359390 acquisition .UpperConfidenceBound (kappa = kappa )
391+
392+
393+ def verify_optimizers_match (optimizer1 , optimizer2 ):
394+ """Helper function to verify two optimizers match."""
395+ assert len (optimizer1 .space ) == len (optimizer2 .space )
396+ assert optimizer1 .max ["target" ] == optimizer2 .max ["target" ]
397+ assert optimizer1 .max ["params" ] == optimizer2 .max ["params" ]
398+
399+
400+
401+ np .testing .assert_array_equal (optimizer1 .space .params , optimizer2 .space .params )
402+ np .testing .assert_array_equal (optimizer1 .space .target , optimizer2 .space .target )
403+
404+ if optimizer1 .is_constrained :
405+ np .testing .assert_array_equal (
406+ optimizer1 .space ._constraint_values ,
407+ optimizer2 .space ._constraint_values
408+ )
409+ assert optimizer1 .space ._constraint .lb == optimizer2 .space ._constraint .lb
410+ assert optimizer1 .space ._constraint .ub == optimizer2 .space ._constraint .ub
411+
412+ assert np .random .get_state ()[1 ][0 ] == np .random .get_state ()[1 ][0 ]
413+
414+ assert optimizer1 ._gp .kernel .get_params () == optimizer2 ._gp .kernel .get_params ()
415+
416+ suggestion1 = optimizer1 .suggest ()
417+ suggestion2 = optimizer2 .suggest ()
418+ assert suggestion1 == suggestion2 , f"\n Suggestion 1: { suggestion1 } \n Suggestion 2: { suggestion2 } "
419+
420+
421+
422+
423+ def test_integration_upper_confidence_bound (target_func_x_and_y , pbounds , tmp_path ):
424+ """Test save/load integration with UpperConfidenceBound acquisition."""
425+ acquisition_function = UpperConfidenceBound (kappa = 2.576 )
426+
427+ # Create and run first optimizer
428+ optimizer = BayesianOptimization (
429+ f = target_func_x_and_y ,
430+ pbounds = pbounds ,
431+ acquisition_function = acquisition_function ,
432+ random_state = 1 ,
433+ verbose = 0
434+ )
435+ optimizer .maximize (init_points = 2 , n_iter = 3 )
436+
437+ # Save state
438+ state_path = tmp_path / "ucb_state.json"
439+ optimizer .save_state (state_path )
440+
441+ # Create new optimizer and load state
442+ new_optimizer = BayesianOptimization (
443+ f = target_func_x_and_y ,
444+ pbounds = pbounds ,
445+ acquisition_function = UpperConfidenceBound (kappa = 2.576 ),
446+ random_state = 1 ,
447+ verbose = 0
448+ )
449+ new_optimizer .load_state (state_path )
450+
451+ verify_optimizers_match (optimizer , new_optimizer )
452+
453+ def test_integration_probability_improvement (target_func_x_and_y , pbounds , tmp_path ):
454+ """Test save/load integration with ProbabilityOfImprovement acquisition."""
455+ acquisition_function = ProbabilityOfImprovement (xi = 0.01 )
456+
457+ optimizer = BayesianOptimization (
458+ f = target_func_x_and_y ,
459+ pbounds = pbounds ,
460+ acquisition_function = acquisition_function ,
461+ random_state = 1 ,
462+ verbose = 0
463+ )
464+ optimizer .maximize (init_points = 2 , n_iter = 3 )
465+
466+ state_path = tmp_path / "pi_state.json"
467+ optimizer .save_state (state_path )
468+
469+ new_optimizer = BayesianOptimization (
470+ f = target_func_x_and_y ,
471+ pbounds = pbounds ,
472+ acquisition_function = ProbabilityOfImprovement (xi = 0.01 ),
473+ random_state = 1 ,
474+ verbose = 0
475+ )
476+ new_optimizer .load_state (state_path )
477+
478+ verify_optimizers_match (optimizer , new_optimizer )
479+
480+ def test_integration_expected_improvement (target_func_x_and_y , pbounds , tmp_path ):
481+ """Test save/load integration with ExpectedImprovement acquisition."""
482+ acquisition_function = ExpectedImprovement (xi = 0.01 )
483+
484+ optimizer = BayesianOptimization (
485+ f = target_func_x_and_y ,
486+ pbounds = pbounds ,
487+ acquisition_function = acquisition_function ,
488+ random_state = 1 ,
489+ verbose = 0
490+ )
491+ optimizer .maximize (init_points = 2 , n_iter = 3 )
492+
493+ state_path = tmp_path / "ei_state.json"
494+ optimizer .save_state (state_path )
495+
496+ new_optimizer = BayesianOptimization (
497+ f = target_func_x_and_y ,
498+ pbounds = pbounds ,
499+ acquisition_function = ExpectedImprovement (xi = 0.01 ),
500+ random_state = 1 ,
501+ verbose = 0
502+ )
503+ new_optimizer .load_state (state_path )
504+
505+ verify_optimizers_match (optimizer , new_optimizer )
506+
507+ def test_integration_constant_liar (target_func_x_and_y , pbounds , tmp_path ):
508+ """Test save/load integration with ConstantLiar acquisition."""
509+ base_acq = UpperConfidenceBound (kappa = 2.576 )
510+ acquisition_function = ConstantLiar (base_acquisition = base_acq )
511+
512+ optimizer = BayesianOptimization (
513+ f = target_func_x_and_y ,
514+ pbounds = pbounds ,
515+ acquisition_function = acquisition_function ,
516+ random_state = 1 ,
517+ verbose = 0
518+ )
519+ optimizer .maximize (init_points = 2 , n_iter = 3 )
520+
521+ state_path = tmp_path / "cl_state.json"
522+ optimizer .save_state (state_path )
523+
524+ new_optimizer = BayesianOptimization (
525+ f = target_func_x_and_y ,
526+ pbounds = pbounds ,
527+ acquisition_function = ConstantLiar (base_acquisition = UpperConfidenceBound (kappa = 2.576 )),
528+ random_state = 1 ,
529+ verbose = 0
530+ )
531+ new_optimizer .load_state (state_path )
532+
533+ verify_optimizers_match (optimizer , new_optimizer )
534+
535+ def test_integration_gp_hedge (target_func_x_and_y , pbounds , tmp_path ):
536+ """Test save/load integration with GPHedge acquisition."""
537+ base_acquisitions = [
538+ UpperConfidenceBound (kappa = 2.576 ),
539+ ProbabilityOfImprovement (xi = 0.01 ),
540+ ExpectedImprovement (xi = 0.01 )
541+ ]
542+ acquisition_function = GPHedge (base_acquisitions = base_acquisitions )
543+
544+ optimizer = BayesianOptimization (
545+ f = target_func_x_and_y ,
546+ pbounds = pbounds ,
547+ acquisition_function = acquisition_function ,
548+ random_state = 1 ,
549+ verbose = 0
550+ )
551+ optimizer .maximize (init_points = 2 , n_iter = 3 )
552+
553+ state_path = tmp_path / "gphedge_state.json"
554+ optimizer .save_state (state_path )
555+
556+ new_base_acquisitions = [
557+ UpperConfidenceBound (kappa = 2.576 ),
558+ ProbabilityOfImprovement (xi = 0.01 ),
559+ ExpectedImprovement (xi = 0.01 )
560+ ]
561+ new_optimizer = BayesianOptimization (
562+ f = target_func_x_and_y ,
563+ pbounds = pbounds ,
564+ acquisition_function = GPHedge (base_acquisitions = new_base_acquisitions ),
565+ random_state = 1 ,
566+ verbose = 0
567+ )
568+ new_optimizer .load_state (state_path )
569+
570+ # Print new optimizer state
571+ print ("\n New Optimizer State:" )
572+ print (f"GP random state: { new_optimizer ._gp .random_state } " )
573+ print (f"GP kernel params:\n { new_optimizer ._gp .kernel_ .get_params ()} " )
574+ print (f"Global random state: { np .random .get_state ()[1 ][0 ]} " )
575+
576+ verify_optimizers_match (optimizer , new_optimizer )
577+
578+ def test_integration_constrained (target_func_x_and_y , pbounds , constraint , tmp_path ):
579+ """Test save/load integration with constraints."""
580+ acquisition_function = ExpectedImprovement (xi = 0.01 )
581+
582+ optimizer = BayesianOptimization (
583+ f = target_func_x_and_y ,
584+ pbounds = pbounds ,
585+ acquisition_function = acquisition_function ,
586+ constraint = constraint ,
587+ random_state = 1 ,
588+ verbose = 0
589+ )
590+ optimizer .maximize (init_points = 2 , n_iter = 3 )
591+
592+ state_path = tmp_path / "constrained_state.json"
593+ optimizer .save_state (state_path )
594+
595+ new_optimizer = BayesianOptimization (
596+ f = target_func_x_and_y ,
597+ pbounds = pbounds ,
598+ acquisition_function = ExpectedImprovement (xi = 0.01 ),
599+ constraint = constraint ,
600+ random_state = 1 ,
601+ verbose = 0
602+ )
603+ new_optimizer .load_state (state_path )
604+
605+ verify_optimizers_match (optimizer , new_optimizer )
0 commit comments