""" algebra/rotor.py — Rotor construction operators for Cl(4,1). Rotors are operators. They live here, in algebra/, not in vocab/. A rotor between two word-versors is a contextual, field-level concern: it describes a transformation being applied, not a property of the vocabulary. """ import numpy as np from .cl41 import geometric_product, reverse from .versor import unitize_versor def word_transition_rotor(A: np.ndarray, B: np.ndarray) -> np.ndarray: """ Compute the rotor R that rotates versor A toward versor B in Cl(4,1). R = unitize(1 + B * reverse(A)) This is a pure construction operation — building a new algebraic object from two input versors. unitize_versor() is the correct primitive here, not normalize_to_versor() (which is reserved for the injection gate). This is a pure operator — it transforms a field state, it does not encode a position. Call this from algebra-aware field logic; never store the result on a vocabulary structure. Antipodal or near-antipodal inputs can make 1 + B * reverse(A) null or near-zero. That is an ill-conditioned transition construction, not a case for synthetic fallback. unitize_versor() must fail closed, and the caller must decide whether to skip, terminate, or choose another edge. Args: A: Source versor, shape (32,), grade-normed to ±1. B: Target versor, shape (32,), grade-normed to ±1. Returns: R: Unitized rotor in Cl(4,1), shape (32,). Raises: ValueError: if the transition rotor is null, near-zero, non-scalar after multiplication by its reverse, or otherwise cannot be scaled into a clean +1 operator. """ R = geometric_product(B, reverse(A)) R = R.copy() R[0] += 1.0 return unitize_versor(R)