Skip to content

Commit

Permalink
Merge pull request #6075 from AndrewVSutherland/main
Browse files Browse the repository at this point in the history
Add maximal/largest CMF search option and two small tweaks
  • Loading branch information
roed314 authored May 27, 2024
2 parents 4c35ab8 + a609797 commit 68c7b9b
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 42 deletions.
76 changes: 38 additions & 38 deletions lmfdb/classical_modular_forms/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
flash_error, to_dict, comma, display_knowl, bigint_knowl, num2letters,
SearchArray, TextBox, TextBoxNoEg, SelectBox, TextBoxWithSelect, YesNoBox,
DoubleSelectBox, RowSpacer, HiddenBox, SearchButtonWithSelect,
SubsetBox, ParityMod, CountBox, SelectBoxNoEg,
SubsetBox, ParityMod, CountBox,
StatsDisplay, proportioners, totaler, integer_divisors,
redirect_no_cache)
from psycodict.utils import range_formatter
Expand Down Expand Up @@ -779,10 +779,21 @@ def newform_parse(info, query):
parse_noop(info, query, 'atkin_lehner_string')
parse_ints(info, query, 'fricke_eigenval')
parse_bool(info, query, 'is_self_dual')
if info.get('is_maximal_largest'):
if info['is_maximal_largest'] == 'maximal':
query['is_maximal'] = True
elif info['is_maximal_largest'] == 'largest':
query['is_largest'] = True
elif info['is_maximal_largest'] == 'notlargest':
query['is_largest'] = False
parse_ints(info, query, 'hecke_ring_index')
parse_ints(info, query, 'hecke_ring_generator_nbound')
parse_noop(info, query, 'projective_image', func=str.upper)
parse_noop(info, query, 'projective_image_type')
if 'projective_image_type' in info and not 'projective_image' in info:
query['projective_image_type'] = info['projective_image_type']
elif info.get('projective_image','').lower() in ["dn","dihedral"]:
query["projective_image_type"] = "Dn"
else:
parse_noop(info, query, 'projective_image', func=str.upper)
parse_ints(info, query, 'artin_degree', name="Artin degree")

def newspace_parse(info, query):
Expand All @@ -802,7 +813,7 @@ def newspace_parse(info, query):
if info['search_type'] != 'SpaceDimensions':
parse_ints(info, query, 'num_forms', name='Number of newforms')
if 'num_forms' not in query and info.get('all_spaces') != 'yes':
# Don't show spaces that only include dimension data but no newforms (Nk2 > 4000, nontrivial character)
# Don't show spaces that only include dimension data but no newforms
query['num_forms'] = {'$exists':True}

def _trace_col(i):
Expand Down Expand Up @@ -850,6 +861,8 @@ def _AL_col(i, p):
download_col="rm_discs"),
CheckCol("is_self_dual", "cmf.selfdual", "Self-dual", default=False),
CheckCol("is_twist_minimal", "cmf.twist_minimal", "Twist minimal", default=False),
CheckCol("is_largest", "cmf.maximal", "Largest", default=False),
CheckCol("is_maximal", "cmf.maximal", "Maximal", default=False),
LinkCol("minimal_twist", "cmf.minimal_twist", "Minimal twist", url_for_label, default=False),
MathCol("inner_twist_count", "cmf.inner_twist_count", "Inner twists", default=False),
MathCol("analytic_rank", "cmf.analytic_rank", "Rank*", default=False),
Expand All @@ -869,7 +882,7 @@ def _AL_col(i, p):
MultiProcessedCol("qexp", "cmf.q-expansion", "$q$-expansion", ["label", "qexp_display"],
lambda label, disp: fr'<a href="{url_for_label(label)}">\({disp}\)</a>' if disp else "",
download_col="qexp_display")],
['analytic_conductor', 'analytic_rank', 'atkin_lehner_eigenvals', 'char_conductor', 'char_orbit_label', 'char_order', 'cm_discs', 'dim', 'relative_dim', 'field_disc_factorization', 'field_poly', 'field_poly_is_real_cyclotomic', 'field_poly_root_of_unity', 'fricke_eigenval', 'hecke_ring_index_factorization', 'inner_twist_count', 'is_cm', 'is_rm', 'is_self_dual', 'is_twist_minimal', 'label', 'level', 'minimal_twist', 'nf_label', 'prim_orbit_index', 'projective_image', 'qexp_display', 'rm_discs', 'sato_tate_group', 'trace_display', 'weight'],
['analytic_conductor', 'analytic_rank', 'atkin_lehner_eigenvals', 'char_conductor', 'char_orbit_label', 'char_order', 'cm_discs', 'dim', 'relative_dim', 'field_disc_factorization', 'field_poly', 'field_poly_is_real_cyclotomic', 'field_poly_root_of_unity', 'fricke_eigenval', 'hecke_ring_index_factorization', 'inner_twist_count', 'is_cm', 'is_largest', 'is_maximal', 'is_rm', 'is_self_dual', 'is_twist_minimal', 'label', 'level', 'minimal_twist', 'nf_label', 'prim_orbit_index', 'projective_image', 'qexp_display', 'rm_discs', 'sato_tate_group', 'trace_display', 'weight'],
tr_class=["middle bottomlined", ""])

