Skip to content

Objectives

categorical

ConstrainedCategoricalObjective

Bases: ConstrainedObjective, Objective

Compute the categorical objective value as:

Po where P is an [n, c] matrix where each row is a probability vector
(P[i, :].sum()=1 for all i) and o is a vector of size [c] of objective values

Attributes:

Name Type Description
w float

float between zero and one for weighting the objective.

desirability list

list of values of size c (c is number of categories) such that the i-th entry is in {True, False}

Source code in bofire/data_models/objectives/categorical.py
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
class ConstrainedCategoricalObjective(ConstrainedObjective, Objective):
    """Compute the categorical objective value as:

        Po where P is an [n, c] matrix where each row is a probability vector
        (P[i, :].sum()=1 for all i) and o is a vector of size [c] of objective values

    Attributes:
        w (float): float between zero and one for weighting the objective.
        desirability (list): list of values of size c (c is number of categories) such that the i-th entry is in {True, False}

    """

    w: TWeight = 1.0
    categories: CategoryVals
    desirability: List[bool]
    type: Literal["ConstrainedCategoricalObjective"] = "ConstrainedCategoricalObjective"

    @model_validator(mode="after")
    def validate_desireability(self):
        """Validates that categories have unique names

        Args:
            categories (List[str]): List or tuple of category names

        Raises:
            ValueError: when categories do not match objective categories

        Returns:
            Tuple[str]: Tuple of the categories

        """
        if len(self.desirability) != len(self.categories):
            raise ValueError(
                "number of categories differs from number of desirabilities",
            )
        return self

    def to_dict(self) -> Dict:
        """Returns the categories and corresponding objective values as dictionary"""
        return dict(zip(self.categories, self.desirability))

    def to_dict_label(self) -> Dict:
        """Returns the categories and label location of categories"""
        return {c: i for i, c in enumerate(self.categories)}

    def from_dict_label(self) -> Dict:
        """Returns the label location and the categories"""
        d = self.to_dict_label()
        return dict(zip(d.values(), d.keys()))

    def __call__(
        self,
        x: Union[pd.Series, np.ndarray],
        x_adapt: Optional[Union[pd.Series, np.ndarray]] = None,
    ) -> Union[pd.Series, np.ndarray, float]:
        """The call function returning a probabilistic reward for x.

        Args:
            x (np.ndarray): A matrix of x values
            x_adapt (Optional[np.ndarray], optional): An array of x values which are used to
                update the objective parameters on the fly. Defaults to None.

        Returns:
            np.ndarray: A reward calculated as inner product of probabilities and feasible objectives.

        """
        return np.dot(x, np.array(self.desirability))

__call__(x, x_adapt=None)

The call function returning a probabilistic reward for x.

Parameters:

Name Type Description Default
x ndarray

A matrix of x values

required
x_adapt Optional[ndarray]

An array of x values which are used to update the objective parameters on the fly. Defaults to None.

None

Returns:

Type Description
Union[Series, ndarray, float]

np.ndarray: A reward calculated as inner product of probabilities and feasible objectives.

Source code in bofire/data_models/objectives/categorical.py
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
def __call__(
    self,
    x: Union[pd.Series, np.ndarray],
    x_adapt: Optional[Union[pd.Series, np.ndarray]] = None,
) -> Union[pd.Series, np.ndarray, float]:
    """The call function returning a probabilistic reward for x.

    Args:
        x (np.ndarray): A matrix of x values
        x_adapt (Optional[np.ndarray], optional): An array of x values which are used to
            update the objective parameters on the fly. Defaults to None.

    Returns:
        np.ndarray: A reward calculated as inner product of probabilities and feasible objectives.

    """
    return np.dot(x, np.array(self.desirability))

from_dict_label()

Returns the label location and the categories

Source code in bofire/data_models/objectives/categorical.py
60
61
62
63
def from_dict_label(self) -> Dict:
    """Returns the label location and the categories"""
    d = self.to_dict_label()
    return dict(zip(d.values(), d.keys()))

to_dict()

Returns the categories and corresponding objective values as dictionary

Source code in bofire/data_models/objectives/categorical.py
52
53
54
def to_dict(self) -> Dict:
    """Returns the categories and corresponding objective values as dictionary"""
    return dict(zip(self.categories, self.desirability))

to_dict_label()

Returns the categories and label location of categories

Source code in bofire/data_models/objectives/categorical.py
56
57
58
def to_dict_label(self) -> Dict:
    """Returns the categories and label location of categories"""
    return {c: i for i, c in enumerate(self.categories)}

validate_desireability()

Validates that categories have unique names

Parameters:

Name Type Description Default
categories List[str]

List or tuple of category names

required

Raises:

Type Description
ValueError

when categories do not match objective categories

Returns:

Type Description

Tuple[str]: Tuple of the categories

