Example for using exclusion constraints incorporating sums and products¶
This examples demonstrates an exclusion constraint using products and sums.
This example assumes some basic familiarity with using BayBE.
We thus refer to campaign
for a basic example.
Necessary imports for this example¶
import os
import numpy as np
from baybe import Campaign
from baybe.constraints import (
DiscreteProductConstraint,
DiscreteSumConstraint,
ThresholdCondition,
)
from baybe.objectives import SingleTargetObjective
from baybe.parameters import (
CategoricalParameter,
NumericalDiscreteParameter,
SubstanceParameter,
)
from baybe.searchspace import SearchSpace
from baybe.targets import NumericalTarget
from baybe.utils.dataframe import add_fake_results
Experiment setup¶
SMOKE_TEST = "SMOKE_TEST" in os.environ
RESOLUTION = 3 if SMOKE_TEST else 5
dict_solvent = {
"water": "O",
"C1": "C",
"C2": "CC",
}
solvent = SubstanceParameter(name="Solvent", data=dict_solvent, encoding="RDKIT")
speed = CategoricalParameter(
name="Speed", values=["slow", "normal", "fast"], encoding="INT"
)
num_parameter_1 = NumericalDiscreteParameter(
name="NumParam1", values=list(np.linspace(0, 100, RESOLUTION)), tolerance=0.5
)
num_parameter_2 = NumericalDiscreteParameter(
name="NumParam2", values=list(np.linspace(0, 100, RESOLUTION)), tolerance=0.5
)
num_parameter_3 = NumericalDiscreteParameter(
name="NumParam3", values=list(np.linspace(0, 100, RESOLUTION)), tolerance=0.5
)
num_parameter_4 = NumericalDiscreteParameter(
name="NumParam4", values=list(np.linspace(0, 100, RESOLUTION)), tolerance=0.5
)
num_parameter_5 = NumericalDiscreteParameter(
name="NumParam5", values=list(np.linspace(0, 100, RESOLUTION)), tolerance=0.5
)
num_parameter_6 = NumericalDiscreteParameter(
name="NumParam6", values=list(np.linspace(0, 100, RESOLUTION)), tolerance=0.5
)
parameters = [
solvent,
speed,
num_parameter_1,
num_parameter_2,
num_parameter_3,
num_parameter_4,
num_parameter_5,
num_parameter_6,
]
Creating the constraints¶
Constraints are used when creating the searchspace object. Thus, they need to be defined prior to the searchspace creation.
sum_constraint_1 = DiscreteSumConstraint(
parameters=["NumParam1", "NumParam2"],
condition=ThresholdCondition(threshold=150.0, operator="<="),
)
sum_constraint_2 = DiscreteSumConstraint(
parameters=["NumParam5", "NumParam6"],
condition=ThresholdCondition(threshold=100, operator="=", tolerance=1.0),
)
prod_constraint = DiscreteProductConstraint(
parameters=["NumParam3", "NumParam4"],
condition=ThresholdCondition(threshold=30, operator=">="),
)
constraints = [sum_constraint_1, sum_constraint_2, prod_constraint]
Creating the searchspace and the objective¶
searchspace = SearchSpace.from_product(parameters=parameters, constraints=constraints)
[17:00:57] DEPRECATION WARNING: please use MorganGenerator
[17:00:57] DEPRECATION WARNING: please use MorganGenerator
[17:00:57] DEPRECATION WARNING: please use MorganGenerator
[17:00:57] DEPRECATION WARNING: please use MorganGenerator
[17:00:57] DEPRECATION WARNING: please use MorganGenerator
[17:00:57] DEPRECATION WARNING: please use MorganGenerator
[17:00:57] DEPRECATION WARNING: please use MorganGenerator
[17:00:57] DEPRECATION WARNING: please use MorganGenerator
[17:00:57] DEPRECATION WARNING: please use MorganGenerator
objective = SingleTargetObjective(target=NumericalTarget(name="Target_1", mode="MAX"))
Creating and printing the campaign¶
campaign = Campaign(searchspace=searchspace, objective=objective)
print(campaign)
Campaign
Meta Data
Batches done: 0
Fits done: 0
SearchSpace
Search Space Type: DISCRETE
SubspaceDiscrete
Discrete Parameters
Name Type Num_Values Encoding
0 NumParam1 NumericalDis... 3 None
1 NumParam2 NumericalDis... 3 None
2 NumParam3 NumericalDis... 3 None
.. ... ... ... ...
5 NumParam6 NumericalDis... 3 None
6 Solvent SubstancePar... 3 SubstanceEnc...
7 Speed CategoricalP... 3 CategoricalE...
[8 rows x 4 columns]
Experimental Representation
Solvent Speed ... NumParam5 NumParam6
0 C1 fast ... 0.0 100.0
1 C1 fast ... 50.0 50.0
2 C1 fast ... 100.0 0.0
.. ... ... ... ... ...
861 water slow ... 0.0 100.0
862 water slow ... 50.0 50.0
863 water slow ... 100.0 0.0
[864 rows x 8 columns]
Meta Data
was_recommended: 0/864
was_measured: 0/864
dont_recommend: 0/864
Constraints
Type Affected_Paramet
0 DiscreteSumC... [NumParam1, ...
1 DiscreteSumC... [NumParam5, ...
2 DiscreteProd... [NumParam3, ...
Computational Representation
NumParam1 NumParam2 ... Solvent_RDKIT_Ma Speed
0 0.0 0.0 ... -0.078 0.0
1 0.0 0.0 ... -0.078 0.0
2 0.0 0.0 ... -0.078 0.0
.. ... ... ... ... ...
861 100.0 50.0 ... -0.412 2.0
862 100.0 50.0 ... -0.412 2.0
863 100.0 50.0 ... -0.412 2.0
[864 rows x 9 columns]
Objective
Type: SingleTargetObjective
Targets
Type Name ... Upper_Bound Transformation
0 NumericalTarget Target_1 ... inf None
[1 rows x 6 columns]
TwoPhaseMetaRecommender
Initial recommender
RandomRecommender
Compatibility: SearchSpaceType.HYBRID
Recommender
BotorchRecommender
Surrogate
GaussianProcessSurrogate
Supports Transfer Learning: True
Kernel factory: DefaultKernelFactory()
Acquisition function: qLogExpectedImprovement()
Compatibility: SearchSpaceType.HYBRID
Sequential continuous: False
Hybrid sampler: None
Sampling percentage: 1.0
Switch after: 1
Manual verification of the constraints¶
The following loop performs some recommendations and manually verifies the given constraints.
N_ITERATIONS = 2 if SMOKE_TEST else 5
for kIter in range(N_ITERATIONS):
print(f"\n\n#### ITERATION {kIter+1} ####")
print("## ASSERTS ##")
print(
"Number of entries with 1,2-sum above 150: ",
(
campaign.searchspace.discrete.exp_rep[["NumParam1", "NumParam2"]].sum(
axis=1
)
> 150.0
).sum(),
)
print(
"Number of entries with 3,4-product under 30: ",
(
campaign.searchspace.discrete.exp_rep[["NumParam3", "NumParam4"]].prod(
axis=1
)
< 30
).sum(),
)
print(
"Number of entries with 5,6-sum unequal to 100: ",
campaign.searchspace.discrete.exp_rep[["NumParam5", "NumParam6"]]
.sum(axis=1)
.apply(lambda x: x - 100.0)
.abs()
.gt(0.01)
.sum(),
)
rec = campaign.recommend(batch_size=5)
add_fake_results(rec, campaign.targets)
campaign.add_measurements(rec)
#### ITERATION 1 ####
## ASSERTS ##
Number of entries with 1,2-sum above 150: 0
Number of entries with 3,4-product under 30: 0
Number of entries with 5,6-sum unequal to 100: 0
#### ITERATION 2 ####
## ASSERTS ##
Number of entries with 1,2-sum above 150: 0
Number of entries with 3,4-product under 30: 0
Number of entries with 5,6-sum unequal to 100: 0