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,1491 @@
1
+ # sage_setup: distribution = sagemath-schemes
2
+ # sage.doctest: needs sage.libs.pari
3
+ r"""
4
+ Congruence subgroup `\Gamma_H(N)`
5
+
6
+ AUTHORS:
7
+
8
+ - Jordi Quer
9
+ - David Loeffler
10
+ """
11
+
12
+ # #############################################################################
13
+ #
14
+ # Copyright (C) 2009, The Sage Group -- http://www.sagemath.org/
15
+ #
16
+ # Distributed under the terms of the GNU General Public License (GPL)
17
+ #
18
+ # The full text of the GPL is available at:
19
+ #
20
+ # https://www.gnu.org/licenses/
21
+ #
22
+ # #############################################################################
23
+ from collections.abc import Iterator
24
+
25
+ from sage.arith.functions import lcm
26
+ from sage.arith.misc import (
27
+ divisors,
28
+ euler_phi,
29
+ factor,
30
+ gcd,
31
+ get_gcd,
32
+ get_inverse_mod,
33
+ xgcd,
34
+ )
35
+ from sage.groups.matrix_gps.finitely_generated import MatrixGroup
36
+ from sage.matrix.constructor import matrix
37
+ from sage.misc.cachefunc import cached_method
38
+ from sage.modular.arithgroup.congroup_generic import CongruenceSubgroup
39
+ from sage.modular.cusps import Cusp
40
+ from sage.modular.modsym.p1list import lift_to_sl2z
41
+ from sage.rings.finite_rings.integer_mod_ring import Zmod
42
+ from sage.rings.integer_ring import ZZ
43
+ from sage.structure.richcmp import richcmp, richcmp_method
44
+
45
+ _gammaH_cache = {}
46
+
47
+
48
+ def GammaH_constructor(level, H):
49
+ r"""
50
+ Return the congruence subgroup `\Gamma_H(N)`, which is the subgroup of
51
+ `SL_2(\ZZ)` consisting of matrices of the form `\begin{pmatrix} a & b \\
52
+ c & d \end{pmatrix}` with `N | c` and `a, d \in H`, for `H` a specified
53
+ subgroup of `(\ZZ/N\ZZ)^\times`.
54
+
55
+ INPUT:
56
+
57
+ - ``level`` -- integer
58
+ - ``H`` -- either 0, 1, or a list
59
+ * If H is a list, return `\Gamma_H(N)`, where `H`
60
+ is the subgroup of `(\ZZ/N\ZZ)^*` **generated** by the
61
+ elements of the list.
62
+ * If H = 0, returns `\Gamma_0(N)`.
63
+ * If H = 1, returns `\Gamma_1(N)`.
64
+
65
+ EXAMPLES::
66
+
67
+ sage: GammaH(11,0) # indirect doctest
68
+ Congruence Subgroup Gamma0(11)
69
+ sage: GammaH(11,1)
70
+ Congruence Subgroup Gamma1(11)
71
+ sage: GammaH(11,[10])
72
+ Congruence Subgroup Gamma_H(11) with H generated by [10]
73
+ sage: GammaH(11,[10,1])
74
+ Congruence Subgroup Gamma_H(11) with H generated by [10]
75
+ sage: GammaH(14,[10])
76
+ Traceback (most recent call last):
77
+ ...
78
+ ArithmeticError: The generators [10] must be units modulo 14
79
+ """
80
+ from .all import SL2Z, Gamma0, Gamma1
81
+ if level == 1:
82
+ return SL2Z
83
+ elif H == 0:
84
+ return Gamma0(level)
85
+ elif H == 1:
86
+ return Gamma1(level)
87
+
88
+ H = _normalize_H(H, level)
89
+ if H == []:
90
+ return Gamma1(level)
91
+
92
+ Hlist = _list_subgroup(level, H)
93
+ if len(Hlist) == euler_phi(level):
94
+ return Gamma0(level)
95
+
96
+ key = (level, tuple(H))
97
+ try:
98
+ return _gammaH_cache[key]
99
+ except KeyError:
100
+ _gammaH_cache[key] = GammaH_class(level, H, Hlist)
101
+ return _gammaH_cache[key]
102
+
103
+
104
+ def is_GammaH(x):
105
+ """
106
+ Return ``True`` if x is a congruence subgroup of type GammaH.
107
+
108
+ EXAMPLES::
109
+
110
+ sage: from sage.modular.arithgroup.congroup_gammaH import is_GammaH
111
+ sage: is_GammaH(GammaH(13, [2]))
112
+ doctest:warning...
113
+ DeprecationWarning: The function is_GammaH is deprecated; use 'isinstance(..., GammaH_class)' instead.
114
+ See https://github.com/sagemath/sage/issues/38035 for details.
115
+ True
116
+ sage: is_GammaH(Gamma0(6))
117
+ True
118
+ sage: is_GammaH(Gamma1(6))
119
+ True
120
+ sage: is_GammaH(sage.modular.arithgroup.congroup_generic.CongruenceSubgroup(5))
121
+ False
122
+ """
123
+ from sage.misc.superseded import deprecation
124
+ deprecation(38035, "The function is_GammaH is deprecated; use 'isinstance(..., GammaH_class)' instead.")
125
+ return isinstance(x, GammaH_class)
126
+
127
+
128
+ def _normalize_H(H, level) -> list:
129
+ """
130
+ Normalize representatives for a given subgroup H of the units
131
+ modulo level.
132
+
133
+ .. NOTE::
134
+
135
+ This function does *not* make any attempt to find a minimal
136
+ set of generators for H. It simply normalizes the inputs for use
137
+ in hashing.
138
+
139
+ EXAMPLES::
140
+
141
+ sage: sage.modular.arithgroup.congroup_gammaH._normalize_H([23], 10)
142
+ [3]
143
+ sage: sage.modular.arithgroup.congroup_gammaH._normalize_H([1,5], 7)
144
+ [3]
145
+ sage: sage.modular.arithgroup.congroup_gammaH._normalize_H([4,18], 14)
146
+ Traceback (most recent call last):
147
+ ...
148
+ ArithmeticError: The generators [4, 4] must be units modulo 14
149
+ sage: sage.modular.arithgroup.congroup_gammaH._normalize_H([3,17], 14)
150
+ [3]
151
+ sage: sage.modular.arithgroup.congroup_gammaH._normalize_H([-1,7,9], 10)
152
+ [3, 9]
153
+
154
+ TESTS::
155
+
156
+ sage: sage.modular.arithgroup.congroup_gammaH._normalize_H([4, 16], 21)
157
+ [4]
158
+ """
159
+ H = [ZZ(h) % level for h in H]
160
+ for h in H:
161
+ if gcd(h, level) > 1:
162
+ raise ArithmeticError('The generators %s must be units modulo %s' % (H, level))
163
+ H = {u for u in H if u > 1}
164
+ final_H = set()
165
+ for h in H:
166
+ inv_h = h.inverse_mod(level)
167
+ if inv_h <= h:
168
+ final_H.add(inv_h)
169
+ else:
170
+ final_H.add(h)
171
+ return sorted(final_H)
172
+
173
+
174
+ @richcmp_method
175
+ class GammaH_class(CongruenceSubgroup):
176
+ r"""
177
+ The congruence subgroup `\Gamma_H(N)` for some subgroup `H \trianglelefteq
178
+ (\ZZ / N\ZZ)^\times`, which is the subgroup of `\SL_2(\ZZ)` consisting of
179
+ matrices of the form `\begin{pmatrix} a &
180
+ b \\ c & d \end{pmatrix}` with `N \mid c` and `a, d \in H`.
181
+
182
+ TESTS:
183
+
184
+ We test calculation of various invariants of the group::
185
+
186
+ sage: GammaH(33,[2]).projective_index()
187
+ 96
188
+ sage: GammaH(33,[2]).genus()
189
+ 5
190
+ sage: GammaH(7,[2]).genus()
191
+ 0
192
+ sage: GammaH(23, [1..22]).genus()
193
+ 2
194
+ sage: Gamma0(23).genus()
195
+ 2
196
+ sage: GammaH(23, [1]).genus()
197
+ 12
198
+ sage: Gamma1(23).genus()
199
+ 12
200
+
201
+ We calculate the dimensions of some modular forms spaces::
202
+
203
+ sage: GammaH(33,[2]).dimension_cusp_forms(2)
204
+ 5
205
+ sage: GammaH(33,[2]).dimension_cusp_forms(3)
206
+ 0
207
+ sage: GammaH(33,[2,5]).dimension_cusp_forms(2)
208
+ 3
209
+ sage: GammaH(32079, [21676]).dimension_cusp_forms(20)
210
+ 180266112
211
+
212
+ An example in weight 1::
213
+
214
+ sage: GammaH(20, [9]).dimension_cusp_forms(1)
215
+ 0
216
+ """
217
+
218
+ def __init__(self, level, H, Hlist=None) -> None:
219
+ r"""
220
+ The congruence subgroup `\Gamma_H(N)`.
221
+
222
+ The subgroup `H` must be given as a list.
223
+
224
+ EXAMPLES::
225
+
226
+ sage: GammaH(117, [4])
227
+ Congruence Subgroup Gamma_H(117) with H generated by [4]
228
+ sage: G = GammaH(16, [7])
229
+ sage: TestSuite(G).run()
230
+ sage: G is loads(dumps(G))
231
+ True
232
+ """
233
+ CongruenceSubgroup.__init__(self, level)
234
+ self.__H = H
235
+ if Hlist is None:
236
+ Hlist = _list_subgroup(level, H)
237
+ self.__Hlist = Hlist
238
+
239
+ def restrict(self, M):
240
+ r"""
241
+ Return the subgroup of `\Gamma_0(M)`, for `M` a divisor of `N`,
242
+ obtained by taking the image of this group under reduction modulo `N`.
243
+
244
+ EXAMPLES::
245
+
246
+ sage: G = GammaH(33,[2])
247
+ sage: G.restrict(11)
248
+ Congruence Subgroup Gamma0(11)
249
+ sage: G.restrict(1)
250
+ Modular Group SL(2,Z)
251
+ sage: G.restrict(15)
252
+ Traceback (most recent call last):
253
+ ...
254
+ ValueError: M (=15) must be a divisor of the level (33) of self
255
+ """
256
+ M = ZZ(M)
257
+ if self.level() % M:
258
+ raise ValueError("M (=%s) must be a divisor of the level (%s) of self" % (M, self.level()))
259
+ return self._new_group_from_level(M)
260
+
261
+ def extend(self, M):
262
+ r"""
263
+ Return the subgroup of `\Gamma_0(M)`, for `M` a multiple of `N`,
264
+ obtained by taking the preimage of this group under the reduction map;
265
+ in other words, the intersection of this group with `\Gamma_0(M)`.
266
+
267
+ EXAMPLES::
268
+
269
+ sage: G = GammaH(33, [2])
270
+ sage: G.extend(99)
271
+ Congruence Subgroup Gamma_H(99) with H generated by [2, 17, 68]
272
+ sage: G.extend(11)
273
+ Traceback (most recent call last):
274
+ ...
275
+ ValueError: M (=11) must be a multiple of the level (33) of self
276
+ """
277
+ M = ZZ(M)
278
+ if M % self.level():
279
+ raise ValueError("M (=%s) must be a multiple of the level (%s) of self" % (M, self.level()))
280
+ return self._new_group_from_level(M)
281
+
282
+ def __reduce__(self) -> tuple:
283
+ """
284
+ Used for pickling ``self``.
285
+
286
+ EXAMPLES::
287
+
288
+ sage: GammaH(92,[45,47]).__reduce__()
289
+ (<function GammaH_constructor at ...>, (92, [45, 47]))
290
+ """
291
+ return GammaH_constructor, (self.level(), self.__H)
292
+
293
+ def divisor_subgroups(self) -> list:
294
+ r"""
295
+ Given this congruence subgroup `\Gamma_H(N)`, return all
296
+ subgroups `\Gamma_G(M)` for `M` a divisor of `N` and such that
297
+ `G` is equal to the image of `H` modulo `M`.
298
+
299
+ EXAMPLES::
300
+
301
+ sage: G = GammaH(33,[2]); G
302
+ Congruence Subgroup Gamma_H(33) with H generated by [2]
303
+ sage: G._list_of_elements_in_H()
304
+ [1, 2, 4, 8, 16, 17, 25, 29, 31, 32]
305
+ sage: G.divisor_subgroups()
306
+ [Modular Group SL(2,Z),
307
+ Congruence Subgroup Gamma0(3),
308
+ Congruence Subgroup Gamma0(11),
309
+ Congruence Subgroup Gamma_H(33) with H generated by [2]]
310
+ """
311
+ v = self.__H
312
+ ans = []
313
+ for M in self.level().divisors():
314
+ w = [a % M for a in v if a % M]
315
+ ans.append(GammaH_constructor(M, w))
316
+ return ans
317
+
318
+ def to_even_subgroup(self):
319
+ r"""
320
+ Return the smallest even subgroup of `SL(2, \ZZ)` containing ``self``.
321
+
322
+ EXAMPLES::
323
+
324
+ sage: GammaH(11, [4]).to_even_subgroup()
325
+ Congruence Subgroup Gamma0(11)
326
+ sage: Gamma1(11).to_even_subgroup()
327
+ Congruence Subgroup Gamma_H(11) with H generated by [10]
328
+ """
329
+ if self.is_even():
330
+ return self
331
+ return GammaH_constructor(self.level(), self._generators_for_H() + [-1])
332
+
333
+ def __richcmp__(self, other, op) -> bool:
334
+ """
335
+ Compare ``self`` to ``other``.
336
+
337
+ The ordering on congruence subgroups of the form GammaH(N) for some H
338
+ is first by level, then by the order of H, then lexicographically by H.
339
+ In particular, this means that we have Gamma1(N) < GammaH(N) <
340
+ Gamma0(N) for every nontrivial proper subgroup H.
341
+
342
+ EXAMPLES::
343
+
344
+ sage: G = GammaH(86, [9])
345
+ sage: G == G
346
+ True
347
+ sage: G != GammaH(86, [11])
348
+ True
349
+ sage: Gamma1(11) < Gamma0(11)
350
+ True
351
+ sage: Gamma1(11) == GammaH(11, [])
352
+ True
353
+ sage: Gamma0(11) == GammaH(11, [2])
354
+ True
355
+ sage: G = Gamma0(86)
356
+ sage: G == G
357
+ True
358
+ sage: G != GammaH(86, [11])
359
+ True
360
+ sage: Gamma1(17) < Gamma0(17)
361
+ True
362
+ sage: Gamma0(1) == SL2Z
363
+ True
364
+ sage: Gamma0(2) == Gamma1(2)
365
+ True
366
+
367
+ sage: [x._list_of_elements_in_H() for x in sorted(Gamma0(24).gamma_h_subgroups())] # optional - gap_package_polycyclic
368
+ [[1],
369
+ [1, 5],
370
+ [1, 7],
371
+ [1, 11],
372
+ [1, 13],
373
+ [1, 17],
374
+ [1, 19],
375
+ [1, 23],
376
+ [1, 5, 7, 11],
377
+ [1, 5, 13, 17],
378
+ [1, 5, 19, 23],
379
+ [1, 7, 13, 19],
380
+ [1, 7, 17, 23],
381
+ [1, 11, 13, 23],
382
+ [1, 11, 17, 19],
383
+ [1, 5, 7, 11, 13, 17, 19, 23]]
384
+ """
385
+ if isinstance(other, GammaH_class):
386
+ return richcmp((self.level(), -self.index(),
387
+ self._list_of_elements_in_H()),
388
+ (other.level(), -other.index(),
389
+ other._list_of_elements_in_H()), op)
390
+ return NotImplemented
391
+
392
+ def _generators_for_H(self):
393
+ """
394
+ Return generators for the subgroup `H` of the units mod
395
+ ``self.level()`` that defines ``self``.
396
+
397
+ EXAMPLES::
398
+
399
+ sage: GammaH(17,[4])._generators_for_H()
400
+ [4]
401
+ sage: GammaH(12,[-1])._generators_for_H()
402
+ [11]
403
+ """
404
+ return self.__H
405
+
406
+ def _repr_(self) -> str:
407
+ """
408
+ Return the string representation of ``self``.
409
+
410
+ EXAMPLES::
411
+
412
+ sage: GammaH(123, [55])._repr_()
413
+ 'Congruence Subgroup Gamma_H(123) with H generated by [55]'
414
+ """
415
+ return "Congruence Subgroup Gamma_H(%s) with H generated by %s" % (self.level(), self.__H)
416
+
417
+ def _latex_(self) -> str:
418
+ r"""
419
+ Return the \LaTeX representation of ``self``.
420
+
421
+ EXAMPLES::
422
+
423
+ sage: GammaH(5,[4])._latex_()
424
+ '\\Gamma_H(5, [4])'
425
+ """
426
+ return '\\Gamma_H(%s, %s)' % (self.level(), self.__H)
427
+
428
+ def _list_of_elements_in_H(self) -> list:
429
+ """
430
+ Return a sorted list of Python ints that are representatives
431
+ between 1 and N-1 of the elements of H.
432
+
433
+ WARNING: Do not change this returned list.
434
+
435
+ EXAMPLES::
436
+
437
+ sage: G = GammaH(11,[3]); G
438
+ Congruence Subgroup Gamma_H(11) with H generated by [3]
439
+ sage: G._list_of_elements_in_H()
440
+ [1, 3, 4, 5, 9]
441
+ """
442
+ return self.__Hlist
443
+
444
+ def is_even(self) -> bool:
445
+ """
446
+ Return ``True`` precisely if this subgroup contains the matrix -1.
447
+
448
+ EXAMPLES::
449
+
450
+ sage: GammaH(10, [3]).is_even()
451
+ True
452
+ sage: GammaH(14, [1]).is_even()
453
+ False
454
+ """
455
+ if self.level() == 1:
456
+ return True
457
+ v = self._list_of_elements_in_H()
458
+ return int(self.level() - 1) in v
459
+
460
+ @cached_method
461
+ def generators(self, algorithm='farey'):
462
+ r"""
463
+ Return generators for this congruence subgroup. The result is cached.
464
+
465
+ INPUT:
466
+
467
+ - ``algorithm`` -- string; either ``'farey'`` (default) or
468
+ ``todd-coxeter``
469
+
470
+ If ``algorithm`` is set to ``'farey'``, then the generators will be
471
+ calculated using Farey symbols, which will always return a *minimal*
472
+ generating set. See :mod:`~sage.modular.arithgroup.farey_symbol` for
473
+ more information.
474
+
475
+ If ``algorithm`` is set to ``'todd-coxeter'``, a simpler algorithm
476
+ based on Todd-Coxeter enumeration will be used. This tends to return
477
+ far larger sets of generators.
478
+
479
+ EXAMPLES::
480
+
481
+ sage: GammaH(7, [2]).generators()
482
+ [
483
+ [1 1] [ 2 -1] [ 4 -3]
484
+ [0 1], [ 7 -3], [ 7 -5]
485
+ ]
486
+ sage: GammaH(7, [2]).generators(algorithm='todd-coxeter')
487
+ [
488
+ [1 1] [-13 4] [ 15 4] [-3 -1] [ 1 -1] [1 0] [1 1] [-3 -1]
489
+ [0 1], [ 42 -13], [-49 -13], [ 7 2], [ 0 1], [7 1], [0 1], [ 7 2],
490
+ <BLANKLINE>
491
+ [-13 4] [-5 -1] [-5 -2] [-10 3] [ 1 0] [ 2 -1] [1 0]
492
+ [ 42 -13], [21 4], [28 11], [ 63 -19], [-7 1], [ 7 -3], [7 1],
493
+ <BLANKLINE>
494
+ [-3 -1] [ 15 -4] [ 2 -1] [-5 1] [ 8 -3] [11 5] [-13 -4]
495
+ [ 7 2], [ 49 -13], [ 7 -3], [14 -3], [-21 8], [35 16], [-42 -13]
496
+ ]
497
+ """
498
+ if algorithm == "farey":
499
+ return self.farey_symbol().generators()
500
+ if algorithm == "todd-coxeter":
501
+ from sage.modular.modsym.ghlist import GHlist
502
+
503
+ from .congroup import generators_helper
504
+ level = self.level()
505
+ gen_list = generators_helper(GHlist(self), level)
506
+ return [self(g, check=False) for g in gen_list]
507
+
508
+ raise ValueError("Unknown algorithm '%s' (should be either 'farey' or 'todd-coxeter')" % algorithm)
509
+
510
+ def _coset_reduction_data_first_coord(self) -> list[tuple]:
511
+ """
512
+ Compute data used for determining the canonical coset
513
+ representative of an element of SL_2(Z) modulo ``self``.
514
+
515
+ This function specifically returns data needed for the first
516
+ part of the reduction step (the first coordinate).
517
+
518
+ INPUT:
519
+
520
+ - ``self`` -- a congruence subgroup Gamma_0(N), Gamma_1(N), or Gamma_H(N)
521
+
522
+ OUTPUT: list v such that
523
+
524
+ v[u] = (min(u*h: h in H),
525
+ gcd(u,N) ,
526
+ an h such that h*u = min(u*h: h in H)).
527
+
528
+ EXAMPLES::
529
+
530
+ sage: G = Gamma0(12)
531
+ sage: G._coset_reduction_data_first_coord()
532
+ [(0, 12, 0), (1, 1, 1), (2, 2, 1), (3, 3, 1), (4, 4, 1), (1, 1, 5), (6, 6, 1),
533
+ (1, 1, 7), (4, 4, 5), (3, 3, 7), (2, 2, 5), (1, 1, 11)]
534
+ """
535
+ H = [int(x) for x in self._list_of_elements_in_H()]
536
+ N = int(self.level())
537
+
538
+ # Get some useful fast functions for inverse and gcd
539
+ inverse_mod = get_inverse_mod(N) # optimal inverse function
540
+ gcd = get_gcd(N) # optimal gcd function
541
+
542
+ # We will be filling this list in below.
543
+ reduct_data = [0] * N
544
+
545
+ # We can fill in 0 and all elements of H immediately
546
+ reduct_data[0] = (0, N, 0)
547
+ for u in H:
548
+ reduct_data[u] = (1, 1, inverse_mod(u, N))
549
+
550
+ # Make a table of the reduction of H (mod N/d), one for each
551
+ # divisor d.
552
+ repr_H_mod_N_over_d = {}
553
+ for d in divisors(N):
554
+ # We special-case N == d because in this case,
555
+ # 1 % N_over_d is 0
556
+ if N == d:
557
+ repr_H_mod_N_over_d[d] = [1]
558
+ break
559
+ N_over_d = N // d
560
+ # For each element of H, we look at its image mod
561
+ # N_over_d. If we haven't yet seen it, add it on to
562
+ # the end of z.
563
+ w = [0] * N_over_d
564
+ z = [1]
565
+ for x in H:
566
+ val = x % N_over_d
567
+ if not w[val]:
568
+ w[val] = 1
569
+ z.append(x)
570
+ repr_H_mod_N_over_d[d] = z
571
+
572
+ # Compute the rest of the tuples. The values left to process
573
+ # are those where reduct_data has a 0. Note that several of
574
+ # these values are processed on each loop below, so re-index
575
+ # each time.
576
+ while True:
577
+ try:
578
+ u = reduct_data.index(0)
579
+ except ValueError:
580
+ break
581
+ d = gcd(u, N)
582
+ for x in repr_H_mod_N_over_d[d]:
583
+ reduct_data[(u * x) % N] = (u, d, inverse_mod(x, N))
584
+
585
+ return reduct_data
586
+
587
+ def _coset_reduction_data_second_coord(self) -> dict:
588
+ """
589
+ Compute data used for determining the canonical coset
590
+ representative of an element of SL_2(Z) modulo ``self``.
591
+
592
+ This function specifically returns data needed for the second
593
+ part of the reduction step (the second coordinate).
594
+
595
+ OUTPUT:
596
+
597
+ A dictionary v with keys the divisors of N such that v[d]
598
+ is the subgroup {h in H : h = 1 (mod N/d)}.
599
+
600
+ EXAMPLES::
601
+
602
+ sage: G = GammaH(240,[7,239])
603
+ sage: G._coset_reduction_data_second_coord()
604
+ {1: [1],
605
+ 2: [1],
606
+ 3: [1],
607
+ 4: [1],
608
+ 5: [1, 49],
609
+ 6: [1],
610
+ 8: [1],
611
+ 10: [1, 49],
612
+ 12: [1],
613
+ 15: [1, 49],
614
+ 16: [1],
615
+ 20: [1, 49],
616
+ 24: [1, 191],
617
+ 30: [1, 49, 137, 233],
618
+ 40: [1, 7, 49, 103],
619
+ 48: [1, 191],
620
+ 60: [1, 49, 137, 233],
621
+ 80: [1, 7, 49, 103],
622
+ 120: [1, 7, 49, 103, 137, 191, 233, 239],
623
+ 240: [1, 7, 49, 103, 137, 191, 233, 239]}
624
+ sage: G = GammaH(1200,[-1,7]); G
625
+ Congruence Subgroup Gamma_H(1200) with H generated by [7, 1199]
626
+ sage: K = sorted(G._coset_reduction_data_second_coord())
627
+ sage: K == divisors(1200)
628
+ True
629
+ """
630
+ H = self._list_of_elements_in_H()
631
+ N = self.level()
632
+ v = {1: [1], N: H}
633
+ for d in divisors(N):
634
+ if 1 < d < N:
635
+ N_over_d = N // d
636
+ v[d] = [x for x in H if x % N_over_d == 1]
637
+ return v
638
+
639
+ @cached_method
640
+ def _coset_reduction_data(self) -> tuple[list[tuple], dict]:
641
+ """
642
+ Compute data used for determining the canonical coset
643
+ representative of an element of SL_2(Z) modulo ``self``.
644
+
645
+ EXAMPLES::
646
+
647
+ sage: G = GammaH(13, [-1]); G
648
+ Congruence Subgroup Gamma_H(13) with H generated by [12]
649
+ sage: G._coset_reduction_data()
650
+ ([(0, 13, 0), (1, 1, 1), (2, 1, 1), (3, 1, 1), (4, 1, 1), (5, 1, 1), (6, 1, 1), (6, 1, 12), (5, 1, 12), (4, 1, 12), (3, 1, 12), (2, 1, 12), (1, 1, 12)], {1: [1], 13: [1, 12]})
651
+ """
652
+ return (self._coset_reduction_data_first_coord(),
653
+ self._coset_reduction_data_second_coord())
654
+
655
+ def _reduce_coset(self, uu, vv) -> tuple:
656
+ r"""
657
+ Compute a canonical form for a given Manin symbol.
658
+
659
+ INPUT:
660
+
661
+ Two integers (uu,vv) that define an element of `(Z/NZ)^2`.
662
+
663
+ - ``uu`` -- integer
664
+ - ``vv`` -- integer
665
+
666
+ OUTPUT: pair of integers that are equivalent to (uu,vv)
667
+
668
+ .. NOTE::
669
+
670
+ We do *not* require that gcd(uu,vv,N) = 1. If the gcd is
671
+ not 1, we return (0,0).
672
+
673
+ EXAMPLES:
674
+
675
+ An example at level 9::
676
+
677
+ sage: G = GammaH(9,[4]); G
678
+ Congruence Subgroup Gamma_H(9) with H generated by [4]
679
+ sage: a = []
680
+ sage: for i in range(G.level()):
681
+ ....: for j in range(G.level()):
682
+ ....: a.append(G._reduce_coset(i,j))
683
+ sage: v = list(set(a))
684
+ sage: v.sort()
685
+ sage: v
686
+ [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (1, 7), (1, 8), (2, 0), (2, 1), (2, 2), (2, 3), (2, 4), (2, 5), (2, 6), (2, 7), (2, 8), (3, 1), (3, 2), (6, 1), (6, 2)]
687
+
688
+ An example at level 100::
689
+
690
+ sage: G = GammaH(100,[3,7]); G
691
+ Congruence Subgroup Gamma_H(100) with H generated by [3, 7]
692
+ sage: a = []
693
+ sage: for i in range(G.level()):
694
+ ....: for j in range(G.level()):
695
+ ....: a.append(G._reduce_coset(i,j))
696
+ sage: v = list(set(a))
697
+ sage: v.sort()
698
+ sage: len(v)
699
+ 361
700
+
701
+ This demonstrates the problem underlying :issue:`1220`::
702
+
703
+ sage: G = GammaH(99, [67])
704
+ sage: G._reduce_coset(11,-3)
705
+ (11, 96)
706
+ sage: G._reduce_coset(77, -3)
707
+ (11, 96)
708
+ """
709
+ N = int(self.level())
710
+ u = uu % N
711
+ v = vv % N
712
+ first, second = self._coset_reduction_data()
713
+
714
+ if gcd(first[u][1], first[v][1]) != 1:
715
+ return (0, 0)
716
+ if not u:
717
+ return (0, first[v][0])
718
+ if not v:
719
+ return (first[u][0], 0)
720
+
721
+ new_u = first[u][0]
722
+ d = first[u][1]
723
+ new_v = (first[u][2] * v) % N
724
+ H_ls = second[d]
725
+ if len(H_ls) > 1:
726
+ new_v = min((new_v * h) % N for h in H_ls)
727
+
728
+ return (new_u, new_v)
729
+
730
+ def reduce_cusp(self, c):
731
+ r"""
732
+ Compute a minimal representative for the given cusp c.
733
+
734
+ This returns a cusp c' which is equivalent to the given cusp,
735
+ and is in lowest terms with minimal positive denominator, and
736
+ minimal positive numerator for that denominator.
737
+
738
+ Two cusps `u_1/v_1` and `u_2/v_2` are equivalent modulo `\Gamma_H(N)`
739
+ if and only if
740
+
741
+ .. MATH::
742
+
743
+ v_1 = h v_2 \bmod N\quad \text{and}\quad u_1 = h^{-1} u_2 \bmod {\rm gcd}(v_1,N)
744
+
745
+ or
746
+
747
+ .. MATH::
748
+
749
+ v_1 = -h v_2 \bmod N\quad \text{and}\quad u_1 = -h^{-1} u_2 \bmod {\rm gcd}(v_1,N)
750
+
751
+ for some `h \in H`.
752
+
753
+ EXAMPLES::
754
+
755
+ sage: GammaH(6,[5]).reduce_cusp(5/3)
756
+ 1/3
757
+ sage: GammaH(12,[5]).reduce_cusp(Cusp(8,9))
758
+ 1/3
759
+ sage: GammaH(12,[5]).reduce_cusp(5/12)
760
+ Infinity
761
+ sage: GammaH(12,[]).reduce_cusp(Cusp(5,12))
762
+ 5/12
763
+ sage: GammaH(21,[5]).reduce_cusp(Cusp(-9/14))
764
+ 1/7
765
+ sage: Gamma1(5).reduce_cusp(oo)
766
+ Infinity
767
+ sage: Gamma1(5).reduce_cusp(0)
768
+ 0
769
+ """
770
+ return self._reduce_cusp(c)[0]
771
+
772
+ def _reduce_cusp(self, c) -> tuple:
773
+ r"""
774
+ Compute a minimal representative for the given cusp c.
775
+
776
+ This returns a pair (c', t), where c' is the minimal representative
777
+ for the given cusp, and t is either 1 or -1, as explained
778
+ below. Largely for internal use.
779
+
780
+ The minimal representative for a cusp is the element in `P^1(Q)`
781
+ in lowest terms with minimal positive denominator, and minimal
782
+ positive numerator for that denominator.
783
+
784
+ Two cusps `u1/v1` and `u2/v2` are equivalent modulo `\Gamma_H(N)`
785
+ if and only if
786
+
787
+ - `v1 = h*v2 (mod N)` and `u1 = h^(-1)*u2 (mod gcd(v1,N))`
788
+
789
+ or
790
+
791
+ - `v1 = -h*v2 (mod N)` and `u1 = -h^(-1)*u2 (mod gcd(v1,N))`
792
+
793
+ for some `h \in H`. Then t is 1 or -1 as c and c' fall into
794
+ the first or second case, respectively.
795
+
796
+ EXAMPLES::
797
+
798
+ sage: GammaH(6,[5])._reduce_cusp(Cusp(5,3))
799
+ (1/3, -1)
800
+ sage: GammaH(12,[5])._reduce_cusp(Cusp(8,9))
801
+ (1/3, -1)
802
+ sage: GammaH(12,[5])._reduce_cusp(Cusp(5,12))
803
+ (Infinity, 1)
804
+ sage: GammaH(12,[])._reduce_cusp(Cusp(5,12))
805
+ (5/12, 1)
806
+ sage: GammaH(21,[5])._reduce_cusp(Cusp(-9/14))
807
+ (1/7, 1)
808
+ """
809
+ c = Cusp(c)
810
+ N = int(self.level())
811
+ Cusps = c.parent()
812
+ v = int(c.denominator() % N)
813
+ H = self._list_of_elements_in_H()
814
+
815
+ # First, if N | v, take care of this case. If u is in \pm H,
816
+ # then we return Infinity. If not, let u_0 be the minimum
817
+ # of \{ h*u | h \in \pm H \}. Then return u_0/N.
818
+ if not v:
819
+ u = c.numerator() % N
820
+ if u in H:
821
+ return Cusps((1, 0)), 1
822
+ if (N - u) in H:
823
+ return Cusps((1, 0)), -1
824
+ ls = [(u * h) % N for h in H]
825
+ m1 = min(ls)
826
+ m2 = N - max(ls)
827
+ if m1 < m2:
828
+ return Cusps((m1, N)), 1
829
+ else:
830
+ return Cusps((m2, N)), -1
831
+
832
+ u = int(c.numerator() % v)
833
+ gcd = get_gcd(N)
834
+ d = gcd(v, N)
835
+
836
+ # If (N,v) == 1, let v_0 be the minimal element
837
+ # in \{ v * h | h \in \pm H \}. Then we either return
838
+ # Infinity or 1/v_0, as v is or is not in \pm H,
839
+ # respectively.
840
+ if d == 1:
841
+ if v in H:
842
+ return Cusps((0, 1)), 1
843
+ if (N - v) in H:
844
+ return Cusps((0, 1)), -1
845
+ ls = [(v * h) % N for h in H]
846
+ m1 = min(ls)
847
+ m2 = N - max(ls)
848
+ if m1 < m2:
849
+ return Cusps((1, m1)), 1
850
+ else:
851
+ return Cusps((1, m2)), -1
852
+
853
+ val_min = v
854
+ inv_mod = get_inverse_mod(N)
855
+
856
+ # Now we're in the case (N,v) > 1. So we have to do several
857
+ # steps: first, compute v_0 as above. While computing this
858
+ # minimum, keep track of *all* pairs of (h,s) which give this
859
+ # value of v_0.
860
+ hs_ls = [(1, 1)]
861
+ for h in H:
862
+ tmp = (v * h) % N
863
+
864
+ if tmp < val_min:
865
+ val_min = tmp
866
+ hs_ls = [(inv_mod(h, N), 1)]
867
+ elif tmp == val_min:
868
+ hs_ls.append((inv_mod(h, N), 1))
869
+
870
+ if (N - tmp) < val_min:
871
+ val_min = N - tmp
872
+ hs_ls = [(inv_mod(h, N), -1)]
873
+ elif (N - tmp) == val_min:
874
+ hs_ls.append((inv_mod(h, N), -1))
875
+
876
+ # Finally, we find our minimal numerator. Let u_1 be the
877
+ # minimum of s*h^-1*u mod d as (h,s) ranges over the elements
878
+ # of hs_ls. We must find the smallest integer u_0 which is
879
+ # smaller than v_0, congruent to u_1 mod d, and coprime to
880
+ # v_0. Then u_0/v_0 is our minimal representative.
881
+ u_min = val_min
882
+ sign = None
883
+ for h_inv, s in hs_ls:
884
+ tmp = (h_inv * s * u) % d
885
+ while gcd(tmp, val_min) > 1 and tmp < u_min:
886
+ tmp += d
887
+ if tmp < u_min:
888
+ u_min = tmp
889
+ sign = s
890
+
891
+ return Cusps((u_min, val_min)), sign
892
+
893
+ def _find_cusps(self) -> list:
894
+ r"""
895
+ Return an ordered list of inequivalent cusps for ``self``, i.e. a
896
+ set of representatives for the orbits of ``self`` on
897
+ `\mathbf{P}^1(\QQ)`. These are returned in a reduced
898
+ form; see self.reduce_cusp for the definition of reduced.
899
+
900
+ ALGORITHM:
901
+
902
+ Lemma 3.2 in Cremona's 1997 book shows that for the action
903
+ of Gamma1(N) on "signed projective space"
904
+ `\Q^2 / (\Q_{\geq 0}^+)`, we have `u_1/v_1 \sim u_2 / v_2`
905
+ if and only if `v_1 = v_2 \bmod N` and `u_1 = u_2 \bmod
906
+ gcd(v_1, N)`. It follows that every orbit has a
907
+ representative `u/v` with `v \le N` and `0 \le u \le
908
+ gcd(v, N)`. We iterate through all pairs `(u,v)`
909
+ satisfying this.
910
+
911
+ Having found a set containing at least one of every
912
+ equivalence class modulo Gamma1(N), we can be sure of
913
+ picking up every class modulo GammaH(N) since this
914
+ contains Gamma1(N); and the reduce_cusp call does the
915
+ checking to make sure we don't get any duplicates.
916
+
917
+ EXAMPLES::
918
+
919
+ sage: Gamma1(5)._find_cusps()
920
+ [0, 2/5, 1/2, Infinity]
921
+ sage: Gamma1(35)._find_cusps()
922
+ [0, 2/35, 1/17, 1/16, 1/15, 1/14, 1/13, 1/12, 3/35, 1/11, 1/10, 1/9, 4/35, 1/8, 2/15, 1/7, 1/6, 6/35, 1/5, 3/14, 8/35, 1/4, 9/35, 4/15, 2/7, 3/10, 11/35, 1/3, 12/35, 5/14, 13/35, 2/5, 3/7, 16/35, 17/35, 1/2, 8/15, 4/7, 3/5, 9/14, 7/10, 5/7, 11/14, 4/5, 6/7, 9/10, 13/14, Infinity]
923
+ sage: Gamma1(24)._find_cusps() == Gamma1(24).cusps(algorithm='modsym')
924
+ True
925
+ sage: GammaH(24, [13,17])._find_cusps() == GammaH(24,[13,17]).cusps(algorithm='modsym')
926
+ True
927
+ """
928
+ s = []
929
+ hashes = []
930
+ N = self.level()
931
+
932
+ for d in range(1, 1 + N):
933
+ w = N.gcd(d)
934
+ M = int(w) if w > 1 else 2
935
+ for a in range(1, M):
936
+ if gcd(a, w) != 1:
937
+ continue
938
+ while gcd(a, d) != 1:
939
+ a += w
940
+ c = self.reduce_cusp(Cusp(a, d))
941
+ h = hash(c)
942
+ if h not in hashes:
943
+ hashes.append(h)
944
+ s.append(c)
945
+ return sorted(s)
946
+
947
+ def _contains_sl2(self, a, b, c, d) -> bool:
948
+ r"""
949
+ Test whether [a,b,c,d] is an element of this subgroup.
950
+
951
+ EXAMPLES::
952
+
953
+ sage: G = GammaH(10, [3])
954
+ sage: [1, 0, -10, 1] in G
955
+ True
956
+ sage: matrix(ZZ, 2, [7, 1, 20, 3]) in G
957
+ True
958
+ sage: SL2Z.0 in G
959
+ False
960
+ sage: GammaH(10, [9])([7, 1, 20, 3]) # indirect doctest
961
+ Traceback (most recent call last):
962
+ ...
963
+ TypeError: matrix [ 7 1]
964
+ [20 3] is not an element of Congruence Subgroup Gamma_H(10) with H generated by [9]
965
+ """
966
+ N = self.level()
967
+ return (c % N == 0) and (d % N in self._list_of_elements_in_H())
968
+
969
+ def gamma0_coset_reps(self) -> list:
970
+ r"""
971
+ Return a set of coset representatives for ``self \\ Gamma0(N)``, where
972
+ N is the level of ``self``.
973
+
974
+ EXAMPLES::
975
+
976
+ sage: GammaH(108, [1,-1]).gamma0_coset_reps()
977
+ [
978
+ [1 0] [-43 -2] [ 31 2] [-49 -5] [ 25 3] [-19 -3]
979
+ [0 1], [108 5], [108 7], [108 11], [108 13], [108 17],
980
+ <BLANKLINE>
981
+ [-17 -3] [ 47 10] [ 13 3] [ 41 11] [ 7 2] [-37 -12]
982
+ [108 19], [108 23], [108 25], [108 29], [108 31], [108 35],
983
+ <BLANKLINE>
984
+ [-35 -12] [ 29 11] [ -5 -2] [ 23 10] [-11 -5] [ 53 26]
985
+ [108 37], [108 41], [108 43], [108 47], [108 49], [108 53]
986
+ ]
987
+ """
988
+ from .all import SL2Z
989
+ N = self.level()
990
+ return [SL2Z(lift_to_sl2z(0, d.lift(), N))
991
+ for d in _GammaH_coset_helper(N, self._list_of_elements_in_H())]
992
+
993
+ def coset_reps(self) -> Iterator:
994
+ r"""
995
+ Return a set of coset representatives for ``self \\ SL2Z``.
996
+
997
+ EXAMPLES::
998
+
999
+ sage: list(Gamma1(3).coset_reps())
1000
+ [
1001
+ [1 0] [-1 0] [ 0 -1] [ 0 1] [1 0] [-1 0] [ 0 -1] [ 0 1]
1002
+ [0 1], [ 0 -1], [ 1 0], [-1 0], [1 1], [-1 -1], [ 1 2], [-1 -2]
1003
+ ]
1004
+ sage: len(list(Gamma1(31).coset_reps())) == 31**2 - 1
1005
+ True
1006
+ """
1007
+ from sage.modular.arithgroup.congroup_sl2z import SL2Z
1008
+ from sage.modular.congroup import Gamma0
1009
+ reps1 = Gamma0(self.level()).coset_reps()
1010
+ for r in reps1:
1011
+ reps2 = self.gamma0_coset_reps()
1012
+ for t in reps2:
1013
+ yield SL2Z(t) * r
1014
+
1015
+ def is_subgroup(self, other) -> bool:
1016
+ r"""
1017
+ Return ``True`` if ``self`` is a subgroup of ``right``, and ``False``
1018
+ otherwise.
1019
+
1020
+ EXAMPLES::
1021
+
1022
+ sage: GammaH(24,[7]).is_subgroup(SL2Z)
1023
+ True
1024
+ sage: GammaH(24,[7]).is_subgroup(Gamma0(8))
1025
+ True
1026
+ sage: GammaH(24, []).is_subgroup(GammaH(24, [7]))
1027
+ True
1028
+ sage: GammaH(24, []).is_subgroup(Gamma1(24))
1029
+ True
1030
+ sage: GammaH(24, [17]).is_subgroup(GammaH(24, [7]))
1031
+ False
1032
+ sage: GammaH(1371, [169]).is_subgroup(GammaH(457, [169]))
1033
+ True
1034
+ """
1035
+ from sage.modular.arithgroup.congroup_gamma0 import Gamma0_class
1036
+ from sage.modular.arithgroup.congroup_gamma1 import Gamma1_class
1037
+ if not isinstance(other, GammaH_class):
1038
+ raise NotImplementedError
1039
+
1040
+ # level of self should divide level of other
1041
+ if self.level() % other.level():
1042
+ return False
1043
+
1044
+ # easy cases
1045
+ if isinstance(other, Gamma0_class):
1046
+ return True # recall self is a GammaH, so it's contained in Gamma0
1047
+
1048
+ if isinstance(other, Gamma1_class) and len(self._generators_for_H()) > 0:
1049
+ return False
1050
+
1051
+ else:
1052
+ # difficult case
1053
+ t = other._list_of_elements_in_H()
1054
+ return all(x in t for x in self._generators_for_H())
1055
+
1056
+ def index(self):
1057
+ r"""
1058
+ Return the index of ``self`` in SL2Z.
1059
+
1060
+ EXAMPLES::
1061
+
1062
+ sage: [G.index() for G in Gamma0(40).gamma_h_subgroups()] # optional - gap_package_polycyclic
1063
+ [72, 144, 144, 144, 144, 288, 288, 288, 288, 144, 288, 288, 576, 576, 144, 288, 288, 576, 576, 144, 288, 288, 576, 576, 288, 576, 1152]
1064
+ """
1065
+ from .all import Gamma1
1066
+ return Gamma1(self.level()).index() / len(self._list_of_elements_in_H())
1067
+
1068
+ def nu2(self):
1069
+ r"""
1070
+ Return the number of orbits of elliptic points of order 2 for this
1071
+ group.
1072
+
1073
+ EXAMPLES::
1074
+
1075
+ sage: [H.nu2() for n in [1..10] for H in Gamma0(n).gamma_h_subgroups()] # optional - gap_package_polycyclic
1076
+ [1, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0]
1077
+ sage: GammaH(33,[2]).nu2()
1078
+ 0
1079
+ sage: GammaH(5,[2]).nu2()
1080
+ 2
1081
+
1082
+ AUTHORS:
1083
+
1084
+ - Jordi Quer
1085
+ """
1086
+ N = self.level()
1087
+ H = self._list_of_elements_in_H()
1088
+ if N % 4 == 0:
1089
+ return ZZ(0)
1090
+ for p, r in N.factor():
1091
+ if p % 4 == 3:
1092
+ return ZZ(0)
1093
+ return (euler_phi(N) // len(H)) * len([x for x in H if (x**2 + 1) % N == 0])
1094
+
1095
+ def nu3(self):
1096
+ r"""
1097
+ Return the number of orbits of elliptic points of order 3 for this
1098
+ group.
1099
+
1100
+ EXAMPLES::
1101
+
1102
+ sage: [H.nu3() for n in [1..10] for H in Gamma0(n).gamma_h_subgroups()] # optional - gap_package_polycyclic
1103
+ [1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
1104
+ sage: GammaH(33,[2]).nu3()
1105
+ 0
1106
+ sage: GammaH(7,[2]).nu3()
1107
+ 2
1108
+
1109
+ AUTHORS:
1110
+
1111
+ - Jordi Quer
1112
+ """
1113
+ N = self.level()
1114
+ H = self._list_of_elements_in_H()
1115
+ if N % 9 == 0:
1116
+ return ZZ(0)
1117
+ for p, r in N.factor():
1118
+ if p % 3 == 2:
1119
+ return ZZ(0)
1120
+ lenHpm = len(H)
1121
+ if N - ZZ(1) not in H:
1122
+ lenHpm *= 2
1123
+ return (euler_phi(N) // lenHpm) * len([1 for x in H if not (x**2 + x + 1) % N])
1124
+
1125
+ def ncusps(self):
1126
+ r"""
1127
+ Return the number of orbits of cusps (regular or otherwise) for this subgroup.
1128
+
1129
+ EXAMPLES::
1130
+
1131
+ sage: GammaH(33,[2]).ncusps()
1132
+ 8
1133
+ sage: GammaH(32079, [21676]).ncusps()
1134
+ 28800
1135
+
1136
+ AUTHORS:
1137
+
1138
+ - Jordi Quer
1139
+ """
1140
+ N = self.level()
1141
+ H = self._list_of_elements_in_H()
1142
+ c = ZZ.zero()
1143
+ for d in N.divisors():
1144
+ d2 = d**2
1145
+ if d2 > N:
1146
+ continue
1147
+ Nd = lcm(d, N // d)
1148
+ Hd = {x % Nd for x in H}
1149
+ lenHd = len(Hd)
1150
+ if Nd - 1 not in Hd:
1151
+ lenHd *= 2
1152
+ summand = euler_phi(d) * euler_phi(N // d) // lenHd
1153
+ if d2 == N:
1154
+ c = c + summand
1155
+ else:
1156
+ c = c + 2 * summand
1157
+ return c
1158
+
1159
+ def nregcusps(self):
1160
+ r"""
1161
+ Return the number of orbits of regular cusps for this subgroup.
1162
+
1163
+ A cusp is regular if we may find a parabolic element
1164
+ generating the stabiliser of that cusp whose eigenvalues are
1165
+ both +1 rather than -1. If G contains -1, all cusps are regular.
1166
+
1167
+ EXAMPLES::
1168
+
1169
+ sage: GammaH(20, [17]).nregcusps()
1170
+ 4
1171
+ sage: GammaH(20, [17]).nirregcusps()
1172
+ 2
1173
+ sage: GammaH(3212, [2045, 2773]).nregcusps()
1174
+ 1440
1175
+ sage: GammaH(3212, [2045, 2773]).nirregcusps()
1176
+ 720
1177
+
1178
+ AUTHOR:
1179
+
1180
+ - Jordi Quer
1181
+ """
1182
+ if self.is_even():
1183
+ return self.ncusps()
1184
+
1185
+ N = self.level()
1186
+ H = self._list_of_elements_in_H()
1187
+
1188
+ c = ZZ.zero()
1189
+ for d in divisors(N):
1190
+ d2 = d**2
1191
+ if d2 > N:
1192
+ continue
1193
+ Nd = lcm(d, N // d)
1194
+ Hd = {x % Nd for x in H}
1195
+ if Nd - 1 not in Hd:
1196
+ summand = euler_phi(d) * euler_phi(N // d) // (2 * len(Hd))
1197
+ if d2 == N:
1198
+ c = c + summand
1199
+ else:
1200
+ c = c + 2 * summand
1201
+ return c
1202
+
1203
+ def nirregcusps(self):
1204
+ r"""
1205
+ Return the number of irregular cusps for this subgroup.
1206
+
1207
+ EXAMPLES::
1208
+
1209
+ sage: GammaH(3212, [2045, 2773]).nirregcusps()
1210
+ 720
1211
+ """
1212
+ return self.ncusps() - self.nregcusps()
1213
+
1214
+ def dimension_cusp_forms(self, k=2):
1215
+ r"""
1216
+ Return the dimension of the space of weight k cusp forms for this
1217
+ group.
1218
+
1219
+ For `k \ge 2`, this is given by a standard formula in terms of k
1220
+ and various invariants of the group; see Diamond + Shurman, "A First
1221
+ Course in Modular Forms", section 3.5 and 3.6. If k is not given,
1222
+ default to k = 2.
1223
+
1224
+ For dimensions of spaces of cusp forms with character for Gamma1, use
1225
+ the dimension_cusp_forms method of the Gamma1 class, or the standalone
1226
+ function dimension_cusp_forms().
1227
+
1228
+ For weight 1 cusp forms, there is no simple formula for the dimensions,
1229
+ so we first try to rule out nonzero cusp forms existing via
1230
+ Riemann-Roch, and if this fails, we trigger computation of the cusp
1231
+ form space using Schaeffer's algorithm; this can be quite expensive in
1232
+ large levels.
1233
+
1234
+ EXAMPLES::
1235
+
1236
+ sage: GammaH(31, [23]).dimension_cusp_forms(10)
1237
+ 69
1238
+ sage: GammaH(31, [7]).dimension_cusp_forms(1)
1239
+ 1
1240
+ """
1241
+ k = ZZ(k)
1242
+ if k != 1:
1243
+ return CongruenceSubgroup.dimension_cusp_forms(self, k)
1244
+
1245
+ from sage.modular.modform.weight1 import dimension_wt1_cusp_forms_gH
1246
+ return dimension_wt1_cusp_forms_gH(self)
1247
+
1248
+ def dimension_new_cusp_forms(self, k=2, p=0):
1249
+ r"""
1250
+ Return the dimension of the space of new (or `p`-new)
1251
+ weight `k` cusp forms for this congruence subgroup.
1252
+
1253
+ INPUT:
1254
+
1255
+ - ``k`` -- integer (default: 2); the weight. Not fully implemented for
1256
+ `k = 1`.
1257
+ - ``p`` -- integer (default: 0); if nonzero, compute the `p`-new
1258
+ subspace
1259
+
1260
+ OUTPUT: integer
1261
+
1262
+ EXAMPLES::
1263
+
1264
+ sage: GammaH(33,[2]).dimension_new_cusp_forms()
1265
+ 3
1266
+ sage: Gamma1(4*25).dimension_new_cusp_forms(2, p=5)
1267
+ 225
1268
+ sage: Gamma1(33).dimension_new_cusp_forms(2)
1269
+ 19
1270
+ sage: Gamma1(33).dimension_new_cusp_forms(2,p=11)
1271
+ 21
1272
+ """
1273
+ N = self.level()
1274
+ if p == 0 or N % p:
1275
+ return sum(H.dimension_cusp_forms(k) * mumu(N // H.level())
1276
+ for H in self.divisor_subgroups())
1277
+ return self.dimension_cusp_forms(k) - \
1278
+ 2 * self.restrict(N // p).dimension_new_cusp_forms(k)
1279
+
1280
+ def image_mod_n(self):
1281
+ r"""
1282
+ Return the image of this group in `SL(2, \ZZ / N\ZZ)`.
1283
+
1284
+ EXAMPLES::
1285
+
1286
+ sage: Gamma0(3).image_mod_n()
1287
+ Matrix group over Ring of integers modulo 3 with 2 generators (
1288
+ [2 0] [1 1]
1289
+ [0 2], [0 1]
1290
+ )
1291
+
1292
+ TESTS::
1293
+
1294
+ sage: for n in [2..20]: # optional - gap_package_polycyclic
1295
+ ....: for g in Gamma0(n).gamma_h_subgroups():
1296
+ ....: G = g.image_mod_n()
1297
+ ....: assert G.order() == Gamma(n).index() / g.index()
1298
+ """
1299
+ N = self.level()
1300
+ if N == 1:
1301
+ raise NotImplementedError("matrix groups over ring of integers modulo 1 not implemented")
1302
+ gens = [matrix(Zmod(N), 2, 2, [x, 0, 0, Zmod(N).one() / x]) for x in self._generators_for_H()]
1303
+ gens += [matrix(Zmod(N), 2, 2, [1, 1, 0, 1])]
1304
+ return MatrixGroup(gens)
1305
+
1306
+ def atkin_lehner_matrix(self, Q):
1307
+ r"""
1308
+ Return the matrix of the Atkin--Lehner--Li operator `W_Q` associated to
1309
+ an exact divisor `Q` of `N`, where `N` is the level of this group; that
1310
+ is, `gcd(Q, N/Q) = 1`.
1311
+
1312
+ .. NOTE::
1313
+
1314
+ We follow the conventions of [AL1978]_ here, so `W_Q` is given by
1315
+ the action of any matrix of the form `\begin{pmatrix} Qx & y \\ Nz
1316
+ & Qw \end{pmatrix}` where `x,y,z,w` are integers such that `y = 1
1317
+ \bmod Q`, `x = 1 \bmod N/Q`, and `det(W_Q) = Q`. For convenience,
1318
+ we actually always choose `x = y = 1`.
1319
+
1320
+ INPUT:
1321
+
1322
+ - ``Q`` -- an integer dividing `N`, where `N` is the level of
1323
+ this group. If this divisor does not satisfy `gcd(Q, N/Q) = 1`, it
1324
+ will be replaced by the unique integer with this property having
1325
+ the same prime factors as `Q`.
1326
+
1327
+ EXAMPLES::
1328
+
1329
+ sage: Gamma1(994).atkin_lehner_matrix(71)
1330
+ [ 71 1]
1331
+ [4970 71]
1332
+ sage: Gamma1(996).atkin_lehner_matrix(2)
1333
+ [ 4 1]
1334
+ [-996 -248]
1335
+ sage: Gamma1(15).atkin_lehner_matrix(7)
1336
+ Traceback (most recent call last):
1337
+ ...
1338
+ ValueError: Q must divide the level
1339
+ """
1340
+ # normalise Q
1341
+ Q = ZZ(Q)
1342
+ N = self.level()
1343
+ if not Q.divides(N):
1344
+ raise ValueError("Q must divide the level")
1345
+ Q = N // N.prime_to_m_part(Q)
1346
+
1347
+ _, z, w = xgcd(-N // Q, Q)
1348
+ # so w * Q - z*(N/Q) = 1
1349
+ return matrix(ZZ, 2, 2, [Q, 1, N * z, Q * w])
1350
+
1351
+ @cached_method
1352
+ def characters_mod_H(self, sign=None, galois_orbits=False):
1353
+ r"""
1354
+ Return the characters of `(\ZZ / N\ZZ)^*`, of the specified sign, which
1355
+ are trivial on H.
1356
+
1357
+ INPUT:
1358
+
1359
+ - ``sign`` -- (default: ``None``) if not ``None``, return only
1360
+ characters of the given sign
1361
+
1362
+ - ``galois_orbits`` -- (default: ``False``) if ``True``, return only
1363
+ one character from each Galois orbit
1364
+
1365
+ EXAMPLES::
1366
+
1367
+ sage: GammaH(5, [-1]).characters_mod_H()
1368
+ [Dirichlet character modulo 5 of conductor 5 mapping 2 |--> -1,
1369
+ Dirichlet character modulo 5 of conductor 1 mapping 2 |--> 1]
1370
+ sage: Gamma1(31).characters_mod_H(galois_orbits=True,sign=-1)
1371
+ [Dirichlet character modulo 31 of conductor 31 mapping 3 |--> zeta30,
1372
+ Dirichlet character modulo 31 of conductor 31 mapping 3 |--> zeta30^3,
1373
+ Dirichlet character modulo 31 of conductor 31 mapping 3 |--> zeta30^5,
1374
+ Dirichlet character modulo 31 of conductor 31 mapping 3 |--> -1]
1375
+ sage: GammaH(31, [-1]).characters_mod_H(sign=-1)
1376
+ []
1377
+ """
1378
+ if sign == -1 and self.is_even():
1379
+ # shortcut for trivial special case
1380
+ return []
1381
+
1382
+ from sage.modular.dirichlet import DirichletGroup
1383
+ chis = DirichletGroup(self.level()).galois_orbits()
1384
+ A = []
1385
+ for U in chis:
1386
+ chi = U[0]
1387
+ if sign is not None:
1388
+ if chi(-1) != sign:
1389
+ continue
1390
+ if not all(chi(h) == 1 for h in self._generators_for_H()):
1391
+ continue
1392
+ if galois_orbits:
1393
+ A.append(chi)
1394
+ else:
1395
+ A += U
1396
+ return A
1397
+
1398
+
1399
+ def _list_subgroup(N, gens) -> list:
1400
+ r"""
1401
+ Given an integer ``N`` and a list of integers ``gens``, return a list of
1402
+ the elements of the subgroup of `(\ZZ / N\ZZ)^\times` generated by the
1403
+ elements of ``gens``.
1404
+
1405
+ EXAMPLES::
1406
+
1407
+ sage: sage.modular.arithgroup.congroup_gammaH._list_subgroup(11, [3])
1408
+ [1, 3, 4, 5, 9]
1409
+ """
1410
+ H = {1}
1411
+ N = int(N)
1412
+ for g in gens:
1413
+ if gcd(g, N) != 1:
1414
+ raise ValueError("gen (=%s) is not in (Z/%sZ)^*" % (g, N))
1415
+ gk = int(g) % N
1416
+ sbgrp = [gk]
1417
+ while gk not in H:
1418
+ gk = (gk * g) % N
1419
+ sbgrp.append(gk)
1420
+ H = {(x * h) % N for x in sbgrp for h in H}
1421
+ return sorted(H)
1422
+
1423
+
1424
+ def _GammaH_coset_helper(N, H) -> list:
1425
+ r"""
1426
+ Return a list of coset representatives for H in (Z / NZ)^*.
1427
+
1428
+ EXAMPLES::
1429
+
1430
+ sage: from sage.modular.arithgroup.congroup_gammaH import _GammaH_coset_helper
1431
+ sage: _GammaH_coset_helper(108, [1, 107])
1432
+ [1, 5, 7, 11, 13, 17, 19, 23, 25, 29, 31, 35, 37, 41, 43, 47, 49, 53]
1433
+ """
1434
+ t = [Zmod(N).one()]
1435
+ W = [Zmod(N)(h) for h in H]
1436
+ HH = [Zmod(N)(h) for h in H]
1437
+ k = euler_phi(N)
1438
+
1439
+ for i in range(1, N):
1440
+ if gcd(i, N) != 1:
1441
+ continue
1442
+ if i not in W:
1443
+ t.append(t[0] * i)
1444
+ W += [i * h for h in HH]
1445
+ if len(W) == k:
1446
+ break
1447
+ return t
1448
+
1449
+
1450
+ def mumu(N):
1451
+ """
1452
+ Return 0 if any cube divides `N`. Otherwise return
1453
+ `(-2)^v` where `v` is the number of primes that
1454
+ exactly divide `N`.
1455
+
1456
+ This is similar to the Möbius function.
1457
+
1458
+ INPUT:
1459
+
1460
+ - ``N`` -- integer at least 1
1461
+
1462
+ OUTPUT: integer
1463
+
1464
+ EXAMPLES::
1465
+
1466
+ sage: from sage.modular.arithgroup.congroup_gammaH import mumu
1467
+ sage: mumu(27)
1468
+ 0
1469
+ sage: mumu(6*25)
1470
+ 4
1471
+ sage: mumu(7*9*25)
1472
+ -2
1473
+ sage: mumu(9*25)
1474
+ 1
1475
+
1476
+ TESTS::
1477
+
1478
+ sage: mumu(0)
1479
+ Traceback (most recent call last):
1480
+ ...
1481
+ ValueError: N must be at least 1
1482
+ """
1483
+ if N < 1:
1484
+ raise ValueError("N must be at least 1")
1485
+ p = 1
1486
+ for _, r in factor(N):
1487
+ if r > 2:
1488
+ return ZZ.zero()
1489
+ elif r == 1:
1490
+ p *= -2
1491
+ return ZZ(p)