passagemath-schemes 10.6.47__cp312-cp312-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 (311) 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.6.47.dist-info/METADATA +204 -0
  7. passagemath_schemes-10.6.47.dist-info/METADATA.bak +205 -0
  8. passagemath_schemes-10.6.47.dist-info/RECORD +311 -0
  9. passagemath_schemes-10.6.47.dist-info/WHEEL +6 -0
  10. passagemath_schemes-10.6.47.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-312-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-312-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-312-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-312-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-312-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-312-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-312-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-312-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_nf.py +1241 -0
  154. sage/modular/modsym/relation_matrix.py +591 -0
  155. sage/modular/modsym/relation_matrix_pyx.cpython-312-darwin.so +0 -0
  156. sage/modular/modsym/relation_matrix_pyx.pyx +108 -0
  157. sage/modular/modsym/space.py +2468 -0
  158. sage/modular/modsym/subspace.py +455 -0
  159. sage/modular/modsym/tests.py +375 -0
  160. sage/modular/multiple_zeta.py +2632 -0
  161. sage/modular/multiple_zeta_F_algebra.py +786 -0
  162. sage/modular/overconvergent/all.py +6 -0
  163. sage/modular/overconvergent/genus0.py +1878 -0
  164. sage/modular/overconvergent/hecke_series.py +1187 -0
  165. sage/modular/overconvergent/weightspace.py +778 -0
  166. sage/modular/pollack_stevens/all.py +4 -0
  167. sage/modular/pollack_stevens/distributions.py +874 -0
  168. sage/modular/pollack_stevens/fund_domain.py +1572 -0
  169. sage/modular/pollack_stevens/manin_map.py +859 -0
  170. sage/modular/pollack_stevens/modsym.py +1593 -0
  171. sage/modular/pollack_stevens/padic_lseries.py +417 -0
  172. sage/modular/pollack_stevens/sigma0.py +534 -0
  173. sage/modular/pollack_stevens/space.py +1076 -0
  174. sage/modular/quasimodform/all.py +3 -0
  175. sage/modular/quasimodform/element.py +845 -0
  176. sage/modular/quasimodform/ring.py +828 -0
  177. sage/modular/quatalg/all.py +3 -0
  178. sage/modular/quatalg/brandt.py +1642 -0
  179. sage/modular/ssmod/all.py +8 -0
  180. sage/modular/ssmod/ssmod.py +827 -0
  181. sage/rings/all__sagemath_schemes.py +1 -0
  182. sage/rings/polynomial/all__sagemath_schemes.py +1 -0
  183. sage/rings/polynomial/binary_form_reduce.py +585 -0
  184. sage/schemes/all.py +41 -0
  185. sage/schemes/berkovich/all.py +6 -0
  186. sage/schemes/berkovich/berkovich_cp_element.py +2582 -0
  187. sage/schemes/berkovich/berkovich_space.py +748 -0
  188. sage/schemes/curves/affine_curve.py +2928 -0
  189. sage/schemes/curves/all.py +33 -0
  190. sage/schemes/curves/closed_point.py +434 -0
  191. sage/schemes/curves/constructor.py +381 -0
  192. sage/schemes/curves/curve.py +542 -0
  193. sage/schemes/curves/plane_curve_arrangement.py +1283 -0
  194. sage/schemes/curves/point.py +463 -0
  195. sage/schemes/curves/projective_curve.py +3026 -0
  196. sage/schemes/curves/zariski_vankampen.py +1932 -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 +1036 -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 +1102 -0
  208. sage/schemes/elliptic_curves/constructor.py +1552 -0
  209. sage/schemes/elliptic_curves/ec_database.py +175 -0
  210. sage/schemes/elliptic_curves/ell_curve_isogeny.py +3972 -0
  211. sage/schemes/elliptic_curves/ell_egros.py +459 -0
  212. sage/schemes/elliptic_curves/ell_field.py +2836 -0
  213. sage/schemes/elliptic_curves/ell_finite_field.py +3359 -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 +4787 -0
  220. sage/schemes/elliptic_curves/ell_rational_field.py +7368 -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 +1669 -0
  227. sage/schemes/elliptic_curves/gp_simon.py +152 -0
  228. sage/schemes/elliptic_curves/heegner.py +7335 -0
  229. sage/schemes/elliptic_curves/height.py +2109 -0
  230. sage/schemes/elliptic_curves/hom.py +1406 -0
  231. sage/schemes/elliptic_curves/hom_composite.py +934 -0
  232. sage/schemes/elliptic_curves/hom_frobenius.py +522 -0
  233. sage/schemes/elliptic_curves/hom_scalar.py +531 -0
  234. sage/schemes/elliptic_curves/hom_sum.py +682 -0
  235. sage/schemes/elliptic_curves/hom_velusqrt.py +1290 -0
  236. sage/schemes/elliptic_curves/homset.py +271 -0
  237. sage/schemes/elliptic_curves/isogeny_class.py +1521 -0
  238. sage/schemes/elliptic_curves/isogeny_small_degree.py +2797 -0
  239. sage/schemes/elliptic_curves/jacobian.py +237 -0
  240. sage/schemes/elliptic_curves/kodaira_symbol.py +344 -0
  241. sage/schemes/elliptic_curves/kraus.py +1014 -0
  242. sage/schemes/elliptic_curves/lseries_ell.py +943 -0
  243. sage/schemes/elliptic_curves/mod5family.py +105 -0
  244. sage/schemes/elliptic_curves/mod_poly.py +197 -0
  245. sage/schemes/elliptic_curves/mod_sym_num.cpython-312-darwin.so +0 -0
  246. sage/schemes/elliptic_curves/mod_sym_num.pyx +3796 -0
  247. sage/schemes/elliptic_curves/modular_parametrization.py +305 -0
  248. sage/schemes/elliptic_curves/padic_lseries.py +1793 -0
  249. sage/schemes/elliptic_curves/padics.py +1816 -0
  250. sage/schemes/elliptic_curves/period_lattice.py +2234 -0
  251. sage/schemes/elliptic_curves/period_lattice_region.cpython-312-darwin.so +0 -0
  252. sage/schemes/elliptic_curves/period_lattice_region.pyx +722 -0
  253. sage/schemes/elliptic_curves/saturation.py +715 -0
  254. sage/schemes/elliptic_curves/sha_tate.py +1158 -0
  255. sage/schemes/elliptic_curves/weierstrass_morphism.py +1117 -0
  256. sage/schemes/elliptic_curves/weierstrass_transform.py +200 -0
  257. sage/schemes/hyperelliptic_curves/all.py +6 -0
  258. sage/schemes/hyperelliptic_curves/constructor.py +291 -0
  259. sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py +1914 -0
  260. sage/schemes/hyperelliptic_curves/hyperelliptic_g2.py +192 -0
  261. sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py +954 -0
  262. sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py +1332 -0
  263. sage/schemes/hyperelliptic_curves/hyperelliptic_rational_field.py +84 -0
  264. sage/schemes/hyperelliptic_curves/invariants.py +410 -0
  265. sage/schemes/hyperelliptic_curves/jacobian_endomorphism_utils.py +315 -0
  266. sage/schemes/hyperelliptic_curves/jacobian_g2.py +32 -0
  267. sage/schemes/hyperelliptic_curves/jacobian_generic.py +419 -0
  268. sage/schemes/hyperelliptic_curves/jacobian_homset.py +186 -0
  269. sage/schemes/hyperelliptic_curves/jacobian_morphism.py +875 -0
  270. sage/schemes/hyperelliptic_curves/kummer_surface.py +99 -0
  271. sage/schemes/hyperelliptic_curves/mestre.py +302 -0
  272. sage/schemes/hyperelliptic_curves/monsky_washnitzer.py +3871 -0
  273. sage/schemes/jacobians/abstract_jacobian.py +277 -0
  274. sage/schemes/jacobians/all.py +2 -0
  275. sage/schemes/overview.py +161 -0
  276. sage/schemes/plane_conics/all.py +22 -0
  277. sage/schemes/plane_conics/con_field.py +1296 -0
  278. sage/schemes/plane_conics/con_finite_field.py +158 -0
  279. sage/schemes/plane_conics/con_number_field.py +456 -0
  280. sage/schemes/plane_conics/con_rational_field.py +406 -0
  281. sage/schemes/plane_conics/con_rational_function_field.py +580 -0
  282. sage/schemes/plane_conics/constructor.py +249 -0
  283. sage/schemes/plane_quartics/all.py +2 -0
  284. sage/schemes/plane_quartics/quartic_constructor.py +71 -0
  285. sage/schemes/plane_quartics/quartic_generic.py +73 -0
  286. sage/schemes/riemann_surfaces/all.py +1 -0
  287. sage/schemes/riemann_surfaces/riemann_surface.py +4117 -0
  288. sage_wheels/share/cremona/cremona_mini.db +0 -0
  289. sage_wheels/share/ellcurves/rank0 +30427 -0
  290. sage_wheels/share/ellcurves/rank1 +31871 -0
  291. sage_wheels/share/ellcurves/rank10 +6 -0
  292. sage_wheels/share/ellcurves/rank11 +6 -0
  293. sage_wheels/share/ellcurves/rank12 +1 -0
  294. sage_wheels/share/ellcurves/rank14 +1 -0
  295. sage_wheels/share/ellcurves/rank15 +1 -0
  296. sage_wheels/share/ellcurves/rank17 +1 -0
  297. sage_wheels/share/ellcurves/rank19 +1 -0
  298. sage_wheels/share/ellcurves/rank2 +2388 -0
  299. sage_wheels/share/ellcurves/rank20 +1 -0
  300. sage_wheels/share/ellcurves/rank21 +1 -0
  301. sage_wheels/share/ellcurves/rank22 +1 -0
  302. sage_wheels/share/ellcurves/rank23 +1 -0
  303. sage_wheels/share/ellcurves/rank24 +1 -0
  304. sage_wheels/share/ellcurves/rank28 +1 -0
  305. sage_wheels/share/ellcurves/rank3 +836 -0
  306. sage_wheels/share/ellcurves/rank4 +10 -0
  307. sage_wheels/share/ellcurves/rank5 +5 -0
  308. sage_wheels/share/ellcurves/rank6 +5 -0
  309. sage_wheels/share/ellcurves/rank7 +5 -0
  310. sage_wheels/share/ellcurves/rank8 +6 -0
  311. sage_wheels/share/ellcurves/rank9 +7 -0