@search_wrap(table=db.mf_newforms,
Expand Down Expand Up @@ -1554,13 +1567,6 @@ def __init__(self):
example='1-10',
example_span='1-10')

Nk2 = TextBox(
name='Nk2',
knowl='cmf.nk2',
label=r'\(Nk^2\)',
example='40-100',
example_span='40-100')

cm = SelectBox(
name='cm',
options=[('', 'any CM'), ('yes', 'has CM'), ('no', 'no CM')],
Expand Down Expand Up @@ -1600,6 +1606,12 @@ def __init__(self):
knowl='cmf.selfdual',
label='Is self-dual')

is_maximal_largest = SelectBox(
name='is_maximal_largest',
knowl='cmf.maximal',
label='Is maximal/largest',
options=[('',''),('maximal','maximal'),('largest','largest'),('notlargest','not largest')])

coefficient_ring_index = TextBox(
name='hecke_ring_index',
label='Coefficient ring index',
Expand All @@ -1625,19 +1637,8 @@ def __init__(self):
name='projective_image',
label='Projective image',
knowl='cmf.projective_image',
example='D15',
example_span='weight 1 only')

projective_image_type = SelectBoxNoEg(
name='projective_image_type',
knowl='cmf.projective_image',
label='Projective image type',
options=[('', ''),
('Dn', 'Dn'),
('A4', 'A4'),
('S4', 'S4'),
('A5','A5')],
example_span='weight 1 only')
example='Dn',
example_span='A5, D7, or Dn; weight 1 only')

num_newforms = TextBox(
name='num_forms',
Expand Down Expand Up @@ -1685,29 +1686,28 @@ def __init__(self):
[level, weight],
[level_primes, character],
[char_order, char_primitive],
[dim, analytic_rank],
[analytic_conductor, Nk2],
[dim, is_maximal_largest],
[analytic_conductor, analytic_rank],
[coefficient_field, is_self_dual],
[inner_twist_count, is_twist_minimal],
[self_twist_discs, self_twist],
[coefficient_ring_index, hecke_ring_generator_nbound],
[projective_image, projective_image_type],
[results]]
[self_twist_discs, self_twist],
[inner_twist_count, is_twist_minimal],
[results, projective_image]]

self.refine_array = [
[level, weight, analytic_conductor, analytic_rank, dim],
[level_primes, character, char_primitive, char_order, coefficient_field],
[self_twist, self_twist_discs, inner_twist_count, is_twist_minimal, is_self_dual],
[Nk2, coefficient_ring_index, hecke_ring_generator_nbound, projective_image, projective_image_type]]
[level_primes, character, char_primitive, char_order, is_maximal_largest],
[coefficient_field, self_twist, self_twist_discs, inner_twist_count, is_self_dual],
[coefficient_ring_index, hecke_ring_generator_nbound, is_twist_minimal, projective_image]]

self.space_array = [
[level, weight, analytic_conductor, Nk2, dim],
[level_primes, character, char_primitive, char_order, num_newforms]
[level, weight, analytic_conductor, dim, num_newforms],
[level_primes, character, char_primitive, char_order]
]

self.sd_array = [
[level, weight, analytic_conductor, Nk2, hdim],
[level_primes, character, char_primitive, char_order, hnum_newforms]
[level, weight, analytic_conductor, hdim, hnum_newforms],
[level_primes, character, char_primitive, char_order]
]

