gemseo_box_subdivision.subdivisions.box#

A Cartesian subdivision of a design space.

Classes

BoxSubdivision(lower_bounds, upper_bounds)

A Cartesian subdivision of a design space.

class gemseo_box_subdivision.subdivisions.box.BoxSubdivision(lower_bounds, upper_bounds)[source]#

Bases: object

A Cartesian subdivision of a design space.

Each scalar component of each design variable is split into contiguous subdivisions. The Cartesian product of these subdivisions defines the boxes in which a sub-problem can be solved.

The subdivision of a component is described by its bounds, so that the box selected by a one-hot vector \(\alpha\) has bounds

\[\ell_j(\alpha) = \sum_k l_{j,k} \alpha_{j,k}, \qquad u_j(\alpha) = \sum_k u_{j,k} \alpha_{j,k},\]

which are affine in \(\alpha\).

Parameters:
  • lower_bounds (Mapping[str, ndarray])

  • upper_bounds (Mapping[str, ndarray])

DEFAULT_BOUND_MARGIN: Final[float] = 0.0001#

The default relative margin of create_relaxed_design_space().

ONE_HOT_SUFFIX: Final[str] = '_box'#

The default suffix of the one-hot variable selecting a subdivision.

NORMALIZED_SUFFIX: Final[str] = '_normalized'#

The default suffix of the normalized variable of a box.

classmethod from_design_space(design_space, n_subdivisions, variable_names=())[source]#

Create a uniform subdivision of a design space.

Parameters:
  • design_space (DesignSpace) – The design space to subdivide.

  • n_subdivisions (int | Mapping[str, int]) – The number of subdivisions of every variable, or of each variable.

  • variable_names (Iterable[str]) – The variables to subdivide. If empty, subdivide all the variables of the design space.

Returns:

The uniform subdivision of the design space.

Raises:

ValueError – If a variable is unknown, has a non-finite bound, or has a non-positive number of subdivisions.

Return type:

BoxSubdivision

property variable_names: tuple[str, ...]#

The names of the subdivided variables.

property sizes: dict[str, int]#

The size of each subdivided variable.

property n_subdivisions: dict[str, int]#

The number of subdivisions of each variable.

property n_boxes: int#

The number of boxes of the Cartesian subdivision.

property n_binaries: int#

The number of binary variables encoding the choice of a box.

This is the size of the master problem, linear in the number of design variable components, whereas n_boxes is exponential in it.

property max_step: int#

The largest trust-region step of the master, with the default weights.

The master restricts each of its iterations to a neighbourhood of the incumbent box: writing $w_j$ for the weights of the catalogue of a component and $alpha$ for the incumbent, a candidate $alpha’$ must satisfy

$$ sum_{j ,:, alpha’_j = alpha_j} w_j(alpha) gesum_j w_j(alpha) - texttt{max_step}, $$

so the cost of a move is the sum of the weights the incumbent holds over the components the candidate changes. The constraint never reads what those components change to, so no weighting of an ordered catalogue makes it a proximity; with the weights this package sets, all equal, it is the number of components changed, which is a distance.

This property is the largest such distance, the number of components of the subdivision, at which the trust region is inactive.

Note

A radius that large is not what works: the master explores better when it may change only a couple of components per iteration, see [the results](../../algorithm/benchmark.md). This property says where the region stops constraining, not what to set.

get_lower_bounds(name)[source]#

Return the lower bounds of the subdivisions of a variable.

Parameters:

name (str) – The name of the variable.

Returns:

The lower bounds, shaped (size, n_subdivisions).

Return type:

ndarray

get_upper_bounds(name)[source]#

Return the upper bounds of the subdivisions of a variable.

Parameters:

name (str) – The name of the variable.

Returns:

The upper bounds, shaped (size, n_subdivisions).

Return type:

ndarray

create_relaxed_design_space(design_space, margin=0.0001)[source]#

Return a copy of a design space whose bounds are slightly widened.

When a box lies against the border of the design space, the face of the box and the bound of the design space coincide. Both are then active at a sub-problem optimum lying on that face, and the Lagrange multiplier is attributed to the bound rather than to the box constraint. The sensitivity of the sub-problem optimum with respect to the box selection would then be computed as zero for every border box.

Widening the bounds by a small margin keeps them inactive, so that the multiplier is carried by the box constraint. The box itself is still enforced, by the constraint, hence the design variables remain in the original bounds up to the constraint tolerance.

Parameters:
  • design_space (DesignSpace) – The design space to relax.

  • margin (float) – The margin, relative to the range of each variable.

Returns:

A copy of the design space with widened bounds.

Raises:

ValueError – If the margin is negative.

Return type:

DesignSpace

get_one_hot_names(overrides=mappingproxy({}))[source]#

Return the name of the one-hot variable of each subdivided variable.

Parameters:

overrides (Mapping[str, str]) – The names to use instead of the default ones.

Returns:

The name of the one-hot variable of each subdivided variable.

Return type:

dict[str, str]

locate(name, value)[source]#

Return the index of the subdivision containing each component of a value.

A value lying on the border between two subdivisions is assigned to the first of them, and a value outside the original bounds is assigned to the closest subdivision.

Parameters:
  • name (str) – The name of the variable.

  • value (ndarray) – The value of the variable.

Returns:

The index of the subdivision of each component.

Return type:

ndarray

get_normalized_names(overrides=mappingproxy({}))[source]#

Return the name of the normalized variable of each subdivided variable.

Parameters:

overrides (Mapping[str, str]) – The names to use instead of the default ones.

Returns:

The name of the normalized variable of each subdivided variable.

Return type:

dict[str, str]

compute_bounds(name, one_hot)[source]#

Compute the bounds of the box selected by a one-hot vector.

Parameters:
  • name (str) – The name of the variable.

  • one_hot (ndarray) – The flat one-hot vector selecting a subdivision per component.

Returns:

The lower and upper bounds of the selected box.

Return type:

tuple[ndarray, ndarray]