Source code for httk.core.vectors.vector_api

"""
The minimal canonical vector interface shared by all vector backends and views.
"""

import fractions
from abc import ABC, abstractmethod
from typing import Any

# The canonical interchange is a (possibly nested) tuple of fractions.Fraction, or a bare
# Fraction for a scalar. It is exact when ``fractions_exact`` is True; members whose hub is a
# deterministic approximation report False, and exact-construction paths refuse them.
type Fractions = fractions.Fraction | tuple[Fractions, ...]


[docs] class VectorAPI(ABC): """ Abstract base class for the canonical vector interface. It declares the ``fractions`` accessor (a nested tuple of :class:`fractions.Fraction`, or a bare Fraction for a scalar) that every vector backend produces from its own native representation and every vector view builds its presentation from, together with the ``dim`` shape tuple. The interchange is exact when :attr:`fractions_exact` is True; members such as irrational surds whose hub is a deterministic approximation report False, and exact construction paths refuse them. This is the single interchange format; there is no pairwise conversion between backends. On top of the two abstract accessors it provides the guaranteed float renderings :meth:`to_floats` and :meth:`to_float`, derived from the ``fractions`` hub — so *whatever* object the family hands you, ``.to_floats()`` works. (The exact value types :class:`~httk.core.vectors.fracvector.FracVector` and :class:`~httk.core.vectors.surdvector.SurdVector` honor the same contract with their own implementations, while the numpy backend adds a dtype-guarded fast path with the hub as fallback. Surd values render floats at fixed high precision independent of the decimal context, unlike the hub's context-precision reduction. """ @property @abstractmethod def fractions(self) -> Fractions: """Return the Fraction interchange representation.""" raise NotImplementedError @property def fractions_exact(self) -> bool: """Return whether ``fractions`` reproduces this value exactly. Members whose Fraction interchange may be a deterministic approximation override this property with ``False``; exact construction paths must refuse those members. """ return True @property @abstractmethod def dim(self) -> tuple[int, ...]: """Return the tensor shape as a tuple of dimensions.""" raise NotImplementedError
[docs] def to_floats(self) -> Any: """ Return the value as nested lists of floats. The value as (possibly nested) plain lists of ``float`` — a bare ``float`` for a scalar. Derived from the ``fractions`` hub; when :attr:`fractions_exact` is False, the result is the member's deterministic approximation. Nested lists match the ``numpy.ndarray.tolist()`` convention and are directly JSON-serializable. :return: The rendered value. """ def rec(node: Fractions) -> Any: if isinstance(node, tuple): return [rec(e) for e in node] return float(node) return rec(self.fractions)
[docs] def to_float(self) -> float: """ Return the scalar value as a plain ``float``. Raises :class:`TypeError` on a non-scalar. :return: The rendered scalar value. :raises TypeError: If the value is not scalar. """ value = self.fractions if isinstance(value, tuple): raise TypeError(f"to_float: expected a scalar, got shape {self.dim}") return float(value)