passagemath-schemes 10.6.47__cp312-cp312-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.6.47.dist-info/METADATA +204 -0
- passagemath_schemes-10.6.47.dist-info/METADATA.bak +205 -0
- passagemath_schemes-10.6.47.dist-info/RECORD +311 -0
- passagemath_schemes-10.6.47.dist-info/WHEEL +6 -0
- passagemath_schemes-10.6.47.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-312-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-312-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-312-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-312-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-312-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-312-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-312-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-312-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_nf.py +1241 -0
- sage/modular/modsym/relation_matrix.py +591 -0
- sage/modular/modsym/relation_matrix_pyx.cpython-312-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-312-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-312-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,1572 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-schemes
|
|
2
|
+
r"""
|
|
3
|
+
Manin relations for overconvergent modular symbols
|
|
4
|
+
|
|
5
|
+
Code to create the Manin Relations class, which solves the "Manin relations".
|
|
6
|
+
That is, a description of `Div^0(P^1(\QQ))` as a `\ZZ[\Gamma_0(N)]`-module in
|
|
7
|
+
terms of generators and relations is found. The method used is geometric,
|
|
8
|
+
constructing a nice fundamental domain for `\Gamma_0(N)` and reading the
|
|
9
|
+
relevant Manin relations off of that picture. The algorithm follows [PS2011]_.
|
|
10
|
+
|
|
11
|
+
AUTHORS:
|
|
12
|
+
|
|
13
|
+
- Robert Pollack, Jonathan Hanke (2012): initial version
|
|
14
|
+
"""
|
|
15
|
+
# ****************************************************************************
|
|
16
|
+
# Copyright (C) 2012 Robert Pollack <rpollack@math.bu.edu>
|
|
17
|
+
# Jonathan Hanke <jonhanke@gmail.com>
|
|
18
|
+
#
|
|
19
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
20
|
+
# as published by the Free Software Foundation; either version 2 of
|
|
21
|
+
# the License, or (at your option) any later version.
|
|
22
|
+
# https://www.gnu.org/licenses/
|
|
23
|
+
# ****************************************************************************
|
|
24
|
+
|
|
25
|
+
from sage.matrix.matrix_space import MatrixSpace
|
|
26
|
+
from sage.modular.modsym.all import P1List
|
|
27
|
+
from sage.rings.integer import Integer
|
|
28
|
+
from sage.rings.integer_ring import ZZ
|
|
29
|
+
from sage.rings.rational_field import QQ
|
|
30
|
+
from sage.structure.sage_object import SageObject
|
|
31
|
+
from sage.misc.cachefunc import cached_method
|
|
32
|
+
|
|
33
|
+
from .sigma0 import Sigma0
|
|
34
|
+
|
|
35
|
+
M2ZSpace = MatrixSpace(ZZ,2)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def M2Z(x):
|
|
39
|
+
r"""
|
|
40
|
+
Create an immutable `2 \times 2` integer matrix from ``x``.
|
|
41
|
+
|
|
42
|
+
INPUT:
|
|
43
|
+
|
|
44
|
+
- ``x`` -- anything that can be converted into a `2 \times 2` matrix
|
|
45
|
+
|
|
46
|
+
EXAMPLES::
|
|
47
|
+
|
|
48
|
+
sage: from sage.modular.pollack_stevens.fund_domain import M2Z
|
|
49
|
+
sage: M2Z([1,2,3,4])
|
|
50
|
+
[1 2]
|
|
51
|
+
[3 4]
|
|
52
|
+
sage: M2Z(1)
|
|
53
|
+
[1 0]
|
|
54
|
+
[0 1]
|
|
55
|
+
"""
|
|
56
|
+
x = M2ZSpace(x)
|
|
57
|
+
x.set_immutable()
|
|
58
|
+
return x
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
Id = M2Z([1, 0, 0, 1])
|
|
62
|
+
sig = M2Z([0, 1, -1, 0])
|
|
63
|
+
tau = M2Z([0, -1, 1, -1])
|
|
64
|
+
minone_inf_path = M2Z([1, 1, -1, 0])
|
|
65
|
+
|
|
66
|
+
# We store these so that we do not have to constantly create them.
|
|
67
|
+
t00 = (0, 0)
|
|
68
|
+
t10 = (1, 0)
|
|
69
|
+
t01 = (0, 1)
|
|
70
|
+
t11 = (1, 1)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class PollackStevensModularDomain(SageObject):
|
|
74
|
+
r"""
|
|
75
|
+
The domain of a modular symbol.
|
|
76
|
+
|
|
77
|
+
INPUT:
|
|
78
|
+
|
|
79
|
+
- ``N`` -- positive integer, the level of the congruence subgroup
|
|
80
|
+
`\Gamma_0(N)`
|
|
81
|
+
|
|
82
|
+
- ``reps`` -- list of `2 \times 2` matrices, the coset
|
|
83
|
+
representatives of `Div^0(P^1(\QQ))`
|
|
84
|
+
|
|
85
|
+
- ``indices`` -- list of integers; indices of elements in
|
|
86
|
+
``reps`` which are generators
|
|
87
|
+
|
|
88
|
+
- ``rels`` -- list of list of triples ``(d, A, i)``, one for each
|
|
89
|
+
coset representative of ``reps`` which describes how to express the
|
|
90
|
+
elements of ``reps`` in terms of generators specified by ``indices``.
|
|
91
|
+
See :meth:`relations` for a detailed explanations of these triples.
|
|
92
|
+
|
|
93
|
+
- ``equiv_ind`` -- dictionary which maps normalized coordinates on
|
|
94
|
+
`P^1(\ZZ/N\ZZ)` to an integer such that a matrix whose bottom row is
|
|
95
|
+
equivalent to `[a:b]` in `P^1(\ZZ/N\ZZ)` is in the coset of
|
|
96
|
+
``reps[equiv_ind[(a,b)]]``
|
|
97
|
+
|
|
98
|
+
EXAMPLES::
|
|
99
|
+
|
|
100
|
+
sage: from sage.modular.pollack_stevens.fund_domain import PollackStevensModularDomain, M2Z
|
|
101
|
+
sage: PollackStevensModularDomain(2 , [M2Z([1,0,0,1]), M2Z([1,1,-1,0]), M2Z([0,-1,1,1])], [0,2], [[(1, M2Z([1,0,0,1]), 0)], [(-1,M2Z([-1,-1,0,-1]),0)], [(1, M2Z([1,0,0,1]), 2)]], {(0,1): 0, (1,0): 1, (1,1): 2})
|
|
102
|
+
Modular Symbol domain of level 2
|
|
103
|
+
|
|
104
|
+
TESTS:
|
|
105
|
+
|
|
106
|
+
The level ``N`` must be an integer::
|
|
107
|
+
|
|
108
|
+
sage: PollackStevensModularDomain(1/2, None, None, None, None)
|
|
109
|
+
Traceback (most recent call last):
|
|
110
|
+
...
|
|
111
|
+
TypeError: no conversion of this rational to integer
|
|
112
|
+
sage: PollackStevensModularDomain(Gamma0(11), None, None, None, None)
|
|
113
|
+
Traceback (most recent call last):
|
|
114
|
+
...
|
|
115
|
+
TypeError: unable to coerce <class 'sage.modular.arithgroup.congroup_gamma0.Gamma0_class_with_category'> to an integer
|
|
116
|
+
"""
|
|
117
|
+
def __init__(self, N, reps, indices, rels, equiv_ind):
|
|
118
|
+
r"""
|
|
119
|
+
INPUT:
|
|
120
|
+
|
|
121
|
+
See :class:`PollackStevensModularDomain`.
|
|
122
|
+
|
|
123
|
+
EXAMPLES::
|
|
124
|
+
|
|
125
|
+
sage: from sage.modular.pollack_stevens.fund_domain import PollackStevensModularDomain, ManinRelations
|
|
126
|
+
sage: isinstance(ManinRelations(11), PollackStevensModularDomain) # indirect doctest
|
|
127
|
+
True
|
|
128
|
+
"""
|
|
129
|
+
self._N = ZZ(N)
|
|
130
|
+
self._reps = reps
|
|
131
|
+
|
|
132
|
+
self._indices = sorted(indices)
|
|
133
|
+
self._gens = tuple(M2Z(reps[i]) for i in self._indices)
|
|
134
|
+
self._ngens = len(indices)
|
|
135
|
+
|
|
136
|
+
if len(rels) != len(reps):
|
|
137
|
+
raise ValueError("length of reps and length of rels must be equal")
|
|
138
|
+
self._rels = rels
|
|
139
|
+
self._rel_dict = {reps[j]: L for j, L in enumerate(rels)}
|
|
140
|
+
|
|
141
|
+
self._equiv_ind = equiv_ind
|
|
142
|
+
self._equiv_rep = {ky: reps[vy] for ky, vy in equiv_ind.items()}
|
|
143
|
+
|
|
144
|
+
def _repr_(self):
|
|
145
|
+
r"""
|
|
146
|
+
A string representation of this domain.
|
|
147
|
+
|
|
148
|
+
EXAMPLES::
|
|
149
|
+
|
|
150
|
+
sage: from sage.modular.pollack_stevens.fund_domain import PollackStevensModularDomain, M2Z
|
|
151
|
+
sage: PollackStevensModularDomain(2 , [M2Z([1,0,0,1]), M2Z([1,1,-1,0]), M2Z([0,-1,1,1])], [0,2], [[(1, M2Z([1,0,0,1]), 0)], [(-1,M2Z([-1,-1,0,-1]),0)], [(1, M2Z([1,0,0,1]), 2)]], {(0,1): 0, (1,0): 1, (1,1): 2})._repr_()
|
|
152
|
+
'Modular Symbol domain of level 2'
|
|
153
|
+
"""
|
|
154
|
+
return "Modular Symbol domain of level %s" % self._N
|
|
155
|
+
|
|
156
|
+
def __len__(self):
|
|
157
|
+
r"""
|
|
158
|
+
Return the number of coset representatives.
|
|
159
|
+
|
|
160
|
+
EXAMPLES::
|
|
161
|
+
|
|
162
|
+
sage: from sage.modular.pollack_stevens.fund_domain import ManinRelations
|
|
163
|
+
sage: A = ManinRelations(11)
|
|
164
|
+
sage: len(A)
|
|
165
|
+
12
|
|
166
|
+
"""
|
|
167
|
+
return len(self._reps)
|
|
168
|
+
|
|
169
|
+
def __getitem__(self, i):
|
|
170
|
+
r"""
|
|
171
|
+
Return the ``i``-th coset representative.
|
|
172
|
+
|
|
173
|
+
EXAMPLES::
|
|
174
|
+
|
|
175
|
+
sage: from sage.modular.pollack_stevens.fund_domain import ManinRelations
|
|
176
|
+
sage: A = ManinRelations(11)
|
|
177
|
+
sage: A[4]
|
|
178
|
+
[-1 -2]
|
|
179
|
+
[ 2 3]
|
|
180
|
+
"""
|
|
181
|
+
return self._reps[i]
|
|
182
|
+
|
|
183
|
+
def __iter__(self):
|
|
184
|
+
r"""
|
|
185
|
+
Return an iterator over all coset representatives.
|
|
186
|
+
|
|
187
|
+
EXAMPLES::
|
|
188
|
+
|
|
189
|
+
sage: from sage.modular.pollack_stevens.fund_domain import ManinRelations
|
|
190
|
+
sage: A = ManinRelations(11)
|
|
191
|
+
sage: for rep in A:
|
|
192
|
+
....: if rep[1,0] == 1:
|
|
193
|
+
....: print(rep)
|
|
194
|
+
[ 0 -1]
|
|
195
|
+
[ 1 3]
|
|
196
|
+
[ 0 -1]
|
|
197
|
+
[ 1 2]
|
|
198
|
+
[ 0 -1]
|
|
199
|
+
[ 1 1]
|
|
200
|
+
"""
|
|
201
|
+
return iter(self._reps)
|
|
202
|
+
|
|
203
|
+
def gens(self) -> tuple:
|
|
204
|
+
r"""
|
|
205
|
+
Return the tuple of coset representatives chosen as generators.
|
|
206
|
+
|
|
207
|
+
EXAMPLES::
|
|
208
|
+
|
|
209
|
+
sage: from sage.modular.pollack_stevens.fund_domain import ManinRelations
|
|
210
|
+
sage: A = ManinRelations(11)
|
|
211
|
+
sage: A.gens()
|
|
212
|
+
(
|
|
213
|
+
[1 0] [ 0 -1] [-1 -1]
|
|
214
|
+
[0 1], [ 1 3], [ 3 2]
|
|
215
|
+
)
|
|
216
|
+
"""
|
|
217
|
+
return self._gens
|
|
218
|
+
|
|
219
|
+
def gen(self, n=0):
|
|
220
|
+
r"""
|
|
221
|
+
Return the `n`-th generator.
|
|
222
|
+
|
|
223
|
+
INPUT:
|
|
224
|
+
|
|
225
|
+
- ``n`` -- integer (default: 0); which generator is desired
|
|
226
|
+
|
|
227
|
+
EXAMPLES::
|
|
228
|
+
|
|
229
|
+
sage: from sage.modular.pollack_stevens.fund_domain import ManinRelations
|
|
230
|
+
sage: A = ManinRelations(137)
|
|
231
|
+
sage: A.gen(17)
|
|
232
|
+
[-4 -1]
|
|
233
|
+
[ 9 2]
|
|
234
|
+
"""
|
|
235
|
+
return self._gens[n]
|
|
236
|
+
|
|
237
|
+
def ngens(self):
|
|
238
|
+
r"""
|
|
239
|
+
Return the number of generators.
|
|
240
|
+
|
|
241
|
+
OUTPUT:
|
|
242
|
+
|
|
243
|
+
The number of coset representatives from which a modular symbol's value
|
|
244
|
+
on any coset can be derived.
|
|
245
|
+
|
|
246
|
+
EXAMPLES::
|
|
247
|
+
|
|
248
|
+
sage: from sage.modular.pollack_stevens.fund_domain import ManinRelations
|
|
249
|
+
sage: A = ManinRelations(1137)
|
|
250
|
+
sage: A.ngens()
|
|
251
|
+
255
|
|
252
|
+
"""
|
|
253
|
+
return len(self._gens)
|
|
254
|
+
|
|
255
|
+
def level(self):
|
|
256
|
+
r"""
|
|
257
|
+
Return the level `N` of `\Gamma_0(N)` that we work with.
|
|
258
|
+
|
|
259
|
+
OUTPUT:
|
|
260
|
+
|
|
261
|
+
The integer `N` of the group `\Gamma_0(N)` for which the Manin
|
|
262
|
+
Relations are being computed.
|
|
263
|
+
|
|
264
|
+
EXAMPLES::
|
|
265
|
+
|
|
266
|
+
sage: from sage.modular.pollack_stevens.fund_domain import ManinRelations
|
|
267
|
+
sage: A = ManinRelations(11)
|
|
268
|
+
sage: A.level()
|
|
269
|
+
11
|
|
270
|
+
"""
|
|
271
|
+
return self._N
|
|
272
|
+
|
|
273
|
+
def indices(self, n=None):
|
|
274
|
+
r"""
|
|
275
|
+
Return the `n`-th index of the coset representatives which were
|
|
276
|
+
chosen as our generators.
|
|
277
|
+
|
|
278
|
+
In particular, the divisors associated to these coset representatives
|
|
279
|
+
generate all divisors over `\ZZ[\Gamma_0(N)]`, and thus a modular
|
|
280
|
+
symbol is uniquely determined by its values on these divisors.
|
|
281
|
+
|
|
282
|
+
INPUT:
|
|
283
|
+
|
|
284
|
+
- ``n`` -- integer (default: ``None``)
|
|
285
|
+
|
|
286
|
+
OUTPUT:
|
|
287
|
+
|
|
288
|
+
The ``n``-th index of the generating set in ``self.reps()`` or all
|
|
289
|
+
indices if ``n`` is ``None``.
|
|
290
|
+
|
|
291
|
+
EXAMPLES::
|
|
292
|
+
|
|
293
|
+
sage: from sage.modular.pollack_stevens.fund_domain import ManinRelations
|
|
294
|
+
sage: A = ManinRelations(11)
|
|
295
|
+
sage: A.indices()
|
|
296
|
+
[0, 2, 3]
|
|
297
|
+
|
|
298
|
+
sage: A.indices(2)
|
|
299
|
+
3
|
|
300
|
+
|
|
301
|
+
sage: A = ManinRelations(13)
|
|
302
|
+
sage: A.indices()
|
|
303
|
+
[0, 2, 3, 4, 5]
|
|
304
|
+
|
|
305
|
+
sage: A = ManinRelations(101)
|
|
306
|
+
sage: A.indices()
|
|
307
|
+
[0, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 16, 17, 19, 20, 23, 24, 26, 28]
|
|
308
|
+
"""
|
|
309
|
+
if n is None:
|
|
310
|
+
return self._indices
|
|
311
|
+
else:
|
|
312
|
+
return self._indices[n]
|
|
313
|
+
|
|
314
|
+
def reps(self, n=None):
|
|
315
|
+
r"""
|
|
316
|
+
Return the ``n``-th coset representative associated with our
|
|
317
|
+
fundamental domain.
|
|
318
|
+
|
|
319
|
+
INPUT:
|
|
320
|
+
|
|
321
|
+
- ``n`` -- integer (default: ``None``)
|
|
322
|
+
|
|
323
|
+
OUTPUT:
|
|
324
|
+
|
|
325
|
+
The ``n``-th coset representative or all coset representatives if ``n``
|
|
326
|
+
is ``None``.
|
|
327
|
+
|
|
328
|
+
EXAMPLES::
|
|
329
|
+
|
|
330
|
+
sage: from sage.modular.pollack_stevens.fund_domain import ManinRelations
|
|
331
|
+
sage: A = ManinRelations(11)
|
|
332
|
+
sage: A.reps(0)
|
|
333
|
+
[1 0]
|
|
334
|
+
[0 1]
|
|
335
|
+
sage: A.reps(1)
|
|
336
|
+
[ 1 1]
|
|
337
|
+
[-1 0]
|
|
338
|
+
sage: A.reps(2)
|
|
339
|
+
[ 0 -1]
|
|
340
|
+
[ 1 3]
|
|
341
|
+
sage: A.reps()
|
|
342
|
+
[
|
|
343
|
+
[1 0] [ 1 1] [ 0 -1] [-1 -1] [-1 -2] [-2 -1] [ 0 -1] [ 1 0]
|
|
344
|
+
[0 1], [-1 0], [ 1 3], [ 3 2], [ 2 3], [ 3 1], [ 1 2], [-2 1],
|
|
345
|
+
<BLANKLINE>
|
|
346
|
+
[ 0 -1] [ 1 0] [-1 -1] [ 1 -1]
|
|
347
|
+
[ 1 1], [-1 1], [ 2 1], [-1 2]
|
|
348
|
+
]
|
|
349
|
+
"""
|
|
350
|
+
if n is None:
|
|
351
|
+
return self._reps
|
|
352
|
+
else:
|
|
353
|
+
return self._reps[n]
|
|
354
|
+
|
|
355
|
+
def relations(self, A=None):
|
|
356
|
+
r"""
|
|
357
|
+
Express the divisor attached to the coset representative of ``A`` in
|
|
358
|
+
terms of our chosen generators.
|
|
359
|
+
|
|
360
|
+
INPUT:
|
|
361
|
+
|
|
362
|
+
- ``A`` -- ``None``, an integer, or a coset representative (default:
|
|
363
|
+
``None``)
|
|
364
|
+
|
|
365
|
+
OUTPUT:
|
|
366
|
+
|
|
367
|
+
A `\ZZ[\Gamma_0(N)]`-relation expressing the divisor attached to ``A``
|
|
368
|
+
in terms of the generating set. The relation is given as a list of
|
|
369
|
+
triples ``(d, B, i)`` such that the divisor attached to ``A`` is the sum
|
|
370
|
+
of ``d`` times the divisor attached to ``B^{-1} * self.reps(i)``.
|
|
371
|
+
|
|
372
|
+
If ``A`` is an integer, then return this data for the ``A``-th
|
|
373
|
+
coset representative.
|
|
374
|
+
|
|
375
|
+
If ``A`` is ``None``, then return this data in a list for all coset
|
|
376
|
+
representatives.
|
|
377
|
+
|
|
378
|
+
.. NOTE::
|
|
379
|
+
|
|
380
|
+
These relations allow us to recover the value of a modular symbol
|
|
381
|
+
on any coset representative in terms of its values on our
|
|
382
|
+
generating set.
|
|
383
|
+
|
|
384
|
+
EXAMPLES::
|
|
385
|
+
|
|
386
|
+
sage: from sage.modular.pollack_stevens.fund_domain import ManinRelations
|
|
387
|
+
sage: MR = ManinRelations(11)
|
|
388
|
+
sage: MR.indices()
|
|
389
|
+
[0, 2, 3]
|
|
390
|
+
sage: MR.relations(0)
|
|
391
|
+
[(1, [1 0]
|
|
392
|
+
[0 1], 0)]
|
|
393
|
+
sage: MR.relations(2)
|
|
394
|
+
[(1, [1 0]
|
|
395
|
+
[0 1], 2)]
|
|
396
|
+
sage: MR.relations(3)
|
|
397
|
+
[(1, [1 0]
|
|
398
|
+
[0 1], 3)]
|
|
399
|
+
|
|
400
|
+
The fourth coset representative can be expressed through the
|
|
401
|
+
second coset representative::
|
|
402
|
+
|
|
403
|
+
sage: MR.reps(4)
|
|
404
|
+
[-1 -2]
|
|
405
|
+
[ 2 3]
|
|
406
|
+
sage: d, B, i = MR.relations(4)[0]
|
|
407
|
+
sage: P = B.inverse()*MR.reps(i); P
|
|
408
|
+
[ 2 -1]
|
|
409
|
+
[-3 2]
|
|
410
|
+
sage: d # the above corresponds to minus the divisor of A.reps(4) since d is -1
|
|
411
|
+
-1
|
|
412
|
+
|
|
413
|
+
The sixth coset representative can be expressed as the sum of
|
|
414
|
+
the second and the third::
|
|
415
|
+
|
|
416
|
+
sage: MR.reps(6)
|
|
417
|
+
[ 0 -1]
|
|
418
|
+
[ 1 2]
|
|
419
|
+
sage: MR.relations(6)
|
|
420
|
+
[(1, [1 0]
|
|
421
|
+
[0 1], 2), (1, [1 0]
|
|
422
|
+
[0 1], 3)]
|
|
423
|
+
sage: MR.reps(2), MR.reps(3) # MR.reps(6) is the sum of these divisors
|
|
424
|
+
(
|
|
425
|
+
[ 0 -1] [-1 -1]
|
|
426
|
+
[ 1 3], [ 3 2]
|
|
427
|
+
)
|
|
428
|
+
|
|
429
|
+
TESTS:
|
|
430
|
+
|
|
431
|
+
Test that the other ways of calling this method work::
|
|
432
|
+
|
|
433
|
+
sage: MR.relations(MR.reps(6))
|
|
434
|
+
[(1, [1 0]
|
|
435
|
+
[0 1], 2), (1, [1 0]
|
|
436
|
+
[0 1], 3)]
|
|
437
|
+
sage: MR.relations(None)
|
|
438
|
+
[[(1, [1 0]
|
|
439
|
+
[0 1], 0)], [(-1, [-1 -1]
|
|
440
|
+
[ 0 -1], 0)], [(1, [1 0]
|
|
441
|
+
[0 1], 2)], [(1, [1 0]
|
|
442
|
+
[0 1], 3)], [(-1, [-3 -2]
|
|
443
|
+
[11 7], 2)], [(-1, [-4 -3]
|
|
444
|
+
[11 8], 3)], [(1, [1 0]
|
|
445
|
+
[0 1], 2), (1, [1 0]
|
|
446
|
+
[0 1], 3)], [(-1, [1 0]
|
|
447
|
+
[0 1], 2), (-1, [1 0]
|
|
448
|
+
[0 1], 3)], [(1, [1 0]
|
|
449
|
+
[0 1], 2), (1, [1 0]
|
|
450
|
+
[0 1], 3), (-1, [-3 -2]
|
|
451
|
+
[11 7], 2), (-1, [-4 -3]
|
|
452
|
+
[11 8], 3)], [(-1, [1 0]
|
|
453
|
+
[0 1], 2), (-1, [1 0]
|
|
454
|
+
[0 1], 3), (1, [-3 -2]
|
|
455
|
+
[11 7], 2), (1, [-4 -3]
|
|
456
|
+
[11 8], 3)], [(-1, [-3 -2]
|
|
457
|
+
[11 7], 2), (-1, [-4 -3]
|
|
458
|
+
[11 8], 3)], [(1, [-3 -2]
|
|
459
|
+
[11 7], 2), (1, [-4 -3]
|
|
460
|
+
[11 8], 3)]]
|
|
461
|
+
"""
|
|
462
|
+
if A is None:
|
|
463
|
+
return self._rels
|
|
464
|
+
elif isinstance(A, (int, Integer, slice)):
|
|
465
|
+
return self._rels[A]
|
|
466
|
+
else:
|
|
467
|
+
return self._rel_dict[A]
|
|
468
|
+
|
|
469
|
+
def equivalent_index(self, A):
|
|
470
|
+
r"""
|
|
471
|
+
Return the index of the coset representative equivalent to ``A``.
|
|
472
|
+
|
|
473
|
+
Here by equivalent we mean the unique coset representative whose bottom
|
|
474
|
+
row is equivalent to the bottom row of ``A`` in `P^1(\ZZ/N\ZZ)`.
|
|
475
|
+
|
|
476
|
+
INPUT:
|
|
477
|
+
|
|
478
|
+
- ``A`` -- an element of `SL_2(\ZZ)`
|
|
479
|
+
|
|
480
|
+
OUTPUT:
|
|
481
|
+
|
|
482
|
+
The unique integer ``j`` satisfying that the bottom row of
|
|
483
|
+
``self.reps(j)`` is equivalent to the bottom row of ``A``.
|
|
484
|
+
|
|
485
|
+
EXAMPLES::
|
|
486
|
+
|
|
487
|
+
sage: from sage.modular.pollack_stevens.fund_domain import ManinRelations
|
|
488
|
+
sage: MR = ManinRelations(11)
|
|
489
|
+
sage: A = matrix(ZZ,2,2,[1,5,3,16])
|
|
490
|
+
sage: j = MR.equivalent_index(A); j
|
|
491
|
+
11
|
|
492
|
+
sage: MR.reps(11)
|
|
493
|
+
[ 1 -1]
|
|
494
|
+
[-1 2]
|
|
495
|
+
sage: MR.equivalent_rep(A)
|
|
496
|
+
[ 1 -1]
|
|
497
|
+
[-1 2]
|
|
498
|
+
sage: MR.P1().normalize(3,16)
|
|
499
|
+
(1, 9)
|
|
500
|
+
"""
|
|
501
|
+
return self._equiv_ind[self._P.normalize(A[t10], A[t11])]
|
|
502
|
+
|
|
503
|
+
def equivalent_rep(self, A):
|
|
504
|
+
r"""
|
|
505
|
+
Return a coset representative that is equivalent to ``A`` modulo
|
|
506
|
+
`\Gamma_0(N)`.
|
|
507
|
+
|
|
508
|
+
INPUT:
|
|
509
|
+
|
|
510
|
+
- ``A`` -- a matrix in `SL_2(\ZZ)`
|
|
511
|
+
|
|
512
|
+
OUTPUT:
|
|
513
|
+
|
|
514
|
+
The unique generator congruent to ``A`` modulo `\Gamma_0(N)`.
|
|
515
|
+
|
|
516
|
+
EXAMPLES::
|
|
517
|
+
|
|
518
|
+
sage: from sage.modular.pollack_stevens.fund_domain import ManinRelations
|
|
519
|
+
sage: A = matrix([[5,3],[38,23]])
|
|
520
|
+
sage: ManinRelations(60).equivalent_rep(A)
|
|
521
|
+
[-7 -3]
|
|
522
|
+
[26 11]
|
|
523
|
+
"""
|
|
524
|
+
return self._reps[self.equivalent_index(A)]
|
|
525
|
+
|
|
526
|
+
def P1(self):
|
|
527
|
+
r"""
|
|
528
|
+
Return the Sage representation of `P^1(\ZZ/N\ZZ)`.
|
|
529
|
+
|
|
530
|
+
EXAMPLES::
|
|
531
|
+
|
|
532
|
+
sage: from sage.modular.pollack_stevens.fund_domain import ManinRelations
|
|
533
|
+
sage: A = ManinRelations(11)
|
|
534
|
+
sage: A.P1()
|
|
535
|
+
The projective line over the integers modulo 11
|
|
536
|
+
"""
|
|
537
|
+
return self._P
|
|
538
|
+
|
|
539
|
+
|
|
540
|
+
class ManinRelations(PollackStevensModularDomain):
|
|
541
|
+
r"""
|
|
542
|
+
This class gives a description of `Div^0(P^1(\QQ))` as a
|
|
543
|
+
`\ZZ[\Gamma_0(N)]`-module.
|
|
544
|
+
|
|
545
|
+
INPUT:
|
|
546
|
+
|
|
547
|
+
- ``N`` -- positive integer, the level of `\Gamma_0(N)` to work with
|
|
548
|
+
|
|
549
|
+
EXAMPLES::
|
|
550
|
+
|
|
551
|
+
sage: from sage.modular.pollack_stevens.fund_domain import ManinRelations
|
|
552
|
+
sage: ManinRelations(1)
|
|
553
|
+
Manin Relations of level 1
|
|
554
|
+
sage: ManinRelations(11)
|
|
555
|
+
Manin Relations of level 11
|
|
556
|
+
|
|
557
|
+
Large values of ``N`` are not supported::
|
|
558
|
+
|
|
559
|
+
sage: ManinRelations(2^20)
|
|
560
|
+
Traceback (most recent call last):
|
|
561
|
+
...
|
|
562
|
+
OverflowError: Modulus is too large (must be <= 46340)
|
|
563
|
+
|
|
564
|
+
TESTS:
|
|
565
|
+
|
|
566
|
+
``N`` has to be a positive integer::
|
|
567
|
+
|
|
568
|
+
sage: ManinRelations(0)
|
|
569
|
+
Traceback (most recent call last):
|
|
570
|
+
...
|
|
571
|
+
ValueError: N must be a positive integer
|
|
572
|
+
sage: ManinRelations(-5)
|
|
573
|
+
Traceback (most recent call last):
|
|
574
|
+
...
|
|
575
|
+
ValueError: N must be a positive integer
|
|
576
|
+
"""
|
|
577
|
+
def __init__(self, N):
|
|
578
|
+
r"""
|
|
579
|
+
Create an instance of this class.
|
|
580
|
+
|
|
581
|
+
INPUT:
|
|
582
|
+
|
|
583
|
+
- ``N`` -- positive integer; the level of `\Gamma_0(N)` to work with
|
|
584
|
+
|
|
585
|
+
EXAMPLES::
|
|
586
|
+
|
|
587
|
+
sage: from sage.modular.pollack_stevens.fund_domain import ManinRelations
|
|
588
|
+
sage: type(ManinRelations(30))
|
|
589
|
+
<class 'sage.modular.pollack_stevens.fund_domain.ManinRelations'>
|
|
590
|
+
"""
|
|
591
|
+
N = ZZ(N)
|
|
592
|
+
if N <= 0:
|
|
593
|
+
raise ValueError("N must be a positive integer")
|
|
594
|
+
self._N = N
|
|
595
|
+
SN = Sigma0(N)
|
|
596
|
+
|
|
597
|
+
# Creates and stores the Sage representation of P^1(Z/NZ)
|
|
598
|
+
P = P1List(N)
|
|
599
|
+
self._P = P
|
|
600
|
+
IdN = SN([1, 0, 0, 1])
|
|
601
|
+
|
|
602
|
+
# Creates a fundamental domain for Gamma_0(N) whose boundary
|
|
603
|
+
# is a union of unimodular paths (except in the case of
|
|
604
|
+
# 3-torsion). We will call the intersection of this domain
|
|
605
|
+
# with the real axis the collection of cusps (even if some
|
|
606
|
+
# are Gamma_0(N) equivalent to one another).
|
|
607
|
+
cusps = self.form_list_of_cusps()
|
|
608
|
+
|
|
609
|
+
# Takes the boundary of this fundamental domain and finds
|
|
610
|
+
# SL_2(Z) matrices whose associated unimodular path gives
|
|
611
|
+
# this boundary. These matrices form the beginning of our
|
|
612
|
+
# collection of coset reps for Gamma_0(N) / SL_2(Z).
|
|
613
|
+
coset_reps = self.fd_boundary(cusps)
|
|
614
|
+
|
|
615
|
+
# Takes the bottom row of each of our current coset reps,
|
|
616
|
+
# thinking of them as distinct elements of P^1(Z/NZ)
|
|
617
|
+
p1s = [(coset_reps[j])[1] for j in range(len(coset_reps))]
|
|
618
|
+
|
|
619
|
+
# Initializes relevant Manin data
|
|
620
|
+
gens_index = []
|
|
621
|
+
twotor_index = []
|
|
622
|
+
twotorrels = []
|
|
623
|
+
threetor_index = []
|
|
624
|
+
threetorrels = []
|
|
625
|
+
rels = [0] * len(coset_reps)
|
|
626
|
+
gammas = {}
|
|
627
|
+
|
|
628
|
+
# the list rels (above) will give Z[Gamma_0(N)] relations between
|
|
629
|
+
# the associated divisor of each coset representatives in terms
|
|
630
|
+
# of our chosen set of generators.
|
|
631
|
+
# entries of rels will be lists of elements of the form (c,A,r)
|
|
632
|
+
# with c a constant, A a Gamma_0(N) matrix, and r the index of a
|
|
633
|
+
# generator. The meaning is that the divisor associated to the
|
|
634
|
+
# j-th coset rep will equal the sum of:
|
|
635
|
+
##
|
|
636
|
+
# c * A^(-1) * (divisor associated to r-th coset rep)
|
|
637
|
+
##
|
|
638
|
+
# as one varies over all (c,A,r) in rels[j].
|
|
639
|
+
# (Here r must be in self.generator_indices().)
|
|
640
|
+
##
|
|
641
|
+
# This will be used for modular symbols as then the value of a
|
|
642
|
+
# modular symbol phi on the (associated divisor) of the j-th
|
|
643
|
+
# element of coset_reps will be the sum of c * phi (r-th generator) | A
|
|
644
|
+
# as one varies over the tuples in rels[j]
|
|
645
|
+
|
|
646
|
+
boundary_checked = [False] * len(coset_reps)
|
|
647
|
+
|
|
648
|
+
# The list boundary_checked keeps track of which boundary pieces of the
|
|
649
|
+
# fundamental domain have been already used as we are picking
|
|
650
|
+
# our generators
|
|
651
|
+
|
|
652
|
+
# The following loop will choose our generators by picking one edge
|
|
653
|
+
# out of each pair of edges that are glued to each other and picking
|
|
654
|
+
# each edge glued to itself (arising from two-torsion)
|
|
655
|
+
# ------------------------------------------------------------------
|
|
656
|
+
for r in range(len(coset_reps)):
|
|
657
|
+
if not boundary_checked[r]:
|
|
658
|
+
|
|
659
|
+
# We now check if this boundary edge is glued to itself by
|
|
660
|
+
# Gamma_0(N)
|
|
661
|
+
|
|
662
|
+
if P.normalize(p1s[r][0], p1s[r][1]) == P.normalize(-p1s[r][1], p1s[r][0]):
|
|
663
|
+
# This edge is glued to itself and so coset_reps[r]
|
|
664
|
+
# needs to be added to our generator list.
|
|
665
|
+
|
|
666
|
+
# this relation expresses the fact that
|
|
667
|
+
# coset_reps[r] is one of our basic generators
|
|
668
|
+
rels[r] = [(1, IdN, r)]
|
|
669
|
+
|
|
670
|
+
# the index r is adding to our list
|
|
671
|
+
# of indexes of generators
|
|
672
|
+
gens_index.append(r)
|
|
673
|
+
|
|
674
|
+
# the index r is adding to our list of indexes of
|
|
675
|
+
# generators which satisfy a 2-torsion relation
|
|
676
|
+
twotor_index.append(r)
|
|
677
|
+
|
|
678
|
+
# we use the adjugate instead of the inverse for speed
|
|
679
|
+
gam = SN(coset_reps[r] * sig * coset_reps[r].adjugate())
|
|
680
|
+
# gam is 2-torsion matrix and in Gamma_0(N).
|
|
681
|
+
# if D is the divisor associated to coset_reps[r]
|
|
682
|
+
# then gam * D = - D and so (1+gam)D=0.
|
|
683
|
+
|
|
684
|
+
# This gives a restriction to the possible values of
|
|
685
|
+
# modular symbols on D
|
|
686
|
+
|
|
687
|
+
# The 2-torsion matrix gam is recorded in our list of
|
|
688
|
+
# 2-torsion relations.
|
|
689
|
+
twotorrels.append(gam)
|
|
690
|
+
|
|
691
|
+
# We have now finished with this edge.
|
|
692
|
+
boundary_checked[r] = True
|
|
693
|
+
|
|
694
|
+
else:
|
|
695
|
+
c = coset_reps[r][t10]
|
|
696
|
+
d = coset_reps[r][t11]
|
|
697
|
+
|
|
698
|
+
# In the following case the ideal triangle below
|
|
699
|
+
# the unimodular path described by coset_reps[r]
|
|
700
|
+
# contains a point fixed by a 3-torsion element.
|
|
701
|
+
if (c ** 2 + d ** 2 + c * d) % N == 0:
|
|
702
|
+
|
|
703
|
+
# the index r is adding to our list of indexes
|
|
704
|
+
# of generators
|
|
705
|
+
gens_index.append(r)
|
|
706
|
+
|
|
707
|
+
# this relation expresses the fact that coset_reps[r]
|
|
708
|
+
# is one of our basic generators
|
|
709
|
+
rels[r] = [(1, IdN, r)]
|
|
710
|
+
|
|
711
|
+
# the index r is adding to our list of indexes of
|
|
712
|
+
# generators which satisfy a 3-torsion relation
|
|
713
|
+
threetor_index.append(r)
|
|
714
|
+
|
|
715
|
+
# Use the adjugate instead of the inverse for speed.
|
|
716
|
+
gam = SN(coset_reps[r] * tau * coset_reps[r].adjugate())
|
|
717
|
+
# gam is 3-torsion matrix and in Gamma_0(N).
|
|
718
|
+
# if D is the divisor associated to coset_reps[r]
|
|
719
|
+
# then (1+gam+gam^2)D=0.
|
|
720
|
+
# This gives a restriction to the possible values of
|
|
721
|
+
# modular symbols on D
|
|
722
|
+
|
|
723
|
+
# The 3-torsion matrix gam is recorded in our list of
|
|
724
|
+
# 3-torsion relations.
|
|
725
|
+
threetorrels.append(gam)
|
|
726
|
+
|
|
727
|
+
# The reverse of the unimodular path associated to
|
|
728
|
+
# coset_reps[r] is not Gamma_0(N) equivalent to it, so
|
|
729
|
+
# we need to include it in our list of coset
|
|
730
|
+
# representatives and record the relevant relations.
|
|
731
|
+
|
|
732
|
+
a = coset_reps[r][t00]
|
|
733
|
+
b = coset_reps[r][t01]
|
|
734
|
+
|
|
735
|
+
A = M2Z([-b, a, -d, c])
|
|
736
|
+
coset_reps.append(A)
|
|
737
|
+
# A (representing the reversed edge) is included in
|
|
738
|
+
# our list of coset reps
|
|
739
|
+
|
|
740
|
+
rels.append([(-1, IdN, r)])
|
|
741
|
+
# This relation means that phi on the reversed edge
|
|
742
|
+
# equals -phi on original edge
|
|
743
|
+
|
|
744
|
+
boundary_checked[r] = True
|
|
745
|
+
# We have now finished with this edge.
|
|
746
|
+
|
|
747
|
+
else:
|
|
748
|
+
# This is the generic case where neither 2 or
|
|
749
|
+
# 3-torsion intervenes.
|
|
750
|
+
# The below loop searches through the remaining edges
|
|
751
|
+
# and finds which one is equivalent to the reverse of
|
|
752
|
+
# coset_reps[r]
|
|
753
|
+
# ---------------------------------------------------
|
|
754
|
+
for s in range(r + 1, len(coset_reps)):
|
|
755
|
+
if boundary_checked[s]:
|
|
756
|
+
continue
|
|
757
|
+
if P.normalize(p1s[s][0], p1s[s][1]) == P.normalize(-p1s[r][1], p1s[r][0]):
|
|
758
|
+
# the reverse of coset_reps[r] is
|
|
759
|
+
# Gamma_0(N)-equivalent to coset_reps[s]
|
|
760
|
+
# coset_reps[r] will now be made a generator
|
|
761
|
+
# and we need to express phi(coset_reps[s])
|
|
762
|
+
# in terms of phi(coset_reps[r])
|
|
763
|
+
|
|
764
|
+
gens_index.append(r)
|
|
765
|
+
# the index r is adding to our list of
|
|
766
|
+
# indexes of generators
|
|
767
|
+
|
|
768
|
+
rels[r] = [(1, IdN, r)]
|
|
769
|
+
# this relation expresses the fact that
|
|
770
|
+
# coset_reps[r] is one of our basic generators
|
|
771
|
+
|
|
772
|
+
A = coset_reps[s] * sig
|
|
773
|
+
# A corresponds to reversing the orientation
|
|
774
|
+
# of the edge corr. to coset_reps[r]
|
|
775
|
+
# Use adjugate instead of inverse for speed
|
|
776
|
+
gam = SN(coset_reps[r] * A.adjugate())
|
|
777
|
+
# gam is in Gamma_0(N) (by assumption of
|
|
778
|
+
# ending up here in this if statement)
|
|
779
|
+
|
|
780
|
+
rels[s] = [(-1, gam, r)]
|
|
781
|
+
# this relation means that phi evaluated on
|
|
782
|
+
# coset_reps[s] equals -phi(coset_reps[r])|gam
|
|
783
|
+
# To see this, let D_r be the divisor
|
|
784
|
+
# associated to coset_reps[r] and D_s to
|
|
785
|
+
# coset_reps[s]. Then gam D_s = -D_r and so
|
|
786
|
+
# phi(gam D_s) = - phi(D_r) and thus
|
|
787
|
+
# phi(D_s) = -phi(D_r)|gam
|
|
788
|
+
# since gam is in Gamma_0(N)
|
|
789
|
+
|
|
790
|
+
gammas[coset_reps[r]] = gam
|
|
791
|
+
# this is a dictionary whose keys are the
|
|
792
|
+
# non-torsion generators and whose values
|
|
793
|
+
# are the corresponding gamma_i. It is
|
|
794
|
+
# eventually stored as self.gammas.
|
|
795
|
+
|
|
796
|
+
boundary_checked[r] = True
|
|
797
|
+
boundary_checked[s] = True
|
|
798
|
+
break
|
|
799
|
+
|
|
800
|
+
# We now need to complete our list of coset representatives by
|
|
801
|
+
# finding all unimodular paths in the interior of the fundamental
|
|
802
|
+
# domain, as well as express these paths in terms of our chosen set
|
|
803
|
+
# of generators.
|
|
804
|
+
# -------------------------------------------------------------------
|
|
805
|
+
|
|
806
|
+
for r in range(len(cusps) - 2):
|
|
807
|
+
# r is the index of the cusp on the left of the path. We only run
|
|
808
|
+
# thru to the number of cusps - 2 since you cannot start an
|
|
809
|
+
# interior path on either of the last two cusps
|
|
810
|
+
|
|
811
|
+
for s in range(r + 2, len(cusps)):
|
|
812
|
+
# s is in the index of the cusp on the right of the path
|
|
813
|
+
cusp1 = cusps[r]
|
|
814
|
+
cusp2 = cusps[s]
|
|
815
|
+
if self.is_unimodular_path(cusp1, cusp2):
|
|
816
|
+
A, B = self.unimod_to_matrices(cusp1, cusp2)
|
|
817
|
+
# A and B are the matrices whose associated paths
|
|
818
|
+
# connect cusp1 to cusp2 and cusp2 to cusp1 (respectively)
|
|
819
|
+
coset_reps.extend([A, B])
|
|
820
|
+
# A and B are added to our coset reps
|
|
821
|
+
vA = []
|
|
822
|
+
vB = []
|
|
823
|
+
|
|
824
|
+
# This loop now encodes the relation between the
|
|
825
|
+
# unimodular path A and our generators. This is done
|
|
826
|
+
# simply by accounting for all of the edges that lie
|
|
827
|
+
# below the path attached to A (as they form a triangle)
|
|
828
|
+
# Similarly, this is also done for B.
|
|
829
|
+
|
|
830
|
+
# Running between the cusps between cusp1 and cusp2
|
|
831
|
+
for rel in rels[r + 2: s + 2]:
|
|
832
|
+
# Add edge relation
|
|
833
|
+
vA.append(rel[0])
|
|
834
|
+
# Add negative of edge relation
|
|
835
|
+
vB.append((-rel[0][0], rel[0][1], rel[0][2]))
|
|
836
|
+
# Add relations for A and B to relations list
|
|
837
|
+
rels.extend([vA, vB])
|
|
838
|
+
|
|
839
|
+
# Make the translation table between the Sage and Geometric
|
|
840
|
+
# descriptions of P^1
|
|
841
|
+
equiv_ind = {}
|
|
842
|
+
for i, rep in enumerate(coset_reps):
|
|
843
|
+
ky = P.normalize(rep[t10], rep[t11])
|
|
844
|
+
equiv_ind[ky] = i
|
|
845
|
+
|
|
846
|
+
self.gammas = gammas
|
|
847
|
+
PollackStevensModularDomain.__init__(self, N, coset_reps, gens_index,
|
|
848
|
+
rels, equiv_ind)
|
|
849
|
+
|
|
850
|
+
# A list of indices of the (geometric) coset representatives whose
|
|
851
|
+
# paths are identified by some 2-torsion element (which switches the
|
|
852
|
+
# path orientation)
|
|
853
|
+
self._indices_with_two_torsion = twotor_index
|
|
854
|
+
self._reps_with_two_torsion = [coset_reps[i] for i in twotor_index]
|
|
855
|
+
|
|
856
|
+
# A dictionary of (2-torsion in PSL_2(Z)) matrices in
|
|
857
|
+
# Gamma_0(N) that give the orientation identification in the
|
|
858
|
+
# paths listed in twotor_index above!
|
|
859
|
+
self._two_torsion = {}
|
|
860
|
+
for j, tor_elt in zip(twotor_index, twotorrels):
|
|
861
|
+
self._two_torsion[coset_reps[j]] = tor_elt
|
|
862
|
+
|
|
863
|
+
# A list of indices of the (geometric) coset representatives that
|
|
864
|
+
# form one side of an ideal triangle with an interior fixed point of
|
|
865
|
+
# a 3-torsion element of Gamma_0(N)
|
|
866
|
+
self._indices_with_three_torsion = threetor_index
|
|
867
|
+
self._reps_with_three_torsion = [coset_reps[i] for i in threetor_index]
|
|
868
|
+
|
|
869
|
+
# A dictionary of (3-torsion in PSL_2(Z)) matrices in
|
|
870
|
+
# Gamma_0(N) that give the interior fixed point described in
|
|
871
|
+
# threetor_index above!
|
|
872
|
+
self._three_torsion = {}
|
|
873
|
+
for j, tor_elt in zip(threetor_index, threetorrels):
|
|
874
|
+
self._three_torsion[coset_reps[j]] = tor_elt
|
|
875
|
+
|
|
876
|
+
def _repr_(self):
|
|
877
|
+
r"""
|
|
878
|
+
A printable representation of this domain.
|
|
879
|
+
|
|
880
|
+
EXAMPLES::
|
|
881
|
+
|
|
882
|
+
sage: from sage.modular.pollack_stevens.fund_domain import ManinRelations
|
|
883
|
+
sage: ManinRelations(11)._repr_()
|
|
884
|
+
'Manin Relations of level 11'
|
|
885
|
+
"""
|
|
886
|
+
return "Manin Relations of level %s" % self._N
|
|
887
|
+
|
|
888
|
+
def indices_with_two_torsion(self):
|
|
889
|
+
r"""
|
|
890
|
+
Return the indices of coset representatives whose associated unimodular path
|
|
891
|
+
contains a point fixed by a `\Gamma_0(N)` element of order 2 (where the
|
|
892
|
+
order is computed in `PSL_2(\ZZ)`).
|
|
893
|
+
|
|
894
|
+
OUTPUT: list of integers
|
|
895
|
+
|
|
896
|
+
EXAMPLES::
|
|
897
|
+
|
|
898
|
+
sage: from sage.modular.pollack_stevens.fund_domain import ManinRelations
|
|
899
|
+
sage: MR = ManinRelations(11)
|
|
900
|
+
sage: MR.indices_with_two_torsion()
|
|
901
|
+
[]
|
|
902
|
+
sage: MR = ManinRelations(13)
|
|
903
|
+
sage: MR.indices_with_two_torsion()
|
|
904
|
+
[3, 4]
|
|
905
|
+
sage: MR.reps(3), MR.reps(4)
|
|
906
|
+
(
|
|
907
|
+
[-1 -1] [-1 -2]
|
|
908
|
+
[ 3 2], [ 2 3]
|
|
909
|
+
)
|
|
910
|
+
|
|
911
|
+
The corresponding matrix of order 2::
|
|
912
|
+
|
|
913
|
+
sage: A = MR.two_torsion_matrix(MR.reps(3)); A
|
|
914
|
+
[ 5 2]
|
|
915
|
+
[-13 -5]
|
|
916
|
+
sage: A^2
|
|
917
|
+
[-1 0]
|
|
918
|
+
[ 0 -1]
|
|
919
|
+
|
|
920
|
+
You can see that multiplication by ``A`` just interchanges the rational
|
|
921
|
+
cusps determined by the columns of the matrix ``MR.reps(3)``::
|
|
922
|
+
|
|
923
|
+
sage: MR.reps(3), A*MR.reps(3)
|
|
924
|
+
(
|
|
925
|
+
[-1 -1] [ 1 -1]
|
|
926
|
+
[ 3 2], [-2 3]
|
|
927
|
+
)
|
|
928
|
+
"""
|
|
929
|
+
return self._indices_with_two_torsion
|
|
930
|
+
|
|
931
|
+
def reps_with_two_torsion(self):
|
|
932
|
+
r"""
|
|
933
|
+
The coset representatives whose associated unimodular path contains a
|
|
934
|
+
point fixed by a `\Gamma_0(N)` element of order 2 (where the order is
|
|
935
|
+
computed in `PSL_2(\ZZ)`).
|
|
936
|
+
|
|
937
|
+
OUTPUT: list of matrices
|
|
938
|
+
|
|
939
|
+
EXAMPLES::
|
|
940
|
+
|
|
941
|
+
sage: from sage.modular.pollack_stevens.fund_domain import ManinRelations
|
|
942
|
+
sage: MR = ManinRelations(11)
|
|
943
|
+
sage: MR.reps_with_two_torsion()
|
|
944
|
+
[]
|
|
945
|
+
sage: MR = ManinRelations(13)
|
|
946
|
+
sage: MR.reps_with_two_torsion()
|
|
947
|
+
[
|
|
948
|
+
[-1 -1] [-1 -2]
|
|
949
|
+
[ 3 2], [ 2 3]
|
|
950
|
+
]
|
|
951
|
+
sage: B = MR.reps_with_two_torsion()[0]
|
|
952
|
+
|
|
953
|
+
The corresponding matrix of order 2::
|
|
954
|
+
|
|
955
|
+
sage: A = MR.two_torsion_matrix(B); A
|
|
956
|
+
[ 5 2]
|
|
957
|
+
[-13 -5]
|
|
958
|
+
sage: A^2
|
|
959
|
+
[-1 0]
|
|
960
|
+
[ 0 -1]
|
|
961
|
+
|
|
962
|
+
You can see that multiplication by ``A`` just interchanges the rational
|
|
963
|
+
cusps determined by the columns of the matrix ``MR.reps(3)``::
|
|
964
|
+
|
|
965
|
+
sage: B, A*B
|
|
966
|
+
(
|
|
967
|
+
[-1 -1] [ 1 -1]
|
|
968
|
+
[ 3 2], [-2 3]
|
|
969
|
+
)
|
|
970
|
+
"""
|
|
971
|
+
return self._reps_with_two_torsion
|
|
972
|
+
|
|
973
|
+
def two_torsion_matrix(self, A):
|
|
974
|
+
r"""
|
|
975
|
+
Return the matrix of order two in `\Gamma_0(N)` which
|
|
976
|
+
corresponds to an ``A`` in ``self.reps_with_two_torsion()``.
|
|
977
|
+
|
|
978
|
+
INPUT:
|
|
979
|
+
|
|
980
|
+
- ``A`` -- a matrix in ``self.reps_with_two_torsion()``
|
|
981
|
+
|
|
982
|
+
EXAMPLES::
|
|
983
|
+
|
|
984
|
+
sage: from sage.modular.pollack_stevens.fund_domain import ManinRelations
|
|
985
|
+
sage: MR = ManinRelations(25)
|
|
986
|
+
sage: B = MR.reps_with_two_torsion()[0]
|
|
987
|
+
|
|
988
|
+
The corresponding matrix of order 2::
|
|
989
|
+
|
|
990
|
+
sage: A = MR.two_torsion_matrix(B); A
|
|
991
|
+
[ 7 2]
|
|
992
|
+
[-25 -7]
|
|
993
|
+
sage: A^2
|
|
994
|
+
[-1 0]
|
|
995
|
+
[ 0 -1]
|
|
996
|
+
"""
|
|
997
|
+
return self._two_torsion[A]
|
|
998
|
+
|
|
999
|
+
def indices_with_three_torsion(self):
|
|
1000
|
+
r"""
|
|
1001
|
+
A list of indices of coset representatives whose associated unimodular
|
|
1002
|
+
path contains a point fixed by a `\Gamma_0(N)` element of order 3 in
|
|
1003
|
+
the ideal triangle directly below that path (the order is computed in
|
|
1004
|
+
`PSL_2(\ZZ)`).
|
|
1005
|
+
|
|
1006
|
+
EXAMPLES::
|
|
1007
|
+
|
|
1008
|
+
sage: from sage.modular.pollack_stevens.fund_domain import ManinRelations
|
|
1009
|
+
sage: MR = ManinRelations(11)
|
|
1010
|
+
sage: MR.indices_with_three_torsion()
|
|
1011
|
+
[]
|
|
1012
|
+
sage: MR = ManinRelations(13)
|
|
1013
|
+
sage: MR.indices_with_three_torsion()
|
|
1014
|
+
[2, 5]
|
|
1015
|
+
sage: B = MR.reps(2); B
|
|
1016
|
+
[ 0 -1]
|
|
1017
|
+
[ 1 3]
|
|
1018
|
+
|
|
1019
|
+
The corresponding matrix of order three::
|
|
1020
|
+
|
|
1021
|
+
sage: A = MR.three_torsion_matrix(B); A
|
|
1022
|
+
[-4 -1]
|
|
1023
|
+
[13 3]
|
|
1024
|
+
sage: A^3
|
|
1025
|
+
[1 0]
|
|
1026
|
+
[0 1]
|
|
1027
|
+
|
|
1028
|
+
The columns of ``B`` and the columns of ``A*B`` and ``A^2*B`` give the
|
|
1029
|
+
same rational cusps::
|
|
1030
|
+
|
|
1031
|
+
sage: B
|
|
1032
|
+
[ 0 -1]
|
|
1033
|
+
[ 1 3]
|
|
1034
|
+
sage: A*B, A^2*B
|
|
1035
|
+
(
|
|
1036
|
+
[-1 1] [ 1 0]
|
|
1037
|
+
[ 3 -4], [-4 1]
|
|
1038
|
+
)
|
|
1039
|
+
"""
|
|
1040
|
+
return self._indices_with_three_torsion
|
|
1041
|
+
|
|
1042
|
+
def reps_with_three_torsion(self):
|
|
1043
|
+
r"""
|
|
1044
|
+
A list of coset representatives whose associated unimodular
|
|
1045
|
+
path contains a point fixed by a `\Gamma_0(N)` element of
|
|
1046
|
+
order 3 in the ideal triangle directly below that path (the
|
|
1047
|
+
order is computed in `PSL_2(\ZZ)`).
|
|
1048
|
+
|
|
1049
|
+
EXAMPLES::
|
|
1050
|
+
|
|
1051
|
+
sage: from sage.modular.pollack_stevens.fund_domain import ManinRelations
|
|
1052
|
+
sage: MR = ManinRelations(13)
|
|
1053
|
+
sage: B = MR.reps_with_three_torsion()[0]; B
|
|
1054
|
+
[ 0 -1]
|
|
1055
|
+
[ 1 3]
|
|
1056
|
+
|
|
1057
|
+
The corresponding matrix of order three::
|
|
1058
|
+
|
|
1059
|
+
sage: A = MR.three_torsion_matrix(B); A
|
|
1060
|
+
[-4 -1]
|
|
1061
|
+
[13 3]
|
|
1062
|
+
sage: A^3
|
|
1063
|
+
[1 0]
|
|
1064
|
+
[0 1]
|
|
1065
|
+
|
|
1066
|
+
The columns of ``B`` and the columns of ``A*B`` and ``A^2*B``
|
|
1067
|
+
give the same rational cusps::
|
|
1068
|
+
|
|
1069
|
+
sage: B
|
|
1070
|
+
[ 0 -1]
|
|
1071
|
+
[ 1 3]
|
|
1072
|
+
sage: A*B, A^2*B
|
|
1073
|
+
(
|
|
1074
|
+
[-1 1] [ 1 0]
|
|
1075
|
+
[ 3 -4], [-4 1]
|
|
1076
|
+
)
|
|
1077
|
+
"""
|
|
1078
|
+
return self._reps_with_three_torsion
|
|
1079
|
+
|
|
1080
|
+
def three_torsion_matrix(self, A):
|
|
1081
|
+
r"""
|
|
1082
|
+
Return the matrix of order two in `\Gamma_0(N)` which
|
|
1083
|
+
corresponds to an ``A`` in ``self.reps_with_two_torsion()``.
|
|
1084
|
+
|
|
1085
|
+
INPUT:
|
|
1086
|
+
|
|
1087
|
+
- ``A`` -- a matrix in ``self.reps_with_two_torsion()``
|
|
1088
|
+
|
|
1089
|
+
EXAMPLES::
|
|
1090
|
+
|
|
1091
|
+
sage: from sage.modular.pollack_stevens.fund_domain import ManinRelations
|
|
1092
|
+
sage: MR = ManinRelations(37)
|
|
1093
|
+
sage: B = MR.reps_with_three_torsion()[0]
|
|
1094
|
+
|
|
1095
|
+
The corresponding matrix of order 3::
|
|
1096
|
+
|
|
1097
|
+
sage: A = MR.three_torsion_matrix(B); A
|
|
1098
|
+
[-11 -3]
|
|
1099
|
+
[ 37 10]
|
|
1100
|
+
sage: A^3
|
|
1101
|
+
[1 0]
|
|
1102
|
+
[0 1]
|
|
1103
|
+
"""
|
|
1104
|
+
return self._three_torsion[A]
|
|
1105
|
+
|
|
1106
|
+
def form_list_of_cusps(self):
|
|
1107
|
+
r"""
|
|
1108
|
+
Return the intersection of a fundamental domain for `\Gamma_0(N)` with
|
|
1109
|
+
the real axis.
|
|
1110
|
+
|
|
1111
|
+
The construction of this fundamental domain follows the arguments of
|
|
1112
|
+
[PS2011]_ Section 2. The boundary of this fundamental domain consists
|
|
1113
|
+
entirely of unimodular paths when `\Gamma_0(N)` has no elements of
|
|
1114
|
+
order 3. (See [PS2011]_ Section 2.5 for the case when there are
|
|
1115
|
+
elements of order 3.)
|
|
1116
|
+
|
|
1117
|
+
OUTPUT:
|
|
1118
|
+
|
|
1119
|
+
A sorted list of rational numbers marking the intersection of a
|
|
1120
|
+
fundamental domain for `\Gamma_0(N)` with the real axis.
|
|
1121
|
+
|
|
1122
|
+
EXAMPLES::
|
|
1123
|
+
|
|
1124
|
+
sage: from sage.modular.pollack_stevens.fund_domain import ManinRelations
|
|
1125
|
+
sage: A = ManinRelations(11)
|
|
1126
|
+
sage: A.form_list_of_cusps()
|
|
1127
|
+
[-1, -2/3, -1/2, -1/3, 0]
|
|
1128
|
+
sage: A = ManinRelations(13)
|
|
1129
|
+
sage: A.form_list_of_cusps()
|
|
1130
|
+
[-1, -2/3, -1/2, -1/3, 0]
|
|
1131
|
+
sage: A = ManinRelations(101)
|
|
1132
|
+
sage: A.form_list_of_cusps()
|
|
1133
|
+
[-1, -6/7, -5/6, -4/5, -7/9, -3/4, -11/15, -8/11, -5/7, -7/10,
|
|
1134
|
+
-9/13, -2/3, -5/8, -13/21, -8/13, -3/5, -7/12, -11/19, -4/7, -1/2,
|
|
1135
|
+
-4/9, -3/7, -5/12, -7/17, -2/5, -3/8, -4/11, -1/3, -2/7, -3/11,
|
|
1136
|
+
-1/4, -2/9, -1/5, -1/6, 0]
|
|
1137
|
+
"""
|
|
1138
|
+
# Get the level
|
|
1139
|
+
N = self.level()
|
|
1140
|
+
|
|
1141
|
+
# Some convenient shortcuts
|
|
1142
|
+
P = self.P1()
|
|
1143
|
+
sP = len(P.list()) # Size of P^1(Z/NZ)
|
|
1144
|
+
|
|
1145
|
+
# Initialize some lists
|
|
1146
|
+
|
|
1147
|
+
C = [QQ(-1), "?", QQ.zero()]
|
|
1148
|
+
|
|
1149
|
+
# Initialize the list of cusps at the bottom of the fund. domain.
|
|
1150
|
+
# The ? denotes that it has not yet been checked if more cusps need
|
|
1151
|
+
# to be added between the surrounding cusps.
|
|
1152
|
+
|
|
1153
|
+
full_domain = False # Says that we are not done yet!
|
|
1154
|
+
|
|
1155
|
+
v = [False] * sP
|
|
1156
|
+
# This initializes a list indexed by P^1(Z/NZ) which keeps track of
|
|
1157
|
+
# which right coset representatives we've found for Gamma_0(N)/SL_2(Z)
|
|
1158
|
+
# thru the construction of a fundamental domain
|
|
1159
|
+
|
|
1160
|
+
# Includes the coset repns formed by the original ideal triangle
|
|
1161
|
+
# (with corners at -1, 0, infty)
|
|
1162
|
+
|
|
1163
|
+
v[P.index(0, 1)] = True
|
|
1164
|
+
v[P.index(1, -1)] = True
|
|
1165
|
+
v[P.index(-1, 0)] = True
|
|
1166
|
+
|
|
1167
|
+
# Main Loop -- Ideal Triangle Flipping
|
|
1168
|
+
# ====================================
|
|
1169
|
+
while (not full_domain):
|
|
1170
|
+
full_domain = True
|
|
1171
|
+
|
|
1172
|
+
# This loop runs through the current set of cusps
|
|
1173
|
+
# and checks to see if more cusps should be added
|
|
1174
|
+
# -----------------------------------------------
|
|
1175
|
+
for s in range(1, len(C), 2):
|
|
1176
|
+
# range over odd indices in the final list C
|
|
1177
|
+
if C[s] == "?":
|
|
1178
|
+
|
|
1179
|
+
# Single out our two cusps (path from cusp2 to cusp1)
|
|
1180
|
+
cusp1 = C[s - 1]
|
|
1181
|
+
cusp2 = C[s + 1]
|
|
1182
|
+
|
|
1183
|
+
# Makes the unimodular transform for the path from cusp2
|
|
1184
|
+
# to cusp1
|
|
1185
|
+
|
|
1186
|
+
b1 = cusp1.denominator()
|
|
1187
|
+
b2 = cusp2.denominator()
|
|
1188
|
+
|
|
1189
|
+
# This is the point where it is determined whether
|
|
1190
|
+
# or not the adjacent triangle should be added
|
|
1191
|
+
# ------------------------------------------------
|
|
1192
|
+
pos = P.index(b2, b1)
|
|
1193
|
+
# The Sage index of the bottom row of our
|
|
1194
|
+
# unimodular transformation gam
|
|
1195
|
+
|
|
1196
|
+
# Check if we need to flip (since this P1 element has not
|
|
1197
|
+
# yet been accounted for!)
|
|
1198
|
+
if not v[pos]:
|
|
1199
|
+
v[pos] = True # Say this P1 element now occurs
|
|
1200
|
+
v[P.index(b1, -(b1 + b2))] = True
|
|
1201
|
+
# Say that the other two ideal triangle edges
|
|
1202
|
+
# also occur!
|
|
1203
|
+
|
|
1204
|
+
v[P.index(-(b1 + b2), b2)] = True
|
|
1205
|
+
|
|
1206
|
+
# Check to see if this triangle contains a fixed
|
|
1207
|
+
# point by an element of Gamma_0(N). If such an
|
|
1208
|
+
# element is present, the fundamental domain can be
|
|
1209
|
+
# extended no further.
|
|
1210
|
+
|
|
1211
|
+
if (b1 ** 2 + b2 ** 2 + b1 * b2) % N != 0:
|
|
1212
|
+
|
|
1213
|
+
# this congruence is exactly equivalent to
|
|
1214
|
+
# gam * [0 -1; 1 -1] * gam^(-1) is in Gamma_0(N)
|
|
1215
|
+
# where gam is the matrix corresponding to the
|
|
1216
|
+
# unimodular path connecting cusp1 to cusp2
|
|
1217
|
+
|
|
1218
|
+
C[s] = "i"
|
|
1219
|
+
# The '?' is changed to an 'i' indicating
|
|
1220
|
+
# that a new cusp needs to be inserted here
|
|
1221
|
+
full_domain = False
|
|
1222
|
+
else:
|
|
1223
|
+
C[s] = "x"
|
|
1224
|
+
# The '?' is changed to an 'x' and no
|
|
1225
|
+
# more checking below is needed! =)
|
|
1226
|
+
else:
|
|
1227
|
+
C[s] = "x"
|
|
1228
|
+
# The '?' is changed to an 'x' and no more
|
|
1229
|
+
# checking below is needed! =)
|
|
1230
|
+
|
|
1231
|
+
# Now insert the missing cusps (where there is an 'i' in
|
|
1232
|
+
# the final list)
|
|
1233
|
+
# This will keep the fundamental domain as flat as possible!
|
|
1234
|
+
# ---------------------------------------------------------------
|
|
1235
|
+
s = 1
|
|
1236
|
+
while s < len(C): # range over odd indices in the final list C
|
|
1237
|
+
if C[s] == "i":
|
|
1238
|
+
C[s] = "?"
|
|
1239
|
+
|
|
1240
|
+
# Single out our two cusps (path from cusp2 to cusp1)
|
|
1241
|
+
cusp1 = C[s - 1]
|
|
1242
|
+
cusp2 = C[s + 1]
|
|
1243
|
+
|
|
1244
|
+
# Makes the unimodular transform for the path
|
|
1245
|
+
# from cusp2 to cusp1
|
|
1246
|
+
a1 = cusp1.numerator()
|
|
1247
|
+
b1 = cusp1.denominator()
|
|
1248
|
+
a2 = cusp2.numerator()
|
|
1249
|
+
b2 = cusp2.denominator()
|
|
1250
|
+
|
|
1251
|
+
# Inserts the Farey center of these two cusps!
|
|
1252
|
+
a = a1 + a2
|
|
1253
|
+
b = b1 + b2
|
|
1254
|
+
C.insert(s + 1, a / b)
|
|
1255
|
+
C.insert(s + 2, "?")
|
|
1256
|
+
s += 2
|
|
1257
|
+
s += 2
|
|
1258
|
+
|
|
1259
|
+
# Remove the (now superfluous) extra string characters that appear
|
|
1260
|
+
# in the odd list entries
|
|
1261
|
+
return [QQ(C[ss]) for ss in range(0, len(C), 2)]
|
|
1262
|
+
|
|
1263
|
+
def is_unimodular_path(self, r1, r2) -> bool:
|
|
1264
|
+
r"""
|
|
1265
|
+
Determine whether two (non-infinite) cusps are connected by a
|
|
1266
|
+
unimodular path.
|
|
1267
|
+
|
|
1268
|
+
INPUT:
|
|
1269
|
+
|
|
1270
|
+
- ``r1``, ``r2`` -- rational numbers
|
|
1271
|
+
|
|
1272
|
+
OUTPUT:
|
|
1273
|
+
|
|
1274
|
+
A boolean expressing whether or not a unimodular path connects ``r1``
|
|
1275
|
+
to ``r2``.
|
|
1276
|
+
|
|
1277
|
+
EXAMPLES::
|
|
1278
|
+
|
|
1279
|
+
sage: from sage.modular.pollack_stevens.fund_domain import ManinRelations
|
|
1280
|
+
sage: A = ManinRelations(11)
|
|
1281
|
+
sage: A.is_unimodular_path(0,1/3)
|
|
1282
|
+
True
|
|
1283
|
+
sage: A.is_unimodular_path(1/3,0)
|
|
1284
|
+
True
|
|
1285
|
+
sage: A.is_unimodular_path(0,2/3)
|
|
1286
|
+
False
|
|
1287
|
+
sage: A.is_unimodular_path(2/3,0)
|
|
1288
|
+
False
|
|
1289
|
+
"""
|
|
1290
|
+
a = r1.numerator()
|
|
1291
|
+
b = r2.numerator()
|
|
1292
|
+
c = r1.denominator()
|
|
1293
|
+
d = r2.denominator()
|
|
1294
|
+
return (a * d - b * c) ** 2 == 1
|
|
1295
|
+
|
|
1296
|
+
def unimod_to_matrices(self, r1, r2):
|
|
1297
|
+
r"""
|
|
1298
|
+
Return the two matrices whose associated unimodular paths connect
|
|
1299
|
+
``r1`` and ``r2`` and ``r2`` and ``r1``, respectively.
|
|
1300
|
+
|
|
1301
|
+
INPUT:
|
|
1302
|
+
|
|
1303
|
+
- ``r1``, ``r2`` -- rational numbers (that are assumed to be connected
|
|
1304
|
+
by a unimodular path)
|
|
1305
|
+
|
|
1306
|
+
OUTPUT: a pair of `2 \times 2` matrices of determinant 1
|
|
1307
|
+
|
|
1308
|
+
EXAMPLES::
|
|
1309
|
+
|
|
1310
|
+
sage: from sage.modular.pollack_stevens.fund_domain import ManinRelations
|
|
1311
|
+
sage: A = ManinRelations(11)
|
|
1312
|
+
sage: A.unimod_to_matrices(0,1/3)
|
|
1313
|
+
(
|
|
1314
|
+
[ 0 1] [1 0]
|
|
1315
|
+
[-1 3], [3 1]
|
|
1316
|
+
)
|
|
1317
|
+
"""
|
|
1318
|
+
a = r1.numerator()
|
|
1319
|
+
b = r2.numerator()
|
|
1320
|
+
c = r1.denominator()
|
|
1321
|
+
d = r2.denominator()
|
|
1322
|
+
if (a * d - b * c) == 1:
|
|
1323
|
+
ans = M2Z([a, b, c, d]), M2Z([-b, a, -d, c])
|
|
1324
|
+
else:
|
|
1325
|
+
ans = M2Z([-a, b, -c, d]), M2Z([b, a, d, c])
|
|
1326
|
+
return ans
|
|
1327
|
+
|
|
1328
|
+
def fd_boundary(self, C):
|
|
1329
|
+
r"""
|
|
1330
|
+
Find matrices whose associated unimodular paths give the
|
|
1331
|
+
boundary of a fundamental domain.
|
|
1332
|
+
|
|
1333
|
+
Here the fundamental domain is for `\Gamma_0(N)`. (In the
|
|
1334
|
+
case when `\Gamma_0(N)` has elements of order three the shape
|
|
1335
|
+
cut out by these unimodular matrices is a little smaller than
|
|
1336
|
+
a fundamental domain. See Section 2.5 of [PS2011]_.)
|
|
1337
|
+
|
|
1338
|
+
INPUT:
|
|
1339
|
+
|
|
1340
|
+
- ``C`` -- list of rational numbers coming from
|
|
1341
|
+
``self.form_list_of_cusps()``
|
|
1342
|
+
|
|
1343
|
+
OUTPUT:
|
|
1344
|
+
|
|
1345
|
+
A list of `2 \times 2` integer matrices of determinant 1 whose associated
|
|
1346
|
+
unimodular paths give the boundary of a fundamental domain for
|
|
1347
|
+
`\Gamma_0(N)` (or nearly so in the case of 3-torsion).
|
|
1348
|
+
|
|
1349
|
+
EXAMPLES::
|
|
1350
|
+
|
|
1351
|
+
sage: from sage.modular.pollack_stevens.fund_domain import ManinRelations
|
|
1352
|
+
sage: A = ManinRelations(11)
|
|
1353
|
+
sage: C = A.form_list_of_cusps(); C
|
|
1354
|
+
[-1, -2/3, -1/2, -1/3, 0]
|
|
1355
|
+
sage: A.fd_boundary(C)
|
|
1356
|
+
[
|
|
1357
|
+
[1 0] [ 1 1] [ 0 -1] [-1 -1] [-1 -2] [-2 -1]
|
|
1358
|
+
[0 1], [-1 0], [ 1 3], [ 3 2], [ 2 3], [ 3 1]
|
|
1359
|
+
]
|
|
1360
|
+
sage: A = ManinRelations(13)
|
|
1361
|
+
sage: C = A.form_list_of_cusps(); C
|
|
1362
|
+
[-1, -2/3, -1/2, -1/3, 0]
|
|
1363
|
+
sage: A.fd_boundary(C)
|
|
1364
|
+
[
|
|
1365
|
+
[1 0] [ 1 1] [ 0 -1] [-1 -1] [-1 -2] [-2 -1]
|
|
1366
|
+
[0 1], [-1 0], [ 1 3], [ 3 2], [ 2 3], [ 3 1]
|
|
1367
|
+
]
|
|
1368
|
+
sage: A = ManinRelations(101)
|
|
1369
|
+
sage: C = A.form_list_of_cusps(); C
|
|
1370
|
+
[-1, -6/7, -5/6, -4/5, -7/9, -3/4, -11/15, -8/11, -5/7, -7/10,
|
|
1371
|
+
-9/13, -2/3, -5/8, -13/21, -8/13, -3/5, -7/12, -11/19, -4/7, -1/2,
|
|
1372
|
+
-4/9, -3/7, -5/12, -7/17, -2/5, -3/8, -4/11, -1/3, -2/7, -3/11,
|
|
1373
|
+
-1/4, -2/9, -1/5, -1/6, 0]
|
|
1374
|
+
sage: A.fd_boundary(C)
|
|
1375
|
+
[
|
|
1376
|
+
[1 0] [ 1 1] [ 0 -1] [-1 -1] [-1 -2] [-2 -1] [-1 -3] [-3 -2]
|
|
1377
|
+
[0 1], [-1 0], [ 1 6], [ 6 5], [ 5 9], [ 9 4], [ 4 11], [11 7],
|
|
1378
|
+
<BLANKLINE>
|
|
1379
|
+
[-2 -1] [-1 -4] [-4 -3] [-3 -2] [-2 -7] [-7 -5] [-5 -3] [-3 -4]
|
|
1380
|
+
[ 7 3], [ 3 11], [11 8], [ 8 5], [ 5 17], [17 12], [12 7], [ 7 9],
|
|
1381
|
+
<BLANKLINE>
|
|
1382
|
+
[-4 -1] [-1 -4] [ -4 -11] [-11 -7] [-7 -3] [-3 -8] [ -8 -13]
|
|
1383
|
+
[ 9 2], [ 2 7], [ 7 19], [ 19 12], [12 5], [ 5 13], [ 13 21],
|
|
1384
|
+
<BLANKLINE>
|
|
1385
|
+
[-13 -5] [-5 -2] [-2 -9] [-9 -7] [-7 -5] [-5 -8] [ -8 -11]
|
|
1386
|
+
[ 21 8], [ 8 3], [ 3 13], [13 10], [10 7], [ 7 11], [ 11 15],
|
|
1387
|
+
<BLANKLINE>
|
|
1388
|
+
[-11 -3] [-3 -7] [-7 -4] [-4 -5] [-5 -6] [-6 -1]
|
|
1389
|
+
[ 15 4], [ 4 9], [ 9 5], [ 5 6], [ 6 7], [ 7 1]
|
|
1390
|
+
]
|
|
1391
|
+
"""
|
|
1392
|
+
C.reverse() # Reverse here to get clockwise orientation of boundary
|
|
1393
|
+
|
|
1394
|
+
# These matrices correspond to the paths from infty to 0 and
|
|
1395
|
+
# -1 to infty
|
|
1396
|
+
mats = [Id, minone_inf_path]
|
|
1397
|
+
|
|
1398
|
+
# Now find SL_2(Z) matrices whose associated unimodular paths
|
|
1399
|
+
# connect the cusps listed in C.
|
|
1400
|
+
for j in range(len(C) - 1):
|
|
1401
|
+
a = C[j].numerator()
|
|
1402
|
+
b = C[j + 1].numerator()
|
|
1403
|
+
c = C[j].denominator()
|
|
1404
|
+
d = C[j + 1].denominator()
|
|
1405
|
+
new_mat = M2Z([a, b, c, d])
|
|
1406
|
+
mats.append(new_mat)
|
|
1407
|
+
|
|
1408
|
+
return mats
|
|
1409
|
+
|
|
1410
|
+
@cached_method
|
|
1411
|
+
def prep_hecke_on_gen(self, l, gen, modulus=None):
|
|
1412
|
+
r"""
|
|
1413
|
+
This function does some precomputations needed to compute `T_l`.
|
|
1414
|
+
|
|
1415
|
+
In particular, if `\phi` is a modular symbol and `D_m` is the divisor
|
|
1416
|
+
associated to the generator ``gen``, to compute `(\phi|T_{l})(D_m)` one
|
|
1417
|
+
needs to compute `\phi(\gamma_a D_m)|\gamma_a` where `\gamma_a` runs
|
|
1418
|
+
through the `l+1` matrices defining `T_l`. One
|
|
1419
|
+
then takes `\gamma_a D_m` and writes it as a sum of unimodular
|
|
1420
|
+
divisors. For each such unimodular divisor, say `[M]` where `M` is a
|
|
1421
|
+
`SL_2` matrix, we then write `M=\gamma h` where `\gamma` is in
|
|
1422
|
+
`\Gamma_0(N)` and `h` is one of our chosen coset representatives. Then
|
|
1423
|
+
`\phi([M]) = \phi([h]) | \gamma^{-1}`. Thus, one has
|
|
1424
|
+
|
|
1425
|
+
.. MATH::
|
|
1426
|
+
|
|
1427
|
+
(\phi | \gamma_a)(D_m) = \sum_h \sum_j \phi([h]) | \gamma_{hj}^{-1} \cdot \gamma_a
|
|
1428
|
+
|
|
1429
|
+
as `h` runs over all coset representatives and `j` simply runs over
|
|
1430
|
+
however many times `M_h` appears in the above computation.
|
|
1431
|
+
|
|
1432
|
+
Finally, the output of this function is a dictionary ``D``
|
|
1433
|
+
whose keys are the coset representatives in ``self.reps()``
|
|
1434
|
+
where each value is a list of matrices, and the entries of
|
|
1435
|
+
``D`` satisfy:
|
|
1436
|
+
|
|
1437
|
+
.. MATH::
|
|
1438
|
+
|
|
1439
|
+
D[h][j] = \gamma_{hj} * \gamma_a
|
|
1440
|
+
|
|
1441
|
+
INPUT:
|
|
1442
|
+
|
|
1443
|
+
- ``l`` -- a prime
|
|
1444
|
+
- ``gen`` -- a generator
|
|
1445
|
+
|
|
1446
|
+
OUTPUT:
|
|
1447
|
+
|
|
1448
|
+
A list of lists (see above).
|
|
1449
|
+
|
|
1450
|
+
EXAMPLES::
|
|
1451
|
+
|
|
1452
|
+
sage: # needs eclib
|
|
1453
|
+
sage: E = EllipticCurve('11a')
|
|
1454
|
+
sage: phi = E.pollack_stevens_modular_symbol()
|
|
1455
|
+
sage: phi.values()
|
|
1456
|
+
[-1/5, 1, 0]
|
|
1457
|
+
sage: M = phi.parent().source()
|
|
1458
|
+
sage: w = M.prep_hecke_on_gen(2, M.gens()[0])
|
|
1459
|
+
sage: one = Matrix(ZZ,2,2,1)
|
|
1460
|
+
sage: one.set_immutable()
|
|
1461
|
+
sage: w[one]
|
|
1462
|
+
[[1 0]
|
|
1463
|
+
[0 2], [1 1]
|
|
1464
|
+
[0 2], [2 0]
|
|
1465
|
+
[0 1]]
|
|
1466
|
+
"""
|
|
1467
|
+
N = self.level()
|
|
1468
|
+
SN = Sigma0(N)
|
|
1469
|
+
|
|
1470
|
+
ans = {}
|
|
1471
|
+
# this will be the dictionary D above enumerated by coset reps
|
|
1472
|
+
|
|
1473
|
+
# This loop will run thru the l+1 (or l) matrices
|
|
1474
|
+
# defining T_l of the form [1, a, 0, l] and carry out the
|
|
1475
|
+
# computation described above.
|
|
1476
|
+
# -------------------------------------
|
|
1477
|
+
for a in range(l + 1):
|
|
1478
|
+
if ((a < l) or (N % l != 0)) and (modulus is None or a % l == modulus % l):
|
|
1479
|
+
# if the level is not prime to l the matrix [l, 0, 0, 1] is avoided.
|
|
1480
|
+
gamma = basic_hecke_matrix(a, l)
|
|
1481
|
+
t = gamma * gen
|
|
1482
|
+
# In the notation above this is gam_a * D_m
|
|
1483
|
+
from .manin_map import unimod_matrices_to_infty, unimod_matrices_from_infty
|
|
1484
|
+
v = unimod_matrices_from_infty(t[0, 0], t[1, 0]) + unimod_matrices_to_infty(t[0, 1], t[1, 1])
|
|
1485
|
+
# This expresses t as a sum of unimodular divisors
|
|
1486
|
+
|
|
1487
|
+
# This loop runs over each such unimodular divisor
|
|
1488
|
+
# ------------------------------------------------
|
|
1489
|
+
for A in v:
|
|
1490
|
+
# B is the coset rep equivalent to A
|
|
1491
|
+
B = self.equivalent_rep(A)
|
|
1492
|
+
# gaminv = B*A^(-1), but A is in SL2.
|
|
1493
|
+
gaminv = B * A.adjugate()
|
|
1494
|
+
# The matrix gaminv * gamma is added to our list in the j-th slot
|
|
1495
|
+
# (as described above)
|
|
1496
|
+
tmp = SN(gaminv * gamma)
|
|
1497
|
+
try:
|
|
1498
|
+
ans[B].append(tmp)
|
|
1499
|
+
except KeyError:
|
|
1500
|
+
ans[B] = [tmp]
|
|
1501
|
+
|
|
1502
|
+
return ans
|
|
1503
|
+
|
|
1504
|
+
@cached_method
|
|
1505
|
+
def prep_hecke_on_gen_list(self, l, gen, modulus=None):
|
|
1506
|
+
r"""
|
|
1507
|
+
Return the precomputation to compute `T_l` in a way that
|
|
1508
|
+
speeds up the Hecke calculation.
|
|
1509
|
+
|
|
1510
|
+
Namely, returns a list of the form [h,A].
|
|
1511
|
+
|
|
1512
|
+
INPUT:
|
|
1513
|
+
|
|
1514
|
+
- ``l`` -- a prime
|
|
1515
|
+
- ``gen`` -- a generator
|
|
1516
|
+
|
|
1517
|
+
OUTPUT:
|
|
1518
|
+
|
|
1519
|
+
A list of lists (see above).
|
|
1520
|
+
|
|
1521
|
+
EXAMPLES::
|
|
1522
|
+
|
|
1523
|
+
sage: # needs eclib
|
|
1524
|
+
sage: E = EllipticCurve('11a')
|
|
1525
|
+
sage: phi = E.pollack_stevens_modular_symbol()
|
|
1526
|
+
sage: phi.values()
|
|
1527
|
+
[-1/5, 1, 0]
|
|
1528
|
+
sage: M = phi.parent().source()
|
|
1529
|
+
sage: len(M.prep_hecke_on_gen_list(2, M.gens()[0]))
|
|
1530
|
+
4
|
|
1531
|
+
"""
|
|
1532
|
+
ans = []
|
|
1533
|
+
for h, vh in self.prep_hecke_on_gen(l, gen, modulus=modulus).items():
|
|
1534
|
+
ans.extend([(h, v) for v in vh])
|
|
1535
|
+
return ans
|
|
1536
|
+
|
|
1537
|
+
|
|
1538
|
+
def basic_hecke_matrix(a, l):
|
|
1539
|
+
r"""
|
|
1540
|
+
Return the `2 \times 2` matrix with entries ``[1, a, 0, l]`` if ``a<l``
|
|
1541
|
+
and ``[l, 0, 0, 1]`` if ``a>=l``.
|
|
1542
|
+
|
|
1543
|
+
INPUT:
|
|
1544
|
+
|
|
1545
|
+
- ``a`` -- integer or Infinity
|
|
1546
|
+
- ``l`` -- a prime
|
|
1547
|
+
|
|
1548
|
+
OUTPUT: a `2 \times 2` matrix of determinant l
|
|
1549
|
+
|
|
1550
|
+
EXAMPLES::
|
|
1551
|
+
|
|
1552
|
+
sage: from sage.modular.pollack_stevens.fund_domain import basic_hecke_matrix
|
|
1553
|
+
sage: basic_hecke_matrix(0, 7)
|
|
1554
|
+
[1 0]
|
|
1555
|
+
[0 7]
|
|
1556
|
+
sage: basic_hecke_matrix(5, 7)
|
|
1557
|
+
[1 5]
|
|
1558
|
+
[0 7]
|
|
1559
|
+
sage: basic_hecke_matrix(7, 7)
|
|
1560
|
+
[7 0]
|
|
1561
|
+
[0 1]
|
|
1562
|
+
sage: basic_hecke_matrix(19, 7)
|
|
1563
|
+
[7 0]
|
|
1564
|
+
[0 1]
|
|
1565
|
+
sage: basic_hecke_matrix(infinity, 7)
|
|
1566
|
+
[7 0]
|
|
1567
|
+
[0 1]
|
|
1568
|
+
"""
|
|
1569
|
+
if a < l:
|
|
1570
|
+
return M2Z([1, a, 0, l])
|
|
1571
|
+
else:
|
|
1572
|
+
return M2Z([l, 0, 0, 1])
|