passagemath-schemes 10.6.40__cp314-cp314-macosx_13_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of passagemath-schemes might be problematic. Click here for more details.
- passagemath_schemes/.dylibs/libflint.22.0.dylib +0 -0
- passagemath_schemes/.dylibs/libgmp.10.dylib +0 -0
- passagemath_schemes/.dylibs/libgmpxx.4.dylib +0 -0
- passagemath_schemes/.dylibs/libmpfr.6.dylib +0 -0
- passagemath_schemes/__init__.py +3 -0
- passagemath_schemes-10.6.40.dist-info/METADATA +204 -0
- passagemath_schemes-10.6.40.dist-info/METADATA.bak +205 -0
- passagemath_schemes-10.6.40.dist-info/RECORD +314 -0
- passagemath_schemes-10.6.40.dist-info/WHEEL +6 -0
- passagemath_schemes-10.6.40.dist-info/top_level.txt +3 -0
- sage/all__sagemath_schemes.py +23 -0
- sage/databases/all__sagemath_schemes.py +7 -0
- sage/databases/cremona.py +1723 -0
- sage/dynamics/all__sagemath_schemes.py +2 -0
- sage/dynamics/arithmetic_dynamics/affine_ds.py +1083 -0
- sage/dynamics/arithmetic_dynamics/all.py +14 -0
- sage/dynamics/arithmetic_dynamics/berkovich_ds.py +1101 -0
- sage/dynamics/arithmetic_dynamics/dynamical_semigroup.py +1543 -0
- sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py +2426 -0
- sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py +1169 -0
- sage/dynamics/arithmetic_dynamics/generic_ds.py +663 -0
- sage/dynamics/arithmetic_dynamics/product_projective_ds.py +339 -0
- sage/dynamics/arithmetic_dynamics/projective_ds.py +9558 -0
- sage/dynamics/arithmetic_dynamics/projective_ds_helper.cpython-314-darwin.so +0 -0
- sage/dynamics/arithmetic_dynamics/projective_ds_helper.pyx +301 -0
- sage/dynamics/arithmetic_dynamics/wehlerK3.py +2576 -0
- sage/lfunctions/all.py +18 -0
- sage/lfunctions/dokchitser.py +745 -0
- sage/lfunctions/pari.py +818 -0
- sage/lfunctions/zero_sums.cpython-314-darwin.so +0 -0
- sage/lfunctions/zero_sums.pyx +1847 -0
- sage/modular/abvar/abvar.py +5135 -0
- sage/modular/abvar/abvar_ambient_jacobian.py +413 -0
- sage/modular/abvar/abvar_newform.py +244 -0
- sage/modular/abvar/all.py +8 -0
- sage/modular/abvar/constructor.py +186 -0
- sage/modular/abvar/cuspidal_subgroup.py +371 -0
- sage/modular/abvar/finite_subgroup.py +896 -0
- sage/modular/abvar/homology.py +720 -0
- sage/modular/abvar/homspace.py +998 -0
- sage/modular/abvar/lseries.py +415 -0
- sage/modular/abvar/morphism.py +935 -0
- sage/modular/abvar/torsion_point.py +274 -0
- sage/modular/abvar/torsion_subgroup.py +740 -0
- sage/modular/all.py +43 -0
- sage/modular/arithgroup/all.py +20 -0
- sage/modular/arithgroup/arithgroup_element.cpython-314-darwin.so +0 -0
- sage/modular/arithgroup/arithgroup_element.pyx +474 -0
- sage/modular/arithgroup/arithgroup_generic.py +1402 -0
- sage/modular/arithgroup/arithgroup_perm.py +2692 -0
- sage/modular/arithgroup/congroup.cpython-314-darwin.so +0 -0
- sage/modular/arithgroup/congroup.pyx +334 -0
- sage/modular/arithgroup/congroup_gamma.py +363 -0
- sage/modular/arithgroup/congroup_gamma0.py +692 -0
- sage/modular/arithgroup/congroup_gamma1.py +653 -0
- sage/modular/arithgroup/congroup_gammaH.py +1469 -0
- sage/modular/arithgroup/congroup_generic.py +628 -0
- sage/modular/arithgroup/congroup_sl2z.py +267 -0
- sage/modular/arithgroup/farey_symbol.cpython-314-darwin.so +0 -0
- sage/modular/arithgroup/farey_symbol.pyx +1066 -0
- sage/modular/arithgroup/tests.py +418 -0
- sage/modular/btquotients/all.py +4 -0
- sage/modular/btquotients/btquotient.py +3753 -0
- sage/modular/btquotients/pautomorphicform.py +2570 -0
- sage/modular/buzzard.py +100 -0
- sage/modular/congroup.py +29 -0
- sage/modular/congroup_element.py +13 -0
- sage/modular/cusps.py +1109 -0
- sage/modular/cusps_nf.py +1270 -0
- sage/modular/dims.py +569 -0
- sage/modular/dirichlet.py +3310 -0
- sage/modular/drinfeld_modform/all.py +2 -0
- sage/modular/drinfeld_modform/element.py +446 -0
- sage/modular/drinfeld_modform/ring.py +773 -0
- sage/modular/drinfeld_modform/tutorial.py +236 -0
- sage/modular/etaproducts.py +1065 -0
- sage/modular/hecke/algebra.py +746 -0
- sage/modular/hecke/all.py +20 -0
- sage/modular/hecke/ambient_module.py +1019 -0
- sage/modular/hecke/degenmap.py +119 -0
- sage/modular/hecke/element.py +325 -0
- sage/modular/hecke/hecke_operator.py +780 -0
- sage/modular/hecke/homspace.py +206 -0
- sage/modular/hecke/module.py +1767 -0
- sage/modular/hecke/morphism.py +174 -0
- sage/modular/hecke/submodule.py +989 -0
- sage/modular/hypergeometric_misc.cpython-314-darwin.so +0 -0
- sage/modular/hypergeometric_misc.pxd +4 -0
- sage/modular/hypergeometric_misc.pyx +166 -0
- sage/modular/hypergeometric_motive.py +2017 -0
- sage/modular/local_comp/all.py +2 -0
- sage/modular/local_comp/liftings.py +292 -0
- sage/modular/local_comp/local_comp.py +1071 -0
- sage/modular/local_comp/smoothchar.py +1825 -0
- sage/modular/local_comp/type_space.py +748 -0
- sage/modular/modform/all.py +30 -0
- sage/modular/modform/ambient.py +815 -0
- sage/modular/modform/ambient_R.py +177 -0
- sage/modular/modform/ambient_eps.py +306 -0
- sage/modular/modform/ambient_g0.py +124 -0
- sage/modular/modform/ambient_g1.py +204 -0
- sage/modular/modform/constructor.py +545 -0
- sage/modular/modform/cuspidal_submodule.py +708 -0
- sage/modular/modform/defaults.py +14 -0
- sage/modular/modform/eis_series.py +505 -0
- sage/modular/modform/eisenstein_submodule.py +663 -0
- sage/modular/modform/element.py +4131 -0
- sage/modular/modform/find_generators.py +59 -0
- sage/modular/modform/half_integral.py +154 -0
- sage/modular/modform/hecke_operator_on_qexp.py +247 -0
- sage/modular/modform/j_invariant.py +47 -0
- sage/modular/modform/l_series_gross_zagier.py +133 -0
- sage/modular/modform/l_series_gross_zagier_coeffs.cpython-314-darwin.so +0 -0
- sage/modular/modform/l_series_gross_zagier_coeffs.pyx +177 -0
- sage/modular/modform/notes.py +45 -0
- sage/modular/modform/numerical.py +514 -0
- sage/modular/modform/periods.py +14 -0
- sage/modular/modform/ring.py +1257 -0
- sage/modular/modform/space.py +1860 -0
- sage/modular/modform/submodule.py +118 -0
- sage/modular/modform/tests.py +64 -0
- sage/modular/modform/theta.py +110 -0
- sage/modular/modform/vm_basis.py +381 -0
- sage/modular/modform/weight1.py +220 -0
- sage/modular/modform_hecketriangle/abstract_ring.py +1932 -0
- sage/modular/modform_hecketriangle/abstract_space.py +2528 -0
- sage/modular/modform_hecketriangle/all.py +30 -0
- sage/modular/modform_hecketriangle/analytic_type.py +590 -0
- sage/modular/modform_hecketriangle/constructor.py +416 -0
- sage/modular/modform_hecketriangle/element.py +351 -0
- sage/modular/modform_hecketriangle/functors.py +752 -0
- sage/modular/modform_hecketriangle/graded_ring.py +541 -0
- sage/modular/modform_hecketriangle/graded_ring_element.py +2225 -0
- sage/modular/modform_hecketriangle/hecke_triangle_group_element.py +3352 -0
- sage/modular/modform_hecketriangle/hecke_triangle_groups.py +1432 -0
- sage/modular/modform_hecketriangle/readme.py +1214 -0
- sage/modular/modform_hecketriangle/series_constructor.py +580 -0
- sage/modular/modform_hecketriangle/space.py +1037 -0
- sage/modular/modform_hecketriangle/subspace.py +423 -0
- sage/modular/modsym/all.py +17 -0
- sage/modular/modsym/ambient.py +3846 -0
- sage/modular/modsym/boundary.py +1420 -0
- sage/modular/modsym/element.py +336 -0
- sage/modular/modsym/g1list.py +178 -0
- sage/modular/modsym/ghlist.py +182 -0
- sage/modular/modsym/hecke_operator.py +73 -0
- sage/modular/modsym/manin_symbol.cpython-314-darwin.so +0 -0
- sage/modular/modsym/manin_symbol.pxd +5 -0
- sage/modular/modsym/manin_symbol.pyx +497 -0
- sage/modular/modsym/manin_symbol_list.py +1295 -0
- sage/modular/modsym/modsym.py +400 -0
- sage/modular/modsym/modular_symbols.py +384 -0
- sage/modular/modsym/p1list.cpython-314-darwin.so +0 -0
- sage/modular/modsym/p1list.pxd +29 -0
- sage/modular/modsym/p1list.pyx +1372 -0
- sage/modular/modsym/p1list_nf.py +1241 -0
- sage/modular/modsym/relation_matrix.py +591 -0
- sage/modular/modsym/relation_matrix_pyx.cpython-314-darwin.so +0 -0
- sage/modular/modsym/relation_matrix_pyx.pyx +108 -0
- sage/modular/modsym/space.py +2468 -0
- sage/modular/modsym/subspace.py +455 -0
- sage/modular/modsym/tests.py +375 -0
- sage/modular/multiple_zeta.py +2632 -0
- sage/modular/multiple_zeta_F_algebra.py +786 -0
- sage/modular/overconvergent/all.py +6 -0
- sage/modular/overconvergent/genus0.py +1878 -0
- sage/modular/overconvergent/hecke_series.py +1187 -0
- sage/modular/overconvergent/weightspace.py +778 -0
- sage/modular/pollack_stevens/all.py +4 -0
- sage/modular/pollack_stevens/distributions.py +874 -0
- sage/modular/pollack_stevens/fund_domain.py +1572 -0
- sage/modular/pollack_stevens/manin_map.py +859 -0
- sage/modular/pollack_stevens/modsym.py +1593 -0
- sage/modular/pollack_stevens/padic_lseries.py +417 -0
- sage/modular/pollack_stevens/sigma0.py +534 -0
- sage/modular/pollack_stevens/space.py +1076 -0
- sage/modular/quasimodform/all.py +3 -0
- sage/modular/quasimodform/element.py +845 -0
- sage/modular/quasimodform/ring.py +828 -0
- sage/modular/quatalg/all.py +3 -0
- sage/modular/quatalg/brandt.py +1642 -0
- sage/modular/ssmod/all.py +8 -0
- sage/modular/ssmod/ssmod.py +827 -0
- sage/rings/all__sagemath_schemes.py +1 -0
- sage/rings/polynomial/all__sagemath_schemes.py +1 -0
- sage/rings/polynomial/binary_form_reduce.py +585 -0
- sage/schemes/all.py +41 -0
- sage/schemes/berkovich/all.py +6 -0
- sage/schemes/berkovich/berkovich_cp_element.py +2582 -0
- sage/schemes/berkovich/berkovich_space.py +748 -0
- sage/schemes/curves/affine_curve.py +2928 -0
- sage/schemes/curves/all.py +33 -0
- sage/schemes/curves/closed_point.py +434 -0
- sage/schemes/curves/constructor.py +381 -0
- sage/schemes/curves/curve.py +542 -0
- sage/schemes/curves/plane_curve_arrangement.py +1283 -0
- sage/schemes/curves/point.py +463 -0
- sage/schemes/curves/projective_curve.py +3026 -0
- sage/schemes/curves/zariski_vankampen.py +1932 -0
- sage/schemes/cyclic_covers/all.py +2 -0
- sage/schemes/cyclic_covers/charpoly_frobenius.py +320 -0
- sage/schemes/cyclic_covers/constructor.py +137 -0
- sage/schemes/cyclic_covers/cycliccover_finite_field.py +1309 -0
- sage/schemes/cyclic_covers/cycliccover_generic.py +310 -0
- sage/schemes/elliptic_curves/BSD.py +1036 -0
- sage/schemes/elliptic_curves/Qcurves.py +592 -0
- sage/schemes/elliptic_curves/addition_formulas_ring.py +94 -0
- sage/schemes/elliptic_curves/all.py +49 -0
- sage/schemes/elliptic_curves/cardinality.py +609 -0
- sage/schemes/elliptic_curves/cm.py +1102 -0
- sage/schemes/elliptic_curves/constructor.py +1552 -0
- sage/schemes/elliptic_curves/ec_database.py +175 -0
- sage/schemes/elliptic_curves/ell_curve_isogeny.py +3972 -0
- sage/schemes/elliptic_curves/ell_egros.py +459 -0
- sage/schemes/elliptic_curves/ell_field.py +2836 -0
- sage/schemes/elliptic_curves/ell_finite_field.py +3359 -0
- sage/schemes/elliptic_curves/ell_generic.py +3760 -0
- sage/schemes/elliptic_curves/ell_local_data.py +1207 -0
- sage/schemes/elliptic_curves/ell_modular_symbols.py +775 -0
- sage/schemes/elliptic_curves/ell_number_field.py +4220 -0
- sage/schemes/elliptic_curves/ell_padic_field.py +107 -0
- sage/schemes/elliptic_curves/ell_point.py +4787 -0
- sage/schemes/elliptic_curves/ell_rational_field.py +7368 -0
- sage/schemes/elliptic_curves/ell_tate_curve.py +671 -0
- sage/schemes/elliptic_curves/ell_torsion.py +436 -0
- sage/schemes/elliptic_curves/ell_wp.py +352 -0
- sage/schemes/elliptic_curves/formal_group.py +760 -0
- sage/schemes/elliptic_curves/gal_reps.py +1459 -0
- sage/schemes/elliptic_curves/gal_reps_number_field.py +1669 -0
- sage/schemes/elliptic_curves/gp_simon.py +152 -0
- sage/schemes/elliptic_curves/heegner.py +7335 -0
- sage/schemes/elliptic_curves/height.py +2109 -0
- sage/schemes/elliptic_curves/hom.py +1406 -0
- sage/schemes/elliptic_curves/hom_composite.py +934 -0
- sage/schemes/elliptic_curves/hom_frobenius.py +522 -0
- sage/schemes/elliptic_curves/hom_scalar.py +531 -0
- sage/schemes/elliptic_curves/hom_sum.py +682 -0
- sage/schemes/elliptic_curves/hom_velusqrt.py +1290 -0
- sage/schemes/elliptic_curves/homset.py +271 -0
- sage/schemes/elliptic_curves/isogeny_class.py +1521 -0
- sage/schemes/elliptic_curves/isogeny_small_degree.py +2797 -0
- sage/schemes/elliptic_curves/jacobian.py +237 -0
- sage/schemes/elliptic_curves/kodaira_symbol.py +344 -0
- sage/schemes/elliptic_curves/kraus.py +1014 -0
- sage/schemes/elliptic_curves/lseries_ell.py +943 -0
- sage/schemes/elliptic_curves/mod5family.py +105 -0
- sage/schemes/elliptic_curves/mod_poly.py +197 -0
- sage/schemes/elliptic_curves/mod_sym_num.cpython-314-darwin.so +0 -0
- sage/schemes/elliptic_curves/mod_sym_num.pyx +3796 -0
- sage/schemes/elliptic_curves/modular_parametrization.py +305 -0
- sage/schemes/elliptic_curves/padic_lseries.py +1793 -0
- sage/schemes/elliptic_curves/padics.py +1816 -0
- sage/schemes/elliptic_curves/period_lattice.py +2234 -0
- sage/schemes/elliptic_curves/period_lattice_region.cpython-314-darwin.so +0 -0
- sage/schemes/elliptic_curves/period_lattice_region.pyx +722 -0
- sage/schemes/elliptic_curves/saturation.py +715 -0
- sage/schemes/elliptic_curves/sha_tate.py +1158 -0
- sage/schemes/elliptic_curves/weierstrass_morphism.py +1117 -0
- sage/schemes/elliptic_curves/weierstrass_transform.py +200 -0
- sage/schemes/hyperelliptic_curves/all.py +6 -0
- sage/schemes/hyperelliptic_curves/constructor.py +291 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py +1914 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_g2.py +192 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py +954 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py +1332 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_rational_field.py +84 -0
- sage/schemes/hyperelliptic_curves/invariants.py +410 -0
- sage/schemes/hyperelliptic_curves/jacobian_endomorphism_utils.py +315 -0
- sage/schemes/hyperelliptic_curves/jacobian_g2.py +32 -0
- sage/schemes/hyperelliptic_curves/jacobian_generic.py +419 -0
- sage/schemes/hyperelliptic_curves/jacobian_homset.py +186 -0
- sage/schemes/hyperelliptic_curves/jacobian_morphism.py +875 -0
- sage/schemes/hyperelliptic_curves/kummer_surface.py +99 -0
- sage/schemes/hyperelliptic_curves/mestre.py +302 -0
- sage/schemes/hyperelliptic_curves/monsky_washnitzer.py +3871 -0
- sage/schemes/jacobians/abstract_jacobian.py +277 -0
- sage/schemes/jacobians/all.py +2 -0
- sage/schemes/overview.py +161 -0
- sage/schemes/plane_conics/all.py +22 -0
- sage/schemes/plane_conics/con_field.py +1296 -0
- sage/schemes/plane_conics/con_finite_field.py +158 -0
- sage/schemes/plane_conics/con_number_field.py +456 -0
- sage/schemes/plane_conics/con_rational_field.py +406 -0
- sage/schemes/plane_conics/con_rational_function_field.py +580 -0
- sage/schemes/plane_conics/constructor.py +249 -0
- sage/schemes/plane_quartics/all.py +2 -0
- sage/schemes/plane_quartics/quartic_constructor.py +71 -0
- sage/schemes/plane_quartics/quartic_generic.py +73 -0
- sage/schemes/riemann_surfaces/all.py +1 -0
- sage/schemes/riemann_surfaces/riemann_surface.py +4117 -0
- sage_wheels/share/cremona/cremona_mini.db +0 -0
- sage_wheels/share/ellcurves/rank0 +30427 -0
- sage_wheels/share/ellcurves/rank1 +31871 -0
- sage_wheels/share/ellcurves/rank10 +6 -0
- sage_wheels/share/ellcurves/rank11 +6 -0
- sage_wheels/share/ellcurves/rank12 +1 -0
- sage_wheels/share/ellcurves/rank14 +1 -0
- sage_wheels/share/ellcurves/rank15 +1 -0
- sage_wheels/share/ellcurves/rank17 +1 -0
- sage_wheels/share/ellcurves/rank19 +1 -0
- sage_wheels/share/ellcurves/rank2 +2388 -0
- sage_wheels/share/ellcurves/rank20 +1 -0
- sage_wheels/share/ellcurves/rank21 +1 -0
- sage_wheels/share/ellcurves/rank22 +1 -0
- sage_wheels/share/ellcurves/rank23 +1 -0
- sage_wheels/share/ellcurves/rank24 +1 -0
- sage_wheels/share/ellcurves/rank28 +1 -0
- sage_wheels/share/ellcurves/rank3 +836 -0
- sage_wheels/share/ellcurves/rank4 +10 -0
- sage_wheels/share/ellcurves/rank5 +5 -0
- sage_wheels/share/ellcurves/rank6 +5 -0
- sage_wheels/share/ellcurves/rank7 +5 -0
- sage_wheels/share/ellcurves/rank8 +6 -0
- sage_wheels/share/ellcurves/rank9 +7 -0
|
@@ -0,0 +1,1065 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-schemes
|
|
2
|
+
r"""
|
|
3
|
+
Eta-products on modular curves `X_0(N)`
|
|
4
|
+
|
|
5
|
+
This package provides a class for representing eta-products, which
|
|
6
|
+
are meromorphic functions on modular curves of the form
|
|
7
|
+
|
|
8
|
+
.. MATH::
|
|
9
|
+
|
|
10
|
+
\prod_{d | N} \eta(q^d)^{r_d}
|
|
11
|
+
|
|
12
|
+
where `\eta(q)` is Dirichlet's eta function
|
|
13
|
+
|
|
14
|
+
.. MATH::
|
|
15
|
+
|
|
16
|
+
q^{1/24} \prod_{n = 1}^\infty(1-q^n) .
|
|
17
|
+
|
|
18
|
+
These are useful for obtaining explicit models of modular curves.
|
|
19
|
+
|
|
20
|
+
See :issue:`3934` for background.
|
|
21
|
+
|
|
22
|
+
AUTHOR:
|
|
23
|
+
|
|
24
|
+
- David Loeffler (2008-08-22): initial version
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
# ***************************************************************************
|
|
28
|
+
# Copyright (C) 2008 William Stein <wstein@gmail.com>
|
|
29
|
+
# 2008 David Loeffler <d.loeffler.01@cantab.net>
|
|
30
|
+
#
|
|
31
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
32
|
+
# https://www.gnu.org/licenses/
|
|
33
|
+
# ***************************************************************************
|
|
34
|
+
from __future__ import annotations
|
|
35
|
+
from typing import Any
|
|
36
|
+
|
|
37
|
+
from sage.arith.misc import divisors, prime_divisors, euler_phi, is_square, gcd
|
|
38
|
+
from sage.categories.groups import Groups
|
|
39
|
+
from sage.matrix.constructor import matrix
|
|
40
|
+
from sage.modules.free_module import FreeModule
|
|
41
|
+
from sage.rings.finite_rings.integer_mod import Mod
|
|
42
|
+
from sage.rings.finite_rings.integer_mod_ring import IntegerModRing
|
|
43
|
+
from sage.rings.integer import Integer
|
|
44
|
+
from sage.rings.integer_ring import ZZ
|
|
45
|
+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
|
|
46
|
+
from sage.rings.power_series_ring import PowerSeriesRing
|
|
47
|
+
from sage.rings.rational_field import QQ
|
|
48
|
+
from sage.structure.element import Element
|
|
49
|
+
from sage.structure.formal_sum import FormalSum
|
|
50
|
+
from sage.structure.parent import Parent
|
|
51
|
+
from sage.structure.richcmp import richcmp, richcmp_method, op_EQ, op_NE
|
|
52
|
+
from sage.structure.sage_object import SageObject
|
|
53
|
+
from sage.structure.unique_representation import UniqueRepresentation
|
|
54
|
+
|
|
55
|
+
import weakref
|
|
56
|
+
|
|
57
|
+
_cache: dict[int, Any] = {}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def EtaGroup(level):
|
|
61
|
+
r"""
|
|
62
|
+
Create the group of eta products of the given level.
|
|
63
|
+
|
|
64
|
+
EXAMPLES::
|
|
65
|
+
|
|
66
|
+
sage: EtaGroup(12)
|
|
67
|
+
Group of eta products on X_0(12)
|
|
68
|
+
sage: EtaGroup(1/2)
|
|
69
|
+
Traceback (most recent call last):
|
|
70
|
+
...
|
|
71
|
+
TypeError: Level (=1/2) must be a positive integer
|
|
72
|
+
sage: EtaGroup(0)
|
|
73
|
+
Traceback (most recent call last):
|
|
74
|
+
...
|
|
75
|
+
ValueError: Level (=0) must be a positive integer
|
|
76
|
+
"""
|
|
77
|
+
if level in _cache:
|
|
78
|
+
G = _cache[level]()
|
|
79
|
+
if G is not None:
|
|
80
|
+
return G
|
|
81
|
+
G = EtaGroup_class(level)
|
|
82
|
+
_cache[level] = weakref.ref(G)
|
|
83
|
+
return G
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class EtaGroupElement(Element):
|
|
87
|
+
|
|
88
|
+
def __init__(self, parent, rdict):
|
|
89
|
+
r"""
|
|
90
|
+
Create an eta product object. Usually called implicitly via
|
|
91
|
+
EtaGroup_class.__call__ or the EtaProduct factory function.
|
|
92
|
+
|
|
93
|
+
EXAMPLES::
|
|
94
|
+
|
|
95
|
+
sage: EtaProduct(8, {1:24, 2:-24})
|
|
96
|
+
Eta product of level 8 : (eta_1)^24 (eta_2)^-24
|
|
97
|
+
sage: g = _; g == loads(dumps(g))
|
|
98
|
+
True
|
|
99
|
+
sage: TestSuite(g).run()
|
|
100
|
+
"""
|
|
101
|
+
self._N = parent._N
|
|
102
|
+
N = self._N
|
|
103
|
+
|
|
104
|
+
if isinstance(rdict, EtaGroupElement):
|
|
105
|
+
rdict = rdict._rdict
|
|
106
|
+
# Note: This is needed because the "x in G" test tries to call G(x)
|
|
107
|
+
# and see if it returns an error. So sometimes this will be getting
|
|
108
|
+
# called with rdict being an eta product, not a dictionary.
|
|
109
|
+
|
|
110
|
+
if rdict == 1:
|
|
111
|
+
rdict = {}
|
|
112
|
+
|
|
113
|
+
# Check Ligozat criteria
|
|
114
|
+
sumR = sumDR = sumNoverDr = 0
|
|
115
|
+
prod = 1
|
|
116
|
+
for d in list(rdict):
|
|
117
|
+
if N % d:
|
|
118
|
+
raise ValueError("%s does not divide %s" % (d, N))
|
|
119
|
+
|
|
120
|
+
if rdict[d] == 0:
|
|
121
|
+
del rdict[d]
|
|
122
|
+
continue
|
|
123
|
+
sumR += rdict[d]
|
|
124
|
+
sumDR += rdict[d] * d
|
|
125
|
+
sumNoverDr += rdict[d] * (N // d)
|
|
126
|
+
prod *= (N // d)**rdict[d]
|
|
127
|
+
|
|
128
|
+
if sumR != 0:
|
|
129
|
+
raise ValueError("sum r_d (=%s) is not 0" % sumR)
|
|
130
|
+
if sumDR % 24:
|
|
131
|
+
raise ValueError("sum d r_d (=%s) is not 0 mod 24" % sumDR)
|
|
132
|
+
if sumNoverDr % 24:
|
|
133
|
+
raise ValueError("sum (N/d) r_d (=%s) is not 0 mod 24" % sumNoverDr)
|
|
134
|
+
if not is_square(prod):
|
|
135
|
+
raise ValueError("product (N/d)^(r_d) (=%s) is not a square" % prod)
|
|
136
|
+
|
|
137
|
+
self._sumDR = ZZ(sumDR) # this is useful to have around
|
|
138
|
+
self._rdict = rdict
|
|
139
|
+
|
|
140
|
+
Element.__init__(self, parent)
|
|
141
|
+
|
|
142
|
+
def _mul_(self, other):
|
|
143
|
+
r"""
|
|
144
|
+
Return the product of ``self`` and ``other``.
|
|
145
|
+
|
|
146
|
+
EXAMPLES::
|
|
147
|
+
|
|
148
|
+
sage: # needs fpylll
|
|
149
|
+
sage: eta1, eta2 = EtaGroup(4).basis() # indirect doctest
|
|
150
|
+
sage: eta1 * eta2
|
|
151
|
+
Eta product of level 4 : (eta_1)^24 (eta_2)^-48 (eta_4)^24
|
|
152
|
+
"""
|
|
153
|
+
newdict = {d: self._rdict.get(d, 0) + other._rdict.get(d, 0)
|
|
154
|
+
for d in set(self._rdict).union(other._rdict)}
|
|
155
|
+
P = self.parent()
|
|
156
|
+
return P.element_class(P, newdict)
|
|
157
|
+
|
|
158
|
+
def _div_(self, other):
|
|
159
|
+
r"""
|
|
160
|
+
Return `self * other^{-1}`.
|
|
161
|
+
|
|
162
|
+
EXAMPLES::
|
|
163
|
+
|
|
164
|
+
sage: # needs fpylll
|
|
165
|
+
sage: eta1, eta2 = EtaGroup(4).basis()
|
|
166
|
+
sage: eta1 / eta2 # indirect doctest
|
|
167
|
+
Eta product of level 4 : (eta_1)^-8 (eta_4)^8
|
|
168
|
+
sage: (eta1 / eta2) * eta2 == eta1
|
|
169
|
+
True
|
|
170
|
+
"""
|
|
171
|
+
newdict = {d: self._rdict.get(d, 0) - other._rdict.get(d, 0)
|
|
172
|
+
for d in set(self._rdict).union(other._rdict)}
|
|
173
|
+
P = self.parent()
|
|
174
|
+
return P.element_class(P, newdict)
|
|
175
|
+
|
|
176
|
+
def __invert__(self):
|
|
177
|
+
r"""
|
|
178
|
+
Return the inverse of ``self``.
|
|
179
|
+
|
|
180
|
+
EXAMPLES::
|
|
181
|
+
|
|
182
|
+
sage: # needs fpylll
|
|
183
|
+
sage: eta1, eta2 = EtaGroup(4).basis()
|
|
184
|
+
sage: ~eta2 # indirect doctest
|
|
185
|
+
Eta product of level 4 : (eta_1)^-16 (eta_2)^24 (eta_4)^-8
|
|
186
|
+
"""
|
|
187
|
+
newdict = {d: -self._rdict[d] for d in self._rdict}
|
|
188
|
+
P = self.parent()
|
|
189
|
+
return P.element_class(P, newdict)
|
|
190
|
+
|
|
191
|
+
def is_one(self) -> bool:
|
|
192
|
+
r"""
|
|
193
|
+
Return whether ``self`` is the one of the monoid.
|
|
194
|
+
|
|
195
|
+
EXAMPLES::
|
|
196
|
+
|
|
197
|
+
sage: e = EtaProduct(3, {3:12, 1:-12})
|
|
198
|
+
sage: e.is_one()
|
|
199
|
+
False
|
|
200
|
+
sage: e.parent().one().is_one()
|
|
201
|
+
True
|
|
202
|
+
sage: ep = EtaProduct(5, {})
|
|
203
|
+
sage: ep.is_one()
|
|
204
|
+
True
|
|
205
|
+
sage: ep.parent().one() == ep
|
|
206
|
+
True
|
|
207
|
+
"""
|
|
208
|
+
return not self._rdict
|
|
209
|
+
|
|
210
|
+
def _richcmp_(self, other, op) -> bool:
|
|
211
|
+
r"""
|
|
212
|
+
Compare ``self`` to ``other``.
|
|
213
|
+
|
|
214
|
+
Eta products are compared according to their rdicts.
|
|
215
|
+
|
|
216
|
+
EXAMPLES::
|
|
217
|
+
|
|
218
|
+
sage: EtaProduct(2, {2:24,1:-24}) == 1
|
|
219
|
+
False
|
|
220
|
+
sage: EtaProduct(6, {1:-24, 2:24}) == EtaProduct(6, {1:-24, 2:24})
|
|
221
|
+
True
|
|
222
|
+
sage: EtaProduct(6, {1:-24, 2:24}) == EtaProduct(6, {1:24, 2:-24})
|
|
223
|
+
False
|
|
224
|
+
sage: EtaProduct(6, {1:-24, 2:24}) < EtaProduct(6, {1:-24, 2:24, 3:24, 6:-24})
|
|
225
|
+
True
|
|
226
|
+
sage: EtaProduct(6, {1:-24, 2:24, 3:24, 6:-24}) < EtaProduct(6, {1:-24, 2:24})
|
|
227
|
+
False
|
|
228
|
+
"""
|
|
229
|
+
if op in [op_EQ, op_NE]:
|
|
230
|
+
test = (self._N == other._N and
|
|
231
|
+
self._rdict == other._rdict)
|
|
232
|
+
return test == (op == op_EQ)
|
|
233
|
+
return richcmp((self._N, sorted(self._rdict.items())),
|
|
234
|
+
(other._N, sorted(other._rdict.items())), op)
|
|
235
|
+
|
|
236
|
+
def _short_repr(self) -> str:
|
|
237
|
+
r"""
|
|
238
|
+
A short string representation of ``self``, which does not specify the
|
|
239
|
+
level.
|
|
240
|
+
|
|
241
|
+
EXAMPLES::
|
|
242
|
+
|
|
243
|
+
sage: EtaProduct(3, {3:12, 1:-12})._short_repr()
|
|
244
|
+
'(eta_1)^-12 (eta_3)^12'
|
|
245
|
+
"""
|
|
246
|
+
if self.degree() == 0:
|
|
247
|
+
return "1"
|
|
248
|
+
return " ".join("(eta_%s)^%s" % (d, exp)
|
|
249
|
+
for d, exp in sorted(self._rdict.items()))
|
|
250
|
+
|
|
251
|
+
def _repr_(self) -> str:
|
|
252
|
+
r"""
|
|
253
|
+
Return the string representation of ``self``.
|
|
254
|
+
|
|
255
|
+
EXAMPLES::
|
|
256
|
+
|
|
257
|
+
sage: EtaProduct(3, {3:12, 1:-12})._repr_()
|
|
258
|
+
'Eta product of level 3 : (eta_1)^-12 (eta_3)^12'
|
|
259
|
+
"""
|
|
260
|
+
return "Eta product of level %s : " % self.level() + self._short_repr()
|
|
261
|
+
|
|
262
|
+
def level(self) -> Integer:
|
|
263
|
+
r"""
|
|
264
|
+
Return the level of this eta product.
|
|
265
|
+
|
|
266
|
+
EXAMPLES::
|
|
267
|
+
|
|
268
|
+
sage: e = EtaProduct(3, {3:12, 1:-12})
|
|
269
|
+
sage: e.level()
|
|
270
|
+
3
|
|
271
|
+
sage: EtaProduct(12, {6:6, 2:-6}).level() # not the lcm of the d's
|
|
272
|
+
12
|
|
273
|
+
sage: EtaProduct(36, {6:6, 2:-6}).level() # not minimal
|
|
274
|
+
36
|
|
275
|
+
"""
|
|
276
|
+
return self._N
|
|
277
|
+
|
|
278
|
+
def q_expansion(self, n):
|
|
279
|
+
r"""
|
|
280
|
+
Return the `q`-expansion of ``self`` at the cusp at infinity.
|
|
281
|
+
|
|
282
|
+
INPUT:
|
|
283
|
+
|
|
284
|
+
- ``n`` -- integer; number of terms to calculate
|
|
285
|
+
|
|
286
|
+
OUTPUT:
|
|
287
|
+
|
|
288
|
+
A power series over `\ZZ` in the variable `q`, with a *relative*
|
|
289
|
+
precision of `1 + O(q^n)`.
|
|
290
|
+
|
|
291
|
+
ALGORITHM: Calculates eta to (n/m) terms, where m is the smallest
|
|
292
|
+
integer dividing self.level() such that self.r(m) != 0. Then
|
|
293
|
+
multiplies.
|
|
294
|
+
|
|
295
|
+
EXAMPLES::
|
|
296
|
+
|
|
297
|
+
sage: EtaProduct(36, {6:6, 2:-6}).q_expansion(10)
|
|
298
|
+
q + 6*q^3 + 27*q^5 + 92*q^7 + 279*q^9 + O(q^11)
|
|
299
|
+
sage: R.<q> = ZZ[[]]
|
|
300
|
+
sage: EtaProduct(2,{2:24,1:-24}).q_expansion(100) == delta_qexp(101)(q^2)/delta_qexp(101)(q)
|
|
301
|
+
True
|
|
302
|
+
"""
|
|
303
|
+
R, q = PowerSeriesRing(ZZ, 'q').objgen()
|
|
304
|
+
pr = R.one().O(n)
|
|
305
|
+
if not self._rdict: # if self.is_one():
|
|
306
|
+
return pr
|
|
307
|
+
# self.r(d) should always be nonzero since we filtered out the 0s
|
|
308
|
+
eta_n = max(n // d for d in self._rdict) # if self.r(d)
|
|
309
|
+
eta = qexp_eta(R, eta_n)
|
|
310
|
+
for d in self._rdict:
|
|
311
|
+
rd = self._rdict[d]
|
|
312
|
+
if rd:
|
|
313
|
+
pr *= eta(q ** d) ** ZZ(rd)
|
|
314
|
+
return pr * q**(self._sumDR // 24)
|
|
315
|
+
|
|
316
|
+
def qexp(self, n):
|
|
317
|
+
"""
|
|
318
|
+
Alias for ``self.q_expansion()``.
|
|
319
|
+
|
|
320
|
+
EXAMPLES::
|
|
321
|
+
|
|
322
|
+
sage: e = EtaProduct(36, {6:8, 3:-8})
|
|
323
|
+
sage: e.qexp(10)
|
|
324
|
+
q + 8*q^4 + 36*q^7 + O(q^10)
|
|
325
|
+
sage: e.qexp(30) == e.q_expansion(30)
|
|
326
|
+
True
|
|
327
|
+
"""
|
|
328
|
+
return self.q_expansion(n)
|
|
329
|
+
|
|
330
|
+
def order_at_cusp(self, cusp: CuspFamily) -> Integer:
|
|
331
|
+
r"""
|
|
332
|
+
Return the order of vanishing of ``self`` at the given cusp.
|
|
333
|
+
|
|
334
|
+
INPUT:
|
|
335
|
+
|
|
336
|
+
- ``cusp`` -- a :class:`CuspFamily` object
|
|
337
|
+
|
|
338
|
+
OUTPUT: integer
|
|
339
|
+
|
|
340
|
+
EXAMPLES::
|
|
341
|
+
|
|
342
|
+
sage: e = EtaProduct(2, {2:24, 1:-24})
|
|
343
|
+
sage: e.order_at_cusp(CuspFamily(2, 1)) # cusp at infinity
|
|
344
|
+
1
|
|
345
|
+
sage: e.order_at_cusp(CuspFamily(2, 2)) # cusp 0
|
|
346
|
+
-1
|
|
347
|
+
"""
|
|
348
|
+
if not isinstance(cusp, CuspFamily):
|
|
349
|
+
raise TypeError("argument (=%s) should be a CuspFamily" % cusp)
|
|
350
|
+
if cusp.level() != self._N:
|
|
351
|
+
raise ValueError("cusp not on right curve")
|
|
352
|
+
sigma = sum(ell * self._rdict[ell] / cusp.width() *
|
|
353
|
+
(gcd(cusp.width(), self._N // ell))**2
|
|
354
|
+
for ell in self._rdict)
|
|
355
|
+
return sigma / ZZ(24) / gcd(cusp.width(), self._N // cusp.width())
|
|
356
|
+
|
|
357
|
+
def divisor(self):
|
|
358
|
+
r"""
|
|
359
|
+
Return the divisor of ``self``, as a formal sum of CuspFamily objects.
|
|
360
|
+
|
|
361
|
+
EXAMPLES::
|
|
362
|
+
|
|
363
|
+
sage: e = EtaProduct(12, {1:-336, 2:576, 3:696, 4:-216, 6:-576, 12:-144})
|
|
364
|
+
sage: e.divisor() # FormalSum seems to print things in a random order?
|
|
365
|
+
-131*(Inf) - 50*(c_{2}) + 11*(0) + 50*(c_{6}) + 169*(c_{4}) - 49*(c_{3})
|
|
366
|
+
sage: e = EtaProduct(2^8, {8:1,32:-1})
|
|
367
|
+
sage: e.divisor() # random
|
|
368
|
+
-(c_{2}) - (Inf) - (c_{8,2}) - (c_{8,3}) - (c_{8,4}) - (c_{4,2})
|
|
369
|
+
- (c_{8,1}) - (c_{4,1}) + (c_{32,4}) + (c_{32,3}) + (c_{64,1})
|
|
370
|
+
+ (0) + (c_{32,2}) + (c_{64,2}) + (c_{128}) + (c_{32,1})
|
|
371
|
+
"""
|
|
372
|
+
return FormalSum([(self.order_at_cusp(c), c)
|
|
373
|
+
for c in AllCusps(self.level())])
|
|
374
|
+
|
|
375
|
+
def degree(self) -> Integer:
|
|
376
|
+
r"""
|
|
377
|
+
Return the degree of ``self`` as a map `X_0(N) \to \mathbb{P}^1`.
|
|
378
|
+
|
|
379
|
+
This is the sum of all the positive coefficients in the divisor
|
|
380
|
+
of ``self``.
|
|
381
|
+
|
|
382
|
+
EXAMPLES::
|
|
383
|
+
|
|
384
|
+
sage: e = EtaProduct(12, {1:-336, 2:576, 3:696, 4:-216, 6:-576, 12:-144})
|
|
385
|
+
sage: e.degree()
|
|
386
|
+
230
|
|
387
|
+
"""
|
|
388
|
+
return sum(self.order_at_cusp(c)
|
|
389
|
+
for c in AllCusps(self._N)
|
|
390
|
+
if self.order_at_cusp(c) > 0)
|
|
391
|
+
|
|
392
|
+
def r(self, d) -> Integer:
|
|
393
|
+
r"""
|
|
394
|
+
Return the exponent `r_d` of `\eta(q^d)` in ``self``.
|
|
395
|
+
|
|
396
|
+
EXAMPLES::
|
|
397
|
+
|
|
398
|
+
sage: e = EtaProduct(12, {2:24, 3:-24})
|
|
399
|
+
sage: e.r(3)
|
|
400
|
+
-24
|
|
401
|
+
sage: e.r(4)
|
|
402
|
+
0
|
|
403
|
+
"""
|
|
404
|
+
return self._rdict.get(d, 0)
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
class EtaGroup_class(UniqueRepresentation, Parent):
|
|
408
|
+
r"""
|
|
409
|
+
The group of eta products of a given level under multiplication.
|
|
410
|
+
|
|
411
|
+
TESTS::
|
|
412
|
+
|
|
413
|
+
sage: TestSuite(EtaGroup(12)).run()
|
|
414
|
+
|
|
415
|
+
sage: EtaGroup(12) == EtaGroup(12)
|
|
416
|
+
True
|
|
417
|
+
sage: EtaGroup(12) == EtaGroup(13)
|
|
418
|
+
False
|
|
419
|
+
|
|
420
|
+
sage: EtaGroup(12) != EtaGroup(12)
|
|
421
|
+
False
|
|
422
|
+
sage: EtaGroup(12) != EtaGroup(13)
|
|
423
|
+
True
|
|
424
|
+
"""
|
|
425
|
+
|
|
426
|
+
def __init__(self, level):
|
|
427
|
+
r"""
|
|
428
|
+
Create the group of eta products of a given level, which must be a
|
|
429
|
+
positive integer.
|
|
430
|
+
|
|
431
|
+
EXAMPLES::
|
|
432
|
+
|
|
433
|
+
sage: G = EtaGroup(12); G # indirect doctest
|
|
434
|
+
Group of eta products on X_0(12)
|
|
435
|
+
sage: TestSuite(G).run()
|
|
436
|
+
"""
|
|
437
|
+
try:
|
|
438
|
+
level = ZZ(level)
|
|
439
|
+
except TypeError:
|
|
440
|
+
raise TypeError("Level (=%s) must be a positive integer" % level)
|
|
441
|
+
if level < 1:
|
|
442
|
+
raise ValueError("Level (=%s) must be a positive integer" % level)
|
|
443
|
+
self._N = level
|
|
444
|
+
Parent.__init__(self, category=Groups().Commutative())
|
|
445
|
+
|
|
446
|
+
def _repr_(self) -> str:
|
|
447
|
+
r"""
|
|
448
|
+
String representation of ``self``.
|
|
449
|
+
|
|
450
|
+
EXAMPLES::
|
|
451
|
+
|
|
452
|
+
sage: EtaGroup(12)._repr_()
|
|
453
|
+
'Group of eta products on X_0(12)'
|
|
454
|
+
"""
|
|
455
|
+
return "Group of eta products on X_0(%s)" % self.level()
|
|
456
|
+
|
|
457
|
+
def one(self) -> EtaGroupElement:
|
|
458
|
+
r"""
|
|
459
|
+
Return the identity element of ``self``.
|
|
460
|
+
|
|
461
|
+
EXAMPLES::
|
|
462
|
+
|
|
463
|
+
sage: EtaGroup(12).one()
|
|
464
|
+
Eta product of level 12 : 1
|
|
465
|
+
"""
|
|
466
|
+
return self({})
|
|
467
|
+
|
|
468
|
+
def _element_constructor_(self, dic):
|
|
469
|
+
r"""
|
|
470
|
+
Create an element of this group (an eta product object) with
|
|
471
|
+
exponents from the given dictionary.
|
|
472
|
+
|
|
473
|
+
INPUT:
|
|
474
|
+
|
|
475
|
+
- ``dic`` -- dictionary
|
|
476
|
+
|
|
477
|
+
See the docstring of :func:`EtaProduct` for how ``dic`` is used.
|
|
478
|
+
|
|
479
|
+
EXAMPLES::
|
|
480
|
+
|
|
481
|
+
sage: EtaGroup(2).__call__({1:24, 2:-24})
|
|
482
|
+
Eta product of level 2 : (eta_1)^24 (eta_2)^-24
|
|
483
|
+
"""
|
|
484
|
+
return self.element_class(self, dic)
|
|
485
|
+
|
|
486
|
+
def level(self) -> Integer:
|
|
487
|
+
r"""
|
|
488
|
+
Return the level of ``self``.
|
|
489
|
+
|
|
490
|
+
EXAMPLES::
|
|
491
|
+
|
|
492
|
+
sage: EtaGroup(10).level()
|
|
493
|
+
10
|
|
494
|
+
"""
|
|
495
|
+
return self._N
|
|
496
|
+
|
|
497
|
+
def basis(self, reduce=True) -> list:
|
|
498
|
+
r"""
|
|
499
|
+
Produce a basis for the free abelian group of eta-products of level
|
|
500
|
+
N (under multiplication), attempting to find basis vectors of the
|
|
501
|
+
smallest possible degree.
|
|
502
|
+
|
|
503
|
+
INPUT:
|
|
504
|
+
|
|
505
|
+
- ``reduce`` -- boolean (default: ``True``); whether or not to apply
|
|
506
|
+
LLL-reduction to the calculated basis
|
|
507
|
+
|
|
508
|
+
EXAMPLES::
|
|
509
|
+
|
|
510
|
+
sage: # needs fpylll
|
|
511
|
+
sage: EtaGroup(5).basis()
|
|
512
|
+
[Eta product of level 5 : (eta_1)^6 (eta_5)^-6]
|
|
513
|
+
sage: EtaGroup(12).basis()
|
|
514
|
+
[Eta product of level 12 : (eta_1)^-3 (eta_2)^2 (eta_3)^1 (eta_4)^-1 (eta_6)^-2 (eta_12)^3,
|
|
515
|
+
Eta product of level 12 : (eta_1)^-4 (eta_2)^2 (eta_3)^4 (eta_6)^-2,
|
|
516
|
+
Eta product of level 12 : (eta_1)^6 (eta_2)^-9 (eta_3)^-2 (eta_4)^3 (eta_6)^3 (eta_12)^-1,
|
|
517
|
+
Eta product of level 12 : (eta_1)^-1 (eta_2)^3 (eta_3)^3 (eta_4)^-2 (eta_6)^-9 (eta_12)^6,
|
|
518
|
+
Eta product of level 12 : (eta_1)^3 (eta_3)^-1 (eta_4)^-3 (eta_12)^1]
|
|
519
|
+
sage: EtaGroup(12).basis(reduce=False) # much bigger coefficients
|
|
520
|
+
[Eta product of level 12 : (eta_1)^384 (eta_2)^-576 (eta_3)^-696 (eta_4)^216 (eta_6)^576 (eta_12)^96,
|
|
521
|
+
Eta product of level 12 : (eta_2)^24 (eta_12)^-24,
|
|
522
|
+
Eta product of level 12 : (eta_1)^-40 (eta_2)^116 (eta_3)^96 (eta_4)^-30 (eta_6)^-80 (eta_12)^-62,
|
|
523
|
+
Eta product of level 12 : (eta_1)^-4 (eta_2)^-33 (eta_3)^-4 (eta_4)^1 (eta_6)^3 (eta_12)^37,
|
|
524
|
+
Eta product of level 12 : (eta_1)^15 (eta_2)^-24 (eta_3)^-29 (eta_4)^9 (eta_6)^24 (eta_12)^5]
|
|
525
|
+
|
|
526
|
+
ALGORITHM: An eta product of level `N` is uniquely
|
|
527
|
+
determined by the integers `r_d` for `d | N` with
|
|
528
|
+
`d < N`, since `\sum_{d | N} r_d = 0`. The valid
|
|
529
|
+
`r_d` are those that satisfy two congruences modulo 24,
|
|
530
|
+
and one congruence modulo 2 for every prime divisor of N. We beef
|
|
531
|
+
up the congruences modulo 2 to congruences modulo 24 by multiplying
|
|
532
|
+
by 12. To calculate the kernel of the ensuing map
|
|
533
|
+
`\ZZ^m \to (\ZZ/24\ZZ)^n`
|
|
534
|
+
we lift it arbitrarily to an integer matrix and calculate its Smith
|
|
535
|
+
normal form. This gives a basis for the lattice.
|
|
536
|
+
|
|
537
|
+
This lattice typically contains "large" elements, so by default we
|
|
538
|
+
pass it to the reduce_basis() function which performs
|
|
539
|
+
LLL-reduction to give a more manageable basis.
|
|
540
|
+
"""
|
|
541
|
+
N = self.level()
|
|
542
|
+
divs = divisors(N)[:-1]
|
|
543
|
+
s = len(divs)
|
|
544
|
+
primedivs = prime_divisors(N)
|
|
545
|
+
|
|
546
|
+
rows = []
|
|
547
|
+
for di in divs:
|
|
548
|
+
# generate a row of relation matrix
|
|
549
|
+
row = [Mod(di, 24) - Mod(N, 24), Mod(N // di, 24) - Mod(1, 24)]
|
|
550
|
+
row.extend(Mod(12 * (N // di).valuation(p), 24)
|
|
551
|
+
for p in primedivs)
|
|
552
|
+
rows.append(row)
|
|
553
|
+
|
|
554
|
+
M = matrix(IntegerModRing(24), rows)
|
|
555
|
+
Mlift = M.change_ring(ZZ)
|
|
556
|
+
# now we compute elementary factors of Mlift
|
|
557
|
+
S, U, V = Mlift.smith_form()
|
|
558
|
+
good_vects = []
|
|
559
|
+
for i in range(U.nrows()):
|
|
560
|
+
vect = U.row(i)
|
|
561
|
+
nf = (i < S.ncols() and S[i, i]) or 0 # ?
|
|
562
|
+
good_vects.append((vect * 24 / gcd(nf, 24)).list())
|
|
563
|
+
for v in good_vects:
|
|
564
|
+
v.append(-sum(list(v)))
|
|
565
|
+
dicts: list[dict] = []
|
|
566
|
+
for v in good_vects:
|
|
567
|
+
dicts.append({})
|
|
568
|
+
for i in range(s):
|
|
569
|
+
dicts[-1][divs[i]] = v[i]
|
|
570
|
+
dicts[-1][N] = v[-1]
|
|
571
|
+
if reduce:
|
|
572
|
+
return self.reduce_basis([self(d) for d in dicts])
|
|
573
|
+
else:
|
|
574
|
+
return [self(d) for d in dicts]
|
|
575
|
+
|
|
576
|
+
def reduce_basis(self, long_etas) -> list:
|
|
577
|
+
r"""
|
|
578
|
+
Produce a more manageable basis via LLL-reduction.
|
|
579
|
+
|
|
580
|
+
INPUT:
|
|
581
|
+
|
|
582
|
+
- ``long_etas`` -- a list of EtaGroupElement objects (which
|
|
583
|
+
should all be of the same level)
|
|
584
|
+
|
|
585
|
+
OUTPUT:
|
|
586
|
+
|
|
587
|
+
- a new list of EtaGroupElement objects having
|
|
588
|
+
hopefully smaller norm
|
|
589
|
+
|
|
590
|
+
ALGORITHM: We define the norm of an eta-product to be the
|
|
591
|
+
`L^2` norm of its divisor (as an element of the free
|
|
592
|
+
`\ZZ`-module with the cusps as basis and the
|
|
593
|
+
standard inner product). Applying LLL-reduction to this gives a
|
|
594
|
+
basis of hopefully more tractable elements. Of course we'd like to
|
|
595
|
+
use the `L^1` norm as this is just twice the degree, which
|
|
596
|
+
is a much more natural invariant, but `L^2` norm is easier
|
|
597
|
+
to work with!
|
|
598
|
+
|
|
599
|
+
EXAMPLES::
|
|
600
|
+
|
|
601
|
+
sage: # needs fpylll
|
|
602
|
+
sage: EtaGroup(4).reduce_basis([ EtaProduct(4, {1:8,2:24,4:-32}), EtaProduct(4, {1:8, 4:-8})])
|
|
603
|
+
[Eta product of level 4 : (eta_1)^8 (eta_4)^-8,
|
|
604
|
+
Eta product of level 4 : (eta_1)^-8 (eta_2)^24 (eta_4)^-16]
|
|
605
|
+
"""
|
|
606
|
+
N = self.level()
|
|
607
|
+
cusps = AllCusps(N)
|
|
608
|
+
r = matrix(ZZ, [[et.order_at_cusp(c) for c in cusps] for et in long_etas])
|
|
609
|
+
V = FreeModule(ZZ, r.ncols())
|
|
610
|
+
A = V.submodule_with_basis([V(rw) for rw in r.rows()])
|
|
611
|
+
rred = r.LLL()
|
|
612
|
+
short_etas = []
|
|
613
|
+
for shortvect in rred.rows():
|
|
614
|
+
bv = A.coordinates(shortvect)
|
|
615
|
+
dic = {d: sum(bv[i] * long_etas[i].r(d)
|
|
616
|
+
for i in range(r.nrows()))
|
|
617
|
+
for d in divisors(N)}
|
|
618
|
+
short_etas.append(self(dic))
|
|
619
|
+
return short_etas
|
|
620
|
+
|
|
621
|
+
Element = EtaGroupElement
|
|
622
|
+
|
|
623
|
+
|
|
624
|
+
def EtaProduct(level, dic) -> EtaGroupElement:
|
|
625
|
+
r"""
|
|
626
|
+
Create an :class:`EtaGroupElement` object representing the function
|
|
627
|
+
`\prod_{d | N} \eta(q^d)^{r_d}`.
|
|
628
|
+
|
|
629
|
+
This checks the criteria of Ligozat to ensure that this product
|
|
630
|
+
really is the `q`-expansion of a meromorphic function on `X_0(N)`.
|
|
631
|
+
|
|
632
|
+
INPUT:
|
|
633
|
+
|
|
634
|
+
- ``level`` -- integer; the N such that this eta
|
|
635
|
+
product is a function on `X_0(N)`
|
|
636
|
+
|
|
637
|
+
- ``dic`` -- a dictionary indexed by divisors of N such that the
|
|
638
|
+
coefficient of `\eta(q^d)` is r[d]. Only nonzero coefficients need be
|
|
639
|
+
specified. If Ligozat's criteria are not satisfied, a :exc:`ValueError`
|
|
640
|
+
will be raised.
|
|
641
|
+
|
|
642
|
+
OUTPUT:
|
|
643
|
+
|
|
644
|
+
An EtaGroupElement object, whose parent is the EtaGroup of level N and
|
|
645
|
+
whose coefficients are the given dictionary.
|
|
646
|
+
|
|
647
|
+
.. NOTE::
|
|
648
|
+
|
|
649
|
+
The dictionary ``dic`` does not uniquely specify N. It is
|
|
650
|
+
possible for two EtaGroupElements with different `N`'s to
|
|
651
|
+
be created with the same dictionary, and these represent different
|
|
652
|
+
objects (although they will have the same `q`-expansion at
|
|
653
|
+
the cusp `\infty`).
|
|
654
|
+
|
|
655
|
+
EXAMPLES::
|
|
656
|
+
|
|
657
|
+
sage: EtaProduct(3, {3:12, 1:-12})
|
|
658
|
+
Eta product of level 3 : (eta_1)^-12 (eta_3)^12
|
|
659
|
+
sage: EtaProduct(3, {3:6, 1:-6})
|
|
660
|
+
Traceback (most recent call last):
|
|
661
|
+
...
|
|
662
|
+
ValueError: sum d r_d (=12) is not 0 mod 24
|
|
663
|
+
sage: EtaProduct(3, {4:6, 1:-6})
|
|
664
|
+
Traceback (most recent call last):
|
|
665
|
+
...
|
|
666
|
+
ValueError: 4 does not divide 3
|
|
667
|
+
"""
|
|
668
|
+
return EtaGroup(level)(dic)
|
|
669
|
+
|
|
670
|
+
|
|
671
|
+
def num_cusps_of_width(N, d) -> Integer:
|
|
672
|
+
r"""
|
|
673
|
+
Return the number of cusps on `X_0(N)` of width ``d``.
|
|
674
|
+
|
|
675
|
+
INPUT:
|
|
676
|
+
|
|
677
|
+
- ``N`` -- integer; the level
|
|
678
|
+
|
|
679
|
+
- ``d`` -- integer; an integer dividing `N`, the cusp width
|
|
680
|
+
|
|
681
|
+
EXAMPLES::
|
|
682
|
+
|
|
683
|
+
sage: from sage.modular.etaproducts import num_cusps_of_width
|
|
684
|
+
sage: [num_cusps_of_width(18,d) for d in divisors(18)]
|
|
685
|
+
[1, 1, 2, 2, 1, 1]
|
|
686
|
+
sage: num_cusps_of_width(4,8)
|
|
687
|
+
Traceback (most recent call last):
|
|
688
|
+
...
|
|
689
|
+
ValueError: N and d must be positive integers with d|N
|
|
690
|
+
"""
|
|
691
|
+
N = ZZ(N)
|
|
692
|
+
d = ZZ(d)
|
|
693
|
+
if N <= 0 or d <= 0 or N % d:
|
|
694
|
+
raise ValueError("N and d must be positive integers with d|N")
|
|
695
|
+
|
|
696
|
+
return euler_phi(d.gcd(N // d))
|
|
697
|
+
|
|
698
|
+
|
|
699
|
+
def AllCusps(N) -> list:
|
|
700
|
+
r"""
|
|
701
|
+
Return a list of CuspFamily objects corresponding to the cusps of
|
|
702
|
+
`X_0(N)`.
|
|
703
|
+
|
|
704
|
+
INPUT:
|
|
705
|
+
|
|
706
|
+
- ``N`` -- integer; the level
|
|
707
|
+
|
|
708
|
+
EXAMPLES::
|
|
709
|
+
|
|
710
|
+
sage: AllCusps(18)
|
|
711
|
+
[(Inf), (c_{2}), (c_{3,1}), (c_{3,2}), (c_{6,1}), (c_{6,2}), (c_{9}), (0)]
|
|
712
|
+
sage: AllCusps(0)
|
|
713
|
+
Traceback (most recent call last):
|
|
714
|
+
...
|
|
715
|
+
ValueError: N must be positive
|
|
716
|
+
"""
|
|
717
|
+
N = ZZ(N)
|
|
718
|
+
if N <= 0:
|
|
719
|
+
raise ValueError("N must be positive")
|
|
720
|
+
|
|
721
|
+
c = []
|
|
722
|
+
for d in divisors(N):
|
|
723
|
+
n = num_cusps_of_width(N, d)
|
|
724
|
+
if n == 1:
|
|
725
|
+
c.append(CuspFamily(N, d))
|
|
726
|
+
elif n > 1:
|
|
727
|
+
c.extend(CuspFamily(N, d, label=str(i + 1))
|
|
728
|
+
for i in range(n))
|
|
729
|
+
return c
|
|
730
|
+
|
|
731
|
+
|
|
732
|
+
@richcmp_method
|
|
733
|
+
class CuspFamily(SageObject):
|
|
734
|
+
r"""
|
|
735
|
+
A family of elliptic curves parametrising a region of `X_0(N)`.
|
|
736
|
+
"""
|
|
737
|
+
def __init__(self, N, width, label=None):
|
|
738
|
+
r"""
|
|
739
|
+
Create the cusp of width d on X_0(N) corresponding to the family
|
|
740
|
+
of Tate curves `(\CC_p/q^d, \langle \zeta q\rangle)`.
|
|
741
|
+
|
|
742
|
+
Here `\zeta` is a primitive root of unity of order `r` with
|
|
743
|
+
`\mathrm{lcm}(r,d) = N`. The cusp does not store zeta, so we
|
|
744
|
+
store an arbitrary label instead.
|
|
745
|
+
|
|
746
|
+
EXAMPLES::
|
|
747
|
+
|
|
748
|
+
sage: CuspFamily(8, 4)
|
|
749
|
+
(c_{4})
|
|
750
|
+
sage: CuspFamily(16, 4, '1')
|
|
751
|
+
(c_{4,1})
|
|
752
|
+
"""
|
|
753
|
+
N = ZZ(N)
|
|
754
|
+
if N <= 0:
|
|
755
|
+
raise ValueError("N must be positive")
|
|
756
|
+
self._N = N
|
|
757
|
+
self._width = width
|
|
758
|
+
if N % width:
|
|
759
|
+
raise ValueError("bad width")
|
|
760
|
+
if num_cusps_of_width(N, width) > 1 and label is None:
|
|
761
|
+
raise ValueError("there are %s > 1 cusps of width %s on X_0(%s): specify a label" % (num_cusps_of_width(N, width), width, N))
|
|
762
|
+
if num_cusps_of_width(N, width) == 1 and label is not None:
|
|
763
|
+
raise ValueError("there is only one cusp of width %s on X_0(%s): no need to specify a label" % (width, N))
|
|
764
|
+
self.label = label
|
|
765
|
+
|
|
766
|
+
@property
|
|
767
|
+
def __tuple(self):
|
|
768
|
+
"""
|
|
769
|
+
The defining data of this ``CuspFamily`` as tuple, used for
|
|
770
|
+
comparisons.
|
|
771
|
+
"""
|
|
772
|
+
return (self._N, self._width, self.label)
|
|
773
|
+
|
|
774
|
+
def __richcmp__(self, other, op) -> bool:
|
|
775
|
+
"""
|
|
776
|
+
EXAMPLES::
|
|
777
|
+
|
|
778
|
+
sage: a = CuspFamily(16, 4, "1"); a
|
|
779
|
+
(c_{4,1})
|
|
780
|
+
sage: b = CuspFamily(16, 4, "2"); b
|
|
781
|
+
(c_{4,2})
|
|
782
|
+
sage: c = CuspFamily(8, 8); c
|
|
783
|
+
(0)
|
|
784
|
+
sage: a == a
|
|
785
|
+
True
|
|
786
|
+
sage: a == b
|
|
787
|
+
False
|
|
788
|
+
sage: a != b
|
|
789
|
+
True
|
|
790
|
+
sage: a == c
|
|
791
|
+
False
|
|
792
|
+
sage: a < c
|
|
793
|
+
False
|
|
794
|
+
sage: a > c
|
|
795
|
+
True
|
|
796
|
+
sage: a != "foo"
|
|
797
|
+
True
|
|
798
|
+
"""
|
|
799
|
+
if not isinstance(other, CuspFamily):
|
|
800
|
+
return NotImplemented
|
|
801
|
+
return richcmp(self.__tuple, other.__tuple, op)
|
|
802
|
+
|
|
803
|
+
def __hash__(self):
|
|
804
|
+
"""
|
|
805
|
+
EXAMPLES::
|
|
806
|
+
|
|
807
|
+
sage: hash(CuspFamily(10, 1)) # random
|
|
808
|
+
-4769758480201659164
|
|
809
|
+
"""
|
|
810
|
+
return hash(self.__tuple)
|
|
811
|
+
|
|
812
|
+
def width(self) -> Integer:
|
|
813
|
+
r"""
|
|
814
|
+
Return the width of this cusp.
|
|
815
|
+
|
|
816
|
+
EXAMPLES::
|
|
817
|
+
|
|
818
|
+
sage: e = CuspFamily(10, 1)
|
|
819
|
+
sage: e.width()
|
|
820
|
+
1
|
|
821
|
+
"""
|
|
822
|
+
return self._width
|
|
823
|
+
|
|
824
|
+
def level(self) -> Integer:
|
|
825
|
+
r"""
|
|
826
|
+
Return the level of this cusp.
|
|
827
|
+
|
|
828
|
+
EXAMPLES::
|
|
829
|
+
|
|
830
|
+
sage: e = CuspFamily(10, 1)
|
|
831
|
+
sage: e.level()
|
|
832
|
+
10
|
|
833
|
+
"""
|
|
834
|
+
return self._N
|
|
835
|
+
|
|
836
|
+
def sage_cusp(self):
|
|
837
|
+
r"""
|
|
838
|
+
Return the corresponding element of `\mathbb{P}^1(\QQ)`.
|
|
839
|
+
|
|
840
|
+
EXAMPLES::
|
|
841
|
+
|
|
842
|
+
sage: CuspFamily(10, 1).sage_cusp() # not implemented
|
|
843
|
+
Infinity
|
|
844
|
+
"""
|
|
845
|
+
raise NotImplementedError
|
|
846
|
+
|
|
847
|
+
def _repr_(self) -> str:
|
|
848
|
+
r"""
|
|
849
|
+
Return a string representation of ``self``.
|
|
850
|
+
|
|
851
|
+
EXAMPLES::
|
|
852
|
+
|
|
853
|
+
sage: CuspFamily(16, 4, "1")._repr_()
|
|
854
|
+
'(c_{4,1})'
|
|
855
|
+
"""
|
|
856
|
+
if self.width() == 1:
|
|
857
|
+
return "(Inf)"
|
|
858
|
+
elif self.width() == self.level():
|
|
859
|
+
return "(0)"
|
|
860
|
+
return "(c_{%s%s})" % (self.width(), ((self.label and ("," + self.label)) or ""))
|
|
861
|
+
|
|
862
|
+
|
|
863
|
+
def qexp_eta(ps_ring, prec):
|
|
864
|
+
r"""
|
|
865
|
+
Return the `q`-expansion of `\eta(q) / q^{1/24}`.
|
|
866
|
+
|
|
867
|
+
Here `\eta(q)` is Dedekind's function
|
|
868
|
+
|
|
869
|
+
.. MATH::
|
|
870
|
+
|
|
871
|
+
\eta(q) = q^{1/24}\prod_{n=1}^\infty (1-q^n).
|
|
872
|
+
|
|
873
|
+
The result is an element of ``ps_ring``, with precision ``prec``.
|
|
874
|
+
|
|
875
|
+
INPUT:
|
|
876
|
+
|
|
877
|
+
- ``ps_ring`` -- PowerSeriesRing; a power series ring
|
|
878
|
+
|
|
879
|
+
- ``prec`` -- integer; the number of terms to compute
|
|
880
|
+
|
|
881
|
+
OUTPUT: an element of ``ps_ring`` which is the `q`-expansion of
|
|
882
|
+
`\eta(q)/q^{1/24}` truncated to prec terms.
|
|
883
|
+
|
|
884
|
+
ALGORITHM: We use the Euler identity
|
|
885
|
+
|
|
886
|
+
.. MATH::
|
|
887
|
+
|
|
888
|
+
\eta(q) = q^{1/24}( 1 + \sum_{n \ge 1} (-1)^n (q^{n(3n+1)/2} + q^{n(3n-1)/2})
|
|
889
|
+
|
|
890
|
+
to compute the expansion.
|
|
891
|
+
|
|
892
|
+
EXAMPLES::
|
|
893
|
+
|
|
894
|
+
sage: from sage.modular.etaproducts import qexp_eta
|
|
895
|
+
sage: qexp_eta(ZZ[['q']], 100)
|
|
896
|
+
1 - q - q^2 + q^5 + q^7 - q^12 - q^15 + q^22 + q^26 - q^35 - q^40 + q^51 + q^57 - q^70 - q^77 + q^92 + O(q^100)
|
|
897
|
+
"""
|
|
898
|
+
prec = Integer(prec)
|
|
899
|
+
if not prec > 0:
|
|
900
|
+
raise ValueError("prec must be a positive integer")
|
|
901
|
+
v = [Integer(0)] * prec
|
|
902
|
+
pm = Integer(1)
|
|
903
|
+
v[0] = pm
|
|
904
|
+
try:
|
|
905
|
+
n = 1
|
|
906
|
+
while True:
|
|
907
|
+
pm = -pm
|
|
908
|
+
v[n * (3 * n - 1) // 2] = pm
|
|
909
|
+
v[n * (3 * n + 1) // 2] = pm
|
|
910
|
+
n += 1
|
|
911
|
+
except IndexError:
|
|
912
|
+
pass
|
|
913
|
+
return ps_ring(v, prec=prec)
|
|
914
|
+
|
|
915
|
+
|
|
916
|
+
def eta_poly_relations(eta_elements, degree, labels=['x1', 'x2'],
|
|
917
|
+
verbose=False):
|
|
918
|
+
r"""
|
|
919
|
+
Find polynomial relations between eta products.
|
|
920
|
+
|
|
921
|
+
INPUT:
|
|
922
|
+
|
|
923
|
+
- ``eta_elements`` -- list; a list of EtaGroupElement objects.
|
|
924
|
+
Not implemented unless this list has precisely two elements. degree
|
|
925
|
+
|
|
926
|
+
- ``degree`` -- integer; the maximal degree of polynomial to look for
|
|
927
|
+
|
|
928
|
+
- ``labels`` -- list of strings; labels to use for the polynomial returned
|
|
929
|
+
|
|
930
|
+
- ``verbose`` -- boolean (default: ``False``); if ``True``, prints information as
|
|
931
|
+
it goes
|
|
932
|
+
|
|
933
|
+
OUTPUT: list of polynomials which is a Groebner basis for the
|
|
934
|
+
part of the ideal of relations between eta_elements which is
|
|
935
|
+
generated by elements up to the given degree; or None, if no
|
|
936
|
+
relations were found.
|
|
937
|
+
|
|
938
|
+
ALGORITHM: An expression of the form
|
|
939
|
+
`\sum_{0 \le i,j \le d} a_{ij} x^i y^j` is zero if and
|
|
940
|
+
only if it vanishes at the cusp infinity to degree at least
|
|
941
|
+
`v = d(deg(x) + deg(y))`. For all terms up to `q^v`
|
|
942
|
+
in the `q`-expansion of this expression to be zero is a
|
|
943
|
+
system of `v + k` linear equations in `d^2`
|
|
944
|
+
coefficients, where `k` is the number of nonzero negative
|
|
945
|
+
coefficients that can appear.
|
|
946
|
+
|
|
947
|
+
Solving these equations and calculating a basis for the solution
|
|
948
|
+
space gives us a set of polynomial relations, but this is generally
|
|
949
|
+
far from a minimal generating set for the ideal, so we calculate a
|
|
950
|
+
Groebner basis.
|
|
951
|
+
|
|
952
|
+
As a test, we calculate five extra terms of `q`-expansion
|
|
953
|
+
and check that this doesn't change the answer.
|
|
954
|
+
|
|
955
|
+
EXAMPLES::
|
|
956
|
+
|
|
957
|
+
sage: from sage.modular.etaproducts import eta_poly_relations
|
|
958
|
+
sage: t = EtaProduct(26, {2:2,13:2,26:-2,1:-2})
|
|
959
|
+
sage: u = EtaProduct(26, {2:4,13:2,26:-4,1:-2})
|
|
960
|
+
sage: eta_poly_relations([t, u], 3)
|
|
961
|
+
sage: eta_poly_relations([t, u], 4)
|
|
962
|
+
[x1^3*x2 - 13*x1^3 - 4*x1^2*x2 - 4*x1*x2 - x2^2 + x2]
|
|
963
|
+
|
|
964
|
+
Use ``verbose=True`` to see the details of the computation::
|
|
965
|
+
|
|
966
|
+
sage: eta_poly_relations([t, u], 3, verbose=True)
|
|
967
|
+
Trying to find a relation of degree 3
|
|
968
|
+
Lowest order of a term at infinity = -12
|
|
969
|
+
Highest possible degree of a term = 15
|
|
970
|
+
Trying all coefficients from q^-12 to q^15 inclusive
|
|
971
|
+
No polynomial relation of order 3 valid for 28 terms
|
|
972
|
+
Check:
|
|
973
|
+
Trying all coefficients from q^-12 to q^20 inclusive
|
|
974
|
+
No polynomial relation of order 3 valid for 33 terms
|
|
975
|
+
|
|
976
|
+
::
|
|
977
|
+
|
|
978
|
+
sage: eta_poly_relations([t, u], 4, verbose=True)
|
|
979
|
+
Trying to find a relation of degree 4
|
|
980
|
+
Lowest order of a term at infinity = -16
|
|
981
|
+
Highest possible degree of a term = 20
|
|
982
|
+
Trying all coefficients from q^-16 to q^20 inclusive
|
|
983
|
+
Check:
|
|
984
|
+
Trying all coefficients from q^-16 to q^25 inclusive
|
|
985
|
+
[x1^3*x2 - 13*x1^3 - 4*x1^2*x2 - 4*x1*x2 - x2^2 + x2]
|
|
986
|
+
"""
|
|
987
|
+
if len(eta_elements) > 2:
|
|
988
|
+
raise NotImplementedError("do not know how to find relations between more than two elements")
|
|
989
|
+
|
|
990
|
+
eta1, eta2 = eta_elements
|
|
991
|
+
|
|
992
|
+
if verbose:
|
|
993
|
+
print("Trying to find a relation of degree %s" % degree)
|
|
994
|
+
inf = CuspFamily(eta1.level(), 1)
|
|
995
|
+
loterm = -(min(0, eta1.order_at_cusp(inf)) + min(0, eta2.order_at_cusp(inf))) * degree
|
|
996
|
+
if verbose:
|
|
997
|
+
print("Lowest order of a term at infinity = %s" % -loterm)
|
|
998
|
+
|
|
999
|
+
maxdeg = sum([eta1.degree(), eta2.degree()]) * degree
|
|
1000
|
+
if verbose:
|
|
1001
|
+
print("Highest possible degree of a term = %s" % maxdeg)
|
|
1002
|
+
m = loterm + maxdeg + 1
|
|
1003
|
+
oldgrob = _eta_relations_helper(eta1, eta2, degree, m, labels, verbose)
|
|
1004
|
+
if verbose:
|
|
1005
|
+
print("Check:")
|
|
1006
|
+
newgrob = _eta_relations_helper(eta1, eta2, degree, m + 5, labels, verbose)
|
|
1007
|
+
if oldgrob != newgrob:
|
|
1008
|
+
raise ArithmeticError("Check: answers different!")
|
|
1009
|
+
return newgrob
|
|
1010
|
+
|
|
1011
|
+
|
|
1012
|
+
def _eta_relations_helper(eta1, eta2, degree, qexp_terms, labels, verbose):
|
|
1013
|
+
r"""
|
|
1014
|
+
Helper function used by eta_poly_relations. Finds a basis for the
|
|
1015
|
+
space of linear relations between the first qexp_terms of the
|
|
1016
|
+
`q`-expansions of the monomials
|
|
1017
|
+
`\eta_1^i * \eta_2^j` for `0 \le i,j < degree`,
|
|
1018
|
+
and calculates a Groebner basis for the ideal generated by these
|
|
1019
|
+
relations.
|
|
1020
|
+
|
|
1021
|
+
Liable to return meaningless results if qexp_terms isn't at least
|
|
1022
|
+
`1 + d*(m_1,m_2)` where
|
|
1023
|
+
|
|
1024
|
+
.. MATH::
|
|
1025
|
+
|
|
1026
|
+
m_i = min(0, {\text degree of the pole of $\eta_i$ at $\infty$})
|
|
1027
|
+
|
|
1028
|
+
as then 1 will be in the ideal.
|
|
1029
|
+
|
|
1030
|
+
EXAMPLES::
|
|
1031
|
+
|
|
1032
|
+
sage: # needs fpylll
|
|
1033
|
+
sage: from sage.modular.etaproducts import _eta_relations_helper
|
|
1034
|
+
sage: r,s = EtaGroup(4).basis()
|
|
1035
|
+
sage: _eta_relations_helper(r,s,4,100,['a','b'],False)
|
|
1036
|
+
[a + 1/16*b - 1/16]
|
|
1037
|
+
sage: _eta_relations_helper(EtaProduct(26, {2:2,13:2,26:-2,1:-2}),EtaProduct(26, {2:4,13:2,26:-4,1:-2}),3,12,['a','b'],False) # not enough terms, will return rubbish
|
|
1038
|
+
[1]
|
|
1039
|
+
"""
|
|
1040
|
+
indices = [(i, j) for j in range(degree) for i in range(degree)]
|
|
1041
|
+
inf = CuspFamily(eta1.level(), 1)
|
|
1042
|
+
|
|
1043
|
+
pole_at_infinity = -(min(0, eta1.order_at_cusp(inf)) + min(0, eta2.order_at_cusp(inf))) * degree
|
|
1044
|
+
if verbose:
|
|
1045
|
+
print("Trying all coefficients from q^%s to q^%s inclusive" % (-pole_at_infinity, -pole_at_infinity + qexp_terms - 1))
|
|
1046
|
+
|
|
1047
|
+
rows: list[list] = [[] for _ in range(qexp_terms)]
|
|
1048
|
+
for i in indices:
|
|
1049
|
+
func = (eta1**i[0] * eta2**i[1]).qexp(qexp_terms)
|
|
1050
|
+
for j in range(qexp_terms):
|
|
1051
|
+
rows[j].append(func[j - pole_at_infinity])
|
|
1052
|
+
M = matrix(rows)
|
|
1053
|
+
V = M.right_kernel()
|
|
1054
|
+
if V.dimension() == 0:
|
|
1055
|
+
if verbose:
|
|
1056
|
+
print("No polynomial relation of order %s valid for %s terms" % (degree, qexp_terms))
|
|
1057
|
+
return None
|
|
1058
|
+
if V.dimension() >= 1:
|
|
1059
|
+
R = PolynomialRing(QQ, 2, labels)
|
|
1060
|
+
x, y = R.gens()
|
|
1061
|
+
relations = [sum([c[v] * x**indices[v][0] * y**indices[v][1]
|
|
1062
|
+
for v in range(len(indices))])
|
|
1063
|
+
for c in V.basis()]
|
|
1064
|
+
id = R.ideal(relations)
|
|
1065
|
+
return id.groebner_basis()
|