Source code for pocketpartition.core.kunz._distance

"""
kunz_distance — module-level convenience function for comparing semigroups.
"""

__all__ = ['kunz_distance']

from ..numerical_semigroup import NumericalSemigroup
from ._vector import KunzVector
from ._fourier import FourierKunzVector


[docs] def kunz_distance( S: "NumericalSemigroup | KunzVector | FourierKunzVector", T: "NumericalSemigroup | KunzVector | FourierKunzVector", norm: str = "L2", ) -> float: """ Compute the distance between two numerical semigroups (or already-built Kunz / FourierKunz vectors) using their normalised Kunz step functions. Parameters ---------- S, T : NumericalSemigroup | KunzVector | FourierKunzVector The two objects to compare. NumericalSemigroup and KunzVector inputs are automatically converted to FourierKunzVector. norm : {"L1", "L2", "Linf"} Which norm to use (default ``"L2"``): - ``"L1"`` — sum of absolute differences (normalised by grid size) - ``"L2"`` — root-mean-square differences *(default)* - ``"Linf"`` — maximum absolute difference Returns ------- float d(f_S, f_T) ≥ 0, where equality holds iff the two normalised Kunz step functions are identical. Examples -------- >>> from pocketpartition import NumericalSemigroup, kunz_distance >>> S = NumericalSemigroup(generators=[3, 4, 5]) >>> T = NumericalSemigroup(generators=[3, 5]) >>> kunz_distance(S, T) # L2 (default) # doctest: +ELLIPSIS 0.816... >>> kunz_distance(S, T, norm="L1") # doctest: +ELLIPSIS 0.666... >>> kunz_distance(S, T, norm="Linf") # doctest: +ELLIPSIS 1.0... """ def _to_fkv(obj): if isinstance(obj, FourierKunzVector): return obj if isinstance(obj, KunzVector): return FourierKunzVector(obj) if isinstance(obj, NumericalSemigroup): return FourierKunzVector(obj) raise TypeError( f"Expected NumericalSemigroup, KunzVector, or FourierKunzVector, " f"got {type(obj).__name__}." ) return _to_fkv(S).distance(_to_fkv(T), norm=norm)