passagemath-schemes 10.8.1a4__cp314-cp314t-macosx_13_0_arm64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (312) hide show
  1. passagemath_schemes/.dylibs/libflint.22.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.8.1a4.dist-info/METADATA +203 -0
  7. passagemath_schemes-10.8.1a4.dist-info/METADATA.bak +204 -0
  8. passagemath_schemes-10.8.1a4.dist-info/RECORD +312 -0
  9. passagemath_schemes-10.8.1a4.dist-info/WHEEL +6 -0
  10. passagemath_schemes-10.8.1a4.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 +9556 -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 +2578 -0
  27. sage/lfunctions/all.py +18 -0
  28. sage/lfunctions/dokchitser.py +727 -0
  29. sage/lfunctions/pari.py +971 -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 +5132 -0
  33. sage/modular/abvar/abvar_ambient_jacobian.py +414 -0
  34. sage/modular/abvar/abvar_newform.py +246 -0
  35. sage/modular/abvar/all.py +8 -0
  36. sage/modular/abvar/constructor.py +187 -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 +721 -0
  40. sage/modular/abvar/homspace.py +989 -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 +741 -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 +1406 -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 +361 -0
  54. sage/modular/arithgroup/congroup_gamma0.py +692 -0
  55. sage/modular/arithgroup/congroup_gamma1.py +659 -0
  56. sage/modular/arithgroup/congroup_gammaH.py +1491 -0
  57. sage/modular/arithgroup/congroup_generic.py +630 -0
  58. sage/modular/arithgroup/congroup_sl2z.py +266 -0
  59. sage/modular/arithgroup/farey_symbol.cpython-314t-darwin.so +0 -0
  60. sage/modular/arithgroup/farey_symbol.pyx +1067 -0
  61. sage/modular/arithgroup/tests.py +425 -0
  62. sage/modular/btquotients/all.py +4 -0
  63. sage/modular/btquotients/btquotient.py +3736 -0
  64. sage/modular/btquotients/pautomorphicform.py +2564 -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 +1107 -0
  69. sage/modular/cusps_nf.py +1270 -0
  70. sage/modular/dims.py +571 -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 +1076 -0
  77. sage/modular/hecke/algebra.py +725 -0
  78. sage/modular/hecke/all.py +19 -0
  79. sage/modular/hecke/ambient_module.py +994 -0
  80. sage/modular/hecke/degenmap.py +119 -0
  81. sage/modular/hecke/element.py +302 -0
  82. sage/modular/hecke/hecke_operator.py +736 -0
  83. sage/modular/hecke/homspace.py +185 -0
  84. sage/modular/hecke/module.py +1744 -0
  85. sage/modular/hecke/morphism.py +139 -0
  86. sage/modular/hecke/submodule.py +970 -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 +2020 -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 +1070 -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 +817 -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 +120 -0
  101. sage/modular/modform/ambient_g1.py +199 -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 +487 -0
  106. sage/modular/modform/eisenstein_submodule.py +663 -0
  107. sage/modular/modform/element.py +4105 -0
  108. sage/modular/modform/half_integral.py +154 -0
  109. sage/modular/modform/hecke_operator_on_qexp.py +247 -0
  110. sage/modular/modform/j_invariant.py +47 -0
  111. sage/modular/modform/l_series_gross_zagier.py +127 -0
  112. sage/modular/modform/l_series_gross_zagier_coeffs.cpython-314t-darwin.so +0 -0
  113. sage/modular/modform/l_series_gross_zagier_coeffs.pyx +177 -0
  114. sage/modular/modform/notes.py +45 -0
  115. sage/modular/modform/numerical.py +514 -0
  116. sage/modular/modform/periods.py +14 -0
  117. sage/modular/modform/ring.py +1257 -0
  118. sage/modular/modform/space.py +1859 -0
  119. sage/modular/modform/submodule.py +118 -0
  120. sage/modular/modform/tests.py +64 -0
  121. sage/modular/modform/theta.py +110 -0
  122. sage/modular/modform/vm_basis.py +380 -0
  123. sage/modular/modform/weight1.py +221 -0
  124. sage/modular/modform_hecketriangle/abstract_ring.py +1932 -0
  125. sage/modular/modform_hecketriangle/abstract_space.py +2527 -0
  126. sage/modular/modform_hecketriangle/all.py +30 -0
  127. sage/modular/modform_hecketriangle/analytic_type.py +590 -0
  128. sage/modular/modform_hecketriangle/constructor.py +416 -0
  129. sage/modular/modform_hecketriangle/element.py +351 -0
  130. sage/modular/modform_hecketriangle/functors.py +752 -0
  131. sage/modular/modform_hecketriangle/graded_ring.py +541 -0
  132. sage/modular/modform_hecketriangle/graded_ring_element.py +2225 -0
  133. sage/modular/modform_hecketriangle/hecke_triangle_group_element.py +3349 -0
  134. sage/modular/modform_hecketriangle/hecke_triangle_groups.py +1426 -0
  135. sage/modular/modform_hecketriangle/readme.py +1214 -0
  136. sage/modular/modform_hecketriangle/series_constructor.py +580 -0
  137. sage/modular/modform_hecketriangle/space.py +1037 -0
  138. sage/modular/modform_hecketriangle/subspace.py +423 -0
  139. sage/modular/modsym/all.py +17 -0
  140. sage/modular/modsym/ambient.py +3844 -0
  141. sage/modular/modsym/boundary.py +1420 -0
  142. sage/modular/modsym/element.py +336 -0
  143. sage/modular/modsym/g1list.py +178 -0
  144. sage/modular/modsym/ghlist.py +182 -0
  145. sage/modular/modsym/hecke_operator.py +73 -0
  146. sage/modular/modsym/manin_symbol.cpython-314t-darwin.so +0 -0
  147. sage/modular/modsym/manin_symbol.pxd +5 -0
  148. sage/modular/modsym/manin_symbol.pyx +497 -0
  149. sage/modular/modsym/manin_symbol_list.py +1291 -0
  150. sage/modular/modsym/modsym.py +400 -0
  151. sage/modular/modsym/modular_symbols.py +384 -0
  152. sage/modular/modsym/p1list_nf.py +1241 -0
  153. sage/modular/modsym/relation_matrix.py +591 -0
  154. sage/modular/modsym/relation_matrix_pyx.cpython-314t-darwin.so +0 -0
  155. sage/modular/modsym/relation_matrix_pyx.pyx +108 -0
  156. sage/modular/modsym/space.py +2468 -0
  157. sage/modular/modsym/subspace.py +455 -0
  158. sage/modular/modsym/tests.py +376 -0
  159. sage/modular/multiple_zeta.py +2635 -0
  160. sage/modular/multiple_zeta_F_algebra.py +789 -0
  161. sage/modular/overconvergent/all.py +6 -0
  162. sage/modular/overconvergent/genus0.py +1879 -0
  163. sage/modular/overconvergent/hecke_series.py +1187 -0
  164. sage/modular/overconvergent/weightspace.py +776 -0
  165. sage/modular/pollack_stevens/all.py +4 -0
  166. sage/modular/pollack_stevens/distributions.py +874 -0
  167. sage/modular/pollack_stevens/fund_domain.py +1572 -0
  168. sage/modular/pollack_stevens/manin_map.py +856 -0
  169. sage/modular/pollack_stevens/modsym.py +1590 -0
  170. sage/modular/pollack_stevens/padic_lseries.py +417 -0
  171. sage/modular/pollack_stevens/sigma0.py +534 -0
  172. sage/modular/pollack_stevens/space.py +1078 -0
  173. sage/modular/quasimodform/all.py +3 -0
  174. sage/modular/quasimodform/element.py +846 -0
  175. sage/modular/quasimodform/ring.py +826 -0
  176. sage/modular/quatalg/all.py +3 -0
  177. sage/modular/quatalg/brandt.py +1642 -0
  178. sage/modular/ssmod/all.py +8 -0
  179. sage/modular/ssmod/ssmod.py +827 -0
  180. sage/rings/all__sagemath_schemes.py +1 -0
  181. sage/rings/polynomial/all__sagemath_schemes.py +1 -0
  182. sage/rings/polynomial/binary_form_reduce.py +585 -0
  183. sage/schemes/all.py +41 -0
  184. sage/schemes/berkovich/all.py +6 -0
  185. sage/schemes/berkovich/berkovich_cp_element.py +2582 -0
  186. sage/schemes/berkovich/berkovich_space.py +700 -0
  187. sage/schemes/curves/affine_curve.py +2924 -0
  188. sage/schemes/curves/all.py +33 -0
  189. sage/schemes/curves/closed_point.py +434 -0
  190. sage/schemes/curves/constructor.py +397 -0
  191. sage/schemes/curves/curve.py +542 -0
  192. sage/schemes/curves/plane_curve_arrangement.py +1283 -0
  193. sage/schemes/curves/point.py +463 -0
  194. sage/schemes/curves/projective_curve.py +3203 -0
  195. sage/schemes/curves/weighted_projective_curve.py +106 -0
  196. sage/schemes/curves/zariski_vankampen.py +1931 -0
  197. sage/schemes/cyclic_covers/all.py +2 -0
  198. sage/schemes/cyclic_covers/charpoly_frobenius.py +320 -0
  199. sage/schemes/cyclic_covers/constructor.py +137 -0
  200. sage/schemes/cyclic_covers/cycliccover_finite_field.py +1309 -0
  201. sage/schemes/cyclic_covers/cycliccover_generic.py +310 -0
  202. sage/schemes/elliptic_curves/BSD.py +991 -0
  203. sage/schemes/elliptic_curves/Qcurves.py +592 -0
  204. sage/schemes/elliptic_curves/addition_formulas_ring.py +94 -0
  205. sage/schemes/elliptic_curves/all.py +49 -0
  206. sage/schemes/elliptic_curves/cardinality.py +609 -0
  207. sage/schemes/elliptic_curves/cm.py +1103 -0
  208. sage/schemes/elliptic_curves/constructor.py +1530 -0
  209. sage/schemes/elliptic_curves/ec_database.py +175 -0
  210. sage/schemes/elliptic_curves/ell_curve_isogeny.py +3971 -0
  211. sage/schemes/elliptic_curves/ell_egros.py +457 -0
  212. sage/schemes/elliptic_curves/ell_field.py +2837 -0
  213. sage/schemes/elliptic_curves/ell_finite_field.py +3249 -0
  214. sage/schemes/elliptic_curves/ell_generic.py +3760 -0
  215. sage/schemes/elliptic_curves/ell_local_data.py +1207 -0
  216. sage/schemes/elliptic_curves/ell_modular_symbols.py +775 -0
  217. sage/schemes/elliptic_curves/ell_number_field.py +4220 -0
  218. sage/schemes/elliptic_curves/ell_padic_field.py +107 -0
  219. sage/schemes/elliptic_curves/ell_point.py +4944 -0
  220. sage/schemes/elliptic_curves/ell_rational_field.py +7184 -0
  221. sage/schemes/elliptic_curves/ell_tate_curve.py +671 -0
  222. sage/schemes/elliptic_curves/ell_torsion.py +436 -0
  223. sage/schemes/elliptic_curves/ell_wp.py +352 -0
  224. sage/schemes/elliptic_curves/formal_group.py +760 -0
  225. sage/schemes/elliptic_curves/gal_reps.py +1459 -0
  226. sage/schemes/elliptic_curves/gal_reps_number_field.py +1663 -0
  227. sage/schemes/elliptic_curves/gp_simon.py +152 -0
  228. sage/schemes/elliptic_curves/heegner.py +7328 -0
  229. sage/schemes/elliptic_curves/height.py +2108 -0
  230. sage/schemes/elliptic_curves/hom.py +1788 -0
  231. sage/schemes/elliptic_curves/hom_composite.py +1084 -0
  232. sage/schemes/elliptic_curves/hom_fractional.py +544 -0
  233. sage/schemes/elliptic_curves/hom_frobenius.py +522 -0
  234. sage/schemes/elliptic_curves/hom_scalar.py +531 -0
  235. sage/schemes/elliptic_curves/hom_sum.py +681 -0
  236. sage/schemes/elliptic_curves/hom_velusqrt.py +1290 -0
  237. sage/schemes/elliptic_curves/homset.py +271 -0
  238. sage/schemes/elliptic_curves/isogeny_class.py +1523 -0
  239. sage/schemes/elliptic_curves/isogeny_small_degree.py +2797 -0
  240. sage/schemes/elliptic_curves/jacobian.py +247 -0
  241. sage/schemes/elliptic_curves/kodaira_symbol.py +344 -0
  242. sage/schemes/elliptic_curves/kraus.py +1014 -0
  243. sage/schemes/elliptic_curves/lseries_ell.py +915 -0
  244. sage/schemes/elliptic_curves/mod5family.py +105 -0
  245. sage/schemes/elliptic_curves/mod_poly.py +197 -0
  246. sage/schemes/elliptic_curves/mod_sym_num.cpython-314t-darwin.so +0 -0
  247. sage/schemes/elliptic_curves/mod_sym_num.pyx +3796 -0
  248. sage/schemes/elliptic_curves/modular_parametrization.py +305 -0
  249. sage/schemes/elliptic_curves/padic_lseries.py +1793 -0
  250. sage/schemes/elliptic_curves/padics.py +1816 -0
  251. sage/schemes/elliptic_curves/period_lattice.py +2234 -0
  252. sage/schemes/elliptic_curves/period_lattice_region.cpython-314t-darwin.so +0 -0
  253. sage/schemes/elliptic_curves/period_lattice_region.pyx +722 -0
  254. sage/schemes/elliptic_curves/saturation.py +716 -0
  255. sage/schemes/elliptic_curves/sha_tate.py +1158 -0
  256. sage/schemes/elliptic_curves/weierstrass_morphism.py +1117 -0
  257. sage/schemes/elliptic_curves/weierstrass_transform.py +200 -0
  258. sage/schemes/hyperelliptic_curves/all.py +6 -0
  259. sage/schemes/hyperelliptic_curves/constructor.py +369 -0
  260. sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py +1948 -0
  261. sage/schemes/hyperelliptic_curves/hyperelliptic_g2.py +192 -0
  262. sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py +936 -0
  263. sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py +1332 -0
  264. sage/schemes/hyperelliptic_curves/hyperelliptic_rational_field.py +84 -0
  265. sage/schemes/hyperelliptic_curves/invariants.py +410 -0
  266. sage/schemes/hyperelliptic_curves/jacobian_endomorphism_utils.py +312 -0
  267. sage/schemes/hyperelliptic_curves/jacobian_g2.py +32 -0
  268. sage/schemes/hyperelliptic_curves/jacobian_generic.py +437 -0
  269. sage/schemes/hyperelliptic_curves/jacobian_homset.py +186 -0
  270. sage/schemes/hyperelliptic_curves/jacobian_morphism.py +878 -0
  271. sage/schemes/hyperelliptic_curves/kummer_surface.py +99 -0
  272. sage/schemes/hyperelliptic_curves/mestre.py +302 -0
  273. sage/schemes/hyperelliptic_curves/monsky_washnitzer.py +3863 -0
  274. sage/schemes/jacobians/abstract_jacobian.py +277 -0
  275. sage/schemes/jacobians/all.py +2 -0
  276. sage/schemes/overview.py +161 -0
  277. sage/schemes/plane_conics/all.py +22 -0
  278. sage/schemes/plane_conics/con_field.py +1296 -0
  279. sage/schemes/plane_conics/con_finite_field.py +158 -0
  280. sage/schemes/plane_conics/con_number_field.py +456 -0
  281. sage/schemes/plane_conics/con_rational_field.py +406 -0
  282. sage/schemes/plane_conics/con_rational_function_field.py +581 -0
  283. sage/schemes/plane_conics/constructor.py +249 -0
  284. sage/schemes/plane_quartics/all.py +2 -0
  285. sage/schemes/plane_quartics/quartic_constructor.py +71 -0
  286. sage/schemes/plane_quartics/quartic_generic.py +53 -0
  287. sage/schemes/riemann_surfaces/all.py +1 -0
  288. sage/schemes/riemann_surfaces/riemann_surface.py +4177 -0
  289. sage_wheels/share/cremona/cremona_mini.db +0 -0
  290. sage_wheels/share/ellcurves/rank0 +30427 -0
  291. sage_wheels/share/ellcurves/rank1 +31871 -0
  292. sage_wheels/share/ellcurves/rank10 +6 -0
  293. sage_wheels/share/ellcurves/rank11 +6 -0
  294. sage_wheels/share/ellcurves/rank12 +1 -0
  295. sage_wheels/share/ellcurves/rank14 +1 -0
  296. sage_wheels/share/ellcurves/rank15 +1 -0
  297. sage_wheels/share/ellcurves/rank17 +1 -0
  298. sage_wheels/share/ellcurves/rank19 +1 -0
  299. sage_wheels/share/ellcurves/rank2 +2388 -0
  300. sage_wheels/share/ellcurves/rank20 +1 -0
  301. sage_wheels/share/ellcurves/rank21 +1 -0
  302. sage_wheels/share/ellcurves/rank22 +1 -0
  303. sage_wheels/share/ellcurves/rank23 +1 -0
  304. sage_wheels/share/ellcurves/rank24 +1 -0
  305. sage_wheels/share/ellcurves/rank28 +1 -0
  306. sage_wheels/share/ellcurves/rank3 +836 -0
  307. sage_wheels/share/ellcurves/rank4 +10 -0
  308. sage_wheels/share/ellcurves/rank5 +5 -0
  309. sage_wheels/share/ellcurves/rank6 +5 -0
  310. sage_wheels/share/ellcurves/rank7 +5 -0
  311. sage_wheels/share/ellcurves/rank8 +6 -0
  312. sage_wheels/share/ellcurves/rank9 +7 -0
