checks.py

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

7677 bytes, as of the version from 2026-10-16 09:08 (current). Recorded here, not run.

"""Independent checks for Weil--Petersson volumes -- numberdb.org/T459.

Run: sage -python checks.py
Read back the draft too: NUMBERDB_KEY_FROM_STDIN=1 sage -python checks.py < keyfile
No network writes. JSON evidence goes to stdout.

Independent coefficient method: Kaufmann-Manin-Zagier's set-partition
transform (Liu-Xu, arXiv:0708.0565v2, Lemma 2.2), evaluated using a separate
Fraction implementation of the pure-psi DVV recurrence. No arithmetic or
combinatorial helpers are shared with the mixed-kappa generator. The 17
constant terms transcribed from Norman Do, arXiv:1103.4674v1 Appendix B,
are an external tabulation. A third method checks every genus-zero value
using Zograf's scalar volume recurrence (Do Section 3.1).
MPFI at 512 bits independently encloses each exact coefficient times pi^(2m).
Written decimals are interpreted as their full last-place intervals.
"""
import os
import sys
import json
from fractions import Fraction as F
from functools import lru_cache
from math import factorial, comb, prod
from collections import Counter
from decimal import Decimal

import numberdb.sage as numberdb
from sage.rings.rational_field import QQ
from sage.rings.real_mpfi import RealIntervalField
from check import exactness, measure, agrees_with, names_its_rings
from generate import coefficient, volume, WeilPeterssonVolumes


def odd(n):
    return prod(range(1,n+1,2))


def psi(g, ds):
    return _psi(g,tuple(sorted(ds)))


@lru_cache(None)
def _psi(g, ds):
    n=len(ds)
    if g<0 or 2*g-2+n<=0 or any(d<0 for d in ds) or sum(ds)!=3*g-3+n:
        return F(0)
    if g==0:
        return F(factorial(n-3),prod(factorial(d) for d in ds))
    if n==1:
        return F(1,24**g*factorial(g))
    if ds[0]==0:
        rest=ds[1:]
        return sum((psi(g,rest[:j]+(e-1,)+rest[j+1:])
                    for j,e in enumerate(rest) if e), F(0))
    if ds[0]==1:
        return (2*g-3+n)*psi(g,ds[1:])
    d=ds[0]
    rest=ds[1:]
    result=F(0)
    for j,e in enumerate(rest):
        result += F(odd(2*d+2*e-1),odd(2*e-1))*psi(g,rest[:j]+(d+e-1,)+rest[j+1:])
    for a in range(d-1):
        b=d-2-a
        result += F(odd(2*a+1)*odd(2*b+1),2)*psi(g-1,(a,b)+rest)
        for mask in range(1<<len(rest)):
            left=tuple(rest[j] for j in range(len(rest)) if mask>>j&1)
            right=tuple(rest[j] for j in range(len(rest)) if not(mask>>j&1))
            for h in range(g+1):
                result += (F(odd(2*a+1)*odd(2*b+1),2)*psi(h,(a,)+left)
                           *psi(g-h,(b,)+right))
    return result/odd(2*d+1)


def partitions(total, minimum=1):
    if total==0:
        yield ()
    for first in range(minimum,total+1):
        for tail in partitions(total-first,first):
            yield (first,)+tail


def independent_coefficient(g,n):
    m=3*g-3+n
    out=F(0)
    for parts in partitions(m):
        divisor=prod(factorial(p) for p in parts)*prod(factorial(a) for a in Counter(parts).values())
        out += F((-1)**(m-len(parts)),divisor)*psi(g,(0,)*n+tuple(p+1 for p in parts))
    return out*2**m


@lru_cache(None)
def zograf(n):
    if n==3:
        return F(1)
    return sum((F(k*(n-k-2)*comb(n-4,k-1)*comb(n,k+1),2*(n-1))
                *zograf(k+2)*zograf(n-k) for k in range(1,n-2)),F(0))


# Coefficients of pi^(6g-6+2n), Do Appendix B, pp. 33-34.
PUBLISHED={
    (0,3):F(1), (0,4):F(2), (0,5):F(10), (0,6):F(244,3), (0,7):F(2758,3),
    (1,1):F(1,12), (1,2):F(1,4), (1,3):F(14,9), (1,4):F(529,36), (1,5):F(16751,90),
    (2,0):F(43,2160), (2,1):F(29,192), (2,2):F(787,480), (2,3):F(1498069,64800),
    (3,0):F(176557,1209600), (3,1):F(9292841,4082400), (3,2):F(2800144027,65318400),
}


