Source code for openswmm_gymnasium.scoring.pareto

"""
Pareto-front extraction for minimisation problems.

@author: Caleb Buahin
@copyright: Copyright (c) 2026 Caleb Buahin
@license: MIT
"""

from __future__ import annotations

import numpy as np
from numpy.typing import ArrayLike, NDArray


[docs] def is_dominated(point: ArrayLike, others: ArrayLike) -> bool: """Return whether C{point} is dominated by at least one row of C{others}. For minimisation: row C{j} dominates C{point} iff C{j[d] <= point[d]} for every dimension C{d} and C{j[d] < point[d]} for at least one C{d}. @param point: 1-D array of length C{d}. @type point: array_like @param others: 2-D array of shape C{(n, d)}. @type others: array_like @return: C{True} if some row of C{others} strictly dominates C{point}. @rtype: bool """ p = np.asarray(point, dtype=float) o = np.asarray(others, dtype=float) if o.ndim != 2: raise ValueError("others must be a 2-D array of shape (n, d)") le = np.all(o <= p, axis=1) lt = np.any(o < p, axis=1) return bool(np.any(le & lt))
[docs] def pareto_front(points: ArrayLike) -> NDArray[np.float64]: """Return the non-dominated subset of C{points} (minimisation). @param points: 2-D array of shape C{(n, d)}. @type points: array_like @return: Subset of rows of C{points} that are non-dominated, in the original ordering. @rtype: numpy.ndarray """ p = np.asarray(points, dtype=float) if p.size == 0: return p.reshape(0, p.shape[1] if p.ndim == 2 else 0) if p.ndim != 2: raise ValueError("points must be a 2-D array of shape (n, d)") n = p.shape[0] dominated = np.zeros(n, dtype=bool) for i in range(n): if dominated[i]: continue # Row i is dominated if any other row j satisfies j <= i with at # least one strict. le = np.all(p <= p[i], axis=1) lt = np.any(p < p[i], axis=1) dom_by = le & lt dom_by[i] = False if np.any(dom_by): dominated[i] = True return p[~dominated]