Skip to content

main -> dev - #7194

Merged
AndrewVSutherland merged 67 commits into
devfrom
main
Aug 31, 2026
Merged

main -> dev#7194
AndrewVSutherland merged 67 commits into
devfrom
main

Conversation

@AndrewVSutherland

Copy link
Copy Markdown
Member

No description provided.

rvisser7 and others added 30 commits March 22, 2026 23:22
…6654)

Jump-box searches for family names that coincide with a stored family,
e.g. Sp(2,5)=SL(2,5) or PSp(2,5)=PSL(2,5), flashed "has not yet been
added" although the groups are in the database under the other name.
Add a FAMILY_ALIASES table used by group_jump to translate the
gps_special_names lookup for the exact coincidences Sp/PSp/GSp/ASp/
PSigmaSp/ASigmaSp in dimension 2 and Spin in dimension 3; the
valid_params fallback still sees the family the user typed so error
messages stay accurate.  Also refresh stale family names in
valid_params (CSp->GSp, GO->Orth, PGO->PO, CSO->GSO, CO->GOrth, add
ASp) to match current gps_families, as already done in web_groups.py.

Verified with a test-client script (Sp(2,5) and Sp(2, 5) -> 120.5,
PSp(2,5) -> 60.5, GSp(2,7) -> 2016.a, Spin(3,4) -> 60.5, stored
families such as Sp(4,3) unchanged) and new checks in
test_browse_page.py::test_lookup; pytest -k "lookup or famly" passes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Knowls clicked inside a table cell insert a full-width row whose content
(min 700px via knowl_click_handler in lmfdb.js) stretched narrow tables,
pushing the other columns apart on pages like /rcs.  Add inline-size
containment to td > .knowl-output so the inserted row is ignored when
column widths are computed: the knowl box now simply spans the table's
current width, and over-wide content scrolls horizontally inside the box
instead of stretching the table.

Verified with a local server and browser on /rcs (table width and column
positions identical before/during/after opening source and reliability
knowls, previously 526px -> 692px with columns jumping ~100px), on
NumberField search results (th knowl in results header) and on the
EllipticCurve/Q/11/a/2 invariants table (KaTeX-heavy td knowl); paragraph
knowls are unaffected.  lmfdb/tests/test_root.py (renders /style.css)
passes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Only quadratic p-adic fields had a readable nickname (Q_p(sqrt d)).
Nickname every unramified extension as Q_p(zeta_{p^f-1}) and every tame
extension as Q_p(zeta_{p^f-1}, root[e](zeta^k p)); the f=1 radicand is
written p*r to match the existing sqrt(p*u) convention, with k=0 and
zeta^k=-1 simplified. The twist exponent k is read from the stored
Eisenstein/unramified data (no discrete log) and normalized to a canonical
Frobenius-orbit representative so Q_p-isomorphic presentations coincide;
wild fields keep their label. Nicknames now show on field homepages, the
field-data knowl, subfield/completion displays, and the families Base column.

Verified with sage/pari over all 7731 tame degree>2 fields: 0 mismatches
vs an independent discrete-log computation, per-(p,e,f) counts equal the
number of Frobenius orbits, and each nickname field is Q_p-isomorphic to
the stored field. pytest local_fields: 9 passed (new test_nicknames);
pyflakes clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: ahmadalguydi <ahmadalgaidy@hotmail.com>
The jump-box tests only exercised four of the seven FAMILY_ALIASES entries,
and none of them reached valid_params, so the refreshed family names there
were untested.

- test_family_alias_lookup: a stored example for each FAMILY_ALIASES entry,
  including the previously untested ASp(2,2), PSigmaSp(2,5) and
  ASigmaSp(2,2), plus an assertion that the case list and FAMILY_ALIASES
  stay in sync.
- test_absent_family_lookup: valid but absent groups in both parity branches
  of valid_params, covering the newly accepted GSp/ASp and the renamed
  Orth*/PO*/GSO*/GOrth* identifiers, and two wrong-parity names that must
  still be reported as invalid.

Targets verified against gps_special_names (ASL(2,2)=ASigmaL(2,2)=24.12,
PSigmaL(2,5)=60.5) and every identifier in the two valid_params lists
checked against the distinct family values in gps_families.
Verified with sage -python -m pytest
lmfdb/groups/abstract/test_browse_page.py -k 'lookup or family or famly':
5 passed, 68 deselected; pyflakes clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Review of PR #20 pointed out that the added `overflow-x: auto` on
`td > .knowl-output` turns the box into a scroll container, which exposes
the scrollable overflow of the absolutely positioned `.knowl-footer`
(`width: 100%` starting after the parent's 10px left padding, plus its own
10px left padding). Measured in the browser, that is 20px of scroll range
on every table knowl, so even a short knowl whose content fits gained a
horizontal scrollbar (box height 123px -> 138px).

