Multi-objective Bayesian Optimization¶
TNK function $n=2$ variables: $x_i \in [0, \pi], i=1,2$
Objectives:
- $f_i(x) = x_i$
Constraints:
- $g_1(x) = -x_1^2 -x_2^2 + 1 + 0.1 \cos\left(16 \arctan \frac{x_1}{x_2}\right) \le 0$
- $g_2(x) = (x_1 - 1/2)^2 + (x_2-1/2)^2 \le 0.5$
In [1]:
Copied!
# set values if testing
import os
import pandas as pd
import numpy as np
from xopt import Xopt, Evaluator
from xopt.generators.bayesian import MOBOGenerator
from xopt.resources.test_functions.tnk import evaluate_TNK, tnk_vocs
import matplotlib.pyplot as plt
# Ignore all warnings
import warnings
warnings.filterwarnings("ignore")
SMOKE_TEST = os.environ.get("SMOKE_TEST")
N_MC_SAMPLES = 1 if SMOKE_TEST else 128
NUM_RESTARTS = 1 if SMOKE_TEST else 20
N_STEPS = 1 if SMOKE_TEST else 30
MAX_ITER = 1 if SMOKE_TEST else 200
evaluator = Evaluator(function=evaluate_TNK)
print(tnk_vocs.dict())
# set values if testing
import os
import pandas as pd
import numpy as np
from xopt import Xopt, Evaluator
from xopt.generators.bayesian import MOBOGenerator
from xopt.resources.test_functions.tnk import evaluate_TNK, tnk_vocs
import matplotlib.pyplot as plt
# Ignore all warnings
import warnings
warnings.filterwarnings("ignore")
SMOKE_TEST = os.environ.get("SMOKE_TEST")
N_MC_SAMPLES = 1 if SMOKE_TEST else 128
NUM_RESTARTS = 1 if SMOKE_TEST else 20
N_STEPS = 1 if SMOKE_TEST else 30
MAX_ITER = 1 if SMOKE_TEST else 200
evaluator = Evaluator(function=evaluate_TNK)
print(tnk_vocs.dict())
{'variables': {'x1': [0.0, 3.14159], 'x2': [0.0, 3.14159]}, 'constraints': {'c1': ['GREATER_THAN', 0.0], 'c2': ['LESS_THAN', 0.5]}, 'objectives': {'y1': 'MINIMIZE', 'y2': 'MINIMIZE'}, 'constants': {'a': 'dummy_constant'}, 'observables': []}
In [2]:
Copied!
generator = MOBOGenerator(vocs=tnk_vocs, reference_point={"y1": 1.5, "y2": 1.5})
generator.n_monte_carlo_samples = N_MC_SAMPLES
generator.numerical_optimizer.n_restarts = NUM_RESTARTS
generator.numerical_optimizer.max_iter = MAX_ITER
generator.gp_constructor.use_low_noise_prior = True
X = Xopt(generator=generator, evaluator=evaluator, vocs=tnk_vocs)
X.evaluate_data(pd.DataFrame({"x1": [1.0, 0.75], "x2": [0.75, 1.0]}))
for i in range(N_STEPS):
print(i)
X.step()
generator = MOBOGenerator(vocs=tnk_vocs, reference_point={"y1": 1.5, "y2": 1.5})
generator.n_monte_carlo_samples = N_MC_SAMPLES
generator.numerical_optimizer.n_restarts = NUM_RESTARTS
generator.numerical_optimizer.max_iter = MAX_ITER
generator.gp_constructor.use_low_noise_prior = True
X = Xopt(generator=generator, evaluator=evaluator, vocs=tnk_vocs)
X.evaluate_data(pd.DataFrame({"x1": [1.0, 0.75], "x2": [0.75, 1.0]}))
for i in range(N_STEPS):
print(i)
X.step()
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
In [3]:
Copied!
X.generator.data
X.generator.data
Out[3]:
x1 | x2 | a | y1 | y2 | c1 | c2 | xopt_runtime | xopt_error | |
---|---|---|---|---|---|---|---|---|---|
0 | 1.000000 | 0.750000 | dummy_constant | 1.000000 | 0.750000 | 0.626888 | 0.312500 | 0.000237 | False |
1 | 0.750000 | 1.000000 | dummy_constant | 0.750000 | 1.000000 | 0.626888 | 0.312500 | 0.000137 | False |
2 | 0.443152 | 1.573545 | dummy_constant | 0.443152 | 1.573545 | 1.703896 | 1.155731 | 0.000158 | False |
3 | 0.288393 | 0.518940 | dummy_constant | 0.288393 | 0.518940 | -0.621650 | 0.045136 | 0.000150 | False |
4 | 0.000000 | 0.000000 | dummy_constant | 0.000000 | 0.000000 | -1.100000 | 0.500000 | 0.000152 | False |
5 | 0.023187 | 0.906145 | dummy_constant | 0.023187 | 0.906145 | -0.270103 | 0.392304 | 0.000162 | False |
6 | 3.141590 | 0.334401 | dummy_constant | 3.141590 | 0.334401 | 8.993970 | 7.005421 | 0.000153 | False |
7 | 0.153376 | 1.025569 | dummy_constant | 0.153376 | 1.025569 | 0.147361 | 0.396371 | 0.000152 | False |
8 | 0.928655 | 0.182506 | dummy_constant | 0.928655 | 0.182506 | -0.004358 | 0.284548 | 0.000156 | False |
9 | 0.996561 | 0.092324 | dummy_constant | 0.996561 | 0.092324 | -0.007601 | 0.412773 | 0.000155 | False |
10 | 0.768162 | 0.629417 | dummy_constant | 0.768162 | 0.629417 | -0.012520 | 0.088660 | 0.000150 | False |
11 | 1.034047 | 0.113721 | dummy_constant | 1.034047 | 0.113721 | 0.100264 | 0.434417 | 0.000150 | False |
12 | 1.013023 | 0.033168 | dummy_constant | 1.013023 | 0.033168 | -0.059282 | 0.481125 | 0.000150 | False |
13 | 0.467963 | 0.879828 | dummy_constant | 0.467963 | 0.879828 | -0.010191 | 0.145295 | 0.000151 | False |
14 | 0.000322 | 1.008081 | dummy_constant | 0.000322 | 1.008081 | -0.083771 | 0.507825 | 0.000149 | False |
15 | 0.631064 | 0.768268 | dummy_constant | 0.631064 | 0.768268 | -0.012224 | 0.089145 | 0.000154 | False |
16 | 0.900051 | 0.471779 | dummy_constant | 0.900051 | 0.471779 | 0.019778 | 0.160838 | 0.000153 | False |
17 | 1.010050 | 0.012295 | dummy_constant | 1.010050 | 0.012295 | -0.077757 | 0.498007 | 0.000150 | False |
18 | 0.708258 | 0.729352 | dummy_constant | 0.708258 | 0.729352 | -0.063674 | 0.095974 | 0.000149 | False |
19 | 0.839502 | 0.582848 | dummy_constant | 0.839502 | 0.582848 | 0.140435 | 0.122126 | 0.000153 | False |
20 | 0.065480 | 1.044557 | dummy_constant | 0.065480 | 1.044557 | 0.041499 | 0.485350 | 0.000156 | False |
21 | 0.034678 | 0.007846 | dummy_constant | 0.034678 | 0.007846 | -0.907373 | 0.458739 | 0.000152 | False |
22 | 0.331845 | 0.962579 | dummy_constant | 0.331845 | 0.962579 | -0.019733 | 0.242256 | 0.000159 | False |
23 | 1.013091 | 0.004432 | dummy_constant | 1.013091 | 0.004432 | -0.073381 | 0.508850 | 0.000169 | False |
24 | 1.036434 | 0.052532 | dummy_constant | 1.036434 | 0.052532 | 0.008026 | 0.487989 | 0.000154 | False |
25 | 0.951654 | 0.372634 | dummy_constant | 0.951654 | 0.372634 | -0.050678 | 0.220213 | 0.000153 | False |
26 | 1.000375 | 0.005699 | dummy_constant | 1.000375 | 0.005699 | -0.098802 | 0.494709 | 0.000153 | False |
27 | 0.095930 | 1.058826 | dummy_constant | 0.095930 | 1.058826 | 0.117835 | 0.475560 | 0.000154 | False |
28 | 0.087313 | 1.017469 | dummy_constant | 0.087313 | 1.017469 | 0.022888 | 0.438084 | 0.000157 | False |
29 | 0.041737 | 1.033315 | dummy_constant | 0.041737 | 1.033315 | -0.010373 | 0.494430 | 0.000152 | False |
30 | 1.022290 | 0.032071 | dummy_constant | 1.022290 | 0.032071 | -0.041567 | 0.491744 | 0.000147 | False |
31 | 1.047658 | 0.072998 | dummy_constant | 1.047658 | 0.072998 | 0.058722 | 0.482260 | 0.000148 | False |
plot results¶
In [4]:
Copied!
fig, ax = plt.subplots()
theta = np.linspace(0, np.pi / 2)
r = np.sqrt(1 + 0.1 * np.cos(16 * theta))
x_1 = r * np.sin(theta)
x_2_lower = r * np.cos(theta)
x_2_upper = (0.5 - (x_1 - 0.5) ** 2) ** 0.5 + 0.5
z = np.zeros_like(x_1)
# ax2.plot(x_1, x_2_lower,'r')
ax.fill_between(x_1, z, x_2_lower, fc="white")
circle = plt.Circle(
(0.5, 0.5), 0.5**0.5, color="r", alpha=0.25, zorder=0, label="Valid Region"
)
ax.add_patch(circle)
history = pd.concat(
[X.data, tnk_vocs.feasibility_data(X.data)], axis=1, ignore_index=False
)
ax.plot(*history[["x1", "x2"]][history["feasible"]].to_numpy().T, ".C1")
ax.plot(*history[["x1", "x2"]][~history["feasible"]].to_numpy().T, ".C2")
ax.set_xlim(0, 3.14)
ax.set_ylim(0, 3.14)
ax.set_xlabel("x1")
ax.set_ylabel("x2")
ax.set_aspect("equal")
fig, ax = plt.subplots()
theta = np.linspace(0, np.pi / 2)
r = np.sqrt(1 + 0.1 * np.cos(16 * theta))
x_1 = r * np.sin(theta)
x_2_lower = r * np.cos(theta)
x_2_upper = (0.5 - (x_1 - 0.5) ** 2) ** 0.5 + 0.5
z = np.zeros_like(x_1)
# ax2.plot(x_1, x_2_lower,'r')
ax.fill_between(x_1, z, x_2_lower, fc="white")
circle = plt.Circle(
(0.5, 0.5), 0.5**0.5, color="r", alpha=0.25, zorder=0, label="Valid Region"
)
ax.add_patch(circle)
history = pd.concat(
[X.data, tnk_vocs.feasibility_data(X.data)], axis=1, ignore_index=False
)
ax.plot(*history[["x1", "x2"]][history["feasible"]].to_numpy().T, ".C1")
ax.plot(*history[["x1", "x2"]][~history["feasible"]].to_numpy().T, ".C2")
ax.set_xlim(0, 3.14)
ax.set_ylim(0, 3.14)
ax.set_xlabel("x1")
ax.set_ylabel("x2")
ax.set_aspect("equal")
Plot path through input space¶
In [5]:
Copied!
ax = history.plot("x1", "x2")
ax.set_ylim(0, 3.14)
ax.set_xlim(0, 3.14)
ax.set_aspect("equal")
ax = history.plot("x1", "x2")
ax.set_ylim(0, 3.14)
ax.set_xlim(0, 3.14)
ax.set_aspect("equal")
In [6]:
Copied!
## visualize model
X.generator.visualize_model(show_feasibility=True)
## visualize model
X.generator.visualize_model(show_feasibility=True)
Out[6]:
(<Figure size 800x1980 with 22 Axes>, array([[<Axes: title={'center': 'Posterior Mean [y1]'}, xlabel='x1', ylabel='x2'>, <Axes: title={'center': 'Posterior SD [y1]'}, xlabel='x1', ylabel='x2'>], [<Axes: title={'center': 'Posterior Mean [y2]'}, xlabel='x1', ylabel='x2'>, <Axes: title={'center': 'Posterior SD [y2]'}, xlabel='x1', ylabel='x2'>], [<Axes: title={'center': 'Posterior Mean [c1]'}, xlabel='x1', ylabel='x2'>, <Axes: title={'center': 'Posterior SD [c1]'}, xlabel='x1', ylabel='x2'>], [<Axes: title={'center': 'Posterior Mean [c2]'}, xlabel='x1', ylabel='x2'>, <Axes: title={'center': 'Posterior SD [c2]'}, xlabel='x1', ylabel='x2'>], [<Axes: title={'center': 'Acq. Function'}, xlabel='x1', ylabel='x2'>, <Axes: >], [<Axes: title={'center': 'Feasibility'}, xlabel='x1', ylabel='x2'>, <Axes: >]], dtype=object))
In [7]:
Copied!
X.generator.update_pareto_front_history()
X.generator.pareto_front_history.plot(y="hypervolume", label="Hypervolume")
X.generator.update_pareto_front_history()
X.generator.pareto_front_history.plot(y="hypervolume", label="Hypervolume")
Out[7]:
<Axes: >
In [8]:
Copied!
X.generator.pareto_front_history
X.generator.pareto_front_history
Out[8]:
iteration | hypervolume | n_non_dominated | |
---|---|---|---|
0 | 0 | 0.375000 | 1 |
1 | 1 | 0.500000 | 2 |
2 | 2 | 0.500000 | 2 |
3 | 3 | 0.500000 | 2 |
4 | 4 | 0.500000 | 2 |
5 | 5 | 0.500000 | 2 |
6 | 6 | 0.500000 | 2 |
7 | 7 | 0.783057 | 3 |
8 | 8 | 0.783057 | 3 |
9 | 9 | 0.783057 | 3 |
10 | 10 | 0.783057 | 3 |
11 | 11 | 1.079533 | 4 |
12 | 12 | 1.079533 | 4 |
13 | 13 | 1.079533 | 4 |
14 | 14 | 1.079533 | 4 |
15 | 15 | 1.079533 | 4 |
16 | 16 | 1.141800 | 4 |
17 | 17 | 1.141800 | 4 |
18 | 18 | 1.141800 | 4 |
19 | 19 | 1.167058 | 5 |
20 | 20 | 1.207090 | 6 |
21 | 21 | 1.207090 | 6 |
22 | 22 | 1.207090 | 6 |
23 | 23 | 1.207090 | 6 |
24 | 24 | 1.235455 | 7 |
25 | 25 | 1.235455 | 7 |
26 | 26 | 1.235455 | 7 |
27 | 27 | 1.235455 | 7 |
28 | 28 | 1.242078 | 7 |
29 | 29 | 1.242078 | 7 |
30 | 30 | 1.242078 | 7 |
31 | 31 | 1.242078 | 7 |
In [9]:
Copied!
X.data
X.data
Out[9]:
x1 | x2 | a | y1 | y2 | c1 | c2 | xopt_runtime | xopt_error | |
---|---|---|---|---|---|---|---|---|---|
0 | 1.000000 | 0.750000 | dummy_constant | 1.000000 | 0.750000 | 0.626888 | 0.312500 | 0.000237 | False |
1 | 0.750000 | 1.000000 | dummy_constant | 0.750000 | 1.000000 | 0.626888 | 0.312500 | 0.000137 | False |
2 | 0.443152 | 1.573545 | dummy_constant | 0.443152 | 1.573545 | 1.703896 | 1.155731 | 0.000158 | False |
3 | 0.288393 | 0.518940 | dummy_constant | 0.288393 | 0.518940 | -0.621650 | 0.045136 | 0.000150 | False |
4 | 0.000000 | 0.000000 | dummy_constant | 0.000000 | 0.000000 | -1.100000 | 0.500000 | 0.000152 | False |
5 | 0.023187 | 0.906145 | dummy_constant | 0.023187 | 0.906145 | -0.270103 | 0.392304 | 0.000162 | False |
6 | 3.141590 | 0.334401 | dummy_constant | 3.141590 | 0.334401 | 8.993970 | 7.005421 | 0.000153 | False |
7 | 0.153376 | 1.025569 | dummy_constant | 0.153376 | 1.025569 | 0.147361 | 0.396371 | 0.000152 | False |
8 | 0.928655 | 0.182506 | dummy_constant | 0.928655 | 0.182506 | -0.004358 | 0.284548 | 0.000156 | False |
9 | 0.996561 | 0.092324 | dummy_constant | 0.996561 | 0.092324 | -0.007601 | 0.412773 | 0.000155 | False |
10 | 0.768162 | 0.629417 | dummy_constant | 0.768162 | 0.629417 | -0.012520 | 0.088660 | 0.000150 | False |
11 | 1.034047 | 0.113721 | dummy_constant | 1.034047 | 0.113721 | 0.100264 | 0.434417 | 0.000150 | False |
12 | 1.013023 | 0.033168 | dummy_constant | 1.013023 | 0.033168 | -0.059282 | 0.481125 | 0.000150 | False |
13 | 0.467963 | 0.879828 | dummy_constant | 0.467963 | 0.879828 | -0.010191 | 0.145295 | 0.000151 | False |
14 | 0.000322 | 1.008081 | dummy_constant | 0.000322 | 1.008081 | -0.083771 | 0.507825 | 0.000149 | False |
15 | 0.631064 | 0.768268 | dummy_constant | 0.631064 | 0.768268 | -0.012224 | 0.089145 | 0.000154 | False |
16 | 0.900051 | 0.471779 | dummy_constant | 0.900051 | 0.471779 | 0.019778 | 0.160838 | 0.000153 | False |
17 | 1.010050 | 0.012295 | dummy_constant | 1.010050 | 0.012295 | -0.077757 | 0.498007 | 0.000150 | False |
18 | 0.708258 | 0.729352 | dummy_constant | 0.708258 | 0.729352 | -0.063674 | 0.095974 | 0.000149 | False |
19 | 0.839502 | 0.582848 | dummy_constant | 0.839502 | 0.582848 | 0.140435 | 0.122126 | 0.000153 | False |
20 | 0.065480 | 1.044557 | dummy_constant | 0.065480 | 1.044557 | 0.041499 | 0.485350 | 0.000156 | False |
21 | 0.034678 | 0.007846 | dummy_constant | 0.034678 | 0.007846 | -0.907373 | 0.458739 | 0.000152 | False |
22 | 0.331845 | 0.962579 | dummy_constant | 0.331845 | 0.962579 | -0.019733 | 0.242256 | 0.000159 | False |
23 | 1.013091 | 0.004432 | dummy_constant | 1.013091 | 0.004432 | -0.073381 | 0.508850 | 0.000169 | False |
24 | 1.036434 | 0.052532 | dummy_constant | 1.036434 | 0.052532 | 0.008026 | 0.487989 | 0.000154 | False |
25 | 0.951654 | 0.372634 | dummy_constant | 0.951654 | 0.372634 | -0.050678 | 0.220213 | 0.000153 | False |
26 | 1.000375 | 0.005699 | dummy_constant | 1.000375 | 0.005699 | -0.098802 | 0.494709 | 0.000153 | False |
27 | 0.095930 | 1.058826 | dummy_constant | 0.095930 | 1.058826 | 0.117835 | 0.475560 | 0.000154 | False |
28 | 0.087313 | 1.017469 | dummy_constant | 0.087313 | 1.017469 | 0.022888 | 0.438084 | 0.000157 | False |
29 | 0.041737 | 1.033315 | dummy_constant | 0.041737 | 1.033315 | -0.010373 | 0.494430 | 0.000152 | False |
30 | 1.022290 | 0.032071 | dummy_constant | 1.022290 | 0.032071 | -0.041567 | 0.491744 | 0.000147 | False |
31 | 1.047658 | 0.072998 | dummy_constant | 1.047658 | 0.072998 | 0.058722 | 0.482260 | 0.000148 | False |
In [ ]:
Copied!