passagemath-schemes 10.8.1a4__cp314-cp314t-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.
- 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.8.1a4.dist-info/METADATA +203 -0
- passagemath_schemes-10.8.1a4.dist-info/METADATA.bak +204 -0
- passagemath_schemes-10.8.1a4.dist-info/RECORD +312 -0
- passagemath_schemes-10.8.1a4.dist-info/WHEEL +6 -0
- passagemath_schemes-10.8.1a4.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 +9556 -0
- sage/dynamics/arithmetic_dynamics/projective_ds_helper.cpython-314t-darwin.so +0 -0
- sage/dynamics/arithmetic_dynamics/projective_ds_helper.pyx +301 -0
- sage/dynamics/arithmetic_dynamics/wehlerK3.py +2578 -0
- sage/lfunctions/all.py +18 -0
- sage/lfunctions/dokchitser.py +727 -0
- sage/lfunctions/pari.py +971 -0
- sage/lfunctions/zero_sums.cpython-314t-darwin.so +0 -0
- sage/lfunctions/zero_sums.pyx +1847 -0
- sage/modular/abvar/abvar.py +5132 -0
- sage/modular/abvar/abvar_ambient_jacobian.py +414 -0
- sage/modular/abvar/abvar_newform.py +246 -0
- sage/modular/abvar/all.py +8 -0
- sage/modular/abvar/constructor.py +187 -0
- sage/modular/abvar/cuspidal_subgroup.py +371 -0
- sage/modular/abvar/finite_subgroup.py +896 -0
- sage/modular/abvar/homology.py +721 -0
- sage/modular/abvar/homspace.py +989 -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 +741 -0
- sage/modular/all.py +43 -0
- sage/modular/arithgroup/all.py +20 -0
- sage/modular/arithgroup/arithgroup_element.cpython-314t-darwin.so +0 -0
- sage/modular/arithgroup/arithgroup_element.pyx +474 -0
- sage/modular/arithgroup/arithgroup_generic.py +1406 -0
- sage/modular/arithgroup/arithgroup_perm.py +2692 -0
- sage/modular/arithgroup/congroup.cpython-314t-darwin.so +0 -0
- sage/modular/arithgroup/congroup.pyx +334 -0
- sage/modular/arithgroup/congroup_gamma.py +361 -0
- sage/modular/arithgroup/congroup_gamma0.py +692 -0
- sage/modular/arithgroup/congroup_gamma1.py +659 -0
- sage/modular/arithgroup/congroup_gammaH.py +1491 -0
- sage/modular/arithgroup/congroup_generic.py +630 -0
- sage/modular/arithgroup/congroup_sl2z.py +266 -0
- sage/modular/arithgroup/farey_symbol.cpython-314t-darwin.so +0 -0
- sage/modular/arithgroup/farey_symbol.pyx +1067 -0
- sage/modular/arithgroup/tests.py +425 -0
- sage/modular/btquotients/all.py +4 -0
- sage/modular/btquotients/btquotient.py +3736 -0
- sage/modular/btquotients/pautomorphicform.py +2564 -0
- sage/modular/buzzard.py +100 -0
- sage/modular/congroup.py +29 -0
- sage/modular/congroup_element.py +13 -0
- sage/modular/cusps.py +1107 -0
- sage/modular/cusps_nf.py +1270 -0
- sage/modular/dims.py +571 -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 +1076 -0
- sage/modular/hecke/algebra.py +725 -0
- sage/modular/hecke/all.py +19 -0
- sage/modular/hecke/ambient_module.py +994 -0
- sage/modular/hecke/degenmap.py +119 -0
- sage/modular/hecke/element.py +302 -0
- sage/modular/hecke/hecke_operator.py +736 -0
- sage/modular/hecke/homspace.py +185 -0
- sage/modular/hecke/module.py +1744 -0
- sage/modular/hecke/morphism.py +139 -0
- sage/modular/hecke/submodule.py +970 -0
- sage/modular/hypergeometric_misc.cpython-314t-darwin.so +0 -0
- sage/modular/hypergeometric_misc.pxd +4 -0
- sage/modular/hypergeometric_misc.pyx +166 -0
- sage/modular/hypergeometric_motive.py +2020 -0
- sage/modular/local_comp/all.py +2 -0
- sage/modular/local_comp/liftings.py +292 -0
- sage/modular/local_comp/local_comp.py +1070 -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 +817 -0
- sage/modular/modform/ambient_R.py +177 -0
- sage/modular/modform/ambient_eps.py +306 -0
- sage/modular/modform/ambient_g0.py +120 -0
- sage/modular/modform/ambient_g1.py +199 -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 +487 -0
- sage/modular/modform/eisenstein_submodule.py +663 -0
- sage/modular/modform/element.py +4105 -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 +127 -0
- sage/modular/modform/l_series_gross_zagier_coeffs.cpython-314t-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 +1859 -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 +380 -0
- sage/modular/modform/weight1.py +221 -0
- sage/modular/modform_hecketriangle/abstract_ring.py +1932 -0
- sage/modular/modform_hecketriangle/abstract_space.py +2527 -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 +3349 -0
- sage/modular/modform_hecketriangle/hecke_triangle_groups.py +1426 -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 +3844 -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-314t-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 +1291 -0
- sage/modular/modsym/modsym.py +400 -0
- sage/modular/modsym/modular_symbols.py +384 -0
- sage/modular/modsym/p1list_nf.py +1241 -0
- sage/modular/modsym/relation_matrix.py +591 -0
- sage/modular/modsym/relation_matrix_pyx.cpython-314t-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 +376 -0
- sage/modular/multiple_zeta.py +2635 -0
- sage/modular/multiple_zeta_F_algebra.py +789 -0
- sage/modular/overconvergent/all.py +6 -0
- sage/modular/overconvergent/genus0.py +1879 -0
- sage/modular/overconvergent/hecke_series.py +1187 -0
- sage/modular/overconvergent/weightspace.py +776 -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 +856 -0
- sage/modular/pollack_stevens/modsym.py +1590 -0
- sage/modular/pollack_stevens/padic_lseries.py +417 -0
- sage/modular/pollack_stevens/sigma0.py +534 -0
- sage/modular/pollack_stevens/space.py +1078 -0
- sage/modular/quasimodform/all.py +3 -0
- sage/modular/quasimodform/element.py +846 -0
- sage/modular/quasimodform/ring.py +826 -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 +700 -0
- sage/schemes/curves/affine_curve.py +2924 -0
- sage/schemes/curves/all.py +33 -0
- sage/schemes/curves/closed_point.py +434 -0
- sage/schemes/curves/constructor.py +397 -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 +3203 -0
- sage/schemes/curves/weighted_projective_curve.py +106 -0
- sage/schemes/curves/zariski_vankampen.py +1931 -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 +991 -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 +1103 -0
- sage/schemes/elliptic_curves/constructor.py +1530 -0
- sage/schemes/elliptic_curves/ec_database.py +175 -0
- sage/schemes/elliptic_curves/ell_curve_isogeny.py +3971 -0
- sage/schemes/elliptic_curves/ell_egros.py +457 -0
- sage/schemes/elliptic_curves/ell_field.py +2837 -0
- sage/schemes/elliptic_curves/ell_finite_field.py +3249 -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 +4944 -0
- sage/schemes/elliptic_curves/ell_rational_field.py +7184 -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 +1663 -0
- sage/schemes/elliptic_curves/gp_simon.py +152 -0
- sage/schemes/elliptic_curves/heegner.py +7328 -0
- sage/schemes/elliptic_curves/height.py +2108 -0
- sage/schemes/elliptic_curves/hom.py +1788 -0
- sage/schemes/elliptic_curves/hom_composite.py +1084 -0
- sage/schemes/elliptic_curves/hom_fractional.py +544 -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 +681 -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 +1523 -0
- sage/schemes/elliptic_curves/isogeny_small_degree.py +2797 -0
- sage/schemes/elliptic_curves/jacobian.py +247 -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 +915 -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-314t-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-314t-darwin.so +0 -0
- sage/schemes/elliptic_curves/period_lattice_region.pyx +722 -0
- sage/schemes/elliptic_curves/saturation.py +716 -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 +369 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py +1948 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_g2.py +192 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py +936 -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 +312 -0
- sage/schemes/hyperelliptic_curves/jacobian_g2.py +32 -0
- sage/schemes/hyperelliptic_curves/jacobian_generic.py +437 -0
- sage/schemes/hyperelliptic_curves/jacobian_homset.py +186 -0
- sage/schemes/hyperelliptic_curves/jacobian_morphism.py +878 -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 +3863 -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 +581 -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 +53 -0
- sage/schemes/riemann_surfaces/all.py +1 -0
- sage/schemes/riemann_surfaces/riemann_surface.py +4177 -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,2527 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-schemes
|
|
2
|
+
# sage.doctest: needs sage.combinat sage.graphs
|
|
3
|
+
r"""
|
|
4
|
+
Modular forms for Hecke triangle groups
|
|
5
|
+
|
|
6
|
+
AUTHORS:
|
|
7
|
+
|
|
8
|
+
- Jonas Jermann (2013): initial version
|
|
9
|
+
"""
|
|
10
|
+
# ****************************************************************************
|
|
11
|
+
# Copyright (C) 2013-2014 Jonas Jermann <jjermann2@gmail.com>
|
|
12
|
+
#
|
|
13
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
14
|
+
# as published by the Free Software Foundation; either version 2 of
|
|
15
|
+
# the License, or (at your option) any later version.
|
|
16
|
+
# https://www.gnu.org/licenses/
|
|
17
|
+
# ****************************************************************************
|
|
18
|
+
from sage.matrix.constructor import matrix
|
|
19
|
+
from sage.misc.cachefunc import cached_method
|
|
20
|
+
from sage.misc.lazy_import import lazy_import
|
|
21
|
+
from sage.modules.free_module_element import FreeModuleElement
|
|
22
|
+
from sage.modules.free_module_element import vector
|
|
23
|
+
from sage.rings.infinity import infinity
|
|
24
|
+
from sage.rings.integer import Integer
|
|
25
|
+
from sage.rings.integer_ring import ZZ
|
|
26
|
+
from sage.rings.laurent_series_ring import LaurentSeriesRing
|
|
27
|
+
from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic
|
|
28
|
+
from sage.rings.power_series_ring import PowerSeriesRing_generic
|
|
29
|
+
from sage.rings.rational_field import QQ
|
|
30
|
+
from sage.structure.element import parent
|
|
31
|
+
|
|
32
|
+
from .abstract_ring import FormsRing_abstract
|
|
33
|
+
|
|
34
|
+
lazy_import('sage.rings.imaginary_unit', 'I')
|
|
35
|
+
lazy_import('sage.rings.lazy_series_ring', ('LazyLaurentSeriesRing', 'LazyPowerSeriesRing'))
|
|
36
|
+
lazy_import('sage.rings.qqbar', 'QQbar')
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class FormsSpace_abstract(FormsRing_abstract):
|
|
40
|
+
r"""
|
|
41
|
+
Abstract (Hecke) forms space.
|
|
42
|
+
|
|
43
|
+
This should never be called directly. Instead one should
|
|
44
|
+
instantiate one of the derived classes of this class.
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
from .element import FormsElement
|
|
48
|
+
Element = FormsElement
|
|
49
|
+
|
|
50
|
+
def __init__(self, group, base_ring, k, ep, n):
|
|
51
|
+
r"""
|
|
52
|
+
Abstract (Hecke) forms space.
|
|
53
|
+
|
|
54
|
+
INPUT:
|
|
55
|
+
|
|
56
|
+
- ``group`` -- the Hecke triangle group (default: ``HeckeTriangleGroup(3)``)
|
|
57
|
+
|
|
58
|
+
- ``k`` -- the weight (default: `0`)
|
|
59
|
+
|
|
60
|
+
- ``ep`` -- the epsilon (default: ``None``); if ``None``, then `k(n-2)`
|
|
61
|
+
has to be divisible by `2` and ``ep=(-1)^(k*(n-2)/2)`` is used
|
|
62
|
+
|
|
63
|
+
- ``base_ring`` -- the base_ring (default: `\Z`)
|
|
64
|
+
|
|
65
|
+
OUTPUT: the corresponding abstract (Hecke) forms space
|
|
66
|
+
|
|
67
|
+
EXAMPLES::
|
|
68
|
+
|
|
69
|
+
sage: from sage.modular.modform_hecketriangle.space import ModularForms
|
|
70
|
+
sage: MF = ModularForms(n=5, base_ring=ZZ, k=6, ep=-1)
|
|
71
|
+
sage: MF
|
|
72
|
+
ModularForms(n=5, k=6, ep=-1) over Integer Ring
|
|
73
|
+
sage: MF.group()
|
|
74
|
+
Hecke triangle group for n = 5
|
|
75
|
+
sage: MF.base_ring()
|
|
76
|
+
Integer Ring
|
|
77
|
+
sage: MF.weight()
|
|
78
|
+
6
|
|
79
|
+
sage: MF.ep()
|
|
80
|
+
-1
|
|
81
|
+
sage: MF.has_reduce_hom()
|
|
82
|
+
True
|
|
83
|
+
sage: MF.is_homogeneous()
|
|
84
|
+
True
|
|
85
|
+
"""
|
|
86
|
+
# from space import canonical_parameters
|
|
87
|
+
# (group, base_ring, k, ep, n) = canonical_parameters(group, base_ring, k, ep, n)
|
|
88
|
+
|
|
89
|
+
super().__init__(group=group, base_ring=base_ring, red_hom=True, n=n)
|
|
90
|
+
# self.register_embedding(self.hom(lambda f: f.parent().graded_ring()(f), codomain=self.graded_ring()))
|
|
91
|
+
|
|
92
|
+
self._weight = k
|
|
93
|
+
self._ep = ep
|
|
94
|
+
(self._l1, self._l2) = self.weight_parameters()
|
|
95
|
+
self._module = None
|
|
96
|
+
self._ambient_space = self
|
|
97
|
+
|
|
98
|
+
def _repr_(self):
|
|
99
|
+
r"""
|
|
100
|
+
Return the string representation of ``self``.
|
|
101
|
+
|
|
102
|
+
EXAMPLES::
|
|
103
|
+
|
|
104
|
+
sage: from sage.modular.modform_hecketriangle.space import QuasiModularForms
|
|
105
|
+
sage: QuasiModularForms(n=4, k=2, ep=-1)
|
|
106
|
+
QuasiModularForms(n=4, k=2, ep=-1) over Integer Ring
|
|
107
|
+
"""
|
|
108
|
+
|
|
109
|
+
return "{}Forms(n={}, k={}, ep={}) over {}".format(self._analytic_type.analytic_space_name(), self._group.n(), self._weight, self._ep, self._base_ring)
|
|
110
|
+
|
|
111
|
+
def _latex_(self):
|
|
112
|
+
r"""
|
|
113
|
+
Return the LaTeX representation of ``self``.
|
|
114
|
+
|
|
115
|
+
EXAMPLES::
|
|
116
|
+
|
|
117
|
+
sage: from sage.modular.modform_hecketriangle.space import QuasiWeakModularForms
|
|
118
|
+
sage: latex(QuasiWeakModularForms())
|
|
119
|
+
QM^!_{ n=3 }(0,\ 1)(\Bold{Z})
|
|
120
|
+
"""
|
|
121
|
+
|
|
122
|
+
from sage.misc.latex import latex
|
|
123
|
+
return r"{}_{{ n={} }}({},\ {})({})".format(self._analytic_type.latex_space_name(), self._group.n(), self._weight, self._ep, latex(self._base_ring))
|
|
124
|
+
|
|
125
|
+
def _element_constructor_(self, el):
|
|
126
|
+
r"""
|
|
127
|
+
Return ``el`` coerced into this forms space.
|
|
128
|
+
|
|
129
|
+
EXAMPLES::
|
|
130
|
+
|
|
131
|
+
sage: from sage.modular.modform_hecketriangle.graded_ring import MeromorphicModularFormsRing
|
|
132
|
+
sage: from sage.modular.modform_hecketriangle.space import ModularForms, QuasiWeakModularForms
|
|
133
|
+
sage: MF = ModularForms(k=12, ep=1)
|
|
134
|
+
sage: (x,y,z,d) = MF.pol_ring().gens()
|
|
135
|
+
|
|
136
|
+
sage: Delta = MeromorphicModularFormsRing().Delta()
|
|
137
|
+
sage: Delta.parent()
|
|
138
|
+
MeromorphicModularFormsRing(n=3) over Integer Ring
|
|
139
|
+
sage: MF(Delta)
|
|
140
|
+
q - 24*q^2 + 252*q^3 - 1472*q^4 + O(q^5)
|
|
141
|
+
sage: MF(Delta).parent() == MF
|
|
142
|
+
True
|
|
143
|
+
|
|
144
|
+
sage: E2 = MF.E2()
|
|
145
|
+
sage: e2 = QuasiWeakModularForms(n=infinity, k=2, ep=-1)(E2)
|
|
146
|
+
sage: e2
|
|
147
|
+
1 - 24*q^2 - 72*q^4 + O(q^5)
|
|
148
|
+
sage: e2.parent()
|
|
149
|
+
QuasiWeakModularForms(n=+Infinity, k=2, ep=-1) over Integer Ring
|
|
150
|
+
sage: e2.as_ring_element()
|
|
151
|
+
(-f_i + 3*E2)/2
|
|
152
|
+
sage: MF(x^3)
|
|
153
|
+
1 + 720*q + 179280*q^2 + 16954560*q^3 + 396974160*q^4 + O(q^5)
|
|
154
|
+
sage: MF(x^3).parent() == MF
|
|
155
|
+
True
|
|
156
|
+
|
|
157
|
+
sage: qexp = Delta.q_expansion(prec=2)
|
|
158
|
+
sage: qexp
|
|
159
|
+
q + O(q^2)
|
|
160
|
+
sage: qexp.parent()
|
|
161
|
+
Power Series Ring in q over Fraction Field of Univariate Polynomial Ring in d over Integer Ring
|
|
162
|
+
sage: MF(qexp)
|
|
163
|
+
q - 24*q^2 + 252*q^3 - 1472*q^4 + O(q^5)
|
|
164
|
+
sage: MF(qexp) == MF(Delta)
|
|
165
|
+
True
|
|
166
|
+
|
|
167
|
+
sage: QF = QuasiWeakModularForms(n=8, k=10/3, ep=-1)
|
|
168
|
+
sage: QF.default_prec(2)
|
|
169
|
+
sage: el2 = QF.quasi_part_gens(min_exp=-1)[4]
|
|
170
|
+
sage: el2.reduced_parent()
|
|
171
|
+
QuasiWeakModularForms(n=8, k=10/3, ep=-1) over Integer Ring
|
|
172
|
+
sage: prec = QF.required_laurent_prec(min_exp=-1)
|
|
173
|
+
sage: qexp2 = el2.q_expansion(prec=prec)
|
|
174
|
+
sage: qexp2
|
|
175
|
+
q^-1 - 19/(64*d) - 7497/(262144*d^2)*q + 15889/(8388608*d^3)*q^2 + 543834047/(1649267441664*d^4)*q^3 + 711869853/(43980465111040*d^5)*q^4 + O(q^5)
|
|
176
|
+
sage: qexp2.parent()
|
|
177
|
+
Laurent Series Ring in q over Fraction Field of Univariate Polynomial Ring in d over Integer Ring
|
|
178
|
+
sage: QF(qexp2)
|
|
179
|
+
q^-1 - 19/(64*d) - 7497/(262144*d^2)*q + O(q^2)
|
|
180
|
+
sage: QF(qexp2).reduced_parent()
|
|
181
|
+
QuasiWeakModularForms(n=8, k=10/3, ep=-1) over Integer Ring
|
|
182
|
+
sage: QF(qexp2) == el2
|
|
183
|
+
True
|
|
184
|
+
|
|
185
|
+
sage: QF = QuasiWeakModularForms(n=infinity, k=2, ep=-1)
|
|
186
|
+
sage: el3 = QF.f_i() + QF.f_i()^3/QF.E4()
|
|
187
|
+
sage: prec = QF.required_laurent_prec(order_1=-1)
|
|
188
|
+
sage: qexp3 = el3.q_expansion(prec=prec)
|
|
189
|
+
sage: qexp3
|
|
190
|
+
2 - 7/(4*d)*q + 195/(256*d^2)*q^2 - 903/(4096*d^3)*q^3 + 41987/(1048576*d^4)*q^4 - 181269/(33554432*d^5)*q^5 + O(q^6)
|
|
191
|
+
sage: QF.construct_quasi_form(qexp3, check=False) == el3
|
|
192
|
+
False
|
|
193
|
+
sage: QF.construct_quasi_form(qexp3, order_1=-1) == el3
|
|
194
|
+
True
|
|
195
|
+
|
|
196
|
+
sage: MF([0,1]) == MF(Delta)
|
|
197
|
+
True
|
|
198
|
+
sage: MF([1,0]) == MF(x^3) - 720*MF(Delta)
|
|
199
|
+
True
|
|
200
|
+
|
|
201
|
+
sage: vec = MF(Delta).coordinate_vector()
|
|
202
|
+
sage: vec
|
|
203
|
+
(0, 1)
|
|
204
|
+
sage: vec.parent()
|
|
205
|
+
Vector space of dimension 2 over Fraction Field of Univariate Polynomial Ring in d over Integer Ring
|
|
206
|
+
sage: vec in MF.module()
|
|
207
|
+
True
|
|
208
|
+
sage: MF(vec) == MF(Delta)
|
|
209
|
+
True
|
|
210
|
+
|
|
211
|
+
sage: subspace = MF.subspace([MF(Delta)])
|
|
212
|
+
sage: subspace
|
|
213
|
+
Subspace of dimension 1 of ModularForms(n=3, k=12, ep=1) over Integer Ring
|
|
214
|
+
sage: subspace(MF(Delta)) == subspace(d*(x^3-y^2)) == subspace(qexp) == subspace([0,1]) == subspace(vec) == subspace.gen()
|
|
215
|
+
True
|
|
216
|
+
sage: subspace(MF(Delta)).parent() == subspace(d*(x^3-y^2)).parent() == subspace(qexp).parent() == subspace([0,1]).parent() == subspace(vec).parent()
|
|
217
|
+
True
|
|
218
|
+
sage: subspace([1]) == subspace.gen()
|
|
219
|
+
True
|
|
220
|
+
sage: ssvec = subspace(vec).coordinate_vector()
|
|
221
|
+
sage: ssvec
|
|
222
|
+
(1)
|
|
223
|
+
sage: ssvec.parent()
|
|
224
|
+
Vector space of dimension 1 over Fraction Field of Univariate Polynomial Ring in d over Integer Ring
|
|
225
|
+
sage: ambvec = subspace(vec).ambient_coordinate_vector()
|
|
226
|
+
sage: ambvec
|
|
227
|
+
(0, 1)
|
|
228
|
+
sage: ambvec.parent()
|
|
229
|
+
Vector space of degree 2 and dimension 1 over Fraction Field of Univariate Polynomial Ring in d over Integer Ring
|
|
230
|
+
Basis matrix:
|
|
231
|
+
[0 1]
|
|
232
|
+
sage: subspace(ambvec) == subspace(vec) and subspace(ambvec).parent() == subspace(vec).parent()
|
|
233
|
+
True
|
|
234
|
+
"""
|
|
235
|
+
|
|
236
|
+
from .graded_ring_element import FormsRingElement
|
|
237
|
+
if isinstance(el, FormsRingElement):
|
|
238
|
+
if (self.hecke_n() == infinity and el.hecke_n() == ZZ(3)):
|
|
239
|
+
el_f = el._reduce_d()._rat
|
|
240
|
+
(x,y,z,d) = self.pol_ring().gens()
|
|
241
|
+
|
|
242
|
+
num_sub = el_f.numerator().subs( x=(y**2 + 3*x)/ZZ(4), y=(9*x*y - y**3)/ZZ(8), z=(3*z - y)/ZZ(2))
|
|
243
|
+
denom_sub = el_f.denominator().subs( x=(y**2 + 3*x)/ZZ(4), y=(9*x*y - y**3)/ZZ(8), z=(3*z - y)/ZZ(2))
|
|
244
|
+
new_num = num_sub.numerator()*denom_sub.denominator()
|
|
245
|
+
new_denom = denom_sub.numerator()*num_sub.denominator()
|
|
246
|
+
|
|
247
|
+
el = self._rat_field(new_num) / self._rat_field(new_denom)
|
|
248
|
+
elif self.group() == el.group():
|
|
249
|
+
el = el._rat
|
|
250
|
+
else:
|
|
251
|
+
raise ValueError("{} has group {} != {}".format(el, el.group(), self.group()))
|
|
252
|
+
return self.element_class(self, el)
|
|
253
|
+
# This assumes that the series corresponds to a _weakly
|
|
254
|
+
# holomorphic_ (quasi) form. It also assumes that the form is
|
|
255
|
+
# holomorphic at -1 for n=infinity (this assumption however
|
|
256
|
+
# can be changed in construct_form
|
|
257
|
+
# resp. construct_quasi_form))
|
|
258
|
+
P = parent(el)
|
|
259
|
+
if isinstance(P, (LaurentSeriesRing, PowerSeriesRing_generic,
|
|
260
|
+
LazyLaurentSeriesRing, LazyPowerSeriesRing)):
|
|
261
|
+
if self.is_modular():
|
|
262
|
+
return self.construct_form(el)
|
|
263
|
+
else:
|
|
264
|
+
return self.construct_quasi_form(el)
|
|
265
|
+
if isinstance(el, FreeModuleElement) and (self.module() is P or self.ambient_module() is P):
|
|
266
|
+
return self.element_from_ambient_coordinates(el)
|
|
267
|
+
if not self.is_ambient() and isinstance(el, (list, tuple, FreeModuleElement)) and len(el) == self.rank():
|
|
268
|
+
try:
|
|
269
|
+
return self.element_from_coordinates(el)
|
|
270
|
+
except (ArithmeticError, TypeError):
|
|
271
|
+
pass
|
|
272
|
+
if self.ambient_module() and self.ambient_module().has_coerce_map_from(P):
|
|
273
|
+
return self.element_from_ambient_coordinates(self.ambient_module()(el))
|
|
274
|
+
if isinstance(el, (list, tuple)) and len(el) == self.degree():
|
|
275
|
+
try:
|
|
276
|
+
return self.element_from_ambient_coordinates(el)
|
|
277
|
+
except (ArithmeticError, TypeError):
|
|
278
|
+
pass
|
|
279
|
+
|
|
280
|
+
return self.element_class(self, el)
|
|
281
|
+
|
|
282
|
+
def _coerce_map_from_(self, S):
|
|
283
|
+
r"""
|
|
284
|
+
Return whether or not there exists a coercion from ``S`` to ``self``.
|
|
285
|
+
|
|
286
|
+
EXAMPLES::
|
|
287
|
+
|
|
288
|
+
sage: from sage.modular.modform_hecketriangle.space import QuasiWeakModularForms, ModularForms, CuspForms, ZeroForm
|
|
289
|
+
sage: MF1 = QuasiWeakModularForms(n=4, base_ring=CC, k=0, ep=1)
|
|
290
|
+
sage: MF2 = ModularForms(n=4, k=24, ep=1)
|
|
291
|
+
sage: MF3 = ModularForms(n=4, k=24, ep=-1)
|
|
292
|
+
sage: MF4 = CuspForms(n=4, k=0, ep=1)
|
|
293
|
+
sage: MF5 = ZeroForm(n=4, k=10, ep=-1)
|
|
294
|
+
sage: MF6 = QuasiWeakModularForms(n=3, k=24, ep=1)
|
|
295
|
+
sage: MF7 = QuasiWeakModularForms(n=infinity, k=24, ep=1)
|
|
296
|
+
sage: subspace1 = MF3.subspace([MF3.gen(0), MF3.gen(1)])
|
|
297
|
+
sage: subspace2 = MF3.subspace([MF3.gen(2)])
|
|
298
|
+
sage: subspace3 = MF3.subspace([MF3.gen(0), MF3.gen(0)+MF3.gen(2)])
|
|
299
|
+
|
|
300
|
+
sage: MF2.has_coerce_map_from(MF3)
|
|
301
|
+
False
|
|
302
|
+
sage: MF1.has_coerce_map_from(MF4)
|
|
303
|
+
True
|
|
304
|
+
sage: MF4.has_coerce_map_from(MF5)
|
|
305
|
+
True
|
|
306
|
+
sage: MF4.has_coerce_map_from(ZZ)
|
|
307
|
+
False
|
|
308
|
+
sage: MF1.has_coerce_map_from(ZZ)
|
|
309
|
+
True
|
|
310
|
+
sage: MF7.has_coerce_map_from(MF6)
|
|
311
|
+
True
|
|
312
|
+
sage: MF7.has_coerce_map_from(MF2)
|
|
313
|
+
False
|
|
314
|
+
sage: MF3.has_coerce_map_from(subspace1)
|
|
315
|
+
True
|
|
316
|
+
sage: subspace1.has_coerce_map_from(MF3)
|
|
317
|
+
False
|
|
318
|
+
sage: subspace3.has_coerce_map_from(subspace1)
|
|
319
|
+
False
|
|
320
|
+
sage: subspace3.has_coerce_map_from(subspace2)
|
|
321
|
+
True
|
|
322
|
+
"""
|
|
323
|
+
from .space import ZeroForm
|
|
324
|
+
from .subspace import SubSpaceForms
|
|
325
|
+
if isinstance(S, ZeroForm):
|
|
326
|
+
return True
|
|
327
|
+
if (isinstance(S, SubSpaceForms)
|
|
328
|
+
and isinstance(self, SubSpaceForms)):
|
|
329
|
+
if (self.ambient_space().has_coerce_map_from(S.ambient_space())):
|
|
330
|
+
S2 = S.change_ambient_space(self.ambient_space())
|
|
331
|
+
return self.module().has_coerce_map_from(S2.module())
|
|
332
|
+
else:
|
|
333
|
+
return False
|
|
334
|
+
elif (isinstance(S, FormsSpace_abstract)
|
|
335
|
+
and self.graded_ring().has_coerce_map_from(S.graded_ring())
|
|
336
|
+
and S.weight() == self._weight
|
|
337
|
+
and S.ep() == self._ep
|
|
338
|
+
and not isinstance(self, SubSpaceForms)):
|
|
339
|
+
return True
|
|
340
|
+
else:
|
|
341
|
+
return self.contains_coeff_ring() \
|
|
342
|
+
and self.coeff_ring().has_coerce_map_from(S)
|
|
343
|
+
|
|
344
|
+
# Since forms spaces are modules instead of rings
|
|
345
|
+
# we have to manually define one().
|
|
346
|
+
# one() allows to take the power 0 of an element
|
|
347
|
+
@cached_method
|
|
348
|
+
def one(self):
|
|
349
|
+
r"""
|
|
350
|
+
Return the one element from the corresponding space of constant forms.
|
|
351
|
+
|
|
352
|
+
.. NOTE:: The one element does not lie in ``self`` in general.
|
|
353
|
+
|
|
354
|
+
EXAMPLES::
|
|
355
|
+
|
|
356
|
+
sage: from sage.modular.modform_hecketriangle.space import CuspForms
|
|
357
|
+
sage: MF = CuspForms(k=12)
|
|
358
|
+
sage: MF.Delta()^0 == MF.one()
|
|
359
|
+
True
|
|
360
|
+
sage: (MF.Delta()^0).parent()
|
|
361
|
+
ModularForms(n=3, k=0, ep=1) over Integer Ring
|
|
362
|
+
"""
|
|
363
|
+
return self.extend_type("holo", ring=True)(1).reduce()
|
|
364
|
+
|
|
365
|
+
def is_ambient(self) -> bool:
|
|
366
|
+
r"""
|
|
367
|
+
Return whether ``self`` is an ambient space.
|
|
368
|
+
|
|
369
|
+
EXAMPLES::
|
|
370
|
+
|
|
371
|
+
sage: from sage.modular.modform_hecketriangle.space import ModularForms
|
|
372
|
+
sage: MF = ModularForms(k=12)
|
|
373
|
+
sage: MF.is_ambient()
|
|
374
|
+
True
|
|
375
|
+
sage: MF.subspace([MF.gen(0)]).is_ambient()
|
|
376
|
+
False
|
|
377
|
+
"""
|
|
378
|
+
return self._ambient_space == self
|
|
379
|
+
|
|
380
|
+
def ambient_space(self):
|
|
381
|
+
r"""
|
|
382
|
+
Return the ambient space of ``self``.
|
|
383
|
+
|
|
384
|
+
EXAMPLES::
|
|
385
|
+
|
|
386
|
+
sage: from sage.modular.modform_hecketriangle.space import ModularForms
|
|
387
|
+
sage: MF = ModularForms(k=12)
|
|
388
|
+
sage: MF.ambient_space()
|
|
389
|
+
ModularForms(n=3, k=12, ep=1) over Integer Ring
|
|
390
|
+
sage: MF.ambient_space() == MF
|
|
391
|
+
True
|
|
392
|
+
sage: subspace = MF.subspace([MF.gen(0)])
|
|
393
|
+
sage: subspace
|
|
394
|
+
Subspace of dimension 1 of ModularForms(n=3, k=12, ep=1) over Integer Ring
|
|
395
|
+
sage: subspace.ambient_space() == MF
|
|
396
|
+
True
|
|
397
|
+
"""
|
|
398
|
+
|
|
399
|
+
return self._ambient_space
|
|
400
|
+
|
|
401
|
+
def module(self):
|
|
402
|
+
r"""
|
|
403
|
+
Return the module associated to ``self``.
|
|
404
|
+
|
|
405
|
+
EXAMPLES::
|
|
406
|
+
|
|
407
|
+
sage: from sage.modular.modform_hecketriangle.space import ModularForms
|
|
408
|
+
sage: MF = ModularForms(k=12)
|
|
409
|
+
sage: MF.module()
|
|
410
|
+
Vector space of dimension 2 over Fraction Field of Univariate Polynomial Ring in d over Integer Ring
|
|
411
|
+
sage: subspace = MF.subspace([MF.gen(0)])
|
|
412
|
+
sage: subspace.module()
|
|
413
|
+
Vector space of degree 2 and dimension 1 over Fraction Field of Univariate Polynomial Ring in d over Integer Ring
|
|
414
|
+
Basis matrix:
|
|
415
|
+
[1 0]
|
|
416
|
+
"""
|
|
417
|
+
|
|
418
|
+
return self._module
|
|
419
|
+
|
|
420
|
+
def ambient_module(self):
|
|
421
|
+
r"""
|
|
422
|
+
Return the module associated to the ambient space of ``self``.
|
|
423
|
+
|
|
424
|
+
EXAMPLES::
|
|
425
|
+
|
|
426
|
+
sage: from sage.modular.modform_hecketriangle.space import ModularForms
|
|
427
|
+
sage: MF = ModularForms(k=12)
|
|
428
|
+
sage: MF.ambient_module()
|
|
429
|
+
Vector space of dimension 2 over Fraction Field of Univariate Polynomial Ring in d over Integer Ring
|
|
430
|
+
sage: MF.ambient_module() == MF.module()
|
|
431
|
+
True
|
|
432
|
+
sage: subspace = MF.subspace([MF.gen(0)])
|
|
433
|
+
sage: subspace.ambient_module() == MF.module()
|
|
434
|
+
True
|
|
435
|
+
"""
|
|
436
|
+
|
|
437
|
+
return self._ambient_space._module
|
|
438
|
+
|
|
439
|
+
def subspace(self, basis):
|
|
440
|
+
r"""
|
|
441
|
+
Return the subspace of ``self`` generated by ``basis``.
|
|
442
|
+
|
|
443
|
+
EXAMPLES::
|
|
444
|
+
|
|
445
|
+
sage: from sage.modular.modform_hecketriangle.space import ModularForms
|
|
446
|
+
sage: MF = ModularForms(k=24)
|
|
447
|
+
sage: MF.dimension()
|
|
448
|
+
3
|
|
449
|
+
sage: subspace = MF.subspace([MF.gen(0), MF.gen(1)])
|
|
450
|
+
sage: subspace
|
|
451
|
+
Subspace of dimension 2 of ModularForms(n=3, k=24, ep=1) over Integer Ring
|
|
452
|
+
"""
|
|
453
|
+
|
|
454
|
+
from .subspace import SubSpaceForms
|
|
455
|
+
return SubSpaceForms(self, basis)
|
|
456
|
+
|
|
457
|
+
def change_ring(self, new_base_ring):
|
|
458
|
+
r"""
|
|
459
|
+
Return the same space as ``self`` but over a new base ring ``new_base_ring``.
|
|
460
|
+
|
|
461
|
+
EXAMPLES::
|
|
462
|
+
|
|
463
|
+
sage: from sage.modular.modform_hecketriangle.space import CuspForms
|
|
464
|
+
sage: CuspForms(n=5, k=24).change_ring(CC)
|
|
465
|
+
CuspForms(n=5, k=24, ep=1) over Complex Field with 53 bits of precision
|
|
466
|
+
"""
|
|
467
|
+
|
|
468
|
+
return self.__class__.__base__(self.group(), new_base_ring, self.weight(), self.ep())
|
|
469
|
+
|
|
470
|
+
def construction(self):
|
|
471
|
+
r"""
|
|
472
|
+
Return a functor that constructs ``self`` (used by the coercion machinery).
|
|
473
|
+
|
|
474
|
+
EXAMPLES::
|
|
475
|
+
|
|
476
|
+
sage: from sage.modular.modform_hecketriangle.space import QuasiModularForms
|
|
477
|
+
sage: QuasiModularForms(n=4, k=2, ep=1, base_ring=CC).construction()
|
|
478
|
+
(QuasiModularFormsFunctor(n=4, k=2, ep=1),
|
|
479
|
+
BaseFacade(Complex Field with 53 bits of precision))
|
|
480
|
+
|
|
481
|
+
sage: from sage.modular.modform_hecketriangle.space import ModularForms
|
|
482
|
+
sage: MF=ModularForms(k=12)
|
|
483
|
+
sage: MF.subspace([MF.gen(1)]).construction()
|
|
484
|
+
(FormsSubSpaceFunctor with 1 generator for the ModularFormsFunctor(n=3, k=12, ep=1), BaseFacade(Integer Ring))
|
|
485
|
+
"""
|
|
486
|
+
|
|
487
|
+
from .functors import FormsSubSpaceFunctor, FormsSpaceFunctor, BaseFacade
|
|
488
|
+
ambient_space_functor = FormsSpaceFunctor(self._analytic_type, self._group, self._weight, self._ep)
|
|
489
|
+
|
|
490
|
+
if (self.is_ambient()):
|
|
491
|
+
return (ambient_space_functor, BaseFacade(self._base_ring))
|
|
492
|
+
else:
|
|
493
|
+
return (FormsSubSpaceFunctor(ambient_space_functor, self._basis), BaseFacade(self._base_ring))
|
|
494
|
+
|
|
495
|
+
@cached_method
|
|
496
|
+
def weight(self):
|
|
497
|
+
r"""
|
|
498
|
+
Return the weight of (elements of) ``self``.
|
|
499
|
+
|
|
500
|
+
EXAMPLES::
|
|
501
|
+
|
|
502
|
+
sage: from sage.modular.modform_hecketriangle.space import QuasiModularForms
|
|
503
|
+
sage: QuasiModularForms(n=16, k=16/7, ep=-1).weight()
|
|
504
|
+
16/7
|
|
505
|
+
"""
|
|
506
|
+
|
|
507
|
+
return self._weight
|
|
508
|
+
|
|
509
|
+
@cached_method
|
|
510
|
+
def ep(self):
|
|
511
|
+
r"""
|
|
512
|
+
Return the multiplier of (elements of) ``self``.
|
|
513
|
+
|
|
514
|
+
EXAMPLES::
|
|
515
|
+
|
|
516
|
+
sage: from sage.modular.modform_hecketriangle.space import QuasiModularForms
|
|
517
|
+
sage: QuasiModularForms(n=16, k=16/7, ep=-1).ep()
|
|
518
|
+
-1
|
|
519
|
+
"""
|
|
520
|
+
|
|
521
|
+
return self._ep
|
|
522
|
+
|
|
523
|
+
@cached_method
|
|
524
|
+
def contains_coeff_ring(self):
|
|
525
|
+
r"""
|
|
526
|
+
Return whether ``self`` contains its coefficient ring.
|
|
527
|
+
|
|
528
|
+
EXAMPLES::
|
|
529
|
+
|
|
530
|
+
sage: from sage.modular.modform_hecketriangle.space import QuasiModularForms
|
|
531
|
+
sage: QuasiModularForms(k=0, ep=1, n=8).contains_coeff_ring()
|
|
532
|
+
True
|
|
533
|
+
sage: QuasiModularForms(k=0, ep=-1, n=8).contains_coeff_ring()
|
|
534
|
+
False
|
|
535
|
+
"""
|
|
536
|
+
|
|
537
|
+
return ((self.AT("holo") <= self._analytic_type) and (self.weight() == QQ(0)) and (self.ep() == ZZ(1)))
|
|
538
|
+
|
|
539
|
+
def element_from_coordinates(self, vec):
|
|
540
|
+
r"""
|
|
541
|
+
If ``self`` has an associated free module, then return the element of ``self``
|
|
542
|
+
corresponding to the given coordinate vector ``vec``. Otherwise raise an exception.
|
|
543
|
+
|
|
544
|
+
INPUT:
|
|
545
|
+
|
|
546
|
+
- ``vec`` -- a coordinate vector with respect to ``self.gens()``
|
|
547
|
+
|
|
548
|
+
OUTPUT: an element of ``self`` corresponding to the coordinate vector ``vec``
|
|
549
|
+
|
|
550
|
+
EXAMPLES::
|
|
551
|
+
|
|
552
|
+
sage: from sage.modular.modform_hecketriangle.space import ModularForms
|
|
553
|
+
sage: MF = ModularForms(k=24)
|
|
554
|
+
sage: MF.dimension()
|
|
555
|
+
3
|
|
556
|
+
sage: el = MF.element_from_coordinates([1,1,1])
|
|
557
|
+
sage: el
|
|
558
|
+
1 + q + q^2 + 52611612*q^3 + 39019413208*q^4 + O(q^5)
|
|
559
|
+
sage: el == MF.gen(0) + MF.gen(1) + MF.gen(2)
|
|
560
|
+
True
|
|
561
|
+
sage: el.parent() == MF
|
|
562
|
+
True
|
|
563
|
+
|
|
564
|
+
sage: subspace = MF.subspace([MF.gen(0), MF.gen(1)])
|
|
565
|
+
sage: el = subspace.element_from_coordinates([1,1])
|
|
566
|
+
sage: el
|
|
567
|
+
1 + q + 52611660*q^3 + 39019412128*q^4 + O(q^5)
|
|
568
|
+
sage: el == subspace.gen(0) + subspace.gen(1)
|
|
569
|
+
True
|
|
570
|
+
sage: el.parent() == subspace
|
|
571
|
+
True
|
|
572
|
+
"""
|
|
573
|
+
if not self.module():
|
|
574
|
+
raise ValueError(f"no free module defined for {self}")
|
|
575
|
+
basis = self.gens()
|
|
576
|
+
assert len(basis) == len(vec)
|
|
577
|
+
# vec = self.module()(self.module().linear_combination_of_basis(vec))
|
|
578
|
+
# this also handles the trivial case (dimension 0)
|
|
579
|
+
return self(sum([vec[k] * basis[k] for k in range(len(vec))]))
|
|
580
|
+
|
|
581
|
+
def element_from_ambient_coordinates(self, vec):
|
|
582
|
+
r"""
|
|
583
|
+
If ``self`` has an associated free module, then return the element of ``self``
|
|
584
|
+
corresponding to the given ``vec``. Otherwise raise an exception.
|
|
585
|
+
|
|
586
|
+
INPUT:
|
|
587
|
+
|
|
588
|
+
- ``vec`` -- an element of ``self.module()`` or ``self.ambient_module()``
|
|
589
|
+
|
|
590
|
+
OUTPUT: an element of ``self`` corresponding to ``vec``
|
|
591
|
+
|
|
592
|
+
EXAMPLES::
|
|
593
|
+
|
|
594
|
+
sage: from sage.modular.modform_hecketriangle.space import ModularForms
|
|
595
|
+
sage: MF = ModularForms(k=24)
|
|
596
|
+
sage: MF.dimension()
|
|
597
|
+
3
|
|
598
|
+
sage: el = MF.element_from_ambient_coordinates([1,1,1])
|
|
599
|
+
sage: el == MF.element_from_coordinates([1,1,1])
|
|
600
|
+
True
|
|
601
|
+
sage: el.parent() == MF
|
|
602
|
+
True
|
|
603
|
+
|
|
604
|
+
sage: subspace = MF.subspace([MF.gen(0), MF.gen(1)])
|
|
605
|
+
sage: el = subspace.element_from_ambient_coordinates([1,1,0])
|
|
606
|
+
sage: el
|
|
607
|
+
1 + q + 52611660*q^3 + 39019412128*q^4 + O(q^5)
|
|
608
|
+
sage: el.parent() == subspace
|
|
609
|
+
True
|
|
610
|
+
"""
|
|
611
|
+
|
|
612
|
+
return self(self.ambient_space().element_from_coordinates(vec))
|
|
613
|
+
|
|
614
|
+
def homogeneous_part(self, k, ep):
|
|
615
|
+
r"""
|
|
616
|
+
Since ``self`` already is a homogeneous component return ``self``
|
|
617
|
+
unless the degree differs in which case a :exc:`ValueError` is raised.
|
|
618
|
+
|
|
619
|
+
EXAMPLES::
|
|
620
|
+
|
|
621
|
+
sage: from sage.modular.modform_hecketriangle.space import QuasiMeromorphicModularForms
|
|
622
|
+
sage: MF = QuasiMeromorphicModularForms(n=6, k=4)
|
|
623
|
+
sage: MF == MF.homogeneous_part(4,1)
|
|
624
|
+
True
|
|
625
|
+
sage: MF.homogeneous_part(5,1)
|
|
626
|
+
Traceback (most recent call last):
|
|
627
|
+
...
|
|
628
|
+
ValueError: QuasiMeromorphicModularForms(n=6, k=4, ep=1) over Integer Ring already is homogeneous with degree (4, 1) != (5, 1)!
|
|
629
|
+
"""
|
|
630
|
+
|
|
631
|
+
if (k == self._weight and ep == self._ep):
|
|
632
|
+
return self
|
|
633
|
+
else:
|
|
634
|
+
raise ValueError("{} already is homogeneous with degree ({}, {}) != ({}, {})!".format(self, self._weight, self._ep, k, ep))
|
|
635
|
+
|
|
636
|
+
def weight_parameters(self):
|
|
637
|
+
r"""
|
|
638
|
+
Check whether ``self`` has a valid weight and multiplier.
|
|
639
|
+
|
|
640
|
+
If not then an exception is raised. Otherwise the two weight
|
|
641
|
+
parameters corresponding to the weight and multiplier of ``self``
|
|
642
|
+
are returned.
|
|
643
|
+
|
|
644
|
+
The weight parameters are e.g. used to calculate dimensions
|
|
645
|
+
or precisions of Fourier expansion.
|
|
646
|
+
|
|
647
|
+
EXAMPLES::
|
|
648
|
+
|
|
649
|
+
sage: from sage.modular.modform_hecketriangle.space import MeromorphicModularForms
|
|
650
|
+
sage: MF = MeromorphicModularForms(n=18, k=-7, ep=-1)
|
|
651
|
+
sage: MF.weight_parameters()
|
|
652
|
+
(-3, 17)
|
|
653
|
+
sage: (MF._l1, MF._l2) == MF.weight_parameters()
|
|
654
|
+
True
|
|
655
|
+
sage: (k, ep) = (MF.weight(), MF.ep())
|
|
656
|
+
sage: n = MF.hecke_n()
|
|
657
|
+
sage: k == 4*(n*MF._l1 + MF._l2)/(n-2) + (1-ep)*n/(n-2)
|
|
658
|
+
True
|
|
659
|
+
|
|
660
|
+
sage: from sage.modular.modform_hecketriangle.space import ModularForms
|
|
661
|
+
sage: MF = ModularForms(n=5, k=12, ep=1)
|
|
662
|
+
sage: MF.weight_parameters()
|
|
663
|
+
(1, 4)
|
|
664
|
+
sage: (MF._l1, MF._l2) == MF.weight_parameters()
|
|
665
|
+
True
|
|
666
|
+
sage: (k, ep) = (MF.weight(), MF.ep())
|
|
667
|
+
sage: n = MF.hecke_n()
|
|
668
|
+
sage: k == 4*(n*MF._l1 + MF._l2)/(n-2) + (1-ep)*n/(n-2)
|
|
669
|
+
True
|
|
670
|
+
sage: MF.dimension() == MF._l1 + 1
|
|
671
|
+
True
|
|
672
|
+
|
|
673
|
+
sage: MF = ModularForms(n=infinity, k=8, ep=1)
|
|
674
|
+
sage: MF.weight_parameters()
|
|
675
|
+
(2, 0)
|
|
676
|
+
sage: MF.dimension() == MF._l1 + 1
|
|
677
|
+
True
|
|
678
|
+
"""
|
|
679
|
+
|
|
680
|
+
n = self._group.n()
|
|
681
|
+
k = self._weight
|
|
682
|
+
ep = self._ep
|
|
683
|
+
if (n == infinity):
|
|
684
|
+
num = (k-(1-ep)) / ZZ(4)
|
|
685
|
+
else:
|
|
686
|
+
num = (k-(1-ep)*ZZ(n)/ZZ(n-2)) * ZZ(n-2) / ZZ(4)
|
|
687
|
+
if (num.is_integral()):
|
|
688
|
+
num = ZZ(num)
|
|
689
|
+
if (n == infinity):
|
|
690
|
+
# TODO: Figure out what to do in this case
|
|
691
|
+
# (l1 and l2 are no longer defined in an analog/unique way)
|
|
692
|
+
# l2 = num % ZZ(2)
|
|
693
|
+
# l1 = ((num-l2)/ZZ(2)).numerator()
|
|
694
|
+
# TODO: The correct generalization seems (l1,l2) = (0,num)
|
|
695
|
+
l2 = ZZ.zero()
|
|
696
|
+
l1 = num
|
|
697
|
+
else:
|
|
698
|
+
l2 = num % n
|
|
699
|
+
l1 = ((num-l2)/n).numerator()
|
|
700
|
+
else:
|
|
701
|
+
raise ValueError("Invalid or non-occurring weight k={}, ep={}!".format(k,ep))
|
|
702
|
+
return (l1, l2)
|
|
703
|
+
|
|
704
|
+
# TODO: this only makes sense for modular forms,
|
|
705
|
+
# resp. needs a big adjustment for quasi modular forms
|
|
706
|
+
def aut_factor(self, gamma, t):
|
|
707
|
+
r"""
|
|
708
|
+
The automorphy factor of ``self``.
|
|
709
|
+
|
|
710
|
+
INPUT:
|
|
711
|
+
|
|
712
|
+
- ``gamma`` -- an element of the group of ``self``
|
|
713
|
+
|
|
714
|
+
- ``t`` -- an element of the upper half plane
|
|
715
|
+
|
|
716
|
+
EXAMPLES::
|
|
717
|
+
|
|
718
|
+
sage: from sage.modular.modform_hecketriangle.space import ModularForms
|
|
719
|
+
sage: MF = ModularForms(n=8, k=4, ep=1)
|
|
720
|
+
sage: full_factor = lambda mat, t: (mat[1][0]*t+mat[1][1])**4
|
|
721
|
+
sage: T = MF.group().T()
|
|
722
|
+
sage: S = MF.group().S()
|
|
723
|
+
sage: i = AlgebraicField()(i)
|
|
724
|
+
sage: z = 1 + i/2
|
|
725
|
+
|
|
726
|
+
sage: MF.aut_factor(S, z)
|
|
727
|
+
3/2*I - 7/16
|
|
728
|
+
sage: MF.aut_factor(-T^(-2), z)
|
|
729
|
+
1
|
|
730
|
+
sage: MF.aut_factor(MF.group().V(6), z)
|
|
731
|
+
173.2640595631...? + 343.8133289126...?*I
|
|
732
|
+
sage: MF.aut_factor(S, z) == full_factor(S, z)
|
|
733
|
+
True
|
|
734
|
+
sage: MF.aut_factor(T, z) == full_factor(T, z)
|
|
735
|
+
True
|
|
736
|
+
sage: MF.aut_factor(MF.group().V(6), z) == full_factor(MF.group().V(6), z)
|
|
737
|
+
True
|
|
738
|
+
|
|
739
|
+
sage: MF = ModularForms(n=7, k=14/5, ep=-1)
|
|
740
|
+
sage: T = MF.group().T()
|
|
741
|
+
sage: S = MF.group().S()
|
|
742
|
+
|
|
743
|
+
sage: MF.aut_factor(S, z)
|
|
744
|
+
1.3655215324256...? + 0.056805991182877...?*I
|
|
745
|
+
sage: MF.aut_factor(-T^(-2), z)
|
|
746
|
+
1
|
|
747
|
+
sage: MF.aut_factor(S, z) == MF.ep() * (z/i)^MF.weight()
|
|
748
|
+
True
|
|
749
|
+
sage: MF.aut_factor(MF.group().V(6), z)
|
|
750
|
+
13.23058830577...? + 15.71786610686...?*I
|
|
751
|
+
"""
|
|
752
|
+
|
|
753
|
+
if (gamma.is_translation()):
|
|
754
|
+
return ZZ(1)
|
|
755
|
+
elif (gamma.is_reflection()):
|
|
756
|
+
return self._ep * (t/QQbar(I))**self._weight
|
|
757
|
+
else:
|
|
758
|
+
L = list(gamma.word_S_T()[0])
|
|
759
|
+
aut_f = ZZ(1)
|
|
760
|
+
while (len(L) > 0):
|
|
761
|
+
M = L.pop(-1)
|
|
762
|
+
aut_f *= self.aut_factor(M, t)
|
|
763
|
+
t = M.acton(t)
|
|
764
|
+
return aut_f
|
|
765
|
+
|
|
766
|
+
@cached_method
|
|
767
|
+
def F_simple(self, order_1=ZZ.zero()):
|
|
768
|
+
r"""
|
|
769
|
+
Return a (the most) simple normalized element of ``self``
|
|
770
|
+
corresponding to the weight parameters ``l1=self._l1`` and
|
|
771
|
+
``l2=self._l2``. If the element does not lie in ``self`` the
|
|
772
|
+
type of its parent is extended accordingly.
|
|
773
|
+
|
|
774
|
+
The main part of the element is given by the ``(l1 - order_1)``-th power
|
|
775
|
+
of ``f_inf``, up to a small holomorphic correction factor.
|
|
776
|
+
|
|
777
|
+
INPUT:
|
|
778
|
+
|
|
779
|
+
- ``order_1`` -- an integer (default: 0) denoting the desired order at
|
|
780
|
+
``-1`` in the case ``n = infinity``. If ``n != infinity`` the
|
|
781
|
+
parameter is ignored.
|
|
782
|
+
|
|
783
|
+
EXAMPLES::
|
|
784
|
+
|
|
785
|
+
sage: from sage.modular.modform_hecketriangle.space import WeakModularForms
|
|
786
|
+
sage: MF = WeakModularForms(n=18, k=-7, ep=-1)
|
|
787
|
+
sage: MF.disp_prec(1)
|
|
788
|
+
sage: MF.F_simple()
|
|
789
|
+
q^-3 + 16/(81*d)*q^-2 - 4775/(104976*d^2)*q^-1 - 14300/(531441*d^3) + O(q)
|
|
790
|
+
sage: MF.F_simple() == MF.f_inf()^MF._l1 * MF.f_rho()^MF._l2 * MF.f_i()
|
|
791
|
+
True
|
|
792
|
+
|
|
793
|
+
sage: from sage.modular.modform_hecketriangle.space import CuspForms, ModularForms
|
|
794
|
+
sage: MF = CuspForms(n=5, k=2, ep=-1)
|
|
795
|
+
sage: MF._l1
|
|
796
|
+
-1
|
|
797
|
+
sage: MF.F_simple().parent()
|
|
798
|
+
WeakModularForms(n=5, k=2, ep=-1) over Integer Ring
|
|
799
|
+
|
|
800
|
+
sage: MF = ModularForms(n=infinity, k=8, ep=1)
|
|
801
|
+
sage: MF.F_simple().reduced_parent()
|
|
802
|
+
ModularForms(n=+Infinity, k=8, ep=1) over Integer Ring
|
|
803
|
+
sage: MF.F_simple()
|
|
804
|
+
q^2 - 16*q^3 + 120*q^4 + O(q^5)
|
|
805
|
+
sage: MF.F_simple(order_1=2)
|
|
806
|
+
1 + 32*q + 480*q^2 + 4480*q^3 + 29152*q^4 + O(q^5)
|
|
807
|
+
"""
|
|
808
|
+
|
|
809
|
+
(x,y,z,d) = self.rat_field().gens()
|
|
810
|
+
n = self.hecke_n()
|
|
811
|
+
|
|
812
|
+
if (n == infinity):
|
|
813
|
+
order_1 = ZZ(order_1)
|
|
814
|
+
order_inf = self._l1 - order_1
|
|
815
|
+
|
|
816
|
+
finf_pol = d*(x - y**2)
|
|
817
|
+
rat = finf_pol**order_inf * x**order_1 * y**(ZZ(1-self._ep)/ZZ(2))
|
|
818
|
+
else:
|
|
819
|
+
order_inf = self._l1
|
|
820
|
+
order_1 = order_inf
|
|
821
|
+
|
|
822
|
+
finf_pol = d*(x**n - y**2)
|
|
823
|
+
rat = finf_pol**self._l1 * x**self._l2 * y**(ZZ(1-self._ep)/ZZ(2))
|
|
824
|
+
|
|
825
|
+
if (order_inf > 0 and order_1 > 0):
|
|
826
|
+
new_space = self.extend_type("cusp")
|
|
827
|
+
elif (order_inf >= 0 and order_1 >= 0):
|
|
828
|
+
new_space = self.extend_type("holo")
|
|
829
|
+
else:
|
|
830
|
+
new_space = self.extend_type("weak")
|
|
831
|
+
|
|
832
|
+
return new_space(rat)
|
|
833
|
+
|
|
834
|
+
def Faber_pol(self, m, order_1=ZZ.zero(), fix_d=False, d_num_prec=None):
|
|
835
|
+
r"""
|
|
836
|
+
Return the ``m``-th Faber polynomial of ``self``.
|
|
837
|
+
|
|
838
|
+
Namely a polynomial ``P(q)`` such that ``P(J_inv)*F_simple(order_1)``
|
|
839
|
+
has a Fourier expansion of the form ``q^m + O(q^(order_inf + 1))``.
|
|
840
|
+
where ``order_inf = self._l1 - order_1`` and ``d^(order_inf - m)*P(q)``
|
|
841
|
+
is a monic polynomial of degree ``order_inf - m``.
|
|
842
|
+
|
|
843
|
+
If ``n=infinity`` a non-trivial order of ``-1`` can be specified through the
|
|
844
|
+
parameter ``order_1`` (default: 0). Otherwise it is ignored.
|
|
845
|
+
|
|
846
|
+
The Faber polynomials are e.g. used to construct a basis of weakly holomorphic
|
|
847
|
+
forms and to recover such forms from their initial Fourier coefficients.
|
|
848
|
+
|
|
849
|
+
INPUT:
|
|
850
|
+
|
|
851
|
+
- ``m`` -- an integer ``m <= order_inf = self._l1 - order_1``
|
|
852
|
+
|
|
853
|
+
- ``order_1`` -- the order at ``-1`` of F_simple (default: 0);
|
|
854
|
+
this parameter is ignored if ``n != infinity``
|
|
855
|
+
|
|
856
|
+
- ``fix_d`` -- if ``False`` (default) a formal parameter is used for
|
|
857
|
+
``d``. If ``True`` then the numerical value of ``d`` is used (resp.
|
|
858
|
+
an exact value if the group is arithmetic). Otherwise the given
|
|
859
|
+
value is used for ``d``.
|
|
860
|
+
|
|
861
|
+
- ``d_num_prec`` -- the precision to be used if a numerical value for
|
|
862
|
+
``d`` is substituted (default: ``None``), otherwise the default
|
|
863
|
+
numerical precision of ``self.parent()`` is used
|
|
864
|
+
|
|
865
|
+
OUTPUT: the corresponding Faber polynomial ``P(q)``
|
|
866
|
+
|
|
867
|
+
EXAMPLES::
|
|
868
|
+
|
|
869
|
+
sage: from sage.modular.modform_hecketriangle.space import WeakModularForms
|
|
870
|
+
sage: MF = WeakModularForms(n=5, k=62/3, ep=-1)
|
|
871
|
+
sage: MF.weight_parameters()
|
|
872
|
+
(2, 3)
|
|
873
|
+
|
|
874
|
+
sage: MF.Faber_pol(2)
|
|
875
|
+
1
|
|
876
|
+
sage: MF.Faber_pol(1)
|
|
877
|
+
1/d*q - 19/(100*d)
|
|
878
|
+
sage: MF.Faber_pol(0)
|
|
879
|
+
1/d^2*q^2 - 117/(200*d^2)*q + 9113/(320000*d^2)
|
|
880
|
+
sage: MF.Faber_pol(-2)
|
|
881
|
+
1/d^4*q^4 - 11/(8*d^4)*q^3 + 41013/(80000*d^4)*q^2 - 2251291/(48000000*d^4)*q + 1974089431/(4915200000000*d^4)
|
|
882
|
+
sage: (MF.Faber_pol(2)(MF.J_inv())*MF.F_simple()).q_expansion(prec=MF._l1+2)
|
|
883
|
+
q^2 - 41/(200*d)*q^3 + O(q^4)
|
|
884
|
+
sage: (MF.Faber_pol(1)(MF.J_inv())*MF.F_simple()).q_expansion(prec=MF._l1+1)
|
|
885
|
+
q + O(q^3)
|
|
886
|
+
sage: (MF.Faber_pol(0)(MF.J_inv())*MF.F_simple()).q_expansion(prec=MF._l1+1)
|
|
887
|
+
1 + O(q^3)
|
|
888
|
+
sage: (MF.Faber_pol(-2)(MF.J_inv())*MF.F_simple()).q_expansion(prec=MF._l1+1)
|
|
889
|
+
q^-2 + O(q^3)
|
|
890
|
+
|
|
891
|
+
sage: MF.Faber_pol(2, fix_d=1)
|
|
892
|
+
1
|
|
893
|
+
sage: MF.Faber_pol(1, fix_d=1)
|
|
894
|
+
q - 19/100
|
|
895
|
+
sage: MF.Faber_pol(-2, fix_d=1)
|
|
896
|
+
q^4 - 11/8*q^3 + 41013/80000*q^2 - 2251291/48000000*q + 1974089431/4915200000000
|
|
897
|
+
sage: (MF.Faber_pol(2, fix_d=1)(MF.J_inv())*MF.F_simple()).q_expansion(prec=MF._l1+2, fix_d=1)
|
|
898
|
+
q^2 - 41/200*q^3 + O(q^4)
|
|
899
|
+
sage: (MF.Faber_pol(-2)(MF.J_inv())*MF.F_simple()).q_expansion(prec=MF._l1+1, fix_d=1)
|
|
900
|
+
q^-2 + O(q^3)
|
|
901
|
+
|
|
902
|
+
sage: MF = WeakModularForms(n=4, k=-2, ep=1)
|
|
903
|
+
sage: MF.weight_parameters()
|
|
904
|
+
(-1, 3)
|
|
905
|
+
|
|
906
|
+
sage: MF.Faber_pol(-1)
|
|
907
|
+
1
|
|
908
|
+
sage: MF.Faber_pol(-2, fix_d=True)
|
|
909
|
+
256*q - 184
|
|
910
|
+
sage: MF.Faber_pol(-3, fix_d=True)
|
|
911
|
+
65536*q^2 - 73728*q + 14364
|
|
912
|
+
sage: (MF.Faber_pol(-1, fix_d=True)(MF.J_inv())*MF.F_simple()).q_expansion(prec=MF._l1+2, fix_d=True)
|
|
913
|
+
q^-1 + 80 + O(q)
|
|
914
|
+
sage: (MF.Faber_pol(-2, fix_d=True)(MF.J_inv())*MF.F_simple()).q_expansion(prec=MF._l1+2, fix_d=True)
|
|
915
|
+
q^-2 + 400 + O(q)
|
|
916
|
+
sage: (MF.Faber_pol(-3)(MF.J_inv())*MF.F_simple()).q_expansion(prec=MF._l1+2, fix_d=True)
|
|
917
|
+
q^-3 + 2240 + O(q)
|
|
918
|
+
|
|
919
|
+
sage: MF = WeakModularForms(n=infinity, k=14, ep=-1)
|
|
920
|
+
sage: MF.Faber_pol(3)
|
|
921
|
+
1
|
|
922
|
+
sage: MF.Faber_pol(2)
|
|
923
|
+
1/d*q + 3/(8*d)
|
|
924
|
+
sage: MF.Faber_pol(1)
|
|
925
|
+
1/d^2*q^2 + 75/(1024*d^2)
|
|
926
|
+
sage: MF.Faber_pol(0)
|
|
927
|
+
1/d^3*q^3 - 3/(8*d^3)*q^2 + 3/(512*d^3)*q + 41/(4096*d^3)
|
|
928
|
+
sage: MF.Faber_pol(-1)
|
|
929
|
+
1/d^4*q^4 - 3/(4*d^4)*q^3 + 81/(1024*d^4)*q^2 + 9075/(8388608*d^4)
|
|
930
|
+
sage: (MF.Faber_pol(-1)(MF.J_inv())*MF.F_simple()).q_expansion(prec=MF._l1 + 1)
|
|
931
|
+
q^-1 + O(q^4)
|
|
932
|
+
|
|
933
|
+
sage: MF.Faber_pol(3, order_1=-1)
|
|
934
|
+
1/d*q + 3/(4*d)
|
|
935
|
+
sage: MF.Faber_pol(1, order_1=2)
|
|
936
|
+
1
|
|
937
|
+
sage: MF.Faber_pol(0, order_1=2)
|
|
938
|
+
1/d*q - 3/(8*d)
|
|
939
|
+
sage: MF.Faber_pol(-1, order_1=2)
|
|
940
|
+
1/d^2*q^2 - 3/(4*d^2)*q + 81/(1024*d^2)
|
|
941
|
+
sage: (MF.Faber_pol(-1, order_1=2)(MF.J_inv())*MF.F_simple(order_1=2)).q_expansion(prec=MF._l1 + 1)
|
|
942
|
+
q^-1 - 9075/(8388608*d^4)*q^3 + O(q^4)
|
|
943
|
+
"""
|
|
944
|
+
|
|
945
|
+
m = ZZ(m)
|
|
946
|
+
if (self.hecke_n() == infinity):
|
|
947
|
+
order_1 = ZZ(order_1)
|
|
948
|
+
order_inf = self._l1 - order_1
|
|
949
|
+
else:
|
|
950
|
+
order_inf = self._l1
|
|
951
|
+
order_1 = order_inf
|
|
952
|
+
|
|
953
|
+
if (m > order_inf):
|
|
954
|
+
raise ValueError("Invalid basis index: m = {} > {} = order_inf!".format(m, order_inf))
|
|
955
|
+
|
|
956
|
+
prec = 2*order_inf - m + 1
|
|
957
|
+
d = self.get_d(fix_d=fix_d, d_num_prec=d_num_prec)
|
|
958
|
+
q = self.get_q(prec=prec, fix_d=fix_d, d_num_prec=d_num_prec)
|
|
959
|
+
|
|
960
|
+
simple_qexp = self.F_simple(order_1=order_1).q_expansion(prec=prec, fix_d=fix_d, d_num_prec=d_num_prec)
|
|
961
|
+
J_qexp = self.J_inv().q_expansion(prec=order_inf - m, fix_d=fix_d, d_num_prec=d_num_prec)
|
|
962
|
+
|
|
963
|
+
# The precision could be infinity, otherwise we could do this:
|
|
964
|
+
# assert temp_reminder.prec() == 1
|
|
965
|
+
temp_reminder = (1 / simple_qexp / q**(-m)).add_bigoh(1)
|
|
966
|
+
|
|
967
|
+
fab_pol = q.parent()([])
|
|
968
|
+
while (len(temp_reminder.coefficients()) > 0):
|
|
969
|
+
temp_coeff = temp_reminder.coefficients()[0]
|
|
970
|
+
temp_exp = -temp_reminder.exponents()[0]
|
|
971
|
+
fab_pol += temp_coeff * (q/d)**temp_exp
|
|
972
|
+
|
|
973
|
+
temp_reminder -= temp_coeff * (J_qexp/d)**temp_exp
|
|
974
|
+
# The first term is zero only up to numerical errors,
|
|
975
|
+
# so we manually have to remove it
|
|
976
|
+
if (not d.parent().is_exact()):
|
|
977
|
+
temp_reminder = temp_reminder.truncate_neg(-temp_exp+1)
|
|
978
|
+
|
|
979
|
+
return fab_pol.polynomial()
|
|
980
|
+
|
|
981
|
+
# very similar to Faber_pol: faber_pol(q)=Faber_pol(d*q)
|
|
982
|
+
def faber_pol(self, m, order_1=ZZ.zero(), fix_d=False, d_num_prec=None):
|
|
983
|
+
r"""
|
|
984
|
+
If ``n=infinity`` a non-trivial order of ``-1`` can be specified through the
|
|
985
|
+
parameter ``order_1`` (default: 0). Otherwise it is ignored.
|
|
986
|
+
Return the `m`-th Faber polynomial of ``self``
|
|
987
|
+
with a different normalization based on ``j_inv``
|
|
988
|
+
instead of ``J_inv``.
|
|
989
|
+
|
|
990
|
+
Namely a polynomial ``p(q)`` such that ``p(j_inv)*F_simple()``
|
|
991
|
+
has a Fourier expansion of the form ``q^m + O(q^(order_inf + 1))``.
|
|
992
|
+
where ``order_inf = self._l1 - order_1`` and ``p(q)`` is a
|
|
993
|
+
monic polynomial of degree ``order_inf - m``.
|
|
994
|
+
|
|
995
|
+
If ``n=infinity`` a non-trivial order of ``-1`` can be specified through the
|
|
996
|
+
parameter ``order_1`` (default: 0). Otherwise it is ignored.
|
|
997
|
+
|
|
998
|
+
The relation to ``Faber_pol`` is: ``faber_pol(q) = Faber_pol(d*q)``.
|
|
999
|
+
|
|
1000
|
+
INPUT:
|
|
1001
|
+
|
|
1002
|
+
- ``m`` -- integer; ``m <= self._l1 - order_1``
|
|
1003
|
+
|
|
1004
|
+
- ``order_1`` -- the order at ``-1`` of ``F_simple`` (default: 0);
|
|
1005
|
+
this parameter is ignored if ``n != infinity``
|
|
1006
|
+
|
|
1007
|
+
- ``fix_d`` -- if ``False`` (default) a formal parameter is used for
|
|
1008
|
+
``d``. If ``True`` then the numerical value of ``d`` is used (resp.
|
|
1009
|
+
an exact value if the group is arithmetic). Otherwise the given value
|
|
1010
|
+
is used for ``d``.
|
|
1011
|
+
|
|
1012
|
+
- ``d_num_prec`` -- the precision to be used if a numerical value for
|
|
1013
|
+
``d`` is substituted (default: ``None``), otherwise the default
|
|
1014
|
+
numerical precision of ``self.parent()`` is used
|
|
1015
|
+
|
|
1016
|
+
OUTPUT: the corresponding Faber polynomial ``p(q)``
|
|
1017
|
+
|
|
1018
|
+
EXAMPLES::
|
|
1019
|
+
|
|
1020
|
+
sage: from sage.modular.modform_hecketriangle.space import WeakModularForms
|
|
1021
|
+
sage: MF = WeakModularForms(n=5, k=62/3, ep=-1)
|
|
1022
|
+
sage: MF.weight_parameters()
|
|
1023
|
+
(2, 3)
|
|
1024
|
+
|
|
1025
|
+
sage: MF.faber_pol(2)
|
|
1026
|
+
1
|
|
1027
|
+
sage: MF.faber_pol(1)
|
|
1028
|
+
q - 19/(100*d)
|
|
1029
|
+
sage: MF.faber_pol(0)
|
|
1030
|
+
q^2 - 117/(200*d)*q + 9113/(320000*d^2)
|
|
1031
|
+
sage: MF.faber_pol(-2)
|
|
1032
|
+
q^4 - 11/(8*d)*q^3 + 41013/(80000*d^2)*q^2 - 2251291/(48000000*d^3)*q + 1974089431/(4915200000000*d^4)
|
|
1033
|
+
sage: (MF.faber_pol(2)(MF.j_inv())*MF.F_simple()).q_expansion(prec=MF._l1+2)
|
|
1034
|
+
q^2 - 41/(200*d)*q^3 + O(q^4)
|
|
1035
|
+
sage: (MF.faber_pol(1)(MF.j_inv())*MF.F_simple()).q_expansion(prec=MF._l1+1)
|
|
1036
|
+
q + O(q^3)
|
|
1037
|
+
sage: (MF.faber_pol(0)(MF.j_inv())*MF.F_simple()).q_expansion(prec=MF._l1+1)
|
|
1038
|
+
1 + O(q^3)
|
|
1039
|
+
sage: (MF.faber_pol(-2)(MF.j_inv())*MF.F_simple()).q_expansion(prec=MF._l1+1)
|
|
1040
|
+
q^-2 + O(q^3)
|
|
1041
|
+
|
|
1042
|
+
sage: MF = WeakModularForms(n=4, k=-2, ep=1)
|
|
1043
|
+
sage: MF.weight_parameters()
|
|
1044
|
+
(-1, 3)
|
|
1045
|
+
|
|
1046
|
+
sage: MF.faber_pol(-1)
|
|
1047
|
+
1
|
|
1048
|
+
sage: MF.faber_pol(-2, fix_d=True)
|
|
1049
|
+
q - 184
|
|
1050
|
+
sage: MF.faber_pol(-3, fix_d=True)
|
|
1051
|
+
q^2 - 288*q + 14364
|
|
1052
|
+
sage: (MF.faber_pol(-1, fix_d=True)(MF.j_inv())*MF.F_simple()).q_expansion(prec=MF._l1+2, fix_d=True)
|
|
1053
|
+
q^-1 + 80 + O(q)
|
|
1054
|
+
sage: (MF.faber_pol(-2, fix_d=True)(MF.j_inv())*MF.F_simple()).q_expansion(prec=MF._l1+2, fix_d=True)
|
|
1055
|
+
q^-2 + 400 + O(q)
|
|
1056
|
+
sage: (MF.faber_pol(-3)(MF.j_inv())*MF.F_simple()).q_expansion(prec=MF._l1+2, fix_d=True)
|
|
1057
|
+
q^-3 + 2240 + O(q)
|
|
1058
|
+
|
|
1059
|
+
sage: MF = WeakModularForms(n=infinity, k=14, ep=-1)
|
|
1060
|
+
sage: MF.faber_pol(3)
|
|
1061
|
+
1
|
|
1062
|
+
sage: MF.faber_pol(2)
|
|
1063
|
+
q + 3/(8*d)
|
|
1064
|
+
sage: MF.faber_pol(1)
|
|
1065
|
+
q^2 + 75/(1024*d^2)
|
|
1066
|
+
sage: MF.faber_pol(0)
|
|
1067
|
+
q^3 - 3/(8*d)*q^2 + 3/(512*d^2)*q + 41/(4096*d^3)
|
|
1068
|
+
sage: MF.faber_pol(-1)
|
|
1069
|
+
q^4 - 3/(4*d)*q^3 + 81/(1024*d^2)*q^2 + 9075/(8388608*d^4)
|
|
1070
|
+
sage: (MF.faber_pol(-1)(MF.j_inv())*MF.F_simple()).q_expansion(prec=MF._l1 + 1)
|
|
1071
|
+
q^-1 + O(q^4)
|
|
1072
|
+
|
|
1073
|
+
sage: MF.faber_pol(3, order_1=-1)
|
|
1074
|
+
q + 3/(4*d)
|
|
1075
|
+
sage: MF.faber_pol(1, order_1=2)
|
|
1076
|
+
1
|
|
1077
|
+
sage: MF.faber_pol(0, order_1=2)
|
|
1078
|
+
q - 3/(8*d)
|
|
1079
|
+
sage: MF.faber_pol(-1, order_1=2)
|
|
1080
|
+
q^2 - 3/(4*d)*q + 81/(1024*d^2)
|
|
1081
|
+
sage: (MF.faber_pol(-1, order_1=2)(MF.j_inv())*MF.F_simple(order_1=2)).q_expansion(prec=MF._l1 + 1)
|
|
1082
|
+
q^-1 - 9075/(8388608*d^4)*q^3 + O(q^4)
|
|
1083
|
+
"""
|
|
1084
|
+
|
|
1085
|
+
m = ZZ(m)
|
|
1086
|
+
if (self.hecke_n() == infinity):
|
|
1087
|
+
order_1 = ZZ(order_1)
|
|
1088
|
+
order_inf = self._l1 - order_1
|
|
1089
|
+
else:
|
|
1090
|
+
order_inf = self._l1
|
|
1091
|
+
order_1 = order_inf
|
|
1092
|
+
|
|
1093
|
+
if (m > order_inf):
|
|
1094
|
+
raise ValueError("Invalid basis index: m = {} > {} = order_inf!".format(m, order_inf))
|
|
1095
|
+
|
|
1096
|
+
prec = 2*order_inf - m + 1
|
|
1097
|
+
d = self.get_d(fix_d=fix_d, d_num_prec=d_num_prec)
|
|
1098
|
+
q = self.get_q(prec=prec, fix_d=fix_d, d_num_prec=d_num_prec)
|
|
1099
|
+
|
|
1100
|
+
simple_qexp = self.F_simple(order_1=order_1).q_expansion(prec=prec, fix_d=fix_d, d_num_prec=d_num_prec)
|
|
1101
|
+
j_qexp = self.j_inv().q_expansion(prec=order_inf - m, fix_d=fix_d, d_num_prec=d_num_prec)
|
|
1102
|
+
|
|
1103
|
+
# The precision could be infinity, otherwise we could do this:
|
|
1104
|
+
# assert temp_reminder.prec() == 1
|
|
1105
|
+
temp_reminder = (1 / simple_qexp / q**(-m)).add_bigoh(1)
|
|
1106
|
+
|
|
1107
|
+
fab_pol = q.parent()([])
|
|
1108
|
+
while (len(temp_reminder.coefficients()) > 0):
|
|
1109
|
+
temp_coeff = temp_reminder.coefficients()[0]
|
|
1110
|
+
temp_exp = -temp_reminder.exponents()[0]
|
|
1111
|
+
fab_pol += temp_coeff*q**temp_exp
|
|
1112
|
+
|
|
1113
|
+
temp_reminder -= temp_coeff*j_qexp**temp_exp
|
|
1114
|
+
# The first term is zero only up to numerical errors,
|
|
1115
|
+
# so we manually have to remove it
|
|
1116
|
+
if not d.parent().is_exact():
|
|
1117
|
+
temp_reminder = temp_reminder.truncate_neg(-temp_exp+1)
|
|
1118
|
+
|
|
1119
|
+
return fab_pol.polynomial()
|
|
1120
|
+
|
|
1121
|
+
def F_basis_pol(self, m, order_1=ZZ.zero()):
|
|
1122
|
+
r"""
|
|
1123
|
+
Return a polynomial corresponding to the basis element of
|
|
1124
|
+
the corresponding space of weakly holomorphic forms of
|
|
1125
|
+
the same degree as ``self``. The basis element is determined
|
|
1126
|
+
by the property that the Fourier expansion is of the form
|
|
1127
|
+
``q^m + O(q^(order_inf + 1))``, where ``order_inf = self._l1 - order_1``.
|
|
1128
|
+
|
|
1129
|
+
If ``n=infinity`` a non-trivial order of ``-1`` can be specified through
|
|
1130
|
+
the parameter ``order_1`` (default: 0). Otherwise it is ignored.
|
|
1131
|
+
|
|
1132
|
+
INPUT:
|
|
1133
|
+
|
|
1134
|
+
- ``m`` -- integer; ``m <= self._l1``
|
|
1135
|
+
|
|
1136
|
+
- ``order_1`` -- the order at ``-1`` of ``F_simple`` (default: 0);
|
|
1137
|
+
this parameter is ignored if ``n != infinity``
|
|
1138
|
+
|
|
1139
|
+
OUTPUT:
|
|
1140
|
+
|
|
1141
|
+
A polynomial in ``x,y,z,d``, corresponding to ``f_rho, f_i, E2``
|
|
1142
|
+
and the (possibly) transcendental parameter ``d``.
|
|
1143
|
+
|
|
1144
|
+
EXAMPLES::
|
|
1145
|
+
|
|
1146
|
+
sage: from sage.modular.modform_hecketriangle.space import WeakModularForms
|
|
1147
|
+
sage: MF = WeakModularForms(n=5, k=62/3, ep=-1)
|
|
1148
|
+
sage: MF.weight_parameters()
|
|
1149
|
+
(2, 3)
|
|
1150
|
+
|
|
1151
|
+
sage: MF.F_basis_pol(2)
|
|
1152
|
+
x^13*y*d^2 - 2*x^8*y^3*d^2 + x^3*y^5*d^2
|
|
1153
|
+
sage: MF.F_basis_pol(1) * 100
|
|
1154
|
+
81*x^13*y*d - 62*x^8*y^3*d - 19*x^3*y^5*d
|
|
1155
|
+
sage: MF.F_basis_pol(0)
|
|
1156
|
+
(141913*x^13*y + 168974*x^8*y^3 + 9113*x^3*y^5)/320000
|
|
1157
|
+
|
|
1158
|
+
sage: MF(MF.F_basis_pol(2)).q_expansion(prec=MF._l1+2)
|
|
1159
|
+
q^2 - 41/(200*d)*q^3 + O(q^4)
|
|
1160
|
+
sage: MF(MF.F_basis_pol(1)).q_expansion(prec=MF._l1+1)
|
|
1161
|
+
q + O(q^3)
|
|
1162
|
+
sage: MF(MF.F_basis_pol(0)).q_expansion(prec=MF._l1+1)
|
|
1163
|
+
1 + O(q^3)
|
|
1164
|
+
sage: MF(MF.F_basis_pol(-2)).q_expansion(prec=MF._l1+1)
|
|
1165
|
+
q^-2 + O(q^3)
|
|
1166
|
+
sage: MF(MF.F_basis_pol(-2)).parent()
|
|
1167
|
+
WeakModularForms(n=5, k=62/3, ep=-1) over Integer Ring
|
|
1168
|
+
|
|
1169
|
+
sage: MF = WeakModularForms(n=4, k=-2, ep=1)
|
|
1170
|
+
sage: MF.weight_parameters()
|
|
1171
|
+
(-1, 3)
|
|
1172
|
+
|
|
1173
|
+
sage: MF.F_basis_pol(-1)
|
|
1174
|
+
x^3/(x^4*d - y^2*d)
|
|
1175
|
+
sage: MF.F_basis_pol(-2)
|
|
1176
|
+
(9*x^7 + 23*x^3*y^2)/(32*x^8*d^2 - 64*x^4*y^2*d^2 + 32*y^4*d^2)
|
|
1177
|
+
|
|
1178
|
+
sage: MF(MF.F_basis_pol(-1)).q_expansion(prec=MF._l1+2)
|
|
1179
|
+
q^-1 + 5/(16*d) + O(q)
|
|
1180
|
+
sage: MF(MF.F_basis_pol(-2)).q_expansion(prec=MF._l1+2)
|
|
1181
|
+
q^-2 + 25/(4096*d^2) + O(q)
|
|
1182
|
+
|
|
1183
|
+
sage: MF = WeakModularForms(n=infinity, k=14, ep=-1)
|
|
1184
|
+
sage: MF.F_basis_pol(3)
|
|
1185
|
+
-y^7*d^3 + 3*x*y^5*d^3 - 3*x^2*y^3*d^3 + x^3*y*d^3
|
|
1186
|
+
sage: MF.F_basis_pol(2)
|
|
1187
|
+
(3*y^7*d^2 - 17*x*y^5*d^2 + 25*x^2*y^3*d^2 - 11*x^3*y*d^2)/(-8)
|
|
1188
|
+
sage: MF.F_basis_pol(1)
|
|
1189
|
+
(-75*y^7*d + 225*x*y^5*d - 1249*x^2*y^3*d + 1099*x^3*y*d)/1024
|
|
1190
|
+
sage: MF.F_basis_pol(0)
|
|
1191
|
+
(41*y^7 - 147*x*y^5 - 1365*x^2*y^3 - 2625*x^3*y)/(-4096)
|
|
1192
|
+
sage: MF.F_basis_pol(-1)
|
|
1193
|
+
(-9075*y^9 + 36300*x*y^7 - 718002*x^2*y^5 - 4928052*x^3*y^3 - 2769779*x^4*y)/(8388608*y^2*d - 8388608*x*d)
|
|
1194
|
+
|
|
1195
|
+
sage: MF.F_basis_pol(3, order_1=-1)
|
|
1196
|
+
(-3*y^9*d^3 + 16*x*y^7*d^3 - 30*x^2*y^5*d^3 + 24*x^3*y^3*d^3 - 7*x^4*y*d^3)/(-4*x)
|
|
1197
|
+
sage: MF.F_basis_pol(1, order_1=2)
|
|
1198
|
+
-x^2*y^3*d + x^3*y*d
|
|
1199
|
+
sage: MF.F_basis_pol(0, order_1=2)
|
|
1200
|
+
(-3*x^2*y^3 - 5*x^3*y)/(-8)
|
|
1201
|
+
sage: MF.F_basis_pol(-1, order_1=2)
|
|
1202
|
+
(-81*x^2*y^5 - 606*x^3*y^3 - 337*x^4*y)/(1024*y^2*d - 1024*x*d)
|
|
1203
|
+
"""
|
|
1204
|
+
|
|
1205
|
+
(x,y,z,d) = self.rat_field().gens()
|
|
1206
|
+
n = self._group.n()
|
|
1207
|
+
|
|
1208
|
+
if (n == infinity):
|
|
1209
|
+
order_1 = ZZ(order_1)
|
|
1210
|
+
order_inf = self._l1 - order_1
|
|
1211
|
+
finf_pol = d*(x-y**2)
|
|
1212
|
+
jinv_pol = x/(x-y**2)
|
|
1213
|
+
rat = finf_pol**order_inf * x**order_1 * y**(ZZ(1-self._ep)/ZZ(2)) * self.Faber_pol(m, order_1)(jinv_pol)
|
|
1214
|
+
else:
|
|
1215
|
+
order_inf = self._l1
|
|
1216
|
+
order_1 = order_inf
|
|
1217
|
+
finf_pol = d*(x**n-y**2)
|
|
1218
|
+
jinv_pol = x**n/(x**n-y**2)
|
|
1219
|
+
rat = finf_pol**order_inf * x**self._l2 * y**(ZZ(1-self._ep)/ZZ(2)) * self.Faber_pol(m)(jinv_pol)
|
|
1220
|
+
|
|
1221
|
+
return rat
|
|
1222
|
+
|
|
1223
|
+
def F_basis(self, m, order_1=ZZ.zero()):
|
|
1224
|
+
r"""
|
|
1225
|
+
Return a weakly holomorphic element of ``self``
|
|
1226
|
+
(extended if necessarily) determined by the property that
|
|
1227
|
+
the Fourier expansion is of the form is of the form
|
|
1228
|
+
``q^m + O(q^(order_inf + 1))``, where ``order_inf = self._l1 - order_1``.
|
|
1229
|
+
|
|
1230
|
+
In particular for all ``m <= order_inf`` these elements form
|
|
1231
|
+
a basis of the space of weakly holomorphic modular forms
|
|
1232
|
+
of the corresponding degree in case ``n!=infinity``.
|
|
1233
|
+
|
|
1234
|
+
If ``n=infinity`` a non-trivial order of ``-1`` can be specified through
|
|
1235
|
+
the parameter ``order_1`` (default: 0). Otherwise it is ignored.
|
|
1236
|
+
|
|
1237
|
+
INPUT:
|
|
1238
|
+
|
|
1239
|
+
- ``m`` -- integer; ``m <= self._l1``
|
|
1240
|
+
|
|
1241
|
+
- ``order_1`` -- the order at ``-1`` of ``F_simple`` (default: 0);
|
|
1242
|
+
this parameter is ignored if ``n != infinity``
|
|
1243
|
+
|
|
1244
|
+
OUTPUT:
|
|
1245
|
+
|
|
1246
|
+
The corresponding element in (possibly an extension of) ``self``.
|
|
1247
|
+
Note that the order at ``-1`` of the resulting element may be
|
|
1248
|
+
bigger than ``order_1`` (rare).
|
|
1249
|
+
|
|
1250
|
+
EXAMPLES::
|
|
1251
|
+
|
|
1252
|
+
sage: from sage.modular.modform_hecketriangle.space import WeakModularForms, CuspForms
|
|
1253
|
+
sage: MF = WeakModularForms(n=5, k=62/3, ep=-1)
|
|
1254
|
+
sage: MF.disp_prec(MF._l1+2)
|
|
1255
|
+
sage: MF.weight_parameters()
|
|
1256
|
+
(2, 3)
|
|
1257
|
+
|
|
1258
|
+
sage: MF.F_basis(2)
|
|
1259
|
+
q^2 - 41/(200*d)*q^3 + O(q^4)
|
|
1260
|
+
sage: MF.F_basis(1)
|
|
1261
|
+
q - 13071/(640000*d^2)*q^3 + O(q^4)
|
|
1262
|
+
sage: MF.F_basis(0)
|
|
1263
|
+
1 - 277043/(192000000*d^3)*q^3 + O(q^4)
|
|
1264
|
+
sage: MF.F_basis(-2)
|
|
1265
|
+
q^-2 - 162727620113/(40960000000000000*d^5)*q^3 + O(q^4)
|
|
1266
|
+
sage: MF.F_basis(-2).parent() == MF
|
|
1267
|
+
True
|
|
1268
|
+
|
|
1269
|
+
sage: MF = CuspForms(n=4, k=-2, ep=1)
|
|
1270
|
+
sage: MF.weight_parameters()
|
|
1271
|
+
(-1, 3)
|
|
1272
|
+
|
|
1273
|
+
sage: MF.F_basis(-1).parent()
|
|
1274
|
+
WeakModularForms(n=4, k=-2, ep=1) over Integer Ring
|
|
1275
|
+
sage: MF.F_basis(-1).parent().disp_prec(MF._l1+2)
|
|
1276
|
+
sage: MF.F_basis(-1)
|
|
1277
|
+
q^-1 + 80 + O(q)
|
|
1278
|
+
sage: MF.F_basis(-2)
|
|
1279
|
+
q^-2 + 400 + O(q)
|
|
1280
|
+
|
|
1281
|
+
sage: MF = WeakModularForms(n=infinity, k=14, ep=-1)
|
|
1282
|
+
sage: MF.F_basis(3)
|
|
1283
|
+
q^3 - 48*q^4 + O(q^5)
|
|
1284
|
+
sage: MF.F_basis(2)
|
|
1285
|
+
q^2 - 1152*q^4 + O(q^5)
|
|
1286
|
+
sage: MF.F_basis(1)
|
|
1287
|
+
q - 18496*q^4 + O(q^5)
|
|
1288
|
+
sage: MF.F_basis(0)
|
|
1289
|
+
1 - 224280*q^4 + O(q^5)
|
|
1290
|
+
sage: MF.F_basis(-1)
|
|
1291
|
+
q^-1 - 2198304*q^4 + O(q^5)
|
|
1292
|
+
|
|
1293
|
+
sage: MF.F_basis(3, order_1=-1)
|
|
1294
|
+
q^3 + O(q^5)
|
|
1295
|
+
sage: MF.F_basis(1, order_1=2)
|
|
1296
|
+
q - 300*q^3 - 4096*q^4 + O(q^5)
|
|
1297
|
+
sage: MF.F_basis(0, order_1=2)
|
|
1298
|
+
1 - 24*q^2 - 2048*q^3 - 98328*q^4 + O(q^5)
|
|
1299
|
+
sage: MF.F_basis(-1, order_1=2)
|
|
1300
|
+
q^-1 - 18150*q^3 - 1327104*q^4 + O(q^5)
|
|
1301
|
+
"""
|
|
1302
|
+
|
|
1303
|
+
basis_pol = self.F_basis_pol(m, order_1=order_1)
|
|
1304
|
+
|
|
1305
|
+
if (self.hecke_n() == infinity):
|
|
1306
|
+
(x,y,z,d) = self.pol_ring().gens()
|
|
1307
|
+
if (x.divides(basis_pol.numerator()) and m > 0):
|
|
1308
|
+
new_space = self.extend_type("cusp")
|
|
1309
|
+
elif (x.divides(basis_pol.denominator()) or m < 0):
|
|
1310
|
+
new_space = self.extend_type("weak")
|
|
1311
|
+
else:
|
|
1312
|
+
new_space = self.extend_type("holo")
|
|
1313
|
+
else:
|
|
1314
|
+
if (m > 0):
|
|
1315
|
+
new_space = self.extend_type("cusp")
|
|
1316
|
+
elif (m >= 0):
|
|
1317
|
+
new_space = self.extend_type("holo")
|
|
1318
|
+
else:
|
|
1319
|
+
new_space = self.extend_type("weak")
|
|
1320
|
+
|
|
1321
|
+
return new_space(basis_pol)
|
|
1322
|
+
|
|
1323
|
+
def _canonical_min_exp(self, min_exp, order_1):
|
|
1324
|
+
r"""
|
|
1325
|
+
Return an adjusted value of ``min_exp`` and ``order_1`` corresponding
|
|
1326
|
+
to the analytic type of ``self``.
|
|
1327
|
+
|
|
1328
|
+
EXAMPLES::
|
|
1329
|
+
|
|
1330
|
+
sage: from sage.modular.modform_hecketriangle.space import CuspForms
|
|
1331
|
+
sage: CF = CuspForms(n=5, k=16, ep=1)
|
|
1332
|
+
sage: CF._canonical_min_exp(-2, 0)
|
|
1333
|
+
(1, 0)
|
|
1334
|
+
|
|
1335
|
+
sage: CF = CuspForms(n=infinity, k=10, ep=-1)
|
|
1336
|
+
sage: CF._canonical_min_exp(-2, -2)
|
|
1337
|
+
(1, 1)
|
|
1338
|
+
"""
|
|
1339
|
+
|
|
1340
|
+
min_exp = ZZ(min_exp)
|
|
1341
|
+
order_1 = ZZ(order_1)
|
|
1342
|
+
if self.is_holomorphic():
|
|
1343
|
+
if self.is_cuspidal():
|
|
1344
|
+
min_exp = max(min_exp, 1)
|
|
1345
|
+
order_1 = max(order_1, 1)
|
|
1346
|
+
else:
|
|
1347
|
+
min_exp = max(min_exp, 0)
|
|
1348
|
+
order_1 = max(order_1, 0)
|
|
1349
|
+
|
|
1350
|
+
if (self.hecke_n() != infinity):
|
|
1351
|
+
order_1 = ZZ.zero()
|
|
1352
|
+
|
|
1353
|
+
return (min_exp, order_1)
|
|
1354
|
+
|
|
1355
|
+
def quasi_part_gens(self, r=None, min_exp=0, max_exp=infinity, order_1=ZZ.zero()) -> tuple:
|
|
1356
|
+
r"""
|
|
1357
|
+
Return a basis in ``self`` of the subspace of (quasi) weakly
|
|
1358
|
+
holomorphic forms which satisfy the specified properties on
|
|
1359
|
+
the quasi parts and the initial Fourier coefficient.
|
|
1360
|
+
|
|
1361
|
+
INPUT:
|
|
1362
|
+
|
|
1363
|
+
- ``r`` -- an integer or ``None`` (default), indicating the desired
|
|
1364
|
+
power of ``E2``; if ``r`` is ``None`` then all possible powers
|
|
1365
|
+
(``r``) are chosen
|
|
1366
|
+
|
|
1367
|
+
- ``min_exp`` -- integer (default: 0); a lower bound for the first
|
|
1368
|
+
non-trivial Fourier coefficient of the generators
|
|
1369
|
+
|
|
1370
|
+
- ``max_exp`` -- integer or ``infinity`` (default) giving an upper
|
|
1371
|
+
bound for the first non-trivial Fourier coefficient of the
|
|
1372
|
+
generators. If ``max_exp==infinity`` then no upper bound is assumed.
|
|
1373
|
+
|
|
1374
|
+
- ``order_1`` -- a lower bound for the order at ``-1`` of all quasi
|
|
1375
|
+
parts of the basis elements (default: 0). If ``n!=infinity`` this
|
|
1376
|
+
parameter is ignored.
|
|
1377
|
+
|
|
1378
|
+
OUTPUT:
|
|
1379
|
+
|
|
1380
|
+
A basis in ``self`` of the subspace of forms which are modular
|
|
1381
|
+
after dividing by ``E2^r`` and which have a Fourier expansion
|
|
1382
|
+
of the form ``q^m + O(q^(m+1))`` with ``min_exp <= m <=
|
|
1383
|
+
max_exp`` for each quasi part (and at least the specified
|
|
1384
|
+
order at ``-1`` in case ``n=infinity``). Note that linear
|
|
1385
|
+
combinations of forms/quasi parts maybe have a higher order at
|
|
1386
|
+
infinity than ``max_exp``.
|
|
1387
|
+
|
|
1388
|
+
EXAMPLES::
|
|
1389
|
+
|
|
1390
|
+
sage: from sage.modular.modform_hecketriangle.space import QuasiWeakModularForms
|
|
1391
|
+
sage: QF = QuasiWeakModularForms(n=8, k=10/3, ep=-1)
|
|
1392
|
+
sage: QF.default_prec(1)
|
|
1393
|
+
sage: QF.quasi_part_gens(min_exp=-1)
|
|
1394
|
+
(q^-1 + O(q), 1 + O(q), q^-1 - 9/(128*d) + O(q),
|
|
1395
|
+
1 + O(q), q^-1 - 19/(64*d) + O(q), q^-1 + 1/(64*d) + O(q))
|
|
1396
|
+
|
|
1397
|
+
sage: QF.quasi_part_gens(min_exp=-1, max_exp=-1)
|
|
1398
|
+
(q^-1 + O(q), q^-1 - 9/(128*d) + O(q),
|
|
1399
|
+
q^-1 - 19/(64*d) + O(q), q^-1 + 1/(64*d) + O(q))
|
|
1400
|
+
sage: QF.quasi_part_gens(min_exp=-2, r=1)
|
|
1401
|
+
(q^-2 - 9/(128*d)*q^-1 - 261/(131072*d^2) + O(q),
|
|
1402
|
+
q^-1 - 9/(128*d) + O(q), 1 + O(q))
|
|
1403
|
+
|
|
1404
|
+
sage: from sage.modular.modform_hecketriangle.space import ModularForms
|
|
1405
|
+
sage: MF = ModularForms(k=36)
|
|
1406
|
+
sage: MF.quasi_part_gens(min_exp=2)
|
|
1407
|
+
(q^2 + 194184*q^4 + O(q^5), q^3 - 72*q^4 + O(q^5))
|
|
1408
|
+
|
|
1409
|
+
sage: from sage.modular.modform_hecketriangle.space import QuasiModularForms
|
|
1410
|
+
sage: MF = QuasiModularForms(n=5, k=6, ep=-1)
|
|
1411
|
+
sage: MF.default_prec(2)
|
|
1412
|
+
sage: MF.dimension()
|
|
1413
|
+
3
|
|
1414
|
+
sage: MF.quasi_part_gens(r=0)
|
|
1415
|
+
(1 - 37/(200*d)*q + O(q^2),)
|
|
1416
|
+
sage: MF.quasi_part_gens(r=0)[0] == MF.E6()
|
|
1417
|
+
True
|
|
1418
|
+
sage: MF.quasi_part_gens(r=1)
|
|
1419
|
+
(1 + 33/(200*d)*q + O(q^2),)
|
|
1420
|
+
sage: MF.quasi_part_gens(r=1)[0] == MF.E2()*MF.E4()
|
|
1421
|
+
True
|
|
1422
|
+
sage: MF.quasi_part_gens(r=2)
|
|
1423
|
+
()
|
|
1424
|
+
sage: MF.quasi_part_gens(r=3)
|
|
1425
|
+
(1 - 27/(200*d)*q + O(q^2),)
|
|
1426
|
+
sage: MF.quasi_part_gens(r=3)[0] == MF.E2()^3
|
|
1427
|
+
True
|
|
1428
|
+
|
|
1429
|
+
sage: from sage.modular.modform_hecketriangle.space import QuasiCuspForms, CuspForms
|
|
1430
|
+
sage: MF = QuasiCuspForms(n=5, k=18, ep=-1)
|
|
1431
|
+
sage: MF.default_prec(4)
|
|
1432
|
+
sage: MF.dimension()
|
|
1433
|
+
8
|
|
1434
|
+
sage: MF.quasi_part_gens(r=0)
|
|
1435
|
+
(q - 34743/(640000*d^2)*q^3 + O(q^4), q^2 - 69/(200*d)*q^3 + O(q^4))
|
|
1436
|
+
sage: MF.quasi_part_gens(r=1)
|
|
1437
|
+
(q - 9/(200*d)*q^2 + 37633/(640000*d^2)*q^3 + O(q^4),
|
|
1438
|
+
q^2 + 1/(200*d)*q^3 + O(q^4))
|
|
1439
|
+
sage: MF.quasi_part_gens(r=2)
|
|
1440
|
+
(q - 1/(4*d)*q^2 - 24903/(640000*d^2)*q^3 + O(q^4),)
|
|
1441
|
+
sage: MF.quasi_part_gens(r=3)
|
|
1442
|
+
(q + 1/(10*d)*q^2 - 7263/(640000*d^2)*q^3 + O(q^4),)
|
|
1443
|
+
sage: MF.quasi_part_gens(r=4)
|
|
1444
|
+
(q - 11/(20*d)*q^2 + 53577/(640000*d^2)*q^3 + O(q^4),)
|
|
1445
|
+
sage: MF.quasi_part_gens(r=5)
|
|
1446
|
+
(q - 1/(5*d)*q^2 + 4017/(640000*d^2)*q^3 + O(q^4),)
|
|
1447
|
+
|
|
1448
|
+
sage: MF.quasi_part_gens(r=1)[0] == MF.E2() * CuspForms(n=5, k=16, ep=1).gen(0)
|
|
1449
|
+
True
|
|
1450
|
+
sage: MF.quasi_part_gens(r=1)[1] == MF.E2() * CuspForms(n=5, k=16, ep=1).gen(1)
|
|
1451
|
+
True
|
|
1452
|
+
sage: MF.quasi_part_gens(r=3)[0] == MF.E2()^3 * MF.Delta()
|
|
1453
|
+
True
|
|
1454
|
+
|
|
1455
|
+
sage: MF = QuasiCuspForms(n=infinity, k=18, ep=-1)
|
|
1456
|
+
sage: MF.quasi_part_gens(r=1, min_exp=-2) == MF.quasi_part_gens(r=1, min_exp=1)
|
|
1457
|
+
True
|
|
1458
|
+
sage: MF.quasi_part_gens(r=1)
|
|
1459
|
+
(q - 8*q^2 - 8*q^3 + 5952*q^4 + O(q^5),
|
|
1460
|
+
q^2 - 8*q^3 + 208*q^4 + O(q^5),
|
|
1461
|
+
q^3 - 16*q^4 + O(q^5))
|
|
1462
|
+
|
|
1463
|
+
sage: MF = QuasiWeakModularForms(n=infinity, k=4, ep=1)
|
|
1464
|
+
sage: MF.quasi_part_gens(r=2, min_exp=2, order_1=-2)[0] == MF.E2()^2 * MF.E4()^(-2) * MF.f_inf()^2
|
|
1465
|
+
True
|
|
1466
|
+
sage: [v.order_at(-1) for v in MF.quasi_part_gens(r=0, min_exp=2, order_1=-2)]
|
|
1467
|
+
[-2, -2]
|
|
1468
|
+
"""
|
|
1469
|
+
if not self.is_weakly_holomorphic():
|
|
1470
|
+
from warnings import warn
|
|
1471
|
+
warn("This function only determines generators of (quasi) weakly modular forms!")
|
|
1472
|
+
|
|
1473
|
+
min_exp, order_1 = self._canonical_min_exp(min_exp, order_1)
|
|
1474
|
+
|
|
1475
|
+
# For modular forms spaces the quasi parts are all zero except for r=0
|
|
1476
|
+
if self.is_modular():
|
|
1477
|
+
r = ZZ(r)
|
|
1478
|
+
if r:
|
|
1479
|
+
return ()
|
|
1480
|
+
|
|
1481
|
+
# The lower bounds on the powers of f_inf and E4 determine
|
|
1482
|
+
# how large powers of E2 we can fit in...
|
|
1483
|
+
n = self.hecke_n()
|
|
1484
|
+
if n == infinity:
|
|
1485
|
+
max_numerator_weight = self._weight - 4*min_exp - 4*order_1 + 4
|
|
1486
|
+
else:
|
|
1487
|
+
max_numerator_weight = self._weight - 4*n/(n-2)*min_exp + 4
|
|
1488
|
+
|
|
1489
|
+
# If r is not specified we gather all generators for all possible r's
|
|
1490
|
+
if r is None:
|
|
1491
|
+
gens = []
|
|
1492
|
+
for rnew in range(QQ(max_numerator_weight / ZZ(2)).floor() + 1):
|
|
1493
|
+
gens.extend(self.quasi_part_gens(r=rnew, min_exp=min_exp, max_exp=max_exp, order_1=order_1))
|
|
1494
|
+
return tuple(gens)
|
|
1495
|
+
|
|
1496
|
+
r = ZZ(r)
|
|
1497
|
+
if r < 0 or 2*r > max_numerator_weight:
|
|
1498
|
+
return ()
|
|
1499
|
+
|
|
1500
|
+
E2 = self.E2()
|
|
1501
|
+
ambient_weak_space = self.graded_ring().reduce_type("weak",
|
|
1502
|
+
degree=(self._weight-QQ(2*r), self._ep*(-1)**r))
|
|
1503
|
+
order_inf = ambient_weak_space._l1 - order_1
|
|
1504
|
+
|
|
1505
|
+
if max_exp == infinity:
|
|
1506
|
+
max_exp = order_inf
|
|
1507
|
+
elif max_exp < min_exp:
|
|
1508
|
+
return ()
|
|
1509
|
+
else:
|
|
1510
|
+
max_exp = min(ZZ(max_exp), order_inf)
|
|
1511
|
+
|
|
1512
|
+
return tuple(self(ambient_weak_space.F_basis(m, order_1=order_1) * E2**r)
|
|
1513
|
+
for m in range(min_exp, max_exp + 1))
|
|
1514
|
+
|
|
1515
|
+
def quasi_part_dimension(self, r=None, min_exp=0, max_exp=infinity, order_1=ZZ.zero()):
|
|
1516
|
+
r"""
|
|
1517
|
+
Return the dimension of the subspace of ``self`` generated by
|
|
1518
|
+
``self.quasi_part_gens(r, min_exp, max_exp, order_1)``.
|
|
1519
|
+
|
|
1520
|
+
See :meth:`quasi_part_gens` for more details.
|
|
1521
|
+
|
|
1522
|
+
EXAMPLES::
|
|
1523
|
+
|
|
1524
|
+
sage: from sage.modular.modform_hecketriangle.space import QuasiModularForms, QuasiCuspForms, QuasiWeakModularForms
|
|
1525
|
+
sage: MF = QuasiModularForms(n=5, k=6, ep=-1)
|
|
1526
|
+
sage: [v.as_ring_element() for v in MF.gens()]
|
|
1527
|
+
[f_rho^2*f_i, f_rho^3*E2, E2^3]
|
|
1528
|
+
sage: MF.dimension()
|
|
1529
|
+
3
|
|
1530
|
+
sage: MF.quasi_part_dimension(r=0)
|
|
1531
|
+
1
|
|
1532
|
+
sage: MF.quasi_part_dimension(r=1)
|
|
1533
|
+
1
|
|
1534
|
+
sage: MF.quasi_part_dimension(r=2)
|
|
1535
|
+
0
|
|
1536
|
+
sage: MF.quasi_part_dimension(r=3)
|
|
1537
|
+
1
|
|
1538
|
+
|
|
1539
|
+
sage: MF = QuasiCuspForms(n=5, k=18, ep=-1)
|
|
1540
|
+
sage: MF.dimension()
|
|
1541
|
+
8
|
|
1542
|
+
sage: MF.quasi_part_dimension(r=0)
|
|
1543
|
+
2
|
|
1544
|
+
sage: MF.quasi_part_dimension(r=1)
|
|
1545
|
+
2
|
|
1546
|
+
sage: MF.quasi_part_dimension(r=2)
|
|
1547
|
+
1
|
|
1548
|
+
sage: MF.quasi_part_dimension(r=3)
|
|
1549
|
+
1
|
|
1550
|
+
sage: MF.quasi_part_dimension(r=4)
|
|
1551
|
+
1
|
|
1552
|
+
sage: MF.quasi_part_dimension(r=5)
|
|
1553
|
+
1
|
|
1554
|
+
sage: MF.quasi_part_dimension(min_exp=2, max_exp=2)
|
|
1555
|
+
2
|
|
1556
|
+
|
|
1557
|
+
sage: MF = QuasiCuspForms(n=infinity, k=18, ep=-1)
|
|
1558
|
+
sage: MF.quasi_part_dimension(r=1, min_exp=-2)
|
|
1559
|
+
3
|
|
1560
|
+
sage: MF.quasi_part_dimension()
|
|
1561
|
+
12
|
|
1562
|
+
sage: MF.quasi_part_dimension(order_1=3)
|
|
1563
|
+
2
|
|
1564
|
+
|
|
1565
|
+
sage: MF = QuasiWeakModularForms(n=infinity, k=4, ep=1)
|
|
1566
|
+
sage: MF.quasi_part_dimension(min_exp=2, order_1=-2)
|
|
1567
|
+
4
|
|
1568
|
+
sage: [v.order_at(-1) for v in MF.quasi_part_gens(r=0, min_exp=2, order_1=-2)]
|
|
1569
|
+
[-2, -2]
|
|
1570
|
+
"""
|
|
1571
|
+
|
|
1572
|
+
if (not self.is_weakly_holomorphic()):
|
|
1573
|
+
from warnings import warn
|
|
1574
|
+
warn("This function only determines the dimension of some (quasi) weakly subspace!")
|
|
1575
|
+
|
|
1576
|
+
(min_exp, order_1) = self._canonical_min_exp(min_exp, order_1)
|
|
1577
|
+
|
|
1578
|
+
# For modular forms spaces the quasi parts are all zero except for r=0
|
|
1579
|
+
if self.is_modular():
|
|
1580
|
+
r = ZZ.zero()
|
|
1581
|
+
if r != 0:
|
|
1582
|
+
return ZZ.zero()
|
|
1583
|
+
|
|
1584
|
+
# The lower bounds on the powers of f_inf and E4 determine
|
|
1585
|
+
# how large powers of E2 we can fit in...
|
|
1586
|
+
n = self.hecke_n()
|
|
1587
|
+
if (n == infinity):
|
|
1588
|
+
max_numerator_weight = self._weight - 4*min_exp - 4*order_1 + 4
|
|
1589
|
+
else:
|
|
1590
|
+
max_numerator_weight = self._weight - 4*n/(n-2)*min_exp + 4
|
|
1591
|
+
|
|
1592
|
+
# If r is not specified we calculate the total dimension over all possible r's
|
|
1593
|
+
if r is None:
|
|
1594
|
+
return sum([self.quasi_part_dimension(r=rnew, min_exp=min_exp, max_exp=max_exp, order_1=order_1) for rnew in range(QQ(max_numerator_weight/ZZ(2)).floor() + 1)])
|
|
1595
|
+
|
|
1596
|
+
r = ZZ(r)
|
|
1597
|
+
if (r < 0 or 2*r > max_numerator_weight):
|
|
1598
|
+
return ZZ.zero()
|
|
1599
|
+
|
|
1600
|
+
k = self._weight - QQ(2*r)
|
|
1601
|
+
ep = self._ep * (-1)**r
|
|
1602
|
+
if (n == infinity):
|
|
1603
|
+
num = (k - (1-ep)) / ZZ(4)
|
|
1604
|
+
l2 = order_1
|
|
1605
|
+
order_inf = ZZ(num) - order_1
|
|
1606
|
+
else:
|
|
1607
|
+
num = ZZ((k-(1-ep)*ZZ(n)/ZZ(n-2)) * ZZ(n-2) / ZZ(4))
|
|
1608
|
+
l2 = num % n
|
|
1609
|
+
order_inf = ((num - l2) / n).numerator()
|
|
1610
|
+
|
|
1611
|
+
if (max_exp == infinity):
|
|
1612
|
+
max_exp = order_inf
|
|
1613
|
+
elif (max_exp < min_exp):
|
|
1614
|
+
return ZZ.zero()
|
|
1615
|
+
else:
|
|
1616
|
+
max_exp = min(ZZ(max_exp), order_inf)
|
|
1617
|
+
|
|
1618
|
+
return max(ZZ.zero(), max_exp - min_exp + 1)
|
|
1619
|
+
|
|
1620
|
+
def construct_form(self, laurent_series, order_1=ZZ.zero(), check=True, rationalize=False):
|
|
1621
|
+
r"""
|
|
1622
|
+
Try to construct an element of ``self`` with the given Fourier
|
|
1623
|
+
expansion. The assumption is made that the specified Fourier
|
|
1624
|
+
expansion corresponds to a weakly holomorphic modular form.
|
|
1625
|
+
|
|
1626
|
+
If the precision is too low to determine the
|
|
1627
|
+
element an exception is raised.
|
|
1628
|
+
|
|
1629
|
+
INPUT:
|
|
1630
|
+
|
|
1631
|
+
- ``laurent_series`` -- a Laurent or Power series
|
|
1632
|
+
|
|
1633
|
+
- ``order_1`` -- a lower bound for the order at ``-1`` of the form
|
|
1634
|
+
(default: 0). If ``n!=infinity`` this parameter is ignored.
|
|
1635
|
+
|
|
1636
|
+
- ``check`` -- if ``True`` (default) then the series expansion of the
|
|
1637
|
+
constructed form is compared against the given series
|
|
1638
|
+
|
|
1639
|
+
- ``rationalize`` -- if ``True`` (default: ``False``) then the series
|
|
1640
|
+
is "rationalized" beforehand. Note that in non-exact or
|
|
1641
|
+
non-arithmetic cases this is experimental and extremely unreliable!
|
|
1642
|
+
|
|
1643
|
+
OUTPUT:
|
|
1644
|
+
|
|
1645
|
+
If possible: An element of ``self`` with the same initial
|
|
1646
|
+
Fourier expansion as ``laurent_series``.
|
|
1647
|
+
|
|
1648
|
+
Note: For modular spaces it is also possible to call
|
|
1649
|
+
``self(laurent_series)`` instead.
|
|
1650
|
+
|
|
1651
|
+
EXAMPLES::
|
|
1652
|
+
|
|
1653
|
+
sage: from sage.modular.modform_hecketriangle.space import CuspForms
|
|
1654
|
+
sage: Delta = CuspForms(k=12).Delta()
|
|
1655
|
+
sage: qexp = Delta.q_expansion(prec=2)
|
|
1656
|
+
sage: qexp.parent()
|
|
1657
|
+
Power Series Ring in q over Fraction Field of Univariate Polynomial Ring in d over Integer Ring
|
|
1658
|
+
sage: qexp
|
|
1659
|
+
q + O(q^2)
|
|
1660
|
+
sage: CuspForms(k=12).construct_form(qexp) == Delta
|
|
1661
|
+
True
|
|
1662
|
+
|
|
1663
|
+
sage: from sage.modular.modform_hecketriangle.space import WeakModularForms
|
|
1664
|
+
sage: J_inv = WeakModularForms(n=7).J_inv()
|
|
1665
|
+
sage: qexp2 = J_inv.q_expansion(prec=1)
|
|
1666
|
+
sage: qexp2.parent()
|
|
1667
|
+
Laurent Series Ring in q over Fraction Field of Univariate Polynomial Ring in d over Integer Ring
|
|
1668
|
+
sage: qexp2
|
|
1669
|
+
d*q^-1 + 151/392 + O(q)
|
|
1670
|
+
sage: WeakModularForms(n=7).construct_form(qexp2) == J_inv
|
|
1671
|
+
True
|
|
1672
|
+
|
|
1673
|
+
sage: MF = WeakModularForms(n=5, k=62/3, ep=-1)
|
|
1674
|
+
sage: MF.default_prec(MF._l1+1)
|
|
1675
|
+
sage: d = MF.get_d()
|
|
1676
|
+
sage: MF.weight_parameters()
|
|
1677
|
+
(2, 3)
|
|
1678
|
+
sage: el2 = d*MF.F_basis(2) + 2*MF.F_basis(1) + MF.F_basis(-2)
|
|
1679
|
+
sage: qexp2 = el2.q_expansion()
|
|
1680
|
+
sage: qexp2.parent()
|
|
1681
|
+
Laurent Series Ring in q over Fraction Field of Univariate Polynomial Ring in d over Integer Ring
|
|
1682
|
+
sage: qexp2
|
|
1683
|
+
q^-2 + 2*q + d*q^2 + O(q^3)
|
|
1684
|
+
sage: WeakModularForms(n=5, k=62/3, ep=-1).construct_form(qexp2) == el2
|
|
1685
|
+
True
|
|
1686
|
+
|
|
1687
|
+
sage: MF = WeakModularForms(n=infinity, k=-2, ep=-1)
|
|
1688
|
+
sage: el3 = MF.f_i()/MF.f_inf() + MF.f_i()*MF.f_inf()/MF.E4()^2
|
|
1689
|
+
sage: MF.quasi_part_dimension(min_exp=-1, order_1=-2)
|
|
1690
|
+
3
|
|
1691
|
+
sage: prec = MF._l1 + 3
|
|
1692
|
+
sage: qexp3 = el3.q_expansion(prec)
|
|
1693
|
+
sage: qexp3
|
|
1694
|
+
q^-1 - 1/(4*d) + ((1024*d^2 - 33)/(1024*d^2))*q + O(q^2)
|
|
1695
|
+
sage: MF.construct_form(qexp3, order_1=-2) == el3
|
|
1696
|
+
True
|
|
1697
|
+
sage: MF.construct_form(el3.q_expansion(prec + 1), order_1=-3) == el3
|
|
1698
|
+
True
|
|
1699
|
+
|
|
1700
|
+
sage: WF = WeakModularForms(n=14)
|
|
1701
|
+
sage: qexp = WF.J_inv().q_expansion_fixed_d(d_num_prec=1000)
|
|
1702
|
+
sage: qexp.parent()
|
|
1703
|
+
Laurent Series Ring in q over Real Field with 1000 bits of precision
|
|
1704
|
+
sage: WF.construct_form(qexp, rationalize=True) == WF.J_inv()
|
|
1705
|
+
doctest:...: UserWarning: Using an experimental rationalization of coefficients, please check the result for correctness!
|
|
1706
|
+
True
|
|
1707
|
+
"""
|
|
1708
|
+
|
|
1709
|
+
base_ring = laurent_series.base_ring()
|
|
1710
|
+
if isinstance(base_ring.base(), PolynomialRing_generic):
|
|
1711
|
+
if not (self.coeff_ring().has_coerce_map_from(base_ring)):
|
|
1712
|
+
raise ValueError("The Laurent coefficients don't coerce into the coefficient ring of self!")
|
|
1713
|
+
elif rationalize:
|
|
1714
|
+
laurent_series = self.rationalize_series(laurent_series)
|
|
1715
|
+
else:
|
|
1716
|
+
raise ValueError("The Laurent coefficients are not in the proper form yet. Try rationalize_series(laurent_series) beforehand (experimental).")
|
|
1717
|
+
|
|
1718
|
+
order_1 = self._canonical_min_exp(0, order_1)[1]
|
|
1719
|
+
order_inf = self._l1 - order_1
|
|
1720
|
+
|
|
1721
|
+
if (laurent_series.prec() < order_inf + 1):
|
|
1722
|
+
raise ValueError("Insufficient precision: {} < {} = order_inf!".format(laurent_series.prec(), order_inf + 1))
|
|
1723
|
+
|
|
1724
|
+
new_series = laurent_series.add_bigoh(order_inf + 1)
|
|
1725
|
+
coefficients = new_series.coefficients()
|
|
1726
|
+
exponents = new_series.exponents()
|
|
1727
|
+
|
|
1728
|
+
if (len(coefficients) == 0):
|
|
1729
|
+
return self(0)
|
|
1730
|
+
|
|
1731
|
+
rat = sum([coefficients[j] * self.F_basis_pol(exponents[j], order_1=order_1)
|
|
1732
|
+
for j in range(ZZ(len(coefficients)))])
|
|
1733
|
+
|
|
1734
|
+
el = self(rat)
|
|
1735
|
+
|
|
1736
|
+
if (check):
|
|
1737
|
+
prec = min(laurent_series.prec(), laurent_series.exponents()[-1] + 1)
|
|
1738
|
+
if (el.q_expansion(prec=prec) != laurent_series):
|
|
1739
|
+
raise ValueError("The Laurent series {} does not correspond to a form of {}".format(laurent_series, self.reduce_type(["weak"])))
|
|
1740
|
+
|
|
1741
|
+
return el
|
|
1742
|
+
|
|
1743
|
+
@cached_method
|
|
1744
|
+
def _quasi_form_matrix(self, min_exp=0, order_1=ZZ.zero(), incr_prec_by=0):
|
|
1745
|
+
r"""
|
|
1746
|
+
Return a base change matrix which transforms coordinate vectors
|
|
1747
|
+
with respect to a certain basis into a vector corresponding to
|
|
1748
|
+
Laurent coefficients of a series.
|
|
1749
|
+
|
|
1750
|
+
This is a helper function used to construct weakly holomorphic quasi
|
|
1751
|
+
forms based on their initial Laurent coefficients
|
|
1752
|
+
(see :meth:`construct_quasi_form`).
|
|
1753
|
+
|
|
1754
|
+
INPUT:
|
|
1755
|
+
|
|
1756
|
+
- ``min_exp`` -- integer (default: 0), namely the lower bound for the
|
|
1757
|
+
order at infinity resp. the exponent of the Laurent series
|
|
1758
|
+
|
|
1759
|
+
- ``order_1`` -- a lower bound for the order at ``-1`` of all quasi
|
|
1760
|
+
parts of the subspace (default: 0). If ``n!=infinity`` this parameter
|
|
1761
|
+
is ignored.
|
|
1762
|
+
|
|
1763
|
+
- ``incr_prec_by`` -- integer (default: 0) which specifies how much the
|
|
1764
|
+
precision should be increased compared to the size of the
|
|
1765
|
+
corresponding basis
|
|
1766
|
+
|
|
1767
|
+
OUTPUT: the corresponding base change matrix
|
|
1768
|
+
|
|
1769
|
+
EXAMPLES::
|
|
1770
|
+
|
|
1771
|
+
sage: from sage.modular.modform_hecketriangle.space import QuasiWeakModularForms, ModularForms, QuasiModularForms
|
|
1772
|
+
sage: QF = QuasiWeakModularForms(n=8, k=10/3, ep=-1)
|
|
1773
|
+
sage: A = QF._quasi_form_matrix(min_exp=-1)
|
|
1774
|
+
sage: A[3]
|
|
1775
|
+
(-1215/(65536*d^3), -2171/(131072*d^2), 134099/(16777216*d^3), -811/(131072*d^2), 15889/(8388608*d^3), -8851/(8388608*d^3))
|
|
1776
|
+
|
|
1777
|
+
sage: MF = ModularForms(k=36)
|
|
1778
|
+
sage: MF._quasi_form_matrix(min_exp=2)
|
|
1779
|
+
[1 0]
|
|
1780
|
+
[0 1]
|
|
1781
|
+
|
|
1782
|
+
sage: QuasiModularForms(k=2)._quasi_form_matrix()
|
|
1783
|
+
[1]
|
|
1784
|
+
|
|
1785
|
+
sage: QF = QuasiWeakModularForms(n=infinity, k=-2, ep=-1)
|
|
1786
|
+
sage: A = QF._quasi_form_matrix(min_exp=-1, order_1=0)
|
|
1787
|
+
sage: A
|
|
1788
|
+
[ 1 1]
|
|
1789
|
+
[-1/(4*d) 0]
|
|
1790
|
+
"""
|
|
1791
|
+
|
|
1792
|
+
(min_exp, order_1) = self._canonical_min_exp(min_exp, order_1)
|
|
1793
|
+
|
|
1794
|
+
order_inf = self._l1 - order_1
|
|
1795
|
+
|
|
1796
|
+
# We have to add + 1 to get a correct upper bound in all cases
|
|
1797
|
+
# since corresponding weak space might have a higher l1 (+1) than
|
|
1798
|
+
# ``self``, even if the weight is smaller
|
|
1799
|
+
max_exp = order_inf + 1
|
|
1800
|
+
|
|
1801
|
+
basis = self.quasi_part_gens(min_exp=min_exp, max_exp=max_exp, order_1=order_1)
|
|
1802
|
+
|
|
1803
|
+
column_size = len(basis)
|
|
1804
|
+
# a non-trivial incr_prec_by will be added in case the resulting matrix does not have full rank
|
|
1805
|
+
row_size = column_size + incr_prec_by
|
|
1806
|
+
prec = row_size + min_exp
|
|
1807
|
+
|
|
1808
|
+
coeff_ring = self.coeff_ring()
|
|
1809
|
+
A = matrix(coeff_ring, row_size, 0)
|
|
1810
|
+
|
|
1811
|
+
for gen in basis:
|
|
1812
|
+
A = A.augment(gen.q_expansion_vector(min_exp=min_exp, max_exp=prec-1))
|
|
1813
|
+
|
|
1814
|
+
# So far this case never happened but potentially A could be singular!
|
|
1815
|
+
# In this case we want to increase the row size until A has maximal
|
|
1816
|
+
# rank (i.e. column size).
|
|
1817
|
+
|
|
1818
|
+
# This is done up increasing the precision of everything by about 20%
|
|
1819
|
+
# of the column size until A has maximal rank:
|
|
1820
|
+
if (A.rank() < column_size):
|
|
1821
|
+
if (incr_prec_by == 0):
|
|
1822
|
+
from sage.misc.verbose import verbose
|
|
1823
|
+
verbose("Encountered a base change matrix with not-yet-maximal rank (rare, please report)!")
|
|
1824
|
+
incr_prec_by += column_size//ZZ(5) + 1
|
|
1825
|
+
return self._quasi_form_matrix(min_exp=min_exp, order_1=order_1, incr_prec_by=incr_prec_by)
|
|
1826
|
+
elif (incr_prec_by == 0):
|
|
1827
|
+
return A
|
|
1828
|
+
|
|
1829
|
+
# At this point the matrix has maximal rank but might be too big.
|
|
1830
|
+
# Since we are interested in the (exact) required size resp. precision
|
|
1831
|
+
# we have to decrease the (row) size as much as possible while keeping
|
|
1832
|
+
# maximal rank. We cannot simply choose pivots/etc since we want to
|
|
1833
|
+
# keep a simple correspondence to Fourier coefficients!
|
|
1834
|
+
|
|
1835
|
+
# We start by using an initial binary search to delete some unnecessary rows:
|
|
1836
|
+
while (A.rank() == column_size):
|
|
1837
|
+
row_size = A.dimensions()[0]
|
|
1838
|
+
|
|
1839
|
+
# to avoid infinite loops
|
|
1840
|
+
if (row_size == column_size):
|
|
1841
|
+
return A
|
|
1842
|
+
|
|
1843
|
+
B = A
|
|
1844
|
+
A = A.delete_rows(list(range(column_size + (row_size-column_size)//2 - 1, row_size)))
|
|
1845
|
+
|
|
1846
|
+
# Next we simply delete row by row. Note that A is still modified here...
|
|
1847
|
+
while (B.rank() == column_size):
|
|
1848
|
+
A = B
|
|
1849
|
+
row_size = B.dimensions()[0]
|
|
1850
|
+
B = B.delete_rows([row_size-1])
|
|
1851
|
+
|
|
1852
|
+
return A
|
|
1853
|
+
|
|
1854
|
+
def required_laurent_prec(self, min_exp=0, order_1=ZZ.zero()):
|
|
1855
|
+
r"""
|
|
1856
|
+
Return an upper bound for the required precision for Laurent series to
|
|
1857
|
+
uniquely determine a corresponding (quasi) form in ``self`` with the given
|
|
1858
|
+
lower bound ``min_exp`` for the order at infinity (for each quasi part).
|
|
1859
|
+
|
|
1860
|
+
.. NOTE::
|
|
1861
|
+
|
|
1862
|
+
For ``n=infinity`` only the holomorphic case (``min_exp >= 0``)
|
|
1863
|
+
is supported (in particular a nonnegative order at ``-1`` is assumed).
|
|
1864
|
+
|
|
1865
|
+
INPUT:
|
|
1866
|
+
|
|
1867
|
+
- ``min_exp`` -- integer (default: 0); namely the lower bound for the
|
|
1868
|
+
order at infinity resp. the exponent of the Laurent series
|
|
1869
|
+
|
|
1870
|
+
- ``order_1`` -- a lower bound for the order at ``-1`` for all quasi
|
|
1871
|
+
parts (default: 0). If ``n!=infinity`` this parameter is ignored.
|
|
1872
|
+
|
|
1873
|
+
OUTPUT:
|
|
1874
|
+
|
|
1875
|
+
An integer, namely an upper bound for the number of required
|
|
1876
|
+
Laurent coefficients. The bound should be precise or at least
|
|
1877
|
+
pretty sharp.
|
|
1878
|
+
|
|
1879
|
+
EXAMPLES::
|
|
1880
|
+
|
|
1881
|
+
sage: from sage.modular.modform_hecketriangle.space import QuasiWeakModularForms, ModularForms, QuasiModularForms
|
|
1882
|
+
sage: QF = QuasiWeakModularForms(n=8, k=10/3, ep=-1)
|
|
1883
|
+
sage: QF.required_laurent_prec(min_exp=-1)
|
|
1884
|
+
5
|
|
1885
|
+
|
|
1886
|
+
sage: MF = ModularForms(k=36)
|
|
1887
|
+
sage: MF.required_laurent_prec(min_exp=2)
|
|
1888
|
+
4
|
|
1889
|
+
|
|
1890
|
+
sage: QuasiModularForms(k=2).required_laurent_prec()
|
|
1891
|
+
1
|
|
1892
|
+
|
|
1893
|
+
sage: QuasiWeakModularForms(n=infinity, k=2, ep=-1).required_laurent_prec(order_1=-1)
|
|
1894
|
+
6
|
|
1895
|
+
"""
|
|
1896
|
+
|
|
1897
|
+
(min_exp, order_1) = self._canonical_min_exp(min_exp, order_1)
|
|
1898
|
+
|
|
1899
|
+
return self._quasi_form_matrix(min_exp=min_exp, order_1=order_1).dimensions()[0] + min_exp
|
|
1900
|
+
|
|
1901
|
+
def construct_quasi_form(self, laurent_series, order_1=ZZ.zero(), check=True, rationalize=False):
|
|
1902
|
+
r"""
|
|
1903
|
+
Try to construct an element of ``self`` with the given Fourier
|
|
1904
|
+
expansion. The assumption is made that the specified Fourier
|
|
1905
|
+
expansion corresponds to a weakly holomorphic quasi modular form.
|
|
1906
|
+
|
|
1907
|
+
If the precision is too low to determine the
|
|
1908
|
+
element an exception is raised.
|
|
1909
|
+
|
|
1910
|
+
INPUT:
|
|
1911
|
+
|
|
1912
|
+
- ``laurent_series`` -- a Laurent or Power series
|
|
1913
|
+
|
|
1914
|
+
- ``order_1`` -- a lower bound for the order at ``-1`` for all quasi
|
|
1915
|
+
parts of the form (default: 0). If ``n!=infinity`` this parameter is
|
|
1916
|
+
ignored.
|
|
1917
|
+
|
|
1918
|
+
- ``check`` -- if ``True`` (default) then the series expansion of the
|
|
1919
|
+
constructed form is compared against the given (rationalized) series.
|
|
1920
|
+
|
|
1921
|
+
- ``rationalize`` -- if ``True`` (default: ``False``) then the series
|
|
1922
|
+
is "rationalized" beforehand. Note that in non-exact or
|
|
1923
|
+
non-arithmetic cases this is experimental and extremely unreliable!
|
|
1924
|
+
|
|
1925
|
+
OUTPUT:
|
|
1926
|
+
|
|
1927
|
+
If possible: An element of ``self`` with the same initial
|
|
1928
|
+
Fourier expansion as ``laurent_series``.
|
|
1929
|
+
|
|
1930
|
+
Note: For non modular spaces it is also possible to call
|
|
1931
|
+
``self(laurent_series)`` instead. Also note that this function works
|
|
1932
|
+
much faster if a corresponding (cached) ``q_basis`` is available.
|
|
1933
|
+
|
|
1934
|
+
EXAMPLES::
|
|
1935
|
+
|
|
1936
|
+
sage: from sage.modular.modform_hecketriangle.space import QuasiWeakModularForms, ModularForms, QuasiModularForms, QuasiCuspForms
|
|
1937
|
+
sage: QF = QuasiWeakModularForms(n=8, k=10/3, ep=-1)
|
|
1938
|
+
sage: el = QF.quasi_part_gens(min_exp=-1)[4]
|
|
1939
|
+
sage: prec = QF.required_laurent_prec(min_exp=-1)
|
|
1940
|
+
sage: prec
|
|
1941
|
+
5
|
|
1942
|
+
sage: qexp = el.q_expansion(prec=prec)
|
|
1943
|
+
sage: qexp
|
|
1944
|
+
q^-1 - 19/(64*d) - 7497/(262144*d^2)*q + 15889/(8388608*d^3)*q^2 + 543834047/(1649267441664*d^4)*q^3 + 711869853/(43980465111040*d^5)*q^4 + O(q^5)
|
|
1945
|
+
sage: qexp.parent()
|
|
1946
|
+
Laurent Series Ring in q over Fraction Field of Univariate Polynomial Ring in d over Integer Ring
|
|
1947
|
+
sage: constructed_el = QF.construct_quasi_form(qexp)
|
|
1948
|
+
sage: constructed_el.parent()
|
|
1949
|
+
QuasiWeakModularForms(n=8, k=10/3, ep=-1) over Integer Ring
|
|
1950
|
+
sage: el == constructed_el
|
|
1951
|
+
True
|
|
1952
|
+
|
|
1953
|
+
If a q_basis is available the construction uses a different algorithm which we also check::
|
|
1954
|
+
|
|
1955
|
+
sage: basis = QF.q_basis(min_exp=-1)
|
|
1956
|
+
sage: QF(qexp) == constructed_el
|
|
1957
|
+
True
|
|
1958
|
+
|
|
1959
|
+
sage: MF = ModularForms(k=36)
|
|
1960
|
+
sage: el2 = MF.quasi_part_gens(min_exp=2)[1]
|
|
1961
|
+
sage: prec = MF.required_laurent_prec(min_exp=2)
|
|
1962
|
+
sage: prec
|
|
1963
|
+
4
|
|
1964
|
+
sage: qexp2 = el2.q_expansion(prec=prec + 1)
|
|
1965
|
+
sage: qexp2
|
|
1966
|
+
q^3 - 1/(24*d)*q^4 + O(q^5)
|
|
1967
|
+
sage: qexp2.parent()
|
|
1968
|
+
Power Series Ring in q over Fraction Field of Univariate Polynomial Ring in d over Integer Ring
|
|
1969
|
+
sage: constructed_el2 = MF.construct_quasi_form(qexp2)
|
|
1970
|
+
sage: constructed_el2.parent()
|
|
1971
|
+
ModularForms(n=3, k=36, ep=1) over Integer Ring
|
|
1972
|
+
sage: el2 == constructed_el2
|
|
1973
|
+
True
|
|
1974
|
+
|
|
1975
|
+
sage: QF = QuasiModularForms(k=2)
|
|
1976
|
+
sage: q = QF.get_q()
|
|
1977
|
+
sage: qexp3 = 1 + O(q)
|
|
1978
|
+
sage: QF(qexp3)
|
|
1979
|
+
1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 + O(q^5)
|
|
1980
|
+
sage: QF(qexp3) == QF.E2()
|
|
1981
|
+
True
|
|
1982
|
+
|
|
1983
|
+
sage: QF = QuasiWeakModularForms(n=infinity, k=2, ep=-1)
|
|
1984
|
+
sage: el4 = QF.f_i() + QF.f_i()^3/QF.E4()
|
|
1985
|
+
sage: prec = QF.required_laurent_prec(order_1=-1)
|
|
1986
|
+
sage: qexp4 = el4.q_expansion(prec=prec)
|
|
1987
|
+
sage: qexp4
|
|
1988
|
+
2 - 7/(4*d)*q + 195/(256*d^2)*q^2 - 903/(4096*d^3)*q^3 + 41987/(1048576*d^4)*q^4 - 181269/(33554432*d^5)*q^5 + O(q^6)
|
|
1989
|
+
sage: QF.construct_quasi_form(qexp4, check=False) == el4
|
|
1990
|
+
False
|
|
1991
|
+
sage: QF.construct_quasi_form(qexp4, order_1=-1) == el4
|
|
1992
|
+
True
|
|
1993
|
+
|
|
1994
|
+
sage: QF = QuasiCuspForms(n=8, k=22/3, ep=-1)
|
|
1995
|
+
sage: el = QF(QF.f_inf()*QF.E2())
|
|
1996
|
+
sage: qexp = el.q_expansion_fixed_d(d_num_prec=1000)
|
|
1997
|
+
sage: qexp.parent()
|
|
1998
|
+
Power Series Ring in q over Real Field with 1000 bits of precision
|
|
1999
|
+
sage: QF.construct_quasi_form(qexp, rationalize=True) == el
|
|
2000
|
+
True
|
|
2001
|
+
"""
|
|
2002
|
+
|
|
2003
|
+
base_ring = laurent_series.base_ring()
|
|
2004
|
+
if isinstance(base_ring.base(), PolynomialRing_generic):
|
|
2005
|
+
if not (self.coeff_ring().has_coerce_map_from(base_ring)):
|
|
2006
|
+
raise ValueError("The Laurent coefficients don't coerce into the coefficient ring of self!")
|
|
2007
|
+
elif rationalize:
|
|
2008
|
+
laurent_series = self.rationalize_series(laurent_series)
|
|
2009
|
+
else:
|
|
2010
|
+
raise ValueError("The Laurent coefficients are not in the proper form yet. Try rationalize_series(laurent_series) beforehand (experimental).")
|
|
2011
|
+
|
|
2012
|
+
prec = min(laurent_series.prec(), laurent_series.exponents()[-1] + 1)
|
|
2013
|
+
|
|
2014
|
+
min_exp1 = laurent_series.exponents()[0]
|
|
2015
|
+
(min_exp, order_1) = self._canonical_min_exp(min_exp1, order_1)
|
|
2016
|
+
|
|
2017
|
+
if (min_exp != min_exp1):
|
|
2018
|
+
raise ValueError("Due to the behavior at infinity the given Laurent series cannot possibly be an element of {}".format(self))
|
|
2019
|
+
|
|
2020
|
+
# if a q_basis is available we can construct the form much faster
|
|
2021
|
+
if (self.q_basis.is_in_cache(min_exp=min_exp, order_1=order_1)):
|
|
2022
|
+
basis = self.q_basis(min_exp=min_exp, order_1=order_1)
|
|
2023
|
+
size = len(basis)
|
|
2024
|
+
|
|
2025
|
+
if (prec < min_exp + size):
|
|
2026
|
+
raise ValueError("Insufficient precision: {} < {}!".format(laurent_series.prec(), min_exp + size))
|
|
2027
|
+
|
|
2028
|
+
b = vector(self.coeff_ring(), [laurent_series[m] for m in range(min_exp, min_exp + len(basis))])
|
|
2029
|
+
|
|
2030
|
+
el = self(sum([b[k]*basis[k] for k in range(len(basis))]))
|
|
2031
|
+
else:
|
|
2032
|
+
A = self._quasi_form_matrix(min_exp=min_exp, order_1=order_1)
|
|
2033
|
+
row_size = A.dimensions()[0]
|
|
2034
|
+
|
|
2035
|
+
if (prec < min_exp + row_size):
|
|
2036
|
+
raise ValueError("Insufficient precision: {} < {}!".format(laurent_series.prec(), min_exp + row_size))
|
|
2037
|
+
|
|
2038
|
+
b = vector(self.coeff_ring(), [laurent_series[m] for m in range(min_exp, min_exp + row_size)])
|
|
2039
|
+
try:
|
|
2040
|
+
coord_vector = A.solve_right(b)
|
|
2041
|
+
except ValueError:
|
|
2042
|
+
raise ValueError("The Laurent series {} does not correspond to a (quasi) form of {}".format(laurent_series, self.reduce_type(["quasi", "weak"])))
|
|
2043
|
+
|
|
2044
|
+
order_inf = self._l1 - order_1
|
|
2045
|
+
|
|
2046
|
+
# We have to add + 1 to get a correct upper bound in all cases
|
|
2047
|
+
# since corresponding weak space might have a higher l1 (+1) than
|
|
2048
|
+
# ``self``, even if the weight is smaller
|
|
2049
|
+
max_exp = order_inf + 1
|
|
2050
|
+
basis = self.quasi_part_gens(min_exp=min_exp, max_exp=max_exp, order_1=order_1)
|
|
2051
|
+
|
|
2052
|
+
el = self(sum([coord_vector[k]*basis[k] for k in range(len(coord_vector))]))
|
|
2053
|
+
|
|
2054
|
+
if (check):
|
|
2055
|
+
if (el.q_expansion(prec=prec) != laurent_series):
|
|
2056
|
+
raise ValueError("The Laurent series {} does not correspond to a form of {}".format(laurent_series, self.reduce_type(["quasi", "weak"])))
|
|
2057
|
+
|
|
2058
|
+
return el
|
|
2059
|
+
|
|
2060
|
+
@cached_method
|
|
2061
|
+
def q_basis(self, m=None, min_exp=0, order_1=ZZ.zero()):
|
|
2062
|
+
r"""
|
|
2063
|
+
Try to return a (basis) element of ``self`` with a Laurent series of the form
|
|
2064
|
+
``q^m + O(q^N)``, where ``N=self.required_laurent_prec(min_exp)``.
|
|
2065
|
+
|
|
2066
|
+
If ``m==None`` the whole basis (with varying ``m``'s) is returned if it exists.
|
|
2067
|
+
|
|
2068
|
+
INPUT:
|
|
2069
|
+
|
|
2070
|
+
- ``m`` -- integer, indicating the desired initial Laurent exponent
|
|
2071
|
+
of the element. If ``m==None`` (default) then the whole basis is
|
|
2072
|
+
returned.
|
|
2073
|
+
|
|
2074
|
+
- ``min_exp`` -- integer (default: 0); the minimal Laurent exponent
|
|
2075
|
+
(for each quasi part) of the subspace of ``self`` which should be
|
|
2076
|
+
considered
|
|
2077
|
+
|
|
2078
|
+
- ``order_1`` -- a lower bound for the order at ``-1`` of all quasi
|
|
2079
|
+
parts of the subspace (default: 0). If ``n!=infinity`` this parameter
|
|
2080
|
+
is ignored.
|
|
2081
|
+
|
|
2082
|
+
OUTPUT:
|
|
2083
|
+
|
|
2084
|
+
The corresponding basis (if ``m==None``) resp. the corresponding basis vector (if ``m!=None``).
|
|
2085
|
+
If the basis resp. element doesn't exist an exception is raised.
|
|
2086
|
+
|
|
2087
|
+
EXAMPLES::
|
|
2088
|
+
|
|
2089
|
+
sage: from sage.modular.modform_hecketriangle.space import QuasiWeakModularForms, ModularForms, QuasiModularForms
|
|
2090
|
+
sage: QF = QuasiWeakModularForms(n=8, k=10/3, ep=-1)
|
|
2091
|
+
sage: QF.default_prec(QF.required_laurent_prec(min_exp=-1))
|
|
2092
|
+
sage: q_basis = QF.q_basis(min_exp=-1)
|
|
2093
|
+
sage: q_basis
|
|
2094
|
+
[q^-1 + O(q^5), 1 + O(q^5), q + O(q^5), q^2 + O(q^5), q^3 + O(q^5), q^4 + O(q^5)]
|
|
2095
|
+
sage: QF.q_basis(m=-1, min_exp=-1)
|
|
2096
|
+
q^-1 + O(q^5)
|
|
2097
|
+
|
|
2098
|
+
sage: MF = ModularForms(k=36)
|
|
2099
|
+
sage: MF.q_basis() == list(MF.gens())
|
|
2100
|
+
True
|
|
2101
|
+
|
|
2102
|
+
sage: QF = QuasiModularForms(k=6)
|
|
2103
|
+
sage: QF.required_laurent_prec()
|
|
2104
|
+
3
|
|
2105
|
+
sage: QF.q_basis()
|
|
2106
|
+
[1 - 20160*q^3 - 158760*q^4 + O(q^5), q - 60*q^3 - 248*q^4 + O(q^5), q^2 + 8*q^3 + 30*q^4 + O(q^5)]
|
|
2107
|
+
|
|
2108
|
+
sage: QF = QuasiWeakModularForms(n=infinity, k=-2, ep=-1)
|
|
2109
|
+
sage: QF.q_basis(order_1=-1)
|
|
2110
|
+
[1 - 168*q^2 + 2304*q^3 - 19320*q^4 + O(q^5),
|
|
2111
|
+
q - 18*q^2 + 180*q^3 - 1316*q^4 + O(q^5)]
|
|
2112
|
+
"""
|
|
2113
|
+
if (not self.is_weakly_holomorphic()):
|
|
2114
|
+
from warnings import warn
|
|
2115
|
+
warn("This function only determines elements / a basis of (quasi) weakly modular forms!")
|
|
2116
|
+
|
|
2117
|
+
(min_exp, order_1) = self._canonical_min_exp(min_exp, order_1)
|
|
2118
|
+
order_inf = self._l1 - order_1
|
|
2119
|
+
|
|
2120
|
+
if (m is None):
|
|
2121
|
+
A = self._quasi_form_matrix(min_exp=min_exp, order_1=order_1)
|
|
2122
|
+
|
|
2123
|
+
# If A is square it should automatically be invertible (by the previous procedures)
|
|
2124
|
+
if (A.is_square()):
|
|
2125
|
+
B = A.inverse()
|
|
2126
|
+
|
|
2127
|
+
max_exp = order_inf + 1
|
|
2128
|
+
basis = self.quasi_part_gens(min_exp=min_exp, max_exp=max_exp, order_1=order_1)
|
|
2129
|
+
|
|
2130
|
+
column_len = A.dimensions()[1]
|
|
2131
|
+
q_basis = []
|
|
2132
|
+
for k in range(column_len):
|
|
2133
|
+
el = self(sum([B[l][k] * basis[l] for l in range(column_len)]))
|
|
2134
|
+
q_basis += [el]
|
|
2135
|
+
|
|
2136
|
+
return q_basis
|
|
2137
|
+
else:
|
|
2138
|
+
raise ValueError("Unfortunately a q_basis doesn't exist in this case (this is rare/interesting, please report)")
|
|
2139
|
+
else:
|
|
2140
|
+
if (m < min_exp):
|
|
2141
|
+
raise ValueError("Index out of range: m={} < {}=min_exp".format(m, min_exp))
|
|
2142
|
+
|
|
2143
|
+
# If the whole basis is available, then use it
|
|
2144
|
+
if (self.q_basis.is_in_cache(min_exp=min_exp, order_1=order_1)):
|
|
2145
|
+
q_basis = self.q_basis(min_exp=min_exp, order_1=order_1)
|
|
2146
|
+
|
|
2147
|
+
column_len = len(q_basis)
|
|
2148
|
+
if (m >= column_len + min_exp):
|
|
2149
|
+
raise ValueError("Index out of range: m={} >= {}=dimension + min_exp".format(m, column_len + min_exp))
|
|
2150
|
+
|
|
2151
|
+
return q_basis[m - min_exp]
|
|
2152
|
+
|
|
2153
|
+
row_len = self.required_laurent_prec(min_exp=min_exp, order_1=order_1) - min_exp
|
|
2154
|
+
if (m >= row_len + min_exp):
|
|
2155
|
+
raise ValueError("Index out of range: m={} >= {}=required_precision + min_exp".format(m, row_len + min_exp))
|
|
2156
|
+
|
|
2157
|
+
A = self._quasi_form_matrix(min_exp=min_exp, order_1=order_1)
|
|
2158
|
+
b = vector(self.coeff_ring(), row_len)
|
|
2159
|
+
b[m - min_exp] = 1
|
|
2160
|
+
try:
|
|
2161
|
+
coord_vector = A.solve_right(b)
|
|
2162
|
+
except ValueError:
|
|
2163
|
+
raise ValueError("Unfortunately the q_basis vector (m={}, min_exp={}) doesn't exist in this case (this is rare/interesting, please report)".format(m, min_exp))
|
|
2164
|
+
|
|
2165
|
+
max_exp = order_inf + 1
|
|
2166
|
+
basis = self.quasi_part_gens(min_exp=min_exp, max_exp=max_exp, order_1=order_1)
|
|
2167
|
+
|
|
2168
|
+
column_len = A.dimensions()[1]
|
|
2169
|
+
return self(sum([coord_vector[l] * basis[l]
|
|
2170
|
+
for l in range(column_len)]))
|
|
2171
|
+
|
|
2172
|
+
def rationalize_series(self, laurent_series, coeff_bound=1e-10, denom_factor=ZZ(1)):
|
|
2173
|
+
r"""
|
|
2174
|
+
Try to return a Laurent series with coefficients in ``self.coeff_ring()``
|
|
2175
|
+
that matches the given Laurent series.
|
|
2176
|
+
|
|
2177
|
+
We give our best but there is absolutely no guarantee that it will work!
|
|
2178
|
+
|
|
2179
|
+
INPUT:
|
|
2180
|
+
|
|
2181
|
+
- ``laurent_series`` -- a Laurent series. If the Laurent coefficients
|
|
2182
|
+
already coerce into ``self.coeff_ring()`` with a formal parameter
|
|
2183
|
+
then the Laurent series is returned as is.
|
|
2184
|
+
|
|
2185
|
+
Otherwise it is assumed that the series is normalized in the sense
|
|
2186
|
+
that the first non-trivial coefficient is a power of ``d`` (e.g.
|
|
2187
|
+
``1``).
|
|
2188
|
+
|
|
2189
|
+
- ``coeff_bound`` -- either ``None`` resp. ``0`` or a positive real
|
|
2190
|
+
number (default: ``1e-10``). If specified ``coeff_bound`` gives a
|
|
2191
|
+
lower bound for the size of the initial Laurent coefficients. If a
|
|
2192
|
+
coefficient is smaller it is assumed to be zero.
|
|
2193
|
+
|
|
2194
|
+
For calculations with very small coefficients (less than ``1e-10``)
|
|
2195
|
+
``coeff_bound`` should be set to something even smaller or just ``0``.
|
|
2196
|
+
|
|
2197
|
+
Non-exact calculations often produce nonzero coefficients which are
|
|
2198
|
+
supposed to be zero. In those cases this parameter helps a lot.
|
|
2199
|
+
|
|
2200
|
+
- ``denom_factor`` -- integer (default: 1) whose factor might occur in
|
|
2201
|
+
the denominator of the given Laurent coefficients (in addition to
|
|
2202
|
+
naturally occurring factors).
|
|
2203
|
+
|
|
2204
|
+
OUTPUT:
|
|
2205
|
+
|
|
2206
|
+
A Laurent series over ``self.coeff_ring()`` corresponding to the given
|
|
2207
|
+
Laurent series.
|
|
2208
|
+
|
|
2209
|
+
EXAMPLES::
|
|
2210
|
+
|
|
2211
|
+
sage: from sage.modular.modform_hecketriangle.space import WeakModularForms, ModularForms, QuasiCuspForms
|
|
2212
|
+
sage: WF = WeakModularForms(n=14)
|
|
2213
|
+
sage: qexp = WF.J_inv().q_expansion_fixed_d(d_num_prec=1000)
|
|
2214
|
+
sage: qexp.parent()
|
|
2215
|
+
Laurent Series Ring in q over Real Field with 1000 bits of precision
|
|
2216
|
+
sage: qexp_int = WF.rationalize_series(qexp)
|
|
2217
|
+
sage: qexp_int.add_bigoh(3)
|
|
2218
|
+
d*q^-1 + 37/98 + 2587/(38416*d)*q + 899/(117649*d^2)*q^2 + O(q^3)
|
|
2219
|
+
sage: qexp_int == WF.J_inv().q_expansion()
|
|
2220
|
+
True
|
|
2221
|
+
sage: WF.rationalize_series(qexp_int) == qexp_int
|
|
2222
|
+
True
|
|
2223
|
+
sage: WF(qexp_int) == WF.J_inv()
|
|
2224
|
+
True
|
|
2225
|
+
|
|
2226
|
+
sage: WF.rationalize_series(qexp.parent()(1))
|
|
2227
|
+
1
|
|
2228
|
+
sage: WF.rationalize_series(qexp_int.parent()(1)).parent()
|
|
2229
|
+
Laurent Series Ring in q over Fraction Field of Univariate Polynomial Ring in d over Integer Ring
|
|
2230
|
+
|
|
2231
|
+
sage: MF = ModularForms(n=infinity, k=4)
|
|
2232
|
+
sage: qexp = MF.E4().q_expansion_fixed_d()
|
|
2233
|
+
sage: qexp.parent()
|
|
2234
|
+
Power Series Ring in q over Rational Field
|
|
2235
|
+
sage: qexp_int = MF.rationalize_series(qexp)
|
|
2236
|
+
sage: qexp_int.parent()
|
|
2237
|
+
Power Series Ring in q over Fraction Field of Univariate Polynomial Ring in d over Integer Ring
|
|
2238
|
+
sage: qexp_int == MF.E4().q_expansion()
|
|
2239
|
+
True
|
|
2240
|
+
sage: MF.rationalize_series(qexp_int) == qexp_int
|
|
2241
|
+
True
|
|
2242
|
+
sage: MF(qexp_int) == MF.E4()
|
|
2243
|
+
True
|
|
2244
|
+
|
|
2245
|
+
sage: QF = QuasiCuspForms(n=8, k=22/3, ep=-1)
|
|
2246
|
+
sage: el = QF(QF.f_inf()*QF.E2())
|
|
2247
|
+
sage: qexp = el.q_expansion_fixed_d(d_num_prec=1000)
|
|
2248
|
+
sage: qexp.parent()
|
|
2249
|
+
Power Series Ring in q over Real Field with 1000 bits of precision
|
|
2250
|
+
sage: qexp_int = QF.rationalize_series(qexp)
|
|
2251
|
+
sage: qexp_int.parent()
|
|
2252
|
+
Power Series Ring in q over Fraction Field of Univariate Polynomial Ring in d over Integer Ring
|
|
2253
|
+
sage: qexp_int == el.q_expansion()
|
|
2254
|
+
True
|
|
2255
|
+
sage: QF.rationalize_series(qexp_int) == qexp_int
|
|
2256
|
+
True
|
|
2257
|
+
sage: QF(qexp_int) == el
|
|
2258
|
+
True
|
|
2259
|
+
"""
|
|
2260
|
+
|
|
2261
|
+
from sage.misc.misc_c import prod
|
|
2262
|
+
from sage.rings.fast_arith import prime_range
|
|
2263
|
+
from warnings import warn
|
|
2264
|
+
|
|
2265
|
+
denom_factor = ZZ(denom_factor)
|
|
2266
|
+
base_ring = laurent_series.base_ring()
|
|
2267
|
+
series_prec = laurent_series.prec()
|
|
2268
|
+
|
|
2269
|
+
# If the coefficients already coerce to our coefficient ring
|
|
2270
|
+
# and are in polynomial form we simply return the Laurent series
|
|
2271
|
+
if (isinstance(base_ring.base(), PolynomialRing_generic)):
|
|
2272
|
+
if (self.coeff_ring().has_coerce_map_from(base_ring)):
|
|
2273
|
+
return laurent_series
|
|
2274
|
+
else:
|
|
2275
|
+
raise ValueError("The Laurent coefficients don't coerce into the coefficient ring of self!")
|
|
2276
|
+
# Else the case that the Laurent series is exact but the group is non-arithmetic
|
|
2277
|
+
# shouldn't occur (except for trivial cases)
|
|
2278
|
+
elif (base_ring.is_exact() and not self.group().is_arithmetic()):
|
|
2279
|
+
prec = self.default_num_prec()
|
|
2280
|
+
dvalue = self.group().dvalue().n(prec)
|
|
2281
|
+
# For arithmetic groups the coefficients are exact though (so is d)
|
|
2282
|
+
elif (base_ring.is_exact()):
|
|
2283
|
+
prec = self.default_num_prec()
|
|
2284
|
+
dvalue = self.group().dvalue()
|
|
2285
|
+
else:
|
|
2286
|
+
prec = laurent_series.base_ring().prec()
|
|
2287
|
+
dvalue = self.group().dvalue().n(prec)
|
|
2288
|
+
|
|
2289
|
+
# This messes up doctests! :-(
|
|
2290
|
+
warn("Using an experimental rationalization of coefficients, please check the result for correctness!")
|
|
2291
|
+
|
|
2292
|
+
d = self.get_d()
|
|
2293
|
+
q = self.get_q()
|
|
2294
|
+
|
|
2295
|
+
if (not base_ring.is_exact() and coeff_bound):
|
|
2296
|
+
coeff_bound = base_ring(coeff_bound)
|
|
2297
|
+
num_q = laurent_series.parent().gen()
|
|
2298
|
+
laurent_series = sum([laurent_series[i]*num_q**i for i in range(laurent_series.exponents()[0], laurent_series.exponents()[-1]+1) if laurent_series[i].abs() > coeff_bound]).add_bigoh(series_prec)
|
|
2299
|
+
|
|
2300
|
+
first_exp = laurent_series.exponents()[0]
|
|
2301
|
+
first_coeff = laurent_series[first_exp]
|
|
2302
|
+
d_power = (first_coeff.abs().n(prec).log()/dvalue.n(prec).log()).round()
|
|
2303
|
+
|
|
2304
|
+
if (first_coeff < 0):
|
|
2305
|
+
return -self.rationalize_series(-laurent_series, coeff_bound=coeff_bound)
|
|
2306
|
+
elif (first_exp + d_power != 0):
|
|
2307
|
+
cor_factor = dvalue**(-(first_exp + d_power))
|
|
2308
|
+
return d**(first_exp + d_power) * self.rationalize_series(cor_factor * laurent_series, coeff_bound=coeff_bound)
|
|
2309
|
+
else:
|
|
2310
|
+
if (base_ring.is_exact() and self.group().is_arithmetic()):
|
|
2311
|
+
tolerance = 0
|
|
2312
|
+
else:
|
|
2313
|
+
tolerance = 10*ZZ(1).n(prec).ulp()
|
|
2314
|
+
|
|
2315
|
+
if (first_coeff * dvalue**first_exp - ZZ(1)) > tolerance:
|
|
2316
|
+
raise ValueError("The Laurent series is not normalized correctly!")
|
|
2317
|
+
|
|
2318
|
+
# TODO: This is not a good enough estimate, see e.g. E12
|
|
2319
|
+
# (however for exact base rings + arithmetic groups we don't need it)
|
|
2320
|
+
def denominator_estimate(m):
|
|
2321
|
+
cor_exp = max(-first_exp, 0)
|
|
2322
|
+
m += cor_exp
|
|
2323
|
+
|
|
2324
|
+
if self.group().is_arithmetic():
|
|
2325
|
+
return ZZ(1/dvalue)**m
|
|
2326
|
+
|
|
2327
|
+
hecke_n = self.hecke_n()
|
|
2328
|
+
bad_factors = [fac for fac in Integer(m).factorial().factor() if (fac[0] % hecke_n) not in [1, hecke_n-1] and fac[0] > 2]
|
|
2329
|
+
bad_factorial = prod([fac[0]**fac[1] for fac in bad_factors])
|
|
2330
|
+
|
|
2331
|
+
return ZZ(2**(6*m) * hecke_n**(2*m) * prod([ p**m for p in prime_range(m+1) if hecke_n % p == 0 and p > 2 ]) * bad_factorial)**(cor_exp + 1)
|
|
2332
|
+
|
|
2333
|
+
def rationalize_coefficient(coeff, m):
|
|
2334
|
+
# TODO: figure out a correct bound for the required precision
|
|
2335
|
+
if (not self.group().is_arithmetic() and denominator_estimate(m).log(2).n().ceil() > prec):
|
|
2336
|
+
warn("The precision from coefficient m={} on is too low!".format(m))
|
|
2337
|
+
|
|
2338
|
+
rational_coeff = coeff * dvalue**m
|
|
2339
|
+
|
|
2340
|
+
if (base_ring.is_exact() and self.group().is_arithmetic() and rational_coeff in QQ):
|
|
2341
|
+
rational_coeff = QQ(rational_coeff)
|
|
2342
|
+
else:
|
|
2343
|
+
int_estimate = denominator_estimate(m) * denom_factor * rational_coeff
|
|
2344
|
+
rational_coeff = int_estimate.round() / denominator_estimate(m) / denom_factor
|
|
2345
|
+
|
|
2346
|
+
return rational_coeff / d**m
|
|
2347
|
+
|
|
2348
|
+
return sum([rationalize_coefficient(laurent_series[m], m) * q**m
|
|
2349
|
+
for m in range(first_exp, laurent_series.exponents()[-1] + 1)]).add_bigoh(series_prec)
|
|
2350
|
+
|
|
2351
|
+
# DEFAULT METHODS (should be overwritten in concrete classes)
|
|
2352
|
+
|
|
2353
|
+
def _an_element_(self):
|
|
2354
|
+
r"""
|
|
2355
|
+
Return an element of ``self``.
|
|
2356
|
+
|
|
2357
|
+
EXAMPLES::
|
|
2358
|
+
|
|
2359
|
+
sage: from sage.modular.modform_hecketriangle.space import QuasiMeromorphicModularForms
|
|
2360
|
+
sage: el = QuasiMeromorphicModularForms(k=2, ep=-1).an_element()
|
|
2361
|
+
sage: el.parent()
|
|
2362
|
+
QuasiMeromorphicModularForms(n=3, k=2, ep=-1) over Integer Ring
|
|
2363
|
+
sage: el.is_zero()
|
|
2364
|
+
True
|
|
2365
|
+
sage: el
|
|
2366
|
+
O(q^5)
|
|
2367
|
+
"""
|
|
2368
|
+
# this seems ok, so might as well leave it as is for everything
|
|
2369
|
+
return self(ZZ.zero())
|
|
2370
|
+
# return self.F_simple()
|
|
2371
|
+
|
|
2372
|
+
@cached_method
|
|
2373
|
+
def dimension(self):
|
|
2374
|
+
r"""
|
|
2375
|
+
Return the dimension of ``self``.
|
|
2376
|
+
|
|
2377
|
+
.. NOTE::
|
|
2378
|
+
|
|
2379
|
+
This method should be overloaded by subclasses.
|
|
2380
|
+
|
|
2381
|
+
EXAMPLES::
|
|
2382
|
+
|
|
2383
|
+
sage: from sage.modular.modform_hecketriangle.space import QuasiMeromorphicModularForms
|
|
2384
|
+
sage: QuasiMeromorphicModularForms(k=2, ep=-1).dimension()
|
|
2385
|
+
+Infinity
|
|
2386
|
+
"""
|
|
2387
|
+
|
|
2388
|
+
return infinity
|
|
2389
|
+
|
|
2390
|
+
def rank(self):
|
|
2391
|
+
r"""
|
|
2392
|
+
Return the rank of ``self``.
|
|
2393
|
+
|
|
2394
|
+
EXAMPLES::
|
|
2395
|
+
|
|
2396
|
+
sage: from sage.modular.modform_hecketriangle.space import ModularForms
|
|
2397
|
+
sage: MF = ModularForms(n=4, k=24, ep=-1)
|
|
2398
|
+
sage: MF.rank()
|
|
2399
|
+
3
|
|
2400
|
+
sage: MF.subspace([MF.gen(0), MF.gen(2)]).rank()
|
|
2401
|
+
2
|
|
2402
|
+
"""
|
|
2403
|
+
|
|
2404
|
+
return self.dimension()
|
|
2405
|
+
|
|
2406
|
+
def degree(self):
|
|
2407
|
+
r"""
|
|
2408
|
+
Return the degree of ``self``.
|
|
2409
|
+
|
|
2410
|
+
EXAMPLES::
|
|
2411
|
+
|
|
2412
|
+
sage: from sage.modular.modform_hecketriangle.space import ModularForms
|
|
2413
|
+
sage: MF = ModularForms(n=4, k=24, ep=-1)
|
|
2414
|
+
sage: MF.degree()
|
|
2415
|
+
3
|
|
2416
|
+
sage: MF.subspace([MF.gen(0), MF.gen(2)]).degree() # defined in subspace.py
|
|
2417
|
+
3
|
|
2418
|
+
"""
|
|
2419
|
+
|
|
2420
|
+
return self.dimension()
|
|
2421
|
+
|
|
2422
|
+
def coordinate_vector(self, v):
|
|
2423
|
+
r"""
|
|
2424
|
+
This method should be overloaded by subclasses.
|
|
2425
|
+
|
|
2426
|
+
Return the coordinate vector of the element ``v``
|
|
2427
|
+
with respect to ``self.gens()``.
|
|
2428
|
+
|
|
2429
|
+
NOTE:
|
|
2430
|
+
|
|
2431
|
+
Elements use this method (from their parent)
|
|
2432
|
+
to calculate their coordinates.
|
|
2433
|
+
|
|
2434
|
+
INPUT:
|
|
2435
|
+
|
|
2436
|
+
- ``v`` -- an element of ``self``
|
|
2437
|
+
|
|
2438
|
+
EXAMPLES::
|
|
2439
|
+
|
|
2440
|
+
sage: from sage.modular.modform_hecketriangle.space import ModularForms
|
|
2441
|
+
sage: MF = ModularForms(n=4, k=24, ep=-1)
|
|
2442
|
+
sage: MF.coordinate_vector(MF.gen(0)).parent() # defined in space.py
|
|
2443
|
+
Vector space of dimension 3 over Fraction Field of Univariate Polynomial Ring in d over Integer Ring
|
|
2444
|
+
sage: MF.coordinate_vector(MF.gen(0)) # defined in space.py
|
|
2445
|
+
(1, 0, 0)
|
|
2446
|
+
sage: subspace = MF.subspace([MF.gen(0), MF.gen(2)])
|
|
2447
|
+
sage: subspace.coordinate_vector(subspace.gen(0)).parent() # defined in subspace.py
|
|
2448
|
+
Vector space of dimension 2 over Fraction Field of Univariate Polynomial Ring in d over Integer Ring
|
|
2449
|
+
sage: subspace.coordinate_vector(subspace.gen(0)) # defined in subspace.py
|
|
2450
|
+
(1, 0)
|
|
2451
|
+
"""
|
|
2452
|
+
|
|
2453
|
+
raise NotImplementedError("No coordinate vector is implemented yet for {}!".format(self))
|
|
2454
|
+
|
|
2455
|
+
@cached_method
|
|
2456
|
+
def ambient_coordinate_vector(self, v):
|
|
2457
|
+
r"""
|
|
2458
|
+
Return the coordinate vector of the element ``v``
|
|
2459
|
+
in ``self.module()`` with respect to the basis
|
|
2460
|
+
from ``self.ambient_space``.
|
|
2461
|
+
|
|
2462
|
+
NOTE:
|
|
2463
|
+
|
|
2464
|
+
Elements use this method (from their parent)
|
|
2465
|
+
to calculate their coordinates.
|
|
2466
|
+
|
|
2467
|
+
INPUT:
|
|
2468
|
+
|
|
2469
|
+
- ``v`` -- an element of ``self``
|
|
2470
|
+
|
|
2471
|
+
EXAMPLES::
|
|
2472
|
+
|
|
2473
|
+
sage: from sage.modular.modform_hecketriangle.space import ModularForms
|
|
2474
|
+
sage: MF = ModularForms(n=4, k=24, ep=-1)
|
|
2475
|
+
sage: MF.ambient_coordinate_vector(MF.gen(0)).parent()
|
|
2476
|
+
Vector space of dimension 3 over Fraction Field of Univariate Polynomial Ring in d over Integer Ring
|
|
2477
|
+
sage: MF.ambient_coordinate_vector(MF.gen(0))
|
|
2478
|
+
(1, 0, 0)
|
|
2479
|
+
sage: subspace = MF.subspace([MF.gen(0), MF.gen(2)])
|
|
2480
|
+
sage: subspace.ambient_coordinate_vector(subspace.gen(0)).parent()
|
|
2481
|
+
Vector space of degree 3 and dimension 2 over Fraction Field of Univariate Polynomial Ring in d over Integer Ring
|
|
2482
|
+
Basis matrix:
|
|
2483
|
+
[1 0 0]
|
|
2484
|
+
[0 0 1]
|
|
2485
|
+
sage: subspace.ambient_coordinate_vector(subspace.gen(0))
|
|
2486
|
+
(1, 0, 0)
|
|
2487
|
+
"""
|
|
2488
|
+
|
|
2489
|
+
return self.module()(self.ambient_space().coordinate_vector(v))
|
|
2490
|
+
|
|
2491
|
+
def gens(self) -> tuple:
|
|
2492
|
+
r"""
|
|
2493
|
+
This method should be overloaded by subclasses.
|
|
2494
|
+
|
|
2495
|
+
Return a basis of ``self`` as a tuple.
|
|
2496
|
+
|
|
2497
|
+
Note that the coordinate vector of elements of ``self``
|
|
2498
|
+
are with respect to this basis.
|
|
2499
|
+
|
|
2500
|
+
EXAMPLES::
|
|
2501
|
+
|
|
2502
|
+
sage: from sage.modular.modform_hecketriangle.space import ModularForms
|
|
2503
|
+
sage: ModularForms(k=12).gens() # defined in space.py
|
|
2504
|
+
(1 + 196560*q^2 + 16773120*q^3 + 398034000*q^4 + O(q^5),
|
|
2505
|
+
q - 24*q^2 + 252*q^3 - 1472*q^4 + O(q^5))
|
|
2506
|
+
"""
|
|
2507
|
+
raise NotImplementedError(f"No generators are implemented yet for {self}!")
|
|
2508
|
+
|
|
2509
|
+
def gen(self, k=0):
|
|
2510
|
+
r"""
|
|
2511
|
+
Return the ``k``-th basis element of ``self``
|
|
2512
|
+
if possible (default: ``k=0``).
|
|
2513
|
+
|
|
2514
|
+
EXAMPLES::
|
|
2515
|
+
|
|
2516
|
+
sage: from sage.modular.modform_hecketriangle.space import ModularForms
|
|
2517
|
+
sage: ModularForms(k=12).gen(1).parent()
|
|
2518
|
+
ModularForms(n=3, k=12, ep=1) over Integer Ring
|
|
2519
|
+
sage: ModularForms(k=12).gen(1)
|
|
2520
|
+
q - 24*q^2 + 252*q^3 - 1472*q^4 + O(q^5)
|
|
2521
|
+
"""
|
|
2522
|
+
|
|
2523
|
+
k = ZZ(k)
|
|
2524
|
+
if k >= 0 and k < self.dimension():
|
|
2525
|
+
return self.gens()[k]
|
|
2526
|
+
else:
|
|
2527
|
+
raise ValueError("Invalid index: k={} does not satisfy 0 <= k <= {}!".format(k, self.dimension()))
|