Skip to content

Commit 12c42c4

Browse files
roed314claude
andcommitted
Address review: pin the Conway generator convention and test the projection (LMFDB#6975)
The download description for the Curves column said only that "a" denotes a generator of the base field over its prime field, which does not pin down the stored equations: a finite field has many generators, and a different choice changes the coefficients. Give the same convention the isogeny class homepage does, namely that a is the image of x in GF(p)[x]/(C(x)) for C the degree r Conway polynomial used by the LMFDB, and stop conflating the two missing-data states: null means the curves have not been computed, while an empty list means the computation was carried out and there are no such curves (spot checks confirm this reading: whole (g, q) blocks are either uncomputed or fully computed, and in the computed blocks the empty lists fall exactly on the classes recorded as containing no Jacobian). Also cover the conditional projection with tests. test_curves_projection pins both directions - curves is absent from db_cols, curves_requested is false by default and true with showcol=curves, the search sets __projection__ only when the column is shown, AbvarFq_download.get_projection adds curves only then, and the generic Downloader.get_projection still just restricts db_cols to the table's columns. test_curves_not_computed replaces the weak "label appears on the page" check with assertions on the rendered Curves cells and on the downloaded values, and test_curves_search_column now checks the raw equations plus the Conway polynomial wording in every non-CSV language, gp included since that is what the issue asked for. Verified with sage -python: 22 abvar/fq tests pass (20 before, two new), number-field and local-field download tests pass, pyflakes and ruff clean, and sage/gp downloads inspected by hand for a computed row, a NULL row (None/null) and an empty list row ([]). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent 01e625d commit 12c42c4

2 files changed

Lines changed: 89 additions & 5 deletions

File tree

lmfdb/abvar/fq/main.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -707,7 +707,12 @@ def extended_code(c):
707707
MathCol("jacobian_count", "av.jacobian_count", "Jacobians", default=False),
708708
MathCol("hyp_count", "av.hyperelliptic_count", "Hyperelliptic Jacobians", default=False),
709709
ProcessedCol("curves", "ag.jacobian", "Curves", curves_display_search, default=False,
710-
download_desc="Equations of curves whose Jacobians are in the isogeny class. For a base field GF(p^r) with r > 1, the variable a denotes a generator of the base field over its prime field. The list may be empty or missing if no such curves are known."),
710+
download_desc="Equations of curves whose Jacobians are in the isogeny class.\n"
711+
"For a base field GF(p^r) with r > 1, the variable a is the image of x in GF(p)[x]/(C(x)),\n"
712+
"where C is the degree r Conway polynomial over GF(p) used by the LMFDB;\n"
713+
"equivalently, a is a root of that Conway polynomial.\n"
714+
"A null value means that the curves in this isogeny class have not been computed;\n"
715+
"an empty list means that the computation was carried out and there are no such curves."),
711716
MathCol("twist_count", "av.twist", "Num. twists", default=False),
712717
MathCol("max_twist_degree", "av.twist", "Max. twist degree", default=False),
713718
MathCol("geometric_extension_degree", "av.endomorphism_field", "End. degree", default=False),

lmfdb/abvar/fq/test_av.py

