checks.py

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

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

"""Independent integral, elliptic-period and readback checks for numberdb.org/T665.

    sage -python checks.py
    sage -python checks.py --stored

For the second command set NUMBERDB_API_KEY while the table is private.
Attach check.py and generate.py alongside this file. Local checks use the
campaign's unchanged exactness, names_its_rings and measure helpers. The
independent positive-series integral uses no beta or gamma function.
All numerical output is JSON on stdout, suitable for preserving as evidence.
"""
import os
import sys
import json
import math
from fractions import Fraction
from functools import lru_cache
from pathlib import Path

import numberdb.sage as numberdb
from sage.rings.real_arb import RealBallField
from sage.rings.complex_arb import ComplexBallField
from sage.rings.rational_field import QQ
from sage.env import SAGE_VERSION
from numberdb._write import to_text
from numberdb._compare import _complex_parts, _claim, _as_fraction, digits_of
from numberdb._generate import _current_entries
from check import exactness, measure, names_its_rings
from generate import FermatPeriods

R = RealBallField(500)
C = ComplexBallField(500)
TERMS = 450


def half_integral(x, y):
    x, y = R(x), R(y)
    term = R(2)**(-x) / x
    total = R(0)
    for k in range(TERMS):
        total += term
        term *= (k + 1 - y) * (x + k) / ((k + 1) * (x + k + 1) * 2)
    return total.add_error(2 * term)


@lru_cache(maxsize=None)
def euler_integral(x, y):
    assert 0 < x <= 1 and 0 < y <= 1
    return half_integral(x, y) + half_integral(y, x)


def independent_period(key):
    N, a, b = key
    x, y = QQ(a) / N, QQ(b) / N
    integral = euler_integral(x, y) / N
    angle = R.pi() * R(QQ(a + b) / N)
    scale = -4 * (R.pi() * R(x)).sin() * (R.pi() * R(y)).sin() * integral
    real = R(0) if 2 * (a + b) == N else scale * angle.cos()
    return C(real, scale * angle.sin())


def elliptic_k_agm(m):
    a, b = R(1), (1 - R(m)).sqrt()
    for _ in range(12):
        a, b = (a + b) / 2, (a * b).sqrt()
    lo, hi = R.pi() / (2 * a), R.pi() / (2 * b)
    return ((lo + hi) / 2).add_error(abs(hi - lo) / 2)


def ball_fraction(f):
    f = Fraction(f)
    return R(QQ(f.numerator) / f.denominator)


def component_claim(text):
    exact = _as_fraction(text)
    if exact is not None:
        return exact, exact
    claim = _claim(text)
    assert claim is not None, text
    mid, rad = map(Fraction, claim)
    return mid - rad, mid + rad


def claim_ball(text):
    lo, hi = component_claim(text)
    return ball_fraction((lo + hi) / 2).add_error(ball_fraction((hi - lo) / 2))


def written_ball(text):
    parts = _complex_parts(text)
    assert parts is not None, text
    return C(*(claim_ball(t) for t in parts))


def contains_claim(text, value):
    parts = _complex_parts(text)
    for part, val in zip(parts, [value.real(), value.imag()]):
        lo, hi = component_claim(part)
        if lo == hi:
            assert val.is_exact() and val == ball_fraction(lo)
        else:
            # Both inequalities certify containment, with endpoints converted
            # from exact rational decimal claims, not from float midpoints.
            assert val > ball_fraction(lo), (text, value)
            assert val < ball_fraction(hi), (text, value)


def small_radius(value, bits):
    assert value.real().is_finite() and value.imag().is_finite()
    margins = []
    for part in [value.real(), value.imag()]:
        if part.is_zero():
            assert part.is_exact()
            continue
        assert not part.contains_zero(), value
        ratio = R(part.rad()) / abs(part)
        assert ratio < R(2)**(-bits), (value, ratio)
        margins.append(float(-ratio.log() / R(2).log()))
    return min(margins)