Source code in bofire/data_models/objectives/categorical.py
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
@model_validator(mode="after")
def validate_desireability(self):
    """Validates that categories have unique names

    Args:
        categories (List[str]): List or tuple of category names

    Raises:
        ValueError: when categories do not match objective categories

    Returns:
        Tuple[str]: Tuple of the categories

    """
    if len(self.desirability) != len(self.categories):
        raise ValueError(
            "number of categories differs from number of desirabilities",
        )
    return self

desirabilities

DecreasingDesirabilityObjective

Bases: DesirabilityObjective

An objective returning a reward the negative, shifted scaled identity, but trimmed at the bounds:

d = ((upper_bound - x) / (upper_bound - lower_bound))^t

where:

t = exp(log_shape_factor)

Note, that with clipping the reward is always between zero and one.

Attributes:

Name Type Description
clip bool

Whether to clip the values below/above the lower/upper bound, by default True.

log_shape_factor float

Logarithm of the shape factor: Whether the interpolation between the lower bound and the upper is linear (=0), convex (>0) or concave (<0) , by default 0.0.

w float

relative weight, by default = 1.

bounds tuple[float]

lower and upper bound of the desirability. Below bounds[0] the desirability is =1 (if clip=True) or >1 (if clip=False). Above bounds[1] the desirability is =0 (if clip=True) or <0 (if clip=False). Defaults to (0, 1).

Source code in bofire/data_models/objectives/desirabilities.py
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
class DecreasingDesirabilityObjective(DesirabilityObjective):
    """An objective returning a reward the negative, shifted scaled identity, but trimmed at the bounds:

        d = ((upper_bound - x) / (upper_bound - lower_bound))^t

    where:

        t = exp(log_shape_factor)

    Note, that with clipping the reward is always between zero and one.

    Attributes:
        clip (bool): Whether to clip the values below/above the lower/upper bound, by
            default True.
        log_shape_factor (float): Logarithm of the shape factor:
            Whether the interpolation between the lower bound and the upper is linear (=0),
            convex (>0) or concave (<0) , by default 0.0.
        w (float): relative weight, by default = 1.
        bounds (tuple[float]): lower and upper bound of the desirability. Below
            bounds[0] the desirability is =1 (if clip=True) or >1 (if clip=False). Above
            bounds[1] the desirability is =0  (if clip=True) or <0 (if clip=False).
            Defaults to (0, 1).
    """

    type: Literal["DecreasingDesirabilityObjective"] = "DecreasingDesirabilityObjective"  # type: ignore
    log_shape_factor: float = 0.0

    def call_numpy(
        self,
        x: np.ndarray,
        x_adapt: Optional[Union[pd.Series, np.ndarray]] = None,
    ) -> np.ndarray:
        y = np.zeros(x.shape)
        if self.clip:
            y[x < self.lower_bound] = 1.0
            y[x > self.upper_bound] = 0.0
            between = (x >= self.lower_bound) & (x <= self.upper_bound)
        else:
            between = np.full(x.shape, True)

        t = np.exp(self.log_shape_factor)

        y[between] = np.power(
            (self.upper_bound - x[between]) / (self.upper_bound - self.lower_bound), t
        )

        return y

DesirabilityObjective

Bases: IdentityObjective

Abstract class for desirability objectives. Works as Identity Objective

Source code in bofire/data_models/objectives/desirabilities.py
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
class DesirabilityObjective(IdentityObjective):
    """Abstract class for desirability objectives. Works as Identity Objective"""

    type: Literal["DesirabilityObjective"] = "DesirabilityObjective"  # type: ignore
    clip: bool = True

    @pydantic.model_validator(mode="after")
    def validate_clip(self):
        if self.clip:
            return self

        log_shapes = {
            key: val
            for (key, val) in self.__dict__.items()
            if key.startswith("log_shape_factor")
        }
        for key, log_shape_ in log_shapes.items():
            if log_shape_ != 0:
                raise ValueError(
                    f"Log shape factor {key} must be zero if clip is False."
                )
        return self

    def __call__(
        self, x: Union[pd.Series, np.ndarray], x_adapt
    ) -> Union[pd.Series, np.ndarray]:
        """Wrapper function for to call numpy and torch functions with series
        or numpy arrays. matches __call__ signature of objectives."""
        if isinstance(x, pd.Series):
            s: pd.Series = x
            return pd.Series(self.call_numpy(s.to_numpy()), name=s.name)

        return self.call_numpy(x)

    @abstractmethod
    def call_numpy(self, x: np.ndarray) -> np.ndarray:
        raise NotImplementedError()

__call__(x, x_adapt)

Wrapper function for to call numpy and torch functions with series or numpy arrays. matches call signature of objectives.

Source code in bofire/data_models/objectives/desirabilities.py
34
35
36
37
38
39
40
41
42
43
def __call__(
    self, x: Union[pd.Series, np.ndarray], x_adapt
) -> Union[pd.Series, np.ndarray]:
    """Wrapper function for to call numpy and torch functions with series
    or numpy arrays. matches __call__ signature of objectives."""
    if isinstance(x, pd.Series):
        s: pd.Series = x
        return pd.Series(self.call_numpy(s.to_numpy()), name=s.name)

    return self.call_numpy(x)

