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
sage/modular/cusps.py ADDED
@@ -0,0 +1,1107 @@
1
+ # sage_setup: distribution = sagemath-schemes
2
+ r"""
3
+ The set `\mathbb{P}^1(\QQ)` of cusps
4
+
5
+ EXAMPLES::
6
+
7
+ sage: Cusps
8
+ Set P^1(QQ) of all cusps
9
+
10
+ ::
11
+
12
+ sage: Cusp(oo)
13
+ Infinity
14
+ """
15
+
16
+ # ****************************************************************************
17
+ # Copyright (C) 2005 William Stein <wstein@gmail.com>
18
+ #
19
+ # Distributed under the terms of the GNU General Public License (GPL)
20
+ #
21
+ # This code is distributed in the hope that it will be useful,
22
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
23
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24
+ # General Public License for more details.
25
+ #
26
+ # The full text of the GPL is available at:
27
+ #
28
+ # https://www.gnu.org/licenses/
29
+ # ****************************************************************************
30
+ from typing import Any
31
+
32
+ from sage.misc.cachefunc import cached_method
33
+ from sage.misc.fast_methods import Singleton
34
+ from sage.modular.modsym.p1list import lift_to_sl2z_llong
35
+ from sage.rings.infinity import Infinity, InfinityRing
36
+ from sage.rings.integer import Integer
37
+ from sage.rings.integer_ring import ZZ
38
+ from sage.rings.rational import Rational
39
+ from sage.rings.rational_field import QQ
40
+ from sage.structure.element import Element, InfinityElement
41
+ from sage.structure.element import Matrix
42
+ from sage.structure.parent import Parent
43
+ from sage.structure.richcmp import richcmp
44
+
45
+ try:
46
+ from sage.libs.pari import pari
47
+ from cypari2.gen import Gen as pari_gen
48
+ except ImportError:
49
+ pari_gen = ()
50
+
51
+
52
+ class Cusp(Element):
53
+ """
54
+ A cusp.
55
+
56
+ A cusp is either a rational number or infinity, i.e., an element of
57
+ the projective line over Q. A Cusp is stored as a pair (a,b), where
58
+ gcd(a,b)=1 and a,b are of type Integer.
59
+
60
+ EXAMPLES::
61
+
62
+ sage: a = Cusp(2/3); b = Cusp(oo)
63
+ sage: a.parent()
64
+ Set P^1(QQ) of all cusps
65
+ sage: a.parent() is b.parent()
66
+ True
67
+ """
68
+ def __init__(self, a, b=None, parent=None, check=True):
69
+ r"""
70
+ Create the cusp a/b in `\mathbb{P}^1(\QQ)`, where if b=0
71
+ this is the cusp at infinity.
72
+
73
+ When present, b must either be Infinity or coercible to an
74
+ Integer.
75
+
76
+ EXAMPLES::
77
+
78
+ sage: Cusp(2,3)
79
+ 2/3
80
+ sage: Cusp(3,6)
81
+ 1/2
82
+ sage: Cusp(1,0)
83
+ Infinity
84
+ sage: Cusp(infinity)
85
+ Infinity
86
+ sage: Cusp(5)
87
+ 5
88
+ sage: Cusp(1/2)
89
+ 1/2
90
+ sage: Cusp(1.5)
91
+ 3/2
92
+ sage: Cusp(int(7))
93
+ 7
94
+ sage: Cusp(1, 2, check=False)
95
+ 1/2
96
+ sage: Cusp('sage', 2.5, check=False) # don't do this!
97
+ sage/2.50000000000000
98
+
99
+ ::
100
+
101
+ sage: I**2
102
+ -1
103
+ sage: Cusp(I)
104
+ Traceback (most recent call last):
105
+ ...
106
+ TypeError: unable to convert I to a cusp
107
+
108
+ ::
109
+
110
+ sage: a = Cusp(2,3)
111
+ sage: loads(a.dumps()) == a
112
+ True
113
+
114
+ ::
115
+
116
+ sage: Cusp(1/3,0)
117
+ Infinity
118
+ sage: Cusp((1,0))
119
+ Infinity
120
+
121
+ TESTS::
122
+
123
+ sage: Cusp("1/3", 5)
124
+ 1/15
125
+ sage: Cusp(Cusp(3/5), 7)
126
+ 3/35
127
+ sage: Cusp(5/3, 0)
128
+ Infinity
129
+ sage: Cusp(3,oo)
130
+ 0
131
+ sage: Cusp((7,3), 5)
132
+ 7/15
133
+ sage: Cusp(int(5), 7)
134
+ 5/7
135
+
136
+ ::
137
+
138
+ sage: Cusp(0,0)
139
+ Traceback (most recent call last):
140
+ ...
141
+ TypeError: unable to convert (0, 0) to a cusp
142
+
143
+ ::
144
+
145
+ sage: Cusp(oo,oo)
146
+ Traceback (most recent call last):
147
+ ...
148
+ TypeError: unable to convert (+Infinity, +Infinity) to a cusp
149
+
150
+ ::
151
+
152
+ sage: Cusp(Cusp(oo),oo)
153
+ Traceback (most recent call last):
154
+ ...
155
+ TypeError: unable to convert (Infinity, +Infinity) to a cusp
156
+
157
+ Conversion from PARI is supported (see :issue:`32091`)::
158
+
159
+ sage: Cusp(pari.oo())
160
+ Infinity
161
+ sage: Cusp(pari(2/3))
162
+ 2/3
163
+ """
164
+ if parent is None:
165
+ parent = Cusps
166
+ Element.__init__(self, parent)
167
+
168
+ if not check:
169
+ self.__a = a
170
+ self.__b = b
171
+ return
172
+
173
+ if b is None:
174
+ if isinstance(a, Integer):
175
+ self.__a = a
176
+ self.__b = ZZ.one()
177
+ elif isinstance(a, Rational):
178
+ self.__a = a.numer()
179
+ self.__b = a.denom()
180
+ elif (isinstance(a, InfinityElement) or
181
+ (isinstance(a, pari_gen) and a.type() == 't_INFINITY')):
182
+ self.__a = ZZ.one()
183
+ self.__b = ZZ.zero()
184
+ elif isinstance(a, Cusp):
185
+ self.__a = a.__a
186
+ self.__b = a.__b
187
+ elif isinstance(a, int):
188
+ self.__a = ZZ(a)
189
+ self.__b = ZZ.one()
190
+ elif isinstance(a, (tuple, list)):
191
+ if len(a) != 2:
192
+ raise TypeError("unable to convert %r to a cusp" % a)
193
+ if ZZ(a[1]) == 0:
194
+ self.__a = ZZ.one()
195
+ self.__b = ZZ.zero()
196
+ return
197
+ try:
198
+ r = QQ((a[0], a[1]))
199
+ self.__a = r.numer()
200
+ self.__b = r.denom()
201
+ except (ValueError, TypeError):
202
+ raise TypeError(f"unable to convert {a} to a cusp")
203
+ else:
204
+ try:
205
+ r = QQ(a)
206
+ self.__a = r.numer()
207
+ self.__b = r.denom()
208
+ except (ValueError, TypeError):
209
+ raise TypeError("unable to convert %r to a cusp" % a)
210
+ return
211
+
212
+ if isinstance(b, InfinityElement):
213
+ if isinstance(a, InfinityElement) or (isinstance(a, Cusp) and a.is_infinity()):
214
+ raise TypeError("unable to convert (%r, %r) to a cusp" % (a, b))
215
+ self.__a = ZZ.zero()
216
+ self.__b = ZZ.one()
217
+ return
218
+ elif not b:
219
+ if not a:
220
+ raise TypeError("unable to convert (%r, %r) to a cusp" % (a, b))
221
+ self.__a = ZZ.one()
222
+ self.__b = ZZ.zero()
223
+ return
224
+
225
+ if isinstance(a, (Integer, Rational)):
226
+ r = a / ZZ(b)
227
+ elif isinstance(a, InfinityElement):
228
+ self.__a = ZZ.one()
229
+ self.__b = ZZ.zero()
230
+ return
231
+ elif isinstance(a, Cusp):
232
+ if a.__b:
233
+ r = a.__a / (a.__b * b)
234
+ else:
235
+ self.__a = ZZ.one()
236
+ self.__b = ZZ.zero()
237
+ return
238
+ elif isinstance(a, int):
239
+ r = ZZ(a) / b
240
+ elif isinstance(a, (tuple, list)):
241
+ if len(a) != 2:
242
+ raise TypeError("unable to convert (%r, %r) to a cusp" % (a, b))
243
+ r = ZZ(a[0]) / (ZZ(a[1]) * b)
244
+ else:
245
+ try:
246
+ r = QQ(a) / b
247
+ except (ValueError, TypeError):
248
+ raise TypeError("unable to convert (%r, %r) to a cusp" % (a, b))
249
+
250
+ self.__a = r.numer()
251
+ self.__b = r.denom()
252
+
253
+ def __hash__(self):
254
+ """
255
+ EXAMPLES::
256
+
257
+ sage: hash(Cusp(1/3)) == hash((1,3))
258
+ True
259
+ sage: hash(Cusp(oo)) == hash((1,0))
260
+ True
261
+ """
262
+ return hash((self.__a, self.__b))
263
+
264
+ def _richcmp_(self, right, op):
265
+ """
266
+ Compare the cusps ``self`` and ``right``.
267
+
268
+ Comparison is as for rational numbers, except with the cusp oo
269
+ greater than everything but itself.
270
+
271
+ The ordering in comparison is only really meaningful for infinity
272
+ or elements that coerce to the rationals.
273
+
274
+ EXAMPLES::
275
+
276
+ sage: Cusp(2/3) == Cusp(oo)
277
+ False
278
+
279
+ sage: Cusp(2/3) < Cusp(oo)
280
+ True
281
+
282
+ sage: Cusp(2/3)> Cusp(oo)
283
+ False
284
+
285
+ sage: Cusp(2/3) > Cusp(5/2)
286
+ False
287
+
288
+ sage: Cusp(2/3) < Cusp(5/2)
289
+ True
290
+
291
+ sage: Cusp(2/3) == Cusp(5/2)
292
+ False
293
+
294
+ sage: Cusp(oo) == Cusp(oo)
295
+ True
296
+
297
+ sage: 19/3 < Cusp(oo)
298
+ True
299
+
300
+ sage: Cusp(oo) < 19/3
301
+ False
302
+
303
+ sage: Cusp(2/3) < Cusp(11/7)
304
+ True
305
+
306
+ sage: Cusp(11/7) < Cusp(2/3)
307
+ False
308
+
309
+ sage: 2 < Cusp(3)
310
+ True
311
+ """
312
+ if not self.__b:
313
+ s = Infinity
314
+ else:
315
+ s = self._rational_()
316
+ if not right.__b:
317
+ o = Infinity
318
+ else:
319
+ o = right._rational_()
320
+ return richcmp(s, o, op)
321
+
322
+ def is_infinity(self) -> bool:
323
+ """
324
+ Return ``True`` if this is the cusp infinity.
325
+
326
+ EXAMPLES::
327
+
328
+ sage: Cusp(3/5).is_infinity()
329
+ False
330
+ sage: Cusp(1,0).is_infinity()
331
+ True
332
+ sage: Cusp(0,1).is_infinity()
333
+ False
334
+ """
335
+ return not self.__b
336
+
337
+ def numerator(self):
338
+ """
339
+ Return the numerator of the cusp a/b.
340
+
341
+ EXAMPLES::
342
+
343
+ sage: x = Cusp(6,9); x
344
+ 2/3
345
+ sage: x.numerator()
346
+ 2
347
+ sage: Cusp(oo).numerator()
348
+ 1
349
+ sage: Cusp(-5/10).numerator()
350
+ -1
351
+ """
352
+ return self.__a
353
+
354
+ def denominator(self):
355
+ """
356
+ Return the denominator of the cusp a/b.
357
+
358
+ EXAMPLES::
359
+
360
+ sage: x = Cusp(6,9); x
361
+ 2/3
362
+ sage: x.denominator()
363
+ 3
364
+ sage: Cusp(oo).denominator()
365
+ 0
366
+ sage: Cusp(-5/10).denominator()
367
+ 2
368
+ """
369
+ return self.__b
370
+
371
+ @cached_method
372
+ def _rational_(self):
373
+ """
374
+ Coerce to a rational number.
375
+
376
+ EXAMPLES::
377
+
378
+ sage: QQ(Cusp(oo))
379
+ Traceback (most recent call last):
380
+ ...
381
+ TypeError: cusp Infinity is not a rational number
382
+ sage: QQ(Cusp(-3,7))
383
+ -3/7
384
+ sage: Cusp(11,2)._rational_()
385
+ 11/2
386
+ """
387
+ if not self.__b:
388
+ raise TypeError("cusp %s is not a rational number" % self)
389
+ return self.__a / self.__b
390
+
391
+ def _integer_(self, ZZ=None):
392
+ """
393
+ Coerce to an integer.
394
+
395
+ EXAMPLES::
396
+
397
+ sage: ZZ(Cusp(-19))
398
+ -19
399
+ sage: Cusp(4,2)._integer_()
400
+ 2
401
+
402
+ ::
403
+
404
+ sage: ZZ(Cusp(oo))
405
+ Traceback (most recent call last):
406
+ ...
407
+ TypeError: cusp Infinity is not an integer
408
+ sage: ZZ(Cusp(-3,7))
409
+ Traceback (most recent call last):
410
+ ...
411
+ TypeError: cusp -3/7 is not an integer
412
+ """
413
+ if self.__b != 1:
414
+ raise TypeError("cusp %s is not an integer" % self)
415
+ return self.__a
416
+
417
+ def _repr_(self):
418
+ """
419
+ String representation of this cusp.
420
+
421
+ EXAMPLES::
422
+
423
+ sage: a = Cusp(2/3); a
424
+ 2/3
425
+ sage: a._repr_()
426
+ '2/3'
427
+ sage: a.rename('2/3(cusp)'); a
428
+ 2/3(cusp)
429
+ """
430
+ if self.__b.is_zero():
431
+ return "Infinity"
432
+ if self.__b != 1:
433
+ return "%s/%s" % (self.__a, self.__b)
434
+ else:
435
+ return str(self.__a)
436
+
437
+ def _latex_(self):
438
+ r"""
439
+ Latex representation of this cusp.
440
+
441
+ EXAMPLES::
442
+
443
+ sage: latex(Cusp(-2/7))
444
+ \frac{-2}{7}
445
+ sage: latex(Cusp(oo))
446
+ \infty
447
+ sage: latex(Cusp(oo)) == Cusp(oo)._latex_()
448
+ True
449
+ """
450
+ if self.__b.is_zero():
451
+ return "\\infty"
452
+ if self.__b != 1:
453
+ return "\\frac{%s}{%s}" % (self.__a, self.__b)
454
+ else:
455
+ return str(self.__a)
456
+
457
+ def __neg__(self):
458
+ """
459
+ The negative of this cusp.
460
+
461
+ EXAMPLES::
462
+
463
+ sage: -Cusp(2/7)
464
+ -2/7
465
+ sage: -Cusp(oo)
466
+ Infinity
467
+ """
468
+ return Cusp(-self.__a, self.__b)
469
+
470
+ def is_gamma0_equiv(self, other, N,
471
+ transformation=None) -> bool | tuple[bool, Any]:
472
+ r"""
473
+ Return whether ``self`` and ``other`` are equivalent modulo the action of
474
+ `\Gamma_0(N)` via linear fractional transformations.
475
+
476
+ INPUT:
477
+
478
+ - ``other`` -- cusp
479
+
480
+ - ``N`` -- integer (specifies the group `\Gamma_0(N)`)
481
+
482
+ - ``transformation`` -- ``None`` (default) or either the string 'matrix' or
483
+ ``'corner'``. If ``'matrix'``, it also returns a matrix in `\Gamma_0(N)` that
484
+ sends ``self`` to ``other``. The matrix is chosen such that the lower
485
+ left entry is as small as possible in absolute value. If ``'corner'`` (or
486
+ ``True`` for backwards compatibility), it returns only the upper left
487
+ entry of such a matrix.
488
+
489
+ OUTPUT:
490
+
491
+ - a boolean -- ``True`` if ``self`` and ``other`` are equivalent
492
+
493
+ - a matrix or an integer -- returned only if transformation is 'matrix'
494
+ or 'corner', respectively
495
+
496
+ EXAMPLES::
497
+
498
+ sage: x = Cusp(2,3)
499
+ sage: y = Cusp(4,5)
500
+ sage: x.is_gamma0_equiv(y, 2)
501
+ True
502
+ sage: _, ga = x.is_gamma0_equiv(y, 2, 'matrix'); ga
503
+ [-1 2]
504
+ [-2 3]
505
+ sage: x.is_gamma0_equiv(y, 3)
506
+ False
507
+ sage: x.is_gamma0_equiv(y, 3, 'matrix')
508
+ (False, None)
509
+ sage: Cusp(1/2).is_gamma0_equiv(1/3,11,'corner')
510
+ (True, 19)
511
+
512
+ sage: Cusp(1,0)
513
+ Infinity
514
+ sage: z = Cusp(1,0)
515
+ sage: x.is_gamma0_equiv(z, 3, 'matrix')
516
+ (
517
+ [-1 1]
518
+ True, [-3 2]
519
+ )
520
+
521
+
522
+ ALGORITHM: See Proposition 2.2.3 of Cremona's book 'Algorithms for
523
+ Modular Elliptic Curves', or Prop 2.27 of Stein's Ph.D. thesis.
524
+ """
525
+ if transformation not in [False, True, "matrix", None, "corner"]:
526
+ raise ValueError("Value %s of the optional argument transformation is not valid.")
527
+
528
+ if not isinstance(other, Cusp):
529
+ other = Cusp(other)
530
+ N = ZZ(N)
531
+ u1 = self.__a
532
+ v1 = self.__b
533
+ u2 = other.__a
534
+ v2 = other.__b
535
+
536
+ zero = ZZ.zero()
537
+ one = ZZ.one()
538
+
539
+ if transformation == "matrix":
540
+ from sage.matrix.constructor import matrix
541
+
542
+ if v1 == v2 and u1 == u2:
543
+ if not transformation:
544
+ return True
545
+ elif transformation == "matrix":
546
+ return True, matrix(ZZ, [[1, 0], [0, 1]])
547
+ else:
548
+ return True, one
549
+
550
+ # a necessary, but not sufficient condition unless N is square-free
551
+ if v1.gcd(N) != v2.gcd(N):
552
+ if not transformation:
553
+ return False
554
+ else:
555
+ return False, None
556
+
557
+ if (u1, v1) != (zero, one):
558
+ if v1 in [zero, one]:
559
+ s1 = one
560
+ else:
561
+ s1 = u1.inverse_mod(v1)
562
+ else:
563
+ s1 = 0
564
+ if (u2, v2) != (zero, one):
565
+ if v2 in [zero, one]:
566
+ s2 = one
567
+ else:
568
+ s2 = u2.inverse_mod(v2)
569
+ else:
570
+ s2 = zero
571
+ g = (v1 * v2).gcd(N)
572
+ a = s1 * v2 - s2 * v1
573
+ if a % g != 0:
574
+ if not transformation:
575
+ return False
576
+ else:
577
+ return False, None
578
+
579
+ if not transformation:
580
+ return True
581
+
582
+ # Now we know the cusps are equivalent. Use the proof of Prop 2.2.3
583
+ # of Cremona to find a matrix in Gamma_0(N) relating them.
584
+ if v1 == 0: # the first is oo
585
+ if v2 == 0: # both are oo
586
+ if transformation == "matrix":
587
+ return (True, matrix(ZZ, [[1, 0], [0, 1]]))
588
+ else:
589
+ return (True, one)
590
+ else:
591
+ dum, s2, r2 = u2.xgcd(-v2)
592
+ assert dum.is_one()
593
+ if transformation == "matrix":
594
+ return (True, matrix(ZZ, [[u2, r2], [v2, s2]]))
595
+ else:
596
+ return (True, u2)
597
+
598
+ elif v2 == 0: # the second is oo
599
+ dum, s1, r1 = u1.xgcd(-v1)
600
+ assert dum.is_one()
601
+ if transformation == "matrix":
602
+ return (True, matrix(ZZ, [[s1, -r1], [-v1, u1]]))
603
+ else:
604
+ return (True, s1)
605
+
606
+ dum, s2, r2 = u2.xgcd(-v2)
607
+ assert dum.is_one()
608
+ dum, s1, r1 = u1.xgcd(-v1)
609
+ assert dum.is_one()
610
+ a = s1 * v2 - s2 * v1
611
+ assert (a % g).is_zero()
612
+ # solve x*v1*v2 + a = 0 (mod N).
613
+ d, x0, y0 = (v1 * v2).xgcd(N) # x0*v1*v2 + y0*N = d = g.
614
+ # so x0*v1*v2 - g = 0 (mod N)
615
+ x = -x0 * ZZ(a / g)
616
+ # now x*v1*v2 + a = 0 (mod N)
617
+
618
+ # the rest is all added in trac #10926
619
+ s1p = s1 + x * v1
620
+ M = N // g
621
+
622
+ if transformation == "matrix":
623
+ C = s1p * v2 - s2 * v1
624
+ if C % (M * v1 * v2) == 0:
625
+ k = - C // (M * v1 * v2)
626
+ else:
627
+ k = - (C / (M * v1 * v2)).round("away")
628
+
629
+ s1pp = s1p + k * M * v1
630
+ # C += k*M*v1*v2 # is now the smallest in absolute value
631
+ C = s1pp * v2 - s2 * v1
632
+ A = u2 * s1pp - r2 * v1
633
+
634
+ r1pp = r1 + (x + k * M) * u1
635
+ B = r2 * u1 - r1pp * u2
636
+ D = s2 * u1 - r1pp * v2
637
+
638
+ ga = matrix(ZZ, [[A, B], [C, D]])
639
+ assert ga.det() == 1
640
+ assert C % N == 0
641
+ assert (A * u1 + B * v1) / (C * u1 + D * v1) == u2 / v2
642
+ return (True, ga)
643
+
644
+ else:
645
+ # mainly for backwards compatibility and
646
+ # for how it is used in modular symbols
647
+ A = (u2 * s1p - r2 * v1)
648
+ if u2 != 0 and v1 != 0:
649
+ A = A % (u2 * v1 * M)
650
+ return (True, A)
651
+
652
+ def is_gamma1_equiv(self, other, N) -> tuple[bool, int]:
653
+ r"""
654
+ Return whether ``self`` and ``other`` are equivalent modulo the action of
655
+ `\Gamma_1(N)` via linear fractional transformations.
656
+
657
+ INPUT:
658
+
659
+ - ``other`` -- cusp
660
+
661
+ - ``N`` -- integer (specifies the group `\Gamma_1(N)`)
662
+
663
+ OUTPUT:
664
+
665
+ - ``bool`` -- ``True`` if ``self`` and ``other`` are equivalent
666
+
667
+ - ``int`` -- 0, 1 or -1, gives further information
668
+ about the equivalence: If the two cusps are u1/v1 and u2/v2, then
669
+ they are equivalent if and only if v1 = v2 (mod N) and u1 = u2 (mod
670
+ gcd(v1,N)) or v1 = -v2 (mod N) and u1 = -u2 (mod gcd(v1,N)) The
671
+ sign is +1 for the first and -1 for the second. If the two cusps
672
+ are not equivalent then 0 is returned.
673
+
674
+ EXAMPLES::
675
+
676
+ sage: x = Cusp(2,3)
677
+ sage: y = Cusp(4,5)
678
+ sage: x.is_gamma1_equiv(y,2)
679
+ (True, 1)
680
+ sage: x.is_gamma1_equiv(y,3)
681
+ (False, 0)
682
+ sage: z = Cusp(QQ(x) + 10)
683
+ sage: x.is_gamma1_equiv(z,10)
684
+ (True, 1)
685
+ sage: z = Cusp(1,0)
686
+ sage: x.is_gamma1_equiv(z, 3)
687
+ (True, -1)
688
+ sage: Cusp(0).is_gamma1_equiv(oo, 1)
689
+ (True, 1)
690
+ sage: Cusp(0).is_gamma1_equiv(oo, 3)
691
+ (False, 0)
692
+ """
693
+ if not isinstance(other, Cusp):
694
+ other = Cusp(other)
695
+ N = ZZ(N)
696
+ u1 = self.__a
697
+ v1 = self.__b
698
+ u2 = other.__a
699
+ v2 = other.__b
700
+ g = v1.gcd(N)
701
+ if ((v2 - v1) % N == 0 and (u2 - u1) % g == 0):
702
+ return True, 1
703
+ elif ((v2 + v1) % N == 0 and (u2 + u1) % g == 0):
704
+ return True, -1
705
+ return False, 0
706
+
707
+ def is_gamma_h_equiv(self, other, G) -> tuple[bool, int]:
708
+ r"""
709
+ Return a pair ``(b, t)``, where ``b`` is ``True`` or ``False`` as
710
+ ``self`` and ``other`` are equivalent under the action of `G`, and `t`
711
+ is 1 or -1, as described below.
712
+
713
+ Two cusps `u1/v1` and `u2/v2` are equivalent modulo
714
+ Gamma_H(N) if and only if `v1 = h*v2 (\mathrm{mod} N)` and
715
+ `u1 = h^{(-1)}*u2 (\mathrm{mod} gcd(v1,N))` or
716
+ `v1 = -h*v2 (mod N)` and
717
+ `u1 = -h^{(-1)}*u2 (\mathrm{mod} gcd(v1,N))` for some
718
+ `h \in H`. Then t is 1 or -1 as c and c' fall into the
719
+ first or second case, respectively.
720
+
721
+ INPUT:
722
+
723
+ - ``other`` -- cusp
724
+
725
+ - ``G`` -- a congruence subgroup Gamma_H(N)
726
+
727
+ OUTPUT:
728
+
729
+ - ``bool`` -- ``True`` if ``self`` and ``other`` are equivalent
730
+
731
+ - ``int`` -- -1, 0, 1; extra info
732
+
733
+ EXAMPLES::
734
+
735
+ sage: # needs sage.libs.pari
736
+ sage: x = Cusp(2,3)
737
+ sage: y = Cusp(4,5)
738
+ sage: x.is_gamma_h_equiv(y,GammaH(13,[2]))
739
+ (True, 1)
740
+ sage: x.is_gamma_h_equiv(y,GammaH(13,[5]))
741
+ (False, 0)
742
+ sage: x.is_gamma_h_equiv(y,GammaH(5,[]))
743
+ (False, 0)
744
+ sage: x.is_gamma_h_equiv(y,GammaH(23,[4]))
745
+ (True, -1)
746
+
747
+ Enumerating the cusps for a space of modular symbols uses this
748
+ function.
749
+
750
+ ::
751
+
752
+ sage: # needs sage.libs.pari
753
+ sage: G = GammaH(25,[6]); M = G.modular_symbols(); M
754
+ Modular Symbols space of dimension 11 for Congruence Subgroup Gamma_H(25)
755
+ with H generated by [6] of weight 2 with sign 0 over Rational Field
756
+ sage: M.cusps()
757
+ [8/25, 1/3, 6/25, 1/4, 1/15, -7/15, 7/15, 4/15, 1/20, 3/20, 7/20, 9/20]
758
+ sage: len(M.cusps())
759
+ 12
760
+
761
+ This is always one more than the associated space of weight 2 Eisenstein
762
+ series.
763
+
764
+ ::
765
+
766
+ sage: # needs sage.libs.pari
767
+ sage: G.dimension_eis(2)
768
+ 11
769
+ sage: M.cuspidal_subspace()
770
+ Modular Symbols subspace of dimension 0 of
771
+ Modular Symbols space of dimension 11 for Congruence Subgroup Gamma_H(25)
772
+ with H generated by [6] of weight 2 with sign 0 over Rational Field
773
+ sage: G.dimension_cusp_forms(2)
774
+ 0
775
+ """
776
+ from sage.modular.arithgroup.congroup_gammaH import GammaH_class
777
+ if not isinstance(other, Cusp):
778
+ other = Cusp(other)
779
+ if not isinstance(G, GammaH_class):
780
+ raise TypeError("G must be a group GammaH(N).")
781
+
782
+ H = G._list_of_elements_in_H()
783
+ N = ZZ(G.level())
784
+ u1 = self.__a
785
+ v1 = self.__b
786
+ u2 = other.__a
787
+ v2 = other.__b
788
+ g = v1.gcd(N)
789
+
790
+ for h in H:
791
+ v_tmp = (h * v1) % N
792
+ u_tmp = (h * u2) % N
793
+ if (v_tmp - v2) % N == 0 and (u_tmp - u1) % g == 0:
794
+ return True, 1
795
+ if (v_tmp + v2) % N == 0 and (u_tmp + u1) % g == 0:
796
+ return True, -1
797
+ return False, 0
798
+
799
+ def _acted_upon_(self, g, self_on_left):
800
+ r"""
801
+ Implement the left action of `SL_2(\ZZ)` on ``self``.
802
+
803
+ EXAMPLES::
804
+
805
+ sage: g = matrix(ZZ, 2, [1,1,0,1]); g
806
+ [1 1]
807
+ [0 1]
808
+ sage: g * Cusp(2,5)
809
+ 7/5
810
+ sage: Cusp(2,5) * g
811
+ Traceback (most recent call last):
812
+ ...
813
+ TypeError: unsupported operand parent(s) for *: 'Set P^1(QQ) of all cusps' and 'Full MatrixSpace of 2 by 2 dense matrices over Integer Ring'
814
+ sage: h = matrix(ZZ, 2, [12,3,-100,7])
815
+ sage: h * Cusp(2,5)
816
+ -13/55
817
+ sage: Cusp(2,5)._acted_upon_(h, False)
818
+ -13/55
819
+ sage: (h*g) * Cusp(3,7) == h * (g * Cusp(3,7))
820
+ True
821
+
822
+ sage: cm = sage.structure.element.get_coercion_model()
823
+ sage: cm.explain(MatrixSpace(ZZ, 2), Cusps)
824
+ Action discovered.
825
+ Left action by Full MatrixSpace of 2 by 2 dense matrices over Integer Ring on Set P^1(QQ) of all cusps
826
+ Result lives in Set P^1(QQ) of all cusps
827
+ Set P^1(QQ) of all cusps
828
+ """
829
+ if not self_on_left:
830
+ if (isinstance(g, Matrix) and g.base_ring() is ZZ
831
+ and g.ncols() == 2 == g.nrows()):
832
+ a, b, c, d = g.list()
833
+ return Cusp(a * self.__a + b * self.__b,
834
+ c * self.__a + d * self.__b)
835
+
836
+ def apply(self, g):
837
+ """
838
+ Return g(self), where g=[a,b,c,d] is a list of length 4, which we
839
+ view as a linear fractional transformation.
840
+
841
+ EXAMPLES: Apply the identity matrix::
842
+
843
+ sage: Cusp(0).apply([1,0,0,1])
844
+ 0
845
+ sage: Cusp(0).apply([0,-1,1,0])
846
+ Infinity
847
+ sage: Cusp(0).apply([1,-3,0,1])
848
+ -3
849
+ """
850
+ return Cusp(g[0] * self.__a + g[1] * self.__b,
851
+ g[2] * self.__a + g[3] * self.__b)
852
+
853
+ def galois_action(self, t, N):
854
+ r"""
855
+ Suppose this cusp is `\alpha`, `G` a congruence subgroup of level `N`
856
+ and `\sigma` is the automorphism in the Galois group of
857
+ `\QQ(\zeta_N)/\QQ` that sends `\zeta_N` to `\zeta_N^t`. Then this
858
+ function computes a cusp `\beta` such that `\sigma([\alpha]) = [\beta]`,
859
+ where `[\alpha]` is the equivalence class of `\alpha` modulo `G`.
860
+
861
+ This code only needs as input the level and not the group since the
862
+ action of Galois for a congruence group `G` of level `N` is compatible
863
+ with the action of the full congruence group `\Gamma(N)`.
864
+
865
+ INPUT:
866
+
867
+ - ``t`` -- integer that is coprime to N
868
+
869
+ - ``N`` -- positive integer (level)
870
+
871
+ OUTPUT: a cusp
872
+
873
+ .. WARNING::
874
+
875
+ In some cases `N` must fit in a long long, i.e., there
876
+ are cases where this algorithm isn't fully implemented.
877
+
878
+ .. NOTE::
879
+
880
+ Modular curves can have multiple non-isomorphic models over `\QQ`.
881
+ The action of Galois depends on such a model. The model over `\QQ`
882
+ of `X(G)` used here is the model where the function field
883
+ `\QQ(X(G))` is given by the functions whose Fourier expansion at
884
+ `\infty` have their coefficients in `\QQ`. For `X(N):=X(\Gamma(N))`
885
+ the corresponding moduli interpretation over `\ZZ[1/N]` is that
886
+ `X(N)` parametrizes pairs `(E,a)` where `E` is a (generalized)
887
+ elliptic curve and `a: \ZZ / N\ZZ \times \mu_N \to E` is a closed
888
+ immersion such that the Weil pairing of `a(1,1)` and `a(0,\zeta_N)`
889
+ is `\zeta_N`. In this parameterisation the point `z \in H`
890
+ corresponds to the pair `(E_z,a_z)` with `E_z=\CC/(z \ZZ+\ZZ)` and
891
+ `a_z: \ZZ / N\ZZ \times \mu_N \to E` given by `a_z(1,1) = z/N` and
892
+ `a_z(0,\zeta_N) = 1/N`.
893
+ Similarly `X_1(N):=X(\Gamma_1(N))` parametrizes pairs `(E,a)` where
894
+ `a: \mu_N \to E` is a closed immersion.
895
+
896
+ EXAMPLES::
897
+
898
+ sage: Cusp(1/10).galois_action(3, 50)
899
+ 1/170
900
+ sage: Cusp(oo).galois_action(3, 50)
901
+ Infinity
902
+ sage: c = Cusp(0).galois_action(3, 50); c
903
+ 50/17
904
+ sage: Gamma0(50).reduce_cusp(c)
905
+ 0
906
+
907
+ Here we compute the permutations of the action for t=3 on cusps for
908
+ Gamma0(50). ::
909
+
910
+ sage: N = 50; t=3; G = Gamma0(N); C = G.cusps()
911
+ sage: cl = lambda z: exists(C, lambda y:y.is_gamma0_equiv(z, N))[1]
912
+ sage: for i in range(5):
913
+ ....: print((i, t^i))
914
+ ....: print([cl(alpha.galois_action(t^i,N)) for alpha in C])
915
+ (0, 1)
916
+ [0, 1/25, 1/10, 1/5, 3/10, 2/5, 1/2, 3/5, 7/10, 4/5, 9/10, Infinity]
917
+ (1, 3)
918
+ [0, 1/25, 7/10, 2/5, 1/10, 4/5, 1/2, 1/5, 9/10, 3/5, 3/10, Infinity]
919
+ (2, 9)
920
+ [0, 1/25, 9/10, 4/5, 7/10, 3/5, 1/2, 2/5, 3/10, 1/5, 1/10, Infinity]
921
+ (3, 27)
922
+ [0, 1/25, 3/10, 3/5, 9/10, 1/5, 1/2, 4/5, 1/10, 2/5, 7/10, Infinity]
923
+ (4, 81)
924
+ [0, 1/25, 1/10, 1/5, 3/10, 2/5, 1/2, 3/5, 7/10, 4/5, 9/10, Infinity]
925
+
926
+ TESTS:
927
+
928
+ Here we check that the Galois action is indeed a permutation on the
929
+ cusps of Gamma1(48) and check that :issue:`13253` is fixed. ::
930
+
931
+ sage: # needs sage.libs.pari
932
+ sage: G = Gamma1(48)
933
+ sage: C = G.cusps()
934
+ sage: for i in Integers(48).unit_gens():
935
+ ....: C_permuted = [G.reduce_cusp(c.galois_action(i,48)) for c in C]
936
+ ....: assert len(set(C_permuted))==len(C)
937
+
938
+ We test that Gamma1(19) has 9 rational cusps and check that :issue:`8998`
939
+ is fixed. ::
940
+
941
+ sage: # needs sage.libs.pari
942
+ sage: G = Gamma1(19)
943
+ sage: [c for c in G.cusps() if c.galois_action(2,19).is_gamma1_equiv(c,19)[0]]
944
+ [2/19, 3/19, 4/19, 5/19, 6/19, 7/19, 8/19, 9/19, Infinity]
945
+
946
+
947
+ REFERENCES:
948
+
949
+ - Section 1.3 of Glenn Stevens, "Arithmetic on Modular Curves"
950
+
951
+ - There is a long comment about our algorithm in the source code for this function.
952
+
953
+ AUTHORS:
954
+
955
+ - William Stein, 2009-04-18
956
+ """
957
+ if self.is_infinity():
958
+ return self
959
+ if not isinstance(t, Integer):
960
+ t = Integer(t)
961
+
962
+ # Our algorithm for computing the Galois action works as
963
+ # follows (see Section 1.3 of Glenn Stevens "Arithmetic on
964
+ # Modular Curves" for a proof that the action given below is
965
+ # correct). We alternatively view the set of cusps as the
966
+ # Gamma-equivalence classes of column vectors [a;b] with
967
+ # gcd(a,b,N)=1, and the left action of Gamma by matrix
968
+ # multiplication. The action of t is induced by [a;b] |-->
969
+ # [a;t'*b], where t' is an inverse mod N of t. For [a;t'*b]
970
+ # with gcd(a,t'*b)==1, the cusp corresponding to [a;t'*b] is
971
+ # just the rational number a/(t'*b). Thus in this case, to
972
+ # compute the action of t we just do a/b <--> [a;b] |--->
973
+ # [a;t'*b] <--> a/(t'*b). IN the other case when we get
974
+ # [a;t'*b] with gcd(a,t'*b) != 1, which can and does happen,
975
+ # we have to work a bit harder. We need to find [c;d] such
976
+ # that [c;d] is congruent to [a;t'*b] modulo N, and
977
+ # gcd(c,d)=1. There is a standard lifting algorithm that is
978
+ # implemented for working with P^1(Z/NZ) [it is needed for
979
+ # modular symbols algorithms], so we just apply it to lift
980
+ # [a,t'*b] to a matrix [A,B;c,d] in SL_2(Z) with lower two
981
+ # entries congruent to [a,t'*b] modulo N. This exactly solves
982
+ # our problem, since gcd(c,d)=1.
983
+
984
+ a = self.__a
985
+ b = self.__b * t.inverse_mod(N)
986
+ if b.gcd(a) != 1:
987
+ _, _, a, b = lift_to_sl2z_llong(a, b, N)
988
+ a = Integer(a)
989
+ b = Integer(b)
990
+
991
+ # Now that we've computed the Galois action, we efficiently
992
+ # construct the corresponding cusp as a Cusp object.
993
+ return Cusp(a, b, check=False)
994
+
995
+ def __pari__(self):
996
+ """
997
+ Return a PARI representation of ``self``.
998
+
999
+ EXAMPLES::
1000
+
1001
+ sage: Cusp(1, 0).__pari__() # needs sage.libs.pari
1002
+ +oo
1003
+ sage: pari(Cusp(3, 2)) # needs sage.libs.pari
1004
+ 3/2
1005
+ """
1006
+ b = self.__b
1007
+ return pari(self.__a / b) if b else pari.oo()
1008
+
1009
+
1010
+ class Cusps_class(Singleton, Parent):
1011
+ """
1012
+ The set of cusps.
1013
+
1014
+ EXAMPLES::
1015
+
1016
+ sage: C = Cusps; C
1017
+ Set P^1(QQ) of all cusps
1018
+ sage: loads(C.dumps()) == C
1019
+ True
1020
+ """
1021
+ def __init__(self):
1022
+ r"""
1023
+ The set of cusps, i.e. `\mathbb{P}^1(\QQ)`.
1024
+
1025
+ EXAMPLES::
1026
+
1027
+ sage: C = sage.modular.cusps.Cusps_class() ; C
1028
+ Set P^1(QQ) of all cusps
1029
+ sage: Cusps == C
1030
+ True
1031
+ """
1032
+ Parent.__init__(self, self)
1033
+
1034
+ Element = Cusp
1035
+
1036
+ def _repr_(self):
1037
+ """
1038
+ String representation of the set of cusps.
1039
+
1040
+ EXAMPLES::
1041
+
1042
+ sage: Cusps
1043
+ Set P^1(QQ) of all cusps
1044
+ sage: Cusps._repr_()
1045
+ 'Set P^1(QQ) of all cusps'
1046
+ sage: Cusps.rename('CUSPS'); Cusps
1047
+ CUSPS
1048
+ sage: Cusps.rename(); Cusps
1049
+ Set P^1(QQ) of all cusps
1050
+ sage: Cusps
1051
+ Set P^1(QQ) of all cusps
1052
+ """
1053
+ return "Set P^1(QQ) of all cusps"
1054
+
1055
+ def _latex_(self):
1056
+ r"""
1057
+ Return latex representation of ``self``.
1058
+
1059
+ EXAMPLES::
1060
+
1061
+ sage: latex(Cusps)
1062
+ \mathbf{P}^1(\QQ)
1063
+ sage: latex(Cusps) == Cusps._latex_()
1064
+ True
1065
+ """
1066
+ return r"\mathbf{P}^1(\QQ)"
1067
+
1068
+ def __call__(self, x):
1069
+ """
1070
+ Coerce x into the set of cusps.
1071
+
1072
+ EXAMPLES::
1073
+
1074
+ sage: a = Cusps(-4/5); a
1075
+ -4/5
1076
+ sage: Cusps(a) is a
1077
+ False
1078
+ sage: Cusps(1.5)
1079
+ 3/2
1080
+ sage: Cusps(oo)
1081
+ Infinity
1082
+ sage: Cusps(I)
1083
+ Traceback (most recent call last):
1084
+ ...
1085
+ TypeError: unable to convert I to a cusp
1086
+
1087
+ TESTS::
1088
+
1089
+ sage: Cusps.has_coerce_map_from(ZZ)
1090
+ True
1091
+ sage: Cusps.has_coerce_map_from(QQ)
1092
+ True
1093
+ sage: Cusps.has_coerce_map_from(GF(7))
1094
+ False
1095
+ """
1096
+ return Cusp(x)
1097
+
1098
+ def _coerce_map_from_(self, R):
1099
+ if QQ.has_coerce_map_from(R):
1100
+ return True
1101
+ return R is InfinityRing
1102
+
1103
+ def _element_constructor_(self, x):
1104
+ return Cusp(x)
1105
+
1106
+
1107
+ Cusps = Cusps_class()