passagemath-schemes 10.6.40__cp314-cp314-macosx_13_0_arm64.whl

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

Potentially problematic release.


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

Files changed (314) hide show
  1. passagemath_schemes/.dylibs/libflint.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.40.dist-info/METADATA +204 -0
  7. passagemath_schemes-10.6.40.dist-info/METADATA.bak +205 -0
  8. passagemath_schemes-10.6.40.dist-info/RECORD +314 -0
  9. passagemath_schemes-10.6.40.dist-info/WHEEL +6 -0
  10. passagemath_schemes-10.6.40.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-314-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-314-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-314-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-314-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-314-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-314-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-314-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-314-darwin.so +0 -0
  148. sage/modular/modsym/manin_symbol.pxd +5 -0
  149. sage/modular/modsym/manin_symbol.pyx +497 -0
  150. sage/modular/modsym/manin_symbol_list.py +1295 -0
  151. sage/modular/modsym/modsym.py +400 -0
  152. sage/modular/modsym/modular_symbols.py +384 -0
  153. sage/modular/modsym/p1list.cpython-314-darwin.so +0 -0
  154. sage/modular/modsym/p1list.pxd +29 -0
  155. sage/modular/modsym/p1list.pyx +1372 -0
  156. sage/modular/modsym/p1list_nf.py +1241 -0
  157. sage/modular/modsym/relation_matrix.py +591 -0
  158. sage/modular/modsym/relation_matrix_pyx.cpython-314-darwin.so +0 -0
  159. sage/modular/modsym/relation_matrix_pyx.pyx +108 -0
  160. sage/modular/modsym/space.py +2468 -0
  161. sage/modular/modsym/subspace.py +455 -0
  162. sage/modular/modsym/tests.py +375 -0
  163. sage/modular/multiple_zeta.py +2632 -0
  164. sage/modular/multiple_zeta_F_algebra.py +786 -0
  165. sage/modular/overconvergent/all.py +6 -0
  166. sage/modular/overconvergent/genus0.py +1878 -0
  167. sage/modular/overconvergent/hecke_series.py +1187 -0
  168. sage/modular/overconvergent/weightspace.py +778 -0
  169. sage/modular/pollack_stevens/all.py +4 -0
  170. sage/modular/pollack_stevens/distributions.py +874 -0
  171. sage/modular/pollack_stevens/fund_domain.py +1572 -0
  172. sage/modular/pollack_stevens/manin_map.py +859 -0
  173. sage/modular/pollack_stevens/modsym.py +1593 -0
  174. sage/modular/pollack_stevens/padic_lseries.py +417 -0
  175. sage/modular/pollack_stevens/sigma0.py +534 -0
  176. sage/modular/pollack_stevens/space.py +1076 -0
  177. sage/modular/quasimodform/all.py +3 -0
  178. sage/modular/quasimodform/element.py +845 -0
  179. sage/modular/quasimodform/ring.py +828 -0
  180. sage/modular/quatalg/all.py +3 -0
  181. sage/modular/quatalg/brandt.py +1642 -0
  182. sage/modular/ssmod/all.py +8 -0
  183. sage/modular/ssmod/ssmod.py +827 -0
  184. sage/rings/all__sagemath_schemes.py +1 -0
  185. sage/rings/polynomial/all__sagemath_schemes.py +1 -0
  186. sage/rings/polynomial/binary_form_reduce.py +585 -0
  187. sage/schemes/all.py +41 -0
  188. sage/schemes/berkovich/all.py +6 -0
  189. sage/schemes/berkovich/berkovich_cp_element.py +2582 -0
  190. sage/schemes/berkovich/berkovich_space.py +748 -0
  191. sage/schemes/curves/affine_curve.py +2928 -0
  192. sage/schemes/curves/all.py +33 -0
  193. sage/schemes/curves/closed_point.py +434 -0
  194. sage/schemes/curves/constructor.py +381 -0
  195. sage/schemes/curves/curve.py +542 -0
  196. sage/schemes/curves/plane_curve_arrangement.py +1283 -0
  197. sage/schemes/curves/point.py +463 -0
  198. sage/schemes/curves/projective_curve.py +3026 -0
  199. sage/schemes/curves/zariski_vankampen.py +1932 -0
  200. sage/schemes/cyclic_covers/all.py +2 -0
  201. sage/schemes/cyclic_covers/charpoly_frobenius.py +320 -0
  202. sage/schemes/cyclic_covers/constructor.py +137 -0
  203. sage/schemes/cyclic_covers/cycliccover_finite_field.py +1309 -0
  204. sage/schemes/cyclic_covers/cycliccover_generic.py +310 -0
  205. sage/schemes/elliptic_curves/BSD.py +1036 -0
  206. sage/schemes/elliptic_curves/Qcurves.py +592 -0
  207. sage/schemes/elliptic_curves/addition_formulas_ring.py +94 -0
  208. sage/schemes/elliptic_curves/all.py +49 -0
  209. sage/schemes/elliptic_curves/cardinality.py +609 -0
  210. sage/schemes/elliptic_curves/cm.py +1102 -0
  211. sage/schemes/elliptic_curves/constructor.py +1552 -0
  212. sage/schemes/elliptic_curves/ec_database.py +175 -0
  213. sage/schemes/elliptic_curves/ell_curve_isogeny.py +3972 -0
  214. sage/schemes/elliptic_curves/ell_egros.py +459 -0
  215. sage/schemes/elliptic_curves/ell_field.py +2836 -0
  216. sage/schemes/elliptic_curves/ell_finite_field.py +3359 -0
  217. sage/schemes/elliptic_curves/ell_generic.py +3760 -0
  218. sage/schemes/elliptic_curves/ell_local_data.py +1207 -0
  219. sage/schemes/elliptic_curves/ell_modular_symbols.py +775 -0
  220. sage/schemes/elliptic_curves/ell_number_field.py +4220 -0
  221. sage/schemes/elliptic_curves/ell_padic_field.py +107 -0
  222. sage/schemes/elliptic_curves/ell_point.py +4787 -0
  223. sage/schemes/elliptic_curves/ell_rational_field.py +7368 -0
  224. sage/schemes/elliptic_curves/ell_tate_curve.py +671 -0
  225. sage/schemes/elliptic_curves/ell_torsion.py +436 -0
  226. sage/schemes/elliptic_curves/ell_wp.py +352 -0
  227. sage/schemes/elliptic_curves/formal_group.py +760 -0
  228. sage/schemes/elliptic_curves/gal_reps.py +1459 -0
  229. sage/schemes/elliptic_curves/gal_reps_number_field.py +1669 -0
  230. sage/schemes/elliptic_curves/gp_simon.py +152 -0
  231. sage/schemes/elliptic_curves/heegner.py +7335 -0
  232. sage/schemes/elliptic_curves/height.py +2109 -0
  233. sage/schemes/elliptic_curves/hom.py +1406 -0
  234. sage/schemes/elliptic_curves/hom_composite.py +934 -0
  235. sage/schemes/elliptic_curves/hom_frobenius.py +522 -0
  236. sage/schemes/elliptic_curves/hom_scalar.py +531 -0
  237. sage/schemes/elliptic_curves/hom_sum.py +682 -0
  238. sage/schemes/elliptic_curves/hom_velusqrt.py +1290 -0
  239. sage/schemes/elliptic_curves/homset.py +271 -0
  240. sage/schemes/elliptic_curves/isogeny_class.py +1521 -0
  241. sage/schemes/elliptic_curves/isogeny_small_degree.py +2797 -0
  242. sage/schemes/elliptic_curves/jacobian.py +237 -0
  243. sage/schemes/elliptic_curves/kodaira_symbol.py +344 -0
  244. sage/schemes/elliptic_curves/kraus.py +1014 -0
  245. sage/schemes/elliptic_curves/lseries_ell.py +943 -0
  246. sage/schemes/elliptic_curves/mod5family.py +105 -0
  247. sage/schemes/elliptic_curves/mod_poly.py +197 -0
  248. sage/schemes/elliptic_curves/mod_sym_num.cpython-314-darwin.so +0 -0
  249. sage/schemes/elliptic_curves/mod_sym_num.pyx +3796 -0
  250. sage/schemes/elliptic_curves/modular_parametrization.py +305 -0
  251. sage/schemes/elliptic_curves/padic_lseries.py +1793 -0
  252. sage/schemes/elliptic_curves/padics.py +1816 -0
  253. sage/schemes/elliptic_curves/period_lattice.py +2234 -0
  254. sage/schemes/elliptic_curves/period_lattice_region.cpython-314-darwin.so +0 -0
  255. sage/schemes/elliptic_curves/period_lattice_region.pyx +722 -0
  256. sage/schemes/elliptic_curves/saturation.py +715 -0
  257. sage/schemes/elliptic_curves/sha_tate.py +1158 -0
  258. sage/schemes/elliptic_curves/weierstrass_morphism.py +1117 -0
  259. sage/schemes/elliptic_curves/weierstrass_transform.py +200 -0
  260. sage/schemes/hyperelliptic_curves/all.py +6 -0
  261. sage/schemes/hyperelliptic_curves/constructor.py +291 -0
  262. sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py +1914 -0
  263. sage/schemes/hyperelliptic_curves/hyperelliptic_g2.py +192 -0
  264. sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py +954 -0
  265. sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py +1332 -0
  266. sage/schemes/hyperelliptic_curves/hyperelliptic_rational_field.py +84 -0
  267. sage/schemes/hyperelliptic_curves/invariants.py +410 -0
  268. sage/schemes/hyperelliptic_curves/jacobian_endomorphism_utils.py +315 -0
  269. sage/schemes/hyperelliptic_curves/jacobian_g2.py +32 -0
  270. sage/schemes/hyperelliptic_curves/jacobian_generic.py +419 -0
  271. sage/schemes/hyperelliptic_curves/jacobian_homset.py +186 -0
  272. sage/schemes/hyperelliptic_curves/jacobian_morphism.py +875 -0
  273. sage/schemes/hyperelliptic_curves/kummer_surface.py +99 -0
  274. sage/schemes/hyperelliptic_curves/mestre.py +302 -0
  275. sage/schemes/hyperelliptic_curves/monsky_washnitzer.py +3871 -0
  276. sage/schemes/jacobians/abstract_jacobian.py +277 -0
  277. sage/schemes/jacobians/all.py +2 -0
  278. sage/schemes/overview.py +161 -0
  279. sage/schemes/plane_conics/all.py +22 -0
  280. sage/schemes/plane_conics/con_field.py +1296 -0
  281. sage/schemes/plane_conics/con_finite_field.py +158 -0
  282. sage/schemes/plane_conics/con_number_field.py +456 -0
  283. sage/schemes/plane_conics/con_rational_field.py +406 -0
  284. sage/schemes/plane_conics/con_rational_function_field.py +580 -0
  285. sage/schemes/plane_conics/constructor.py +249 -0
  286. sage/schemes/plane_quartics/all.py +2 -0
  287. sage/schemes/plane_quartics/quartic_constructor.py +71 -0
  288. sage/schemes/plane_quartics/quartic_generic.py +73 -0
  289. sage/schemes/riemann_surfaces/all.py +1 -0
  290. sage/schemes/riemann_surfaces/riemann_surface.py +4117 -0
  291. sage_wheels/share/cremona/cremona_mini.db +0 -0
  292. sage_wheels/share/ellcurves/rank0 +30427 -0
  293. sage_wheels/share/ellcurves/rank1 +31871 -0
  294. sage_wheels/share/ellcurves/rank10 +6 -0
  295. sage_wheels/share/ellcurves/rank11 +6 -0
  296. sage_wheels/share/ellcurves/rank12 +1 -0
  297. sage_wheels/share/ellcurves/rank14 +1 -0
  298. sage_wheels/share/ellcurves/rank15 +1 -0
  299. sage_wheels/share/ellcurves/rank17 +1 -0
  300. sage_wheels/share/ellcurves/rank19 +1 -0
  301. sage_wheels/share/ellcurves/rank2 +2388 -0
  302. sage_wheels/share/ellcurves/rank20 +1 -0
  303. sage_wheels/share/ellcurves/rank21 +1 -0
  304. sage_wheels/share/ellcurves/rank22 +1 -0
  305. sage_wheels/share/ellcurves/rank23 +1 -0
  306. sage_wheels/share/ellcurves/rank24 +1 -0
  307. sage_wheels/share/ellcurves/rank28 +1 -0
  308. sage_wheels/share/ellcurves/rank3 +836 -0
  309. sage_wheels/share/ellcurves/rank4 +10 -0
  310. sage_wheels/share/ellcurves/rank5 +5 -0
  311. sage_wheels/share/ellcurves/rank6 +5 -0
  312. sage_wheels/share/ellcurves/rank7 +5 -0
  313. sage_wheels/share/ellcurves/rank8 +6 -0
  314. sage_wheels/share/ellcurves/rank9 +7 -0
