#!/usr/bin/env python3 """Independent standard-library-only checker for powered-kernel seed residues. Uses logarithmic derivatives and harmonic/factorial prefix sums, not FLINT polynomial products or reflected jets. Every pole is computed separately. """ import argparse import json import math from pathlib import Path import time def is_prime(p): return p>=2 and all(p%d for d in range(2,math.isqrt(p)+1)) def check(record): started=time.monotonic() n,q,p=record['n'],record['power'],record['prime'] bound=record['zero_bound'];orders=record['pole_orders'];cap=max(orders)*q # Reconstruct the published profile from its defining parameters, rather # than trusting the input record's pole orders or endpoint convention. assert n==480 and record['rn']==560 and bound==1599 assert record['trim_outer_zero_pair'] is True and record['derivative_order']==2*q kappas=list(range(1,9))+list(range(10,47,2)) expected_orders=[8+sum(3*k<=j<=480-3*k for k in kappas) for j in range(481)] assert orders==expected_orders assert is_prime(p) and p>max(n+bound,2*n,cap+2*q) assert n%2==0 and bound%2==1 and orders==orders[::-1] blocks=[];previous=0 for a in range(n//2+1): weight=orders[a]-previous assert weight>=0 if weight:blocks.append((a,n-a,weight)) previous=orders[a] def prefixes(values,maximum): table=[[0]*(len(values)+1) for _ in range(maximum+1)] for j,value in enumerate(values,1): inv=pow(value,-1,p);power=1 for m in range(1,maximum+1): power=power*inv%p table[m][j]=(table[m][j-1]+power)%p return table positive=prefixes(list(range(1,n+1)),cap) odd_count=(n+bound+1)//2 odd=prefixes(list(range(1,2*odd_count,2)),cap) factorial=[1] for j in range(1,n+1):factorial.append(factorial[-1]*j%p) odd_factorial=[1] for j in range(odd_count):odd_factorial.append(odd_factorial[-1]*(2*j+1)%p) half_powers=[1] for j in range(cap):half_powers.append(half_powers[-1]*pow(2,-1,p)%p) maximum_s=cap+2*q assert set(record['even_beta_coefficients'])==set(map(str,range(2*q+2,maximum_s+1,2))) tails=[[0]*(n+1) for _ in range(maximum_s+1)] for j in range(n): inv=pow(2*j+1,-1,p);power=1 for s in range(1,maximum_s+1): power=power*inv%p tails[s][j+1]=(tails[s][j]+(-1)**j*power)%p constant=0;beta=[0]*(maximum_s+1) for k in range(n+1): a=n-2*k;size=q*orders[k];shift=q if a==0 else 0 pos=(a+bound+1)//2;neg=(bound-a+1)//2 numerator=pow((-1)**neg*odd_factorial[pos]*odd_factorial[neg]%p,3*q,p) if a:numerator=numerator*pow(a,q,p)%p denominator=1 for left,right,multiplicity in blocks: block_value=1 if right>k: lo=max(left-k,1);hi=right-k block_value=block_value*factorial[hi]*pow(factorial[lo-1],-1,p)%p if left