import os
import warnings
import matplotlib.pyplot as plt
import pandas as pd
import bofire.strategies.api as strategies
from bofire.benchmarks.api import BNH
from bofire.data_models.api import Domain, Inputs, Outputs
from bofire.data_models.features.api import ContinuousInput, ContinuousOutput
from bofire.data_models.objectives.api import (
MaximizeSigmoidObjective,
MinimizeObjective,
MinimizeSigmoidObjective,
)
from bofire.data_models.strategies.api import MoboStrategy, RandomStrategy
from bofire.plot.api import plot_objective_plotly
from bofire.runners.api import run
from bofire.utils.multiobjective import compute_hypervolume
warnings.simplefilter("once")
SMOKE_TEST = os.environ.get("SMOKE_TEST")BNH Benchmark
Imports
Random Strategy
def sample(domain):
datamodel = RandomStrategy(domain=domain)
sampler = strategies.map(data_model=datamodel)
sampled = sampler.ask(10)
return sampled
def hypervolume(domain: Domain, experiments: pd.DataFrame) -> float:
if "c1" in experiments.columns:
return compute_hypervolume(
domain,
experiments.loc[(experiments.c1 <= 25) & (experiments.c2 >= 7.7)],
ref_point={"f1": 140, "f2": 50},
)
return compute_hypervolume(domain, experiments, ref_point={"f1": 140, "f2": 50})
random_results = run(
BNH(constraints=True),
strategy_factory=lambda domain: strategies.map(RandomStrategy(domain=domain)),
n_iterations=50 if not SMOKE_TEST else 1,
metric=hypervolume,
initial_sampler=sample,
n_runs=1,
n_procs=1,
) 0%| | 0/1 [00:00<?, ?it/s]/opt/hostedtoolcache/Python/3.12.12/x64/lib/python3.12/site-packages/bofire/utils/torch_tools.py:706: UserWarning:
The given NumPy array is not writable, and PyTorch does not support non-writable tensors. This means writing to this tensor will result in undefined behavior. You may want to copy the array to protect its data or make it writable before converting it to a tensor. This type of warning will be suppressed for the rest of this program. (Triggered internally at /pytorch/torch/csrc/utils/tensor_numpy.cpp:213.)
Run 0: 0%| | 0/1 [00:00<?, ?it/s]Run 0: 0%| | 0/1 [00:00<?, ?it/s, Current Best:=4536.375]Run 0: 100%|██████████| 1/1 [00:00<00:00, 46.95it/s, Current Best:=4536.375]
MOBO Strategy
Without Constraints
def strategy_factory(domain: Domain):
data_model = MoboStrategy(domain=domain, ref_point={"f1": 140, "f2": 50})
return strategies.map(data_model)
results = run(
BNH(constraints=False),
strategy_factory=strategy_factory,
n_iterations=50 if not SMOKE_TEST else 1,
metric=hypervolume,
initial_sampler=sample,
n_runs=1,
n_procs=1,
) 0%| | 0/1 [00:00<?, ?it/s]Run 0: 0%| | 0/1 [00:03<?, ?it/s]Run 0: 0%| | 0/1 [00:03<?, ?it/s, Current Best:=4751.094]Run 0: 100%|██████████| 1/1 [00:03<00:00, 3.87s/it, Current Best:=4751.094]Run 0: 100%|██████████| 1/1 [00:03<00:00, 3.87s/it, Current Best:=4751.094]
With Constraints
Manual Setup of the Domain
domain = Domain(
inputs=Inputs(
features=[
ContinuousInput(key="x1", bounds=(0, 5)),
ContinuousInput(key="x2", bounds=(0, 3)),
],
),
outputs=Outputs(
features=[
ContinuousOutput(key="f1", objective=MinimizeObjective()),
ContinuousOutput(key="f2", objective=MinimizeObjective()),
# these are the output constraints, choose MinimizeSigmoidObjective for lower bound constraints
# and MaximizeSigmoidObjective for upper bound constraints
# tp is the threshold point, steepness is the steepness of the sigmoid that is applied to the constraint
# usually a steepness of 1000 is fine.
ContinuousOutput(
key="c1",
objective=MinimizeSigmoidObjective(tp=25, steepness=1000),
),
ContinuousOutput(
key="c2",
objective=MaximizeSigmoidObjective(tp=7.7, steepness=1000),
),
],
),
)One can visualize the objectives in the following way:
feat = domain.outputs.get_by_key("c1")
if not SMOKE_TEST:
plot_objective_plotly(feat, lower=20, upper=30) # type: ignorefeat = domain.outputs.get_by_key("c2")
if not SMOKE_TEST:
plot_objective_plotly(feat, lower=5, upper=10) # type: ignoreRun tbe optimization
The warnings can be ignored. They are stemming just from an internal postprocessing step and will be removed soon.
c_results = run(
BNH(constraints=True),
strategy_factory=strategy_factory,
n_iterations=50 if not SMOKE_TEST else 1,
metric=hypervolume,
initial_sampler=sample,
n_runs=1,
n_procs=1,
) 0%| | 0/1 [00:00<?, ?it/s]/opt/hostedtoolcache/Python/3.12.12/x64/lib/python3.12/site-packages/pandas/core/arraylike.py:402: RuntimeWarning:
overflow encountered in exp
Run 0: 0%| | 0/1 [00:03<?, ?it/s]Run 0: 0%| | 0/1 [00:03<?, ?it/s, Current Best:=4397.589]Run 0: 100%|██████████| 1/1 [00:03<00:00, 3.78s/it, Current Best:=4397.589]Run 0: 100%|██████████| 1/1 [00:03<00:00, 3.78s/it, Current Best:=4397.589]
if not SMOKE_TEST:
fig, ax = plt.subplots()
ax.plot(results[0][1], label="without constraints")
ax.plot(c_results[0][1], label="with constraints")
ax.set_xlabel("iteration")
ax.set_ylabel("hypervolume")
ax.legend()
plt.show()