core/algebra/rotor.py
Shay 9723941a38
Fail closed on invalid versor construction
Make versor construction fail closed instead of synthesizing hash-derived fallback rotors.

- remove pseudo-random construction fallback from unitize_versor
- add signed residual helper for +1 field states vs ±1 manifold entries
- validate vocab manifold entries with full residuals
- document antipodal transition rotor failure contract
- add focused invariant tests for versor closure and manifold validation
2026-05-14 10:55:11 -07:00

48 lines
1.8 KiB
Python

"""
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)