Skip to content

Select the correct newform via traces in CMF GP and Magma code snippets (LMFDB#5403, LMFDB#6060) - #28

Closed
roed-math wants to merge 4 commits into
mainfrom
ai/t32-cmf-snippet-select
Closed

Select the correct newform via traces in CMF GP and Magma code snippets (LMFDB#5403, LMFDB#6060)#28
roed-math wants to merge 4 commits into
mainfrom
ai/t32-cmf-snippet-select

Conversation

@roed-math

Copy link
Copy Markdown
Owner

The Pari/GP snippet on newform pages took f = lf[1] ("index may be different") and Magma had no selection at all, even though the eigenbasis order of GP/Magma often differs from the LMFDB order (e.g. PARI reverses 37.2.a and 34.2.c; Magma reverses 80.5.h from LMFDB#6059). Following the Sage snippet from LMFDB#6515, the GP and Magma snippets now select the newform whose absolute Hecke eigenvalue traces up to the newspace's trace bound match the stored traces. The GP version computes traces from mfeigenbasis with a small abstrace helper (rescaling by degrees since PARI represents coefficients in subtowers); the Magma version selects from NewformDecomposition(NewSubspace(CuspidalSubspace(ModularSymbols(chi,k,-1)))) because Newforms(CuspForms(chi,k)) in current Magma (V2.29-4) silently returns wrong eigenvalues in many character spaces (e.g. 32.2.g, 110.2.f, 102.2.h; verified against LMFDB data, PARI and Magma's own modular symbols). Selection adds 0-1 ms in GP and at most ~0.2 s in Magma on all 19 tested labels, verified by running the generated snippets in both systems and comparing traces beyond the selection window; a snippet_test section now lets the snippet CI cover newform pages. For weight 1 the Magma snippet is omitted since Magma has no weight-1 newforms (its init already errors there). Addresses LMFDB#5403. Addresses LMFDB#6060.

🤖 Generated with Claude Code

roed314 and others added 4 commits July 19, 2026 11:54
LMFDB#6060)

The GP snippet took f = lf[1] and Magma had no selection, although the
GP/Magma eigenbasis order often differs from the LMFDB order (PARI
reverses 37.2.a and 34.2.c; Magma reverses 80.5.h from LMFDB#6059).
Following the Sage snippet, select the orbit whose absolute eigenvalue
traces up to the newspace trace bound match the stored traces: in GP via
mfeigenbasis with an abstrace helper (rescaling by field degrees since
PARI represents coefficients in subtowers), in Magma via the modular
symbols NewformDecomposition, because Newforms(CuspForms(chi,k)) in
Magma V2.29-4 silently returns wrong eigenvalues in many character
spaces (32.2.g, 110.2.f, 102.2.h). Weight 1 keeps no Magma snippet
(Magma has no weight 1 newforms). Adds a snippet_test section so the
snippet CI covers newform pages.

Verified by running the rendered snippets and full code downloads in gp
and Magma for 19 newforms (incl. order-mismatch, nested-coefficient-
field, trace_bound 0 and weight 1 cases), comparing traces beyond the
selection window with the database; selection costs 0-1 ms in GP and
at most ~0.2 s in Magma.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The initialize-newspace-common anchor still ran

    S := CuspForms(chi, k);
    N := Newforms(S);

before the modular symbols selector, so every downloaded Magma script
executed the computation that this branch identifies as unreliable, left
N unused, and labelled it "Compute space of new eigenforms". Move the
Magma character construction and the NewformDecomposition into
initialize-newspace-weight-not-1, and let the newform block only select
the matching component of the already computed decomposition.

Weight 1 previously dropped Magma from just the newform and qexp
sections, so the inherited init block, the "Show commands" selector, the
Magma commands download and download_code all still offered a Magma
script that cannot work. Drop Magma from every section and from both
language lists instead, expose the result as WebNewform.code_langs so
that the downloads list cannot drift from the snippets, and let
download_code return 404 rather than a header-only script.

Add a Magma snippet log for 80.5.h.b, the regression case of LMFDB#6059:
Magma lists that orbit before 80.5.h.a, and the selected component
matches the stored traces well past the selection window. Since the
scheduled snippet workflow ignores Magma, also assert at the text level
that the download uses NewformDecomposition and the trace comprehension,
and never CuspForms or Newforms(S).

Move wrap_traces to module level and unit test it on 675.1.g.a, whose
trace bound of 46 makes the trace list wrap: each language gets a valid
multiline assignment, gp keeps its trailing backslash, and all three
round-trip to the stored traces.

Along the way, two fixes to generate_snippet_tests.py: -o gp selected
nothing, because pari was renamed to gp only after --only and --ignore
were applied; and Magma seeds its random number generator from the
clock, so a randomised NewformDecomposition printed a or -a from run to
run and no Magma log was reproducible. Reset the seed per snippet file,
and raise parisizemax, which the 8MB default makes too small for mfinit
of a weight 1 newspace of moderate level.
Magma seeds its RNG from the clock and several of its algorithms are
randomised, so a Magma snippet log is not reproducible: 80.5.h.b prints
its q-expansion in terms of a or -a depending on the run, and the
committed elliptic curve log is equally unstable (four runs of the
37.a1 snippet gave (0 : -1 : 1) three times and (0 : 0 : 1) once).

SetSeed does fix this, but it fixes it to a different generator than the
one that happens to be in the committed logs, so turning it on requires
regenerating every Magma log in the repository. That is a repository
wide change and does not belong in a PR about the CMF snippets, so leave
the behaviour alone and just record the finding where the rest of the
Magma handling is explained.
@roed-math

Copy link
Copy Markdown
Owner Author

Addressed the review (commits b21812d and e50df0e, on top of dd9ce8a).

1. Magma no longer computes Newforms(CuspForms(chi,k)) at all

The initialize-newspace-common anchor still executed the unreliable computation (leaving N unused) before the modular-symbols selector ran. The anchor is now Pari-only; the Magma character construction and the decomposition moved into initialize-newspace-weight-not-1, and the newform block only selects the matching component:

chi := DirichletCharacter("80.79");
M := NewSubspace(CuspidalSubspace(ModularSymbols(chi, 5, -1)));
D := NewformDecomposition(M);

traces := [2,0,0,0,14];
f := [d : d in D | ... eq traces][1];

No generated Magma script contains CuspForms or Newforms(S) any more. test_code_download_no_duplicates was requiring CuspForms(chi, 2) to occur once, which locked in the stale computation; it now asserts on NewformDecomposition(.

2. Weight 1 offers no Magma anywhere, and a direct request 404s

Rather than popping Magma from two sections, weight 1 now drops Magma from every section and from both language lists (prompt and show), so a single rule covers all four paths:

  • no section in form.code keeps a magma entry;
  • the page no longer offers Magma in "Show commands";
  • WebNewform.downloads omits Magma commands, driven by a new code_langs attribute so the downloads list and the snippets cannot drift apart;
  • download_code_newform/23.1.b.a/magma returns 404 instead of a header-only script.

The separate Modular form to Magma data export is untouched.

3. Magma coverage, including a real fixture

Added a checked-in Magma snippet log for 80.5.h.b, generated with Magma V2.29-4 and CHIMP. It confirms LMFDB#6059: Magma's decomposition lists this orbit first, so without selection the snippet returns 80.5.h.a. The selected component agrees with the stored traces well past the 5-term selection window (a_9 = -162, against 478 for 80.5.h.a).

Since the scheduled snippet workflow ignores Magma, test_cmf.py also asserts at the text level, for 417.2.d.a and 80.5.h.b, that NewformDecomposition( occurs exactly once, that the trace comprehension is present, that CuspForms/Newforms(S) are absent, and that the q-expansion is taken of the selected f.

4. Trace wrapping

wrap_traces moved to module level and is unit tested on 675.1.g.a, whose trace bound of 46 makes the list wrap: each language gets a valid multiline assignment, gp keeps its trailing , \ on every line but the last, sage and magma take no continuation, and all three round-trip to the stored trace list. The generated gp download is checked to contain the wrapped form.

I did not add a fixture for the wrapping case. Every form with a long enough trace list has dimension > 1, and for those the last line of the gp snippet already fails:

? L = lfunmf(mf,f); lfun(L,1)
*** lfun: incorrect type in lfunmisc_to_ldata (t_VEC).

lfunmf returns a vector of L-functions when the form has several conjugates. This is pre-existing and independent of this PR (plain 23.2.a.a hits it too), but it means such a fixture would carry a genuine error. Probably worth its own issue. I did check by hand that gp executes the wrapped assignment correctly: #traces comes out as 46 and the selection picks the right form.

Two fixes to generate_snippet_tests.py

  • -o gp selected nothing, because pari was renamed to gp only after --only/--ignore were applied. So the documented command was a silent no-op. Normalised before filtering; both spellings now work.
  • Set parisizemax for gp: the 8 MB default stack overflows on mfinit of a weight 1 newspace of moderate level. The existing gp logs regenerate byte-identically with it.

One thing I deliberately did not change

Magma seeds its RNG from the clock and several of its algorithms are randomised, so Magma snippet logs are not reproducible today. 80.5.h.b prints its q-expansion in terms of a or -a depending on the run, and the existing elliptic curve log is equally unstable: four runs of the 37.a1 snippet gave (0 : -1 : 1) three times and (0 : 0 : 1) once.

SetSeed fixes this, but it fixes the output to a different generator than the one in the committed logs, so enabling it means regenerating every Magma log in the repository. That is repo-wide and does not belong here, so I reverted it (e50df0e) and left a note next to the rest of the Magma handling. Happy to do it as a separate PR if you want it.

Testing

  • lmfdb/classical_modular_forms/test_cmf.py: 35 passed, 1 skipped.
  • gp snippet fixtures (37.2.a.a, 95.1.d.a) regenerate with no diff.
  • The 80.5.h.b Magma fixture regenerates with no diff and no errors.
  • pyflakes, pylint and ruff per tox -e lint are clean on the changed files.

@roed-math

Copy link
Copy Markdown
Owner Author

Filed the two findings upstream:

The third item, -o gp selecting no languages, is fixed in this PR rather than filed.

@roed314

roed314 commented Aug 5, 2026

Copy link
Copy Markdown

GPT signed off.

@roed-math

Copy link
Copy Markdown
Owner Author

Superseded by LMFDB#7164, opened upstream from this same branch. Closing here; review continues upstream.

@roed-math roed-math closed this Aug 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants