#!/usr/bin/env python3
"""Memory-efficient YB modulo space search.
Generates combos on-the-fly instead of precomputing all."""
import sys, math, itertools
sys.path.insert(0, '.')
from multi_strand_braid import pairwise_coprime, cross, moduli_from_pairs, F_multi

A0, S = [1, 2, 5, 6], 7

# Precompute coprime pairs up to 2000
pairs = [(p,q) for p in range(2, 2000) for q in range(p+1, 2000) if math.gcd(p,q) == 1]
print(f"Coprime pairs: {len(pairs)}")

def test_yb_4tuple(a, b, c, d):
    init = [(a,b),(c,d)]
    s1 = cross(init, 0, True)
    if not s1: return None
    s1s2 = cross(s1, 1, False)
    if not s1s2: return None
    s1s2s1 = cross(s1s2, 0, True)
    if not s1s2s1: return None
    s2 = cross(init, 1, False)
    if not s2: return None
    s2s1 = cross(s2, 0, True)
    if not s2s1: return None
    s2s1s2 = cross(s2s1, 1, False)
    if not s2s1s2: return None
    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:
        return (a,b,c,d,a*b*c*d,f1)
    return None

# Smart search: iterate pairs but only check promising ones
found = []
checked = 0
for i, (a,b) in enumerate(pairs):
    # For this pair, we need partner moduli beyond a+6 (3 over crossings)
    min_c = a + 7  # strand2 min must exceed strand1 max after crossings
    for j in range(i+1, len(pairs)):
        c, d = pairs[j]
        if c < min_c:
            continue
        if not pairwise_coprime([a,b,c,d]):
            continue
        checked += 1
        if checked > 100000:
            break
        result = test_yb_4tuple(a, b, c, d)
        if result:
            found.append(result)
            a,b,c,d,M,f1 = result
            print(f"YB #{len(found)}: [{a},{b}]x[{c},{d}] M={M}")
    if checked > 100000:
        break

print(f"\nChecked: {checked}")
print(f"YB-valid: {len(found)}")
if found:
    smallest = min(found, key=lambda x: x[4])
    print(f"\nSmallest YB configuration:")
    print(f"  Strand1: ({smallest[0]},{smallest[1]})")
    print(f"  Strand2: ({smallest[2]},{smallest[3]})")
    print(f"  M = {smallest[4]}")
    print(f"  FA = {smallest[5]}")