def identities(values):
    symmetry = reduction = zero_real = conjugation = translated = 0
    for (N, a, b), value in values.items():
        assert value.overlaps(values[(N, b, a)])
        symmetry += 1
        h = math.gcd(N, math.gcd(a, b))
        if h > 1:
            assert (h * value).overlaps(values[(N // h, a // h, b // h)])
            reduction += 1
        assert value.imag() < 0
        if 2 * (a + b) == N:
            assert value.real().is_zero()
            zero_real += 1
        elif 2 * (a + b) < N:
            assert value.real() < 0
        else:
            assert value.real() > 0
        factor = (-2 * C.pi() * C.gen(0) * (a + b) / N).exp()
        assert value.conjugate().overlaps(factor * value)
        conjugation += 1
        # Integrate each of the four translated path segments independently,
        # then compare with the character-action formula for every translate.
        root = (2 * C.pi() * C.gen(0) / N).exp()
        roots = [root**j for j in range(N)]
        path = euler_integral(QQ(a)/N, QQ(b)/N) / N
        for r in range(N):
            for s in range(N):
                e = (a*r+b*s) % N
                direct = (roots[e] - roots[(e+b)%N]
                          + roots[(e+a+b)%N] - roots[(e+a)%N]) * path
                assert (roots[e] * value).overlaps(direct)
                translated += 1
    quartic = -2 * C.gen(0) * elliptic_k_agm(QQ(1) / 2)
    assert values[(4, 1, 1)].overlaps(quartic)
    return {'symmetry_rows':symmetry,'imprimitive_reductions':reduction,
            'exact_zero_real_parts':zero_real,'conjugation_rows':conjugation,
            'quartic_agm_control':True,'translated_cycle_integrals':translated}


def metadata_checks(keys):
    metadata = json.loads(Path(__file__).with_name('character-data.json').read_text())
    assert [(r['N'], r['a'], r['b']) for r in metadata] == keys
    full_characters = relations = 0
    for N in range(3, 11):
        assert sum(key[0] == N for key in keys) == (N - 1) * (N - 2) // 2
        for a in range(1,N):
            for b in range(1,N):
                if a + b == N:
                    continue
                full_characters += 1
                for c in [a, b, (a+b) % N]:
                    g = math.gcd(N, c)
                    counts = [sum((j*c) % N == k for j in range(N)) for k in range(N)]
                    assert N // g >= 2
                    assert counts == [g if k % g == 0 else 0 for k in range(N)]
                    # g copies of all roots of order N/g sum to zero.
                    relations += 1
    for row in metadata:
        N,a,b=row['N'],row['a'],row['b']
        h=math.gcd(N,math.gcd(a,b));d=N//h
        assert row['gcd']==h and row['d']==d and row['reduced_pair']==[a//h,b//h]
        assert row['genus']==(N-1)*(N-2)//2
        units=[u for u in range(1,d) if math.gcd(u,d)==1]
        expected=[{'u':u,'pair':[(u*a//h)%d,(u*b//h)%d],
                   'holomorphic':(u*a//h)%d+(u*b//h)%d<d} for u in units]
        assert row['galois_embeddings']==expected
        assert 2*sum(e['holomorphic'] for e in expected)==len(units)
        assert sorted({tuple(e['pair']) for e in expected}) == sorted({(p[0]//h,p[1]//h) for p in row['orbit_N']})
    return {'metadata_rows':len(metadata),'full_cohomology_characters':full_characters,
            'geometric_sum_relations':relations}


def main():
    # Controls precede every scientific comparison.
    c1 = euler_integral(QQ(1),QQ(1))
    c2 = euler_integral(QQ(1)/2,QQ(1)/2)
    c3 = elliptic_k_agm(0)
    assert 1 in c1 and 0 not in c1
    assert c2.overlaps(R.pi()) and R(c2.rad()) < R(2)**-420
    assert c3.overlaps(R.pi()/2) and R(c3.rad()) < R(2)**-420
    assert not c2.overlaps(R.pi()+R(10)**-90)
    generator = FermatPeriods()
    assert not names_its_rings(str(Path(__file__).with_name('generate.py')))
    raw = {tuple(p[k] for k in generator.parameters):generator.value(p,100)
           for p in generator.enumerate()}
    values = {}
    for key, v in raw.items():
        if isinstance(v, numberdb.ComplexInterval):
            lo, hi = v.imag.lower, v.imag.upper
            imag = ball_fraction((lo + hi) / 2).add_error(ball_fraction((hi - lo) / 2))
            values[key] = C(ball_fraction(v.real), imag)
        else:
            values[key] = v
    keys=list(values)
    assert len(keys)==120 and keys==sorted(keys)
    assert not exactness(raw)
    independent = {key:independent_period(key) for key in keys}
    bit_margins=[]
    independent_bit_margins=[]
    written={}
    for key,value in values.items():
        other=independent[key]
        bit_margins.append(small_radius(value,400))
        independent_bit_margins.append(small_radius(other,420))
        assert value.overlaps(other), key
        assert not (value+C(R(10)**-90)).overlaps(other), key
        text=to_text(raw[key],digits=100)
        assert digits_of(text)>=100, (key, text, digits_of(text))
        contains_claim(text,other)
        written[','.join(map(str,key))]=text
    report={
        'table':'T665','stage':'build','sage':SAGE_VERSION,
        'numberdb':__import__('numberdb').__version__, 'working_bits':int(numberdb.bits(100,losing=96)),
        'independent_bits':500,'series_terms_per_half':TERMS,
        'controls':['Euler integral (1,1) = 1','Euler integral (1/2,1/2) = pi',
                    'AGM K(m=0) = pi/2','10^-90 perturbations rejected'],
        'generated_rows':len(values),'independent_series_comparisons':len(values),
        'negative_controls_rejected':len(values)+1,
        'minimum_component_relative_bits':min(bit_margins),
        'minimum_independent_component_relative_bits':min(independent_bit_margins),
        'measurement_raw_balls':measure(values),
        'measurement_written':measure(written),
        'identities':identities(values),'metadata':metadata_checks(keys),
        'skill_manifest':'agents/runs/20261102T013956Z-build-skills/manifest.json',
        'skill_versions':json.loads(Path(__file__).with_name('skill-manifest.json').read_text())['versions'],
        'written_values':written}
    if '--stored' in sys.argv or os.environ.get('NUMBERDB_KEY_FROM_STDIN')=='1':
        if os.environ.get('NUMBERDB_KEY_FROM_STDIN')=='1':
            key=sys.stdin.read().strip()
            if '=' in key and key.split('=',1)[0].isidentifier():
                key=key.split('=',1)[1].strip().strip('\"\'')
            numberdb.configure(api_key=key)
        current=_current_entries('T665',None)
        assert list(current)==list(written), (len(current),len(written))
        stored={}
        for key in keys:
            text=current[','.join(map(str,key))]
            contains_claim(text,independent[key])
            stored[key]=written_ball(text)
        report['readback_rows']=len(stored)
        report['readback_identities']=identities(stored)
        companion=numberdb.table('T25')['Numbers']['1/2']
        if isinstance(companion,dict):companion=companion['number']
        assert (-2*C.gen(0)*claim_ball(companion)).overlaps(stored[(4,1,1)])
        report['stored_T25_quartic_control']=True
        verification=generator.verify(sample=None)
        assert verification.ok,verification
        report['generator_verify']=str(verification)
    print(json.dumps(report,indent=2,default=str))


if __name__=='__main__':
    main()