"""Extra checks for towers.py:
 (1) brute-force O(N^2) pairwise certification of the final set at 512 bits
     (no sweep-line shortcut), flagged items separated by real part only;
 (2) counts how many (v,w) combinations were merged by exact identity;
 (3) independent NON-rigorous cross-check: plain mpmath evaluation of v^w
     (mpmath's own principal power), clustering at 1e-60, n<=11 only (mpmath overflows at n=12) relative tolerance."""
import sys, itertools
import towers as T
from flint import ctx
import mpmath

N = int(sys.argv[1]) if len(sys.argv) > 1 else 12
LI = T.intern({0: (T.ZERO, T.F(1, 2))})
V = {1: {LI}}
for n in range(2, N + 1):
    S = set(); combos = 0
    for k in range(1, n):
        for lv in V[k]:
            for lw in V[n - k]:
                S.add(T.power(lv, lw, final=(n == N))); combos += 1
    V[n] = S
    print(n, "combinations", combos, "distinct ids", len(S))
S = sorted(V[N]); p = 512
ctx.prec = p
Z = {i: T.enclose(i, p) for i in S}
bad = 0
for a, b in itertools.combinations(S, 2):
    za, zb = Z[a], Z[b]
    if a in T.FLAGGED or b in T.FLAGGED:
        sep = not za.real.overlaps(zb.real)
    else:
        sep = not (za.real.overlaps(zb.real) and za.imag.overlaps(zb.imag))
    if not sep:
        bad += 1
print("brute-force pairwise at %d bits: %d unseparated pairs among %d" % (p, bad, len(S)))

# (3) mpmath cross-check
mpmath.mp.dps = 150
W = {1: [mpmath.mpc(0, 1)]}
for n in range(2, min(N, 11) + 1):
    vals = []
    for k in range(1, n):
        for v in W[k]:
            for w in W[n - k]:
                vals.append(mpmath.power(v, w))
    # cluster by log (handles tiny/huge); principal log
    keyed = []
    for z in vals:
        L = mpmath.log(z)
        keyed.append(L)
    keyed.sort(key=lambda L: (float(mpmath.re(L)) if abs(mpmath.re(L)) < 1e300 else float(mpmath.sign(mpmath.re(L))) * 1e300, float(mpmath.im(L))))
    reps = []
    for L in keyed:
        if not any(abs(L - R) <= 1e-60 * (1 + abs(R)) for R in reps):
            reps.append(L)
    W[n] = [mpmath.exp(L) for L in reps]
    print("mpmath non-rigorous", n, len(reps))
