bayesian-optimization/BayesianOptimization

Suggest-Evaluate-Register paradigm not working with constraints

Vidarrwin opened this issue · 3 comments

Describe the bug
When implementing optimization using the Suggest-Evaluate-Register paradigm, second call to optimizer.suggest(util_func) in loop results in TypeError: 'NoneType' object is not subscriptable.

To Reproduce
I used the notebook constraints.ipynb to try and implement the Suggest-Evaluate-Register paradigm with constraints in the following issue_snippet.py file:

import numpy as np
from bayes_opt import BayesianOptimization
from bayes_opt import UtilityFunction
import matplotlib.pyplot as plt
from scipy.optimize import NonlinearConstraint


def target_function(x, y):
    # Gardner is looking for the minimum, but this packages looks for maxima, thus the sign switch
    return np.cos(2 * x) * np.cos(y) + np.sin(x)


def constraint_function(x, y):
    return np.cos(x) * np.cos(y) - np.sin(x) * np.sin(y)


constraint_limit = 0.5
constraint = NonlinearConstraint(constraint_function, -np.inf, constraint_limit)

# Bounded region of parameter space
pbounds = {"x": (0, 6), "y": (0, 6)}

optimizer = BayesianOptimization(
    f=None,
    constraint=constraint,
    pbounds=pbounds,
    verbose=0,  # verbose = 1 prints only when a maximum is observed, verbose = 0 is silent
    random_state=1,
)

util_func = UtilityFunction()

for i in range(20):
    next_point = optimizer.suggest(util_func)
    target = target_function(**next_point)
    constraint_value = constraint_function(next_point["x"], next_point["y"])

    optimizer.register(
        params=next_point, target=target, constraint_value=constraint_value
    )

print(optimizer.max)

Output

  File "C:\bo\issue_snippet.py", line 34, in <module>
    next_point = optimizer.suggest(util_func)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\bo\.env\Lib\site-packages\bayes_opt\bayesian_optimization.py", line 276, in suggest
    y_max_params=self._space.params_to_array(self._space.max()['params']))
                                             ~~~~~~~~~~~~~~~~~^^^^^^^^^^
TypeError: 'NoneType' object is not subscriptable

Expected output

{'target': np.float64(1.763860854788071), 'params': {'x': np.float64(1.4289811571617572), 'y': np.float64(2.5083402722272017)}, 'constraint': np.float64(-0.6997643336023384)
(or at least some result)

Expected behavior
The for loop should work and give a result.

Screenshots
If applicable, add screenshots to help explain your problem.

Environment

  • OS: Windows
  • python Version 3.12.5
  • numpy Version 2.1.1
  • scipy Version 1.14.1
  • bayesian-optimization Version 1.5.1

Additional context
Hello there!

First thank you for your work :)

I wanted to optimize a constrained black-box model using your BO module, and especially the Suggest-Evaluate-Register paradigm, so I first tried to change one of your constraint examples using this paradigm.
The constraints.ipynb notebook works perfectly fine using the optimize.maximise() call.
Unfortunately I could not make it work using the other paradigm.

Here is some information that might help with isue:

  • With the above code, the first iteration of the for loop works, but the second call to optimizer.suggest(util_func) fails and results in TypeError: 'NoneType' object is not subscriptable.

    It seems that the TargetSpace.max function returns None, even in the second iteration of the loop.
    The call self._target_max() in the TargetSpace.max at line 439 seems to only return None.
    It feels like the first target value computed and given in the first iteration to optimizer.register(params=next_point, target=target, constraint_value=constraint_value) is not kept.

I hope it was clear enough, thank you for your attention.

Hey @Vidarrwin,

this can happen if the optimizer has no valid (= constraints fulfilled) point at the time of the suggest step. We fixed this on master already, but not in the released version. The workaround here would be to increase the number of randomly sampled points to prime the optimizer so that there's at least one valid point.

Thank you for your help!
The random state fixed a first point which did not fulfill the constraint.
I changed it and it now works!

glad to hear. Feel free to let us know if you run into other issues.