Fix field state introspection and pack manifold geometry

This commit is contained in:
Shay 2026-05-13 14:24:29 -07:00
parent 52de2218b7
commit 4e7c29b84a
2 changed files with 20 additions and 4 deletions

View file

@ -4,7 +4,7 @@ FieldState — the complete cognitive field at one moment.
Invariant: versor_condition(F) < 1e-6 always.
This is checked at injection and maintained structurally by versor_apply().
FieldState is immutable by design (frozen=True, slots=True).
FieldState is immutable by design (frozen=True).
The np.ndarray F is copied and validated at construction the copy() call
is the explicit contract boundary. Callers must not retain a mutable
reference to the array passed in and expect coherence.
@ -17,7 +17,7 @@ import numpy as np
_EXPECTED_COMPONENTS = 32
@dataclass(frozen=True, slots=True)
@dataclass(frozen=True)
class FieldState:
F: np.ndarray # shape (32,) float32 — Cl(4,1) multivector on the versor manifold
node: int = 0 # current node index in the vocabulary manifold
@ -28,7 +28,6 @@ class FieldState:
# Enforce copy + dtype + shape at the construction boundary.
# frozen=True prevents reassignment, but ndarray contents are still
# mutable via the array object; copy() here is the defence.
# slots=True closes __dict__ so no incidental attributes can be added.
F = np.array(self.F, dtype=np.float32).copy()
if F.shape != (_EXPECTED_COMPONENTS,):
raise ValueError(

View file

@ -36,13 +36,30 @@ def _feature_rotor(name: str, salt: str, weight: float) -> np.ndarray:
return rotor
def _domain_features(domain: str) -> list[tuple[str, float]]:
"""
Lift hierarchical semantic domains into a small feature chain.
A domain like ``logos.illumination.photon`` contributes the trunk
(``logos``), then the branch (``logos.illumination``), then the leaf.
This reduces accidental hash collisions where unrelated surfaces land
close together despite having disjoint semantic structure.
"""
parts = domain.lower().split(".")
return [
(".".join(parts[: depth + 1]), 0.45 / (depth + 1))
for depth in range(len(parts))
]
def _entry_to_coordinate(entry: LexicalEntry) -> np.ndarray:
vec = np.zeros(N_COMPONENTS, dtype=np.float32)
vec[0] = 1.0
pos = (entry.pos or entry.part_of_speech or "").lower()
for domain in entry.semantic_domains:
vec = geometric_product(vec, _feature_rotor(domain.lower(), "domain", 0.7))
for feature, weight in _domain_features(domain):
vec = geometric_product(vec, _feature_rotor(feature, "domain", weight))
if pos:
vec = geometric_product(vec, _feature_rotor(pos, "pos", 0.35))