back to table · edit · history · where entries came from · files · download
5080 bytes, as of the version from 2026-10-16 10:44 (current). Recorded here, not run.
"""Independent repair checks for lambda_g Hodge integrals, numberdb.org/T462.
Run with SageMath and numberdb installed, alongside the attached generate.py:
sage -python repair_checks.py T462.json
Without a JSON filename, use T462-check-input.json if present; otherwise read
T462 through numberdb (its owner's API key is needed while it is a draft).
Checks are read-only. This script does not write values or offer a draft.
The Bernoulli formula uses Sage's Bernoulli numbers, independently of the
attached generator's reciprocal-sine recurrence. A separate genus-zero
string recursion checks the genus-zero formula. Permutations are enumerated
to check the moved profile convention on every stored exponent profile.
"""
import numberdb.sage as numberdb
from sage.rings.rational_field import QQ
# Initialize mixed Python-int/rational coercions on a named-import Sage.
from sage.rings.real_mpfr import RealField
from sage.arith.misc import bernoulli
from collections import Counter
from functools import lru_cache
from itertools import permutations
from math import factorial
from pathlib import Path
import json
import sys
from generate import integral as generator_integral, LambdaGHodge
ROOT = Path(__file__).resolve().parent
def scalar(value):
return value['number'] if isinstance(value, dict) else value
def independent_integral(g, ds):
n = len(ds)
assert g >= 0 and all(d >= 0 for d in ds)
assert 2*g-2+n > 0 and sum(ds) == 2*g-3+n
base = QQ(1) if g == 0 else (1-QQ(1)/2**(2*g-1))*abs(bernoulli(2*g))/factorial(2*g)
value = base*factorial(sum(ds))
for d in ds:
value /= factorial(d)
return value
@lru_cache(None)
def zero_string(ds):
if len(ds) < 3 or min(ds) < 0 or sum(ds) != len(ds)-3:
return QQ(0)
if ds == (0,0,0):
return QQ(1)
rest = list(ds)
rest.remove(0)
result = QQ(0)
for j,d in enumerate(rest):
if d:
reduced = rest.copy()
reduced[j] -= 1
result += zero_string(tuple(sorted(reduced)))
return result
def enumerate_profiles(total, n, minimum=0):
if n == 0:
if total == 0:
yield ()
return
for d in range(minimum, total//n+1):
for tail in enumerate_profiles(total-d, n-1, d):
yield (d,)+tail
def check(doc):
assert independent_integral(1,(0,)) == QQ(1)/24
assert independent_integral(2,(1,2)) == QQ(7)/1920
assert independent_integral(3,(1,2,3)) == QQ(31)/16128
assert independent_integral(1,(0,)) != QQ(1)/12
assert zero_string((0,0,0)) == 1
assert zero_string((0,0,0,1,1)) == 2
values = {(int(g),tuple(map(int,ds.split(',')))):QQ(scalar(v))
for g,ns in doc['Numbers'].items() for n,rows in ns.items()
for ds,v in rows.items()}
expected = {(g,ds) for g in range(1,6) for n in range(1,6)
for ds in enumerate_profiles(2*g-3+n,n)}
assert len(values) == 232 and set(values) == expected
gen = LambdaGHodge()
actual = {}
for p in gen.enumerate():
actual[(int(p['g']),tuple(map(int,p['d'].split(','))))] = QQ(scalar(gen.value(p)))
assert actual == values
ns = {}
exec(doc['Programs']['sage']['code'], ns)
count_permutations = 0
count_strings = count_dilatons = 0
for (g,ds),value in values.items():
assert value == independent_integral(g,ds) == ns['lambda_g_integral'](g,list(ds))
for perm in set(permutations(ds)):
assert generator_integral(g,perm) == value
assert independent_integral(g,perm) == value
count_permutations += 1
if 0 in ds and len(ds)>1:
rest=list(ds);rest.remove(0)
rhs=QQ(0)
for j,d in enumerate(rest):
if d:
lowered=rest.copy();lowered[j]-=1
rhs += values[(g,tuple(sorted(lowered)))]
assert rhs == value
count_strings += 1
if 1 in ds and len(ds)>1:
rest=list(ds);rest.remove(1)
assert value == (2*g-2+len(rest))*values[(g,tuple(rest))]
count_dilatons += 1
genus_zero=0
for n in range(3,9):
for ds in enumerate_profiles(n-3,n):
assert independent_integral(0,ds) == zero_string(ds) == generator_integral(0,ds)
genus_zero += 1
assert ns['lambda_g_integral'](0,[0,0,0,1,1]) == 2
result = {'exact_stored_entries':len(values),'entries_by_genus':dict(Counter(g for g,ds in values)),
'permuted_profiles_checked':count_permutations,'string_equations':count_strings,
'dilaton_equations':count_dilatons,'genus_zero_profiles':genus_zero,
'attached_generator_matches':True,'page_program_matches':True,
'known_and_wrong_normalization_controls_passed':True}
print(json.dumps(result,indent=2))
return result
if __name__ == '__main__':
path=Path(sys.argv[1]) if len(sys.argv)>1 else ROOT/'T462-check-input.json'
doc=json.loads(path.read_text()) if path.exists() else numberdb.table('T462')
check(doc)