back to table · edit · history · where entries came from · files · download
6225 bytes, as of the version from 2026-11-09 14:49 (current). Recorded here, not run.
"""Critical values of symmetric-square L-functions of level-one cusp forms -- numberdb.org/T690.
Run with SageMath:
sage -pip install numberdb # once
sage -python generate.py # recompute and verify all rows
sage -python generate.py --publish # fill the existing draft
NUMBERDB_API_KEY is needed for private reads or writes. Submission fills the
existing table; it does not offer, review or publish a draft. The enumeration
and all exact coefficient arithmetic are in this file. No cached numerical
result is required. See argument-selection.md and checks.py for scope and
independent validation. Values use fresh PARI lfun computations at 160 and 220
working decimal digits and retain 100 significant digits, heuristically.
"""
import numberdb.sage as numberdb
from sage.rings.integer_ring import ZZ
from sage.rings.rational_field import QQ
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
from sage.rings.real_mpfr import RealField
from sage.libs.pari import pari
from functools import lru_cache
import os
import sys
WEIGHTS = (12, 16, 18, 20, 22, 24, 26)
WORKING_DIGITS = (160, 220)
COEFFICIENT_BUFFER = 50
EMBEDDING_EXTRA_BITS = 80
pari.allocatemem(160*1024*1024, silent=True)
ZERO = (0, 0)
ONE = (1, 0)
def critical_integers(k):
return tuple(range(1, k, 2)) + tuple(range(k, 2*k-1, 2))
def add(a, b):
return (a[0]+b[0], a[1]+b[1])
def scale(a, n):
return (a[0]*n, a[1]*n)
def mul(a, b):
# Exact arithmetic in Z[t]/(t^2-1080t-20468736), t=a_2 in weight 24.
return (a[0]*b[0]+20468736*a[1]*b[1],
a[0]*b[1]+a[1]*b[0]+1080*a[1]*b[1])
@lru_cache(maxsize=24)
def fourier_coefficients(k, nmax):
"""Exact pairs A+B*t; B=0 for every rational-coefficient form."""
P = PolynomialRing(ZZ, 'q')
e4, e6 = [0]*(nmax+1), [0]*(nmax+1)
e4[0] = e6[0] = 1
for d in range(1, nmax+1):
c4, c6 = 240*d**3, -504*d**5
for n in range(d, nmax+1, d):
e4[n] += c4
e6[n] += c6
E4, E6 = P(e4), P(e6)
raw = (E4**3-E6**2).truncate(nmax+1)
assert all(c % 1728 == 0 for c in raw)
D = P([c//1728 for c in raw])
E4sq = (E4*E4).truncate(nmax+1)
if k == 24:
D2 = (D*D).truncate(nmax+1)
A = (D*E4sq*E4-696*D2).truncate(nmax+1)
return tuple((int(A[n]), int(D2[n])) for n in range(nmax+1))
factors = {12:P(1),16:E4,18:E6,20:E4sq,
22:(E4*E6).truncate(nmax+1),
26:(E4sq*E6).truncate(nmax+1)}
F = (D*factors[k]).truncate(nmax+1)
return tuple((int(F[n]),0) for n in range(nmax+1))
def smallest_factors(nmax):
spf=list(range(nmax+1))
for p in range(2,nmax+1):
if spf[p]==p:
for n in range(p*p,nmax+1,p):
if spf[n]==n:spf[n]=p
return spf
@lru_cache(maxsize=24)
def symmetric_coefficients(k, nmax):
"""Reciprocal cubic Euler factors followed by multiplicativity."""
a=fourier_coefficients(k,nmax)
spf=smallest_factors(nmax)
local={}
for p in range(2,nmax+1):
if spf[p]!=p:continue
B=p**(k-1)
A=add(mul(a[p],a[p]),(-B,0))
cs=[ONE]; power=p
while power<=nmax:
j=len(cs)
v=mul(A,cs[-1])
if j>=2:v=add(v,scale(mul(A,cs[-2]),-B))
if j>=3:v=add(v,scale(cs[-3],B**3))
cs.append(v);power*=p
local[p]=cs
b=[ZERO]*(nmax+1);b[1]=ONE
for n in range(2,nmax+1):
p=spf[n];m=n;j=0
while m%p==0:m//=p;j+=1
b[n]=mul(local[p][j],b[m])
return tuple(b)
def embedded_a2(i, bits):
R=RealField(bits)
r=R(1080**2+4*20468736).sqrt()
return (R(1080)+(-r if i==1 else r))/R(2)
@lru_cache(maxsize=16)
def compute_form(k,i,working):
"""One fresh Linit per embedded form and requested working precision."""
bits=numberdb.bits(working)
dummy=pari.lfuncreate([[1],0,[0,1,2-k],2*k-1,1,1])
domain=[k-1,k-1,0]
cost=pari.lfuncost(dummy,domain,precision=bits)
nmax=int(cost[0])+COEFFICIENT_BUFFER
embedding_bits=max(bits,int(cost[1]))+EMBEDDING_EXTRA_BITS
root=embedded_a2(i,embedding_bits) if k==24 else None
exact=symmetric_coefficients(k,nmax)
coefs=[pari(a)+pari(b)*pari(root) if b else pari(a) for a,b in exact[1:]]
L=pari.lfuncreate([coefs,0,[0,1,2-k],2*k-1,1,1])
init=pari.lfuninit(L,domain,precision=bits)
R=RealField(bits)
values={s:str(R(pari.lfun(init,s,precision=bits))) for s in critical_integers(k)}
# Theta functional-equation residual is a diagnostic, not a certified bound.
feq=str(pari.lfuncheckfeq(L,precision=bits))
return values, {'k':k,'i':i,'working_digits':working,'bits':bits,
'coefficient_count':nmax,'embedding_bits':embedding_bits,
'theta_feq_log2':feq}
class SymmetricSquareValues(numberdb.Generator):
table='T690'
parameters=('k','i','s')
type='R'
digits=100
rigour='heuristic (agreement-checked)'
files=('generate.py','checks.py','argument-selection.md','roster.json',
'numerical-evidence.json','skill-evidence.json','source-evidence.json',
'algebraic_checks.py','readback_checks.py')
def enumerate(self):
for k in WEIGHTS:
for i in range(1,3 if k==24 else 2):
for s in critical_integers(k):
yield {'k':k,'i':i,'s':s}
def value(self,params,digits):
k,i,s=(int(params[t]) for t in self.parameters)
if k not in WEIGHTS or i not in range(1,3 if k==24 else 2) or s not in critical_integers(k):
raise ValueError('Outside the documented selection')
return numberdb.agreeing(lambda w:compute_form(k,i,w)[0][s],at=WORKING_DIGITS)
if __name__=='__main__':
if os.environ.get('NUMBERDB_KEY_FROM_STDIN')=='1':
numberdb.configure(api_key=sys.stdin.read().strip())
if '--publish' in sys.argv or os.environ.get('NUMBERDB_PUBLISH')=='1':
print(SymmetricSquareValues().publish(message='Compute all 162 critical values with exact Euler coefficients and independent checks'))
else:
report=SymmetricSquareValues().verify(sample=None)
print(report)
sys.exit(0 if report.ok else 1)