IncreasingDesirabilityObjective

Bases: DesirabilityObjective

An objective returning a reward the scaled identity, but trimmed at the bounds:

d = ((x - lower_bound) / (upper_bound - lower_bound))^t

if clip is True, the reward is zero for x < lower_bound and one for x > upper_bound.

where:

t = exp(log_shape_factor)

Note, that with clipping the reward is always between zero and one.

Attributes:

Name Type Description
clip bool

Whether to clip the values below/above the lower/upper bound, by default True.

log_shape_factor float

Logarithm of the shape factor: Whether the interpolation between the lower bound and the upper is linear (=0), convex (>0) or concave (<0) , by default 0.0.

w float

relative weight, by default = 1.

bounds tuple[float]

lower and upper bound of the desirability. Below bounds[0] the desirability is =0 (if clip=True) or <0 (if clip=False). Above bounds[1] the desirability is =1 (if clip=True) or >1 (if clip=False). Defaults to (0, 1).

Source code in bofire/data_models/objectives/desirabilities.py
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
class IncreasingDesirabilityObjective(DesirabilityObjective):
    """An objective returning a reward the scaled identity, but trimmed at the bounds:

        d = ((x - lower_bound) / (upper_bound - lower_bound))^t

    if clip is True, the reward is zero for x < lower_bound and one for x > upper_bound.

    where:

        t = exp(log_shape_factor)

    Note, that with clipping the reward is always between zero and one.

    Attributes:
        clip (bool): Whether to clip the values below/above the lower/upper bound, by
            default True.
        log_shape_factor (float): Logarithm of the shape factor:
            Whether the interpolation between the lower bound and the upper is linear (=0),
            convex (>0) or concave (<0) , by default 0.0.
        w (float): relative weight, by default = 1.
        bounds (tuple[float]): lower and upper bound of the desirability. Below
            bounds[0] the desirability is =0 (if clip=True) or <0 (if clip=False). Above
            bounds[1] the desirability is =1  (if clip=True) or >1 (if clip=False).
            Defaults to (0, 1).
    """

    type: Literal["IncreasingDesirabilityObjective"] = "IncreasingDesirabilityObjective"  # type: ignore
    log_shape_factor: float = 0.0

    def call_numpy(
        self,
        x: np.ndarray,
        x_adapt: Optional[Union[pd.Series, np.ndarray]] = None,
    ) -> np.ndarray:
        y = np.zeros(x.shape)
        if self.clip:
            y[x < self.lower_bound] = 0.0
            y[x > self.upper_bound] = 1.0
            between = (x >= self.lower_bound) & (x <= self.upper_bound)
        else:
            between = np.full(x.shape, True)

        t = np.exp(self.log_shape_factor)

        y[between] = np.power(
            (x[between] - self.lower_bound) / (self.upper_bound - self.lower_bound), t
        )

        return y

PeakDesirabilityObjective

Bases: DesirabilityObjective

A piecewise (linear or convex/concave) objective that increases from the lower bound to the peak position and decreases from the peak position to the upper bound.

Attributes:

Name Type Description
clip bool

Whether to clip the values below/above the lower/upper bound, by default True.

log_shape_factor float

Logarithm of the shape factor for the increasing part: Whether the interpolation between the lower bound and the peak is linear (=0), convex (>1) or concave (<1) , by default 0.0.

log_shape_factor_decreasing float

Logarithm of the shape factor for the decreasing part. Whether the interpolation between the peak and the upper bound is linear (=0), convex (>0) or concave (<0), by default 0.0.

peak_position float

Position of the peak, by default 0.5.

w float

relative weight: desirability, when x=peak_position, by default = 1.

bounds tuple[float]

lower and upper bound of the desirability. Below bounds[0] the desirability is =0 (if clip=True) or <0 (if clip=False). Above bounds[1] the desirability is =0 (if clip=True) or <0 (if clip=False). Defaults to (0, 1).

