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,3352 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-schemes
|
|
2
|
+
# sage.doctest: needs sage.libs.gap
|
|
3
|
+
r"""
|
|
4
|
+
Hecke triangle group elements
|
|
5
|
+
|
|
6
|
+
AUTHORS:
|
|
7
|
+
|
|
8
|
+
- Jonas Jermann (2014): initial version
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
# ****************************************************************************
|
|
12
|
+
# Copyright (C) 2013-2014 Jonas Jermann <jjermann2@gmail.com>
|
|
13
|
+
#
|
|
14
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
15
|
+
# as published by the Free Software Foundation; either version 2 of
|
|
16
|
+
# the License, or (at your option) any later version.
|
|
17
|
+
# https://www.gnu.org/licenses/
|
|
18
|
+
# ****************************************************************************
|
|
19
|
+
|
|
20
|
+
from sage.misc.latex import latex
|
|
21
|
+
from sage.misc.lazy_import import lazy_import
|
|
22
|
+
from sage.misc.misc_c import prod
|
|
23
|
+
from sage.misc.cachefunc import cached_method
|
|
24
|
+
|
|
25
|
+
from sage.rings.integer_ring import ZZ
|
|
26
|
+
from sage.rings.infinity import infinity
|
|
27
|
+
from sage.rings.cc import CC
|
|
28
|
+
|
|
29
|
+
from sage.groups.matrix_gps.group_element import MatrixGroupElement_generic
|
|
30
|
+
|
|
31
|
+
lazy_import('sage.rings.qqbar', 'AA')
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _in_HyperbolicPlane(x):
|
|
35
|
+
try:
|
|
36
|
+
from sage.geometry.hyperbolic_space.hyperbolic_interface import HyperbolicPlane
|
|
37
|
+
except ImportError:
|
|
38
|
+
return False
|
|
39
|
+
return x in HyperbolicPlane()
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# We want to simplify p after the coercion (pari bug for AA)
|
|
43
|
+
def coerce_AA(p):
|
|
44
|
+
r"""
|
|
45
|
+
Return the argument first coerced into ``AA`` and then simplified.
|
|
46
|
+
|
|
47
|
+
This leads to a major performance gain with some operations.
|
|
48
|
+
|
|
49
|
+
EXAMPLES::
|
|
50
|
+
|
|
51
|
+
sage: # needs sage.rings.number_field sage.symbolic
|
|
52
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_group_element import coerce_AA
|
|
53
|
+
sage: p = (791264*AA(2*cos(pi/8))^2 - 463492).sqrt()
|
|
54
|
+
sage: AA(p)._exact_field()
|
|
55
|
+
Number Field in a with defining polynomial y^8 ... with a in ...
|
|
56
|
+
sage: coerce_AA(p)._exact_field()
|
|
57
|
+
Number Field in a with defining polynomial y^4 - 1910*y^2 - 3924*y + 681058
|
|
58
|
+
with a in ...?
|
|
59
|
+
"""
|
|
60
|
+
el = AA(p)
|
|
61
|
+
el.simplify()
|
|
62
|
+
# el.exactify()
|
|
63
|
+
|
|
64
|
+
return el
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def cyclic_representative(L):
|
|
68
|
+
r"""
|
|
69
|
+
Return a unique representative among all cyclic permutations
|
|
70
|
+
of the given list/tuple.
|
|
71
|
+
|
|
72
|
+
INPUT:
|
|
73
|
+
|
|
74
|
+
- ``L`` -- list or tuple
|
|
75
|
+
|
|
76
|
+
OUTPUT:
|
|
77
|
+
|
|
78
|
+
The maximal element among all cyclic permutations with respect
|
|
79
|
+
to lexicographical ordering.
|
|
80
|
+
|
|
81
|
+
EXAMPLES::
|
|
82
|
+
|
|
83
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_group_element import cyclic_representative
|
|
84
|
+
sage: cyclic_representative((1,))
|
|
85
|
+
(1,)
|
|
86
|
+
sage: cyclic_representative((2,2))
|
|
87
|
+
(2, 2)
|
|
88
|
+
sage: cyclic_representative((1,2,1,2))
|
|
89
|
+
(2, 1, 2, 1)
|
|
90
|
+
sage: cyclic_representative((1,2,3,2,3,1))
|
|
91
|
+
(3, 2, 3, 1, 1, 2)
|
|
92
|
+
"""
|
|
93
|
+
L = list(L)
|
|
94
|
+
n = len(L)
|
|
95
|
+
Lmax = L[:]
|
|
96
|
+
for _ in range(n - 1):
|
|
97
|
+
L.append(L.pop(0))
|
|
98
|
+
if L > Lmax:
|
|
99
|
+
Lmax = L[:]
|
|
100
|
+
|
|
101
|
+
return tuple(Lmax)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class HeckeTriangleGroupElement(MatrixGroupElement_generic):
|
|
105
|
+
r"""
|
|
106
|
+
Elements of HeckeTriangleGroup.
|
|
107
|
+
"""
|
|
108
|
+
def __init__(self, parent, M, check=True, **kwargs):
|
|
109
|
+
r"""
|
|
110
|
+
An element of HeckeTriangle group given by a matrix ``M``.
|
|
111
|
+
|
|
112
|
+
INPUT:
|
|
113
|
+
|
|
114
|
+
- ``parent`` -- a ``HeckeTriangleGroup``
|
|
115
|
+
|
|
116
|
+
- ``M`` -- a matrix which coerces into the matrix space
|
|
117
|
+
of ``parent``. For example with entries in a
|
|
118
|
+
polynomial ring over ``ZZ`` with parameter ``lam``.
|
|
119
|
+
|
|
120
|
+
- ``check`` -- boolean (default: ``True``); if ``True``
|
|
121
|
+
then a (possibly long) check is performed
|
|
122
|
+
to see whether ``M`` really corresponds to a
|
|
123
|
+
group element of ``parent``.
|
|
124
|
+
|
|
125
|
+
EXAMPLES::
|
|
126
|
+
|
|
127
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup, HeckeTriangleGroupElement
|
|
128
|
+
sage: lam = PolynomialRing(ZZ, 'lam').gen()
|
|
129
|
+
sage: M = matrix([[-1, 0], [-lam^4 + 5*lam^2 + lam - 5, -1]])
|
|
130
|
+
sage: G = HeckeTriangleGroup(4)
|
|
131
|
+
sage: G(M)
|
|
132
|
+
Traceback (most recent call last):
|
|
133
|
+
...
|
|
134
|
+
TypeError: The matrix is not an element of Hecke triangle group for n = 4,
|
|
135
|
+
up to equivalence it identifies two nonequivalent points.
|
|
136
|
+
|
|
137
|
+
sage: G = HeckeTriangleGroup(10)
|
|
138
|
+
sage: el = G(M)
|
|
139
|
+
sage: el == HeckeTriangleGroupElement(G, M)
|
|
140
|
+
True
|
|
141
|
+
sage: type(el)
|
|
142
|
+
<class 'sage.modular.modform_hecketriangle.hecke_triangle_groups.HeckeTriangleGroup_with_category.element_class'>
|
|
143
|
+
sage: el.category()
|
|
144
|
+
Category of elements of Hecke triangle group for n = 10
|
|
145
|
+
sage: type(HeckeTriangleGroupElement(G, M))
|
|
146
|
+
<class 'sage.modular.modform_hecketriangle.hecke_triangle_group_element.HeckeTriangleGroupElement'>
|
|
147
|
+
sage: HeckeTriangleGroupElement(G, M).category()
|
|
148
|
+
Category of elements of Hecke triangle group for n = 10
|
|
149
|
+
sage: el
|
|
150
|
+
[ -1 0]
|
|
151
|
+
[lam -1]
|
|
152
|
+
sage: el.matrix().parent()
|
|
153
|
+
Full MatrixSpace of 2 by 2 dense matrices over
|
|
154
|
+
Maximal Order generated by lam in Number Field in lam
|
|
155
|
+
with defining polynomial x^4 - 5*x^2 + 5
|
|
156
|
+
with lam = 1.902113032590308?
|
|
157
|
+
|
|
158
|
+
sage: M = matrix([[-1, lam], [0, 1]])
|
|
159
|
+
sage: G(M)
|
|
160
|
+
Traceback (most recent call last):
|
|
161
|
+
...
|
|
162
|
+
TypeError: The matrix is not an element of Hecke triangle group for n = 10,
|
|
163
|
+
it has determinant -1 != 1.
|
|
164
|
+
|
|
165
|
+
sage: G.T().inverse()
|
|
166
|
+
[ 1 -lam]
|
|
167
|
+
[ 0 1]
|
|
168
|
+
sage: G.U() == G.T()*G.S()
|
|
169
|
+
True
|
|
170
|
+
sage: G.U()^(-10) == -G.I()
|
|
171
|
+
True
|
|
172
|
+
"""
|
|
173
|
+
MatrixGroupElement_generic.__init__(self, parent, M, check=check, convert=True)
|
|
174
|
+
|
|
175
|
+
# The matrix check involves a lengthy element method (_word_S_T_data)
|
|
176
|
+
# whose result is also used for other purposes. For performance reason the
|
|
177
|
+
# results are stored/cached in the element. Moreover this avoids code duplication.
|
|
178
|
+
# In particular this means we cannot call the method from _matrix_check().
|
|
179
|
+
# Instead it is called here in the __init__ method of the element
|
|
180
|
+
# (after the preliminary checks).
|
|
181
|
+
if check:
|
|
182
|
+
if self._matrix.determinant() != 1:
|
|
183
|
+
raise TypeError("The matrix is not an element of {}, it has determinant {} != 1.".format(parent, self._matrix.determinant()))
|
|
184
|
+
self._word_S_T_data()
|
|
185
|
+
|
|
186
|
+
@cached_method
|
|
187
|
+
def _word_S_T_data(self):
|
|
188
|
+
r"""
|
|
189
|
+
Return a tuple ``(L, sgn)`` which describes the decomposition
|
|
190
|
+
of ``self`` as a product of the generators ``S`` and ``T``
|
|
191
|
+
together with a sign correction ``sgn``.
|
|
192
|
+
|
|
193
|
+
If this decomposition is not possible a :exc:`TypeError`
|
|
194
|
+
is raised. In particular this function can be used to
|
|
195
|
+
check the membership in ``parent`` of an arbitrary matrix
|
|
196
|
+
over the base ring.
|
|
197
|
+
|
|
198
|
+
OUTPUT:
|
|
199
|
+
|
|
200
|
+
The tuple entries of ``L`` are either of the form ``(0, 1)``,
|
|
201
|
+
corresponding to ``S`` or ``(1, m)`` corresponding to
|
|
202
|
+
``T^m``, where ``m`` is a non-trivial integer. ``sgn`` is +-1.
|
|
203
|
+
|
|
204
|
+
EXAMPLES::
|
|
205
|
+
|
|
206
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
207
|
+
sage: G = HeckeTriangleGroup(n=17)
|
|
208
|
+
sage: G.I()._word_S_T_data()
|
|
209
|
+
((), 1)
|
|
210
|
+
sage: (-G.V(2))._word_S_T_data()
|
|
211
|
+
(((1, 1), (0, 1), (1, 1)), -1)
|
|
212
|
+
sage: G.U()._word_S_T_data()
|
|
213
|
+
(((1, 1), (0, 1)), 1)
|
|
214
|
+
|
|
215
|
+
sage: G = HeckeTriangleGroup(n=infinity)
|
|
216
|
+
sage: (-G.V(2)*G.V(3))._word_S_T_data()
|
|
217
|
+
(((1, 1), (0, 1), (1, 2), (0, 1), (1, 1), (0, 1), (1, 1)), -1)
|
|
218
|
+
sage: G.U()._word_S_T_data()
|
|
219
|
+
(((1, 1), (0, 1)), 1)
|
|
220
|
+
"""
|
|
221
|
+
res = []
|
|
222
|
+
ID = self.parent().I()._matrix
|
|
223
|
+
T = self.parent().T()._matrix
|
|
224
|
+
S = self.parent().S()._matrix
|
|
225
|
+
M = self._matrix
|
|
226
|
+
lam = self.parent().lam()
|
|
227
|
+
zero = ZZ.zero()
|
|
228
|
+
one = ZZ.one()
|
|
229
|
+
half = one / ZZ(2)
|
|
230
|
+
|
|
231
|
+
while True:
|
|
232
|
+
a, b, c, d = M.list()
|
|
233
|
+
mshift = coerce_AA((4*a*c + b*d) / (4*c*c + d*d))
|
|
234
|
+
m = (mshift / lam + half).floor()
|
|
235
|
+
if m != zero:
|
|
236
|
+
res.append((one, m),)
|
|
237
|
+
M = T**(-m) * M
|
|
238
|
+
a, b, c, d = M.list()
|
|
239
|
+
|
|
240
|
+
abs_t = coerce_AA((4*a*a + b*b) / (4*c*c + d*d))
|
|
241
|
+
if coerce_AA(abs_t) < 1:
|
|
242
|
+
M = (-S) * M
|
|
243
|
+
res.append((zero, one),)
|
|
244
|
+
elif M == ID:
|
|
245
|
+
return (tuple(res), one)
|
|
246
|
+
elif M == -ID:
|
|
247
|
+
return (tuple(res), -one)
|
|
248
|
+
else:
|
|
249
|
+
raise TypeError("The matrix is not an element of {}, up to equivalence it identifies two nonequivalent points.".format(self.parent()))
|
|
250
|
+
|
|
251
|
+
def word_S_T(self):
|
|
252
|
+
r"""
|
|
253
|
+
Decompose ``self`` into a product of the generators
|
|
254
|
+
``S`` and ``T`` of its parent, together with a sign
|
|
255
|
+
correction matrix, namely: ``self = sgn * prod(L)``.
|
|
256
|
+
|
|
257
|
+
Warning:
|
|
258
|
+
If ``self`` is +- the identity ``prod(L)`` is an empty product
|
|
259
|
+
which produces ``1`` instead of the identity matrix.
|
|
260
|
+
|
|
261
|
+
OUTPUT:
|
|
262
|
+
|
|
263
|
+
The function returns a tuple ``(L, sgn)`` where the entries
|
|
264
|
+
of ``L`` are either the generator ``S`` or a non-trivial
|
|
265
|
+
integer power of the generator ``T``. ``sgn`` is +- the identity.
|
|
266
|
+
|
|
267
|
+
If this decomposition is not possible a :exc:`TypeError` is raised.
|
|
268
|
+
|
|
269
|
+
EXAMPLES::
|
|
270
|
+
|
|
271
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
272
|
+
sage: G = HeckeTriangleGroup(n=17)
|
|
273
|
+
sage: (-G.I()).word_S_T()[0]
|
|
274
|
+
()
|
|
275
|
+
sage: (-G.I()).word_S_T()[1]
|
|
276
|
+
[-1 0]
|
|
277
|
+
[ 0 -1]
|
|
278
|
+
sage: L, sgn = (-G.V(2)).word_S_T()
|
|
279
|
+
sage: L
|
|
280
|
+
(
|
|
281
|
+
[ 1 lam] [ 0 -1] [ 1 lam]
|
|
282
|
+
[ 0 1], [ 1 0], [ 0 1]
|
|
283
|
+
)
|
|
284
|
+
sage: sgn == -G.I()
|
|
285
|
+
True
|
|
286
|
+
sage: -G.V(2) == sgn * prod(L)
|
|
287
|
+
True
|
|
288
|
+
sage: L, sgn = G.U().word_S_T()
|
|
289
|
+
sage: L
|
|
290
|
+
(
|
|
291
|
+
[ 1 lam] [ 0 -1]
|
|
292
|
+
[ 0 1], [ 1 0]
|
|
293
|
+
)
|
|
294
|
+
sage: sgn == G.I()
|
|
295
|
+
True
|
|
296
|
+
sage: G.U() == sgn * prod(L)
|
|
297
|
+
True
|
|
298
|
+
|
|
299
|
+
sage: G = HeckeTriangleGroup(n=infinity)
|
|
300
|
+
sage: L, sgn = (-G.V(2)*G.V(3)).word_S_T()
|
|
301
|
+
sage: L
|
|
302
|
+
(
|
|
303
|
+
[1 2] [ 0 -1] [1 4] [ 0 -1] [1 2] [ 0 -1] [1 2]
|
|
304
|
+
[0 1], [ 1 0], [0 1], [ 1 0], [0 1], [ 1 0], [0 1]
|
|
305
|
+
)
|
|
306
|
+
sage: -G.V(2)*G.V(3) == sgn * prod(L)
|
|
307
|
+
True
|
|
308
|
+
"""
|
|
309
|
+
Tf = self.parent().T
|
|
310
|
+
S = self.parent().S()
|
|
311
|
+
L, sgn = self._word_S_T_data()
|
|
312
|
+
|
|
313
|
+
M = [S if v[0] == 0 else Tf(v[1]) for v in L]
|
|
314
|
+
if sgn > 0:
|
|
315
|
+
sgn = self.parent().I()
|
|
316
|
+
else:
|
|
317
|
+
sgn = -self.parent().I()
|
|
318
|
+
|
|
319
|
+
return (tuple(M), sgn)
|
|
320
|
+
|
|
321
|
+
def _repr_(self):
|
|
322
|
+
r"""
|
|
323
|
+
Return the string representation of ``self``.
|
|
324
|
+
The result depends on the default element representation
|
|
325
|
+
method of the parent: ``self.parent().element_repr_method()``.
|
|
326
|
+
|
|
327
|
+
See :meth:`string_repr` for a list of possible methods
|
|
328
|
+
and for more examples.
|
|
329
|
+
|
|
330
|
+
EXAMPLES::
|
|
331
|
+
|
|
332
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
333
|
+
sage: G = HeckeTriangleGroup(n=5)
|
|
334
|
+
sage: el = G.S()*G.T(3)*G.S()*G.T(-2)
|
|
335
|
+
sage: el
|
|
336
|
+
[ -1 2*lam]
|
|
337
|
+
[ 3*lam -6*lam - 7]
|
|
338
|
+
sage: el.string_repr()
|
|
339
|
+
'[ -1 2*lam]\n[ 3*lam -6*lam - 7]'
|
|
340
|
+
sage: G.element_repr_method("basic")
|
|
341
|
+
sage: el
|
|
342
|
+
S*T^3*S*T^(-2)
|
|
343
|
+
sage: el.string_repr("basic")
|
|
344
|
+
'S*T^3*S*T^(-2)'
|
|
345
|
+
"""
|
|
346
|
+
return self.string_repr(self.parent().element_repr_method())
|
|
347
|
+
|
|
348
|
+
def string_repr(self, method='default'):
|
|
349
|
+
r"""
|
|
350
|
+
Return a string representation of ``self`` using the specified ``method``.
|
|
351
|
+
This method is used to represent ``self``.
|
|
352
|
+
The default representation method can be set for the parent with
|
|
353
|
+
``self.parent().element_repr_method(method)``.
|
|
354
|
+
|
|
355
|
+
INPUT:
|
|
356
|
+
|
|
357
|
+
- ``method`` -- one of
|
|
358
|
+
|
|
359
|
+
- ``'default'`` -- use the usual representation method for matrix
|
|
360
|
+
group elements
|
|
361
|
+
|
|
362
|
+
- ``'basic'`` -- the representation is given as a word in ``S`` and
|
|
363
|
+
powers of ``T``. Note: If ``S, T`` are defined accordingly the
|
|
364
|
+
output can be used/evaluated directly to recover ``self``.
|
|
365
|
+
|
|
366
|
+
- ``'conj'`` -- the conjugacy representative of the element is
|
|
367
|
+
represented as a word in powers of the basic blocks, together with
|
|
368
|
+
an unspecified conjugation matrix
|
|
369
|
+
|
|
370
|
+
- ``'block'`` -- same as ``conj`` but the conjugation matrix is
|
|
371
|
+
specified as well. Note: Assuming ``S, T, U, V`` are defined
|
|
372
|
+
accordingly the output can directly be used/evaluated to recover
|
|
373
|
+
``self``.
|
|
374
|
+
|
|
375
|
+
Warning: For ``n=infinity`` the methods ``conj`` and ``block`` are not verified at all
|
|
376
|
+
and are probably wrong!
|
|
377
|
+
|
|
378
|
+
EXAMPLES::
|
|
379
|
+
|
|
380
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
381
|
+
sage: G = HeckeTriangleGroup(n=5)
|
|
382
|
+
sage: el1 = -G.I()
|
|
383
|
+
sage: el2 = G.S()*G.T(3)*G.S()*G.T(-2)
|
|
384
|
+
sage: el3 = G.V(2)*G.V(3)^2*G.V(4)^3
|
|
385
|
+
sage: el4 = G.U()^4
|
|
386
|
+
sage: el5 = (G.V(2)*G.T()).acton(-G.S())
|
|
387
|
+
|
|
388
|
+
sage: el4.string_repr(method='basic')
|
|
389
|
+
'S*T^(-1)'
|
|
390
|
+
|
|
391
|
+
sage: G.element_repr_method('default')
|
|
392
|
+
sage: el1
|
|
393
|
+
[-1 0]
|
|
394
|
+
[ 0 -1]
|
|
395
|
+
sage: el2
|
|
396
|
+
[ -1 2*lam]
|
|
397
|
+
[ 3*lam -6*lam - 7]
|
|
398
|
+
sage: el3
|
|
399
|
+
[34*lam + 19 5*lam + 4]
|
|
400
|
+
[27*lam + 18 5*lam + 2]
|
|
401
|
+
sage: el4
|
|
402
|
+
[ 0 -1]
|
|
403
|
+
[ 1 -lam]
|
|
404
|
+
sage: el5
|
|
405
|
+
[-7*lam - 4 9*lam + 6]
|
|
406
|
+
[-4*lam - 5 7*lam + 4]
|
|
407
|
+
|
|
408
|
+
sage: G.element_repr_method('basic')
|
|
409
|
+
sage: el1
|
|
410
|
+
-1
|
|
411
|
+
sage: el2
|
|
412
|
+
S*T^3*S*T^(-2)
|
|
413
|
+
sage: el3
|
|
414
|
+
-T*S*T*S*T^(-1)*S*T^(-2)*S*T^(-4)*S
|
|
415
|
+
sage: el4
|
|
416
|
+
S*T^(-1)
|
|
417
|
+
sage: el5
|
|
418
|
+
T*S*T^2*S*T^(-2)*S*T^(-1)
|
|
419
|
+
|
|
420
|
+
sage: G.element_repr_method('conj')
|
|
421
|
+
sage: el1
|
|
422
|
+
[-1]
|
|
423
|
+
sage: el2
|
|
424
|
+
[-V(4)^2*V(1)^3]
|
|
425
|
+
sage: el3
|
|
426
|
+
[V(3)^2*V(4)^3*V(2)]
|
|
427
|
+
sage: el4
|
|
428
|
+
[-U^(-1)]
|
|
429
|
+
sage: el5
|
|
430
|
+
[-S]
|
|
431
|
+
|
|
432
|
+
sage: G.element_repr_method('block')
|
|
433
|
+
sage: el1
|
|
434
|
+
-1
|
|
435
|
+
sage: el2
|
|
436
|
+
-(S*T^3) * (V(4)^2*V(1)^3) * (S*T^3)^(-1)
|
|
437
|
+
sage: el3
|
|
438
|
+
(T*S*T) * (V(3)^2*V(4)^3*V(2)) * (T*S*T)^(-1)
|
|
439
|
+
sage: el4
|
|
440
|
+
-U^(-1)
|
|
441
|
+
sage: el5
|
|
442
|
+
-(T*S*T^2) * (S) * (T*S*T^2)^(-1)
|
|
443
|
+
|
|
444
|
+
sage: G.element_repr_method('default')
|
|
445
|
+
|
|
446
|
+
sage: G = HeckeTriangleGroup(n=infinity)
|
|
447
|
+
sage: el = G.S()*G.T(3)*G.S()*G.T(-2)
|
|
448
|
+
sage: print(el.string_repr())
|
|
449
|
+
[ -1 4]
|
|
450
|
+
[ 6 -25]
|
|
451
|
+
sage: print(el.string_repr(method='basic'))
|
|
452
|
+
S*T^3*S*T^(-2)
|
|
453
|
+
"""
|
|
454
|
+
if method == "default":
|
|
455
|
+
return MatrixGroupElement_generic._repr_(self)
|
|
456
|
+
if method == "basic":
|
|
457
|
+
L, sgn = self._word_S_T_data()
|
|
458
|
+
|
|
459
|
+
if not L:
|
|
460
|
+
return "-1" if sgn < 0 else "1"
|
|
461
|
+
|
|
462
|
+
Lstr = list(L)
|
|
463
|
+
for i, (v0, v1) in enumerate(Lstr):
|
|
464
|
+
if v0 == 0:
|
|
465
|
+
Lstr[i] = "S"
|
|
466
|
+
elif v1 == 1:
|
|
467
|
+
Lstr[i] = "T"
|
|
468
|
+
else:
|
|
469
|
+
if v1 < 0:
|
|
470
|
+
exp = "(" + str(v1) + ")"
|
|
471
|
+
else:
|
|
472
|
+
exp = str(v1)
|
|
473
|
+
Lstr[i] = "T^" + exp
|
|
474
|
+
Lstr = "*".join(Lstr)
|
|
475
|
+
|
|
476
|
+
return "-" + Lstr if sgn < 0 else Lstr
|
|
477
|
+
|
|
478
|
+
if method == "block":
|
|
479
|
+
if self.parent().n() == infinity:
|
|
480
|
+
from warnings import warn
|
|
481
|
+
warn("The case n=infinity here is not verified at all and probably wrong!")
|
|
482
|
+
|
|
483
|
+
L, R, sgn = self._block_decomposition_data()
|
|
484
|
+
|
|
485
|
+
repr_str = self.string_repr(method='conj')
|
|
486
|
+
repr_str = repr_str[1:-1]
|
|
487
|
+
if sgn < 0:
|
|
488
|
+
repr_str = repr_str[1:]
|
|
489
|
+
|
|
490
|
+
# if self != R.inverse().acton(self):
|
|
491
|
+
if R.is_identity():
|
|
492
|
+
repr_str = "{}{}".format("-" if sgn < 0 else "", repr_str)
|
|
493
|
+
else:
|
|
494
|
+
R_str = "({})".format(R.string_repr(method='basic'))
|
|
495
|
+
repr_str = "{}{} * ({}) * {}^(-1)".format("-" if sgn < 0 else "", R_str, repr_str, R_str)
|
|
496
|
+
|
|
497
|
+
return repr_str
|
|
498
|
+
|
|
499
|
+
if method == "conj":
|
|
500
|
+
if self.parent().n() == infinity:
|
|
501
|
+
from warnings import warn
|
|
502
|
+
warn("The case n=infinity here is not verified at all and probably wrong!")
|
|
503
|
+
|
|
504
|
+
L, R, sgn = self._block_decomposition_data()
|
|
505
|
+
|
|
506
|
+
if self.is_elliptic():
|
|
507
|
+
L = [L]
|
|
508
|
+
|
|
509
|
+
repr_str = ""
|
|
510
|
+
begin = True
|
|
511
|
+
for v in L:
|
|
512
|
+
if self.is_identity():
|
|
513
|
+
pass
|
|
514
|
+
elif self.is_elliptic():
|
|
515
|
+
if v[0] == 0:
|
|
516
|
+
repr_str += "S"
|
|
517
|
+
elif v[1] == 1:
|
|
518
|
+
repr_str += "U"
|
|
519
|
+
else:
|
|
520
|
+
exp = "{}".format(v[1])
|
|
521
|
+
if v[1] < 0:
|
|
522
|
+
exp = "({})".format(exp)
|
|
523
|
+
repr_str += "U^{}".format(exp)
|
|
524
|
+
begin = False
|
|
525
|
+
elif v[1] == 0:
|
|
526
|
+
pass
|
|
527
|
+
else:
|
|
528
|
+
if not begin:
|
|
529
|
+
repr_str += "*"
|
|
530
|
+
factor = "V({})".format(v[0])
|
|
531
|
+
if v[1] == 1:
|
|
532
|
+
repr_str += factor
|
|
533
|
+
else:
|
|
534
|
+
exp = "{}".format(v[1])
|
|
535
|
+
if v[1] < 0:
|
|
536
|
+
exp = "({})".format(exp)
|
|
537
|
+
repr_str += "{}^{}".format(factor, exp)
|
|
538
|
+
begin = False
|
|
539
|
+
|
|
540
|
+
if begin:
|
|
541
|
+
repr_str += "1"
|
|
542
|
+
|
|
543
|
+
if sgn < 0:
|
|
544
|
+
repr_str = f"-{repr_str}"
|
|
545
|
+
|
|
546
|
+
return f"[{repr_str}]"
|
|
547
|
+
|
|
548
|
+
raise NotImplementedError
|
|
549
|
+
|
|
550
|
+
# We cache this method since the calculation is rather long and the
|
|
551
|
+
# result is being reused:
|
|
552
|
+
# - For block decompositions
|
|
553
|
+
# - For calculating reduced (and simple) elements (and all dependent methods)
|
|
554
|
+
@cached_method
|
|
555
|
+
def continued_fraction(self):
|
|
556
|
+
r"""
|
|
557
|
+
For hyperbolic and parabolic elements: Return the (negative)
|
|
558
|
+
lambda-continued fraction expansion (lambda-CF) of the (attracting)
|
|
559
|
+
hyperbolic fixed point of ``self``.
|
|
560
|
+
|
|
561
|
+
Let ``r_j in Z`` for ``j >= 0``. A finite lambda-CF is defined as:
|
|
562
|
+
``[r_0; r_1, ..., r_k] := (T^(r_0)*S* ... *T^(r_k)*S)(infinity)``,
|
|
563
|
+
where ``S`` and ``T`` are the generators of ``self``. An infinite
|
|
564
|
+
lambda-CF is defined as a corresponding limit value (k->infinity)
|
|
565
|
+
if it exists.
|
|
566
|
+
|
|
567
|
+
In this case the lambda-CF of parabolic and hyperbolic fixed points
|
|
568
|
+
are returned which have an eventually periodic lambda-CF.
|
|
569
|
+
The parabolic elements are exactly those with a cyclic permutation
|
|
570
|
+
of the period ``[2, 1, ..., 1]`` with ``n-3`` ones.
|
|
571
|
+
|
|
572
|
+
Warning: The case ``n=infinity`` is not verified at all
|
|
573
|
+
and probably wrong!
|
|
574
|
+
|
|
575
|
+
OUTPUT:
|
|
576
|
+
|
|
577
|
+
A tuple ``(preperiod, period)`` with the preperiod and period
|
|
578
|
+
tuples of the lambda-CF.
|
|
579
|
+
|
|
580
|
+
EXAMPLES::
|
|
581
|
+
|
|
582
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
583
|
+
sage: G = HeckeTriangleGroup(n=7)
|
|
584
|
+
sage: G.T().continued_fraction()
|
|
585
|
+
((0, 1), (1, 1, 1, 1, 2))
|
|
586
|
+
sage: G.V(2).acton(G.T(-3)).continued_fraction()
|
|
587
|
+
((), (2, 1, 1, 1, 1))
|
|
588
|
+
sage: (-G.V(2)).continued_fraction()
|
|
589
|
+
((1,), (2,))
|
|
590
|
+
sage: (-G.V(2)^3*G.V(6)^2*G.V(3)).continued_fraction()
|
|
591
|
+
((1,), (2, 2, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 2))
|
|
592
|
+
sage: (G.U()^4*G.S()*G.V(2)).acton(-G.V(2)^3*G.V(6)^2*G.V(3)).continued_fraction()
|
|
593
|
+
((1, 1, 1, 2), (2, 2, 2, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1))
|
|
594
|
+
sage: (G.V(1)^5*G.V(2)*G.V(3)^3).continued_fraction()
|
|
595
|
+
((6,), (2, 1, 2, 1, 2, 1, 7))
|
|
596
|
+
|
|
597
|
+
sage: G = HeckeTriangleGroup(n=8)
|
|
598
|
+
sage: G.T().continued_fraction()
|
|
599
|
+
((0, 1), (1, 1, 1, 1, 1, 2))
|
|
600
|
+
sage: G.V(2).acton(G.T(-3)).continued_fraction()
|
|
601
|
+
((), (2, 1, 1, 1, 1, 1))
|
|
602
|
+
sage: (-G.V(2)).continued_fraction()
|
|
603
|
+
((1,), (2,))
|
|
604
|
+
sage: (-G.V(2)^3*G.V(6)^2*G.V(3)).continued_fraction()
|
|
605
|
+
((1,), (2, 2, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 2))
|
|
606
|
+
sage: (G.U()^4*G.S()*G.V(2)).acton(-G.V(2)^3*G.V(6)^2*G.V(3)).continued_fraction()
|
|
607
|
+
((1, 1, 1, 2), (2, 2, 2, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1))
|
|
608
|
+
sage: (G.V(1)^5*G.V(2)*G.V(3)^3).continued_fraction()
|
|
609
|
+
((6,), (2, 1, 2, 1, 2, 1, 7))
|
|
610
|
+
sage: (G.V(2)^3*G.V(5)*G.V(1)*G.V(6)^2*G.V(4)).continued_fraction()
|
|
611
|
+
((1,), (2, 2, 2, 1, 1, 1, 3, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 2))
|
|
612
|
+
"""
|
|
613
|
+
if self.parent().n() == infinity:
|
|
614
|
+
from warnings import warn
|
|
615
|
+
warn("The case n=infinity here is not verified at all and probably wrong!")
|
|
616
|
+
|
|
617
|
+
if self.is_identity():
|
|
618
|
+
raise NotImplementedError
|
|
619
|
+
if self.is_elliptic():
|
|
620
|
+
# Note: The algorithm still produces "something"
|
|
621
|
+
# emb = self.root_extension_embedding(QQbar)
|
|
622
|
+
raise NotImplementedError
|
|
623
|
+
|
|
624
|
+
emb = self.root_extension_embedding(AA)
|
|
625
|
+
G = self.parent()
|
|
626
|
+
S = G.S()
|
|
627
|
+
TI = G.T().inverse()
|
|
628
|
+
lam = G.lam()
|
|
629
|
+
|
|
630
|
+
p = self.fixed_points()[0]
|
|
631
|
+
|
|
632
|
+
cf_dict = {}
|
|
633
|
+
L = []
|
|
634
|
+
cf_index = ZZ.zero()
|
|
635
|
+
one = ZZ.one()
|
|
636
|
+
|
|
637
|
+
while p not in cf_dict:
|
|
638
|
+
cf_dict[p] = cf_index
|
|
639
|
+
if p == infinity:
|
|
640
|
+
# TODO: The choice of r doesn't matter?
|
|
641
|
+
r = ZZ.zero()
|
|
642
|
+
# elif self.is_elliptic():
|
|
643
|
+
# r = ZZ(emb(p/lam).real().floor() + 1)
|
|
644
|
+
else:
|
|
645
|
+
emb_res = emb(p/lam)
|
|
646
|
+
emb_res.simplify()
|
|
647
|
+
emb_res.exactify()
|
|
648
|
+
r = emb_res.floor() + one
|
|
649
|
+
L.append(r)
|
|
650
|
+
p = (S*TI**r).acton(p)
|
|
651
|
+
cf_index += one
|
|
652
|
+
|
|
653
|
+
preperiod_len = cf_dict[p]
|
|
654
|
+
# period_len = cf_index - preperiod_len
|
|
655
|
+
|
|
656
|
+
return (tuple(L[:preperiod_len]), tuple(L[preperiod_len:]))
|
|
657
|
+
|
|
658
|
+
# TODO: allow output as word?
|
|
659
|
+
# We cache this method since the calculation is rather long and the
|
|
660
|
+
# data is being reused when working with primitive representatives
|
|
661
|
+
# and conjugacy classes.
|
|
662
|
+
@cached_method
|
|
663
|
+
def _primitive_block_decomposition_data(self):
|
|
664
|
+
r"""
|
|
665
|
+
Return a tuple ``(L, R)`` which describes the
|
|
666
|
+
decomposition of ``self`` into a very specific
|
|
667
|
+
primitive conjugacy representative whose
|
|
668
|
+
decomposition is further described by the tuple ``L``,
|
|
669
|
+
and the corresponding conjugation matrix ``R``.
|
|
670
|
+
|
|
671
|
+
Together they describe the primitive part of ``self``.
|
|
672
|
+
I.e. an element which is equal to ``self`` up
|
|
673
|
+
to a sign after taking the appropriate power
|
|
674
|
+
and which itself cannot be written as a non-trivial
|
|
675
|
+
power (at least for non-elliptic elements).
|
|
676
|
+
|
|
677
|
+
To construct the representative see
|
|
678
|
+
:meth:`primitive_representative`. To construct
|
|
679
|
+
the primitive part see :meth:`primitive_part`.
|
|
680
|
+
To get a corresponding decomposition of ``self``
|
|
681
|
+
see :meth:`block_decomposition`.
|
|
682
|
+
|
|
683
|
+
In the hyperbolic and parabolic case the
|
|
684
|
+
representative is given as a product of powers of
|
|
685
|
+
``V(j)`` (more precisely ``self.parent().V(j)``),
|
|
686
|
+
where ``1 <= j <= n-1``.
|
|
687
|
+
|
|
688
|
+
The number of such factors is called ``block length``
|
|
689
|
+
(see :meth:`block_length`). Each block (and also
|
|
690
|
+
their product) has a positive sign and
|
|
691
|
+
nonnegative entries.
|
|
692
|
+
|
|
693
|
+
In the elliptic case the primitive representative
|
|
694
|
+
is either ``S`` or ``U``.
|
|
695
|
+
|
|
696
|
+
Warning: The case ``n=infinity`` is not verified at all
|
|
697
|
+
and probably wrong!
|
|
698
|
+
|
|
699
|
+
OUTPUT:
|
|
700
|
+
|
|
701
|
+
A tuple ``(L, R)``, where ``R`` is an element of
|
|
702
|
+
the Hecke triangle group that conjugates the
|
|
703
|
+
described primitive representative to the primitive
|
|
704
|
+
part of ``self``.
|
|
705
|
+
|
|
706
|
+
In the hyperbolic and parabolic case ``L`` is an
|
|
707
|
+
ordered tuple of (tuple) data ``(j, k)``, corresponding
|
|
708
|
+
to a factor ``V(j)^k``.
|
|
709
|
+
|
|
710
|
+
If the representative is the identity then ``((1,0),)``
|
|
711
|
+
is returned (consistent with the previous notation).
|
|
712
|
+
|
|
713
|
+
In the elliptic case ``L=(a, 1)``, with either ``a=0``
|
|
714
|
+
corresponding to the representative ``S`` or ``a=1``
|
|
715
|
+
corresponding to the representative ``U``.
|
|
716
|
+
|
|
717
|
+
EXAMPLES::
|
|
718
|
+
|
|
719
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
720
|
+
sage: G = HeckeTriangleGroup(n=7)
|
|
721
|
+
sage: G.element_repr_method("basic")
|
|
722
|
+
|
|
723
|
+
sage: L, R = G.T()._primitive_block_decomposition_data()
|
|
724
|
+
sage: L
|
|
725
|
+
((1, 1),)
|
|
726
|
+
sage: R
|
|
727
|
+
T^(-1)
|
|
728
|
+
sage: L, R = G.V(2).acton(G.T(-3))._primitive_block_decomposition_data()
|
|
729
|
+
sage: L
|
|
730
|
+
((6, 1),)
|
|
731
|
+
sage: R
|
|
732
|
+
T
|
|
733
|
+
sage: L, R = (-G.V(2))._primitive_block_decomposition_data()
|
|
734
|
+
sage: L
|
|
735
|
+
((2, 1),)
|
|
736
|
+
sage: R
|
|
737
|
+
T*S*T
|
|
738
|
+
sage: L, R = (-G.V(2)^3*G.V(6)^2*G.V(3))._primitive_block_decomposition_data()
|
|
739
|
+
sage: L
|
|
740
|
+
((2, 3), (6, 2), (3, 1))
|
|
741
|
+
sage: R
|
|
742
|
+
1
|
|
743
|
+
sage: L, R = (G.U()^4*G.S()*G.V(2)).acton(-G.V(2)^3*G.V(6)^2*G.V(3))._primitive_block_decomposition_data()
|
|
744
|
+
sage: L
|
|
745
|
+
((2, 3), (6, 2), (3, 1))
|
|
746
|
+
sage: R
|
|
747
|
+
T*S*T*S*T*S*T^2*S*T
|
|
748
|
+
sage: L, R = (G.V(1)^5*G.V(2)*G.V(3)^3)._primitive_block_decomposition_data()
|
|
749
|
+
sage: L
|
|
750
|
+
((3, 3), (1, 5), (2, 1))
|
|
751
|
+
sage: R
|
|
752
|
+
T^6*S*T
|
|
753
|
+
|
|
754
|
+
sage: G.element_repr_method("default")
|
|
755
|
+
sage: L, R = G.I()._primitive_block_decomposition_data()
|
|
756
|
+
sage: L
|
|
757
|
+
((6, 0),)
|
|
758
|
+
sage: R
|
|
759
|
+
[1 0]
|
|
760
|
+
[0 1]
|
|
761
|
+
|
|
762
|
+
sage: L, R = G.U()._primitive_block_decomposition_data()
|
|
763
|
+
sage: L
|
|
764
|
+
(1, 1)
|
|
765
|
+
sage: R
|
|
766
|
+
[1 0]
|
|
767
|
+
[0 1]
|
|
768
|
+
sage: L, R = (-G.S())._primitive_block_decomposition_data()
|
|
769
|
+
sage: L
|
|
770
|
+
(0, 1)
|
|
771
|
+
sage: R
|
|
772
|
+
[-1 0]
|
|
773
|
+
[ 0 -1]
|
|
774
|
+
sage: L, R = (G.V(2)*G.V(3)).acton(G.U()^6)._primitive_block_decomposition_data()
|
|
775
|
+
sage: L
|
|
776
|
+
(1, 1)
|
|
777
|
+
sage: R
|
|
778
|
+
[-2*lam^2 - 2*lam + 2 -2*lam^2 - 2*lam + 1]
|
|
779
|
+
[ -2*lam^2 + 1 -2*lam^2 - lam + 2]
|
|
780
|
+
"""
|
|
781
|
+
if self.parent().n() == infinity:
|
|
782
|
+
from warnings import warn
|
|
783
|
+
warn("The case n=infinity here is not verified at all and probably wrong!")
|
|
784
|
+
|
|
785
|
+
G = self.parent()
|
|
786
|
+
zero = ZZ.zero()
|
|
787
|
+
one = ZZ.one()
|
|
788
|
+
|
|
789
|
+
# The elliptic case (for this case we use a special notation):
|
|
790
|
+
if self.is_elliptic():
|
|
791
|
+
if self.parent().n() == infinity:
|
|
792
|
+
raise NotImplementedError
|
|
793
|
+
|
|
794
|
+
from sage.rings.qqbar import QQbar
|
|
795
|
+
|
|
796
|
+
emb = self.root_extension_embedding(QQbar)
|
|
797
|
+
p = self.fixed_points()[0]
|
|
798
|
+
embp = emb(p)
|
|
799
|
+
embp.simplify()
|
|
800
|
+
embp.exactify()
|
|
801
|
+
R, embw = G.get_FD(embp)
|
|
802
|
+
w = R.inverse().acton(p)
|
|
803
|
+
# we should have: embw == emb(w)
|
|
804
|
+
embw = emb(w)
|
|
805
|
+
embw.simplify()
|
|
806
|
+
embw.exactify()
|
|
807
|
+
|
|
808
|
+
if embw == QQbar.gen():
|
|
809
|
+
R = -R
|
|
810
|
+
L = (zero, one)
|
|
811
|
+
elif (embw == -one/G.rho()):
|
|
812
|
+
R = R*G.T().inverse()
|
|
813
|
+
L = (one, one)
|
|
814
|
+
else:
|
|
815
|
+
raise RuntimeError("There is something wrong in the method "
|
|
816
|
+
"_primitive_block_decomposition_data. Please contact sage-devel@googlegroups.com")
|
|
817
|
+
|
|
818
|
+
return (L, R)
|
|
819
|
+
|
|
820
|
+
# The identity case (consistent with the notation in the parabolic case):
|
|
821
|
+
if self.is_identity():
|
|
822
|
+
return (((ZZ(self.parent().n()-one), zero),), G.I())
|
|
823
|
+
|
|
824
|
+
# The hyperbolic and parabolic case:
|
|
825
|
+
# The parabolic case is much simpler but the same algorithm
|
|
826
|
+
# as in the hyperbolic case still works
|
|
827
|
+
|
|
828
|
+
preperiod, period = self.continued_fraction()
|
|
829
|
+
|
|
830
|
+
number_of_ones = []
|
|
831
|
+
list_larger = []
|
|
832
|
+
ones = 0
|
|
833
|
+
for l in period:
|
|
834
|
+
if l > 1:
|
|
835
|
+
number_of_ones.append(ones)
|
|
836
|
+
ones = 0
|
|
837
|
+
list_larger.append(l)
|
|
838
|
+
else:
|
|
839
|
+
ones += 1
|
|
840
|
+
number_of_ones.append(ones)
|
|
841
|
+
|
|
842
|
+
initial_ones = number_of_ones.pop(0)
|
|
843
|
+
if not list_larger:
|
|
844
|
+
list_v1 = [-ZZ.one()]
|
|
845
|
+
list_vlarger = [initial_ones + 2]
|
|
846
|
+
else:
|
|
847
|
+
list_v1 = [v - 2 for v in list_larger]
|
|
848
|
+
list_vlarger = [v + 2 for v in number_of_ones]
|
|
849
|
+
list_vlarger[-1] += initial_ones
|
|
850
|
+
|
|
851
|
+
L = []
|
|
852
|
+
for k in range(len(list_vlarger)):
|
|
853
|
+
if list_v1[k] != 0:
|
|
854
|
+
L.append([ZZ(1), list_v1[k]])
|
|
855
|
+
L.append([ZZ(list_vlarger[k]), ZZ(1)])
|
|
856
|
+
|
|
857
|
+
L_len = len(L)
|
|
858
|
+
k = 0
|
|
859
|
+
while k < L_len - 1:
|
|
860
|
+
if L[k][0] == L[k+1][0]:
|
|
861
|
+
k_entry = L.pop(k+1)
|
|
862
|
+
L[k][1] += k_entry[1]
|
|
863
|
+
L_len -= 1
|
|
864
|
+
else:
|
|
865
|
+
k += 1
|
|
866
|
+
if L_len > 1 and L[-1][0] == L[0][0]:
|
|
867
|
+
k_entry = L.pop(-1)
|
|
868
|
+
L[0][1] += k_entry[1]
|
|
869
|
+
R = G.V(L[0][0])**(-k_entry[1])
|
|
870
|
+
else:
|
|
871
|
+
R = G.I()
|
|
872
|
+
|
|
873
|
+
# This should determine whether self is conjugate to a positive power of V(1) or V(n-1)
|
|
874
|
+
# sign((a+d)*(b-c)) is actually a conjugacy invariant for the parabolic subspace
|
|
875
|
+
# and distinguishes the two (three) cases (sign(0):=0)
|
|
876
|
+
if self.is_parabolic() and coerce_AA(self.trace() * (self.b() - self.c())).sign() > 0:
|
|
877
|
+
# In this case self should be conjugate to a positive power of V(1)
|
|
878
|
+
# in either case L is / should be (at the moment) always equal to [n-1, 1]
|
|
879
|
+
L[0][0] = 1
|
|
880
|
+
R = R * (-G.S())
|
|
881
|
+
|
|
882
|
+
R = G.V(initial_ones + 1) * R
|
|
883
|
+
R = prod((G.T(r) * G.S() for r in preperiod), G.I()) * R
|
|
884
|
+
|
|
885
|
+
L = tuple(tuple(v) for v in L)
|
|
886
|
+
|
|
887
|
+
return (L, R)
|
|
888
|
+
|
|
889
|
+
def primitive_representative(self, method='block'):
|
|
890
|
+
r"""
|
|
891
|
+
Return a tuple ``(P, R)`` which gives the
|
|
892
|
+
decomposition of the primitive part of ``self``,
|
|
893
|
+
namely ``R*P*R.inverse()`` into a specific
|
|
894
|
+
representative ``P`` and the corresponding
|
|
895
|
+
conjugation matrix ``R`` (the result depends on
|
|
896
|
+
the method used).
|
|
897
|
+
|
|
898
|
+
Together they describe the primitive part of ``self``.
|
|
899
|
+
I.e. an element which is equal to ``self`` up
|
|
900
|
+
to a sign after taking the appropriate power.
|
|
901
|
+
|
|
902
|
+
See :meth:`_primitive_block_decomposition_data` for a description
|
|
903
|
+
about the representative in case the default method
|
|
904
|
+
``block`` is used. Also see :meth:`primitive_part`
|
|
905
|
+
to construct the primitive part of ``self``.
|
|
906
|
+
|
|
907
|
+
Warning: The case ``n=infinity`` is not verified at all
|
|
908
|
+
and probably wrong!
|
|
909
|
+
|
|
910
|
+
INPUT:
|
|
911
|
+
|
|
912
|
+
- ``method`` -- ``'block'`` (default) or ``'cf'``. The method used to
|
|
913
|
+
determine ``P`` and ``R``. If ``self`` is elliptic, this parameter is
|
|
914
|
+
ignored, and if ``self`` is +- the identity then the ``block`` method
|
|
915
|
+
is used.
|
|
916
|
+
|
|
917
|
+
With ``'block'`` the decomposition described in
|
|
918
|
+
:meth:`_primitive_block_decomposition_data` is used.
|
|
919
|
+
|
|
920
|
+
With ``'cf'`` a reduced representative from the lambda-CF of ``self``
|
|
921
|
+
is used (see :meth:`continued_fraction`). In that case ``P``
|
|
922
|
+
corresponds to the period and ``R`` to the preperiod.
|
|
923
|
+
|
|
924
|
+
OUTPUT:
|
|
925
|
+
|
|
926
|
+
A tuple ``(P, R)`` of group elements such that
|
|
927
|
+
``R*P*R.inverse()`` is a/the primitive part of ``self``
|
|
928
|
+
|
|
929
|
+
EXAMPLES::
|
|
930
|
+
|
|
931
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
932
|
+
sage: G = HeckeTriangleGroup(n=7)
|
|
933
|
+
sage: G.element_repr_method("basic")
|
|
934
|
+
sage: el = G.T().primitive_representative(method='cf')
|
|
935
|
+
sage: el
|
|
936
|
+
(S*T^(-1)*S*T^(-1)*S*T*S, S*T*S)
|
|
937
|
+
sage: (el[0]).is_primitive()
|
|
938
|
+
True
|
|
939
|
+
sage: el = G.V(2).acton(G.T(-3)).primitive_representative(method='cf')
|
|
940
|
+
sage: el
|
|
941
|
+
(-T*S*T^(-1)*S*T^(-1), 1)
|
|
942
|
+
sage: (el[0]).is_primitive()
|
|
943
|
+
True
|
|
944
|
+
sage: el = (-G.V(2)).primitive_representative(method='cf')
|
|
945
|
+
sage: el
|
|
946
|
+
(T^2*S, T*S)
|
|
947
|
+
sage: (el[0]).is_primitive()
|
|
948
|
+
True
|
|
949
|
+
sage: el = (-G.V(2)^3*G.V(6)^2*G.V(3)).primitive_representative(method='cf')
|
|
950
|
+
sage: el
|
|
951
|
+
(-T^2*S*T^2*S*T*S*T^(-2)*S*T*S*T*S*T^2*S, T*S)
|
|
952
|
+
sage: (el[0]).is_primitive()
|
|
953
|
+
True
|
|
954
|
+
sage: el = (G.U()^4*G.S()*G.V(2)).acton(-G.V(2)^3*G.V(6)^2*G.V(3)).primitive_representative(method='cf')
|
|
955
|
+
sage: el
|
|
956
|
+
(-T^2*S*T^2*S*T^2*S*T*S*T^(-2)*S*T*S*T*S, T*S*T*S*T*S*T^2*S)
|
|
957
|
+
sage: (el[0]).is_primitive()
|
|
958
|
+
True
|
|
959
|
+
sage: el = (G.V(1)^5*G.V(2)*G.V(3)^3).primitive_representative(method='cf')
|
|
960
|
+
sage: el
|
|
961
|
+
(T^2*S*T*S*T^2*S*T*S*T^2*S*T*S*T^7*S, T^6*S)
|
|
962
|
+
sage: (el[0]).is_primitive()
|
|
963
|
+
True
|
|
964
|
+
sage: el = (G.V(2)*G.V(3)).acton(G.U()^6).primitive_representative(method='cf')
|
|
965
|
+
sage: el
|
|
966
|
+
(T*S, -T*S*T^2*S*T*S*T)
|
|
967
|
+
sage: (el[0]).is_primitive()
|
|
968
|
+
True
|
|
969
|
+
|
|
970
|
+
sage: G.element_repr_method("block")
|
|
971
|
+
sage: el = G.T().primitive_representative()
|
|
972
|
+
sage: (el[0]).is_primitive()
|
|
973
|
+
True
|
|
974
|
+
sage: el = G.V(2).acton(G.T(-3)).primitive_representative()
|
|
975
|
+
sage: el
|
|
976
|
+
((-S*T^(-1)*S) * (V(6)) * (-S*T^(-1)*S)^(-1), (T^(-1)) * (V(1)) * (T^(-1))^(-1))
|
|
977
|
+
sage: (el[0]).is_primitive()
|
|
978
|
+
True
|
|
979
|
+
sage: el = (-G.V(2)).primitive_representative()
|
|
980
|
+
sage: el
|
|
981
|
+
((T*S*T) * (V(2)) * (T*S*T)^(-1), (T*S*T) * (V(2)) * (T*S*T)^(-1))
|
|
982
|
+
sage: (el[0]).is_primitive()
|
|
983
|
+
True
|
|
984
|
+
sage: el = (-G.V(2)^3*G.V(6)^2*G.V(3)).primitive_representative()
|
|
985
|
+
sage: el
|
|
986
|
+
(V(2)^3*V(6)^2*V(3), 1)
|
|
987
|
+
sage: (el[0]).is_primitive()
|
|
988
|
+
True
|
|
989
|
+
sage: el = (G.U()^4*G.S()*G.V(2)).acton(-G.V(2)^3*G.V(6)^2*G.V(3)).primitive_representative()
|
|
990
|
+
sage: el
|
|
991
|
+
(V(2)^3*V(6)^2*V(3), (T*S*T*S*T*S*T) * (V(2)*V(4)) * (T*S*T*S*T*S*T)^(-1))
|
|
992
|
+
sage: (el[0]).is_primitive()
|
|
993
|
+
True
|
|
994
|
+
sage: el = (G.V(1)^5*G.V(2)*G.V(3)^3).primitive_representative()
|
|
995
|
+
sage: el
|
|
996
|
+
(V(3)^3*V(1)^5*V(2), (T^6*S*T) * (V(1)^5*V(2)) * (T^6*S*T)^(-1))
|
|
997
|
+
sage: (el[0]).is_primitive()
|
|
998
|
+
True
|
|
999
|
+
|
|
1000
|
+
sage: G.element_repr_method("default")
|
|
1001
|
+
sage: el = G.I().primitive_representative()
|
|
1002
|
+
sage: el
|
|
1003
|
+
(
|
|
1004
|
+
[1 0] [1 0]
|
|
1005
|
+
[0 1], [0 1]
|
|
1006
|
+
)
|
|
1007
|
+
sage: (el[0]).is_primitive()
|
|
1008
|
+
True
|
|
1009
|
+
|
|
1010
|
+
sage: el = G.U().primitive_representative()
|
|
1011
|
+
sage: el
|
|
1012
|
+
(
|
|
1013
|
+
[lam -1] [1 0]
|
|
1014
|
+
[ 1 0], [0 1]
|
|
1015
|
+
)
|
|
1016
|
+
sage: (el[0]).is_primitive()
|
|
1017
|
+
True
|
|
1018
|
+
sage: el = (-G.S()).primitive_representative()
|
|
1019
|
+
sage: el
|
|
1020
|
+
(
|
|
1021
|
+
[ 0 -1] [-1 0]
|
|
1022
|
+
[ 1 0], [ 0 -1]
|
|
1023
|
+
)
|
|
1024
|
+
sage: (el[0]).is_primitive()
|
|
1025
|
+
True
|
|
1026
|
+
sage: el = (G.V(2)*G.V(3)).acton(G.U()^6).primitive_representative()
|
|
1027
|
+
sage: el
|
|
1028
|
+
(
|
|
1029
|
+
[lam -1] [-2*lam^2 - 2*lam + 2 -2*lam^2 - 2*lam + 1]
|
|
1030
|
+
[ 1 0], [ -2*lam^2 + 1 -2*lam^2 - lam + 2]
|
|
1031
|
+
)
|
|
1032
|
+
sage: (el[0]).is_primitive()
|
|
1033
|
+
True
|
|
1034
|
+
"""
|
|
1035
|
+
if self.parent().n() == infinity:
|
|
1036
|
+
from warnings import warn
|
|
1037
|
+
warn("The case n=infinity here is not verified at all and probably wrong!")
|
|
1038
|
+
|
|
1039
|
+
G = self.parent()
|
|
1040
|
+
|
|
1041
|
+
if self.is_identity():
|
|
1042
|
+
method = "block"
|
|
1043
|
+
|
|
1044
|
+
if self.is_elliptic():
|
|
1045
|
+
if self.parent().n() == infinity:
|
|
1046
|
+
raise NotImplementedError
|
|
1047
|
+
|
|
1048
|
+
data, R = self._primitive_block_decomposition_data()
|
|
1049
|
+
if data[0] == 0:
|
|
1050
|
+
P = G.S()
|
|
1051
|
+
else:
|
|
1052
|
+
P = G.U()
|
|
1053
|
+
|
|
1054
|
+
return (P, R)
|
|
1055
|
+
|
|
1056
|
+
if method == "cf":
|
|
1057
|
+
preperiod, period = self.continued_fraction()
|
|
1058
|
+
|
|
1059
|
+
P = prod((G.T()**r * G.S() for r in period), G.I())
|
|
1060
|
+
R = prod((G.T()**r * G.S() for r in preperiod), G.I())
|
|
1061
|
+
|
|
1062
|
+
return (P, R)
|
|
1063
|
+
|
|
1064
|
+
elif method == "block":
|
|
1065
|
+
data_list, R = self._primitive_block_decomposition_data()
|
|
1066
|
+
P = prod((G.V(v[0])**v[1] for v in data_list), G.I())
|
|
1067
|
+
|
|
1068
|
+
return (P, R)
|
|
1069
|
+
|
|
1070
|
+
else:
|
|
1071
|
+
raise ValueError("if the element is not elliptic, then method must "
|
|
1072
|
+
"be either be 'cf' or 'block'")
|
|
1073
|
+
|
|
1074
|
+
def primitive_part(self, method='cf'):
|
|
1075
|
+
r"""
|
|
1076
|
+
Return the primitive part of ``self``. I.e. a group element
|
|
1077
|
+
``A`` with nonnegative trace such that
|
|
1078
|
+
``self = sign * A^power``, where ``sign = self.sign()``
|
|
1079
|
+
is +- the identity (to correct the sign) and
|
|
1080
|
+
``power = self.primitive_power()``.
|
|
1081
|
+
|
|
1082
|
+
The primitive part itself is chosen such that it cannot be
|
|
1083
|
+
written as a non-trivial power of another element.
|
|
1084
|
+
It is a generator of the stabilizer of the corresponding
|
|
1085
|
+
(attracting) fixed point.
|
|
1086
|
+
|
|
1087
|
+
If ``self`` is elliptic then the primitive part is
|
|
1088
|
+
chosen as a conjugate of ``S`` or ``U``.
|
|
1089
|
+
|
|
1090
|
+
Warning: The case ``n=infinity`` is not verified at all
|
|
1091
|
+
and probably wrong!
|
|
1092
|
+
|
|
1093
|
+
INPUT:
|
|
1094
|
+
|
|
1095
|
+
- ``method`` -- the method used to determine the primitive
|
|
1096
|
+
part (see :meth:`primitive_representative`),
|
|
1097
|
+
default: ``'cf'``. The parameter is ignored
|
|
1098
|
+
for elliptic elements or +- the identity.
|
|
1099
|
+
|
|
1100
|
+
The result should not depend on the method.
|
|
1101
|
+
|
|
1102
|
+
OUTPUT: the primitive part as a group element of ``self``
|
|
1103
|
+
|
|
1104
|
+
EXAMPLES::
|
|
1105
|
+
|
|
1106
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
1107
|
+
sage: G = HeckeTriangleGroup(n=7)
|
|
1108
|
+
sage: G.element_repr_method("block")
|
|
1109
|
+
sage: G.T().primitive_part()
|
|
1110
|
+
(T^(-1)*S) * (V(6)) * (T^(-1)*S)^(-1)
|
|
1111
|
+
sage: G.V(2).acton(G.T(-3)).primitive_part()
|
|
1112
|
+
(T) * (V(6)) * (T)^(-1)
|
|
1113
|
+
sage: (-G.V(2)).primitive_part()
|
|
1114
|
+
(T*S*T) * (V(2)) * (T*S*T)^(-1)
|
|
1115
|
+
sage: (-G.V(2)^3*G.V(6)^2*G.V(3)).primitive_part()
|
|
1116
|
+
V(2)^3*V(6)^2*V(3)
|
|
1117
|
+
sage: (G.U()^4*G.S()*G.V(2)).acton(-G.V(2)^3*G.V(6)^2*G.V(3)).primitive_part()
|
|
1118
|
+
(T*S*T*S*T*S*T^2*S*T) * (V(2)^3*V(6)^2*V(3)) * (T*S*T*S*T*S*T^2*S*T)^(-1)
|
|
1119
|
+
sage: (G.V(1)^5*G.V(2)*G.V(3)^3).primitive_part()
|
|
1120
|
+
(T^6*S*T) * (V(3)^3*V(1)^5*V(2)) * (T^6*S*T)^(-1)
|
|
1121
|
+
sage: (G.V(2)*G.V(3)).acton(G.U()^6).primitive_part()
|
|
1122
|
+
(-T*S*T^2*S*T*S*T) * (U) * (-T*S*T^2*S*T*S*T)^(-1)
|
|
1123
|
+
|
|
1124
|
+
sage: (-G.I()).primitive_part()
|
|
1125
|
+
1
|
|
1126
|
+
|
|
1127
|
+
sage: G.U().primitive_part()
|
|
1128
|
+
U
|
|
1129
|
+
sage: (-G.S()).primitive_part()
|
|
1130
|
+
S
|
|
1131
|
+
sage: el = (G.V(2)*G.V(3)).acton(G.U()^6)
|
|
1132
|
+
sage: el.primitive_part()
|
|
1133
|
+
(-T*S*T^2*S*T*S*T) * (U) * (-T*S*T^2*S*T*S*T)^(-1)
|
|
1134
|
+
sage: el.primitive_part() == el.primitive_part(method='block')
|
|
1135
|
+
True
|
|
1136
|
+
|
|
1137
|
+
sage: G.T().primitive_part()
|
|
1138
|
+
(T^(-1)*S) * (V(6)) * (T^(-1)*S)^(-1)
|
|
1139
|
+
sage: G.T().primitive_part(method='block')
|
|
1140
|
+
(T^(-1)) * (V(1)) * (T^(-1))^(-1)
|
|
1141
|
+
sage: G.V(2).acton(G.T(-3)).primitive_part() == G.V(2).acton(G.T(-3)).primitive_part(method='block')
|
|
1142
|
+
True
|
|
1143
|
+
sage: (-G.V(2)).primitive_part() == (-G.V(2)).primitive_part(method='block')
|
|
1144
|
+
True
|
|
1145
|
+
sage: el = -G.V(2)^3*G.V(6)^2*G.V(3)
|
|
1146
|
+
sage: el.primitive_part() == el.primitive_part(method='block')
|
|
1147
|
+
True
|
|
1148
|
+
sage: el = (G.U()^4*G.S()*G.V(2)).acton(-G.V(2)^3*G.V(6)^2*G.V(3))
|
|
1149
|
+
sage: el.primitive_part() == el.primitive_part(method='block')
|
|
1150
|
+
True
|
|
1151
|
+
sage: el=G.V(1)^5*G.V(2)*G.V(3)^3
|
|
1152
|
+
sage: el.primitive_part() == el.primitive_part(method='block')
|
|
1153
|
+
True
|
|
1154
|
+
|
|
1155
|
+
sage: G.element_repr_method("default")
|
|
1156
|
+
"""
|
|
1157
|
+
if self.parent().n() == infinity:
|
|
1158
|
+
from warnings import warn
|
|
1159
|
+
warn("The case n=infinity here is not verified at all and probably wrong!")
|
|
1160
|
+
|
|
1161
|
+
P, R = self.primitive_representative(method=method)
|
|
1162
|
+
|
|
1163
|
+
return R * P * R.inverse()
|
|
1164
|
+
|
|
1165
|
+
def reduce(self, primitive=True):
|
|
1166
|
+
r"""
|
|
1167
|
+
Return a reduced version of ``self`` (with the same
|
|
1168
|
+
the same fixed points). Also see :meth:`is_reduced`.
|
|
1169
|
+
|
|
1170
|
+
If ``self`` is elliptic (or +- the identity) the result
|
|
1171
|
+
is never reduced (by definition). Instead a more canonical
|
|
1172
|
+
conjugation representative of ``self`` (resp. it's
|
|
1173
|
+
primitive part) is chosen.
|
|
1174
|
+
|
|
1175
|
+
Warning: The case ``n=infinity`` is not verified at all
|
|
1176
|
+
and probably wrong!
|
|
1177
|
+
|
|
1178
|
+
INPUT:
|
|
1179
|
+
|
|
1180
|
+
- ``primitive`` -- if ``True`` (default) then a primitive
|
|
1181
|
+
representative for ``self`` is returned
|
|
1182
|
+
|
|
1183
|
+
EXAMPLES::
|
|
1184
|
+
|
|
1185
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
1186
|
+
sage: G = HeckeTriangleGroup(n=7)
|
|
1187
|
+
sage: print(G.T().reduce().string_repr("basic"))
|
|
1188
|
+
S*T^(-1)*S*T^(-1)*S*T*S
|
|
1189
|
+
sage: G.T().reduce().is_reduced(require_hyperbolic=False)
|
|
1190
|
+
True
|
|
1191
|
+
sage: print(G.V(2).acton(-G.T(-3)).reduce().string_repr("basic"))
|
|
1192
|
+
-T*S*T^(-1)*S*T^(-1)
|
|
1193
|
+
sage: print(G.V(2).acton(-G.T(-3)).reduce(primitive=False).string_repr("basic"))
|
|
1194
|
+
T*S*T^(-3)*S*T^(-1)
|
|
1195
|
+
sage: print((-G.V(2)).reduce().string_repr("basic"))
|
|
1196
|
+
T^2*S
|
|
1197
|
+
sage: (-G.V(2)).reduce().is_reduced()
|
|
1198
|
+
True
|
|
1199
|
+
sage: print((-G.V(2)^3*G.V(6)^2*G.V(3)).reduce().string_repr("block"))
|
|
1200
|
+
(-S*T^(-1)) * (V(2)^3*V(6)^2*V(3)) * (-S*T^(-1))^(-1)
|
|
1201
|
+
sage: (-G.V(2)^3*G.V(6)^2*G.V(3)).reduce().is_reduced()
|
|
1202
|
+
True
|
|
1203
|
+
|
|
1204
|
+
sage: print((-G.I()).reduce().string_repr("block"))
|
|
1205
|
+
1
|
|
1206
|
+
sage: print(G.U().reduce().string_repr("block"))
|
|
1207
|
+
U
|
|
1208
|
+
sage: print((-G.S()).reduce().string_repr("block"))
|
|
1209
|
+
S
|
|
1210
|
+
sage: print((G.V(2)*G.V(3)).acton(G.U()^6).reduce().string_repr("block"))
|
|
1211
|
+
U
|
|
1212
|
+
sage: print((G.V(2)*G.V(3)).acton(G.U()^6).reduce(primitive=False).string_repr("block"))
|
|
1213
|
+
-U^(-1)
|
|
1214
|
+
"""
|
|
1215
|
+
if self.parent().n() == infinity:
|
|
1216
|
+
from warnings import warn
|
|
1217
|
+
warn("The case n=infinity here is not verified at all and probably wrong!")
|
|
1218
|
+
|
|
1219
|
+
P, R = self.primitive_representative(method='cf')
|
|
1220
|
+
|
|
1221
|
+
if primitive:
|
|
1222
|
+
return P
|
|
1223
|
+
else:
|
|
1224
|
+
return R.inverse().acton(self)
|
|
1225
|
+
|
|
1226
|
+
def sign(self):
|
|
1227
|
+
r"""
|
|
1228
|
+
Return the sign element/matrix (+- identity) of ``self``.
|
|
1229
|
+
The sign is given by the sign of the trace.
|
|
1230
|
+
if the trace is zero it is instead given by the sign
|
|
1231
|
+
of the lower left entry.
|
|
1232
|
+
|
|
1233
|
+
EXAMPLES::
|
|
1234
|
+
|
|
1235
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
1236
|
+
sage: G = HeckeTriangleGroup(n=7)
|
|
1237
|
+
sage: (-G.T(-1)).sign()
|
|
1238
|
+
[-1 0]
|
|
1239
|
+
[ 0 -1]
|
|
1240
|
+
sage: G.S().sign()
|
|
1241
|
+
[1 0]
|
|
1242
|
+
[0 1]
|
|
1243
|
+
sage: (-G.S()).sign()
|
|
1244
|
+
[-1 0]
|
|
1245
|
+
[ 0 -1]
|
|
1246
|
+
sage: (G.U()^6).sign()
|
|
1247
|
+
[-1 0]
|
|
1248
|
+
[ 0 -1]
|
|
1249
|
+
|
|
1250
|
+
sage: G = HeckeTriangleGroup(n=8)
|
|
1251
|
+
sage: (G.U()^4).trace()
|
|
1252
|
+
0
|
|
1253
|
+
sage: (G.U()^4).sign()
|
|
1254
|
+
[1 0]
|
|
1255
|
+
[0 1]
|
|
1256
|
+
sage: (G.U()^(-4)).sign()
|
|
1257
|
+
[-1 0]
|
|
1258
|
+
[ 0 -1]
|
|
1259
|
+
"""
|
|
1260
|
+
sgn = coerce_AA(self._matrix.trace()).sign()
|
|
1261
|
+
|
|
1262
|
+
if sgn > 0:
|
|
1263
|
+
return self.parent().I()
|
|
1264
|
+
elif sgn < 0:
|
|
1265
|
+
return -self.parent().I()
|
|
1266
|
+
else:
|
|
1267
|
+
sgnc = coerce_AA(self.c()).sign()
|
|
1268
|
+
if sgnc > 0:
|
|
1269
|
+
return self.parent().I()
|
|
1270
|
+
elif sgnc < 0:
|
|
1271
|
+
return -self.parent().I()
|
|
1272
|
+
else:
|
|
1273
|
+
raise AssertionError("This shouldn't happen!")
|
|
1274
|
+
|
|
1275
|
+
@cached_method
|
|
1276
|
+
def primitive_power(self, method='cf'):
|
|
1277
|
+
r"""
|
|
1278
|
+
Return the primitive power of ``self``. I.e. an integer
|
|
1279
|
+
``power`` such that ``self = sign * primitive_part^power``,
|
|
1280
|
+
where ``sign = self.sign()`` and
|
|
1281
|
+
``primitive_part = self.primitive_part(method)``.
|
|
1282
|
+
|
|
1283
|
+
Warning: For the parabolic case the sign depends on
|
|
1284
|
+
the method: The "cf" method may return a negative power
|
|
1285
|
+
but the "block" method never will.
|
|
1286
|
+
|
|
1287
|
+
Warning: The case ``n=infinity`` is not verified at all
|
|
1288
|
+
and probably wrong!
|
|
1289
|
+
|
|
1290
|
+
INPUT:
|
|
1291
|
+
|
|
1292
|
+
- ``method`` -- the method used to determine the primitive
|
|
1293
|
+
power (see :meth:`primitive_representative`),
|
|
1294
|
+
default: ``'cf'``. The parameter is ignored
|
|
1295
|
+
for elliptic elements or +- the identity.
|
|
1296
|
+
|
|
1297
|
+
OUTPUT:
|
|
1298
|
+
|
|
1299
|
+
An integer. For +- the identity element ``0`` is returned,
|
|
1300
|
+
for parabolic and hyperbolic elements a positive integer.
|
|
1301
|
+
And for elliptic elements a (nonzero) integer with minimal
|
|
1302
|
+
absolute value such that ``primitive_part^power`` still
|
|
1303
|
+
has a positive sign.
|
|
1304
|
+
|
|
1305
|
+
EXAMPLES::
|
|
1306
|
+
|
|
1307
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
1308
|
+
sage: G = HeckeTriangleGroup(n=7)
|
|
1309
|
+
sage: G.T().primitive_power()
|
|
1310
|
+
-1
|
|
1311
|
+
sage: G.V(2).acton(G.T(-3)).primitive_power()
|
|
1312
|
+
3
|
|
1313
|
+
sage: (-G.V(2)^2).primitive_power()
|
|
1314
|
+
2
|
|
1315
|
+
sage: el = (-G.V(2)*G.V(6)*G.V(3)*G.V(2)*G.V(6)*G.V(3))
|
|
1316
|
+
sage: el.primitive_power()
|
|
1317
|
+
2
|
|
1318
|
+
sage: (G.U()^4*G.S()*G.V(2)).acton(el).primitive_power()
|
|
1319
|
+
2
|
|
1320
|
+
sage: (G.V(2)*G.V(3)).acton(G.U()^6).primitive_power()
|
|
1321
|
+
-1
|
|
1322
|
+
sage: G.V(2).acton(G.T(-3)).primitive_power() == G.V(2).acton(G.T(-3)).primitive_power(method='block')
|
|
1323
|
+
True
|
|
1324
|
+
|
|
1325
|
+
sage: (-G.I()).primitive_power()
|
|
1326
|
+
0
|
|
1327
|
+
sage: G.U().primitive_power()
|
|
1328
|
+
1
|
|
1329
|
+
sage: (-G.S()).primitive_power()
|
|
1330
|
+
1
|
|
1331
|
+
sage: el = (G.V(2)*G.V(3)).acton(G.U()^6)
|
|
1332
|
+
sage: el.primitive_power()
|
|
1333
|
+
-1
|
|
1334
|
+
sage: el.primitive_power() == (-el).primitive_power()
|
|
1335
|
+
True
|
|
1336
|
+
sage: (G.U()^(-6)).primitive_power()
|
|
1337
|
+
1
|
|
1338
|
+
|
|
1339
|
+
sage: G = HeckeTriangleGroup(n=8)
|
|
1340
|
+
sage: (G.U()^4).primitive_power()
|
|
1341
|
+
4
|
|
1342
|
+
sage: (G.U()^(-4)).primitive_power()
|
|
1343
|
+
4
|
|
1344
|
+
"""
|
|
1345
|
+
if self.parent().n() == infinity:
|
|
1346
|
+
from warnings import warn
|
|
1347
|
+
warn("The case n=infinity here is not verified at all and probably wrong!")
|
|
1348
|
+
|
|
1349
|
+
zero = ZZ.zero()
|
|
1350
|
+
one = ZZ.one()
|
|
1351
|
+
two = ZZ(2)
|
|
1352
|
+
|
|
1353
|
+
if self.is_identity():
|
|
1354
|
+
return zero
|
|
1355
|
+
|
|
1356
|
+
if self.is_elliptic():
|
|
1357
|
+
if self.parent().n() == infinity:
|
|
1358
|
+
raise NotImplementedError
|
|
1359
|
+
|
|
1360
|
+
data, R = self._primitive_block_decomposition_data()
|
|
1361
|
+
if data[0] == 0:
|
|
1362
|
+
return one
|
|
1363
|
+
else:
|
|
1364
|
+
G = self.parent()
|
|
1365
|
+
U = G.U()
|
|
1366
|
+
U_power = R.inverse() * self * R
|
|
1367
|
+
|
|
1368
|
+
Uj = G.I()
|
|
1369
|
+
for j in range(1, G.n()):
|
|
1370
|
+
Uj *= U
|
|
1371
|
+
if U_power == Uj:
|
|
1372
|
+
# L = [one, ZZ(j)]
|
|
1373
|
+
break
|
|
1374
|
+
if U_power == -Uj:
|
|
1375
|
+
# L = [one, ZZ(-j)]
|
|
1376
|
+
break
|
|
1377
|
+
else:
|
|
1378
|
+
raise RuntimeError("There is a problem in the method "
|
|
1379
|
+
"'primitive_power'. Please contact sage-devel@googlegroups.com")
|
|
1380
|
+
|
|
1381
|
+
if abs(j) < G.n()/two:
|
|
1382
|
+
return j
|
|
1383
|
+
elif two*j == G.n():
|
|
1384
|
+
return j
|
|
1385
|
+
# for the cases from here on the sign has to be adjusted
|
|
1386
|
+
# to the
|
|
1387
|
+
# sign of self (in self._block_decomposition_data())
|
|
1388
|
+
elif two*j == -G.n():
|
|
1389
|
+
return -j
|
|
1390
|
+
elif j > 0:
|
|
1391
|
+
return j - G.n()
|
|
1392
|
+
else:
|
|
1393
|
+
return j + G.n()
|
|
1394
|
+
|
|
1395
|
+
primitive_part = self.primitive_part(method=method)
|
|
1396
|
+
if method == "cf" and self.is_parabolic():
|
|
1397
|
+
power_sign = coerce_AA(self.trace() * (self[1][0] - self[0][1])).sign()
|
|
1398
|
+
else:
|
|
1399
|
+
power_sign = one
|
|
1400
|
+
|
|
1401
|
+
normalized_self = self.sign() * self**power_sign
|
|
1402
|
+
M = primitive_part
|
|
1403
|
+
|
|
1404
|
+
power = 1
|
|
1405
|
+
while M != normalized_self:
|
|
1406
|
+
M *= primitive_part
|
|
1407
|
+
power += 1
|
|
1408
|
+
|
|
1409
|
+
return power*power_sign
|
|
1410
|
+
|
|
1411
|
+
def block_length(self, primitive=False):
|
|
1412
|
+
r"""
|
|
1413
|
+
Return the block length of ``self``. The block length is
|
|
1414
|
+
given by the number of factors used for the decomposition
|
|
1415
|
+
of the conjugacy representative of ``self`` described in
|
|
1416
|
+
:meth:`primitive_representative`. In particular the block
|
|
1417
|
+
length is invariant under conjugation.
|
|
1418
|
+
|
|
1419
|
+
The definition is mostly used for parabolic or hyperbolic
|
|
1420
|
+
elements: In particular it gives a lower bound for the
|
|
1421
|
+
(absolute value of) the trace and the discriminant for
|
|
1422
|
+
primitive hyperbolic elements. Namely
|
|
1423
|
+
``abs(trace) >= lambda * block_length`` and
|
|
1424
|
+
``discriminant >= block_length^2 * lambda^2 - 4``.
|
|
1425
|
+
|
|
1426
|
+
Warning: The case ``n=infinity`` is not verified at all
|
|
1427
|
+
and probably wrong!
|
|
1428
|
+
|
|
1429
|
+
INPUT:
|
|
1430
|
+
|
|
1431
|
+
- ``primitive`` -- boolean (default: ``False``); if ``True`` then the
|
|
1432
|
+
conjugacy representative of the primitive part is used instead
|
|
1433
|
+
|
|
1434
|
+
OUTPUT:
|
|
1435
|
+
|
|
1436
|
+
An integer. For hyperbolic elements a nonnegative integer.
|
|
1437
|
+
For parabolic elements a negative sign corresponds to taking
|
|
1438
|
+
the inverse. For elliptic elements a (non-trivial) integer
|
|
1439
|
+
with minimal absolute value is chosen. For +- the identity
|
|
1440
|
+
element ``0`` is returned.
|
|
1441
|
+
|
|
1442
|
+
EXAMPLES::
|
|
1443
|
+
|
|
1444
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
1445
|
+
sage: G = HeckeTriangleGroup(n=7)
|
|
1446
|
+
sage: G.T().block_length()
|
|
1447
|
+
1
|
|
1448
|
+
sage: G.V(2).acton(G.T(-3)).block_length()
|
|
1449
|
+
3
|
|
1450
|
+
sage: G.V(2).acton(G.T(-3)).block_length(primitive=True)
|
|
1451
|
+
1
|
|
1452
|
+
sage: (-G.V(2)).block_length()
|
|
1453
|
+
1
|
|
1454
|
+
|
|
1455
|
+
sage: el = -G.V(2)^3*G.V(6)^2*G.V(3)
|
|
1456
|
+
sage: t = el.block_length()
|
|
1457
|
+
sage: D = el.discriminant()
|
|
1458
|
+
sage: trace = el.trace()
|
|
1459
|
+
sage: (trace, D, t)
|
|
1460
|
+
(-124*lam^2 - 103*lam + 68, 65417*lam^2 + 52456*lam - 36300, 6)
|
|
1461
|
+
sage: abs(AA(trace)) >= AA(G.lam()*t)
|
|
1462
|
+
True
|
|
1463
|
+
sage: AA(D) >= AA(t^2 * G.lam() - 4)
|
|
1464
|
+
True
|
|
1465
|
+
sage: (el^3).block_length(primitive=True) == t
|
|
1466
|
+
True
|
|
1467
|
+
|
|
1468
|
+
sage: el = (G.U()^4*G.S()*G.V(2)).acton(-G.V(2)^3*G.V(6)^2*G.V(3))
|
|
1469
|
+
sage: t = el.block_length()
|
|
1470
|
+
sage: D = el.discriminant()
|
|
1471
|
+
sage: trace = el.trace()
|
|
1472
|
+
sage: (trace, D, t)
|
|
1473
|
+
(-124*lam^2 - 103*lam + 68, 65417*lam^2 + 52456*lam - 36300, 6)
|
|
1474
|
+
sage: abs(AA(trace)) >= AA(G.lam()*t)
|
|
1475
|
+
True
|
|
1476
|
+
sage: AA(D) >= AA(t^2 * G.lam() - 4)
|
|
1477
|
+
True
|
|
1478
|
+
sage: (el^(-2)).block_length(primitive=True) == t
|
|
1479
|
+
True
|
|
1480
|
+
|
|
1481
|
+
sage: el = G.V(1)^5*G.V(2)*G.V(3)^3
|
|
1482
|
+
sage: t = el.block_length()
|
|
1483
|
+
sage: D = el.discriminant()
|
|
1484
|
+
sage: trace = el.trace()
|
|
1485
|
+
sage: (trace, D, t)
|
|
1486
|
+
(284*lam^2 + 224*lam - 156, 330768*lam^2 + 265232*lam - 183556, 9)
|
|
1487
|
+
sage: abs(AA(trace)) >= AA(G.lam()*t)
|
|
1488
|
+
True
|
|
1489
|
+
sage: AA(D) >= AA(t^2 * G.lam() - 4)
|
|
1490
|
+
True
|
|
1491
|
+
sage: (el^(-1)).block_length(primitive=True) == t
|
|
1492
|
+
True
|
|
1493
|
+
|
|
1494
|
+
sage: (G.V(2)*G.V(3)).acton(G.U()^6).block_length()
|
|
1495
|
+
1
|
|
1496
|
+
sage: (G.V(2)*G.V(3)).acton(G.U()^6).block_length(primitive=True)
|
|
1497
|
+
1
|
|
1498
|
+
|
|
1499
|
+
sage: (-G.I()).block_length()
|
|
1500
|
+
0
|
|
1501
|
+
sage: G.U().block_length()
|
|
1502
|
+
1
|
|
1503
|
+
sage: (-G.S()).block_length()
|
|
1504
|
+
1
|
|
1505
|
+
"""
|
|
1506
|
+
if self.parent().n() == infinity:
|
|
1507
|
+
from warnings import warn
|
|
1508
|
+
warn("The case n=infinity here is not verified at all and probably wrong!")
|
|
1509
|
+
|
|
1510
|
+
if primitive:
|
|
1511
|
+
L = self._primitive_block_decomposition_data()[0]
|
|
1512
|
+
else:
|
|
1513
|
+
L = self._block_decomposition_data()[0]
|
|
1514
|
+
|
|
1515
|
+
if self.is_elliptic():
|
|
1516
|
+
if self.parent().n() == infinity:
|
|
1517
|
+
raise NotImplementedError
|
|
1518
|
+
|
|
1519
|
+
return abs(L[1])
|
|
1520
|
+
else:
|
|
1521
|
+
return sum(abs(v[1]) for v in L)
|
|
1522
|
+
|
|
1523
|
+
# @cached_method
|
|
1524
|
+
def _block_decomposition_data(self):
|
|
1525
|
+
r"""
|
|
1526
|
+
Return a tuple ``(L, R, sgn)`` which describes the
|
|
1527
|
+
decomposition of ``self`` into a specific
|
|
1528
|
+
conjugacy representative whose decomposition is
|
|
1529
|
+
further described by the tuple ``L``. The conjugation
|
|
1530
|
+
matrix is returned as ``R`` and since all
|
|
1531
|
+
factors have a positive sign, the sign ``sgn``
|
|
1532
|
+
of ``self`` is supplied as well as +- 1 (which corresponds
|
|
1533
|
+
to the sign of the sign matrix ``self.sign()``).
|
|
1534
|
+
|
|
1535
|
+
The function is a generalization of
|
|
1536
|
+
:meth:`_primitive_block_decomposition_data`
|
|
1537
|
+
(see for more information) to give the decomposition data
|
|
1538
|
+
for possibly non-primitive elements.
|
|
1539
|
+
|
|
1540
|
+
Also see :meth:`block_decomposition()` for more information
|
|
1541
|
+
on the block decomposition.
|
|
1542
|
+
|
|
1543
|
+
Warning: The case ``n=infinity`` is not verified at all
|
|
1544
|
+
and probably wrong!
|
|
1545
|
+
|
|
1546
|
+
OUTPUT:
|
|
1547
|
+
|
|
1548
|
+
A tuple ``(L, R, sgn)``, where ``R`` is an element of
|
|
1549
|
+
the Hecke triangle group that conjugates the
|
|
1550
|
+
described representative to ``self`` up to the given sign.
|
|
1551
|
+
|
|
1552
|
+
In the hyperbolic and parabolic case ``L`` is an
|
|
1553
|
+
ordered tuple of (tuple) data ``(j, k)``, corresponding
|
|
1554
|
+
to a factor ``V(j)^k``.
|
|
1555
|
+
|
|
1556
|
+
If the representative is the identity then ``((1, 0))``
|
|
1557
|
+
is returned (consistent with the previous notation).
|
|
1558
|
+
|
|
1559
|
+
In the elliptic case ``L=(a, k)``, with either ``a=0``
|
|
1560
|
+
corresponding to the representative ``S^k`` or with
|
|
1561
|
+
``a=1`` corresponding to the representative ``U^k``.
|
|
1562
|
+
|
|
1563
|
+
EXAMPLES::
|
|
1564
|
+
|
|
1565
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
1566
|
+
sage: G = HeckeTriangleGroup(n=7)
|
|
1567
|
+
sage: G.element_repr_method("basic")
|
|
1568
|
+
|
|
1569
|
+
sage: L, R, sgn = G.T()._block_decomposition_data()
|
|
1570
|
+
sage: (L, sgn)
|
|
1571
|
+
(((1, 1),), 1)
|
|
1572
|
+
sage: R
|
|
1573
|
+
T^(-1)
|
|
1574
|
+
sage: L, R, sgn = G.V(2).acton(G.T(-3))._block_decomposition_data()
|
|
1575
|
+
sage: (L, sgn)
|
|
1576
|
+
(((6, 3),), 1)
|
|
1577
|
+
sage: R
|
|
1578
|
+
T
|
|
1579
|
+
sage: L, R, sgn = (-G.V(2)^2)._block_decomposition_data()
|
|
1580
|
+
sage: (L, sgn)
|
|
1581
|
+
(((2, 2),), -1)
|
|
1582
|
+
sage: R
|
|
1583
|
+
T*S*T
|
|
1584
|
+
sage: el = (-G.V(2)*G.V(6)*G.V(3)*G.V(2)*G.V(6)*G.V(3))
|
|
1585
|
+
sage: L, R, sgn = el._block_decomposition_data()
|
|
1586
|
+
sage: (L, sgn)
|
|
1587
|
+
(((6, 1), (3, 1), (2, 1), (6, 1), (3, 1), (2, 1)), -1)
|
|
1588
|
+
sage: R
|
|
1589
|
+
T*S*T
|
|
1590
|
+
sage: L, R, sgn = (G.U()^4*G.S()*G.V(2)).acton(el)._block_decomposition_data()
|
|
1591
|
+
sage: (L, sgn)
|
|
1592
|
+
(((2, 1), (6, 1), (3, 1), (2, 1), (6, 1), (3, 1)), -1)
|
|
1593
|
+
sage: R
|
|
1594
|
+
T*S*T*S*T*S*T^2*S*T
|
|
1595
|
+
sage: L, R, sgn = (G.V(1)^5*G.V(2)*G.V(3)^3)._block_decomposition_data()
|
|
1596
|
+
sage: (L, sgn)
|
|
1597
|
+
(((3, 3), (1, 5), (2, 1)), 1)
|
|
1598
|
+
sage: R
|
|
1599
|
+
T^6*S*T
|
|
1600
|
+
|
|
1601
|
+
sage: G.element_repr_method("default")
|
|
1602
|
+
sage: L, R, sgn = (-G.I())._block_decomposition_data()
|
|
1603
|
+
sage: (L, sgn)
|
|
1604
|
+
(((6, 0),), -1)
|
|
1605
|
+
sage: R
|
|
1606
|
+
[1 0]
|
|
1607
|
+
[0 1]
|
|
1608
|
+
sage: L, R, sgn = G.U()._block_decomposition_data()
|
|
1609
|
+
sage: (L, sgn)
|
|
1610
|
+
((1, 1), 1)
|
|
1611
|
+
sage: R
|
|
1612
|
+
[1 0]
|
|
1613
|
+
[0 1]
|
|
1614
|
+
sage: L, R, sgn = (-G.S())._block_decomposition_data()
|
|
1615
|
+
sage: (L, sgn)
|
|
1616
|
+
((0, 1), -1)
|
|
1617
|
+
sage: R
|
|
1618
|
+
[-1 0]
|
|
1619
|
+
[ 0 -1]
|
|
1620
|
+
sage: L, R, sgn = (G.V(2)*G.V(3)).acton(G.U()^6)._block_decomposition_data()
|
|
1621
|
+
sage: (L, sgn)
|
|
1622
|
+
((1, -1), -1)
|
|
1623
|
+
sage: R
|
|
1624
|
+
[-2*lam^2 - 2*lam + 2 -2*lam^2 - 2*lam + 1]
|
|
1625
|
+
[ -2*lam^2 + 1 -2*lam^2 - lam + 2]
|
|
1626
|
+
sage: L, R, sgn = (G.U()^(-6))._block_decomposition_data()
|
|
1627
|
+
sage: (L, sgn)
|
|
1628
|
+
((1, 1), -1)
|
|
1629
|
+
sage: R
|
|
1630
|
+
[1 0]
|
|
1631
|
+
[0 1]
|
|
1632
|
+
|
|
1633
|
+
sage: G = HeckeTriangleGroup(n=8)
|
|
1634
|
+
sage: L, R, sgn = (G.U()^4)._block_decomposition_data()
|
|
1635
|
+
sage: (L, sgn)
|
|
1636
|
+
((1, 4), 1)
|
|
1637
|
+
sage: R
|
|
1638
|
+
[1 0]
|
|
1639
|
+
[0 1]
|
|
1640
|
+
sage: L, R, sgn = (G.U()^(-4))._block_decomposition_data()
|
|
1641
|
+
sage: (L, sgn)
|
|
1642
|
+
((1, 4), -1)
|
|
1643
|
+
sage: R
|
|
1644
|
+
[1 0]
|
|
1645
|
+
[0 1]
|
|
1646
|
+
"""
|
|
1647
|
+
if self.parent().n() == infinity:
|
|
1648
|
+
from warnings import warn
|
|
1649
|
+
warn("The case n=infinity here is not verified at all and probably wrong!")
|
|
1650
|
+
|
|
1651
|
+
L, R = self._primitive_block_decomposition_data()
|
|
1652
|
+
if self.sign() == self.parent().I():
|
|
1653
|
+
sgn = ZZ(1)
|
|
1654
|
+
else:
|
|
1655
|
+
sgn = ZZ(-1)
|
|
1656
|
+
|
|
1657
|
+
if self.is_identity():
|
|
1658
|
+
return (L, R, sgn)
|
|
1659
|
+
|
|
1660
|
+
if self.is_elliptic():
|
|
1661
|
+
if self.parent().n() == infinity:
|
|
1662
|
+
raise NotImplementedError
|
|
1663
|
+
|
|
1664
|
+
# Since L is primitive L[1] should be equal to 1
|
|
1665
|
+
M = (L[0], self.primitive_power())
|
|
1666
|
+
return (M, R, sgn)
|
|
1667
|
+
|
|
1668
|
+
# If the length of L is 1, there is always at most one block
|
|
1669
|
+
# Note that this is includes the parabolic case
|
|
1670
|
+
if len(L) == 1:
|
|
1671
|
+
# Since L is primitive L[0][1] should be equal to 1
|
|
1672
|
+
# Also note that in the non-elliptic case:
|
|
1673
|
+
# abs(self.primitive_power()) == self.primitive_power(method="block")
|
|
1674
|
+
L2 = ((L[0][0], abs(self.primitive_power())),)
|
|
1675
|
+
else:
|
|
1676
|
+
L2 = L * abs(self.primitive_power())
|
|
1677
|
+
|
|
1678
|
+
return (L2, R, sgn)
|
|
1679
|
+
|
|
1680
|
+
def block_decomposition(self):
|
|
1681
|
+
r"""
|
|
1682
|
+
Return a tuple ``(L, R, sgn)`` such that
|
|
1683
|
+
``self = sgn * R.acton(prod(L)) = sgn * R*prod(L)*R.inverse()``.
|
|
1684
|
+
|
|
1685
|
+
In the parabolic and hyperbolic case the tuple entries
|
|
1686
|
+
in ``L`` are powers of basic block matrices:
|
|
1687
|
+
``V(j) = U^(j-1)*T = self.parent().V(j)`` for ``1 <= j <= n-1``.
|
|
1688
|
+
In the elliptic case the tuple entries are either ``S`` or ``U``.
|
|
1689
|
+
|
|
1690
|
+
This decomposition data is (also) described by
|
|
1691
|
+
:meth:`_block_decomposition_data`.
|
|
1692
|
+
|
|
1693
|
+
Warning: The case ``n=infinity`` is not verified at all
|
|
1694
|
+
and probably wrong!
|
|
1695
|
+
|
|
1696
|
+
EXAMPLES::
|
|
1697
|
+
|
|
1698
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
1699
|
+
sage: G = HeckeTriangleGroup(n=7)
|
|
1700
|
+
sage: G.element_repr_method("basic")
|
|
1701
|
+
|
|
1702
|
+
sage: G.T().block_decomposition()
|
|
1703
|
+
((T,), T^(-1), 1)
|
|
1704
|
+
sage: G.V(2).acton(G.T(-3)).block_decomposition()
|
|
1705
|
+
((-S*T^(-3)*S,), T, 1)
|
|
1706
|
+
sage: (-G.V(2)^2).block_decomposition()
|
|
1707
|
+
((T*S*T^2*S*T,), T*S*T, -1)
|
|
1708
|
+
|
|
1709
|
+
sage: el = (-G.V(2)*G.V(6)*G.V(3)*G.V(2)*G.V(6)*G.V(3))
|
|
1710
|
+
sage: el.block_decomposition()
|
|
1711
|
+
((-S*T^(-1)*S, T*S*T*S*T, T*S*T, -S*T^(-1)*S, T*S*T*S*T, T*S*T), T*S*T, -1)
|
|
1712
|
+
sage: (G.U()^4*G.S()*G.V(2)).acton(el).block_decomposition()
|
|
1713
|
+
((T*S*T, -S*T^(-1)*S, T*S*T*S*T, T*S*T, -S*T^(-1)*S, T*S*T*S*T), T*S*T*S*T*S*T^2*S*T, -1)
|
|
1714
|
+
sage: (G.V(1)^5*G.V(2)*G.V(3)^3).block_decomposition()
|
|
1715
|
+
((T*S*T*S*T^2*S*T*S*T^2*S*T*S*T, T^5, T*S*T), T^6*S*T, 1)
|
|
1716
|
+
|
|
1717
|
+
sage: G.element_repr_method("default")
|
|
1718
|
+
sage: (-G.I()).block_decomposition()
|
|
1719
|
+
(
|
|
1720
|
+
([1 0] [1 0] [-1 0]
|
|
1721
|
+
[0 1],), [0 1], [ 0 -1]
|
|
1722
|
+
)
|
|
1723
|
+
sage: G.U().block_decomposition()
|
|
1724
|
+
(
|
|
1725
|
+
([lam -1] [1 0] [1 0]
|
|
1726
|
+
[ 1 0],), [0 1], [0 1]
|
|
1727
|
+
)
|
|
1728
|
+
sage: (-G.S()).block_decomposition()
|
|
1729
|
+
(
|
|
1730
|
+
([ 0 -1] [-1 0] [-1 0]
|
|
1731
|
+
[ 1 0],), [ 0 -1], [ 0 -1]
|
|
1732
|
+
)
|
|
1733
|
+
sage: (G.V(2)*G.V(3)).acton(G.U()^6).block_decomposition()
|
|
1734
|
+
(
|
|
1735
|
+
([ 0 1] [-2*lam^2 - 2*lam + 2 -2*lam^2 - 2*lam + 1] [-1 0]
|
|
1736
|
+
[ -1 lam],), [ -2*lam^2 + 1 -2*lam^2 - lam + 2], [ 0 -1]
|
|
1737
|
+
)
|
|
1738
|
+
sage: (G.U()^(-6)).block_decomposition()
|
|
1739
|
+
(
|
|
1740
|
+
([lam -1] [1 0] [-1 0]
|
|
1741
|
+
[ 1 0],), [0 1], [ 0 -1]
|
|
1742
|
+
)
|
|
1743
|
+
|
|
1744
|
+
sage: G = HeckeTriangleGroup(n=8)
|
|
1745
|
+
sage: (G.U()^4).block_decomposition()
|
|
1746
|
+
(
|
|
1747
|
+
([ lam^2 - 1 -lam^3 + 2*lam] [1 0] [1 0]
|
|
1748
|
+
[ lam^3 - 2*lam -lam^2 + 1],), [0 1], [0 1]
|
|
1749
|
+
)
|
|
1750
|
+
sage: (G.U()^(-4)).block_decomposition()
|
|
1751
|
+
(
|
|
1752
|
+
([ lam^2 - 1 -lam^3 + 2*lam] [1 0] [-1 0]
|
|
1753
|
+
[ lam^3 - 2*lam -lam^2 + 1],), [0 1], [ 0 -1]
|
|
1754
|
+
)
|
|
1755
|
+
"""
|
|
1756
|
+
if self.parent().n() == infinity:
|
|
1757
|
+
from warnings import warn
|
|
1758
|
+
warn("The case n=infinity here is not verified at all and probably wrong!")
|
|
1759
|
+
|
|
1760
|
+
G = self.parent()
|
|
1761
|
+
L, R, sgn = self._block_decomposition_data()
|
|
1762
|
+
if sgn > 0:
|
|
1763
|
+
sgn = G.I()
|
|
1764
|
+
else:
|
|
1765
|
+
sgn = -G.I()
|
|
1766
|
+
|
|
1767
|
+
if self.is_identity():
|
|
1768
|
+
return ((G.I(),), R, sgn)
|
|
1769
|
+
|
|
1770
|
+
if self.is_elliptic():
|
|
1771
|
+
if self.parent().n() == infinity:
|
|
1772
|
+
raise NotImplementedError
|
|
1773
|
+
|
|
1774
|
+
if L[0] == 0:
|
|
1775
|
+
P = G.S()
|
|
1776
|
+
else:
|
|
1777
|
+
P = G.U()
|
|
1778
|
+
return ((P**L[1],), R, sgn)
|
|
1779
|
+
else:
|
|
1780
|
+
return (tuple(G.V(v[0])**v[1] for v in L), R, sgn)
|
|
1781
|
+
|
|
1782
|
+
def conjugacy_type(self, ignore_sign=True, primitive=False):
|
|
1783
|
+
r"""
|
|
1784
|
+
Return a unique description of the conjugacy class of ``self``
|
|
1785
|
+
(by default only up to a sign).
|
|
1786
|
+
|
|
1787
|
+
Warning: The case ``n=infinity`` is not verified at all
|
|
1788
|
+
and probably wrong!
|
|
1789
|
+
|
|
1790
|
+
INPUT:
|
|
1791
|
+
|
|
1792
|
+
- ``ignore_sign`` -- if ``True`` (default) then the conjugacy
|
|
1793
|
+
classes are only considered up to a sign
|
|
1794
|
+
|
|
1795
|
+
- ``primitive`` -- boolean (default: ``False``); if ``True`` then the
|
|
1796
|
+
conjugacy class of the primitive part is considered instead and the
|
|
1797
|
+
sign is ignored
|
|
1798
|
+
|
|
1799
|
+
OUTPUT:
|
|
1800
|
+
|
|
1801
|
+
A unique representative for the given block data (without the
|
|
1802
|
+
conjugation matrix) among all cyclic permutations.
|
|
1803
|
+
If ``ignore_sign=True`` then the sign is excluded as well.
|
|
1804
|
+
|
|
1805
|
+
EXAMPLES::
|
|
1806
|
+
|
|
1807
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
1808
|
+
sage: G = HeckeTriangleGroup(n=7)
|
|
1809
|
+
sage: (-G.I()).conjugacy_type()
|
|
1810
|
+
((6, 0),)
|
|
1811
|
+
sage: G.U().acton(G.S()).conjugacy_type()
|
|
1812
|
+
(0, 1)
|
|
1813
|
+
sage: (G.U()^4).conjugacy_type()
|
|
1814
|
+
(1, -3)
|
|
1815
|
+
sage: ((G.V(2)*G.V(3)^2*G.V(2)*G.V(3))^2).conjugacy_type()
|
|
1816
|
+
((3, 2), (2, 1), (3, 1), (2, 1), (3, 2), (2, 1), (3, 1), (2, 1))
|
|
1817
|
+
|
|
1818
|
+
sage: (-G.I()).conjugacy_type(ignore_sign=False)
|
|
1819
|
+
(((6, 0),), -1)
|
|
1820
|
+
sage: G.S().conjugacy_type(ignore_sign=False)
|
|
1821
|
+
((0, 1), 1)
|
|
1822
|
+
sage: (G.U()^4).conjugacy_type(ignore_sign=False)
|
|
1823
|
+
((1, -3), -1)
|
|
1824
|
+
sage: G.U().acton((G.V(2)*G.V(3)^2*G.V(2)*G.V(3))^2).conjugacy_type(ignore_sign=False)
|
|
1825
|
+
(((3, 2), (2, 1), (3, 1), (2, 1), (3, 2), (2, 1), (3, 1), (2, 1)), 1)
|
|
1826
|
+
|
|
1827
|
+
sage: (-G.I()).conjugacy_type(primitive=True)
|
|
1828
|
+
((6, 0),)
|
|
1829
|
+
sage: G.S().conjugacy_type(primitive=True)
|
|
1830
|
+
(0, 1)
|
|
1831
|
+
sage: G.V(2).acton(G.U()^4).conjugacy_type(primitive=True)
|
|
1832
|
+
(1, 1)
|
|
1833
|
+
sage: (G.V(3)^2).conjugacy_type(primitive=True)
|
|
1834
|
+
((3, 1),)
|
|
1835
|
+
sage: G.S().acton((G.V(2)*G.V(3)^2*G.V(2)*G.V(3))^2).conjugacy_type(primitive=True)
|
|
1836
|
+
((3, 2), (2, 1), (3, 1), (2, 1))
|
|
1837
|
+
"""
|
|
1838
|
+
if self.parent().n() == infinity:
|
|
1839
|
+
from warnings import warn
|
|
1840
|
+
warn("The case n=infinity here is not verified at all and probably wrong!")
|
|
1841
|
+
|
|
1842
|
+
if primitive:
|
|
1843
|
+
ignore_sign = True
|
|
1844
|
+
L, R = self._primitive_block_decomposition_data()
|
|
1845
|
+
else:
|
|
1846
|
+
L, R, sgn = self._block_decomposition_data()
|
|
1847
|
+
|
|
1848
|
+
if not self.is_elliptic():
|
|
1849
|
+
L = tuple(cyclic_representative(L))
|
|
1850
|
+
return L if ignore_sign else (L, sgn)
|
|
1851
|
+
|
|
1852
|
+
def reduced_elements(self):
|
|
1853
|
+
r"""
|
|
1854
|
+
Return the cycle of reduced elements in the (primitive)
|
|
1855
|
+
conjugacy class of ``self``.
|
|
1856
|
+
|
|
1857
|
+
I.e. the set (cycle) of all reduced elements which are
|
|
1858
|
+
conjugate to ``self.primitive_part()``.
|
|
1859
|
+
E.g. ``self.primitive_representative().reduce()``.
|
|
1860
|
+
|
|
1861
|
+
Also see :meth:`is_reduced`.
|
|
1862
|
+
In particular the result of this method only depends on the
|
|
1863
|
+
(primitive) conjugacy class of ``self``.
|
|
1864
|
+
|
|
1865
|
+
The method assumes that ``self`` is hyperbolic or parabolic.
|
|
1866
|
+
|
|
1867
|
+
Warning: The case ``n=infinity`` is not verified at all
|
|
1868
|
+
and probably wrong!
|
|
1869
|
+
|
|
1870
|
+
EXAMPLES::
|
|
1871
|
+
|
|
1872
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
1873
|
+
sage: G = HeckeTriangleGroup(n=5)
|
|
1874
|
+
sage: G.element_repr_method("basic")
|
|
1875
|
+
|
|
1876
|
+
sage: el = G.V(1)
|
|
1877
|
+
sage: el.continued_fraction()
|
|
1878
|
+
((0, 1), (1, 1, 2))
|
|
1879
|
+
sage: R = el.reduced_elements()
|
|
1880
|
+
sage: R
|
|
1881
|
+
[T*S*T*S*T^2*S, T*S*T^2*S*T*S, -T*S*T^(-1)*S*T^(-1)]
|
|
1882
|
+
sage: [v.continued_fraction() for v in R]
|
|
1883
|
+
[((), (1, 1, 2)), ((), (1, 2, 1)), ((), (2, 1, 1))]
|
|
1884
|
+
|
|
1885
|
+
sage: el = G.V(3)*G.V(2)^(-1)*G.V(1)*G.V(6)
|
|
1886
|
+
sage: el.continued_fraction()
|
|
1887
|
+
((1,), (3,))
|
|
1888
|
+
sage: R = el.reduced_elements()
|
|
1889
|
+
sage: [v.continued_fraction() for v in R]
|
|
1890
|
+
[((), (3,))]
|
|
1891
|
+
|
|
1892
|
+
sage: G.element_repr_method("default")
|
|
1893
|
+
"""
|
|
1894
|
+
if self.parent().n() == infinity:
|
|
1895
|
+
from warnings import warn
|
|
1896
|
+
warn("The case n=infinity here is not verified at all and probably wrong!")
|
|
1897
|
+
|
|
1898
|
+
if self.is_identity() or self.is_elliptic():
|
|
1899
|
+
raise NotImplementedError
|
|
1900
|
+
|
|
1901
|
+
def rotate(l, n):
|
|
1902
|
+
return tuple(l[n:] + l[:n])
|
|
1903
|
+
|
|
1904
|
+
G = self.parent()
|
|
1905
|
+
L = []
|
|
1906
|
+
period = self.continued_fraction()[1]
|
|
1907
|
+
period_set = set()
|
|
1908
|
+
for k in range(len(period)):
|
|
1909
|
+
cur_period = rotate(period, k)
|
|
1910
|
+
if cur_period in period_set:
|
|
1911
|
+
continue
|
|
1912
|
+
period_set.add(cur_period)
|
|
1913
|
+
L.append(prod((G.T()**r * G.S() for r in cur_period), G.I()))
|
|
1914
|
+
|
|
1915
|
+
return L
|
|
1916
|
+
|
|
1917
|
+
def simple_elements(self):
|
|
1918
|
+
r"""
|
|
1919
|
+
Return all simple elements in the primitive conjugacy
|
|
1920
|
+
class of ``self``.
|
|
1921
|
+
|
|
1922
|
+
I.e. the set of all simple elements which are
|
|
1923
|
+
conjugate to ``self.primitive_part()``.
|
|
1924
|
+
|
|
1925
|
+
Also see :meth:`is_simple`.
|
|
1926
|
+
In particular the result of this method only depends on the
|
|
1927
|
+
(primitive) conjugacy class of ``self``.
|
|
1928
|
+
|
|
1929
|
+
The method assumes that ``self`` is hyperbolic.
|
|
1930
|
+
|
|
1931
|
+
Warning: The case ``n=infinity`` is not verified at all
|
|
1932
|
+
and probably wrong!
|
|
1933
|
+
|
|
1934
|
+
EXAMPLES::
|
|
1935
|
+
|
|
1936
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
1937
|
+
sage: G = HeckeTriangleGroup(n=5)
|
|
1938
|
+
|
|
1939
|
+
sage: el = G.V(2)
|
|
1940
|
+
sage: el.continued_fraction()
|
|
1941
|
+
((1,), (2,))
|
|
1942
|
+
sage: R = el.simple_elements()
|
|
1943
|
+
sage: R
|
|
1944
|
+
[
|
|
1945
|
+
[lam lam]
|
|
1946
|
+
[ 1 lam]
|
|
1947
|
+
]
|
|
1948
|
+
sage: R[0].is_simple()
|
|
1949
|
+
True
|
|
1950
|
+
|
|
1951
|
+
sage: el = G.V(3)*G.V(2)^(-1)*G.V(1)*G.V(6)
|
|
1952
|
+
sage: el.continued_fraction()
|
|
1953
|
+
((1,), (3,))
|
|
1954
|
+
sage: R = el.simple_elements()
|
|
1955
|
+
sage: R
|
|
1956
|
+
[
|
|
1957
|
+
[ 2*lam 2*lam + 1] [ lam 2*lam + 1]
|
|
1958
|
+
[ 1 lam], [ 1 2*lam]
|
|
1959
|
+
]
|
|
1960
|
+
sage: [v.is_simple() for v in R]
|
|
1961
|
+
[True, True]
|
|
1962
|
+
|
|
1963
|
+
sage: el = G.V(1)^2*G.V(2)*G.V(4)
|
|
1964
|
+
sage: el.discriminant()
|
|
1965
|
+
135*lam + 86
|
|
1966
|
+
sage: R = el.simple_elements()
|
|
1967
|
+
sage: R
|
|
1968
|
+
[
|
|
1969
|
+
[ 3*lam 3*lam + 2] [8*lam + 3 3*lam + 2] [5*lam + 2 9*lam + 6]
|
|
1970
|
+
[3*lam + 4 6*lam + 3], [ lam + 2 lam], [ lam + 2 4*lam + 1],
|
|
1971
|
+
[2*lam + 1 7*lam + 4]
|
|
1972
|
+
[ lam + 2 7*lam + 2]
|
|
1973
|
+
]
|
|
1974
|
+
|
|
1975
|
+
This agrees with the results (p.16) from Culp-Ressler on
|
|
1976
|
+
binary quadratic forms for Hecke triangle groups::
|
|
1977
|
+
|
|
1978
|
+
sage: [v.continued_fraction() for v in R]
|
|
1979
|
+
[((1,), (1, 1, 4, 2)),
|
|
1980
|
+
((3,), (2, 1, 1, 4)),
|
|
1981
|
+
((2,), (2, 1, 1, 4)),
|
|
1982
|
+
((1,), (2, 1, 1, 4))]
|
|
1983
|
+
"""
|
|
1984
|
+
if self.parent().n() == infinity:
|
|
1985
|
+
from warnings import warn
|
|
1986
|
+
warn("The case n=infinity here is not verified at all and probably wrong!")
|
|
1987
|
+
|
|
1988
|
+
if not self.is_hyperbolic():
|
|
1989
|
+
return []
|
|
1990
|
+
|
|
1991
|
+
G = self.parent()
|
|
1992
|
+
emb = self.root_extension_embedding(AA)
|
|
1993
|
+
R = self.reduced_elements()
|
|
1994
|
+
L = []
|
|
1995
|
+
|
|
1996
|
+
for r in R:
|
|
1997
|
+
fp = r.fixed_points()[0]
|
|
1998
|
+
|
|
1999
|
+
emb_res = emb(fp / G.lam())
|
|
2000
|
+
emb_res.simplify()
|
|
2001
|
+
emb_res.exactify()
|
|
2002
|
+
L.extend(G.T(-j).acton(r) for j in range(1, emb_res.floor() + 1))
|
|
2003
|
+
|
|
2004
|
+
return L
|
|
2005
|
+
|
|
2006
|
+
def simple_fixed_point_set(self, extended=True):
|
|
2007
|
+
r"""
|
|
2008
|
+
Return a set of all attracting fixed points in the
|
|
2009
|
+
conjugacy class of the primitive part of ``self``.
|
|
2010
|
+
|
|
2011
|
+
If ``extended=True`` (default) then also
|
|
2012
|
+
``S.acton(alpha)`` are added for ``alpha`` in the set.
|
|
2013
|
+
|
|
2014
|
+
This is a so called `irreducible system of poles`
|
|
2015
|
+
for rational period functions for the parent group.
|
|
2016
|
+
I.e. the fixed points occur as a irreducible part
|
|
2017
|
+
of the nonzero pole set of some rational period
|
|
2018
|
+
function and all pole sets are given as a union
|
|
2019
|
+
of such irreducible systems of poles.
|
|
2020
|
+
|
|
2021
|
+
The method assumes that ``self`` is hyperbolic.
|
|
2022
|
+
|
|
2023
|
+
Warning: The case ``n=infinity`` is not verified at all
|
|
2024
|
+
and probably wrong!
|
|
2025
|
+
|
|
2026
|
+
EXAMPLES::
|
|
2027
|
+
|
|
2028
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
2029
|
+
sage: G = HeckeTriangleGroup(n=5)
|
|
2030
|
+
|
|
2031
|
+
sage: el = G.V(2)
|
|
2032
|
+
sage: el.simple_fixed_point_set()
|
|
2033
|
+
{1/2*e, (-1/2*lam + 1/2)*e}
|
|
2034
|
+
sage: el.simple_fixed_point_set(extended=False)
|
|
2035
|
+
{1/2*e}
|
|
2036
|
+
|
|
2037
|
+
sage: el = G.V(3)*G.V(2)^(-1)*G.V(1)*G.V(6)
|
|
2038
|
+
sage: el.simple_fixed_point_set()
|
|
2039
|
+
{(-lam + 3/2)*e + 1/2*lam - 1, (-lam + 3/2)*e - 1/2*lam + 1, 1/2*e - 1/2*lam, 1/2*e + 1/2*lam}
|
|
2040
|
+
|
|
2041
|
+
sage: el.simple_fixed_point_set(extended=False)
|
|
2042
|
+
{1/2*e - 1/2*lam, 1/2*e + 1/2*lam}
|
|
2043
|
+
"""
|
|
2044
|
+
if self.parent().n() == infinity:
|
|
2045
|
+
from warnings import warn
|
|
2046
|
+
warn("The case n=infinity here is not verified at all and probably wrong!")
|
|
2047
|
+
|
|
2048
|
+
if self.is_identity() or self.is_elliptic():
|
|
2049
|
+
raise NotImplementedError
|
|
2050
|
+
|
|
2051
|
+
from sage.sets.set import Set
|
|
2052
|
+
|
|
2053
|
+
R = self.simple_elements()
|
|
2054
|
+
FPS = Set(v.fixed_points()[0] for v in R)
|
|
2055
|
+
|
|
2056
|
+
if not extended:
|
|
2057
|
+
return FPS
|
|
2058
|
+
|
|
2059
|
+
S = self.parent().S()
|
|
2060
|
+
FPS2 = Set(S.acton(v) for v in FPS)
|
|
2061
|
+
|
|
2062
|
+
return FPS.union(FPS2)
|
|
2063
|
+
|
|
2064
|
+
def _latex_(self):
|
|
2065
|
+
r"""
|
|
2066
|
+
Return the LaTeX representation of ``self``.
|
|
2067
|
+
|
|
2068
|
+
EXAMPLES::
|
|
2069
|
+
|
|
2070
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
2071
|
+
sage: V = HeckeTriangleGroup(17).V(13)
|
|
2072
|
+
sage: latex(V)
|
|
2073
|
+
\begin{pmatrix} \mathit{\lambda}^{3} - 2 \mathit{\lambda} & \mathit{\lambda}^{2} - 1 \\ \mathit{\lambda}^{4} - 3 \mathit{\lambda}^{2} + 1 & \mathit{\lambda}^{3} - 2 \mathit{\lambda} \end{pmatrix}
|
|
2074
|
+
"""
|
|
2075
|
+
latex_out = r"\begin{pmatrix} %s & %s \\ %s & %s \end{pmatrix}" % (latex(self.a()), latex(self.b()), latex(self.c()), latex(self.d()))
|
|
2076
|
+
return latex_out.replace("lam", r"\lambda")
|
|
2077
|
+
|
|
2078
|
+
def __neg__(self):
|
|
2079
|
+
r"""
|
|
2080
|
+
Return the group element corresponding to the negative of the underlying matrix.
|
|
2081
|
+
|
|
2082
|
+
EXAMPLES::
|
|
2083
|
+
|
|
2084
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
2085
|
+
sage: U = HeckeTriangleGroup(n=7).U()
|
|
2086
|
+
sage: -U
|
|
2087
|
+
[-lam 1]
|
|
2088
|
+
[ -1 0]
|
|
2089
|
+
"""
|
|
2090
|
+
return self.parent().element_class(self.parent(), -self._matrix, check=False)
|
|
2091
|
+
|
|
2092
|
+
def __getitem__(self, key):
|
|
2093
|
+
r"""
|
|
2094
|
+
Return the corresponding rows/entries of the underlying matrix.
|
|
2095
|
+
|
|
2096
|
+
EXAMPLES::
|
|
2097
|
+
|
|
2098
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
2099
|
+
sage: U = HeckeTriangleGroup(n=7).U()
|
|
2100
|
+
sage: U[0]
|
|
2101
|
+
(lam, -1)
|
|
2102
|
+
sage: U[0].parent()
|
|
2103
|
+
Ambient free module of rank 2 over the principal ideal domain Maximal Order generated by lam in Number Field in lam with defining polynomial x^3 - x^2 - 2*x + 1 with lam = 1.801937735804839?
|
|
2104
|
+
sage: U[1][0]
|
|
2105
|
+
1
|
|
2106
|
+
sage: U[1][0].parent()
|
|
2107
|
+
Maximal Order generated by lam in Number Field in lam with defining polynomial x^3 - x^2 - 2*x + 1 with lam = 1.801937735804839?
|
|
2108
|
+
"""
|
|
2109
|
+
return self._matrix[key]
|
|
2110
|
+
|
|
2111
|
+
def a(self):
|
|
2112
|
+
r"""
|
|
2113
|
+
Return the upper left entry of ``self``.
|
|
2114
|
+
|
|
2115
|
+
EXAMPLES::
|
|
2116
|
+
|
|
2117
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
2118
|
+
sage: U = HeckeTriangleGroup(n=7).U()
|
|
2119
|
+
sage: U.a()
|
|
2120
|
+
lam
|
|
2121
|
+
sage: U.a().parent()
|
|
2122
|
+
Maximal Order generated by lam in Number Field in lam with defining polynomial x^3 - x^2 - 2*x + 1 with lam = 1.801937735804839?
|
|
2123
|
+
"""
|
|
2124
|
+
return self._matrix[0][0]
|
|
2125
|
+
|
|
2126
|
+
def b(self):
|
|
2127
|
+
r"""
|
|
2128
|
+
Return the upper right entry of ``self``.
|
|
2129
|
+
|
|
2130
|
+
EXAMPLES::
|
|
2131
|
+
|
|
2132
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
2133
|
+
sage: U = HeckeTriangleGroup(n=7).U()
|
|
2134
|
+
sage: U.b()
|
|
2135
|
+
-1
|
|
2136
|
+
sage: U.b().parent()
|
|
2137
|
+
Maximal Order generated by lam in Number Field in lam with defining polynomial x^3 - x^2 - 2*x + 1 with lam = 1.801937735804839?
|
|
2138
|
+
"""
|
|
2139
|
+
return self._matrix[0][1]
|
|
2140
|
+
|
|
2141
|
+
def c(self):
|
|
2142
|
+
r"""
|
|
2143
|
+
Return the lower left entry of ``self``.
|
|
2144
|
+
|
|
2145
|
+
EXAMPLES::
|
|
2146
|
+
|
|
2147
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
2148
|
+
sage: U = HeckeTriangleGroup(n=7).U()
|
|
2149
|
+
sage: U.c()
|
|
2150
|
+
1
|
|
2151
|
+
"""
|
|
2152
|
+
return self._matrix[1][0]
|
|
2153
|
+
|
|
2154
|
+
def d(self):
|
|
2155
|
+
r"""
|
|
2156
|
+
Return the lower right of ``self``.
|
|
2157
|
+
|
|
2158
|
+
EXAMPLES::
|
|
2159
|
+
|
|
2160
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
2161
|
+
sage: U = HeckeTriangleGroup(n=7).U()
|
|
2162
|
+
sage: U.d()
|
|
2163
|
+
0
|
|
2164
|
+
"""
|
|
2165
|
+
return self._matrix[1][1]
|
|
2166
|
+
|
|
2167
|
+
def trace(self):
|
|
2168
|
+
r"""
|
|
2169
|
+
Return the trace of ``self``, which is the sum of the diagonal entries.
|
|
2170
|
+
|
|
2171
|
+
EXAMPLES::
|
|
2172
|
+
|
|
2173
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
2174
|
+
sage: G = HeckeTriangleGroup(n=7)
|
|
2175
|
+
sage: G.U().trace()
|
|
2176
|
+
lam
|
|
2177
|
+
sage: G.S().trace()
|
|
2178
|
+
0
|
|
2179
|
+
"""
|
|
2180
|
+
return self._matrix.trace()
|
|
2181
|
+
|
|
2182
|
+
def discriminant(self):
|
|
2183
|
+
r"""
|
|
2184
|
+
Return the discriminant of ``self`` which corresponds to
|
|
2185
|
+
the discriminant of the corresponding quadratic form of ``self``.
|
|
2186
|
+
|
|
2187
|
+
EXAMPLES::
|
|
2188
|
+
|
|
2189
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
2190
|
+
sage: G = HeckeTriangleGroup(n=7)
|
|
2191
|
+
sage: G.V(3).discriminant()
|
|
2192
|
+
4*lam^2 + 4*lam - 4
|
|
2193
|
+
sage: AA(G.V(3).discriminant())
|
|
2194
|
+
16.19566935808922?
|
|
2195
|
+
"""
|
|
2196
|
+
return self.trace()**2 - 4
|
|
2197
|
+
|
|
2198
|
+
def is_translation(self, exclude_one=False) -> bool:
|
|
2199
|
+
r"""
|
|
2200
|
+
Return whether ``self`` is a translation.
|
|
2201
|
+
|
|
2202
|
+
If ``exclude_one = True``,
|
|
2203
|
+
then the identity map is not considered as a translation.
|
|
2204
|
+
|
|
2205
|
+
EXAMPLES::
|
|
2206
|
+
|
|
2207
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
2208
|
+
sage: (-HeckeTriangleGroup(n=7).T(-4)).is_translation()
|
|
2209
|
+
True
|
|
2210
|
+
sage: (-HeckeTriangleGroup(n=7).I()).is_translation()
|
|
2211
|
+
True
|
|
2212
|
+
sage: (-HeckeTriangleGroup(n=7).I()).is_translation(exclude_one=True)
|
|
2213
|
+
False
|
|
2214
|
+
"""
|
|
2215
|
+
a, b, c, d = self._matrix.list()
|
|
2216
|
+
|
|
2217
|
+
if not (c.is_zero() and a == d and (a.is_one() or (-a).is_one())):
|
|
2218
|
+
return False
|
|
2219
|
+
return not (exclude_one and b.is_zero())
|
|
2220
|
+
|
|
2221
|
+
def is_reflection(self) -> bool:
|
|
2222
|
+
r"""
|
|
2223
|
+
Return whether ``self`` is the usual reflection on the unit circle.
|
|
2224
|
+
|
|
2225
|
+
EXAMPLES::
|
|
2226
|
+
|
|
2227
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
2228
|
+
sage: (-HeckeTriangleGroup(n=7).S()).is_reflection()
|
|
2229
|
+
True
|
|
2230
|
+
sage: HeckeTriangleGroup(n=7).U().is_reflection()
|
|
2231
|
+
False
|
|
2232
|
+
"""
|
|
2233
|
+
return self == self.parent().S() or self == -self.parent().S()
|
|
2234
|
+
|
|
2235
|
+
def is_hyperbolic(self) -> bool:
|
|
2236
|
+
r"""
|
|
2237
|
+
Return whether ``self`` is a hyperbolic matrix.
|
|
2238
|
+
|
|
2239
|
+
EXAMPLES::
|
|
2240
|
+
|
|
2241
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
2242
|
+
sage: G = HeckeTriangleGroup(n=7)
|
|
2243
|
+
sage: [ G.V(k).is_hyperbolic() for k in range(1,8) ]
|
|
2244
|
+
[False, True, True, True, True, False, False]
|
|
2245
|
+
sage: G.U().is_hyperbolic()
|
|
2246
|
+
False
|
|
2247
|
+
"""
|
|
2248
|
+
return coerce_AA(self.discriminant()) > 0
|
|
2249
|
+
|
|
2250
|
+
def is_parabolic(self, exclude_one=False) -> bool:
|
|
2251
|
+
r"""
|
|
2252
|
+
Return whether ``self`` is a parabolic matrix.
|
|
2253
|
+
|
|
2254
|
+
If ``exclude_one`` is set, then +- the identity
|
|
2255
|
+
element is not considered parabolic.
|
|
2256
|
+
|
|
2257
|
+
EXAMPLES::
|
|
2258
|
+
|
|
2259
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
2260
|
+
sage: G = HeckeTriangleGroup(n=7)
|
|
2261
|
+
sage: [ G.V(k).is_parabolic() for k in range(1,8) ]
|
|
2262
|
+
[True, False, False, False, False, True, False]
|
|
2263
|
+
sage: G.U().is_parabolic()
|
|
2264
|
+
False
|
|
2265
|
+
sage: G.V(6).is_parabolic(exclude_one=True)
|
|
2266
|
+
True
|
|
2267
|
+
sage: G.V(7).is_parabolic(exclude_one=True)
|
|
2268
|
+
False
|
|
2269
|
+
"""
|
|
2270
|
+
if exclude_one and self.is_identity():
|
|
2271
|
+
return False
|
|
2272
|
+
|
|
2273
|
+
return self.discriminant() == 0
|
|
2274
|
+
|
|
2275
|
+
def is_identity(self) -> bool:
|
|
2276
|
+
r"""
|
|
2277
|
+
Return whether ``self`` is the identity or minus the identity.
|
|
2278
|
+
|
|
2279
|
+
EXAMPLES::
|
|
2280
|
+
|
|
2281
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
2282
|
+
sage: G = HeckeTriangleGroup(n=7)
|
|
2283
|
+
sage: [ G.V(k).is_identity() for k in range(1,8) ]
|
|
2284
|
+
[False, False, False, False, False, False, False]
|
|
2285
|
+
sage: G.U().is_identity()
|
|
2286
|
+
False
|
|
2287
|
+
"""
|
|
2288
|
+
if self == self.parent().I() or self == -self.parent().I():
|
|
2289
|
+
return True
|
|
2290
|
+
else:
|
|
2291
|
+
return False
|
|
2292
|
+
|
|
2293
|
+
def is_elliptic(self) -> bool:
|
|
2294
|
+
r"""
|
|
2295
|
+
Return whether ``self`` is an elliptic matrix.
|
|
2296
|
+
|
|
2297
|
+
EXAMPLES::
|
|
2298
|
+
|
|
2299
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
2300
|
+
sage: G = HeckeTriangleGroup(n=7)
|
|
2301
|
+
sage: [ G.V(k).is_elliptic() for k in range(1,8) ]
|
|
2302
|
+
[False, False, False, False, False, False, True]
|
|
2303
|
+
sage: G.U().is_elliptic()
|
|
2304
|
+
True
|
|
2305
|
+
"""
|
|
2306
|
+
return coerce_AA(self.discriminant()) < 0
|
|
2307
|
+
|
|
2308
|
+
def is_primitive(self) -> bool:
|
|
2309
|
+
r"""
|
|
2310
|
+
Return whether ``self`` is primitive. We call an element
|
|
2311
|
+
primitive if (up to a sign and taking inverses) it generates
|
|
2312
|
+
the full stabilizer subgroup of the corresponding fixed point.
|
|
2313
|
+
In the non-elliptic case this means that primitive elements
|
|
2314
|
+
cannot be written as a `non-trivial` power of another element.
|
|
2315
|
+
|
|
2316
|
+
The notion is mostly used for hyperbolic and parabolic elements.
|
|
2317
|
+
|
|
2318
|
+
Warning: The case ``n=infinity`` is not verified at all
|
|
2319
|
+
and probably wrong!
|
|
2320
|
+
|
|
2321
|
+
EXAMPLES::
|
|
2322
|
+
|
|
2323
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
2324
|
+
sage: G = HeckeTriangleGroup(n=7)
|
|
2325
|
+
sage: G.V(2).acton(G.T(-1)).is_primitive()
|
|
2326
|
+
True
|
|
2327
|
+
sage: G.T(3).is_primitive()
|
|
2328
|
+
False
|
|
2329
|
+
sage: (-G.V(2)^2).is_primitive()
|
|
2330
|
+
False
|
|
2331
|
+
sage: (G.V(1)^5*G.V(2)*G.V(3)^3).is_primitive()
|
|
2332
|
+
True
|
|
2333
|
+
|
|
2334
|
+
sage: (-G.I()).is_primitive()
|
|
2335
|
+
True
|
|
2336
|
+
sage: (-G.U()).is_primitive()
|
|
2337
|
+
True
|
|
2338
|
+
sage: (-G.S()).is_primitive()
|
|
2339
|
+
True
|
|
2340
|
+
sage: (G.U()^6).is_primitive()
|
|
2341
|
+
True
|
|
2342
|
+
|
|
2343
|
+
sage: G = HeckeTriangleGroup(n=8)
|
|
2344
|
+
sage: (G.U()^2).is_primitive()
|
|
2345
|
+
False
|
|
2346
|
+
sage: (G.U()^(-4)).is_primitive()
|
|
2347
|
+
False
|
|
2348
|
+
sage: (G.U()^(-3)).is_primitive()
|
|
2349
|
+
True
|
|
2350
|
+
"""
|
|
2351
|
+
if self.parent().n() == infinity:
|
|
2352
|
+
from warnings import warn
|
|
2353
|
+
warn("The case n=infinity here is not verified at all and probably wrong!")
|
|
2354
|
+
|
|
2355
|
+
pow = self.primitive_power()
|
|
2356
|
+
|
|
2357
|
+
if self.is_elliptic():
|
|
2358
|
+
if self.parent().n() == infinity:
|
|
2359
|
+
raise NotImplementedError
|
|
2360
|
+
|
|
2361
|
+
# if this is not up-to-sign then a factor 2 should
|
|
2362
|
+
# be added before (the second) self.parent().n()
|
|
2363
|
+
return (pow % (2*self.parent().n())).gcd(self.parent().n()) == 1
|
|
2364
|
+
else:
|
|
2365
|
+
return abs(pow) <= 1
|
|
2366
|
+
|
|
2367
|
+
def is_reduced(self, require_primitive=True,
|
|
2368
|
+
require_hyperbolic=True) -> bool:
|
|
2369
|
+
r"""
|
|
2370
|
+
Return whether ``self`` is reduced.
|
|
2371
|
+
|
|
2372
|
+
We call an element
|
|
2373
|
+
reduced if the associated lambda-CF is purely periodic.
|
|
2374
|
+
|
|
2375
|
+
I.e. (in the hyperbolic case) if the associated hyperbolic
|
|
2376
|
+
fixed point (resp. the associated hyperbolic binary quadratic form)
|
|
2377
|
+
is reduced.
|
|
2378
|
+
|
|
2379
|
+
Note that if ``self`` is reduced then the element corresponding
|
|
2380
|
+
to the cyclic permutation of the lambda-CF (which is conjugate
|
|
2381
|
+
to the original element) is again reduced. In particular the
|
|
2382
|
+
reduced elements in the conjugacy class of ``self`` form a
|
|
2383
|
+
finite cycle.
|
|
2384
|
+
|
|
2385
|
+
Elliptic elements and +- identity are not considered reduced.
|
|
2386
|
+
|
|
2387
|
+
Warning: The case ``n=infinity`` is not verified at all
|
|
2388
|
+
and probably wrong!
|
|
2389
|
+
|
|
2390
|
+
INPUT:
|
|
2391
|
+
|
|
2392
|
+
- ``require_primitive`` -- if ``True`` (default) then non-primitive
|
|
2393
|
+
elements are not considered reduced
|
|
2394
|
+
|
|
2395
|
+
- ``require_hyperbolic`` -- if ``True`` (default) then non-hyperbolic
|
|
2396
|
+
elements are not considered reduced
|
|
2397
|
+
|
|
2398
|
+
EXAMPLES::
|
|
2399
|
+
|
|
2400
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
2401
|
+
sage: G = HeckeTriangleGroup(n=7)
|
|
2402
|
+
sage: G.I().is_reduced(require_hyperbolic=False)
|
|
2403
|
+
False
|
|
2404
|
+
sage: G.U().reduce().is_reduced(require_hyperbolic=False)
|
|
2405
|
+
False
|
|
2406
|
+
sage: G.T().reduce().is_reduced()
|
|
2407
|
+
False
|
|
2408
|
+
sage: G.T().reduce().is_reduced(require_hyperbolic=False)
|
|
2409
|
+
True
|
|
2410
|
+
sage: (G.V(5)^2).reduce(primitive=False).is_reduced()
|
|
2411
|
+
False
|
|
2412
|
+
sage: (G.V(5)^2).reduce(primitive=False).is_reduced(require_primitive=False)
|
|
2413
|
+
True
|
|
2414
|
+
sage: G.V(5).reduce().is_reduced()
|
|
2415
|
+
True
|
|
2416
|
+
sage: (-G.V(2)).reduce().is_reduced()
|
|
2417
|
+
True
|
|
2418
|
+
sage: (-G.V(2)^3*G.V(6)^2*G.V(3)).reduce().is_reduced()
|
|
2419
|
+
True
|
|
2420
|
+
sage: (G.U()^4*G.S()*G.V(2)).acton(-G.V(2)^3*G.V(6)^2*G.V(3)).reduce().is_reduced()
|
|
2421
|
+
True
|
|
2422
|
+
"""
|
|
2423
|
+
if self.parent().n() == infinity:
|
|
2424
|
+
from warnings import warn
|
|
2425
|
+
warn("The case n=infinity here is not verified at all and probably wrong!")
|
|
2426
|
+
|
|
2427
|
+
if self.is_identity() or self.is_elliptic():
|
|
2428
|
+
return False
|
|
2429
|
+
elif require_hyperbolic and not self.is_hyperbolic():
|
|
2430
|
+
return False
|
|
2431
|
+
elif require_primitive and not self.is_primitive():
|
|
2432
|
+
return False
|
|
2433
|
+
else:
|
|
2434
|
+
return self.continued_fraction()[0] == ()
|
|
2435
|
+
|
|
2436
|
+
def is_simple(self) -> bool:
|
|
2437
|
+
r"""
|
|
2438
|
+
Return whether ``self`` is simple.
|
|
2439
|
+
|
|
2440
|
+
We call an element
|
|
2441
|
+
simple if it is hyperbolic, primitive, has positive sign
|
|
2442
|
+
and if the associated hyperbolic fixed points satisfy:
|
|
2443
|
+
``alpha' < 0 < alpha`` where ``alpha`` is the attracting
|
|
2444
|
+
fixed point for the element.
|
|
2445
|
+
|
|
2446
|
+
I.e. if the associated hyperbolic fixed point (resp. the
|
|
2447
|
+
associated hyperbolic binary quadratic form) is simple.
|
|
2448
|
+
|
|
2449
|
+
There are only finitely many simple elements for a given
|
|
2450
|
+
discriminant. They can be used to provide explicit
|
|
2451
|
+
descriptions of rational period functions.
|
|
2452
|
+
|
|
2453
|
+
Warning: The case ``n=infinity`` is not verified at all
|
|
2454
|
+
and probably wrong!
|
|
2455
|
+
|
|
2456
|
+
EXAMPLES::
|
|
2457
|
+
|
|
2458
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
2459
|
+
sage: G = HeckeTriangleGroup(n=5)
|
|
2460
|
+
|
|
2461
|
+
sage: el = G.V(2)
|
|
2462
|
+
sage: el.is_simple()
|
|
2463
|
+
True
|
|
2464
|
+
sage: R = el.simple_elements()
|
|
2465
|
+
sage: [v.is_simple() for v in R]
|
|
2466
|
+
[True]
|
|
2467
|
+
sage: fp1, fp2 = R[0].fixed_points(embedded=True)
|
|
2468
|
+
sage: (fp1, fp2)
|
|
2469
|
+
(1.272019649514069?, -1.272019649514069?)
|
|
2470
|
+
sage: fp2 < 0 < fp1
|
|
2471
|
+
True
|
|
2472
|
+
|
|
2473
|
+
sage: el = G.V(3)*G.V(2)^(-1)*G.V(1)*G.V(6)
|
|
2474
|
+
sage: el.is_simple()
|
|
2475
|
+
False
|
|
2476
|
+
sage: R = el.simple_elements()
|
|
2477
|
+
sage: [v.is_simple() for v in R]
|
|
2478
|
+
[True, True]
|
|
2479
|
+
sage: fp1, fp2 = R[1].fixed_points(embedded=True)
|
|
2480
|
+
sage: fp2 < 0 < fp1
|
|
2481
|
+
True
|
|
2482
|
+
|
|
2483
|
+
sage: el = G.V(1)^2*G.V(2)*G.V(4)
|
|
2484
|
+
sage: el.is_simple()
|
|
2485
|
+
True
|
|
2486
|
+
sage: R = el.simple_elements()
|
|
2487
|
+
sage: el in R
|
|
2488
|
+
True
|
|
2489
|
+
sage: [v.is_simple() for v in R]
|
|
2490
|
+
[True, True, True, True]
|
|
2491
|
+
sage: fp1, fp2 = R[2].fixed_points(embedded=True)
|
|
2492
|
+
sage: fp2 < 0 < fp1
|
|
2493
|
+
True
|
|
2494
|
+
"""
|
|
2495
|
+
if self != self.primitive_part():
|
|
2496
|
+
return False
|
|
2497
|
+
|
|
2498
|
+
# The last condition is/should be equivalent to:
|
|
2499
|
+
a, b, c, d = self._matrix.list()
|
|
2500
|
+
return (coerce_AA(a) > 0 and coerce_AA(b) > 0 and coerce_AA(c) > 0 and coerce_AA(d) > 0)
|
|
2501
|
+
|
|
2502
|
+
def is_hecke_symmetric(self) -> bool:
|
|
2503
|
+
r"""
|
|
2504
|
+
Return whether the conjugacy class of the primitive part of
|
|
2505
|
+
``self``, denoted by ``[gamma]`` is `Hecke-symmetric`:
|
|
2506
|
+
I.e. if ``[gamma] == [gamma^(-1)]``.
|
|
2507
|
+
|
|
2508
|
+
This is equivalent to ``self.simple_fixed_point_set()`` being
|
|
2509
|
+
equal with it's `Hecke-conjugated` set (where each fixed point
|
|
2510
|
+
is replaced by the other (`Hecke-conjugated`) fixed point.
|
|
2511
|
+
|
|
2512
|
+
It is also equivalent to ``[Q] == [-Q]`` for the corresponding
|
|
2513
|
+
hyperbolic binary quadratic form ``Q``.
|
|
2514
|
+
|
|
2515
|
+
The method assumes that ``self`` is hyperbolic.
|
|
2516
|
+
|
|
2517
|
+
.. WARNING::
|
|
2518
|
+
|
|
2519
|
+
The case ``n=infinity`` is not verified at all and probably wrong!
|
|
2520
|
+
|
|
2521
|
+
EXAMPLES::
|
|
2522
|
+
|
|
2523
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
2524
|
+
sage: G = HeckeTriangleGroup(n=5)
|
|
2525
|
+
|
|
2526
|
+
sage: el = G.V(2)
|
|
2527
|
+
sage: el.is_hecke_symmetric()
|
|
2528
|
+
False
|
|
2529
|
+
sage: (el.simple_fixed_point_set(), el.inverse().simple_fixed_point_set())
|
|
2530
|
+
({1/2*e, (-1/2*lam + 1/2)*e}, {-1/2*e, (1/2*lam - 1/2)*e})
|
|
2531
|
+
|
|
2532
|
+
sage: el = G.V(3)*G.V(2)^(-1)*G.V(1)*G.V(6)
|
|
2533
|
+
sage: el.is_hecke_symmetric()
|
|
2534
|
+
False
|
|
2535
|
+
sage: el.simple_fixed_point_set() == el.inverse().simple_fixed_point_set()
|
|
2536
|
+
False
|
|
2537
|
+
|
|
2538
|
+
sage: el = G.V(2)*G.V(3)
|
|
2539
|
+
sage: el.is_hecke_symmetric()
|
|
2540
|
+
True
|
|
2541
|
+
sage: sorted(el.simple_fixed_point_set(), key=str)
|
|
2542
|
+
[(-lam + 3/2)*e + 1/2*lam - 1,
|
|
2543
|
+
(-lam + 3/2)*e - 1/2*lam + 1,
|
|
2544
|
+
(lam - 3/2)*e + 1/2*lam - 1,
|
|
2545
|
+
(lam - 3/2)*e - 1/2*lam + 1]
|
|
2546
|
+
sage: el.simple_fixed_point_set() == el.inverse().simple_fixed_point_set()
|
|
2547
|
+
True
|
|
2548
|
+
"""
|
|
2549
|
+
if self.parent().n() == infinity:
|
|
2550
|
+
from warnings import warn
|
|
2551
|
+
warn("The case n=infinity here is not verified at all and probably wrong!")
|
|
2552
|
+
|
|
2553
|
+
if self.is_identity() or self.is_elliptic():
|
|
2554
|
+
raise NotImplementedError
|
|
2555
|
+
|
|
2556
|
+
return self.conjugacy_type() == self.inverse().conjugacy_type()
|
|
2557
|
+
|
|
2558
|
+
def rational_period_function(self, k):
|
|
2559
|
+
r"""
|
|
2560
|
+
The method assumes that ``self`` is hyperbolic.
|
|
2561
|
+
|
|
2562
|
+
Return the rational period function of weight ``k`` for
|
|
2563
|
+
the primitive conjugacy class of ``self``.
|
|
2564
|
+
|
|
2565
|
+
A `rational period function` of weight ``k`` is a
|
|
2566
|
+
rational function ``q`` which satisfies:
|
|
2567
|
+
``q + q|S == 0`` and ``q + q|U + q|U^2 + ... + q|U^(n-1) == 0``,
|
|
2568
|
+
where ``S = self.parent().S()``, ``U = self.parent().U()`` and
|
|
2569
|
+
``|`` is the usual `slash-operator` of weight `k`.
|
|
2570
|
+
Note that if ``k < 0`` then ``q`` is a polynomial.
|
|
2571
|
+
|
|
2572
|
+
This method returns a very basic rational period function
|
|
2573
|
+
associated with the primitive conjugacy class of ``self``.
|
|
2574
|
+
The (strong) expectation is that all rational period functions
|
|
2575
|
+
are formed by linear combinations of such functions.
|
|
2576
|
+
|
|
2577
|
+
There is also a close relation with modular integrals of
|
|
2578
|
+
weight ``2-k`` and sometimes ``2-k`` is used for the weight
|
|
2579
|
+
instead of ``k``.
|
|
2580
|
+
|
|
2581
|
+
Warning: The case ``n=infinity`` is not verified at all
|
|
2582
|
+
and probably wrong!
|
|
2583
|
+
|
|
2584
|
+
EXAMPLES::
|
|
2585
|
+
|
|
2586
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
2587
|
+
sage: G = HeckeTriangleGroup(n=5)
|
|
2588
|
+
sage: S = G.S()
|
|
2589
|
+
sage: U = G.U()
|
|
2590
|
+
|
|
2591
|
+
sage: def is_rpf(f, k=None) -> bool:
|
|
2592
|
+
....: if not f + S.slash(f, k=k) == 0:
|
|
2593
|
+
....: return False
|
|
2594
|
+
....: return sum((U^m).slash(f, k=k) for m in range(G.n())) == 0
|
|
2595
|
+
|
|
2596
|
+
sage: z = PolynomialRing(G.base_ring(), 'z').gen()
|
|
2597
|
+
sage: [is_rpf(1 - z^(-k), k=k) for k in range(-6, 6, 2)] # long time
|
|
2598
|
+
[True, True, True, True, True, True]
|
|
2599
|
+
sage: [is_rpf(1/z, k=k) for k in range(-6, 6, 2)]
|
|
2600
|
+
[False, False, False, False, True, False]
|
|
2601
|
+
|
|
2602
|
+
sage: el = G.V(2)
|
|
2603
|
+
sage: el.is_hecke_symmetric()
|
|
2604
|
+
False
|
|
2605
|
+
sage: rpf = el.rational_period_function(-4)
|
|
2606
|
+
sage: is_rpf(rpf) == is_rpf(rpf, k=-4)
|
|
2607
|
+
True
|
|
2608
|
+
sage: is_rpf(rpf)
|
|
2609
|
+
True
|
|
2610
|
+
sage: is_rpf(rpf, k=-6)
|
|
2611
|
+
False
|
|
2612
|
+
sage: is_rpf(rpf, k=2)
|
|
2613
|
+
False
|
|
2614
|
+
sage: rpf
|
|
2615
|
+
-lam*z^4 + lam
|
|
2616
|
+
sage: rpf = el.rational_period_function(-2)
|
|
2617
|
+
sage: is_rpf(rpf)
|
|
2618
|
+
True
|
|
2619
|
+
sage: rpf
|
|
2620
|
+
(lam + 1)*z^2 - lam - 1
|
|
2621
|
+
sage: el.rational_period_function(0) == 0
|
|
2622
|
+
True
|
|
2623
|
+
sage: rpf = el.rational_period_function(2)
|
|
2624
|
+
sage: is_rpf(rpf)
|
|
2625
|
+
True
|
|
2626
|
+
sage: rpf
|
|
2627
|
+
((lam + 1)*z^2 - lam - 1)/(lam*z^4 + (-lam - 2)*z^2 + lam)
|
|
2628
|
+
|
|
2629
|
+
sage: el = G.V(3)*G.V(2)^(-1)*G.V(1)*G.V(6)
|
|
2630
|
+
sage: el.is_hecke_symmetric()
|
|
2631
|
+
False
|
|
2632
|
+
sage: rpf = el.rational_period_function(-6)
|
|
2633
|
+
sage: is_rpf(rpf)
|
|
2634
|
+
True
|
|
2635
|
+
sage: rpf
|
|
2636
|
+
(68*lam + 44)*z^6 + (-24*lam - 12)*z^4 + (24*lam + 12)*z^2 - 68*lam - 44
|
|
2637
|
+
sage: rpf = el.rational_period_function(-2)
|
|
2638
|
+
sage: is_rpf(rpf)
|
|
2639
|
+
True
|
|
2640
|
+
sage: rpf
|
|
2641
|
+
(4*lam + 4)*z^2 - 4*lam - 4
|
|
2642
|
+
sage: el.rational_period_function(0) == 0
|
|
2643
|
+
True
|
|
2644
|
+
sage: rpf = el.rational_period_function(2)
|
|
2645
|
+
sage: is_rpf(rpf) == is_rpf(rpf, k=2)
|
|
2646
|
+
True
|
|
2647
|
+
sage: is_rpf(rpf)
|
|
2648
|
+
True
|
|
2649
|
+
sage: rpf.denominator()
|
|
2650
|
+
(8*lam + 5)*z^8 + (-94*lam - 58)*z^6 + (199*lam + 124)*z^4 + (-94*lam - 58)*z^2 + 8*lam + 5
|
|
2651
|
+
|
|
2652
|
+
sage: el = G.V(2)*G.V(3)
|
|
2653
|
+
sage: el.is_hecke_symmetric()
|
|
2654
|
+
True
|
|
2655
|
+
sage: el.rational_period_function(-4) == 0
|
|
2656
|
+
True
|
|
2657
|
+
sage: rpf = el.rational_period_function(-2)
|
|
2658
|
+
sage: is_rpf(rpf)
|
|
2659
|
+
True
|
|
2660
|
+
sage: rpf
|
|
2661
|
+
(8*lam + 4)*z^2 - 8*lam - 4
|
|
2662
|
+
sage: el.rational_period_function(0) == 0
|
|
2663
|
+
True
|
|
2664
|
+
sage: rpf = el.rational_period_function(2)
|
|
2665
|
+
sage: is_rpf(rpf)
|
|
2666
|
+
True
|
|
2667
|
+
sage: rpf.denominator()
|
|
2668
|
+
(144*lam + 89)*z^8 + (-618*lam - 382)*z^6 + (951*lam + 588)*z^4 + (-618*lam - 382)*z^2 + 144*lam + 89
|
|
2669
|
+
sage: el.rational_period_function(4) == 0
|
|
2670
|
+
True
|
|
2671
|
+
"""
|
|
2672
|
+
if self.parent().n() == infinity:
|
|
2673
|
+
from warnings import warn
|
|
2674
|
+
warn("The case n=infinity here is not verified at all and probably wrong!")
|
|
2675
|
+
|
|
2676
|
+
if self.is_identity() or self.is_elliptic():
|
|
2677
|
+
raise NotImplementedError("This method is not implemented for the identity or elliptic element")
|
|
2678
|
+
|
|
2679
|
+
try:
|
|
2680
|
+
k = ZZ(k)
|
|
2681
|
+
if k % 2:
|
|
2682
|
+
raise TypeError
|
|
2683
|
+
except TypeError:
|
|
2684
|
+
raise ValueError(f"k={k} must be an even integer!")
|
|
2685
|
+
|
|
2686
|
+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
|
|
2687
|
+
P = PolynomialRing(self.parent().base_ring(), 'z')
|
|
2688
|
+
z = P.gen()
|
|
2689
|
+
|
|
2690
|
+
s = P.zero()
|
|
2691
|
+
|
|
2692
|
+
# L1 = []
|
|
2693
|
+
for v in self.simple_elements():
|
|
2694
|
+
a, b, c, d = v._matrix.list()
|
|
2695
|
+
Q = c*z**2 + (d - a)*z - b
|
|
2696
|
+
s += Q**(-k/ZZ(2))
|
|
2697
|
+
|
|
2698
|
+
for v in self.inverse().simple_elements():
|
|
2699
|
+
a, b, c, d = v._matrix.list()
|
|
2700
|
+
Q = c*z**2 + (d - a)*z - b
|
|
2701
|
+
s -= ZZ(-1)**(k/ZZ(2)) * Q**(-k/ZZ(2))
|
|
2702
|
+
|
|
2703
|
+
return s
|
|
2704
|
+
|
|
2705
|
+
def linking_number(self):
|
|
2706
|
+
r"""
|
|
2707
|
+
Let ``g`` denote a holomorphic primitive of ``E2`` in the sense:
|
|
2708
|
+
``lambda/(2*pi*i) d/dz g = E2``. Let ``gamma=self`` and let
|
|
2709
|
+
``M_gamma(z)`` be ``Log((c*z+d) * sgn(a+d))`` if ``c, a+d > 0``,
|
|
2710
|
+
resp. ``Log((c*z+d) / i*sgn(c))`` if ``a+d = 0, c!=0``,
|
|
2711
|
+
resp. ``0`` if ``c=0``. Let ``k=4 * n / (n-2)``, then:
|
|
2712
|
+
|
|
2713
|
+
``g(gamma.acton(z) - g(z) - k*M_gamma(z)`` is equal to
|
|
2714
|
+
``2*pi*i / (n-2) * self.linking_number()``.
|
|
2715
|
+
|
|
2716
|
+
In particular it is independent of ``z`` and a conjugacy invariant.
|
|
2717
|
+
|
|
2718
|
+
If ``self`` is hyperbolic then in the classical case ``n=3``
|
|
2719
|
+
this is the linking number of the closed geodesic
|
|
2720
|
+
(corresponding to ``self``) with the trefoil knot.
|
|
2721
|
+
|
|
2722
|
+
EXAMPLES::
|
|
2723
|
+
|
|
2724
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
2725
|
+
sage: from sage.modular.modform_hecketriangle.space import QuasiModularForms
|
|
2726
|
+
|
|
2727
|
+
sage: def E2_primitive(z, n=3, prec=10, num_prec=53):
|
|
2728
|
+
....: G = HeckeTriangleGroup(n=n)
|
|
2729
|
+
....: MF = QuasiModularForms(group=G, k=2, ep=-1)
|
|
2730
|
+
....: q = MF.get_q(prec=prec)
|
|
2731
|
+
....: int_series = integrate((MF.E2().q_expansion(prec=prec) - 1) / q)
|
|
2732
|
+
....: t_const = (2*pi*i/G.lam()).n(num_prec)
|
|
2733
|
+
....: d = MF.get_d(fix_d=True, d_num_prec=num_prec)
|
|
2734
|
+
....: q = exp(t_const * z)
|
|
2735
|
+
....: return t_const*z + sum((int_series.coefficients()[m]).subs(d=d) * q**int_series.exponents()[m]
|
|
2736
|
+
....: for m in range(len(int_series.coefficients())))
|
|
2737
|
+
|
|
2738
|
+
sage: def M(gamma, z, num_prec=53):
|
|
2739
|
+
....: a = ComplexField(num_prec)(gamma.a())
|
|
2740
|
+
....: b = ComplexField(num_prec)(gamma.b())
|
|
2741
|
+
....: c = ComplexField(num_prec)(gamma.c())
|
|
2742
|
+
....: d = ComplexField(num_prec)(gamma.d())
|
|
2743
|
+
....: if c == 0:
|
|
2744
|
+
....: return 0
|
|
2745
|
+
....: elif a + d == 0:
|
|
2746
|
+
....: return log(-i.n(num_prec)*(c*z + d)*sign(c))
|
|
2747
|
+
....: else:
|
|
2748
|
+
....: return log((c*z+d)*sign(a+d))
|
|
2749
|
+
|
|
2750
|
+
sage: def num_linking_number(A, z, n=3, prec=10, num_prec=53):
|
|
2751
|
+
....: z = z.n(num_prec)
|
|
2752
|
+
....: k = 4 * n / (n - 2)
|
|
2753
|
+
....: return (n-2) / (2*pi*i).n(num_prec) * (E2_primitive(A.acton(z), n=n, prec=prec, num_prec=num_prec)
|
|
2754
|
+
....: - E2_primitive(z, n=n, prec=prec, num_prec=num_prec)
|
|
2755
|
+
....: - k*M(A, z, num_prec=num_prec))
|
|
2756
|
+
|
|
2757
|
+
sage: G = HeckeTriangleGroup(8)
|
|
2758
|
+
sage: z = i
|
|
2759
|
+
sage: for A in [G.S(), G.T(), G.U(), G.U()^(G.n()//2), G.U()^(-3)]:
|
|
2760
|
+
....: print("A={}: ".format(A.string_repr("conj")))
|
|
2761
|
+
....: num_linking_number(A, z, G.n())
|
|
2762
|
+
....: A.linking_number()
|
|
2763
|
+
A=[S]:
|
|
2764
|
+
0.000000000000...
|
|
2765
|
+
0
|
|
2766
|
+
A=[V(1)]:
|
|
2767
|
+
6.000000000000...
|
|
2768
|
+
6
|
|
2769
|
+
A=[U]:
|
|
2770
|
+
-2.00000000000...
|
|
2771
|
+
-2
|
|
2772
|
+
A=[U^4]:
|
|
2773
|
+
0.596987639289... + 0.926018962976...*I
|
|
2774
|
+
0
|
|
2775
|
+
A=[U^(-3)]:
|
|
2776
|
+
5.40301236071... + 0.926018962976...*I
|
|
2777
|
+
6
|
|
2778
|
+
|
|
2779
|
+
sage: z = ComplexField(1000)(- 2.3 + 3.1*i)
|
|
2780
|
+
sage: B = G.I()
|
|
2781
|
+
sage: for A in [G.S(), G.T(), G.U(), G.U()^(G.n()//2), G.U()^(-3)]:
|
|
2782
|
+
....: print("A={}: ".format(A.string_repr("conj")))
|
|
2783
|
+
....: num_linking_number(B.acton(A), z, G.n(), prec=100, num_prec=1000).n(53)
|
|
2784
|
+
....: B.acton(A).linking_number()
|
|
2785
|
+
A=[S]:
|
|
2786
|
+
6.63923483989...e-31 + 2.45195568651...e-30*I
|
|
2787
|
+
0
|
|
2788
|
+
A=[V(1)]:
|
|
2789
|
+
6.000000000000...
|
|
2790
|
+
6
|
|
2791
|
+
A=[U]:
|
|
2792
|
+
-2.00000000000... + 2.45195568651...e-30*I
|
|
2793
|
+
-2
|
|
2794
|
+
A=[U^4]:
|
|
2795
|
+
0.00772492873864... + 0.00668936643212...*I
|
|
2796
|
+
0
|
|
2797
|
+
A=[U^(-3)]:
|
|
2798
|
+
5.99730551444... + 0.000847636355069...*I
|
|
2799
|
+
6
|
|
2800
|
+
|
|
2801
|
+
sage: z = ComplexField(5000)(- 2.3 + 3.1*i)
|
|
2802
|
+
sage: B = G.U()
|
|
2803
|
+
sage: for A in [G.S(), G.T(), G.U(), G.U()^(G.n()//2), G.U()^(-3)]: # long time
|
|
2804
|
+
....: print("A={}: ".format(A.string_repr("conj")))
|
|
2805
|
+
....: num_linking_number(B.acton(A), z, G.n(), prec=200, num_prec=5000).n(53)
|
|
2806
|
+
....: B.acton(A).linking_number()
|
|
2807
|
+
A=[S]:
|
|
2808
|
+
-7.90944791339...e-34 - 9.38956758807...e-34*I
|
|
2809
|
+
0
|
|
2810
|
+
A=[V(1)]:
|
|
2811
|
+
5.99999997397... - 5.96520311160...e-8*I
|
|
2812
|
+
6
|
|
2813
|
+
A=[U]:
|
|
2814
|
+
-2.00000000000... - 1.33113963568...e-61*I
|
|
2815
|
+
-2
|
|
2816
|
+
A=[U^4]:
|
|
2817
|
+
-2.32704571946...e-6 + 5.91899385948...e-7*I
|
|
2818
|
+
0
|
|
2819
|
+
A=[U^(-3)]:
|
|
2820
|
+
6.00000032148... - 1.82676936467...e-7*I
|
|
2821
|
+
6
|
|
2822
|
+
|
|
2823
|
+
sage: A = G.V(2)*G.V(3)
|
|
2824
|
+
sage: B = G.I()
|
|
2825
|
+
sage: num_linking_number(B.acton(A), z, G.n(), prec=200, num_prec=5000).n(53) # long time
|
|
2826
|
+
6.00498424588... - 0.00702329345176...*I
|
|
2827
|
+
sage: A.linking_number()
|
|
2828
|
+
6
|
|
2829
|
+
|
|
2830
|
+
The numerical properties for anything larger are basically
|
|
2831
|
+
too bad to make nice further tests...
|
|
2832
|
+
"""
|
|
2833
|
+
if self.is_identity():
|
|
2834
|
+
return ZZ.zero()
|
|
2835
|
+
|
|
2836
|
+
L, R, sgn = self._block_decomposition_data()
|
|
2837
|
+
n = self.parent().n()
|
|
2838
|
+
|
|
2839
|
+
if self.is_elliptic():
|
|
2840
|
+
if L[0] == 0:
|
|
2841
|
+
return ZZ(0)
|
|
2842
|
+
elif 2*L[1] == n:
|
|
2843
|
+
return ZZ(0)
|
|
2844
|
+
else:
|
|
2845
|
+
return ZZ(-2*L[1])
|
|
2846
|
+
else:
|
|
2847
|
+
t = sum(v[1] for v in L)
|
|
2848
|
+
u = sum((v[0]-1) for v in L)
|
|
2849
|
+
|
|
2850
|
+
return ZZ((n-2)*t - 2*u)
|
|
2851
|
+
|
|
2852
|
+
def root_extension_field(self):
|
|
2853
|
+
r"""
|
|
2854
|
+
Return a field extension which contains the fixed points of ``self``.
|
|
2855
|
+
Namely the root extension field of the parent for the discriminant of ``self``.
|
|
2856
|
+
Also see the parent method ``root_extension_field(D)`` and
|
|
2857
|
+
:meth:`root_extension_embedding` (which provides the correct embedding).
|
|
2858
|
+
|
|
2859
|
+
EXAMPLES::
|
|
2860
|
+
|
|
2861
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
2862
|
+
sage: G = HeckeTriangleGroup(n=infinity)
|
|
2863
|
+
sage: G.V(3).discriminant()
|
|
2864
|
+
32
|
|
2865
|
+
sage: G.V(3).root_extension_field() == G.root_extension_field(32)
|
|
2866
|
+
True
|
|
2867
|
+
sage: G.T().root_extension_field() == G.root_extension_field(G.T().discriminant()) == G.base_field()
|
|
2868
|
+
True
|
|
2869
|
+
sage: (G.S()).root_extension_field() == G.root_extension_field(G.S().discriminant())
|
|
2870
|
+
True
|
|
2871
|
+
|
|
2872
|
+
sage: G = HeckeTriangleGroup(n=7)
|
|
2873
|
+
sage: D = G.V(3).discriminant()
|
|
2874
|
+
sage: D
|
|
2875
|
+
4*lam^2 + 4*lam - 4
|
|
2876
|
+
sage: G.V(3).root_extension_field() == G.root_extension_field(D)
|
|
2877
|
+
True
|
|
2878
|
+
sage: G.U().root_extension_field() == G.root_extension_field(G.U().discriminant())
|
|
2879
|
+
True
|
|
2880
|
+
sage: G.V(1).root_extension_field() == G.base_field()
|
|
2881
|
+
True
|
|
2882
|
+
"""
|
|
2883
|
+
return self.parent().root_extension_field(self.discriminant())
|
|
2884
|
+
|
|
2885
|
+
def root_extension_embedding(self, K=None):
|
|
2886
|
+
r"""
|
|
2887
|
+
Return the correct embedding from the root extension field to ``K``.
|
|
2888
|
+
|
|
2889
|
+
INPUT:
|
|
2890
|
+
|
|
2891
|
+
- ``K`` -- a field to which we want the (correct) embedding.
|
|
2892
|
+
If ``K=None`` (default), then ``AlgebraicField()`` is
|
|
2893
|
+
used for elliptic elements and ``AlgebraicRealField()``
|
|
2894
|
+
otherwise.
|
|
2895
|
+
|
|
2896
|
+
EXAMPLES::
|
|
2897
|
+
|
|
2898
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
2899
|
+
sage: G = HeckeTriangleGroup(n=infinity)
|
|
2900
|
+
|
|
2901
|
+
sage: fp = (-G.S()).fixed_points()[0]
|
|
2902
|
+
sage: alg_fp = (-G.S()).root_extension_embedding()(fp)
|
|
2903
|
+
sage: alg_fp
|
|
2904
|
+
1*I
|
|
2905
|
+
sage: alg_fp == (-G.S()).fixed_points(embedded=True)[0]
|
|
2906
|
+
True
|
|
2907
|
+
|
|
2908
|
+
sage: fp = (-G.V(2)).fixed_points()[1]
|
|
2909
|
+
sage: alg_fp = (-G.V(2)).root_extension_embedding()(fp)
|
|
2910
|
+
sage: alg_fp
|
|
2911
|
+
-1.732050807568...?
|
|
2912
|
+
sage: alg_fp == (-G.V(2)).fixed_points(embedded=True)[1]
|
|
2913
|
+
True
|
|
2914
|
+
|
|
2915
|
+
sage: fp = (-G.V(2)).fixed_points()[0]
|
|
2916
|
+
sage: alg_fp = (-G.V(2)).root_extension_embedding()(fp)
|
|
2917
|
+
sage: alg_fp
|
|
2918
|
+
1.732050807568...?
|
|
2919
|
+
sage: alg_fp == (-G.V(2)).fixed_points(embedded=True)[0]
|
|
2920
|
+
True
|
|
2921
|
+
|
|
2922
|
+
sage: G = HeckeTriangleGroup(n=7)
|
|
2923
|
+
|
|
2924
|
+
sage: fp = (-G.S()).fixed_points()[1]
|
|
2925
|
+
sage: alg_fp = (-G.S()).root_extension_embedding()(fp)
|
|
2926
|
+
sage: alg_fp
|
|
2927
|
+
0.?... - 1.000000000000...?*I
|
|
2928
|
+
sage: alg_fp == (-G.S()).fixed_points(embedded=True)[1]
|
|
2929
|
+
True
|
|
2930
|
+
|
|
2931
|
+
sage: fp = (-G.U()^4).fixed_points()[0]
|
|
2932
|
+
sage: alg_fp = (-G.U()^4).root_extension_embedding()(fp)
|
|
2933
|
+
sage: alg_fp
|
|
2934
|
+
0.9009688679024...? + 0.4338837391175...?*I
|
|
2935
|
+
sage: alg_fp == (-G.U()^4).fixed_points(embedded=True)[0]
|
|
2936
|
+
True
|
|
2937
|
+
|
|
2938
|
+
sage: (-G.U()^4).root_extension_embedding(CC)(fp)
|
|
2939
|
+
0.900968867902... + 0.433883739117...*I
|
|
2940
|
+
sage: (-G.U()^4).root_extension_embedding(CC)(fp).parent()
|
|
2941
|
+
Complex Field with 53 bits of precision
|
|
2942
|
+
|
|
2943
|
+
sage: fp = (-G.V(5)).fixed_points()[1]
|
|
2944
|
+
sage: alg_fp = (-G.V(5)).root_extension_embedding()(fp)
|
|
2945
|
+
sage: alg_fp
|
|
2946
|
+
-0.6671145837954...?
|
|
2947
|
+
sage: alg_fp == (-G.V(5)).fixed_points(embedded=True)[1]
|
|
2948
|
+
True
|
|
2949
|
+
"""
|
|
2950
|
+
return self.parent().root_extension_embedding(self.discriminant(), K)
|
|
2951
|
+
|
|
2952
|
+
def fixed_points(self, embedded=False, order='default'):
|
|
2953
|
+
r"""
|
|
2954
|
+
Return a pair of (mutually conjugate) fixed points of ``self``
|
|
2955
|
+
in a possible quadratic extension of the base field.
|
|
2956
|
+
|
|
2957
|
+
INPUT:
|
|
2958
|
+
|
|
2959
|
+
- ``embedded`` -- boolean (default: ``False``); if ``True``, the fixed
|
|
2960
|
+
points are embedded into ``AlgebraicRealField`` resp.
|
|
2961
|
+
``AlgebraicField``
|
|
2962
|
+
|
|
2963
|
+
- ``order`` -- if ``order='none'`` the fixed points are chosen
|
|
2964
|
+
and ordered according to a fixed formula
|
|
2965
|
+
|
|
2966
|
+
If ``order='sign'`` the fixed points are always ordered
|
|
2967
|
+
according to the sign in front of the square root.
|
|
2968
|
+
|
|
2969
|
+
If ``order='default'`` (default) then in case the fixed
|
|
2970
|
+
points are hyperbolic they are ordered according to the
|
|
2971
|
+
sign of the trace of ``self`` instead, such that the
|
|
2972
|
+
attracting fixed point comes first.
|
|
2973
|
+
|
|
2974
|
+
If ``order='trace'`` the fixed points are always ordered
|
|
2975
|
+
according to the sign of the trace of ``self``.
|
|
2976
|
+
If the trace is zero they are ordered by the sign in
|
|
2977
|
+
front of the square root. In particular the fixed_points
|
|
2978
|
+
in this case remain the same for ``-self``.
|
|
2979
|
+
|
|
2980
|
+
OUTPUT:
|
|
2981
|
+
|
|
2982
|
+
If ``embedded=True`` an element of either ``AlgebraicRealField`` or
|
|
2983
|
+
``AlgebraicField`` is returned. Otherwise an element of a relative field
|
|
2984
|
+
extension over the base field of (the parent of) ``self`` is returned.
|
|
2985
|
+
|
|
2986
|
+
Warning: Relative field extensions do not support default embeddings.
|
|
2987
|
+
So the correct embedding (which is the positive resp. imaginary positive
|
|
2988
|
+
one) has to be chosen.
|
|
2989
|
+
|
|
2990
|
+
EXAMPLES::
|
|
2991
|
+
|
|
2992
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
2993
|
+
sage: G = HeckeTriangleGroup(n=infinity)
|
|
2994
|
+
sage: (-G.T(-4)).fixed_points()
|
|
2995
|
+
(+Infinity, +Infinity)
|
|
2996
|
+
sage: (-G.S()).fixed_points()
|
|
2997
|
+
(1/2*e, -1/2*e)
|
|
2998
|
+
sage: p = (-G.S()).fixed_points(embedded=True)[0]
|
|
2999
|
+
sage: p
|
|
3000
|
+
I
|
|
3001
|
+
sage: (-G.S()).acton(p) == p
|
|
3002
|
+
True
|
|
3003
|
+
sage: (-G.V(2)).fixed_points()
|
|
3004
|
+
(1/2*e, -1/2*e)
|
|
3005
|
+
sage: (-G.V(2)).fixed_points() == G.V(2).fixed_points()
|
|
3006
|
+
True
|
|
3007
|
+
sage: p = (-G.V(2)).fixed_points(embedded=True)[1]
|
|
3008
|
+
sage: p
|
|
3009
|
+
-1.732050807568878?
|
|
3010
|
+
sage: (-G.V(2)).acton(p) == p
|
|
3011
|
+
True
|
|
3012
|
+
|
|
3013
|
+
sage: G = HeckeTriangleGroup(n=7)
|
|
3014
|
+
sage: (-G.S()).fixed_points()
|
|
3015
|
+
(1/2*e, -1/2*e)
|
|
3016
|
+
sage: p = (-G.S()).fixed_points(embedded=True)[1]
|
|
3017
|
+
sage: p
|
|
3018
|
+
-I
|
|
3019
|
+
sage: (-G.S()).acton(p) == p
|
|
3020
|
+
True
|
|
3021
|
+
sage: (G.U()^4).fixed_points()
|
|
3022
|
+
((1/2*lam^2 - 1/2*lam - 1/2)*e + 1/2*lam, (-1/2*lam^2 + 1/2*lam + 1/2)*e + 1/2*lam)
|
|
3023
|
+
sage: pts = (G.U()^4).fixed_points(order='trace')
|
|
3024
|
+
sage: (G.U()^4).fixed_points() == [pts[1], pts[0]]
|
|
3025
|
+
False
|
|
3026
|
+
sage: (G.U()^4).fixed_points(order='trace') == (-G.U()^4).fixed_points(order='trace')
|
|
3027
|
+
True
|
|
3028
|
+
sage: (G.U()^4).fixed_points() == (G.U()^4).fixed_points(order='none')
|
|
3029
|
+
True
|
|
3030
|
+
sage: (-G.U()^4).fixed_points() == (G.U()^4).fixed_points()
|
|
3031
|
+
True
|
|
3032
|
+
sage: (-G.U()^4).fixed_points(order='none') == pts
|
|
3033
|
+
True
|
|
3034
|
+
sage: p = (G.U()^4).fixed_points(embedded=True)[1]
|
|
3035
|
+
sage: p
|
|
3036
|
+
0.9009688679024191? - 0.4338837391175581?*I
|
|
3037
|
+
sage: (G.U()^4).acton(p) == p
|
|
3038
|
+
True
|
|
3039
|
+
sage: (-G.V(5)).fixed_points()
|
|
3040
|
+
((1/2*lam^2 - 1/2*lam - 1/2)*e, (-1/2*lam^2 + 1/2*lam + 1/2)*e)
|
|
3041
|
+
sage: (-G.V(5)).fixed_points() == G.V(5).fixed_points()
|
|
3042
|
+
True
|
|
3043
|
+
sage: p = (-G.V(5)).fixed_points(embedded=True)[0]
|
|
3044
|
+
sage: p
|
|
3045
|
+
0.6671145837954892?
|
|
3046
|
+
sage: (-G.V(5)).acton(p) == p
|
|
3047
|
+
True
|
|
3048
|
+
"""
|
|
3049
|
+
if self.c() == 0:
|
|
3050
|
+
return (infinity, infinity)
|
|
3051
|
+
else:
|
|
3052
|
+
D = self.discriminant()
|
|
3053
|
+
if D.is_square():
|
|
3054
|
+
e = D.sqrt()
|
|
3055
|
+
else:
|
|
3056
|
+
e = self.root_extension_field().gen()
|
|
3057
|
+
|
|
3058
|
+
a, b, c, d = self._matrix.list()
|
|
3059
|
+
|
|
3060
|
+
if order == "none":
|
|
3061
|
+
sgn = ZZ(1)
|
|
3062
|
+
elif order == "sign":
|
|
3063
|
+
sgn = coerce_AA(c).sign()
|
|
3064
|
+
elif order == "default":
|
|
3065
|
+
if self.is_elliptic() or self.trace() == 0:
|
|
3066
|
+
sgn = coerce_AA(c).sign()
|
|
3067
|
+
else:
|
|
3068
|
+
sgn = coerce_AA(self.trace()).sign()
|
|
3069
|
+
elif order == "trace":
|
|
3070
|
+
if self.trace() == 0:
|
|
3071
|
+
sgn = coerce_AA(c).sign()
|
|
3072
|
+
else:
|
|
3073
|
+
sgn = coerce_AA(self.trace()).sign()
|
|
3074
|
+
else:
|
|
3075
|
+
raise NotImplementedError
|
|
3076
|
+
|
|
3077
|
+
if embedded:
|
|
3078
|
+
e = coerce_AA(D).sqrt()
|
|
3079
|
+
e.simplify()
|
|
3080
|
+
a = coerce_AA(a)
|
|
3081
|
+
d = coerce_AA(d)
|
|
3082
|
+
c = coerce_AA(c)
|
|
3083
|
+
|
|
3084
|
+
root1 = (a-d)/(2*c) + sgn*e/(2*c)
|
|
3085
|
+
root2 = (a-d)/(2*c) - sgn*e/(2*c)
|
|
3086
|
+
|
|
3087
|
+
if embedded:
|
|
3088
|
+
root1.simplify()
|
|
3089
|
+
root1.exactify()
|
|
3090
|
+
root2.simplify()
|
|
3091
|
+
root2.exactify()
|
|
3092
|
+
|
|
3093
|
+
return (root1, root2)
|
|
3094
|
+
|
|
3095
|
+
def acton(self, tau):
|
|
3096
|
+
r"""
|
|
3097
|
+
Return the image of ``tau`` under the action of ``self``
|
|
3098
|
+
by linear fractional transformations or by conjugation
|
|
3099
|
+
in case ``tau`` is an element of the parent of ``self``.
|
|
3100
|
+
|
|
3101
|
+
It is possible to act on points of ``HyperbolicPlane()``.
|
|
3102
|
+
|
|
3103
|
+
.. NOTE::
|
|
3104
|
+
|
|
3105
|
+
There is a 1-1 correspondence between hyperbolic
|
|
3106
|
+
fixed points and the corresponding primitive element
|
|
3107
|
+
in the stabilizer. The action in the two cases above
|
|
3108
|
+
is compatible with this correspondence.
|
|
3109
|
+
|
|
3110
|
+
INPUT:
|
|
3111
|
+
|
|
3112
|
+
- ``tau`` -- either an element of ``self`` or any
|
|
3113
|
+
element to which a linear fractional
|
|
3114
|
+
transformation can be applied in the usual way.
|
|
3115
|
+
|
|
3116
|
+
In particular ``infinity`` is a possible
|
|
3117
|
+
argument and a possible return value.
|
|
3118
|
+
|
|
3119
|
+
As mentioned it is also possible to use
|
|
3120
|
+
points of ``HyperbolicPlane()``.
|
|
3121
|
+
|
|
3122
|
+
EXAMPLES::
|
|
3123
|
+
|
|
3124
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
3125
|
+
sage: G = HeckeTriangleGroup(5)
|
|
3126
|
+
sage: G.S().acton(SR(1 + i/2))
|
|
3127
|
+
2/5*I - 4/5
|
|
3128
|
+
sage: G.S().acton(SR(1 + i/2)).parent()
|
|
3129
|
+
Symbolic Ring
|
|
3130
|
+
sage: G.S().acton(QQbar(1 + i/2))
|
|
3131
|
+
2/5*I - 4/5
|
|
3132
|
+
sage: G.S().acton(QQbar(1 + i/2)).parent()
|
|
3133
|
+
Algebraic Field
|
|
3134
|
+
|
|
3135
|
+
sage: G.S().acton(i + exp(-2))
|
|
3136
|
+
-1/(e^(-2) + I)
|
|
3137
|
+
sage: G.S().acton(i + exp(-2)).parent()
|
|
3138
|
+
Symbolic Ring
|
|
3139
|
+
|
|
3140
|
+
sage: G.T().acton(infinity) == infinity
|
|
3141
|
+
True
|
|
3142
|
+
sage: G.U().acton(infinity)
|
|
3143
|
+
lam
|
|
3144
|
+
sage: G.V(2).acton(-G.lam()) == infinity
|
|
3145
|
+
True
|
|
3146
|
+
|
|
3147
|
+
sage: G.V(2).acton(G.U()) == G.V(2)*G.U()*G.V(2).inverse()
|
|
3148
|
+
True
|
|
3149
|
+
sage: G.V(2).inverse().acton(G.U())
|
|
3150
|
+
[ 0 -1]
|
|
3151
|
+
[ 1 lam]
|
|
3152
|
+
|
|
3153
|
+
sage: p = HyperbolicPlane().PD().get_point(-I/2+1/8)
|
|
3154
|
+
sage: G.V(2).acton(p)
|
|
3155
|
+
Point in PD -((-(47*I + 161)*sqrt(5) - 47*I - 161)/(145*sqrt(5) + 94*I + 177)
|
|
3156
|
+
+ I)/(I*(-(47*I + 161)*sqrt(5) - 47*I - 161)/(145*sqrt(5) + 94*I + 177) + 1)
|
|
3157
|
+
sage: bool(G.V(2).acton(p).to_model('UHP').coordinates()
|
|
3158
|
+
....: == G.V(2).acton(p.to_model('UHP').coordinates()))
|
|
3159
|
+
True
|
|
3160
|
+
|
|
3161
|
+
sage: p = HyperbolicPlane().PD().get_point(I)
|
|
3162
|
+
sage: G.U().acton(p)
|
|
3163
|
+
Boundary point in PD 1/2*(sqrt(5) - 2*I + 1)/(-1/2*I*sqrt(5) - 1/2*I + 1)
|
|
3164
|
+
sage: G.U().acton(p).to_model('UHP') == HyperbolicPlane().UHP().get_point(G.lam())
|
|
3165
|
+
True
|
|
3166
|
+
sage: G.U().acton(p) == HyperbolicPlane().UHP().get_point(G.lam()).to_model('PD')
|
|
3167
|
+
True
|
|
3168
|
+
"""
|
|
3169
|
+
|
|
3170
|
+
if tau.parent() == self.parent():
|
|
3171
|
+
return self*tau*self.inverse()
|
|
3172
|
+
|
|
3173
|
+
# if tau is a point of HyperbolicPlane then we use its coordinates in the UHP model
|
|
3174
|
+
model = None
|
|
3175
|
+
if _in_HyperbolicPlane(tau):
|
|
3176
|
+
model = tau.model()
|
|
3177
|
+
tau = tau.to_model('UHP').coordinates()
|
|
3178
|
+
|
|
3179
|
+
a, b, c, d = self._matrix.list()
|
|
3180
|
+
|
|
3181
|
+
if tau == infinity:
|
|
3182
|
+
if c.is_zero():
|
|
3183
|
+
result = infinity
|
|
3184
|
+
else:
|
|
3185
|
+
result = a/c
|
|
3186
|
+
elif c*tau + d == 0:
|
|
3187
|
+
result = infinity
|
|
3188
|
+
else:
|
|
3189
|
+
result = (a*tau + b) / (c*tau + d)
|
|
3190
|
+
|
|
3191
|
+
if model is None:
|
|
3192
|
+
return result
|
|
3193
|
+
else:
|
|
3194
|
+
from sage.geometry.hyperbolic_space.hyperbolic_interface import HyperbolicPlane
|
|
3195
|
+
return HyperbolicPlane().UHP().get_point(result).to_model(model)
|
|
3196
|
+
|
|
3197
|
+
def _act_on_(self, other, self_on_left):
|
|
3198
|
+
r"""
|
|
3199
|
+
Define the action by linear fractional transformation of Hecke triangle group
|
|
3200
|
+
elements on complex points (using :meth:`acton`).
|
|
3201
|
+
|
|
3202
|
+
For the action on matrices by conjugation :meth:`acton` has to be used explicitly
|
|
3203
|
+
(to avoid confusion/ambiguity in expressions of the form gamma1*gamma2*z).
|
|
3204
|
+
|
|
3205
|
+
EXAMPLES::
|
|
3206
|
+
|
|
3207
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
3208
|
+
sage: G = HeckeTriangleGroup(5)
|
|
3209
|
+
sage: p = HyperbolicPlane().PD().get_point(I)
|
|
3210
|
+
sage: G.U()*p
|
|
3211
|
+
Boundary point in PD 1/2*(sqrt(5) - 2*I + 1)/(-1/2*I*sqrt(5) - 1/2*I + 1)
|
|
3212
|
+
sage: G.S()*G.U()*p == G.S()*(G.U()*p)
|
|
3213
|
+
True
|
|
3214
|
+
sage: G.S()*G.U()*p == (G.S()*G.U())*p
|
|
3215
|
+
True
|
|
3216
|
+
sage: (G.S()*G.U())*p == G.S()*(G.U()*p)
|
|
3217
|
+
True
|
|
3218
|
+
|
|
3219
|
+
sage: p = G.lam()
|
|
3220
|
+
sage: G.U()*G.T()*p
|
|
3221
|
+
1/2*lam + 1/2
|
|
3222
|
+
sage: p = QQbar(i*sqrt(2))
|
|
3223
|
+
sage: G.U()*p
|
|
3224
|
+
1.618033988749895? + 0.7071067811865475?*I
|
|
3225
|
+
sage: p = CC(-i + sqrt(2))
|
|
3226
|
+
sage: G.U()*p
|
|
3227
|
+
1.14662946795886 - 0.333333333333333*I
|
|
3228
|
+
sage: p = infinity
|
|
3229
|
+
sage: G.U()*p
|
|
3230
|
+
lam
|
|
3231
|
+
"""
|
|
3232
|
+
|
|
3233
|
+
if self_on_left:
|
|
3234
|
+
if other == infinity or other in CC or _in_HyperbolicPlane(other):
|
|
3235
|
+
return self.acton(other)
|
|
3236
|
+
return None
|
|
3237
|
+
|
|
3238
|
+
def slash(self, f, tau=None, k=None):
|
|
3239
|
+
r"""
|
|
3240
|
+
Return the `slash-operator` of weight ``k`` to applied to ``f``,
|
|
3241
|
+
evaluated at ``tau``. I.e. ``(f|_k[self])(tau)``.
|
|
3242
|
+
|
|
3243
|
+
INPUT:
|
|
3244
|
+
|
|
3245
|
+
- ``f`` -- a function in ``tau`` (or an object for which
|
|
3246
|
+
evaluation at ``self.acton(tau)`` makes sense
|
|
3247
|
+
|
|
3248
|
+
- ``tau`` -- where to evaluate the result.
|
|
3249
|
+
This should be a valid argument for :meth:`acton`.
|
|
3250
|
+
|
|
3251
|
+
If ``tau`` is a point of ``HyperbolicPlane()`` then
|
|
3252
|
+
its coordinates in the upper half plane model are used.
|
|
3253
|
+
|
|
3254
|
+
Default: ``None`` in which case ``f`` has to be
|
|
3255
|
+
a rational function / polynomial in one variable and
|
|
3256
|
+
the generator of the polynomial ring is used for ``tau``.
|
|
3257
|
+
That way ``slash`` acts on rational functions / polynomials.
|
|
3258
|
+
|
|
3259
|
+
- ``k`` -- even integer
|
|
3260
|
+
|
|
3261
|
+
Default: ``None`` in which case ``f`` either
|
|
3262
|
+
has to be a rational function / polynomial in one
|
|
3263
|
+
variable (then -degree is used).
|
|
3264
|
+
Or ``f`` needs to have a ``weight`` attribute which
|
|
3265
|
+
is then used.
|
|
3266
|
+
|
|
3267
|
+
EXAMPLES::
|
|
3268
|
+
|
|
3269
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
3270
|
+
sage: from sage.modular.modform_hecketriangle.space import ModularForms
|
|
3271
|
+
sage: G = HeckeTriangleGroup(n=5)
|
|
3272
|
+
sage: E4 = ModularForms(group=G, k=4, ep=1).E4()
|
|
3273
|
+
sage: z = CC(-1/(-1/(2*i+30)-1))
|
|
3274
|
+
sage: (G.S()).slash(E4, z)
|
|
3275
|
+
32288.0558881... - 118329.856601...*I
|
|
3276
|
+
sage: (G.V(2)*G.V(3)).slash(E4, z)
|
|
3277
|
+
32288.0558892... - 118329.856603...*I
|
|
3278
|
+
sage: E4(z)
|
|
3279
|
+
32288.0558881... - 118329.856601...*I
|
|
3280
|
+
|
|
3281
|
+
sage: z = HyperbolicPlane().PD().get_point(CC(-I/2 + 1/8))
|
|
3282
|
+
sage: (G.V(2)*G.V(3)).slash(E4, z)
|
|
3283
|
+
-(21624.437... - 12725.035...*I)/((0.610... + 0.324...*I)*sqrt(5) + 2.720... + 0.648...*I)^4
|
|
3284
|
+
|
|
3285
|
+
sage: z = PolynomialRing(G.base_ring(), 'z').gen()
|
|
3286
|
+
sage: rat = z^2 + 1/(z-G.lam())
|
|
3287
|
+
sage: dr = rat.numerator().degree() - rat.denominator().degree()
|
|
3288
|
+
sage: G.S().slash(rat) == G.S().slash(rat, tau=None, k=-dr)
|
|
3289
|
+
True
|
|
3290
|
+
sage: G.S().slash(rat)
|
|
3291
|
+
(z^6 - lam*z^4 - z^3)/(-lam*z^4 - z^3)
|
|
3292
|
+
sage: G.S().slash(rat, k=0)
|
|
3293
|
+
(z^4 - lam*z^2 - z)/(-lam*z^4 - z^3)
|
|
3294
|
+
sage: G.S().slash(rat, k=-4)
|
|
3295
|
+
(z^8 - lam*z^6 - z^5)/(-lam*z^4 - z^3)
|
|
3296
|
+
"""
|
|
3297
|
+
|
|
3298
|
+
if k is None:
|
|
3299
|
+
if hasattr(f, 'weight'):
|
|
3300
|
+
k = f.weight()
|
|
3301
|
+
else:
|
|
3302
|
+
try:
|
|
3303
|
+
par = f.numerator().parent()
|
|
3304
|
+
degf = par(f.numerator()).degree() - par(f.denominator()).degree()
|
|
3305
|
+
except (ValueError, TypeError, AttributeError):
|
|
3306
|
+
raise ValueError("The weight k could not be determined automatically and needs to be specified manually!")
|
|
3307
|
+
k = -degf
|
|
3308
|
+
|
|
3309
|
+
try:
|
|
3310
|
+
k = ZZ(k)
|
|
3311
|
+
if k % 2:
|
|
3312
|
+
raise TypeError
|
|
3313
|
+
except TypeError:
|
|
3314
|
+
raise ValueError("k={} must be an even integer!".format(k))
|
|
3315
|
+
|
|
3316
|
+
if tau is None:
|
|
3317
|
+
try:
|
|
3318
|
+
tau = f.numerator().parent().gen()
|
|
3319
|
+
except (ValueError, TypeError, AttributeError):
|
|
3320
|
+
raise ValueError("f={} is not a rational function or a polynomial in one variable, so tau has to be specified explicitly!".format(f))
|
|
3321
|
+
|
|
3322
|
+
if _in_HyperbolicPlane(tau):
|
|
3323
|
+
tau = tau.to_model('UHP').coordinates()
|
|
3324
|
+
|
|
3325
|
+
return (self.c()*tau + self.d())**(-k) * f(self.acton(tau))
|
|
3326
|
+
|
|
3327
|
+
def as_hyperbolic_plane_isometry(self, model='UHP'):
|
|
3328
|
+
r"""
|
|
3329
|
+
Return ``self`` as an isometry of ``HyperbolicPlane()`` (in the upper
|
|
3330
|
+
half plane model).
|
|
3331
|
+
|
|
3332
|
+
EXAMPLES::
|
|
3333
|
+
|
|
3334
|
+
sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
|
|
3335
|
+
sage: el = HeckeTriangleGroup(7).V(4)
|
|
3336
|
+
sage: el.as_hyperbolic_plane_isometry()
|
|
3337
|
+
Isometry in UHP
|
|
3338
|
+
[lam^2 - 1 lam]
|
|
3339
|
+
[lam^2 - 1 lam^2 - 1]
|
|
3340
|
+
sage: el.as_hyperbolic_plane_isometry().parent()
|
|
3341
|
+
Set of Morphisms
|
|
3342
|
+
from Hyperbolic plane in the Upper Half Plane Model
|
|
3343
|
+
to Hyperbolic plane in the Upper Half Plane Model
|
|
3344
|
+
in Category of hyperbolic models of Hyperbolic plane
|
|
3345
|
+
sage: el.as_hyperbolic_plane_isometry("KM").parent()
|
|
3346
|
+
Set of Morphisms
|
|
3347
|
+
from Hyperbolic plane in the Klein Disk Model
|
|
3348
|
+
to Hyperbolic plane in the Klein Disk Model
|
|
3349
|
+
in Category of hyperbolic models of Hyperbolic plane
|
|
3350
|
+
"""
|
|
3351
|
+
from sage.geometry.hyperbolic_space.hyperbolic_interface import HyperbolicPlane
|
|
3352
|
+
return HyperbolicPlane().UHP().get_isometry(self._matrix).to_model(model)
|