135 lines
4.5 KiB
Python
135 lines
4.5 KiB
Python
|
|
"""Plan 03-01 CONN-05 RED: TEM factorization (Whittington-Behrens 2020).
|
||
|
|
|
||
|
|
Verifies BSC binding/unbinding fidelity at D=10000 across 15 / 17 / 18
|
||
|
|
role-filler pairs (D-TEM-02 target). Constitutional invariants:
|
||
|
|
|
||
|
|
- Tensor-product bind is XOR-reversible (BSC self-inverse semantics).
|
||
|
|
- Pack/unpack maintains >= 95% unbind accuracy at 15 pairs.
|
||
|
|
- structure_hv is exactly STRUCTURE_HV_BYTES (1250 bytes) packed bits.
|
||
|
|
"""
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
import pytest
|
||
|
|
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------- module surface
|
||
|
|
|
||
|
|
|
||
|
|
def test_role_vocabulary_has_18_entries() -> None:
|
||
|
|
"""D-TEM Claude's Discretion locks role count at 18 (covers WHEN/WHERE/...
|
||
|
|
plus tier/lang/community/etc. structural attributes per MemoryRecord).
|
||
|
|
"""
|
||
|
|
from iai_mcp.tem import ROLE_VOCABULARY
|
||
|
|
|
||
|
|
assert isinstance(ROLE_VOCABULARY, tuple)
|
||
|
|
assert len(ROLE_VOCABULARY) == 18
|
||
|
|
# Constitutional minimum subset from CONTEXT.md D-TEM:
|
||
|
|
for required in ("WHEN", "WHERE", "ROLE", "PROJECT", "COMMUNITY_ID", "TEMPORAL_POSITION"):
|
||
|
|
assert required in ROLE_VOCABULARY, f"missing constitutional role {required!r}"
|
||
|
|
|
||
|
|
|
||
|
|
def test_role_hv_is_deterministic_and_correct_length() -> None:
|
||
|
|
"""Same role symbol always returns same bytes; length is STRUCTURE_HV_BYTES."""
|
||
|
|
from iai_mcp.tem import role_hv
|
||
|
|
from iai_mcp.types import STRUCTURE_HV_BYTES
|
||
|
|
|
||
|
|
a = role_hv("WHEN")
|
||
|
|
b = role_hv("WHEN")
|
||
|
|
assert isinstance(a, bytes)
|
||
|
|
assert len(a) == STRUCTURE_HV_BYTES
|
||
|
|
assert a == b # Deterministic codebook.
|
||
|
|
|
||
|
|
c = role_hv("WHERE")
|
||
|
|
assert c != a # Different roles produce different hvs.
|
||
|
|
|
||
|
|
|
||
|
|
def test_filler_hv_is_deterministic_and_correct_length() -> None:
|
||
|
|
"""Same filler string always returns same bytes; length is STRUCTURE_HV_BYTES."""
|
||
|
|
from iai_mcp.tem import filler_hv
|
||
|
|
from iai_mcp.types import STRUCTURE_HV_BYTES
|
||
|
|
|
||
|
|
a = filler_hv("2026-04-17")
|
||
|
|
b = filler_hv("2026-04-17")
|
||
|
|
assert isinstance(a, bytes)
|
||
|
|
assert len(a) == STRUCTURE_HV_BYTES
|
||
|
|
assert a == b
|
||
|
|
|
||
|
|
|
||
|
|
def test_bind_is_xor_reversible() -> None:
|
||
|
|
"""BSC tensor-product binding is bytewise XOR; XOR is self-inverse."""
|
||
|
|
from iai_mcp.tem import bind, role_hv
|
||
|
|
|
||
|
|
a = role_hv("WHEN")
|
||
|
|
b = role_hv("PROJECT")
|
||
|
|
bound = bind(a, b)
|
||
|
|
assert isinstance(bound, bytes)
|
||
|
|
assert len(bound) == len(a)
|
||
|
|
# XOR self-inverse: bind(bind(a, b), b) == a
|
||
|
|
assert bind(bound, b) == a
|
||
|
|
assert bind(bound, a) == b
|
||
|
|
|
||
|
|
|
||
|
|
def test_unbind_inverts_bind() -> None:
|
||
|
|
"""unbind(bind(a, b), a) recovers b bit-for-bit."""
|
||
|
|
from iai_mcp.tem import bind, role_hv, unbind
|
||
|
|
|
||
|
|
a = role_hv("ROLE")
|
||
|
|
b = role_hv("LANG")
|
||
|
|
bound = bind(a, b)
|
||
|
|
recovered = unbind(bound, a)
|
||
|
|
assert recovered == b
|
||
|
|
|
||
|
|
|
||
|
|
# -------------------------------------------------------- fidelity at N pairs
|
||
|
|
|
||
|
|
|
||
|
|
def _fidelity_at(n_pairs: int) -> float:
|
||
|
|
"""Pack n_pairs role-filler pairs, then test unbind recovery against
|
||
|
|
a known filler codebook of size 18. Returns matched / n_pairs in [0, 1]."""
|
||
|
|
from iai_mcp.tem import (
|
||
|
|
ROLE_VOCABULARY,
|
||
|
|
bind,
|
||
|
|
filler_hv,
|
||
|
|
pack_pairs,
|
||
|
|
role_hv,
|
||
|
|
unbind,
|
||
|
|
)
|
||
|
|
|
||
|
|
# Deterministic seed=42-derived filler set (one filler per role, 18 total).
|
||
|
|
fillers = [filler_hv(f"filler-seed42-{i}") for i in range(len(ROLE_VOCABULARY))]
|
||
|
|
roles = list(ROLE_VOCABULARY[:n_pairs])
|
||
|
|
pairs = [(roles[i], fillers[i]) for i in range(n_pairs)]
|
||
|
|
packed = pack_pairs(pairs)
|
||
|
|
assert isinstance(packed, bytes)
|
||
|
|
|
||
|
|
# Hamming-distance helper.
|
||
|
|
def hamming(x: bytes, y: bytes) -> int:
|
||
|
|
return sum(bin(a ^ b).count("1") for a, b in zip(x, y))
|
||
|
|
|
||
|
|
correct = 0
|
||
|
|
for i, role in enumerate(roles):
|
||
|
|
unbound = unbind(packed, role_hv(role))
|
||
|
|
# Nearest-neighbour against the known filler codebook (size 18).
|
||
|
|
best = min(range(len(fillers)), key=lambda j: hamming(unbound, fillers[j]))
|
||
|
|
if best == i:
|
||
|
|
correct += 1
|
||
|
|
return correct / n_pairs
|
||
|
|
|
||
|
|
|
||
|
|
def test_unbind_fidelity_15_pairs() -> None:
|
||
|
|
"""D-TEM-02: at 15 role-filler pairs, unbind fidelity >= 0.95."""
|
||
|
|
fidelity = _fidelity_at(15)
|
||
|
|
assert fidelity >= 0.95, f"unbind fidelity at 15 pairs = {fidelity:.3f} < 0.95"
|
||
|
|
|
||
|
|
|
||
|
|
def test_unbind_fidelity_17_pairs() -> None:
|
||
|
|
"""D-TEM-02 secondary target: at 17 pairs, fidelity >= 0.92."""
|
||
|
|
fidelity = _fidelity_at(17)
|
||
|
|
assert fidelity >= 0.92, f"unbind fidelity at 17 pairs = {fidelity:.3f} < 0.92"
|
||
|
|
|
||
|
|
|
||
|
|
def test_unbind_fidelity_18_pairs() -> None:
|
||
|
|
"""D-TEM-02 outer bound: at 18 pairs (whole vocab), fidelity >= 0.90."""
|
||
|
|
fidelity = _fidelity_at(18)
|
||
|
|
assert fidelity >= 0.90, f"unbind fidelity at 18 pairs = {fidelity:.3f} < 0.90"
|