Source code in bofire/data_models/objectives/desirabilities.py
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
class PeakDesirabilityObjective(DesirabilityObjective):
    """
    A piecewise (linear or convex/concave) objective that increases from the lower bound
    to the peak position and decreases from the peak position to the upper bound.

    Attributes:
        clip (bool): Whether to clip the values below/above the lower/upper bound, by
            default True.
        log_shape_factor (float): Logarithm of the shape factor for the increasing part:
            Whether the interpolation between the lower bound and the peak is linear (=0),
            convex (>1) or concave (<1) , by default 0.0.
        log_shape_factor_decreasing (float): Logarithm of the shape factor for the
            decreasing part. Whether the interpolation between the peak and the upper
            bound is linear (=0), convex (>0) or concave (<0), by default 0.0.
        peak_position (float): Position of the peak, by default 0.5.
        w (float): relative weight: desirability, when x=peak_position, by default = 1.
        bounds (tuple[float]): lower and upper bound of the desirability. Below
            bounds[0] the desirability is =0 (if clip=True) or <0 (if clip=False). Above
            bounds[1] the desirability is =0  (if clip=True) or <0 (if clip=False).
            Defaults to (0, 1).
    """

    type: Literal["PeakDesirabilityObjective"] = "PeakDesirabilityObjective"  # type: ignore
    log_shape_factor: float = 0.0
    log_shape_factor_decreasing: float = 0.0  # often named log_t
    peak_position: float = 0.5  # often named T

    def call_numpy(
        self,
        x: np.ndarray,
        x_adapt: Optional[Union[pd.Series, np.ndarray]] = None,
    ) -> np.ndarray:
        y = np.zeros(x.shape)
        if self.clip:
            Incr = (x >= self.lower_bound) & (x <= self.peak_position)
            Decr = (x <= self.upper_bound) & (x > self.peak_position)
        else:
            Incr, Decr = x <= self.peak_position, x > self.peak_position

        s: float = np.exp(self.log_shape_factor)
        t: float = np.exp(self.log_shape_factor_decreasing)
        y[Incr] = np.power(
            np.divide(
                (x[Incr] - self.lower_bound), (self.peak_position - self.lower_bound)
            ),
            s,
        )
        y[Decr] = np.power(
            np.divide(
                (x[Decr] - self.upper_bound), (self.peak_position - self.upper_bound)
            ),
            t,
        )

        return y * self.w

    @pydantic.model_validator(mode="after")
    def validate_peak_position(self):
        bounds = self.bounds
        if self.peak_position < bounds[0] or self.peak_position > bounds[1]:
            raise ValueError(
                f"Peak position must be within bounds {bounds}, got {self.peak_position}"
            )
        return self

identity

IdentityObjective

Bases: Objective

An objective returning the identity as reward. The return can be scaled, when a lower and upper bound are provided.

Attributes:

Name Type Description
w float

float between zero and one for weighting the objective

bounds Tuple[float]

Bound for normalizing the objective between zero and one. Defaults to (0,1).

Source code in bofire/data_models/objectives/identity.py
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
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]

    @property
    def lower_bound(self) -> float:
        return self.bounds[0]

    @property
    def upper_bound(self) -> float:
        return self.bounds[1]

    @field_validator("bounds")
    @classmethod
    def validate_lower_upper(cls, bounds):
        """Validation function to ensure that lower bound is always greater the upper bound

        Args:
            values (Dict): The attributes of the class

        Raises:
            ValueError: when a lower bound higher than the upper bound is passed

        Returns:
            Dict: The attributes of the class

        """
        if bounds[0] > bounds[1]:
            raise ValueError(
                f"lower bound must be <= upper bound, got {bounds[0]} > {bounds[1]}",
            )
        return bounds

    def __call__(
        self,
        x: Union[pd.Series, np.ndarray],
        x_adapt: Optional[Union[pd.Series, np.ndarray]] = None,
    ) -> Union[pd.Series, np.ndarray]:
        """The call function returning a reward for passed x values

        Args:
            x (np.ndarray): An array of x values
            x_adapt (Optional[np.ndarray], optional): An array of x values which are used to
                update the objective parameters on the fly. Defaults to None.

        Returns:
            np.ndarray: The identity as reward, might be normalized to the passed lower and upper bounds

        """
        return (x - self.lower_bound) / (self.upper_bound - self.lower_bound)

__call__(x, x_adapt=None)

The call function returning a reward for passed x values

Parameters:

Name Type Description Default
x ndarray

An array of x values

required
x_adapt Optional[ndarray]

An array of x values which are used to update the objective parameters on the fly. Defaults to None.

None

Returns:

Type Description
Union[Series, ndarray]

np.ndarray: The identity as reward, might be normalized to the passed lower and upper bounds

Source code in bofire/data_models/objectives/identity.py
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
def __call__(
    self,
    x: Union[pd.Series, np.ndarray],
    x_adapt: Optional[Union[pd.Series, np.ndarray]] = None,
) -> Union[pd.Series, np.ndarray]:
    """The call function returning a reward for passed x values

    Args:
        x (np.ndarray): An array of x values
        x_adapt (Optional[np.ndarray], optional): An array of x values which are used to
            update the objective parameters on the fly. Defaults to None.

    Returns:
        np.ndarray: The identity as reward, might be normalized to the passed lower and upper bounds

    """
    return (x - self.lower_bound) / (self.upper_bound - self.lower_bound)

validate_lower_upper(bounds) classmethod

Validation function to ensure that lower bound is always greater the upper bound

Parameters:

Name Type Description Default
values Dict

The attributes of the class

required

Raises:

Type Description
ValueError

when a lower bound higher than the upper bound is passed

Returns:

