evomo.utils#

Submodules#

Functions#

load_pareto_front_from_file(fname[, device, dtype])

Load Pareto front from the constrained problems' pf directory.

parse_evaluate(→ Tuple[torch.Tensor, ...)

Parse output from evaluate function. Returns (fit, cv) where cv is None if unconstrained.

register_lazy_buffer(→ None)

Register optional persistent state, materializing it before checkpoint loading.

at_least_2d(→ Tuple[torch.Tensor, bool])

Ensure the input tensor is at least 2D. Returns (X_2d, was_1d).

get_pareto_front(→ torch.Tensor)

Return the non-dominated set (Pareto front) of the given objectives.

unique_rows_sorted(x[, return_index])

Compute unique rows of a 2D tensor using a pure sorting-based approach.

Package Contents#

evomo.utils.load_pareto_front_from_file(fname, device=None, dtype=torch.float32)#

Load Pareto front from the constrained problems’ pf directory.

evomo.utils.parse_evaluate(eval_out: torch.Tensor | Tuple[torch.Tensor, ...]) → Tuple[torch.Tensor, torch.Tensor | None]#

Parse output from evaluate function. Returns (fit, cv) where cv is None if unconstrained.

evomo.utils.register_lazy_buffer(module: torch.nn.Module, name: str, *, device_like: str) → None#

Register optional persistent state, materializing it before checkpoint loading.

The buffer starts as None and accepts normal tensor assignments after evaluation. A fresh instance can restore its shape and dtype from a checkpoint. Already initialized buffers retain PyTorch’s normal shape validation.

device_like names an existing tensor attribute on the same module, such as "pop". Its device is read at load time, so use a parameter or buffer that follows module device transfers. The tensor itself is not captured by the hook. Standard load_state_dict(assign=True) semantics still take precedence: assigned tensors retain the checkpoint’s device and dtype.

As with ordinary None buffers, absent checkpoint keys leave fresh state as None. This helper does not infer or validate a problem’s number of constraints.

Example:

self.pop = Mutable(population)
register_lazy_buffer(self, "cv", device_like="pop")
evomo.utils.at_least_2d(X: torch.Tensor) → Tuple[torch.Tensor, bool]#

Ensure the input tensor is at least 2D. Returns (X_2d, was_1d).

evomo.utils.get_pareto_front(f: torch.Tensor) → torch.Tensor#

Return the non-dominated set (Pareto front) of the given objectives.

evomo.utils.unique_rows_sorted(x: torch.Tensor, return_index: bool = True)#

Compute unique rows of a 2D tensor using a pure sorting-based approach.

This function performs a stable lexicographic sort on the rows of x (from the last column to the first), then removes consecutive duplicates. It is a robust replacement for torch.unique(…, dim=0) when: - certain PyTorch versions do not support required arguments, - you want deterministic stable behavior, - you want full control over the uniqueness logic.

Parameters#

xtorch.Tensor

A 2D tensor of shape (N, M), where N is the number of rows and M is the number of columns. Each row is treated as a key.

return_indexbool, default=True

If True, also return the indices of the unique rows in the original input tensor x.

Returns#

uniqtorch.Tensor

A 2D tensor containing unique rows of x after sorting. Shape: (K, M), where K <= N.

uniq_idxtorch.Tensor, optional

Only returned if return_index=True. A 1D tensor of shape (K,) containing the original indices of uniq rows in x.

Notes#

  • Sorting is performed lexicographically using stable sorts column-by-column. This guarantees deterministic ordering given deterministic torch.sort.

  • Uniqueness is determined by comparing adjacent sorted rows.

  • The output order is the lexicographically sorted order, not the original order.

Complexity#

Time: O(M * N log N), where M is number of columns. Space: O(N) for indexing buffers.

Examples#

>>> x = torch.tensor([[1, 2], [1, 2], [1, 3], [0, 1]])
>>> uniq, idx = unique_rows_sorted(x, return_index=True)
>>> uniq
tensor([[0, 1],
        [1, 2],
        [1, 3]])
>>> idx
tensor([3, 0, 2])