@@ -0,0 +1,3796 @@
1
+ # sage_setup: distribution = sagemath-schemes
2
+ # cdivision=False
3
+ # cython: cdivision_warnings=False
4
+ # cython: profile=False
5
+ r"""
6
+ Modular symbols by numerical integration
7
+
8
+ We describe here the method for computing modular symbols
9
+ by numerical approximations of the integral of the modular form on a
10
+ path between cusps.
11
+
12
+ More precisely, let `E` be an elliptic curve and `f` the newform
13
+ associated to the isogeny class of `E`. If
14
+
15
+ .. MATH::
16
+
17
+ \lambda(r\to r') = 2\pi i \int_{r}^{r'} f(\tau) d\tau
18
+
19
+ then the modular symbol `[r]^{+}` is defined as the quotient of
20
+ the real part of `\lambda(\infty\to r)` by the least positive real
21
+ period of `E`. Similarly for the negative modular symbol, it is the
22
+ quotient of the imaginary part of the above by the smallest positive
23
+ imaginary part of a period on the imaginary axis.
24
+
25
+ The theorem of Manin-Drinfeld shows that the modular symbols are
26
+ rational numbers with small denominator. They are used for the
27
+ computation of special values of the `L`-function of `E` twisted by
28
+ Dirichlet characters and for the computation of `p`-adic `L`-functions.
29
+
30
+ ALGORITHM:
31
+
32
+ The implementation of modular symbols in eclib and directly in sage
33
+ uses the algorithm described in Cremona's book [Cre1997]_ and Stein's
34
+ book [St2007]_. First the space of all
35
+ modular symbols of the given level is computed, then the space
36
+ corresponding to the given newform is determined. Even if these initial
37
+ steps may take a while, the evaluation afterwards is instantaneous. All
38
+ computations are done with rational numbers and hence are exact.
39
+
40
+ Instead the method used here (see [Wu2018]_ for details)
41
+ is by evaluating the above integrals
42
+ `\lambda(r\to r')` by numerical approximation. Since we know precise
43
+ bounds on the denominator, we can make rigorous estimates on the
44
+ error to guarantee that the result is proven to be the correct rational
45
+ number.
46
+
47
+ The paths over which we integrate are split up and Atkin-Lehner
48
+ operators are used to compute the badly converging part of the integrals
49
+ by using the Fourier expansion at other cusps than `\infty`.
50
+
51
+ .. NOTE::
52
+
53
+ There is one assumption for the correctness of these computations: The
54
+ Manin constant for the `X_0`-optimal curve should be `1` if the curve
55
+ lies outside the Cremona tables. This is known for all curves in the
56
+ Cremona table, but only conjectured for general curves.
57
+
58
+ EXAMPLES:
59
+
60
+ The most likely usage for the code is through the functions
61
+ ``modular_symbol`` with implementation set to "num" and through
62
+ ``modular_symbol_numerical``::
63
+
64
+ sage: E = EllipticCurve("5077a1")
65
+ sage: M = E.modular_symbol(implementation='num')
66
+ sage: M(0)
67
+ 0
68
+ sage: M(1/123)
69
+ 4
70
+ sage: Mn = E.modular_symbol_numerical(sign=-1, prec=30)
71
+ sage: Mn(3/123) # abs tol 1e-11
72
+ 3.00000000000018
73
+
74
+ In more details. A numerical modular symbols ``M`` is created from an
75
+ elliptic curve with a chosen ``sign`` (though the other sign will also be
76
+ accessible, too)::
77
+
78
+ sage: E = EllipticCurve([101,103])
79
+ sage: E.conductor()
80
+ 35261176
81
+ sage: M = E.modular_symbol(implementation='num', sign=-1)
82
+ sage: M
83
+ Numerical modular symbol attached to
84
+ Elliptic Curve defined by y^2 = x^3 + 101*x + 103 over Rational Field
85
+
86
+ We can then compute the value `[13/17]^{-}` and `[1/17]^{+}` by calling
87
+ the function ``M``. The value of `[0]^{+}=0` tells us that the rank of
88
+ this curve is positive::
89
+
90
+ sage: M(13/17)
91
+ -1/2
92
+ sage: M(1/17,sign=+1)
93
+ -3
94
+ sage: M(0, sign=+1)
95
+ 0
96
+
97
+ One can compute the numerical approximation to these rational numbers
98
+ to any proven binary precision::
99
+
100
+ sage: M.approximative_value(13/17, prec=2) # abs tol 1e-4
101
+ -0.500003172770455
102
+ sage: M.approximative_value(13/17, prec=4) # abs tol 1e-6
103
+ -0.500000296037388
104
+ sage: M.approximative_value(0, sign=+1, prec=6) # abs tol 1e-8
105
+ 0.000000000000000
106
+
107
+
108
+ There are a few other things that one can do with ``M``. The Manin
109
+ symbol `M(c:d)` for a point `(c:d)` in the projective line can be
110
+ computed.::
111
+
112
+ sage: M.manin_symbol(1,5)
113
+ -1
114
+
115
+ In some cases useful, there is a function that returns all `[a/m]^{+}`
116
+ for a fixed denominator `m`. This is rather quicker for small `m` than
117
+ computing them individually::
118
+
119
+ sage: M.all_values_for_one_denominator(7)
120
+ {1/7: 0, 2/7: 3/2, 3/7: 3/2, 4/7: -3/2, 5/7: -3/2, 6/7: 0}
121
+
122
+ Finally a word of warning. The algorithm is fast when the cusps involved
123
+ are unitary. If the curve is semistable, all cusps are unitary. But
124
+ rational numbers with a prime `p` dividing the denominator once, but the
125
+ conductor more than once, are very difficult. For instance for the above
126
+ example, a seemingly harmless command like ``M(1/2)`` would take a very
127
+ very long time to return a value. However it is possible to compute them
128
+ for smaller conductors::
129
+
130
+ sage: E = EllipticCurve("664a1")
131
+ sage: M = E.modular_symbol(implementation='num')
132
+ sage: M(1/2)
133
+ 0
134
+
135
+ The problem with non-unitary cusps is dealt with rather easily when one
136
+ can twist to a semistable curve, like in this example::
137
+
138
+ sage: C = EllipticCurve("11a1")
139
+ sage: E = C.quadratic_twist(101)
140
+ sage: M = E.modular_symbol(implementation='num')
141
+ sage: M(1/101)
142
+ 41
143
+
144
+ AUTHORS:
145
+
146
+ - Chris Wuthrich (2013-16)
147
+ """
148
+
149
+ # ***************************************************************************
150
+ # Copyright (C) 2016 Chris Wuthrich <christian.wuthrich@gmail.com>
151
+ #
152
+ # Distributed under the terms of the GNU General Public License (GPL)
153
+ #
154
+ # This code is distributed in the hope that it will be useful,
155
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
156
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
157
+ # General Public License for more details.
158
+ #
159
+ # The full text of the GPL is available at:
160
+ #
161
+ # https://www.gnu.org/licenses/
162
+ # ***************************************************************************
163
+
164
+ from cysignals.memory cimport sig_malloc, sig_free, sig_realloc
165
+ from cysignals.signals cimport sig_check
166
+
167
+ from sage.arith.misc import euler_phi, kronecker as kronecker_symbol
168
+ from sage.misc.cachefunc import cached_method
169
+ from sage.misc.misc_c import prod
170
+ from sage.misc.verbose import verbose
171
+ from sage.rings.complex_mpfr cimport ComplexNumber
172
+ from sage.rings.complex_mpfr import ComplexField
173
+ from sage.rings.integer cimport Integer
174
+ from sage.rings.rational cimport Rational
175
+ from sage.rings.real_mpfr cimport RealNumber, RealField
176
+
177
+
178
+ cdef extern from "<math.h>":
179
+ double log(double)
180
+ double exp(double)
181
+ double cos(double)
182
+ double sin(double)
183
+ double ceil(double)
184
+ double sqrt(double)
185
+
186
+ # doing this before cimport ComplexNumber does not compile
187
+ # don't ask me why
188
+ cdef extern from "<complex.h>":
189
+ complex cexp(complex)
190
+ complex csqrt(complex)
191
+
192
+ ctypedef long long llong
193
+
194
+ cimport sage.rings.fast_arith
195
+ import sage.rings.fast_arith
196
+ cdef sage.rings.fast_arith.arith_llong arith_llong
197
+ fa = sage.rings.fast_arith.arith_llong()
198
+
199
+ cdef llong llgcd(llong a, llong b) except -1:
200
+ return fa.gcd_longlong(a,b)
201
+
202
+ cdef llong llinvmod(llong a, llong m) noexcept:
203
+ return fa.inverse_mod_longlong(a, m)
204
+
205
+ DEF TWOPI = 6.28318530717958647
206
+
207
+ # use_partials arguments take three values
208
+ # 0 don't use kappa
209
+ # 1 use kappa
210
+ # 2 decide : use if m^4 < N or m < PARTIALLIMIT
211
+ DEF PARTIAL_LIMIT = 82
212
+
213
+ # ==========================================
214
+ # the following are copied from fast_arith.pyx because
215
+ # I did not manage to import them properly
216
+
217
+ cdef llong llabs(llong x) except -1:
218
+ r"""
219
+ Return the absolute value of a long long.
220
+ """
221
+ if x < 0:
222
+ return -x
223
+ return x
224
+
225
+ cdef llong llsign(llong n) except -2:
226
+ r"""
227
+ Return the sign of a long long
228
+ """
229
+ if n < 0:
230
+ return -1
231
+ return 1
232
+
233
+ cdef llong llxgcd(llong a, llong b, llong *ss, llong *tt) except -1:
234
+ r"""
235
+ Compute the greatest common divisor `g` of `a` and `b`,
236
+ which is returned as the value. The integers `s` and `t` such
237
+ that `g=s a + t b` are returned via pointers.
238
+ """
239
+ cdef llong psign, qsign, p, q, r, s, c, quot, new_r, new_s
240
+ if a == 0:
241
+ ss[0] = 0
242
+ tt[0] = llsign(b)
243
+ return llabs(b)
244
+ if b == 0:
245
+ ss[0] = llsign(a)
246
+ tt[0] = 0
247
+ return llabs(a)
248
+ psign = 1
249
+ qsign = 1
250
+ if a < 0:
251
+ a = -a
252
+ psign = -1
253
+ if b < 0:
254
+ b = -b
255
+ qsign = -1
256
+ p = 1
257
+ q = 0
258
+ r = 0
259
+ s = 1
260
+ while b:
261
+ c = a % b
262
+ quot = a // b
263
+ a = b
264
+ b = c
265
+ new_r = p - quot*r
266
+ new_s = q - quot*s
267
+ p = r
268
+ q = s
269
+ r = new_r
270
+ s = new_s
271
+ ss[0] = p * psign
272
+ tt[0] = q * qsign
273
+ return a
274
+
275
+
276
+ def _test_llfunctions(a, b):
277
+ r"""
278
+ Doctest function for the above three functions.
279
+ Given a, b this returns the absolute value of a,
280
+ the sign of b, their gcd g and s and t such that
281
+ g = s*a + b*t
282
+
283
+ EXAMPLES::
284
+
285
+ sage: from sage.schemes.elliptic_curves.mod_sym_num \
286
+ ....: import _test_llfunctions
287
+ sage: _test_llfunctions(13,19)
288
+ (13, 1, 1, 3, -2)
289
+ sage: _test_llfunctions(-1234,-567)
290
+ (1234, -1, 1, 17, -37)
291
+ sage: _test_llfunctions(144,60)
292
+ (144, 1, 12, -2, 5)
293
+ """
294
+ cdef llong s, t
295
+ a1 = Integer(llabs(a))
296
+ a2 = Integer(llsign(b))
297
+ a3 = Integer(llxgcd(a, b, &s, &t))
298
+ a4 = Integer(s)
299
+ a5 = Integer(t)
300
+ assert a*a4 + b*a5 == a3
301
+ return (a1,a2,a3,a4,a5)
302
+
303
+
304
+ # ================================
305
+
306
+ # this is a llong version of a function in
307
+ # sage.modular.modsym.p1list.pyx
308
+
309
+ cdef int proj_normalise(llong N, llong u, llong v,
310
+ llong* uu, llong* vv) except -1:
311
+ r"""
312
+ Compute the canonical representative of
313
+ `\mathbb{P}^1(\ZZ/N\ZZ)` equivalent to `(u,v)`.
314
+
315
+ INPUT:
316
+
317
+ - ``N`` -- integer (the modulus or level)
318
+
319
+ - ``u`` -- integer (the first coordinate of (u:v))
320
+
321
+ - ``v`` -- integer (the second coordinate of (u:v))
322
+
323
+ OUTPUT:
324
+
325
+ If `\gcd(u,v,N) = 1`, then returns (in a pointer)
326
+
327
+ - ``uu`` -- integer
328
+
329
+ - ``vv`` -- integer
330
+
331
+ if `\gcd(u,v,N) \not= 1`, returns 0, 0, 0.
332
+ """
333
+ cdef llong d, k, g, s, t, min_v, min_t, Ng, vNg
334
+ # verbose(" enter proj_normalise with N=%s, u=%s, v=%s" % (N,u,v),
335
+ # level=5)
336
+ if N == 1:
337
+ uu[0] = 0
338
+ vv[0] = 0
339
+ return 0
340
+ # the % operator on llongs seems not to work with negatives
341
+ if u < 0:
342
+ u = N - ((-u) % N)
343
+ if v < 0:
344
+ v = N - ((-v) % N)
345
+ u = u % N
346
+ v = v % N
347
+ # verbose(" now N=%s, u=%s, v=%s" % (N,u,v), level=5)
348
+ if u == 0:
349
+ uu[0] = 0
350
+ if llgcd(v, N) == 1:
351
+ vv[0] = 1
352
+ else:
353
+ vv[0] = 0
354
+ return 0
355
+ g = llxgcd(u, N, &s, &t)
356
+ if s < 0:
357
+ s = N - ((-s) % N)
358
+ if t < 0:
359
+ t = N - ((-t) % N)
360
+ s = s % N
361
+ t = t % N
362
+ if llgcd(g, v) != 1:
363
+ uu[0] = 0
364
+ vv[0] = 0
365
+ return 0
366
+ # Now g = s*u + t*N, so s is a "pseudo-inverse" of u mod N
367
+ # Adjust s modulo N/g so it is coprime to N.
368
+ if g != 1:
369
+ d = N // g
370
+ while llgcd(s, N) != 1:
371
+ s = (s + d) % N
372
+ # verbose(" now g=%s, s=%s, t=%s" % (g,s,t), level=5)
373
+
374
+ # Multiply [u,v] by s; then [s*u,s*v] = [g,s*v] (mod N)
375
+ u = g
376
+ v = (s*v) % N
377
+ min_v = v
378
+ min_t = 1
379
+ if g != 1:
380
+ Ng = N // g
381
+ vNg = (v * Ng) % N
382
+ t = 1
383
+ k = 2
384
+ while k <= g:
385
+ v = (v + vNg) % N
386
+ t = (t + Ng) % N
387
+ if v < min_v and llgcd(t, N) == 1:
388
+ min_v = v
389
+ min_t = t
390
+ k += 1
391
+ v = min_v
392
+ uu[0] = u
393
+ vv[0] = v
394
+ # verbose(" leaving proj_normalise with s=%s, t=%s" % (u,v), level=5)
395
+ return 0
396
+
397
+
398
+ def _test_proj_normalise(N, u, v):
399
+ r"""
400
+ The doctest function for proj_normalise.
401
+
402
+ EXAMPLES::
403
+
404
+ sage: from sage.schemes.elliptic_curves.mod_sym_num \
405
+ ....: import _test_proj_normalise
406
+ sage: _test_proj_normalise(90,7,77)
407
+ (1, 11)
408
+ sage: _test_proj_normalise(90,7,78)
409
+ (1, 24)
410
+ sage: _test_proj_normalise(24,4,9)
411
+ (4, 3)
412
+ sage: _test_proj_normalise(24,4,8)
413
+ (0, 0)
414
+ sage: _test_proj_normalise(17,-1,-7)
415
+ (1, 7)
416
+ """
417
+ cdef llong uu, vv
418
+ _ = proj_normalise(N,u,v,&uu,&vv)
419
+ return (Integer(uu), Integer(vv))
420
+
421
+
422
+ cdef int best_proj_point(llong u, llong v, llong N,
423
+ llong* uu, llong* vv) except -1:
424
+ r"""
425
+ Given a point `(u:v)` on the projective line modulo `N`.
426
+ This returns a representation `(x:y)` with
427
+ small `|x|` and `|y|`.
428
+
429
+ In many cases this is best possible, in the sense that
430
+ `|x|+|y|` is as small as possible, but not always.
431
+ """
432
+ cdef llong w, p, q, Nnew, r, a, b, si
433
+ cdef llong x0, x1, y0, y1, t0, t1, s0, s1
434
+ # verbose(" enter best_proj_point with N=%s, u=%s, v=%s" % (N,u,v),
435
+ # level=5)
436
+ if u == 0:
437
+ uu[0] = <llong>0
438
+ vv[0] = <llong>1
439
+ return 0
440
+ if v == 0:
441
+ uu[0] = <llong>1
442
+ vv[0] = <llong>0
443
+ return 0
444
+
445
+ if llgcd(u, N) == 1:
446
+ w = (v * llinvmod(u, N)) % N
447
+ y0 = <llong>0
448
+ y1 = N
449
+ x0 = <llong>1
450
+ x1 = w
451
+ elif llgcd(v, N) == 1:
452
+ w = (u * llinvmod(v, N)) % N
453
+ y0 = N
454
+ y1 = <llong>0
455
+ x0 = w
456
+ x1 = <llong>1
457
+ else: # cases like (p:q) mod p*q drop here
458
+ p = llgcd(u, N)
459
+ q = llgcd(v, N)
460
+ Nnew = (N // p) // q
461
+ w = ((u // p) * llinvmod(v // q, Nnew)) % Nnew
462
+ y0 = N // q
463
+ y1 = <llong>0
464
+ x0 = w*p
465
+ x1 = q
466
+
467
+ # y will always be the longer and x the shorter
468
+ while llabs(x0) + llabs(x1) < llabs(y0) + llabs(y1):
469
+ if llsign(x0) == llsign(x1):
470
+ r = (y0+y1) // (x0+x1)
471
+ else:
472
+ r = (y0-y1) // (x0-x1)
473
+ t0 = y0 - r * x0
474
+ t1 = y1 - r * x1
475
+ s0 = t0 - x0
476
+ s1 = t1 - x1
477
+ if llabs(s0) + llabs(s1) < llabs(t0) + llabs(t1):
478
+ t0 = s0
479
+ t1 = s1
480
+ # t is now the shortest vector on the line y + RR x
481
+ # verbose(" reduced vector to (%s,%s)" % (t0,t1), level=4)
482
+ y0 = x0
483
+ y1 = x1
484
+ x0 = t0
485
+ x1 = t1
486
+
487
+ if llgcd(y0, y1) == 1:
488
+ uu[0] = y0
489
+ vv[0] = y1
490
+ return 0
491
+ elif llgcd(x0, x1) == 1:
492
+ uu[0] = x0
493
+ vv[0] = x1
494
+ return 0
495
+ else:
496
+ # we fall here if the first two shortest vector are both
497
+ # not permitted, here we do a search until we hit a solution.
498
+ # verbose(" both shortest vectors ((%s,%s) and (%s,%s)) are not "
499
+ # "permitted. The result is not guaranteed to "
500
+ # "be best possible." % (x0, x1, y0, y1), level=3)
501
+ r = <llong>2
502
+ a = <llong>1
503
+ b = a
504
+ si = a
505
+ t0 = a * x0 + b * y0
506
+ t1 = a * x1 + b * y1
507
+ while llgcd(t0, t1) != 1:
508
+ b += si
509
+ a -= 1
510
+ if a == 0:
511
+ a = <llong>(-1)
512
+ b = r-1
513
+ si = a
514
+ if b == 0:
515
+ r += 1
516
+ a = r-1
517
+ b = <llong>1
518
+ si = b
519
+ t0 = a * x0 + b * y0
520
+ t1 = a * x1 + b * y1
521
+ # verbose("works with t = %s*x+%s*y" % (a, b), level=3)
522
+ uu[0] = t0
523
+ vv[0] = t1
524
+ return 0
525
+
526
+
527
+ def _test_best_proj_point(u, v, N):
528
+ r"""
529
+ Doctest function of best_proj_point.
530
+
531
+ EXAMPLES::
532
+
533
+ sage: from sage.schemes.elliptic_curves.mod_sym_num \
534
+ ....: import _test_best_proj_point
535
+ sage: _test_best_proj_point(11,35,101)
536
+ (-1, 6)
537
+ sage: _test_best_proj_point(123456789,987654321,1000000001)
538
+ (101, 79)
539
+ sage: _test_best_proj_point(3,10,27)
540
+ (3, 1)
541
+ sage: _test_best_proj_point(-1,99,101)
542
+ (1, 2)
543
+
544
+ Here an example where the returned value is worse than
545
+ the given::
546
+
547
+ sage: _test_best_proj_point(11,1,30)
548
+ (-13, 7)
549
+ """
550
+ cdef llong uu, vv
551
+ a = best_proj_point(u, v, N, &uu, &vv)
552
+ assert a == 0
553
+ return (Integer(uu), Integer(vv))
554
+
555
+
556
+ #======================================================================
557
+
558
+ cdef class _CuspsForModularSymbolNumerical:
559
+ r"""
560
+ Minimalistic class implementing cusps (not `\infty`).
561
+ Here a cusp is a rational number together with a level.
562
+ This class provides the methods atkin_lehner and
563
+ is_unitary and attaches _width, _a, _m to it.
564
+
565
+ It is to only to be used internally.
566
+ """
567
+ cdef public llong _a, _m, _width
568
+ cdef public llong _N_level # trac 29290 renamed
569
+ cdef public Rational _r
570
+
571
+ def __init__(self, Rational r, llong N):
572
+ r"""
573
+ The rational (non-infinite) cusp r on X_0(N).
574
+
575
+ INPUT:
576
+
577
+ - ``r`` -- a rational number
578
+
579
+ - ``N`` -- the level as a long long
580
+
581
+ EXAMPLES::
582
+
583
+ sage: from sage.schemes.elliptic_curves.mod_sym_num \
584
+ ....: import _CuspsForModularSymbolNumerical
585
+ sage: r = _CuspsForModularSymbolNumerical(3/7,99)
586
+ """
587
+ cdef llong a, m, B
588
+ # verbose(" enter __init__ of cusps with r=%s and N=%s" % (r,N),
589
+ # level=5)
590
+ a = <llong>(r.numerator())
591
+ m = <llong>(r.denominator())
592
+ a = a % m
593
+ if 2*a > m:
594
+ a -= m
595
+ self._r = Rational((a, m))
596
+ B = llgcd(m, N)
597
+ self._width = N // B
598
+ self._a = a
599
+ self._m = m
600
+ self._N_level = N
601
+ # we could make it inherit from general cusps
602
+ # but there is no need for this here
603
+ # from sage.modular.cusps import Cusp
604
+ # Cusp.__init__(self, a,m)
605
+
606
+ cdef public int is_unitary(self) noexcept:
607
+ r"""
608
+ Return whether the cusp is unitary,
609
+ i.e. whether there exists an Atkin-
610
+ Lehner operator that brings it to i`\infty`.
611
+ """
612
+ cdef llong B
613
+ B = llgcd(self._m, self._N_level)
614
+ return llgcd(self._width, B) == 1
615
+
616
+ cdef public int atkin_lehner(self, llong* res) except -1:
617
+ r"""
618
+ If the cusp is unitary, this returns
619
+ an Atkin-Lehner matrix for it. It is
620
+ returned into the pointer as a list of
621
+ four [a,b,c,d] corresponds to
622
+ [[a,b],[c,d]].
623
+ """
624
+ cdef llong Q, B, c, x, y
625
+
626
+ # verbose(" enter atkin_lehner for cusp r=%s" % self._r, level=5)
627
+ Q = self._width
628
+ B = llgcd(self._m, self._N_level)
629
+ c = self._m // B
630
+ if llgcd(Q, B) != 1:
631
+ raise ValueError("This cusp is not in the Atkin-Lehner "
632
+ "orbit of oo.")
633
+ _ = llxgcd(self._a * Q, self._m, &x, &y)
634
+ res[0] = Q * x
635
+ res[1] = y
636
+ res[2] = -c * self._N_level
637
+ res[3] = Q * self._a
638
+ # verbose(" leaving atkin_lehner with w_Q = "
639
+ # "[%s, %s, %s, %s]" % (res[0], res[1], res[2], res[3]),
640
+ # level=5)
641
+ return 0
642
+
643
+
644
+ def _test_cusps(r, N):
645
+ r"""
646
+ Doctest function for the above class.
647
+
648
+ Given the rational r and an integer N,
649
+ this gives back its width, whether it is
650
+ unitary and if so an atkin-lehner
651
+ matrix
652
+
653
+ EXAMPLES::
654
+
655
+ sage: from sage.schemes.elliptic_curves.mod_sym_num import _test_cusps
656
+ sage: _test_cusps(0/1,11)
657
+ (11, 1, [[0, 1], [-11, 0]])
658
+ sage: _test_cusps(5/7,11)
659
+ (11, 1, [[-11, -3], [-77, -22]])
660
+ sage: _test_cusps(3/11,11)
661
+ (1, 1, [[4, -1], [-11, 3]])
662
+ sage: _test_cusps(1/3,27)
663
+ (9, 0, [[0, 0], [0, 0]])
664
+ sage: _test_cusps(1/9,27)
665
+ (3, 0, [[0, 0], [0, 0]])
666
+ sage: _test_cusps(5/27,27)
667
+ (1, 1, [[11, -2], [-27, 5]])
668
+ """
669
+ cdef llong *wQ = [0L, 0L, 0L, 0L]
670
+ rc = _CuspsForModularSymbolNumerical(r, N)
671
+ a1 = rc._width
672
+ a2 = rc.is_unitary()
673
+ if a2:
674
+ _ = rc.atkin_lehner(wQ)
675
+ a = Integer(wQ[0])
676
+ b = Integer(wQ[1])
677
+ c = Integer(wQ[2])
678
+ d = Integer(wQ[3])
679
+ assert a*d - b*c == a1*a2
680
+ M = [[a, b], [c, d]]
681
+ return (Integer(a1), Integer(a2), M)
682
+
683
+ # ==============================================
684
+
685
+
686
+ cdef class ModularSymbolNumerical:
687
+ r"""
688
+ This class assigning to an elliptic curve over `\QQ` a modular symbol.
689
+ Unlike the other implementations this class does not precompute a
690
+ basis for this space. Instead at each call, it evaluates the integral
691
+ using numerical approximation. All bounds are very strictly
692
+ implemented and the output is a correct proven rational number.
693
+
694
+ INPUT:
695
+
696
+ - ``E`` -- an elliptic curve over the rational numbers
697
+
698
+ - ``sign`` -- either -1 or +1 (default). This sets the default
699
+ value of ``sign`` throughout the class. Both are still accessible.
700
+
701
+ OUTPUT: a modular symbol
702
+
703
+ EXAMPLES::
704
+
705
+ sage: E = EllipticCurve("5077a1")
706
+ sage: M = E.modular_symbol(implementation='num')
707
+ sage: M(0)
708
+ 0
709
+ sage: M(77/57)
710
+ -1
711
+ sage: M(33/37, -1)
712
+ 2
713
+ sage: M = E.modular_symbol(sign=-1, implementation='num')
714
+ sage: M(2/7)
715
+ 2
716
+
717
+ sage: from sage.schemes.elliptic_curves.mod_sym_num \
718
+ ....: import ModularSymbolNumerical
719
+ sage: M = ModularSymbolNumerical(EllipticCurve("11a1"))
720
+ sage: M(1/3, -1)
721
+ 1/2
722
+ sage: M(1/2)
723
+ -4/5
724
+ """
725
+ cdef:
726
+ llong _N_E, _cut_val, _t_plus, _t_minus
727
+ llong _t_unitary_minus, _t_unitary_plus
728
+ int _lans
729
+ int * _ans
730
+ double * _ans_num
731
+ double _eps_plus, _eps_minus, _eps_unitary_plus, _eps_unitary_minus
732
+ public RealNumber _om1, _om2
733
+ object _E, _epsQs, _Mt, _Epari
734
+ public dict _cached_methods
735
+ Rational _twist_q
736
+ Integer _D
737
+ int _global_sign
738
+
739
+ # debug and optimisation
740
+ # public Integer nc_sums # number of calls to summation
741
+ # public Integer nc_direct # number of direct integrations vs
742
+ # public Integer nc_indirect # number of indirect
743
+ # public Integer nc_terms # number of terms summed in total
744
+
745
+ def __cinit__(self):
746
+ r"""
747
+ Initialisation function.
748
+ Allocate memory to store the
749
+ Fourier coefficients of the newform.
750
+
751
+ EXAMPLES::
752
+
753
+ sage: E = EllipticCurve([1,-1])
754
+ sage: M = E.modular_symbol(implementation='num')
755
+ sage: M(12/11) # indirect doctest
756
+ 1/2
757
+ """
758
+ self._ans_num = <double *> sig_malloc(1002 * sizeof(double))
759
+ self._ans = <int*> sig_malloc(1002 * sizeof(int))
760
+ if self._ans is NULL or self._ans_num is NULL:
761
+ if self._ans is not NULL:
762
+ sig_free(self._ans)
763
+ if self._ans_num is not NULL:
764
+ sig_free(self._ans_num)
765
+ raise MemoryError("Memory.")
766
+
767
+ def __init__(self, E, sign=+1):
768
+ r"""
769
+ See the class docstring for full documentation.
770
+
771
+ EXAMPLES::
772
+
773
+ sage: E = EllipticCurve("27a1")
774
+ sage: M = E. modular_symbol(implementation='num')
775
+ sage: M(1/9)
776
+ 1/2
777
+ sage: M(1/3)
778
+ -1/6
779
+ sage: M(1/3, -1)
780
+ 1/6
781
+ """
782
+ # verbose(" enter __init_ of modular symbols", level=5)
783
+ self._E = E
784
+ self._Epari= E.pari_mincurve()
785
+ self._global_sign = <int>sign
786
+ self._N_E = <llong>(E.conductor())
787
+ self._D = -Integer(1)
788
+ self._set_epsQs()
789
+ self._initialise_an_coefficients()
790
+ self._set_den_bounds()
791
+ self._cached_methods = {}
792
+
793
+ # self.nc_sums = Integer(0)
794
+ # self.nc_direct = Integer(0)
795
+ # self.nc_indirect = Integer(0)
796
+ # self.nc_terms = Integer(0)
797
+
798
+ # this is a bound to decide when to go directly to ioo
799
+ # rather than using further convergents.
800
+ # see symbol(r) where it is used
801
+ self._cut_val = <llong>(E.conductor().isqrt() // 4)
802
+ if self._cut_val < 100:
803
+ self._cut_val = 100
804
+ # this is can be used to disable it
805
+ # self._cut_val = <long>(-1)
806
+ # verbose(" leaving __init__", level=5)
807
+
808
+ def __dealloc__(self):
809
+ r"""
810
+ Free the memory of the stored Fourier coefficients
811
+ """
812
+ sig_free(self._ans_num)
813
+ sig_free(self._ans)
814
+
815
+ # == basics ================
816
+
817
+ def __repr__(self):
818
+ """
819
+ String representation of modular symbols.
820
+
821
+ EXAMPLES::
822
+
823
+ sage: E = EllipticCurve("14a1")
824
+ sage: M = E.modular_symbol(implementation='num')
825
+ sage: M
826
+ Numerical modular symbol attached to Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x - 6 over Rational Field
827
+ """
828
+ return "Numerical modular symbol attached to %s" % (self._E)
829
+
830
+ def elliptic_curve(self):
831
+ r"""
832
+ Return the elliptic curve of this modular symbol.
833
+
834
+ EXAMPLES::
835
+
836
+ sage: E = EllipticCurve("15a4")
837
+ sage: M = E.modular_symbol(implementation='num')
838
+ sage: M.elliptic_curve()
839
+ Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 + 35*x - 28 over Rational Field
840
+ """
841
+ return self._E
842
+
843
+ def __call__(self, r, int sign=0, use_twist=True):
844
+ r"""
845
+ The modular symbol evaluated at rational. It returns a
846
+ rational number.
847
+
848
+ INPUT:
849
+
850
+ - ``r`` -- a rational (or integer)
851
+
852
+ - ``sign`` -- either +1 or -1, or 0 (default),
853
+ in which case the sign passed to the class is taken
854
+
855
+ - ``use_twist`` -- boolean (default: ``True``); decides if we
856
+ allow to use a quadratic twist
857
+
858
+ OUTPUT: a rational number
859
+
860
+ EXAMPLES::
861
+
862
+ sage: E = EllipticCurve("36a1")
863
+ sage: M = E.modular_symbol(implementation='num')
864
+ sage: M(2/5)
865
+ -1/3
866
+ sage: M(2/5, -1)
867
+ 1/2
868
+
869
+ sage: E = EllipticCurve("54a1")
870
+ sage: M = E.modular_symbol(implementation='num')
871
+ sage: M(5/9)
872
+ -1/2
873
+
874
+ sage: E = EllipticCurve("5077a1")
875
+ sage: M = E.modular_symbol(implementation='num')
876
+ sage: M(234/567)
877
+ 0
878
+ sage: M(112379/43568779)
879
+ 5
880
+ """
881
+ cdef Rational ra
882
+
883
+ if sign == 0:
884
+ sign = self._global_sign
885
+
886
+ # verbose(" enter __call__ of modular symbols for r=%s"
887
+ # "and sign=%s and use_twist=%s" % (r,sign,use_twist), level=5)
888
+ if isinstance(r, Rational):
889
+ ra = r
890
+ elif isinstance(r, Integer):
891
+ ra = Rational((0, 1))
892
+ elif isinstance(r, sage.rings.infinity.PlusInfinity):
893
+ return Rational(0)
894
+ else: # who knows
895
+ raise ValueError("The modular symbol can be evaluated at a "
896
+ "rational number only.")
897
+ if use_twist:
898
+ if self._D == -1:
899
+ self._set_up_twist()
900
+ if self._D != 1:
901
+ return self._twisted_symbol(ra, sign=sign)
902
+ return self._evaluate(ra, sign=sign)
903
+
904
+ def approximative_value(self, r, int sign=0, int prec=20, use_twist=True):
905
+ r"""
906
+ The numerical modular symbol evaluated at rational.
907
+
908
+ It returns a real number, which should be equal
909
+ to a rational number to the given binary
910
+ precision ``prec``. In practice the precision is
911
+ often much higher. See the examples below.
912
+
913
+ INPUT:
914
+
915
+ - ``r`` -- a rational (or integer)
916
+
917
+ - ``sign`` -- either +1 or -1, or 0 (default),
918
+ in which case the sign passed to the class is taken
919
+
920
+ - ``prec`` -- integer (default: 20)
921
+
922
+ - ``use_twist`` -- ``True`` (default) allows to use a
923
+ quadratic twist of the curve to lower the conductor
924
+
925
+ OUTPUT: a real number
926
+
927
+ EXAMPLES::
928
+
929
+ sage: E = EllipticCurve("5077a1")
930
+ sage: M = E.modular_symbol(implementation='num')
931
+ sage: M.approximative_value(123/567) # abs tol 1e-11
932
+ -4.00000000000845
933
+ sage: M.approximative_value(123/567,prec=2) # abs tol 1e-9
934
+ -4.00002815242902
935
+
936
+ sage: E = EllipticCurve([11,88])
937
+ sage: E.conductor()
938
+ 1715296
939
+ sage: M = E.modular_symbol(implementation='num')
940
+ sage: M.approximative_value(0,prec=2) # abs tol 1e-11
941
+ -0.0000176374317982166
942
+ sage: M.approximative_value(1/7,prec=2) # abs tol 1e-11
943
+ 0.999981178147778
944
+ sage: M.approximative_value(1/7,prec=10) # abs tol 1e-11
945
+ 0.999999972802649
946
+ """
947
+ cdef Rational ra
948
+ cdef ComplexNumber ans
949
+ cdef double eps
950
+ cdef object L
951
+ cdef int cinf
952
+
953
+ if sign == 0:
954
+ sign = self._global_sign
955
+
956
+ # verbose(" enter approximative_value of modular symbols for r=%s,"
957
+ # "sign=%s and prec=%s " % (r,sign,prec,), level=5)
958
+ if isinstance(r, Rational):
959
+ ra = r
960
+ elif isinstance(r, Integer):
961
+ ra = Rational((0, 1))
962
+ else: # who knows
963
+ raise ValueError("The modular symbol can be evaluated at a"
964
+ "rational number only.")
965
+ if use_twist:
966
+ if self._D == -1:
967
+ self._set_up_twist()
968
+ if self._D != 1:
969
+ return self._twisted_approx(ra, sign=sign, prec=prec)
970
+
971
+ eps = <double>2
972
+ eps = eps ** (-prec)
973
+
974
+ ans = self._evaluate_approx(ra, eps)
975
+
976
+ if prec > self._om1.parent().prec():
977
+ L = self._E.period_lattice().basis(prec=prec)
978
+ self._om1 = L[0]
979
+ self._om2 = L[1].imag()
980
+ cinf = self._E.real_components()
981
+ if cinf == 1:
982
+ self._om2 *= 2
983
+
984
+ if sign == 1:
985
+ return ans.real()/ self._om1
986
+ else:
987
+ return ans.imag()/ self._om2
988
+
989
+ # == initialisation ========
990
+
991
+ def _set_epsQs(self):
992
+ r"""
993
+ This sets the signs of the action by the Atkin-Lehner involutions
994
+ on the modular form
995
+
996
+ The eigenvalues are stored in a python dict _epsQs.
997
+ Doctest in _test_init.
998
+
999
+ EXAMPLES::
1000
+
1001
+ sage: E = EllipticCurve("20a2")
1002
+ sage: M = E.modular_symbol(implementation='num') #indirect doctest
1003
+ """
1004
+ self._epsQs = {d: prod(self._E.root_number(p)
1005
+ for p in d.prime_divisors())
1006
+ for d in Integer(self._N_E).divisors()}
1007
+
1008
+ def _set_den_bounds(self):
1009
+ r"""
1010
+ This sets the bounds on the denominators and the allowed errors.
1011
+ There are four integers _t_plus, _t_minus, _t_unitary_plus,
1012
+ _t_unitary_minus, which are proven upper bounds for the denominator
1013
+ of modular symbols (under the assumption that the optimal
1014
+ Manin constant is a divisor of 2).
1015
+ It also sets _eps_plus etc which are the errors that we are
1016
+ allowed to do in computations.
1017
+
1018
+ Doctest in _test_init
1019
+
1020
+ EXAMPLES::
1021
+
1022
+ sage: E = EllipticCurve("240b3")
1023
+ sage: M = E.modular_symbol(implementation='num') #indirect doctest
1024
+ """
1025
+ from sage.databases.cremona import CremonaDatabase
1026
+
1027
+ cdef:
1028
+ Integer N, p, delta, t0
1029
+ Rational q_plus, q_minus, s
1030
+ int co, cinf, E0cinf
1031
+ RealNumber E0om1, E0om2, q
1032
+
1033
+ # verbose(" enter _set_bounds", level=5)
1034
+ N = Integer(self._N_E)
1035
+ E = self._E
1036
+ L = E.period_lattice().basis()
1037
+ self._om1 = L[0]
1038
+ self._om2 = L[1].imag()
1039
+ cinf = E.real_components()
1040
+ if cinf == 1:
1041
+ self._om2 *= 2
1042
+
1043
+ # find the best curve to compare it too.
1044
+ # if the curve is in the database,
1045
+ # we can compare to the X_0-optimal curve
1046
+ isog = E.isogeny_class()
1047
+ if N <= CremonaDatabase().largest_conductor():
1048
+ E0 = E.optimal_curve()
1049
+ # otherwise, we take a "maximal" curve
1050
+ # that the worst that can happen and is sort of the
1051
+ # opposite of what we expect, but
1052
+ else:
1053
+ E0 = min(isog.curves,
1054
+ key=lambda C: C.period_lattice().complex_area())
1055
+ # E0 has now conjecturally Manin constant = 1
1056
+
1057
+ # now determine the bound for E0 coming from the
1058
+ # theorem of Manin and Drinfeld.
1059
+ # delta is such that the cusps are all defined over
1060
+ # the cyclotomic field zeta_delta
1061
+ delta = Integer(1)
1062
+ for p in N.prime_divisors():
1063
+ delta *= p ** (N.valuation(p)//2)
1064
+ if delta % 2 == 0:
1065
+ delta *= 2
1066
+
1067
+ # on points of good reduction, the torsion is injective
1068
+ # so t0 will be a bound for the denominators of both
1069
+ # plus and minus for E0
1070
+ p = Integer(1)
1071
+ co = 0
1072
+ t0 = Integer(0)
1073
+ while co < 5 or p < max(100,10*delta) and p < self._lans:
1074
+ p += delta
1075
+ if p.is_prime() and N % p != 0:
1076
+ t0 = t0.gcd(p + 1 - self._ans[p])
1077
+ co += 1
1078
+ if (p-2).is_prime() and N % (p-2) != 0:
1079
+ t0 = t0.gcd((p-1)**2 - self._ans[p-2]**2)
1080
+ co += 1
1081
+ if E0.real_components() == 1:
1082
+ t0 *= Integer(2) # slanted lattice
1083
+
1084
+ # This is a not strictly necessary precaution:
1085
+ # Cremona is not always certain to have the optimal
1086
+ # curve correctly determined. If not, the index
1087
+ # is just 2.
1088
+ # For curves outside, we could have in the very worst case
1089
+ # that the optimal curve is another maximal curve. Then
1090
+ # a factor 2 should be fine, too, but it is not guaranteed.
1091
+ t0 *= 2
1092
+
1093
+ # now compare the lattice for E0 with the one for E
1094
+ L = E0.period_lattice().basis()
1095
+ E0om1 = L[0]
1096
+ E0om2 = L[1].imag()
1097
+ E0cinf = E0.real_components()
1098
+ if E0cinf == 1:
1099
+ E0om2 *= Integer(2)
1100
+
1101
+ maxdeg = max(max(x) for x in isog.matrix())
1102
+ q = self._om1 / E0om1 * maxdeg
1103
+ q_plus = q.round() / maxdeg
1104
+ q = self._om2 / E0om2 * maxdeg
1105
+ q_minus = q.round() / maxdeg
1106
+ s = q_plus * t0
1107
+ self._t_plus = s.numerator()
1108
+ s = q_minus * t0
1109
+ self._t_minus = s.numerator()
1110
+
1111
+ # now to the bound for the unitary cusps
1112
+ # this is a bit better because they
1113
+ # are defined over Q
1114
+ t0 = E0.torsion_order()
1115
+ if cinf == 1:
1116
+ t0 *= Integer(2)
1117
+ s = q_plus * t0
1118
+ self._t_unitary_plus = s.numerator()
1119
+ t0 = Integer(2)
1120
+ s = q_minus * t0
1121
+ self._t_unitary_minus = s.numerator()
1122
+
1123
+ if N.is_squarefree():
1124
+ self._t_plus = llgcd(self._t_plus, self._t_unitary_plus)
1125
+ self._t_minus = llgcd(self._t_minus, self._t_unitary_minus)
1126
+
1127
+ # set the epsilons
1128
+ self._eps_plus = <double>self._om1 / 2 / self._t_plus
1129
+ self._eps_minus = <double>self._om2 / 2 / self._t_minus
1130
+ self._eps_unitary_plus = <double>self._om1 /2 / self._t_unitary_plus
1131
+ self._eps_unitary_minus = <double>self._om2 /2 / self._t_unitary_minus
1132
+
1133
+ # this code checks if the above is ok,
1134
+ # we tested quite a few curves with it
1135
+ # change the variables to public
1136
+ # from sage.schemes.elliptic_curves.mod_sym_num import ModularSymbolNumerical
1137
+ # def dens_check(E):
1138
+ # N = E.conductor()
1139
+ # Cu = Gamma0(N).cusps()
1140
+ # m = E.modular_symbol()
1141
+ # d_plus = max([ denominator(m(r)) for r in Cu if r != oo])
1142
+ # m = E.modular_symbol(-1)
1143
+ # d_minus = max([ denominator(m(r)) for r in Cu if r != oo])
1144
+ # M = ModularSymbolNumerical(E)
1145
+ # print(E.label(), (d_plus, d_minus), (M._t_plus, M._t_minus),
1146
+ # (M._t_unitary_plus, M._t_unitary_plus))
1147
+ # if M._t_plus < d_plus or M._t_minus < d_minus:
1148
+ # print("**** b u g *** ")
1149
+
1150
+ def _set_up_twist(self):
1151
+ r"""
1152
+ This sets up the minimal twist. This is only called from __call__
1153
+ if use_twist is True.
1154
+
1155
+ EXAMPLES::
1156
+
1157
+ sage: E = EllipticCurve("63a2")
1158
+ sage: M = E.modular_symbol(implementation='num')
1159
+ sage: M(3/4, use_twist=True) # indirect doctest
1160
+ -1
1161
+ """
1162
+ cdef Integer D, ell
1163
+ cdef RealNumber qq, Db
1164
+
1165
+ # verbose(" enter _set_up_twist", level=5)
1166
+ Et, D = self._E.minimal_quadratic_twist()
1167
+ # we now have to make sure that |D| is as small as
1168
+ # possible (the above may give a D != 1 and yet
1169
+ # the conductor is still the same) and we
1170
+ # have to make sure that when twisting by a
1171
+ # prime ell, the twisted curve does not have
1172
+ # additive reduction. Otherwise, unitary
1173
+ # cusps will become non-movable.
1174
+ if D != 1:
1175
+ Nt = Et.conductor()
1176
+ for ell in D.prime_divisors():
1177
+ if Nt.valuation(ell) >= 2:
1178
+ D = D.prime_to_m_part(ell)
1179
+ if ell % 4 == 3:
1180
+ D = -D
1181
+ if D % 4 == 3:
1182
+ D = -D
1183
+ Et = self._E.quadratic_twist(D)
1184
+ self._D = D
1185
+ verbose(" twisting by %s to get conductor %s" % (D, Et.conductor()),
1186
+ level=2)
1187
+ # now set up period change
1188
+ if D != 1:
1189
+ self._Mt = ModularSymbolNumerical(Et)
1190
+ RR = RealField(53)
1191
+ Db = RR(D.abs())
1192
+ Db = Db.sqrt()
1193
+ # a theorem by vivek pal guarantees that qq below
1194
+ # are integers.
1195
+ if D > 0:
1196
+ qq = self._om1 * Db/ self._Mt._om1 * 2
1197
+ self._twist_q = Rational((qq.round(), 2))
1198
+ qq = self._om2 * Db/ self._Mt._om2 * 2
1199
+ assert self._twist_q == Rational((qq.round(), 2))
1200
+ else:
1201
+ qq = self._om2 * Db/self._Mt._om1 * 2
1202
+ self._twist_q = Rational((qq.round(), 2))
1203
+ qq = self._om1 * Db/self._Mt._om2 * 2
1204
+ assert self._twist_q == Rational((qq.round(), 2))
1205
+
1206
+ def _round(self, RealNumber val, int sign, int unitary):
1207
+ r"""
1208
+ Round the numerical approximation to the rational.
1209
+ A warning is printed if the rounding is off by more
1210
+ than 0.1.
1211
+
1212
+ INPUT:
1213
+
1214
+ - ``val`` -- a real number to round
1215
+
1216
+ - ``sign`` -- either +1 or -1
1217
+
1218
+ - ``unitary`` -- boolean (int)
1219
+
1220
+ OUTPUT: a rational
1221
+
1222
+ EXAMPLES::
1223
+
1224
+ sage: from sage.schemes.elliptic_curves.mod_sym_num \
1225
+ ....: import ModularSymbolNumerical
1226
+ sage: M = ModularSymbolNumerical(EllipticCurve("11a1"))
1227
+ sage: va = M._from_ioo_to_r_approx(0/1,0.01)
1228
+ sage: va = va.real()
1229
+ sage: M._round(va,1,True)
1230
+ 1/5
1231
+ """
1232
+ cdef:
1233
+ Rational res
1234
+ llong t, r
1235
+ RealNumber q, qt
1236
+
1237
+ # verbose(" enter _round with value=%s" % val, level=5)
1238
+ if sign == 1 and unitary:
1239
+ q = val/self._om1
1240
+ t = self._t_unitary_plus
1241
+ elif sign == 1 and not unitary:
1242
+ q = val/self._om1
1243
+ t = self._t_plus
1244
+ elif sign == -1 and unitary:
1245
+ q = val/self._om2
1246
+ t = self._t_unitary_minus
1247
+ elif sign == -1 and not unitary:
1248
+ q = val/self._om2
1249
+ t = self._t_minus
1250
+
1251
+ qt = q * t
1252
+ r = qt.round()
1253
+ res = Rational((r, t))
1254
+ err = (q-res).abs()
1255
+
1256
+ if err > 0.1:
1257
+ # the following did not work (compilation failed)
1258
+ # from warnings import warn
1259
+ # warn(Rounded an error of %s, looks like a bug." % err,
1260
+ # RuntimeWarning, stacklevel=5)
1261
+ print ("Warning: Rounded an error of ", err, ", looks like a bug "
1262
+ + "in mod_sym_num.pyx.")
1263
+ verbose(" rounding with an error of %s" % err, level=3)
1264
+ return res
1265
+
1266
+ def _initialise_an_coefficients(self):
1267
+ r"""
1268
+ Compute the Fourier coefficients `a_n` for all `n` up to 1000.
1269
+ Doctest in _test_init
1270
+
1271
+ EXAMPLES::
1272
+
1273
+ sage: E = EllipticCurve([-11,13])
1274
+ sage: M = E.modular_symbol(implementation='num') #indirect doctest
1275
+ """
1276
+ cdef int n
1277
+ # verbose(" enter _initialise_an_coeffients", level=5)
1278
+ n = 0
1279
+ self_ans = self._E.anlist(1000, python_ints=True)
1280
+ while n <= 1000:
1281
+ self._ans[n] = self_ans[n]
1282
+ n += 1
1283
+ self._lans = len(self_ans)
1284
+ # the 53 bit numerical version
1285
+ n = 1
1286
+ self._ans_num[0] = <double>0
1287
+ while n <= 1000:
1288
+ self._ans_num[n] = <double>(self_ans[n]) / n
1289
+ n += 1
1290
+
1291
+ def _add_an_coefficients(self, int T):
1292
+ r"""
1293
+ Compute the Fourier coefficients `a_n` for all `n`
1294
+ up to and including `T`.
1295
+ Further doctests in _test_init
1296
+
1297
+ INPUT:
1298
+
1299
+ - ``T`` -- integer
1300
+
1301
+ EXAMPLES::
1302
+
1303
+ sage: from sage.schemes.elliptic_curves.mod_sym_num \
1304
+ ....: import ModularSymbolNumerical
1305
+ sage: M = ModularSymbolNumerical(EllipticCurve("11a1"))
1306
+ sage: M._add_an_coefficients(10000)
1307
+ """
1308
+ cdef llong n
1309
+ # verbose(" enter add_an_coeffs with T=%s" % T, level=5)
1310
+ # we artificially add 100 extra terms, to avoid calling this
1311
+ # function again with only a few new terms
1312
+ T += 100
1313
+
1314
+ self._ans_num = <double *> sig_realloc(self._ans_num,
1315
+ (T+2)*sizeof(double))
1316
+ self._ans = <int*> sig_realloc(self._ans, (T+2)*sizeof(int))
1317
+ if self._ans is NULL or self._ans_num is NULL:
1318
+ if self._ans is not NULL:
1319
+ sig_free(self._ans)
1320
+ if self._ans_num is not NULL:
1321
+ sig_free(self._ans_num)
1322
+ raise MemoryError("Memory error with coefficients.")
1323
+
1324
+ verbose(" not enough precomputed coefficients, "
1325
+ "adding %s" % (T - self._lans), level=3)
1326
+ # if we add more than 20% new values, redo it from scratch
1327
+ if 5* T > 6*self._lans:
1328
+ self_ans = self._E.anlist(T+1, python_ints=True)
1329
+ n = self._lans # only copy new values
1330
+ while n <= T:
1331
+ self._ans[n] = self_ans[n]
1332
+ n += 1
1333
+ n = self._lans
1334
+ self._ans_num[0] = <double>0
1335
+ while n <= T:
1336
+ self._ans_num[n] = <double>(self_ans[n]) / <double>n
1337
+ n += 1
1338
+ # last n such that ans[n] is allowed
1339
+ self._lans = T
1340
+ # otherwise, add new values with a_k
1341
+ else:
1342
+ n = self._lans
1343
+ while n <= T:
1344
+ self._ans[n] = self._Epari.ellak(n).__int__()
1345
+ self._ans_num[n] = <double>(self._ans[n]) / <double>n
1346
+ n += 1
1347
+ # last n such that ans[n] is allowed
1348
+ self._lans = T
1349
+
1350
+ def clear_cache(self):
1351
+ r"""
1352
+ Clear the cached values in all methods of this class.
1353
+
1354
+ EXAMPLES::
1355
+
1356
+ sage: E = EllipticCurve("11a1")
1357
+ sage: M = E.modular_symbol(implementation='num')
1358
+ sage: M(0)
1359
+ 1/5
1360
+ sage: M.clear_cache()
1361
+ sage: M(0)
1362
+ 1/5
1363
+ """
1364
+ cadi = self._cached_methods
1365
+ for me in cadi:
1366
+ cadi[me].clear_cache()
1367
+
1368
+ #================== Low level summation =========
1369
+
1370
+ def _integration_to_tau(self, ComplexNumber tau,
1371
+ int number_of_terms, int prec):
1372
+ r"""
1373
+ Given a point `\tau` in the upper half plane
1374
+ this returns a complex number that is a close
1375
+ approximation to the integral of the modular
1376
+ form from `i\infty` to `\tau`.
1377
+
1378
+ INPUT:
1379
+
1380
+ - ``tau`` -- a point in the upper half plane
1381
+
1382
+ - ``number_of_terms`` -- integer describing
1383
+ how many terms to sum
1384
+
1385
+ - ``prec`` -- integer; setting the precision
1386
+ to ``prec`` bits in all of the computation
1387
+
1388
+ OUTPUT: a complex number
1389
+
1390
+ EXAMPLES::
1391
+
1392
+ sage: from sage.schemes.elliptic_curves.mod_sym_num \
1393
+ ....: import ModularSymbolNumerical
1394
+ sage: I = ComplexField(53).0
1395
+ sage: M = ModularSymbolNumerical(EllipticCurve("11a1"))
1396
+ sage: M._integration_to_tau(0.01*I, 1000, 53) # abs tol 1e-11
1397
+ 0.253841860855911
1398
+ sage: M._integration_to_tau(0.01*I, 1000, 200) # abs tol 1e-20
1399
+ 0.25384186085591068433775876735181198283836641798722...
1400
+ sage: M._integration_to_tau(0.001*I, 1000, 200) # abs tol 1e-20
1401
+ 0.253856919662568106448824346122252246436991427234479...
1402
+
1403
+ sage: E = EllipticCurve("37a1")
1404
+ sage: ms = ModularSymbolNumerical(E)
1405
+ sage: ms._integration_to_tau(0.0001*I, 1000, 53) # abs tol 1e-11
1406
+ -0.0105693920159096
1407
+ sage: ms._integration_to_tau(0.3+0.01*I,1000,60) # abs tol 1e-11
1408
+ 0.41268108621256428 + 0.91370544691462463*I
1409
+ """
1410
+ # verbose(" enter _integration_to_tau with tau=%s, T=%s,"
1411
+ # "prec=%s" % (tau,number_of_terms,prec), level=5)
1412
+ cdef ComplexNumber q, s
1413
+ cdef int n
1414
+
1415
+ # self.nc_sums += 1
1416
+ # self.nc_terms += Integer(number_of_terms)
1417
+
1418
+ if number_of_terms > 10000000:
1419
+ print("Warning: more than 10^7 terms to sum")
1420
+ if number_of_terms > self._lans:
1421
+ self._add_an_coefficients(number_of_terms)
1422
+
1423
+ CC = ComplexField(prec)
1424
+ q = 2 * CC.pi() * CC.gens()[0]
1425
+ q *= CC(tau)
1426
+ q = q.exp()
1427
+ verbose(" start sum over %s terms " % number_of_terms, level=4)
1428
+ s = CC(0)
1429
+ n = number_of_terms
1430
+ # using Horner's rule
1431
+ while n > 0:
1432
+ sig_check()
1433
+ s *= q
1434
+ s += CC(self._ans[n])/n
1435
+ n -= 1
1436
+ s *= q
1437
+ # verbose(" leaving integration_to_tau with sum=%s" % s, level=5)
1438
+ return s
1439
+
1440
+ # the version using double is 70-80 times faster it seems.
1441
+ cdef complex _integration_to_tau_double(self, complex tau,
1442
+ int number_of_terms) noexcept:
1443
+ r"""
1444
+ Given a point `\tau` in the upper half plane
1445
+ this returns a complex number that is a close
1446
+ approximation to `\lambda(tau)`,
1447
+ the integral of the modular
1448
+ form from `i\infty` to `\tau`.
1449
+
1450
+ INPUT:
1451
+
1452
+ - ``tau`` -- a point in the upper half plane
1453
+
1454
+ - ``number_of_terms`` -- integer describing
1455
+ how many terms to sum
1456
+
1457
+ OUTPUT: a complex number
1458
+
1459
+ EXAMPLES::
1460
+
1461
+ sage: from sage.schemes.elliptic_curves.mod_sym_num \
1462
+ ....: import ModularSymbolNumerical
1463
+ sage: M = ModularSymbolNumerical(EllipticCurve("17a1"))
1464
+ sage: M._from_ioo_to_r_approx(9/13,0.01,use_partials=0) # abs tol 1e-5
1465
+ 0.386771552192424 - 2.74574021880459*I
1466
+ """
1467
+ # verbose(" enter integrations_to_tau_double with tau=%s,"
1468
+ # " T=%s" % (tau,number_of_terms), level=5)
1469
+ cdef complex q, s
1470
+ cdef int n
1471
+ # self.nc_sums += 1
1472
+ # self.nc_terms += Integer(number_of_terms)
1473
+
1474
+ if number_of_terms > 10000000:
1475
+ print("Warning: more than 10^7 terms to sum")
1476
+ # raise Warning("more than 10^7 terms to sum")
1477
+ if number_of_terms > self._lans:
1478
+ self._add_an_coefficients(number_of_terms)
1479
+
1480
+ q = complex(0, TWOPI) # 2 pi i
1481
+ q *= tau
1482
+ q = cexp(q)
1483
+ verbose(" start sum over %s terms " % number_of_terms, level=4)
1484
+ s = 0
1485
+ n = number_of_terms
1486
+ # using Horner's rule
1487
+ while n > 0:
1488
+ sig_check()
1489
+ s *= q
1490
+ s += self._ans_num[n]
1491
+ n -= 1
1492
+ s *= q
1493
+ # verbose(" leaving integration_to_tau_double with sum=%s" % s,
1494
+ # level=5)
1495
+ return s
1496
+
1497
+ cdef int _partial_real_sums_double(self, double y, int m,
1498
+ int number_of_terms,
1499
+ double* res) except -1:
1500
+ r"""
1501
+ Given a real positive number `y` (representing
1502
+ the imaginary part of a point in the upper half
1503
+ plane), this returns a list of approximations
1504
+ to the partial sums `\kappa_{j,m}(y)`
1505
+
1506
+ INPUT:
1507
+
1508
+ - ``y`` -- a positive real number
1509
+
1510
+ - ``m`` -- integer
1511
+
1512
+ - ``number_of_terms`` -- integer describing
1513
+ how many terms to sum
1514
+
1515
+ OUTPUT: list of real numbers (in a pointer)
1516
+
1517
+ EXAMPLES::
1518
+
1519
+ sage: from sage.schemes.elliptic_curves.mod_sym_num \
1520
+ ....: import ModularSymbolNumerical
1521
+ sage: M = ModularSymbolNumerical(EllipticCurve("37b2"))
1522
+ sage: M._from_ioo_to_r_approx(0/1,0.01,use_partials=1) # abs tol 1e-5
1523
+ 0.725681061936153
1524
+ """
1525
+ # verbose(" enter partial_real_sums_double with y=%s, m=%s,"
1526
+ # " T=%s" % (y,m,number_of_terms), level=5)
1527
+ cdef double q, qq
1528
+ cdef int n, i
1529
+ # self.nc_sums += 1
1530
+ # self.nc_terms += Integer(number_of_terms)
1531
+
1532
+ if number_of_terms > 10000000:
1533
+ print(" Warning: more than 10^7 terms to sum")
1534
+
1535
+ if number_of_terms > self._lans:
1536
+ self._add_an_coefficients(number_of_terms)
1537
+
1538
+ q = <double>(-TWOPI)
1539
+ q *= y
1540
+ qq = q * <double>m
1541
+ q = exp(q)
1542
+ qq = exp(qq)
1543
+ verbose(" start sum over %s terms " % number_of_terms, level=4)
1544
+ i = 0
1545
+ while i < m:
1546
+ res[i] = 0
1547
+ i += 1
1548
+ n = number_of_terms
1549
+ i = n % m
1550
+ while n > 0:
1551
+ sig_check()
1552
+ res[i] *= qq
1553
+ res[i] += self._ans_num[n]
1554
+ n -= 1
1555
+ i -= 1
1556
+ if i == -1:
1557
+ i = m-1
1558
+ i = 1
1559
+ while i < m:
1560
+ res[i] *= q ** i
1561
+ i += 1
1562
+ res[0] *= qq
1563
+ # verbose(" leaving _partial_real_sums_double with result %s,"
1564
+ # " %s, ... %s" % (res[0], res[1], res[m-1]), level=5)
1565
+ return 0
1566
+
1567
+ def _partial_real_sums(self, RealNumber y, int m,
1568
+ int number_of_terms,
1569
+ int prec):
1570
+ r"""
1571
+ Given a real positive number `y` (representing
1572
+ the imaginary part of a point in the upper half
1573
+ plane), this returns a list of approximations
1574
+ to the partial sums `\kappa_{j,m}(y)`
1575
+
1576
+ INPUT:
1577
+
1578
+ - ``y`` -- a positive real number
1579
+
1580
+ - ``m`` -- integer
1581
+
1582
+ - ``number_of_terms`` -- integer describing
1583
+ how many terms to sum
1584
+
1585
+ - ``prec`` -- integer setting the precision
1586
+ to ``prec`` bits in all of the computation
1587
+
1588
+ OUTPUT: list of real numbers
1589
+
1590
+ EXAMPLES::
1591
+
1592
+ sage: from sage.schemes.elliptic_curves.mod_sym_num \
1593
+ ....: import ModularSymbolNumerical
1594
+ sage: E = EllipticCurve([1,0,-1064,-1,0])
1595
+ sage: m = ModularSymbolNumerical(E)
1596
+ sage: m._partial_real_sums(0.2, 7, 10000, 57)
1597
+ [-0.00008643214783335204,
1598
+ 0.2846256879231407,
1599
+ -0.04049993474185631,
1600
+ -0.01536940717542450,
1601
+ -0.001640896372921393,
1602
+ 4.706713577985852e-8,
1603
+ 0.0001771330855478248]
1604
+ """
1605
+ # verbose(" enter partial_real_sums with y=%s, m=%s,"
1606
+ # " T=%s" % (y,m,number_of_terms), level=5)
1607
+ cdef RealNumber q, qq
1608
+ cdef int n, i
1609
+ # self.nc_sums += 1
1610
+ # self.nc_terms += Integer(number_of_terms)
1611
+
1612
+ if number_of_terms > 10000000:
1613
+ print(" Warning: more than 10^7 terms to sum")
1614
+
1615
+ if number_of_terms > self._lans:
1616
+ self._add_an_coefficients(number_of_terms)
1617
+
1618
+ RR = RealField(prec)
1619
+ q = - 2 * RR.pi()
1620
+ q *= RR(y)
1621
+ qq = q * m
1622
+ q = q.exp()
1623
+ qq = qq.exp()
1624
+ verbose(" start sum over %s terms " % number_of_terms, level=4)
1625
+ i = 0
1626
+ res = []
1627
+ while i < m:
1628
+ res.append(RR(0))
1629
+ i += 1
1630
+ n = number_of_terms
1631
+ i = n % m
1632
+ while n > 0:
1633
+ sig_check()
1634
+ res[i] *= qq
1635
+ res[i] += RR(self._ans[n])/n
1636
+ n -= 1
1637
+ i -= 1
1638
+ if i == -1:
1639
+ i = m-1
1640
+ i = 1
1641
+ while i < m:
1642
+ res[i] *= q ** i
1643
+ i += 1
1644
+ res[0] *= qq
1645
+ # verbose(" leaving _partial_real_sums with result"
1646
+ # " %s, %s, ... %s" % (res[0], res[1], res[m-1]), level=5)
1647
+ return res
1648
+
1649
+ #================
1650
+
1651
+ def _get_truncation_and_prec(self, double y, double eps):
1652
+ r"""
1653
+ Compute the numbers of terms needed in the sum approximating
1654
+ the integral, and the precision of each term needed.
1655
+
1656
+ INPUT:
1657
+
1658
+ - ``y`` -- a positive real number, representing the imaginary
1659
+ part of an element in the upper half plane and
1660
+
1661
+ - ``eps`` -- a positive real number, the maximal allowed error
1662
+
1663
+ OUTPUT: two integers `T` and `b`
1664
+
1665
+ If `T` would be larger than `2^31`, the value (-1,-1) is
1666
+ returned instead.
1667
+
1668
+ EXAMPLES::
1669
+
1670
+ sage: from sage.schemes.elliptic_curves.mod_sym_num \
1671
+ ....: import ModularSymbolNumerical
1672
+ sage: M = ModularSymbolNumerical(EllipticCurve("11a2"))
1673
+ sage: M._get_truncation_and_prec(0.001,0.0001)
1674
+ (2275, 53)
1675
+ sage: M._get_truncation_and_prec(0.01,0.01)
1676
+ (118, 53)
1677
+ sage: M._get_truncation_and_prec(0.00001,0.01)
1678
+ (216405, 53)
1679
+ sage: M._get_truncation_and_prec(0.00001,0.0001)
1680
+ (283246, 58)
1681
+
1682
+ sage: M = ModularSymbolNumerical(EllipticCurve("5077a1"))
1683
+ sage: M._get_truncation_and_prec(10^(-11),10^(-2))
1684
+ (-1, -1)
1685
+ """
1686
+ # verbose(" enter _get_truncation_and_prec with y=%s"
1687
+ # " and eps=%s" % (y,eps), level=5)
1688
+ # how much of the error comes from truncation and how much
1689
+ # from precision.
1690
+ DEF split_error_truncations = 0.99
1691
+ DEF split_error_prec = 1 - split_error_truncations
1692
+
1693
+ cdef double tt, bb, A, twopiy
1694
+ cdef int T, B, T0
1695
+
1696
+ twopiy = <double>TWOPI
1697
+ twopiy *= y
1698
+ tt = twopiy
1699
+ tt *= split_error_truncations * eps
1700
+ tt = log(tt)
1701
+ tt = - tt / twopiy
1702
+ if tt < 2147483648:
1703
+ T = <int>(ceil(tt))
1704
+ else:
1705
+ T = -1
1706
+ return T, T
1707
+ # verbose(" now tt =%s, twopiy=%s, T=%s" % (tt,twopiy,T), level=4)
1708
+
1709
+ # the justification for these numbers is explained at the
1710
+ # very end of this file
1711
+ if T > 4324320:
1712
+ A = 6
1713
+ T0 = 4324320
1714
+ elif T > 2162160:
1715
+ A = 5
1716
+ T0 = 2162160
1717
+ elif T > 831600:
1718
+ A = 4
1719
+ T0 = 831600
1720
+ elif T > 277200:
1721
+ A = 3
1722
+ T0 = 277200
1723
+ elif T > 55440:
1724
+ A = 2
1725
+ T0 = 55440
1726
+ elif T > 10080:
1727
+ A = 3/2
1728
+ T0 = 10080
1729
+ else: # does not improve
1730
+ A = 1
1731
+ T0 = T
1732
+
1733
+ tt -= log(A)/twopiy
1734
+ T = min(T, max(<int>(ceil(tt)), T0))
1735
+ # verbose(" now tt =%s, twopiy=%s, T=%s" % (tt,twopiy,T), level=4)
1736
+
1737
+ bb = split_error_prec * eps
1738
+ bb /= T + bb
1739
+ bb /= 2
1740
+ bb /= T
1741
+ bb = - log(bb)/ log(2)
1742
+ B = <int>(ceil(bb))
1743
+ B = max(B, 53)
1744
+ T = max(T, 100)
1745
+ # verbose(" leaving _get_truncation_and_prec with T=%s,"
1746
+ # " B=%s" % (T,B), level=5)
1747
+ return T, B
1748
+
1749
+ # ===============
1750
+
1751
+ @cached_method # its modified below for max eps
1752
+ def _kappa(self, llong m, llong z, eps=None):
1753
+ r"""
1754
+ This returns all `\kappa_{j,m}(1/\sqrt{z})` for a given
1755
+ integer `m` and another integer `z`. This function `\kappa` is
1756
+ defined by the following sum:
1757
+
1758
+ .. MATH::
1759
+
1760
+ \kappa_{j,m}(y) = \sum_{n\equiv j \bmod m} \frac{a_n}{n}
1761
+ e^{- 2\pi n y}
1762
+
1763
+ This is used to compute all the modular symbols `[a/m]` for
1764
+ a fixed `m`.
1765
+
1766
+ INPUT:
1767
+
1768
+ - ``m`` -- integer (long long)
1769
+
1770
+ - ``z`` -- another integer (long long)
1771
+
1772
+ - ``eps`` -- either ``None`` (default) or a real number (double),
1773
+ describing the precision to which the terms are computed.
1774
+ Each term is off by less than ``eps``/``m``. If ``None``, the
1775
+ ``eps`` is chosen from the precomputed precision related
1776
+ to the periods.
1777
+
1778
+ OUTPUT: list of `m` real numbers
1779
+
1780
+ EXAMPLES::
1781
+
1782
+ sage: E = EllipticCurve("43a1")
1783
+ sage: M = E.modular_symbol(implementation='num')
1784
+ sage: M._kappa(3,4) # abs tol 1e-11
1785
+ [-5.379533671373222e-05, 0.043215661934968536, -0.0018675632930897528]
1786
+ sage: M._kappa(3,17) # abs tol 1e-11
1787
+ [-0.0068222516409258815, 0.2189879706778559, -0.047856204984566546]
1788
+ sage: M._kappa(3,12345,0.01) # abs tol 1e-11
1789
+ [-0.04800196513225438, 1.501878908740486, -1.4540035671680258]
1790
+ sage: M._kappa(3,12345,0.001) # abs tol 1e-11
1791
+ [-0.04790883326924006, 1.5019073235739455, -1.4539982909123526]
1792
+
1793
+ This is to check that the caching works when asked with lower
1794
+ precision::
1795
+
1796
+ sage: M._kappa(7,9,0.0001) # abs tol 1e-11
1797
+ [-3.848348562241613e-46,
1798
+ 0.12314471107014528,
1799
+ -0.01516461914094593,
1800
+ -0.0012449611795634324,
1801
+ 0.00011498287475216501,
1802
+ -2.265525136998248e-05,
1803
+ 2.3248943281270047e-06]
1804
+ sage: M._kappa(7,9,0.1) # abs tol 1e-11
1805
+ [-3.848348562241613e-46,
1806
+ 0.12314471107014528,
1807
+ -0.01516461914094593,
1808
+ -0.0012449611795634324,
1809
+ 0.00011498287475216501,
1810
+ -2.265525136998248e-05,
1811
+ 2.3248943281270047e-06]
1812
+ """
1813
+ # verbose(" enter _kappa with m=%s, z=%s and eps=%s" % (m,z,eps),
1814
+ # level=5)
1815
+ cdef:
1816
+ int T, prec, j
1817
+ double * ra
1818
+ object res
1819
+ double y, epsi
1820
+ RealNumber yr
1821
+
1822
+ y = <double>(z)
1823
+ y = sqrt(y)
1824
+ y = 1/y
1825
+ if eps is None:
1826
+ epsi = self._eps_unitary_plus
1827
+ if epsi > self._eps_unitary_minus:
1828
+ epsi = self._eps_unitary_minus
1829
+ else:
1830
+ epsi = eps
1831
+
1832
+ # if called with a previous (m,z,eps) but a larger eps,
1833
+ # return the cached value
1834
+ cac = self._cached_methods['_kappa'].cache
1835
+ for ke in cac:
1836
+ mm, zz, eeps = ke[0]
1837
+ if mm == m and zz == z:
1838
+ if eps is None:
1839
+ if eeps is None or eeps <= epsi:
1840
+ return cac[ke]
1841
+ else:
1842
+ if eeps is not None and eeps <= eps:
1843
+ return cac[ke]
1844
+
1845
+ T, prec = self._get_truncation_and_prec(y, epsi)
1846
+ if T == -1:
1847
+ raise ValueError("Too many terms > 2^31 would have to be"
1848
+ + "summed up. Giving up.")
1849
+ T += m
1850
+ # verbose(" precision in _kappa set to %s,"
1851
+ # " summing over %s terms" % (prec,T), level=3)
1852
+
1853
+ if prec > 53:
1854
+ RR = RealField(prec)
1855
+ yr = RR(z)
1856
+ yr = yr.sqrt()
1857
+ yr = yr**(-1)
1858
+ res = self._partial_real_sums(yr, m, T, prec)
1859
+ # return a python list of doubles that we cache
1860
+ res = [<double>(res[j]) for j in range(m)]
1861
+ else:
1862
+ ra = <double *> sig_malloc(m * sizeof(double))
1863
+ if ra is NULL:
1864
+ raise MemoryError
1865
+ _ = self._partial_real_sums_double(y, m, T, ra)
1866
+ res = [ra[j] for j in range(m)]
1867
+ sig_free(ra)
1868
+ # verbose(" leaving _kappa with"
1869
+ # " [%s, %s, ... %s]" % (res[0], res[1], res[m-1]), level=5)
1870
+ return res
1871
+
1872
+ def _from_ioo_to_r_approx(self, Rational r, double eps,
1873
+ int use_partials=2):
1874
+ r"""
1875
+ Given a cusp `r` this computes the integral `\lambda(r)`
1876
+ from `i\infty` to `r` to the given precision `eps`.
1877
+
1878
+ INPUT:
1879
+
1880
+ - ``r`` -- a rational number
1881
+
1882
+ - ``eps`` -- a positive real number
1883
+
1884
+ - ``use_partials`` -- int: 0 don't use partials,
1885
+ 1 use them, 2 (default) decide if meaningful
1886
+
1887
+ OUTPUT: a complex number
1888
+
1889
+ EXAMPLES::
1890
+
1891
+ sage: from sage.schemes.elliptic_curves.mod_sym_num \
1892
+ ....: import ModularSymbolNumerical
1893
+ sage: E = EllipticCurve("37a1")
1894
+ sage: m = ModularSymbolNumerical(E)
1895
+ sage: m._from_ioo_to_r_approx(1/7,0.01) # abs tol 1e-11
1896
+ 2.99345862520910 - 4.24742221394325e-8*I
1897
+ sage: m._from_ioo_to_r_approx(2/7,0.01) # abs tol 1e-11
1898
+ 2.45138940312063*I
1899
+ sage: m._from_ioo_to_r_approx(0/1,0.001) # abs tol 1e-11
1900
+ -2.77555756156289e-17
1901
+
1902
+ sage: E = EllipticCurve("37b1")
1903
+ sage: m = ModularSymbolNumerical(E)
1904
+ sage: m._from_ioo_to_r_approx(0/1,0.01) # abs tol 1e-11
1905
+ 0.725681061936153
1906
+
1907
+ sage: E = EllipticCurve("5077a1")
1908
+ sage: m = ModularSymbolNumerical(E)
1909
+ sage: m._from_ioo_to_r_approx(-1/7,0.01, use_partials=1) # abs tol 1e-11
1910
+ 6.22747859174503 - 1.48055642530800*I
1911
+ sage: m._from_ioo_to_r_approx(-1/7,0.01, use_partials=0) # abs tol 1e-11
1912
+ 6.22747410432385 - 1.48055182979493*I
1913
+
1914
+ This uses 65 bits of precision::
1915
+
1916
+ sage: m._from_ioo_to_r_approx(-1/7,0.0000000001) # abs tol 1e-11
1917
+ 6.227531974630294568 - 1.480548268241443085*I
1918
+ """
1919
+ # verbose(" enter _from_ioo_to_r_approx with r=%s"
1920
+ # " and eps=%s" % (r,eps), level=5)
1921
+ cdef:
1922
+ llong m, Q, epsQ, a, u
1923
+ double yy, taui
1924
+ int T, prec, j
1925
+ double complex tauc, tauphc, int1c, int2c, twopii, ze1, ze2, su
1926
+ ComplexNumber tau, tauph, int1, int2
1927
+ llong * wQ = [0L, 0L, 0L, 0L]
1928
+ object ka
1929
+
1930
+ rc = _CuspsForModularSymbolNumerical(r, self._N_E)
1931
+ Q = rc._width
1932
+ _ = rc.atkin_lehner(wQ)
1933
+ m = rc._m
1934
+ epsQ = self._epsQs[Q]
1935
+ r = rc._r
1936
+
1937
+ # now we determine the best place to cut the integration.
1938
+ # we will integrate from r to r+i*yy and then to i*oo
1939
+ yy = <double>Q
1940
+ yy = sqrt(yy)
1941
+ yy = 1 / yy / m
1942
+ T, prec = self._get_truncation_and_prec(yy, eps/2)
1943
+ if T == -1:
1944
+ raise ValueError("Too many terms > 2^31 would have to be"
1945
+ + " summed up. Giving up.")
1946
+ if m == 1:
1947
+ use_partials = 0
1948
+ if use_partials == 2:
1949
+ use_partials = (prec==53) and (m**4 < self._N_E or m < PARTIAL_LIMIT)
1950
+
1951
+ if not use_partials and prec > 53:
1952
+ CC = ComplexField(prec)
1953
+ tau = CC(-Q)
1954
+ tau = tau.sqrt()
1955
+ tau = r - 1/tau/m
1956
+ tauph = (tau * wQ[0] + wQ[1])/(wQ[2]*tau + wQ[3])
1957
+ verbose(" computing integral from i*oo to %s using %s terms "
1958
+ "and precision %s" % (tau, T, prec),level=2)
1959
+ int1 = self._integration_to_tau(tau, T, prec)
1960
+ verbose(" yields %s " % int1, level=2)
1961
+ verbose(" compute integral from %s to %s by computing an "
1962
+ "integral from i*oo to %s" % (r, tau, tauph),level=2)
1963
+ int2 = self._integration_to_tau(tauph, T, prec)
1964
+ int2 *= -epsQ
1965
+ verbose(" yields %s" % int2, level=2)
1966
+ return int2 + int1
1967
+
1968
+ elif not use_partials: # prec = 53
1969
+ taui = <double>(Q)
1970
+ taui = sqrt(taui)
1971
+ taui = 1/taui/m
1972
+ tauc = complex(r, taui)
1973
+ # verbose("act on %s by [[%s,%s],[%s,%s]]" % (tauc, wQ[0],
1974
+ # wQ[1], wQ[2], wQ[3]), level =4)
1975
+ tauphc = (tauc * wQ[0] + wQ[1])/(wQ[2]*tauc + wQ[3])
1976
+ verbose(" computing integral from i*oo to %s using %s terms "
1977
+ "in fast double precision" % (tauc, T),level=2)
1978
+ int1c = self._integration_to_tau_double(tauc, T)
1979
+ verbose(" yields %s " % int1c, level=2)
1980
+ verbose(" compute integral from %s to %s by computing an "
1981
+ "integral from i*oo to %s" % (r, tauc, tauphc),level=2)
1982
+ int2c = self._integration_to_tau_double(tauphc, T)
1983
+ int2c *= -epsQ
1984
+ verbose(" yields %s" % int2c, level=2)
1985
+ CC = ComplexField(prec)
1986
+ return CC(int2c + int1c)
1987
+
1988
+ else: # use_partial
1989
+ verbose(" computing integral from i*oo to %s using "
1990
+ "using partials with "
1991
+ "y =%s" % (r, yy), level=2)
1992
+ ka = self._kappa(m, m*m*Q,eps/2)
1993
+ a = rc._a
1994
+ twopii = TWOPI * complex("j")
1995
+ ze1 = twopii / m * a
1996
+ ze1 = cexp(ze1)
1997
+ u = llinvmod(Q * a, m)
1998
+ ze2 = - twopii / m * u
1999
+ ze2 = cexp(ze2)
2000
+ j = 0
2001
+ su = 0
2002
+ verbose(" summing up %s partial sums, having set u = %s,"
2003
+ " z1 =%s, z2=%s" % (m, u, ze1, ze2), level=4)
2004
+ while j < m:
2005
+ sig_check()
2006
+ su += ka[j] * ((ze1 ** j) - epsQ * (ze2 ** j))
2007
+ j += 1
2008
+ CC = ComplexField(prec)
2009
+ return CC(su)
2010
+
2011
+ cdef _from_r_to_rr_approx_direct(self, Rational r, Rational rr,
2012
+ Integer epsQ, Integer epsQQ,
2013
+ llong* wQ, llong* wQQ,
2014
+ int T, int prec, double eps,
2015
+ int use_partials=2):
2016
+ r"""
2017
+ This is just a helper function for _from_r_to_rr_approx. In case
2018
+ the integral is evaluated directly this function is called.
2019
+
2020
+ INPUT:
2021
+
2022
+ - ``r``, ``rr`` -- two Rationals
2023
+
2024
+ - ``espQ``, ``espQ`` -- two Integers
2025
+
2026
+ - ``T``, ``prec`` -- two ints
2027
+
2028
+ - ``use_partials`` -- int: 0 don't use partials,
2029
+ 1 use them, 2 (default) decide if meaningful
2030
+
2031
+ OUTPUT: a complex number
2032
+
2033
+ EXAMPLES::
2034
+
2035
+ sage: from sage.schemes.elliptic_curves.mod_sym_num \
2036
+ ....: import ModularSymbolNumerical
2037
+ sage: M = ModularSymbolNumerical(EllipticCurve("11a1"))
2038
+ sage: M._from_r_to_rr_approx(1/3,0/1,0.000001,use_partials=0) # abs tol 1e-11
2039
+ -0.634604652139777 + 1.45881661693850*I
2040
+ sage: M._from_r_to_rr_approx(1/3,0/1,0.000001,use_partials=1) # abs tol 1e-11
2041
+ -0.634604652139777 + 1.45881661693849*I
2042
+ """
2043
+ cdef:
2044
+ ComplexNumber tau0, tau1, int1, int2
2045
+ RealNumber x1, x2, s
2046
+ complex tau0c, tau1c, int1c, int2c, ze1, ze2, su, twopii
2047
+ llong g, u, v, uu, vv, D, a, aa, m, mm, Q, QQ, z, xi, xixi
2048
+ int oi, j
2049
+ double x1d, x2d, sd
2050
+
2051
+ # verbose(" enter _from_r_to_rr_approx_direct with r=%s,"
2052
+ # " rr=%s,..." % (r,rr), level=5)
2053
+ rc = _CuspsForModularSymbolNumerical(r, self._N_E)
2054
+ m = rc._m
2055
+ a = rc._a
2056
+ Q = rc._width
2057
+ rrc = _CuspsForModularSymbolNumerical(rr,self._N_E)
2058
+ mm = rrc._m
2059
+ aa = rrc._a
2060
+ QQ = rrc._width
2061
+ oi = llxgcd(Q*a, m, &u, &v)
2062
+ oi = llxgcd(QQ*aa, mm, &uu, &vv)
2063
+ # verbose(" The inverses are (u,v)=(%s,%s) and
2064
+ # (uu,vv)=%s,%s" % (u,v,uu,vv), level=3)
2065
+
2066
+ if use_partials == 2:
2067
+ g = llgcd(Q, QQ)
2068
+ D = Q * QQ
2069
+ D /= g
2070
+ D *= llabs(a*mm-aa*m)
2071
+ use_partials = (prec==53) and (D**4 < self._N_E or D < PARTIAL_LIMIT)
2072
+
2073
+ CC = ComplexField(prec)
2074
+ if not use_partials and prec > 53:
2075
+ RR = RealField(prec)
2076
+ x1 = RR(Q)
2077
+ x1 = x1*aa*u + mm*v
2078
+ x1 = x1/Q/(a*mm-aa*m)
2079
+ x2 = RR(QQ)
2080
+ x2 = x2*a*uu + m*vv
2081
+ x2 = x2/QQ/(aa*m-a*mm)
2082
+ s = RR(Q)
2083
+ s = s*QQ
2084
+ s = s.sqrt()
2085
+ s = s * llabs(a*mm-aa*m)
2086
+ s = 1/s
2087
+ tau0 = CC(x1, s)
2088
+ tau1 = CC(x2, s)
2089
+ # verbose(" two points are %s and %s" % (tau0, tau1), level=3)
2090
+ verbose(" computing integral from %s to tau by computing "
2091
+ "the integral from i*oo to %s" % (r, tau0), level=3)
2092
+ int1 = self._integration_to_tau(tau0, T, prec)
2093
+ int1 *= - epsQ
2094
+ verbose(" yields %s " % int1, level=3)
2095
+ verbose(" computing integral from tau to %s by computing "
2096
+ "the integral from i*oo to %s" % (rr, tau1), level=3)
2097
+ int2 = self._integration_to_tau(tau1, T, prec)
2098
+ int2 *= epsQQ
2099
+ verbose(" yields %s " % int2, level=3)
2100
+ ans = int2 + int1
2101
+ elif not use_partials:
2102
+ x1d = Q
2103
+ x1d = x1d*aa*u + mm*v
2104
+ x1d = x1d/Q/(a*mm-aa*m)
2105
+ x2d = QQ
2106
+ x2d = x2d*a*uu + m*vv
2107
+ x2d = x2d/QQ/(aa*m-a*mm)
2108
+ sd = Q
2109
+ sd = sd*QQ
2110
+ sd = sqrt(sd)
2111
+ sd = sd * llabs(a*mm-aa*m)
2112
+ sd = 1/sd
2113
+ tau0c = complex(x1d,sd)
2114
+ tau1c = complex(x2d,sd)
2115
+ verbose(" computing integral from %s to tau by computing "
2116
+ "the integral from i*oo to %s" % (r, tau0c),
2117
+ level=3)
2118
+ int1c = self._integration_to_tau_double(tau0c, T)
2119
+ int1c *= -epsQ
2120
+ verbose(" yields %s " % int1c, level=3)
2121
+ verbose(" computing integral from tau to %s by computing "
2122
+ "the integral from i*oo to "
2123
+ "%s" % (rr, tau1c), level=3)
2124
+ int2c = self._integration_to_tau_double(tau1c, T)
2125
+ int2c *= epsQQ
2126
+ verbose(" yields %s " % int2c, level=3)
2127
+ ans = int2c + int1c
2128
+ else: # use_partials
2129
+ g = llgcd(Q, QQ)
2130
+ D = Q * QQ
2131
+ D /= g
2132
+ D *= llabs(a*mm-aa*m)
2133
+ xi = (Q*aa*u+v*mm) * (QQ // g) * llsign(a*mm-aa*m)
2134
+ xixi = (QQ*a*uu+vv*m) * (Q // g) * llsign(aa*m-a*mm)
2135
+ z = Q * QQ * (a*mm-aa*m)**2
2136
+ ka = self._kappa(D, z, eps/2)
2137
+ twopii = TWOPI * complex("j")
2138
+ ze1 = twopii / D * xixi
2139
+ ze1 = cexp(ze1)
2140
+ ze2 = twopii / D * xi
2141
+ ze2 = cexp(ze2)
2142
+ j = 0
2143
+ su = 0
2144
+ verbose(" summing up %s partial sums" % D, level=4)
2145
+ while j < D:
2146
+ sig_check()
2147
+ su += (ze1**j * epsQQ - ze2**j * epsQ) * ka[j]
2148
+ j += 1
2149
+ ans = su
2150
+ return CC(ans)
2151
+
2152
+ def _from_r_to_rr_approx(self, Rational r, Rational rr, double eps,
2153
+ method=None, int use_partials=2):
2154
+ r"""
2155
+ Given a cusp `r` this computes the integral `\lambda(r\to r')`
2156
+ from `r` to `r'` to the given precision ``eps``.
2157
+
2158
+ INPUT:
2159
+
2160
+ - ``r`` -- a rational number `r`
2161
+
2162
+ - ``rr`` -- a second rational number `r'`
2163
+
2164
+ - ``eps`` -- a positive real number
2165
+
2166
+ - ``method`` -- string or ``None``: either ``'direct'``,
2167
+ ``'indirect'``, or ``'both'``. When method is not given (default),
2168
+ then the better of the two is chosen. ``'both'`` raises an error if
2169
+ the two methods differ by more than ``eps``.
2170
+
2171
+ - ``use_partials`` -- int: 0 don't use partials,
2172
+ 1 use them, 2 (default) decide if meaningful
2173
+
2174
+ OUTPUT: a complex number
2175
+
2176
+ EXAMPLES::
2177
+
2178
+ sage: from sage.schemes.elliptic_curves.mod_sym_num \
2179
+ ....: import ModularSymbolNumerical
2180
+ sage: M = ModularSymbolNumerical(EllipticCurve("11a1"))
2181
+ sage: M._from_r_to_rr_approx(0/1,2/5,0.01) # abs tol 1e-11
2182
+ 1.90381395641933 - 1.45881661693850*I
2183
+ sage: M._from_r_to_rr_approx(0/1,2/5,0.001, "both", use_partials=0) # abs tol 1e-11
2184
+ 1.90381395641931 - 1.45881661693851*I
2185
+ sage: M._from_r_to_rr_approx(0/1,2/5,0.001, "both", use_partials=1) # abs tol 1e-11
2186
+ 1.90381395641933 - 1.45881661693850*I
2187
+
2188
+ sage: M._from_r_to_rr_approx(1/11,1/7,0.001) # abs tol 1e-11
2189
+ -0.888446512995687 + 1.45881661693850*I
2190
+ sage: M._from_r_to_rr_approx(0/1,44/98761,0.001) # abs tol 1e-11
2191
+ 0.634604184365293 + 1.45881886531983*I
2192
+ sage: M._from_r_to_rr_approx(0/1,123/456,0.0000001) # abs tol 1e-11
2193
+ 1.26920930437008 - 2.91763323391590*I
2194
+
2195
+ sage: M = ModularSymbolNumerical(EllipticCurve("389a1"))
2196
+ sage: M._from_r_to_rr_approx(0/1,1/5,0.0001, "both") # abs tol 1e-5
2197
+ -4.98042489791268 - 6.06124058444291e-8*I
2198
+ sage: M._from_r_to_rr_approx(1/3,1/7,0.001, "both", use_partials=0) # abs tol 1e-5
2199
+ -2.49020330904154 + 5.91520739782657*I
2200
+ sage: M._from_r_to_rr_approx(1/3,1/7,0.0001, "both", use_partials=0) # abs tol 1e-5
2201
+ -2.49021239793944 + 5.91521298876557*I
2202
+ sage: M._from_r_to_rr_approx(1/3,1/7,0.0001, "both") # abs tol 1e-5
2203
+ -2.49021247526015 + 5.91521314939661*I
2204
+
2205
+
2206
+ sage: M = ModularSymbolNumerical(EllipticCurve("5077a1"))
2207
+ sage: M._from_r_to_rr_approx(0/1, -7/3179, 0.001) # abs tol 1e-5 # long time
2208
+ -6.22753195853020 - 5.92219314384901*I
2209
+
2210
+ sage: E = EllipticCurve([91,127])
2211
+ sage: M = ModularSymbolNumerical(E)
2212
+ sage: M._from_r_to_rr_approx(7/11,14/75,0.01,"direct")
2213
+ Traceback (most recent call last):
2214
+ ...
2215
+ ValueError: Too many terms > 2^31 would have to be summed up. Giving up.
2216
+ """
2217
+ cdef:
2218
+ llong m, Q, mm, QQ, a, aa
2219
+ llong * wQ = [0L, 0L, 0L, 0L]
2220
+ llong * wQQ = [0L, 0L, 0L, 0L]
2221
+ Integer epsQ, epsQQ
2222
+ double s, yy
2223
+ ComplexNumber ans, ans2
2224
+ int T=0, prec=0, T1=0, T2=0, oi
2225
+
2226
+ # verbose(" enter _from_r_to_rr_approx with r=%s,"
2227
+ # " rr=%s, " % (r,rr), level=5)
2228
+ rc = _CuspsForModularSymbolNumerical(r, self._N_E)
2229
+ m = rc._m
2230
+ a = rc._a
2231
+ Q = rc._width
2232
+ oi = rc.atkin_lehner(wQ)
2233
+ epsQ = self._epsQs[Q]
2234
+ r = rc._r
2235
+
2236
+ rrc = _CuspsForModularSymbolNumerical(rr,self._N_E)
2237
+ mm = rrc._m
2238
+ aa = rrc._a
2239
+ QQ = rrc._width
2240
+ oi = rrc.atkin_lehner(wQQ)
2241
+ epsQQ = self._epsQs[QQ]
2242
+ rr = rrc._r
2243
+
2244
+ if r == rr:
2245
+ return ComplexField(53)(0)
2246
+
2247
+ # now we determine the best place to cut the direct integration.
2248
+ # we will integrate from r to x+i*y and then to rr
2249
+ if method != "indirect":
2250
+ # overflow danger
2251
+ s = <double>Q
2252
+ s *= QQ
2253
+ s = sqrt(s)
2254
+ s = s * llabs(a*mm-aa*m)
2255
+ s = 1/s
2256
+ # verbose(" direct method goes to s=%s and eps=%s" % (s,eps),
2257
+ # level=3)
2258
+ T, prec = self._get_truncation_and_prec(s, eps/2)
2259
+ # verbose(" giving T=%s and prec=%s" % (T,prec), level=3)
2260
+ if T == -1:
2261
+ if method == "direct" or method == "both":
2262
+ raise ValueError("Too many terms > 2^31 would have to"
2263
+ + " be summed up. Giving up.")
2264
+ else: # method was None
2265
+ method = "indirect"
2266
+
2267
+ # now we compare it to the indirect integration via i*oo
2268
+ if method != "direct":
2269
+ yy = <double>Q
2270
+ yy = sqrt(yy)
2271
+ yy = 1/yy/m
2272
+ T1, prec1 = self._get_truncation_and_prec(yy, eps/4)
2273
+ yy = <double>QQ
2274
+ yy = sqrt(yy)
2275
+ yy = 1/yy/mm
2276
+ T2, prec2 = self._get_truncation_and_prec(yy, eps/4)
2277
+ if T1 == -1 or T2 == -1:
2278
+ if method == "indirect" or method == "both":
2279
+ raise ValueError("Too many terms > 2^31 would have to"
2280
+ + " be summed up. Giving up.")
2281
+ else: # method was None
2282
+ method = "direct"
2283
+
2284
+ if method is None:
2285
+ if prec > 53 and prec1 == 53 and prec2 == 53:
2286
+ method = "indirect"
2287
+ elif prec == 53 and (prec1>53 or prec2>53):
2288
+ method = "direct"
2289
+ elif T < T1 + T2:
2290
+ method = "direct"
2291
+ else:
2292
+ method = "indirect"
2293
+
2294
+ if method == "direct" or method == "both":
2295
+ verbose(" using the direct integration from %s to %s with "
2296
+ "%s terms to sum" % (r, rr, T), level=2)
2297
+ # self.nc_direct += 1
2298
+ ans = self._from_r_to_rr_approx_direct(r, rr, epsQ, epsQQ,
2299
+ wQ, wQQ, T, prec, eps,
2300
+ use_partials)
2301
+ if method != "both":
2302
+ return ans
2303
+
2304
+ if method == "indirect" or method == "both":
2305
+ verbose(" using the indirect integration from %s to %s "
2306
+ "with %s terms to sum" % (r, rr, T1+T2), level=2)
2307
+ # self.nc_indirect += 1
2308
+ ans2 = (self._from_ioo_to_r_approx(r, eps/2,
2309
+ use_partials=use_partials)
2310
+ - self._from_ioo_to_r_approx(rr, eps/2,
2311
+ use_partials=use_partials))
2312
+ if method != "both":
2313
+ return ans2
2314
+
2315
+ if method == "both":
2316
+ if not use_partials and not (ans - ans2).abs() < eps:
2317
+ txt = "Bug in modular symbols. "
2318
+ txt += "The indirect and direct computation of the modular "
2319
+ txt += "symbol from %s to %s differ by too much" % (r, rr)
2320
+ raise RuntimeError(txt)
2321
+
2322
+ return (ans + ans2)/2
2323
+
2324
+ def _transportable_approx(self, Rational r, Rational rr, double eps):
2325
+ r"""
2326
+ Given two cusps `r` and `r'`, which are `\Gamma_0(N)`-equivalent,
2327
+ this computes the integral `\lambda(r\to r')` by transporting
2328
+ the path to a path between `\tau` and `\gamma(\tau)` for
2329
+ `\gamma\in\Gamma_0(N)` and a well-chosen `\tau`.
2330
+
2331
+ So far we have only implemented that it is transported close
2332
+ to `0` or `i\infty`. Note that this method does not require the
2333
+ cusps to be unitary.
2334
+
2335
+ INPUT:
2336
+
2337
+ - ``r`` -- a rational number
2338
+
2339
+ - ``rr`` -- another rational number
2340
+
2341
+ - ``eps`` -- a positive real number
2342
+
2343
+ OUTPUT: a complex number
2344
+
2345
+ EXAMPLES::
2346
+
2347
+ sage: from sage.schemes.elliptic_curves.mod_sym_num \
2348
+ ....: import ModularSymbolNumerical
2349
+ sage: M = ModularSymbolNumerical(EllipticCurve("11a1"))
2350
+ sage: M._transportable_approx(0/1,-2/7,0.001) # abs tol 1e-11
2351
+ -0.634604652139777 + 1.45881661693850*I
2352
+ sage: M._from_r_to_rr_approx(0/1,-2/7,0.001) # abs tol 1e-11
2353
+ -0.634604652139776 + 1.45881661693850*I
2354
+ sage: M._from_r_to_rr_approx(0/1,-2/7,0.0001) # abs tol 1e-11
2355
+ -0.634604652139776 + 1.45881661693850*I
2356
+ sage: M._from_r_to_rr_approx(0/1,-2/7,0.00001) # abs tol 1e-11
2357
+ -0.634604652139776 + 1.45881661693850*I
2358
+ sage: M._from_r_to_rr_approx(0/1,-2/7,0.000001) # abs tol 1e-11
2359
+ -0.634604652139776 + 1.45881661693850*I
2360
+
2361
+ sage: M = ModularSymbolNumerical(EllipticCurve("37a1"))
2362
+ sage: M._transportable_approx(0/1,-1/19,0.001) # abs tol 1e-11
2363
+ -1.14879551982305e-8 + 1.65994273881864e-10*I
2364
+ sage: M._transportable_approx(0/1,-4/17,0.001) # abs tol 1e-11
2365
+ -2.99345356727791 + 2.45138870627435*I
2366
+ sage: M._transportable_approx(0/1,-4/17,0.00001) # abs tol 1e-11
2367
+ -2.99345863532461 + 2.45138938269979*I
2368
+ sage: M._from_r_to_rr_approx(0/1,-4/17,0.00001) # abs tol 1e-11
2369
+ -2.99345862657997 + 2.45138938852658*I
2370
+
2371
+ This goes via i `\infty`::
2372
+
2373
+ sage: M = ModularSymbolNumerical(EllipticCurve("5077a1"))
2374
+ sage: M._transportable_approx(0/1, -35/144, 0.001) # abs tol 1e-11
2375
+ -6.22753189644996 + 3.23405342839145e-7*I
2376
+ sage: M._from_r_to_rr_approx(0/1, -35/144, 0.001) # abs tol 1e-10
2377
+ -6.22753204310913 - 1.31710951034592e-8*I
2378
+
2379
+ While this one goes via 0::
2380
+
2381
+ sage: M._transportable_approx(0/1, -7/31798, 0.001) # abs tol 1e-11
2382
+ -7.01577418382726e-9 - 7.40274138232394*I
2383
+ sage: M._from_r_to_rr_approx(0/1, -7/31798, 0.001) # abs tol 1e-5 # long time
2384
+ -7.02253033502132e-9 - 7.40274138234031*I
2385
+ """
2386
+ cdef:
2387
+ Integer c, a, b, d
2388
+ int T, prec
2389
+ double yy
2390
+ ComplexNumber tau1, tau2, int1, int2
2391
+ complex tau1c, tau2c, int1c, int2c
2392
+
2393
+ # verbose(" enter transportable_symbol_approx with r=%s,"
2394
+ # " rr=%s" % (r,rr), level=5)
2395
+
2396
+ #this finds a gamma with smallest |c|
2397
+ from sage.modular.cusps import Cusp
2398
+ rc = Cusp(r)
2399
+ boo, ga = rc.is_gamma0_equiv(rr, self._N_E, "matrix")
2400
+
2401
+ if not boo:
2402
+ raise ValueError("The cusps %s and %s are not "
2403
+ "Gamma_0(%s)-equivalent" % (r, rr, self._N_E))
2404
+
2405
+ # now find the same for the move to 0
2406
+ c = ga[1][0]
2407
+ r0 = - Rational((c/self._N_E, ga[0][0]))
2408
+ rc0 = Cusp(r0)
2409
+ _, ga0 = rc0.is_gamma0_equiv(0, self._N_E, "matrix")
2410
+
2411
+ if c.abs() > ga0[1][0].abs(): # better at 0
2412
+ ga = ga0
2413
+ c = ga[1][0]
2414
+ eN = -self._epsQs[self._N_E]
2415
+ else: # better at i oo
2416
+ eN = 1
2417
+
2418
+ a = ga[0][0]
2419
+ b = ga[0][1]
2420
+ d = ga[1][1]
2421
+
2422
+ if (a + d).abs() <= 2:
2423
+ # parabolic matrix has a fixed point among the cusps
2424
+ # and so we can simply give back 0
2425
+ # because ga has then finite order
2426
+ CC = ComplexField(53)
2427
+ return CC(0)
2428
+
2429
+ yy = <double>(c.abs())
2430
+ yy = 1/yy
2431
+ T, prec = self._get_truncation_and_prec(yy, eps/2)
2432
+ if T == -1:
2433
+ raise ValueError("Too many terms > 2^31 would have to be summed"
2434
+ + "up. Giving up.")
2435
+
2436
+ if prec > 53:
2437
+ CC = ComplexField(prec)
2438
+ tau1 = CC(-d/c, 1/c.abs())
2439
+ # computes the integral from tau to i*oo
2440
+ verbose(" computing integral from i*oo to %s using %s terms "
2441
+ "and precision %s" % (tau1, T, prec), level=3)
2442
+ int1 = self._integration_to_tau(tau1, T, prec)
2443
+ verbose(" yields %s " % int1, level=3)
2444
+ tau2 = (tau1 * a + b)/(c*tau1 + d)
2445
+ verbose(" computing integral from i*oo to %s using %s terms "
2446
+ "and precision %s" % (tau2, T, prec), level=3)
2447
+ int2 = self._integration_to_tau(tau2, T, prec)
2448
+ ans = eN * (int1 - int2)
2449
+ else:
2450
+ tau1c = complex(-d/c, 1/c.abs())
2451
+ # computes the integral from tau to i*oo
2452
+ verbose(" computing integral from i*oo to %s using %s terms "
2453
+ "and fast double precision" % (tau1c, T), level=3)
2454
+ int1c = self._integration_to_tau_double(tau1c, T)
2455
+ verbose(" yields %s " % int1c, level=3)
2456
+ tau2c = (tau1c * a + b)/(c*tau1c + d)
2457
+ verbose(" computing integral from i*oo to %s using %s terms "
2458
+ "and fast double precision" % (tau2c, T), level=3)
2459
+ int2c = self._integration_to_tau_double(tau2c, T)
2460
+ verbose(" yields %s" % int2c, level=3)
2461
+ ans = eN * ComplexField(53)(int1c - int2c)
2462
+ return ans
2463
+
2464
+ #======= precise rationals =====
2465
+
2466
+ # (key=lambda r,sign,use_partials:(r,sign)) lead to a compiler crash
2467
+ @cached_method
2468
+ def _value_ioo_to_r(self, Rational r, int sign=0,
2469
+ int use_partials=2):
2470
+ r"""
2471
+ Return `[r]^+` or `[r]^-` for a rational `r`.
2472
+
2473
+ INPUT:
2474
+
2475
+ - ``r`` -- a rational number, which has to be a unitary cusp
2476
+
2477
+ - ``sign`` -- either +1 or -1, or 0 (default),
2478
+ in which case the sign passed to the class is taken
2479
+
2480
+ - ``use_partials`` -- integer; 0 don't use partial summation to do
2481
+ the computation, 1 do use them, 2 (default) decide if it is
2482
+ meaningful to do so
2483
+
2484
+ OUTPUT: a rational number
2485
+
2486
+ EXAMPLES::
2487
+
2488
+ sage: from sage.schemes.elliptic_curves.mod_sym_num \
2489
+ ....: import ModularSymbolNumerical
2490
+ sage: E = EllipticCurve("11a1")
2491
+ sage: M = E.modular_symbol(implementation='num')
2492
+ sage: M._value_ioo_to_r(0/1)
2493
+ 1/5
2494
+ sage: M._value_ioo_to_r(3/11,-1)
2495
+ 1/2
2496
+
2497
+ sage: E = EllipticCurve("5077a1")
2498
+ sage: M = E.modular_symbol(implementation='num')
2499
+ sage: M._value_ioo_to_r(0/1)
2500
+ 0
2501
+ sage: M._value_ioo_to_r(123/456)
2502
+ -3
2503
+ sage: M._value_ioo_to_r(-9/55,-1)
2504
+ -2
2505
+ """
2506
+ # verbose(" enter _value_ioo_to_r with r=%s, sign=%s" % (r,sign),
2507
+ # level=5)
2508
+ cdef:
2509
+ double eps
2510
+ ComplexNumber la
2511
+ RealNumber lap
2512
+ if sign == 0:
2513
+ sign = self._global_sign
2514
+ if sign == 1:
2515
+ eps = self._eps_unitary_plus
2516
+ else:
2517
+ eps = self._eps_unitary_minus
2518
+ la = self._from_ioo_to_r_approx(r, eps, use_partials=use_partials)
2519
+ if sign == 1:
2520
+ lap = la.real()
2521
+ else:
2522
+ lap = la.imag()
2523
+ return self._round(lap, sign, True)
2524
+
2525
+ @cached_method
2526
+ def _value_r_to_rr(self, Rational r, Rational rr, int sign=0,
2527
+ int use_partials=2):
2528
+ r"""
2529
+ Return the rational number `[r']^+ - [r]^+`. However the
2530
+ computation may choose to work directly along the path from
2531
+ `r` to `r'` rather than going via `i\infty`, depending on what is
2532
+ faster.
2533
+
2534
+ INPUT:
2535
+
2536
+ - ``r``, ``rr`` -- two rational numbers, both have to be
2537
+ unitary cusps
2538
+
2539
+ - ``sign`` -- either +1 or -1, or 0 (default),
2540
+ in which case the sign passed to the class is taken
2541
+
2542
+ - ``use_partials`` -- integer; 0 don't use partial summation to do
2543
+ the computation, 1 do use them, 2 (default) decide if it is
2544
+ meaningful to do so
2545
+
2546
+ OUTPUT: a rational number
2547
+
2548
+ EXAMPLES::
2549
+
2550
+ sage: from sage.schemes.elliptic_curves.mod_sym_num \
2551
+ ....: import ModularSymbolNumerical
2552
+ sage: E = EllipticCurve("57a1")
2553
+ sage: M = E.modular_symbol(implementation='num')
2554
+ sage: M._value_r_to_rr(0/1,8/9)
2555
+ 0
2556
+ sage: M._value_r_to_rr(0/1,8/9,use_partials=0)
2557
+ 0
2558
+ sage: M._value_r_to_rr(17/19,-5/9)
2559
+ 1/2
2560
+ sage: M._value_r_to_rr(14/19,-5/9,-1)
2561
+ 1/2
2562
+ sage: M._value_r_to_rr(174/179,-53/91,-1)
2563
+ -1
2564
+
2565
+ sage: E = EllipticCurve([91,127])
2566
+ sage: E.conductor()
2567
+ 55196272
2568
+ sage: E.conductor().factor()
2569
+ 2^4 * 3449767
2570
+ sage: M = E.modular_symbol(implementation='num')
2571
+ sage: M._value_r_to_rr(0/1,4/5)
2572
+ 1
2573
+ sage: M._value_r_to_rr(7/11,14/75) # long time
2574
+ -1
2575
+ """
2576
+ # verbose(" enter _value_r_to_rr with r=%s, rr=%s,"
2577
+ # " sign=%s" % (r,rr,sign), level=5)
2578
+ cdef:
2579
+ double eps
2580
+ ComplexNumber la
2581
+ RealNumber lap
2582
+
2583
+ if sign == 0:
2584
+ sign = self._global_sign
2585
+ if sign == 1:
2586
+ eps = self._eps_unitary_plus
2587
+ else:
2588
+ eps = self._eps_unitary_minus
2589
+ la = self._from_r_to_rr_approx(r, rr, eps, use_partials=use_partials)
2590
+ if sign == 1:
2591
+ lap = la.real()
2592
+ else:
2593
+ lap = la.imag()
2594
+ return self._round(lap, sign, True)
2595
+
2596
+ @cached_method
2597
+ def transportable_symbol(self, Rational r, Rational rr, int sign=0):
2598
+ r"""
2599
+ Return the symbol `[r']^+ - [r]^+` where `r'=\gamma(r)` for some
2600
+ `\gamma\in\Gamma_0(N)`. These symbols can be computed by transporting
2601
+ the path into the upper half plane close to one of the unitary cusps.
2602
+ Here we have implemented it only to move close to `i\infty` and `0`.
2603
+
2604
+ INPUT:
2605
+
2606
+ - ``r``, ``rr`` -- two rational numbers
2607
+
2608
+ - ``sign`` -- either +1 or -1, or 0 (default),
2609
+ in which case the sign passed to the class is taken
2610
+
2611
+ OUTPUT: a rational number
2612
+
2613
+ EXAMPLES::
2614
+
2615
+ sage: E = EllipticCurve("11a1")
2616
+ sage: M = E.modular_symbol(implementation='num')
2617
+ sage: M.transportable_symbol(0/1,-2/7)
2618
+ -1/2
2619
+
2620
+ sage: E = EllipticCurve("37a1")
2621
+ sage: M = E.modular_symbol(implementation='num')
2622
+ sage: M.transportable_symbol(0/1,-1/19)
2623
+ 0
2624
+ sage: M.transportable_symbol(0/1,-1/19,-1)
2625
+ 0
2626
+
2627
+ sage: E = EllipticCurve("5077a1")
2628
+ sage: M = E.modular_symbol(implementation='num')
2629
+ sage: M.transportable_symbol(0/1,-35/144)
2630
+ -3
2631
+ sage: M.transportable_symbol(0/1,-35/144,-1)
2632
+ 0
2633
+ sage: M.transportable_symbol(0/1, -7/31798)
2634
+ 0
2635
+ sage: M.transportable_symbol(0/1, -7/31798, -1)
2636
+ -5
2637
+ """
2638
+ # verbose(" enter transportable_symbol with r=%s, rr=%s,"
2639
+ # " sign=%s" % (r,rr,sign), level=5)
2640
+ cdef:
2641
+ double eps
2642
+ ComplexNumber la
2643
+ RealNumber lap
2644
+
2645
+ if sign == 0:
2646
+ sign = self._global_sign
2647
+ if sign == 1:
2648
+ eps = self._eps_unitary_plus
2649
+ else:
2650
+ eps = self._eps_unitary_minus
2651
+ la = self._transportable_approx(r, rr, eps)
2652
+ if sign == 1:
2653
+ lap = la.real()
2654
+ else:
2655
+ lap = la.imag()
2656
+ return self._round(lap, sign, True)
2657
+
2658
+ #@cached_method
2659
+ def _symbol_non_unitary(self, Rational r, int sign=0):
2660
+ r"""
2661
+ Given a rational number `r`, this computes the modular symbol
2662
+ `[r]^+` or `[r]^-`. There is no assumption here on the cusp `r`,
2663
+ so a rather slow method via transportable paths is chosen. This
2664
+ should only be used for small denominators that are non unitary
2665
+ cusps.
2666
+
2667
+ INPUT:
2668
+
2669
+ - ``r`` -- a rational number representing a unitary cusp
2670
+
2671
+ - ``sign`` -- either +1 or -1, or 0 (default),
2672
+ in which case the sign passed to the class is taken
2673
+
2674
+ OUTPUT: a rational number
2675
+
2676
+ EXAMPLES::
2677
+
2678
+ sage: from sage.schemes.elliptic_curves.mod_sym_num \
2679
+ ....: import ModularSymbolNumerical
2680
+ sage: M = ModularSymbolNumerical(EllipticCurve("49a1"))
2681
+ sage: M._symbol_non_unitary(1/7)
2682
+ 1/4
2683
+ sage: M._symbol_non_unitary(1/7,sign=-1)
2684
+ 5/28
2685
+
2686
+ Test for :issue:`28476` ::
2687
+
2688
+ sage: M = ModularSymbolNumerical(EllipticCurve("361a1"))
2689
+ sage: M._symbol_non_unitary(1/19)
2690
+ 5/19
2691
+ """
2692
+ # verbose(" enter _symbol_non_unitary with r=%s,"
2693
+ # " sign=%s" % (r,sign), level=5)
2694
+ cdef:
2695
+ llong m, B, N_ell, aell, u, N = self._N_E
2696
+ Integer ell
2697
+ Rational r2, res
2698
+
2699
+ if sign == 0:
2700
+ sign = self._global_sign
2701
+
2702
+ rc = _CuspsForModularSymbolNumerical(r, N)
2703
+ r = rc._r
2704
+ m = rc._m
2705
+ B = llgcd(m, N)
2706
+
2707
+ # find a prime congruent to 1 modulo B
2708
+ ell = Integer(B) + 1
2709
+ while llgcd(ell, N) != 1 or not ell.is_prime():
2710
+ ell += B
2711
+ if ell > self._lans:
2712
+ aell = self._E.ap(ell)
2713
+ else:
2714
+ aell = Integer(self._ans[ell])
2715
+ N_ell = ell + 1 - aell
2716
+ # {ell * r , r}
2717
+ verbose(" Compute symbol {ell*r -> r} = {%s -> %s}" % (ell*r, r),
2718
+ level=4)
2719
+ res = self.transportable_symbol(ell * r, r, sign=sign)
2720
+ # {(r + u)/ ell, r}
2721
+ u = Integer(0)
2722
+ while u < ell:
2723
+ r2 = (r+u) / ell
2724
+ verbose(" Compute symbol {r2-> r} = {%s -> %s}" % (r2, r),
2725
+ level=4)
2726
+ res += self.transportable_symbol(r2, r, sign=sign)
2727
+ u += 1
2728
+ return -res/N_ell
2729
+
2730
+ @cached_method # one call to manin_symbol will set between 4 and 8 values in fact
2731
+ def _manin_symbol_with_cache(self, llong u, llong v, int sign):
2732
+ r"""
2733
+ This helper function is called by manin_symbol below.
2734
+ The sign has to be 1 or -1, the coordinates u, v
2735
+ should already be in the normalised presentation.
2736
+
2737
+ See the docstring of manin_symbol for detail,
2738
+ examples and indirect doctest for this method.
2739
+
2740
+ EXAMPLES::
2741
+
2742
+ sage: from sage.schemes.elliptic_curves.mod_sym_num \
2743
+ ....: import ModularSymbolNumerical
2744
+ sage: E = EllipticCurve('37a1')
2745
+ sage: ms = ModularSymbolNumerical(E)
2746
+ sage: ms.manin_symbol(4,17)
2747
+ 1
2748
+ sage: ms._cached_methods["_manin_symbol_with_cache"].cache # random
2749
+ {((1, 5, 1), ()): 1,
2750
+ ((1, 15, 1), ()): -1,
2751
+ ((1, 22, 1), ()): -1,
2752
+ ((1, 32, 1), ()): 1}
2753
+ sage: ms._cached_methods["_manin_symbol_with_cache"].cache[(1,15,1),()]
2754
+ -1
2755
+ sage: ms.manin_symbol(4+17,-4)
2756
+ 0
2757
+ sage: ms._cached_methods["_manin_symbol_with_cache"].cache # random
2758
+ {((1, 4, 1), ()): 0,
2759
+ ((1, 5, 1), ()): 1,
2760
+ ((1, 8, 1), ()): 1,
2761
+ ((1, 9, 1), ()): 0,
2762
+ ((1, 14, 1), ()): -1,
2763
+ ((1, 15, 1), ()): -1,
2764
+ ((1, 22, 1), ()): -1,
2765
+ ((1, 23, 1), ()): -1,
2766
+ ((1, 28, 1), ()): 0,
2767
+ ((1, 29, 1), ()): 1,
2768
+ ((1, 32, 1), ()): 1,
2769
+ ((1, 33, 1), ()): 0}
2770
+ sage: ms._cached_methods["_manin_symbol_with_cache"].cache[ (1,23,1), () ]
2771
+ -1
2772
+ """
2773
+ cdef:
2774
+ llong c, d, x, y, N = self._N_E, Mu, Mv, Qu, Qv, du=1, dv=1
2775
+ Rational r, rr, res
2776
+
2777
+ # verbose(" enter _manin_symbol_with_cache with u=%s, v=%s,"
2778
+ # " sign =%s" % (u,v,sign), level=5)
2779
+
2780
+ if u == 0:
2781
+ verbose(" integrating from 0 to i*oo", level=3)
2782
+ r = Rational(0)
2783
+ return self._value_ioo_to_r(r, sign, use_partials=0)
2784
+ elif v == 0:
2785
+ verbose(" integrating from i*oo to 0", level=3)
2786
+ r = Rational(0)
2787
+ return - self._value_ioo_to_r(r, sign, use_partials=0)
2788
+ else:
2789
+ # (c:d) = (u:v) but c and d are fairly small
2790
+ # in absolute value
2791
+ Mu = llgcd(u, N)
2792
+ Qu = N // Mu
2793
+ Mv = llgcd(v, N)
2794
+ Qv = N // Mv
2795
+ isunitary = (llgcd(Qu, Mu) == 1 and llgcd(Qv, Mv) == 1)
2796
+ if isunitary: # unitary case
2797
+ _ = best_proj_point(u, v, self._N_E, &c, &d)
2798
+ else: # at least one of the two cusps is not unitary
2799
+ du = llgcd(Qu,Mu)
2800
+ dv = llgcd(Qv, Mv)
2801
+ NMM = N // Mv // Mu
2802
+ if dv == 1:
2803
+ c = Mu
2804
+ d = llinvmod(u // Mu, NMM)
2805
+ d *= v
2806
+ d = d % (N // Mu)
2807
+ while llgcd(c,d) != 1:
2808
+ d += N // Mu
2809
+ d = d % N
2810
+ # now (u:v) = (c:d) with c as small as possible.
2811
+ else:
2812
+ d = Mv
2813
+ c = llinvmod(v // Mv, NMM)
2814
+ c *= u
2815
+ c = c % (N // Mv)
2816
+ while llgcd(c, d) != 1:
2817
+ c += N // Mv
2818
+ c = c % N
2819
+ # now (u:v) = (c:d) with d as small as possible.
2820
+ # verbose(" better representant on P^1: "
2821
+ # "(%s : %s)" % (c, d), level=3)
2822
+ # _, x, y = c.xgcd(d)
2823
+ _ = llxgcd(c, d, &x, &y)
2824
+ #if above != 1 or (c*v-u*d) % N != 0:
2825
+ # print("BUG: ",u,v,c,d,Mu,Mv)
2826
+ x = x % N
2827
+ y = y % N
2828
+ # [[y -x], [c,d]] has det 1
2829
+ if c > 0:
2830
+ rr = Rational((y, c))
2831
+ else:
2832
+ rr = - Rational((y, -c))
2833
+ if d > 0:
2834
+ r = -Rational((x, d))
2835
+ else:
2836
+ r = Rational((x, -d))
2837
+ if isunitary:
2838
+ verbose(" integrate between %s and %s" % (r, rr), level=3)
2839
+ return self._value_r_to_rr(r, rr, sign, use_partials=2)
2840
+ else:
2841
+ if dv > 1:
2842
+ res = self._symbol_non_unitary(r,sign)
2843
+ else:
2844
+ res = self._value_ioo_to_r(r,sign, use_partials=2)
2845
+ if du > 1:
2846
+ res -= self._symbol_non_unitary(rr,sign)
2847
+ else:
2848
+ res -= self._value_ioo_to_r(rr,sign, use_partials=2)
2849
+ return res
2850
+
2851
+ def manin_symbol(self, llong u, llong v, int sign=0):
2852
+ r"""
2853
+ Given a pair `(u,v)` presenting a point in
2854
+ `\mathbb{P}^1(\mathbb{Z}/N\mathbb{Z})` and hence a coset of
2855
+ `\Gamma_0(N)`, this computes the value of the Manin
2856
+ symbol `M(u:v)`.
2857
+
2858
+ INPUT:
2859
+
2860
+ - ``u`` -- integer
2861
+
2862
+ - ``v`` -- integer such that `(u:v)` is a projective point
2863
+ modulo `N`
2864
+
2865
+ - ``sign`` -- either +1 or -1, or 0 (default),
2866
+ in which case the sign passed to the class is taken
2867
+
2868
+ EXAMPLES::
2869
+
2870
+ sage: E = EllipticCurve('11a1')
2871
+ sage: M = E.modular_symbol(implementation='num')
2872
+ sage: M.manin_symbol(1,3)
2873
+ -1/2
2874
+ sage: M.manin_symbol(1,3, sign=-1)
2875
+ -1/2
2876
+ sage: M.manin_symbol(1,5)
2877
+ 1
2878
+ sage: M.manin_symbol(1,5)
2879
+ 1
2880
+
2881
+ sage: E = EllipticCurve('14a1')
2882
+ sage: M = E.modular_symbol(implementation='num')
2883
+ sage: M.manin_symbol(1,2)
2884
+ -1/2
2885
+ sage: M.manin_symbol(17,6)
2886
+ -1/2
2887
+ sage: M.manin_symbol(-1,12)
2888
+ -1/2
2889
+ """
2890
+ # verbose(" enter manin_symbol with u=%s, v=%s,"
2891
+ # " sign =%s" % (u,v,sign), level=5)
2892
+ cdef:
2893
+ llong un, vn
2894
+ int oi
2895
+ Rational res, r2
2896
+
2897
+ if sign == 0:
2898
+ sign = self._global_sign
2899
+
2900
+ oi = proj_normalise(self._N_E, u, v, &un, &vn)
2901
+ # verbose(" normalized representant on P^1: "
2902
+ # "(%s :%s)" % (un, vn), level=3)
2903
+
2904
+ # is it already in the cache ?
2905
+ c = self._cached_methods
2906
+ if "_manin_symbol_with_cache" in c:
2907
+ c = c["_manin_symbol_with_cache"]
2908
+ if c.is_in_cache(un, vn, sign):
2909
+ res = self._manin_symbol_with_cache(un, vn, sign)
2910
+ return res
2911
+
2912
+ # the actual work in now done in a helper function
2913
+ # which does the correct caching
2914
+ res = self._manin_symbol_with_cache(un, vn, sign)
2915
+
2916
+ # using the Manin relations coming from
2917
+ # complex conjugation, the matrices S and T in SL_2
2918
+ # we get for free additional values of Manin
2919
+ # symbols that we cache, too.
2920
+ # This sets 6 values in average
2921
+ c = self._cached_methods["_manin_symbol_with_cache"]
2922
+
2923
+ # (-v:u) = - (u:v)
2924
+ oi = proj_normalise(self._N_E, -v, u, &un, &vn)
2925
+ c.set_cache(-res, un, vn, sign)
2926
+
2927
+ # (v:u) = -1 * sign * (u:v)
2928
+ oi = proj_normalise(self._N_E, v, u, &un, &vn)
2929
+ c.set_cache(-sign*res, un, vn, sign)
2930
+
2931
+ # (-u:v) = sign * (u:v)
2932
+ oi = proj_normalise(self._N_E, -u, v, &un, &vn)
2933
+ c.set_cache(sign*res, un, vn, sign)
2934
+
2935
+ # (u:v) + (u+v:-u) +(v,-u-v) = 0
2936
+ # is (u+v:-u) already computed, we set the third
2937
+ oi = proj_normalise(self._N_E, u+v, -u, &un, &vn)
2938
+ if c.is_in_cache(un, vn, sign):
2939
+ r2 = - res - c(un, vn, sign)
2940
+
2941
+ # (v:-u-v) = r2
2942
+ oi = proj_normalise(self._N_E, v, -u-v, &un, &vn)
2943
+ c.set_cache(r2, un, vn, sign)
2944
+
2945
+ # (u+v:v) = -r2
2946
+ oi = proj_normalise(self._N_E, u+v, v, &un, &vn)
2947
+ c.set_cache(-r2, un, vn, sign)
2948
+
2949
+ # (-u-v:v) = -1 * sign * r2
2950
+ oi = proj_normalise(self._N_E, -u-v, v, &un, &vn)
2951
+ c.set_cache(-sign*r2, un, vn, sign)
2952
+
2953
+ # (-v:-u-v) = sign * r2
2954
+ oi = proj_normalise(self._N_E, -v, -u-v, &un, &vn)
2955
+ c.set_cache(sign*r2, un, vn, sign)
2956
+
2957
+ # is (v,-u-v) already computed, we set (u+v:-u)
2958
+ oi = proj_normalise(self._N_E, v, -u-v, &un, &vn)
2959
+ if c.is_in_cache(un, vn, sign):
2960
+ r2 = - res - c(un, vn, sign)
2961
+
2962
+ # (u+v:-u) = r2
2963
+ oi = proj_normalise(self._N_E, u+v, -u, &un, &vn)
2964
+ c.set_cache(r2, un, vn, sign)
2965
+
2966
+ # (u:u+v) = -r2
2967
+ oi = proj_normalise(self._N_E, u, u+v, &un, &vn)
2968
+ c.set_cache(-r2, un, vn, sign)
2969
+
2970
+ # (-u:u+v) = -1 * sign * r2
2971
+ oi = proj_normalise(self._N_E, -u, u+v, &un, &vn)
2972
+ c.set_cache(-sign*r2, un, vn, sign)
2973
+
2974
+ # (-u-v:-u) = sign * r2
2975
+ oi = proj_normalise(self._N_E, -u-v, -u, &un, &vn)
2976
+ c.set_cache(sign*r2, un, vn, sign)
2977
+
2978
+ return res
2979
+
2980
+ # ===============================
2981
+
2982
+ @cached_method # not sure this is not a waist
2983
+ def _evaluate(self, Rational r, int sign=0):
2984
+ r"""
2985
+ Given a rational number `r` this computes the modular symbol
2986
+ `[r]^+` or `[r]^-`.
2987
+
2988
+ INPUT:
2989
+
2990
+ - ``r`` -- a rational number representing a unitary cusp
2991
+
2992
+ - ``sign`` -- either +1 or -1, or 0 (default),
2993
+ in which case the sign passed to the class is taken
2994
+
2995
+ OUTPUT: a rational number
2996
+
2997
+ EXAMPLES::
2998
+
2999
+ sage: from sage.schemes.elliptic_curves.mod_sym_num \
3000
+ ....: import ModularSymbolNumerical
3001
+ sage: E = EllipticCurve('5077a1')
3002
+ sage: M = ModularSymbolNumerical(E)
3003
+ sage: M._evaluate(1/7)
3004
+ 3
3005
+ sage: M._evaluate(1/7, -1)
3006
+ 1
3007
+ sage: M._evaluate(-1/4112)
3008
+ 3
3009
+
3010
+ sage: E = EllipticCurve('11a1')
3011
+ sage: M = ModularSymbolNumerical(E)
3012
+ sage: M._evaluate(1/99999)
3013
+ -4/5
3014
+
3015
+ sage: M = ModularSymbolNumerical(EllipticCurve("32a1"))
3016
+ sage: M._evaluate(3/5)
3017
+ -1/4
3018
+
3019
+ Non-unitary examples::
3020
+
3021
+ sage: M = ModularSymbolNumerical(EllipticCurve("20a1"))
3022
+ sage: M._evaluate(1/2)
3023
+ -1/6
3024
+ sage: M._evaluate(1/2, -1)
3025
+ 0
3026
+ sage: M = ModularSymbolNumerical(EllipticCurve("49a1"))
3027
+ sage: M._evaluate(2/7)
3028
+ -1/4
3029
+ sage: M = ModularSymbolNumerical(EllipticCurve("121a1"))
3030
+ sage: M._evaluate(3/11)
3031
+ 1/2
3032
+
3033
+ This takes a bit longer::
3034
+
3035
+ sage: M = ModularSymbolNumerical(EllipticCurve("78a1"))
3036
+ sage: M._evaluate(1/38)
3037
+ 2
3038
+ sage: M._evaluate(5/38)
3039
+ 1/2
3040
+ sage: M._evaluate(1/123456789012345678901234567)
3041
+ -1
3042
+ """
3043
+ # verbose(" enter _evaluate with r=%s, sign=%s" % (r,sign),
3044
+ # level=5)
3045
+ cdef:
3046
+ llong N = self._N_E, u, v
3047
+ Rational r2, res
3048
+ Integer a, m, B, Q, y, x, M, uu, vv
3049
+
3050
+ if sign == 0:
3051
+ sign = self._global_sign
3052
+
3053
+ a = r.numerator()
3054
+ m = r.denominator()
3055
+ a = a % m
3056
+ if 2*a > m:
3057
+ a -= m
3058
+ r = a/m
3059
+
3060
+ if N % 4 == 0 and m % 4 != 0 and m % 2 == 0:
3061
+ # this follows from T_2
3062
+ r2 = (a-m/2)/m
3063
+ return -self._evaluate(r2, sign=sign)
3064
+
3065
+ B = m.gcd(N)
3066
+ Q = N // B
3067
+ # verbose(" cusp is %s/%s of width %s" % (a,m,Q), level=4)
3068
+
3069
+ if r == 0:
3070
+ return self._value_ioo_to_r(r, sign=sign)
3071
+
3072
+ if m < self._cut_val:
3073
+ # now at some point we go directly to ioo
3074
+ M = N//Q
3075
+ if Q.gcd(M) == 1:
3076
+ res = self._value_ioo_to_r(r, sign=sign)
3077
+ else:
3078
+ res = self._symbol_non_unitary(r, sign=sign)
3079
+ else:
3080
+ # so a*y + x*m = 1 and 0 <= |y| < m/2
3081
+ _, y, x = a.xgcd(m)
3082
+ y = y % m
3083
+ if 2*y > m:
3084
+ y -= m
3085
+ x = (1-y*a) // m
3086
+ # verbose(" smallest xgcd is "
3087
+ # + " %s = %s * %s + %s * %s" % (a.gcd(m),a,y,x,m),
3088
+ # level=4)
3089
+ # make the cusp -x/y unitary if possible.
3090
+ B = y.gcd(N)
3091
+ if B.gcd(N//B) != 1:
3092
+ if y > 0:
3093
+ y -= m
3094
+ x += a
3095
+ else:
3096
+ y += m
3097
+ x -= a
3098
+ # Note: it could still be non-unitary.
3099
+ # Example: N=36 a=2, m=5
3100
+ uu = (-y) % N
3101
+ vv = m % N
3102
+ u = <llong>uu
3103
+ v = <llong>vv
3104
+ r2 = - x/y
3105
+ verbose(" Next piece: integrate from %s to %s via the Manin"
3106
+ " symbol for (%s : %s)" % (r, r2, u, v), level=2)
3107
+ res = self.manin_symbol(u,v,sign=sign)
3108
+ res += self._evaluate(r2, sign=sign)
3109
+
3110
+ return res
3111
+
3112
+ @cached_method
3113
+ def all_values_for_one_denominator(self, llong m, int sign=0):
3114
+ r"""
3115
+ Given an integer ``m`` and a ``sign``, this returns the
3116
+ modular symbols `[a/m]` for all `a` coprime to `m`
3117
+ using partial sums.
3118
+ This is much quicker than computing them one by one.
3119
+
3120
+ This will only work if `m` is relatively small and
3121
+ if the cusps `a/m` are unitary.
3122
+
3123
+ INPUT:
3124
+
3125
+ - ``m`` -- a natural number
3126
+
3127
+ - ``sign`` -- either +1 or -1, or 0 (default),
3128
+ in which case the sign passed to the class is taken
3129
+
3130
+ OUTPUT: a dictionary of fractions with denominator `m`
3131
+ giving rational numbers.
3132
+
3133
+ EXAMPLES::
3134
+
3135
+ sage: E = EllipticCurve('5077a1')
3136
+ sage: M = E.modular_symbol(implementation='num')
3137
+ sage: M.all_values_for_one_denominator(7)
3138
+ {1/7: 3, 2/7: 0, 3/7: -3, 4/7: -3, 5/7: 0, 6/7: 3}
3139
+ sage: [M(a/7) for a in [1..6]]
3140
+ [3, 0, -3, -3, 0, 3]
3141
+ sage: M.all_values_for_one_denominator(3,-1)
3142
+ {1/3: 4, 2/3: -4}
3143
+
3144
+ sage: E = EllipticCurve('11a1')
3145
+ sage: M = E.modular_symbol(implementation='num')
3146
+ sage: M.all_values_for_one_denominator(12)
3147
+ {1/12: 1/5, 5/12: -23/10, 7/12: -23/10, 11/12: 1/5}
3148
+ sage: M.all_values_for_one_denominator(12, -1)
3149
+ {1/12: 0, 5/12: 1/2, 7/12: -1/2, 11/12: 0}
3150
+
3151
+ sage: E = EllipticCurve('20a1')
3152
+ sage: M = E.modular_symbol(implementation='num')
3153
+ sage: M.all_values_for_one_denominator(4)
3154
+ {1/4: 0, 3/4: 0}
3155
+ sage: M.all_values_for_one_denominator(8)
3156
+ {1/8: 1/2, 3/8: -1/2, 5/8: -1/2, 7/8: 1/2}
3157
+ """
3158
+
3159
+ # TODO: This function should really use some multi-radix FFT
3160
+ # however for small m there is not much gain
3161
+ cdef:
3162
+ llong N, Q, z, a, astar, j, epsQ
3163
+ double resam, twopim
3164
+ RealNumber val
3165
+ dict res
3166
+
3167
+ # verbose(" enter all_symbol with m=%s" % m, level=5)
3168
+
3169
+ if sign == 0:
3170
+ sign = self._global_sign
3171
+
3172
+ RR = RealField(53)
3173
+ N = self._N_E
3174
+ Q = N // llgcd(m, N)
3175
+ if llgcd(m, Q) > 1:
3176
+ raise NotImplementedError("Only implemented for cusps that are "
3177
+ "in the Atkin-Lehner orbit of oo")
3178
+ # verbose(" compute all partial sums with denominator m=%s" % m,
3179
+ # level=3)
3180
+ z = Q*m*m
3181
+ v = self._kappa(m, z)
3182
+
3183
+ epsQ = self._epsQs[Q]
3184
+
3185
+ res = dict()
3186
+ a = 1
3187
+ twopim = TWOPI
3188
+ twopim = twopim/m
3189
+ if sign == 1:
3190
+ while a < m:
3191
+ if llgcd(a,m) == 1:
3192
+ astar = llinvmod(Q*a, m)
3193
+ j = 0
3194
+ resam = 0
3195
+ while j < m:
3196
+ resam += (v[j]*(cos(twopim*j*a)
3197
+ - epsQ*cos(twopim*j*astar)))
3198
+ j += 1
3199
+ val = RR(resam)
3200
+ res[Rational((a, m))] = self._round(val, 1, True)
3201
+ a += 1
3202
+ else:
3203
+ while a < m:
3204
+ if llgcd(a,m) == 1:
3205
+ astar = llinvmod(Q*a, m)
3206
+ j = 0
3207
+ resam = 0
3208
+ while j < m:
3209
+ resam += (v[j]*(sin(twopim *j *a)
3210
+ + epsQ *sin(twopim*j*astar)))
3211
+ j += 1
3212
+ val = RR(resam)
3213
+ res[Rational((a, m))] = self._round(val, -1, True)
3214
+ a += 1
3215
+
3216
+ return res
3217
+
3218
+ def _twisted_symbol(self, Rational ra, int sign=0):
3219
+ r"""
3220
+ Compute the value of the modular symbol by
3221
+ using the symbols of the quadratic twist.
3222
+
3223
+ INPUT:
3224
+
3225
+ - ``ra`` -- a rational number
3226
+
3227
+ - ``sign`` -- either +1 or -1, or 0 (default),
3228
+ in which case the sign passed to the class is taken
3229
+
3230
+ OUTPUT: a rational number
3231
+
3232
+ EXAMPLES::
3233
+
3234
+ sage: E = EllipticCurve("735e4")
3235
+ sage: M = E.modular_symbol(implementation='num')
3236
+ sage: M(1/19, sign=-1, use_twist=False) #indirect doctest
3237
+ 4
3238
+ sage: M(1/19, sign=-1, use_twist=True)
3239
+ 4
3240
+ sage: M(6/19, sign=1, use_twist=False)
3241
+ 3
3242
+ sage: M(6/19, sign=1, use_twist=True)
3243
+ 3
3244
+ """
3245
+ cdef Integer D, Da, a
3246
+ cdef Rational res, t
3247
+ # verbose(" enter _twisted symbol with ra=%s,
3248
+ # sign=%s" % (ra,sign),
3249
+ # level=5)
3250
+ if sign == 0:
3251
+ sign = self._global_sign
3252
+ if self._D == -1:
3253
+ self._set_up_twist()
3254
+ D = self._D
3255
+ Da = D.abs()
3256
+ a = Integer(1)
3257
+ res = Rational((0, 1))
3258
+ s = sign * D.sign()
3259
+ verbose(" start sum of twisted symbols with disc %s" % D, level=4)
3260
+ while a < Da:
3261
+ if a.gcd(Da) == 1:
3262
+ t = self._Mt(ra - a/Da, sign=s, use_twist=False)
3263
+ res += kronecker_symbol(D,a) * t
3264
+ a += 1
3265
+ res = res/ self._twist_q
3266
+ if sign == 1 and D < 0:
3267
+ res = -res
3268
+ return res
3269
+
3270
+ #====================== approximative versions
3271
+
3272
+ def _evaluate_approx(self, Rational r, double eps):
3273
+ r"""
3274
+ Given a rational number `r` this computes the integral
3275
+ `\lambda(r)` with maximal error ``eps``.
3276
+
3277
+ INPUT:
3278
+
3279
+ - ``r`` -- a rational number representing a unitary cusp
3280
+
3281
+ - ``eps`` -- a positive real number
3282
+
3283
+ OUTPUT: a complex number
3284
+
3285
+ EXAMPLES::
3286
+
3287
+ sage: from sage.schemes.elliptic_curves.mod_sym_num \
3288
+ ....: import ModularSymbolNumerical
3289
+ sage: E = EllipticCurve('5077a1')
3290
+ sage: m = ModularSymbolNumerical(E)
3291
+ sage: m._evaluate_approx(1/11,0.000001) # abs tol 1e-11
3292
+ 9.69540669970570e-10 - 5.80486769763411e-11*I
3293
+ sage: m._evaluate_approx(1/17,0.000001) # abs tol 1e-11
3294
+ -9.01145713605445e-10 + 7.40274134212215*I
3295
+
3296
+ sage: M = ModularSymbolNumerical(EllipticCurve([-12,79]))
3297
+ sage: M.elliptic_curve().conductor()
3298
+ 287280
3299
+ sage: M._evaluate_approx(0/1,0.01) # abs tol 1e-11
3300
+ 0.000000000000000
3301
+ sage: M._evaluate_approx(1/17,0.01) # abs tol 1e-11
3302
+ 1.08712572498569 - 0.548379313090719*I
3303
+
3304
+ Test that is also works for non-unitary cusps (:issue:`29476`) ::
3305
+
3306
+ sage: E = EllipticCurve("20a1")
3307
+ sage: m = E.modular_symbol_numerical()
3308
+ sage: m(1/2) # abs tol 1e-4
3309
+ -0.166666666666667
3310
+ """
3311
+ # verbose(" enter _evaluate_approx with r=%s, eps=%s" % (r,eps),
3312
+ # level=5)
3313
+ cdef:
3314
+ llong N = self._N_E
3315
+ ComplexNumber res
3316
+ Rational r2
3317
+ Integer a, m, Q, x, y, B, M
3318
+
3319
+ a = r.numerator()
3320
+ m = r.denominator()
3321
+ a = a % m
3322
+ if 2*a > m:
3323
+ a -= m
3324
+ r = a/m
3325
+ B = m.gcd(N)
3326
+ Q = N // B
3327
+ verbose(" cusp is %s/%s of width %s" % (a, m, Q), level=4)
3328
+
3329
+ if r == 0:
3330
+ return self._from_ioo_to_r_approx(r, eps, use_partials=0)
3331
+
3332
+ M = N//Q
3333
+ if Q.gcd(M) != 1:
3334
+ return self._symbol_non_unitary_approx(r, eps)
3335
+
3336
+ if m < self._cut_val:
3337
+ # now at some point we go directly to ioo
3338
+ return self._from_ioo_to_r_approx(r, eps, use_partials=0)
3339
+
3340
+ _, y, x = a.xgcd(m)
3341
+ y = y % m
3342
+ if 2*y > m:
3343
+ y -= m
3344
+ x = (1-y*a) // m
3345
+ # verbose(" smallest xgcd is "
3346
+ # + " %s = %s * %s + %s * %s" % (a.gcd(m),a,y,x,m),
3347
+ # level=4)
3348
+ # make the cusp -x/y unitary if possible.
3349
+ B = y.gcd(N)
3350
+ if B.gcd(N // B) != 1:
3351
+ if y > 0:
3352
+ y -= m
3353
+ x += a
3354
+ else:
3355
+ y += m
3356
+ x -= a
3357
+ r2 = - x / y
3358
+ B = y.gcd(N)
3359
+ Q = N // B
3360
+ if Q.gcd(N // Q) != 1: # r2 is not unitary
3361
+ return self._symbol_non_unitary_approx(r, eps)
3362
+
3363
+ r2 = - x / y
3364
+ verbose("Next piece: integrate to the cusp %s " % r2, level=2)
3365
+ res = self._from_r_to_rr_approx(r, r2, eps,
3366
+ use_partials=2)
3367
+ res += self._evaluate_approx(r2, eps)
3368
+ return res
3369
+
3370
+ def _symbol_non_unitary_approx(self, Rational r, double eps):
3371
+ r"""
3372
+ Given a rational number `r` this computes the integral
3373
+ `\\lambda(r)` to maximal error ``eps``.
3374
+
3375
+ There is no assumption here on the cusp `r`,
3376
+ so a rather slow method via transportable paths is chosen. For
3377
+ unitary cusps please use ``_symbol_unitary_approx``.
3378
+
3379
+ INPUT:
3380
+
3381
+ - ``r`` -- a rational number representing a unitary cusp
3382
+
3383
+ - ``eps`` -- a positive real
3384
+
3385
+ OUTPUT: a complex number
3386
+
3387
+ EXAMPLES::
3388
+
3389
+ sage: from sage.schemes.elliptic_curves.mod_sym_num \
3390
+ ....: import ModularSymbolNumerical
3391
+ sage: M = ModularSymbolNumerical(EllipticCurve("20a1"))
3392
+ sage: M._symbol_non_unitary_approx(1/2,0.0001) # abs tol 1e-11
3393
+ -0.470729190326520 + 2.59052039079203e-16*I
3394
+
3395
+ sage: M = ModularSymbolNumerical(EllipticCurve("49a1"))
3396
+ sage: M._symbol_non_unitary_approx(2/7,0.000000001) # abs tol 1e-11
3397
+ -0.483327926404308 + 0.548042354981878*I
3398
+
3399
+ A bit longer take::
3400
+
3401
+ sage: M = ModularSymbolNumerical(EllipticCurve("78a1"))
3402
+ sage: M._symbol_non_unitary_approx(1/38,0.1) # abs tol 1e-11
3403
+ 2.90087559068021 + 2.86538550720028e-7*I
3404
+ sage: M._symbol_non_unitary_approx(5/38,0.1) # abs tol 1e-11
3405
+ 0.725215164486092 - 1.19349741385624*I
3406
+ """
3407
+ # verbose(" enter _symbol_nonunitary_approx with r=%s,"
3408
+ # " eps=%s" % (r,eps), level=5)
3409
+ cdef:
3410
+ llong m, B, N_ell, aell, u, N = self._N_E
3411
+ Integer ell
3412
+ Rational r2
3413
+ ComplexNumber res
3414
+
3415
+ rc = _CuspsForModularSymbolNumerical(r, N)
3416
+ r = rc._r
3417
+ m = rc._m
3418
+ B = llgcd(m, N)
3419
+
3420
+ # find a prime congruent to 1 modulo B
3421
+ ell = Integer(B) + 1
3422
+ while llgcd(ell, N) != 1 or not ell.is_prime():
3423
+ ell += B
3424
+ if ell > self._lans:
3425
+ aell = self._E.ap(ell)
3426
+ else:
3427
+ aell = Integer(self._ans[ell])
3428
+ N_ell = ell + 1 - aell
3429
+ # {ell * r , r}
3430
+ verbose(" Compute symbol {ell*r -> r} = {%s -> %s}" % (ell*r, r),
3431
+ level=4)
3432
+ res = self._transportable_approx(ell * r, r, eps)
3433
+ # {(r + u)/ ell, r}
3434
+ u = Integer(0)
3435
+ while u < ell:
3436
+ r2 = (r+u) / ell
3437
+ verbose(" Compute symbol {r2-> r} = {%s -> %s}" % (r2, r),
3438
+ level=4)
3439
+ res += self._transportable_approx(r2, r, eps)
3440
+ u += 1
3441
+ return -res/N_ell
3442
+
3443
+ def _twisted_approx(self, Rational ra, int sign=0, int prec=20):
3444
+ r"""
3445
+ Compute the approximate value of the modular
3446
+ symbol by using the symbols of the quadratic twist.
3447
+
3448
+ Note that _set_up_twist needs to be called first
3449
+ and D must be different from 1.
3450
+
3451
+ INPUT:
3452
+
3453
+ - ``ra`` -- a rational number
3454
+
3455
+ - ``sign`` -- either +1 or -1, or 0 (default),
3456
+ in which case the sign passed to the class is taken
3457
+
3458
+ - ``prec`` -- integer (default: 20)
3459
+
3460
+ OUTPUT: a real number
3461
+
3462
+ EXAMPLES::
3463
+
3464
+ sage: E = EllipticCurve("735e4")
3465
+ sage: M = E.modular_symbol(implementation='num')
3466
+ sage: M.approximative_value(1/19, sign=-1, prec=20, use_twist=False) # indirect doctest abs tol 1e-11
3467
+ 4.00000000089736
3468
+ sage: M.approximative_value(1/19, sign=-1, prec=20, use_twist=True) # abs tol 1e-11
3469
+ 3.99999999982043
3470
+
3471
+ sage: M.approximative_value(6/19, sign=1, prec=20, use_twist=False) # abs tol 1e-11
3472
+ 2.99999999944834
3473
+ sage: M.approximative_value(6/19, sign=1, prec=20, use_twist=True) # abs tol 1e-11
3474
+ 3.00000000021937
3475
+ """
3476
+ cdef Integer D, Da, a, s, precd
3477
+ cdef RealNumber res, t
3478
+ # verbose(" enter _twisted approx with ra=%s,
3479
+ # eps=%s" % (ra,eps),
3480
+ # level=5)
3481
+
3482
+ if sign == 0:
3483
+ sign = self._global_sign
3484
+ D = self._D
3485
+ s = sign * D.sign()
3486
+ Da = D.abs()
3487
+ precd = prec + euler_phi(Da).log(2,20).ceil()
3488
+ a = Integer(1)
3489
+ res = self._Mt.approximative_value(ra - a/Da, s, precd)
3490
+ verbose(" start sum of twisted symbols with disc %s" % D, level=4)
3491
+ a += 1
3492
+ while a < Da:
3493
+ if a.gcd(Da) == 1:
3494
+ t = self._Mt.approximative_value(ra - a/Da, s, precd, use_twist=False)
3495
+ res += kronecker_symbol(D,a) * t
3496
+ a += 1
3497
+ res = res/self._twist_q
3498
+ if sign == 1 and D < 0:
3499
+ res = -res
3500
+ return res
3501
+
3502
+
3503
+ #==========================
3504
+ # Doctest functions for the above class
3505
+
3506
+ def _test_init(E):
3507
+ r"""
3508
+ Doctest function for the initialisation of
3509
+ ModularSymbolNumerical.
3510
+
3511
+ INPUT:
3512
+
3513
+ - ``E`` -- an elliptic curve
3514
+
3515
+ OUTPUT:
3516
+
3517
+ - a dictionary of eigenvalues for the Atkin-Lehner involutions
3518
+
3519
+ - five integers representing the Fourier coefficients `a_1`,
3520
+ `a_2`, `a_3`, `a_389` and `a_2013`. (This will test
3521
+ _add_an_coefficients).
3522
+
3523
+ - four integers that are bounds for the denominators as in
3524
+ _set_den_bounds
3525
+
3526
+ - four real numbers which are allowed errors in computations
3527
+
3528
+ EXAMPLES::
3529
+
3530
+ sage: from sage.schemes.elliptic_curves.mod_sym_num import _test_init
3531
+ sage: _test_init(EllipticCurve("11a1")) # abs tol 1e-11
3532
+ ({1: 1, 11: -1}, [1, -2, -1, -15, -12], [10, 2, 10, 2],
3533
+ [0.06346046521397766,
3534
+ 0.7294083084692475,
3535
+ 0.06346046521397766,
3536
+ 0.7294083084692475])
3537
+ sage: _test_init(EllipticCurve("11a2")) # abs tol 1e-11
3538
+ ({1: 1, 11: -1}, [1, -2, -1, -15, -12], [2, 2, 2, 2],
3539
+ [0.06346046521397766,
3540
+ 0.7294083084692475,
3541
+ 0.06346046521397766,
3542
+ 0.7294083084692475])
3543
+ sage: _test_init(EllipticCurve("11a3")) # abs tol 1e-11
3544
+ ({1: 1, 11: -1}, [1, -2, -1, -15, -12], [50, 2, 50, 2],
3545
+ [0.06346046521397768,
3546
+ 0.7294083084692478,
3547
+ 0.06346046521397768,
3548
+ 0.7294083084692478])
3549
+
3550
+ sage: _test_init(EllipticCurve("14a6")) # abs tol 1e-11
3551
+ ({1: 1, 2: 1, 7: -1, 14: -1},
3552
+ [1, -1, -2, 18, 0],
3553
+ [9, 1, 9, 1],
3554
+ [0.16511182967224025,
3555
+ 0.6627456198412432,
3556
+ 0.16511182967224025,
3557
+ 0.6627456198412432])
3558
+
3559
+ sage: _test_init(EllipticCurve("20a1")) # abs tol 1e-11
3560
+ ({1: 1, 2: -1, 4: -1, 5: 1, 10: -1, 20: -1},
3561
+ [1, 0, -2, -6, 0], [48, 48, 12, 2],
3562
+ [0.029420574395407434,
3563
+ 0.023689220823344594,
3564
+ 0.11768229758162974,
3565
+ 0.5685412997602702])
3566
+ sage: _test_init(EllipticCurve("37a1")) # abs tol 1e-11
3567
+ ({1: 1, 37: 1}, [1, -2, -3, 4, -120], [1, 2, 1, 2],
3568
+ [1.4967293231159797,
3569
+ 0.6128473454966975,
3570
+ 1.4967293231159797,
3571
+ 0.6128473454966975])
3572
+
3573
+ sage: E = EllipticCurve([91,127])
3574
+ sage: E.conductor().factor()
3575
+ 2^4 * 3449767
3576
+ sage: _test_init(E) # abs tol 1e-11
3577
+ ({1: 1,
3578
+ 2: -1,
3579
+ 4: -1,
3580
+ 8: -1,
3581
+ 16: -1,
3582
+ 3449767: 1,
3583
+ 6899534: -1,
3584
+ 13799068: -1,
3585
+ 27598136: -1,
3586
+ 55196272: -1},
3587
+ [1, 0, 0, 2, 0],
3588
+ [4, 4, 2, 2],
3589
+ [0.15583810484385163,
3590
+ 0.14150261234359426,
3591
+ 0.31167620968770327,
3592
+ 0.28300522468718853])
3593
+ """
3594
+ M = ModularSymbolNumerical(E)
3595
+ e = M._epsQs
3596
+ a1 = Integer(M._ans[1])
3597
+ a2 = Integer(M._ans[2])
3598
+ a3 = Integer(M._ans[3])
3599
+ a4 = Integer(M._ans[389])
3600
+ M._add_an_coefficients(2014)
3601
+ a5 = Integer(M._ans[2013])
3602
+ t1 = Integer(M._t_plus)
3603
+ t2 = Integer(M._t_minus)
3604
+ t3 = Integer(M._t_unitary_plus)
3605
+ t4 = Integer(M._t_unitary_minus)
3606
+ e1 = M._eps_plus
3607
+ e2 = M._eps_minus
3608
+ e3 = M._eps_unitary_plus
3609
+ e4 = M._eps_unitary_minus
3610
+ return e, [a1, a2, a3, a4, a5], [t1, t2, t3, t4], [e1, e2, e3, e4]
3611
+
3612
+
3613
+ def _test_integration(E, a, b, T):
3614
+ r"""
3615
+ Doctest for the numerical integration in
3616
+ _integration_to_tau_double in the above class.
3617
+
3618
+ INPUT:
3619
+
3620
+ - ``E`` -- an elliptic curve
3621
+
3622
+ - ``a``, ``b`` -- two real numbers representing real and
3623
+ imaginary part of a complex number tau
3624
+
3625
+ - ``T `` -- integer for the number of terms to use
3626
+
3627
+ OUTPUT: a complex number
3628
+
3629
+ EXAMPLES::
3630
+
3631
+ sage: from sage.schemes.elliptic_curves.mod_sym_num \
3632
+ ....: import _test_integration
3633
+ sage: E = EllipticCurve("11a1")
3634
+ sage: _test_integration(E, 0,0.01,1000) # abs tol 1e-11
3635
+ (0.2538418608559108+0j)
3636
+ sage: _test_integration(E, 0,0.0001,10000) # abs tol 1e-11
3637
+ (0.2538815728257322+0j)
3638
+
3639
+ sage: E = EllipticCurve("37a1")
3640
+ sage: _test_integration(E, 0, 0.0001,1000) # abs tol 1e-11
3641
+ (-0.0105693920159094+0j)
3642
+ sage: _test_integration(E, 0.7, 0.1, 10000) # abs tol 1e-11
3643
+ (-0.021614803690068213-0.7770316490609953j)
3644
+ sage: _test_integration(E, 0.7, 0.1, 20000) # abs tol 1e-11
3645
+ (-0.021614803690068213-0.7770316490609953j)
3646
+ """
3647
+ M = ModularSymbolNumerical(E)
3648
+ c = complex(a,b)
3649
+ tt = <int>T
3650
+ ans = M._integration_to_tau_double(c,tt)
3651
+ return ans
3652
+
3653
+
3654
+ def _test_integration_via_partials(E, y, m, T):
3655
+ r"""
3656
+ Doctest for the numerical integration in
3657
+ _partial_real_sums_double in the above class.
3658
+
3659
+ INPUT:
3660
+
3661
+ - ``E`` -- an elliptic curve
3662
+
3663
+ - ``y`` -- a real number
3664
+
3665
+ - ``m`` -- integer
3666
+
3667
+ - ``T `` -- integer for the number of terms to use
3668
+
3669
+ OUTPUT: list of `m` real numbers
3670
+
3671
+ EXAMPLES::
3672
+
3673
+ sage: from sage.schemes.elliptic_curves.mod_sym_num \
3674
+ ....: import _test_integration_via_partials
3675
+ sage: E = EllipticCurve("11a1")
3676
+ sage: _test_integration_via_partials(E,0.001,3,1000) # abs tol 1e-11
3677
+ [-0.16916415619939476, 1.0536872023214188, -0.6306661264594561]
3678
+
3679
+ sage: E = EllipticCurve("121c1")
3680
+ sage: _test_integration_via_partials(E,0.03,3,700) # abs tol 1e-11
3681
+ [0.49198993741342784, 0.6601504274130793, 0.3177042713926389]
3682
+ sage: _test_integration_via_partials(E,0.03,3,7000) # abs tol 1e-11
3683
+ [0.49198993741342784, 0.6601504274130793, 0.3177042713926389]
3684
+ """
3685
+ cdef int mm = <int>(m)
3686
+ cdef double * ra
3687
+ ra = <double *> sig_malloc(mm * sizeof(double))
3688
+ if ra is NULL:
3689
+ raise MemoryError
3690
+ M = ModularSymbolNumerical(E)
3691
+ _ = M._partial_real_sums_double(y, m, T, ra)
3692
+ res = [ra[j] for j in range(m)]
3693
+ sig_free(ra)
3694
+ return res
3695
+
3696
+
3697
+ def _test_against_table(range_of_conductors, other_implementation='sage', list_of_cusps=None, verb=False):
3698
+ r"""
3699
+ This test function checks the modular symbols here against the
3700
+ ones implemented already. Note that for some curves the current
3701
+ implementation does not scale them correctly and so we might be off
3702
+ by a small integer.
3703
+
3704
+ INPUT:
3705
+
3706
+ - ``range_of_conductors`` -- list of integers; all curves with
3707
+ conductors in that list will be tested
3708
+
3709
+ - ``list_of_cusps`` -- list of rationals to be tested
3710
+
3711
+ - ``verb`` -- if ``True`` (default) prints the values
3712
+
3713
+ OUTPUT: boolean; if ``False`` the function also prints information
3714
+
3715
+ EXAMPLES::
3716
+
3717
+ sage: from sage.schemes.elliptic_curves.mod_sym_num \
3718
+ ....: import _test_against_table
3719
+ sage: _test_against_table([11,37]) # long time
3720
+ True
3721
+ """
3722
+ boo = True
3723
+ from sage.schemes.elliptic_curves.ell_rational_field import cremona_curves
3724
+ if list_of_cusps is None:
3725
+ list_of_cusps = []
3726
+ for C in cremona_curves(range_of_conductors):
3727
+ if verb:
3728
+ print("testing curve ", C.label())
3729
+ m = C.modular_symbol(implementation=other_implementation)
3730
+ m2 = C.modular_symbol(sign=-1, implementation=other_implementation)
3731
+ M = ModularSymbolNumerical(C)
3732
+ # a few random small rationals
3733
+ if len(list_of_cusps)==0:
3734
+ list_of_cusps = [Rational((0,1)),Rational((1,1)),Rational((1,2)),
3735
+ Rational((1,3)),Rational((1,4)),Rational((2,5)),
3736
+ Rational((1,6)),Rational((3,7)),Rational((1,8)),
3737
+ Rational((5,9)),Rational((7,10))]
3738
+ for r in list_of_cusps:
3739
+ mr = m(r)
3740
+ m2r = m2(r)
3741
+ Mr = M(r)
3742
+ M2r = M(r, sign=-1)
3743
+ if verb:
3744
+ print("r={} : ({},{}),({}, {})".format(r,mr,m2r,Mr,M2r), end=" ", flush=True)
3745
+ if mr != Mr or m2r != M2r:
3746
+ print (("B u g : curve = {}, cusp = {}, sage's symbols"
3747
+ + "({},{}), our symbols ({}, {})").format(C.label(), r,
3748
+ mr, m2r, Mr, M2r))
3749
+ boo = False
3750
+ M.clear_cache()
3751
+ return boo
3752
+
3753
+
3754
+ # =========================================
3755
+ #
3756
+ # Justification for numbers in _get_truncation_and_prec
3757
+ # in the estimates of sigma_0(n)
3758
+ # the following code in sage gives n_0 such that
3759
+ # sigma0(n) < B * sqrt(n) for all n> n0 for a given B
3760
+ #
3761
+ #y = lambda n: number_of_divisors(n)/sqrt(n*1.)
3762
+ #
3763
+ #def hidef(B):
3764
+ # """finds all n with y(n) > B for some bound B"""
3765
+ # li = [1]
3766
+ # old = [1]
3767
+ # while old:
3768
+ # new = []
3769
+ # p = 1
3770
+ # boo = True
3771
+ # while boo:
3772
+ # p = next_prime(p)
3773
+ # boo = False
3774
+ # for n in old:
3775
+ # m = n*p
3776
+ # if m not in new and y(m) > B:
3777
+ # new.append(m)
3778
+ # boo = True
3779
+ # li += new
3780
+ # old = new
3781
+ # return li
3782
+ #
3783
+ #def last_hidef(B):
3784
+ # n = max(hidef(B))
3785
+ # return n, y(n)
3786
+ #
3787
+ #for B in [1,2/3,1/2,1/3,1/4,1/5,1/6]:
3788
+ # print(last_hidef(B))
3789
+ #
3790
+ #(1260, 1.01418510567422)
3791
+ #(10080, 0.717137165600636)
3792
+ #(55440, 0.509647191437626)
3793
+ #(277200, 0.341881729378914)
3794
+ #(831600, 0.263180677983908)
3795
+ #(2162160, 0.217623636951613)
3796
+ #(4324320, 0.184659779321958)