From 748efce7e780ce8e2b8161c46120ba3f7a16ee44 Mon Sep 17 00:00:00 2001 From: assaferan Date: Fri, 19 Aug 2022 09:49:57 -0400 Subject: [PATCH 001/482] attempt 1 --- .../DESIGN_CONSIDERATIONS.md | 139 -- lmfdb/siegel_modular_forms/__init__.py | 1 + lmfdb/siegel_modular_forms/dimensions.py | 657 ------ lmfdb/siegel_modular_forms/family.py | 71 - lmfdb/siegel_modular_forms/family_data.py | 101 - lmfdb/siegel_modular_forms/siegel_core.py | 655 ----- .../siegel_modular_form.py | 2098 ++++++++++++++--- lmfdb/siegel_modular_forms/smf_test_pages.py | 33 - .../test_siegel_modular_forms.py | 164 -- 9 files changed, 1788 insertions(+), 2131 deletions(-) delete mode 100644 lmfdb/siegel_modular_forms/DESIGN_CONSIDERATIONS.md delete mode 100644 lmfdb/siegel_modular_forms/dimensions.py delete mode 100644 lmfdb/siegel_modular_forms/family.py delete mode 100644 lmfdb/siegel_modular_forms/family_data.py delete mode 100644 lmfdb/siegel_modular_forms/siegel_core.py delete mode 100644 lmfdb/siegel_modular_forms/smf_test_pages.py delete mode 100644 lmfdb/siegel_modular_forms/test_siegel_modular_forms.py diff --git a/lmfdb/siegel_modular_forms/DESIGN_CONSIDERATIONS.md b/lmfdb/siegel_modular_forms/DESIGN_CONSIDERATIONS.md deleted file mode 100644 index 3fe863139f..0000000000 --- a/lmfdb/siegel_modular_forms/DESIGN_CONSIDERATIONS.md +++ /dev/null @@ -1,139 +0,0 @@ -# The (new) design of the Siegel modular forms part of the LMFDB - -## Author: Nils Skoruppa , September 2013 - - -The pages in the package siegel_modular_forms (SMF) provide a view on -samples of Siegel modular forms or eigenvalue packages of all kind. A -single sample will ideally provide, (aside from some meta information -like origin, creators etc.), Fourier coefficients, explicit formulas, -eigenvalues, weights, group(s) and character(s). A sample should be -uniquely identifiable by name. To set up such a unique name we -subdivide our forms into collections (which, however, are allowed to -overlap). A unique identifier is then - - `collection.weight.type.no` - -like e.g. `Sp4Z.4.Eis.1` or `Gamma_2.30.Cusp.1`. The choice of -collections has to ensure that these naming scheme makes our samples -uniquely identifiable by name. The `no` is arbitrarily chosen -according to the *begin of membership*, ı.e. *last in gets the smallest -free number*. Note that a sample will then possibly have several -unique identifiers. - -For achieving this presentation of data we have to prepare three -layers: - - 1. the organization of data in the data base - 2. the physical layout of data in web pages. - 3. the encapsulation of data in compound objects - - -### 1. Organization of data - -The data should be represented as instances of the following objects. - -``` - Family/Collection - /\ - | - | - Fourier coefficients <--- Sample --> Eigenvalues - | - | - \/ - Field -``` - -The arrow indicates that every sample contains exactly one pointer to -an instance of field, Fourier coefficients, eigenvalues and -collection. Two instances of sample are *semantically identical* if -their Fourier coefficients are the same (since we shall have only -finitely many Fourier coefficients we have to make sure that two -instances point to the same Fourier coefficients only if we are sure -that they are indeed mathematically identical). - - -### 2. Physical layout of data - -According to the *BROWSE and SEARCH* paradigm of the lmfdb project -the entrance page of the SMF will provide - - * fields for browsing (i.e. providing views of the available forms ordered) - * by family/collection - * by weight - * by group - * by degree of fields - * and to browse dimensions - - * forms for providing searches for available samples - on restricting the search by - * weight - * group - * degree of the number field - * ??? - * and a form to fetch a specific sample (using 'expert' knowledge). - -The collection pages (which you reach by choosing a collection) -provide background information about the collection and a dimension -calculator (if this make sense and dimensions are known). - - -### 3. Encapsulation of data - -A collection consists of a set of data of a certain type of -automorphic forms. Every collection will be represented by its own -home page, which shows which data are available for browsing or -searching. Codewise, collections are instances of the class -Collection. - -Possible data are - - * group - * character - * sym_pow - * dimension (a function computing dimensions - for subspaces for this type of forms) - * generators - * description - * learnmore page - -Methods are (aside from providing the above data) - - * dimension (calculation on the fly or look up) - * members (look up in the db). - -### The members of a collection - -is a set of forms, which are implemented by -the class Sample. The typical date of a form are - - * Fourier coefficients - * eigenvalues - * weight - * list of collections it belongs to - * the creator(s) of the data - * explicit formula(s) (polynomial in generators of a ring of - automorphic forms, a modular form whose arithmetic/multiplicative - lift it is etc.) - -The last sort of data is still a challenge and we push its -implementation until we have enough examples to respond to. - -### Finally - -we will not be STRICT, i.e. we never force a collection or a form to -possess desired date (since because of the complexity of the involved -computations or diverging goals of the donators these cannot always be -provided). If some requested data are not available we return -'None'. The rendering machinery has to take care of this possible -answer. This approach makes it possible that we can easily plugin new -collections even if the provided data do not exhibit an ideal -completeness. - -In particular, we should be prepared to have samples with only one of -the possible informations 'field', 'Fourier coefficients' or -'eigenvalues'. This might lead to somewhat strange collections like -e.g. 'Gamma0(5)_fields'. However, since even such informations are -worthy in view of the computational complexity of Siegel modular forms -we are happy to present them. \ No newline at end of file diff --git a/lmfdb/siegel_modular_forms/__init__.py b/lmfdb/siegel_modular_forms/__init__.py index 65cad9edde..1e7aba3c1b 100644 --- a/lmfdb/siegel_modular_forms/__init__.py +++ b/lmfdb/siegel_modular_forms/__init__.py @@ -6,6 +6,7 @@ smf_page = Blueprint('smf', __name__, template_folder='templates', static_folder='static') +smf = smf_page smf_logger = make_logger(smf_page) diff --git a/lmfdb/siegel_modular_forms/dimensions.py b/lmfdb/siegel_modular_forms/dimensions.py deleted file mode 100644 index 5ddb37ae8b..0000000000 --- a/lmfdb/siegel_modular_forms/dimensions.py +++ /dev/null @@ -1,657 +0,0 @@ -# -*- coding: utf-8 -*- -# This file provides functions for computing dimensions of -# collections of Siegel modular forms. It is partly based on -# code implemented together with David Yuen and Fabien Cléry. -# -# Author: Nils Skoruppa - -from sage.all import is_odd, is_even, ZZ, QQ, FunctionField, PowerSeriesRing -from lmfdb.utils import flash_error - -from lmfdb import db -from lmfdb.utils import parse_ints_to_list_flash - -MAXWT = 9999 -MAXWTRANGE = 100 -MAXJ = 99 - -#################################################################### -## For general dimension related data from the data base -## For Release 1.0 this is only relevant to Gamma_2 -#################################################################### - -def parse_dim_args(dim_args, default_dim_args): - res={} - for v in ['k','j']: - arg = dim_args.get(v) if dim_args else None - if not arg: - arg = default_dim_args.get(v) if default_dim_args else None - if arg: - res[v] = parse_ints_to_list_flash(arg, "$"+v+"$") - args={} - if 'k' in res: - if res['k'][-1] > MAXWT: - flash_error("$k$ cannot exceed %s.", MAXWT) - raise ValueError("dim_args") - if len(res['k']) > MAXWTRANGE: - flash_error("range for $k$ cannot include more than %s values.", MAXWTRANGE) - raise ValueError("dim_args") - args = {'k_range':res['k']} - if 'j' in res: - if res['j'][-1] > MAXJ: - flash_error("$j$ cannot exceed %s.", MAXJ) - raise ValueError("dim_args") - args['j_range'] = [j for j in res['j'] if j%2 == 0] - if not args['j_range']: - flash_error("$j$ should be a nonnegative even integer.") - raise ValueError("dim_args") - return args - -#################################################################### -## Dimension formulas for Gamma(2), Gamma0(2), Gamma1(2), Sp4(Z) -#################################################################### - -def dimension_Gamma_2(wt_range, j): - r""" -
    -
  • First entry of the respective triple: The full space.
  • -
  • Second entry: The codimension of the subspace of cusp forms.
  • -
  • Third entry: The subspace of cusp forms.
  • -
-

More precisely, The triple $[a,b,c]$ in -

    -
  • - row All - and in in the $k$th column shows the dimension of - the full space $M_{k,j}(\Gamma(2))$, - of the non cusp forms, and of the cusp forms.
  • -
  • - in row $p$, where $p$ is a partition of $6$, - and in in the $k$th column shows the multiplicity of the - $\mathrm{Sp}(4,\Z)$-representation - associated to $p$ in the full $\mathrm{Sp}(4,\Z)$-module - $M_{k,j}(\Gamma(2))$, - in the submodule of non cusp forms and of cusp forms. - (See below for details.) -
  • -
