passagemath-schemes 10.6.38__cp314-cp314t-macosx_13_0_arm64.whl

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

Potentially problematic release.


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

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