checks.py

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

6436 bytes, as of the version from 2026-10-26 04:07 (current). Recorded here, not run.

"""Independent checks for Jacobi theta3 singular-nome constants, T504.

Run beside generate.py with SageMath:
    sage -python checks.py
    sage -python checks.py --stored  # needs NUMBERDB_API_KEY for a draft

The bounded elementary series use no Jacobi theta routine. Every comparison
requires finite, narrow enclosures as well as overlap. Positive controls
check theta3(0)=1 and K(0)=pi/2; negative controls reject disjoint and wide
balls. A Gamma evaluation checks the r=1 closed form independently of theta
series. For every r we also check the elliptic relation using the published
m_r values in T295 and the independent K-values in T296. Those stored values
are read as intervals, never treated as exact midpoints.

The script prints machine-readable evidence and all serialized values. In
--stored mode, it rechecks the entire set of identities using the values read
back from T504. It performs no writes.
"""
import json
import platform
import sys
from decimal import Decimal
from fractions import Fraction

import numberdb.sage as numberdb
from sage.rings.real_arb import RealBallField
from sage.rings.complex_arb import ComplexBallField
from sage.rings.real_mpfi import RealIntervalField
from sage.rings.rational_field import QQ
from numberdb._write import to_text
from sage.version import version as sage_version
from generate import ThetaThreeSingularNomes
from check import exactness, measure, names_its_rings

R = RealBallField(512)
C = ComplexBallField(512)
I = RealIntervalField(512)


def rational(text):
    f = Fraction(text)
    return QQ(f.numerator) / QQ(f.denominator)


def written_ball(entry):
    text = entry['number'] if isinstance(entry, dict) else entry
    if '.' not in text and 'e' not in text.lower():
        return R(rational(text))
    d = Decimal(text)
    unit = QQ(10) ** d.as_tuple().exponent
    center = rational(text)
    return R(I(center - unit, center + unit))


def narrow(x, digits=90):
    return bool(x.is_finite() and (x - R(x.center())).abs() < R(10) ** (-digits))


def agree(a, b, digits=90):
    assert narrow(a, digits) and narrow(b, digits), 'nonfinite or wide enclosure'
    assert a.overlaps(b), 'disjoint enclosures'
    return True


def theta_series(q, j, N=12):
    if j == 2:
        s = 2 * sum((q ** (QQ((2*n+1)**2) / 4) for n in range(N+1)), R(0))
        tail = 2 * q ** (QQ((2*N+3)**2) / 4) / (1-q**(2*N+4))
    else:
        s = R(1) + 2 * sum((((-1)**n if j == 4 else 1)*q**(n*n)
                           for n in range(1,N+1)), R(0))
        tail = 2*q**((N+1)**2)/(1-q**(2*N+3))
    return s.add_error(tail)


def eta_product(q, M=64):
    Q = q*q
    finite = q ** (QQ(1)/12)
    for n in range(1, M+1):
        finite *= 1-Q**n
    error = Q**(M+1)/(1-Q)
    assert error < 1
    return finite * R(1).union(1-error)


def K(m):
    z = C(m).elliptic_k()
    assert z.real().is_finite() and z.imag().is_finite() and z.imag().contains_zero()
    return z.real()


def main(stored=False):
    # Establish that these controls actually return their known answers.
    agree(theta_series(R(0),3),R(1),120)
    agree(K(R(0)),R.pi()/2,120)
    assert not R(1).overlaps(R(2))
    assert not narrow(R(1).add_error(R(1)))
    assert not narrow(R('nan'))
    gen=ThetaThreeSingularNomes()
    raw={int(p['r']):gen.value(p,100) for p in gen.enumerate()}
    assert not exactness(raw)
    assert not names_its_rings(__file__.replace('checks.py','generate.py'))
    written={r:to_text(x,100) for r,x in raw.items()}
    # The whole high-precision enclosure must fit inside what the decimal says.
    for r in raw:
        center = rational(written[r])
        unit = QQ(10) ** Decimal(written[r]).as_tuple().exponent
        assert raw[r] > R(center-unit) and raw[r] < R(center+unit)
    if stored:
        doc=numberdb.table('T504')
        rows=doc['Numbers']
        assert set(rows)==set(map(str,range(1,13)))
        values={r:written_ball(rows[str(r)]) for r in raw}
        assert all((rows[str(r)]['number'] if isinstance(rows[str(r)],dict)
                    else rows[str(r)]) == written[r] for r in raw)
    else:
        values=raw
    d295=numberdb.table('T295')['Numbers']
    d296=numberdb.table('T296')['Numbers']
    d297=numberdb.table('T297')['Numbers']
    d299=numberdb.table('T299')['Numbers']
    evidence=[]
    for r,x in values.items():
        q=(-R.pi()*R(r).sqrt()).exp()
        t2=theta_series(q,2); t3=theta_series(q,3); t4=theta_series(q,4)
        eta=eta_product(q)
        # All identities planned for the prose, across the full range.
        agree(R(x),t3)
        agree(R(x)**4,t2**4+t4**4)
        agree(t2*R(x)*t4,2*eta**3)
        m=written_ball(d295[str(r)]['parameter'])
        agree((t2/R(x))**4,m)
        km=K(m)
        agree(R.pi()*R(x)**2/2,km)
        agree(R.pi()*R(x)**2/2,written_ball(d296[str(r)]))
        agree(K(1-m)/km,R(r).sqrt())
        G=written_ball(d297[str(r)]['ramanujan'])
        f=written_ball(d297[str(r)]['weber'])
        agree(R(x),R(2).sqrt()*G**2*eta)
        agree(R(x),f**2*eta)
        e=C(m).elliptic_e().real()
        alpha=1/(R.pi()*R(x)**4)+R(r).sqrt()*(1-e/km)
        agree(alpha,written_ball(d299[str(r)]))
        evidence.append({'r':r,'production_accuracy_bits':int(raw[r].accuracy()),
                         'series_accuracy_bits':int(t3.accuracy()),
                         'checks':['bounded theta series','Jacobi quartic identity',
                         'eta product identity','T295 parameter','elliptic K from T295',
                         'T296 value','complementary elliptic ratio','T297 Ramanujan and Weber',
                         'T299 elliptic alpha']})
    gamma=R(QQ(1)/4).gamma()/(R(2).sqrt()*R.pi()**(QQ(3)/4))
    agree(R(values[1]),gamma)
    assert all(values[r]>values[r+1] for r in range(1,12))
    return {'table':'T504','mode':'stored' if stored else 'computed',
            'versions':{'sage':sage_version,'python':platform.python_version(),
                        'numberdb':numberdb.__version__},
            'entries':12,'all_passed':True,'controls_passed':True,
            'gamma_r1_passed':True,'strictly_decreasing':True,
            'working_bits':numberdb.bits(100,losing=96),
            'minimum_accuracy_bits':min(int(x.accuracy()) for x in raw.values()),
            'measured_serialized':measure(written),'values':written,'evidence':evidence}


if __name__=='__main__':
    print(json.dumps(main('--stored' in sys.argv),indent=2))