Skip to content

Commit 6e59e96

Browse files
committed
Make constraints work with parameter types
1 parent acd4c54 commit 6e59e96

File tree

5 files changed

+43
-35
lines changed

5 files changed

+43
-35
lines changed

bayes_opt/acquisition.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -992,11 +992,11 @@ def _copy_target_space(self, target_space: TargetSpace) -> TargetSpace:
992992
keys = target_space.keys
993993
pbounds = {key: bound for key, bound in zip(keys, target_space.bounds)}
994994
target_space_copy = TargetSpace(
995-
None,
996-
pbounds=pbounds,
997-
constraint=target_space.constraint,
998-
allow_duplicate_points=target_space._allow_duplicate_points,
995+
None, pbounds=pbounds, allow_duplicate_points=target_space._allow_duplicate_points
999996
)
997+
if target_space._constraint is not None:
998+
target_space_copy.set_constraint(target_space.constraint)
999+
10001000
target_space_copy._params = deepcopy(target_space._params)
10011001
target_space_copy._target = deepcopy(target_space._target)
10021002

bayes_opt/bayesian_optimization.py

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -101,25 +101,23 @@ def __init__(
101101
else:
102102
self._acquisition_function = acquisition_function
103103

104+
# Data structure containing the function to be optimized, the
105+
# bounds of its domain, and a record of the evaluations we have
106+
# done so far
107+
self._space = TargetSpace(
108+
f, pbounds, random_state=random_state, allow_duplicate_points=self._allow_duplicate_points
109+
)
104110
if constraint is None:
105-
# Data structure containing the function to be optimized, the
106-
# bounds of its domain, and a record of the evaluations we have
107-
# done so far
108-
self._space = TargetSpace(
109-
f, pbounds, random_state=random_state, allow_duplicate_points=self._allow_duplicate_points
110-
)
111111
self.is_constrained = False
112112
else:
113113
constraint_ = ConstraintModel(
114-
constraint.fun, constraint.lb, constraint.ub, random_state=random_state
115-
)
116-
self._space = TargetSpace(
117-
f,
118-
pbounds,
119-
constraint=constraint_,
114+
constraint.fun,
115+
constraint.lb,
116+
constraint.ub,
117+
transform=self._space.kernel_transform,
120118
random_state=random_state,
121-
allow_duplicate_points=self._allow_duplicate_points,
122119
)
120+
self._space.set_constraint(constraint_)
123121
self.is_constrained = True
124122

125123
# Internal GP regressor

bayes_opt/target_space.py

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@ def __init__(
7171
self,
7272
target_func: Callable[..., float] | None,
7373
pbounds: BoundsMapping,
74-
constraint: ConstraintModel | None = None,
7574
random_state: int | RandomState | None = None,
7675
allow_duplicate_points: bool | None = False,
7776
) -> None:
@@ -98,17 +97,24 @@ def __init__(
9897
# keep track of unique points we have seen so far
9998
self._cache: dict[tuple[float, ...], float | tuple[float, float | NDArray[Float]]] = {}
10099

101-
self._constraint: ConstraintModel | None = constraint
100+
self._constraint: ConstraintModel | None = None
102101

103-
if constraint is not None:
104-
# preallocated memory for constraint fulfillment
105-
self._constraint_values: NDArray[Float]
106-
if constraint.lb.size == 1:
107-
self._constraint_values = np.empty(shape=(0), dtype=float)
108-
else:
109-
self._constraint_values = np.empty(shape=(0, self._constraint.lb.size), dtype=float)
102+
def set_constraint(self, constraint: ConstraintModel) -> None:
103+
"""Set the constraint model.
104+
105+
Parameters
106+
----------
107+
constraint : ConstraintModel
108+
The constraint model to be set.
109+
"""
110+
self._constraint = constraint
111+
112+
# preallocated memory for constraint fulfillment
113+
self._constraint_values: NDArray[Float]
114+
if constraint.lb.size == 1:
115+
self._constraint_values = np.empty(shape=(0), dtype=float)
110116
else:
111-
self._constraint = None
117+
self._constraint_values = np.empty(shape=(0, self._constraint.lb.size), dtype=float)
112118

113119
def __contains__(self, x: NDArray[Float]) -> bool:
114120
"""Check if this parameter has already been registered.

tests/test_acquisition.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,9 @@ def constraint_func():
6464
@pytest.fixture
6565
def constrained_target_space(target_func):
6666
constraint_model = ConstraintModel(fun=lambda params: params["x"] + params["y"], lb=0.0, ub=1.0)
67-
return TargetSpace(
68-
target_func=target_func, pbounds={"x": (1, 4), "y": (0, 3)}, constraint=constraint_model
69-
)
67+
space = TargetSpace(target_func=target_func, pbounds={"x": (1, 4), "y": (0, 3)})
68+
space.set_constraint(constraint_model)
69+
return space
7070

7171

7272
class MockAcquisition(acquisition.AcquisitionFunction):

tests/test_target_space.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,9 @@ def test_register():
9999

100100

101101
def test_register_with_constraint():
102-
constraint = ConstraintModel(lambda x: x, -2, 2, transform=lambda x: x)
103-
space = TargetSpace(target_func, PBOUNDS, constraint=constraint)
102+
constraint = ConstraintModel(lambda x: x, -2, 2, transform=None)
103+
space = TargetSpace(target_func, PBOUNDS)
104+
space.set_constraint(constraint)
104105

105106
assert len(space) == 0
106107
# registering with dict
@@ -195,7 +196,8 @@ def test_y_max():
195196
def test_y_max_with_constraint():
196197
PBOUNDS = {"p1": (0, 10), "p2": (1, 100)}
197198
constraint = ConstraintModel(lambda p1, p2: p1 - p2, -2, 2)
198-
space = TargetSpace(target_func, PBOUNDS, constraint)
199+
space = TargetSpace(target_func, PBOUNDS)
200+
space.set_constraint(constraint)
199201
assert space._target_max() is None
200202
space.probe(params={"p1": 1, "p2": 2}) # Feasible
201203
space.probe(params={"p1": 5, "p2": 1}) # Unfeasible
@@ -229,7 +231,8 @@ def test_max():
229231
def test_max_with_constraint():
230232
PBOUNDS = {"p1": (0, 10), "p2": (1, 100)}
231233
constraint = ConstraintModel(lambda p1, p2: p1 - p2, -2, 2)
232-
space = TargetSpace(target_func, PBOUNDS, constraint=constraint)
234+
space = TargetSpace(target_func, PBOUNDS)
235+
space.set_constraint(constraint)
233236

234237
assert space.max() is None
235238
space.probe(params={"p1": 1, "p2": 2}) # Feasible
@@ -242,7 +245,8 @@ def test_max_with_constraint():
242245
def test_max_with_constraint_identical_target_value():
243246
PBOUNDS = {"p1": (0, 10), "p2": (1, 100)}
244247
constraint = ConstraintModel(lambda p1, p2: p1 - p2, -2, 2)
245-
space = TargetSpace(target_func, PBOUNDS, constraint=constraint)
248+
space = TargetSpace(target_func, PBOUNDS)
249+
space.set_constraint(constraint)
246250

247251
assert space.max() is None
248252
space.probe(params={"p1": 1, "p2": 2}) # Feasible

0 commit comments

Comments
 (0)