readback_checks.py

back to table · edit · history · where entries came from · files · download

3757 bytes, as of the version from 2026-10-30 01:46. Recorded here, not run.

"""Check every stored T614 mass interval and companion radius after readback.
Run: sage -python readback_checks.py, with NUMBERDB_API_KEY for the draft.
The campaign may pipe the key with NUMBERDB_KEY_FROM_STDIN=1.
Requires generate.py, solver.py, numerical-evidence.json,
independent-evidence.json and skills-evidence.json beside this script.
"""
import os,sys,json,pathlib
from decimal import Decimal,localcontext
import numberdb.sage as numberdb
from sage.rings.real_arb import RealBallField
from generate import INDICES


def decimal_interval(s):
    d=Decimal(s);ulp=Decimal(10)**d.as_tuple().exponent
    return d-ulp,d+ulp,ulp


def main():
    if os.environ.get('NUMBERDB_KEY_FROM_STDIN')=='1':
        token=sys.stdin.read().strip()
        if '=' in token and token.split('=',1)[0].replace('_','').isalnum():
            token=token.split('=',1)[1].strip().strip('\"\'')
        os.environ['NUMBERDB_API_KEY']=token
    d=numberdb.table('T614');radii=numberdb.table('T613')
    assert d['Title']=='Mass constants of Lane–Emden polytropes'
    assert d['Display properties']['number-header']==r'$\mu_n$'
    assert d['Parameters']['n']['type']=='Q'
    assert list(d['Numbers'])==list(INDICES)
    p=pathlib.Path(__file__).parent
    computed=json.loads((p/'numerical-evidence.json').read_text())['values']
    independent=json.loads((p/'independent-evidence.json').read_text())
    assert json.loads((p/'skills-evidence.json').read_text())['versions'][0]['sha256']=='28ecbeeccb0c5e5d6eb541b5a5b0f88aec47b154374d909085116d34f5629199'
    report={'table':'T614','skill_manifest':'agents/runs/20261030T013608Z-build-skills/manifest.json','rows':{}}
    B=RealBallField(700)
    with localcontext() as ctx:
        ctx.prec=250
        for n,item in d['Numbers'].items():
            s=item['number'] if isinstance(item,dict) else item
            lo,hi,ulp=decimal_interval(s);center=Decimal(s)
            assert len(center.as_tuple().digits)>=100,(n,'too few digits')
            if n in ('0','1','5'):
                target=2*B(6).sqrt() if n=='0' else (B.pi() if n=='1' else B(3).sqrt())
                assert target.is_finite() and B(target.rad())<B('1e-190')
                assert B(str(lo))<target and target<B(str(hi)),n
            else:
                for precision in ('150','210'):
                    assert lo<Decimal(computed[n][precision]['mass'])<hi,(n,precision)
            independent_error=abs(Decimal(independent[n]['value'])-center)/abs(center)
            assert independent_error<Decimal('1e-40'),(n,independent_error)
            row={'stored_interval_pass':True,'significant_digits':len(center.as_tuple().digits),'independent_relative_difference':str(independent_error)}
            if n!='5':
                rr=radii['Numbers'][n];rs=rr['number'] if isinstance(rr,dict) else rr
                rlo,rhi,_=decimal_interval(rs)
                assert rlo<Decimal(computed[n]['210']['radius'])<rhi,('companion',n)
                xi=Decimal(independent[n]['radius']);J=Decimal(independent[n]['pressure_integral'])
                nn=Decimal(n.split('/')[0])/(Decimal(n.split('/')[1]) if '/' in n else 1)
                virial=(nn+1)*center*center/((5-nn)*xi)
                error=abs(J-virial)/abs(virial)
                assert error<Decimal('1e-40'),('stored virial',n,error)
                row['companion_radius_interval_pass']=True
                row['stored_virial_relative_error']=str(error)
            report['rows'][n]=row
        # Deliberately shifted mass fails the decimal-interval predicate.
        anchor=Decimal(d['Numbers']['1']['number'])
        lo,hi,ulp=decimal_interval(str(anchor))
        assert not lo<anchor+100*ulp<hi
    print('DATA '+json.dumps(report))
if __name__=='__main__':main()