@@ -0,0 +1,1065 @@
1
+ # sage_setup: distribution = sagemath-schemes
2
+ r"""
3
+ Eta-products on modular curves `X_0(N)`
4
+
5
+ This package provides a class for representing eta-products, which
6
+ are meromorphic functions on modular curves of the form
7
+
8
+ .. MATH::
9
+
10
+ \prod_{d | N} \eta(q^d)^{r_d}
11
+
12
+ where `\eta(q)` is Dirichlet's eta function
13
+
14
+ .. MATH::
15
+
16
+ q^{1/24} \prod_{n = 1}^\infty(1-q^n) .
17
+
18
+ These are useful for obtaining explicit models of modular curves.
19
+
20
+ See :issue:`3934` for background.
21
+
22
+ AUTHOR:
23
+
24
+ - David Loeffler (2008-08-22): initial version
25
+ """
26
+
27
+ # ***************************************************************************
28
+ # Copyright (C) 2008 William Stein <wstein@gmail.com>
29
+ # 2008 David Loeffler <d.loeffler.01@cantab.net>
30
+ #
31
+ # Distributed under the terms of the GNU General Public License (GPL)
32
+ # https://www.gnu.org/licenses/
33
+ # ***************************************************************************
34
+ from __future__ import annotations
35
+ from typing import Any
36
+
37
+ from sage.arith.misc import divisors, prime_divisors, euler_phi, is_square, gcd
38
+ from sage.categories.groups import Groups
39
+ from sage.matrix.constructor import matrix
40
+ from sage.modules.free_module import FreeModule
41
+ from sage.rings.finite_rings.integer_mod import Mod
42
+ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing
43
+ from sage.rings.integer import Integer
44
+ from sage.rings.integer_ring import ZZ
45
+ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
46
+ from sage.rings.power_series_ring import PowerSeriesRing
47
+ from sage.rings.rational_field import QQ
48
+ from sage.structure.element import Element
49
+ from sage.structure.formal_sum import FormalSum
50
+ from sage.structure.parent import Parent
51
+ from sage.structure.richcmp import richcmp, richcmp_method, op_EQ, op_NE
52
+ from sage.structure.sage_object import SageObject
53
+ from sage.structure.unique_representation import UniqueRepresentation
54
+
55
+ import weakref
56
+
57
+ _cache: dict[int, Any] = {}
58
+
59
+
60
+ def EtaGroup(level):
61
+ r"""
62
+ Create the group of eta products of the given level.
63
+
64
+ EXAMPLES::
65
+
66
+ sage: EtaGroup(12)
67
+ Group of eta products on X_0(12)
68
+ sage: EtaGroup(1/2)
69
+ Traceback (most recent call last):
70
+ ...
71
+ TypeError: Level (=1/2) must be a positive integer
72
+ sage: EtaGroup(0)
73
+ Traceback (most recent call last):
74
+ ...
75
+ ValueError: Level (=0) must be a positive integer
76
+ """
77
+ if level in _cache:
78
+ G = _cache[level]()
79
+ if G is not None:
80
+ return G
81
+ G = EtaGroup_class(level)
82
+ _cache[level] = weakref.ref(G)
83
+ return G
84
+
85
+
86
+ class EtaGroupElement(Element):
87
+
88
+ def __init__(self, parent, rdict):
89
+ r"""
90
+ Create an eta product object. Usually called implicitly via
91
+ EtaGroup_class.__call__ or the EtaProduct factory function.
92
+
93
+ EXAMPLES::
94
+
95
+ sage: EtaProduct(8, {1:24, 2:-24})
96
+ Eta product of level 8 : (eta_1)^24 (eta_2)^-24
97
+ sage: g = _; g == loads(dumps(g))
98
+ True
99
+ sage: TestSuite(g).run()
100
+ """
101
+ self._N = parent._N
102
+ N = self._N
103
+
104
+ if isinstance(rdict, EtaGroupElement):
105
+ rdict = rdict._rdict
106
+ # Note: This is needed because the "x in G" test tries to call G(x)
107
+ # and see if it returns an error. So sometimes this will be getting
108
+ # called with rdict being an eta product, not a dictionary.
109
+
110
+ if rdict == 1:
111
+ rdict = {}
112
+
113
+ # Check Ligozat criteria
114
+ sumR = sumDR = sumNoverDr = 0
115
+ prod = 1
116
+ for d in list(rdict):
117
+ if N % d:
118
+ raise ValueError("%s does not divide %s" % (d, N))
119
+
120
+ if rdict[d] == 0:
121
+ del rdict[d]
122
+ continue
123
+ sumR += rdict[d]
124
+ sumDR += rdict[d] * d
125
+ sumNoverDr += rdict[d] * (N // d)
126
+ prod *= (N // d)**rdict[d]
127
+
128
+ if sumR != 0:
129
+ raise ValueError("sum r_d (=%s) is not 0" % sumR)
130
+ if sumDR % 24:
131
+ raise ValueError("sum d r_d (=%s) is not 0 mod 24" % sumDR)
132
+ if sumNoverDr % 24:
133
+ raise ValueError("sum (N/d) r_d (=%s) is not 0 mod 24" % sumNoverDr)
134
+ if not is_square(prod):
135
+ raise ValueError("product (N/d)^(r_d) (=%s) is not a square" % prod)
136
+
137
+ self._sumDR = ZZ(sumDR) # this is useful to have around
138
+ self._rdict = rdict
139
+
140
+ Element.__init__(self, parent)
141
+
142
+ def _mul_(self, other):
143
+ r"""
144
+ Return the product of ``self`` and ``other``.
145
+
146
+ EXAMPLES::
147
+
148
+ sage: # needs fpylll
149
+ sage: eta1, eta2 = EtaGroup(4).basis() # indirect doctest
150
+ sage: eta1 * eta2
151
+ Eta product of level 4 : (eta_1)^24 (eta_2)^-48 (eta_4)^24
152
+ """
153
+ newdict = {d: self._rdict.get(d, 0) + other._rdict.get(d, 0)
154
+ for d in set(self._rdict).union(other._rdict)}
155
+ P = self.parent()
156
+ return P.element_class(P, newdict)
157
+
158
+ def _div_(self, other):
159
+ r"""
160
+ Return `self * other^{-1}`.
161
+
162
+ EXAMPLES::
163
+
164
+ sage: # needs fpylll
165
+ sage: eta1, eta2 = EtaGroup(4).basis()
166
+ sage: eta1 / eta2 # indirect doctest
167
+ Eta product of level 4 : (eta_1)^-8 (eta_4)^8
168
+ sage: (eta1 / eta2) * eta2 == eta1
169
+ True
170
+ """
171
+ newdict = {d: self._rdict.get(d, 0) - other._rdict.get(d, 0)
172
+ for d in set(self._rdict).union(other._rdict)}
173
+ P = self.parent()
174
+ return P.element_class(P, newdict)
175
+
176
+ def __invert__(self):
177
+ r"""
178
+ Return the inverse of ``self``.
179
+
180
+ EXAMPLES::
181
+
182
+ sage: # needs fpylll
183
+ sage: eta1, eta2 = EtaGroup(4).basis()
184
+ sage: ~eta2 # indirect doctest
185
+ Eta product of level 4 : (eta_1)^-16 (eta_2)^24 (eta_4)^-8
186
+ """
187
+ newdict = {d: -self._rdict[d] for d in self._rdict}
188
+ P = self.parent()
189
+ return P.element_class(P, newdict)
190
+
191
+ def is_one(self) -> bool:
192
+ r"""
193
+ Return whether ``self`` is the one of the monoid.
194
+
195
+ EXAMPLES::
196
+
197
+ sage: e = EtaProduct(3, {3:12, 1:-12})
198
+ sage: e.is_one()
199
+ False
200
+ sage: e.parent().one().is_one()
201
+ True
202
+ sage: ep = EtaProduct(5, {})
203
+ sage: ep.is_one()
204
+ True
205
+ sage: ep.parent().one() == ep
206
+ True
207
+ """
208
+ return not self._rdict
209
+
210
+ def _richcmp_(self, other, op) -> bool:
211
+ r"""
212
+ Compare ``self`` to ``other``.
213
+
214
+ Eta products are compared according to their rdicts.
215
+
216
+ EXAMPLES::
217
+
218
+ sage: EtaProduct(2, {2:24,1:-24}) == 1
219
+ False
220
+ sage: EtaProduct(6, {1:-24, 2:24}) == EtaProduct(6, {1:-24, 2:24})
221
+ True
222
+ sage: EtaProduct(6, {1:-24, 2:24}) == EtaProduct(6, {1:24, 2:-24})
223
+ False
224
+ sage: EtaProduct(6, {1:-24, 2:24}) < EtaProduct(6, {1:-24, 2:24, 3:24, 6:-24})
225
+ True
226
+ sage: EtaProduct(6, {1:-24, 2:24, 3:24, 6:-24}) < EtaProduct(6, {1:-24, 2:24})
227
+ False
228
+ """
229
+ if op in [op_EQ, op_NE]:
230
+ test = (self._N == other._N and
231
+ self._rdict == other._rdict)
232
+ return test == (op == op_EQ)
233
+ return richcmp((self._N, sorted(self._rdict.items())),
234
+ (other._N, sorted(other._rdict.items())), op)
235
+
236
+ def _short_repr(self) -> str:
237
+ r"""
238
+ A short string representation of ``self``, which does not specify the
239
+ level.
240
+
241
+ EXAMPLES::
242
+
243
+ sage: EtaProduct(3, {3:12, 1:-12})._short_repr()
244
+ '(eta_1)^-12 (eta_3)^12'
245
+ """
246
+ if self.degree() == 0:
247
+ return "1"
248
+ return " ".join("(eta_%s)^%s" % (d, exp)
249
+ for d, exp in sorted(self._rdict.items()))
250
+
251
+ def _repr_(self) -> str:
252
+ r"""
253
+ Return the string representation of ``self``.
254
+
255
+ EXAMPLES::
256
+
257
+ sage: EtaProduct(3, {3:12, 1:-12})._repr_()
258
+ 'Eta product of level 3 : (eta_1)^-12 (eta_3)^12'
259
+ """
260
+ return "Eta product of level %s : " % self.level() + self._short_repr()
261
+
262
+ def level(self) -> Integer:
263
+ r"""
264
+ Return the level of this eta product.
265
+
266
+ EXAMPLES::
267
+
268
+ sage: e = EtaProduct(3, {3:12, 1:-12})
269
+ sage: e.level()
270
+ 3
271
+ sage: EtaProduct(12, {6:6, 2:-6}).level() # not the lcm of the d's
272
+ 12
273
+ sage: EtaProduct(36, {6:6, 2:-6}).level() # not minimal
274
+ 36
275
+ """
276
+ return self._N
277
+
278
+ def q_expansion(self, n):
279
+ r"""
280
+ Return the `q`-expansion of ``self`` at the cusp at infinity.
281
+
282
+ INPUT:
283
+
284
+ - ``n`` -- integer; number of terms to calculate
285
+
286
+ OUTPUT:
287
+
288
+ A power series over `\ZZ` in the variable `q`, with a *relative*
289
+ precision of `1 + O(q^n)`.
290
+
291
+ ALGORITHM: Calculates eta to (n/m) terms, where m is the smallest
292
+ integer dividing self.level() such that self.r(m) != 0. Then
293
+ multiplies.
294
+
295
+ EXAMPLES::
296
+
297
+ sage: EtaProduct(36, {6:6, 2:-6}).q_expansion(10)
298
+ q + 6*q^3 + 27*q^5 + 92*q^7 + 279*q^9 + O(q^11)
299
+ sage: R.<q> = ZZ[[]]
300
+ sage: EtaProduct(2,{2:24,1:-24}).q_expansion(100) == delta_qexp(101)(q^2)/delta_qexp(101)(q)
301
+ True
302
+ """
303
+ R, q = PowerSeriesRing(ZZ, 'q').objgen()
304
+ pr = R.one().O(n)
305
+ if not self._rdict: # if self.is_one():
306
+ return pr
307
+ # self.r(d) should always be nonzero since we filtered out the 0s
308
+ eta_n = max(n // d for d in self._rdict) # if self.r(d)
309
+ eta = qexp_eta(R, eta_n)
310
+ for d in self._rdict:
311
+ rd = self._rdict[d]
312
+ if rd:
313
+ pr *= eta(q ** d) ** ZZ(rd)
314
+ return pr * q**(self._sumDR // 24)
315
+
316
+ def qexp(self, n):
317
+ """
318
+ Alias for ``self.q_expansion()``.
319
+
320
+ EXAMPLES::
321
+
322
+ sage: e = EtaProduct(36, {6:8, 3:-8})
323
+ sage: e.qexp(10)
324
+ q + 8*q^4 + 36*q^7 + O(q^10)
325
+ sage: e.qexp(30) == e.q_expansion(30)
326
+ True
327
+ """
328
+ return self.q_expansion(n)
329
+
330
+ def order_at_cusp(self, cusp: CuspFamily) -> Integer:
331
+ r"""
332
+ Return the order of vanishing of ``self`` at the given cusp.
333
+
334
+ INPUT:
335
+
336
+ - ``cusp`` -- a :class:`CuspFamily` object
337
+
338
+ OUTPUT: integer
339
+
340
+ EXAMPLES::
341
+
342
+ sage: e = EtaProduct(2, {2:24, 1:-24})
343
+ sage: e.order_at_cusp(CuspFamily(2, 1)) # cusp at infinity
344
+ 1
345
+ sage: e.order_at_cusp(CuspFamily(2, 2)) # cusp 0
346
+ -1
347
+ """
348
+ if not isinstance(cusp, CuspFamily):
349
+ raise TypeError("argument (=%s) should be a CuspFamily" % cusp)
350
+ if cusp.level() != self._N:
351
+ raise ValueError("cusp not on right curve")
352
+ sigma = sum(ell * self._rdict[ell] / cusp.width() *
353
+ (gcd(cusp.width(), self._N // ell))**2
354
+ for ell in self._rdict)
355
+ return sigma / ZZ(24) / gcd(cusp.width(), self._N // cusp.width())
356
+
357
+ def divisor(self):
358
+ r"""
359
+ Return the divisor of ``self``, as a formal sum of CuspFamily objects.
360
+
361
+ EXAMPLES::
362
+
363
+ sage: e = EtaProduct(12, {1:-336, 2:576, 3:696, 4:-216, 6:-576, 12:-144})
364
+ sage: e.divisor() # FormalSum seems to print things in a random order?
365
+ -131*(Inf) - 50*(c_{2}) + 11*(0) + 50*(c_{6}) + 169*(c_{4}) - 49*(c_{3})
366
+ sage: e = EtaProduct(2^8, {8:1,32:-1})
367
+ sage: e.divisor() # random
368
+ -(c_{2}) - (Inf) - (c_{8,2}) - (c_{8,3}) - (c_{8,4}) - (c_{4,2})
369
+ - (c_{8,1}) - (c_{4,1}) + (c_{32,4}) + (c_{32,3}) + (c_{64,1})
370
+ + (0) + (c_{32,2}) + (c_{64,2}) + (c_{128}) + (c_{32,1})
371
+ """
372
+ return FormalSum([(self.order_at_cusp(c), c)
373
+ for c in AllCusps(self.level())])
374
+
375
+ def degree(self) -> Integer:
376
+ r"""
377
+ Return the degree of ``self`` as a map `X_0(N) \to \mathbb{P}^1`.
378
+
379
+ This is the sum of all the positive coefficients in the divisor
380
+ of ``self``.
381
+
382
+ EXAMPLES::
383
+
384
+ sage: e = EtaProduct(12, {1:-336, 2:576, 3:696, 4:-216, 6:-576, 12:-144})
385
+ sage: e.degree()
386
+ 230
387
+ """
388
+ return sum(self.order_at_cusp(c)
389
+ for c in AllCusps(self._N)
390
+ if self.order_at_cusp(c) > 0)
391
+
392
+ def r(self, d) -> Integer:
393
+ r"""
394
+ Return the exponent `r_d` of `\eta(q^d)` in ``self``.
395
+
396
+ EXAMPLES::
397
+
398
+ sage: e = EtaProduct(12, {2:24, 3:-24})
399
+ sage: e.r(3)
400
+ -24
401
+ sage: e.r(4)
402
+ 0
403
+ """
404
+ return self._rdict.get(d, 0)
405
+
406
+
407
+ class EtaGroup_class(UniqueRepresentation, Parent):
408
+ r"""
409
+ The group of eta products of a given level under multiplication.
410
+
411
+ TESTS::
412
+
413
+ sage: TestSuite(EtaGroup(12)).run()
414
+
415
+ sage: EtaGroup(12) == EtaGroup(12)
416
+ True
417
+ sage: EtaGroup(12) == EtaGroup(13)
418
+ False
419
+
420
+ sage: EtaGroup(12) != EtaGroup(12)
421
+ False
422
+ sage: EtaGroup(12) != EtaGroup(13)
423
+ True
424
+ """
425
+
426
+ def __init__(self, level):
427
+ r"""
428
+ Create the group of eta products of a given level, which must be a
429
+ positive integer.
430
+
431
+ EXAMPLES::
432
+
433
+ sage: G = EtaGroup(12); G # indirect doctest
434
+ Group of eta products on X_0(12)
435
+ sage: TestSuite(G).run()
436
+ """
437
+ try:
438
+ level = ZZ(level)
439
+ except TypeError:
440
+ raise TypeError("Level (=%s) must be a positive integer" % level)
441
+ if level < 1:
442
+ raise ValueError("Level (=%s) must be a positive integer" % level)
443
+ self._N = level
444
+ Parent.__init__(self, category=Groups().Commutative())
445
+
446
+ def _repr_(self) -> str:
447
+ r"""
448
+ String representation of ``self``.
449
+
450
+ EXAMPLES::
451
+
452
+ sage: EtaGroup(12)._repr_()
453
+ 'Group of eta products on X_0(12)'
454
+ """
455
+ return "Group of eta products on X_0(%s)" % self.level()
456
+
457
+ def one(self) -> EtaGroupElement:
458
+ r"""
459
+ Return the identity element of ``self``.
460
+
461
+ EXAMPLES::
462
+
463
+ sage: EtaGroup(12).one()
464
+ Eta product of level 12 : 1
465
+ """
466
+ return self({})
467
+
468
+ def _element_constructor_(self, dic):
469
+ r"""
470
+ Create an element of this group (an eta product object) with
471
+ exponents from the given dictionary.
472
+
473
+ INPUT:
474
+
475
+ - ``dic`` -- dictionary
476
+
477
+ See the docstring of :func:`EtaProduct` for how ``dic`` is used.
478
+
479
+ EXAMPLES::
480
+
481
+ sage: EtaGroup(2).__call__({1:24, 2:-24})
482
+ Eta product of level 2 : (eta_1)^24 (eta_2)^-24
483
+ """
484
+ return self.element_class(self, dic)
485
+
486
+ def level(self) -> Integer:
487
+ r"""
488
+ Return the level of ``self``.
489
+
490
+ EXAMPLES::
491
+
492
+ sage: EtaGroup(10).level()
493
+ 10
494
+ """
495
+ return self._N
496
+
497
+ def basis(self, reduce=True) -> list:
498
+ r"""
499
+ Produce a basis for the free abelian group of eta-products of level
500
+ N (under multiplication), attempting to find basis vectors of the
501
+ smallest possible degree.
502
+
503
+ INPUT:
504
+
505
+ - ``reduce`` -- boolean (default: ``True``); whether or not to apply
506
+ LLL-reduction to the calculated basis
507
+
508
+ EXAMPLES::
509
+
510
+ sage: # needs fpylll
511
+ sage: EtaGroup(5).basis()
512
+ [Eta product of level 5 : (eta_1)^6 (eta_5)^-6]
513
+ sage: EtaGroup(12).basis()
514
+ [Eta product of level 12 : (eta_1)^-3 (eta_2)^2 (eta_3)^1 (eta_4)^-1 (eta_6)^-2 (eta_12)^3,
515
+ Eta product of level 12 : (eta_1)^-4 (eta_2)^2 (eta_3)^4 (eta_6)^-2,
516
+ Eta product of level 12 : (eta_1)^6 (eta_2)^-9 (eta_3)^-2 (eta_4)^3 (eta_6)^3 (eta_12)^-1,
517
+ Eta product of level 12 : (eta_1)^-1 (eta_2)^3 (eta_3)^3 (eta_4)^-2 (eta_6)^-9 (eta_12)^6,
518
+ Eta product of level 12 : (eta_1)^3 (eta_3)^-1 (eta_4)^-3 (eta_12)^1]
519
+ sage: EtaGroup(12).basis(reduce=False) # much bigger coefficients
520
+ [Eta product of level 12 : (eta_1)^384 (eta_2)^-576 (eta_3)^-696 (eta_4)^216 (eta_6)^576 (eta_12)^96,
521
+ Eta product of level 12 : (eta_2)^24 (eta_12)^-24,
522
+ Eta product of level 12 : (eta_1)^-40 (eta_2)^116 (eta_3)^96 (eta_4)^-30 (eta_6)^-80 (eta_12)^-62,
523
+ Eta product of level 12 : (eta_1)^-4 (eta_2)^-33 (eta_3)^-4 (eta_4)^1 (eta_6)^3 (eta_12)^37,
524
+ Eta product of level 12 : (eta_1)^15 (eta_2)^-24 (eta_3)^-29 (eta_4)^9 (eta_6)^24 (eta_12)^5]
525
+
526
+ ALGORITHM: An eta product of level `N` is uniquely
527
+ determined by the integers `r_d` for `d | N` with
528
+ `d < N`, since `\sum_{d | N} r_d = 0`. The valid
529
+ `r_d` are those that satisfy two congruences modulo 24,
530
+ and one congruence modulo 2 for every prime divisor of N. We beef
531
+ up the congruences modulo 2 to congruences modulo 24 by multiplying
532
+ by 12. To calculate the kernel of the ensuing map
533
+ `\ZZ^m \to (\ZZ/24\ZZ)^n`
534
+ we lift it arbitrarily to an integer matrix and calculate its Smith
535
+ normal form. This gives a basis for the lattice.
536
+
537
+ This lattice typically contains "large" elements, so by default we
538
+ pass it to the reduce_basis() function which performs
539
+ LLL-reduction to give a more manageable basis.
540
+ """
541
+ N = self.level()
542
+ divs = divisors(N)[:-1]
543
+ s = len(divs)
544
+ primedivs = prime_divisors(N)
545
+
546
+ rows = []
547
+ for di in divs:
548
+ # generate a row of relation matrix
549
+ row = [Mod(di, 24) - Mod(N, 24), Mod(N // di, 24) - Mod(1, 24)]
550
+ row.extend(Mod(12 * (N // di).valuation(p), 24)
551
+ for p in primedivs)
552
+ rows.append(row)
553
+
554
+ M = matrix(IntegerModRing(24), rows)
555
+ Mlift = M.change_ring(ZZ)
556
+ # now we compute elementary factors of Mlift
557
+ S, U, V = Mlift.smith_form()
558
+ good_vects = []
559
+ for i in range(U.nrows()):
560
+ vect = U.row(i)
561
+ nf = (i < S.ncols() and S[i, i]) or 0 # ?
562
+ good_vects.append((vect * 24 / gcd(nf, 24)).list())
563
+ for v in good_vects:
564
+ v.append(-sum(list(v)))
565
+ dicts: list[dict] = []
566
+ for v in good_vects:
567
+ dicts.append({})
568
+ for i in range(s):
569
+ dicts[-1][divs[i]] = v[i]
570
+ dicts[-1][N] = v[-1]
571
+ if reduce:
572
+ return self.reduce_basis([self(d) for d in dicts])
573
+ else:
574
+ return [self(d) for d in dicts]
575
+
576
+ def reduce_basis(self, long_etas) -> list:
577
+ r"""
578
+ Produce a more manageable basis via LLL-reduction.
579
+
580
+ INPUT:
581
+
582
+ - ``long_etas`` -- a list of EtaGroupElement objects (which
583
+ should all be of the same level)
584
+
585
+ OUTPUT:
586
+
587
+ - a new list of EtaGroupElement objects having
588
+ hopefully smaller norm
589
+
590
+ ALGORITHM: We define the norm of an eta-product to be the
591
+ `L^2` norm of its divisor (as an element of the free
592
+ `\ZZ`-module with the cusps as basis and the
593
+ standard inner product). Applying LLL-reduction to this gives a
594
+ basis of hopefully more tractable elements. Of course we'd like to
595
+ use the `L^1` norm as this is just twice the degree, which
596
+ is a much more natural invariant, but `L^2` norm is easier
597
+ to work with!
598
+
599
+ EXAMPLES::
600
+
601
+ sage: # needs fpylll
602
+ sage: EtaGroup(4).reduce_basis([ EtaProduct(4, {1:8,2:24,4:-32}), EtaProduct(4, {1:8, 4:-8})])
603
+ [Eta product of level 4 : (eta_1)^8 (eta_4)^-8,
604
+ Eta product of level 4 : (eta_1)^-8 (eta_2)^24 (eta_4)^-16]
605
+ """
606
+ N = self.level()
607
+ cusps = AllCusps(N)
608
+ r = matrix(ZZ, [[et.order_at_cusp(c) for c in cusps] for et in long_etas])
609
+ V = FreeModule(ZZ, r.ncols())
610
+ A = V.submodule_with_basis([V(rw) for rw in r.rows()])
611
+ rred = r.LLL()
612
+ short_etas = []
613
+ for shortvect in rred.rows():
614
+ bv = A.coordinates(shortvect)
615
+ dic = {d: sum(bv[i] * long_etas[i].r(d)
616
+ for i in range(r.nrows()))
617
+ for d in divisors(N)}
618
+ short_etas.append(self(dic))
619
+ return short_etas
620
+
621
+ Element = EtaGroupElement
622
+
623
+
624
+ def EtaProduct(level, dic) -> EtaGroupElement:
625
+ r"""
626
+ Create an :class:`EtaGroupElement` object representing the function
627
+ `\prod_{d | N} \eta(q^d)^{r_d}`.
628
+
629
+ This checks the criteria of Ligozat to ensure that this product
630
+ really is the `q`-expansion of a meromorphic function on `X_0(N)`.
631
+
632
+ INPUT:
633
+
634
+ - ``level`` -- integer; the N such that this eta
635
+ product is a function on `X_0(N)`
636
+
637
+ - ``dic`` -- a dictionary indexed by divisors of N such that the
638
+ coefficient of `\eta(q^d)` is r[d]. Only nonzero coefficients need be
639
+ specified. If Ligozat's criteria are not satisfied, a :exc:`ValueError`
640
+ will be raised.
641
+
642
+ OUTPUT:
643
+
644
+ An EtaGroupElement object, whose parent is the EtaGroup of level N and
645
+ whose coefficients are the given dictionary.
646
+
647
+ .. NOTE::
648
+
649
+ The dictionary ``dic`` does not uniquely specify N. It is
650
+ possible for two EtaGroupElements with different `N`'s to
651
+ be created with the same dictionary, and these represent different
652
+ objects (although they will have the same `q`-expansion at
653
+ the cusp `\infty`).
654
+
655
+ EXAMPLES::
656
+
657
+ sage: EtaProduct(3, {3:12, 1:-12})
658
+ Eta product of level 3 : (eta_1)^-12 (eta_3)^12
659
+ sage: EtaProduct(3, {3:6, 1:-6})
660
+ Traceback (most recent call last):
661
+ ...
662
+ ValueError: sum d r_d (=12) is not 0 mod 24
663
+ sage: EtaProduct(3, {4:6, 1:-6})
664
+ Traceback (most recent call last):
665
+ ...
666
+ ValueError: 4 does not divide 3
667
+ """
668
+ return EtaGroup(level)(dic)
669
+
670
+
671
+ def num_cusps_of_width(N, d) -> Integer:
672
+ r"""
673
+ Return the number of cusps on `X_0(N)` of width ``d``.
674
+
675
+ INPUT:
676
+
677
+ - ``N`` -- integer; the level
678
+
679
+ - ``d`` -- integer; an integer dividing `N`, the cusp width
680
+
681
+ EXAMPLES::
682
+
683
+ sage: from sage.modular.etaproducts import num_cusps_of_width
684
+ sage: [num_cusps_of_width(18,d) for d in divisors(18)]
685
+ [1, 1, 2, 2, 1, 1]
686
+ sage: num_cusps_of_width(4,8)
687
+ Traceback (most recent call last):
688
+ ...
689
+ ValueError: N and d must be positive integers with d|N
690
+ """
691
+ N = ZZ(N)
692
+ d = ZZ(d)
693
+ if N <= 0 or d <= 0 or N % d:
694
+ raise ValueError("N and d must be positive integers with d|N")
695
+
696
+ return euler_phi(d.gcd(N // d))
697
+
698
+
699
+ def AllCusps(N) -> list:
700
+ r"""
701
+ Return a list of CuspFamily objects corresponding to the cusps of
702
+ `X_0(N)`.
703
+
704
+ INPUT:
705
+
706
+ - ``N`` -- integer; the level
707
+
708
+ EXAMPLES::
709
+
710
+ sage: AllCusps(18)
711
+ [(Inf), (c_{2}), (c_{3,1}), (c_{3,2}), (c_{6,1}), (c_{6,2}), (c_{9}), (0)]
712
+ sage: AllCusps(0)
713
+ Traceback (most recent call last):
714
+ ...
715
+ ValueError: N must be positive
716
+ """
717
+ N = ZZ(N)
718
+ if N <= 0:
719
+ raise ValueError("N must be positive")
720
+
721
+ c = []
722
+ for d in divisors(N):
723
+ n = num_cusps_of_width(N, d)
724
+ if n == 1:
725
+ c.append(CuspFamily(N, d))
726
+ elif n > 1:
727
+ c.extend(CuspFamily(N, d, label=str(i + 1))
728
+ for i in range(n))
729
+ return c
730
+
731
+
732
+ @richcmp_method
733
+ class CuspFamily(SageObject):
734
+ r"""
735
+ A family of elliptic curves parametrising a region of `X_0(N)`.
736
+ """
737
+ def __init__(self, N, width, label=None):
738
+ r"""
739
+ Create the cusp of width d on X_0(N) corresponding to the family
740
+ of Tate curves `(\CC_p/q^d, \langle \zeta q\rangle)`.
741
+
742
+ Here `\zeta` is a primitive root of unity of order `r` with
743
+ `\mathrm{lcm}(r,d) = N`. The cusp does not store zeta, so we
744
+ store an arbitrary label instead.
745
+
746
+ EXAMPLES::
747
+
748
+ sage: CuspFamily(8, 4)
749
+ (c_{4})
750
+ sage: CuspFamily(16, 4, '1')
751
+ (c_{4,1})
752
+ """
753
+ N = ZZ(N)
754
+ if N <= 0:
755
+ raise ValueError("N must be positive")
756
+ self._N = N
757
+ self._width = width
758
+ if N % width:
759
+ raise ValueError("bad width")
760
+ if num_cusps_of_width(N, width) > 1 and label is None:
761
+ raise ValueError("there are %s > 1 cusps of width %s on X_0(%s): specify a label" % (num_cusps_of_width(N, width), width, N))
762
+ if num_cusps_of_width(N, width) == 1 and label is not None:
763
+ raise ValueError("there is only one cusp of width %s on X_0(%s): no need to specify a label" % (width, N))
764
+ self.label = label
765
+
766
+ @property
767
+ def __tuple(self):
768
+ """
769
+ The defining data of this ``CuspFamily`` as tuple, used for
770
+ comparisons.
771
+ """
772
+ return (self._N, self._width, self.label)
773
+
774
+ def __richcmp__(self, other, op) -> bool:
775
+ """
776
+ EXAMPLES::
777
+
778
+ sage: a = CuspFamily(16, 4, "1"); a
779
+ (c_{4,1})
780
+ sage: b = CuspFamily(16, 4, "2"); b
781
+ (c_{4,2})
782
+ sage: c = CuspFamily(8, 8); c
783
+ (0)
784
+ sage: a == a
785
+ True
786
+ sage: a == b
787
+ False
788
+ sage: a != b
789
+ True
790
+ sage: a == c
791
+ False
792
+ sage: a < c
793
+ False
794
+ sage: a > c
795
+ True
796
+ sage: a != "foo"
797
+ True
798
+ """
799
+ if not isinstance(other, CuspFamily):
800
+ return NotImplemented
801
+ return richcmp(self.__tuple, other.__tuple, op)
802
+
803
+ def __hash__(self):
804
+ """
805
+ EXAMPLES::
806
+
807
+ sage: hash(CuspFamily(10, 1)) # random
808
+ -4769758480201659164
809
+ """
810
+ return hash(self.__tuple)
811
+
812
+ def width(self) -> Integer:
813
+ r"""
814
+ Return the width of this cusp.
815
+
816
+ EXAMPLES::
817
+
818
+ sage: e = CuspFamily(10, 1)
819
+ sage: e.width()
820
+ 1
821
+ """
822
+ return self._width
823
+
824
+ def level(self) -> Integer:
825
+ r"""
826
+ Return the level of this cusp.
827
+
828
+ EXAMPLES::
829
+
830
+ sage: e = CuspFamily(10, 1)
831
+ sage: e.level()
832
+ 10
833
+ """
834
+ return self._N
835
+
836
+ def sage_cusp(self):
837
+ r"""
838
+ Return the corresponding element of `\mathbb{P}^1(\QQ)`.
839
+
840
+ EXAMPLES::
841
+
842
+ sage: CuspFamily(10, 1).sage_cusp() # not implemented
843
+ Infinity
844
+ """
845
+ raise NotImplementedError
846
+
847
+ def _repr_(self) -> str:
848
+ r"""
849
+ Return a string representation of ``self``.
850
+
851
+ EXAMPLES::
852
+
853
+ sage: CuspFamily(16, 4, "1")._repr_()
854
+ '(c_{4,1})'
855
+ """
856
+ if self.width() == 1:
857
+ return "(Inf)"
858
+ elif self.width() == self.level():
859
+ return "(0)"
860
+ return "(c_{%s%s})" % (self.width(), ((self.label and ("," + self.label)) or ""))
861
+
862
+
863
+ def qexp_eta(ps_ring, prec):
864
+ r"""
865
+ Return the `q`-expansion of `\eta(q) / q^{1/24}`.
866
+
867
+ Here `\eta(q)` is Dedekind's function
868
+
869
+ .. MATH::
870
+
871
+ \eta(q) = q^{1/24}\prod_{n=1}^\infty (1-q^n).
872
+
873
+ The result is an element of ``ps_ring``, with precision ``prec``.
874
+
875
+ INPUT:
876
+
877
+ - ``ps_ring`` -- PowerSeriesRing; a power series ring
878
+
879
+ - ``prec`` -- integer; the number of terms to compute
880
+
881
+ OUTPUT: an element of ``ps_ring`` which is the `q`-expansion of
882
+ `\eta(q)/q^{1/24}` truncated to prec terms.
883
+
884
+ ALGORITHM: We use the Euler identity
885
+
886
+ .. MATH::
887
+
888
+ \eta(q) = q^{1/24}( 1 + \sum_{n \ge 1} (-1)^n (q^{n(3n+1)/2} + q^{n(3n-1)/2})
889
+
890
+ to compute the expansion.
891
+
892
+ EXAMPLES::
893
+
894
+ sage: from sage.modular.etaproducts import qexp_eta
895
+ sage: qexp_eta(ZZ[['q']], 100)
896
+ 1 - q - q^2 + q^5 + q^7 - q^12 - q^15 + q^22 + q^26 - q^35 - q^40 + q^51 + q^57 - q^70 - q^77 + q^92 + O(q^100)
897
+ """
898
+ prec = Integer(prec)
899
+ if not prec > 0:
900
+ raise ValueError("prec must be a positive integer")
901
+ v = [Integer(0)] * prec
902
+ pm = Integer(1)
903
+ v[0] = pm
904
+ try:
905
+ n = 1
906
+ while True:
907
+ pm = -pm
908
+ v[n * (3 * n - 1) // 2] = pm
909
+ v[n * (3 * n + 1) // 2] = pm
910
+ n += 1
911
+ except IndexError:
912
+ pass
913
+ return ps_ring(v, prec=prec)
914
+
915
+
916
+ def eta_poly_relations(eta_elements, degree, labels=['x1', 'x2'],
917
+ verbose=False):
918
+ r"""
919
+ Find polynomial relations between eta products.
920
+
921
+ INPUT:
922
+
923
+ - ``eta_elements`` -- list; a list of EtaGroupElement objects.
924
+ Not implemented unless this list has precisely two elements. degree
925
+
926
+ - ``degree`` -- integer; the maximal degree of polynomial to look for
927
+
928
+ - ``labels`` -- list of strings; labels to use for the polynomial returned
929
+
930
+ - ``verbose`` -- boolean (default: ``False``); if ``True``, prints information as
931
+ it goes
932
+
933
+ OUTPUT: list of polynomials which is a Groebner basis for the
934
+ part of the ideal of relations between eta_elements which is
935
+ generated by elements up to the given degree; or None, if no
936
+ relations were found.
937
+
938
+ ALGORITHM: An expression of the form
939
+ `\sum_{0 \le i,j \le d} a_{ij} x^i y^j` is zero if and
940
+ only if it vanishes at the cusp infinity to degree at least
941
+ `v = d(deg(x) + deg(y))`. For all terms up to `q^v`
942
+ in the `q`-expansion of this expression to be zero is a
943
+ system of `v + k` linear equations in `d^2`
944
+ coefficients, where `k` is the number of nonzero negative
945
+ coefficients that can appear.
946
+
947
+ Solving these equations and calculating a basis for the solution
948
+ space gives us a set of polynomial relations, but this is generally
949
+ far from a minimal generating set for the ideal, so we calculate a
950
+ Groebner basis.
951
+
952
+ As a test, we calculate five extra terms of `q`-expansion
953
+ and check that this doesn't change the answer.
954
+
955
+ EXAMPLES::
956
+
957
+ sage: from sage.modular.etaproducts import eta_poly_relations
958
+ sage: t = EtaProduct(26, {2:2,13:2,26:-2,1:-2})
959
+ sage: u = EtaProduct(26, {2:4,13:2,26:-4,1:-2})
960
+ sage: eta_poly_relations([t, u], 3)
961
+ sage: eta_poly_relations([t, u], 4)
962
+ [x1^3*x2 - 13*x1^3 - 4*x1^2*x2 - 4*x1*x2 - x2^2 + x2]
963
+
964
+ Use ``verbose=True`` to see the details of the computation::
965
+
966
+ sage: eta_poly_relations([t, u], 3, verbose=True)
967
+ Trying to find a relation of degree 3
968
+ Lowest order of a term at infinity = -12
969
+ Highest possible degree of a term = 15
970
+ Trying all coefficients from q^-12 to q^15 inclusive
971
+ No polynomial relation of order 3 valid for 28 terms
972
+ Check:
973
+ Trying all coefficients from q^-12 to q^20 inclusive
974
+ No polynomial relation of order 3 valid for 33 terms
975
+
976
+ ::
977
+
978
+ sage: eta_poly_relations([t, u], 4, verbose=True)
979
+ Trying to find a relation of degree 4
980
+ Lowest order of a term at infinity = -16
981
+ Highest possible degree of a term = 20
982
+ Trying all coefficients from q^-16 to q^20 inclusive
983
+ Check:
984
+ Trying all coefficients from q^-16 to q^25 inclusive
985
+ [x1^3*x2 - 13*x1^3 - 4*x1^2*x2 - 4*x1*x2 - x2^2 + x2]
986
+ """
987
+ if len(eta_elements) > 2:
988
+ raise NotImplementedError("do not know how to find relations between more than two elements")
989
+
990
+ eta1, eta2 = eta_elements
991
+
992
+ if verbose:
993
+ print("Trying to find a relation of degree %s" % degree)
994
+ inf = CuspFamily(eta1.level(), 1)
995
+ loterm = -(min(0, eta1.order_at_cusp(inf)) + min(0, eta2.order_at_cusp(inf))) * degree
996
+ if verbose:
997
+ print("Lowest order of a term at infinity = %s" % -loterm)
998
+
999
+ maxdeg = sum([eta1.degree(), eta2.degree()]) * degree
1000
+ if verbose:
1001
+ print("Highest possible degree of a term = %s" % maxdeg)
1002
+ m = loterm + maxdeg + 1
1003
+ oldgrob = _eta_relations_helper(eta1, eta2, degree, m, labels, verbose)
1004
+ if verbose:
1005
+ print("Check:")
1006
+ newgrob = _eta_relations_helper(eta1, eta2, degree, m + 5, labels, verbose)
1007
+ if oldgrob != newgrob:
1008
+ raise ArithmeticError("Check: answers different!")
1009
+ return newgrob
1010
+
1011
+
1012
+ def _eta_relations_helper(eta1, eta2, degree, qexp_terms, labels, verbose):
1013
+ r"""
1014
+ Helper function used by eta_poly_relations. Finds a basis for the
1015
+ space of linear relations between the first qexp_terms of the
1016
+ `q`-expansions of the monomials
1017
+ `\eta_1^i * \eta_2^j` for `0 \le i,j < degree`,
1018
+ and calculates a Groebner basis for the ideal generated by these
1019
+ relations.
1020
+
1021
+ Liable to return meaningless results if qexp_terms isn't at least
1022
+ `1 + d*(m_1,m_2)` where
1023
+
1024
+ .. MATH::
1025
+
1026
+ m_i = min(0, {\text degree of the pole of $\eta_i$ at $\infty$})
1027
+
1028
+ as then 1 will be in the ideal.
1029
+
1030
+ EXAMPLES::
1031
+
1032
+ sage: # needs fpylll
1033
+ sage: from sage.modular.etaproducts import _eta_relations_helper
1034
+ sage: r,s = EtaGroup(4).basis()
1035
+ sage: _eta_relations_helper(r,s,4,100,['a','b'],False)
1036
+ [a + 1/16*b - 1/16]
1037
+ sage: _eta_relations_helper(EtaProduct(26, {2:2,13:2,26:-2,1:-2}),EtaProduct(26, {2:4,13:2,26:-4,1:-2}),3,12,['a','b'],False) # not enough terms, will return rubbish
1038
+ [1]
1039
+ """
1040
+ indices = [(i, j) for j in range(degree) for i in range(degree)]
1041
+ inf = CuspFamily(eta1.level(), 1)
1042
+
1043
+ pole_at_infinity = -(min(0, eta1.order_at_cusp(inf)) + min(0, eta2.order_at_cusp(inf))) * degree
1044
+ if verbose:
1045
+ print("Trying all coefficients from q^%s to q^%s inclusive" % (-pole_at_infinity, -pole_at_infinity + qexp_terms - 1))
1046
+
1047
+ rows: list[list] = [[] for _ in range(qexp_terms)]
1048
+ for i in indices:
1049
+ func = (eta1**i[0] * eta2**i[1]).qexp(qexp_terms)
1050
+ for j in range(qexp_terms):
1051
+ rows[j].append(func[j - pole_at_infinity])
1052
+ M = matrix(rows)
1053
+ V = M.right_kernel()
1054
+ if V.dimension() == 0:
1055
+ if verbose:
1056
+ print("No polynomial relation of order %s valid for %s terms" % (degree, qexp_terms))
1057
+ return None
1058
+ if V.dimension() >= 1:
1059
+ R = PolynomialRing(QQ, 2, labels)
1060
+ x, y = R.gens()
1061
+ relations = [sum([c[v] * x**indices[v][0] * y**indices[v][1]
1062
+ for v in range(len(indices))])
1063
+ for c in V.basis()]
1064
+ id = R.ideal(relations)
1065
+ return id.groebner_basis()