Source code for openswmm_gymnasium.scoring.normalization

"""
Min-max normalisation against L{ideal} and L{reference} (nadir) points.

@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 normalize( points: ArrayLike, ideal: ArrayLike, reference: ArrayLike, ) -> NDArray[np.float64]: """Return C{(points - ideal) / (reference - ideal)}. @param points: Array of shape C{(d,)} or C{(n, d)}. @type points: array_like @param ideal: 1-D array of length C{d} giving the per-dimension best-possible value (lower in minimisation). @type ideal: array_like @param reference: 1-D array of length C{d} giving the per-dimension worst-case (nadir) value used as the hypervolume reference. @type reference: array_like @return: Same shape as C{points}, values typically in C{[0, 1]} but B{not clipped} — callers do their own clipping if required. @rtype: numpy.ndarray @raise ValueError: If C{reference[d] <= ideal[d]} for any C{d}. """ p = np.asarray(points, dtype=float) ideal_a = np.asarray(ideal, dtype=float) ref_a = np.asarray(reference, dtype=float) span = ref_a - ideal_a if np.any(span <= 0): raise ValueError( f"reference must be strictly greater than ideal in every " f"dimension; got ideal={ideal_a}, reference={ref_a}" ) return (p - ideal_a) / span