""" wild_field.py -- two Eisenstein polynomials of one field over W(F_q), q = 2^f: is the wild readout's capped departure min(lam, 3e/2) the field's at q > 2, or only min(lam, e)? QUESTION. wild_q.py: at q > 2 the top class's kernel (the one residue a with a^e = ubar) has least landing 2e + min(lam, e); the units whose pi'^2 digit y (pi' = T(a) pi) lies in F_2 keep 2e + min(lam, 3e/2), and at lam = e, 0 or 2 y off F_2 land past 3e. Read on F and on G, the Eisenstein polynomial of the uniformizer pi_1 = pi (1 + T(delta) pi) of the same field. DERIVATION (frozen before code). The kernel and its landings are the field's (pi -> eps pi sends a -> a/eps, ubar -> ubar/eps^e), so min(lam, e) is, and so is the number of y whose units land past 3e (U_3 lands at 7e/2 or deeper). T(a) pi = T(a) pi_1 - T(a delta) pi_1^2 + ..., so y_1 = y + delta/a: the deep pair of a lam > e polynomial, F_2 in the pi frame, is {delta/a, delta/a + 1} in the pi_1 frame, off F_2 iff delta is not in {0, a}; then G can have neither lam < e (least landing 3e) nor lam > e (deep pair F_2): lam_G = e. TRANSPLANT re-derived: at f = 1, delta/a is in F_2, and the f = 1 invariance stands. PREDICTIONS, over wild_q's anchor population (departures 1..3e/2 + 1 and the anchor itself), f = 2 (e = 2, 4, 8), f = 3 (e = 2, 4), dbar = 1 and one other, every delta in F_q: P1 min(lam_G, e) = min(lam_F, e) at every pair. P2 lam_F > e, delta not in {0, a}: lam_G = e, G's deep y the pair {delta/a, delta/a + 1}. P3 (the arm without the ingredient) lam_F > e, delta in {0, a} (as frozen; the code reads delta = a alone, delta = 0 being G = F): min(lam_G, 3e/2) = min(lam_F, 3e/2). P4 lam_F = e: lam_G > e iff delta/a is one of F's deep y. P5 G's deep-y count equals F's at every pair. KILL, printed: the pairs off P1 .. P5, summed; any nonzero kills. P2's arm must hold a pair at every (f, e). The headline (min(lam, 3e/2) is not the field's at q > 2) stands iff P2 holds on its arm and P3's arm prints lam_G > e. CONTROLS, read first. C1 f = 1, e = 4 and 8, delta = 1: min(lam_G, 3e/2) = min(lam_F, 3e/2) at every polynomial (wild.py's theorem). C2 at every pair G is Eisenstein and G(pi_1) = 0 mod 2^N1 in O_K (Cayley-Hamilton: the matrix of pi_1 is right). DESIGN. O_K mod 2^N1, N1 = 7, as in tame_q.Ring; G is the characteristic polynomial of multiplication by pi_1 on 1, pi, .., pi^(e-1), by Berkowitz's division-free recursion; G's b_i and d are its coefficients halved, so G is read mod 2^6, which holds every level read (at most 7e/2 + 1 < 6e). FINDINGS (copied from the printed run). - Controls: at f = 1, delta = 1, min(lam_G, 3e/2) = min(lam_F, 3e/2) at 8 polynomials (e = 4) and 14 (e = 8), lam itself moving past the cap (4: 6 -> 12, 7 -> 6); G Eisenstein with G(pi_1) = 0 at every pair, here and below. - The kill missed: 424 pairs at f = 2 (e = 2, 4, 8) and f = 3 (e = 2, 4), 344 of them with delta != 0 (the other 80 are G = F), P1..P5 off 0. P2's arm, 136 pairs, every lam_G = e with the deep pair at {delta/a, delta/a + 1} (f = 2, e = 4: lam_F = 6, the cap, goes to 4). P3's arm (delta = a), 40 pairs, keeps lam_G > e at all 40. At lam_F = e, 8 of 46 pairs go up to lam_G > e, each where delta/a is a deep y of F. - So at q > 2 one field holds Eisenstein polynomials with lam = e and with lam > e: min(lam, e) is the field's and min(lam, 3e/2) is not. That the polynomials of a field with lam > e share min(lam, 3e/2) is a proof (the least landing past 3e is the field's); the run reads it only on P3's 40 translates (e = 8: 12 <-> 13, anchor -> 12), one per polynomial: given P2, no other pair has both lam > e. RUN RECORD. 13/13 checks, 2.5 s. """ import random import sys import time from tame_q import Ring, build, fq_all, u_of, INF from wild_q import anchor_digits, designed, lam_of, landing, unit CHECKS = [] N1 = 7 def check(name, ok, detail=""): CHECKS.append(bool(ok)) tail = f" ({detail})" if detail else "" print(f" {'PASS' if ok else 'FAIL'} {name}{tail}") def charpoly(R, M): """[1, c_1, .., c_n] with det(x I - M) = sum c_k x^(n-k), over Z_q.""" n, zero = len(M), (0,) * R.f one = (1,) + (0,) * (R.f - 1) P = [one, R.zneg(M[0][0])] for r in range(1, n): t = [one, R.zneg(M[r][r])] v = [M[i][r] for i in range(r)] for _ in range(r): s = zero for j in range(r): s = R.zadd(s, R.zmul(M[r][j], v[j])) t.append(R.zneg(s)) w = [] for i in range(r): s = zero for j in range(r): s = R.zadd(s, R.zmul(M[i][j], v[j])) w.append(s) v = w newP = [] for i in range(r + 2): s = zero for j in range(min(i, r) + 1): s = R.zadd(s, R.zmul(t[i - j], P[j])) newP.append(s) P = newP return P def translate(R, delta): """G for pi_1 = pi + T(delta) pi^2; returns (G's ring mod 2^(N1-1), Eisenstein?, G(pi_1) == 0?).""" e, f = R.e, R.f pi1 = R.add(R.pi_pow(1), R.scal(R.omega(delta), R.pi_pow(2))) cols = [R.mul(pi1, R.pi_pow(j)) for j in range(e)] M = [[cols[j][i] for j in range(e)] for i in range(e)] P = charpoly(R, M) coef = {i: P[e - i] for i in range(e + 1)} ev = R.zero() for i in range(e + 1): ev = R.add(ev, R.scal(coef[i], R.power(pi1, i))) zero_ok = all(not any(c) for c in ev) eis = all(c % 2 == 0 for i in range(e) for c in coef[i]) and \ any((c // 2) % 2 for c in coef[0]) half = 2 ** (N1 - 1) b = [(0,) * f] + [tuple((c // 2) % half for c in coef[i]) for i in range(1, e)] d = tuple((-(c // 2)) % half for c in coef[0]) return Ring(2, f, e, b, d, N1 - 1), eis, zero_ok def kernel_a(R, ub): return [a for a in fq_all(2, R.f)[1:] if R.fq_pow(a, R.e) == ub][0] def deep_ys(R, a): """The y whose kernel unit 1 + T(a) pi + T(a^2 y) pi^2 lands past 3e.""" e, n, zero = R.e, R.e.bit_length() - 1, (0,) * R.f return {y for y in fq_all(2, R.f) if landing(R, unit(R, 1, a, R.fq_mul(R.fq_mul(a, a), y), zero), n) > 3 * e} def read_pair(RF, delta): """lam, deep set and a for F and its translate G by delta.""" e = RF.e RG, eis, zero_ok = translate(RF, delta) out = [] for R in (RF, RG): u = u_of(R) ub = tuple(c % 2 for c in u[0]) dbar = tuple(c % 2 for c in R.d) R0 = Ring(2, R.f, e, [None] * e, None, R.N) lam = lam_of(R, dbar, anchor_digits(R0, e, dbar)) a = kernel_a(R, ub) out.append((lam, deep_ys(R, a), a)) return out, eis, zero_ok def fq_add(x, y): return tuple((p + q) % 2 for p, q in zip(x, y)) def read_grid(rng, f, e, dbars, deltas=None): F = fq_all(2, f) R0 = Ring(2, f, e, [None] * e, None, N1) top = 2 * e + 4 tally = {k: 0 for k in ("pairs", "P1", "P2", "P3", "P4", "P5", "C2", "arm2", "arm3", "arm3_deep", "arm4", "arm4_up")} rows = [] for dbar in dbars: ref = anchor_digits(R0, e, dbar) for dep in list(range(1, 3 * e // 2 + 2)) + [INF]: RF = build(2, f, e, dbar, designed(rng, R0, F, e, dbar, ref, dep, top), N1) for delta in (deltas or F): ((lf, df, a), (lg, dg, ag)), eis, zok = read_pair(RF, delta) tally["pairs"] += 1 tally["C2"] += not (eis and zok and a == ag) cap = 3 * e // 2 tally["P1"] += min(lg, e) != min(lf, e) tally["P5"] += len(dg) != len(df) shift = R0.fq_mul(delta, R0.fq_inv(a)) if not any(delta): pass elif lf > e: if delta == a: tally["arm3"] += 1 tally["arm3_deep"] += lg > e tally["P3"] += min(lg, cap) != min(lf, cap) else: tally["arm2"] += 1 pair = {shift, fq_add(shift, (1,) + (0,) * (f - 1))} tally["P2"] += not (lg == e and dg == pair) elif lf == e: tally["arm4"] += 1 tally["arm4_up"] += lg > e tally["P4"] += (lg > e) != (shift in df) rows.append((dep, delta, lf, lg, len(df), len(dg))) return tally, rows def section_control(rng): print("C f = 1, delta = 1: wild.py's invariance, and the translate") for e in (4, 8): t, rows = read_grid(rng, 1, e, [(1,)], deltas=[(1,)]) cap = 3 * e // 2 off = [r for r in rows if min(r[2], cap) != min(r[3], cap)] check(f"C1 e = {e}: min(lam_G, 3e/2) = min(lam_F, 3e/2)", not off, f"{t['pairs']} polys, off {off[:3]}; lam_F -> lam_G " f"{[(r[2], r[3]) for r in rows]}") check(f"C2 e = {e}: G Eisenstein, G(pi_1) = 0, one kernel a", t["C2"] == 0, f"{t['C2']} off") def section_pairs(rng): print("P f = 2, 3: two polynomials of one field") total = {} for f, es, other in ((2, (2, 4, 8), (0, 1)), (3, (2, 4), (0, 1, 0))): for e in es: t0 = time.time() t, rows = read_grid(rng, f, e, [(1,) + (0,) * (f - 1), other]) for k, v in t.items(): total[k] = total.get(k, 0) + v print(f" f = {f}, e = {e}: {t['pairs']} pairs; arm P2 " f"{t['arm2']} (off {t['P2']}), arm P3 {t['arm3']} " f"(lam_G > e at {t['arm3_deep']}, off {t['P3']}), " f"lam_F = e {t['arm4']} (lam_G > e at {t['arm4_up']}, " f"off {t['P4']}); P1 off {t['P1']}, P5 off {t['P5']}, " f"C2 off {t['C2']}; {time.time() - t0:.1f} s") check(f"P2's arm is nonempty at f = {f}, e = {e}", t["arm2"] > 0, f"{t['arm2']} pairs") lams = sorted({(r[2], r[3]) for r in rows if r[2] >= e}) print(f" (lam_F, lam_G) met with lam_F >= e: {lams}") kill = sum(total[k] for k in ("P1", "P2", "P3", "P4", "P5")) print(f" KILL count (P1..P5 off, summed): {kill}") check("C2 at every pair", total["C2"] == 0, f"{total['C2']} off") check("the kill did not fire", kill == 0, f"{kill}") check("P3's arm keeps lam_G > e (the ingredient removed)", total["arm3"] > 0 and total["arm3_deep"] == total["arm3"], f"{total['arm3_deep']} of {total['arm3']}") check("P4: some lam_F = e polynomial has a translate with lam_G > e", total["arm4_up"] > 0, f"{total['arm4_up']} of {total['arm4']}") def main(): rng = random.Random(1705) t0 = time.time() section_control(rng) if not all(CHECKS): print("control red: the run is void") sys.exit(1) section_pairs(rng) print(f"{sum(CHECKS)}/{len(CHECKS)} checks passed, " f"{time.time() - t0:.1f} s") sys.exit(0 if all(CHECKS) else 1) if __name__ == "__main__": main()