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.
- passagemath_schemes/.dylibs/libflint.22.0.dylib +0 -0
- passagemath_schemes/.dylibs/libgmp.10.dylib +0 -0
- passagemath_schemes/.dylibs/libgmpxx.4.dylib +0 -0
- passagemath_schemes/.dylibs/libmpfr.6.dylib +0 -0
- passagemath_schemes/__init__.py +3 -0
- passagemath_schemes-10.6.40.dist-info/METADATA +204 -0
- passagemath_schemes-10.6.40.dist-info/METADATA.bak +205 -0
- passagemath_schemes-10.6.40.dist-info/RECORD +314 -0
- passagemath_schemes-10.6.40.dist-info/WHEEL +6 -0
- passagemath_schemes-10.6.40.dist-info/top_level.txt +3 -0
- sage/all__sagemath_schemes.py +23 -0
- sage/databases/all__sagemath_schemes.py +7 -0
- sage/databases/cremona.py +1723 -0
- sage/dynamics/all__sagemath_schemes.py +2 -0
- sage/dynamics/arithmetic_dynamics/affine_ds.py +1083 -0
- sage/dynamics/arithmetic_dynamics/all.py +14 -0
- sage/dynamics/arithmetic_dynamics/berkovich_ds.py +1101 -0
- sage/dynamics/arithmetic_dynamics/dynamical_semigroup.py +1543 -0
- sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py +2426 -0
- sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py +1169 -0
- sage/dynamics/arithmetic_dynamics/generic_ds.py +663 -0
- sage/dynamics/arithmetic_dynamics/product_projective_ds.py +339 -0
- sage/dynamics/arithmetic_dynamics/projective_ds.py +9558 -0
- sage/dynamics/arithmetic_dynamics/projective_ds_helper.cpython-314-darwin.so +0 -0
- sage/dynamics/arithmetic_dynamics/projective_ds_helper.pyx +301 -0
- sage/dynamics/arithmetic_dynamics/wehlerK3.py +2576 -0
- sage/lfunctions/all.py +18 -0
- sage/lfunctions/dokchitser.py +745 -0
- sage/lfunctions/pari.py +818 -0
- sage/lfunctions/zero_sums.cpython-314-darwin.so +0 -0
- sage/lfunctions/zero_sums.pyx +1847 -0
- sage/modular/abvar/abvar.py +5135 -0
- sage/modular/abvar/abvar_ambient_jacobian.py +413 -0
- sage/modular/abvar/abvar_newform.py +244 -0
- sage/modular/abvar/all.py +8 -0
- sage/modular/abvar/constructor.py +186 -0
- sage/modular/abvar/cuspidal_subgroup.py +371 -0
- sage/modular/abvar/finite_subgroup.py +896 -0
- sage/modular/abvar/homology.py +720 -0
- sage/modular/abvar/homspace.py +998 -0
- sage/modular/abvar/lseries.py +415 -0
- sage/modular/abvar/morphism.py +935 -0
- sage/modular/abvar/torsion_point.py +274 -0
- sage/modular/abvar/torsion_subgroup.py +740 -0
- sage/modular/all.py +43 -0
- sage/modular/arithgroup/all.py +20 -0
- sage/modular/arithgroup/arithgroup_element.cpython-314-darwin.so +0 -0
- sage/modular/arithgroup/arithgroup_element.pyx +474 -0
- sage/modular/arithgroup/arithgroup_generic.py +1402 -0
- sage/modular/arithgroup/arithgroup_perm.py +2692 -0
- sage/modular/arithgroup/congroup.cpython-314-darwin.so +0 -0
- sage/modular/arithgroup/congroup.pyx +334 -0
- sage/modular/arithgroup/congroup_gamma.py +363 -0
- sage/modular/arithgroup/congroup_gamma0.py +692 -0
- sage/modular/arithgroup/congroup_gamma1.py +653 -0
- sage/modular/arithgroup/congroup_gammaH.py +1469 -0
- sage/modular/arithgroup/congroup_generic.py +628 -0
- sage/modular/arithgroup/congroup_sl2z.py +267 -0
- sage/modular/arithgroup/farey_symbol.cpython-314-darwin.so +0 -0
- sage/modular/arithgroup/farey_symbol.pyx +1066 -0
- sage/modular/arithgroup/tests.py +418 -0
- sage/modular/btquotients/all.py +4 -0
- sage/modular/btquotients/btquotient.py +3753 -0
- sage/modular/btquotients/pautomorphicform.py +2570 -0
- sage/modular/buzzard.py +100 -0
- sage/modular/congroup.py +29 -0
- sage/modular/congroup_element.py +13 -0
- sage/modular/cusps.py +1109 -0
- sage/modular/cusps_nf.py +1270 -0
- sage/modular/dims.py +569 -0
- sage/modular/dirichlet.py +3310 -0
- sage/modular/drinfeld_modform/all.py +2 -0
- sage/modular/drinfeld_modform/element.py +446 -0
- sage/modular/drinfeld_modform/ring.py +773 -0
- sage/modular/drinfeld_modform/tutorial.py +236 -0
- sage/modular/etaproducts.py +1065 -0
- sage/modular/hecke/algebra.py +746 -0
- sage/modular/hecke/all.py +20 -0
- sage/modular/hecke/ambient_module.py +1019 -0
- sage/modular/hecke/degenmap.py +119 -0
- sage/modular/hecke/element.py +325 -0
- sage/modular/hecke/hecke_operator.py +780 -0
- sage/modular/hecke/homspace.py +206 -0
- sage/modular/hecke/module.py +1767 -0
- sage/modular/hecke/morphism.py +174 -0
- sage/modular/hecke/submodule.py +989 -0
- sage/modular/hypergeometric_misc.cpython-314-darwin.so +0 -0
- sage/modular/hypergeometric_misc.pxd +4 -0
- sage/modular/hypergeometric_misc.pyx +166 -0
- sage/modular/hypergeometric_motive.py +2017 -0
- sage/modular/local_comp/all.py +2 -0
- sage/modular/local_comp/liftings.py +292 -0
- sage/modular/local_comp/local_comp.py +1071 -0
- sage/modular/local_comp/smoothchar.py +1825 -0
- sage/modular/local_comp/type_space.py +748 -0
- sage/modular/modform/all.py +30 -0
- sage/modular/modform/ambient.py +815 -0
- sage/modular/modform/ambient_R.py +177 -0
- sage/modular/modform/ambient_eps.py +306 -0
- sage/modular/modform/ambient_g0.py +124 -0
- sage/modular/modform/ambient_g1.py +204 -0
- sage/modular/modform/constructor.py +545 -0
- sage/modular/modform/cuspidal_submodule.py +708 -0
- sage/modular/modform/defaults.py +14 -0
- sage/modular/modform/eis_series.py +505 -0
- sage/modular/modform/eisenstein_submodule.py +663 -0
- sage/modular/modform/element.py +4131 -0
- sage/modular/modform/find_generators.py +59 -0
- sage/modular/modform/half_integral.py +154 -0
- sage/modular/modform/hecke_operator_on_qexp.py +247 -0
- sage/modular/modform/j_invariant.py +47 -0
- sage/modular/modform/l_series_gross_zagier.py +133 -0
- sage/modular/modform/l_series_gross_zagier_coeffs.cpython-314-darwin.so +0 -0
- sage/modular/modform/l_series_gross_zagier_coeffs.pyx +177 -0
- sage/modular/modform/notes.py +45 -0
- sage/modular/modform/numerical.py +514 -0
- sage/modular/modform/periods.py +14 -0
- sage/modular/modform/ring.py +1257 -0
- sage/modular/modform/space.py +1860 -0
- sage/modular/modform/submodule.py +118 -0
- sage/modular/modform/tests.py +64 -0
- sage/modular/modform/theta.py +110 -0
- sage/modular/modform/vm_basis.py +381 -0
- sage/modular/modform/weight1.py +220 -0
- sage/modular/modform_hecketriangle/abstract_ring.py +1932 -0
- sage/modular/modform_hecketriangle/abstract_space.py +2528 -0
- sage/modular/modform_hecketriangle/all.py +30 -0
- sage/modular/modform_hecketriangle/analytic_type.py +590 -0
- sage/modular/modform_hecketriangle/constructor.py +416 -0
- sage/modular/modform_hecketriangle/element.py +351 -0
- sage/modular/modform_hecketriangle/functors.py +752 -0
- sage/modular/modform_hecketriangle/graded_ring.py +541 -0
- sage/modular/modform_hecketriangle/graded_ring_element.py +2225 -0
- sage/modular/modform_hecketriangle/hecke_triangle_group_element.py +3352 -0
- sage/modular/modform_hecketriangle/hecke_triangle_groups.py +1432 -0
- sage/modular/modform_hecketriangle/readme.py +1214 -0
- sage/modular/modform_hecketriangle/series_constructor.py +580 -0
- sage/modular/modform_hecketriangle/space.py +1037 -0
- sage/modular/modform_hecketriangle/subspace.py +423 -0
- sage/modular/modsym/all.py +17 -0
- sage/modular/modsym/ambient.py +3846 -0
- sage/modular/modsym/boundary.py +1420 -0
- sage/modular/modsym/element.py +336 -0
- sage/modular/modsym/g1list.py +178 -0
- sage/modular/modsym/ghlist.py +182 -0
- sage/modular/modsym/hecke_operator.py +73 -0
- sage/modular/modsym/manin_symbol.cpython-314-darwin.so +0 -0
- sage/modular/modsym/manin_symbol.pxd +5 -0
- sage/modular/modsym/manin_symbol.pyx +497 -0
- sage/modular/modsym/manin_symbol_list.py +1295 -0
- sage/modular/modsym/modsym.py +400 -0
- sage/modular/modsym/modular_symbols.py +384 -0
- sage/modular/modsym/p1list.cpython-314-darwin.so +0 -0
- sage/modular/modsym/p1list.pxd +29 -0
- sage/modular/modsym/p1list.pyx +1372 -0
- sage/modular/modsym/p1list_nf.py +1241 -0
- sage/modular/modsym/relation_matrix.py +591 -0
- sage/modular/modsym/relation_matrix_pyx.cpython-314-darwin.so +0 -0
- sage/modular/modsym/relation_matrix_pyx.pyx +108 -0
- sage/modular/modsym/space.py +2468 -0
- sage/modular/modsym/subspace.py +455 -0
- sage/modular/modsym/tests.py +375 -0
- sage/modular/multiple_zeta.py +2632 -0
- sage/modular/multiple_zeta_F_algebra.py +786 -0
- sage/modular/overconvergent/all.py +6 -0
- sage/modular/overconvergent/genus0.py +1878 -0
- sage/modular/overconvergent/hecke_series.py +1187 -0
- sage/modular/overconvergent/weightspace.py +778 -0
- sage/modular/pollack_stevens/all.py +4 -0
- sage/modular/pollack_stevens/distributions.py +874 -0
- sage/modular/pollack_stevens/fund_domain.py +1572 -0
- sage/modular/pollack_stevens/manin_map.py +859 -0
- sage/modular/pollack_stevens/modsym.py +1593 -0
- sage/modular/pollack_stevens/padic_lseries.py +417 -0
- sage/modular/pollack_stevens/sigma0.py +534 -0
- sage/modular/pollack_stevens/space.py +1076 -0
- sage/modular/quasimodform/all.py +3 -0
- sage/modular/quasimodform/element.py +845 -0
- sage/modular/quasimodform/ring.py +828 -0
- sage/modular/quatalg/all.py +3 -0
- sage/modular/quatalg/brandt.py +1642 -0
- sage/modular/ssmod/all.py +8 -0
- sage/modular/ssmod/ssmod.py +827 -0
- sage/rings/all__sagemath_schemes.py +1 -0
- sage/rings/polynomial/all__sagemath_schemes.py +1 -0
- sage/rings/polynomial/binary_form_reduce.py +585 -0
- sage/schemes/all.py +41 -0
- sage/schemes/berkovich/all.py +6 -0
- sage/schemes/berkovich/berkovich_cp_element.py +2582 -0
- sage/schemes/berkovich/berkovich_space.py +748 -0
- sage/schemes/curves/affine_curve.py +2928 -0
- sage/schemes/curves/all.py +33 -0
- sage/schemes/curves/closed_point.py +434 -0
- sage/schemes/curves/constructor.py +381 -0
- sage/schemes/curves/curve.py +542 -0
- sage/schemes/curves/plane_curve_arrangement.py +1283 -0
- sage/schemes/curves/point.py +463 -0
- sage/schemes/curves/projective_curve.py +3026 -0
- sage/schemes/curves/zariski_vankampen.py +1932 -0
- sage/schemes/cyclic_covers/all.py +2 -0
- sage/schemes/cyclic_covers/charpoly_frobenius.py +320 -0
- sage/schemes/cyclic_covers/constructor.py +137 -0
- sage/schemes/cyclic_covers/cycliccover_finite_field.py +1309 -0
- sage/schemes/cyclic_covers/cycliccover_generic.py +310 -0
- sage/schemes/elliptic_curves/BSD.py +1036 -0
- sage/schemes/elliptic_curves/Qcurves.py +592 -0
- sage/schemes/elliptic_curves/addition_formulas_ring.py +94 -0
- sage/schemes/elliptic_curves/all.py +49 -0
- sage/schemes/elliptic_curves/cardinality.py +609 -0
- sage/schemes/elliptic_curves/cm.py +1102 -0
- sage/schemes/elliptic_curves/constructor.py +1552 -0
- sage/schemes/elliptic_curves/ec_database.py +175 -0
- sage/schemes/elliptic_curves/ell_curve_isogeny.py +3972 -0
- sage/schemes/elliptic_curves/ell_egros.py +459 -0
- sage/schemes/elliptic_curves/ell_field.py +2836 -0
- sage/schemes/elliptic_curves/ell_finite_field.py +3359 -0
- sage/schemes/elliptic_curves/ell_generic.py +3760 -0
- sage/schemes/elliptic_curves/ell_local_data.py +1207 -0
- sage/schemes/elliptic_curves/ell_modular_symbols.py +775 -0
- sage/schemes/elliptic_curves/ell_number_field.py +4220 -0
- sage/schemes/elliptic_curves/ell_padic_field.py +107 -0
- sage/schemes/elliptic_curves/ell_point.py +4787 -0
- sage/schemes/elliptic_curves/ell_rational_field.py +7368 -0
- sage/schemes/elliptic_curves/ell_tate_curve.py +671 -0
- sage/schemes/elliptic_curves/ell_torsion.py +436 -0
- sage/schemes/elliptic_curves/ell_wp.py +352 -0
- sage/schemes/elliptic_curves/formal_group.py +760 -0
- sage/schemes/elliptic_curves/gal_reps.py +1459 -0
- sage/schemes/elliptic_curves/gal_reps_number_field.py +1669 -0
- sage/schemes/elliptic_curves/gp_simon.py +152 -0
- sage/schemes/elliptic_curves/heegner.py +7335 -0
- sage/schemes/elliptic_curves/height.py +2109 -0
- sage/schemes/elliptic_curves/hom.py +1406 -0
- sage/schemes/elliptic_curves/hom_composite.py +934 -0
- sage/schemes/elliptic_curves/hom_frobenius.py +522 -0
- sage/schemes/elliptic_curves/hom_scalar.py +531 -0
- sage/schemes/elliptic_curves/hom_sum.py +682 -0
- sage/schemes/elliptic_curves/hom_velusqrt.py +1290 -0
- sage/schemes/elliptic_curves/homset.py +271 -0
- sage/schemes/elliptic_curves/isogeny_class.py +1521 -0
- sage/schemes/elliptic_curves/isogeny_small_degree.py +2797 -0
- sage/schemes/elliptic_curves/jacobian.py +237 -0
- sage/schemes/elliptic_curves/kodaira_symbol.py +344 -0
- sage/schemes/elliptic_curves/kraus.py +1014 -0
- sage/schemes/elliptic_curves/lseries_ell.py +943 -0
- sage/schemes/elliptic_curves/mod5family.py +105 -0
- sage/schemes/elliptic_curves/mod_poly.py +197 -0
- sage/schemes/elliptic_curves/mod_sym_num.cpython-314-darwin.so +0 -0
- sage/schemes/elliptic_curves/mod_sym_num.pyx +3796 -0
- sage/schemes/elliptic_curves/modular_parametrization.py +305 -0
- sage/schemes/elliptic_curves/padic_lseries.py +1793 -0
- sage/schemes/elliptic_curves/padics.py +1816 -0
- sage/schemes/elliptic_curves/period_lattice.py +2234 -0
- sage/schemes/elliptic_curves/period_lattice_region.cpython-314-darwin.so +0 -0
- sage/schemes/elliptic_curves/period_lattice_region.pyx +722 -0
- sage/schemes/elliptic_curves/saturation.py +715 -0
- sage/schemes/elliptic_curves/sha_tate.py +1158 -0
- sage/schemes/elliptic_curves/weierstrass_morphism.py +1117 -0
- sage/schemes/elliptic_curves/weierstrass_transform.py +200 -0
- sage/schemes/hyperelliptic_curves/all.py +6 -0
- sage/schemes/hyperelliptic_curves/constructor.py +291 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py +1914 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_g2.py +192 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py +954 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py +1332 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_rational_field.py +84 -0
- sage/schemes/hyperelliptic_curves/invariants.py +410 -0
- sage/schemes/hyperelliptic_curves/jacobian_endomorphism_utils.py +315 -0
- sage/schemes/hyperelliptic_curves/jacobian_g2.py +32 -0
- sage/schemes/hyperelliptic_curves/jacobian_generic.py +419 -0
- sage/schemes/hyperelliptic_curves/jacobian_homset.py +186 -0
- sage/schemes/hyperelliptic_curves/jacobian_morphism.py +875 -0
- sage/schemes/hyperelliptic_curves/kummer_surface.py +99 -0
- sage/schemes/hyperelliptic_curves/mestre.py +302 -0
- sage/schemes/hyperelliptic_curves/monsky_washnitzer.py +3871 -0
- sage/schemes/jacobians/abstract_jacobian.py +277 -0
- sage/schemes/jacobians/all.py +2 -0
- sage/schemes/overview.py +161 -0
- sage/schemes/plane_conics/all.py +22 -0
- sage/schemes/plane_conics/con_field.py +1296 -0
- sage/schemes/plane_conics/con_finite_field.py +158 -0
- sage/schemes/plane_conics/con_number_field.py +456 -0
- sage/schemes/plane_conics/con_rational_field.py +406 -0
- sage/schemes/plane_conics/con_rational_function_field.py +580 -0
- sage/schemes/plane_conics/constructor.py +249 -0
- sage/schemes/plane_quartics/all.py +2 -0
- sage/schemes/plane_quartics/quartic_constructor.py +71 -0
- sage/schemes/plane_quartics/quartic_generic.py +73 -0
- sage/schemes/riemann_surfaces/all.py +1 -0
- sage/schemes/riemann_surfaces/riemann_surface.py +4117 -0
- sage_wheels/share/cremona/cremona_mini.db +0 -0
- sage_wheels/share/ellcurves/rank0 +30427 -0
- sage_wheels/share/ellcurves/rank1 +31871 -0
- sage_wheels/share/ellcurves/rank10 +6 -0
- sage_wheels/share/ellcurves/rank11 +6 -0
- sage_wheels/share/ellcurves/rank12 +1 -0
- sage_wheels/share/ellcurves/rank14 +1 -0
- sage_wheels/share/ellcurves/rank15 +1 -0
- sage_wheels/share/ellcurves/rank17 +1 -0
- sage_wheels/share/ellcurves/rank19 +1 -0
- sage_wheels/share/ellcurves/rank2 +2388 -0
- sage_wheels/share/ellcurves/rank20 +1 -0
- sage_wheels/share/ellcurves/rank21 +1 -0
- sage_wheels/share/ellcurves/rank22 +1 -0
- sage_wheels/share/ellcurves/rank23 +1 -0
- sage_wheels/share/ellcurves/rank24 +1 -0
- sage_wheels/share/ellcurves/rank28 +1 -0
- sage_wheels/share/ellcurves/rank3 +836 -0
- sage_wheels/share/ellcurves/rank4 +10 -0
- sage_wheels/share/ellcurves/rank5 +5 -0
- sage_wheels/share/ellcurves/rank6 +5 -0
- sage_wheels/share/ellcurves/rank7 +5 -0
- sage_wheels/share/ellcurves/rank8 +6 -0
- 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)
|