The declaration was also redundant: `.knowl-content` already has
`max-width: 100%; overflow: auto` and is the right inner scroller for
over-wide content. Drop `overflow-x` (so the box keeps the inherited
`overflow: hidden`) and reword the comment accordingly.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
PrimeBound.__call__ verified that the queried values were finite sets of
primes, but never checked them against the bound it was constructed with.
So the registered ec_curvedata checker

    ("conductor", PrimeBound(300000000), "elliptic curves with prime conductor at most 300 million")

certified any prime conductor as complete, however large:

    sage: results_complete("ec_curvedata", {"conductor": 1000000007}, db)
    (True, 'elliptic curves with prime conductor at most 300 million', None)

Delegate the range check to Bound.__call__, as the sibling CPrimeBound
already does, and add regression tests for a prime past the bound.

The bound is checked before primality so that a large range is rejected
without iterating over it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…-7038

fix: show exponent one for cusp orbit sizes
roed314 and others added 29 commits August 6, 2026 14:49
Follow-on to the prose pass, kept separate so it can be dropped on its
own.  Every name here has all of its references inside a single file (or,
for favourite_list, one view and its template), so each rename is the
definition and its uses together:

  draw_spectrum.py        centre_ratio, y_centre -> center_ratio, y_center
  WebEllipticCurve.py     EC_R_plot's colour parameter -> color
  web_newform.py          factorisation loop variable -> factorization
  galois_reps.py          renormalise_coefficients -> renormalize_coefficients
  search_wrapper.py       query_cancelled_error -> query_canceled_error
  hecke_algebras          favourite_list -> favorite_list (view + template)
  test_st.py              test_favourites -> test_favorites

query_cancelled_error is worth a look: it handles psycopg's
QueryCanceledError, which spells it with one l, so the handler and the
exception now agree.

Not renamed: signtocolour, which lmfdb/utils/__init__.py exports in
__all__ and five modules import.  Renaming it is an API change rather
than a spelling fix, so it and the locals built on it (signcolour,
thiscolour, colourplus, colourminus, test_signtocolour) are left for a
separate decision.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The test suite runs against a shared server, devmirror by default, whose
statement_timeout is 0.  psycodict only sets a timeout for connections made as
the "webserver" role, and the tests connect as "lmfdb", so nothing bounds a
query the tests issue.  A slow one runs until something outside the job stops
it.

That is not hypothetical.  On 2026-08-06 the Dirichlet character search in
lmfdb/characters/test_characters.py held five separate CI jobs for between 26
minutes and 2h33m; the run that started at 08:50 UTC finished at 11:24, and four
others that had started as much as two hours later finished within a minute of
it, all reporting a cancelled query.  The same search takes about seven seconds
against an idle server.

Set PGOPTIONS in the tests environment.  libpq applies it to every connection it
opens, including the ones psycodict opens when it resets a broken connection, so
the timeout cannot be lost on a reconnect and the test harness needs to know
nothing about it.  A query stopped this way raises the QueryCanceledError the
search pages already catch, so a slow search now renders the ordinary timeout
page in 120 seconds rather than hanging.

120s is chosen as a hang catcher rather than a performance budget: well above
anything the suite issues against a healthy server, well below the hangs it
exists to stop.  Exporting PGOPTIONS overrides it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
DirichletSearchTest.test_search is the test that has been hanging and then
failing CI.  Its conductor and order ranges match every modulus admitting a
character of conductor 25 to 50: 537,164 orbits, all of which must be read
before the sort by modulus can pick the first page of 51.  EXPLAIN ANALYZE on
devmirror puts that at 434,307 buffer reads, about 3.4GB, for 6.7 seconds
against an idle server.

That cost is inherent to the query rather than a regression, and this test
exists to check that the search parses conductor ranges, order ranges, the
primitive flag and parity, not to measure the server.  Use the
check_args_with_timeout helper, which accepts either the expected label or the
timeout page, for the five range searches.

The first search fixes both conductor and order, which matches an index prefix
and lets the index supply the sort too, so it returns from a handful of index
entries.  Leave that one strictly asserted so the test cannot pass vacuously if
the database is unreachable.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
GitHub's default job timeout is 360 minutes.  A job blocked on the database
therefore holds a runner for most of a working day before anyone hears about it:
one on 2026-08-06 ran 5h22m, and several others sat for hours behind the same
query while their eleven sibling jobs finished normally in 3 to 20 minutes.

A healthy job finishes well inside half an hour, the slowest green ones observed
being around 25 minutes including building the conda environment on a cache
miss, so 60 minutes leaves ample headroom while turning a lost morning into a
prompt red build.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The searches this test issued used primitive=Yes|No and parity=Odd|Even.
common_parse reads the primitivity flag from is_primitive via parse_bool, which
accepts "yes"/"no" and not "Yes"/"No", and compares parity against lowercase
"even"/"odd".  None of those four parameters were recognised, so all five
searches ran the same unfiltered conductor and order query.  They passed
because 25.d, 50.d and 56.n are all on that one query's first page.  Confirmed
against the live site: /Character/Dirichlet/?conductor=16&order=4&primitive=no
still returns the primitive orbits 16.e and 16.f.