Name Type Description
Dict

The attributes of the class

Source code in bofire/data_models/objectives/identity.py
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
@field_validator("bounds")
@classmethod
def validate_lower_upper(cls, bounds):
    """Validation function to ensure that lower bound is always greater the upper bound

    Args:
        values (Dict): The attributes of the class

    Raises:
        ValueError: when a lower bound higher than the upper bound is passed

    Returns:
        Dict: The attributes of the class

    """
    if bounds[0] > bounds[1]:
        raise ValueError(
            f"lower bound must be <= upper bound, got {bounds[0]} > {bounds[1]}",
        )
    return bounds

MaximizeObjective

Bases: IdentityObjective

Child class from the identity function without modifications, since the parent class is already defined as maximization

Attributes:

Name Type Description
w float

float between zero and one for weighting the objective

bounds Tuple[float]

Bound for normalizing the objective between zero and one. Defaults to (0,1).

Source code in bofire/data_models/objectives/identity.py
73
74
75
76
77
78
79
80
81
82
class MaximizeObjective(IdentityObjective):
    """Child class from the identity function without modifications, since the parent class is already defined as maximization

    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["MaximizeObjective"] = "MaximizeObjective"

MinimizeObjective

Bases: IdentityObjective

Class returning the negative identity as reward.

Attributes:

Name Type Description
w float

float between zero and one for weighting the objective

bounds Tuple[float]

Bound for normalizing the objective between zero and one. Defaults to (0,1).

Source code in bofire/data_models/objectives/identity.py
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
class MinimizeObjective(IdentityObjective):
    """Class returning the negative identity as reward.

    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["MinimizeObjective"] = "MinimizeObjective"

    def __call__(
        self,
        x: Union[pd.Series, np.ndarray],
        x_adapt: Optional[Union[pd.Series, np.ndarray]] = None,
    ) -> Union[pd.Series, np.ndarray]:
        """The call function returning a reward for passed x values

        Args:
            x (np.ndarray): An array of x values
            x_adapt (Optional[np.ndarray], optional): An array of x values which are used to
                update the objective parameters on the fly. Defaults to None.

        Returns:
            np.ndarray: The negative identity as reward, might be normalized to the passed lower and upper bounds

        """
        return -1.0 * (x - self.lower_bound) / (self.upper_bound - self.lower_bound)

__call__(x, x_adapt=None)

The call function returning a reward for passed x values

Parameters:

Name Type Description Default
x ndarray

An array of x values

required
x_adapt Optional[ndarray]

An array of x values which are used to update the objective parameters on the fly. Defaults to None.

None

Returns:

Type Description
Union[Series, ndarray]

np.ndarray: The negative identity as reward, might be normalized to the passed lower and upper bounds

Source code in bofire/data_models/objectives/identity.py
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
def __call__(
    self,
    x: Union[pd.Series, np.ndarray],
    x_adapt: Optional[Union[pd.Series, np.ndarray]] = None,
) -> Union[pd.Series, np.ndarray]:
    """The call function returning a reward for passed x values

    Args:
        x (np.ndarray): An array of x values
        x_adapt (Optional[np.ndarray], optional): An array of x values which are used to
            update the objective parameters on the fly. Defaults to None.

    Returns:
        np.ndarray: The negative identity as reward, might be normalized to the passed lower and upper bounds

    """
    return -1.0 * (x - self.lower_bound) / (self.upper_bound - self.lower_bound)

objective

ConstrainedObjective

This abstract class offers a convenience routine for transforming sigmoid based objectives to botorch output constraints.

Source code in bofire/data_models/objectives/objective.py
36
37
class ConstrainedObjective:
    """This abstract class offers a convenience routine for transforming sigmoid based objectives to botorch output constraints."""

Objective

Bases: BaseModel

The base class for all objectives

Source code in bofire/data_models/objectives/objective.py
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Objective(BaseModel):
    """The base class for all objectives"""

    type: str

    @abstractmethod
    def __call__(
        self,
        x: Union[pd.Series, np.ndarray],
        x_adapt: Optional[Union[pd.Series, np.ndarray]] = None,
    ) -> Union[pd.Series, np.ndarray]:
        """Abstract method to define the call function for the class Objective

        Args:
            x (np.ndarray): An array of x values for which the objective should be evaluated.
            x_adapt (Optional[np.ndarray], optional): An array of x values which are used to
                update the objective parameters on the fly. Defaults to None.

        Returns:
            np.ndarray: The desirability of the passed x values

        """

__call__(x, x_adapt=None) abstractmethod

Abstract method to define the call function for the class Objective

Parameters:

Name Type Description Default
x ndarray

An array of x values for which the objective should be evaluated.

required
x_adapt Optional[ndarray]

An array of x values which are used to update the objective parameters on the fly. Defaults to None.

None

Returns:

Type Description
Union[Series, ndarray]

np.ndarray: The desirability of the passed x values

