ribs.emitters.GradientOperatorEmitter

class ribs.emitters.GradientOperatorEmitter(archive: ArchiveBase, *, sigma: Float | ArrayLike, sigma_g: Float, initial_solutions: ArrayLike | None = None, x0: ArrayLike | None = None, line_sigma: Float = 0.0, measure_gradients: bool = False, normalize_grad: bool = False, epsilon: Float = 1e-08, operator_type: 'isotropic' | 'iso_line_dd' = 'isotropic', bounds: Collection[tuple[None | Float, None | Float]] | None = None, lower_bounds: ArrayLike | None = None, upper_bounds: ArrayLike | None = None, batch_size: Int = 64, seed: Int | None = None)[source]

Generates solutions with a genetic operator and gradient arborescence.

This emitter is from Fontaine 2021. It proceeds in two stages. The first stage samples a batch of intermediate solutions from the archive and (optionally) applies Gaussian perturbation with zero mean and fixed standard deviation sigma. If the archive is empty and no initial solutions are provided, the sampled solutions will be from a Gaussian centered at x0.

Optionally, an additional operator, Iso+LineDD (Vassiliades 2018), can be applied to the intermediate solutions in the first stage by setting operator_type='iso_line_dd'. The operator samples an additional batch of archive solutions to form a line in parameter space starting from the intermediate solutions. A zero-mean Gaussian interpolation along the line is then applied to the intermediate solutions, with standard deviation line_sigma.

The second stage creates new solutions by branching from each of the intermediate solutions. It leverages the gradient information of the objective and measure functions, generating a new solution from each solution point \(\boldsymbol{\theta_i}\) using gradient arborescence. The gradient coefficients \(\boldsymbol{c_i}\) are drawn from a zero-centered Gaussian distribution with standard deviation sigma_g. Note that the objective gradient coefficient is forced to be non-negative by taking its absolute value \(|c_{i,0}|\).

