Fix field state introspection and pack manifold geometry
This commit is contained in:
parent
52de2218b7
commit
4e7c29b84a
2 changed files with 20 additions and 4 deletions
|
|
@ -4,7 +4,7 @@ FieldState — the complete cognitive field at one moment.
|
||||||
Invariant: versor_condition(F) < 1e-6 always.
|
Invariant: versor_condition(F) < 1e-6 always.
|
||||||
This is checked at injection and maintained structurally by versor_apply().
|
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
|
The np.ndarray F is copied and validated at construction — the copy() call
|
||||||
is the explicit contract boundary. Callers must not retain a mutable
|
is the explicit contract boundary. Callers must not retain a mutable
|
||||||
reference to the array passed in and expect coherence.
|
reference to the array passed in and expect coherence.
|
||||||
|
|
@ -17,7 +17,7 @@ import numpy as np
|
||||||
_EXPECTED_COMPONENTS = 32
|
_EXPECTED_COMPONENTS = 32
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True, slots=True)
|
@dataclass(frozen=True)
|
||||||
class FieldState:
|
class FieldState:
|
||||||
F: np.ndarray # shape (32,) float32 — Cl(4,1) multivector on the versor manifold
|
F: np.ndarray # shape (32,) float32 — Cl(4,1) multivector on the versor manifold
|
||||||
node: int = 0 # current node index in the vocabulary 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.
|
# Enforce copy + dtype + shape at the construction boundary.
|
||||||
# frozen=True prevents reassignment, but ndarray contents are still
|
# frozen=True prevents reassignment, but ndarray contents are still
|
||||||
# mutable via the array object; copy() here is the defence.
|
# 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()
|
F = np.array(self.F, dtype=np.float32).copy()
|
||||||
if F.shape != (_EXPECTED_COMPONENTS,):
|
if F.shape != (_EXPECTED_COMPONENTS,):
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
|
|
|
||||||
|
|
@ -36,13 +36,30 @@ def _feature_rotor(name: str, salt: str, weight: float) -> np.ndarray:
|
||||||
return rotor
|
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:
|
def _entry_to_coordinate(entry: LexicalEntry) -> np.ndarray:
|
||||||
vec = np.zeros(N_COMPONENTS, dtype=np.float32)
|
vec = np.zeros(N_COMPONENTS, dtype=np.float32)
|
||||||
vec[0] = 1.0
|
vec[0] = 1.0
|
||||||
|
|
||||||
pos = (entry.pos or entry.part_of_speech or "").lower()
|
pos = (entry.pos or entry.part_of_speech or "").lower()
|
||||||
for domain in entry.semantic_domains:
|
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:
|
if pos:
|
||||||
vec = geometric_product(vec, _feature_rotor(pos, "pos", 0.35))
|
vec = geometric_product(vec, _feature_rotor(pos, "pos", 0.35))
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue