SilverSight/tests/test_spectral_codebook.py
allaun 4ea68bcecc feat(spectral): gap-aware spectral codebook generator with exact char-poly fingerprints
Implements the Next Steps of docs/SPECTRAL_CODEBOOK_ANALYSIS.md as
python/spectral_codebook.py (stdlib-only; NumPy optional fast path):

- Parses the 250 8x8 braid adjacency matrices from PIST/Matrices250.lean.
- Primary fingerprint: exact integer characteristic-polynomial
  coefficients via Faddeev-LeVerrier in Fraction arithmetic (196 unique
  over 238 distinct matrices, vs 179 unique lambda at 4dp; 6 cospectral
  non-identical groups; 11 exact-duplicate matrix groups / 23 ids).
- Corrects the analysis doc: the 9 'mid band' lambda in (0.5,1) are
  power-iteration non-convergence artifacts - exact rho = 1.0 for all 9
  (peripheral spectra). spectral_radius is now the exact max root
  modulus (numpy eigvals or Durand-Kerner on the exact char poly);
  power-iteration lambda kept only for traceability.
- Gap-aware quantization: dedupe to 238 distinct matrices, boundaries at
  gaps > 3x median gap, min-support guard (>=10 distinct per cluster),
  sparse-tail outlier flagging above lambda ~= 7.66. Result: 9 clusters.
- Round trip encode(matrix) -> (codeword, index) -> decode -> equation_id
  verified bijective over all 250 in tests/test_spectral_codebook.py.
- 278-row RRC/Q16_16Manifold corpus: 28 extra rows are repeated ids;
  boundaries reproduce exactly, no new gaps or clusters.
- Emits data/spectral_codebook.json (schema spectral_codebook_v2) with
  explicit collision classes; docs/SPECTRAL_CODEBOOK_GENERATOR.md notes
  the hashMatrix base-5 injectivity gap and the ClassifyN threshold
  (1.5/4.0 Q16.16) vs analysis-doc (0.5/1.0) mismatch.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-01 20:39:40 -05:00