- - """ - return _dimension_Gamma_2(wt_range, j, group = 'Gamma(2)') - -def dimension_Gamma1_2(wt_range, j): - r""" -
    -
  • First entry of the respective triple: The full space.
  • -
  • Second entry: The codimension of the subspace of cusp forms.
  • -
  • Third entry: The subspace of cusp forms.
  • -
-

More precisely, The triple $[a,b,c]$ in -

    -
  • - row All - and in in the $k$th column shows the dimension of - the full space $M_{k,j}(\Gamma(2))$, - of the non cusp forms, and of the cusp forms.
  • -
  • - in row $p$, where $p$ is a partition of $3$, - and in in the $k$th column shows the multiplicity of the - $\Gamma_1(2)$-representation - associated to $p$ in the full $\Gamma_1(2)$-module $M_{k,j}(\Gamma(2))$, - in the submodule of non cusp forms and of cusp forms. - (See below for details.) -
  • -
- """ - return _dimension_Gamma_2(wt_range, j, group = 'Gamma1(2)') - -def dimension_Gamma0_2(wt_range, j): - """ -
    -
  • Total: The full space.
  • -
  • Non cusp: The codimension of the subspace of cusp forms.
  • -
  • Cusp: The subspace of cusp forms.
  • -
- """ - return _dimension_Gamma_2(wt_range, j, group = 'Gamma0(2)') - -def dimension_Sp4Z(wt_range): - """ -
    -
  • Total: The full space.
  • -
  • Eisenstein: The subspace of Siegel Eisenstein series.
  • -
  • Klingen: The subspace of Klingen Eisenstein series.
  • -
  • Maass: The subspace of Maass liftings.
  • -
  • Interesting: The subspace spanned by cuspidal eigenforms that are not Maass liftings.
  • -
- """ - return _dimension_Sp4Z(wt_range) - -def dimension_Sp4Z_2(wt_range): - """ -
    -
  • Total: The full space.
  • -
  • Non cusp: The subspace of non cusp forms.
  • -
  • Cusp: The subspace of cusp forms.
  • -
- """ - return _dimension_Gamma_2(wt_range, 2, group='Sp4(Z)') - -def dimension_table_Sp4Z_j(wt_range, j_range): - result = {} - for wt in wt_range: - result[wt] = {} - for j in j_range: - if is_odd(j): - for wt in wt_range: - result[wt][j] = 0 - else: - _, olddim = dimension_Sp4Z_j(wt_range, j) - for wt in wt_range: - result[wt][j] = olddim[wt]['Total'] - return result - -def dimension_Sp4Z_j(wt_range, j): - """ -
    -
  • Total: The full space.
  • -
  • Non cusp: The subspace of non cusp forms.
  • -
  • Cusp: The subspace of cusp forms.
  • -
- """ - return _dimension_Gamma_2(wt_range, j, group='Sp4(Z)') - - - -def _dimension_Sp4Z(wt_range): - """ - Return the dimensions of subspaces of Siegel modular forms on $Sp(4,Z)$. - - OUTPUT: - - ("Total", "Eisenstein", "Klingen", "Maass", "Interesting") - """ - headers = ['Total', 'Eisenstein', 'Klingen', 'Maass', 'Interesting'] - - R = PowerSeriesRing(ZZ, default_prec = wt_range[-1] + 1, names = ('x',)) - (x,) = R._first_ngens(1) - H_all = 1 / (1 - x ** 4) / (1 - x ** 6) / (1 - x ** 10) / (1 - x ** 12) - H_Kl = x ** 12 / (1 - x ** 4) / (1 - x ** 6) - H_MS = (x ** 10 + x ** 12) / (1 - x ** 4) / (1 - x ** 6) - - dct = dict((k, - { 'Total': H_all[k], - 'Eisenstein': 1 if k >= 4 else 0, - 'Klingen': H_Kl[k], - 'Maass': H_MS[k], - 'Interesting': H_all[k]-(1 if k >= 4 else 0)-H_Kl[k]-H_MS[k] - } - if is_even(k) else - { 'Total': H_all[k-35], - 'Eisenstein': 0, - 'Klingen': 0, - 'Maass': 0, - 'Interesting': H_all[k-35] - } - ) for k in wt_range) - - return headers, dct - - - -def _dimension_Gamma_2(wt_range, j, group = 'Gamma(2)'): - r""" - Return the dict - {(k-> partition -> [ d(k), e(k), c(k)] for k in wt_range]}, - where d(k), e(k), c(k) are the dimensions - of the $p$-canonical part of $M_{k,j}(\Gamma(2))$ and its subspaces of - Non-cusp forms and cusp forms. - """ - - partitions = [ u'6', u'51', u'42', u'411', u'33', u'321', u'3111', u'222', u'2211', u'21111', u'111111'] - latex_names = { 'Gamma(2)':r'\Gamma(2)', 'Gamma0(2)':r'\Gamma_0(2)', 'Gamma1(2)':r'\Gamma_1(2)', 'Sp4(Z)':r'\mathrm{Sp}(4,\mathbb{Z})' } - - if is_odd(j): - dct = dict((k,dict((h,[0,0,0]) for h in partitions)) for k in wt_range) - for k in dct: - dct[k]['All'] = [0,0,0] - partitions.insert(0,'All') - return partitions, dct - - if 'Sp4(Z)' == group and 2 == j and wt_range[0] < 4: - wt_range1 = [k for k in wt_range if k < 4] - wt_range2 = [k for k in wt_range if k >= 4] - if wt_range2: - headers, dct = _dimension_Gamma_2(wt_range2, j, group) - else: - headers, dct = ['Total', 'Non cusp', 'Cusp'], {} - for k in wt_range1: - dct[k] = {h: 0 for h in headers} - return headers, dct - - if j >= 2 and wt_range[0] < 4: - raise NotImplementedError(r"Dimensions of \(M_{k,j}(%s)\) for \(k<4\) and \(j\ge 2\) not implemented" % latex_names.get(group,group)) - - query = { 'sym_power': str(j), 'group': 'Gamma(2)', 'space': 'total' } - db_total = db.smf_dims.lucky(query) - if not db_total: - raise NotImplementedError(r'Dimensions of \(M_{k,j}\) for \(j=%d\) not implemented' % j) - query['space'] = 'cusp' - db_cusp = db.smf_dims.lucky(query) - if not db_cusp: - raise NotImplementedError(r'Dimensions of \(M_{k,j}\) for \(j=%d\) not implemented' % j) - - P = PowerSeriesRing(ZZ, default_prec =wt_range[-1] + 1, names = ('t')) - Qt = FunctionField(QQ, names=('t')) - total = dict() - cusp = dict() - for p in partitions: - f = Qt(str(db_total[p])) - total[p] = P(f.numerator())/P(f.denominator()) - f = Qt(str(db_cusp[p])) - cusp[p] = P(f.numerator())/P(f.denominator()) - - if 'Gamma(2)' == group: - dct = dict((k, dict((p, [total[p][k], total[p][k]-cusp[p][k], cusp[p][k]]) - for p in partitions)) for k in wt_range) - for k in dct: - dct[k]['All'] = [sum(dct[k][p][i] for p in dct[k]) for i in range(3)] - - partitions.insert(0,'All') - headers = partitions - - elif 'Gamma1(2)' == group: - ps = { '3': ['6', '42', '222'], - '21': ['51', '42', '321'], - '111': ['411', '33']} - - dct = dict((k, dict((p,[ - sum(total[q][k] for q in ps[p]), - sum(total[q][k]-cusp[q][k] for q in ps[p]), - sum(cusp[q][k] for q in ps[p]), - ]) for p in ps)) for k in wt_range) - for k in dct: - dct[k]['All'] = [sum(dct[k][p][i] for p in dct[k]) for i in range(3)] - - headers = list(ps) - headers.sort(reverse=True) - headers.insert(0, 'All') - - elif 'Gamma0(2)' == group: - headers = ['Total', 'Non cusp', 'Cusp'] - ps = ['6', '42', '222'] - dct = dict((k, { 'Total': sum(total[p][k] for p in ps), - 'Non cusp': sum(total[p][k]-cusp[p][k] for p in ps), - 'Cusp': sum(cusp[p][k] for p in ps)}) - for k in wt_range) - - elif 'Sp4(Z)' == group: - headers = ['Total', 'Non cusp', 'Cusp'] - p = '6' - dct = dict((k, { 'Total': total[p][k], - 'Non cusp': total[p][k]-cusp[p][k], - 'Cusp': cusp[p][k]}) - for k in wt_range) - else: - raise NotImplementedError('Dimension for %s not implemented' % group) - - return headers, dct - - -#################################################################### -## Dimension formulas for Sp6Z -#################################################################### - -def dimension_Sp6Z(wt_range): - """ -
    -
  • Total: The full space.
  • -
  • Miyawaki lifts I: The subspace of Miyawaki lifts of type I.
  • -
  • Miyawaki lifts II: The subspace of (conjectured) Miyawaki lifts of type II.
  • -
  • Other: The subspace of cusp forms which are not Miyawaki lifts of type I or II.
  • -