@@ -0,0 +1,3349 @@
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
+ return self == self.parent().I() or self == -self.parent().I()
2289
+
2290
+ def is_elliptic(self) -> bool:
2291
+ r"""
2292
+ Return whether ``self`` is an elliptic matrix.
2293
+
2294
+ EXAMPLES::
2295
+
2296
+ sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
2297
+ sage: G = HeckeTriangleGroup(n=7)
2298
+ sage: [ G.V(k).is_elliptic() for k in range(1,8) ]
2299
+ [False, False, False, False, False, False, True]
2300
+ sage: G.U().is_elliptic()
2301
+ True
2302
+ """
2303
+ return coerce_AA(self.discriminant()) < 0
2304
+
2305
+ def is_primitive(self) -> bool:
2306
+ r"""
2307
+ Return whether ``self`` is primitive. We call an element
2308
+ primitive if (up to a sign and taking inverses) it generates
2309
+ the full stabilizer subgroup of the corresponding fixed point.
2310
+ In the non-elliptic case this means that primitive elements
2311
+ cannot be written as a `non-trivial` power of another element.
2312
+
2313
+ The notion is mostly used for hyperbolic and parabolic elements.
2314
+
2315
+ Warning: The case ``n=infinity`` is not verified at all
2316
+ and probably wrong!
2317
+
2318
+ EXAMPLES::
2319
+
2320
+ sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
2321
+ sage: G = HeckeTriangleGroup(n=7)
2322
+ sage: G.V(2).acton(G.T(-1)).is_primitive()
2323
+ True
2324
+ sage: G.T(3).is_primitive()
2325
+ False
2326
+ sage: (-G.V(2)^2).is_primitive()
2327
+ False
2328
+ sage: (G.V(1)^5*G.V(2)*G.V(3)^3).is_primitive()
2329
+ True
2330
+
2331
+ sage: (-G.I()).is_primitive()
2332
+ True
2333
+ sage: (-G.U()).is_primitive()
2334
+ True
2335
+ sage: (-G.S()).is_primitive()
2336
+ True
2337
+ sage: (G.U()^6).is_primitive()
2338
+ True
2339
+
2340
+ sage: G = HeckeTriangleGroup(n=8)
2341
+ sage: (G.U()^2).is_primitive()
2342
+ False
2343
+ sage: (G.U()^(-4)).is_primitive()
2344
+ False
2345
+ sage: (G.U()^(-3)).is_primitive()
2346
+ True
2347
+ """
2348
+ if self.parent().n() == infinity:
2349
+ from warnings import warn
2350
+ warn("The case n=infinity here is not verified at all and probably wrong!")
2351
+
2352
+ pow = self.primitive_power()
2353
+
2354
+ if self.is_elliptic():
2355
+ if self.parent().n() == infinity:
2356
+ raise NotImplementedError
2357
+
2358
+ # if this is not up-to-sign then a factor 2 should
2359
+ # be added before (the second) self.parent().n()
2360
+ return (pow % (2*self.parent().n())).gcd(self.parent().n()) == 1
2361
+ else:
2362
+ return abs(pow) <= 1
2363
+
2364
+ def is_reduced(self, require_primitive=True,
2365
+ require_hyperbolic=True) -> bool:
2366
+ r"""
2367
+ Return whether ``self`` is reduced.
2368
+
2369
+ We call an element
2370
+ reduced if the associated lambda-CF is purely periodic.
2371
+
2372
+ I.e. (in the hyperbolic case) if the associated hyperbolic
2373
+ fixed point (resp. the associated hyperbolic binary quadratic form)
2374
+ is reduced.
2375
+
2376
+ Note that if ``self`` is reduced then the element corresponding
2377
+ to the cyclic permutation of the lambda-CF (which is conjugate
2378
+ to the original element) is again reduced. In particular the
2379
+ reduced elements in the conjugacy class of ``self`` form a
2380
+ finite cycle.
2381
+
2382
+ Elliptic elements and +- identity are not considered reduced.
2383
+
2384
+ Warning: The case ``n=infinity`` is not verified at all
2385
+ and probably wrong!
2386
+
2387
+ INPUT:
2388
+
2389
+ - ``require_primitive`` -- if ``True`` (default) then non-primitive
2390
+ elements are not considered reduced
2391
+
2392
+ - ``require_hyperbolic`` -- if ``True`` (default) then non-hyperbolic
2393
+ elements are not considered reduced
2394
+
2395
+ EXAMPLES::
2396
+
2397
+ sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
2398
+ sage: G = HeckeTriangleGroup(n=7)
2399
+ sage: G.I().is_reduced(require_hyperbolic=False)
2400
+ False
2401
+ sage: G.U().reduce().is_reduced(require_hyperbolic=False)
2402
+ False
2403
+ sage: G.T().reduce().is_reduced()
2404
+ False
2405
+ sage: G.T().reduce().is_reduced(require_hyperbolic=False)
2406
+ True
2407
+ sage: (G.V(5)^2).reduce(primitive=False).is_reduced()
2408
+ False
2409
+ sage: (G.V(5)^2).reduce(primitive=False).is_reduced(require_primitive=False)
2410
+ True
2411
+ sage: G.V(5).reduce().is_reduced()
2412
+ True
2413
+ sage: (-G.V(2)).reduce().is_reduced()
2414
+ True
2415
+ sage: (-G.V(2)^3*G.V(6)^2*G.V(3)).reduce().is_reduced()
2416
+ True
2417
+ sage: (G.U()^4*G.S()*G.V(2)).acton(-G.V(2)^3*G.V(6)^2*G.V(3)).reduce().is_reduced()
2418
+ True
2419
+ """
2420
+ if self.parent().n() == infinity:
2421
+ from warnings import warn
2422
+ warn("The case n=infinity here is not verified at all and probably wrong!")
2423
+
2424
+ if self.is_identity() or self.is_elliptic():
2425
+ return False
2426
+ elif require_hyperbolic and not self.is_hyperbolic():
2427
+ return False
2428
+ elif require_primitive and not self.is_primitive():
2429
+ return False
2430
+ else:
2431
+ return self.continued_fraction()[0] == ()
2432
+
2433
+ def is_simple(self) -> bool:
2434
+ r"""
2435
+ Return whether ``self`` is simple.
2436
+
2437
+ We call an element
2438
+ simple if it is hyperbolic, primitive, has positive sign
2439
+ and if the associated hyperbolic fixed points satisfy:
2440
+ ``alpha' < 0 < alpha`` where ``alpha`` is the attracting
2441
+ fixed point for the element.
2442
+
2443
+ I.e. if the associated hyperbolic fixed point (resp. the
2444
+ associated hyperbolic binary quadratic form) is simple.
2445
+
2446
+ There are only finitely many simple elements for a given
2447
+ discriminant. They can be used to provide explicit
2448
+ descriptions of rational period functions.
2449
+
2450
+ Warning: The case ``n=infinity`` is not verified at all
2451
+ and probably wrong!
2452
+
2453
+ EXAMPLES::
2454
+
2455
+ sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
2456
+ sage: G = HeckeTriangleGroup(n=5)
2457
+
2458
+ sage: el = G.V(2)
2459
+ sage: el.is_simple()
2460
+ True
2461
+ sage: R = el.simple_elements()
2462
+ sage: [v.is_simple() for v in R]
2463
+ [True]
2464
+ sage: fp1, fp2 = R[0].fixed_points(embedded=True)
2465
+ sage: (fp1, fp2)
2466
+ (1.272019649514069?, -1.272019649514069?)
2467
+ sage: fp2 < 0 < fp1
2468
+ True
2469
+
2470
+ sage: el = G.V(3)*G.V(2)^(-1)*G.V(1)*G.V(6)
2471
+ sage: el.is_simple()
2472
+ False
2473
+ sage: R = el.simple_elements()
2474
+ sage: [v.is_simple() for v in R]
2475
+ [True, True]
2476
+ sage: fp1, fp2 = R[1].fixed_points(embedded=True)
2477
+ sage: fp2 < 0 < fp1
2478
+ True
2479
+
2480
+ sage: el = G.V(1)^2*G.V(2)*G.V(4)
2481
+ sage: el.is_simple()
2482
+ True
2483
+ sage: R = el.simple_elements()
2484
+ sage: el in R
2485
+ True
2486
+ sage: [v.is_simple() for v in R]
2487
+ [True, True, True, True]
2488
+ sage: fp1, fp2 = R[2].fixed_points(embedded=True)
2489
+ sage: fp2 < 0 < fp1
2490
+ True
2491
+ """
2492
+ if self != self.primitive_part():
2493
+ return False
2494
+
2495
+ # The last condition is/should be equivalent to:
2496
+ a, b, c, d = self._matrix.list()
2497
+ return (coerce_AA(a) > 0 and coerce_AA(b) > 0 and coerce_AA(c) > 0 and coerce_AA(d) > 0)
2498
+
2499
+ def is_hecke_symmetric(self) -> bool:
2500
+ r"""
2501
+ Return whether the conjugacy class of the primitive part of
2502
+ ``self``, denoted by ``[gamma]`` is `Hecke-symmetric`:
2503
+ I.e. if ``[gamma] == [gamma^(-1)]``.
2504
+
2505
+ This is equivalent to ``self.simple_fixed_point_set()`` being
2506
+ equal with it's `Hecke-conjugated` set (where each fixed point
2507
+ is replaced by the other (`Hecke-conjugated`) fixed point.
2508
+
2509
+ It is also equivalent to ``[Q] == [-Q]`` for the corresponding
2510
+ hyperbolic binary quadratic form ``Q``.
2511
+
2512
+ The method assumes that ``self`` is hyperbolic.
2513
+
2514
+ .. WARNING::
2515
+
2516
+ The case ``n=infinity`` is not verified at all and probably wrong!
2517
+
2518
+ EXAMPLES::
2519
+
2520
+ sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
2521
+ sage: G = HeckeTriangleGroup(n=5)
2522
+
2523
+ sage: el = G.V(2)
2524
+ sage: el.is_hecke_symmetric()
2525
+ False
2526
+ sage: (el.simple_fixed_point_set(), el.inverse().simple_fixed_point_set())
2527
+ ({1/2*e, (-1/2*lam + 1/2)*e}, {-1/2*e, (1/2*lam - 1/2)*e})
2528
+
2529
+ sage: el = G.V(3)*G.V(2)^(-1)*G.V(1)*G.V(6)
2530
+ sage: el.is_hecke_symmetric()
2531
+ False
2532
+ sage: el.simple_fixed_point_set() == el.inverse().simple_fixed_point_set()
2533
+ False
2534
+
2535
+ sage: el = G.V(2)*G.V(3)
2536
+ sage: el.is_hecke_symmetric()
2537
+ True
2538
+ sage: sorted(el.simple_fixed_point_set(), key=str)
2539
+ [(-lam + 3/2)*e + 1/2*lam - 1,
2540
+ (-lam + 3/2)*e - 1/2*lam + 1,
2541
+ (lam - 3/2)*e + 1/2*lam - 1,
2542
+ (lam - 3/2)*e - 1/2*lam + 1]
2543
+ sage: el.simple_fixed_point_set() == el.inverse().simple_fixed_point_set()
2544
+ True
2545
+ """
2546
+ if self.parent().n() == infinity:
2547
+ from warnings import warn
2548
+ warn("The case n=infinity here is not verified at all and probably wrong!")
2549
+
2550
+ if self.is_identity() or self.is_elliptic():
2551
+ raise NotImplementedError
2552
+
2553
+ return self.conjugacy_type() == self.inverse().conjugacy_type()
2554
+
2555
+ def rational_period_function(self, k):
2556
+ r"""
2557
+ The method assumes that ``self`` is hyperbolic.
2558
+
2559
+ Return the rational period function of weight ``k`` for
2560
+ the primitive conjugacy class of ``self``.
2561
+
2562
+ A `rational period function` of weight ``k`` is a
2563
+ rational function ``q`` which satisfies:
2564
+ ``q + q|S == 0`` and ``q + q|U + q|U^2 + ... + q|U^(n-1) == 0``,
2565
+ where ``S = self.parent().S()``, ``U = self.parent().U()`` and
2566
+ ``|`` is the usual `slash-operator` of weight `k`.
2567
+ Note that if ``k < 0`` then ``q`` is a polynomial.
2568
+
2569
+ This method returns a very basic rational period function
2570
+ associated with the primitive conjugacy class of ``self``.
2571
+ The (strong) expectation is that all rational period functions
2572
+ are formed by linear combinations of such functions.
2573
+
2574
+ There is also a close relation with modular integrals of
2575
+ weight ``2-k`` and sometimes ``2-k`` is used for the weight
2576
+ instead of ``k``.
2577
+
2578
+ Warning: The case ``n=infinity`` is not verified at all
2579
+ and probably wrong!
2580
+
2581
+ EXAMPLES::
2582
+
2583
+ sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
2584
+ sage: G = HeckeTriangleGroup(n=5)
2585
+ sage: S = G.S()
2586
+ sage: U = G.U()
2587
+
2588
+ sage: def is_rpf(f, k=None) -> bool:
2589
+ ....: if not f + S.slash(f, k=k) == 0:
2590
+ ....: return False
2591
+ ....: return sum((U^m).slash(f, k=k) for m in range(G.n())) == 0
2592
+
2593
+ sage: z = PolynomialRing(G.base_ring(), 'z').gen()
2594
+ sage: [is_rpf(1 - z^(-k), k=k) for k in range(-6, 6, 2)] # long time
2595
+ [True, True, True, True, True, True]
2596
+ sage: [is_rpf(1/z, k=k) for k in range(-6, 6, 2)]
2597
+ [False, False, False, False, True, False]
2598
+
2599
+ sage: el = G.V(2)
2600
+ sage: el.is_hecke_symmetric()
2601
+ False
2602
+ sage: rpf = el.rational_period_function(-4)
2603
+ sage: is_rpf(rpf) == is_rpf(rpf, k=-4)
2604
+ True
2605
+ sage: is_rpf(rpf)
2606
+ True
2607
+ sage: is_rpf(rpf, k=-6)
2608
+ False
2609
+ sage: is_rpf(rpf, k=2)
2610
+ False
2611
+ sage: rpf
2612
+ -lam*z^4 + lam
2613
+ sage: rpf = el.rational_period_function(-2)
2614
+ sage: is_rpf(rpf)
2615
+ True
2616
+ sage: rpf
2617
+ (lam + 1)*z^2 - lam - 1
2618
+ sage: el.rational_period_function(0) == 0
2619
+ True
2620
+ sage: rpf = el.rational_period_function(2)
2621
+ sage: is_rpf(rpf)
2622
+ True
2623
+ sage: rpf
2624
+ ((lam + 1)*z^2 - lam - 1)/(lam*z^4 + (-lam - 2)*z^2 + lam)
2625
+
2626
+ sage: el = G.V(3)*G.V(2)^(-1)*G.V(1)*G.V(6)
2627
+ sage: el.is_hecke_symmetric()
2628
+ False
2629
+ sage: rpf = el.rational_period_function(-6)
2630
+ sage: is_rpf(rpf)
2631
+ True
2632
+ sage: rpf
2633
+ (68*lam + 44)*z^6 + (-24*lam - 12)*z^4 + (24*lam + 12)*z^2 - 68*lam - 44
2634
+ sage: rpf = el.rational_period_function(-2)
2635
+ sage: is_rpf(rpf)
2636
+ True
2637
+ sage: rpf
2638
+ (4*lam + 4)*z^2 - 4*lam - 4
2639
+ sage: el.rational_period_function(0) == 0
2640
+ True
2641
+ sage: rpf = el.rational_period_function(2)
2642
+ sage: is_rpf(rpf) == is_rpf(rpf, k=2)
2643
+ True
2644
+ sage: is_rpf(rpf)
2645
+ True
2646
+ sage: rpf.denominator()
2647
+ (8*lam + 5)*z^8 + (-94*lam - 58)*z^6 + (199*lam + 124)*z^4 + (-94*lam - 58)*z^2 + 8*lam + 5
2648
+
2649
+ sage: el = G.V(2)*G.V(3)
2650
+ sage: el.is_hecke_symmetric()
2651
+ True
2652
+ sage: el.rational_period_function(-4) == 0
2653
+ True
2654
+ sage: rpf = el.rational_period_function(-2)
2655
+ sage: is_rpf(rpf)
2656
+ True
2657
+ sage: rpf
2658
+ (8*lam + 4)*z^2 - 8*lam - 4
2659
+ sage: el.rational_period_function(0) == 0
2660
+ True
2661
+ sage: rpf = el.rational_period_function(2)
2662
+ sage: is_rpf(rpf)
2663
+ True
2664
+ sage: rpf.denominator()
2665
+ (144*lam + 89)*z^8 + (-618*lam - 382)*z^6 + (951*lam + 588)*z^4 + (-618*lam - 382)*z^2 + 144*lam + 89
2666
+ sage: el.rational_period_function(4) == 0
2667
+ True
2668
+ """
2669
+ if self.parent().n() == infinity:
2670
+ from warnings import warn
2671
+ warn("The case n=infinity here is not verified at all and probably wrong!")
2672
+
2673
+ if self.is_identity() or self.is_elliptic():
2674
+ raise NotImplementedError("This method is not implemented for the identity or elliptic element")
2675
+
2676
+ try:
2677
+ k = ZZ(k)
2678
+ if k % 2:
2679
+ raise TypeError
2680
+ except TypeError:
2681
+ raise ValueError(f"k={k} must be an even integer!")
2682
+
2683
+ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
2684
+ P = PolynomialRing(self.parent().base_ring(), 'z')
2685
+ z = P.gen()
2686
+
2687
+ s = P.zero()
2688
+
2689
+ # L1 = []
2690
+ for v in self.simple_elements():
2691
+ a, b, c, d = v._matrix.list()
2692
+ Q = c*z**2 + (d - a)*z - b
2693
+ s += Q**(-k/ZZ(2))
2694
+
2695
+ for v in self.inverse().simple_elements():
2696
+ a, b, c, d = v._matrix.list()
2697
+ Q = c*z**2 + (d - a)*z - b
2698
+ s -= ZZ(-1)**(k/ZZ(2)) * Q**(-k/ZZ(2))
2699
+
2700
+ return s
2701
+
2702
+ def linking_number(self):
2703
+ r"""
2704
+ Let ``g`` denote a holomorphic primitive of ``E2`` in the sense:
2705
+ ``lambda/(2*pi*i) d/dz g = E2``. Let ``gamma=self`` and let
2706
+ ``M_gamma(z)`` be ``Log((c*z+d) * sgn(a+d))`` if ``c, a+d > 0``,
2707
+ resp. ``Log((c*z+d) / i*sgn(c))`` if ``a+d = 0, c!=0``,
2708
+ resp. ``0`` if ``c=0``. Let ``k=4 * n / (n-2)``, then:
2709
+
2710
+ ``g(gamma.acton(z) - g(z) - k*M_gamma(z)`` is equal to
2711
+ ``2*pi*i / (n-2) * self.linking_number()``.
2712
+
2713
+ In particular it is independent of ``z`` and a conjugacy invariant.
2714
+
2715
+ If ``self`` is hyperbolic then in the classical case ``n=3``
2716
+ this is the linking number of the closed geodesic
2717
+ (corresponding to ``self``) with the trefoil knot.
2718
+
2719
+ EXAMPLES::
2720
+
2721
+ sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
2722
+ sage: from sage.modular.modform_hecketriangle.space import QuasiModularForms
2723
+
2724
+ sage: def E2_primitive(z, n=3, prec=10, num_prec=53):
2725
+ ....: G = HeckeTriangleGroup(n=n)
2726
+ ....: MF = QuasiModularForms(group=G, k=2, ep=-1)
2727
+ ....: q = MF.get_q(prec=prec)
2728
+ ....: int_series = integrate((MF.E2().q_expansion(prec=prec) - 1) / q)
2729
+ ....: t_const = (2*pi*i/G.lam()).n(num_prec)
2730
+ ....: d = MF.get_d(fix_d=True, d_num_prec=num_prec)
2731
+ ....: q = exp(t_const * z)
2732
+ ....: return t_const*z + sum((int_series.coefficients()[m]).subs(d=d) * q**int_series.exponents()[m]
2733
+ ....: for m in range(len(int_series.coefficients())))
2734
+
2735
+ sage: def M(gamma, z, num_prec=53):
2736
+ ....: a = ComplexField(num_prec)(gamma.a())
2737
+ ....: b = ComplexField(num_prec)(gamma.b())
2738
+ ....: c = ComplexField(num_prec)(gamma.c())
2739
+ ....: d = ComplexField(num_prec)(gamma.d())
2740
+ ....: if c == 0:
2741
+ ....: return 0
2742
+ ....: elif a + d == 0:
2743
+ ....: return log(-i.n(num_prec)*(c*z + d)*sign(c))
2744
+ ....: else:
2745
+ ....: return log((c*z+d)*sign(a+d))
2746
+
2747
+ sage: def num_linking_number(A, z, n=3, prec=10, num_prec=53):
2748
+ ....: z = z.n(num_prec)
2749
+ ....: k = 4 * n / (n - 2)
2750
+ ....: return (n-2) / (2*pi*i).n(num_prec) * (E2_primitive(A.acton(z), n=n, prec=prec, num_prec=num_prec)
2751
+ ....: - E2_primitive(z, n=n, prec=prec, num_prec=num_prec)
2752
+ ....: - k*M(A, z, num_prec=num_prec))
2753
+
2754
+ sage: G = HeckeTriangleGroup(8)
2755
+ sage: z = i
2756
+ sage: for A in [G.S(), G.T(), G.U(), G.U()^(G.n()//2), G.U()^(-3)]:
2757
+ ....: print("A={}: ".format(A.string_repr("conj")))
2758
+ ....: num_linking_number(A, z, G.n())
2759
+ ....: A.linking_number()
2760
+ A=[S]:
2761
+ 0.000000000000...
2762
+ 0
2763
+ A=[V(1)]:
2764
+ 6.000000000000...
2765
+ 6
2766
+ A=[U]:
2767
+ -2.00000000000...
2768
+ -2
2769
+ A=[U^4]:
2770
+ 0.596987639289... + 0.926018962976...*I
2771
+ 0
2772
+ A=[U^(-3)]:
2773
+ 5.40301236071... + 0.926018962976...*I
2774
+ 6
2775
+
2776
+ sage: z = ComplexField(1000)(- 2.3 + 3.1*i)
2777
+ sage: B = G.I()
2778
+ sage: for A in [G.S(), G.T(), G.U(), G.U()^(G.n()//2), G.U()^(-3)]:
2779
+ ....: print("A={}: ".format(A.string_repr("conj")))
2780
+ ....: num_linking_number(B.acton(A), z, G.n(), prec=100, num_prec=1000).n(53)
2781
+ ....: B.acton(A).linking_number()
2782
+ A=[S]:
2783
+ 6.63923483989...e-31 + 2.45195568651...e-30*I
2784
+ 0
2785
+ A=[V(1)]:
2786
+ 6.000000000000...
2787
+ 6
2788
+ A=[U]:
2789
+ -2.00000000000... + 2.45195568651...e-30*I
2790
+ -2
2791
+ A=[U^4]:
2792
+ 0.00772492873864... + 0.00668936643212...*I
2793
+ 0
2794
+ A=[U^(-3)]:
2795
+ 5.99730551444... + 0.000847636355069...*I
2796
+ 6
2797
+
2798
+ sage: z = ComplexField(5000)(- 2.3 + 3.1*i)
2799
+ sage: B = G.U()
2800
+ sage: for A in [G.S(), G.T(), G.U(), G.U()^(G.n()//2), G.U()^(-3)]: # long time
2801
+ ....: print("A={}: ".format(A.string_repr("conj")))
2802
+ ....: num_linking_number(B.acton(A), z, G.n(), prec=200, num_prec=5000).n(53)
2803
+ ....: B.acton(A).linking_number()
2804
+ A=[S]:
2805
+ -7.90944791339...e-34 - 9.38956758807...e-34*I
2806
+ 0
2807
+ A=[V(1)]:
2808
+ 5.99999997397... - 5.96520311160...e-8*I
2809
+ 6
2810
+ A=[U]:
2811
+ -2.00000000000... - 1.33113963568...e-61*I
2812
+ -2
2813
+ A=[U^4]:
2814
+ -2.32704571946...e-6 + 5.91899385948...e-7*I
2815
+ 0
2816
+ A=[U^(-3)]:
2817
+ 6.00000032148... - 1.82676936467...e-7*I
2818
+ 6
2819
+
2820
+ sage: A = G.V(2)*G.V(3)
2821
+ sage: B = G.I()
2822
+ sage: num_linking_number(B.acton(A), z, G.n(), prec=200, num_prec=5000).n(53) # long time
2823
+ 6.00498424588... - 0.00702329345176...*I
2824
+ sage: A.linking_number()
2825
+ 6
2826
+
2827
+ The numerical properties for anything larger are basically
2828
+ too bad to make nice further tests...
2829
+ """
2830
+ if self.is_identity():
2831
+ return ZZ.zero()
2832
+
2833
+ L, R, sgn = self._block_decomposition_data()
2834
+ n = self.parent().n()
2835
+
2836
+ if self.is_elliptic():
2837
+ if L[0] == 0:
2838
+ return ZZ(0)
2839
+ elif 2*L[1] == n:
2840
+ return ZZ(0)
2841
+ else:
2842
+ return ZZ(-2*L[1])
2843
+ else:
2844
+ t = sum(v[1] for v in L)
2845
+ u = sum((v[0]-1) for v in L)
2846
+
2847
+ return ZZ((n-2)*t - 2*u)
2848
+
2849
+ def root_extension_field(self):
2850
+ r"""
2851
+ Return a field extension which contains the fixed points of ``self``.
2852
+ Namely the root extension field of the parent for the discriminant of ``self``.
2853
+ Also see the parent method ``root_extension_field(D)`` and
2854
+ :meth:`root_extension_embedding` (which provides the correct embedding).
2855
+
2856
+ EXAMPLES::
2857
+
2858
+ sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
2859
+ sage: G = HeckeTriangleGroup(n=infinity)
2860
+ sage: G.V(3).discriminant()
2861
+ 32
2862
+ sage: G.V(3).root_extension_field() == G.root_extension_field(32)
2863
+ True
2864
+ sage: G.T().root_extension_field() == G.root_extension_field(G.T().discriminant()) == G.base_field()
2865
+ True
2866
+ sage: (G.S()).root_extension_field() == G.root_extension_field(G.S().discriminant())
2867
+ True
2868
+
2869
+ sage: G = HeckeTriangleGroup(n=7)
2870
+ sage: D = G.V(3).discriminant()
2871
+ sage: D
2872
+ 4*lam^2 + 4*lam - 4
2873
+ sage: G.V(3).root_extension_field() == G.root_extension_field(D)
2874
+ True
2875
+ sage: G.U().root_extension_field() == G.root_extension_field(G.U().discriminant())
2876
+ True
2877
+ sage: G.V(1).root_extension_field() == G.base_field()
2878
+ True
2879
+ """
2880
+ return self.parent().root_extension_field(self.discriminant())
2881
+
2882
+ def root_extension_embedding(self, K=None):
2883
+ r"""
2884
+ Return the correct embedding from the root extension field to ``K``.
2885
+
2886
+ INPUT:
2887
+
2888
+ - ``K`` -- a field to which we want the (correct) embedding.
2889
+ If ``K=None`` (default), then ``AlgebraicField()`` is
2890
+ used for elliptic elements and ``AlgebraicRealField()``
2891
+ otherwise.
2892
+
2893
+ EXAMPLES::
2894
+
2895
+ sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
2896
+ sage: G = HeckeTriangleGroup(n=infinity)
2897
+
2898
+ sage: fp = (-G.S()).fixed_points()[0]
2899
+ sage: alg_fp = (-G.S()).root_extension_embedding()(fp)
2900
+ sage: alg_fp
2901
+ 1*I
2902
+ sage: alg_fp == (-G.S()).fixed_points(embedded=True)[0]
2903
+ True
2904
+
2905
+ sage: fp = (-G.V(2)).fixed_points()[1]
2906
+ sage: alg_fp = (-G.V(2)).root_extension_embedding()(fp)
2907
+ sage: alg_fp
2908
+ -1.732050807568...?
2909
+ sage: alg_fp == (-G.V(2)).fixed_points(embedded=True)[1]
2910
+ True
2911
+
2912
+ sage: fp = (-G.V(2)).fixed_points()[0]
2913
+ sage: alg_fp = (-G.V(2)).root_extension_embedding()(fp)
2914
+ sage: alg_fp
2915
+ 1.732050807568...?
2916
+ sage: alg_fp == (-G.V(2)).fixed_points(embedded=True)[0]
2917
+ True
2918
+
2919
+ sage: G = HeckeTriangleGroup(n=7)
2920
+
2921
+ sage: fp = (-G.S()).fixed_points()[1]
2922
+ sage: alg_fp = (-G.S()).root_extension_embedding()(fp)
2923
+ sage: alg_fp
2924
+ 0.?... - 1.000000000000...?*I
2925
+ sage: alg_fp == (-G.S()).fixed_points(embedded=True)[1]
2926
+ True
2927
+
2928
+ sage: fp = (-G.U()^4).fixed_points()[0]
2929
+ sage: alg_fp = (-G.U()^4).root_extension_embedding()(fp)
2930
+ sage: alg_fp
2931
+ 0.9009688679024...? + 0.4338837391175...?*I
2932
+ sage: alg_fp == (-G.U()^4).fixed_points(embedded=True)[0]
2933
+ True
2934
+
2935
+ sage: (-G.U()^4).root_extension_embedding(CC)(fp)
2936
+ 0.900968867902... + 0.433883739117...*I
2937
+ sage: (-G.U()^4).root_extension_embedding(CC)(fp).parent()
2938
+ Complex Field with 53 bits of precision
2939
+
2940
+ sage: fp = (-G.V(5)).fixed_points()[1]
2941
+ sage: alg_fp = (-G.V(5)).root_extension_embedding()(fp)
2942
+ sage: alg_fp
2943
+ -0.6671145837954...?
2944
+ sage: alg_fp == (-G.V(5)).fixed_points(embedded=True)[1]
2945
+ True
2946
+ """
2947
+ return self.parent().root_extension_embedding(self.discriminant(), K)
2948
+
2949
+ def fixed_points(self, embedded=False, order='default'):
2950
+ r"""
2951
+ Return a pair of (mutually conjugate) fixed points of ``self``
2952
+ in a possible quadratic extension of the base field.
2953
+
2954
+ INPUT:
2955
+
2956
+ - ``embedded`` -- boolean (default: ``False``); if ``True``, the fixed
2957
+ points are embedded into ``AlgebraicRealField`` resp.
2958
+ ``AlgebraicField``
2959
+
2960
+ - ``order`` -- if ``order='none'`` the fixed points are chosen
2961
+ and ordered according to a fixed formula
2962
+
2963
+ If ``order='sign'`` the fixed points are always ordered
2964
+ according to the sign in front of the square root.
2965
+
2966
+ If ``order='default'`` (default) then in case the fixed
2967
+ points are hyperbolic they are ordered according to the
2968
+ sign of the trace of ``self`` instead, such that the
2969
+ attracting fixed point comes first.
2970
+
2971
+ If ``order='trace'`` the fixed points are always ordered
2972
+ according to the sign of the trace of ``self``.
2973
+ If the trace is zero they are ordered by the sign in
2974
+ front of the square root. In particular the fixed_points
2975
+ in this case remain the same for ``-self``.
2976
+
2977
+ OUTPUT:
2978
+
2979
+ If ``embedded=True`` an element of either ``AlgebraicRealField`` or
2980
+ ``AlgebraicField`` is returned. Otherwise an element of a relative field
2981
+ extension over the base field of (the parent of) ``self`` is returned.
2982
+
2983
+ Warning: Relative field extensions do not support default embeddings.
2984
+ So the correct embedding (which is the positive resp. imaginary positive
2985
+ one) has to be chosen.
2986
+
2987
+ EXAMPLES::
2988
+
2989
+ sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
2990
+ sage: G = HeckeTriangleGroup(n=infinity)
2991
+ sage: (-G.T(-4)).fixed_points()
2992
+ (+Infinity, +Infinity)
2993
+ sage: (-G.S()).fixed_points()
2994
+ (1/2*e, -1/2*e)
2995
+ sage: p = (-G.S()).fixed_points(embedded=True)[0]
2996
+ sage: p
2997
+ I
2998
+ sage: (-G.S()).acton(p) == p
2999
+ True
3000
+ sage: (-G.V(2)).fixed_points()
3001
+ (1/2*e, -1/2*e)
3002
+ sage: (-G.V(2)).fixed_points() == G.V(2).fixed_points()
3003
+ True
3004
+ sage: p = (-G.V(2)).fixed_points(embedded=True)[1]
3005
+ sage: p
3006
+ -1.732050807568878?
3007
+ sage: (-G.V(2)).acton(p) == p
3008
+ True
3009
+
3010
+ sage: G = HeckeTriangleGroup(n=7)
3011
+ sage: (-G.S()).fixed_points()
3012
+ (1/2*e, -1/2*e)
3013
+ sage: p = (-G.S()).fixed_points(embedded=True)[1]
3014
+ sage: p
3015
+ -I
3016
+ sage: (-G.S()).acton(p) == p
3017
+ True
3018
+ sage: (G.U()^4).fixed_points()
3019
+ ((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)
3020
+ sage: pts = (G.U()^4).fixed_points(order='trace')
3021
+ sage: (G.U()^4).fixed_points() == [pts[1], pts[0]]
3022
+ False
3023
+ sage: (G.U()^4).fixed_points(order='trace') == (-G.U()^4).fixed_points(order='trace')
3024
+ True
3025
+ sage: (G.U()^4).fixed_points() == (G.U()^4).fixed_points(order='none')
3026
+ True
3027
+ sage: (-G.U()^4).fixed_points() == (G.U()^4).fixed_points()
3028
+ True
3029
+ sage: (-G.U()^4).fixed_points(order='none') == pts
3030
+ True
3031
+ sage: p = (G.U()^4).fixed_points(embedded=True)[1]
3032
+ sage: p
3033
+ 0.9009688679024191? - 0.4338837391175581?*I
3034
+ sage: (G.U()^4).acton(p) == p
3035
+ True
3036
+ sage: (-G.V(5)).fixed_points()
3037
+ ((1/2*lam^2 - 1/2*lam - 1/2)*e, (-1/2*lam^2 + 1/2*lam + 1/2)*e)
3038
+ sage: (-G.V(5)).fixed_points() == G.V(5).fixed_points()
3039
+ True
3040
+ sage: p = (-G.V(5)).fixed_points(embedded=True)[0]
3041
+ sage: p
3042
+ 0.6671145837954892?
3043
+ sage: (-G.V(5)).acton(p) == p
3044
+ True
3045
+ """
3046
+ if self.c() == 0:
3047
+ return (infinity, infinity)
3048
+ else:
3049
+ D = self.discriminant()
3050
+ if D.is_square():
3051
+ e = D.sqrt()
3052
+ else:
3053
+ e = self.root_extension_field().gen()
3054
+
3055
+ a, b, c, d = self._matrix.list()
3056
+
3057
+ if order == "none":
3058
+ sgn = ZZ(1)
3059
+ elif order == "sign":
3060
+ sgn = coerce_AA(c).sign()
3061
+ elif order == "default":
3062
+ if self.is_elliptic() or self.trace() == 0:
3063
+ sgn = coerce_AA(c).sign()
3064
+ else:
3065
+ sgn = coerce_AA(self.trace()).sign()
3066
+ elif order == "trace":
3067
+ if self.trace() == 0:
3068
+ sgn = coerce_AA(c).sign()
3069
+ else:
3070
+ sgn = coerce_AA(self.trace()).sign()
3071
+ else:
3072
+ raise NotImplementedError
3073
+
3074
+ if embedded:
3075
+ e = coerce_AA(D).sqrt()
3076
+ e.simplify()
3077
+ a = coerce_AA(a)
3078
+ d = coerce_AA(d)
3079
+ c = coerce_AA(c)
3080
+
3081
+ root1 = (a-d)/(2*c) + sgn*e/(2*c)
3082
+ root2 = (a-d)/(2*c) - sgn*e/(2*c)
3083
+
3084
+ if embedded:
3085
+ root1.simplify()
3086
+ root1.exactify()
3087
+ root2.simplify()
3088
+ root2.exactify()
3089
+
3090
+ return (root1, root2)
3091
+
3092
+ def acton(self, tau):
3093
+ r"""
3094
+ Return the image of ``tau`` under the action of ``self``
3095
+ by linear fractional transformations or by conjugation
3096
+ in case ``tau`` is an element of the parent of ``self``.
3097
+
3098
+ It is possible to act on points of ``HyperbolicPlane()``.
3099
+
3100
+ .. NOTE::
3101
+
3102
+ There is a 1-1 correspondence between hyperbolic
3103
+ fixed points and the corresponding primitive element
3104
+ in the stabilizer. The action in the two cases above
3105
+ is compatible with this correspondence.
3106
+
3107
+ INPUT:
3108
+
3109
+ - ``tau`` -- either an element of ``self`` or any
3110
+ element to which a linear fractional
3111
+ transformation can be applied in the usual way.
3112
+
3113
+ In particular ``infinity`` is a possible
3114
+ argument and a possible return value.
3115
+
3116
+ As mentioned it is also possible to use
3117
+ points of ``HyperbolicPlane()``.
3118
+
3119
+ EXAMPLES::
3120
+
3121
+ sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
3122
+ sage: G = HeckeTriangleGroup(5)
3123
+ sage: G.S().acton(SR(1 + i/2))
3124
+ 2/5*I - 4/5
3125
+ sage: G.S().acton(SR(1 + i/2)).parent()
3126
+ Symbolic Ring
3127
+ sage: G.S().acton(QQbar(1 + i/2))
3128
+ 2/5*I - 4/5
3129
+ sage: G.S().acton(QQbar(1 + i/2)).parent()
3130
+ Algebraic Field
3131
+
3132
+ sage: G.S().acton(i + exp(-2))
3133
+ -1/(e^(-2) + I)
3134
+ sage: G.S().acton(i + exp(-2)).parent()
3135
+ Symbolic Ring
3136
+
3137
+ sage: G.T().acton(infinity) == infinity
3138
+ True
3139
+ sage: G.U().acton(infinity)
3140
+ lam
3141
+ sage: G.V(2).acton(-G.lam()) == infinity
3142
+ True
3143
+
3144
+ sage: G.V(2).acton(G.U()) == G.V(2)*G.U()*G.V(2).inverse()
3145
+ True
3146
+ sage: G.V(2).inverse().acton(G.U())
3147
+ [ 0 -1]
3148
+ [ 1 lam]
3149
+
3150
+ sage: p = HyperbolicPlane().PD().get_point(-I/2+1/8)
3151
+ sage: G.V(2).acton(p)
3152
+ Point in PD -((-(47*I + 161)*sqrt(5) - 47*I - 161)/(145*sqrt(5) + 94*I + 177)
3153
+ + I)/(I*(-(47*I + 161)*sqrt(5) - 47*I - 161)/(145*sqrt(5) + 94*I + 177) + 1)
3154
+ sage: bool(G.V(2).acton(p).to_model('UHP').coordinates()
3155
+ ....: == G.V(2).acton(p.to_model('UHP').coordinates()))
3156
+ True
3157
+
3158
+ sage: p = HyperbolicPlane().PD().get_point(I)
3159
+ sage: G.U().acton(p)
3160
+ Boundary point in PD 1/2*(sqrt(5) - 2*I + 1)/(-1/2*I*sqrt(5) - 1/2*I + 1)
3161
+ sage: G.U().acton(p).to_model('UHP') == HyperbolicPlane().UHP().get_point(G.lam())
3162
+ True
3163
+ sage: G.U().acton(p) == HyperbolicPlane().UHP().get_point(G.lam()).to_model('PD')
3164
+ True
3165
+ """
3166
+
3167
+ if tau.parent() == self.parent():
3168
+ return self*tau*self.inverse()
3169
+
3170
+ # if tau is a point of HyperbolicPlane then we use its coordinates in the UHP model
3171
+ model = None
3172
+ if _in_HyperbolicPlane(tau):
3173
+ model = tau.model()
3174
+ tau = tau.to_model('UHP').coordinates()
3175
+
3176
+ a, b, c, d = self._matrix.list()
3177
+
3178
+ if tau == infinity:
3179
+ if c.is_zero():
3180
+ result = infinity
3181
+ else:
3182
+ result = a/c
3183
+ elif c*tau + d == 0:
3184
+ result = infinity
3185
+ else:
3186
+ result = (a*tau + b) / (c*tau + d)
3187
+
3188
+ if model is None:
3189
+ return result
3190
+ else:
3191
+ from sage.geometry.hyperbolic_space.hyperbolic_interface import HyperbolicPlane
3192
+ return HyperbolicPlane().UHP().get_point(result).to_model(model)
3193
+
3194
+ def _act_on_(self, other, self_on_left):
3195
+ r"""
3196
+ Define the action by linear fractional transformation of Hecke triangle group
3197
+ elements on complex points (using :meth:`acton`).
3198
+
3199
+ For the action on matrices by conjugation :meth:`acton` has to be used explicitly
3200
+ (to avoid confusion/ambiguity in expressions of the form gamma1*gamma2*z).
3201
+
3202
+ EXAMPLES::
3203
+
3204
+ sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
3205
+ sage: G = HeckeTriangleGroup(5)
3206
+ sage: p = HyperbolicPlane().PD().get_point(I)
3207
+ sage: G.U()*p
3208
+ Boundary point in PD 1/2*(sqrt(5) - 2*I + 1)/(-1/2*I*sqrt(5) - 1/2*I + 1)
3209
+ sage: G.S()*G.U()*p == G.S()*(G.U()*p)
3210
+ True
3211
+ sage: G.S()*G.U()*p == (G.S()*G.U())*p
3212
+ True
3213
+ sage: (G.S()*G.U())*p == G.S()*(G.U()*p)
3214
+ True
3215
+
3216
+ sage: p = G.lam()
3217
+ sage: G.U()*G.T()*p
3218
+ 1/2*lam + 1/2
3219
+ sage: p = QQbar(i*sqrt(2))
3220
+ sage: G.U()*p
3221
+ 1.618033988749895? + 0.7071067811865475?*I
3222
+ sage: p = CC(-i + sqrt(2))
3223
+ sage: G.U()*p
3224
+ 1.14662946795886 - 0.333333333333333*I
3225
+ sage: p = infinity
3226
+ sage: G.U()*p
3227
+ lam
3228
+ """
3229
+
3230
+ if self_on_left:
3231
+ if other == infinity or other in CC or _in_HyperbolicPlane(other):
3232
+ return self.acton(other)
3233
+ return None
3234
+
3235
+ def slash(self, f, tau=None, k=None):
3236
+ r"""
3237
+ Return the `slash-operator` of weight ``k`` to applied to ``f``,
3238
+ evaluated at ``tau``. I.e. ``(f|_k[self])(tau)``.
3239
+
3240
+ INPUT:
3241
+
3242
+ - ``f`` -- a function in ``tau`` (or an object for which
3243
+ evaluation at ``self.acton(tau)`` makes sense
3244
+
3245
+ - ``tau`` -- where to evaluate the result.
3246
+ This should be a valid argument for :meth:`acton`.
3247
+
3248
+ If ``tau`` is a point of ``HyperbolicPlane()`` then
3249
+ its coordinates in the upper half plane model are used.
3250
+
3251
+ Default: ``None`` in which case ``f`` has to be
3252
+ a rational function / polynomial in one variable and
3253
+ the generator of the polynomial ring is used for ``tau``.
3254
+ That way ``slash`` acts on rational functions / polynomials.
3255
+
3256
+ - ``k`` -- even integer
3257
+
3258
+ Default: ``None`` in which case ``f`` either
3259
+ has to be a rational function / polynomial in one
3260
+ variable (then -degree is used).
3261
+ Or ``f`` needs to have a ``weight`` attribute which
3262
+ is then used.
3263
+
3264
+ EXAMPLES::
3265
+
3266
+ sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
3267
+ sage: from sage.modular.modform_hecketriangle.space import ModularForms
3268
+ sage: G = HeckeTriangleGroup(n=5)
3269
+ sage: E4 = ModularForms(group=G, k=4, ep=1).E4()
3270
+ sage: z = CC(-1/(-1/(2*i+30)-1))
3271
+ sage: (G.S()).slash(E4, z)
3272
+ 32288.0558881... - 118329.856601...*I
3273
+ sage: (G.V(2)*G.V(3)).slash(E4, z)
3274
+ 32288.0558892... - 118329.856603...*I
3275
+ sage: E4(z)
3276
+ 32288.0558881... - 118329.856601...*I
3277
+
3278
+ sage: z = HyperbolicPlane().PD().get_point(CC(-I/2 + 1/8))
3279
+ sage: (G.V(2)*G.V(3)).slash(E4, z)
3280
+ -(21624.437... - 12725.035...*I)/((0.610... + 0.324...*I)*sqrt(5) + 2.720... + 0.648...*I)^4
3281
+
3282
+ sage: z = PolynomialRing(G.base_ring(), 'z').gen()
3283
+ sage: rat = z^2 + 1/(z-G.lam())
3284
+ sage: dr = rat.numerator().degree() - rat.denominator().degree()
3285
+ sage: G.S().slash(rat) == G.S().slash(rat, tau=None, k=-dr)
3286
+ True
3287
+ sage: G.S().slash(rat)
3288
+ (z^6 - lam*z^4 - z^3)/(-lam*z^4 - z^3)
3289
+ sage: G.S().slash(rat, k=0)
3290
+ (z^4 - lam*z^2 - z)/(-lam*z^4 - z^3)
3291
+ sage: G.S().slash(rat, k=-4)
3292
+ (z^8 - lam*z^6 - z^5)/(-lam*z^4 - z^3)
3293
+ """
3294
+
3295
+ if k is None:
3296
+ if hasattr(f, 'weight'):
3297
+ k = f.weight()
3298
+ else:
3299
+ try:
3300
+ par = f.numerator().parent()
3301
+ degf = par(f.numerator()).degree() - par(f.denominator()).degree()
3302
+ except (ValueError, TypeError, AttributeError):
3303
+ raise ValueError("The weight k could not be determined automatically and needs to be specified manually!")
3304
+ k = -degf
3305
+
3306
+ try:
3307
+ k = ZZ(k)
3308
+ if k % 2:
3309
+ raise TypeError
3310
+ except TypeError:
3311
+ raise ValueError("k={} must be an even integer!".format(k))
3312
+
3313
+ if tau is None:
3314
+ try:
3315
+ tau = f.numerator().parent().gen()
3316
+ except (ValueError, TypeError, AttributeError):
3317
+ raise ValueError("f={} is not a rational function or a polynomial in one variable, so tau has to be specified explicitly!".format(f))
3318
+
3319
+ if _in_HyperbolicPlane(tau):
3320
+ tau = tau.to_model('UHP').coordinates()
3321
+
3322
+ return (self.c()*tau + self.d())**(-k) * f(self.acton(tau))
3323
+
3324
+ def as_hyperbolic_plane_isometry(self, model='UHP'):
3325
+ r"""
3326
+ Return ``self`` as an isometry of ``HyperbolicPlane()`` (in the upper
3327
+ half plane model).
3328
+
3329
+ EXAMPLES::
3330
+
3331
+ sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
3332
+ sage: el = HeckeTriangleGroup(7).V(4)
3333
+ sage: el.as_hyperbolic_plane_isometry()
3334
+ Isometry in UHP
3335
+ [lam^2 - 1 lam]
3336
+ [lam^2 - 1 lam^2 - 1]
3337
+ sage: el.as_hyperbolic_plane_isometry().parent()
3338
+ Set of Morphisms
3339
+ from Hyperbolic plane in the Upper Half Plane Model
3340
+ to Hyperbolic plane in the Upper Half Plane Model
3341
+ in Category of hyperbolic models of Hyperbolic plane
3342
+ sage: el.as_hyperbolic_plane_isometry("KM").parent()
3343
+ Set of Morphisms
3344
+ from Hyperbolic plane in the Klein Disk Model
3345
+ to Hyperbolic plane in the Klein Disk Model
3346
+ in Category of hyperbolic models of Hyperbolic plane
3347
+ """
3348
+ from sage.geometry.hyperbolic_space.hyperbolic_interface import HyperbolicPlane
3349
+ return HyperbolicPlane().UHP().get_isometry(self._matrix).to_model(model)