-
Notifications
You must be signed in to change notification settings - Fork 43
Description
Motivation
Downstream, sometimes have had a user set bounds on a ContinuousOutput feature. If the bounds do not have identical left and righthand sides, then they are generally ignored.
ParEGO/botorch errors out in searching when the bounds reduce the space to have nothing in it.
This will happen due to human error if the bounds get set to constant, e.g.
bounds=(0.0, 0.0)
Error:
RuntimeError, probability tensor contains either inf, nan or element < 0'
Example of automatic assignment of bounds on Outputs to (0,1)
Notice there's no assigned bounds on the Continuous outptu:
domain = Domain.from_lists(
[
ContinuousInput(key="component_1", bounds=(0, 10)),
ContinuousInput(key="component_2", bounds=(0, 10)),
ContinuousInput(key="component_3", bounds=(0, 10)),
],
[
ContinuousOutput(key="viscosity", objective=MinimizeObjective()),
ContinuousOutput(key="hardness", objective=MaximizeObjective()),
],
)
s = domain.model_dump_json(indent=2)
#| output: asis
print(f"```json\n{s}\n```")
Dumping to json, you can see they were assigned to bounds=(0,1)
Relevant part of the json:
"outputs": {
"type": "Outputs",
"features": [
{
"type": "ContinuousOutput",
"key": "viscosity",
"unit": null,
"objective": {
"type": "MinimizeObjective",
"w": 1.0,
"bounds": [
0.0,
1.0
]
}
]
Now assume someone provides a json domain definition with
{
"type": "ContinuousOutput",
"key": "viscosity",
"unit": null,
"objective": {
"type": "MinimizeObjective",
"w": 1.0,
"bounds": [
0.0,
0.0
]
}
]
Where are bounds set anyway?
MaximizeObjective and MinimizeObjective inherit from IdentityObjective, which explicitly sets Bounds =(0,1)
bofire/bofire/data_models/objectives/identity.py
Lines 11 to 23 in 63e6122
| class IdentityObjective(Objective): | |
| """An objective returning the identity as reward. | |
| The return can be scaled, when a lower and upper bound are provided. | |
| Attributes: | |
| w (float): float between zero and one for weighting the objective | |
| bounds (Tuple[float], optional): Bound for normalizing the objective between zero and one. Defaults to (0,1). | |
| """ | |
| type: Literal["IdentityObjective"] = "IdentityObjective" # type: ignore | |
| w: TWeight = 1 | |
| bounds: Bounds = [0, 1] |
Describe the solution you'd like to see implemented in BoFire.
I think if the validator had a more strict requirement than monotonically increasing, that should do it.
bofire/bofire/data_models/types.py
Lines 94 to 98 in 63e6122
| Bounds = Annotated[ | |
| Union[List[float], Tuple[float, float]], | |
| Field(min_length=2, max_length=2), | |
| AfterValidator(validate_monotonically_increasing), | |
| ] |
STRONGER Solution: drop the bounds on objectives entirely.
[Obviously, will not fix all problems about search spaces being empty, but will catch some problems.]
Describe any alternatives you've considered to the above solution.
Minimally, check the domain for inconsistencies like this and then raise a verbose error.
Is this related to an existing issue in BoFire or another repository? If so please include links to those issues here.
No response
Pull Request
None