- """ - return _dimension_Sp6Z(wt_range) - - -def _dimension_Sp6Z(wt_range): - headers = ['Total', 'Miyawaki lifts I', 'Miyawaki lifts II (conjectured)', 'Other'] - dct = dict() - for k in wt_range: - dims = __dimension_Sp6Z(k) - dct[k] = dict((headers[j],dims[j]) for j in range(4)) - return headers, dct - - -def __dimension_Sp6Z(wt): - """ - Return the dimensions of subspaces of Siegel modular forms on $Sp(6,Z)$. - - OUTPUT - ("Total", "Miyawaki-Type-1", "Miyawaki-Type-2 (conjectured)", "Interesting") - Remember, Miywaki type 2 is ONLY CONJECTURED!! - """ - if not is_even(wt): - return (0, 0, 0, 0) - R = PowerSeriesRing(ZZ, default_prec=wt + 1, names=('x',)) - (x,) = R._first_ngens(1) - S = PowerSeriesRing(ZZ, default_prec=max(2 * wt - 1,1), names=('y',)) - (y,) = S._first_ngens(1) - H_all = 1 / ((1 - x ** 4) * (1 - x ** 12) ** 2 * (1 - x ** 14) * (1 - x ** 18) * - (1 - x ** 20) * (1 - x ** 30)) * ( - 1 + x ** 6 + x ** 10 + x ** 12 + 3 * x ** 16 + 2 * x ** 18 + 2 * x ** 20 + - 5 * x ** 22 + 4 * x ** 24 + 5 * x ** 26 + 7 * x ** 28 + 6 * x ** 30 + 9 * x ** 32 + - 10 * x ** 34 + 10 * x ** 36 + 12 * x ** 38 + 14 * x ** 40 + 15 * x ** 42 + 16 * x ** 44 + - 18 * x ** 46 + 18 * x ** 48 + 19 * x ** 50 + 21 * x ** 52 + 19 * x ** 54 + 21 * x ** 56 + - 21 * x ** 58 + 19 * x ** 60 + 21 * x ** 62 + 19 * x ** 64 + 18 * x ** 66 + 18 * x ** 68 + - 16 * x ** 70 + 15 * x ** 72 + 14 * x ** 74 + 12 * x ** 76 + 10 * x ** 78 + 10 * x ** 80 + - 9 * x ** 82 + 6 * x ** 84 + 7 * x ** 86 + 5 * x ** 88 + 4 * x ** 90 + 5 * x ** 92 + - 2 * x ** 94 + 2 * x ** 96 + 3 * x ** 98 + x ** 102 + x ** 104 + x ** 108 + x ** 114) - - H_noncusp = 1 / (1 - x ** 4) / (1 - x ** 6) / (1 - x ** 10) / (1 - x ** 12) - H_E = y ** 12 / (1 - y ** 4) / (1 - y ** 6) - H_Miyawaki1 = H_E[wt] * H_E[2 * wt - 4] - H_Miyawaki2 = H_E[wt - 2] * H_E[2 * wt - 2] - a, b, c, d = H_all[wt], H_noncusp[wt], H_Miyawaki1, H_Miyawaki2 - return (a, c, d, a - b - c - d) - - - -#################################################################### -## Dimension formulas for Sp8Z -#################################################################### - -def dimension_Sp8Z(wt_range): - """ -
    -
  • Total: The subspace of cusp forms.
  • -
  • Ikeda lifts: The subspace of Ikeda lifts.
  • -
  • Miyawaki lifts: The subspace of Miyawaki lifts.
  • -
  • Other: The subspace that are not Ikeda or Miyawaki lifts.
  • -
- """ - headers = ['Total', 'Ikeda lifts', 'Miyawaki lifts', 'Other'] - dct = dict() - for k in wt_range: - dims = _dimension_Sp8Z(k) - dct[k] = dict((headers[j],dims[j]) for j in range(4)) - return headers, dct - - -def _dimension_Sp8Z(wt): - """ - Return the dimensions of subspaces of Siegel modular forms on $Sp(8,Z)$. - - OUTPUT - ('Total', 'Ikeda lifts', 'Miyawaki lifts', 'Other') - """ - if wt > 16: - raise NotImplementedError(r'Dimensions of $M_{k}(Sp(8,Z))$ for \(k > 16\) not implemented') - if wt == 8: - return (1, 1, 0, 0) - if wt == 10: - return (1, 1, 0, 0) - if wt == 12: - return (2, 1, 1, 0) - if wt == 14: - return (3, 2, 1, 0) - if wt == 16: - return (7, 2, 2, 3) - # odd weight is zero up to weight 15 - return (0, 0, 0, 0) - -# def _dimension_Sp8Z(wt_range): -# """ -# Return the dimensions of subspaces of Siegel modular forms on $Sp(8,Z)$. - -# OUTPUT -# ('Total', 'Ikeda lifts', 'Miyawaki lifts', 'Other') -# """ -# if wt_range[-1] > 16: -# raise NotImplementedError('Dimensions of \(M_{k}\) for \(k > 16\) not implemented') - -# headers = ['Total', 'Ikeda lifts', 'Miyawaki lifts', 'Other'] -# dct = dict ((k, { 'Total':0, 'Ikeda lifts':0, 'Miyawaki lifts':0, 'Other': 0}) for k in range(17)) -# dct[8] = { 'Total':1, 'Ikeda lifts':1, 'Miyawaki lifts':0, 'Other': 0} -# dct[10] = { 'Total':1, 'Ikeda lifts':1, 'Miyawaki lifts':0, 'Other': 0} -# dct[12] = { 'Total':2, 'Ikeda lifts':1, 'Miyawaki lifts':1, 'Other': 0} -# dct[14] = { 'Total':3, 'Ikeda lifts':2, 'Miyawaki lifts':1, 'Other': 0} -# dct[16] = { 'Total':7, 'Ikeda lifts':2, 'Miyawaki lifts':2, 'Other': 3} - -# return headers, dct - - - -#################################################################### -## Dimension formulas for Gamma0_4 half integral -#################################################################### - -def dimension_Gamma0_4_half(wt_range): - """ -
    -
  • Total: The full space.
  • -
  • Non cusp: The codimension of the subspace of cusp forms.
  • -
  • Cusp: The subspace of cusp forms.
  • -
- """ - headers = ['Total', 'Non cusp', 'Cusp'] - dct = dict() - for k in wt_range: - dims = _dimension_Gamma0_4_half(k) - dct[k] = dict((headers[j],dims[j]) for j in range(3)) - return headers, dct - - -def _dimension_Gamma0_4_half(k): - """ - Return the dimensions of subspaces of Siegel modular forms$Gamma0(4)$ - of half integral weight k - 1/2. - - INPUT - The realweight is k-1/2 - - OUTPUT - ('Total', 'Non cusp', 'Cusp') - - REMARK - Note that formula from Hayashida's and Ibukiyama's paper has formula - that coefficient of x^w is for weight (w+1/2). So here w=k-1. - """ - if k < 1: - raise ValueError("$k$ must be a positive integer") - R = PowerSeriesRing(ZZ, default_prec = k, names=('x',)) - (x,) = R._first_ngens(1) - H_all = 1 / (1 - x) / (1 - x ** 2) ** 2 / (1 - x ** 3) - H_cusp = (2 * x ** 5 + x ** 7 + x ** 9 - 2 * x ** 11 + 4 * x ** 6 - x ** 8 + x ** 10 - 3 * - x ** 12 + x ** 14) / (1 - x ** 2) ** 2 / (1 - x ** 6) - a, c = H_all[k - 1], H_cusp[k - 1] - return (a, a - c, c) - - - -#################################################################### -## Dimension formulas for Gamma0_3_psi_3 -#################################################################### - -def dimension_Gamma0_3_psi_3(wt_range): - """ -
    -
  • Total: The full space.
  • -
- """ - headers = ['Total'] - dct = dict() - for k in wt_range: - dims = _dimension_Gamma0_3_psi_3(k) - dct[k] = dict((headers[j],dims[j]) for j in range(len(headers))) -# print headers, dct - return headers, dct - - -def _dimension_Gamma0_3_psi_3(wt): - r""" - Return the dimensions of the space of Siegel modular forms - on $Gamma_0(3)$ with character $\psi_3$. - - OUTPUT - ("Total") - - REMARK - Not completely implemented - """ - R = PowerSeriesRing(ZZ, default_prec = wt + 1, names=('x',)) - (x,) = R._first_ngens(1) - B = 1 / (1 - x ** 1) / (1 - x ** 3) / (1 - x ** 4) / (1 - x ** 3) - H_all_odd = B - H_all_even = B * x ** 14 - if is_even(wt): - return (H_all_even[wt],) - else: - return (H_all_odd[wt],) - -#################################################################### -# Dimension formulas for Gamma0_4_psi_4 -#################################################################### - - -def dimension_Gamma0_4_psi_4(wt_range): - """ -
    -
  • Total: The full space.
  • -
-

Odd weights are not yet implemented.

- """ - headers = ['Total'] - dct = dict() - for k in wt_range: - if is_odd(k): - continue - dims = _dimension_Gamma0_4_psi_4(k) - dct[k] = dict((headers[j], dims[j]) for j in range(len(headers))) - return headers, dct - - -def _dimension_Gamma0_4_psi_4(wt): - r""" - Return the dimensions of subspaces of Siegel modular forms - on $Gamma_0(4)$ - with character $\psi_4$. - - OUTPUT - ("Total") - - REMARK - The formula for odd weights is unknown or not obvious from the paper. - """ - R = PowerSeriesRing(ZZ, default_prec = wt + 1, names=('x',)) - (x,) = R._first_ngens(1) - H_all_even = (x ** 12 + x ** 14) / (1 - x ** 2) ** 3 / (1 - x ** 6) - if is_even(wt): - return (H_all_even[wt],) - else: - raise NotImplementedError(r'Dimensions of $M_{k}(\Gamma_0(4), \psi_4)$ for odd $k$ not implemented') - - - - -#################################################################### -## Dimension formulas for Gamma0_4 -#################################################################### - -def dimension_Gamma0_4(wt_range): - """ -
    -
  • Total: The full space.
  • -
