back to table · edit · history · where entries came from · files · download
7031 bytes, as of the version from 2026-10-16 08:24. Recorded here, not run.
"""Independent checks for psi-class intersection numbers -- numberdb.org/T458.
Run: sage -python checks.py
Check a saved API document: sage -python checks.py stored-document.json
Read the draft and check its values: sage -python checks.py --stored
(The last command requires its owner's NUMBERDB_API_KEY.)
Liu-Xu, arXiv:0710.5322, Theorem 1.1, computes by genus. It uses
Fraction arithmetic and no generator arithmetic. It starts with the
multinomial genus-zero formula and derives <tau_1>_1 rather than using
that number as an input. Source controls are the Macaulay2 HodgeIntegrals
wittenTau documentation, including <tau_5^3>_5 = 41873/255467520.
check.py is the unchanged NumberDB table-build validation helper bundled
for reproducibility. This file prints a JSON evidence report and writes
nothing to the site.
"""
import numberdb.sage as numberdb
from sage.rings.rational_field import QQ
from fractions import Fraction
from functools import lru_cache
from itertools import combinations
from math import factorial, prod
from pathlib import Path
import json
import os
import sys
import time
@lru_cache(None)
def liu_xu(g, ds):
"""Independent genus recursion on an immutable sorted profile."""
n = len(ds)
if g < 0 or any(d < 0 for d in ds) or 2 * g - 2 + n <= 0:
return Fraction(0)
if sum(ds) != 3 * g - 3 + n:
return Fraction(0)
if g == 0:
return Fraction(factorial(n - 3), prod(factorial(d) for d in ds))
if 0 in ds:
reduced = list(ds)
reduced.remove(0)
result = Fraction(0)
for i, degree in enumerate(reduced):
if degree:
other = reduced.copy()
other[i] -= 1
result += liu_xu(g, tuple(sorted(other)))
return result
# The theorem reduces genus when every exponent is positive. Its factors
# with genus 0 vanish by dimension, so only h=1,...,g-1 can contribute.
distinguished = ds[-1]
remaining = ds[:-1]
c = 2 * g + n - 1
term = Fraction(2 * distinguished + 3, 12) * liu_xu(g - 1, tuple(sorted((0,0,0,0,distinguished + 1) + remaining)))
term -= Fraction(c, 6) * liu_xu(g - 1, (0,0,0) + ds)
for size in range(len(remaining) + 1):
for subset in combinations(range(len(remaining)), size):
I = tuple(remaining[i] for i in subset)
J = tuple(remaining[i] for i in range(len(remaining)) if i not in subset)
for h in range(1, g):
right = liu_xu(g - h, (0,0) + J)
if right:
left1 = liu_xu(h, tuple(sorted((0,0,distinguished + 1) + I)))
left2 = liu_xu(h, tuple(sorted((0,distinguished) + I)))
term += ((2 * distinguished + 3) * left1 - c * left2) * right
return term / (c * (c - 1))
def expected(key):
g, n, ds = key
assert n == len(ds)
x = liu_xu(g, ds)
return QQ(x.numerator) / QQ(x.denominator)
def from_document(doc):
"""The API returns nested Numbers keyed by g, n, and the profile string."""
result = {}
for gs, by_n in doc['Numbers'].items():
for ns, by_d in by_n.items():
for profile, entry in by_d.items():
value = entry['number'] if isinstance(entry, dict) else entry
key = (int(gs), int(ns), tuple(map(int, profile.split(','))))
assert key not in result
result[key] = QQ(str(value))
return result
def check_all(values):
from check import exactness, agrees_with, measure, names_its_rings
from generate import MAX_GENUS, MAX_MARKS
assert not exactness(values)
assert not names_its_rings(str(Path(__file__).with_name('generate.py')))
# Controls before comparisons: a failed normalisation must stop the run.
controls = {
(0,(0,0,0)): Fraction(1),
(0,(0,0,0,0,1,2)): Fraction(3),
(0,(0,0,0,0,0,2,2)): Fraction(6),
(1,(1,)): Fraction(1,24),
(2,(4,)): Fraction(1,1152),
(2,(2,3)): Fraction(29,5760),
(5,(5,5,5)): Fraction(41873,255467520),
}
for (g,ds), value in controls.items():
assert liu_xu(g,ds) == value, (g,ds,'independent control')
if (g,len(ds),ds) in values:
assert values[g,len(ds),ds] == QQ(value.numerator) / QQ(value.denominator), (g,ds,'stored control')
disagreements = agrees_with(values, expected)
assert not disagreements, disagreements[:8]
counts = {'independent_Liu_Xu':len(values),'known_answer_controls':len(controls),
'genus_zero':0,'one_point':0,'string':0,'dilaton':0,
'dimension_and_sorted_profile':0}
# Independent completeness count using combinations_with_replacement,
# not the recursive profile enumerator that fills the table.
from itertools import combinations_with_replacement
domain=set()
for g in range(MAX_GENUS+1):
for n in range(1,MAX_MARKS+1):
if 2*g-2+n<=0:
continue
total=3*g-3+n
for ds in combinations_with_replacement(range(total+1),n):
if sum(ds)==total:
domain.add((g,n,ds))
assert set(values)==domain, (len(values),len(domain))
for (g,n,ds), value in values.items():
assert g >= 0 and 2*g-2+n>0 and n==len(ds)
assert tuple(sorted(ds))==ds and min(ds)>=0 and sum(ds)==3*g-3+n
assert value>0
counts['dimension_and_sorted_profile']+=1
if g==0:
assert value==QQ(factorial(n-3)) / QQ(prod(factorial(d) for d in ds))
counts['genus_zero']+=1
if n==1:
assert value==QQ(1) / QQ(24**g*factorial(g))
counts['one_point']+=1
if 0 in ds and (g,n)!=(0,3):
rest=list(ds);rest.remove(0)
rhs=QQ(0)
for j,d in enumerate(rest):
if d:
reduced=rest.copy();reduced[j]-=1
rhs+=values[g,n-1,tuple(sorted(reduced))]
assert value==rhs
counts['string']+=1
if 1 in ds and (g,n)!=(1,1):
rest=list(ds);rest.remove(1)
assert value==(2*g-3+n)*values[g,n-1,tuple(rest)]
counts['dilaton']+=1
return {'ok':True,'checks':counts,'measurement':measure(values),
'independent_cache':str(liu_xu.cache_info())}
if __name__=='__main__':
start=time.monotonic()
if os.environ.get('NUMBERDB_KEY_FROM_STDIN')=='1':
numberdb.configure(api_key=sys.stdin.read().strip())
if sys.argv[1:]==['--stored']:
values=from_document(numberdb.table('T458'))
elif sys.argv[1:]:
values=from_document(json.loads(Path(sys.argv[1]).read_text()))
else:
from generate import PsiIntersections
gen=PsiIntersections()
values={(int(p['g']),int(p['n']),tuple(map(int,p['d'].split(',')))):
gen.value(p,100) for p in gen.enumerate()}
report=check_all(values)
report['elapsed_seconds']=time.monotonic()-start
print(json.dumps(report,indent=2,default=str))