Source code in bofire/data_models/objectives/objective.py
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@abstractmethod
def __call__(
    self,
    x: Union[pd.Series, np.ndarray],
    x_adapt: Optional[Union[pd.Series, np.ndarray]] = None,
) -> Union[pd.Series, np.ndarray]:
    """Abstract method to define the call function for the class Objective

    Args:
        x (np.ndarray): An array of x values for which the objective should be evaluated.
        x_adapt (Optional[np.ndarray], optional): An array of x values which are used to
            update the objective parameters on the fly. Defaults to None.

    Returns:
        np.ndarray: The desirability of the passed x values

    """

sigmoid

MaximizeSigmoidObjective

Bases: SigmoidObjective

Class for a maximizing sigmoid objective

Attributes:

Name Type Description
w float

float between zero and one for weighting the objective.

steepness float

Steepness of the sigmoid function. Has to be greater than zero.

tp float

Turning point of the sigmoid function.

Source code in bofire/data_models/objectives/sigmoid.py
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
class MaximizeSigmoidObjective(SigmoidObjective):
    """Class for a maximizing sigmoid objective

    Attributes:
        w (float): float between zero and one for weighting the objective.
        steepness (float): Steepness of the sigmoid function. Has to be greater than zero.
        tp (float): Turning point of the sigmoid function.

    """

    type: Literal["MaximizeSigmoidObjective"] = "MaximizeSigmoidObjective"

    def __call__(
        self,
        x: Union[pd.Series, np.ndarray],
        x_adapt: Optional[Union[pd.Series, np.ndarray]] = None,
    ) -> Union[pd.Series, np.ndarray]:
        """The call function returning a sigmoid shaped reward for passed x values.

        Args:
            x (np.ndarray): An array of x values
            x_adapt (np.ndarray): An array of x values which are used to update the objective parameters on the fly.

        Returns:
            np.ndarray: A reward calculated with a sigmoid function. The stepness and the tipping point can be modified via passed arguments.

        """
        return 1 / (1 + np.exp(-1 * self.steepness * (x - self.tp)))

__call__(x, x_adapt=None)

The call function returning a sigmoid shaped reward for passed x values.

Parameters:

Name Type Description Default
x ndarray

An array of x values

required
x_adapt ndarray

An array of x values which are used to update the objective parameters on the fly.

None

Returns:

Type Description
Union[Series, ndarray]

np.ndarray: A reward calculated with a sigmoid function. The stepness and the tipping point can be modified via passed arguments.

Source code in bofire/data_models/objectives/sigmoid.py
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
def __call__(
    self,
    x: Union[pd.Series, np.ndarray],
    x_adapt: Optional[Union[pd.Series, np.ndarray]] = None,
) -> Union[pd.Series, np.ndarray]:
    """The call function returning a sigmoid shaped reward for passed x values.

    Args:
        x (np.ndarray): An array of x values
        x_adapt (np.ndarray): An array of x values which are used to update the objective parameters on the fly.

    Returns:
        np.ndarray: A reward calculated with a sigmoid function. The stepness and the tipping point can be modified via passed arguments.

    """
    return 1 / (1 + np.exp(-1 * self.steepness * (x - self.tp)))

MinimizeSigmoidObjective

Bases: SigmoidObjective

Class for a minimizing a sigmoid objective

Attributes:

Name Type Description
w float

float between zero and one for weighting the objective.

steepness float

Steepness of the sigmoid function. Has to be greater than zero.

tp float

Turning point of the sigmoid function.

Source code in bofire/data_models/objectives/sigmoid.py
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
class MinimizeSigmoidObjective(SigmoidObjective):
    """Class for a minimizing a sigmoid objective

    Attributes:
        w (float): float between zero and one for weighting the objective.
        steepness (float): Steepness of the sigmoid function. Has to be greater than zero.
        tp (float): Turning point of the sigmoid function.

    """

    type: Literal["MinimizeSigmoidObjective"] = "MinimizeSigmoidObjective"

    def __call__(
        self,
        x: Union[pd.Series, np.ndarray],
        x_adapt: Optional[Union[pd.Series, np.ndarray]] = None,
    ) -> Union[pd.Series, np.ndarray]:
        """The call function returning a sigmoid shaped reward for passed x values.

        Args:
            x (np.ndarray): An array of x values
            x_adapt (np.ndarray): An array of x values which are used to update the objective parameters on the fly.

        Returns:
            np.ndarray: A reward calculated with a sigmoid function. The stepness and the tipping point can be modified via passed arguments.

        """
        return 1 - 1 / (1 + np.exp(-1 * self.steepness * (x - self.tp)))

__call__(x, x_adapt=None)

The call function returning a sigmoid shaped reward for passed x values.

Parameters:

Name Type Description Default
x ndarray

An array of x values

required
x_adapt ndarray

An array of x values which are used to update the objective parameters on the fly.

None

Returns:

Type Description
Union[Series, ndarray]

