repair-checks.py

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

4158 bytes, as of the version from 2026-11-02 17:55 (current). Recorded here, not run.

"""T682 Programs repair checks. Run: sage -python repair-checks.py.

Place generate.py, repair-program.py and repair-before.json alongside this file.
The root-difference generator remains unchanged. These checks compare it with
the self-contained cotangent/Hurwitz snippet; both use the Arb backend.
No credential or website write is needed. The entire 98-entry saved document
is checked, including interval containment and agreement at 640 working bits.
"""
import json
import sys
import hashlib
import importlib.util
from pathlib import Path
from decimal import Decimal
from fractions import Fraction

import numberdb.sage as numberdb
from sage.rings.rational_field import QQ
from sage.rings.real_arb import RealBallField
from sage.rings.real_mpfi import RealIntervalField
from sage.env import SAGE_VERSION
from generate import moment as root_difference, GeometricSumMahler

base = Path(__file__).resolve().parent
spec = importlib.util.spec_from_file_location('repair_program', base/'repair-program.py')
program = importlib.util.module_from_spec(spec)
spec.loader.exec_module(program)
doc = json.loads((base/'repair-before.json').read_text())
R = RealBallField(640)
I = RealIntervalField(700)

def validate_ball(value):
    assert value.is_finite() and not value.contains_zero()
    assert value.accuracy() >= 334
    return I(value)

def rational(value):
    return QQ(value.numerator)/value.denominator

def saved_interval(text):
    value = Decimal(text)
    unit = Fraction(10)**value.as_tuple().exponent
    center = Fraction(value)
    return I(rational(center-unit), rational(center+unit)), rational(center), rational(unit)

controls = {}
for k, expected in [(2, R.pi()**2/12), (3, -QQ(3)/2*R(3).zeta())]:
    actual = program.moment(2,k)
    validate_ball(actual)
    assert actual.overlaps(expected)
    controls[str(k)] = str(actual)

block = doc['Numbers']
if isinstance(block,list):
    entries = [(int(row['params']['n']),int(row['params']['k']),row['number']) for row in block]
else:
    entries = [(int(n),int(k),v['number'] if isinstance(v,dict) else v)
               for n,group in block.items() for k,v in group.items()]
assert [(n,k) for n,k,_ in entries] == [(p['n'],p['k']) for p in GeometricSumMahler().enumerate()]
results=[]
for n,k,text in entries:
    value = program.moment(n,k)
    high = program.moment(n,k,bits=640)
    other = root_difference(n,k,digits=130)
    stored,center,unit = saved_interval(text)
    for enclosure in (value,high,other):
        interval = validate_ball(enclosure)
        assert stored.lower() < interval.lower() and interval.upper() < stored.upper(), (n,k)
    assert value.overlaps(other) and value.overlaps(high), (n,k)
    results.append({'n':n,'k':k,'ball':str(value),'accuracy_bits':int(value.accuracy()),
                    'radius':str(value.rad()),'midpoint_error_ulps':str(abs(R(value.mid())-center)/unit)})
# One new length confirms that the program is usable beyond the table's prefix;
# this computes a check only and adds no entries.
for k in (2,3):
    value = program.moment(51,k)
    other = root_difference(51,k,digits=130)
    validate_ball(value);validate_ball(other)
    assert value.overlaps(other)

print(json.dumps({'table':'T682','stage':'repair','skill_manifest':
 'agents/runs/20261102T175113Z-repair-skills/manifest.json',
 'skill_sha256':{s:'a2b28d9953264d7b0ca62663785c2952190c5be6d6d3597fd695d9a54d606278' for s in ('local','live')},
 'sage_version':SAGE_VERSION,'python_version':sys.version,
 'working_bits':512,'higher_working_bits':640,'checked_stored_entries':len(results),
 'minimum_accuracy_bits':min(r['accuracy_bits'] for r in results),'controls':controls,
 'extra_length_checked':51,'values_changed':False,
 'method':'Cotangent/Hurwitz formula vs unchanged root-difference/polylogarithm generator; shared Arb backend. Exact rational arguments propagated through balls. All three enclosures strictly contained in every stored decimal interval.',
 'files_sha256':{name:hashlib.sha256((base/name).read_bytes()).hexdigest() for name in ('repair-program.py','generate.py','repair-before.json')},
 'example':str(program.moment(6,3)),'results':results},indent=2))