passagemath-schemes 10.6.40__cp314-cp314-macosx_13_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of passagemath-schemes might be problematic. Click here for more details.
- passagemath_schemes/.dylibs/libflint.22.0.dylib +0 -0
- passagemath_schemes/.dylibs/libgmp.10.dylib +0 -0
- passagemath_schemes/.dylibs/libgmpxx.4.dylib +0 -0
- passagemath_schemes/.dylibs/libmpfr.6.dylib +0 -0
- passagemath_schemes/__init__.py +3 -0
- passagemath_schemes-10.6.40.dist-info/METADATA +204 -0
- passagemath_schemes-10.6.40.dist-info/METADATA.bak +205 -0
- passagemath_schemes-10.6.40.dist-info/RECORD +314 -0
- passagemath_schemes-10.6.40.dist-info/WHEEL +6 -0
- passagemath_schemes-10.6.40.dist-info/top_level.txt +3 -0
- sage/all__sagemath_schemes.py +23 -0
- sage/databases/all__sagemath_schemes.py +7 -0
- sage/databases/cremona.py +1723 -0
- sage/dynamics/all__sagemath_schemes.py +2 -0
- sage/dynamics/arithmetic_dynamics/affine_ds.py +1083 -0
- sage/dynamics/arithmetic_dynamics/all.py +14 -0
- sage/dynamics/arithmetic_dynamics/berkovich_ds.py +1101 -0
- sage/dynamics/arithmetic_dynamics/dynamical_semigroup.py +1543 -0
- sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py +2426 -0
- sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py +1169 -0
- sage/dynamics/arithmetic_dynamics/generic_ds.py +663 -0
- sage/dynamics/arithmetic_dynamics/product_projective_ds.py +339 -0
- sage/dynamics/arithmetic_dynamics/projective_ds.py +9558 -0
- sage/dynamics/arithmetic_dynamics/projective_ds_helper.cpython-314-darwin.so +0 -0
- sage/dynamics/arithmetic_dynamics/projective_ds_helper.pyx +301 -0
- sage/dynamics/arithmetic_dynamics/wehlerK3.py +2576 -0
- sage/lfunctions/all.py +18 -0
- sage/lfunctions/dokchitser.py +745 -0
- sage/lfunctions/pari.py +818 -0
- sage/lfunctions/zero_sums.cpython-314-darwin.so +0 -0
- sage/lfunctions/zero_sums.pyx +1847 -0
- sage/modular/abvar/abvar.py +5135 -0
- sage/modular/abvar/abvar_ambient_jacobian.py +413 -0
- sage/modular/abvar/abvar_newform.py +244 -0
- sage/modular/abvar/all.py +8 -0
- sage/modular/abvar/constructor.py +186 -0
- sage/modular/abvar/cuspidal_subgroup.py +371 -0
- sage/modular/abvar/finite_subgroup.py +896 -0
- sage/modular/abvar/homology.py +720 -0
- sage/modular/abvar/homspace.py +998 -0
- sage/modular/abvar/lseries.py +415 -0
- sage/modular/abvar/morphism.py +935 -0
- sage/modular/abvar/torsion_point.py +274 -0
- sage/modular/abvar/torsion_subgroup.py +740 -0
- sage/modular/all.py +43 -0
- sage/modular/arithgroup/all.py +20 -0
- sage/modular/arithgroup/arithgroup_element.cpython-314-darwin.so +0 -0
- sage/modular/arithgroup/arithgroup_element.pyx +474 -0
- sage/modular/arithgroup/arithgroup_generic.py +1402 -0
- sage/modular/arithgroup/arithgroup_perm.py +2692 -0
- sage/modular/arithgroup/congroup.cpython-314-darwin.so +0 -0
- sage/modular/arithgroup/congroup.pyx +334 -0
- sage/modular/arithgroup/congroup_gamma.py +363 -0
- sage/modular/arithgroup/congroup_gamma0.py +692 -0
- sage/modular/arithgroup/congroup_gamma1.py +653 -0
- sage/modular/arithgroup/congroup_gammaH.py +1469 -0
- sage/modular/arithgroup/congroup_generic.py +628 -0
- sage/modular/arithgroup/congroup_sl2z.py +267 -0
- sage/modular/arithgroup/farey_symbol.cpython-314-darwin.so +0 -0
- sage/modular/arithgroup/farey_symbol.pyx +1066 -0
- sage/modular/arithgroup/tests.py +418 -0
- sage/modular/btquotients/all.py +4 -0
- sage/modular/btquotients/btquotient.py +3753 -0
- sage/modular/btquotients/pautomorphicform.py +2570 -0
- sage/modular/buzzard.py +100 -0
- sage/modular/congroup.py +29 -0
- sage/modular/congroup_element.py +13 -0
- sage/modular/cusps.py +1109 -0
- sage/modular/cusps_nf.py +1270 -0
- sage/modular/dims.py +569 -0
- sage/modular/dirichlet.py +3310 -0
- sage/modular/drinfeld_modform/all.py +2 -0
- sage/modular/drinfeld_modform/element.py +446 -0
- sage/modular/drinfeld_modform/ring.py +773 -0
- sage/modular/drinfeld_modform/tutorial.py +236 -0
- sage/modular/etaproducts.py +1065 -0
- sage/modular/hecke/algebra.py +746 -0
- sage/modular/hecke/all.py +20 -0
- sage/modular/hecke/ambient_module.py +1019 -0
- sage/modular/hecke/degenmap.py +119 -0
- sage/modular/hecke/element.py +325 -0
- sage/modular/hecke/hecke_operator.py +780 -0
- sage/modular/hecke/homspace.py +206 -0
- sage/modular/hecke/module.py +1767 -0
- sage/modular/hecke/morphism.py +174 -0
- sage/modular/hecke/submodule.py +989 -0
- sage/modular/hypergeometric_misc.cpython-314-darwin.so +0 -0
- sage/modular/hypergeometric_misc.pxd +4 -0
- sage/modular/hypergeometric_misc.pyx +166 -0
- sage/modular/hypergeometric_motive.py +2017 -0
- sage/modular/local_comp/all.py +2 -0
- sage/modular/local_comp/liftings.py +292 -0
- sage/modular/local_comp/local_comp.py +1071 -0
- sage/modular/local_comp/smoothchar.py +1825 -0
- sage/modular/local_comp/type_space.py +748 -0
- sage/modular/modform/all.py +30 -0
- sage/modular/modform/ambient.py +815 -0
- sage/modular/modform/ambient_R.py +177 -0
- sage/modular/modform/ambient_eps.py +306 -0
- sage/modular/modform/ambient_g0.py +124 -0
- sage/modular/modform/ambient_g1.py +204 -0
- sage/modular/modform/constructor.py +545 -0
- sage/modular/modform/cuspidal_submodule.py +708 -0
- sage/modular/modform/defaults.py +14 -0
- sage/modular/modform/eis_series.py +505 -0
- sage/modular/modform/eisenstein_submodule.py +663 -0
- sage/modular/modform/element.py +4131 -0
- sage/modular/modform/find_generators.py +59 -0
- sage/modular/modform/half_integral.py +154 -0
- sage/modular/modform/hecke_operator_on_qexp.py +247 -0
- sage/modular/modform/j_invariant.py +47 -0
- sage/modular/modform/l_series_gross_zagier.py +133 -0
- sage/modular/modform/l_series_gross_zagier_coeffs.cpython-314-darwin.so +0 -0
- sage/modular/modform/l_series_gross_zagier_coeffs.pyx +177 -0
- sage/modular/modform/notes.py +45 -0
- sage/modular/modform/numerical.py +514 -0
- sage/modular/modform/periods.py +14 -0
- sage/modular/modform/ring.py +1257 -0
- sage/modular/modform/space.py +1860 -0
- sage/modular/modform/submodule.py +118 -0
- sage/modular/modform/tests.py +64 -0
- sage/modular/modform/theta.py +110 -0
- sage/modular/modform/vm_basis.py +381 -0
- sage/modular/modform/weight1.py +220 -0
- sage/modular/modform_hecketriangle/abstract_ring.py +1932 -0
- sage/modular/modform_hecketriangle/abstract_space.py +2528 -0
- sage/modular/modform_hecketriangle/all.py +30 -0
- sage/modular/modform_hecketriangle/analytic_type.py +590 -0
- sage/modular/modform_hecketriangle/constructor.py +416 -0
- sage/modular/modform_hecketriangle/element.py +351 -0
- sage/modular/modform_hecketriangle/functors.py +752 -0
- sage/modular/modform_hecketriangle/graded_ring.py +541 -0
- sage/modular/modform_hecketriangle/graded_ring_element.py +2225 -0
- sage/modular/modform_hecketriangle/hecke_triangle_group_element.py +3352 -0
- sage/modular/modform_hecketriangle/hecke_triangle_groups.py +1432 -0
- sage/modular/modform_hecketriangle/readme.py +1214 -0
- sage/modular/modform_hecketriangle/series_constructor.py +580 -0
- sage/modular/modform_hecketriangle/space.py +1037 -0
- sage/modular/modform_hecketriangle/subspace.py +423 -0
- sage/modular/modsym/all.py +17 -0
- sage/modular/modsym/ambient.py +3846 -0
- sage/modular/modsym/boundary.py +1420 -0
- sage/modular/modsym/element.py +336 -0
- sage/modular/modsym/g1list.py +178 -0
- sage/modular/modsym/ghlist.py +182 -0
- sage/modular/modsym/hecke_operator.py +73 -0
- sage/modular/modsym/manin_symbol.cpython-314-darwin.so +0 -0
- sage/modular/modsym/manin_symbol.pxd +5 -0
- sage/modular/modsym/manin_symbol.pyx +497 -0
- sage/modular/modsym/manin_symbol_list.py +1295 -0
- sage/modular/modsym/modsym.py +400 -0
- sage/modular/modsym/modular_symbols.py +384 -0
- sage/modular/modsym/p1list.cpython-314-darwin.so +0 -0
- sage/modular/modsym/p1list.pxd +29 -0
- sage/modular/modsym/p1list.pyx +1372 -0
- sage/modular/modsym/p1list_nf.py +1241 -0
- sage/modular/modsym/relation_matrix.py +591 -0
- sage/modular/modsym/relation_matrix_pyx.cpython-314-darwin.so +0 -0
- sage/modular/modsym/relation_matrix_pyx.pyx +108 -0
- sage/modular/modsym/space.py +2468 -0
- sage/modular/modsym/subspace.py +455 -0
- sage/modular/modsym/tests.py +375 -0
- sage/modular/multiple_zeta.py +2632 -0
- sage/modular/multiple_zeta_F_algebra.py +786 -0
- sage/modular/overconvergent/all.py +6 -0
- sage/modular/overconvergent/genus0.py +1878 -0
- sage/modular/overconvergent/hecke_series.py +1187 -0
- sage/modular/overconvergent/weightspace.py +778 -0
- sage/modular/pollack_stevens/all.py +4 -0
- sage/modular/pollack_stevens/distributions.py +874 -0
- sage/modular/pollack_stevens/fund_domain.py +1572 -0
- sage/modular/pollack_stevens/manin_map.py +859 -0
- sage/modular/pollack_stevens/modsym.py +1593 -0
- sage/modular/pollack_stevens/padic_lseries.py +417 -0
- sage/modular/pollack_stevens/sigma0.py +534 -0
- sage/modular/pollack_stevens/space.py +1076 -0
- sage/modular/quasimodform/all.py +3 -0
- sage/modular/quasimodform/element.py +845 -0
- sage/modular/quasimodform/ring.py +828 -0
- sage/modular/quatalg/all.py +3 -0
- sage/modular/quatalg/brandt.py +1642 -0
- sage/modular/ssmod/all.py +8 -0
- sage/modular/ssmod/ssmod.py +827 -0
- sage/rings/all__sagemath_schemes.py +1 -0
- sage/rings/polynomial/all__sagemath_schemes.py +1 -0
- sage/rings/polynomial/binary_form_reduce.py +585 -0
- sage/schemes/all.py +41 -0
- sage/schemes/berkovich/all.py +6 -0
- sage/schemes/berkovich/berkovich_cp_element.py +2582 -0
- sage/schemes/berkovich/berkovich_space.py +748 -0
- sage/schemes/curves/affine_curve.py +2928 -0
- sage/schemes/curves/all.py +33 -0
- sage/schemes/curves/closed_point.py +434 -0
- sage/schemes/curves/constructor.py +381 -0
- sage/schemes/curves/curve.py +542 -0
- sage/schemes/curves/plane_curve_arrangement.py +1283 -0
- sage/schemes/curves/point.py +463 -0
- sage/schemes/curves/projective_curve.py +3026 -0
- sage/schemes/curves/zariski_vankampen.py +1932 -0
- sage/schemes/cyclic_covers/all.py +2 -0
- sage/schemes/cyclic_covers/charpoly_frobenius.py +320 -0
- sage/schemes/cyclic_covers/constructor.py +137 -0
- sage/schemes/cyclic_covers/cycliccover_finite_field.py +1309 -0
- sage/schemes/cyclic_covers/cycliccover_generic.py +310 -0
- sage/schemes/elliptic_curves/BSD.py +1036 -0
- sage/schemes/elliptic_curves/Qcurves.py +592 -0
- sage/schemes/elliptic_curves/addition_formulas_ring.py +94 -0
- sage/schemes/elliptic_curves/all.py +49 -0
- sage/schemes/elliptic_curves/cardinality.py +609 -0
- sage/schemes/elliptic_curves/cm.py +1102 -0
- sage/schemes/elliptic_curves/constructor.py +1552 -0
- sage/schemes/elliptic_curves/ec_database.py +175 -0
- sage/schemes/elliptic_curves/ell_curve_isogeny.py +3972 -0
- sage/schemes/elliptic_curves/ell_egros.py +459 -0
- sage/schemes/elliptic_curves/ell_field.py +2836 -0
- sage/schemes/elliptic_curves/ell_finite_field.py +3359 -0
- sage/schemes/elliptic_curves/ell_generic.py +3760 -0
- sage/schemes/elliptic_curves/ell_local_data.py +1207 -0
- sage/schemes/elliptic_curves/ell_modular_symbols.py +775 -0
- sage/schemes/elliptic_curves/ell_number_field.py +4220 -0
- sage/schemes/elliptic_curves/ell_padic_field.py +107 -0
- sage/schemes/elliptic_curves/ell_point.py +4787 -0
- sage/schemes/elliptic_curves/ell_rational_field.py +7368 -0
- sage/schemes/elliptic_curves/ell_tate_curve.py +671 -0
- sage/schemes/elliptic_curves/ell_torsion.py +436 -0
- sage/schemes/elliptic_curves/ell_wp.py +352 -0
- sage/schemes/elliptic_curves/formal_group.py +760 -0
- sage/schemes/elliptic_curves/gal_reps.py +1459 -0
- sage/schemes/elliptic_curves/gal_reps_number_field.py +1669 -0
- sage/schemes/elliptic_curves/gp_simon.py +152 -0
- sage/schemes/elliptic_curves/heegner.py +7335 -0
- sage/schemes/elliptic_curves/height.py +2109 -0
- sage/schemes/elliptic_curves/hom.py +1406 -0
- sage/schemes/elliptic_curves/hom_composite.py +934 -0
- sage/schemes/elliptic_curves/hom_frobenius.py +522 -0
- sage/schemes/elliptic_curves/hom_scalar.py +531 -0
- sage/schemes/elliptic_curves/hom_sum.py +682 -0
- sage/schemes/elliptic_curves/hom_velusqrt.py +1290 -0
- sage/schemes/elliptic_curves/homset.py +271 -0
- sage/schemes/elliptic_curves/isogeny_class.py +1521 -0
- sage/schemes/elliptic_curves/isogeny_small_degree.py +2797 -0
- sage/schemes/elliptic_curves/jacobian.py +237 -0
- sage/schemes/elliptic_curves/kodaira_symbol.py +344 -0
- sage/schemes/elliptic_curves/kraus.py +1014 -0
- sage/schemes/elliptic_curves/lseries_ell.py +943 -0
- sage/schemes/elliptic_curves/mod5family.py +105 -0
- sage/schemes/elliptic_curves/mod_poly.py +197 -0
- sage/schemes/elliptic_curves/mod_sym_num.cpython-314-darwin.so +0 -0
- sage/schemes/elliptic_curves/mod_sym_num.pyx +3796 -0
- sage/schemes/elliptic_curves/modular_parametrization.py +305 -0
- sage/schemes/elliptic_curves/padic_lseries.py +1793 -0
- sage/schemes/elliptic_curves/padics.py +1816 -0
- sage/schemes/elliptic_curves/period_lattice.py +2234 -0
- sage/schemes/elliptic_curves/period_lattice_region.cpython-314-darwin.so +0 -0
- sage/schemes/elliptic_curves/period_lattice_region.pyx +722 -0
- sage/schemes/elliptic_curves/saturation.py +715 -0
- sage/schemes/elliptic_curves/sha_tate.py +1158 -0
- sage/schemes/elliptic_curves/weierstrass_morphism.py +1117 -0
- sage/schemes/elliptic_curves/weierstrass_transform.py +200 -0
- sage/schemes/hyperelliptic_curves/all.py +6 -0
- sage/schemes/hyperelliptic_curves/constructor.py +291 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py +1914 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_g2.py +192 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py +954 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py +1332 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_rational_field.py +84 -0
- sage/schemes/hyperelliptic_curves/invariants.py +410 -0
- sage/schemes/hyperelliptic_curves/jacobian_endomorphism_utils.py +315 -0
- sage/schemes/hyperelliptic_curves/jacobian_g2.py +32 -0
- sage/schemes/hyperelliptic_curves/jacobian_generic.py +419 -0
- sage/schemes/hyperelliptic_curves/jacobian_homset.py +186 -0
- sage/schemes/hyperelliptic_curves/jacobian_morphism.py +875 -0
- sage/schemes/hyperelliptic_curves/kummer_surface.py +99 -0
- sage/schemes/hyperelliptic_curves/mestre.py +302 -0
- sage/schemes/hyperelliptic_curves/monsky_washnitzer.py +3871 -0
- sage/schemes/jacobians/abstract_jacobian.py +277 -0
- sage/schemes/jacobians/all.py +2 -0
- sage/schemes/overview.py +161 -0
- sage/schemes/plane_conics/all.py +22 -0
- sage/schemes/plane_conics/con_field.py +1296 -0
- sage/schemes/plane_conics/con_finite_field.py +158 -0
- sage/schemes/plane_conics/con_number_field.py +456 -0
- sage/schemes/plane_conics/con_rational_field.py +406 -0
- sage/schemes/plane_conics/con_rational_function_field.py +580 -0
- sage/schemes/plane_conics/constructor.py +249 -0
- sage/schemes/plane_quartics/all.py +2 -0
- sage/schemes/plane_quartics/quartic_constructor.py +71 -0
- sage/schemes/plane_quartics/quartic_generic.py +73 -0
- sage/schemes/riemann_surfaces/all.py +1 -0
- sage/schemes/riemann_surfaces/riemann_surface.py +4117 -0
- sage_wheels/share/cremona/cremona_mini.db +0 -0
- sage_wheels/share/ellcurves/rank0 +30427 -0
- sage_wheels/share/ellcurves/rank1 +31871 -0
- sage_wheels/share/ellcurves/rank10 +6 -0
- sage_wheels/share/ellcurves/rank11 +6 -0
- sage_wheels/share/ellcurves/rank12 +1 -0
- sage_wheels/share/ellcurves/rank14 +1 -0
- sage_wheels/share/ellcurves/rank15 +1 -0
- sage_wheels/share/ellcurves/rank17 +1 -0
- sage_wheels/share/ellcurves/rank19 +1 -0
- sage_wheels/share/ellcurves/rank2 +2388 -0
- sage_wheels/share/ellcurves/rank20 +1 -0
- sage_wheels/share/ellcurves/rank21 +1 -0
- sage_wheels/share/ellcurves/rank22 +1 -0
- sage_wheels/share/ellcurves/rank23 +1 -0
- sage_wheels/share/ellcurves/rank24 +1 -0
- sage_wheels/share/ellcurves/rank28 +1 -0
- sage_wheels/share/ellcurves/rank3 +836 -0
- sage_wheels/share/ellcurves/rank4 +10 -0
- sage_wheels/share/ellcurves/rank5 +5 -0
- sage_wheels/share/ellcurves/rank6 +5 -0
- sage_wheels/share/ellcurves/rank7 +5 -0
- sage_wheels/share/ellcurves/rank8 +6 -0
- sage_wheels/share/ellcurves/rank9 +7 -0
|
@@ -0,0 +1,1257 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-schemes
|
|
2
|
+
# sage.doctest: needs sage.combinat sage.libs.flint sage.libs.pari
|
|
3
|
+
"""
|
|
4
|
+
Graded rings of modular forms
|
|
5
|
+
|
|
6
|
+
This module contains functions to find generators for the graded ring of
|
|
7
|
+
modular forms of given level.
|
|
8
|
+
|
|
9
|
+
AUTHORS:
|
|
10
|
+
|
|
11
|
+
- William Stein (2007-08-24): first version
|
|
12
|
+
- David Ayotte (2021-06): implemented category and Parent/Element frameworks
|
|
13
|
+
"""
|
|
14
|
+
# ****************************************************************************
|
|
15
|
+
# Copyright (C) 2007 William Stein
|
|
16
|
+
# 2021 David Ayotte
|
|
17
|
+
#
|
|
18
|
+
# This program is free software: you can redistribute it and/or modify
|
|
19
|
+
# it under the terms of the GNU General Public License as published by
|
|
20
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
21
|
+
# (at your option) any later version.
|
|
22
|
+
# https://www.gnu.org/licenses/
|
|
23
|
+
# ****************************************************************************
|
|
24
|
+
|
|
25
|
+
from random import shuffle
|
|
26
|
+
|
|
27
|
+
from sage.categories.graded_algebras import GradedAlgebras
|
|
28
|
+
from sage.matrix.constructor import Matrix
|
|
29
|
+
from sage.misc.cachefunc import cached_method
|
|
30
|
+
from sage.misc.misc_c import prod
|
|
31
|
+
from sage.misc.superseded import deprecated_function_alias
|
|
32
|
+
from sage.misc.verbose import verbose
|
|
33
|
+
from sage.modular.arithgroup.all import Gamma0, CongruenceSubgroupBase
|
|
34
|
+
from sage.rings.integer import Integer
|
|
35
|
+
from sage.rings.integer_ring import ZZ
|
|
36
|
+
from sage.rings.polynomial.multi_polynomial import MPolynomial
|
|
37
|
+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
|
|
38
|
+
from sage.rings.polynomial.term_order import TermOrder
|
|
39
|
+
from sage.rings.power_series_poly import PowerSeries_poly
|
|
40
|
+
from sage.rings.rational_field import QQ
|
|
41
|
+
from sage.structure.parent import Parent
|
|
42
|
+
from sage.structure.richcmp import richcmp_method, richcmp
|
|
43
|
+
|
|
44
|
+
from .constructor import ModularForms
|
|
45
|
+
from .element import ModularFormElement, GradedModularFormElement
|
|
46
|
+
from .space import ModularFormsSpace
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _span_of_forms_in_weight(forms, weight, prec, stop_dim=None, use_random=False):
|
|
50
|
+
r"""
|
|
51
|
+
Utility function. Given a nonempty list of pairs ``(k,f)``, where `k` is an
|
|
52
|
+
integer and `f` is a power series, and a weight l, return all weight l
|
|
53
|
+
forms obtained by multiplying together the given forms.
|
|
54
|
+
|
|
55
|
+
INPUT:
|
|
56
|
+
|
|
57
|
+
- ``forms`` -- list of pairs `(k, f)` with k an integer and f a power
|
|
58
|
+
series (all over the same base ring)
|
|
59
|
+
- ``weight`` -- integer
|
|
60
|
+
- ``prec`` -- integer (less than or equal to the precision of all the
|
|
61
|
+
forms in ``forms``); precision to use in power series computations
|
|
62
|
+
- ``stop_dim`` -- integer; stop as soon as we have enough forms to span
|
|
63
|
+
a submodule of this rank (a saturated one if the base ring is `\ZZ`).
|
|
64
|
+
Ignored if ``use_random`` is ``False``.
|
|
65
|
+
- ``use_random`` -- which algorithm to use. If ``True``, tries random products
|
|
66
|
+
of the generators of the appropriate weight until a large enough
|
|
67
|
+
submodule is found (determined by ``stop_dim``). If ``False``, just tries
|
|
68
|
+
everything.
|
|
69
|
+
|
|
70
|
+
Note that if the given forms do generate the whole space, then
|
|
71
|
+
``use_random=True`` will often be quicker (particularly if the weight is
|
|
72
|
+
large); but if the forms don't generate, the randomized algorithm is no
|
|
73
|
+
help and will actually be substantially slower, because it needs to do
|
|
74
|
+
repeated echelon form calls to check if vectors are in a submodule, while
|
|
75
|
+
the non-randomized algorithm just echelonizes one enormous matrix at the
|
|
76
|
+
end.
|
|
77
|
+
|
|
78
|
+
EXAMPLES::
|
|
79
|
+
|
|
80
|
+
sage: import sage.modular.modform.ring as f
|
|
81
|
+
sage: forms = [(4, 240*eisenstein_series_qexp(4,5)), (6,504*eisenstein_series_qexp(6,5))]
|
|
82
|
+
sage: f._span_of_forms_in_weight(forms, 12, prec=5)
|
|
83
|
+
Vector space of degree 5 and dimension 2 over Rational Field
|
|
84
|
+
Basis matrix:
|
|
85
|
+
[ 1 0 196560 16773120 398034000]
|
|
86
|
+
[ 0 1 -24 252 -1472]
|
|
87
|
+
sage: f._span_of_forms_in_weight(forms, 24, prec=5)
|
|
88
|
+
Vector space of degree 5 and dimension 3 over Rational Field
|
|
89
|
+
Basis matrix:
|
|
90
|
+
[ 1 0 0 52416000 39007332000]
|
|
91
|
+
[ 0 1 0 195660 12080128]
|
|
92
|
+
[ 0 0 1 -48 1080]
|
|
93
|
+
sage: ModularForms(1, 24).q_echelon_basis(prec=5)
|
|
94
|
+
[1 + 52416000*q^3 + 39007332000*q^4 + O(q^5),
|
|
95
|
+
q + 195660*q^3 + 12080128*q^4 + O(q^5),
|
|
96
|
+
q^2 - 48*q^3 + 1080*q^4 + O(q^5)]
|
|
97
|
+
|
|
98
|
+
Test the alternative randomized algorithm::
|
|
99
|
+
|
|
100
|
+
sage: f._span_of_forms_in_weight(forms, 24, prec=5,
|
|
101
|
+
....: use_random=True, stop_dim=3)
|
|
102
|
+
Vector space of degree 5 and dimension 3 over Rational Field
|
|
103
|
+
Basis matrix:
|
|
104
|
+
[ 1 0 0 52416000 39007332000]
|
|
105
|
+
[ 0 1 0 195660 12080128]
|
|
106
|
+
[ 0 0 1 -48 1080]
|
|
107
|
+
"""
|
|
108
|
+
t = verbose('multiplying forms up to weight %s' % weight)
|
|
109
|
+
# Algorithm: run through the monomials of the appropriate weight, and build
|
|
110
|
+
# up the vector space they span.
|
|
111
|
+
|
|
112
|
+
n = len(forms)
|
|
113
|
+
R = forms[0][1].base_ring()
|
|
114
|
+
V = R ** prec
|
|
115
|
+
W = V.zero_submodule()
|
|
116
|
+
shortforms = [f[1].truncate_powerseries(prec) for f in forms]
|
|
117
|
+
|
|
118
|
+
# List of weights
|
|
119
|
+
from sage.combinat.integer_vector_weighted import WeightedIntegerVectors
|
|
120
|
+
wts = list(WeightedIntegerVectors(weight, [f[0] for f in forms]))
|
|
121
|
+
t = verbose("calculated weight list", t)
|
|
122
|
+
N = len(wts)
|
|
123
|
+
|
|
124
|
+
if use_random:
|
|
125
|
+
if stop_dim is None:
|
|
126
|
+
raise ValueError("stop_dim must be provided if use_random is True")
|
|
127
|
+
shuffle(wts)
|
|
128
|
+
|
|
129
|
+
for c in range(N):
|
|
130
|
+
w = V(prod(shortforms[i]**wts[c][i] for i in range(n)).padded_list(prec))
|
|
131
|
+
if w in W:
|
|
132
|
+
continue
|
|
133
|
+
W = V.span(list(W.gens()) + [w])
|
|
134
|
+
if stop_dim and W.rank() == stop_dim:
|
|
135
|
+
if R != ZZ or W.index_in_saturation() == 1:
|
|
136
|
+
verbose("Succeeded after %s of %s" % (c, N), t)
|
|
137
|
+
return W
|
|
138
|
+
verbose("Nothing worked", t)
|
|
139
|
+
return W
|
|
140
|
+
else:
|
|
141
|
+
G = [V(prod(forms[i][1]**c[i] for i in range(n)).padded_list(prec)) for c in wts]
|
|
142
|
+
t = verbose('found %s candidates' % N, t)
|
|
143
|
+
W = V.span(G)
|
|
144
|
+
verbose('span has dimension %s' % W.rank(), t)
|
|
145
|
+
return W
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
@richcmp_method
|
|
149
|
+
class ModularFormsRing(Parent):
|
|
150
|
+
r"""
|
|
151
|
+
The ring of modular forms (of weights 0 or at least 2) for a congruence
|
|
152
|
+
subgroup of `\SL_2(\ZZ)`, with coefficients in a specified base ring.
|
|
153
|
+
|
|
154
|
+
EXAMPLES::
|
|
155
|
+
|
|
156
|
+
sage: ModularFormsRing(Gamma1(13))
|
|
157
|
+
Ring of Modular Forms for Congruence Subgroup Gamma1(13) over Rational Field
|
|
158
|
+
sage: m = ModularFormsRing(4); m
|
|
159
|
+
Ring of Modular Forms for Congruence Subgroup Gamma0(4) over Rational Field
|
|
160
|
+
sage: m.modular_forms_of_weight(2)
|
|
161
|
+
Modular Forms space of dimension 2 for Congruence Subgroup Gamma0(4) of weight 2 over Rational Field
|
|
162
|
+
sage: m.modular_forms_of_weight(10)
|
|
163
|
+
Modular Forms space of dimension 6 for Congruence Subgroup Gamma0(4) of weight 10 over Rational Field
|
|
164
|
+
sage: m == loads(dumps(m))
|
|
165
|
+
True
|
|
166
|
+
sage: m.generators()
|
|
167
|
+
[(2, 1 + 24*q^2 + 24*q^4 + 96*q^6 + 24*q^8 + O(q^10)),
|
|
168
|
+
(2, q + 4*q^3 + 6*q^5 + 8*q^7 + 13*q^9 + O(q^10))]
|
|
169
|
+
sage: m.q_expansion_basis(2,10)
|
|
170
|
+
[1 + 24*q^2 + 24*q^4 + 96*q^6 + 24*q^8 + O(q^10),
|
|
171
|
+
q + 4*q^3 + 6*q^5 + 8*q^7 + 13*q^9 + O(q^10)]
|
|
172
|
+
sage: m.q_expansion_basis(3,10)
|
|
173
|
+
[]
|
|
174
|
+
sage: m.q_expansion_basis(10,10)
|
|
175
|
+
[1 + 10560*q^6 + 3960*q^8 + O(q^10),
|
|
176
|
+
q - 8056*q^7 - 30855*q^9 + O(q^10),
|
|
177
|
+
q^2 - 796*q^6 - 8192*q^8 + O(q^10),
|
|
178
|
+
q^3 + 66*q^7 + 832*q^9 + O(q^10),
|
|
179
|
+
q^4 + 40*q^6 + 528*q^8 + O(q^10),
|
|
180
|
+
q^5 + 20*q^7 + 190*q^9 + O(q^10)]
|
|
181
|
+
|
|
182
|
+
Elements of modular forms ring can be initiated via multivariate polynomials (see :meth:`from_polynomial`)::
|
|
183
|
+
|
|
184
|
+
sage: M = ModularFormsRing(1)
|
|
185
|
+
sage: M.ngens()
|
|
186
|
+
2
|
|
187
|
+
sage: E4, E6 = polygens(QQ, 'E4, E6')
|
|
188
|
+
sage: M(E4)
|
|
189
|
+
1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + O(q^6)
|
|
190
|
+
sage: M(E6)
|
|
191
|
+
1 - 504*q - 16632*q^2 - 122976*q^3 - 532728*q^4 - 1575504*q^5 + O(q^6)
|
|
192
|
+
sage: M((E4^3 - E6^2)/1728)
|
|
193
|
+
q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6)
|
|
194
|
+
"""
|
|
195
|
+
|
|
196
|
+
Element = GradedModularFormElement
|
|
197
|
+
|
|
198
|
+
def __init__(self, group, base_ring=QQ):
|
|
199
|
+
r"""
|
|
200
|
+
INPUT:
|
|
201
|
+
|
|
202
|
+
- ``group`` -- a congruence subgroup of `\SL_2(\ZZ)`, or a
|
|
203
|
+
positive integer `N` (interpreted as `\Gamma_0(N)`)
|
|
204
|
+
|
|
205
|
+
- ``base_ring`` -- ring (default: `\QQ`); a base ring, which
|
|
206
|
+
should be `\QQ`, `\ZZ`, or the integers mod `p` for some prime
|
|
207
|
+
`p`
|
|
208
|
+
|
|
209
|
+
TESTS:
|
|
210
|
+
|
|
211
|
+
Check that :issue:`15037` is fixed::
|
|
212
|
+
|
|
213
|
+
sage: ModularFormsRing(3.4)
|
|
214
|
+
Traceback (most recent call last):
|
|
215
|
+
...
|
|
216
|
+
ValueError: group (=3.40000000000000) should be a congruence subgroup
|
|
217
|
+
sage: ModularFormsRing(Gamma0(2), base_ring=PolynomialRing(ZZ, 'x'))
|
|
218
|
+
Traceback (most recent call last):
|
|
219
|
+
...
|
|
220
|
+
ValueError: base ring (=Univariate Polynomial Ring in x over Integer Ring) should be QQ, ZZ or a finite prime field
|
|
221
|
+
|
|
222
|
+
::
|
|
223
|
+
|
|
224
|
+
sage: TestSuite(ModularFormsRing(1)).run()
|
|
225
|
+
sage: TestSuite(ModularFormsRing(Gamma0(6))).run()
|
|
226
|
+
sage: TestSuite(ModularFormsRing(Gamma1(4))).run()
|
|
227
|
+
|
|
228
|
+
.. TODO::
|
|
229
|
+
|
|
230
|
+
- Add graded modular forms over non-trivial Dirichlet character;
|
|
231
|
+
- makes gen_forms returns modular forms over base rings other than `QQ`;
|
|
232
|
+
- implement binary operations between two forms with different groups.
|
|
233
|
+
"""
|
|
234
|
+
if isinstance(group, (int, Integer)):
|
|
235
|
+
group = Gamma0(group)
|
|
236
|
+
elif not isinstance(group, CongruenceSubgroupBase):
|
|
237
|
+
raise ValueError("group (=%s) should be a congruence subgroup" % group)
|
|
238
|
+
|
|
239
|
+
if base_ring != ZZ and not base_ring.is_field() and not base_ring.is_finite():
|
|
240
|
+
raise ValueError("base ring (=%s) should be QQ, ZZ or a finite prime field" % base_ring)
|
|
241
|
+
|
|
242
|
+
self.__group = group
|
|
243
|
+
self.__cached_maxweight = ZZ(-1)
|
|
244
|
+
self.__cached_gens = []
|
|
245
|
+
self.__cached_cusp_maxweight = ZZ(-1)
|
|
246
|
+
self.__cached_cusp_gens = []
|
|
247
|
+
cat = GradedAlgebras(base_ring).Commutative()
|
|
248
|
+
Parent.__init__(self, base=base_ring, category=cat)
|
|
249
|
+
|
|
250
|
+
def change_ring(self, base_ring):
|
|
251
|
+
r"""
|
|
252
|
+
Return a ring of modular forms over a new base ring of the same
|
|
253
|
+
congruence subgroup.
|
|
254
|
+
|
|
255
|
+
INPUT:
|
|
256
|
+
|
|
257
|
+
- ``base_ring`` -- a base ring, which should be `\QQ`, `\ZZ`, or
|
|
258
|
+
the integers mod `p` for some prime `p`
|
|
259
|
+
|
|
260
|
+
EXAMPLES::
|
|
261
|
+
|
|
262
|
+
sage: M = ModularFormsRing(11); M
|
|
263
|
+
Ring of Modular Forms for Congruence Subgroup Gamma0(11) over Rational Field
|
|
264
|
+
sage: M.change_ring(Zmod(7))
|
|
265
|
+
Ring of Modular Forms for Congruence Subgroup Gamma0(11) over Ring of integers modulo 7
|
|
266
|
+
sage: M.change_ring(ZZ)
|
|
267
|
+
Ring of Modular Forms for Congruence Subgroup Gamma0(11) over Integer Ring
|
|
268
|
+
"""
|
|
269
|
+
return ModularFormsRing(self.group(), base_ring=base_ring)
|
|
270
|
+
|
|
271
|
+
def some_elements(self):
|
|
272
|
+
r"""
|
|
273
|
+
Return some elements of this ring.
|
|
274
|
+
|
|
275
|
+
EXAMPLES::
|
|
276
|
+
|
|
277
|
+
sage: ModularFormsRing(1).some_elements()
|
|
278
|
+
[1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + O(q^6),
|
|
279
|
+
1 - 504*q - 16632*q^2 - 122976*q^3 - 532728*q^4 - 1575504*q^5 + O(q^6)]
|
|
280
|
+
"""
|
|
281
|
+
return [self(f) for f in self.gen_forms()]
|
|
282
|
+
|
|
283
|
+
def group(self):
|
|
284
|
+
r"""
|
|
285
|
+
Return the congruence subgroup of this ring of modular forms.
|
|
286
|
+
|
|
287
|
+
EXAMPLES::
|
|
288
|
+
|
|
289
|
+
sage: R = ModularFormsRing(Gamma1(13))
|
|
290
|
+
sage: R.group() is Gamma1(13)
|
|
291
|
+
True
|
|
292
|
+
"""
|
|
293
|
+
return self.__group
|
|
294
|
+
|
|
295
|
+
def gen(self, i):
|
|
296
|
+
r"""
|
|
297
|
+
Return the `i`-th generator of this ring.
|
|
298
|
+
|
|
299
|
+
INPUT:
|
|
300
|
+
|
|
301
|
+
- ``i`` -- integer
|
|
302
|
+
|
|
303
|
+
OUTPUT: an instance of :class:`~sage.modular.modform.GradedModularFormElement`
|
|
304
|
+
|
|
305
|
+
EXAMPLES::
|
|
306
|
+
|
|
307
|
+
sage: M = ModularFormsRing(1)
|
|
308
|
+
sage: E4 = M.0; E4 # indirect doctest
|
|
309
|
+
1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + O(q^6)
|
|
310
|
+
sage: E6 = M.1; E6 # indirect doctest
|
|
311
|
+
1 - 504*q - 16632*q^2 - 122976*q^3 - 532728*q^4 - 1575504*q^5 + O(q^6)
|
|
312
|
+
"""
|
|
313
|
+
if self.base_ring() is not QQ:
|
|
314
|
+
raise NotImplementedError("the base ring of the given ring of modular form should be QQ")
|
|
315
|
+
return self(self.gen_forms()[i])
|
|
316
|
+
|
|
317
|
+
def ngens(self):
|
|
318
|
+
r"""
|
|
319
|
+
Return the number of generators of this ring.
|
|
320
|
+
|
|
321
|
+
EXAMPLES::
|
|
322
|
+
|
|
323
|
+
sage: ModularFormsRing(1).ngens()
|
|
324
|
+
2
|
|
325
|
+
sage: ModularFormsRing(Gamma0(2)).ngens()
|
|
326
|
+
2
|
|
327
|
+
sage: ModularFormsRing(Gamma1(13)).ngens() # long time
|
|
328
|
+
33
|
|
329
|
+
|
|
330
|
+
.. WARNING::
|
|
331
|
+
|
|
332
|
+
Computing the number of generators of a graded ring of modular form for a certain
|
|
333
|
+
congruence subgroup can be very long.
|
|
334
|
+
"""
|
|
335
|
+
return len(self.gen_forms())
|
|
336
|
+
|
|
337
|
+
def polynomial_ring(self, names, gens=None):
|
|
338
|
+
r"""
|
|
339
|
+
Return a polynomial ring of which this ring of modular forms is
|
|
340
|
+
a quotient.
|
|
341
|
+
|
|
342
|
+
INPUT:
|
|
343
|
+
|
|
344
|
+
- ``names`` -- a list or tuple of names (strings), or a comma
|
|
345
|
+
separated string; consists in the names of the polynomial
|
|
346
|
+
ring variables
|
|
347
|
+
- ``gens`` -- list of modular forms generating this ring
|
|
348
|
+
(default: ``None``); if ``gens`` is ``None`` then the list of
|
|
349
|
+
generators returned by the method
|
|
350
|
+
:meth:`~sage.modular.modform.find_generator.ModularFormsRing.gen_forms`
|
|
351
|
+
is used instead. Note that we do not check if the list is
|
|
352
|
+
indeed a generating set.
|
|
353
|
+
|
|
354
|
+
OUTPUT: a multivariate polynomial ring in the variable
|
|
355
|
+
``names``. Each variable of the polynomial ring correspond to a
|
|
356
|
+
generator given in the list ``gens`` (following the ordering of
|
|
357
|
+
the list).
|
|
358
|
+
|
|
359
|
+
EXAMPLES::
|
|
360
|
+
|
|
361
|
+
sage: M = ModularFormsRing(1)
|
|
362
|
+
sage: gens = M.gen_forms()
|
|
363
|
+
sage: M.polynomial_ring('E4, E6', gens)
|
|
364
|
+
Multivariate Polynomial Ring in E4, E6 over Rational Field
|
|
365
|
+
sage: M = ModularFormsRing(Gamma0(8))
|
|
366
|
+
sage: gens = M.gen_forms()
|
|
367
|
+
sage: M.polynomial_ring('g', gens)
|
|
368
|
+
Multivariate Polynomial Ring in g0, g1, g2 over Rational Field
|
|
369
|
+
|
|
370
|
+
The degrees of the variables are the weights of the
|
|
371
|
+
corresponding forms::
|
|
372
|
+
|
|
373
|
+
sage: M = ModularFormsRing(1)
|
|
374
|
+
sage: P.<E4, E6> = M.polynomial_ring()
|
|
375
|
+
sage: E4.degree()
|
|
376
|
+
4
|
|
377
|
+
sage: E6.degree()
|
|
378
|
+
6
|
|
379
|
+
sage: (E4*E6).degree()
|
|
380
|
+
10
|
|
381
|
+
"""
|
|
382
|
+
if gens is None:
|
|
383
|
+
gens = self.gen_forms()
|
|
384
|
+
degs = [f.weight() for f in gens]
|
|
385
|
+
return PolynomialRing(self.base_ring(), len(gens), names,
|
|
386
|
+
order=TermOrder('wdeglex', degs))
|
|
387
|
+
|
|
388
|
+
def _generators_variables_dictionary(self, poly_parent, gens):
|
|
389
|
+
r"""
|
|
390
|
+
Return a dictionary giving an association between polynomial
|
|
391
|
+
ring generators and generators of modular forms ring.
|
|
392
|
+
|
|
393
|
+
INPUT:
|
|
394
|
+
|
|
395
|
+
- ``poly_parent`` -- a polynomial ring
|
|
396
|
+
- ``gen`` -- list of generators of the modular forms ring
|
|
397
|
+
|
|
398
|
+
TESTS::
|
|
399
|
+
|
|
400
|
+
sage: M = ModularFormsRing(Gamma0(6))
|
|
401
|
+
sage: P = QQ['x, y, z']
|
|
402
|
+
sage: M._generators_variables_dictionary(P, M.gen_forms())
|
|
403
|
+
{z: q^2 - 2*q^3 + 3*q^4 + O(q^6),
|
|
404
|
+
y: q + 5*q^3 - 2*q^4 + 6*q^5 + O(q^6),
|
|
405
|
+
x: 1 + 24*q^3 + O(q^6)}
|
|
406
|
+
"""
|
|
407
|
+
if poly_parent.base_ring() != self.base_ring():
|
|
408
|
+
raise ValueError('the base ring of `poly_parent` must be the same as the base ring of the modular forms ring')
|
|
409
|
+
nb_var = poly_parent.ngens()
|
|
410
|
+
nb_gens = self.ngens()
|
|
411
|
+
if nb_var != nb_gens:
|
|
412
|
+
raise ValueError('the number of variables (%s) must be equal to'
|
|
413
|
+
' the number of generators of the modular forms'
|
|
414
|
+
' ring (%s)' % (nb_var, self.ngens()))
|
|
415
|
+
return {poly_parent.gen(i): self(gens[i]) for i in range(0, nb_var)}
|
|
416
|
+
|
|
417
|
+
def from_polynomial(self, polynomial, gens=None):
|
|
418
|
+
r"""
|
|
419
|
+
Return a graded modular form constructed by evaluating a given
|
|
420
|
+
multivariate polynomial at a set of generators.
|
|
421
|
+
|
|
422
|
+
INPUT:
|
|
423
|
+
|
|
424
|
+
- ``polynomial`` -- a multivariate polynomial. The variables
|
|
425
|
+
names of the polynomial should be different from ``'q'``. The
|
|
426
|
+
number of variable of this polynomial should equal the number
|
|
427
|
+
of given generators.
|
|
428
|
+
- ``gens`` -- list of modular forms generating this ring
|
|
429
|
+
(default: ``None``); if ``gens`` is ``None`` then the list of
|
|
430
|
+
generators returned by the method
|
|
431
|
+
:meth:`~sage.modular.modform.find_generator.ModularFormsRing.gen_forms`
|
|
432
|
+
is used instead. Note that we do not check if the list is
|
|
433
|
+
indeed a generating set.
|
|
434
|
+
|
|
435
|
+
OUTPUT: a ``GradedModularFormElement`` given by the polynomial
|
|
436
|
+
relation ``polynomial``
|
|
437
|
+
|
|
438
|
+
EXAMPLES::
|
|
439
|
+
|
|
440
|
+
sage: M = ModularFormsRing(1)
|
|
441
|
+
sage: x,y = polygens(QQ, 'x,y')
|
|
442
|
+
sage: M.from_polynomial(x^2+y^3)
|
|
443
|
+
2 - 1032*q + 774072*q^2 - 77047584*q^3 - 11466304584*q^4 - 498052467504*q^5 + O(q^6)
|
|
444
|
+
sage: M = ModularFormsRing(Gamma0(6))
|
|
445
|
+
sage: M.ngens()
|
|
446
|
+
3
|
|
447
|
+
sage: x,y,z = polygens(QQ, 'x,y,z')
|
|
448
|
+
sage: M.from_polynomial(x+y+z)
|
|
449
|
+
1 + q + q^2 + 27*q^3 + q^4 + 6*q^5 + O(q^6)
|
|
450
|
+
sage: M.0 + M.1 + M.2
|
|
451
|
+
1 + q + q^2 + 27*q^3 + q^4 + 6*q^5 + O(q^6)
|
|
452
|
+
sage: P = x.parent()
|
|
453
|
+
sage: M.from_polynomial(P(1/2))
|
|
454
|
+
1/2
|
|
455
|
+
|
|
456
|
+
Note that the number of variables must be equal to the number of
|
|
457
|
+
generators::
|
|
458
|
+
|
|
459
|
+
sage: x, y = polygens(QQ, 'x, y')
|
|
460
|
+
sage: M(x + y)
|
|
461
|
+
Traceback (most recent call last):
|
|
462
|
+
...
|
|
463
|
+
ValueError: the number of variables (2) must be equal to the number of generators of the modular forms ring (3)
|
|
464
|
+
|
|
465
|
+
TESTS::
|
|
466
|
+
|
|
467
|
+
sage: x,y = polygens(GF(7), 'x, y')
|
|
468
|
+
sage: ModularFormsRing(1, GF(7))(x)
|
|
469
|
+
Traceback (most recent call last):
|
|
470
|
+
...
|
|
471
|
+
NotImplementedError: conversion from polynomial is not implemented if the base ring is not Q
|
|
472
|
+
|
|
473
|
+
..TODO::
|
|
474
|
+
|
|
475
|
+
* add conversion for symbolic expressions?
|
|
476
|
+
"""
|
|
477
|
+
if not self.base_ring() == QQ: # this comes from the method gens_form
|
|
478
|
+
raise NotImplementedError("conversion from polynomial is not implemented if the base ring is not Q")
|
|
479
|
+
if not isinstance(polynomial, MPolynomial):
|
|
480
|
+
raise TypeError('`polynomial` must be a multivariate polynomial')
|
|
481
|
+
if gens is None:
|
|
482
|
+
gens = self.gen_forms()
|
|
483
|
+
dict = self._generators_variables_dictionary(polynomial.parent(), gens)
|
|
484
|
+
if polynomial.is_constant():
|
|
485
|
+
return self(polynomial.constant_coefficient())
|
|
486
|
+
return polynomial.substitute(dict)
|
|
487
|
+
|
|
488
|
+
def _element_constructor_(self, forms_datum):
|
|
489
|
+
r"""
|
|
490
|
+
Return the graded modular form corresponding to the given data.
|
|
491
|
+
|
|
492
|
+
INPUT:
|
|
493
|
+
|
|
494
|
+
- ``forms_datum`` -- dictionary, list, ModularFormElement,
|
|
495
|
+
GradedModularFormElement, RingElement, or Multivariate polynomial; try
|
|
496
|
+
to coerce ``forms_datum`` into ``self``
|
|
497
|
+
|
|
498
|
+
TESTS::
|
|
499
|
+
|
|
500
|
+
sage: M = ModularFormsRing(1)
|
|
501
|
+
sage: E4 = ModularForms(1,4).0; E6 = ModularForms(1,6).0
|
|
502
|
+
sage: M([E4, E6])
|
|
503
|
+
2 - 264*q - 14472*q^2 - 116256*q^3 - 515208*q^4 - 1545264*q^5 + O(q^6)
|
|
504
|
+
sage: M([E4, E4])
|
|
505
|
+
2 + 480*q + 4320*q^2 + 13440*q^3 + 35040*q^4 + 60480*q^5 + O(q^6)
|
|
506
|
+
sage: M({4:E4, 6:E6})
|
|
507
|
+
2 - 264*q - 14472*q^2 - 116256*q^3 - 515208*q^4 - 1545264*q^5 + O(q^6)
|
|
508
|
+
sage: M(E4)
|
|
509
|
+
1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + O(q^6)
|
|
510
|
+
sage: x,y = polygens(QQ, 'x,y')
|
|
511
|
+
sage: M(x^2+x^3 + x*y + y^6)
|
|
512
|
+
4 - 2088*q + 3816216*q^2 - 2296935072*q^3 + 720715388184*q^4 - 77528994304752*q^5 + O(q^6)
|
|
513
|
+
sage: f = ModularForms(3, 10).0
|
|
514
|
+
sage: M(f)
|
|
515
|
+
Traceback (most recent call last):
|
|
516
|
+
...
|
|
517
|
+
ValueError: the group (Congruence Subgroup Gamma0(3)) and/or the base ring (Rational Field) of the given modular form is not consistent with the base space: Ring of Modular Forms for Modular Group SL(2,Z) over Rational Field
|
|
518
|
+
sage: M = ModularFormsRing(1, base_ring=ZZ)
|
|
519
|
+
sage: M(ModularForms(1,4).0)
|
|
520
|
+
Traceback (most recent call last):
|
|
521
|
+
...
|
|
522
|
+
ValueError: the group (Modular Group SL(2,Z)) and/or the base ring (Rational Field) of the given modular form is not consistent with the base space: Ring of Modular Forms for Modular Group SL(2,Z) over Integer Ring
|
|
523
|
+
sage: M('x')
|
|
524
|
+
Traceback (most recent call last):
|
|
525
|
+
...
|
|
526
|
+
TypeError: the defining data structure should be a single modular form, a ring element, a list of modular forms, a multivariate polynomial or a dictionary
|
|
527
|
+
sage: P.<t> = PowerSeriesRing(QQ)
|
|
528
|
+
sage: e = 1 + 240*t + 2160*t^2 + 6720*t^3 + 17520*t^4 + 30240*t^5 + O(t^6)
|
|
529
|
+
sage: ModularFormsRing(1)(e)
|
|
530
|
+
Traceback (most recent call last):
|
|
531
|
+
...
|
|
532
|
+
NotImplementedError: conversion from q-expansion not yet implemented
|
|
533
|
+
"""
|
|
534
|
+
if isinstance(forms_datum, (dict, list)):
|
|
535
|
+
forms_dictionary = forms_datum
|
|
536
|
+
elif isinstance(forms_datum, self.element_class):
|
|
537
|
+
forms_dictionary = forms_datum._forms_dictionary
|
|
538
|
+
elif isinstance(forms_datum, ModularFormElement):
|
|
539
|
+
if self.group().is_subgroup(forms_datum.group()) and self.base_ring().has_coerce_map_from(forms_datum.base_ring()):
|
|
540
|
+
forms_dictionary = {forms_datum.weight(): forms_datum}
|
|
541
|
+
else:
|
|
542
|
+
raise ValueError('the group (%s) and/or the base ring (%s) of the given modular form is not consistent with the base space: %s' % (forms_datum.group(), forms_datum.base_ring(), self))
|
|
543
|
+
elif forms_datum in self.base_ring():
|
|
544
|
+
forms_dictionary = {0: forms_datum}
|
|
545
|
+
elif isinstance(forms_datum, MPolynomial):
|
|
546
|
+
return self.from_polynomial(forms_datum)
|
|
547
|
+
elif isinstance(forms_datum, PowerSeries_poly):
|
|
548
|
+
raise NotImplementedError("conversion from q-expansion not yet implemented")
|
|
549
|
+
else:
|
|
550
|
+
raise TypeError('the defining data structure should be a single modular form, a ring element, a list of modular forms, a multivariate polynomial or a dictionary')
|
|
551
|
+
return self.element_class(self, forms_dictionary)
|
|
552
|
+
|
|
553
|
+
def zero(self):
|
|
554
|
+
r"""
|
|
555
|
+
Return the zero element of this ring.
|
|
556
|
+
|
|
557
|
+
EXAMPLES::
|
|
558
|
+
|
|
559
|
+
sage: M = ModularFormsRing(1)
|
|
560
|
+
sage: zer = M.zero(); zer
|
|
561
|
+
0
|
|
562
|
+
sage: zer.is_zero()
|
|
563
|
+
True
|
|
564
|
+
sage: E4 = ModularForms(1,4).0; E4
|
|
565
|
+
1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + O(q^6)
|
|
566
|
+
sage: E4 + zer
|
|
567
|
+
1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + O(q^6)
|
|
568
|
+
sage: zer * E4
|
|
569
|
+
0
|
|
570
|
+
sage: E4 * zer
|
|
571
|
+
0
|
|
572
|
+
"""
|
|
573
|
+
return self.element_class(self, {})
|
|
574
|
+
|
|
575
|
+
def one(self):
|
|
576
|
+
r"""
|
|
577
|
+
Return the one element of this ring.
|
|
578
|
+
|
|
579
|
+
EXAMPLES::
|
|
580
|
+
|
|
581
|
+
sage: M = ModularFormsRing(1)
|
|
582
|
+
sage: u = M.one(); u
|
|
583
|
+
1
|
|
584
|
+
sage: u.is_one()
|
|
585
|
+
True
|
|
586
|
+
sage: u + u
|
|
587
|
+
2
|
|
588
|
+
sage: E4 = ModularForms(1,4).0; E4
|
|
589
|
+
1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + O(q^6)
|
|
590
|
+
sage: E4 * u
|
|
591
|
+
1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + O(q^6)
|
|
592
|
+
"""
|
|
593
|
+
return self.element_class(self, {0: self.base_ring().one()})
|
|
594
|
+
|
|
595
|
+
def _coerce_map_from_(self, M):
|
|
596
|
+
r"""
|
|
597
|
+
Return ``True`` if there is a coercion map from ``M`` to this
|
|
598
|
+
ring.
|
|
599
|
+
|
|
600
|
+
TESTS::
|
|
601
|
+
|
|
602
|
+
sage: M = ModularFormsRing(1)
|
|
603
|
+
sage: E6 = ModularForms(1,6).0
|
|
604
|
+
sage: D = ModularForms(1,12).1
|
|
605
|
+
sage: M(D) + E6
|
|
606
|
+
2 - 282744/691*q + 122757768/691*q^2 + 11521760544/691*q^3 + 274576933512/691*q^4 + 3198130142256/691*q^5 + O(q^6)
|
|
607
|
+
sage: D + M(E6)
|
|
608
|
+
2 - 282744/691*q + 122757768/691*q^2 + 11521760544/691*q^3 + 274576933512/691*q^4 + 3198130142256/691*q^5 + O(q^6)
|
|
609
|
+
sage: 14 + M(D)
|
|
610
|
+
15 + 65520/691*q + 134250480/691*q^2 + 11606736960/691*q^3 + 274945048560/691*q^4 + 3199218815520/691*q^5 + O(q^6)
|
|
611
|
+
sage: M(D) + 53
|
|
612
|
+
54 + 65520/691*q + 134250480/691*q^2 + 11606736960/691*q^3 + 274945048560/691*q^4 + 3199218815520/691*q^5 + O(q^6)
|
|
613
|
+
"""
|
|
614
|
+
if isinstance(M, ModularFormsSpace):
|
|
615
|
+
if M.group() == self.group() and self.has_coerce_map_from(M.base_ring()):
|
|
616
|
+
return True
|
|
617
|
+
if self.base_ring().has_coerce_map_from(M):
|
|
618
|
+
return True
|
|
619
|
+
return False
|
|
620
|
+
|
|
621
|
+
def __richcmp__(self, other, op):
|
|
622
|
+
r"""
|
|
623
|
+
Compare ``self`` to ``other``.
|
|
624
|
+
|
|
625
|
+
Rings are equal if and only if their groups and base rings are.
|
|
626
|
+
|
|
627
|
+
EXAMPLES::
|
|
628
|
+
|
|
629
|
+
sage: ModularFormsRing(3) == 3
|
|
630
|
+
False
|
|
631
|
+
sage: ModularFormsRing(Gamma0(3)) == ModularFormsRing(Gamma0(7))
|
|
632
|
+
False
|
|
633
|
+
sage: ModularFormsRing(Gamma0(3)) == ModularFormsRing(Gamma0(3))
|
|
634
|
+
True
|
|
635
|
+
"""
|
|
636
|
+
if not isinstance(other, ModularFormsRing):
|
|
637
|
+
return NotImplemented
|
|
638
|
+
|
|
639
|
+
return richcmp((self.group(), self.base_ring()),
|
|
640
|
+
(other.group(), other.base_ring()), op)
|
|
641
|
+
|
|
642
|
+
def _repr_(self):
|
|
643
|
+
r"""
|
|
644
|
+
Return the string representation of ``self``.
|
|
645
|
+
|
|
646
|
+
EXAMPLES::
|
|
647
|
+
|
|
648
|
+
sage: ModularFormsRing(Gamma0(13))._repr_()
|
|
649
|
+
'Ring of Modular Forms for Congruence Subgroup Gamma0(13) over Rational Field'
|
|
650
|
+
sage: ModularFormsRing(Gamma1(13), base_ring=ZZ)._repr_()
|
|
651
|
+
'Ring of Modular Forms for Congruence Subgroup Gamma1(13) over Integer Ring'
|
|
652
|
+
"""
|
|
653
|
+
return "Ring of Modular Forms for %s over %s" % (self.group(), self.base_ring())
|
|
654
|
+
|
|
655
|
+
def modular_forms_of_weight(self, weight):
|
|
656
|
+
"""
|
|
657
|
+
Return the space of modular forms of the given weight and the
|
|
658
|
+
same congruence subgroup.
|
|
659
|
+
|
|
660
|
+
EXAMPLES::
|
|
661
|
+
|
|
662
|
+
sage: R = ModularFormsRing(13)
|
|
663
|
+
sage: R.modular_forms_of_weight(10)
|
|
664
|
+
Modular Forms space of dimension 11 for Congruence Subgroup Gamma0(13) of weight 10 over Rational Field
|
|
665
|
+
sage: ModularFormsRing(Gamma1(13)).modular_forms_of_weight(3)
|
|
666
|
+
Modular Forms space of dimension 20 for Congruence Subgroup Gamma1(13) of weight 3 over Rational Field
|
|
667
|
+
"""
|
|
668
|
+
return ModularForms(self.group(), weight)
|
|
669
|
+
|
|
670
|
+
def generators(self, maxweight=8, prec=10, start_gens=[], start_weight=2):
|
|
671
|
+
r"""
|
|
672
|
+
Return a list of generator of this ring as a list of pairs
|
|
673
|
+
`(k, f)` where `k` is an integer and `f` is a univariate power
|
|
674
|
+
series in `q` corresponding to the `q`-expansion of a modular
|
|
675
|
+
form of weight `k`.
|
|
676
|
+
|
|
677
|
+
More precisely, if `R` is the base ring of self, then this
|
|
678
|
+
function calculates a set of modular forms which generate the
|
|
679
|
+
`R`-algebra of all modular forms of weight up to ``maxweight``
|
|
680
|
+
with coefficients in `R`.
|
|
681
|
+
|
|
682
|
+
INPUT:
|
|
683
|
+
|
|
684
|
+
- ``maxweight`` -- integer (default: 8); check up to this weight
|
|
685
|
+
for generators
|
|
686
|
+
|
|
687
|
+
- ``prec`` -- integer (default: 10); return `q`-expansions to
|
|
688
|
+
this precision
|
|
689
|
+
|
|
690
|
+
- ``start_gens`` -- list (default: ``[]``); list of pairs
|
|
691
|
+
`(k, f)`, or triples `(k, f, F)`, where:
|
|
692
|
+
|
|
693
|
+
- `k` is an integer,
|
|
694
|
+
- `f` is the `q`-expansion of a modular form of weight `k`,
|
|
695
|
+
as a power series over the base ring of self,
|
|
696
|
+
- `F` (if provided) is a modular form object corresponding to F.
|
|
697
|
+
|
|
698
|
+
If this list is nonempty, we find a minimal generating set containing
|
|
699
|
+
these forms. If `F` is not supplied, then `f` needs to have
|
|
700
|
+
sufficiently large precision (an error will be raised if this is not
|
|
701
|
+
the case); otherwise, more terms will be calculated from the modular
|
|
702
|
+
form object `F`.
|
|
703
|
+
|
|
704
|
+
- ``start_weight`` -- integer (default: 2); calculate the graded
|
|
705
|
+
subalgebra of forms of weight at least ``start_weight``
|
|
706
|
+
|
|
707
|
+
OUTPUT:
|
|
708
|
+
|
|
709
|
+
a list of pairs (k, f), where f is the `q`-expansion to precision
|
|
710
|
+
``prec`` of a modular form of weight k.
|
|
711
|
+
|
|
712
|
+
.. SEEALSO::
|
|
713
|
+
|
|
714
|
+
:meth:`gen_forms`, which does exactly the same thing, but returns
|
|
715
|
+
Sage modular form objects rather than bare power series, and keeps
|
|
716
|
+
track of a lifting to characteristic 0 when the base ring is a
|
|
717
|
+
finite field.
|
|
718
|
+
|
|
719
|
+
.. NOTE::
|
|
720
|
+
|
|
721
|
+
If called with the default values of ``start_gens`` (an empty list)
|
|
722
|
+
and ``start_weight`` (2), the values will be cached for re-use on
|
|
723
|
+
subsequent calls to this function. (This cache is shared with
|
|
724
|
+
:meth:`gen_forms`). If called with non-default values for these
|
|
725
|
+
parameters, caching will be disabled.
|
|
726
|
+
|
|
727
|
+
EXAMPLES::
|
|
728
|
+
|
|
729
|
+
sage: ModularFormsRing(SL2Z).generators()
|
|
730
|
+
[(4, 1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + 60480*q^6 + 82560*q^7 + 140400*q^8 + 181680*q^9 + O(q^10)),
|
|
731
|
+
(6, 1 - 504*q - 16632*q^2 - 122976*q^3 - 532728*q^4 - 1575504*q^5 - 4058208*q^6 - 8471232*q^7 - 17047800*q^8 - 29883672*q^9 + O(q^10))]
|
|
732
|
+
sage: s = ModularFormsRing(SL2Z).generators(maxweight=5, prec=3); s
|
|
733
|
+
[(4, 1 + 240*q + 2160*q^2 + O(q^3))]
|
|
734
|
+
sage: s[0][1].parent()
|
|
735
|
+
Power Series Ring in q over Rational Field
|
|
736
|
+
|
|
737
|
+
sage: ModularFormsRing(1).generators(prec=4)
|
|
738
|
+
[(4, 1 + 240*q + 2160*q^2 + 6720*q^3 + O(q^4)),
|
|
739
|
+
(6, 1 - 504*q - 16632*q^2 - 122976*q^3 + O(q^4))]
|
|
740
|
+
sage: ModularFormsRing(2).generators(prec=12)
|
|
741
|
+
[(2, 1 + 24*q + 24*q^2 + 96*q^3 + 24*q^4 + 144*q^5 + 96*q^6 + 192*q^7 + 24*q^8 + 312*q^9 + 144*q^10 + 288*q^11 + O(q^12)),
|
|
742
|
+
(4, 1 + 240*q^2 + 2160*q^4 + 6720*q^6 + 17520*q^8 + 30240*q^10 + O(q^12))]
|
|
743
|
+
sage: ModularFormsRing(4).generators(maxweight=2, prec=20)
|
|
744
|
+
[(2, 1 + 24*q^2 + 24*q^4 + 96*q^6 + 24*q^8 + 144*q^10 + 96*q^12 + 192*q^14 + 24*q^16 + 312*q^18 + O(q^20)),
|
|
745
|
+
(2, q + 4*q^3 + 6*q^5 + 8*q^7 + 13*q^9 + 12*q^11 + 14*q^13 + 24*q^15 + 18*q^17 + 20*q^19 + O(q^20))]
|
|
746
|
+
|
|
747
|
+
Here we see that for ``\Gamma_0(11)`` taking a basis of forms in weights 2
|
|
748
|
+
and 4 is enough to generate everything up to weight 12 (and probably
|
|
749
|
+
everything else).::
|
|
750
|
+
|
|
751
|
+
sage: v = ModularFormsRing(11).generators(maxweight=12)
|
|
752
|
+
sage: len(v)
|
|
753
|
+
3
|
|
754
|
+
sage: [k for k, _ in v]
|
|
755
|
+
[2, 2, 4]
|
|
756
|
+
sage: from sage.modular.dims import dimension_modular_forms
|
|
757
|
+
sage: dimension_modular_forms(11,2)
|
|
758
|
+
2
|
|
759
|
+
sage: dimension_modular_forms(11,4)
|
|
760
|
+
4
|
|
761
|
+
|
|
762
|
+
For congruence subgroups not containing -1, we miss out some forms since we
|
|
763
|
+
can't calculate weight 1 forms at present, but we can still find generators
|
|
764
|
+
for the ring of forms of weight `\ge 2`::
|
|
765
|
+
|
|
766
|
+
sage: ModularFormsRing(Gamma1(4)).generators(prec=10, maxweight=10)
|
|
767
|
+
[(2, 1 + 24*q^2 + 24*q^4 + 96*q^6 + 24*q^8 + O(q^10)),
|
|
768
|
+
(2, q + 4*q^3 + 6*q^5 + 8*q^7 + 13*q^9 + O(q^10)),
|
|
769
|
+
(3, 1 + 12*q^2 + 64*q^3 + 60*q^4 + 160*q^6 + 384*q^7 + 252*q^8 + O(q^10)),
|
|
770
|
+
(3, q + 4*q^2 + 8*q^3 + 16*q^4 + 26*q^5 + 32*q^6 + 48*q^7 + 64*q^8 + 73*q^9 + O(q^10))]
|
|
771
|
+
|
|
772
|
+
Using different base rings will change the generators::
|
|
773
|
+
|
|
774
|
+
sage: ModularFormsRing(Gamma0(13)).generators(maxweight=12, prec=4)
|
|
775
|
+
[(2, 1 + 2*q + 6*q^2 + 8*q^3 + O(q^4)),
|
|
776
|
+
(4, 1 + O(q^4)), (4, q + O(q^4)),
|
|
777
|
+
(4, q^2 + O(q^4)), (4, q^3 + O(q^4)),
|
|
778
|
+
(6, 1 + O(q^4)),
|
|
779
|
+
(6, q + O(q^4))]
|
|
780
|
+
sage: ModularFormsRing(Gamma0(13),base_ring=ZZ).generators(maxweight=12, prec=4)
|
|
781
|
+
[(2, 1 + 2*q + 6*q^2 + 8*q^3 + O(q^4)),
|
|
782
|
+
(4, q + 4*q^2 + 10*q^3 + O(q^4)),
|
|
783
|
+
(4, 2*q^2 + 5*q^3 + O(q^4)),
|
|
784
|
+
(4, q^2 + O(q^4)),
|
|
785
|
+
(4, -2*q^3 + O(q^4)),
|
|
786
|
+
(6, O(q^4)),
|
|
787
|
+
(6, O(q^4)),
|
|
788
|
+
(12, O(q^4))]
|
|
789
|
+
sage: [k for k,f in ModularFormsRing(1, QQ).generators(maxweight=12)]
|
|
790
|
+
[4, 6]
|
|
791
|
+
sage: [k for k,f in ModularFormsRing(1, ZZ).generators(maxweight=12)]
|
|
792
|
+
[4, 6, 12]
|
|
793
|
+
sage: [k for k,f in ModularFormsRing(1, Zmod(5)).generators(maxweight=12)]
|
|
794
|
+
[4, 6]
|
|
795
|
+
sage: [k for k,f in ModularFormsRing(1, Zmod(2)).generators(maxweight=12)]
|
|
796
|
+
[4, 6, 12]
|
|
797
|
+
|
|
798
|
+
An example where ``start_gens`` are specified::
|
|
799
|
+
|
|
800
|
+
sage: M = ModularForms(11, 2); f = (M.0 + M.1).qexp(8)
|
|
801
|
+
sage: ModularFormsRing(11).generators(start_gens = [(2, f)])
|
|
802
|
+
Traceback (most recent call last):
|
|
803
|
+
...
|
|
804
|
+
ValueError: Requested precision cannot be higher than precision of approximate starting generators!
|
|
805
|
+
sage: f = (M.0 + M.1).qexp(10); f
|
|
806
|
+
1 + 17/5*q + 26/5*q^2 + 43/5*q^3 + 94/5*q^4 + 77/5*q^5 + 154/5*q^6 + 86/5*q^7 + 36*q^8 + 146/5*q^9 + O(q^10)
|
|
807
|
+
sage: ModularFormsRing(11).generators(start_gens = [(2, f)])
|
|
808
|
+
[(2, 1 + 17/5*q + 26/5*q^2 + 43/5*q^3 + 94/5*q^4 + 77/5*q^5 + 154/5*q^6 + 86/5*q^7 + 36*q^8 + 146/5*q^9 + O(q^10)),
|
|
809
|
+
(2, 1 + 12*q^2 + 12*q^3 + 12*q^4 + 12*q^5 + 24*q^6 + 24*q^7 + 36*q^8 + 36*q^9 + O(q^10)),
|
|
810
|
+
(4, 1 + O(q^10))]
|
|
811
|
+
"""
|
|
812
|
+
sgs = []
|
|
813
|
+
for x in start_gens:
|
|
814
|
+
if len(x) == 2:
|
|
815
|
+
if x[1].prec() < prec:
|
|
816
|
+
raise ValueError("Requested precision cannot be higher"
|
|
817
|
+
" than precision of approximate starting generators!")
|
|
818
|
+
sgs.append((x[0], x[1], None))
|
|
819
|
+
else:
|
|
820
|
+
sgs.append(x)
|
|
821
|
+
|
|
822
|
+
G = self._find_generators(maxweight, tuple(sgs), start_weight)
|
|
823
|
+
|
|
824
|
+
ret = []
|
|
825
|
+
# Returned generators may be a funny mixture of precisions if start_gens has been used.
|
|
826
|
+
for k, f, F in G:
|
|
827
|
+
if f.prec() < prec:
|
|
828
|
+
f = F.qexp(prec).change_ring(self.base_ring())
|
|
829
|
+
else:
|
|
830
|
+
f = f.truncate_powerseries(prec)
|
|
831
|
+
ret.append((k, f))
|
|
832
|
+
|
|
833
|
+
return ret
|
|
834
|
+
|
|
835
|
+
def gen_forms(self, maxweight=8, start_gens=[], start_weight=2):
|
|
836
|
+
r"""
|
|
837
|
+
Return a list of modular forms generating this ring (as an algebra
|
|
838
|
+
over the appropriate base ring).
|
|
839
|
+
|
|
840
|
+
This method differs from :meth:`generators` only in that it returns
|
|
841
|
+
graded modular form objects, rather than bare `q`-expansions.
|
|
842
|
+
|
|
843
|
+
INPUT:
|
|
844
|
+
|
|
845
|
+
- ``maxweight`` -- integer (default: 8); calculate forms
|
|
846
|
+
generating all forms up to this weight
|
|
847
|
+
|
|
848
|
+
- ``start_gens`` -- list (default: ``[]``); a list of
|
|
849
|
+
modular forms. If this list is nonempty, we find a minimal
|
|
850
|
+
generating set containing these forms.
|
|
851
|
+
|
|
852
|
+
- ``start_weight`` -- integer (default: 2); calculate the graded
|
|
853
|
+
subalgebra of forms of weight at least ``start_weight``
|
|
854
|
+
|
|
855
|
+
.. NOTE::
|
|
856
|
+
|
|
857
|
+
If called with the default values of ``start_gens`` (an empty list)
|
|
858
|
+
and ``start_weight`` (2), the values will be cached for re-use on
|
|
859
|
+
subsequent calls to this function. (This cache is shared with
|
|
860
|
+
:meth:`generators`). If called with non-default values for these
|
|
861
|
+
parameters, caching will be disabled.
|
|
862
|
+
|
|
863
|
+
EXAMPLES::
|
|
864
|
+
|
|
865
|
+
sage: A = ModularFormsRing(Gamma0(11), Zmod(5)).gen_forms(); A
|
|
866
|
+
[1 + 12*q^2 + 12*q^3 + 12*q^4 + 12*q^5 + O(q^6),
|
|
867
|
+
q - 2*q^2 - q^3 + 2*q^4 + q^5 + O(q^6),
|
|
868
|
+
q - 9*q^4 - 10*q^5 + O(q^6)]
|
|
869
|
+
sage: A[0].parent()
|
|
870
|
+
Modular Forms space of dimension 2 for Congruence Subgroup Gamma0(11) of weight 2 over Rational Field
|
|
871
|
+
"""
|
|
872
|
+
sgs = tuple((F.weight(), None, F) for F in start_gens)
|
|
873
|
+
G = self._find_generators(maxweight, sgs, start_weight)
|
|
874
|
+
return [F for k, f, F in G]
|
|
875
|
+
|
|
876
|
+
gens = gen_forms
|
|
877
|
+
|
|
878
|
+
def _find_generators(self, maxweight, start_gens, start_weight):
|
|
879
|
+
r"""
|
|
880
|
+
Returns a list of triples `(k, f, F)` where `F` is a modular
|
|
881
|
+
form of weight `k` and `f` is its `q`-expansion coerced into the
|
|
882
|
+
base ring of self.
|
|
883
|
+
|
|
884
|
+
For internal use. This function is called by :meth:`generators`
|
|
885
|
+
and :meth:`gen_forms`.
|
|
886
|
+
|
|
887
|
+
INPUT:
|
|
888
|
+
|
|
889
|
+
- ``maxweight`` -- maximum weight to try
|
|
890
|
+
- ``start_weight`` -- minimum weight to try
|
|
891
|
+
- ``start_gens`` -- a sequence of tuples of the form `(k, f, F)`, where
|
|
892
|
+
`F` is a modular form of weight `k` and `f` is its `q`-expansion
|
|
893
|
+
coerced into ``self.base_ring()``. Either (but not both) of `f` and `F`
|
|
894
|
+
may be ``None``.
|
|
895
|
+
|
|
896
|
+
OUTPUT: list of tuples, formatted as with ``start_gens``
|
|
897
|
+
|
|
898
|
+
EXAMPLES::
|
|
899
|
+
|
|
900
|
+
sage: R = ModularFormsRing(Gamma1(4))
|
|
901
|
+
sage: R._find_generators(8, (), 2)
|
|
902
|
+
[(2, 1 + 24*q^2 + 24*q^4 + 96*q^6 + 24*q^8 + O(q^9), 1 + 24*q^2 + 24*q^4 + O(q^6)),
|
|
903
|
+
(2, q + 4*q^3 + 6*q^5 + 8*q^7 + O(q^9), q + 4*q^3 + 6*q^5 + O(q^6)),
|
|
904
|
+
(3, 1 + 12*q^2 + 64*q^3 + 60*q^4 + 160*q^6 + 384*q^7 + 252*q^8 + O(q^9), 1 + 12*q^2 + 64*q^3 + 60*q^4 + O(q^6)),
|
|
905
|
+
(3, q + 4*q^2 + 8*q^3 + 16*q^4 + 26*q^5 + 32*q^6 + 48*q^7 + 64*q^8 + O(q^9), q + 4*q^2 + 8*q^3 + 16*q^4 + 26*q^5 + O(q^6))]
|
|
906
|
+
"""
|
|
907
|
+
default_params = (start_gens == () and start_weight == 2)
|
|
908
|
+
|
|
909
|
+
if default_params and self.__cached_maxweight != -1:
|
|
910
|
+
verbose("Already know generators up to weight %s -- using those" % self.__cached_maxweight)
|
|
911
|
+
|
|
912
|
+
if self.__cached_maxweight >= maxweight:
|
|
913
|
+
return [(k, f, F) for k, f, F in self.__cached_gens if k <= maxweight]
|
|
914
|
+
|
|
915
|
+
start_gens = self.__cached_gens
|
|
916
|
+
start_weight = self.__cached_maxweight + 1
|
|
917
|
+
|
|
918
|
+
if self.group().is_even():
|
|
919
|
+
increment = 2
|
|
920
|
+
else:
|
|
921
|
+
increment = 1
|
|
922
|
+
|
|
923
|
+
working_prec = self.modular_forms_of_weight(maxweight).sturm_bound()
|
|
924
|
+
|
|
925
|
+
# parse the list of start gens
|
|
926
|
+
G = []
|
|
927
|
+
for x in start_gens:
|
|
928
|
+
k, f, F = x
|
|
929
|
+
if F is None and f.prec() < working_prec:
|
|
930
|
+
raise ValueError("Need start gens to precision at least %s" % working_prec)
|
|
931
|
+
elif f is None or f.prec() < working_prec:
|
|
932
|
+
f = F.qexp(working_prec).change_ring(self.base_ring())
|
|
933
|
+
G.append((k, f, F))
|
|
934
|
+
|
|
935
|
+
k = start_weight
|
|
936
|
+
if increment == 2 and (k % 2) == 1:
|
|
937
|
+
k += 1
|
|
938
|
+
|
|
939
|
+
while k <= maxweight:
|
|
940
|
+
|
|
941
|
+
if self.modular_forms_of_weight(k).dimension() == 0:
|
|
942
|
+
k += increment
|
|
943
|
+
continue
|
|
944
|
+
|
|
945
|
+
verbose('Looking at k = %s' % k)
|
|
946
|
+
M = self.modular_forms_of_weight(k)
|
|
947
|
+
|
|
948
|
+
# 1. Multiply together all forms in G that give an element
|
|
949
|
+
# of M.
|
|
950
|
+
if G:
|
|
951
|
+
F = _span_of_forms_in_weight(G, k, M.sturm_bound(), None, False)
|
|
952
|
+
else:
|
|
953
|
+
F = (self.base_ring() ** M.sturm_bound()).zero_submodule()
|
|
954
|
+
|
|
955
|
+
# 2. If the dimension of the span of the result is equal
|
|
956
|
+
# to the dimension of M, increment k.
|
|
957
|
+
if F.rank() == M.dimension():
|
|
958
|
+
if self.base_ring().is_field() or F.index_in_saturation() == 1:
|
|
959
|
+
# TODO: Do something clever if the submodule's of the right
|
|
960
|
+
# rank but not saturated -- avoid triggering needless
|
|
961
|
+
# modular symbol computations.
|
|
962
|
+
verbose('Nothing new in weight %s' % k)
|
|
963
|
+
k += increment
|
|
964
|
+
continue
|
|
965
|
+
|
|
966
|
+
# 3. If the dimension is less, compute a basis for G, and
|
|
967
|
+
# try adding basis elements of M into G.
|
|
968
|
+
|
|
969
|
+
verbose("Known generators span a subspace of dimension %s of space of dimension %s" % (F.dimension(), M.dimension()))
|
|
970
|
+
if self.base_ring() == ZZ:
|
|
971
|
+
verbose("saturation index is %s" % F.index_in_saturation())
|
|
972
|
+
|
|
973
|
+
t = verbose("Computing more modular forms at weight %s" % k)
|
|
974
|
+
kprec = M.sturm_bound()
|
|
975
|
+
if self.base_ring() == QQ:
|
|
976
|
+
B = M.q_echelon_basis(working_prec)
|
|
977
|
+
else:
|
|
978
|
+
B = M.q_integral_basis(working_prec)
|
|
979
|
+
t = verbose("done computing forms", t)
|
|
980
|
+
V = F.ambient_module().submodule_with_basis([f.padded_list(kprec) for f in B])
|
|
981
|
+
Q = V / F
|
|
982
|
+
for q in Q.gens():
|
|
983
|
+
try:
|
|
984
|
+
qc = V.coordinates(Q.lift(q))
|
|
985
|
+
except AttributeError:
|
|
986
|
+
# work around a silly free module bug
|
|
987
|
+
qc = V.coordinates(q.lift())
|
|
988
|
+
qcZZ = [ZZ(_) for _ in qc] # lift to ZZ so we can define F
|
|
989
|
+
f = sum([B[i] * qcZZ[i] for i in range(len(B))])
|
|
990
|
+
F = M(f)
|
|
991
|
+
G.append((k, f.change_ring(self.base_ring()), F))
|
|
992
|
+
|
|
993
|
+
verbose('added %s new generators' % Q.ngens(), t)
|
|
994
|
+
k += increment
|
|
995
|
+
|
|
996
|
+
if default_params:
|
|
997
|
+
self.__cached_maxweight = maxweight
|
|
998
|
+
self.__cached_gens = G
|
|
999
|
+
|
|
1000
|
+
return G
|
|
1001
|
+
|
|
1002
|
+
@cached_method
|
|
1003
|
+
def q_expansion_basis(self, weight, prec=None, use_random=True):
|
|
1004
|
+
r"""
|
|
1005
|
+
Return a basis of `q`-expansions for the space of modular forms
|
|
1006
|
+
of the given weight for this group, calculated using the ring
|
|
1007
|
+
generators given by ``find_generators``.
|
|
1008
|
+
|
|
1009
|
+
INPUT:
|
|
1010
|
+
|
|
1011
|
+
- ``weight`` -- the weight
|
|
1012
|
+
- ``prec`` -- integer (default: ``None``); power series
|
|
1013
|
+
precision. If ``None``, the precision defaults to the Sturm
|
|
1014
|
+
bound for the requested level and weight.
|
|
1015
|
+
- ``use_random`` -- boolean (default: ``True``); whether or not to
|
|
1016
|
+
use a randomized algorithm when building up the space of forms
|
|
1017
|
+
at the given weight from known generators of small weight.
|
|
1018
|
+
|
|
1019
|
+
EXAMPLES::
|
|
1020
|
+
|
|
1021
|
+
sage: m = ModularFormsRing(Gamma0(4))
|
|
1022
|
+
sage: m.q_expansion_basis(2,10)
|
|
1023
|
+
[1 + 24*q^2 + 24*q^4 + 96*q^6 + 24*q^8 + O(q^10),
|
|
1024
|
+
q + 4*q^3 + 6*q^5 + 8*q^7 + 13*q^9 + O(q^10)]
|
|
1025
|
+
sage: m.q_expansion_basis(3,10)
|
|
1026
|
+
[]
|
|
1027
|
+
|
|
1028
|
+
sage: X = ModularFormsRing(SL2Z)
|
|
1029
|
+
sage: X.q_expansion_basis(12, 10)
|
|
1030
|
+
[1 + 196560*q^2 + 16773120*q^3 + 398034000*q^4 + 4629381120*q^5 + 34417656000*q^6 + 187489935360*q^7 + 814879774800*q^8 + 2975551488000*q^9 + O(q^10),
|
|
1031
|
+
q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 - 6048*q^6 - 16744*q^7 + 84480*q^8 - 113643*q^9 + O(q^10)]
|
|
1032
|
+
|
|
1033
|
+
We calculate a basis of a massive modular forms space, in two ways.
|
|
1034
|
+
Using this module is about twice as fast as Sage's generic code. ::
|
|
1035
|
+
|
|
1036
|
+
sage: A = ModularFormsRing(11).q_expansion_basis(30, prec=40) # long time (5s)
|
|
1037
|
+
sage: B = ModularForms(Gamma0(11), 30).q_echelon_basis(prec=40) # long time (9s)
|
|
1038
|
+
sage: A == B # long time
|
|
1039
|
+
True
|
|
1040
|
+
|
|
1041
|
+
Check that absurdly small values of ``prec`` don't mess things up::
|
|
1042
|
+
|
|
1043
|
+
sage: ModularFormsRing(11).q_expansion_basis(10, prec=5)
|
|
1044
|
+
[1 + O(q^5), q + O(q^5), q^2 + O(q^5), q^3 + O(q^5),
|
|
1045
|
+
q^4 + O(q^5), O(q^5), O(q^5), O(q^5), O(q^5), O(q^5)]
|
|
1046
|
+
"""
|
|
1047
|
+
d = self.modular_forms_of_weight(weight).dimension()
|
|
1048
|
+
if d == 0:
|
|
1049
|
+
return []
|
|
1050
|
+
|
|
1051
|
+
if prec is None:
|
|
1052
|
+
prec = self.modular_forms_of_weight(weight).sturm_bound()
|
|
1053
|
+
|
|
1054
|
+
working_prec = max(prec, self.modular_forms_of_weight(weight).sturm_bound())
|
|
1055
|
+
|
|
1056
|
+
gen_weight = min(6, weight)
|
|
1057
|
+
|
|
1058
|
+
while True:
|
|
1059
|
+
verbose("Trying to generate the %s-dimensional space at weight %s using generators of weight up to %s" % (d, weight, gen_weight))
|
|
1060
|
+
G = self.generators(maxweight=gen_weight, prec=working_prec)
|
|
1061
|
+
V = _span_of_forms_in_weight(G, weight, prec=working_prec, use_random=use_random, stop_dim=d)
|
|
1062
|
+
if V.rank() == d and (self.base_ring().is_field() or V.index_in_saturation() == 1):
|
|
1063
|
+
break
|
|
1064
|
+
gen_weight += 1
|
|
1065
|
+
verbose("Need more generators: trying again with generators of weight up to %s" % gen_weight)
|
|
1066
|
+
|
|
1067
|
+
R = G[0][1].parent()
|
|
1068
|
+
return [R(list(x), prec=prec) for x in V.gens()]
|
|
1069
|
+
|
|
1070
|
+
def cuspidal_ideal_generators(self, maxweight=8, prec=None):
|
|
1071
|
+
r"""
|
|
1072
|
+
Return a set of generators for the ideal of cuspidal forms in
|
|
1073
|
+
this ring, as a module over the whole ring.
|
|
1074
|
+
|
|
1075
|
+
EXAMPLES::
|
|
1076
|
+
|
|
1077
|
+
sage: ModularFormsRing(Gamma0(3)).cuspidal_ideal_generators(maxweight=12)
|
|
1078
|
+
[(6, q - 6*q^2 + 9*q^3 + 4*q^4 + O(q^5), q - 6*q^2 + 9*q^3 + 4*q^4 + 6*q^5 + O(q^6))]
|
|
1079
|
+
sage: [k for k,f,F in ModularFormsRing(13, base_ring=ZZ).cuspidal_ideal_generators(maxweight=14)]
|
|
1080
|
+
[4, 4, 4, 6, 6, 12]
|
|
1081
|
+
"""
|
|
1082
|
+
working_prec = self.modular_forms_of_weight(maxweight).sturm_bound()
|
|
1083
|
+
|
|
1084
|
+
if self.__cached_cusp_maxweight > -1:
|
|
1085
|
+
k = self.__cached_cusp_maxweight + 1
|
|
1086
|
+
verbose("Already calculated cusp gens up to weight %s -- using those" % (k-1))
|
|
1087
|
+
|
|
1088
|
+
# we may need to increase the precision of the cached cusp
|
|
1089
|
+
# generators
|
|
1090
|
+
G = []
|
|
1091
|
+
for j,f,F in self.__cached_cusp_gens:
|
|
1092
|
+
if f.prec() >= working_prec:
|
|
1093
|
+
f = F.qexp(working_prec).change_ring(self.base_ring())
|
|
1094
|
+
G.append((j, f, F))
|
|
1095
|
+
else:
|
|
1096
|
+
k = 2
|
|
1097
|
+
G = []
|
|
1098
|
+
|
|
1099
|
+
while k <= maxweight:
|
|
1100
|
+
t = verbose(f"Looking for cusp generators in weight {k}")
|
|
1101
|
+
|
|
1102
|
+
kprec = self.modular_forms_of_weight(k).sturm_bound()
|
|
1103
|
+
|
|
1104
|
+
flist = []
|
|
1105
|
+
|
|
1106
|
+
for (j, f, F) in G:
|
|
1107
|
+
for g in self.q_expansion_basis(k - j, prec=kprec):
|
|
1108
|
+
flist.append(g*f)
|
|
1109
|
+
A = self.base_ring() ** kprec
|
|
1110
|
+
W = A.span([A(f.padded_list(kprec)) for f in flist])
|
|
1111
|
+
|
|
1112
|
+
S = self.modular_forms_of_weight(k).cuspidal_submodule()
|
|
1113
|
+
if (W.rank() == S.dimension()
|
|
1114
|
+
and (self.base_ring().is_field() or W.index_in_saturation() == 1)):
|
|
1115
|
+
verbose("Nothing new in weight %s" % k, t)
|
|
1116
|
+
k += 1
|
|
1117
|
+
continue
|
|
1118
|
+
|
|
1119
|
+
t = verbose("Known cusp generators span a submodule of dimension %s of space of dimension %s" % (W.rank(), S.dimension()), t)
|
|
1120
|
+
|
|
1121
|
+
B = S.q_integral_basis(prec=working_prec)
|
|
1122
|
+
V = A.span([A(f.change_ring(self.base_ring()).padded_list(kprec)) for f in B])
|
|
1123
|
+
Q = V/W
|
|
1124
|
+
|
|
1125
|
+
for q in Q.gens():
|
|
1126
|
+
try:
|
|
1127
|
+
qc = V.coordinates(Q.lift(q))
|
|
1128
|
+
except AttributeError:
|
|
1129
|
+
# work around a silly free module bug
|
|
1130
|
+
qc = V.coordinates(q.lift())
|
|
1131
|
+
qcZZ = [ZZ(_) for _ in qc] # lift to ZZ so we can define F
|
|
1132
|
+
f = sum([B[i] * qcZZ[i] for i in range(len(B))])
|
|
1133
|
+
F = S(f)
|
|
1134
|
+
G.append((k, f.change_ring(self.base_ring()), F))
|
|
1135
|
+
|
|
1136
|
+
verbose('added %s new generators' % Q.ngens(), t)
|
|
1137
|
+
k += 1
|
|
1138
|
+
|
|
1139
|
+
self.__cached_cusp_maxweight = maxweight
|
|
1140
|
+
self.__cached_cusp_gens = G
|
|
1141
|
+
|
|
1142
|
+
if prec is None:
|
|
1143
|
+
return G
|
|
1144
|
+
elif prec <= working_prec:
|
|
1145
|
+
return [(k, f.truncate_powerseries(prec), F) for k,f,F in G]
|
|
1146
|
+
else:
|
|
1147
|
+
# user wants increased precision, so we may as well cache that
|
|
1148
|
+
Gnew = [(k, F.qexp(prec).change_ring(self.base_ring()), F) for k, f, F in G]
|
|
1149
|
+
self.__cached_cusp_gens = Gnew
|
|
1150
|
+
return Gnew
|
|
1151
|
+
|
|
1152
|
+
def cuspidal_submodule_q_expansion_basis(self, weight, prec=None):
|
|
1153
|
+
r"""
|
|
1154
|
+
Return a basis of `q`-expansions for the space of cusp forms of
|
|
1155
|
+
weight ``weight`` for this group.
|
|
1156
|
+
|
|
1157
|
+
INPUT:
|
|
1158
|
+
|
|
1159
|
+
- ``weight`` -- the weight
|
|
1160
|
+
- ``prec`` -- integer (default: ``None``) precision of
|
|
1161
|
+
`q`-expansions to return
|
|
1162
|
+
|
|
1163
|
+
ALGORITHM: Uses the method :meth:`cuspidal_ideal_generators` to
|
|
1164
|
+
calculate generators of the ideal of cusp forms inside this ring. Then
|
|
1165
|
+
multiply these up to weight ``weight`` using the generators of the
|
|
1166
|
+
whole modular form space returned by :meth:`q_expansion_basis`.
|
|
1167
|
+
|
|
1168
|
+
EXAMPLES::
|
|
1169
|
+
|
|
1170
|
+
sage: R = ModularFormsRing(Gamma0(3))
|
|
1171
|
+
sage: R.cuspidal_submodule_q_expansion_basis(20)
|
|
1172
|
+
[q - 8532*q^6 - 88442*q^7 + O(q^8), q^2 + 207*q^6 + 24516*q^7 + O(q^8),
|
|
1173
|
+
q^3 + 456*q^6 + O(q^8), q^4 - 135*q^6 - 926*q^7 + O(q^8), q^5 + 18*q^6 + 135*q^7 + O(q^8)]
|
|
1174
|
+
|
|
1175
|
+
We compute a basis of a space of very large weight, quickly (using this
|
|
1176
|
+
module) and slowly (using modular symbols), and verify that the answers
|
|
1177
|
+
are the same. ::
|
|
1178
|
+
|
|
1179
|
+
sage: A = R.cuspidal_submodule_q_expansion_basis(80, prec=30) # long time (1s on sage.math, 2013)
|
|
1180
|
+
sage: B = R.modular_forms_of_weight(80).cuspidal_submodule().q_expansion_basis(prec=30) # long time (19s on sage.math, 2013)
|
|
1181
|
+
sage: A == B # long time
|
|
1182
|
+
True
|
|
1183
|
+
"""
|
|
1184
|
+
d = self.modular_forms_of_weight(weight).cuspidal_submodule().dimension()
|
|
1185
|
+
if d == 0:
|
|
1186
|
+
return []
|
|
1187
|
+
|
|
1188
|
+
minprec = self.modular_forms_of_weight(weight).sturm_bound()
|
|
1189
|
+
if prec is None:
|
|
1190
|
+
prec = working_prec = minprec
|
|
1191
|
+
else:
|
|
1192
|
+
working_prec = max(prec, minprec)
|
|
1193
|
+
|
|
1194
|
+
gen_weight = min(6, weight)
|
|
1195
|
+
|
|
1196
|
+
while True:
|
|
1197
|
+
verbose("Trying to generate the %s-dimensional cuspidal submodule at weight %s using generators of weight up to %s" % (d, weight, gen_weight))
|
|
1198
|
+
G = self.cuspidal_ideal_generators(maxweight=gen_weight, prec=working_prec)
|
|
1199
|
+
|
|
1200
|
+
flist = []
|
|
1201
|
+
for (j, f, F) in G:
|
|
1202
|
+
for g in self.q_expansion_basis(weight - j, prec=working_prec):
|
|
1203
|
+
flist.append(g*f)
|
|
1204
|
+
|
|
1205
|
+
A = self.base_ring() ** working_prec
|
|
1206
|
+
W = A.span([A(f.padded_list(working_prec)) for f in flist])
|
|
1207
|
+
if W.rank() == d and (self.base_ring().is_field() or W.index_in_saturation() == 1):
|
|
1208
|
+
break
|
|
1209
|
+
gen_weight += 1
|
|
1210
|
+
verbose("Need more generators: trying again with generators of weight up to %s" % gen_weight)
|
|
1211
|
+
|
|
1212
|
+
R = G[0][1].parent()
|
|
1213
|
+
return [R(list(x), prec=prec) for x in W.gens()]
|
|
1214
|
+
|
|
1215
|
+
def _to_matrix(self, gens=None, prec=None):
|
|
1216
|
+
r"""
|
|
1217
|
+
Return a matrix corresponding to the `q`-expansion of the generators to the given precision.
|
|
1218
|
+
|
|
1219
|
+
INPUT:
|
|
1220
|
+
|
|
1221
|
+
- ``gens`` -- (default: ``None``) a list of generators. If not provided,
|
|
1222
|
+
the list returned by :meth:`ModularFormsRing.gen_forms`
|
|
1223
|
+
is used instead.
|
|
1224
|
+
- ``prec`` -- (default: ``None``) precision to compute up to, or the Sturm
|
|
1225
|
+
bound if not provided.
|
|
1226
|
+
|
|
1227
|
+
OUTPUT: A matrix.
|
|
1228
|
+
|
|
1229
|
+
TESTS::
|
|
1230
|
+
|
|
1231
|
+
sage: M = ModularFormsRing(1)
|
|
1232
|
+
sage: E4 = M.0; E6 = M.1
|
|
1233
|
+
sage: gens = [E4^3, E6^2]; gens
|
|
1234
|
+
[1 + 720*q + 179280*q^2 + 16954560*q^3 + 396974160*q^4 + 4632858720*q^5 + O(q^6),
|
|
1235
|
+
1 - 1008*q + 220752*q^2 + 16519104*q^3 + 399517776*q^4 + 4624512480*q^5 + O(q^6)]
|
|
1236
|
+
sage: M._to_matrix(gens)
|
|
1237
|
+
[ 1 720]
|
|
1238
|
+
[ 1 -1008]
|
|
1239
|
+
sage: M._to_matrix(gens, 6)
|
|
1240
|
+
[ 1 720 179280 16954560 396974160 4632858720 34413301440]
|
|
1241
|
+
[ 1 -1008 220752 16519104 399517776 4624512480 34423752384]
|
|
1242
|
+
"""
|
|
1243
|
+
if gens is None:
|
|
1244
|
+
gens = self.gen_forms()
|
|
1245
|
+
|
|
1246
|
+
if prec is None:
|
|
1247
|
+
# we don't default to prec=6 because this is an internal function
|
|
1248
|
+
# and is usually used to write other forms as a linear combination
|
|
1249
|
+
# of generators, in which case using the Sturm bound is more reasonable
|
|
1250
|
+
prec = max(gen.group().sturm_bound(gen.weight()) for gen in gens)
|
|
1251
|
+
|
|
1252
|
+
return Matrix(gen.coefficients(range(prec + 1)) for gen in gens)
|
|
1253
|
+
|
|
1254
|
+
|
|
1255
|
+
# Deprecated functions
|
|
1256
|
+
find_generators = deprecated_function_alias(31559, ModularFormsRing.generators)
|
|
1257
|
+
basis_for_modform_space = deprecated_function_alias(31559, ModularFormsRing.q_expansion_basis)
|