np.ndarray: A reward calculated with a sigmoid function. The stepness and the tipping point can be modified via passed arguments.

Source code in bofire/data_models/objectives/sigmoid.py
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
def __call__(
    self,
    x: Union[pd.Series, np.ndarray],
    x_adapt: Optional[Union[pd.Series, np.ndarray]] = None,
) -> Union[pd.Series, np.ndarray]:
    """The call function returning a sigmoid shaped reward for passed x values.

    Args:
        x (np.ndarray): An array of x values
        x_adapt (np.ndarray): An array of x values which are used to update the objective parameters on the fly.

    Returns:
        np.ndarray: A reward calculated with a sigmoid function. The stepness and the tipping point can be modified via passed arguments.

    """
    return 1 - 1 / (1 + np.exp(-1 * self.steepness * (x - self.tp)))

MovingMaximizeSigmoidObjective

Bases: SigmoidObjective

Class for a maximizing sigmoid objective with a moving turning point that depends on so far observed x values.

Attributes:

Name Type Description
w float

float between zero and one for weighting the objective when used in a weighting based strategy.

steepness float

Steepness of the sigmoid function. Has to be greater than zero.

tp float

Relative turning point of the sigmoid function. The actual turning point is calculated by adding the maximum of the observed x values to the relative turning point.

Source code in bofire/data_models/objectives/sigmoid.py
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
class MovingMaximizeSigmoidObjective(SigmoidObjective):
    """Class for a maximizing sigmoid objective with a moving turning point that depends on so far observed x values.

    Attributes:
        w (float): float between zero and one for weighting the objective when used in a weighting based strategy.
        steepness (float): Steepness of the sigmoid function. Has to be greater than zero.
        tp (float): Relative turning point of the sigmoid function. The actual turning point is calculated by adding
            the maximum of the observed x values to the relative turning point.

    """

    type: Literal["MovingMaximizeSigmoidObjective"] = "MovingMaximizeSigmoidObjective"

    def get_adjusted_tp(self, x: Union[pd.Series, np.ndarray]) -> float:
        """Get the adjusted turning point for the sigmoid function.

        Args:
            x (np.ndarray): An array of x values

        Returns:
            float: The adjusted turning point for the sigmoid function.

        """
        return x.max() + self.tp

    def __call__(
        self,
        x: Union[pd.Series, np.ndarray],
        x_adapt: Union[pd.Series, np.ndarray],
    ) -> Union[pd.Series, np.ndarray]:
        """The call function returning a sigmoid shaped reward for passed x values.

        Args:
            x (np.ndarray): An array of x values
            x_adapt (np.ndarray): An array of x values which are used to update the objective parameters on the fly.

        Returns:
            np.ndarray: A reward calculated with a sigmoid function. The stepness and the tipping point can be modified via passed arguments.

        """
        return 1 / (
            1 + np.exp(-1 * self.steepness * (x - self.get_adjusted_tp(x_adapt)))
        )

__call__(x, x_adapt)

The call function returning a sigmoid shaped reward for passed x values.

Parameters:

Name Type Description Default
x ndarray

An array of x values

required
x_adapt ndarray

An array of x values which are used to update the objective parameters on the fly.

required

Returns:

Type Description
Union[Series, ndarray]

np.ndarray: A reward calculated with a sigmoid function. The stepness and the tipping point can be modified via passed arguments.

Source code in bofire/data_models/objectives/sigmoid.py
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
def __call__(
    self,
    x: Union[pd.Series, np.ndarray],
    x_adapt: Union[pd.Series, np.ndarray],
) -> Union[pd.Series, np.ndarray]:
    """The call function returning a sigmoid shaped reward for passed x values.

    Args:
        x (np.ndarray): An array of x values
        x_adapt (np.ndarray): An array of x values which are used to update the objective parameters on the fly.

    Returns:
        np.ndarray: A reward calculated with a sigmoid function. The stepness and the tipping point can be modified via passed arguments.

    """
    return 1 / (
        1 + np.exp(-1 * self.steepness * (x - self.get_adjusted_tp(x_adapt)))
    )

get_adjusted_tp(x)

Get the adjusted turning point for the sigmoid function.

Parameters:

Name Type Description Default
x ndarray

An array of x values

required

Returns:

Name Type Description
float float

The adjusted turning point for the sigmoid function.

Source code in bofire/data_models/objectives/sigmoid.py
72
73
74
75
76
77
78
79
80
81
82
def get_adjusted_tp(self, x: Union[pd.Series, np.ndarray]) -> float:
    """Get the adjusted turning point for the sigmoid function.

    Args:
        x (np.ndarray): An array of x values

    Returns:
        float: The adjusted turning point for the sigmoid function.

    """
    return x.max() + self.tp

SigmoidObjective

Bases: Objective, ConstrainedObjective

Base class for all sigmoid shaped objectives

Attributes:

Name Type Description
w float

float between zero and one for weighting the objective.

