Skip to content

Commit 8ed5a37

Browse files
authored
Merge pull request #368 from till-m/constrained-optimization
Improve constrained optimization
2 parents 7cb736f + 12353c2 commit 8ed5a37

11 files changed

+250
-153
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ to learn how to make the package more flexible, how to deal with categorical par
4040
- Check out this
4141
[notebook](https://github.com/fmfn/BayesianOptimization/blob/master/examples/visualization.ipynb)
4242
with a step by step visualization of how this method works.
43+
- To understand how to use bayesian optimization when additional constraints are present, see the
44+
[constrained optimization notebook](https://github.com/fmfn/BayesianOptimization/blob/master/examples/constraints.ipynb).
4345
- Explore this [notebook](https://github.com/fmfn/BayesianOptimization/blob/master/examples/exploitation_vs_exploration.ipynb)
4446
exemplifying the balance between exploration and exploitation and how to
4547
control it.

bayes_opt/bayesian_optimization.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from bayes_opt.constraint import ConstraintModel
44

5-
from .target_space import TargetSpace, ConstrainedTargetSpace
5+
from .target_space import TargetSpace
66
from .event import Events, DEFAULT_EVENTS
77
from .logger import _get_default_logger
88
from .util import UtilityFunction, acq_max, ensure_rng
@@ -129,7 +129,7 @@ def __init__(self,
129129
# Data structure containing the function to be optimized, the
130130
# bounds of its domain, and a record of the evaluations we have
131131
# done so far
132-
self._space = TargetSpace(f, pbounds, random_state)
132+
self._space = TargetSpace(f, pbounds, random_state=random_state)
133133
self.is_constrained = False
134134
else:
135135
constraint_ = ConstraintModel(
@@ -138,11 +138,11 @@ def __init__(self,
138138
constraint.ub,
139139
random_state=random_state
140140
)
141-
self._space = ConstrainedTargetSpace(
141+
self._space = TargetSpace(
142142
f,
143-
constraint_,
144143
pbounds,
145-
random_state
144+
constraint=constraint_,
145+
random_state=random_state
146146
)
147147
self.is_constrained = True
148148

@@ -175,9 +175,9 @@ def max(self):
175175
def res(self):
176176
return self._space.res()
177177

178-
def register(self, params, target):
178+
def register(self, params, target, constraint_value=None):
179179
"""Expect observation with known target"""
180-
self._space.register(params, target)
180+
self._space.register(params, target, constraint_value)
181181
self.dispatch(Events.OPTIMIZATION_STEP)
182182

183183
def probe(self, params, lazy=True):
@@ -234,7 +234,7 @@ def _prime_queue(self, init_points):
234234

235235
def _prime_subscriptions(self):
236236
if not any([len(subs) for subs in self._events.values()]):
237-
_logger = _get_default_logger(self._verbose)
237+
_logger = _get_default_logger(self._verbose, self.is_constrained)
238238
self.subscribe(Events.OPTIMIZATION_START, _logger)
239239
self.subscribe(Events.OPTIMIZATION_STEP, _logger)
240240
self.subscribe(Events.OPTIMIZATION_END, _logger)

bayes_opt/constraint.py

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,17 +40,13 @@ class ConstraintModel():
4040
def __init__(self, fun, lb, ub, random_state=None):
4141
self.fun = fun
4242

43-
if isinstance(lb, float):
44-
self._lb = np.array([lb])
45-
else:
46-
self._lb = lb
47-
48-
if isinstance(ub, float):
49-
self._ub = np.array([ub])
50-
else:
51-
self._ub = ub
52-
53-
43+
self._lb = np.atleast_1d(lb)
44+
self._ub = np.atleast_1d(ub)
45+
46+
if np.any(self._lb >= self._ub):
47+
msg = "Lower bounds must be less than upper bounds."
48+
raise ValueError(msg)
49+
5450
basis = lambda: GaussianProcessRegressor(
5551
kernel=Matern(nu=2.5),
5652
alpha=1e-6,

bayes_opt/logger.py

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,17 @@
66
from .event import Events
77
from .util import Colours
88

9-
def _get_default_logger(verbose):
10-
return ScreenLogger(verbose=verbose)
9+
def _get_default_logger(verbose, is_constrained):
10+
return ScreenLogger(verbose=verbose, is_constrained=is_constrained)
1111

1212

1313
class ScreenLogger(_Tracker):
1414
_default_cell_size = 9
1515
_default_precision = 4
1616

17-
def __init__(self, verbose=2):
17+
def __init__(self, verbose=2, is_constrained=False):
1818
self._verbose = verbose
19+
self._is_constrained = is_constrained
1920
self._header_length = None
2021
super(ScreenLogger, self).__init__()
2122

@@ -27,6 +28,10 @@ def verbose(self):
2728
def verbose(self, v):
2829
self._verbose = v
2930

31+
@property
32+
def is_constrained(self):
33+
return self._is_constrained
34+
3035
def _format_number(self, x):
3136
if isinstance(x, int):
3237
s = "{x:<{s}}".format(
@@ -47,6 +52,20 @@ def _format_number(self, x):
4752
return s[:self._default_cell_size - 3] + "..."
4853
return s
4954

55+
def _format_bool(self, x):
56+
if 5 > self._default_cell_size:
57+
if x == True:
58+
x_ = 'T'
59+
elif x == False:
60+
x_ = 'F'
61+
else:
62+
x_ = str(x)
63+
s = "{x:<{s}}".format(
64+
x=x_,
65+
s=self._default_cell_size,
66+
)
67+
return s
68+
5069
def _format_key(self, key):
5170
s = "{key:^{s}}".format(
5271
key=key,
@@ -62,6 +81,9 @@ def _step(self, instance, colour=Colours.black):
6281

6382
cells.append(self._format_number(self._iterations + 1))
6483
cells.append(self._format_number(res["target"]))
84+
if self._is_constrained:
85+
cells.append(self._format_bool(res["allowed"]))
86+
6587

6688
for key in instance.space.keys:
6789
cells.append(self._format_number(res["params"][key]))
@@ -72,6 +94,10 @@ def _header(self, instance):
7294
cells = []
7395
cells.append(self._format_key("iter"))
7496
cells.append(self._format_key("target"))
97+
98+
if self._is_constrained:
99+
cells.append(self._format_key("allowed"))
100+
75101
for key in instance.space.keys:
76102
cells.append(self._format_key(key))
77103

0 commit comments

Comments
 (0)