203 lines
8.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""test_spectral_codebook.py — Gap-aware spectral codebook round-trip tests.
Validates the spectral_codebook module against the 250-matrix PIST corpus:
exact char-poly fingerprints (CayleyHamilton in integer arithmetic),
pure-stdlib vs NumPy spectral-radius agreement, gap-aware quantization
invariants, and the encode/decode round trip over all 250 equations.
"""
from __future__ import annotations
import sys
import unittest
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "python"))
import spectral_codebook as sc
def _mat_mul(a, b):
n = len(a)
return [
[sum(a[i][t] * b[t][j] for t in range(n)) for j in range(n)]
for i in range(n)
]
class TestSpectralCodebook(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.matrices = sc.parse_matrices_lean()
cls.codebook = sc.Codebook(cls.matrices)
# ── parsing ─────────────────────────────────────────────────────
def test_parse_250_8x8(self):
self.assertEqual(len(self.matrices), 250)
for eid, mat in self.matrices.items():
self.assertEqual(len(mat), 8, eid)
self.assertTrue(all(len(r) == 8 for r in mat), eid)
self.assertTrue(all(x >= 0 for r in mat for x in r), eid)
# ── exact char poly ─────────────────────────────────────────────
def test_charpoly_identity(self):
# det(λI I) = (λ 1)^8 → coefficients are signed binomials
ident = tuple(tuple(1 if i == j else 0 for j in range(8)) for i in range(8))
expect = (-8, 28, -56, 70, -56, 28, -8, 1)
self.assertEqual(sc.charpoly_coeffs(ident), expect)
def test_cayley_hamilton_integer(self):
"""p(M) = 0 exactly in integer arithmetic (spot check)."""
for eid in sorted(self.matrices)[::50]: # 5 spread-out matrices
m = [list(r) for r in self.matrices[eid]]
coeffs = sc.charpoly_coeffs(m)
n = len(m)
acc = [[1 if i == j else 0 for j in range(n)] for i in range(n)] # M^0
total = [[coeffs[-1] if i == j else 0 for j in range(n)] for i in range(n)]
for k in range(1, n + 1):
acc = _mat_mul(acc, m) # M^k
c = 1 if k == n else coeffs[n - 1 - k]
for i in range(n):
for j in range(n):
total[i][j] += c * acc[i][j]
self.assertTrue(
all(x == 0 for row in total for x in row),
f"CayleyHamilton failed for {eid}",
)
def test_charpoly_trace_relation(self):
for eid, mat in self.matrices.items():
coeffs = self.codebook.profiles[eid]["charpoly"]
self.assertEqual(coeffs[0], -sum(mat[i][i] for i in range(8)), eid)
# ── spectral radius ─────────────────────────────────────────────
def test_pure_root_finder_matches_numpy(self):
"""DurandKerner on the exact char poly agrees with the fast path."""
for eid in sorted(self.matrices)[::10]: # 25 matrices
p = self.codebook.profiles[eid]
pure = sc._durand_kerner_max_modulus(p["charpoly"])
self.assertAlmostEqual(pure, p["spectral_radius"], places=4, msg=eid)
def test_peripheral_spectra_are_unit(self):
"""The 9 'mid band' λ in the committed raw JSON (0.5 ≤ λ < 1) are
power-iteration non-convergence artifacts: exact ρ = 1 for all 9."""
import json
raw_path = Path(__file__).resolve().parent.parent / "data" / "spectral_codebook_raw.json"
raw = json.loads(raw_path.read_text())
artifacts = [
e["equation_id"] for e in raw["entries"]
if 0.5 <= e["spectral_radius"] < 1.0
]
self.assertEqual(len(artifacts), 9)
for eid in artifacts:
self.assertAlmostEqual(
self.codebook.profiles[eid]["spectral_radius"], 1.0, places=6, msg=eid
)
def test_nilpotent_class(self):
"""Every ρ = 0 matrix has char poly exactly x^8 (nilpotent), and the
pure path detects it with no iteration."""
zeros = [
eid for eid, p in self.codebook.profiles.items()
if p["spectral_radius"] == 0.0
]
self.assertEqual(len(zeros), 35)
for eid in zeros:
coeffs = self.codebook.profiles[eid]["charpoly"]
self.assertEqual(list(coeffs), [0] * 8, eid)
self.assertEqual(sc._durand_kerner_max_modulus(coeffs), 0.0)
# ── fingerprints & collisions ───────────────────────────────────
def test_charpoly_strictly_finer_than_lambda(self):
col = self.codebook.collision_report()
self.assertEqual(col["corpus_size"], 250)
self.assertEqual(col["distinct_matrices"], 238)
self.assertEqual(col["duplicate_matrix_groups"], 11)
self.assertEqual(col["duplicate_matrix_members"], 23)
self.assertGreater(col["unique_charpoly"], col["unique_lambda_4dp"])
self.assertGreater(
col["identified_by_charpoly"], col["identified_by_lambda_4dp"]
)
# char poly is NOT injective: collision classes must be explicit
self.assertGreater(col["charpoly_collision_groups"], 0)
self.assertEqual(
sum(len(v) for v in col["charpoly_collision_classes"].values()),
col["charpoly_collision_members"],
)
# ── quantization invariants ─────────────────────────────────────
def test_boundaries_sorted_and_gapped(self):
b = self.codebook.boundaries
self.assertEqual(b, sorted(b))
self.assertGreater(len(b), 0)
# no λ value sits on a boundary
for p in self.codebook.profiles.values():
self.assertNotIn(p["spectral_radius"], b)
def test_min_support_guard(self):
"""Every cluster holds ≥ MIN_SUPPORT distinct matrices."""
for row in self.codebook.cluster_table():
self.assertGreaterEqual(
row["distinct_matrices"], sc.MIN_SUPPORT, row["codeword"]
)
def test_cluster_partition_covers_corpus(self):
table = self.codebook.cluster_table()
self.assertEqual(sum(r["count"] for r in table), 250)
self.assertEqual(sum(r["distinct_matrices"] for r in table), 238)
# ── round trip ──────────────────────────────────────────────────
def test_decode_is_bijective_over_250(self):
seen = set()
for eid in self.matrices:
cw, idx = self.codebook.codeword_of(eid)
self.assertNotIn((cw, idx), seen)
seen.add((cw, idx))
self.assertEqual(self.codebook.decode(cw, idx), eid)
self.assertEqual(len(seen), 250)
def test_encode_decode_round_trip(self):
"""encode(matrix) → decode must return the same equation for every
unique matrix, and a byte-identical matrix for exact duplicates
(identical inputs are information-theoretically indistinguishable)."""
dup_members = {
eid
for ids in self.codebook.matrix_groups.values()
if len(ids) > 1
for eid in ids
}
for eid, mat in self.matrices.items():
cw, idx = self.codebook.encode([list(r) for r in mat])
self.assertIsNotNone(idx, eid)
decoded = self.codebook.decode(cw, idx)
if eid in dup_members:
self.assertEqual(self.matrices[decoded], mat, eid)
else:
self.assertEqual(decoded, eid)
def test_encode_novel_matrix(self):
novel = [[3 if i == j else 1 for j in range(8)] for i in range(8)]
cw, idx = self.codebook.encode(novel)
self.assertIsNone(idx)
self.assertTrue(cw.startswith("C"))
# ── 278-row manifold ────────────────────────────────────────────
def test_manifold_278_no_new_gaps(self):
mc = sc.manifold_check(self.codebook)
self.assertEqual(mc["rows"], 278)
self.assertEqual(mc["unique_ids"], 250)
self.assertEqual(mc["extra_rows"], 28)
self.assertEqual(mc["ids_without_matrix"], [])
self.assertTrue(mc["boundaries_match_250"])
if __name__ == "__main__":
unittest.main()