"""T650 formula-layout repair checks; no website writes.
Run with SageMath: sage -python repair_checks.py
Keep document-before.json, document-candidate.json and skill-provenance.json
beside this file. The original generator remains unchanged.
"""
import json,re,sys,hashlib
from pathlib import Path
import numberdb.sage as numberdb
from sage.rings.rational_field import QQ
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
from sage.env import SAGE_VERSION
import mpmath as mp
p=Path(__file__).resolve().parent
before=json.loads((p/'document-before.json').read_text())
after=json.loads((p/'document-candidate.json').read_text())
assert list(before)==list(after)
assert list(before['Formulas'])==list(after['Formulas'])
assert all(v==after[k] for k,v in before.items() if k!='Formulas')
R=PolynomialRing(QQ,names=('k','g1','g2','h1','h2','pi','I','J'))
k,g1,g2,h1,h2,pi,I,J=R.gens(); F=R.fraction_field()
old=-F(g1**3*k*h1+g2**3*k**2*h2/2)/(4*pi**2)
new=-F(g1**3*k*h1)/(4*pi**2)-F(g2**3*k**2*h2)/(8*pi**2)
assert old==new
assert I-2*J==(I+J)-3*J
old_math=re.findall(r'\$(.*?)\$',before['Formulas']['formula-hypergeometric'],re.S)[2]
new_math=re.findall(r'\$(.*?)\$',after['Formulas']['formula-hypergeometric'],re.S)[2]
def parameters(text):
    matrices=re.findall(r'\\begin\{matrix\}(.*?)\\end\{matrix\}',text)
    return [re.sub(r'\\frac(\d)(\d)',r'\1/\2',s) for s in matrices]
assert parameters(old_math)==parameters(new_math)==[r'1/3,1/3,1/3\\2/3,4/3',r'2/3,2/3,2/3\\4/3,5/3']
R=PolynomialRing(QQ,names=('t','X'));t,X=R.gens();F=R.fraction_field()
a2=-27*t**2;a4=216*t**3*(t-27);a6=-432*t**4*(t-27)**2
b2=4*a2;b4=2*a4;b6=4*a6;b8=4*a2*a6-a4**2
c4=b2**2-24*b4;delta=-b2**2*b8-8*b4**3-27*b6**2+9*b2*b4*b6
assert F(c4**3)/delta==F(t*(t+216)**3)/(t-27)**3
checks=[]
for key in ['24','18-6*sqrt(3)']:
    vals=[]
    for working in [135,185]:
        with mp.workdps(working):
            # Rebuild every radical and cube root at each working precision.
            t=mp.mpf(24) if key=='24' else 18-6*mp.sqrt(3)
            k=mp.root(t,3);a=mp.mpf(1)/3;b=mp.mpf(2)/3
            h1=mp.hyper([a,a,a],[b,1+a],t/27)
            h2=mp.hyper([b,b,b],[2*b,1+b],t/27)
            old=-(mp.gamma(a)**3*k*h1+mp.gamma(b)**3*k**2*h2/2)/(4*mp.pi**2)
            new=-mp.gamma(a)**3*k*h1/(4*mp.pi**2)-mp.gamma(b)**3*k**2*h2/(8*mp.pi**2)
            assert mp.isfinite(old) and mp.isfinite(new)
            assert abs(old-new)<mp.power(10,-working+5)
            vals.append(new)
    with mp.workdps(210):
        stored=before['Numbers'][key]['number']; ulp=mp.power(10,-len(stored.split('.')[1]))
        error=abs(vals[1]-mp.mpf(stored))/ulp
        agreement=-mp.log10(abs(vals[1]-vals[0])/abs(vals[1]))
        assert error<1 and agreement>125
        checks.append({'t':key,'midpoint_error_ulps':mp.nstr(error,15),'agreement_digits':mp.nstr(agreement,15)})
print(json.dumps({'table':'T650','scope':'Layout-only formula repair; exact symbolic regrouping plus two numerical controls, not a new certification of all ten values.','skill_provenance':json.loads((p/'skill-provenance.json').read_text()),'sage':SAGE_VERSION,'python':sys.version.split()[0],'mpmath':mp.__version__,'unchanged_entries':len(before['Numbers']),'unchanged_nonformula_sections':True,'exact_hypergeometric_coefficients_match':True,'exact_hypergeometric_parameters_match':True,'curve_j_invariant_match':True,'numerical_checks':checks,'rigour':'heuristic (agreement-checked), unchanged'},indent=2))