- """ - headers = ['Total'] - dct = dict() - for k in wt_range: - dims = _dimension_Gamma0_4(k) - dct[k] = dict((headers[j],dims[j]) for j in range(len(headers))) - return headers, dct - - -def _dimension_Gamma0_4(wt): - """ - Return the dimensions of subspaces of Siegel modular forms on $Gamma0(4)$. - - OUTPUT - ("Total",) - - REMARK - Not completely implemented - """ - R = PowerSeriesRing(ZZ, 'x') - x = R.gen().O(wt + 1) - H_all = (1 + x**4) * (1 + x**11) / (1 - x**2)**3 / (1 - x**6) - return (H_all[wt],) - - -#################################################################### -## Dimension formulas for Gamma0_3 -#################################################################### - -def dimension_Gamma0_3(wt_range): - """ -
    -
  • Total: The full space.
  • -
- """ - headers = ['Total'] - dct = dict() - for k in wt_range: - dims = _dimension_Gamma0_3(k) - dct[k] = dict((headers[j],dims[j]) for j in range(len(headers))) - return headers, dct - - -def _dimension_Gamma0_3(wt): - """ - Return the dimensions of subspaces of Siegel modular forms on $Gamma0(3)$. - - OUTPUT - ("Total") - - REMARK - Only total dimension implemented. - """ - R = PowerSeriesRing(ZZ, 'x') - x = R.gen().O(wt + 1) - H_all = (1 + 2 * x**4 + x**6 + x**15 * (1 + 2 * x**2 + x**6)) / (1 - x**2) / (1 - x**4) / (1 - x**6)**2 - return (H_all[wt],) - - -#################################################################### -## Dimension formulas for DUMMY_0 -#################################################################### - -def dimension_Dummy_0(wt_range): - """ -
    -
  • Total: The subspace of cusp forms.
  • -
  • Yoda lifts: The subspace of Master Yoda lifts.
  • -
  • Hinkelstein series: The subspace of Hinkelstein series.
  • -
