back to table · edit · history · where entries came from · files · download
9251 bytes, as of the version from 2026-11-02 04:21 (current). Recorded here, not run.
"""Checks for Mathieu and umbral moonshine coefficients -- numberdb.org/T668.
Run: sage -python checks.py [--stored]
Needs generate.py, published-controls.json and check.py beside this file.
Without --stored, tests generated values. With --stored, tests the actual draft
entries (NUMBERDB_API_KEY is required until publication). It also reads T667
and T255 for independent K3 and representation-degree controls.
The PDF control data come from CDH 1204.2779v3 Tables 20–47, extracted before
comparison. No coefficient in the generator comes from those tables.
"""
import json
import pathlib
import sys
from math import isqrt
import numberdb.sage as numberdb
from sage.rings.integer_ring import ZZ
from sage.rings.rational_field import QQ
import generate
from check import exactness, measure, names_its_rings, agrees_with
ROOT = pathlib.Path(__file__).resolve().parent
MANIFEST = 'agents/runs/20261102T034954Z-build-skills/manifest.json'
SKILL_SHA256 = 'a2b28d9953264d7b0ca62663785c2952190c5be6d6d3597fd695d9a54d606278'
def records(document):
"""NumberDB's pure canonical flattening when available, client fallback."""
# Published API documents and generator writes use flat Numbers here.
block = document['Numbers']
if isinstance(block, list):
return block
# Existing T667 and T255 have nested parameter dictionaries.
names = list(document['Parameters'])
result = []
def walk(node, depth, params):
if depth == len(names):
result.append(dict(node, params=params) if isinstance(node,dict)
else {'params':params,'number':node})
else:
for key, val in node.items():
if key not in ('comment', 'param-latex'):
walk(val, depth+1, dict(params, **{names[depth]:str(key)}))
walk(block, 0, {})
return result
def controls():
source = json.loads((ROOT/'published-controls.json').read_text())
return {(item['m'], item['r'], s): ZZ(v)
for item in source['components'] for s,v in item['coefficients']}
def scalar_product(a, b, degree):
return [sum((a[k]*b[n-k] for k in range(n+1)), QQ(0))
for n in range(degree+1)]
def scalar_quotient(a, b, degree):
c = []
for n in range(degree+1):
c.append((a[n]-sum((b[j]*c[n-j] for j in range(1,n+1)),QQ(0)))/QQ(b[0]))
return c
def eot_from_k3(k3, degree):
"""EOT (1.3)–(1.9) at y=-1, using stored K3 Fourier coefficients.
Independent scalar arithmetic, no generator series or helper functions.
Write theta1=-i*q^(1/8)*y^(1/2)*T, eta^3=q^(1/8)*E3,
and mu=q^(-1/8)*S/T. Then q^(1/8)H=Z(-1)*E3/T^2-24*S/T.
"""
z = []
for n in range(degree+1):
total = ZZ(0)
for ell in range(-isqrt(4*n+1), isqrt(4*n+1)+1):
total += (-1 if ell % 2 else 1)*k3[4*n-ell*ell]
z.append(QQ(total))
e3 = [QQ(1)]+[QQ(0)]*degree
for k in range(1,degree+1):
for _ in range(3):
for n in range(degree,k-1,-1):
e3[n] -= e3[n-k]
t = [QQ(0)]*(degree+1)
s = [QQ(1)/2]+[QQ(0)]*degree
for k in range(degree+1):
triangular = k*(k+1)//2
if triangular > degree:
break
t[triangular] += 2
if k:
for j in range((degree-triangular)//k+1):
s[triangular+k*j] += 2*(-1)**j
term1 = scalar_quotient(scalar_product(z,e3,degree),
scalar_product(t,t,degree),degree)
term2 = scalar_quotient(s,t,degree)
return [term1[n]-24*term2[n] for n in range(degree+1)]
def theta_reconstruction(values, finite, degree=30):
positions = 0
for name,m in generate.SYSTEMS:
for n in range(degree+1):
f = finite[m][n]
bound = max(isqrt(4*m*n+1),
max((abs(int(e)) for e in f.exponents()),default=0))
for ell in range(-bound,bound+1):
residue = ell % (2*m)
if residue in (0,m):
expected = ZZ(0)
else:
r = min(residue,2*m-residue)
grade = 4*m*n-ell*ell
if grade == -1 and r == 1:
c = ZZ(-2)
elif grade <= 0:
c = ZZ(0)
else:
c = values[name,r,grade]
expected = -c if residue < m else c
assert f[ell] == expected, ('theta reconstruction',name,n,ell,f[ell],expected)
positions += 1
return positions
def main(stored=False):
# Known-answer controls, before any comparison that is trusted.
assert scalar_quotient([QQ(1),QQ(0),QQ(0)], [QQ(1),QQ(-1),QQ(0)],2) == [1,1,1]
assert scalar_product([QQ(1),QQ(1),QQ(0)],[QQ(1),QQ(-1),QQ(0)],2)==[1,0,-1]
assert generate.divide_y_minus_one(generate.y**2-1)==generate.y+1
assert generate.mu_polynomial_part(1,1)[1] == generate.y**(-2)-generate.y**2
assert exactness({'bad':1.0}), 'Float detection control must fail'
assert not names_its_rings(str(ROOT/'generate.py'))
gen = generate.UmbralCoefficients()
params = list(gen.enumerate())
expected_keys = {(p['X'],int(p['r']),int(p['s'])) for p in params}
assert len(expected_keys)==len(params)==840
# Independently enumerate the constrained domain, without the generator's
# residue-start expression.
independent_keys=set()
for name,m in generate.SYSTEMS:
for r in range(1,m):
for s in range(1,120*m+1):
if (s+r*r) % (4*m) == 0:
independent_keys.add((name,r,s))
assert expected_keys==independent_keys
if stored:
document=numberdb.table('T668')
values={(p['params']['X'],int(p['params']['r']),int(p['params']['s'])):ZZ(p['number'])
for p in records(document)}
assert set(values)==expected_keys
assert [(p['params']['X'],int(p['params']['r']),int(p['params']['s']))
for p in records(document)]==[(p['X'],p['r'],p['s']) for p in params]
else:
values={(p['X'],p['r'],p['s']):gen.value(p,100) for p in params}
assert not exactness(values)
printed = controls()
# Geometric PDF extraction gets explicit known answers and zeros right.
assert [printed[2,1,8*n-1] for n in range(1,4)]==[90,462,1540]
assert printed[13,1,155]==printed[13,2,48]==printed[13,12,12]==0
compare={(name,r,s):printed[m,r,s] for name,m in generate.SYSTEMS
for _,r,s in values if _==name}
assert set(compare)==set(values)
discrepancies=agrees_with(values,lambda key:compare[key])
assert not discrepancies,discrepancies[:10]
# Deliberate wrong answers are rejected by the same comparison.
key=('A1^24',1,7)
for wrong in [values[key]+1,-values[key],values[key]//2]:
assert agrees_with({key:wrong},lambda k:compare[k])
k3doc=numberdb.table('T667')
k3={int(e['params']['D']):ZZ(e['number']) for e in records(k3doc)}
assert [k3[d] for d in [-1,0,3,4]]==[2,20,-128,216]
h=eot_from_k3(k3,30)
assert h[0]==-2
assert all(h[n]==values['A1^24',1,8*n-1] for n in range(1,31))
# All six Jacobi normalizations and the polar-part/theta relation.
z,finite=generate.expansions(32)
for name,m in generate.SYSTEMS:
assert z[m][0]==2*(generate.y+generate.y**(-1))+QQ(24)/QQ(m-1)-4
for series in [z[m],finite[m]]:
assert all(f.parent()==generate.L for f in series)
assert not exactness(series)
assert all(c.denominator()==1 for f in series for c in f.coefficients())
assert -finite[m][0][1]==-2
for r in range(1,m):
for n in range(r*r//(4*m)+1):
if (r,n)!=(1,0):
assert finite[m][n][r]==0
theta_positions=theta_reconstruction(values,finite)
# K3 coefficients independently identify every q^n*y^ell of Z^(2).
k3positions=0
for n in range(31):
for ell in range(-isqrt(4*n+1)-1,isqrt(4*n+1)+2):
d=4*n-ell*ell
assert z[2][n][ell]==(k3[d] if d>=-1 else 0)
k3positions+=1
# Low Mathieu coefficients are twice the corresponding irreducible degrees.
characters=records(numberdb.table('T255'))
m24=[ZZ(e['number']) for e in characters if 'M24' in list(e['params'].values())]
assert all(values['A1^24',1,8*n-1]//2 in m24 for n in range(1,6))
summary={'table':'T668','mode':'stored' if stored else 'generated',
'skill_manifest':MANIFEST,'skill_local_sha256':SKILL_SHA256,'skill_live_sha256':SKILL_SHA256,
'entries':len(values),'published_coefficient_comparisons':len(compare),
'independent_K3_EOT_grades':30,'K3_bivariate_positions':k3positions,
'theta_reconstruction_positions':theta_positions,
'Mathieu_representation_controls':5,
'zero_entries':[list(k) for k,v in values.items() if v==0],
'measurement':measure(values),
'controls_and_mutation_checks':'passed',
'numberdb_version':numberdb.__version__}
print(json.dumps(summary,indent=2,default=str))
return values,summary
if __name__=='__main__':
main('--stored' in sys.argv)