"""Independent checks for T680. Run: sage -python checks.py.

At smooth fibers the independent method differentiates
  H(t,z)=5F4(1,alpha1+t,...,alpha4+t;1+t,1+t,1+t,1+t;z)
with respect to t at zero. H(0,z)=F(z), dH/dt(0,z)=G(z).
At the conifold a gamma-ratio asymptotic tail and its parameter derivative
are summed with Hurwitz zeta. A telescoping case controls both F and G.
The smooth method uses mpmath hypergeometric continuation and parameter derivatives,
not the ODE or conifold matching in numerics.py. No certification is claimed.
Rank-two elliptic nome values control the first logarithmic normalization and
all three smooth paths, before the rank-four computations are trusted.
"""
import numberdb.sage as numberdb
from sage.rings.rational_field import QQ
from mpmath import mp
import mpmath,math,json,time
from generate import CanonicalCoordinates,components,scale
from numerics import fg
from tail_check import conifold_tail

# Deliberately explicit fractions, independent of the cyclotomic parser.
ALPHA={
 '2.2.2.2':('1/2','1/2','1/2','1/2'), '2.2.3':('1/2','1/2','1/3','2/3'),
 '2.2.4':('1/2','1/2','1/4','3/4'), '2.2.6':('1/2','1/2','1/6','5/6'),
 '3.3':('1/3','2/3','1/3','2/3'), '3.4':('1/3','2/3','1/4','3/4'),
 '3.6':('1/3','2/3','1/6','5/6'), '4.4':('1/4','3/4','1/4','3/4'),
 '4.6':('1/4','3/4','1/6','5/6'), '6.6':('1/6','5/6','1/6','5/6'),
 '5':('1/5','2/5','3/5','4/5'), '8':('1/8','3/8','5/8','7/8'),
 '10':('1/10','3/10','7/10','9/10'), '12':('1/12','5/12','7/12','11/12')}
SCALES={'2.2.2.2':256,'2.2.3':432,'2.2.4':1024,'2.2.6':6912,'3.3':729,
 '3.4':1728,'3.6':11664,'4.4':4096,'4.6':27648,'6.6':186624,
 '5':3125,'8':65536,'10':800000,'12':2985984}


def independent(template,z,working=150):
    with mp.workdps(working):
        a=[mp.mpf(v) for v in ALPHA[template]];x=mp.mpf(z)
        H=lambda t:mp.hyper([1]+[v+t for v in a],[1+t]*4,x)
        if x==1:F,G=conifold_tail(a)
        else:F=H(0);G=mp.diff(H,0)
        if x>1:F=mp.conj(F);G=mp.conj(G)
        return F,G,x*mp.exp(G/F)


def close(a,b,digits,label):
    err=abs(a-b)/max(abs(b),mp.mpf('0.01'))
    assert mp.isfinite(a) and mp.isfinite(b),(label,'nonfinite')
    assert err<mp.mpf(10)**(-digits),(label,mp.nstr(err,20))
    return float(-mp.log10(err)) if err else 999.0


def main():
    start=time.monotonic();mp.dps=205
    from sage.env import SAGE_VERSION
    print(json.dumps({'versions':{'Sage':SAGE_VERSION,'mpmath':mpmath.__version__},
       'skill_manifest':'agents/runs/20261102T145807Z-build-skills/manifest.json',
       'skill_sha256':'a2b28d9953264d7b0ca62663785c2952190c5be6d6d3597fd695d9a54d606278'}),flush=True)
    # External known answers test the algorithm, not just F(0)=1 and G(0)=0.
    for z,ref in [(mp.mpf('0.5'),16*mp.exp(-mp.pi)),(-1,-16*mp.exp(-mp.pi)),(2,16j*mp.exp(-mp.pi/2))]:
        f,g=fg([mp.mpf('0.5')]*2,z,150)
        q=z*mp.exp(g/f)
        control=close(q,ref,125,'elliptic nome control')
        print(json.dumps({'control':'rank-two elliptic canonical coordinate','z':str(z),'agreement_digits':control}),flush=True)
    with mp.workdps(160):
        f,g=conifold_tail([mp.mpf(1)]*2,[mp.mpf(1),mp.mpf(3)])
        control=min(close(f,mp.mpf(2),125,'telescoping F'),close(g,mp.mpf(1),125,'telescoping G'))
    print(json.dumps({'control':'telescoping conifold F=2 and G=1','agreement_digits':control}),flush=True)
    assert {t:scale(t) for t in ALPHA}==SCALES
    count=0
    for template in ALPHA:
        for z in ('1','1/2','-1','2'):
            F,G,Q=independent(template,z,140)
            low=components(template,z,140);high=components(template,z,190)
            hf,hg=mp.mpc(*high[2:4]),mp.mpc(*high[4:6])
            hq,lq=mp.mpc(*high[:2]),mp.mpc(*low[:2])
            dig=min(close(hf,F,120,(template,z,'F')),close(hg,G,120,(template,z,'G')),
                    close(hq,Q,120,(template,z,'Q')))
            stability=close(hq,lq,125,(template,z,'working precision'))
            # Scaling is checked against an independently enumerated integer list.
            close(hq/scale(template),Q/SCALES[template],120,(template,z,'integral'))
            if z!='2': assert Q.imag==0 and hq.imag==0
            count+=1
            print(json.dumps({'template':template,'z':z,'scale':scale(template),
                'independent_re':mp.nstr(Q.real,145),'independent_im':mp.nstr(Q.imag,145),
                'F_re':mp.nstr(F.real,145),'F_im':mp.nstr(F.imag,145),
                'G_re':mp.nstr(G.real,145),'G_im':mp.nstr(G.imag,145),
                'generator_re':high[0],'generator_im':high[1],
                'agreement_digits':dig,'stability_digits':stability,'abs_F':mp.nstr(abs(hf),15)}),flush=True)
    print(json.dumps({'passed':True,'fibers':count,'entries':2*count,'seconds':time.monotonic()-start}),flush=True)

if __name__=='__main__':main()
