#!/usr/bin/env python3
"""
Deep Braid Exploration: YB modulo space, braid invariants, stabilization.
"""
import sys, math, itertools, random
from typing import List, Tuple
sys.path.insert(0, '/home/allaun/SilverSight/scripts')
from multi_strand_braid import pairwise_coprime, moduli_from_pairs, F_multi, braid_word, cross
from verify_wrapping import is_sidon

# ============================================================
# 1. YB MODULO SPACE SEARCH
# ============================================================

def search_yb_space(max_mod: int = 100) -> List[dict]:
    """Find ALL 4-tuples where the full YB relation holds with equal FA."""
    results = []
    # Precompute coprime pairs
    coprime_pairs_list = []
    for a in range(2, max_mod+1):
        for b in range(a+1, max_mod+1):
            if math.gcd(a, b) == 1:
                coprime_pairs_list.append((a, b))
    
    total = len(coprime_pairs_list)
    for idx1, (a, b) in enumerate(coprime_pairs_list):
        if idx1 % 100 == 0:
            sys.stdout.write(f"\r  Searching YB space: {idx1}/{total} pairs...")
            sys.stdout.flush()
        for idx2 in range(idx1+1, total):
            c, d = coprime_pairs_list[idx2]
            if not pairwise_coprime([a, b, c, d]):
                continue
            
            # Path 1: σ₁⁺ → σ₂⁻ → σ₁⁺
            s1 = cross([(a,b),(c,d)], 0, True)
            if not s1: continue
            s1s2 = cross(s1, 1, False)
            if not s1s2: continue
            s1s2s1 = cross(s1s2, 0, True)
            if not s1s2s1: continue
            
            # Path 2: σ₂⁻ → σ₁⁺ → σ₂⁻
            s2 = cross([(a,b),(c,d)], 1, False)
            if not s2: continue
            s2s1 = cross(s2, 0, True)
            if not s2s1: continue
            s2s1s2 = cross(s2s1, 1, False)
            if not s2s1s2: continue
            
            # Check equal FA
            A0, S = [1, 2, 5, 6], 7
            f1 = [F_multi(x, S, moduli_from_pairs(s1s2s1)) for x in A0]
            f2 = [F_multi(x, S, moduli_from_pairs(s2s1s2)) for x in A0]
            
            if f1 == f2:
                results.append({
                    'init': [(a,b),(c,d)],
                    'final': s1s2s1,
                    'path1_word': 'σ₁⁺·σ₂⁻·σ₁⁺',
                    'path2_word': 'σ₂⁻·σ₁⁺·σ₂⁻',
                    'FA': f1,
                    'M': a*b*c*d
                })
    print()
    return results

def test_yb_search():
    print("=" * 60)
    print("YB MODULO SPACE SEARCH")
    print("=" * 60)
    
    results = search_yb_space(max_mod=200)
    print(f"\nTotal YB-valid 4-tuples found: {len(results)}")
    if results:
        print(f"\nSmallest by M:")
        for r in sorted(results, key=lambda x: x['M'])[:5]:
            print(f"  {r['init']} M={r['M']:6d} FA={r['FA']}")
        print(f"\nLargest by M:")
        for r in sorted(results, key=lambda x: -x['M'])[:3]:
            print(f"  {r['init']} M={r['M']:8d} FA={r['FA']}")

# ============================================================
# 2. BRAID INVARIANTS FROM M-DIFFERENCES
# ============================================================

def m_difference_spectrum(A, moduli):
    """Compute the M-difference spectrum of a braid configuration."""
    M = 1
    for m in moduli: M *= m
    maxA = max(A)
    if M <= maxA:
        return {'regime': 'aliasing', 'M': M, 'sums': []}
    
    # Compute all pairwise sums
    sums = set()
    for i in range(len(A)):
        for j in range(i, len(A)):
            sums.add(A[i] + A[j])
    sum_list = sorted(sums)
    
    # Find M-differences
    diffs = []
    for i in range(len(sum_list)):
        for j in range(i+1, len(sum_list)):
            d = sum_list[j] - sum_list[i]
            if d > 0 and d % M == 0:
                diffs.append((sum_list[i], sum_list[j], d // M))
    
    return {'regime': 'injective' if M > maxA else 'aliasing', 'M': M, 'sums': sum_list, 'diffs': diffs}

def braid_invariant_from_mdiff(A, S, pairs_seq):
    """Compute braid invariant: the M-difference spectrum through a braid path."""
    invariants = []
    for pairs in pairs_seq:
        mods = moduli_from_pairs(pairs)
        spec = m_difference_spectrum(A, mods)
        invariants.append({
            'pairs': pairs,
            'M': spec['M'],
            'regime': spec['regime'],
            'num_diffs': len(spec.get('diffs', [])),
            'diffs': spec.get('diffs', [])
        })
    return invariants

def test_invariants():
    print("\n" + "=" * 60)
    print("BRAID INVARIANTS FROM M-DIFFERENCES")
    print("=" * 60)
    
    A0, S = [1, 2, 5, 6], 7
    
    # Trace a braid path and compute invariants
    configs = [[(3,4)], [(7,3)], [(11,2)]]
    for config in configs:
        mods = moduli_from_pairs(config)
        FA = [F_multi(a, S, mods) for a in A0]
        M = 1
        for m in mods: M *= m
        spec = m_difference_spectrum(A0, mods)
        sidon = is_sidon(FA)
        pairs_str = str(config[0])
        print(f"  {pairs_str:12s} M={M:3d} Sidon={sidon} sums={len(spec.get('sums',[]))} diffs={len(spec.get('diffs',[]))}")

# ============================================================
# 3. MODULUS REGENERATION AS BRAID STABILIZATION
# ============================================================

def markov_stabilization(pairs, strand=0):
    """A Markov stabilization move: add a trivial crossing to extend word length.
    
    Stabilization: add (L_new_id, L_new_ref) as a new strand, with values
    coprime to all existing moduli.
    """
    existing = moduli_from_pairs(pairs)
    existing_vals = set(existing)
    
    # Find a coprime pair not in existing values
    L_new_id = 2
    while L_new_id in existing_vals: L_new_id += 1
    L_new_ref = L_new_id + 1
    while L_new_ref in existing_vals or math.gcd(L_new_id, L_new_ref) != 1:
        L_new_ref += 1
    
    new_pair = (L_new_id, L_new_ref)
    all_mods = existing + [L_new_id, L_new_ref]
    
    if pairwise_coprime(all_mods):
        return pairs + [new_pair], f"stabilized with {new_pair}"
    return pairs, "stabilization failed"

def test_stabilization():
    print("\n" + "=" * 60)
    print("MODULUS REGENERATION AS BRAID STABILIZATION")
    print("=" * 60)
    
    # Start with a 1-strand system, cross until coprimality fails
    pairs = [(3, 4)]
    history = [pairs]
    for step in range(10):
        # Try over-crossing
        c = cross(pairs, 0, True)
        if c is None:
            # Stabilize: add a new strand with coprime moduli
            pairs, msg = markov_stabilization(pairs)
            print(f"  Step {step}: coprimality failed → {msg}")
            if pairs == history[-1]:
                print(f"  Cannot stabilize further. Stopping.")
                break
        else:
            pairs = c
        history.append(pairs)
        if len(history) <= 6:
            print(f"  Step {step}: pairs={pairs}")
    
    print(f"\n  Total steps before stabilization needed: {len(history)-1}")
    print(f"  Final config: {pairs}")

# ============================================================
# MAIN
# ============================================================

if __name__ == "__main__":
    test_yb_search()
    test_invariants()
    test_stabilization()