That was already the case before this branch, but making the searches tolerate
the timeout page made it worse: five identical expensive scans, none of which
had to match a label to pass.

Use the parameter names the parser reads, and check each filter in both
directions against conductor 16 and order 4, which has a primitive even orbit
(16.e), a primitive odd one (16.f), and imprimitive even and odd ones at
modulus 32.  A filter that stops being parsed widens the search and trips a
negative assertion.  Labels carry their surrounding tags because 416 is also a
multiple of 16, so a bare '16.e' matches the '416.e' further down the page.

Both columns are pinned to single values in these searches, which matches an
index prefix and leaves the index supplying the sort, so they replace the
expensive scan rather than repeating it.  One range search remains, and it is
the only one allowed to settle for the timeout page.  The test issues six
requests, the same as before.

Verified against devmirror: passes, and the four label sets are exactly as
asserted.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The parsing-bug history and the index-prefix reasoning belong in the commit
message and the PR, not in the file.  Keep only what a reader of the test
needs: why each filter is asserted both ways, why labels carry their tags,
and why the last search tolerates a timeout.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Stop CI jobs hanging for hours on a slow database query
GitHub Actions was disabled during a recent outage; this empty commit
kicks the checks back into running.
group_jump matches the input against the regexes in gps_families, which
spell each family the way it is stored, but neither name printed on a group
page always agrees with that spelling.  The "Groups of Lie type" row prints
the family's tex_name, and for the orthogonal and unitary families that uses
other letters (Orth prints as O, GOrth as GO, Unitary as U, GUnitary as GU)
and a +/- exponent for the Plus and Minus families; the code snippets print
magma_cmd, which differs again (Orth is Magma's GO, GOrth is Magma's CO).
So 103680.a shows O(5,3) and GO(5,3) in its Lie type row and GO(5,3) and
CO(5,3) in its snippets, and none of those four could be pasted into the
jump box.

Add FAMILY_NAME_ALIASES, rewriting the family part of a Fam(n,q) name onto
the stored spelling before the gps_families regexes are tried.  Magma's GO,
GOPlus, GOMinus and GU are left out: we print GO and GU for the conformal
groups Magma calls CO and CU, so honoring Magma's reading would return a
different group from the one shown under that name.  No alias is an existing
family name, so every input accepted today still matches as before, and the
error messages keep the user's own spelling.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The redirect tests could not catch a wrong target on their own: families
such as Orth and GOrth agree for many small parameters, so a typo like
"CO": "Orth" still redirected to the expected group.

Pull the rewrite out of group_jump into normalize_family_jump, so it can be
tested as a pure function, and add three tests that fix the meaning of the
table rather than just exercising it: an independently written copy of the
expected mapping, a check that each +/- alias agrees with the alias it is
the exponent form of, and a check of the Magma half against the magma_cmd
column the code snippets are generated from, which also asks for an alias
whenever a family's Magma name differs from its own.  Strengthen the
unclaimed-alias test to probe the gps_families input regexes at both
parities and two field sizes, since those regexes are what decides which
inputs are accepted.  Move the redirect examples to parameters where an
isometry group and its similitude group have different labels.

Deliberately mutating "CO", "GU" and "GO+" to Magma's reading now fails the
tests.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Accept the family names printed on group pages in the abstract groups jump box
Add nicknames for unramified and tame p-adic fields
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add an optional database-independent precheck hook to CompletenessChecker,
running after $or/$and decomposition and before any table lookup or
null-count query.  Register an NFBound precheck that recognizes a root
discriminant range lying above the Galois root discriminant range, so the
intrinsically impossible query no longer waits on the expensive null-data
probe that CI's statement timeout cancels.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The devmirror shards share one database; cap concurrent matrix jobs at six
so functional CI does not double as an uncontrolled load test.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Raise the CI database statement timeout to 10 minutes
psycodict predicates involving None carry SQL-null semantics ({"$ne": None}
means IS NOT NULL), which to_rset misreads as empty numeric sets: None maps to
the whole real line, so its complement is empty.  The precheck could therefore
declare a nonempty search (e.g. grd IS NOT NULL, or "non-null or at most 30")
intrinsically impossible without touching the database.

Conservatively bypass the numeric precheck whenever None appears anywhere in
the rd/grd expression tree, using a sentinel so an omitted constraint stays
distinguishable from an explicit null predicate.  The numeric contradiction
fast path is unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…urrency

Avoid needless completeness queries and cap CI database concurrency
Add Sage and Oscar download links for abstract groups
Add "verified" annotations for the 97 genus 2 curves where Sha is rigorously known
@AndrewVSutherland
AndrewVSutherland merged commit 07c4985 into dev Aug 31, 2026
47 checks passed
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.

7 participants