catalogue_coefficients.py

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

2197 bytes, as of the version from 2026-11-02 20:37 (current). Recorded here, not run.

"""Exact Euler-recursion reconstruction from the live T683 LMFDB attachments.
Used only by independent numerical checks for T684. No PARI modular-form calls.
"""
import numberdb.sage as numberdb
from sage.rings.rational_field import QQ
from sage.rings.integer_ring import ZZ
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
from pathlib import Path
from functools import lru_cache
import json
from forms import ROSTER
BASE=Path(__file__).resolve().parent
NF={r['label']:r for r in json.loads((BASE/'hecke-nf.json').read_text())['data']}
P=PolynomialRing(QQ,'x')


def primes_to(n):
    sieve=[True]*(n+1)
    sieve[0]=sieve[1]=False
    for p in range(2,n+1):
        if sieve[p]:
            yield p
            for j in range(p*p,n+1,p): sieve[j]=False


@lru_cache(maxsize=None)
def independent_coefficients(label, count=600):
    h=NF[label];N,k=h['level'],h['weight'];F=P(h['field_poly']);d=F.degree()
    if h['hecke_ring_power_basis']:
        basis=[P.gen()**i for i in range(d)]
    else:
        basis=[P(v)/QQ(b) for v,b in zip(h['hecke_ring_numerators'],h['hecke_ring_denominators'])]
    def convert(v):
        if isinstance(v,int):v=[v]
        return sum((QQ(c)*b for c,b in zip(v,basis)),P(0))%F
    prime_list=list(primes_to(h['maxp']))
    aps=dict(zip(prime_list,[convert(v) for v in h['ap']]))
    coeff=[P(0)]*(count+1);coeff[1]=P(1)
    row=next(r for r in ROSTER if r['label']==label)
    for p in primes_to(count):
        chi=0 if N%p==0 else (int(ZZ(-N).kronecker(p)) if row['group']=='C' else 1)
        pp=p;prev2=P(1);prev=aps[p]
        while pp<=count:
            coeff[pp]=prev
            prev2,prev=prev,(aps[p]*prev-chi*p**(k-1)*prev2)%F
            pp*=p
    # Reconstruct general products in ascending n after prime powers are fixed.
    for n in range(2,count+1):
        for p in prime_list:
            if n%p==0:
                q=n;pp=1
                while q%p==0:q//=p;pp*=p
                if q>1:coeff[n]=(coeff[pp]*coeff[q])%F
                break
    expected=[P([QQ(c) for c in v]) for v in row['an_power_basis']]
    assert coeff[:len(expected)]==expected,(label,'independent Sturm coefficients')
    return coeff