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.
|
||||
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(
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
Loading…
Reference in a new issue