pyuncertainnumber.opt.bo

Classes

BayesOpt_args_signature

Bayesian Optimisation class with original function signature (arguments signature).

BayesOpt_iterable_signature

Bayesian Optimisation class for iterable function style

BayesOpt_vectorised_signature

Bayesian Optimisation class for vectorised function style

BayesOpt

Bayesian Optimisation class with automatic function signature detection

Functions

check_argument_count(func)

transform_func(fb, **kwargs)

rekey_bounds_by_func(bounds_indexed, func, *[, ...])

Convert bounds like {'0': (lo,hi), '1': (lo,hi), ...}

as_bayes_opt(f_vec, bounds_list[, prefix])

Wrap a vector/array objective f_vec(x) so it can be used by bayes_opt,

as_bayes_opt_2d(f_vec2d, bounds_list[, prefix])

Wrap a strict 2-D objective f_vec2d(X) for bayes_opt.

as_bayes_opt_auto(f_any, bounds_list[, prefix, prefer_2d])

Wrap an objective that might accept either a 1-D vector x (shape (d,))

Module Contents

class pyuncertainnumber.opt.bo.BayesOpt_args_signature(f, design_bounds: dict, task, acquisition_function='UCB', num_explorations=100, num_iterations=100)

Bayesian Optimisation class with original function signature (arguments signature).

It requires the design_bound to be a dictionary, e.g. {‘x1’: (0, 1), ‘x2’: (0, 1)}.

Parameters:
  • f (callable) – the target function to be optimised, should have individual function signature. See notes.

  • design_bounds (dict) – the bounds for the design space, e.g. {‘x1’: (0, 1), ‘x2’: (0, 1)}

  • task (str) – either ‘minimisation’ or ‘maximisation’

  • acquisition_function (str or callable, optional) – the acquisition function to be used, e.g. ‘UCB’, ‘EI’, ‘PI’. If None, defaults to ‘UCB’.

  • num_explorations (int, optional) – the number of initial exploration points. Defaults to 100.

  • num_iterations (int, optional) – the number of iterations to run the optimisation. Defaults to 100.

Note

Acquisition functions can be either a string (e.g. ‘UCB’, ‘EI’, ‘PI’) or a callable function. ‘UCB’ stands for Upper Confidence Bound, ‘EI’ for Expected Improvement, and ‘PI’ for Probability of Improvement. If a string is provided, the parameter for the acquisition function can be passed as an additional argument to the class constructor. For example, for ‘UCB’, you can pass a kappa value, and for ‘EI’ or ‘PI’, you can pass an xi value. For low-level controls, if a callable function is provided, it should already be parameterised.

About the function signature of $f$, by default it should be expecting individual arguments in the form of $f(x_0, x_1, ldots, x_n)$, often one needs to write a wrapper function to unpack the input arguments when working with a black-box model, which typically has vectorisation calling signature. Also, one can specify the xc_bound accordingly. When EpistemicDomain is used as a shortcut to specify the xc_bound, the keys will be automatically mapped to the corresponding arguments of the function.

Example

>>> import numpy as np
>>> from pyuncertainnumber.opt.bo import BayesOpt_args_signature
>>> def black_box_function(x):
...     return np.exp(-(x - 2)**2) + np.exp(-(x - 6)**2 / 10) + 1 / (x**2 + 1)
>>> bo = BayesOpt_args_signature(
...     f=black_box_function,
...     dimension=1,
...     design_bounds={'x': (-2, 10)},
...     task='maximisation',
...     num_explorations=3,
...     num_iterations=20
... )
>>> bo.run(verbose=True)
>>> print(bo.optimal)  # get the optimal parameters and target value

Implementation

This represents the original function signature. The range of the design space, defined in design_bound, is a dictionary mapping parameter names to their bounds. However, in later versions, such as the BayesOpt class, the design bounds can be specified as a list or 2D numpy array of shape (n, 2), and the function signature can be automatically detected.

