Constrained optimization - SEGO#

[1]:
import numpy as np
from matplotlib import pyplot as plt

from smt_optim.benchmarks.registry import get_problem

from smt_optim.core import Driver, ObjectiveConfig, ConstraintConfig, DriverConfig, Problem

from smt_optim.surrogate_models.smt import SmtAutoModel

from smt_optim.acquisition_strategies import MFSEGO

Importing a test function#

[2]:
problem = get_problem("Branin1")

Constrained 2D optimization#

As with unconstrained optimisation, we must first define the problem. The objective is configured using the ObjectiveConfig data class, and each constraint must be defined using the ConstraintConfig data class.

[3]:
obj_config = ObjectiveConfig(
    [problem.objective[-1]],
    type="minimize",
    surrogate=SmtAutoModel,
)

# configure the constraint
cstr_config = ConstraintConfig(
    [problem.constraints[0][-1]],
    type="less",                    # set the constraint type (less, greater or equal)
    value=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 = 10,
    nt_init = 6,
    verbose = True,
    scaling = True,
    seed=42,
)

driver = Driver(prob_definition, opt_config, MFSEGO)

state = driver.optimize()
          iter         budget           fmin       fidelity        gp_time       acq_time
             1              7    6.86090e+01              1          0.609          0.552
             2              8    1.44188e+01              1          0.565          0.289
             3              9    7.18465e+00              1          0.526          0.205
             4             10    6.94315e+00              1          0.538          0.218
             5             11    6.94315e+00              1          0.476          0.357
             6             12    6.94314e+00              1          0.452          0.305
             7             13    6.94314e+00              1          0.449          0.377
             8             14    6.94314e+00              1          0.447          0.245
             9             15    6.94314e+00              1          0.433          0.218
            10             16    6.94314e+00              1          0.410          0.250

The get_best_sample class method enables us to obtain the optimal sample within a specific constraint tolerance by passing the ctol argument. The code snippet below demonstrates how imposing a stricter tolerance constraint can affect the best sample found.

[4]:
tolerances = [1.2e-1, 1e-4]

for tol in tolerances:
    sample = state.get_best_sample(ctol=tol)
    print(sample)

======= sample data =======
x =             [0.12899267 0.74173099]
obj =           [2.00404723]
cstr =          [0.10432214]
eval_time =     [3.05403955e-06 4.44008037e-07]
------- meta data -------
iter =     0
budget =     2
fidelity =     0
===========================

======= sample data =======
x =             [1.         0.20019954]
obj =           [6.94314066]
cstr =          [-0.00019954]
eval_time =     [6.89597800e-06 1.20600453e-06]
------- meta data -------
iter =     10
budget =     16
fidelity =     0
===========================

[5]:
# get the best sample in the dataset
sample = state.get_best_sample(ctol=1e-4)
xt = state.dataset.export_as_dict()["x"]

X = np.linspace(0, 1, 201)

XX, YY = np.meshgrid(X, X)

data = np.vstack((XX.ravel(), YY.ravel())).T
z = np.empty(data.shape[0])
c = np.empty(data.shape[0])

for i in range(data.shape[0]):
    z[i] = problem.objective[-1](data[i, :])
    c[i] = problem.constraints[0][-1](data[i, :])

Z = z.reshape(XX.shape)
C = c.reshape(XX.shape)

fig, ax = plt.subplots()

ax.set_title(problem.name)

ax.contour(XX, YY, Z, levels=20)

ax.contourf(XX, YY, np.where(C <= 0, np.nan, C), levels=0, colors="C7", alpha=0.20)
ax.contour(XX, YY, C, levels=[0], colors="C7")

ax.scatter(xt[:, 0], xt[:, 1], 10, color="C7", alpha=0.75, label="DoE")
ax.scatter(sample.x[0], sample.x[1], c="C3", marker="*", label=r"$f_{min}$", zorder=10)

ax.set_xlabel(r"$x_1$")
ax.set_ylabel(r"$x_2$")

ax.legend()
ax.set_aspect("equal")
plt.show()
../../_images/_collections_tutorial_sego_8_0.png