passagemath-schemes 10.6.47__cp312-cp312-macosx_13_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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.47.dist-info/METADATA +204 -0
- passagemath_schemes-10.6.47.dist-info/METADATA.bak +205 -0
- passagemath_schemes-10.6.47.dist-info/RECORD +311 -0
- passagemath_schemes-10.6.47.dist-info/WHEEL +6 -0
- passagemath_schemes-10.6.47.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-312-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-312-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-312-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-312-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-312-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-312-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-312-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-312-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_nf.py +1241 -0
- sage/modular/modsym/relation_matrix.py +591 -0
- sage/modular/modsym/relation_matrix_pyx.cpython-312-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-312-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-312-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,1847 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-schemes
|
|
2
|
+
# sage.doctest: needs sage.symbolic
|
|
3
|
+
r"""
|
|
4
|
+
Class for computing sums over zeros of motivic `L`-functions
|
|
5
|
+
|
|
6
|
+
All computations are done to double precision.
|
|
7
|
+
|
|
8
|
+
AUTHORS:
|
|
9
|
+
|
|
10
|
+
- Simon Spicer (2014-10): first version
|
|
11
|
+
"""
|
|
12
|
+
# ****************************************************************************
|
|
13
|
+
# Copyright (C) 2014 Simon Spicer <mlungu@uw.edu>
|
|
14
|
+
#
|
|
15
|
+
# This program is free software: you can redistribute it and/or modify
|
|
16
|
+
# it under the terms of the GNU General Public License as published by
|
|
17
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
18
|
+
# (at your option) any later version.
|
|
19
|
+
# https://www.gnu.org/licenses/
|
|
20
|
+
# ****************************************************************************
|
|
21
|
+
|
|
22
|
+
from sage.arith.misc import next_prime
|
|
23
|
+
from sage.functions.log import log, exp
|
|
24
|
+
from sage.functions.other import real, imag
|
|
25
|
+
from sage.libs.flint.ulong_extras cimport n_is_prime
|
|
26
|
+
from sage.misc.verbose import verbose
|
|
27
|
+
from sage.parallel.decorate import parallel
|
|
28
|
+
from sage.parallel.ncpus import ncpus as num_cpus
|
|
29
|
+
from sage.rings.complex_double import CDF
|
|
30
|
+
from sage.rings.infinity import PlusInfinity
|
|
31
|
+
from sage.rings.integer_ring import ZZ
|
|
32
|
+
from sage.rings.real_double import RDF
|
|
33
|
+
from sage.structure.sage_object cimport SageObject
|
|
34
|
+
from sage.symbolic.constants import euler_gamma, pi
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
cdef extern from "<math.h>":
|
|
38
|
+
double c_exp "exp"(double)
|
|
39
|
+
double c_log "log"(double)
|
|
40
|
+
double c_cos "cos"(double)
|
|
41
|
+
double c_acos "acos"(double)
|
|
42
|
+
double c_sqrt "sqrt"(double)
|
|
43
|
+
|
|
44
|
+
# Global variable determining the number of CPUs to use for parallel computations
|
|
45
|
+
cdef NCPUS
|
|
46
|
+
|
|
47
|
+
cdef class LFunctionZeroSum_abstract(SageObject):
|
|
48
|
+
r"""
|
|
49
|
+
Abstract class for computing certain sums over zeros of a motivic `L`-function
|
|
50
|
+
without having to determine the zeros themselves.
|
|
51
|
+
"""
|
|
52
|
+
cdef _pi # Pi to 64 bits
|
|
53
|
+
cdef _euler_gamma # Euler-Mascheroni constant = 0.5772...
|
|
54
|
+
cdef _level # The level of the form attached to self
|
|
55
|
+
cdef _k # The weight of the form attached to self
|
|
56
|
+
cdef _C1 # = log(N)/2 - log(2*pi)
|
|
57
|
+
cdef _C0 # = C1 - euler_gamma
|
|
58
|
+
cdef _ncpus # The number of CPUs to use for parallel computations
|
|
59
|
+
|
|
60
|
+
def ncpus(self, n=None):
|
|
61
|
+
r"""
|
|
62
|
+
Set or return the number of CPUs to be used in parallel computations.
|
|
63
|
+
|
|
64
|
+
If called with no input, the number of CPUs currently set is returned;
|
|
65
|
+
else this value is set to `n`. If `n` is 0 then the number of CPUs is set
|
|
66
|
+
to the max available.
|
|
67
|
+
|
|
68
|
+
INPUT:
|
|
69
|
+
|
|
70
|
+
- ``n`` -- (default: ``None``) if not ``None``, a nonnegative integer
|
|
71
|
+
|
|
72
|
+
OUTPUT: if `n` is not ``None``, returns a positive integer
|
|
73
|
+
|
|
74
|
+
EXAMPLES::
|
|
75
|
+
|
|
76
|
+
sage: Z = LFunctionZeroSum(EllipticCurve("389a"))
|
|
77
|
+
sage: Z.ncpus()
|
|
78
|
+
1
|
|
79
|
+
sage: Z.ncpus(2)
|
|
80
|
+
sage: Z.ncpus()
|
|
81
|
+
2
|
|
82
|
+
|
|
83
|
+
The following output will depend on the system that Sage is running on.
|
|
84
|
+
|
|
85
|
+
::
|
|
86
|
+
|
|
87
|
+
sage: Z.ncpus(0)
|
|
88
|
+
sage: Z.ncpus() # random
|
|
89
|
+
4
|
|
90
|
+
"""
|
|
91
|
+
if n is None:
|
|
92
|
+
return self._ncpus
|
|
93
|
+
elif n < 0:
|
|
94
|
+
raise ValueError("input must be positive integer")
|
|
95
|
+
elif n == 0:
|
|
96
|
+
self._ncpus = num_cpus()
|
|
97
|
+
NCPUS = self._ncpus
|
|
98
|
+
else:
|
|
99
|
+
self._ncpus = n
|
|
100
|
+
NCPUS = self._ncpus
|
|
101
|
+
|
|
102
|
+
def level(self):
|
|
103
|
+
r"""
|
|
104
|
+
Return the level of the form attached to ``self``.
|
|
105
|
+
|
|
106
|
+
If ``self`` was constructed from an elliptic curve,
|
|
107
|
+
then this is equal to the conductor of `E`.
|
|
108
|
+
|
|
109
|
+
EXAMPLES::
|
|
110
|
+
|
|
111
|
+
sage: E = EllipticCurve("389a")
|
|
112
|
+
sage: Z = LFunctionZeroSum(E)
|
|
113
|
+
sage: Z.level()
|
|
114
|
+
389
|
|
115
|
+
"""
|
|
116
|
+
return self._level
|
|
117
|
+
|
|
118
|
+
def weight(self):
|
|
119
|
+
r"""
|
|
120
|
+
Return the weight of the form attached to ``self``.
|
|
121
|
+
|
|
122
|
+
If ``self`` was constructed
|
|
123
|
+
from an elliptic curve, then this is 2.
|
|
124
|
+
|
|
125
|
+
EXAMPLES::
|
|
126
|
+
|
|
127
|
+
sage: E = EllipticCurve("389a")
|
|
128
|
+
sage: Z = LFunctionZeroSum(E)
|
|
129
|
+
sage: Z.weight()
|
|
130
|
+
2
|
|
131
|
+
"""
|
|
132
|
+
return self._k
|
|
133
|
+
|
|
134
|
+
def C0(self, include_euler_gamma=True):
|
|
135
|
+
r"""
|
|
136
|
+
Return the constant term of the logarithmic derivative of the
|
|
137
|
+
completed `L`-function attached to ``self``.
|
|
138
|
+
|
|
139
|
+
This is equal to
|
|
140
|
+
`-\eta + \log(N)/2 - \log(2\pi)`, where `\eta` is the
|
|
141
|
+
Euler-Mascheroni constant `= 0.5772...`
|
|
142
|
+
and `N` is the level of the form attached to ``self``.
|
|
143
|
+
|
|
144
|
+
INPUT:
|
|
145
|
+
|
|
146
|
+
- ``include_euler_gamma`` -- boolean (default: ``True``); if set to
|
|
147
|
+
``False``, return the constant `\log(N)/2 - \log(2\pi)`, i.e., do
|
|
148
|
+
not subtract the Euler-Mascheroni constant
|
|
149
|
+
|
|
150
|
+
EXAMPLES::
|
|
151
|
+
|
|
152
|
+
sage: E = EllipticCurve("389a")
|
|
153
|
+
sage: Z = LFunctionZeroSum(E)
|
|
154
|
+
sage: Z.C0() # tol 1.0e-13
|
|
155
|
+
0.5666969404983447
|
|
156
|
+
sage: Z.C0(include_euler_gamma=False) # tol 1.0e-13
|
|
157
|
+
1.1439126053998776
|
|
158
|
+
"""
|
|
159
|
+
# Computed at initialization
|
|
160
|
+
return self._C1 if not include_euler_gamma else self._C0
|
|
161
|
+
|
|
162
|
+
def cnlist(self, n, python_floats=False):
|
|
163
|
+
r"""
|
|
164
|
+
Return a list of Dirichlet coefficient of the logarithmic
|
|
165
|
+
derivative of the `L`-function attached to ``self``, shifted so that
|
|
166
|
+
the critical line lies on the imaginary axis, up to and
|
|
167
|
+
including `n`.
|
|
168
|
+
|
|
169
|
+
The `i`-th element of the returned list is ``a[i]``.
|
|
170
|
+
|
|
171
|
+
INPUT:
|
|
172
|
+
|
|
173
|
+
- ``n`` -- nonnegative integer
|
|
174
|
+
|
|
175
|
+
- ``python_floats`` -- boolean (default: ``False``); if ``True`` return
|
|
176
|
+
a list of Python floats instead of Sage Real Double Field elements
|
|
177
|
+
|
|
178
|
+
OUTPUT: list of real numbers
|
|
179
|
+
|
|
180
|
+
.. SEEALSO::
|
|
181
|
+
|
|
182
|
+
:meth:`~sage.lfunctions.zero_sums.LFunctionZeroSum_EllipticCurve.cn`
|
|
183
|
+
|
|
184
|
+
.. TODO::
|
|
185
|
+
|
|
186
|
+
Speed this up; make more efficient
|
|
187
|
+
|
|
188
|
+
EXAMPLES::
|
|
189
|
+
|
|
190
|
+
sage: E = EllipticCurve("11a")
|
|
191
|
+
sage: Z = LFunctionZeroSum(E)
|
|
192
|
+
sage: cnlist = Z.cnlist(11)
|
|
193
|
+
sage: for n in range(12): print((n, cnlist[n])) # tol 1.0e-13
|
|
194
|
+
(0, 0.0)
|
|
195
|
+
(1, 0.0)
|
|
196
|
+
(2, 0.6931471805599453)
|
|
197
|
+
(3, 0.3662040962227033)
|
|
198
|
+
(4, 0.0)
|
|
199
|
+
(5, -0.32188758248682003)
|
|
200
|
+
(6, 0.0)
|
|
201
|
+
(7, 0.555974328301518)
|
|
202
|
+
(8, -0.34657359027997264)
|
|
203
|
+
(9, 0.6103401603711721)
|
|
204
|
+
(10, 0.0)
|
|
205
|
+
(11, -0.21799047934530644)
|
|
206
|
+
"""
|
|
207
|
+
if not python_floats:
|
|
208
|
+
return [self.cn(i) for i in range(n + 1)]
|
|
209
|
+
return [float(self.cn(i)) for i in range(n + 1)]
|
|
210
|
+
|
|
211
|
+
def digamma(self, s, include_constant_term=True):
|
|
212
|
+
r"""
|
|
213
|
+
Return the digamma function `\digamma(s)` on the complex input s.
|
|
214
|
+
|
|
215
|
+
This is given by
|
|
216
|
+
`\digamma(s) = -\eta + \sum_{k=1}^{\infty} \frac{s-1}{k(k+s-1)}`,
|
|
217
|
+
where `\eta` is the Euler-Mascheroni constant `=0.5772156649\ldots`.
|
|
218
|
+
|
|
219
|
+
This function is needed in the computing the logarithmic derivative
|
|
220
|
+
of the `L`-function attached to ``self``.
|
|
221
|
+
|
|
222
|
+
INPUT:
|
|
223
|
+
|
|
224
|
+
- ``s`` -- complex number
|
|
225
|
+
|
|
226
|
+
- ``include_constant_term`` -- boolean (default: ``True``); if set
|
|
227
|
+
to ``False``, only the value of the sum over `k` is returned without
|
|
228
|
+
subtracting the Euler-Mascheroni constant, i.e., the returned value
|
|
229
|
+
is equal to `\sum_{k=1}^{\infty} \frac{s-1}{k(k+s-1)}`
|
|
230
|
+
|
|
231
|
+
OUTPUT:
|
|
232
|
+
|
|
233
|
+
A real double precision number if the input is real and not a negative
|
|
234
|
+
integer; Infinity if the input is a negative integer, and a complex
|
|
235
|
+
number otherwise.
|
|
236
|
+
|
|
237
|
+
EXAMPLES::
|
|
238
|
+
|
|
239
|
+
sage: Z = LFunctionZeroSum(EllipticCurve("37a"))
|
|
240
|
+
sage: Z.digamma(3.2) # tol 1.0e-13
|
|
241
|
+
0.9988388912865993
|
|
242
|
+
sage: Z.digamma(3.2,include_constant_term=False) # tol 1.0e-13
|
|
243
|
+
1.576054556188132
|
|
244
|
+
sage: Z.digamma(1+I) # tol 1.0e-13
|
|
245
|
+
0.09465032062247625 + 1.076674047468581*I
|
|
246
|
+
sage: Z.digamma(-2)
|
|
247
|
+
+Infinity
|
|
248
|
+
|
|
249
|
+
Evaluating the sum without the constant term at the positive integers n
|
|
250
|
+
returns the (n-1)th harmonic number.
|
|
251
|
+
|
|
252
|
+
::
|
|
253
|
+
|
|
254
|
+
sage: Z.digamma(3,include_constant_term=False)
|
|
255
|
+
1.5
|
|
256
|
+
sage: Z.digamma(6,include_constant_term=False)
|
|
257
|
+
2.283333333333333
|
|
258
|
+
"""
|
|
259
|
+
# imported here so as to avoid importing Numpy on Sage startup
|
|
260
|
+
from scipy.special import psi
|
|
261
|
+
|
|
262
|
+
if real(s) < 0 and imag(s) == 0:
|
|
263
|
+
try:
|
|
264
|
+
z = ZZ(s)
|
|
265
|
+
return PlusInfinity()
|
|
266
|
+
except Exception:
|
|
267
|
+
pass
|
|
268
|
+
|
|
269
|
+
if imag(s) == 0:
|
|
270
|
+
F = RDF
|
|
271
|
+
else:
|
|
272
|
+
F = CDF
|
|
273
|
+
# Cheating: SciPy already has this function implemented for complex inputs
|
|
274
|
+
z = F(psi(F(s)))
|
|
275
|
+
if include_constant_term:
|
|
276
|
+
return z
|
|
277
|
+
else:
|
|
278
|
+
return z + self._euler_gamma
|
|
279
|
+
|
|
280
|
+
def logarithmic_derivative(self, s, num_terms=10000, as_interval=False):
|
|
281
|
+
r"""
|
|
282
|
+
Compute the value of the logarithmic derivative
|
|
283
|
+
`\frac{L^{\prime}}{L}` at the point s to *low* precision, where `L`
|
|
284
|
+
is the `L`-function attached to ``self``.
|
|
285
|
+
|
|
286
|
+
.. WARNING::
|
|
287
|
+
|
|
288
|
+
The value is computed naively by evaluating the Dirichlet series
|
|
289
|
+
for `\frac{L^{\prime}}{L}`; convergence is controlled by the
|
|
290
|
+
distance of s from the critical strip `0.5<=\Re(s)<=1.5`.
|
|
291
|
+
You may use this method to attempt to compute values inside the
|
|
292
|
+
critical strip; however, results are then *not* guaranteed
|
|
293
|
+
to be correct to any number of digits.
|
|
294
|
+
|
|
295
|
+
INPUT:
|
|
296
|
+
|
|
297
|
+
- ``s`` -- real or complex value
|
|
298
|
+
|
|
299
|
+
- ``num_terms`` -- integer (default: 10000); the maximum number of
|
|
300
|
+
terms summed in the Dirichlet series
|
|
301
|
+
|
|
302
|
+
OUTPUT:
|
|
303
|
+
|
|
304
|
+
A tuple (z,err), where z is the computed value, and err is an
|
|
305
|
+
upper bound on the truncation error in this value introduced
|
|
306
|
+
by truncating the Dirichlet sum.
|
|
307
|
+
|
|
308
|
+
.. NOTE::
|
|
309
|
+
|
|
310
|
+
For the default term cap of 10000, a value accurate to all 53
|
|
311
|
+
bits of a double precision floating point number is only
|
|
312
|
+
guaranteed when `|\Re(s-1)|>4.58`, although in practice inputs
|
|
313
|
+
closer to the critical strip will still yield computed values
|
|
314
|
+
close to the true value.
|
|
315
|
+
|
|
316
|
+
EXAMPLES::
|
|
317
|
+
|
|
318
|
+
sage: E = EllipticCurve([23,100])
|
|
319
|
+
sage: Z = LFunctionZeroSum(E)
|
|
320
|
+
sage: Z.logarithmic_derivative(10) # tol 1.0e-13
|
|
321
|
+
(5.648066742632698e-05, 1.0974102859764345e-34)
|
|
322
|
+
sage: Z.logarithmic_derivative(2.2) # tol 1.0e-13
|
|
323
|
+
(0.5751257063594758, 0.024087912696974387)
|
|
324
|
+
|
|
325
|
+
Increasing the number of terms should see the truncation error
|
|
326
|
+
decrease.
|
|
327
|
+
|
|
328
|
+
::
|
|
329
|
+
|
|
330
|
+
sage: Z.logarithmic_derivative(2.2,num_terms=50000) # long time # rel tol 1.0e-14
|
|
331
|
+
(0.5751579645060139, 0.008988775519160675)
|
|
332
|
+
|
|
333
|
+
Attempting to compute values inside the critical strip
|
|
334
|
+
gives infinite error.
|
|
335
|
+
|
|
336
|
+
::
|
|
337
|
+
|
|
338
|
+
sage: Z.logarithmic_derivative(1.3) # tol 1.0e-13
|
|
339
|
+
(5.442994413920786, +Infinity)
|
|
340
|
+
|
|
341
|
+
Complex inputs and inputs to the left of the critical strip
|
|
342
|
+
are allowed.
|
|
343
|
+
|
|
344
|
+
::
|
|
345
|
+
|
|
346
|
+
sage: Z.logarithmic_derivative(complex(3,-1)) # tol 1.0e-13
|
|
347
|
+
(0.04764548578052381 + 0.16513832809989326*I, 6.584671359095225e-06)
|
|
348
|
+
sage: Z.logarithmic_derivative(complex(-3,-1.1)) # tol 1.0e-13
|
|
349
|
+
(-13.908452173241546 + 2.591443099074753*I, 2.7131584736258447e-14)
|
|
350
|
+
|
|
351
|
+
The logarithmic derivative has poles at the negative integers.
|
|
352
|
+
|
|
353
|
+
::
|
|
354
|
+
|
|
355
|
+
sage: Z.logarithmic_derivative(-3) # tol 1.0e-13
|
|
356
|
+
(-Infinity, 2.7131584736258447e-14)
|
|
357
|
+
"""
|
|
358
|
+
if imag(s) == 0:
|
|
359
|
+
F = RDF
|
|
360
|
+
else:
|
|
361
|
+
F = CDF
|
|
362
|
+
# Inputs left of the critical line are handled via the functional
|
|
363
|
+
# equation of the logarithmic derivative
|
|
364
|
+
if real(s - 1) < 0:
|
|
365
|
+
a = -2 * self._C1 - self.digamma(s) - self.digamma(2 - s)
|
|
366
|
+
b, err = self.logarithmic_derivative(2 - s, num_terms=num_terms)
|
|
367
|
+
return (a + b, err)
|
|
368
|
+
|
|
369
|
+
z = s - 1
|
|
370
|
+
sigma = RDF(real(z))
|
|
371
|
+
# Compute maximum possible Dirichlet series truncation error
|
|
372
|
+
# When s is in the critical strip: no guaranteed precision
|
|
373
|
+
if abs(sigma) <= 0.5:
|
|
374
|
+
err = PlusInfinity()
|
|
375
|
+
else:
|
|
376
|
+
a = RDF(sigma) - RDF(0.5)
|
|
377
|
+
b = log(RDF(num_terms)) * a
|
|
378
|
+
err = (b + 1) * exp(-b) / a**2
|
|
379
|
+
|
|
380
|
+
y = F.zero()
|
|
381
|
+
n = ZZ(2)
|
|
382
|
+
while n <= num_terms:
|
|
383
|
+
if n.is_prime_power():
|
|
384
|
+
cn = self.cn(n)
|
|
385
|
+
y += cn / F(n)**z
|
|
386
|
+
n += 1
|
|
387
|
+
|
|
388
|
+
return (y, err)
|
|
389
|
+
|
|
390
|
+
def completed_logarithmic_derivative(self, s, num_terms=10000):
|
|
391
|
+
r"""
|
|
392
|
+
Compute the value of the completed logarithmic derivative
|
|
393
|
+
`\frac{\Lambda^{\prime}}{\Lambda}` at the point s to *low*
|
|
394
|
+
precision, where `\Lambda = N^{s/2}(2\pi)^s \Gamma(s) L(s)`
|
|
395
|
+
and `L` is the `L`-function attached to ``self``.
|
|
396
|
+
|
|
397
|
+
.. WARNING::
|
|
398
|
+
|
|
399
|
+
This is computed naively by evaluating the Dirichlet series
|
|
400
|
+
for `\frac{L^{\prime}}{L}`; the convergence thereof is
|
|
401
|
+
controlled by the distance of s from the critical strip
|
|
402
|
+
`0.5<=\Re(s)<=1.5`.
|
|
403
|
+
You may use this method to attempt to compute values inside the
|
|
404
|
+
critical strip; however, results are then *not* guaranteed
|
|
405
|
+
to be correct to any number of digits.
|
|
406
|
+
|
|
407
|
+
INPUT:
|
|
408
|
+
|
|
409
|
+
- ``s`` -- real or complex value
|
|
410
|
+
|
|
411
|
+
- ``num_terms`` -- integer (default: 10000); the maximum number of
|
|
412
|
+
terms summed in the Dirichlet series
|
|
413
|
+
|
|
414
|
+
OUTPUT:
|
|
415
|
+
|
|
416
|
+
A tuple (z,err), where z is the computed value, and err is an
|
|
417
|
+
upper bound on the truncation error in this value introduced
|
|
418
|
+
by truncating the Dirichlet sum.
|
|
419
|
+
|
|
420
|
+
.. NOTE::
|
|
421
|
+
|
|
422
|
+
For the default term cap of 10000, a value accurate to all 53
|
|
423
|
+
bits of a double precision floating point number is only
|
|
424
|
+
guaranteed when `|\Re(s-1)|>4.58`, although in practice inputs
|
|
425
|
+
closer to the critical strip will still yield computed values
|
|
426
|
+
close to the true value.
|
|
427
|
+
|
|
428
|
+
.. SEEALSO::
|
|
429
|
+
|
|
430
|
+
:meth:`~sage.lfunctions.zero_sums.LFunctionZeroSum_EllipticCurve.logarithmic_derivative`
|
|
431
|
+
|
|
432
|
+
EXAMPLES::
|
|
433
|
+
|
|
434
|
+
sage: E = EllipticCurve([23,100])
|
|
435
|
+
sage: Z = LFunctionZeroSum(E)
|
|
436
|
+
sage: Z.completed_logarithmic_derivative(3) # tol 1.0e-13
|
|
437
|
+
(6.64372066048195, 6.584671359095225e-06)
|
|
438
|
+
|
|
439
|
+
Complex values are handled. The function is odd about s=1, so
|
|
440
|
+
the value at 2-s should be minus the value at s.
|
|
441
|
+
|
|
442
|
+
::
|
|
443
|
+
|
|
444
|
+
sage: Z.completed_logarithmic_derivative(complex(-2.2,1)) # tol 1.0e-13
|
|
445
|
+
(-6.898080633125154 + 0.22557015394248361*I, 5.623853049808912e-11)
|
|
446
|
+
sage: Z.completed_logarithmic_derivative(complex(4.2,-1)) # tol 1.0e-13
|
|
447
|
+
(6.898080633125154 - 0.22557015394248361*I, 5.623853049808912e-11)
|
|
448
|
+
"""
|
|
449
|
+
if real(s - 1) >= 0:
|
|
450
|
+
Ls = self.logarithmic_derivative(s, num_terms)
|
|
451
|
+
return (self._C1 + self.digamma(s) + Ls[0], Ls[1])
|
|
452
|
+
else:
|
|
453
|
+
Ls = self.logarithmic_derivative(2 - s, num_terms)
|
|
454
|
+
return (-self._C1 - self.digamma(2 - s) - Ls[0], Ls[1])
|
|
455
|
+
|
|
456
|
+
def zerosum(self, Delta=1, tau=0, function='sincsquared_fast', ncpus=None):
|
|
457
|
+
r"""
|
|
458
|
+
Bound from above the analytic rank of the form attached to ``self``.
|
|
459
|
+
|
|
460
|
+
This bound is obtained by computing `\sum_{\gamma} f(\Delta(\gamma-\tau))`,
|
|
461
|
+
where `\gamma` ranges over the imaginary parts of the zeros of `L_E(s)`
|
|
462
|
+
along the critical strip, and `f(x)` is an appropriate even continuous
|
|
463
|
+
`L_2` function such that `f(0)=1`.
|
|
464
|
+
|
|
465
|
+
If `\tau=0`, then as `\Delta` increases this sum converges from above to
|
|
466
|
+
the analytic rank of the `L`-function, as `f(0) = 1` is counted with
|
|
467
|
+
multiplicity `r`, and the other terms all go to 0 uniformly.
|
|
468
|
+
|
|
469
|
+
INPUT:
|
|
470
|
+
|
|
471
|
+
- ``Delta`` -- positive real number (default: 1) parameter denoting the
|
|
472
|
+
tightness of the zero sum
|
|
473
|
+
|
|
474
|
+
- ``tau`` -- real parameter (default: 0) denoting the offset of the sum
|
|
475
|
+
to be computed. When `\tau=0` the sum will converge to the analytic rank
|
|
476
|
+
of the `L`-function as `\Delta` is increased. If `\tau` is the value
|
|
477
|
+
of the imaginary part of a noncentral zero, the limit will be 1
|
|
478
|
+
(assuming the zero is simple); otherwise, the limit will be 0.
|
|
479
|
+
Currently only implemented for the sincsquared and cauchy functions;
|
|
480
|
+
otherwise ignored.
|
|
481
|
+
|
|
482
|
+
- ``function`` -- string (default: ``'sincsquared_fast'``); the function
|
|
483
|
+
`f(x)` as described above. Currently implemented options for `f` are
|
|
484
|
+
|
|
485
|
+
- ``sincsquared`` -- `f(x) = \left(\frac{\sin(\pi x)}{\pi x}\right)^2`
|
|
486
|
+
|
|
487
|
+
- ``gaussian`` -- `f(x) = e^{-x^2}`
|
|
488
|
+
|
|
489
|
+
- ``sincsquared_fast`` -- same as "sincsquared", but implementation
|
|
490
|
+
optimized for elliptic curve `L`-functions, and tau must be 0. self
|
|
491
|
+
must be attached to an elliptic curve over `\QQ` given by its global
|
|
492
|
+
minimal model, otherwise the returned result will be incorrect.
|
|
493
|
+
|
|
494
|
+
- ``sincsquared_parallel`` -- same as "sincsquared_fast", but optimized
|
|
495
|
+
for parallel computation with large (>2.0) `\Delta` values. ``self`` must
|
|
496
|
+
be attached to an elliptic curve over `\QQ` given by its global minimal
|
|
497
|
+
model, otherwise the returned result will be incorrect.
|
|
498
|
+
|
|
499
|
+
- ``cauchy`` -- `f(x) = \frac{1}{1+x^2}`; this is only computable to
|
|
500
|
+
low precision, and only when `\Delta < 2`
|
|
501
|
+
|
|
502
|
+
- ``ncpus`` -- (default: ``None``) if not ``None``, a positive integer
|
|
503
|
+
defining the number of CPUs to be used for the computation. If left as
|
|
504
|
+
``None``, the maximum available number of CPUs will be used.
|
|
505
|
+
Only implemented for algorithm="sincsquared_parallel"; ignored
|
|
506
|
+
otherwise.
|
|
507
|
+
|
|
508
|
+
.. WARNING::
|
|
509
|
+
|
|
510
|
+
Computation time is exponential in `\Delta`, roughly doubling for
|
|
511
|
+
every increase of 0.1 thereof. Using `\Delta=1` will yield a
|
|
512
|
+
computation time of a few milliseconds; `\Delta=2` takes a few
|
|
513
|
+
seconds, and `\Delta=3` takes upwards of an hour. Increase at your
|
|
514
|
+
own risk beyond this!
|
|
515
|
+
|
|
516
|
+
OUTPUT:
|
|
517
|
+
|
|
518
|
+
A positive real number that bounds from above the number of zeros with
|
|
519
|
+
imaginary part equal to `\tau`. When `\tau=0` this is an upper bound for
|
|
520
|
+
the `L`-function's analytic rank.
|
|
521
|
+
|
|
522
|
+
.. SEEALSO::
|
|
523
|
+
|
|
524
|
+
:meth:`~sage.schemes.elliptic_curves.ell_rational_field.EllipticCurve_rational_field.analytic_rank_bound`
|
|
525
|
+
for more documentation and examples on calling this method on elliptic curve
|
|
526
|
+
`L`-functions.
|
|
527
|
+
|
|
528
|
+
EXAMPLES::
|
|
529
|
+
|
|
530
|
+
sage: E = EllipticCurve("389a"); E.rank()
|
|
531
|
+
2
|
|
532
|
+
sage: Z = LFunctionZeroSum(E)
|
|
533
|
+
sage: E.lseries().zeros(3)
|
|
534
|
+
[0.000000000, 0.000000000, 2.87609907]
|
|
535
|
+
sage: Z.zerosum(Delta=1,function='sincsquared_fast') # tol 1.0e-13
|
|
536
|
+
2.037500084595065
|
|
537
|
+
sage: Z.zerosum(Delta=1,function='sincsquared_parallel') # tol 1.0e-11
|
|
538
|
+
2.037500084595065
|
|
539
|
+
sage: Z.zerosum(Delta=1,function='sincsquared') # tol 1.0e-13
|
|
540
|
+
2.0375000845950644
|
|
541
|
+
sage: Z.zerosum(Delta=1,tau=2.876,function='sincsquared') # tol 1.0e-13
|
|
542
|
+
1.075551295651154
|
|
543
|
+
sage: Z.zerosum(Delta=1,tau=1.2,function='sincsquared') # tol 1.0e-13
|
|
544
|
+
0.10831555377490683
|
|
545
|
+
sage: Z.zerosum(Delta=1,function='gaussian') # tol 1.0e-13
|
|
546
|
+
2.056890425029435
|
|
547
|
+
"""
|
|
548
|
+
# If Delta>6.95, then exp(2*pi*Delta)>sys.maxsize, so we get overflow
|
|
549
|
+
# when summing over the logarithmic derivative coefficients
|
|
550
|
+
if Delta > 6.95:
|
|
551
|
+
raise ValueError("Delta value too large; will result in overflow")
|
|
552
|
+
|
|
553
|
+
if function == "sincsquared_parallel":
|
|
554
|
+
return self._zerosum_sincsquared_parallel(Delta=Delta, ncpus=ncpus)
|
|
555
|
+
elif function == "sincsquared_fast":
|
|
556
|
+
return self._zerosum_sincsquared_fast(Delta=Delta)
|
|
557
|
+
elif function == "sincsquared":
|
|
558
|
+
return self._zerosum_sincsquared(Delta=Delta, tau=tau)
|
|
559
|
+
elif function == "gaussian":
|
|
560
|
+
return self._zerosum_gaussian(Delta=Delta)
|
|
561
|
+
elif function == "cauchy":
|
|
562
|
+
return self._zerosum_cauchy(Delta=Delta, tau=tau)
|
|
563
|
+
else:
|
|
564
|
+
raise ValueError("input function not recognized")
|
|
565
|
+
|
|
566
|
+
def _zerosum_sincsquared(self, Delta=1, tau=0):
|
|
567
|
+
r"""
|
|
568
|
+
Bound from above the analytic rank of the form attached to ``self``.
|
|
569
|
+
|
|
570
|
+
This bound is obtained by computing `\sum_{\gamma} f(\Delta \cdot (\gamma-\tau))`,
|
|
571
|
+
where `\gamma` ranges over the imaginary parts of the zeros of `L_E(s)`
|
|
572
|
+
along the critical strip, and `f(x) = \sin(\pi x)/(\pi x)`
|
|
573
|
+
|
|
574
|
+
If `\tau=0`, then as `\Delta` increases this sum limits from above to
|
|
575
|
+
the analytic rank of the `L`-function, as `f(0) = 1` is counted with
|
|
576
|
+
multiplicity `r`, and the other terms all go to 0 uniformly.
|
|
577
|
+
|
|
578
|
+
INPUT:
|
|
579
|
+
|
|
580
|
+
- ``Delta`` -- positive real number (default: 1) parameter denoting the
|
|
581
|
+
tightness of the zero sum
|
|
582
|
+
|
|
583
|
+
- ``tau`` -- real parameter (default: 0) denoting the offset of the sum
|
|
584
|
+
to be computed. When tau=0 the sum will converge from above to the
|
|
585
|
+
analytic rank of the `L`-function as `\Delta` is increased. If tau
|
|
586
|
+
is the value of the imaginary part of a noncentral zero, the limit
|
|
587
|
+
will be 1 (assuming GRH, the zero is simple); otherwise the limit
|
|
588
|
+
will be 0.
|
|
589
|
+
|
|
590
|
+
.. WARNING::
|
|
591
|
+
|
|
592
|
+
Computation time is exponential in `\Delta`, roughly doubling for
|
|
593
|
+
every increase of 0.1 thereof. Using `\Delta=1` will yield a
|
|
594
|
+
computation time of a few milliseconds; `\Delta=2` takes a few
|
|
595
|
+
seconds, and `\Delta=3` takes upwards of an hour. Increase at your
|
|
596
|
+
own risk beyond this!
|
|
597
|
+
|
|
598
|
+
.. WARNING::
|
|
599
|
+
|
|
600
|
+
This method has *not* been optimized with Cython; as such
|
|
601
|
+
computing with this method is slower than the central sum
|
|
602
|
+
(i.e `\tau=0`) versions of self._zerosum_sincsquared_fast() and
|
|
603
|
+
self._zerosum_sincsquared_parallel().
|
|
604
|
+
|
|
605
|
+
OUTPUT:
|
|
606
|
+
|
|
607
|
+
A positive real number that bounds from above the number of zeros with
|
|
608
|
+
imaginary part equal to tau. When tau=0 this is an upper bound for the
|
|
609
|
+
`L`-function's analytic rank.
|
|
610
|
+
|
|
611
|
+
.. SEEALSO::
|
|
612
|
+
|
|
613
|
+
:meth:`~sage.lfunctions.zero_sums.LFunctionZeroSum_abstract.zerosum`
|
|
614
|
+
for the public method that calls this private method.
|
|
615
|
+
|
|
616
|
+
EXAMPLES::
|
|
617
|
+
|
|
618
|
+
sage: E = EllipticCurve("37a"); E.rank()
|
|
619
|
+
1
|
|
620
|
+
sage: Z = LFunctionZeroSum(E)
|
|
621
|
+
sage: E.lseries().zeros(2)
|
|
622
|
+
[0.000000000, 5.00317001]
|
|
623
|
+
|
|
624
|
+
E is a rank 1 curve; the lowest noncentral zero has imaginary part
|
|
625
|
+
~5.003. The zero sum with tau=0 indicates the probable existence of
|
|
626
|
+
a zero at or very close to the central point.
|
|
627
|
+
|
|
628
|
+
::
|
|
629
|
+
|
|
630
|
+
sage: Z._zerosum_sincsquared(Delta=1,tau=0) # tol 1.0e-13
|
|
631
|
+
1.0103840698356257
|
|
632
|
+
|
|
633
|
+
The zero sum also detects a zero at or near 5.003, as expected.
|
|
634
|
+
|
|
635
|
+
::
|
|
636
|
+
|
|
637
|
+
sage: Z._zerosum_sincsquared(Delta=1,tau=5.003) # tol 1.0e-13
|
|
638
|
+
1.0168124546878288
|
|
639
|
+
|
|
640
|
+
However, there is definitely no zero with imaginary part near 2.5,
|
|
641
|
+
as the sum would have to be at least 1.
|
|
642
|
+
|
|
643
|
+
::
|
|
644
|
+
|
|
645
|
+
sage: Z._zerosum_sincsquared(Delta=1,tau=2.5) # tol 1.0e-13
|
|
646
|
+
0.058058210806477814
|
|
647
|
+
"""
|
|
648
|
+
npi = self._pi
|
|
649
|
+
twopi = 2 * npi
|
|
650
|
+
|
|
651
|
+
t = RDF(Delta * twopi)
|
|
652
|
+
expt = RDF(exp(t))
|
|
653
|
+
|
|
654
|
+
u = t * self.C0()
|
|
655
|
+
|
|
656
|
+
# No offset: formulae are simpler
|
|
657
|
+
if tau == 0:
|
|
658
|
+
w = npi**2 / 6 - (RDF.one() / expt).dilog()
|
|
659
|
+
|
|
660
|
+
y = RDF(0)
|
|
661
|
+
n = int(1)
|
|
662
|
+
while n < expt:
|
|
663
|
+
cn = self.cn(n)
|
|
664
|
+
if cn != 0:
|
|
665
|
+
logn = RDF(n).log()
|
|
666
|
+
y += cn * (t - logn)
|
|
667
|
+
n += 1
|
|
668
|
+
# When offset is nonzero, the digamma transform (w) must
|
|
669
|
+
# be computed as an infinite sum
|
|
670
|
+
else:
|
|
671
|
+
tau = RDF(tau)
|
|
672
|
+
cos_tau_t = (tau * t).cos()
|
|
673
|
+
sin_tau_t = (tau * t).sin()
|
|
674
|
+
w = RDF.zero()
|
|
675
|
+
for k in range(1, 1001):
|
|
676
|
+
a1 = tau**2 / (k * (k**2 + tau**2))
|
|
677
|
+
a2 = (k**2 - tau**2) / (k**2 + tau**2)**2
|
|
678
|
+
a3 = (2 * k * tau) / (k**2 + tau**2)**2
|
|
679
|
+
|
|
680
|
+
w0 = a1 * t + a2
|
|
681
|
+
w0 -= (a2 * cos_tau_t - a3 * sin_tau_t) * exp(-k * t)
|
|
682
|
+
w += w0
|
|
683
|
+
|
|
684
|
+
y = RDF.zero()
|
|
685
|
+
n = int(1)
|
|
686
|
+
while n < expt:
|
|
687
|
+
cn = self.cn(n)
|
|
688
|
+
if cn != 0:
|
|
689
|
+
logn = RDF(n).log()
|
|
690
|
+
y += cn * (t - logn) * (tau * logn).cos()
|
|
691
|
+
n += 1
|
|
692
|
+
|
|
693
|
+
return (u + w + y) * 2 / (t**2)
|
|
694
|
+
|
|
695
|
+
def _zerosum_gaussian(self, Delta=1):
|
|
696
|
+
r"""
|
|
697
|
+
Return an upper bound on the analytic rank of the `L`-series attached
|
|
698
|
+
to ``self`` by computing `\sum_{\gamma} f(\Delta*\gamma)`,
|
|
699
|
+
where `\gamma` ranges over the imaginary parts of the zeros of `L_E(s)`
|
|
700
|
+
along the critical strip, and `f(x) = \exp(-x^2)`.
|
|
701
|
+
|
|
702
|
+
As `\Delta` increases this sum limits from above to the analytic rank
|
|
703
|
+
of the form, as `f(0) = 1` is counted with multiplicity `r`, and the
|
|
704
|
+
other terms all go to 0 uniformly.
|
|
705
|
+
|
|
706
|
+
INPUT:
|
|
707
|
+
|
|
708
|
+
- ``Delta`` -- positive real number (default: 1) parameter defining the
|
|
709
|
+
tightness of the zero sum, and thus the closeness of the returned
|
|
710
|
+
estimate to the actual analytic rank of the form attached to ``self``.
|
|
711
|
+
|
|
712
|
+
.. WARNING::
|
|
713
|
+
|
|
714
|
+
Computation time is exponential in `\Delta`, roughly doubling for
|
|
715
|
+
every increase of 0.1 thereof. Using `\Delta=1` will yield a
|
|
716
|
+
computation time of a few milliseconds; `\Delta=2` takes a few
|
|
717
|
+
seconds, and `\Delta=3` takes upwards of an hour. Increase at your
|
|
718
|
+
own risk beyond this!
|
|
719
|
+
|
|
720
|
+
OUTPUT:
|
|
721
|
+
|
|
722
|
+
A positive real number that bounds the analytic rank of the modular form
|
|
723
|
+
attached to ``self`` from above.
|
|
724
|
+
|
|
725
|
+
.. SEEALSO::
|
|
726
|
+
|
|
727
|
+
:meth:`~sage.lfunctions.zero_sums.LFunctionZeroSum_abstract.zerosum`
|
|
728
|
+
for the public method that calls this private method.
|
|
729
|
+
|
|
730
|
+
EXAMPLES::
|
|
731
|
+
|
|
732
|
+
sage: E = EllipticCurve("37a"); E.rank()
|
|
733
|
+
1
|
|
734
|
+
sage: Z = LFunctionZeroSum(E)
|
|
735
|
+
sage: Z._zerosum_gaussian(Delta=1) # tol 1.0e-13
|
|
736
|
+
1.0563950773441664
|
|
737
|
+
"""
|
|
738
|
+
# imported here so as to avoid importing Numpy on Sage startup
|
|
739
|
+
from scipy.special import erfcx
|
|
740
|
+
|
|
741
|
+
npi = self._pi
|
|
742
|
+
Deltasqrtpi = Delta * npi.sqrt()
|
|
743
|
+
|
|
744
|
+
t = RDF(Delta * npi * 2)
|
|
745
|
+
expt = t.exp()
|
|
746
|
+
|
|
747
|
+
u = self.C0()
|
|
748
|
+
|
|
749
|
+
w = RDF.zero()
|
|
750
|
+
for k in range(1, 1001):
|
|
751
|
+
w += RDF.one() / k - erfcx(Delta * k) * Deltasqrtpi
|
|
752
|
+
|
|
753
|
+
y = RDF.zero()
|
|
754
|
+
n = int(1)
|
|
755
|
+
|
|
756
|
+
# TO DO: Error analysis to make sure this bound is good enough to
|
|
757
|
+
# avoid non-negligible truncation error
|
|
758
|
+
while n < expt:
|
|
759
|
+
cn = self.cn(n)
|
|
760
|
+
if cn != 0:
|
|
761
|
+
logn = log(RDF(n))
|
|
762
|
+
y += cn * exp(-(logn / (2 * Delta))**2)
|
|
763
|
+
n += 1
|
|
764
|
+
# y is the truncation of an infinite sum, so we must add a value which
|
|
765
|
+
# exceeds the max amount we could have left out.
|
|
766
|
+
# WARNING: Truncation error analysis has *not* been done; the value of
|
|
767
|
+
# 0.1 is empirical.
|
|
768
|
+
return RDF(u + w + y + 0.1) / Deltasqrtpi
|
|
769
|
+
|
|
770
|
+
def _zerosum_cauchy(self, Delta=1, tau=0, num_terms=None):
|
|
771
|
+
r"""
|
|
772
|
+
Bound from above the analytic rank of the form attached to ``self``
|
|
773
|
+
by computing `\sum_{\gamma} f(\Delta*(\gamma-\tau))`,
|
|
774
|
+
where `\gamma` ranges over the imaginary parts of the zeros of `L_E(s)`
|
|
775
|
+
along the critical strip, and `f(x) = \frac{1}{1+x^2}`.
|
|
776
|
+
|
|
777
|
+
If `\tau=0`, then as `\Delta` increases this sum converges from above
|
|
778
|
+
to the analytic rank of the `L`-function, as `f(0) = 1` is counted
|
|
779
|
+
with multiplicity `r`, and the other terms all go to 0 uniformly.
|
|
780
|
+
|
|
781
|
+
INPUT:
|
|
782
|
+
|
|
783
|
+
- ``Delta`` -- positive real number (default: 1); parameter denoting the
|
|
784
|
+
tightness of the zero sum
|
|
785
|
+
|
|
786
|
+
- ``tau`` -- real parameter (default: 0) denoting the offset of the sum
|
|
787
|
+
to be computed. When tau=0 the sum will converge from above to the
|
|
788
|
+
analytic rank of the `L`-function as `\Delta` is increased. If tau is
|
|
789
|
+
the value of the imaginary part of a noncentral zero, the limit will
|
|
790
|
+
be 1 (assuming GRH, the zero is simple); otherwise the limit will
|
|
791
|
+
be 0.
|
|
792
|
+
|
|
793
|
+
- ``num_terms`` -- positive integer (default: ``None``); the number of
|
|
794
|
+
terms computed in the truncated Dirichlet series for the `L`-function
|
|
795
|
+
attached to ``self``. If left at ``None``, this is set to
|
|
796
|
+
`\ceil(e^{2 \pi \Delta})`, the same number of terms used in the other
|
|
797
|
+
zero sum methods for this value of Delta.
|
|
798
|
+
Increase num_terms to get more accuracy.
|
|
799
|
+
|
|
800
|
+
.. WARNING::
|
|
801
|
+
|
|
802
|
+
This value can only be provably computed when Delta < 2; an error
|
|
803
|
+
will be thrown if a Delta value larger than 2 is supplied.
|
|
804
|
+
Furthermore, beware that computation time is exponential in
|
|
805
|
+
`\Delta`, roughly doubling for every increase of 0.1 thereof.
|
|
806
|
+
Using `\Delta=1` will yield a computation time of a few
|
|
807
|
+
milliseconds, while `\Delta=2` takes a few seconds.
|
|
808
|
+
|
|
809
|
+
OUTPUT:
|
|
810
|
+
|
|
811
|
+
A positive real number that bounds from above the number of zeros with
|
|
812
|
+
imaginary part equal to tau. When tau=0 this is an upper bound for the
|
|
813
|
+
`L`-function's analytic rank.
|
|
814
|
+
|
|
815
|
+
.. SEEALSO::
|
|
816
|
+
|
|
817
|
+
:meth:`~sage.lfunctions.zero_sums.LFunctionZeroSum_abstract.zerosum`
|
|
818
|
+
for the public method that calls this private method.
|
|
819
|
+
|
|
820
|
+
EXAMPLES::
|
|
821
|
+
|
|
822
|
+
sage: E = EllipticCurve("11a")
|
|
823
|
+
sage: zeros = E.lseries().zeros(2)
|
|
824
|
+
sage: zeros[0] # abs tol 1e-8
|
|
825
|
+
6.36261389
|
|
826
|
+
sage: zeros[1] # abs tol 1e-8
|
|
827
|
+
8.60353962
|
|
828
|
+
|
|
829
|
+
E is a rank zero curve; the lowest zero has imaginary part ~6.36. The
|
|
830
|
+
zero sum with tau=0 indicates that there are no zeros at the central
|
|
831
|
+
point (otherwise the returned value would be at least 1).
|
|
832
|
+
|
|
833
|
+
::
|
|
834
|
+
|
|
835
|
+
sage: Z = LFunctionZeroSum(E)
|
|
836
|
+
sage: Z._zerosum_cauchy(Delta=1,tau=0) # tol 1.0e-13
|
|
837
|
+
0.9701073984459051
|
|
838
|
+
|
|
839
|
+
The zero sum with tau=6.36 indicates there might be a zero in the
|
|
840
|
+
vicinity.
|
|
841
|
+
|
|
842
|
+
::
|
|
843
|
+
|
|
844
|
+
sage: Z._zerosum_cauchy(Delta=1,tau=6.36261389) # tol 1.0e-13
|
|
845
|
+
2.180904626331156
|
|
846
|
+
|
|
847
|
+
However, there are no zeros with imaginary part close to 1.5.
|
|
848
|
+
|
|
849
|
+
::
|
|
850
|
+
|
|
851
|
+
sage: Z._zerosum_cauchy(Delta=1,tau=1.5) # tol 1.0e-13
|
|
852
|
+
0.9827072037553375
|
|
853
|
+
|
|
854
|
+
Because of the weak convergence of the Dirichlet series close to the
|
|
855
|
+
critical line, the bound will in general get *worse* for larger Delta.
|
|
856
|
+
This can be mitigated somewhat by increasing the number of terms.
|
|
857
|
+
|
|
858
|
+
::
|
|
859
|
+
|
|
860
|
+
sage: Z._zerosum_cauchy(Delta=1.5) # tol 1.0e-13
|
|
861
|
+
12.93835258975716
|
|
862
|
+
sage: Z._zerosum_cauchy(Delta=1.5,num_terms=100000) # tol 1.0e-13
|
|
863
|
+
10.395183960836599
|
|
864
|
+
|
|
865
|
+
An error will be thrown if a Delta value >= 2 is passed.
|
|
866
|
+
|
|
867
|
+
::
|
|
868
|
+
|
|
869
|
+
sage: Z._zerosum_cauchy(Delta=2)
|
|
870
|
+
Traceback (most recent call last):
|
|
871
|
+
...
|
|
872
|
+
ValueError: bound not provably computable for Delta >= 2
|
|
873
|
+
"""
|
|
874
|
+
if Delta >= 2:
|
|
875
|
+
raise ValueError("bound not provably computable for Delta >= 2")
|
|
876
|
+
Del = RDF(Delta)
|
|
877
|
+
if num_terms is None:
|
|
878
|
+
num_terms = int(exp(2 * self._pi * Del))
|
|
879
|
+
|
|
880
|
+
if tau == 0:
|
|
881
|
+
one = RDF.one()
|
|
882
|
+
s = one / Del + one
|
|
883
|
+
u, err = self.completed_logarithmic_derivative(s, num_terms)
|
|
884
|
+
else:
|
|
885
|
+
one = CDF.one()
|
|
886
|
+
s = CDF(one / Del + one, tau)
|
|
887
|
+
u, err = self.completed_logarithmic_derivative(s, num_terms)
|
|
888
|
+
u = u.real()
|
|
889
|
+
|
|
890
|
+
return (u + err) / Del
|
|
891
|
+
|
|
892
|
+
|
|
893
|
+
cdef class LFunctionZeroSum_EllipticCurve(LFunctionZeroSum_abstract):
|
|
894
|
+
r"""
|
|
895
|
+
Subclass for computing certain sums over zeros of an elliptic curve `L`-function
|
|
896
|
+
without having to determine the zeros themselves.
|
|
897
|
+
"""
|
|
898
|
+
cdef _E # The Elliptic curve attached to self
|
|
899
|
+
cdef _e # PARI ellcurve object used to compute a_p values
|
|
900
|
+
|
|
901
|
+
def __init__(self, E, N=None, ncpus=1):
|
|
902
|
+
r"""
|
|
903
|
+
Initialize ``self``.
|
|
904
|
+
|
|
905
|
+
INPUT:
|
|
906
|
+
|
|
907
|
+
- ``E`` -- an elliptic curve defined over the rational numbers
|
|
908
|
+
|
|
909
|
+
- ``N`` -- (default: ``None``) if not ``None``, a positive integer equal to
|
|
910
|
+
the conductor of E. This is passable so that rank estimation
|
|
911
|
+
can be done for curves whose (large) conductor has been precomputed.
|
|
912
|
+
|
|
913
|
+
- ``ncpus`` -- (default: 1) the number of CPUs to use for computations;
|
|
914
|
+
if set to ``None``, the max available amount will be used
|
|
915
|
+
|
|
916
|
+
EXAMPLES::
|
|
917
|
+
|
|
918
|
+
sage: from sage.lfunctions.zero_sums import LFunctionZeroSum_EllipticCurve
|
|
919
|
+
sage: E = EllipticCurve([1,0,0,3,-4])
|
|
920
|
+
sage: Z = LFunctionZeroSum_EllipticCurve(E); Z
|
|
921
|
+
Zero sum estimator for L-function attached to Elliptic Curve defined by y^2 + x*y = x^3 + 3*x - 4 over Rational Field
|
|
922
|
+
sage: E = EllipticCurve("5077a")
|
|
923
|
+
sage: Z = LFunctionZeroSum_EllipticCurve(E); Z
|
|
924
|
+
Zero sum estimator for L-function attached to Elliptic Curve defined by y^2 + y = x^3 - 7*x + 6 over Rational Field
|
|
925
|
+
"""
|
|
926
|
+
self._k = ZZ(2)
|
|
927
|
+
self._E = E
|
|
928
|
+
if N is not None:
|
|
929
|
+
self._level = N
|
|
930
|
+
else:
|
|
931
|
+
self._level = E.conductor()
|
|
932
|
+
# PARI minicurve for computing a_p coefficients
|
|
933
|
+
self._e = E.pari_mincurve()
|
|
934
|
+
|
|
935
|
+
self._pi = RDF(pi)
|
|
936
|
+
self._euler_gamma = RDF(euler_gamma)
|
|
937
|
+
|
|
938
|
+
# These constants feature in most (all?) sums over the L-function's zeros
|
|
939
|
+
self._C1 = RDF(self._level).log() / 2 - log(self._pi * 2)
|
|
940
|
+
self._C0 = self._C1 - self._euler_gamma
|
|
941
|
+
|
|
942
|
+
# Number of CPUs to use for computations
|
|
943
|
+
if ncpus is None:
|
|
944
|
+
self._ncpus = num_cpus()
|
|
945
|
+
NCPUS = self._ncpus
|
|
946
|
+
else:
|
|
947
|
+
self._ncpus = ncpus
|
|
948
|
+
NCPUS = self._ncpus
|
|
949
|
+
|
|
950
|
+
def __repr__(self):
|
|
951
|
+
r"""
|
|
952
|
+
Representation of ``self``.
|
|
953
|
+
|
|
954
|
+
EXAMPLES::
|
|
955
|
+
|
|
956
|
+
sage: Z = LFunctionZeroSum(EllipticCurve("37a")); Z
|
|
957
|
+
Zero sum estimator for L-function attached to Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
|
|
958
|
+
"""
|
|
959
|
+
s = "Zero sum estimator for L-function attached to "
|
|
960
|
+
return s + str(self._E)
|
|
961
|
+
|
|
962
|
+
def elliptic_curve(self):
|
|
963
|
+
r"""
|
|
964
|
+
Return the elliptic curve associated with ``self``.
|
|
965
|
+
|
|
966
|
+
EXAMPLES::
|
|
967
|
+
|
|
968
|
+
sage: E = EllipticCurve([23,100])
|
|
969
|
+
sage: Z = LFunctionZeroSum(E)
|
|
970
|
+
sage: Z.elliptic_curve()
|
|
971
|
+
Elliptic Curve defined by y^2 = x^3 + 23*x + 100 over Rational Field
|
|
972
|
+
"""
|
|
973
|
+
return self._E
|
|
974
|
+
|
|
975
|
+
def lseries(self):
|
|
976
|
+
r"""
|
|
977
|
+
Return the `L`-series associated with ``self``.
|
|
978
|
+
|
|
979
|
+
EXAMPLES::
|
|
980
|
+
|
|
981
|
+
sage: E = EllipticCurve([23,100])
|
|
982
|
+
sage: Z = LFunctionZeroSum(E)
|
|
983
|
+
sage: Z.lseries()
|
|
984
|
+
Complex L-series of the Elliptic Curve defined by y^2 = x^3 + 23*x + 100 over Rational Field
|
|
985
|
+
"""
|
|
986
|
+
return self._E.lseries()
|
|
987
|
+
|
|
988
|
+
def cn(self, n):
|
|
989
|
+
r"""
|
|
990
|
+
Return the `n`-th Dirichlet coefficient of the logarithmic
|
|
991
|
+
derivative of the `L`-function attached to ``self``, shifted so that
|
|
992
|
+
the critical line lies on the imaginary axis.
|
|
993
|
+
|
|
994
|
+
The returned value is
|
|
995
|
+
zero if `n` is not a perfect prime power;
|
|
996
|
+
when `n=p^e` for `p` a prime of bad reduction it is `-a_p^e log(p)/p^e`,
|
|
997
|
+
where `a_p` is `+1, -1` or `0` according to the reduction type of `p`;
|
|
998
|
+
and when `n=p^e` for a prime `p` of good reduction, the value
|
|
999
|
+
is `-(\alpha_p^e + \beta_p^e) \log(p)/p^e`, where `\alpha_p`
|
|
1000
|
+
and `\beta_p` are the two complex roots of the characteristic equation
|
|
1001
|
+
of Frobenius at `p` on `E`.
|
|
1002
|
+
|
|
1003
|
+
INPUT:
|
|
1004
|
+
|
|
1005
|
+
- ``n`` -- nonnegative integer
|
|
1006
|
+
|
|
1007
|
+
OUTPUT:
|
|
1008
|
+
|
|
1009
|
+
A real number which (by Hasse's Theorem) is at
|
|
1010
|
+
most `2\frac{log(n)}{\sqrt{n}}` in magnitude.
|
|
1011
|
+
|
|
1012
|
+
EXAMPLES::
|
|
1013
|
+
|
|
1014
|
+
sage: E = EllipticCurve("11a")
|
|
1015
|
+
sage: Z = LFunctionZeroSum(E)
|
|
1016
|
+
sage: for n in range(12): print((n, Z.cn(n))) # tol 1.0e-13
|
|
1017
|
+
(0, 0.0)
|
|
1018
|
+
(1, 0.0)
|
|
1019
|
+
(2, 0.6931471805599453)
|
|
1020
|
+
(3, 0.3662040962227033)
|
|
1021
|
+
(4, 0.0)
|
|
1022
|
+
(5, -0.32188758248682003)
|
|
1023
|
+
(6, 0.0)
|
|
1024
|
+
(7, 0.555974328301518)
|
|
1025
|
+
(8, -0.34657359027997264)
|
|
1026
|
+
(9, 0.6103401603711721)
|
|
1027
|
+
(10, 0.0)
|
|
1028
|
+
(11, -0.21799047934530644)
|
|
1029
|
+
"""
|
|
1030
|
+
n = ZZ(n)
|
|
1031
|
+
if n == 0 or n == 1:
|
|
1032
|
+
return RDF.zero()
|
|
1033
|
+
if not n.is_prime_power():
|
|
1034
|
+
return RDF.zero()
|
|
1035
|
+
|
|
1036
|
+
n_float = RDF(n)
|
|
1037
|
+
if n.is_prime():
|
|
1038
|
+
logn = log(n_float)
|
|
1039
|
+
ap = self._E.ap(n)
|
|
1040
|
+
return -ap * logn / n_float
|
|
1041
|
+
else:
|
|
1042
|
+
p, e = n.perfect_power()
|
|
1043
|
+
ap = self._E.ap(p)
|
|
1044
|
+
logp = RDF(p).log()
|
|
1045
|
+
if p.divides(self._level):
|
|
1046
|
+
return - ap**e * logp / n_float
|
|
1047
|
+
a, b = ap, 2
|
|
1048
|
+
# Coefficients for higher powers obey recursion relation
|
|
1049
|
+
for n in range(2, e + 1):
|
|
1050
|
+
a, b = ap * a - p * b, a
|
|
1051
|
+
return -a * logp / n_float
|
|
1052
|
+
|
|
1053
|
+
cdef double _sincsquared_summand_1(self,
|
|
1054
|
+
unsigned long n,
|
|
1055
|
+
double t,
|
|
1056
|
+
int ap,
|
|
1057
|
+
double p,
|
|
1058
|
+
double logp,
|
|
1059
|
+
double thetap,
|
|
1060
|
+
double sqrtp,
|
|
1061
|
+
double logq,
|
|
1062
|
+
double thetaq,
|
|
1063
|
+
double sqrtq,
|
|
1064
|
+
double z) noexcept:
|
|
1065
|
+
r"""
|
|
1066
|
+
Private cdef method to compute the logarithmic derivative
|
|
1067
|
+
summand for the sinc^2 sum at prime values for when
|
|
1068
|
+
n <= sqrt(bound), bound = exp(t)
|
|
1069
|
+
Called in self._zerosum_sincsquared_fast() method
|
|
1070
|
+
"""
|
|
1071
|
+
ap = self._e.ellap(n)
|
|
1072
|
+
p = n
|
|
1073
|
+
sqrtp = c_sqrt(p)
|
|
1074
|
+
thetap = c_acos(ap / (2 * sqrtp))
|
|
1075
|
+
logp = c_log(p)
|
|
1076
|
+
|
|
1077
|
+
sqrtq = 1
|
|
1078
|
+
thetaq = 0
|
|
1079
|
+
logq = logp
|
|
1080
|
+
|
|
1081
|
+
z = 0
|
|
1082
|
+
while logq < t:
|
|
1083
|
+
sqrtq *= sqrtp
|
|
1084
|
+
thetaq += thetap
|
|
1085
|
+
z += 2 * c_cos(thetaq) * (t - logq) / sqrtq
|
|
1086
|
+
logq += logp
|
|
1087
|
+
return -z * logp
|
|
1088
|
+
|
|
1089
|
+
cdef double _sincsquared_summand_2(self,
|
|
1090
|
+
unsigned long n,
|
|
1091
|
+
double t,
|
|
1092
|
+
int ap,
|
|
1093
|
+
double p,
|
|
1094
|
+
double logp) noexcept:
|
|
1095
|
+
r"""
|
|
1096
|
+
Private cdef method to compute the logarithmic derivative
|
|
1097
|
+
summand for the sinc^2 sum at prime values for when
|
|
1098
|
+
sqrt(bound) < n < bound, bound = exp(t)
|
|
1099
|
+
Called in self._zerosum_sincsquared_fast() method
|
|
1100
|
+
"""
|
|
1101
|
+
ap = self._e.ellap(n)
|
|
1102
|
+
p = n
|
|
1103
|
+
logp = c_log(p)
|
|
1104
|
+
return -(t - logp) * (logp / p) * ap
|
|
1105
|
+
|
|
1106
|
+
cpdef _zerosum_sincsquared_fast(self, Delta=1, bad_primes=None):
|
|
1107
|
+
r"""
|
|
1108
|
+
A faster cythonized implementation of self._zerosum_sincsquared().
|
|
1109
|
+
|
|
1110
|
+
.. NOTE::
|
|
1111
|
+
|
|
1112
|
+
This will only produce correct output if self._E is given by its
|
|
1113
|
+
global minimal model, i.e., if self._E.is_minimal() is ``True``.
|
|
1114
|
+
|
|
1115
|
+
INPUT:
|
|
1116
|
+
|
|
1117
|
+
- ``Delta`` -- positive real parameter defining the
|
|
1118
|
+
tightness of the zero sum, and thus the closeness of the returned
|
|
1119
|
+
estimate to the actual analytic rank of the form attached to ``self``
|
|
1120
|
+
|
|
1121
|
+
- ``bad_primes`` -- (default: ``None``) if not ``None``, a list of primes dividing
|
|
1122
|
+
the level of the form attached to ``self``. This is passable so that this
|
|
1123
|
+
method can be run on curves whose conductor is large enough to warrant
|
|
1124
|
+
precomputing bad primes.
|
|
1125
|
+
|
|
1126
|
+
OUTPUT:
|
|
1127
|
+
|
|
1128
|
+
A positive real number that bounds the analytic rank of the modular form
|
|
1129
|
+
attached to ``self`` from above.
|
|
1130
|
+
|
|
1131
|
+
.. SEEALSO::
|
|
1132
|
+
|
|
1133
|
+
:meth:`~sage.lfunctions.zero_sums.LFunctionZeroSum_abstract.zerosum_sincsquared`
|
|
1134
|
+
for the more general but slower version of this method.
|
|
1135
|
+
|
|
1136
|
+
:meth:`~sage.lfunctions.zero_sums.LFunctionZeroSum_abstract.zerosum`
|
|
1137
|
+
for the public method that calls this private method.
|
|
1138
|
+
|
|
1139
|
+
EXAMPLES::
|
|
1140
|
+
|
|
1141
|
+
sage: E = EllipticCurve("37a")
|
|
1142
|
+
sage: Z = LFunctionZeroSum(E)
|
|
1143
|
+
sage: print((E.rank(),Z._zerosum_sincsquared_fast(Delta=1))) # tol 1.0e-13
|
|
1144
|
+
(1, 1.0103840698356263)
|
|
1145
|
+
sage: E = EllipticCurve("121a")
|
|
1146
|
+
sage: Z = LFunctionZeroSum(E)
|
|
1147
|
+
sage: print((E.rank(),Z._zerosum_sincsquared_fast(Delta=1.5))) # tol 1.0e-13
|
|
1148
|
+
(0, 0.0104712060086507)
|
|
1149
|
+
"""
|
|
1150
|
+
# If Delta>6.619, then we will most likely get overflow: some ap values
|
|
1151
|
+
# will be too large to fit into a c int
|
|
1152
|
+
if Delta > 6.619:
|
|
1153
|
+
raise ValueError("Delta value too large; will result in overflow")
|
|
1154
|
+
|
|
1155
|
+
cdef double npi = self._pi
|
|
1156
|
+
cdef double twopi = npi * 2
|
|
1157
|
+
cdef double eg = self._euler_gamma
|
|
1158
|
+
|
|
1159
|
+
cdef double t, u, w, y, z, expt, bound1, logp, logq
|
|
1160
|
+
cdef double thetap, thetaq, sqrtp, sqrtq, p, q
|
|
1161
|
+
cdef int ap, aq
|
|
1162
|
+
|
|
1163
|
+
cdef unsigned long n
|
|
1164
|
+
cdef double N_double = self._level
|
|
1165
|
+
|
|
1166
|
+
t = twopi * Delta
|
|
1167
|
+
expt = c_exp(t)
|
|
1168
|
+
|
|
1169
|
+
u = t * (-eg + c_log(N_double) / 2 - c_log(twopi))
|
|
1170
|
+
w = npi**2 / 6 - (RDF.one() / expt).dilog()
|
|
1171
|
+
|
|
1172
|
+
y = 0
|
|
1173
|
+
# Do bad primes first. Add correct contributions and subtract
|
|
1174
|
+
# incorrect contribution, since we'll add them back later on.
|
|
1175
|
+
if bad_primes is None:
|
|
1176
|
+
bad_primes = self._level.prime_divisors()
|
|
1177
|
+
bad_primes = [prime for prime in bad_primes if prime < expt]
|
|
1178
|
+
for prime in bad_primes:
|
|
1179
|
+
n = prime
|
|
1180
|
+
ap = self._e.ellap(n)
|
|
1181
|
+
p = n
|
|
1182
|
+
sqrtp = c_sqrt(p)
|
|
1183
|
+
thetap = c_acos(ap / (2 * sqrtp))
|
|
1184
|
+
logp = c_log(p)
|
|
1185
|
+
|
|
1186
|
+
q = 1
|
|
1187
|
+
sqrtq = 1
|
|
1188
|
+
aq = 1
|
|
1189
|
+
thetaq = 0
|
|
1190
|
+
logq = logp
|
|
1191
|
+
|
|
1192
|
+
z = 0
|
|
1193
|
+
while logq < t:
|
|
1194
|
+
q *= p
|
|
1195
|
+
sqrtq *= sqrtp
|
|
1196
|
+
aq *= ap
|
|
1197
|
+
thetaq += thetap
|
|
1198
|
+
# Actual value of this term
|
|
1199
|
+
z += (aq / q) * (t - logq)
|
|
1200
|
+
# Incorrect value of this term to be removed below
|
|
1201
|
+
z -= 2 * c_cos(thetaq) * (t - logq) / sqrtq
|
|
1202
|
+
logq += logp
|
|
1203
|
+
y -= z * logp
|
|
1204
|
+
|
|
1205
|
+
# Good prime case. Bad primes are treated as good primes, but their
|
|
1206
|
+
# contribution here is cancelled out above; this way we don't
|
|
1207
|
+
# have to check if each prime divides the level or not.
|
|
1208
|
+
|
|
1209
|
+
# Must deal with n=2,3,5 separately
|
|
1210
|
+
for m in [2, 3, 5]:
|
|
1211
|
+
n = m
|
|
1212
|
+
if n < expt:
|
|
1213
|
+
y += self._sincsquared_summand_1(n, t, ap, p, logp, thetap,
|
|
1214
|
+
sqrtp, logq, thetaq, sqrtq, z)
|
|
1215
|
+
# Now iterate only over those n that are 1 or 5 mod 6
|
|
1216
|
+
n = 11
|
|
1217
|
+
# First: those n that are <= sqrt(bound)
|
|
1218
|
+
bound1 = c_exp(t / 2)
|
|
1219
|
+
while n <= bound1:
|
|
1220
|
+
if n_is_prime(n - 4):
|
|
1221
|
+
y += self._sincsquared_summand_1(n - 4, t, ap, p, logp, thetap,
|
|
1222
|
+
sqrtp, logq, thetaq, sqrtq, z)
|
|
1223
|
+
if n_is_prime(n):
|
|
1224
|
+
y += self._sincsquared_summand_1(n, t, ap, p, logp, thetap,
|
|
1225
|
+
sqrtp, logq, thetaq, sqrtq, z)
|
|
1226
|
+
n += 6
|
|
1227
|
+
# Unlucky split case where n-4 <= sqrt(bound) but n isn't
|
|
1228
|
+
if n - 4 <= bound1 < n:
|
|
1229
|
+
if n_is_prime(n - 4):
|
|
1230
|
+
y += self._sincsquared_summand_1(n - 4, t, ap, p, logp, thetap,
|
|
1231
|
+
sqrtp, logq, thetaq, sqrtq, z)
|
|
1232
|
+
if n <= expt and n_is_prime(n):
|
|
1233
|
+
y += self._sincsquared_summand_2(n, t, ap, p, logp)
|
|
1234
|
+
n += 6
|
|
1235
|
+
# Now sqrt(bound)< n < bound, so we don't need to consider higher
|
|
1236
|
+
# prime power logarithmic derivative coefficients
|
|
1237
|
+
while n <= expt:
|
|
1238
|
+
if n_is_prime(n - 4):
|
|
1239
|
+
y += self._sincsquared_summand_2(n - 4, t, ap, p, logp)
|
|
1240
|
+
if n_is_prime(n):
|
|
1241
|
+
y += self._sincsquared_summand_2(n, t, ap, p, logp)
|
|
1242
|
+
n += 6
|
|
1243
|
+
# Case where n-4 <= t but n isn't
|
|
1244
|
+
n = n - 4
|
|
1245
|
+
if n <= expt and n_is_prime(n):
|
|
1246
|
+
y += self._sincsquared_summand_2(n, t, ap, p, logp)
|
|
1247
|
+
|
|
1248
|
+
return RDF(2 * (u + w + y) / (t**2))
|
|
1249
|
+
|
|
1250
|
+
def _get_residue_data(self, n):
|
|
1251
|
+
r"""
|
|
1252
|
+
Method called by ``self._zerosum_sincsquared_parallel()`` to determine
|
|
1253
|
+
the optimal residue class breakdown when sieving for primes.
|
|
1254
|
+
|
|
1255
|
+
Return a list of small primes, the product thereof, and a list of
|
|
1256
|
+
residues coprime to the product.
|
|
1257
|
+
|
|
1258
|
+
INPUT:
|
|
1259
|
+
|
|
1260
|
+
- ``n`` -- positive integer denoting the number of required chunks
|
|
1261
|
+
|
|
1262
|
+
OUTPUT:
|
|
1263
|
+
|
|
1264
|
+
A triple ``(small_primes, M, residue_chunks)`` such that
|
|
1265
|
+
|
|
1266
|
+
- ``small_primes`` -- list of small primes
|
|
1267
|
+
|
|
1268
|
+
- ``modulus`` -- the product of the small primes
|
|
1269
|
+
|
|
1270
|
+
- ``residue_chunks`` -- list of lists consisting of all integers
|
|
1271
|
+
less than the modulus that are coprime to it, broken into `n`
|
|
1272
|
+
sublists of approximately equal size
|
|
1273
|
+
|
|
1274
|
+
EXAMPLES::
|
|
1275
|
+
|
|
1276
|
+
sage: E = EllipticCurve("37a"); Z = LFunctionZeroSum(E)
|
|
1277
|
+
sage: Z._get_residue_data(8)
|
|
1278
|
+
([2, 3, 5, 7],
|
|
1279
|
+
210,
|
|
1280
|
+
[[1, 37, 71, 107, 143, 179],
|
|
1281
|
+
[11, 41, 73, 109, 149, 181],
|
|
1282
|
+
[13, 43, 79, 113, 151, 187],
|
|
1283
|
+
[17, 47, 83, 121, 157, 191],
|
|
1284
|
+
[19, 53, 89, 127, 163, 193],
|
|
1285
|
+
[23, 59, 97, 131, 167, 197],
|
|
1286
|
+
[29, 61, 101, 137, 169, 199],
|
|
1287
|
+
[31, 67, 103, 139, 173, 209]])
|
|
1288
|
+
"""
|
|
1289
|
+
# If n <=48, primes are sieved for modulo 210
|
|
1290
|
+
if n <= 48:
|
|
1291
|
+
small_primes = [2, 3, 5, 7]
|
|
1292
|
+
modulus = 210
|
|
1293
|
+
residue_list = [1, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47,
|
|
1294
|
+
53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103,
|
|
1295
|
+
107, 109, 113, 121, 127, 131, 137, 139, 143, 149,
|
|
1296
|
+
151, 157, 163, 167, 169, 173, 179, 181, 187, 191,
|
|
1297
|
+
193, 197, 199, 209]
|
|
1298
|
+
# General case for n > 480
|
|
1299
|
+
else:
|
|
1300
|
+
from sage.rings.finite_rings.integer_mod import mod
|
|
1301
|
+
|
|
1302
|
+
modulus, p = 2, 2
|
|
1303
|
+
small_primes, residue_list = [2], [1]
|
|
1304
|
+
num_residues = 1
|
|
1305
|
+
# Enlarge residue_list by repeatedly applying Chinese Remainder
|
|
1306
|
+
# Theorem
|
|
1307
|
+
while num_residues < n:
|
|
1308
|
+
p = next_prime(p)
|
|
1309
|
+
small_primes.append(p)
|
|
1310
|
+
g, h = (mod(p, modulus)**(-1)).lift(), (mod(modulus, p)**(-1)).lift()
|
|
1311
|
+
residue_list = [(a * p * g + b * modulus * h) % (modulus * p)
|
|
1312
|
+
for a in residue_list
|
|
1313
|
+
for b in range(1, p)]
|
|
1314
|
+
num_residues = num_residues * (p - 1)
|
|
1315
|
+
modulus *= p
|
|
1316
|
+
residue_list.sort()
|
|
1317
|
+
|
|
1318
|
+
# Break residue_list into n chunks
|
|
1319
|
+
residue_chunks = [[residue_list[i] for i in range(len(residue_list))
|
|
1320
|
+
if i % n == k] for k in range(n)]
|
|
1321
|
+
|
|
1322
|
+
return small_primes, modulus, residue_chunks
|
|
1323
|
+
|
|
1324
|
+
@parallel(ncpus=NCPUS)
|
|
1325
|
+
def _sum_over_residues(self, residue_sum_data):
|
|
1326
|
+
r"""
|
|
1327
|
+
Return the p-power sum over residues in a residue chunk
|
|
1328
|
+
"""
|
|
1329
|
+
modulus, residues = residue_sum_data[0], residue_sum_data[1]
|
|
1330
|
+
|
|
1331
|
+
cdef double y = 0
|
|
1332
|
+
cdef unsigned long n = residues[0]
|
|
1333
|
+
cdef double t = residue_sum_data[2]
|
|
1334
|
+
cdef double expt = residue_sum_data[3]
|
|
1335
|
+
cdef double bound1 = residue_sum_data[4]
|
|
1336
|
+
|
|
1337
|
+
cdef double z = 0
|
|
1338
|
+
cdef double p = 0
|
|
1339
|
+
cdef double sqrtp = 0
|
|
1340
|
+
cdef double sqrtq = 0
|
|
1341
|
+
cdef double logp = 0
|
|
1342
|
+
cdef double logq = 0
|
|
1343
|
+
cdef double thetap = 0
|
|
1344
|
+
cdef double thetaq = 0
|
|
1345
|
+
cdef int ap = 0
|
|
1346
|
+
|
|
1347
|
+
# Generate a list of increments so that n iterates over integers with
|
|
1348
|
+
# residues in the residue list
|
|
1349
|
+
len_increment_list = len(residues)
|
|
1350
|
+
increments = [residues[i + 1] - residues[i]
|
|
1351
|
+
for i in range(len_increment_list - 1)]
|
|
1352
|
+
increments.append(modulus + residues[0] - residues[-1])
|
|
1353
|
+
|
|
1354
|
+
i = 0
|
|
1355
|
+
# up to bound1=sqrt(expt), higher powers of p must be summed over too
|
|
1356
|
+
while n < bound1:
|
|
1357
|
+
if n_is_prime(n):
|
|
1358
|
+
y += self._sincsquared_summand_1(n, t, ap, p, logp,
|
|
1359
|
+
thetap, sqrtp, logq,
|
|
1360
|
+
thetaq, sqrtq, z)
|
|
1361
|
+
n += increments[i]
|
|
1362
|
+
# cycle over increments
|
|
1363
|
+
i += 1
|
|
1364
|
+
if i >= len_increment_list:
|
|
1365
|
+
i = 0
|
|
1366
|
+
|
|
1367
|
+
# when bound1 <= n < expt, we don't need to consider higher powers of p
|
|
1368
|
+
while n < expt:
|
|
1369
|
+
if n_is_prime(n):
|
|
1370
|
+
y += self._sincsquared_summand_2(n, t, ap, p, logp)
|
|
1371
|
+
n += increments[i]
|
|
1372
|
+
# cycle over increments
|
|
1373
|
+
i += 1
|
|
1374
|
+
if i >= len_increment_list:
|
|
1375
|
+
i = 0
|
|
1376
|
+
|
|
1377
|
+
return y
|
|
1378
|
+
|
|
1379
|
+
def _zerosum_sincsquared_parallel(self,
|
|
1380
|
+
Delta=1,
|
|
1381
|
+
bad_primes=None,
|
|
1382
|
+
ncpus=None):
|
|
1383
|
+
r"""
|
|
1384
|
+
Parallelized implementation of self._zerosum_sincsquared_fast().
|
|
1385
|
+
|
|
1386
|
+
Faster than self._zerosum_sincsquared_fast() when Delta >= ~1.75.
|
|
1387
|
+
|
|
1388
|
+
.. NOTE::
|
|
1389
|
+
|
|
1390
|
+
This will only produce correct output if self._E is given by its
|
|
1391
|
+
global minimal model, i.e. if self._E.is_minimal() is ``True``.
|
|
1392
|
+
|
|
1393
|
+
INPUT:
|
|
1394
|
+
|
|
1395
|
+
- ``Delta`` -- positive real parameter defining the
|
|
1396
|
+
tightness of the zero sum, and thus the closeness of the returned
|
|
1397
|
+
estimate to the actual analytic rank of the form attached to ``self``.
|
|
1398
|
+
|
|
1399
|
+
- ``bad_primes`` -- (default: ``None``) if not ``None``, a list of primes dividing
|
|
1400
|
+
the level of the form attached to ``self``. This is passable so that this
|
|
1401
|
+
method can be run on curves whose conductor is large enough to warrant
|
|
1402
|
+
precomputing bad primes.
|
|
1403
|
+
|
|
1404
|
+
- ``ncpus`` -- (default: ``None``) if not ``None``, a positive integer
|
|
1405
|
+
defining the number of CPUs to be used for the computation. If left as
|
|
1406
|
+
``None``, the maximum available number of CPUs will be used.
|
|
1407
|
+
|
|
1408
|
+
OUTPUT:
|
|
1409
|
+
|
|
1410
|
+
A positive real number that bounds the analytic rank of the modular form
|
|
1411
|
+
attached to ``self`` from above.
|
|
1412
|
+
|
|
1413
|
+
.. SEEALSO::
|
|
1414
|
+
|
|
1415
|
+
:meth:`~sage.lfunctions.zero_sums.LFunctionZeroSum_abstract.zerosum_sincsquared`
|
|
1416
|
+
for the more general but slower version of this method.
|
|
1417
|
+
|
|
1418
|
+
:meth:`~sage.lfunctions.zero_sums.LFunctionZeroSum_abstract.zerosum`
|
|
1419
|
+
for the public method that calls this private method.
|
|
1420
|
+
|
|
1421
|
+
EXAMPLES::
|
|
1422
|
+
|
|
1423
|
+
sage: E = EllipticCurve("37a"); print(E.rank())
|
|
1424
|
+
1
|
|
1425
|
+
sage: Z = LFunctionZeroSum(E)
|
|
1426
|
+
sage: print(Z._zerosum_sincsquared_parallel(Delta=1)) # tol 1.0e-11
|
|
1427
|
+
1.0103840698356263
|
|
1428
|
+
sage: E = EllipticCurve("121a"); print(E.rank())
|
|
1429
|
+
0
|
|
1430
|
+
sage: Z = LFunctionZeroSum(E)
|
|
1431
|
+
sage: print(Z._zerosum_sincsquared_parallel(Delta=1.5,ncpus=2)) # tol 1.0e-11
|
|
1432
|
+
0.01047120600865063
|
|
1433
|
+
"""
|
|
1434
|
+
# If Delta>6.619, then we will most likely get overflow: some ap values
|
|
1435
|
+
# will be too large to fit into a c int
|
|
1436
|
+
if Delta > 6.619:
|
|
1437
|
+
raise ValueError("Delta value too large; will result in overflow")
|
|
1438
|
+
|
|
1439
|
+
cdef double npi = self._pi
|
|
1440
|
+
cdef double twopi = npi * 2
|
|
1441
|
+
cdef double eg = self._euler_gamma
|
|
1442
|
+
cdef double N_double = self._level
|
|
1443
|
+
|
|
1444
|
+
cdef double t, u, w, y, z, expt, bound1, logp, logq
|
|
1445
|
+
cdef double thetap, thetaq, sqrtp, sqrtq, p, q
|
|
1446
|
+
cdef int ap, aq
|
|
1447
|
+
cdef unsigned long n
|
|
1448
|
+
|
|
1449
|
+
# Compute bounds and smooth part of sum
|
|
1450
|
+
t = twopi * Delta
|
|
1451
|
+
expt = c_exp(t)
|
|
1452
|
+
bound1 = c_exp(t / 2)
|
|
1453
|
+
u = t * (-eg + c_log(N_double) / 2 - c_log(twopi))
|
|
1454
|
+
w = npi**2 / 6 - (RDF.one() / expt).dilog()
|
|
1455
|
+
|
|
1456
|
+
# Oscillating part of sum
|
|
1457
|
+
y = 0
|
|
1458
|
+
# Do bad primes first. Add correct contributions and subtract
|
|
1459
|
+
# incorrect contribution; the latter are added back later on.
|
|
1460
|
+
if bad_primes is None:
|
|
1461
|
+
bad_primes = self._level.prime_divisors()
|
|
1462
|
+
bad_primes = [prime for prime in bad_primes if prime < expt]
|
|
1463
|
+
for prime in bad_primes:
|
|
1464
|
+
n = prime
|
|
1465
|
+
ap = self._e.ellap(n)
|
|
1466
|
+
p = n
|
|
1467
|
+
sqrtp = c_sqrt(p)
|
|
1468
|
+
thetap = c_acos(ap / (2 * sqrtp))
|
|
1469
|
+
logp = c_log(p)
|
|
1470
|
+
|
|
1471
|
+
q = 1
|
|
1472
|
+
sqrtq = 1
|
|
1473
|
+
aq = 1
|
|
1474
|
+
thetaq = 0
|
|
1475
|
+
logq = logp
|
|
1476
|
+
|
|
1477
|
+
z = 0
|
|
1478
|
+
while logq < t:
|
|
1479
|
+
q *= p
|
|
1480
|
+
sqrtq *= sqrtp
|
|
1481
|
+
aq *= ap
|
|
1482
|
+
thetaq += thetap
|
|
1483
|
+
# Actual value of this term
|
|
1484
|
+
z += (aq / q) * (t - logq)
|
|
1485
|
+
# Incorrect value of this term to be removed below
|
|
1486
|
+
z -= 2 * c_cos(thetaq) * (t - logq) / sqrtq
|
|
1487
|
+
logq += logp
|
|
1488
|
+
y -= z * logp
|
|
1489
|
+
|
|
1490
|
+
# Good prime case. Bad primes are treated as good primes, but their
|
|
1491
|
+
# contribution here is cancelled out above; this way we don't
|
|
1492
|
+
# have to check if each prime divides the level or not.
|
|
1493
|
+
if ncpus is not None:
|
|
1494
|
+
self._ncpus = ncpus
|
|
1495
|
+
else:
|
|
1496
|
+
ncpus = self._ncpus
|
|
1497
|
+
small_primes, modulus, residue_chunks = self._get_residue_data(ncpus)
|
|
1498
|
+
|
|
1499
|
+
# We must deal with small primes separately
|
|
1500
|
+
for m in small_primes:
|
|
1501
|
+
n = m
|
|
1502
|
+
if n < expt:
|
|
1503
|
+
y += self._sincsquared_summand_1(n, t, ap, p, logp,
|
|
1504
|
+
thetap, sqrtp, logq,
|
|
1505
|
+
thetaq, sqrtq, z)
|
|
1506
|
+
|
|
1507
|
+
# Now the rest of the sum via _sum_over_residues(), which is parallelized
|
|
1508
|
+
residue_sum_data = []
|
|
1509
|
+
for residues in residue_chunks:
|
|
1510
|
+
residue_sum_data.append([modulus, residues, t, expt, bound1])
|
|
1511
|
+
# residue_data = [[modulus]+residue_chunks[i] for i in range(len(residue_chunks))]
|
|
1512
|
+
# for summand in _sum_over_residues(residue_data):
|
|
1513
|
+
for summand in self._sum_over_residues(residue_sum_data):
|
|
1514
|
+
y += summand[1]
|
|
1515
|
+
|
|
1516
|
+
return RDF(2 * (u + w + y) / (t**2))
|
|
1517
|
+
|
|
1518
|
+
def analytic_rank_upper_bound(self,
|
|
1519
|
+
max_Delta=None,
|
|
1520
|
+
adaptive=True,
|
|
1521
|
+
root_number='compute',
|
|
1522
|
+
bad_primes=None,
|
|
1523
|
+
ncpus=None):
|
|
1524
|
+
r"""
|
|
1525
|
+
Return an upper bound for the analytic rank of the `L`-function
|
|
1526
|
+
`L_E(s)` attached to ``self``, conditional on the Generalized Riemann
|
|
1527
|
+
Hypothesis, via computing the zero sum `\sum_{\gamma} f(\Delta\gamma)`,
|
|
1528
|
+
where `\gamma` ranges over the imaginary parts of the zeros of `L(E,s)`
|
|
1529
|
+
along the critical strip, `f(x) = \left(\frac{\sin(\pi x)}{\pi x}\right)^2`,
|
|
1530
|
+
and `\Delta` is the tightness parameter whose maximum value is
|
|
1531
|
+
specified by max_Delta.
|
|
1532
|
+
|
|
1533
|
+
This computation can be run on curves with
|
|
1534
|
+
very large conductor (so long as the conductor is known or quickly
|
|
1535
|
+
computable) when Delta is not too large (see below).
|
|
1536
|
+
|
|
1537
|
+
Uses Bober's rank bounding method as described in [Bob2013]_.
|
|
1538
|
+
|
|
1539
|
+
INPUT:
|
|
1540
|
+
|
|
1541
|
+
- ``max_Delta`` -- (default: ``None``) if not ``None``, a positive real value
|
|
1542
|
+
specifying the maximum Delta value used in the zero sum; larger
|
|
1543
|
+
values of Delta yield better bounds - but runtime is exponential in
|
|
1544
|
+
Delta. If left as ``None``, Delta is set
|
|
1545
|
+
to `\min\left\{\frac{1}{\pi}\left(\log(N+1000)/2-\log(2\pi)-\eta\right), 2.5\right\}`,
|
|
1546
|
+
where `N` is the conductor of the curve attached to ``self``, and `\eta`
|
|
1547
|
+
is the Euler-Mascheroni constant `= 0.5772...`; the crossover
|
|
1548
|
+
point is at conductor ~8.3*10^8. For the former value, empirical
|
|
1549
|
+
results show that for about 99.7% of all curves the returned value
|
|
1550
|
+
is the actual analytic rank.
|
|
1551
|
+
|
|
1552
|
+
- ``adaptive`` -- boolean (default: ``True``)
|
|
1553
|
+
|
|
1554
|
+
- If ``True``, the computation is first run with small and then
|
|
1555
|
+
successively larger Delta values up to max_Delta. If at any
|
|
1556
|
+
point the computed bound is 0 (or 1 when root_number is -1
|
|
1557
|
+
or ``True``), the computation halts and that value is returned;
|
|
1558
|
+
otherwise the minimum of the computed bounds is returned.
|
|
1559
|
+
- If ``False``, the computation is run a single time with
|
|
1560
|
+
Delta=max_Delta, and the resulting bound returned.
|
|
1561
|
+
|
|
1562
|
+
- ``root_number`` -- (default: ``'compute'``) string or integer
|
|
1563
|
+
|
|
1564
|
+
- ``'compute'`` -- the root number of ``self`` is computed and used to
|
|
1565
|
+
(possibly) lower the analytic rank estimate by 1
|
|
1566
|
+
- ``'ignore'`` -- the above step is omitted
|
|
1567
|
+
- ``1`` -- this value is assumed to be the root number of
|
|
1568
|
+
``self``. This is passable so that rank estimation can be done for
|
|
1569
|
+
curves whose root number has been precomputed.
|
|
1570
|
+
- ``-1`` -- this value is assumed to be the root number of
|
|
1571
|
+
``self``. This is passable so that rank estimation can be done for
|
|
1572
|
+
curves whose root number has been precomputed.
|
|
1573
|
+
|
|
1574
|
+
- ``bad_primes`` -- (default: ``None``) if not ``None``, a list of the primes
|
|
1575
|
+
of bad reduction for the curve attached to ``self``. This is passable
|
|
1576
|
+
so that rank estimation can be done for curves of large conductor
|
|
1577
|
+
whose bad primes have been precomputed.
|
|
1578
|
+
|
|
1579
|
+
- ``ncpus`` -- (default: ``None``) if not ``None``, a positive integer
|
|
1580
|
+
defining the maximum number of CPUs to be used for the computation.
|
|
1581
|
+
If left as ``None``, the maximum available number of CPUs will be used.
|
|
1582
|
+
Note: Multiple processors will only be used for Delta values >= 1.75.
|
|
1583
|
+
|
|
1584
|
+
.. NOTE::
|
|
1585
|
+
|
|
1586
|
+
Output will be incorrect if the incorrect root number is specified.
|
|
1587
|
+
|
|
1588
|
+
.. WARNING::
|
|
1589
|
+
|
|
1590
|
+
Zero sum computation time is exponential in the tightness parameter
|
|
1591
|
+
`\Delta`, roughly doubling for every increase of 0.1 thereof.
|
|
1592
|
+
Using `\Delta=1` (and adaptive=False) will yield a runtime of a few
|
|
1593
|
+
milliseconds; `\Delta=2` takes a few seconds, and `\Delta=3` may
|
|
1594
|
+
take upwards of an hour. Increase beyond this at your own risk!
|
|
1595
|
+
|
|
1596
|
+
OUTPUT:
|
|
1597
|
+
|
|
1598
|
+
A nonnegative integer greater than or equal to the analytic rank of
|
|
1599
|
+
``self``. If the returned value is 0 or 1 (the latter if parity is not
|
|
1600
|
+
``False``), then this is the true analytic rank of ``self``.
|
|
1601
|
+
|
|
1602
|
+
.. NOTE::
|
|
1603
|
+
|
|
1604
|
+
If you use set_verbose(1), extra information about the computation
|
|
1605
|
+
will be printed.
|
|
1606
|
+
|
|
1607
|
+
.. SEEALSO::
|
|
1608
|
+
|
|
1609
|
+
:func:`LFunctionZeroSum`
|
|
1610
|
+
:meth:`EllipticCurve.root_number`
|
|
1611
|
+
:func:`~sage.misc.verbose.set_verbose`
|
|
1612
|
+
|
|
1613
|
+
EXAMPLES:
|
|
1614
|
+
|
|
1615
|
+
For most elliptic curves with small conductor the central zero(s)
|
|
1616
|
+
of `L_E(s)` are fairly isolated, so small values of `\Delta`
|
|
1617
|
+
will yield tight rank estimates.
|
|
1618
|
+
|
|
1619
|
+
::
|
|
1620
|
+
|
|
1621
|
+
sage: E = EllipticCurve("11a")
|
|
1622
|
+
sage: E.rank()
|
|
1623
|
+
0
|
|
1624
|
+
sage: Z = LFunctionZeroSum(E)
|
|
1625
|
+
sage: Z.analytic_rank_upper_bound(max_Delta=1,ncpus=1)
|
|
1626
|
+
0
|
|
1627
|
+
|
|
1628
|
+
sage: E = EllipticCurve([-39,123])
|
|
1629
|
+
sage: E.rank()
|
|
1630
|
+
1
|
|
1631
|
+
sage: Z = LFunctionZeroSum(E)
|
|
1632
|
+
sage: Z.analytic_rank_upper_bound(max_Delta=1)
|
|
1633
|
+
1
|
|
1634
|
+
|
|
1635
|
+
This is especially true for elliptic curves with large rank.
|
|
1636
|
+
|
|
1637
|
+
::
|
|
1638
|
+
|
|
1639
|
+
sage: for r in range(9):
|
|
1640
|
+
....: E = elliptic_curves.rank(r)[0]
|
|
1641
|
+
....: print((r, E.analytic_rank_upper_bound(max_Delta=1,
|
|
1642
|
+
....: adaptive=False,root_number='ignore')))
|
|
1643
|
+
(0, 0)
|
|
1644
|
+
(1, 1)
|
|
1645
|
+
(2, 2)
|
|
1646
|
+
(3, 3)
|
|
1647
|
+
(4, 4)
|
|
1648
|
+
(5, 5)
|
|
1649
|
+
(6, 6)
|
|
1650
|
+
(7, 7)
|
|
1651
|
+
(8, 8)
|
|
1652
|
+
|
|
1653
|
+
However, some curves have `L`-functions with low-lying zeroes, and for these
|
|
1654
|
+
larger values of `\Delta` must be used to get tight estimates.
|
|
1655
|
+
|
|
1656
|
+
::
|
|
1657
|
+
|
|
1658
|
+
sage: E = EllipticCurve("974b1")
|
|
1659
|
+
sage: r = E.rank(); r
|
|
1660
|
+
0
|
|
1661
|
+
sage: Z = LFunctionZeroSum(E)
|
|
1662
|
+
sage: Z.analytic_rank_upper_bound(max_Delta=1,root_number='ignore')
|
|
1663
|
+
1
|
|
1664
|
+
sage: Z.analytic_rank_upper_bound(max_Delta=1.3,root_number='ignore')
|
|
1665
|
+
0
|
|
1666
|
+
|
|
1667
|
+
Knowing the root number of E allows us to use smaller Delta values
|
|
1668
|
+
to get tight bounds, thus speeding up runtime considerably.
|
|
1669
|
+
|
|
1670
|
+
::
|
|
1671
|
+
|
|
1672
|
+
sage: Z.analytic_rank_upper_bound(max_Delta=0.6,root_number='compute')
|
|
1673
|
+
0
|
|
1674
|
+
|
|
1675
|
+
The are a small number of curves which have pathologically low-lying
|
|
1676
|
+
zeroes. For these curves, this method will produce a bound that is
|
|
1677
|
+
strictly larger than the analytic rank, unless very large values of
|
|
1678
|
+
Delta are used. The following curve ("256944c1" in the Cremona tables)
|
|
1679
|
+
is a rank 0 curve with a zero at 0.0256...; the smallest Delta value
|
|
1680
|
+
for which the zero sum is strictly less than 2 is ~2.815.
|
|
1681
|
+
|
|
1682
|
+
::
|
|
1683
|
+
|
|
1684
|
+
sage: E = EllipticCurve([0, -1, 0, -7460362000712, -7842981500851012704])
|
|
1685
|
+
sage: N,r = E.conductor(),E.analytic_rank(); N, r
|
|
1686
|
+
(256944, 0)
|
|
1687
|
+
sage: E.analytic_rank_upper_bound(max_Delta=1,adaptive=False)
|
|
1688
|
+
2
|
|
1689
|
+
sage: E.analytic_rank_upper_bound(max_Delta=2,adaptive=False)
|
|
1690
|
+
2
|
|
1691
|
+
|
|
1692
|
+
This method is can be called on curves with large conductor.
|
|
1693
|
+
|
|
1694
|
+
::
|
|
1695
|
+
|
|
1696
|
+
sage: E = EllipticCurve([-2934,19238])
|
|
1697
|
+
sage: Z = LFunctionZeroSum(E)
|
|
1698
|
+
sage: Z.analytic_rank_upper_bound()
|
|
1699
|
+
1
|
|
1700
|
+
|
|
1701
|
+
And it can bound rank on curves with *very* large conductor, so long as
|
|
1702
|
+
you know beforehand/can easily compute the conductor and primes of bad
|
|
1703
|
+
reduction less than `e^{2\pi\Delta}`. The example below is of the rank
|
|
1704
|
+
28 curve discovered by Elkies that is the elliptic curve of (currently)
|
|
1705
|
+
largest known rank.
|
|
1706
|
+
|
|
1707
|
+
::
|
|
1708
|
+
|
|
1709
|
+
sage: a4 = -20067762415575526585033208209338542750930230312178956502
|
|
1710
|
+
sage: a6 = 34481611795030556467032985690390720374855944359319180361266008296291939448732243429
|
|
1711
|
+
sage: E = EllipticCurve([1,-1,1,a4,a6])
|
|
1712
|
+
sage: bad_primes = [2,3,5,7,11,13,17,19,48463]
|
|
1713
|
+
sage: N = 3455601108357547341532253864901605231198511505793733138900595189472144724781456635380154149870961231592352897621963802238155192936274322687070
|
|
1714
|
+
sage: Z = LFunctionZeroSum(E,N)
|
|
1715
|
+
sage: Z.analytic_rank_upper_bound(max_Delta=2.37,adaptive=False, # long time
|
|
1716
|
+
....: root_number=1,bad_primes=bad_primes,ncpus=2)
|
|
1717
|
+
32
|
|
1718
|
+
"""
|
|
1719
|
+
# Helper function: compute zero sum and apply parity if not False
|
|
1720
|
+
def run_computation(Delta):
|
|
1721
|
+
verbose("Computing zero sum with Delta = %s" % Delta)
|
|
1722
|
+
# Empirically, the non-parallelized zero sum method runs faster
|
|
1723
|
+
# for Delta <= 1.75, regardless of the number of available CPUs.
|
|
1724
|
+
if Delta <= 1.75:
|
|
1725
|
+
bound = self._zerosum_sincsquared_fast(Delta=Delta,
|
|
1726
|
+
bad_primes=bad_primes)
|
|
1727
|
+
else:
|
|
1728
|
+
bound = self._zerosum_sincsquared_parallel(Delta=Delta,
|
|
1729
|
+
bad_primes=bad_primes,
|
|
1730
|
+
ncpus=ncpus)
|
|
1731
|
+
verbose("Sum value is %s" % bound)
|
|
1732
|
+
bound = bound.floor()
|
|
1733
|
+
# parity is set to -1 when we're not taking root number into
|
|
1734
|
+
# account
|
|
1735
|
+
if parity == -1:
|
|
1736
|
+
verbose("Without invoking parity, rank bound is %s" % bound)
|
|
1737
|
+
return bound
|
|
1738
|
+
# parity is 0 if E has even analytic rank, and 1 if odd
|
|
1739
|
+
# analytic rank. The returned value must have the same parity
|
|
1740
|
+
# as the parity parameter.
|
|
1741
|
+
if bound % 2 != parity:
|
|
1742
|
+
bound -= 1
|
|
1743
|
+
verbose("Invoking parity, rank bound is %s" % bound)
|
|
1744
|
+
return bound
|
|
1745
|
+
|
|
1746
|
+
# Get/compute parity
|
|
1747
|
+
if root_number == 1 or root_number == -1:
|
|
1748
|
+
parity = (1 - root_number) // 2
|
|
1749
|
+
verbose("Parity set to %s." % parity)
|
|
1750
|
+
elif root_number == "compute":
|
|
1751
|
+
verbose("Computing curve parity...")
|
|
1752
|
+
parity = (1 - self._e.ellrootno()) // 2
|
|
1753
|
+
verbose("Curve has parity %s." % parity)
|
|
1754
|
+
elif root_number == "ignore":
|
|
1755
|
+
verbose("Curve parity ignored.")
|
|
1756
|
+
parity = -1
|
|
1757
|
+
else:
|
|
1758
|
+
raise ValueError("root_number parameter not recognized")
|
|
1759
|
+
if parity == 1:
|
|
1760
|
+
halt_bound = 1
|
|
1761
|
+
verbose("Computation will halt if at any point bound is <= 1.")
|
|
1762
|
+
else:
|
|
1763
|
+
halt_bound = 0
|
|
1764
|
+
verbose("Computation will halt if at any point bound is 0.")
|
|
1765
|
+
|
|
1766
|
+
# Compute max_Delta if necessary
|
|
1767
|
+
if max_Delta is None:
|
|
1768
|
+
verbose("Computing maximum Delta value")
|
|
1769
|
+
pi, eg = self._pi, self._euler_gamma
|
|
1770
|
+
# 1000 is arbitrary - increases Delta for small N
|
|
1771
|
+
max_Delta = (RDF(self._level + 1000).log() / 2 - log(2 * pi) - eg) / pi
|
|
1772
|
+
if max_Delta > 2.5:
|
|
1773
|
+
max_Delta = 2.5
|
|
1774
|
+
verbose("Computed max Delta value too big; setting to 2.5")
|
|
1775
|
+
else:
|
|
1776
|
+
verbose("Maximum Delta value to be used set at %s" % max_Delta)
|
|
1777
|
+
else:
|
|
1778
|
+
verbose("Maximum Delta value to be used set at %s" % max_Delta)
|
|
1779
|
+
|
|
1780
|
+
# When max_Delta <= 1 it's not worth running the computation
|
|
1781
|
+
# multiple times, as it's so quick anyway
|
|
1782
|
+
if not adaptive or max_Delta <= 1:
|
|
1783
|
+
return run_computation(max_Delta)
|
|
1784
|
+
else:
|
|
1785
|
+
bound_list = []
|
|
1786
|
+
# Find starting value. This loop won't ever take long,
|
|
1787
|
+
# since max_Delta is never > 7.
|
|
1788
|
+
Delta = max_Delta
|
|
1789
|
+
while Delta > 1:
|
|
1790
|
+
Delta -= 0.2
|
|
1791
|
+
# Now go back up the sequence of Deltas
|
|
1792
|
+
while Delta <= max_Delta:
|
|
1793
|
+
bound = run_computation(Delta)
|
|
1794
|
+
if bound <= halt_bound:
|
|
1795
|
+
verbose("computed bound <= halt_bound, so halting")
|
|
1796
|
+
return bound
|
|
1797
|
+
else:
|
|
1798
|
+
bound_list.append(bound)
|
|
1799
|
+
# Incrementing Delta by 0.2 each step means runtime
|
|
1800
|
+
# will increase by a factor of ~3.7
|
|
1801
|
+
Delta += 0.2
|
|
1802
|
+
|
|
1803
|
+
# Since the zero sum is not strictly decreasing in Delta,
|
|
1804
|
+
# the last value is not necessarily the smallest
|
|
1805
|
+
smallest_bound = min(bound_list)
|
|
1806
|
+
verbose("Smallest bound computed is %s" % smallest_bound)
|
|
1807
|
+
return smallest_bound
|
|
1808
|
+
|
|
1809
|
+
|
|
1810
|
+
def LFunctionZeroSum(X, *args, **kwds):
|
|
1811
|
+
r"""
|
|
1812
|
+
Constructor for the LFunctionZeroSum class.
|
|
1813
|
+
|
|
1814
|
+
INPUT:
|
|
1815
|
+
|
|
1816
|
+
- ``X`` -- a motivic object; currently only implemented for X = an elliptic curve
|
|
1817
|
+
over the rational numbers
|
|
1818
|
+
|
|
1819
|
+
OUTPUT: an LFunctionZeroSum object
|
|
1820
|
+
|
|
1821
|
+
EXAMPLES::
|
|
1822
|
+
|
|
1823
|
+
sage: E = EllipticCurve("389a")
|
|
1824
|
+
sage: Z = LFunctionZeroSum(E); Z
|
|
1825
|
+
Zero sum estimator for L-function attached to Elliptic Curve defined by y^2 + y = x^3 + x^2 - 2*x over Rational Field
|
|
1826
|
+
|
|
1827
|
+
TESTS::
|
|
1828
|
+
|
|
1829
|
+
sage: E = EllipticCurve([1.2,3.8])
|
|
1830
|
+
sage: LFunctionZeroSum(E)
|
|
1831
|
+
Traceback (most recent call last):
|
|
1832
|
+
...
|
|
1833
|
+
NotImplementedError: currently only implemented for elliptic curves over QQ
|
|
1834
|
+
|
|
1835
|
+
sage: f = Newforms(46)[0]
|
|
1836
|
+
sage: LFunctionZeroSum(f)
|
|
1837
|
+
Traceback (most recent call last):
|
|
1838
|
+
...
|
|
1839
|
+
NotImplementedError: currently only implemented for elliptic curves over QQ
|
|
1840
|
+
"""
|
|
1841
|
+
# Here to avoid import recursion
|
|
1842
|
+
from sage.schemes.elliptic_curves.ell_rational_field import EllipticCurve_rational_field
|
|
1843
|
+
|
|
1844
|
+
if isinstance(X, EllipticCurve_rational_field):
|
|
1845
|
+
return LFunctionZeroSum_EllipticCurve(X, *args, **kwds)
|
|
1846
|
+
|
|
1847
|
+
raise NotImplementedError("currently only implemented for elliptic curves over QQ")
|