- """ - headers = ['Total', 'Yoda lifts', 'Hinkelstein series'] - dct = dict() - for k in wt_range: - dims = _dimension_Dummy_0(k) - dct[k] = dict((headers[j],dims[j]) for j in range(4)) - return headers, dct - - -def _dimension_Dummy_0(wt): - """ - Return the dimensions of subspaces of Siegel modular forms in the collection Dummy_0. - - OUTPUT - ('Total', 'Yoda lifts', 'Hinkelstein series') - """ - # Here goes your code ike e.g.: - if wt > 37: - raise NotImplementedError(r'Dimensions of $Dummy_0$ for \(k > 37\) not implemented') - a,b,c = 1728, 28, 37 - - return (a,b,c) diff --git a/lmfdb/siegel_modular_forms/family.py b/lmfdb/siegel_modular_forms/family.py deleted file mode 100644 index 84e13f12d6..0000000000 --- a/lmfdb/siegel_modular_forms/family.py +++ /dev/null @@ -1,71 +0,0 @@ -# -*- coding: utf-8 -*- -# This file provides the class Collection whose instances -# represent the respective collections of Siegel modular forms. -# -# Author: Nils Skoruppa - -from sage.structure.sage_object import SageObject -from sage.misc.latex import Latex -from lmfdb import db -import importlib -import inspect -from .sample import Samples - -def get_smf_families(): - return [SiegelFamily(doc['name'], doc) for doc in db.smf_families.search({})] - -def get_smf_family(name): - try: - return SiegelFamily(name) - except ValueError: - return None - -class SiegelFamily (SageObject): - """ - Represents a family of spaces of Siegel modular forms. - """ - - def __init__(self, name, doc=None): - if doc is None: - doc = db.smf_families.lucky({ 'name': name }) - if not doc: - raise ValueError ('Siegel modular form family "%s" not found in database' % (name)) - self.name = name - self.latex_name = doc.get('latex_name') - if not self.latex_name: - self.latex_name = Latex(self.name) - self.plain_name = doc.get('plain_name') - if not self.plain_name: - self.plain_name = Latex(self.name) - self.degree = doc.get('degree') - self.dim_args_default = doc.get('dim_args_default') - module = importlib.import_module('lmfdb.siegel_modular_forms.dimensions') - self.__dimension = module.__dict__.get('dimension_'+name) - if self.__dimension: - args = inspect.getfullargspec(self.__dimension).args - self.__dimension_glossary = self.__dimension.__doc__ - self.__dimension_desc = { 'name': name, - 'args': args - } - else: - self.__dimension_desc = None - self.__dimension_glossary = None - self.__samples = None - self.order = doc.get('order') - - def computes_dimensions(self): - return bool(self.__dimension) - - def dimension(self, *args, **kwargs): - return self.__dimension(*args, **kwargs) if self.__dimension else None - - def dimension_desc(self): - return self.__dimension_desc - - def dimension_glossary(self): - return self.__dimension_glossary - - def samples(self): - if not self.__samples: - self.__samples = Samples({'collection': {'$contains': [self.name]}}) - return self.__samples diff --git a/lmfdb/siegel_modular_forms/family_data.py b/lmfdb/siegel_modular_forms/family_data.py deleted file mode 100644 index 024ffa9897..0000000000 --- a/lmfdb/siegel_modular_forms/family_data.py +++ /dev/null @@ -1,101 +0,0 @@ -# This data has been loaded into the smf_families postgres table and is no lonager used, changes here will have no effect! - -families = [ -{ - "name": "Gamma0_2", - "degree": int(2), - "dim_args_default": {"k": "4..24", "j": "2"}, - "latex_name": "M_{k,j}\\left(\\Gamma_0(2)\\right)", - "order": int(50) -}, -{ - "name": "Gamma0_3", - "degree": int(2), - "dim_args_default": { "k": "0..20" }, - "latex_name": "M_k\\left(\\Gamma_0(3)\\right)", - "order": int(80) -}, -{ - "name": "Gamma0_3_psi_3", - "degree": int(2), - "dim_args_default": { "k": "0..20" }, - "latex_name": "M_k\\left(\\Gamma_0(3),\\psi_3\\right)", - "order": int(90) -}, -{ - "name": "Gamma0_4_half", - "degree": int(2), - "dim_args_default": { "k": "1..20" }, - "latex_name": "M_{k-1/2}\\left(\\Gamma_0(4)\\right)", - "order": int(108) -}, -{ - "name": "Gamma0_4", - "degree": int(2), - "dim_args_default": { "k": "0..20" }, - "latex_name": "M_k\\left(\\Gamma_0(4)\\right)", - "order": int(100) -}, -{ - "name": "Gamma0_4_psi_4", - "degree": int(2), - "dim_args_default": { "k": "0..40" }, - "latex_name": "M_k\\left(\\Gamma_0(4),\\psi_4\\right)", - "order": int(105) -}, -{ - "name": "Gamma1_2", - "degree": int(2), - "dim_args_default": { "k": "4..10", "j": "2" }, - "latex_name": "M_{k,j}\\left(\\Gamma_1(2)\\right)", - "order": int(60) -}, -{ - "name": "Gamma_2", - "degree": int(2), - "dim_args_default": { "k": "4..10", "j": "2" }, - "latex_name": "M_{k,j}\\left(\\Gamma(2)\\right)", - "order": int(70) -}, -{ - "name": "Kp", - "degree": int(2), - "latex_name": "M_2\\left(K(p)\\right)", - "order": int(110) -}, -{ - "name": "Sp4Z_2", - "degree": int(2), - "dim_args_default": { "k": "4..24" }, - "latex_name": "M_{k,2}\\left(\\textrm{Sp}(4,\\mathbb{Z})\\right)", - "order": int(30) -}, -{ - "name": "Sp4Z_j", - "degree": int(2), - "dim_args_default": { "k": "4..24", "j": "4" }, - "latex_name": "M_{k,j}\\left(\\textrm{Sp}(4,\\mathbb{Z})\\right)", - "order": int(40) -}, -{ - "name": "Sp4Z", - "degree": int(2), - "dim_args_default": { "k": "0..20" }, - "latex_name": "M_k\\left({\\textrm{Sp}}(4,\\mathbb{Z})\\right)", - "order": int(10) -}, -{ - "name": "Sp6Z", - "degree": int(3), - "dim_args_default": { "k": "0..20" }, - "latex_name": "M_{k}\\left(\\textrm{Sp}(6,\\mathbb{Z})\\right)", - "order": int(130) -}, -{ - "name": "Sp8Z", - "degree": int(4), - "dim_args_default": { "k": "0..16" }, - "latex_name": "M_k\\left(\\textrm{Sp}(8,\\mathbb{Z})\\right)", - "order": int(140) -}, -] diff --git a/lmfdb/siegel_modular_forms/siegel_core.py b/lmfdb/siegel_modular_forms/siegel_core.py deleted file mode 100644 index 1ea256d50b..0000000000 --- a/lmfdb/siegel_modular_forms/siegel_core.py +++ /dev/null @@ -1,655 +0,0 @@ -# -*- coding: utf-8 -*- -# This file provides functions for computing dimensions of -# collections of Siegel modular forms. It is partly based on -# code implemented together with David Yuen and Fabien Cléry. -# -# Author: Nils Skoruppa - -from sage.all import QQ, ZZ, PowerSeriesRing, is_even, is_prime -from lmfdb.utils import integer_divisors - -tbi = 't.b.i.' -uk = '?' - - -def _dimension_Sp4Z(wt): - """ - Return the dimensions of subspaces of Siegel modular forms on $Sp(4,Z)$. - - OUTPUT - ("Total", "Eisenstein", "Klingen", "Maass", "Interesting") - """ - R = PowerSeriesRing(ZZ, default_prec=wt + 1, names=('x',)) - (x,) = R._first_ngens(1) - H_all = 1 / (1 - x ** 4) / (1 - x ** 6) / (1 - x ** 10) / (1 - x ** 12) - H_Kl = x ** 12 / (1 - x ** 4) / (1 - x ** 6) - H_MS = (x ** 10 + x ** 12) / (1 - x ** 4) / (1 - x ** 6) - if is_even(wt): - a, b, c, d = H_all[wt], 1 if wt >= 4 else 0, H_Kl[wt], H_MS[wt] - return (a, b, c, d, a - b - c - d) - else: - a = H_all[wt - 35] - return (a, 0, 0, 0, a) - - -def _dimension_Sp4Z_2(wt): - """ - Return the dimensions of subspaces of vector-valued Siegel modular forms on $Sp(4,Z)$ - of weight integral,2. - - OUTPUT - ("Total", "Non-cusp", "Cusp") - - REMARK - Satoh's paper does not have a description of the cusp forms. - """ - if not is_even(wt): - return (uk, uk, uk) - R = PowerSeriesRing(ZZ, default_prec=wt + 1, names=('x',)) - (x,) = R._first_ngens(1) - H = 1 / (1 - x ** 4) / (1 - x ** 6) / (1 - x ** 10) / (1 - x ** 12) - V = 1 / (1 - x ** 6) / (1 - x ** 10) / (1 - x ** 12) - # W = 1 / (1 - x ** 10) / (1 - x ** 12) - a = H[wt - 10] + H[wt - 14] + H[wt - 16] + V[wt - 16] + V[wt - 18] + V[wt - 22] - return (a, uk, uk) - - -def _dimension_Sp6Z(wt): - """ - Return the dimensions of subspaces of Siegel modular forms on $Sp(4,Z)$. - - OUTPUT - ("Total", "Miyawaki-Type-1", "Miyawaki-Type-2 (conjectured)", "Interesting") - Remember, Miywaki type 2 is ONLY CONJECTURED!! - """ - if not is_even(wt): - return (0, 0, 0, 0) - R = PowerSeriesRing(ZZ, default_prec=wt + 1, names=('x',)) - (x,) = R._first_ngens(1) - R = PowerSeriesRing(ZZ, default_prec=2 * wt - 1, names=('y',)) - (y,) = R._first_ngens(1) - H_all = 1 / ((1 - x ** 4) * (1 - x ** 12) ** 2 * (1 - x ** 14) * (1 - x ** 18) * - (1 - x ** 20) * (1 - x ** 30)) * ( - 1 + x ** 6 + x ** 10 + x ** 12 + 3 * x ** 16 + 2 * x ** 18 + 2 * x ** 20 + - 5 * x ** 22 + 4 * x ** 24 + 5 * x ** 26 + 7 * x ** 28 + 6 * x ** 30 + 9 * x ** 32 + - 10 * x ** 34 + 10 * x ** 36 + 12 * x ** 38 + 14 * x ** 40 + 15 * x ** 42 + 16 * x ** 44 + - 18 * x ** 46 + 18 * x ** 48 + 19 * x ** 50 + 21 * x ** 52 + 19 * x ** 54 + 21 * x ** 56 + - 21 * x ** 58 + 19 * x ** 60 + 21 * x ** 62 + 19 * x ** 64 + 18 * x ** 66 + 18 * x ** 68 + - 16 * x ** 70 + 15 * x ** 72 + 14 * x ** 74 + 12 * x ** 76 + 10 * x ** 78 + 10 * x ** 80 + - 9 * x ** 82 + 6 * x ** 84 + 7 * x ** 86 + 5 * x ** 88 + 4 * x ** 90 + 5 * x ** 92 + - 2 * x ** 94 + 2 * x ** 96 + 3 * x ** 98 + x ** 102 + x ** 104 + x ** 108 + x ** 114) - H_noncusp = 1 / (1 - x ** 4) / (1 - x ** 6) / (1 - x ** 10) / (1 - x ** 12) - H_E = y ** 12 / (1 - y ** 4) / (1 - y ** 6) - H_Miyawaki1 = H_E[wt] * H_E[2 * wt - 4] - H_Miyawaki2 = H_E[wt - 2] * H_E[2 * wt - 2] - a, b, c, d = H_all[wt], H_noncusp[wt], H_Miyawaki1, H_Miyawaki2 - return (a, c, d, a - b - c - d) - - -def _dimension_Sp8Z(wt): - """ - Return the dimensions of subspaces of Siegel modular forms on $Sp(8,Z)$. - - OUTPUT - ('Total', 'Ikeda lifts', 'Miyawaki lifts', 'Other') - """ - if wt > 16: - raise ValueError('Not yet implemented') - if wt == 8: - return (1, 1, 0, 0) - if wt == 10: - return (1, 1, 0, 0) - if wt == 12: - return (2, 1, 1, 0) - if wt == 14: - return (3, 2, 1, 0) - if wt == 16: - return (7, 2, 2, 3) - # odd weight is zero up to weight 15 - return (0, 0, 0, 0) - - -def __S1k(k): - y = k % 12 - if k < 12: - return 0 - if y == 2: - return (k // 12) - 1 - return (k // 12) - - -def __JacobiDimension(k, m): - if (k % 2) == 0: - x = 0 - if k == 2: - x = (len(integer_divisors(m)) - 1) // 2 - for j in range(1, m + 1): - x += (__S1k(k + 2 * j) - ((j * j) // (4 * m))) - return x - x = 0 - for j in range(1, m): - x += (__S1k(k + 2 * j - 1) - ((j * j) // (4 * m))) - return x - - -def _dimension_Kp(wt, p): - """ - Return the dimensions of subspaces of Siegel modular forms on $K(p)$ - for primes $p$. - - OUTPUT - ("Total", "Gritsenko Lifts", "Nonlifts", "Oldforms") - """ - oldforms = 0 - grits = __JacobiDimension(wt, p) - - if not is_prime(p): - return (uk, grits, uk, uk) - - if wt <= 1: - return (0, 0, 0, 0) - if wt == 2: - newforms = '?' - total = '' + str(grits) + ' - ?' - if p < 600: - newforms = 0 - total = grits - interestingPrimes = [277, 349, 353, 389, 461, 523, 587] - if p in interestingPrimes: - if p == 587: - newforms = '0 - 2' - total = '' + str(grits) + ' - ' + str(grits + 2) - newforms = '0 - 1' - total = '' + str(grits) + ' - ' + str(grits + 1) - return (total, grits, newforms, oldforms) - - total = dimKp(wt, p) - newforms = total - grits - oldforms - return (total, grits, newforms, oldforms) - - # for nonprime levels: return ( tbi, grits, tbi, tbi); - - -def _dimension_Gamma0_2(wt): - """ - Return the dimensions of subspaces of Siegel modular forms$Gamma0(2)$. - - OUTPUT - ( "Total", "Eisenstein", "Klingen", "Maass", "Interesting") - - REMARK - Only total dimension implemented. - """ - R = PowerSeriesRing(ZZ, default_prec=wt + 1, names=('x',)) - (x,) = R._first_ngens(1) - H_all = 1 / (1 - x ** 2) / (1 - x ** 4) / (1 - x ** 4) / (1 - x ** 6) - # H_cusp = ?? - # H_Kl = ?? - # H_MS = ?? - if is_even(wt): - a = H_all[wt] - return (a, tbi, tbi, tbi, tbi) - else: - a = H_all[wt - 19] - return (a, 0, 0, 0, a) - - -def _dimension_Gamma0_3(wt): - """ - Return the dimensions of subspaces of Siegel modular forms$Gamma0(3)$. - - OUTPUT - ( "Total", "Eisenstein", "Klingen", "Maass", "Interesting") - - REMARK - Only total dimension implemented. - """ - R = PowerSeriesRing(ZZ, default_prec=wt + 1, names=('x',)) - (x,) = R._first_ngens(1) - H_all = (1 + 2 * x ** 4 + x ** 6 + x ** 15 * (1 + 2 * x ** 2 + x ** 6)) / (1 - x ** 2) / (1 - - x ** 4) / (1 - x ** 6) ** 2 - # H_cusp = ?? - # H_Kl = ?? - # H_MS = ?? - if is_even(wt): - a = H_all[wt] - return (a, tbi, tbi, tbi, tbi) - else: - a = H_all[wt] - return (a, tbi, tbi, 0, tbi) - - -def _dimension_Gamma0_3_psi_3(wt): - r""" - Return the dimensions of subspaces of Siegel modular forms $Gamma0(3)$ - with character $\psi_3$. - - OUTPUT - ( "Total", "Eisenstein", "Klingen", "Maass", "Interesting") - - REMARK - Not completely implemented - """ - R = PowerSeriesRing(ZZ, default_prec=wt + 1, names=('x',)) - (x,) = R._first_ngens(1) - B = 1 / (1 - x ** 1) / (1 - x ** 3) / (1 - x ** 4) / (1 - x ** 3) - H_all_odd = B - H_all_even = B * x ** 14 - # H_cusp = ?? - # H_Kl = ?? - # H_MS = ?? - if is_even(wt): - a = H_all_even[wt] - return (a, tbi, tbi, tbi, tbi) - else: - a = H_all_odd[wt] - return (a, tbi, tbi, 0, tbi) - - -def _dimension_Gamma0_4(wt): - """ - Return the dimensions of subspaces of Siegel modular forms$Gamma0(4)$. - - OUTPUT - ( "Total", "Eisenstein", "Klingen", "Maass", "Interesting") - - REMARK - Not completely implemented - """ - R = PowerSeriesRing(ZZ, default_prec=wt + 1, names=('x',)) - (x,) = R._first_ngens(1) - H_all = (1 + x ** 4)(1 + x ** 11) / (1 - x ** 2) ** 3 / (1 - x ** 6) - # H_cusp = ?? - # H_Kl = ?? - # H_MS = ?? - if is_even(wt): - a = H_all[wt] - return (a, tbi, tbi, tbi, tbi) - else: - a = H_all[wt] - return (a, tbi, tbi, 0, tbi) - - -def _dimension_Gamma0_4_psi_4(wt): - r""" - Return the dimensions of subspaces of Siegel modular forms $Gamma0(4)$ - with character $\psi_4$. - - OUTPUT - ( "Total", "Eisenstein", "Klingen", "Maass", "Interesting") - - REMARK - The formula for odd weights is unknown or not obvious from the paper. - """ - R = PowerSeriesRing(ZZ, default_prec=wt + 1, names=('x',)) - (x,) = R._first_ngens(1) - H_all_even = (x ** 12 + x ** 14) / (1 - x ** 2) ** 3 / (1 - x ** 6) - # H_cusp = ?? - # H_Kl = ?? - # H_MS = ?? - if is_even(wt): - a = H_all_even[wt] - return (a, tbi, tbi, tbi, tbi) - else: - return (uk, uk, uk, uk, uk) - - -def _dimension_Gamma0_4_half(k): - """ - Return the dimensions of subspaces of Siegel modular forms$Gamma0(4)$ - of half integral weight k - 1/2. - - INPUT - The realweight is k-1/2 - - OUTPUT - ('Total', 'Non cusp', 'Cusp') - - REMARK - Note that formula from Hayashida's and Ibukiyama's paper has formula - that coefficient of x^w is for weight (w+1/2). So here w=k-1. - """ - R = PowerSeriesRing(ZZ, default_prec=k, names=('x',)) - (x,) = R._first_ngens(1) - H_all = 1 / (1 - x) / (1 - x ** 2) ** 2 / (1 - x ** 3) - H_cusp = (2 * x ** 5 + x ** 7 + x ** 9 - 2 * x ** 11 + 4 * x ** 6 - x ** 8 + x ** 10 - 3 * - x ** 12 + x ** 14) / (1 - x ** 2) ** 2 / (1 - x ** 6) - a, c = H_all[k - 1], H_cusp[k - 1] - return (a, a - c, c) - -# David's code for the dimension of S_k(K(p)), originally written by Cris in Maple ######### - -_sage_const_3 = ZZ(3) -_sage_const_2 = ZZ(2) -_sage_const_1 = ZZ(1) -_sage_const_0 = ZZ(0) -_sage_const_7 = ZZ(7) -_sage_const_6 = ZZ(6) -_sage_const_5 = ZZ(5) -_sage_const_4 = ZZ(4) -_sage_const_9 = ZZ(9) -_sage_const_8 = ZZ(8) -_sage_const_12 = ZZ(12) -_sage_const_11 = ZZ(11) -_sage_const_10 = ZZ(10) - - -def H1(k, p): - return (p ** _sage_const_2 + _sage_const_1) * (_sage_const_2 * k - _sage_const_2) * (_sage_const_2 * k - _sage_const_3) * (_sage_const_2 * k - _sage_const_4) / (_sage_const_2 ** _sage_const_9 * _sage_const_3 ** _sage_const_3 * _sage_const_5) - - -def H2(k, p): - S1 = ((-_sage_const_1) ** k) * (_sage_const_2 * k - _sage_const_2) * (_sage_const_2 * k - - _sage_const_4) / (_sage_const_2 ** _sage_const_8 * _sage_const_3 ** _sage_const_2) - if p == _sage_const_2: - S2 = ((-_sage_const_1) ** k) * (_sage_const_2 * k - _sage_const_2) * (_sage_const_2 * - k - _sage_const_4) / (_sage_const_2 ** _sage_const_9) - else: - S2 = ((-_sage_const_1) ** k) * (_sage_const_2 * k - _sage_const_2) * (_sage_const_2 * - k - _sage_const_4) / (_sage_const_2 ** _sage_const_7 * _sage_const_3) - return S1 + S2 - - -def tink3(a0, a1, a2, k): - if ((k % _sage_const_3) == _sage_const_0): - S = a0 - if ((k % _sage_const_3) == _sage_const_1): - S = a1 - if ((k % _sage_const_3) == _sage_const_2): - S = a2 - return QQ(S) - - -def tink4(a0, a1, a2, a3, k): - if ((k % _sage_const_4) == _sage_const_0): - S = a0 - if ((k % _sage_const_4) == _sage_const_1): - S = a1 - if ((k % _sage_const_4) == _sage_const_2): - S = a2 - if ((k % _sage_const_4) == _sage_const_3): - S = a3 - return QQ(S) - - -def tink5(a0, a1, a2, a3, a4, k): - if ((k % _sage_const_5) == _sage_const_0): - S = a0 - if ((k % _sage_const_5) == _sage_const_1): - S = a1 - if ((k % _sage_const_5) == _sage_const_2): - S = a2 - if ((k % _sage_const_5) == _sage_const_3): - S = a3 - if ((k % _sage_const_5) == _sage_const_4): - S = a4 - return QQ(S) - - -def tink6(a0, a1, a2, a3, a4, a5, k): - if ((k % _sage_const_6) == _sage_const_0): - S = a0 - if ((k % _sage_const_6) == _sage_const_1): - S = a1 - if ((k % _sage_const_6) == _sage_const_2): - S = a2 - if ((k % _sage_const_6) == _sage_const_3): - S = a3 - if ((k % _sage_const_6) == _sage_const_4): - S = a4 - if ((k % _sage_const_6) == _sage_const_5): - S = a5 - return QQ(S) - - -def tink12(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, k): - if ((k % _sage_const_12) == _sage_const_0): - S = a0 - if ((k % _sage_const_12) == _sage_const_1): - S = a1 - if ((k % _sage_const_12) == _sage_const_2): - S = a2 - if ((k % _sage_const_12) == _sage_const_3): - S = a3 - if ((k % _sage_const_12) == _sage_const_4): - S = a4 - if ((k % _sage_const_12) == _sage_const_5): - S = a5 - if ((k % _sage_const_12) == _sage_const_6): - S = a6 - if ((k % _sage_const_12) == _sage_const_7): - S = a7 - if ((k % _sage_const_12) == _sage_const_8): - S = a8 - if ((k % _sage_const_12) == _sage_const_9): - S = a9 - if ((k % _sage_const_12) == _sage_const_10): - S = a10 - if ((k % _sage_const_12) == _sage_const_11): - S = a11 - return QQ(S) - - -def LS5(p): # Gives the Legendre Symbol (5/p) - return tink5(_sage_const_0, _sage_const_1, -_sage_const_1, -_sage_const_1, _sage_const_1, p) - - -def LS2(p): - """ - Gives the Legendre Symbol (2/p) - """ - return 0 if p == 2 else (-1)**((p**2 - 1) // 8) - - -def LSminus1(p): - """ - Gives the Legendre Symbol (-1/p) - """ - return 1 if p == 2 else (-1)**((p - 1) // 2) - - -def LSminus3(p): # Gives the Legendre Symbol (-3/p) ==(p/3) - return tink3(_sage_const_0, _sage_const_1, -_sage_const_1, p) - - -def H3(k, p): - S = _sage_const_0 - S1 = _sage_const_0 - S1 = tink4(k - _sage_const_2, _sage_const_1 - k, _sage_const_2 - k, k - _sage_const_1, k) - if p == _sage_const_2: - S = _sage_const_5 * S1 / (_sage_const_2 ** _sage_const_5 * _sage_const_3) - else: - S = S1 / (_sage_const_2 ** _sage_const_4 * _sage_const_3) - return S - - -def H4(k, p): - S = _sage_const_0 - S1 = _sage_const_0 - S1 = tink3(_sage_const_2 * k - _sage_const_3, _sage_const_1 - k, _sage_const_2 - k, k) - if p == _sage_const_3: - S = _sage_const_5 * S1 / (_sage_const_2 ** _sage_const_2 * _sage_const_3 ** _sage_const_3) - else: - S = S1 / (_sage_const_2 ** _sage_const_2 * _sage_const_3 ** _sage_const_3) - return S - - -def H5(k, p): - S = _sage_const_0 - S = tink6(-_sage_const_1, _sage_const_1 - k, _sage_const_2 - k, _sage_const_1, k - _sage_const_1, - k - _sage_const_2, k) / (_sage_const_2 ** _sage_const_2 * _sage_const_3 ** _sage_const_2) - return S - - -def H6(k, p): - S = _sage_const_0 - if ((p % _sage_const_4) == _sage_const_1): - S = _sage_const_5 * (_sage_const_2 * k - _sage_const_3) * (p + _sage_const_1) / (_sage_const_2 ** _sage_const_7 * _sage_const_3) + (-_sage_const_1) ** k * (p + _sage_const_1) / (_sage_const_2 ** _sage_const_7) - if ((p % _sage_const_4) == _sage_const_3): - S = (_sage_const_2 * k - _sage_const_3) * (p - _sage_const_1) / (_sage_const_2 ** _sage_const_7) + _sage_const_5 * (-_sage_const_1) ** k * (p - _sage_const_1) / (_sage_const_2 ** _sage_const_7 * _sage_const_3) - if p == _sage_const_2: - S = _sage_const_3 * (_sage_const_2 * k - _sage_const_3) / (_sage_const_2 ** _sage_const_7) + _sage_const_7 * (-_sage_const_1) ** k / (_sage_const_2 ** _sage_const_7 * _sage_const_3) - return S - - -def H7(k, p): - S = _sage_const_0 - S1 = _sage_const_0 - S1 = tink3(_sage_const_0, -_sage_const_1, _sage_const_1, k) - if ((p % _sage_const_3) == _sage_const_1): - S = (_sage_const_2 * k - _sage_const_3) * (p + _sage_const_1) / (_sage_const_2 * _sage_const_3 ** _sage_const_3) + S1 * (p + _sage_const_1) / (_sage_const_2 ** _sage_const_2 * _sage_const_3 ** _sage_const_3) - if ((p % _sage_const_3) == _sage_const_2): - S = (_sage_const_2 * k - _sage_const_3) * (p - _sage_const_1) / (_sage_const_2 ** _sage_const_2 * _sage_const_3 ** _sage_const_3) + S1 * (p - _sage_const_1) / (_sage_const_2 * _sage_const_3 ** _sage_const_3) - if p == _sage_const_3: - S = _sage_const_5 * (_sage_const_2 * k - _sage_const_3) / (_sage_const_2 ** _sage_const_2 * - _sage_const_3 ** _sage_const_3) + S1 / (_sage_const_3 ** _sage_const_3) - return S - - -def H8(k, p): - S = _sage_const_0 - S = tink12(_sage_const_1, _sage_const_0, _sage_const_0, -_sage_const_1, -_sage_const_1, -_sage_const_1, -_sage_const_1, _sage_const_0, _sage_const_0, _sage_const_1, _sage_const_1, _sage_const_1, k) / (_sage_const_2 * _sage_const_3) - return S - - -def H9(k, p): - S = _sage_const_0 - S1 = _sage_const_0 - S1 = tink6( - _sage_const_1, _sage_const_0, _sage_const_0, -_sage_const_1, _sage_const_0, _sage_const_0, k) - if p == _sage_const_2: - S = S1 / (_sage_const_2 * _sage_const_3 ** _sage_const_2) - else: - S = _sage_const_2 * S1 / (_sage_const_3 ** _sage_const_2) - return S - - -def H10(k, p): - S = _sage_const_0 - S1 = _sage_const_0 - S1 = tink5(_sage_const_1, _sage_const_0, _sage_const_0, -_sage_const_1, _sage_const_0, k) - S = (LS5(p) + _sage_const_1) * S1 / _sage_const_5 - return S - - -def H11(k, p): - S = _sage_const_0 - S1 = _sage_const_0 - S1 = tink4(_sage_const_1, _sage_const_0, _sage_const_0, -_sage_const_1, k) - S = (LS2(p) + _sage_const_1) * S1 / (_sage_const_2 ** _sage_const_3) - if p == _sage_const_2: - S = S1 / (_sage_const_2 ** _sage_const_3) - return S - - -def H12(k, p): - S = _sage_const_0 - S1 = _sage_const_0 - S2 = _sage_const_0 - S3 = _sage_const_0 - S1 = tink3(_sage_const_0, _sage_const_1, -_sage_const_1, k) / (_sage_const_2 * _sage_const_3) - S2 = (-_sage_const_1) ** k / (_sage_const_2 * _sage_const_3) - S3 = (-_sage_const_1) ** k / (_sage_const_2 ** _sage_const_2 * _sage_const_3) - S = tink12(_sage_const_0, S1, _sage_const_0, _sage_const_0, _sage_const_0, _sage_const_0, - _sage_const_0, _sage_const_0, _sage_const_0, _sage_const_0, _sage_const_0, S2, p) - if p == _sage_const_2: - S = S3 - if p == _sage_const_3: - S = S3 - return S - - -def H(k, p): - S = H1(k, p) + H2(k, p) + H3(k, p) + H4(k, p) + H5(k, p) + H6(k, p) - S = S + H7(k, p) + H8(k, p) + H9(k, p) + H10(k, p) + H11(k, p) + H12(k, p) - return S - - -def I1(k, p): - S = _sage_const_0 - S1 = _sage_const_0 - S1 = tink6( - _sage_const_0, _sage_const_1, _sage_const_1, _sage_const_0, -_sage_const_1, -_sage_const_1, k) - S = S1 / _sage_const_6 - return S - - -def I2(k, p): - S = _sage_const_0 - S1 = _sage_const_0 - S1 = tink3(-_sage_const_2, _sage_const_1, _sage_const_1, k) - S = S1 / (_sage_const_2 * _sage_const_3 ** _sage_const_2) - return S - - -def I3(k, p): - S = _sage_const_0 - S1 = _sage_const_0 - S2 = _sage_const_0 - S3 = _sage_const_0 - S1 = tink3(-_sage_const_2, _sage_const_1, _sage_const_1, k) / (_sage_const_3 ** _sage_const_2) - S2 = _sage_const_2 * tink3(-_sage_const_1, _sage_const_1, _sage_const_0, k) / ( - _sage_const_3 ** _sage_const_2) - S3 = _sage_const_2 * tink3(-_sage_const_1, _sage_const_0, _sage_const_1, k) / ( - _sage_const_3 ** _sage_const_2) - S = tink3(_sage_const_0, S2, S3, p) - if p == _sage_const_3: - S = S1 - return S - - -def I4(k, p): - S = _sage_const_0 - S1 = _sage_const_0 - S1 = tink4(-_sage_const_1, _sage_const_1, _sage_const_1, -_sage_const_1, k) - S = S1 / (_sage_const_2 ** _sage_const_2) - return S - - -def I5(k, p): - return (-_sage_const_1) ** k / (_sage_const_2 ** _sage_const_3) - - -def I6(k, p): - return (_sage_const_2 - LSminus1(p)) * (-_sage_const_1) ** k / (_sage_const_2 ** _sage_const_4) - - -def I7(k, p): - return -(-_sage_const_1) ** k * (_sage_const_2 * k - _sage_const_3) / (_sage_const_2 ** _sage_const_3 * _sage_const_3) - - -def I8(k, p): - return -p * (_sage_const_2 * k - _sage_const_3) / (_sage_const_2 ** _sage_const_4 * _sage_const_3 ** _sage_const_2) - - -def I9(k, p): - return QQ(-_sage_const_1) / (_sage_const_2 ** _sage_const_3 * _sage_const_3) - - -def I10(k, p): - return (p + _sage_const_1) / (_sage_const_2 ** _sage_const_3 * _sage_const_3) - - -def I11(k, p): - return (_sage_const_1 + LSminus1(p)) * (-_sage_const_1) / (_sage_const_8) - - -def I12(k, p): - return (_sage_const_1 + LSminus3(p)) * (-_sage_const_1) / (_sage_const_6) - - -def II(k, p): - S = I1(k, p) + I2(k, p) + I3(k, p) + I4(k, p) + I5(k, p) + I6(k, p) - S = S + I7(k, p) + I8(k, p) + I9(k, p) + I10(k, p) + I11(k, p) + I12(k, p) - return S - - -def dimKp(k, p): - """ - This returns the dimension of cusp forms for K(p) - of weight k>=3 and PRIME level p - """ - S = H(k, p) + II(k, p) - if k == _sage_const_3: - S = H(k, p) + II(k, p) + _sage_const_1 - return S diff --git a/lmfdb/siegel_modular_forms/siegel_modular_form.py b/lmfdb/siegel_modular_forms/siegel_modular_form.py index b928742253..4afef2dd9e 100644 --- a/lmfdb/siegel_modular_forms/siegel_modular_form.py +++ b/lmfdb/siegel_modular_forms/siegel_modular_form.py @@ -1,335 +1,1811 @@ # -*- coding: utf-8 -*- -# -# Author: Nils Skoruppa -from io import BytesIO +from collections import defaultdict +import re +import os +import yaml -from flask import render_template, url_for, request, send_file, redirect -from sage.all import latex, Set +from flask import render_template, url_for, redirect, abort, request +from sage.all import ( + ZZ, next_prime, cartesian_product_iterator, + cached_function, prime_range, prod, gcd, nth_prime) +from sage.databases.cremona import class_to_int, cremona_letter_code from lmfdb import db from lmfdb.utils import ( - parse_ints, parse_ints_to_list_flash, prop_int_pretty, - to_dict, flash_error) -from lmfdb.number_fields.number_field import poly_to_field_label, field_pretty -from lmfdb.siegel_modular_forms import smf_page -from lmfdb.siegel_modular_forms.family import get_smf_family, get_smf_families -from . import dimensions -from . import sample -from lmfdb.utils import redirect_no_cache - -############################################################################### -# Utility functions -############################################################################### - -def find_samples(family, weight): - slist = db.smf_samples.search({'collection': {'$contains': [family]}, 'weight': int(weight)}, 'name') - ret = [] - for name in slist: - url = url_for(".by_label", label=family+"."+name) - ret.append({'url':url, 'name':name}) - return ret - -def download_sample(name): - a, b = name.split('.') - s = sample.export(a, b) - strIO = BytesIO() - strIO.write(s.encode('utf-8')) - strIO.seek(0) - return send_file(strIO, download_name=name + '.json', as_attachment=True) - - -############################################################################### -# Page routing functions -############################################################################### - -@smf_page.route('/') + parse_ints, parse_floats, parse_bool, parse_primes, parse_nf_string, + parse_noop, parse_equality_constraints, integer_options, parse_subset, + search_wrap, display_float, factor_base_factorization_latex, + flash_error, to_dict, comma, display_knowl, bigint_knowl, num2letters, + SearchArray, TextBox, TextBoxNoEg, SelectBox, TextBoxWithSelect, YesNoBox, + DoubleSelectBox, BasicSpacer, RowSpacer, HiddenBox, SearchButtonWithSelect, + SubsetBox, ParityMod, CountBox, SelectBoxNoEg, + StatsDisplay, proportioners, totaler, integer_divisors, + redirect_no_cache) +from lmfdb.backend.utils import range_formatter +from lmfdb.utils.search_parsing import search_parser +from lmfdb.utils.interesting import interesting_knowls +from lmfdb.utils.search_columns import SearchColumns, LinkCol, MathCol, FloatCol, CheckCol, ProcessedCol, MultiProcessedCol, ColGroup, SpacerCol +from lmfdb.api import datapage +from lmfdb.siegel_modular_forms import smf +from lmfdb.siegel_modular_forms.web_newform import ( + WebNewform, convert_newformlabel_from_conrey, LABEL_RE, + quad_field_knowl, cyc_display, field_display_gen) +from lmfdb.siegel_modular_forms.web_space import ( + WebNewformSpace, WebGamma1Space, DimGrid, convert_spacelabel_from_conrey, + get_bread, get_search_bread, get_dim_bread, newform_search_link, + ALdim_table, NEWLABEL_RE as NEWSPACE_RE, OLDLABEL_RE as OLD_SPACE_LABEL_RE) +from lmfdb.siegel_modular_forms.download import SMF_download +from lmfdb.sato_tate_groups.main import st_display_knowl + +POSINT_RE = re.compile("^[1-9][0-9]*$") +ALPHA_RE = re.compile("^[a-z]+$") + + +_curdir = os.path.dirname(os.path.abspath(__file__)) +ETAQUOTIENTS = yaml.load(open(os.path.join(_curdir, "eta.yaml")), + Loader=yaml.FullLoader) + +@cached_function +def learnmore_list(): + """ + Return the learnmore list + """ + return [('Source and acknowledgments', url_for(".how_computed_page")), + ('Completeness of the data', url_for(".completeness_page")), + ('Reliability of the data', url_for(".reliability_page")), + ('Siegel modular form labels', url_for(".labels_page"))] + + +def learnmore_list_remove(matchstring): + """ + Return the learnmore list with the matchstring entry removed + """ + return [t for t in learnmore_list() if t[0].find(matchstring) < 0] + +@cached_function +def Nk2_bound(nontriv=None): + if nontriv: + return db.smf_samples.max('Nk2',{'char_order':{'$ne':1}}) + else: + return db.smf_samples.max('Nk2') +@cached_function +def weight_bound(nontriv=None): + if nontriv: + return db.smf_samples.max('weight',{'char_order':{'$ne':1}}) + else: + return db.smf_samples.max('weight') + +@cached_function +def level_bound(nontriv=None): + # At the moment, level is not stored in the database + # (We only have "collection"). We therefore return the maximal level + # hardcoded until we fix that. + return 2 + if nontriv: + return db.smf_samples.max('level',{'char_order':{'$ne':1}}) + else: + return db.smf_samples.max('level') + +############################################################################# +# The following functions are used for processing columns in search results # +############################################################################# + +def ALdims_knowl(al_dims, level, weight): + dim_dict = {} + for vec, dim, cnt in al_dims: + dim_dict[tuple(ev for (p, ev) in vec)] = dim + short = "+".join(r'\(%s\)'%dim_dict.get(vec,0) for vec in cartesian_product_iterator([[1,-1] for _ in range(len(al_dims[0][0]))])) + # We erase plus_dim and minus_dim if they're obvious + AL_table = ALdim_table(al_dims, level, weight) + return r'%s'%(AL_table, short) + +def nf_link(m, d, is_real_cyc, nf_label, poly, disc): + # args: ["field_poly_root_of_unity", "dim", "field_poly_is_real_cyclotomic", "nf_label", "field_poly", "field_disc_factorization"] + if m and d != 2: + return cyc_display(m, d, is_real_cyc) + else: + return field_display_gen(nf_label, poly, disc, truncate=16) + +# Since right now we do not have this data, we compute the level +# (and the type of level subgroup) from the collection given +def compute_level_from_collection(collection): + if collection == "Sp8Z": + return 1 + +# at the moment only deal with trivial character +def char_order(mf): + return 1 + +def display_AL(info): + results = info["results"] + print(results) + if not results: + return False + # N = results[0]['level'] + N = compute_level_from_collection(results[0]['collection']) + if not all(compute_level_from_collection(mf['collection']) == N + for mf in results): + return False + if N == 1: + return False + return all(char_order(mf) == 1 for mf in results) + +def display_Fricke(info): + return any(char_order(mf) == 1 for mf in info["results"]) + +# For spaces +def display_decomp(level, weight, char_orbit_label, hecke_orbit_dims): + # input: ['level', 'weight', 'char_orbit_label', 'hecke_orbit_dims'] + if hecke_orbit_dims is None: # shouldn't happen + return 'unknown' + dim_dict = defaultdict(int) + terms = [] + for dim in hecke_orbit_dims: + dim_dict[dim] += 1 + for dim in sorted(dim_dict.keys()): + count = dim_dict[dim] + query = {'weight':weight, + 'char_label':'%s.%s'%(level,char_orbit_label), + 'dim':dim} + if count > 3: + short = r'\({0}\)+\(\cdots\)+\({0}\)'.format(dim) + title = '%s newforms' % count + else: + short = '+'.join([r'\(%s\)'%dim]*count) + title=None + if count == 1: + query['jump'] = 'yes' + link = newform_search_link(short, title=title, **query) + terms.append(link) + return r'+'.join(terms) + +def show_ALdims_col(info): + return any(space.get('AL_dims') for space in info["results"]) + +def display_ALdims(level, weight, al_dims): + if al_dims: + return ALdims_knowl(al_dims, level, weight) + else: + return '' + +def set_info_funcs(info): + info["mf_url"] = lambda mf: url_for_label(mf['label']) + + info["space_type"] = {'M':'Modular forms', + 'S':'Cusp forms', + 'E':'Eisenstein series'} + + info['download_spaces'] = lambda results: any(space['dim'] > 1 for space in results) + info['bigint_knowl'] = bigint_knowl + +@smf.route("/") def index(): - bread = [("Modular forms", url_for('modular_forms')), - ('Siegel', url_for('.index'))] + info = to_dict(request.args, search_array=SMFSearchArray()) if len(request.args) > 0: - if 'download' in request.args: - return download_sample(request.args.get('download')) + # hidden_search_type for prev/next buttons + info['search_type'] = search_type = info.get('search_type', info.get('hst', 'List')) + + if search_type in ['List', 'Random']: + return newform_search(info) + elif search_type in ['Spaces', 'RandomSpace']: + return space_search(info) + elif search_type == 'Dimensions': + return dimension_form_search(info) + elif search_type == 'SpaceDimensions': + bad_keys = [key for key in newform_only_fields if key in info] + if bad_keys: + flash_error("%s invalid for searching spaces", ", ".join(bad_keys)) + return dimension_space_search(info) + elif search_type == 'Traces': + return trace_search(info) + elif search_type == 'SpaceTraces': + return space_trace_search(info) else: - return render_search_results_page(request.args, bread) - return render_main_page(bread) + flash_error("Invalid search type; if you did not enter it in the URL please report") + info["stats"] = SMF_stats() + info["weight_list"] = ('1', '2', '3', '4', '5-8', '9-16', '17-32', '33-64', '65-%d' % weight_bound() ) + info["level_list"] = ('1', '2-10', '11-100', '101-1000', '1001-2000', '2001-4000', '4001-6000', '6001-8000', '8001-%d' % level_bound() ) + return render_template("smf_browse.html", + info=info, + title="Siegel modular forms", + learnmore=learnmore_list(), + bread=get_bread()) -@smf_page.route("/random") +@smf.route("/random/") @redirect_no_cache -def random_sample(): - return url_for('.by_label', label='.'.join(sample.random_sample_name())) - -@smf_page.route('/