API examples#
smt-optim proposes three different APIs, each with its own trade-off between ease of use and customizability. In order of increasing complexity, the three APIs are:
Function API
Component-based API
Ask-Tell API
from smt_optim.benchmarks.registry import get_problem
problem = get_problem("Branin1")
Functional API#
The functional API enables users to initiate an optimization process through a single method call. The following example starts a constrained optimization problem. The minimize method returns a State object containing the optimization dataset (final DoE). Although the minimize method is simple, it offers less flexibility than the other APIs.
from smt_optim import minimize
constraint = [
{
"fun": [problem.constraints[0][-1]],
"upper": 0.0 # the following can also be defined: "lower" or "equal"
},
]
state = minimize(
[problem.objective[-1]],
design_space=problem.bounds,
constraints=constraint,
max_budget=15,
method="mfsego",
driver_kwargs={"seed": 0},
)
sample = state.get_best_sample(ctol=1e-4)
print(f"best sample = \n{sample}")
iter budget fmin rscv fidelity gp_time acq_time
1 6 5.47552e+01 0.000e+00 1 0.402 0.232
2 7 5.47552e+01 0.000e+00 1 0.460 0.276
3 8 3.21653e+01 0.000e+00 1 0.417 0.274
4 9 3.21653e+01 0.000e+00 1 0.350 0.288
5 10 3.21653e+01 0.000e+00 1 0.423 0.521
6 11 6.94315e+00 0.000e+00 1 0.319 0.662
7 12 5.62261e+00 0.000e+00 1 0.314 1.487
8 13 5.58405e+00 0.000e+00 1 0.380 3.159
9 14 5.57583e+00 0.000e+00 1 0.364 1.794
10 15 5.57583e+00 0.000e+00 1 0.342 1.529
best sample =
======= sample data =======
x = [0.96792398 0.20662896]
obj = [5.57583277]
cstr = [-1.1237681e-06]
eval_time = [7.57300586e-06 1.34400034e-06]
------- meta data -------
iter = 9
budget = 14
fidelity = 0
rscv = 0.0
===========================
Component-Based API#
The component-based API enables users to define the surrogate model and acquisition strategy. It also makes the driver class available to the user. Note that the minimize method automates the driver and problem initialization, as shown below.
from smt_optim.core import Driver, ObjectiveConfig, ConstraintConfig, DriverConfig, Problem
from smt_optim.surrogate_models import SmtAutoModel
from smt_optim.acquisition_strategies import MFSEGO
obj_config = ObjectiveConfig(
[problem.objective[-1]],
type="minimize",
surrogate=SmtAutoModel,
)
# configure the constraint
cstr_config = ConstraintConfig(
[problem.constraints[0][-1]],
upper=0.0, # g(x) <= 0
surrogate=SmtAutoModel, # set which GP to model this constraint
)
prob_definition = Problem(
obj_configs=[obj_config],
design_space=problem.bounds, # problem bounds
cstr_configs=[cstr_config], # list the constraints
)
opt_config = DriverConfig(
max_iter = 100,
max_budget = 15,
nt_init = 5,
verbose = True,
scaling = True,
seed=0,
)
driver = Driver(prob_definition, opt_config, MFSEGO)
state = driver.optimize()
sample = state.get_best_sample(ctol=1e-4)
print(f"best sample = \n{sample}")
iter budget fmin rscv fidelity gp_time acq_time
1 6 5.47552e+01 0.000e+00 1 0.393 0.233
2 7 5.47552e+01 0.000e+00 1 0.426 0.272
3 8 3.21653e+01 0.000e+00 1 0.403 0.292
4 9 3.21653e+01 0.000e+00 1 0.348 0.287
5 10 3.21653e+01 0.000e+00 1 0.424 0.516
6 11 6.94315e+00 0.000e+00 1 0.318 0.652
7 12 5.62261e+00 0.000e+00 1 0.343 1.371
8 13 5.58405e+00 0.000e+00 1 0.359 3.125
9 14 5.57583e+00 0.000e+00 1 0.306 1.715
10 15 5.57583e+00 0.000e+00 1 0.341 1.452
best sample =
======= sample data =======
x = [0.96792398 0.20662896]
obj = [5.57583277]
cstr = [-1.1237681e-06]
eval_time = [7.79800757e-06 1.26300438e-06]
------- meta data -------
iter = 9
budget = 14
fidelity = 0
rscv = 0.0
===========================
Ask-Tell API#
The Ask-Tell API uses the same driver and problem initialization as previously shown. Each iteration is called individually with the iteration class method. In the example below, the last iteration is defined entirely manually, similarly to within the driver’s iteration class method. It provides for the maximum control and customization over the optimization process.
import time
from smt_optim.core import Driver, ObjectiveConfig, ConstraintConfig, DriverConfig, Problem
from smt_optim.surrogate_models import SmtAutoModel
from smt_optim.acquisition_strategies import MFSEGO
obj_config = ObjectiveConfig(
[problem.objective[-1]],
type="minimize",
surrogate=SmtAutoModel,
)
# configure the constraint
cstr_config = ConstraintConfig(
[problem.constraints[0][-1]],
upper=0.0, # g(x) <= 0
surrogate=SmtAutoModel, # set which GP to model this constraint
)
prob_definition = Problem(
obj_configs=[obj_config],
design_space=problem.bounds, # problem bounds
cstr_configs=[cstr_config], # list the constraints
)
opt_config = DriverConfig(
max_iter = 100,
max_budget = 20,
nt_init = 5,
verbose = True,
scaling = True,
seed=0,
)
driver = Driver(prob_definition, opt_config, MFSEGO)
# ------- initializes state object -------
# generate initial DoE
driver.start_optim()
print(f"Number of samples: {len(driver.state.dataset.samples)}")
# ------- individually called iterations -------
for idx in range(7):
driver.iteration(driver.state)
print(f"Number of samples: {len(driver.state.dataset.samples)}")
# ------- start of manually defined iteration -------
state = driver.state
# increment iteration counter
state.iter += 1
# scale data
state.scale_dataset(opt_config.scaling)
# build models
state.build_models()
# get infill
t0 = time.perf_counter()
infill = driver.strategy.get_infill(state)
t1 = time.perf_counter()
state.iter_log["acq_opt_time"] = t1 - t0
for i in range(len(infill)):
if infill[i] is not None:
infill[i] *= state.x_factor
infill[i] += state.x_step
state.iter_log["fidelity"] = i + 1
# evaluate infill points
driver.evaluator.sample_func(infill, state)
# log iteration data
driver.call_loggers(state)
# ------- end of manually defined iteration -------
print(f"Number of samples: {len(driver.state.dataset.samples)}")
sample = state.get_best_sample(ctol=1e-4)
print(f"best sample = \n{sample}")
Number of samples: 5
iter budget fmin rscv fidelity gp_time acq_time
1 6 5.47552e+01 0.000e+00 1 0.381 0.222
2 7 5.47552e+01 0.000e+00 1 0.456 0.281
3 8 3.21653e+01 0.000e+00 1 0.437 0.324
4 9 3.21653e+01 0.000e+00 1 0.353 0.274
5 10 3.21653e+01 0.000e+00 1 0.407 0.487
6 11 6.94315e+00 0.000e+00 1 0.318 0.661
7 12 5.62261e+00 0.000e+00 1 0.307 1.374
Number of samples: 12
8 13 5.58405e+00 0.000e+00 1 0.375 3.310
Number of samples: 13
best sample =
======= sample data =======
x = [0.97010966 0.20616457]
obj = [5.58405051]
cstr = [-2.23611547e-06]
eval_time = [1.18830067e-05 1.48700201e-06]
------- meta data -------
iter = 8
budget = 13
fidelity = 0
rscv = 0.0
===========================