Lines changed: 83 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -169,12 +169,91 @@ def test_curves_search_column(self):
169169
page = self.tc.get("/Variety/Abelian/Fq/?q=4&g=1&showcol=curves").get_data(as_text=True)
170170
assert "$y^2+y=x^3+a$" in page
171171
assert "$y^2+a y=x^3$ and 1 more" in page
172-
# Search downloads contain the full lists
173-
data = self.tc.get("/Variety/Abelian/Fq/?q=4&g=1&showcol=curves&Submit=sage&download=1&query=%7B%27q%27%3A+4%2C+%27g%27%3A+1%7D").get_data(as_text=True)
174-
assert '["y^2+a*y=x^3", "y^2+(a+1)*y=x^3"]' in data
175-
# Classes for which curves have not been computed display an empty cell
172+
# Search downloads contain the full lists of raw equations, over a non-prime
173+
# base field as well, and say which generator a of that field is meant.
174+
# The gp download matters for LMFDB#6975, which asked for these equations in PARI/GP.
175+
query = "query=%7B%27q%27%3A+4%2C+%27g%27%3A+1%7D"
176+
for lang in ["sage", "gp", "magma", "oscar", "gap", "text"]:
177+
data = self.tc.get("/Variety/Abelian/Fq/?q=4&g=1&showcol=curves&download=1&Submit=%s&%s" % (lang, query)).get_data(as_text=True)
178+
assert '["y^2+a*y=x^3", "y^2+(a+1)*y=x^3"]' in data
179+
assert "Conway polynomial" in data
180+
# csv files hold the equations but cannot carry the explanatory comments
181+
data = self.tc.get("/Variety/Abelian/Fq/?q=4&g=1&showcol=curves&download=1&Submit=csv&" + query).get_data(as_text=True)
182+
assert "y^2+a*y=x^3" in data
183+
assert "Conway polynomial" not in data
184+
185+
def test_curves_projection(self):
186+
r"""
187+
Check that the (heavy) curves arrays are fetched from the database only when the
188+
Curves column is actually displayed or downloaded (LMFDB#6975).
189+
"""
190+
from lmfdb.utils import Downloader
191+
from lmfdb.abvar.fq.download import AbvarFq_download
192+
from lmfdb.abvar.fq.main import abelian_variety_search, abvar_columns, curves_requested
193+
194+
# curves is deliberately absent from the fixed projection used by every search
195+
assert "curves" not in abvar_columns.db_cols
196+
assert not curves_requested({})
197+
assert curves_requested({"showcol": "curves"})
198+
199+
# the search adds it to the projection only when the column is shown
200+
with self.app.test_request_context("/Variety/Abelian/Fq/?q=4&g=1"):
201+
query = {}
202+
abelian_variety_search.f({"q": "4", "g": "1"}, query)
203+
assert "__projection__" not in query
204+
query = {}
205+
abelian_variety_search.f({"q": "4", "g": "1", "showcol": "curves"}, query)
206+
assert "curves" in query["__projection__"]
207+
208+
# and so do downloads of search results
209+
downloader = AbvarFq_download()
210+
default_projection = downloader.get_projection({}, self.db.av_fq_isog, abvar_columns)
211+
curves_projection = downloader.get_projection({"showcol": "curves"}, self.db.av_fq_isog, abvar_columns)
212+
assert "curves" not in default_projection
213+
assert "curves" in curves_projection
214+
215+
# the generic hook is unchanged: it only restricts db_cols to the table's columns
216+
generic = Downloader().get_projection({"showcol": "curves"}, self.db.av_fq_isog, abvar_columns)
217+
assert generic == default_projection
218+
assert generic == [col for col in abvar_columns.db_cols if col in self.db.av_fq_isog.search_cols]
219+
220+
def test_curves_not_computed(self):
221+
r"""
222+
Isogeny classes whose curves have not been computed (NULL in the database) must be
223+
distinguishable in downloads from those searched without finding a curve (an empty list).
224+
"""
225+
import re
226+
from lmfdb.utils.downloader import GPLanguage, SageLanguage
227+
from lmfdb.abvar.fq.isog_class import AbvarFq_isoclass
228+
from lmfdb.abvar.fq.main import abvar_columns
229+
230+
curves_col = [col for col in abvar_columns.columns if col.name == "curves"][0]
231+
# the curves of 2.729.aee_gmg have not been computed (psycodict omits the NULL column)
232+
not_computed = AbvarFq_isoclass(self.db.av_fq_isog.lookup("2.729.aee_gmg", ["label", "curves"]))
233+
assert not_computed.curves is None
234+
# 2.3.ag_p was searched, and contains no curve
235+
no_curve = AbvarFq_isoclass(self.db.av_fq_isog.lookup("2.3.ag_p", ["label", "curves"]))
236+
assert no_curve.curves == []
237+
# both display as an empty cell
238+
assert curves_col.display(not_computed) == ""
239+
assert curves_col.display(no_curve) == ""
240+
# but downloads give the language's null value for the uncomputed one
241+
assert SageLanguage().to_lang(curves_col.download(not_computed)) == "None"
242+
assert GPLanguage().to_lang(curves_col.download(not_computed)) == "null"
243+
assert SageLanguage().to_lang(curves_col.download(no_curve)) == "[]"
244+
assert GPLanguage().to_lang(curves_col.download(no_curve)) == "[]"
245+
246+
# the cells on the search page are empty, rather than showing None
176247
page = self.tc.get("/Variety/Abelian/Fq/?q=729&g=2&showcol=curves").get_data(as_text=True)
177248
assert "2.729.aee_gmg" in page
249+
cells = re.findall(r'<td class="col-curves"[^>]*>(.*?)</td>', page, re.S)
250+
assert cells and not any(cell.strip() for cell in cells)
251+
252+
# and downloading such a row gives null (here we hide every other column)
253+
hidecol = ".".join(col.name for col in abvar_columns.columns if col.default({}))
254+
url = "/Variety/Abelian/Fq/?q=729&g=2&showcol=curves&hidecol=%s&download=1&download_row_count=2&Submit=%s&query=%%7B%%27q%%27%%3A+729%%2C+%%27g%%27%%3A+2%%7D"
255+
assert "[None]" in self.tc.get(url % (hidecol, "sage")).get_data(as_text=True)
256+
assert "[null]" in self.tc.get(url % (hidecol, "gp")).get_data(as_text=True)
178257

179258
def test_cyclic_group_of_points_display(self):
180259
r"""

0 commit comments

Comments
 (0)