core/tests/test_transition_rotor.py
Shay be6b278dc4
fix(algebra): enforce transition rotor invariants
Replace synthetic word-transition rotor construction with the closed product B * reverse(A).

- preserve make_rotor_from_angle compatibility
- fail closed on non-closed transition candidates instead of using construction fallback behavior
- validate transition operator condition
- add targeted transition rotor regression tests

No GitHub CI/status checks were exposed for this PR.
2026-05-15 21:13:14 -07:00

59 lines
1.8 KiB
Python

from __future__ import annotations
import numpy as np
import pytest
from algebra.cl41 import geometric_product, reverse
from algebra.rotor import make_rotor_from_angle, word_transition_rotor
from algebra.versor import versor_apply, versor_condition
def test_identity_transition_returns_identity_rotor() -> None:
A = make_rotor_from_angle(0.31, bivector_idx=6)
R = word_transition_rotor(A, A)
expected = np.zeros(32, dtype=R.dtype)
expected[0] = 1.0
np.testing.assert_allclose(R, expected, atol=1e-6)
assert versor_condition(R) < 1e-6
def test_transition_rotor_is_exact_closed_product() -> None:
A = make_rotor_from_angle(0.25, bivector_idx=6)
B = make_rotor_from_angle(-0.40, bivector_idx=6)
R = word_transition_rotor(A, B)
expected = geometric_product(B, reverse(A))
np.testing.assert_allclose(R, expected, atol=1e-6)
assert versor_condition(R) < 1e-6
def test_transition_rotor_preserves_field_condition() -> None:
A = make_rotor_from_angle(0.15, bivector_idx=6)
B = make_rotor_from_angle(0.45, bivector_idx=6)
field = make_rotor_from_angle(-0.20, bivector_idx=6)
R = word_transition_rotor(A, B)
transitioned = versor_apply(R, field)
assert versor_condition(R) < 1e-6
assert versor_condition(transitioned) < 1e-6
def test_transition_rotor_rejects_non_closed_candidate_instead_of_fallback() -> None:
A = np.zeros(32, dtype=np.float64)
A[0] = 1.0
B = np.ones(32, dtype=np.float64)
with pytest.raises(ValueError, match="non_closed|non_positive"):
word_transition_rotor(A, B)
def test_transition_rotor_rejects_near_zero_input() -> None:
A = np.zeros(32, dtype=np.float64)
B = make_rotor_from_angle(0.25, bivector_idx=6)
with pytest.raises(ValueError, match="near_zero"):
word_transition_rotor(A, B)