Source code for httk.core.vectors.vector_surd_view

"""
A view presenting any vector backend as a SurdVector (the exact squarefree-radical representation).
"""

from functools import cached_property
from typing import Any, Self

from httk.core.views import unwrap

from .fracvector import FracVector
from .surdvector import SurdVector
from .vector_backend import VectorBackend
from .vector_like import VectorLike
from .vector_view import VectorView


[docs] class VectorSurdView(VectorView, SurdVector): r""" A view presenting an underlying vector backend as an exact :class:`~httk.core.vectors.surdvector.SurdVector`. This view is a genuine SurdVector, so it exposes the full exact surd algebra (``det``/``inv``/``*``/``length``/``...). It is built lazily on first access, following the immutable-subclass pattern of :class:`~httk.core.vectors.vector_frac_view.VectorFracView`: from a surd backend it adopts the exact SurdVector directly, and from a frac/native/numpy backend it embeds the backend's exact rational ``fractions`` at radicand 1 — exactly, since every rational is a surd. (numpy values are binary rationals, so a numpy source embeds the exact float64 rational, not necessarily the original decimal fraction — the same caveat as :class:`~httk.core.vectors.vector_frac_view.VectorFracView`.) :param obj: The source value to present. :param \**hints: Backend-selection and view-conversion hints. """ _backend: VectorBackend def __new__(cls, obj: VectorLike, **hints: Any) -> Self: if isinstance(obj, cls): return obj backend = cls._prepare_backend(obj, hints) instance = object.__new__(cls) instance._backend = backend return instance def __init__(self, obj: VectorLike, **hints: Any) -> None: pass @property def fractions_exact(self) -> bool: """Return whether this view's Fraction interchange is exact.""" backend = getattr(self, "_backend", None) return True if backend is None else backend.fractions_exact def _fill_fractions(self) -> None: # Validate then assign: failed fills leave no partial presentation state, and fills must # not read shadowed attributes or they recurse. if "_backend" not in self.__dict__: return backend = self._backend if isinstance(backend, SurdVector): surd = backend else: surd = SurdVector(backend.fractions) SurdVector._set_components(self, surd._components, surd._dim) def _ensure_materialized(self) -> None: if "_backend" in self.__dict__ and "_components" not in self.__dict__: self._fill_fractions() @cached_property def _components(self) -> dict[int, FracVector]: # type: ignore[override] # pyright: ignore[reportIncompatibleVariableOverride] self._fill_fractions() return self.__dict__["_components"] @cached_property def _dim(self) -> tuple[int, ...]: # type: ignore[override] # pyright: ignore[reportIncompatibleVariableOverride] self._fill_fractions() return self.__dict__["_dim"]
[docs] def unwrap(self) -> Any: """Return the underlying unwrapped vector, or this value when no backend remains.""" backend = getattr(self, "_backend", None) if backend is None: return self return unwrap(backend)
[docs] def unview(self) -> Any: """Return a plain SurdVector containing this view's presented data.""" # A surd backend already holds exactly the presented SurdVector: reuse it. Otherwise # build a plain SurdVector reusing the materialized components mapping. backend = getattr(self, "_backend", None) if isinstance(backend, SurdVector): raw = backend if not isinstance(raw, VectorView): return raw return SurdVector._of(self._components, self._dim)