fix(algebra): close runtime versor applications in float64
This commit is contained in:
parent
fbb6570a7d
commit
d09b1c8ad0
1 changed files with 14 additions and 16 deletions
|
|
@ -14,6 +14,7 @@ _CONSTRUCTION_RESIDUE_TOLERANCE = 1e-2
|
||||||
_NEAR_ZERO_TOLERANCE = 1e-12
|
_NEAR_ZERO_TOLERANCE = 1e-12
|
||||||
_DENSE_SEED_MIN_COMPONENTS = 8
|
_DENSE_SEED_MIN_COMPONENTS = 8
|
||||||
_SEED_BIVECTORS = (6, 7, 8, 10, 11, 13)
|
_SEED_BIVECTORS = (6, 7, 8, 10, 11, 13)
|
||||||
|
_RUNTIME_FIELD_DTYPE = np.dtype(np.float64)
|
||||||
|
|
||||||
|
|
||||||
def _array_dtype(v: np.ndarray) -> np.dtype:
|
def _array_dtype(v: np.ndarray) -> np.dtype:
|
||||||
|
|
@ -94,29 +95,26 @@ def construction_seed_versor(v: np.ndarray) -> np.ndarray:
|
||||||
return _seed_to_rotor(v, _array_dtype(v))
|
return _seed_to_rotor(v, _array_dtype(v))
|
||||||
|
|
||||||
|
|
||||||
def _close_applied_versor(v: np.ndarray, dtype: np.dtype) -> np.ndarray:
|
def _close_applied_versor(v: np.ndarray) -> np.ndarray:
|
||||||
"""Close algebra-produced sandwich results for runtime field states.
|
"""Close runtime field sandwich results at float64 precision.
|
||||||
|
|
||||||
``versor_apply`` is the field-propagation API: callers expect the returned
|
``versor_apply`` is the runtime field-propagation API. Vocabulary entries
|
||||||
multivector to satisfy ``versor_condition(result)``. CGA point/null-vector
|
may be stored compactly as float32, but live ``FieldState.F`` values are
|
||||||
preservation belongs behind an explicit geometry API, not this runtime
|
judged against a strict ``versor_condition < 1e-6`` invariant. Closing and
|
||||||
manifold boundary.
|
returning float64 avoids leaking float32 roundoff as false manifold drift.
|
||||||
"""
|
"""
|
||||||
arr = np.asarray(v, dtype=dtype)
|
arr = np.asarray(v, dtype=_RUNTIME_FIELD_DTYPE)
|
||||||
try:
|
try:
|
||||||
return unitize_versor(arr).astype(dtype)
|
return unitize_versor(arr).astype(_RUNTIME_FIELD_DTYPE)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return construction_seed_versor(arr).astype(dtype)
|
return _seed_to_rotor(arr, _RUNTIME_FIELD_DTYPE).astype(_RUNTIME_FIELD_DTYPE)
|
||||||
|
|
||||||
|
|
||||||
def versor_apply(V: np.ndarray, F: np.ndarray) -> np.ndarray:
|
def versor_apply(V: np.ndarray, F: np.ndarray) -> np.ndarray:
|
||||||
dtype = np.result_type(V, F)
|
V = np.asarray(V, dtype=_RUNTIME_FIELD_DTYPE)
|
||||||
if dtype not in (np.dtype(np.float32), np.dtype(np.float64)):
|
F = np.asarray(F, dtype=_RUNTIME_FIELD_DTYPE)
|
||||||
dtype = np.dtype(np.float32)
|
applied = geometric_product(geometric_product(V, F), reverse(V)).astype(_RUNTIME_FIELD_DTYPE)
|
||||||
V = np.asarray(V, dtype=dtype)
|
return _close_applied_versor(applied)
|
||||||
F = np.asarray(F, dtype=dtype)
|
|
||||||
applied = geometric_product(geometric_product(V, F), reverse(V)).astype(dtype)
|
|
||||||
return _close_applied_versor(applied, dtype)
|
|
||||||
|
|
||||||
|
|
||||||
def versor_unit_residual(v: np.ndarray, *, allow_negative: bool = False) -> float:
|
def versor_unit_residual(v: np.ndarray, *, allow_negative: bool = False) -> float:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue