#!/usr/bin/env python3
"""
Chiral Spectral LUT — mapping 8-strand chiral configuration → spectral state.

8 strands × 4 chiral labels = 4⁸ = 65,536 states
Collapses to exactly 5 distinct spectral fingerprints.

The LUT maps any configuration to its eigenvalue pair {λ_min, λ_max}
using pure integer arithmetic (zero floats).
"""
import json, time

# Chiral weights as rational pairs (num, den) — integer arithmetic, zero floats
CHIRAL = {"A": (1, 1), "S": (1, 2), "L": (3, 2), "R": (3, 2)}
NAMES = ["A", "S", "L", "R"]  # achiral, scarred, left_bias, right_bias

def compute_spectral(chi8):
    """
    Compute {λ_min, λ_max} for an 8-char chiral string like 'AASSSLLR'.
    Integer arithmetic only — zero floats.
    
    The Cartan matrix is 4×2×2 block-diagonal: pairs (0,1), (2,3), (4,5), (6,7).
    Each block [[273, w], [w, 273]] has eigenvalues {273+w, 273-w}
    where w = 128 × (chiral[num]/chiral[den] average of the pair).
    """
    pairs = [(0,1), (2,3), (4,5), (6,7)]
    all_lo, all_hi = [], []
    for a, b in pairs:
        an, ad = CHIRAL[chi8[a]]
        bn, bd = CHIRAL[chi8[b]]
        # w = 128 × (an/ad + bn/bd) = 128 × (an×bd + bn×ad) / (ad×bd)
        num = 128 * (an * bd + bn * ad)
        den = ad * bd
        w = num // den
        all_lo.append(273 + w)
        all_hi.append(273 - w)
    return max(all_lo), min(all_hi)

def build_lut(save=True):
    """Build the full 65,536-entry LUT."""
    t0 = time.time()
    lut = {}
    for mask_int in range(4**8):
        chi = "".join(NAMES[(mask_int >> (i*2)) & 3] for i in range(8))
        lam_max, lam_min = compute_spectral(chi)
        lut[chi] = {"lambda_max": lam_max, "lambda_min": lam_min}
    
    t1 = time.time()
    
    # Classify into regimes
    regimes = {}
    for chi, spec in lut.items():
        key = (spec["lambda_min"], spec["lambda_max"])
        regimes.setdefault(key, [])
        regimes[key].append(chi)
    
    print(f"LUT built in {t1-t0:.1f}s — {len(lut):,} entries, zero floats")
    print(f"\nSpectral regime distribution ({len(regimes)} regimes):")
    for (lo, hi), configs in sorted(regimes.items(), key=lambda x: -len(x[1])):
        regime = "CANONICAL" if lo == 17 else "ROSSBY" if lo < 0 else "SCARRED" if lo > 17 else "OTHER"
        name = {"CANONICAL": "achiral ground state",
                "ROSSBY": "nonabelian (Rossby-active)",
                "SCARRED": "sub-critical (scarred)"}.get(regime, regime)
        print(f"  λ=[{lo:>4}, {hi:>4}]  {len(configs):>5} configs ({len(configs)/len(lut)*100:5.1f}%)  {name}")
    
    if save:
        receipt = {
            "schema": "chiral_spectral_lut_v1", "zero_float": True,
            "entries": len(lut), "regimes": len(regimes),
            "regime_labels": ["CANONICAL", "ROSSBY", "SCARRED"],
            "compute_time_s": round(t1-t0, 2),
            "note": "Integer arithmetic only. Block eigenvalues = 273 ± w, w = 128 × avg(chi)"
        }
        with open("signatures/chiral_spectral_lut.json", "w") as f:
            json.dump(receipt, f, indent=2)
        print(f"\nReceipt: signatures/chiral_spectral_lut.json")
    
    return lut, regimes

if __name__ == "__main__":
    lut, regimes = build_lut()
    
    # Example lookups
    print("\nExample lookups:")
    for chi in ["AAAAAAAA", "SSSSSSSS", "LLLLLLLL", "AASSLRRL", "AASSAASS"]:
        spec = lut.get(chi, {})
        regime = "CANONICAL" if spec.get("lambda_min") == 17 else "ROSSBY" if spec.get("lambda_min", 0) < 0 else "SCARRED"
        print(f"  {chi} → λ=[{spec.get('lambda_min')}, {spec.get('lambda_max')}] {regime}")
