passagemath-schemes 10.6.38__cp314-cp314t-macosx_13_0_arm64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of passagemath-schemes might be problematic. Click here for more details.

Files changed (314) hide show
  1. passagemath_schemes/.dylibs/libflint.21.0.dylib +0 -0
  2. passagemath_schemes/.dylibs/libgmp.10.dylib +0 -0
  3. passagemath_schemes/.dylibs/libgmpxx.4.dylib +0 -0
  4. passagemath_schemes/.dylibs/libmpfr.6.dylib +0 -0
  5. passagemath_schemes/__init__.py +3 -0
  6. passagemath_schemes-10.6.38.dist-info/METADATA +204 -0
  7. passagemath_schemes-10.6.38.dist-info/METADATA.bak +205 -0
  8. passagemath_schemes-10.6.38.dist-info/RECORD +314 -0
  9. passagemath_schemes-10.6.38.dist-info/WHEEL +6 -0
  10. passagemath_schemes-10.6.38.dist-info/top_level.txt +3 -0
  11. sage/all__sagemath_schemes.py +23 -0
  12. sage/databases/all__sagemath_schemes.py +7 -0
  13. sage/databases/cremona.py +1723 -0
  14. sage/dynamics/all__sagemath_schemes.py +2 -0
  15. sage/dynamics/arithmetic_dynamics/affine_ds.py +1083 -0
  16. sage/dynamics/arithmetic_dynamics/all.py +14 -0
  17. sage/dynamics/arithmetic_dynamics/berkovich_ds.py +1101 -0
  18. sage/dynamics/arithmetic_dynamics/dynamical_semigroup.py +1543 -0
  19. sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py +2426 -0
  20. sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py +1169 -0
  21. sage/dynamics/arithmetic_dynamics/generic_ds.py +663 -0
  22. sage/dynamics/arithmetic_dynamics/product_projective_ds.py +339 -0
  23. sage/dynamics/arithmetic_dynamics/projective_ds.py +9558 -0
  24. sage/dynamics/arithmetic_dynamics/projective_ds_helper.cpython-314t-darwin.so +0 -0
  25. sage/dynamics/arithmetic_dynamics/projective_ds_helper.pyx +301 -0
  26. sage/dynamics/arithmetic_dynamics/wehlerK3.py +2576 -0
  27. sage/lfunctions/all.py +18 -0
  28. sage/lfunctions/dokchitser.py +745 -0
  29. sage/lfunctions/pari.py +818 -0
  30. sage/lfunctions/zero_sums.cpython-314t-darwin.so +0 -0
  31. sage/lfunctions/zero_sums.pyx +1847 -0
  32. sage/modular/abvar/abvar.py +5135 -0
  33. sage/modular/abvar/abvar_ambient_jacobian.py +413 -0
  34. sage/modular/abvar/abvar_newform.py +244 -0
  35. sage/modular/abvar/all.py +8 -0
  36. sage/modular/abvar/constructor.py +186 -0
  37. sage/modular/abvar/cuspidal_subgroup.py +371 -0
  38. sage/modular/abvar/finite_subgroup.py +896 -0
  39. sage/modular/abvar/homology.py +720 -0
  40. sage/modular/abvar/homspace.py +998 -0
  41. sage/modular/abvar/lseries.py +415 -0
  42. sage/modular/abvar/morphism.py +935 -0
  43. sage/modular/abvar/torsion_point.py +274 -0
  44. sage/modular/abvar/torsion_subgroup.py +740 -0
  45. sage/modular/all.py +43 -0
  46. sage/modular/arithgroup/all.py +20 -0
  47. sage/modular/arithgroup/arithgroup_element.cpython-314t-darwin.so +0 -0
  48. sage/modular/arithgroup/arithgroup_element.pyx +474 -0
  49. sage/modular/arithgroup/arithgroup_generic.py +1402 -0
  50. sage/modular/arithgroup/arithgroup_perm.py +2692 -0
  51. sage/modular/arithgroup/congroup.cpython-314t-darwin.so +0 -0
  52. sage/modular/arithgroup/congroup.pyx +334 -0
  53. sage/modular/arithgroup/congroup_gamma.py +363 -0
  54. sage/modular/arithgroup/congroup_gamma0.py +692 -0
  55. sage/modular/arithgroup/congroup_gamma1.py +653 -0
  56. sage/modular/arithgroup/congroup_gammaH.py +1469 -0
  57. sage/modular/arithgroup/congroup_generic.py +628 -0
  58. sage/modular/arithgroup/congroup_sl2z.py +267 -0
  59. sage/modular/arithgroup/farey_symbol.cpython-314t-darwin.so +0 -0
  60. sage/modular/arithgroup/farey_symbol.pyx +1066 -0
  61. sage/modular/arithgroup/tests.py +418 -0
  62. sage/modular/btquotients/all.py +4 -0
  63. sage/modular/btquotients/btquotient.py +3753 -0
  64. sage/modular/btquotients/pautomorphicform.py +2570 -0
  65. sage/modular/buzzard.py +100 -0
  66. sage/modular/congroup.py +29 -0
  67. sage/modular/congroup_element.py +13 -0
  68. sage/modular/cusps.py +1109 -0
  69. sage/modular/cusps_nf.py +1270 -0
  70. sage/modular/dims.py +569 -0
  71. sage/modular/dirichlet.py +3310 -0
  72. sage/modular/drinfeld_modform/all.py +2 -0
  73. sage/modular/drinfeld_modform/element.py +446 -0
  74. sage/modular/drinfeld_modform/ring.py +773 -0
  75. sage/modular/drinfeld_modform/tutorial.py +236 -0
  76. sage/modular/etaproducts.py +1065 -0
  77. sage/modular/hecke/algebra.py +746 -0
  78. sage/modular/hecke/all.py +20 -0
  79. sage/modular/hecke/ambient_module.py +1019 -0
  80. sage/modular/hecke/degenmap.py +119 -0
  81. sage/modular/hecke/element.py +325 -0
  82. sage/modular/hecke/hecke_operator.py +780 -0
  83. sage/modular/hecke/homspace.py +206 -0
  84. sage/modular/hecke/module.py +1767 -0
  85. sage/modular/hecke/morphism.py +174 -0
  86. sage/modular/hecke/submodule.py +989 -0
  87. sage/modular/hypergeometric_misc.cpython-314t-darwin.so +0 -0
  88. sage/modular/hypergeometric_misc.pxd +4 -0
  89. sage/modular/hypergeometric_misc.pyx +166 -0
  90. sage/modular/hypergeometric_motive.py +2017 -0
  91. sage/modular/local_comp/all.py +2 -0
  92. sage/modular/local_comp/liftings.py +292 -0
  93. sage/modular/local_comp/local_comp.py +1071 -0
  94. sage/modular/local_comp/smoothchar.py +1825 -0
  95. sage/modular/local_comp/type_space.py +748 -0
  96. sage/modular/modform/all.py +30 -0
  97. sage/modular/modform/ambient.py +815 -0
  98. sage/modular/modform/ambient_R.py +177 -0
  99. sage/modular/modform/ambient_eps.py +306 -0
  100. sage/modular/modform/ambient_g0.py +124 -0
  101. sage/modular/modform/ambient_g1.py +204 -0
  102. sage/modular/modform/constructor.py +545 -0
  103. sage/modular/modform/cuspidal_submodule.py +708 -0
  104. sage/modular/modform/defaults.py +14 -0
  105. sage/modular/modform/eis_series.py +505 -0
  106. sage/modular/modform/eisenstein_submodule.py +663 -0
  107. sage/modular/modform/element.py +4131 -0
  108. sage/modular/modform/find_generators.py +59 -0
  109. sage/modular/modform/half_integral.py +154 -0
  110. sage/modular/modform/hecke_operator_on_qexp.py +247 -0
  111. sage/modular/modform/j_invariant.py +47 -0
  112. sage/modular/modform/l_series_gross_zagier.py +133 -0
  113. sage/modular/modform/l_series_gross_zagier_coeffs.cpython-314t-darwin.so +0 -0
  114. sage/modular/modform/l_series_gross_zagier_coeffs.pyx +177 -0
  115. sage/modular/modform/notes.py +45 -0
  116. sage/modular/modform/numerical.py +514 -0
  117. sage/modular/modform/periods.py +14 -0
  118. sage/modular/modform/ring.py +1257 -0
  119. sage/modular/modform/space.py +1860 -0
  120. sage/modular/modform/submodule.py +118 -0
  121. sage/modular/modform/tests.py +64 -0
  122. sage/modular/modform/theta.py +110 -0
  123. sage/modular/modform/vm_basis.py +381 -0
  124. sage/modular/modform/weight1.py +220 -0
  125. sage/modular/modform_hecketriangle/abstract_ring.py +1932 -0
  126. sage/modular/modform_hecketriangle/abstract_space.py +2528 -0
  127. sage/modular/modform_hecketriangle/all.py +30 -0
  128. sage/modular/modform_hecketriangle/analytic_type.py +590 -0
  129. sage/modular/modform_hecketriangle/constructor.py +416 -0
  130. sage/modular/modform_hecketriangle/element.py +351 -0
  131. sage/modular/modform_hecketriangle/functors.py +752 -0
  132. sage/modular/modform_hecketriangle/graded_ring.py +541 -0
  133. sage/modular/modform_hecketriangle/graded_ring_element.py +2225 -0
  134. sage/modular/modform_hecketriangle/hecke_triangle_group_element.py +3352 -0
  135. sage/modular/modform_hecketriangle/hecke_triangle_groups.py +1432 -0
  136. sage/modular/modform_hecketriangle/readme.py +1214 -0
  137. sage/modular/modform_hecketriangle/series_constructor.py +580 -0
  138. sage/modular/modform_hecketriangle/space.py +1037 -0
  139. sage/modular/modform_hecketriangle/subspace.py +423 -0
  140. sage/modular/modsym/all.py +17 -0
  141. sage/modular/modsym/ambient.py +3846 -0
  142. sage/modular/modsym/boundary.py +1420 -0
  143. sage/modular/modsym/element.py +336 -0
  144. sage/modular/modsym/g1list.py +178 -0
  145. sage/modular/modsym/ghlist.py +182 -0
  146. sage/modular/modsym/hecke_operator.py +73 -0
  147. sage/modular/modsym/manin_symbol.cpython-314t-darwin.so +0 -0
  148. sage/modular/modsym/manin_symbol.pxd +5 -0
  149. sage/modular/modsym/manin_symbol.pyx +497 -0
  150. sage/modular/modsym/manin_symbol_list.py +1295 -0
  151. sage/modular/modsym/modsym.py +400 -0
  152. sage/modular/modsym/modular_symbols.py +384 -0
  153. sage/modular/modsym/p1list.cpython-314t-darwin.so +0 -0
  154. sage/modular/modsym/p1list.pxd +29 -0
  155. sage/modular/modsym/p1list.pyx +1372 -0
  156. sage/modular/modsym/p1list_nf.py +1241 -0
  157. sage/modular/modsym/relation_matrix.py +591 -0
  158. sage/modular/modsym/relation_matrix_pyx.cpython-314t-darwin.so +0 -0
  159. sage/modular/modsym/relation_matrix_pyx.pyx +108 -0
  160. sage/modular/modsym/space.py +2468 -0
  161. sage/modular/modsym/subspace.py +455 -0
  162. sage/modular/modsym/tests.py +375 -0
  163. sage/modular/multiple_zeta.py +2632 -0
  164. sage/modular/multiple_zeta_F_algebra.py +786 -0
  165. sage/modular/overconvergent/all.py +6 -0
  166. sage/modular/overconvergent/genus0.py +1878 -0
  167. sage/modular/overconvergent/hecke_series.py +1187 -0
  168. sage/modular/overconvergent/weightspace.py +778 -0
  169. sage/modular/pollack_stevens/all.py +4 -0
  170. sage/modular/pollack_stevens/distributions.py +874 -0
  171. sage/modular/pollack_stevens/fund_domain.py +1572 -0
  172. sage/modular/pollack_stevens/manin_map.py +859 -0
  173. sage/modular/pollack_stevens/modsym.py +1593 -0
  174. sage/modular/pollack_stevens/padic_lseries.py +417 -0
  175. sage/modular/pollack_stevens/sigma0.py +534 -0
  176. sage/modular/pollack_stevens/space.py +1076 -0
  177. sage/modular/quasimodform/all.py +3 -0
  178. sage/modular/quasimodform/element.py +845 -0
  179. sage/modular/quasimodform/ring.py +828 -0
  180. sage/modular/quatalg/all.py +3 -0
  181. sage/modular/quatalg/brandt.py +1642 -0
  182. sage/modular/ssmod/all.py +8 -0
  183. sage/modular/ssmod/ssmod.py +827 -0
  184. sage/rings/all__sagemath_schemes.py +1 -0
  185. sage/rings/polynomial/all__sagemath_schemes.py +1 -0
  186. sage/rings/polynomial/binary_form_reduce.py +585 -0
  187. sage/schemes/all.py +41 -0
  188. sage/schemes/berkovich/all.py +6 -0
  189. sage/schemes/berkovich/berkovich_cp_element.py +2582 -0
  190. sage/schemes/berkovich/berkovich_space.py +748 -0
  191. sage/schemes/curves/affine_curve.py +2928 -0
  192. sage/schemes/curves/all.py +33 -0
  193. sage/schemes/curves/closed_point.py +434 -0
  194. sage/schemes/curves/constructor.py +381 -0
  195. sage/schemes/curves/curve.py +542 -0
  196. sage/schemes/curves/plane_curve_arrangement.py +1283 -0
  197. sage/schemes/curves/point.py +463 -0
  198. sage/schemes/curves/projective_curve.py +3026 -0
  199. sage/schemes/curves/zariski_vankampen.py +1932 -0
  200. sage/schemes/cyclic_covers/all.py +2 -0
  201. sage/schemes/cyclic_covers/charpoly_frobenius.py +320 -0
  202. sage/schemes/cyclic_covers/constructor.py +137 -0
  203. sage/schemes/cyclic_covers/cycliccover_finite_field.py +1309 -0
  204. sage/schemes/cyclic_covers/cycliccover_generic.py +310 -0
  205. sage/schemes/elliptic_curves/BSD.py +1036 -0
  206. sage/schemes/elliptic_curves/Qcurves.py +592 -0
  207. sage/schemes/elliptic_curves/addition_formulas_ring.py +94 -0
  208. sage/schemes/elliptic_curves/all.py +49 -0
  209. sage/schemes/elliptic_curves/cardinality.py +609 -0
  210. sage/schemes/elliptic_curves/cm.py +1102 -0
  211. sage/schemes/elliptic_curves/constructor.py +1552 -0
  212. sage/schemes/elliptic_curves/ec_database.py +175 -0
  213. sage/schemes/elliptic_curves/ell_curve_isogeny.py +3972 -0
  214. sage/schemes/elliptic_curves/ell_egros.py +459 -0
  215. sage/schemes/elliptic_curves/ell_field.py +2836 -0
  216. sage/schemes/elliptic_curves/ell_finite_field.py +3359 -0
  217. sage/schemes/elliptic_curves/ell_generic.py +3760 -0
  218. sage/schemes/elliptic_curves/ell_local_data.py +1207 -0
  219. sage/schemes/elliptic_curves/ell_modular_symbols.py +775 -0
  220. sage/schemes/elliptic_curves/ell_number_field.py +4220 -0
  221. sage/schemes/elliptic_curves/ell_padic_field.py +107 -0
  222. sage/schemes/elliptic_curves/ell_point.py +4787 -0
  223. sage/schemes/elliptic_curves/ell_rational_field.py +7368 -0
  224. sage/schemes/elliptic_curves/ell_tate_curve.py +671 -0
  225. sage/schemes/elliptic_curves/ell_torsion.py +436 -0
  226. sage/schemes/elliptic_curves/ell_wp.py +352 -0
  227. sage/schemes/elliptic_curves/formal_group.py +760 -0
  228. sage/schemes/elliptic_curves/gal_reps.py +1459 -0
  229. sage/schemes/elliptic_curves/gal_reps_number_field.py +1669 -0
  230. sage/schemes/elliptic_curves/gp_simon.py +152 -0
  231. sage/schemes/elliptic_curves/heegner.py +7335 -0
  232. sage/schemes/elliptic_curves/height.py +2109 -0
  233. sage/schemes/elliptic_curves/hom.py +1406 -0
  234. sage/schemes/elliptic_curves/hom_composite.py +934 -0
  235. sage/schemes/elliptic_curves/hom_frobenius.py +522 -0
  236. sage/schemes/elliptic_curves/hom_scalar.py +531 -0
  237. sage/schemes/elliptic_curves/hom_sum.py +682 -0
  238. sage/schemes/elliptic_curves/hom_velusqrt.py +1290 -0
  239. sage/schemes/elliptic_curves/homset.py +271 -0
  240. sage/schemes/elliptic_curves/isogeny_class.py +1521 -0
  241. sage/schemes/elliptic_curves/isogeny_small_degree.py +2797 -0
  242. sage/schemes/elliptic_curves/jacobian.py +237 -0
  243. sage/schemes/elliptic_curves/kodaira_symbol.py +344 -0
  244. sage/schemes/elliptic_curves/kraus.py +1014 -0
  245. sage/schemes/elliptic_curves/lseries_ell.py +943 -0
  246. sage/schemes/elliptic_curves/mod5family.py +105 -0
  247. sage/schemes/elliptic_curves/mod_poly.py +197 -0
  248. sage/schemes/elliptic_curves/mod_sym_num.cpython-314t-darwin.so +0 -0
  249. sage/schemes/elliptic_curves/mod_sym_num.pyx +3796 -0
  250. sage/schemes/elliptic_curves/modular_parametrization.py +305 -0
  251. sage/schemes/elliptic_curves/padic_lseries.py +1793 -0
  252. sage/schemes/elliptic_curves/padics.py +1816 -0
  253. sage/schemes/elliptic_curves/period_lattice.py +2234 -0
  254. sage/schemes/elliptic_curves/period_lattice_region.cpython-314t-darwin.so +0 -0
  255. sage/schemes/elliptic_curves/period_lattice_region.pyx +722 -0
  256. sage/schemes/elliptic_curves/saturation.py +715 -0
  257. sage/schemes/elliptic_curves/sha_tate.py +1158 -0
  258. sage/schemes/elliptic_curves/weierstrass_morphism.py +1117 -0
  259. sage/schemes/elliptic_curves/weierstrass_transform.py +200 -0
  260. sage/schemes/hyperelliptic_curves/all.py +6 -0
  261. sage/schemes/hyperelliptic_curves/constructor.py +291 -0
  262. sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py +1914 -0
  263. sage/schemes/hyperelliptic_curves/hyperelliptic_g2.py +192 -0
  264. sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py +954 -0
  265. sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py +1332 -0
  266. sage/schemes/hyperelliptic_curves/hyperelliptic_rational_field.py +84 -0
  267. sage/schemes/hyperelliptic_curves/invariants.py +410 -0
  268. sage/schemes/hyperelliptic_curves/jacobian_endomorphism_utils.py +315 -0
  269. sage/schemes/hyperelliptic_curves/jacobian_g2.py +32 -0
  270. sage/schemes/hyperelliptic_curves/jacobian_generic.py +419 -0
  271. sage/schemes/hyperelliptic_curves/jacobian_homset.py +186 -0
  272. sage/schemes/hyperelliptic_curves/jacobian_morphism.py +875 -0
  273. sage/schemes/hyperelliptic_curves/kummer_surface.py +99 -0
  274. sage/schemes/hyperelliptic_curves/mestre.py +302 -0
  275. sage/schemes/hyperelliptic_curves/monsky_washnitzer.py +3871 -0
  276. sage/schemes/jacobians/abstract_jacobian.py +277 -0
  277. sage/schemes/jacobians/all.py +2 -0
  278. sage/schemes/overview.py +161 -0
  279. sage/schemes/plane_conics/all.py +22 -0
  280. sage/schemes/plane_conics/con_field.py +1296 -0
  281. sage/schemes/plane_conics/con_finite_field.py +158 -0
  282. sage/schemes/plane_conics/con_number_field.py +456 -0
  283. sage/schemes/plane_conics/con_rational_field.py +406 -0
  284. sage/schemes/plane_conics/con_rational_function_field.py +580 -0
  285. sage/schemes/plane_conics/constructor.py +249 -0
  286. sage/schemes/plane_quartics/all.py +2 -0
  287. sage/schemes/plane_quartics/quartic_constructor.py +71 -0
  288. sage/schemes/plane_quartics/quartic_generic.py +73 -0
  289. sage/schemes/riemann_surfaces/all.py +1 -0
  290. sage/schemes/riemann_surfaces/riemann_surface.py +4117 -0
  291. sage_wheels/share/cremona/cremona_mini.db +0 -0
  292. sage_wheels/share/ellcurves/rank0 +30427 -0
  293. sage_wheels/share/ellcurves/rank1 +31871 -0
  294. sage_wheels/share/ellcurves/rank10 +6 -0
  295. sage_wheels/share/ellcurves/rank11 +6 -0
  296. sage_wheels/share/ellcurves/rank12 +1 -0
  297. sage_wheels/share/ellcurves/rank14 +1 -0
  298. sage_wheels/share/ellcurves/rank15 +1 -0
  299. sage_wheels/share/ellcurves/rank17 +1 -0
  300. sage_wheels/share/ellcurves/rank19 +1 -0
  301. sage_wheels/share/ellcurves/rank2 +2388 -0
  302. sage_wheels/share/ellcurves/rank20 +1 -0
  303. sage_wheels/share/ellcurves/rank21 +1 -0
  304. sage_wheels/share/ellcurves/rank22 +1 -0
  305. sage_wheels/share/ellcurves/rank23 +1 -0
  306. sage_wheels/share/ellcurves/rank24 +1 -0
  307. sage_wheels/share/ellcurves/rank28 +1 -0
  308. sage_wheels/share/ellcurves/rank3 +836 -0
  309. sage_wheels/share/ellcurves/rank4 +10 -0
  310. sage_wheels/share/ellcurves/rank5 +5 -0
  311. sage_wheels/share/ellcurves/rank6 +5 -0
  312. sage_wheels/share/ellcurves/rank7 +5 -0
  313. sage_wheels/share/ellcurves/rank8 +6 -0
  314. 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)