example: >>> ed = EpistemicDomain(pba.I(-5, 5), pba.I(-5, 5)) >>> BayesOpt(f=foo, … design_bounds= ed.to_BayesOptBounds(func_signature=”arguments”), # the trick … task=’maximisation’, … num_explorations=3, … num_iterations=20, … )

task
num_explorations = 100
num_iterations = 100
design_bounds
acquisition_function
property f

return the function to be optimised

parse_acq(acq, parameter=None)

parse the acquisition function

Parameters:
  • acq (str or callable) – the acquisition function to be used. See notes above.

  • parameter (float, optional) – parameter for the acquisition function, e.g. kappa for UCB, xi for EI and PI

get_results()

inspect the results, to save or not

run(**kwargs)

run the Bayesian optimisation process.

Parameters:
  • verbose (bool, optional) – whether to print the progress. Defaults to False. Use ‘verbose=True’ to see the progress.

  • **kwargs – additional low–level arguments to be passed to the BayesianOptimization constructor.

Example

>>> foo.run(verbose=True)
property optimal: dict

return the optimal parameters and target value as a dictionary

property optimal_xc: numpy.ndarray

return the optimal design points (xc)

property optimal_target: numpy.ndarray

return the optimal target value f(xc*)

class pyuncertainnumber.opt.bo.BayesOpt_iterable_signature(f, design_bounds: list[list[float]], dimension, task, acquisition_function='UCB', num_explorations=100, num_iterations=100)

Bases: BayesOpt_args_signature

Bayesian Optimisation class for iterable function style

See BayesOpt for additional details.

class pyuncertainnumber.opt.bo.BayesOpt_vectorised_signature(f, design_bounds: list[list[float]], task, acquisition_function='UCB', num_explorations=100, num_iterations=100)

Bases: BayesOpt_args_signature

Bayesian Optimisation class for vectorised function style

See BayesOpt for additional details.

class pyuncertainnumber.opt.bo.BayesOpt(f, design_bounds: list | numpy.ndarray, task, acquisition_function='UCB', num_explorations=100, num_iterations=100)

Bases: BayesOpt_args_signature

Bayesian Optimisation class with automatic function signature detection

The go to class for Bayesian Optimisation

Parameters:
  • f (callable) – the target function to be optimised, it could be vectorised or iterable signature but NOT arguments signature. See notes.

  • design_bounds (list | np.ndarray) – the bounds for the design space, e.g. [[0, 1], [0, 1]]

  • task (str) – either ‘minimisation’ or ‘maximisation’

  • acquisition_function (str or callable, optional) – the acquisition function to be used, e.g. ‘UCB’, ‘EI’, ‘PI’. If None, defaults to ‘UCB’.

  • num_explorations (int, optional) – the number of initial exploration points. Defaults to 100.

  • num_iterations (int, optional) – the number of iterations to run the optimisation. Defaults to 100.

Note

Acquisition functions can be either a string (e.g. ‘UCB’, ‘EI’, ‘PI’) or a callable function. ‘UCB’ stands for Upper Confidence Bound, ‘EI’ for Expected Improvement, and ‘PI’ for Probability of Improvement. If a string is provided, the parameter for the acquisition function can be passed as an additional argument to the class constructor. For example, for ‘UCB’, you can pass a kappa value, and for ‘EI’ or ‘PI’, you can pass an xi value. For low-level controls, if a callable function is provided, it should already be parameterised.

About the function signature of $f$, by default it should be expecting individual arguments in the form of $f(x_0, x_1, ldots, x_n)$, often one needs to write a wrapper function to unpack the input arguments when working with a black-box model, which typically has vectorisation calling signature. Also, one can specify the xc_bound accordingly. When EpistemicDomain is used as a shortcut to specify the xc_bound, the keys will be automatically mapped to the corresponding arguments of the function.

The function is assumed to be a vectorised or iterable signature, indicating a f(x) with only one argument.

Example

>>> import numpy as np
>>> from pyuncertainnumber.opt.bo import BayesOpt
>>> def foo_vec(x):
...     return x[:, 0] ** 3 + x[:, 1] + x[:, 2]
>>> bo = BayesOpt(
...     f=foo_vec,
...     design_bounds=[(-2, 2), (-3, 3), (-1, 1)],
...     task='maximisation',
...     num_explorations=3,
...     num_iterations=20
... )
>>> bo.run(verbose=True)
>>> print(bo.optimal)  # get the optimal parameters and target value

Implementation

The range of the design space is defined by design_bounds, which is a 2D numpy array with shape (n, 2), where n is the number of parameters. For consistency, it is recommended to use the class EpistemicDomain.to_BayesOptBounds() to automatically take care of the format of the bounds.

example: >>> BayesOpt(f=foo_vec, … design_bounds= [(-2, 2), (-3, 3), (-1, 1)], … task=’maximisation’, … num_explorations=3, … num_iterations=20, … )

pyuncertainnumber.opt.bo.check_argument_count(func)
pyuncertainnumber.opt.bo.transform_func(fb, **kwargs)
pyuncertainnumber.opt.bo.rekey_bounds_by_func(bounds_indexed: dict, func, *, allow_extras=False)

Convert bounds like {‘0’: (lo,hi), ‘1’: (lo,hi), …} into {‘param_name’: (lo,hi), …} using func’s signature.

pyuncertainnumber.opt.bo.as_bayes_opt(f_vec, bounds_list, prefix='x')

Wrap a vector/array objective f_vec(x) so it can be used by bayes_opt, which calls f(**kwargs) with named scalar params.

Parameters:
  • f_vec (callable) – Objective expecting a 1-D array-like x of length d. May also be vectorized and return a numpy array; we coerce to float.

  • bounds_list (list[tuple[float, float]]) – [(low_0, high_0), …, (low_{d-1}, high_{d-1})]

  • prefix (str) – Name prefix for parameters (x0, x1, …).

Returns:

  • wrapped (callable(**kwargs) -> float)

  • pbounds (dict[str, tuple[float, float]])

  • names (list[str])

pyuncertainnumber.opt.bo.as_bayes_opt_2d(f_vec2d, bounds_list, prefix='x')

Wrap a strict 2-D objective f_vec2d(X) for bayes_opt.

Parameters:
  • f_vec2d (callable) –

    Objective expecting a 2-D array X of shape (m, d) and returning an array of shape (m,) (or something squeezable to that). Example:

    def f_vec2d(X): return X[:, 0]**3 + X[:, 1] + X[:, 2]

  • bounds_list (list[tuple[float, float]]) – Bounds in order for each of the d dimensions.

  • prefix (str) – Parameter name prefix for kwargs: x0, x1, …

Returns:

  • wrapped (callable(**kwargs) -> float) – Callable compatible with BayesianOptimization (single-point evaluation).

  • pbounds (dict[str, tuple[float, float]]) – Name→bounds mapping for bayes_opt.

  • names (list[str]) – The ordered parameter names used by wrapped.

pyuncertainnumber.opt.bo.as_bayes_opt_auto(f_any, bounds_list, prefix='x', prefer_2d=False)

Wrap an objective that might accept either a 1-D vector x (shape (d,)) or a strict 2-D matrix X (shape (m, d), here m=1 per BO call).

The wrapper auto-detects the expected shape on the first call by trying one shape then the other, caches the mode, and always returns a scalar float.

Parameters:
  • f_any (callable) –

    Objective. Examples:
    • def f_vec(x: np.ndarray): return x[0]**3 + x[1] + x[2] # expects (d,)

    • def f_mat(X: np.ndarray): return X[:,0]**3 + X[:,1] + X[:,2] # expects (m,d)->(m,)

  • bounds_list (list[tuple[float, float]]) – [(low_0, high_0), …, (low_{d-1}, high_{d-1})]

  • prefix (str) – Name prefix for kwargs (e.g., x0, x1, …).

  • prefer_2d (bool) – If True, try (1, d) first, else try (d,) first. Useful when you expect strict 2-D but still want auto fallback.

Returns:

  • wrapped (callable(**kwargs) -> float)

  • pbounds (dict[str, tuple[float, float]])

  • names (list[str])