"""Check T528 without changing it.

Run with SageMath and numberdb installed:
  sage -python repair_checks.py [T528-document.json]
Without a document argument, read T528 through the NumberDB API; an unpublished
T528 requires NUMBERDB_API_KEY. NUMBERDB_KEY_FROM_STDIN=1 reads that key on stdin.
This check uses Janson (2007), equations (24)-(25), independently of generate.py.
"""
import hashlib, json, os, sys
from decimal import Decimal
from fractions import Fraction
from math import comb, factorial
from pathlib import Path
import numberdb.sage as numberdb
from sage.rings.rational_field import QQ
from sage.rings.real_arb import RealBallField
from sage.env import SAGE_VERSION

if os.environ.get('NUMBERDB_KEY_FROM_STDIN') == '1':
    token=sys.stdin.read().strip()
    if '=' in token and token.split('=',1)[0].isupper():
        token=token.split('=',1)[1].strip().strip('\'"')
    os.environ['NUMBERDB_API_KEY']=token
if len(sys.argv)>1:
    doc=json.loads(Path(sys.argv[1]).read_text())
else:
    doc=numberdb.table('T528')
R=RealBallField(768)
def rational(x):
    return QQ(x.numerator)/QQ(x.denominator)
d={1:Fraction(5,36)}
for k in range(1,11):
    d[k+1]=d[k]+sum((d[j]*d[k-j]/((k+1)*comb(k,j)) for j in range(1,k)),Fraction(0))
assert [d[k] for k in [1,2,3]]==[Fraction(5,36),Fraction(5,36),Fraction(1105,7776)]
factors={0:Fraction(1,4)}
for k in range(1,12):
    m=k//2
    if k%2:
        factors[k]=Fraction(2**m*3**k*factorial(2*m)*factorial(3*m+1),factorial(6*m+2))*d[k]
    else:
        factors[k]=Fraction(3**k*factorial(2*m-1),2**(5*m)*factorial(3*m-1))*d[k]
assert [factors[k] for k in range(4)]==[Fraction(1,4),Fraction(5,24),Fraction(5,256),Fraction(221,24192)]
assert list(doc['Numbers'])==[str(k) for k in range(12)]
rows=[]
for k in range(12):
    q=factors[k]; stored=doc['Numbers'][str(k)]
    value=R(rational(q)) if k%2 else R(rational(q))*(2*R.pi()).sqrt()
    assert value.is_finite() and value.accuracy()>750
    row={'k':k,'factor':str(q),'accurate_bits':int(value.accuracy())}
    if k%2:
        assert Fraction(stored)==q
        row['exact_match']=True
    else:
        decimal=Decimal(stored); centre=Fraction(decimal);ulp=Fraction(10)**decimal.as_tuple().exponent
        assert len(decimal.as_tuple().digits)==100
        assert value>R(rational(centre-ulp)) and value<R(rational(centre+ulp))
        displacement=(value-R(rational(centre)))/R(rational(ulp))
        row.update(significant_digits=100,contained=True,error_in_ulps=str(displacement),ball=str(value))
    if k:
        direct=(R(2)**(QQ(1-5*k)/2)*R(3)**k*R.pi().sqrt()
                *factorial(k-1)/R(QQ(3*k)/2).gamma()*R(rational(d[k])))
        assert direct.is_finite() and direct.accuracy()>740 and direct.overlaps(value)
        row['direct_gamma_agrees']=True
    rows.append(row)
result={'table':'T528','run':'20261026T212537Z','instruction_manifest':'agents/runs/20261026T212537Z-repair-skills/manifest.json','instruction_manifest_sha256':'d03b756eaa1cd22ce39c8cee78fb3a44b052146786d6371925ac7bc9dec564f3','skill_sha256':'b4d51ded0d52cfe3dcc0859de0845c3879b0c2363273ba7e809a7e06ded40b18','method':'Independent rational d recurrence, exact Gamma simplifications, 768-bit Arb; Janson https://arxiv.org/pdf/0704.2289 equations (24)-(25), Table 1 controls. No approximate input arguments.','sage':SAGE_VERSION,'python':sys.version.split()[0],'numberdb':getattr(numberdb,'__version__','unknown'),'working_bits':768,'rows_checked':len(rows),'controls':'d_1,d_2,d_3 and rho_0,rho_1,rho_2,rho_3 factors matched Table 1','numbers_sha256':hashlib.sha256(json.dumps(doc['Numbers'],ensure_ascii=False,separators=(',',':')).encode()).hexdigest(),'rows':rows,'all_passed':True,'scope':'Repair numerical verification only; not an independent argument-selection verdict.'}
print(json.dumps(result,indent=2))
