Restore FieldState slots in determinism proof
This commit is contained in:
parent
4e7c29b84a
commit
f8113a38ba
2 changed files with 5 additions and 3 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).
|
FieldState is immutable by design (frozen=True, slots=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)
|
@dataclass(frozen=True, slots=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,6 +28,7 @@ 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(
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,7 @@ import hashlib
|
||||||
import json
|
import json
|
||||||
import struct
|
import struct
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
|
from dataclasses import fields
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
@ -498,7 +499,7 @@ class TestDET10FieldStateIsSingleMultivector:
|
||||||
"""FieldState must not hold a copy of the input tokens."""
|
"""FieldState must not hold a copy of the input tokens."""
|
||||||
state = inject(["in", "the", "beginning"], _PinVocab())
|
state = inject(["in", "the", "beginning"], _PinVocab())
|
||||||
# No attribute should store the original token list
|
# No attribute should store the original token list
|
||||||
for attr in vars(state).values():
|
for attr in (getattr(state, field.name) for field in fields(state)):
|
||||||
if isinstance(attr, (list, tuple)):
|
if isinstance(attr, (list, tuple)):
|
||||||
# Allow small metadata tuples but not token-length sequences
|
# Allow small metadata tuples but not token-length sequences
|
||||||
assert len(attr) <= 4, (
|
assert len(attr) <= 4, (
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue