Strategies
Strategies are the key ingredient of BoFire that explore the search space defined in the Domain
and provide candidates for the next experiment or batch of experiments. Available strategies can be clustered in the following subclasses.
Non-predictive Strategies
BoFire offers the following strategies for sampling from the search space (no output features need to be provided in the Domain
):
-
RandomStrategy
: This strategy proposes candidates by (quasi-)random sampling from the search space. It is applicable to almost all combinations of input features and constraints. -
DoEStrategy
: This strategy offers model-based DoE approaches for proposing candidates. -
FractionalFactorialStrategy
: This strategy should be used to generate (fractional-)factorial designs.
Predictive Strategies
Predictive strategies are making use of (Bayesian) surrogate models to provide candidates with the intention to achieve certain goals depending on the provided objectives of the output features.
The following predictive strategies are available:
SoboStrategy
: Bayesian optimization strategy that optimizes a single-objective acquisition function. For multi-objective domains, different scalarizations are possible as implemented in theAdditiveSoboStrategy
,MultiplicativeSoboStrategy
,AdditiveMultiplicativeSoboStrategy
andCustomSoboStrategy
.MoboStrategy
: Bayesian optimization strategy that optimizes a hypervolume based acquisition function for pareto-based multi-objective optimization.QparegoStrategy
: Parallel ParEGO strategy for multiobjective optimization.MultifidelityStrategy:
Single objective multi-fidelity BO as described hereEntingStrategy
: Strategy based on theEntmoot
package that uses tree-based surrogate models to perform both single-objective and multiobjective optimization.
Combining Strategies
In BoFire, the StepwiseStrategy
operates on a sequence of strategies and determines when to switch between them based on customizable logical operators.
The StepwiseStrategy
is comprised of a sequence of Step
s, where each Step
consists of the following three attributes:
strategy_data
: data model of the strategy which should be executed in this step.condition
: A logical expression that determines when thisstep
's strategy should be executed. TheStepwiseStrategy
evaluates each step in order and selects the first strategy whose condition evaluates toTrue
.transform
: An object that can be used to transform experiments and/or candidates before they enter/leave the strategy assigned in the step.
The following example demonstrates how to combine a RandomStrategy
with a SoboStrategy
using the StepwiseStrategy
. In this setup, the RandomStrategy
is applied initially to propose candidates until 10 experiments have been completed. Once this threshold is reached, the strategy automatically switches to the SoboStrategy
for subsequent candidate generation.
import bofire.strategies.api as strategies
from bofire.benchmarks.api import Himmelblau
from bofire.data_models.strategies.api import (
AlwaysTrueCondition,
NumberOfExperimentsCondition,
RandomStrategy,
SoboStrategy,
Step,
StepwiseStrategy,
)
domain = Himmelblau().domain
strategy_data = StepwiseStrategy(
domain=domain,
steps=[
Step(
strategy_data=RandomStrategy(domain=domain),
condition=NumberOfExperimentsCondition(n_experiments=10),
),
Step(
strategy_data=SoboStrategy(domain=domain), condition=AlwaysTrueCondition()
),
],
)
strategy = strategies.map(strategy_data)
When dealing with output constraints, it is often beneficial to ensure that a certain number of experiments satisfy these constraints before proceeding with the main optimization. If no feasible experiments have been found, the strategy should prioritize generating candidates likely to fulfill the output constraints. This can be accomplished by using the qLogPF
(Probability of Feasibility) acquisition function together with the FeasibleExperimentCondition
. This approach allows the optimization process to focus first on feasibility, and only switch to the main objective once enough feasible experiments are available.
In the following example, a RandomStrategy
is applied for the initial 10 experiments to broadly explore the search space. Afterward, the SoboStrategy
with the qLogPF
acquisition function is used to prioritize finding at least one feasible experiment that satisfies the output constraints. Once this feasibility criterion is met, the strategy transitions to the standard SoboStrategy
to focus on optimizing the main objective.
import bofire.strategies.api as strategies
from bofire.benchmarks.api import DTLZ2
from bofire.data_models.acquisition_functions.api import qLogPF
from bofire.data_models.objectives.api import MaximizeSigmoidObjective
from bofire.data_models.strategies.api import (
AlwaysTrueCondition,
FeasibleExperimentCondition,
NumberOfExperimentsCondition,
RandomStrategy,
SoboStrategy,
Step,
StepwiseStrategy,
)
# create a domain with one output constraint by assigning a MaximizeSigmoidObjective
# to the output with key "f_1"
domain = DTLZ2(dim=6).domain
domain.outputs.get_by_key("f_1").objective = MaximizeSigmoidObjective(
tp=0.5, steepness=100
)
strategy_data = StepwiseStrategy(
domain=domain,
steps=[
Step(
strategy_data=RandomStrategy(domain=domain),
condition=NumberOfExperimentsCondition(n_experiments=10),
),
Step(
strategy_data=SoboStrategy(domain=domain, acquisition_function=qLogPF()),
condition=FeasibleExperimentCondition(n_required_feasible_experiments=1),
),
Step(
strategy_data=SoboStrategy(domain=domain), condition=AlwaysTrueCondition()
),
],
)
strategy = strategies.map(strategy_data)