Source code for httk.core.vectors.vector_surd

"""
Backend wrapping a SurdVector in the exact squarefree-radical representation.
"""

import decimal
import fractions
from typing import Any

from .surdvector import SurdVector
from .vector_api import Fractions
from .vector_backend import VectorBackend
from .vector_frac import _fracvector_to_fractions

# Guard digits added to the active decimal context precision when a lossy (irrational) surd must be
# reduced to the rational ``fractions`` hub, mirroring exactmath's Ziv guard convention.
_HUB_GUARD_DIGITS = 3


[docs] class VectorSurd(VectorBackend): """ Backend for a vector backed by an exact :class:`~httk.core.vectors.surdvector.SurdVector` (or :class:`~httk.core.vectors.surdvector.SurdScalar`), kind ``"surd"``. ``unwrap`` returns the exact SurdVector. The canonical ``fractions`` hub is **exact** whenever the value is rational (a surd whose canonical form has only the radicand-1 term), matching the established backend-keeps-the-original principle; when the value is genuinely irrational it is reduced to a *deterministic* rational approximation at the active decimal context precision plus a small guard (lossy but reproducible), and the exact original remains recoverable via ``unwrap``. """ _surdvector: SurdVector # Cannot type annotate __new__ as `Self | None` for some reason def __new__(cls, obj: Any, **hints: Any) -> Any: if not isinstance(obj, SurdVector): return None if hints and hints.get("kind", "surd") != "surd": return None return super().__new__(cls) def __init__(self, obj: SurdVector, **hints: Any) -> None: self._surdvector = obj @property
[docs] def fractions(self) -> Fractions: surd = self._surdvector if surd.is_rational: return _fracvector_to_fractions(surd.coefficient(1)) prec = fractions.Fraction(1, 10 ** (decimal.getcontext().prec + _HUB_GUARD_DIGITS)) return _fracvector_to_fractions(surd._approx_fracvector(prec))
@property
[docs] def dim(self) -> tuple[int, ...]: return self._surdvector.dim
[docs] def unwrap(self) -> Any: return self._surdvector