Essentially, this means that the emitter samples coefficients \(\boldsymbol{c_i} \sim \mathcal{N}(\boldsymbol{0}, \boldsymbol{\sigma_g}I)\) and creates new solutions \(\boldsymbol{\theta'_i}\) by updating the intermediate solutions \(\boldsymbol{\theta_i}\) from the first stage according to:

\[\boldsymbol{\theta'_i} \gets \boldsymbol{\theta_i} + |c_{i,0}| \boldsymbol{\nabla} f(\boldsymbol{\theta_i}) + \sum_{j=1}^k c_{i,j}\boldsymbol{\nabla}m_j(\boldsymbol{\theta_i})\]

Where \(k\) is the number of measures, and \(\boldsymbol{\nabla} f(\boldsymbol{\theta})\) and \(\boldsymbol{\nabla} m_j(\boldsymbol{\theta})\) are the objective and measure gradients of the solution point \(\boldsymbol{\theta}\), respectively.

Parameters:
archive: ArchiveBase

Archive of solutions, e.g., ribs.archives.GridArchive.

sigma: Float | ArrayLike

Standard deviation of the Gaussian perturbation used to generate new solutions in ask_dqd(). Note we assume the Gaussian is diagonal, so if this argument is an array, it must be 1D.

sigma_g: Float

Step size used for gradient arborescence in ask(), branching from the parents generated by ask_dqd(). If measure gradients are used, this acts as the standard deviation of the Gaussian from which to sample the step size. Otherwise, this acts as the step size itself.

initial_solutions: ArrayLike | None = None

An (n, solution_dim) array of solutions to be used when the archive is empty. If this argument is None, then solutions will be sampled from a Gaussian distribution centered at x0 with standard deviation sigma.

x0: ArrayLike | None = None

Center of the Gaussian distribution from which to sample solutions when the archive is empty.

line_sigma: Float = 0.0

the standard deviation of the line Gaussian for Iso+LineDD operator.

measure_gradients: bool = False

Signals if measure gradients will be used.

normalize_grad: bool = False

Whether gradients should be normalized before steps.

epsilon: Float = 1e-08

For numerical stability, we add a small epsilon when normalizing gradients in tell_dqd() – refer to the implementation here. Pass this parameter to configure that epsilon.

operator_type: 'isotropic' | 'iso_line_dd' = 'isotropic'

Either ‘isotropic’ or ‘iso_line_dd’ to mark the operator type for intermediate operations. Defaults to ‘isotropic’.

bounds: Collection[tuple[None | Float, None | Float]] | None = None

Bounds of the solution space. Pass None to indicate there are no bounds. Alternatively, pass an array-like to specify the bounds for each dim. Each element in this array-like can be None to indicate no bound, or a tuple of (lower_bound, upper_bound), where lower_bound or upper_bound may be None to indicate no bound. Unbounded upper bounds are set to +inf, and unbounded lower bounds are set to -inf.

lower_bounds: ArrayLike | None = None

Instead of specifying bounds, lower_bounds and upper_bounds may be specified. This is useful if, for instance, solutions are multi-dimensional. Here, pass None to indicate there are no bounds (i.e., bounds are set to -inf), or pass an array specifying the lower bounds of the solution space.

upper_bounds: ArrayLike | None = None

Upper bounds of the solution space; see lower_bounds above. Pass None to indicate there are no bounds (i.e., bounds are set to inf).

batch_size: Int = 64

Number of solutions to return in ask().

seed: Int | None = None

Value to seed the random number generator. Set to None to avoid a fixed seed.

Raises:

ValueError – There is an error in the bounds configuration.

Methods

ask()

Samples new solutions from a gradient arborescence.

ask_dqd()

Creates new solutions by sampling elites from the archive.

tell(solution, objective, measures, ...)

Gives the emitter results from evaluating solutions.

tell_dqd(solution, objective, measures, ...)

Gives the emitter results of evaluating solutions from ask_dqd().

Attributes

archive

Stores solutions generated by this emitter.

batch_size

Number of solutions to return in ask().

batch_size_dqd

Number of solutions to return in ask_dqd().

epsilon

Added for numerical stability when normalizing gradients in tell_dqd().

initial_solutions

Returned when the archive is empty (if x0 is not set).

lower_bounds

(solution_dim,) array with lower bounds of solution space.

sigma

Standard deviation of the (diagonal) Gaussian distribution.

solution_dim

Dimensionality of solutions produced by this emitter.

upper_bounds

(solution_dim,) array with upper bounds of solution space.

x0

Initial Gaussian distribution center.

ask() ndarray[source]

Samples new solutions from a gradient arborescence.

The gradient arborescence is parameterized by a multivariate Gaussian distribution.

If measure_gradients is used, the multivariate Gaussian is parameterized by sigma_g, and the arborescence coefficient is sampled from the multivariate Gaussian, with the objective coefficient always being non-negative. If measure_gradients is not used, the arborescence coefficient is just sigma_g itself.

This method returns batch_size solutions by branching with gradient arborescence based on the solutions returned by ask_dqd().

Returns:

(batch_size, solution_dim) array – a batch of new solutions to evaluate.

Raises:

RuntimeError – This method was called without first passing gradients with calls to ask_dqd() and tell_dqd().

ask_dqd() ndarray[source]

Creates new solutions by sampling elites from the archive.

If the archive is empty and initial_solutions is given, this method returns no solutions. Otherwise, this method will sample elites from the archive.

Call :meth:`ask_dqd` and :meth:`tell_dqd` (in this order) before calling :meth:`ask` and :meth:`tell`.

Returns:

(batch_size, solution_dim) array – contains batch_size new solutions to evaluate.

tell(solution: numpy.typing.ArrayLike, objective: numpy.typing.ArrayLike, measures: numpy.typing.ArrayLike, add_info: dict[str, ndarray], **fields: numpy.typing.ArrayLike) None

Gives the emitter results from evaluating solutions.

This base class implementation (in EmitterBase) does nothing by default.

Parameters:
solution: numpy.typing.ArrayLike

Array of solutions generated by this emitter’s ask() method.

objective: numpy.typing.ArrayLike

1D array containing the objective function value of each solution.

measures: numpy.typing.ArrayLike

(n, <measure space dimension>) array with the measure space coordinates of each solution.

add_info: dict[str, ndarray]

Data returned from the archive add() method.

**fields: numpy.typing.ArrayLike

Additional data for each solution. Each argument should be an array with batch_size as the first dimension.

tell_dqd(solution: numpy.typing.ArrayLike, objective: numpy.typing.ArrayLike, measures: numpy.typing.ArrayLike, jacobian: numpy.typing.ArrayLike, add_info: dict[str, ndarray], **fields: numpy.typing.ArrayLike) None[source]

Gives the emitter results of evaluating solutions from ask_dqd().

Parameters:
solution: numpy.typing.ArrayLike

(batch_size, solution_dim) array of solutions generated by this emitter’s ask() method.

objective: numpy.typing.ArrayLike

1D array containing the objective function value of each solution.

measures: numpy.typing.ArrayLike

(batch_size, measure space dimension) array with the measure space coordinates of each solution.

jacobian: numpy.typing.ArrayLike

(batch_size, 1 + measure_dim, solution_dim) array consisting of Jacobian matrices of the solutions obtained from ask_dqd(). Each matrix should consist of the objective gradient of the solution followed by the measure gradients.

add_info: dict[str, ndarray]

Data returned from the archive add() method.

**fields: numpy.typing.ArrayLike

Additional data for each solution. Each argument should be an array with batch_size as the first dimension.

property archive : ArchiveBase

Stores solutions generated by this emitter.

property batch_size : int | integer

Number of solutions to return in ask().

property batch_size_dqd : int | integer

Number of solutions to return in ask_dqd().

property epsilon : float | floating

Added for numerical stability when normalizing gradients in tell_dqd().

property initial_solutions : ndarray | None

Returned when the archive is empty (if x0 is not set).

property lower_bounds : ndarray

(solution_dim,) array with lower bounds of solution space.

For instance, [-1, -1, -1] indicates that every dimension of the solution space has a lower bound of -1.

property sigma : float | floating | ndarray

Standard deviation of the (diagonal) Gaussian distribution.

property solution_dim : int | integer | tuple[int | integer, ...]

Dimensionality of solutions produced by this emitter.

property upper_bounds : ndarray

(solution_dim,) array with upper bounds of solution space.

For instance, [1, 1, 1] indicates that every dimension of the solution space has an upper bound of 1.

property x0 : ndarray | None

Initial Gaussian distribution center.

Solutions are sampled from this distribution when the archive is empty (if initial_solutions is not set).