Boundary Strategies
This example compares the boundary strategies available on optimizers.
The objective has its optimum close to the edge of the search space, and the
large epsilon value makes Hill Climbing generate candidates that often
leave the valid range.
from gradient_free_optimizers import HillClimbingOptimizer
BOUNDARIES = ("clip", "reflect", "periodic", "random", "intermediate")
def objective(params):
x = params["x"]
y = params["y"]
return -((x - 0.95) ** 2 + (y - 0.05) ** 2)
search_space = {
"x": (0.0, 1.0),
"y": (0.0, 1.0),
}
initialize = {
"warm_start": [{"x": 0.5, "y": 0.5}],
"random": 2,
}
for boundary in BOUNDARIES:
opt = HillClimbingOptimizer(
search_space,
boundary=boundary,
epsilon=0.6,
n_neighbours=8,
initialize=initialize,
random_state=7,
)
opt.search(objective, n_iter=80, verbosity=[])
best = opt.best_para
print(
f"{boundary:>12}: "
f"x={best['x']:.3f}, y={best['y']:.3f}, "
f"score={opt.best_score:.4f}"
)
Use "clip" for the conservative default, "reflect" to bounce
overshooting steps back into the space, "periodic" for cyclic domains,
"random" for extra exploration, and "intermediate" for damped
edge handling.
The same code is available as examples/boundary_strategies.py.