From 765b58a41f47cb512cc92bed2037ab9060cbfcd3 Mon Sep 17 00:00:00 2001 From: Muhtasim Munif Fahim Date: Sun, 11 Oct 2026 08:52:41 +0600 Subject: [PATCH] test(trajectories): Fix ty invalid-attribute-override on SPSMapping Recent ty versions (0.0.86 here) reject a nested class that overrides a nested class of a base class: the nested `SPSMapping` of `QuadraticFunction` and `ElementWiseQuadratic` is a new class object, and ty checks it against the class object declared on `WithSPSMappingMixin`, so `uv run ty check` fails with two invalid-attribute-override errors. Move the abstract `SPSMapping` to module level and make the two implementations module-level subclasses (`QuadraticSPSMapping` and `ElementWiseQuadraticSPSMapping`). The `sps_mapping` properties keep returning the same objects, so callers are unchanged. Fixes #827 --- tests/trajectories/_objectives.py | 65 +++++++++++++++++-------------- 1 file changed, 35 insertions(+), 30 deletions(-) diff --git a/tests/trajectories/_objectives.py b/tests/trajectories/_objectives.py index ae47f962e..c64975526 100644 --- a/tests/trajectories/_objectives.py +++ b/tests/trajectories/_objectives.py @@ -28,20 +28,23 @@ def __repr__(self) -> str: return f"{self.__class__.__name__}({self.n_values})" +class SPSMapping(ABC): + """Strong Pareto stationary mapping of an objective.""" + + @abstractmethod + def __call__(self, w: Tensor) -> Tensor: + """ + Map a vector with (strictly) positive coordinates to the corresponding strongly pareto + stationary point. + """ + + class WithSPSMappingMixin(ABC): """Mixin adding the possibility to get the Strong Pareto stationary mapping.""" - class SPSMapping(ABC): - @abstractmethod - def __call__(self, w: Tensor) -> Tensor: - """ - Map a vector with (strictly) positive coordinates to the corresponding strongly pareto - stationary point. - """ - @property @abstractmethod - def sps_mapping(self) -> "WithSPSMappingMixin.SPSMapping": + def sps_mapping(self) -> SPSMapping: pass @@ -73,21 +76,22 @@ def quad(x: Tensor, A: Tensor, u: Tensor) -> Tensor: x_minus_u = x - u return x_minus_u @ A @ x_minus_u - class SPSMapping(WithSPSMappingMixin.SPSMapping): - def __init__(self, As: list[Tensor], us: list[Tensor]) -> None: - self.As = As - self.us = us + @property + def sps_mapping(self) -> "QuadraticSPSMapping": + return QuadraticSPSMapping(self.As, self.us) - def __call__(self, w: Tensor) -> Tensor: - G = torch.stack([weight * A for weight, A in zip(w, self.As, strict=False)]).sum(dim=0) - b = torch.stack( - [weight * A @ u for weight, A, u in zip(w, self.As, self.us, strict=False)] - ).sum(dim=0) - return torch.linalg.lstsq(G, b, driver="gelsd").solution - @property - def sps_mapping(self) -> "QuadraticFunction.SPSMapping": - return self.SPSMapping(self.As, self.us) +class QuadraticSPSMapping(SPSMapping): + def __init__(self, As: list[Tensor], us: list[Tensor]) -> None: + self.As = As + self.us = us + + def __call__(self, w: Tensor) -> Tensor: + G = torch.stack([weight * A for weight, A in zip(w, self.As, strict=False)]).sum(dim=0) + b = torch.stack( + [weight * A @ u for weight, A, u in zip(w, self.As, self.us, strict=False)] + ).sum(dim=0) + return torch.linalg.lstsq(G, b, driver="gelsd").solution class HomogenousQuadraticFunction(QuadraticFunction): @@ -113,13 +117,14 @@ def __call__(self, x: Tensor) -> Tensor: def jacobian(self, x: Tensor) -> Tensor: return torch.diag(torch.stack([2 * x[0], 2 * x[1]])) - class SPSMapping(WithSPSMappingMixin.SPSMapping): - def __init__(self, n_values: int) -> None: - self.n_values = n_values + @property + def sps_mapping(self) -> "ElementWiseQuadraticSPSMapping": + return ElementWiseQuadraticSPSMapping(self.n_values) - def __call__(self, w: Tensor) -> Tensor: # noqa: ARG002 - return torch.zeros(self.n_values) - @property - def sps_mapping(self) -> "ElementWiseQuadratic.SPSMapping": - return self.SPSMapping(self.n_values) +class ElementWiseQuadraticSPSMapping(SPSMapping): + def __init__(self, n_values: int) -> None: + self.n_values = n_values + + def __call__(self, w: Tensor) -> Tensor: # noqa: ARG002 + return torch.zeros(self.n_values)