"""splitpart.py -- which split terms carry the rise of PI_1 - PI_k0? QUESTION. Over the real fields with the class k0 to |D| <= 48000, the split places carry the rise of d = PI_1 - PI_k0 with log D (localtype.py: +0.258 of +0.290 per unit at the cut 250, each field weighted by its h+/2 odd characters). Which split terms carry it: the first powers or the higher, and inside Lagrange's zone p < sqrt(D)/2 or outside it? THE DERIVATION (before code). A split P, Pbar in narrow classes c, c^-1 adds (2/e)([c^e = 1] - [c^e = k0]) at each power with p^e < x. (a) e = 1, S1: a uniform c has mean 0 here for every field, so a slope in S1 is a bias of 1 over k0. TRANSPLANT: the uniform c at fixed p as D grows is Chebotarev carried from p -> infinity. (b) e >= 2, S2: a uniform c gives E2 = sum (2/e)(#{g: g^e = 1} - #{g: g^e = k0})/h+, 0 at odd e (k0 = k0^e), 1/|Cl+^2| at e = 2 when k0 is not a square and 0 when it is. (c) Lagrange (known): |m| < sqrt(D)/2 represented primitively by the principal form leads a reduced form of its cycle. So for split p < sqrt(D)/2, P in 1 iff +p leads a form in the cycle of (1, b0, .), P in k0 iff -p does. (d) S1 splits at sqrt(D)/2 into S1lo (the zone) and S1hi. At 250 the zone's prime count grows with D to 48000. PREDICTIONS, frozen before the engine (cut 250, weighted h+/2). C1 Lagrange on the engine: [P in 1] = [+p leads a principal-cycle form], [P in k0] = [-p does], over every split p < sqrt(D)/2; 0 exceptions. C2 S1lo + S1hi + S2 = d_S per field to 1e-12; s(S1lo + c log D) reads s(S1lo) + c to 1e-9, c = 0.29. P1 s(S2) < +0.05, and the mean of S2 - E2 within 0.1 of 0. P2 the per-prime bias inside the zone, mean of S1lo / #zone primes split, is positive in every |D| band; outside it, within 0.02 of 0. KILL ZONE (printed "S1lo share of s(d_S) at 250"): fires if s(S1lo) < 0.5 s(d_S); Lagrange's zone then does not carry the rise. At 10^4 the split prints, no verdict. FINDINGS, the 10323 real fields with k0 to |D| <= 48000, weighted h+/2. F0 CONTROLS. Every principal-cycle form lies in class 1 (by construction); Lagrange read on the engine with 0 exceptions, so +p in the cycle is P in 1 and -p is P in k0; the parts sum to d_S to 1.42e-14; the planted c log D reads c to the tenth digit. P2's "mean of S1lo / #zone primes" is read in the engine as a ratio of means, Sum S1 / Sum primes, both weighted h+/2; a mean of per-field ratios is undefined at a field with no zone prime. F1 KILL ZONE FIRED, and P2 MISSED with the sign reversed: at 250 s(d_S) +0.2581 = S1lo -0.0657 +- 0.0206 + S1hi +0.4204 +- 0.0398 + S2 -0.0966 +- 0.0185 (E2 -0.1471). The first powers lean to k0, not to 1, inside the zone and outside it, and the lean fades with D on both sides: per split prime, Sum S1 / Sum primes reads -0.1374, -0.0750, -0.0707, -0.0542, -0.0506 by band inside the zone and -0.0784, -0.0445, -0.0330, -0.0314, -0.0234 outside. The zone holds 3.26 to 11.83 split primes by band: as sqrt(D)/2 rises, primes cross from S1hi into S1lo, each carrying a negative lean, so S1lo reads -0.448, -0.394, -0.499, -0.521, -0.598 by band and S1hi -1.740 to -0.320; the S1lo, S1hi split tracks the zone's moving edge. At 10^4: +0.8078 = -0.0657 + 1.5815 - 0.7079. F2 P1 half held: s(S2) -0.0966 < 0.05, but S2 sits below the uniform class's E2 by 0.3891 at 250 (1.2183 at 10^4); band means S2 +1.299 to +0.980 against E2 +1.810 to +1.334. d_S by band -0.890, -0.152, -0.023, +0.006, +0.061: the uniform class's value of d_S is E2, which d_S approaches from below. Not derived: why the first powers lean to k0, and why the lean relaxes as D grows at a fixed cut. TIERS: F0 a property (Lagrange, known); F1, F2 observations over this population. RUN RECORD. A rehearsal at --d 3000 (3.0 s). Full: 5/8, the three misses P1's second half and P2's two, 51.4 s, peak commit 55.8 MB under a memory guard (512 MB). P1's second half and P2 are now prints, since a verdict is read, never asserted, and a missed one is the finding: 5/5, 51.5 s, every printed number unchanged. """ import os os.environ.setdefault("OPENBLAS_NUM_THREADS", "1") import sys import time HERE = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, HERE) import numpy as np # noqa: E402 import principal as P # noqa: E402 import localtype as L # noqa: E402 from module_law import check, section, CHECKS # noqa: E402 D_MAX = 48000 if "--d" in sys.argv: D_MAX = int(sys.argv[sys.argv.index("--d") + 1]) J250, J10K = 0, len(P.CUTS) - 1 def split_terms(G, avals): """Per cut: S1lo, S1hi, S2, E2, the zone's and the outside's split prime counts; and the Lagrange exceptions.""" nc = len(P.CUTS) out = np.zeros((6, nc)) bad = 0 pw = {} def npow(e): if e not in pw: vals = [G.power(g, e) for g in range(G.h)] pw[e] = (vals.count(G.e), vals.count(G.k0)) return pw[e] for p in P.SMALL: if P.kron(G.D, p) != 1: continue c = G.place(p) cb = G.inv(c) zone = 4 * p * p < G.D j = P.bucket(p) v = 2 * ((c == G.e) - (c == G.k0)) out[0 if zone else 1, j:] += v out[4 if zone else 5, j:] += 1 if zone: bad += ((c == G.e) != (p in avals)) + \ ((c == G.k0) != (-p in avals)) e, pe = 2, p * p while pe < P.TOP: j = P.bucket(pe) for g in (c, cb): ge = G.power(g, e) out[2, j:] += ((ge == G.e) - (ge == G.k0)) / e n1, nk = npow(e) out[3, j:] += 2 * (n1 - nk) / (e * G.h) e, pe = e + 1, pe * p return out, bad def read(): rows, bad, worst, offcyc = [], 0, 0.0, 0 for D in range(5, D_MAX + 1): if not P.fundamental(D): continue G = P.Group(D) if G.h < 2 or G.k0 == G.e: continue cyc = P.Real(D).cycle(G.one_form) offcyc += sum(G.idx[f] != G.e for f in cyc) t, b = split_terms(G, {f[0] for f in cyc}) bad += b dS = L.parts(G)[2] worst = max(worst, float(np.max(np.abs(t[0] + t[1] + t[2] - dS)))) rows.append((D, G.h // 2, t, dS)) return rows, bad, worst, offcyc def main(): t0 = time.time() section("A LAGRANGE AND THE SPLIT") rows, bad, worst, offcyc = read() n = len(rows) Ds = np.array([r[0] for r in rows]) x = np.log(Ds.astype(float)) wc = np.array([r[1] for r in rows], float) print(f" {n} real fields with k0, |D| <= {D_MAX}" f" [{time.time() - t0:.0f} s]") check("the principal cycle's forms all lie in class 1", offcyc == 0, f"{offcyc} off") check("C1 Lagrange: in the zone P in 1 / k0 iff +p / -p leads a" " principal-cycle form", bad == 0, f"{bad} exceptions") check("C2 S1lo + S1hi + S2 = d_S per field", worst < 1e-12, f"worst {worst:.2e}") def col(k, j): return np.array([r[2][k, j] for r in rows]) s1lo = col(0, J250) sa = L.wslope(x, s1lo, wc)[0] sb = L.wslope(x, s1lo + 0.29 * x, wc)[0] check("C2 s(S1lo + c log D) reads s(S1lo) + c", abs(sb - sa - 0.29) < 1e-9, f"{sb - sa:+.10f}") if not all(CHECKS): print("CONTROL FAILED: the kill is not read.") raise SystemExit(1) section("B THE SLOPES, WEIGHTED h+/2") for j in (J250, J10K): dS = np.array([r[3][j] for r in rows]) s, se = L.wslope(x, dS, wc) parts = [L.wslope(x, col(k, j), wc) for k in range(4)] print(f" cut {P.CUTS[j]:5d}: s(d_S) {s:+.4f} +- {se:.4f} =" f" S1lo {parts[0][0]:+.4f} +- {parts[0][1]:.4f}" f" + S1hi {parts[1][0]:+.4f} +- {parts[1][1]:.4f}" f" + S2 {parts[2][0]:+.4f} +- {parts[2][1]:.4f}" f" (E2 {parts[3][0]:+.4f})") resid = np.sum(wc * (col(2, j) - col(3, j))) / np.sum(wc) print(f" mean S2 - E2 {resid:+.4f}") if j == J250: check("P1 s(S2) < +0.05", parts[2][0] < 0.05, f"{parts[2][0]:+.4f}") print(f" P1 mean S2 - E2 within 0.1 of 0: " f"{'HELD' if abs(resid) <= 0.1 else 'MISSED'}" f" ({resid:+.4f})") share = parts[0][0] / s print(f" S1lo share of s(d_S) at 250: {share:.3f}") print(f" KILL ZONE (share < 0.5): " f"{'FIRED' if share < 0.5 else 'MISSED'}") section("C BY |D| BAND, WEIGHTED h+/2: PER-PRIME BIAS, MEANS") print(" band n zone primes bias in bias out" " S1lo S1hi S2 E2 d_S") p2in, p2out = [], [] for i, (lo, hi) in enumerate(L.BANDS): m = np.array([L.band_of(int(D)) == i for D in Ds]) w = wc[m] def mean(v): return np.sum(w * v[m]) / np.sum(w) bin_ = np.sum(w * col(0, J250)[m]) / max(np.sum(w * col(4, J250)[m]), 1e-300) bout = np.sum(w * col(1, J250)[m]) / np.sum(w * col(5, J250)[m]) p2in.append(bin_) p2out.append(bout) dS = np.array([r[3][J250] for r in rows]) print(f" {lo:5d}-{min(hi, D_MAX):5d} {int(m.sum()):5d}" f" {mean(col(4, J250)):6.2f} {bin_:+.4f} {bout:+.4f}" f" {mean(col(0, J250)):+.3f} {mean(col(1, J250)):+.3f}" f" {mean(col(2, J250)):+.3f} {mean(col(3, J250)):+.3f}" f" {mean(dS):+.3f}") print(f" P2 the per-prime bias in the zone is positive in every band: " f"{'HELD' if all(v > 0 for v in p2in) else 'MISSED'}") print(f" P2 outside the zone within 0.02 of 0: " f"{'HELD' if all(abs(v) <= 0.02 for v in p2out) else 'MISSED'}") print(f"\n{sum(CHECKS)}/{len(CHECKS)} checks PASS," f" {time.time() - t0:.1f} s") raise SystemExit(0 if all(CHECKS) else 1) if __name__ == "__main__": main()