Single-Objective Optimization#
Solve a single-objective optimization problem with an expensive-to-evaluate objective function, using saealib.
First define the problem, then run single-objective optimization with the high-level API’s minimize.
For the detailed specification and customization of each component, see the Concepts pages linked from the following sections.
What you’ll be able to do
By the end of this page, you’ll be able to optimize an expensive single-objective function with minimize().
For a quick run that only requires an objective function, use the high-level API; to choose components by responsibility, see Swap built-in components.
This page covers running single-objective optimization with minimize() and selecting the algorithm, Surrogate, and evaluation Strategy with string arguments.
Set up the problem#
Assume an objective function whose single call takes a long time, like a simulation.
Here, as an example, we minimize the Sphere function as a stand-in for an expensive-to-evaluate function.
import numpy as np
def expensive_func(x):
# assume a function that is expensive to call in practice
return np.sum(x**2)
DIM = 10
LB = [-5.0] * DIM
UB = [5.0] * DIM
DIM is the number of design-variable dimensions, and LB/UB are DIM-dimensional lists giving its lower and upper bounds.
The objective function is defined as a Callable that takes a DIM-dimensional design variable and returns the objective value.
Run minimize or maximize#
minimize is a high-level API that runs an optimization just by specifying dim, lb, and ub.
from saealib import minimize
result = minimize(expensive_func, dim=DIM, lb=LB, ub=UB, seed=0)
print(result.x) # optimal design variables shape: (dim,)
print(result.f) # optimal objective value shape: (n_obj,)
print(result.fe) # true function evaluations
print(result.gen) # completed generations
If the maximum number of evaluations max_fe is omitted, 200 * dim is used as the default.
To explicitly limit the number of evaluations, specify it as follows.
result = minimize(expensive_func, dim=DIM, lb=LB, ub=UB, max_fe=500, seed=0)
Switch components#
minimize lets you switch three components — the evolutionary algorithm, the surrogate model, and the evaluation strategy — via the string-valued algorithm, surrogate, and strategy arguments, respectively.
For all three, you can also pass an instance directly instead of a string.
The internal behavior and customization of each component are covered on the Algorithm, Surrogate, and OptimizationStrategy pages.
Algorithm#
The algorithm argument selects the evolutionary algorithm that generates candidate solutions.
String |
Class |
Characteristics |
|---|---|---|
|
|
Search via crossover and mutation (default) |
|
|
Search via particle velocity updates |
result = minimize(expensive_func, dim=DIM, lb=LB, ub=UB, algorithm="PSO", seed=0)
Surrogate#
The surrogate argument selects the surrogate model that approximates the objective function.
String |
Resolved configuration |
Description |
|---|---|---|
|
|
Local fit over nearby points using a Gaussian RBF kernel |
result = minimize(expensive_func, dim=DIM, lb=LB, ub=UB, surrogate="rbf", seed=0)
Evaluation strategy#
The strategy argument selects the evaluation strategy that decides which of the generated candidates receive a true (expensive) evaluation.
String |
Class |
Behavior |
|---|---|---|
|
|
Evaluates each candidate individually with the surrogate and truly evaluates only the top |
|
|
Advances |
|
|
Narrows down a large pool of candidates with the surrogate and truly evaluates only the top |
result = minimize(expensive_func, dim=DIM, lb=LB, ub=UB, strategy="ib", seed=0)
When the default minimize() configuration is insufficient, configure components individually and register them with Optimizer. Build an Optimizer with the low-level API also covers multiple Termination conditions and per-generation progress through iterate().