def as_qq(x):
    return QQ(x.numerator)/QQ(x.denominator)


def written_interval(text):
    dec=Decimal(text)
    q=as_qq(F(dec))
    if '.' not in text and 'e' not in text.lower():
        return q,q
    exponent=dec.as_tuple().exponent
    ulp=QQ(10)**exponent
    return q-ulp,q+ulp


def read_numbers(doc):
    return {(int(g),int(n)):str(v['number'] if isinstance(v,dict) else v)
            for g,rows in doc['Numbers'].items() for n,v in rows.items()}


def run():
    # Controls run first, including zero, a non-unit value and a positive-genus case.
    assert psi(0,(0,0,0))==1
    assert psi(0,(1,1,0,0,0))==2
    assert psi(1,(1,))==F(1,24)
    assert psi(2,(2,3))==F(29,5760)
    assert psi(1,(0,))==0
    assert independent_coefficient(0,4)==2
    assert zograf(4)==1 and zograf(5)==5
    R=RealIntervalField(512)
    assert (R(1)/R(3)).lower().exact_rational() <= QQ(1)/3 <= (R(1)/R(3)).upper().exact_rational()
    assert (R(1)/R(3)).absolute_diameter().exact_rational()<QQ(10)**(-150)
    expected={(g,n) for g in range(4) for n in range(9) if 2*g-2+n>0}
    gen=WeilPeterssonVolumes()
    keys=[(p['g'],p['n']) for p in gen.enumerate()]
    assert set(keys)==expected and len(keys)==len(expected)
    values={k:volume(*k) for k in keys}
    assert not names_its_rings(os.path.join(os.path.dirname(__file__),'generate.py'))
    assert not exactness(values)
    coefficients={k:coefficient(*k) for k in keys}
    comparison=agrees_with(coefficients,lambda k:as_qq(independent_coefficient(*k)))
    assert not comparison, comparison
    assert not agrees_with({k:coefficients[k] for k in PUBLISHED},lambda k:as_qq(PUBLISHED[k]))
    for g,n in keys:
        if g==0:
            assert coefficients[g,n]==as_qq(zograf(n)*F(2**(n-3),factorial(n-3)))
    widths=[(values[k].upper().exact_rational()-values[k].lower().exact_rational())/values[k].lower().exact_rational()
            for k in keys if k!=(0,3)]
    min_bits=min(int(x.denominator().nbits()-x.numerator().nbits()-1) for x in widths)
    assert min_bits>=340
    independent={}
    for g,n in keys:
        v=R(as_qq(independent_coefficient(g,n)))*R.pi()**(6*g-6+2*n)
        assert v.lower().exact_rational()>0 and v.absolute_diameter().exact_rational()/v.lower().exact_rational()<QQ(10)**(-145)
        if (g,n)!=(0,3):
            ball=values[g,n]
            # This is interval overlap, with narrow widths tested separately.
            assert v.lower().exact_rational()<=ball.upper().exact_rational() and ball.lower().exact_rational()<=v.upper().exact_rational()
        else:
            assert values[g,n]==1 and v==1
        independent[g,n]=v
    result={'table':'T459','entries':len(keys),'exact_coefficient_comparisons':len(keys),
            'published_constant_terms':len(PUBLISHED),'zograf_genus_zero_checks':sum(g==0 for g,n in keys),
            'independent_mpfi_checks':len(keys),'minimum_arb_relative_accuracy_bits':min_bits,
            'mpfi_relative_width_bound':'1e-145','measurement':measure(values),
            'rational_coefficients':{','.join(map(str,k)):str(v) for k,v in coefficients.items()},
            'controls':'passed: non-unit genus-zero, genus-one, genus-two, dimension-zero, rational interval and Zograf base cases',
            'stored_checks':0}
    if os.environ.get('NUMBERDB_KEY_FROM_STDIN')=='1':
        numberdb.configure(api_key=sys.stdin.read().strip())
        stored=read_numbers(numberdb.table('T459'))
        assert set(stored)==expected
        for k,s in stored.items():
            lo,hi=written_interval(s)
            v=independent[k]
            assert lo<=v.lower().exact_rational() and v.upper().exact_rational()<=hi,(k,s)
        assert stored[0,3]=='1'
        result['stored_checks']=len(stored)
        report=gen.verify(sample=None)
        assert report.ok,str(report)
        result['verify']=str(report)
        result['stored_numbers']={','.join(map(str,k)):v for k,v in stored.items()}
    return result

if __name__=='__main__':
    print(json.dumps(run(),indent=2,default=str))