Spaces:
Sleeping
Sleeping
Download spinor_lib/utils.py from SoulFireMage/spinor-lib: direct link, hf CLI and curl.
- Browser
- Download file 3.99 kB
-
https://huggingface.co/spaces/SoulFireMage/spinor-lib/resolve/main/spinor_lib/utils.py
- Command line
-
hf download hf://spaces/SoulFireMage/spinor-lib/spinor_lib/utils.py
-
curl -L -o utils.py https://huggingface.co/spaces/SoulFireMage/spinor-lib/resolve/main/spinor_lib/utils.py
3.99 kB
| """Utility functions for the Spinor library.""" | |
| from typing import Optional, Sequence, Union | |
| import torch | |
| import numpy as np | |
| TensorLike = Union[torch.Tensor, np.ndarray, list, tuple, float, complex] | |
| # Threshold below which a norm is treated as zero (used to avoid divide-by-zero). | |
| DEFAULT_EPS = 1e-12 | |
| def get_backend(tensor: object) -> str: | |
| """Detect the backend of an array-like object ("torch" or "numpy").""" | |
| if isinstance(tensor, torch.Tensor): | |
| return "torch" | |
| if isinstance(tensor, np.ndarray): | |
| return "numpy" | |
| raise TypeError(f"Unsupported tensor type: {type(tensor)}") | |
| def ensure_torch_tensor( | |
| data: TensorLike, | |
| dtype: Optional[torch.dtype] = None, | |
| device: Optional[Union[str, torch.device]] = None, | |
| ) -> torch.Tensor: | |
| """ | |
| Convert input data to a PyTorch tensor. | |
| Existing tensors are returned as-is (so autograd leaves are preserved), | |
| NumPy arrays are wrapped without copying (memory is shared), and anything | |
| else goes through ``torch.as_tensor``. | |
| """ | |
| if isinstance(data, torch.Tensor): | |
| tensor = data | |
| elif isinstance(data, np.ndarray): | |
| tensor = torch.from_numpy(data) | |
| else: | |
| tensor = torch.as_tensor(data) | |
| if dtype is not None or device is not None: | |
| tensor = tensor.to(dtype=dtype, device=device) | |
| return tensor | |
| def validate_spinor_dimension(tensor: torch.Tensor, dim: int = 2) -> None: | |
| """Validate that the last dimension matches the expected spinor dimension.""" | |
| if tensor.ndim == 0: | |
| raise ValueError("Spinor tensor must have at least one dimension") | |
| if tensor.shape[-1] != dim: | |
| raise ValueError( | |
| f"Last dimension must be {dim} for spinors, got {tensor.shape[-1]}" | |
| ) | |
| def check_broadcastable(a: torch.Tensor, b: torch.Tensor) -> torch.Size: | |
| """Return the broadcast shape of two tensors, raising ValueError if impossible.""" | |
| try: | |
| return torch.broadcast_shapes(a.shape, b.shape) | |
| except RuntimeError as exc: | |
| raise ValueError( | |
| f"Shapes {tuple(a.shape)} and {tuple(b.shape)} are not broadcastable" | |
| ) from exc | |
| def real_dtype_of(dtype: torch.dtype) -> torch.dtype: | |
| """Return the real dtype underlying a (possibly complex) dtype.""" | |
| if dtype == torch.complex64: | |
| return torch.float32 | |
| if dtype == torch.complex128: | |
| return torch.float64 | |
| if dtype == torch.complex32: | |
| return torch.float16 | |
| return dtype | |
| def complex_dtype_of(dtype: torch.dtype) -> torch.dtype: | |
| """Return the complex dtype whose real part has the given precision.""" | |
| if dtype.is_complex: | |
| return dtype | |
| if dtype == torch.float64: | |
| return torch.complex128 | |
| # float32 and everything lower-precision (or non-floating) map to complex64 | |
| return torch.complex64 | |
| def resolve_dtype_and_device( | |
| inputs: Sequence[object], | |
| dtype: Optional[torch.dtype], | |
| device: Optional[Union[str, torch.device]], | |
| ) -> "tuple[torch.dtype, torch.device]": | |
| """ | |
| Pick the real working dtype and device for a computation. | |
| If ``dtype`` is given it wins (a complex dtype is mapped to its real part). | |
| Otherwise, use the highest-precision floating dtype among any tensor inputs, | |
| falling back to the torch default. The device comes from ``device`` or the | |
| first tensor input, falling back to CPU. | |
| """ | |
| if dtype is not None: | |
| real_dtype = real_dtype_of(dtype) | |
| else: | |
| real_dtype = None | |
| for x in inputs: | |
| if isinstance(x, torch.Tensor) and x.is_floating_point(): | |
| real_dtype = x.dtype if real_dtype is None else torch.promote_types(real_dtype, x.dtype) | |
| if real_dtype is None: | |
| real_dtype = torch.get_default_dtype() | |
| if device is None: | |
| for x in inputs: | |
| if isinstance(x, torch.Tensor): | |
| device = x.device | |
| break | |
| return real_dtype, torch.device(device) if device is not None else torch.device("cpu") | |