diff --git a/lmfdb/characters/main.py b/lmfdb/characters/main.py index b120ebc429..c07ed9f0e3 100644 --- a/lmfdb/characters/main.py +++ b/lmfdb/characters/main.py @@ -4,7 +4,7 @@ from lmfdb.app import app import re from flask import render_template, url_for, request, redirect, abort -from sage.all import euler_phi, PolynomialRing, QQ, gcd +from sage.all import euler_phi, PolynomialRing, QQ, gcd, ZZ from lmfdb.utils import ( to_dict, flash_error, SearchArray, YesNoBox, display_knowl, ParityBox, TextBox, CountBox, parse_bool, parse_ints, search_wrap, raw_typeset_poly, @@ -14,7 +14,9 @@ from lmfdb.characters.utils import url_character from lmfdb.characters.TinyConrey import ConreyCharacter from lmfdb.api import datapage +from lmfdb.number_fields.web_number_field import formatfield from lmfdb.characters.web_character import ( + valuefield_from_order, WebSmallDirichletCharacter, WebDBDirichletCharacter, WebDBDirichletGroup, @@ -216,7 +218,6 @@ def url_for_label(label): return url_for(".render_Dirichletwebpage", modulus=modulus, orbit_label=orbit_label, number=number) def display_galois_orbit(modulus, first, last, degree): - if degree == 1: disp = r'\(\chi_{{{0}}}({1}, \cdot)\)'.format(modulus, first) return f'

\n{disp}\n

' @@ -230,6 +231,13 @@ def display_galois_orbit(modulus, first, last, degree): disp = r"$, \cdots ,$".join(disp) return f'

\n{disp}\n

' +def display_kernel_field(modulus, first, order): + if order > 12: + return "not computed" + else: + coeffs = ConreyCharacter(modulus,first).kernel_field_poly() + return formatfield([ZZ(x) for x in coeffs]) + character_columns = SearchColumns([ LinkCol("label", "character.dirichlet.galois_orbit_label", "Orbit label", lambda label: label.replace(".", "/"), align="center"), MultiProcessedCol("conrey", "character.dirichlet.conrey", "Conrey labels", ["modulus", "first", "last", "degree"], @@ -237,6 +245,8 @@ def display_galois_orbit(modulus, first, last, degree): MathCol("modulus", "character.dirichlet.modulus", "Modulus"), MathCol("conductor", "character.dirichlet.conductor", "Conductor"), MathCol("order", "character.dirichlet.order", "Order"), + MultiProcessedCol("first", "character.dirichlet.field_cut_out", "Kernel field", ["modulus", "first", "order"], display_kernel_field, align="center", default=False, apply_download=False), + ProcessedCol("order", "character.dirichlet.value_field", "Value field", valuefield_from_order, align="center", apply_download=False), ProcessedCol("is_even", "character.dirichlet.parity", "Parity", lambda is_even: "even" if is_even else "odd"), CheckCol("is_real", "character.dirichlet.real", "Real"), CheckCol("is_primitive", "character.dirichlet.primitive", "Primitive"), diff --git a/lmfdb/characters/web_character.py b/lmfdb/characters/web_character.py index 92e4fcf427..efed78d24e 100644 --- a/lmfdb/characters/web_character.py +++ b/lmfdb/characters/web_character.py @@ -70,6 +70,20 @@ def compute_values(chi, groupelts): "Helper function to compute values of several elements on the fly" return [[k, int(chi.conreyangle(k) * chi.order)] for k in groupelts] +def valuefield_from_order(order): + order2 = order if order % 4 != 2 else order / 2 + nf = WebNumberField.from_cyclo(order2) + if not nf.is_null(): + if order2 == 3: + nfpretty = r'\(\mathbb{Q}(\zeta_3)\)' + elif order2 == 4: + nfpretty = r'\(\mathbb{Q}(i)\)' + else: + nfpretty = nf.field_pretty() + return nf_display_knowl(nf.get_label(), nfpretty) + else: + return r'$\Q(\zeta_{%d})$' % order2 + ############################################################################# ### ### Class for Web objects @@ -486,12 +500,7 @@ def vflabel(self): @lazy_attribute def valuefield(self): - order2 = self.order if self.order % 4 != 2 else self.order / 2 - nf = WebNumberField.from_cyclo(order2) - if not nf.is_null(): - return nf_display_knowl(nf.get_label(), nf.field_pretty()) - else: - return r'$\Q(\zeta_{%d})$' % order2 + return valuefield_from_order(self.order) @lazy_attribute def kerfield(self): diff --git a/lmfdb/hypergm/main.py b/lmfdb/hypergm/main.py index 95fe8fb0de..fd1ba61874 100644 --- a/lmfdb/hypergm/main.py +++ b/lmfdb/hypergm/main.py @@ -13,7 +13,7 @@ image_callback, flash_error, list_to_factored_poly_otherorder, clean_input, parse_ints, parse_bracketed_posints, parse_rational, parse_restricted, integer_options, search_wrap, Downloader, - SearchArray, TextBox, TextBoxNoEg, SelectBox, CountBox, BasicSpacer, SearchButton, + SearchArray, TextBox, TextBoxNoEg, SelectBox, CountBox, BasicSpacer, SearchButton, RowSpacer, to_dict, web_latex, integer_divisors) from lmfdb.utils.interesting import interesting_knowls from lmfdb.utils.search_columns import SearchColumns, MathCol, ProcessedCol, MultiProcessedCol, RationalCol @@ -411,7 +411,7 @@ def get_table(self, info): @search_wrap(table=db.hgm_motives, # overridden if family search - title=r'Hypergeometric motive over $\Q$ search resultS', + title=r'Hypergeometric motive over $\Q$ search results', err_title=r'Hypergeometric motive over $\Q$ search input error', columns=hgm_columns, per_page=50, @@ -455,9 +455,9 @@ def hgm_search(info, query): parse_ints(info, query, 'degree') parse_ints(info, query, 'weight') parse_bracketed_posints(info, query, 'famhodge', 'family Hodge vector', split=True) - parse_restricted(info, query, 'sign', allowed=['+1', 1, -1], process=int) # Make a version to search reversed way if search_type not in ["Family", "RandomFamily"]: + parse_restricted(info, query, 'sign', allowed=['+1', 1, -1], process=int) parse_ints(info, query, 'conductor', 'Conductor', 'cond') parse_rational(info, query, 't') parse_bracketed_posints(info, query, 'hodge', 'Hodge vector') @@ -794,24 +794,28 @@ def __init__(self): label="Conductor", knowl="hgm.conductor", example="64", - example_span="a value, like 32, a list, like 32,64, or a range like 1..10000") + example_span="a value, like 32, a list, like 32,64, or a range like 1..10000", + extra=['class="motive"']) hodge = TextBox( name="hodge", label="Hodge vector", - knowl="mot.hodgevector", - example="[1,1,1,1]") + knowl="hgm.hodge_vector", + example="[1,1,1,1]", + extra=['class="motive"']) t = TextBox( name="t", label="Specialization point $t$", knowl="hgm.specpoint", example="3/2", - example_span="3/2 (1 has an associated degree drop and is always in the database)") + example_span="3/2 (1 has an associated degree drop and is always in the database)", + extra=['class="motive"']) sign = TextBoxNoEg( name="sign", label=r"Root number $\epsilon$", knowl="lfunction.sign", example="-1", - example_span="1 or -1, with -1 occurring only in the symplectic case") + example_span="1 or -1, with -1 occurring only in the symplectic case", + extra=['class="motive"']) # The following two boxes are not yet enabled # generic = YesNoBox( # name="generic", @@ -848,15 +852,7 @@ def __init__(self): def search_types(self, info): st = self._st(info) if st is None: - # We need a custom button for the family search so that it can be clicked by javascript - class FamilySearchButton(SearchButton): - def _input(self, info): - btext = "" - return btext.format(width=self.width, desc=self.description) - return [("Motive", "List of motives"), - FamilySearchButton("Family", "List of families"), - ("Random", "Random motive"), - ("RandomFamily", "Random family")] + raise RuntimeError("Should never get here") elif st == "Family": return [("Family", "Search again"), ("RandomFamily", "Random family")] @@ -871,10 +867,23 @@ def main_array(self, info): else: return self.refine_motive_array + def _html_section(self, array, buttons): + table = self._print_table(array, None, "horizontal") + buttons = self._print_table([RowSpacer(8), [BasicSpacer("Display:")] + buttons], None, "vertical") + return "\n".join([table, buttons]) + def family_html(self): - return self._print_table(self.family_array, None, "horizontal") + # We need a custom button for the family search so that it can be clicked by javascript + class FamilySearchButton(SearchButton): + def _input(self, info): + btext = "" + return btext.format(width=self.width, desc=self.description) + return self._html_section(self.family_array, [FamilySearchButton("Family", "List of families"), SearchButton("RandomFamily", "Random family")]) def motive_html(self): - table = self._print_table(self.motive_array, None, "horizontal") - buttons = self.buttons() - return "\n".join([table, buttons]) + # We need a custom button for the motive search so that it can be clicked by javascript + class MotiveSearchButton(SearchButton): + def _input(self, info): + btext = "" + return btext.format(width=self.width, desc=self.description) + return self._html_section(self.motive_array, [MotiveSearchButton("Motive", "List of motives"), SearchButton("RandomMotive", "Random motive")]) diff --git a/lmfdb/hypergm/templates/hgm-index.html b/lmfdb/hypergm/templates/hgm-index.html index 9b0c72606e..5ea9aeb9a6 100644 --- a/lmfdb/hypergm/templates/hgm-index.html +++ b/lmfdb/hypergm/templates/hgm-index.html @@ -164,13 +164,13 @@

Browse