self.traces_array = [
Expand Down
23 changes: 23 additions & 0 deletions lmfdb/classical_modular_forms/test_cmf.py
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,29 @@ def test_convert_conreylabels(self):
page = self.tc.get('/ModularForm/GL2/Q/holomorphic/38/9/d/a/%d/%d/' % (c, e),follow_redirects=True)
assert "Newform orbit 38.9.d.a" in page.get_data(as_text=True)

def test_maximal(self):
page = self.tc.get("/ModularForm/GL2/Q/holomorphic/?level=1234&weight=2")
assert '15 matches' in page.get_data(as_text=True)
assert '1234.2.a.h' in page.get_data(as_text=True)
assert '1234.2.a.i' in page.get_data(as_text=True)
assert '1234.2.b.c' in page.get_data(as_text=True)
page = self.tc.get("/ModularForm/GL2/Q/holomorphic/?level=1234&weight=2&is_maximal_largest=maximal")
assert 'unique match' in page.get_data(as_text=True)
assert not '1234.2.a.h' in page.get_data(as_text=True)
assert '1234.2.a.i' in page.get_data(as_text=True)
assert not '1234.2.b.c' in page.get_data(as_text=True)
page = self.tc.get("/ModularForm/GL2/Q/holomorphic/?level=1234&weight=2&is_maximal_largest=largest")
assert '5 matches' in page.get_data(as_text=True)
assert '1234.2.a.h' in page.get_data(as_text=True)
assert '1234.2.a.i' in page.get_data(as_text=True)
assert not '1234.2.b.c' in page.get_data(as_text=True)
page = self.tc.get("/ModularForm/GL2/Q/holomorphic/?level=1234&weight=2&is_maximal_largest=notlargest")
assert '10 matches' in page.get_data(as_text=True)
assert not '1234.2.a.h' in page.get_data(as_text=True)
assert not '1234.2.a.i' in page.get_data(as_text=True)
assert '1234.2.b.c' in page.get_data(as_text=True)


def test_dim_table(self):
page = self.tc.get("/ModularForm/GL2/Q/holomorphic/?weight=12&level=23&search_type=Dimensions", follow_redirects=True)
assert 'Dimension search results' in page.get_data(as_text=True)
Expand Down
2 changes: 1 addition & 1 deletion lmfdb/classical_modular_forms/test_cmf2.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ def test_trivial_searches(self):
('level=900-1000&weight=1-&projective_image=D2',
['Results (26 matches)', r"\sqrt{-1}", r"\sqrt{-995}", r"\sqrt{137}"]
)]:
for s in Subsets(['has_self_twist=yes', 'has_self_twist=cm', 'has_self_twist=rm', 'projective_image_type=Dn','dim=1-4']):
for s in Subsets(['has_self_twist=yes', 'has_self_twist=cm', 'has_self_twist=rm', 'projective_image=Dn','dim=1-4']):
s = '&'.join(['/ModularForm/GL2/Q/holomorphic/?search_type=List', begin[0]] + list(s))
page = self.tc.get(s, follow_redirects=True)
for elt in begin[1]:
Expand Down
11 changes: 8 additions & 3 deletions lmfdb/classical_modular_forms/web_newform.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from flask import url_for
from lmfdb.characters.TinyConrey import get_sage_genvalues, ConreyCharacter
from sage.all import (prime_range, latex, QQ, PolynomialRing, prime_pi, gcd,
from sage.all import (prime_range, latex, QQ, PolynomialRing, prime_pi, gcd, previous_prime,
CDF, ZZ, CBF, cached_method, vector, lcm, RR, lazy_attribute)
from sage.databases.cremona import cremona_letter_code, class_to_int

Expand Down Expand Up @@ -182,7 +182,12 @@ def __init__(self, data, space=None, all_m=False, all_n=False, embedding_label=N
self.hecke_ring_cyclotomic_generator = None # in case there is no data in mf_hecke_nf
if self.embedding_label is None:
hecke_cols = ['hecke_ring_numerators', 'hecke_ring_denominators', 'hecke_ring_inverse_numerators', 'hecke_ring_inverse_denominators', 'hecke_ring_cyclotomic_generator', 'hecke_ring_character_values', 'hecke_ring_power_basis', 'maxp']
eigenvals = db.mf_hecke_nf.lucky({'hecke_orbit_code': self.hecke_orbit_code}, ['an'] + hecke_cols)
if self.dim == 1:
# avoid using mf_hecke_nf when the dimension is 1
vals = ConreyCharacter(self.level, db.char_dirichlet.lookup("%s.%s"%(self.level,self.char_orbit_label),projection="first")).values_gens
eigenvals = { 'hecke_ring_cyclotomic_generator': 0, 'hecke_ring_character_values': vals, 'hecke_ring_power_basis': True, 'maxp': previous_prime(len(self.traces)+1), 'an': self.traces }
else:
eigenvals = db.mf_hecke_nf.lucky({'hecke_orbit_code': self.hecke_orbit_code}, ['an'] + hecke_cols)
if eigenvals and eigenvals.get('an'):
self.has_exact_qexp = True
for attr in hecke_cols:
Expand Down Expand Up @@ -1202,7 +1207,7 @@ def to_list(data):
return []
out = [0]*(max(e for _, e in data) + 1)
for c, e in data:
out[e] = c
out[e] += c
return out
coeffs = [to_list(data) for data in self.qexp[:prec]]
return raw_typeset_qexp(coeffs, superscript=True, var=self._zeta_print, final_rawvar='z')
Expand Down

0 comments on commit 68c7b9b

Please sign in to comment.