steepness float

Steepness of the sigmoid function. Has to be greater than zero.

tp float

Turning point of the sigmoid function.

Source code in bofire/data_models/objectives/sigmoid.py
14
15
16
17
18
19
20
21
22
23
24
25
26
class SigmoidObjective(Objective, ConstrainedObjective):
    """Base class for all sigmoid shaped objectives

    Attributes:
        w (float): float between zero and one for weighting the objective.
        steepness (float): Steepness of the sigmoid function. Has to be greater than zero.
        tp (float): Turning point of the sigmoid function.

    """

    steepness: TGt0
    tp: float
    w: TWeight = 1

target

CloseToTargetObjective

Bases: Objective

Optimize towards a target value. It can be used as objective in multiobjective scenarios.

Attributes:

Name Type Description
w float

float between zero and one for weighting the objective.

target_value float

target value that should be reached.

exponent float

the exponent of the expression.

Source code in bofire/data_models/objectives/target.py
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class CloseToTargetObjective(Objective):
    """Optimize towards a target value. It can be used as objective
    in multiobjective scenarios.

    Attributes:
        w (float): float between zero and one for weighting the objective.
        target_value (float): target value that should be reached.
        exponent (float): the exponent of the expression.

    """

    type: Literal["CloseToTargetObjective"] = "CloseToTargetObjective"
    w: TWeight = 1
    target_value: float
    exponent: float

    def __call__(
        self,
        x: Union[pd.Series, np.ndarray],
        x_adapt: Optional[Union[pd.Series, np.ndarray]] = None,
    ) -> Union[pd.Series, np.ndarray]:
        return -1 * (np.abs(x - self.target_value) ** self.exponent)

TargetObjective

Bases: Objective, ConstrainedObjective

Class for objectives for optimizing towards a target value

Attributes:

Name Type Description
w float

float between zero and one for weighting the objective.

target_value float

target value that should be reached.

tolerance float

Tolerance for reaching the target. Has to be greater than zero.

steepness float

Steepness of the sigmoid function. Has to be greater than zero.

Source code in bofire/data_models/objectives/target.py
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
class TargetObjective(Objective, ConstrainedObjective):
    """Class for objectives for optimizing towards a target value

    Attributes:
        w (float): float between zero and one for weighting the objective.
        target_value (float): target value that should be reached.
        tolerance (float): Tolerance for reaching the target. Has to be greater than zero.
        steepness (float): Steepness of the sigmoid function. Has to be greater than zero.

    """

    type: Literal["TargetObjective"] = "TargetObjective"
    w: TWeight = 1
    target_value: float
    tolerance: TGe0
    steepness: TGt0

    def __call__(
        self,
        x: Union[pd.Series, np.ndarray],
        x_adapt: Optional[Union[pd.Series, np.ndarray]] = None,
    ) -> Union[pd.Series, np.ndarray]:
        """The call function returning a reward for passed x values.

        Args:
            x (np.array): An array of x values
            x_adapt (Optional[np.ndarray], optional): An array of x values which are used to
                update the objective parameters on the fly. Defaults to None.

        Returns:
            np.array: An array of reward values calculated by the product of two sigmoidal shaped functions resulting in a maximum at the target value.

        """
        return (
            1
            / (
                1
                + np.exp(
                    -1 * self.steepness * (x - (self.target_value - self.tolerance)),
                )
            )
            * (
                1
                - 1
                / (
                    1.0
                    + np.exp(
                        -1
                        * self.steepness
                        * (x - (self.target_value + self.tolerance)),
                    )
                )
            )
        )

__call__(x, x_adapt=None)

The call function returning a reward for passed x values.

Parameters:

Name Type Description Default
x array

An array of x values

required
x_adapt Optional[ndarray]

An array of x values which are used to update the objective parameters on the fly. Defaults to None.

None

Returns:

Type Description
Union[Series, ndarray]

np.array: An array of reward values calculated by the product of two sigmoidal shaped functions resulting in a maximum at the target value.

Source code in bofire/data_models/objectives/target.py
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
def __call__(
    self,
    x: Union[pd.Series, np.ndarray],
    x_adapt: Optional[Union[pd.Series, np.ndarray]] = None,
) -> Union[pd.Series, np.ndarray]:
    """The call function returning a reward for passed x values.

    Args:
        x (np.array): An array of x values
        x_adapt (Optional[np.ndarray], optional): An array of x values which are used to
            update the objective parameters on the fly. Defaults to None.

    Returns:
        np.array: An array of reward values calculated by the product of two sigmoidal shaped functions resulting in a maximum at the target value.

    """
    return (
        1
        / (
            1
            + np.exp(
                -1 * self.steepness * (x - (self.target_value - self.tolerance)),
            )
        )
        * (
            1
            - 1
            / (
                1.0
                + np.exp(
                    -1
                    * self.steepness
                    * (x - (self.target_value + self.tolerance)),
                )
            )
        )
    )