from math import pi
import numpy as np
# Optional PyTorch support
try:
import torch
TORCH_AVAILABLE = True
except ImportError:
TORCH_AVAILABLE = False
torch = None
from pyhdc.components.input_formatting import _broadcast_operands, _normalize_binding
# Type aliases
from pyhdc.types import ArrayLike
# ============================================================================
# Angle-based Binding (for FHRR)
# ============================================================================
[docs]
def ElementAngleAddition(*hypervectors: ArrayLike) -> ArrayLike:
"""
Binding by adding phase angles.
Used with Fourier Holographic Reduced Representations (FHRR) where
hypervector elements represent phase angles. Operands broadcast over the
trailing batch axes.
Args:
*hypervectors: Variable number of phase hypervectors, or single 2D batch
Returns:
Bound hypervector with phases in [0, 2*pi)
"""
hvs, is_torch, _ = _normalize_binding(*hypervectors)
operands = _broadcast_operands(hvs, is_torch)
total = operands[0]
for operand in operands[1:]:
total = total + operand
if is_torch:
return torch.fmod(total, 2 * pi)
return np.mod(total, 2 * pi)
[docs]
def ElementAngleSubtraction(*hypervectors: ArrayLike) -> ArrayLike:
"""
Unbinding by subtracting phase angles.
Inverse operation for ElementAngleAddition. Operands broadcast over the
trailing batch axes.
Args:
*hypervectors: Variable number of phase hypervectors, or single 2D batch
Returns:
Unbound hypervector with phases in [0, 2*pi)
"""
hvs, is_torch, _ = _normalize_binding(*hypervectors)
operands = _broadcast_operands(hvs, is_torch)
diff = operands[0]
for operand in operands[1:]:
diff = diff - operand
if is_torch:
return torch.fmod(diff, 2 * pi)
return np.mod(diff, 2 * pi)