passagemath-schemes 10.6.40__cp314-cp314-macosx_13_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of passagemath-schemes might be problematic. Click here for more details.
- passagemath_schemes/.dylibs/libflint.22.0.dylib +0 -0
- passagemath_schemes/.dylibs/libgmp.10.dylib +0 -0
- passagemath_schemes/.dylibs/libgmpxx.4.dylib +0 -0
- passagemath_schemes/.dylibs/libmpfr.6.dylib +0 -0
- passagemath_schemes/__init__.py +3 -0
- passagemath_schemes-10.6.40.dist-info/METADATA +204 -0
- passagemath_schemes-10.6.40.dist-info/METADATA.bak +205 -0
- passagemath_schemes-10.6.40.dist-info/RECORD +314 -0
- passagemath_schemes-10.6.40.dist-info/WHEEL +6 -0
- passagemath_schemes-10.6.40.dist-info/top_level.txt +3 -0
- sage/all__sagemath_schemes.py +23 -0
- sage/databases/all__sagemath_schemes.py +7 -0
- sage/databases/cremona.py +1723 -0
- sage/dynamics/all__sagemath_schemes.py +2 -0
- sage/dynamics/arithmetic_dynamics/affine_ds.py +1083 -0
- sage/dynamics/arithmetic_dynamics/all.py +14 -0
- sage/dynamics/arithmetic_dynamics/berkovich_ds.py +1101 -0
- sage/dynamics/arithmetic_dynamics/dynamical_semigroup.py +1543 -0
- sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py +2426 -0
- sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py +1169 -0
- sage/dynamics/arithmetic_dynamics/generic_ds.py +663 -0
- sage/dynamics/arithmetic_dynamics/product_projective_ds.py +339 -0
- sage/dynamics/arithmetic_dynamics/projective_ds.py +9558 -0
- sage/dynamics/arithmetic_dynamics/projective_ds_helper.cpython-314-darwin.so +0 -0
- sage/dynamics/arithmetic_dynamics/projective_ds_helper.pyx +301 -0
- sage/dynamics/arithmetic_dynamics/wehlerK3.py +2576 -0
- sage/lfunctions/all.py +18 -0
- sage/lfunctions/dokchitser.py +745 -0
- sage/lfunctions/pari.py +818 -0
- sage/lfunctions/zero_sums.cpython-314-darwin.so +0 -0
- sage/lfunctions/zero_sums.pyx +1847 -0
- sage/modular/abvar/abvar.py +5135 -0
- sage/modular/abvar/abvar_ambient_jacobian.py +413 -0
- sage/modular/abvar/abvar_newform.py +244 -0
- sage/modular/abvar/all.py +8 -0
- sage/modular/abvar/constructor.py +186 -0
- sage/modular/abvar/cuspidal_subgroup.py +371 -0
- sage/modular/abvar/finite_subgroup.py +896 -0
- sage/modular/abvar/homology.py +720 -0
- sage/modular/abvar/homspace.py +998 -0
- sage/modular/abvar/lseries.py +415 -0
- sage/modular/abvar/morphism.py +935 -0
- sage/modular/abvar/torsion_point.py +274 -0
- sage/modular/abvar/torsion_subgroup.py +740 -0
- sage/modular/all.py +43 -0
- sage/modular/arithgroup/all.py +20 -0
- sage/modular/arithgroup/arithgroup_element.cpython-314-darwin.so +0 -0
- sage/modular/arithgroup/arithgroup_element.pyx +474 -0
- sage/modular/arithgroup/arithgroup_generic.py +1402 -0
- sage/modular/arithgroup/arithgroup_perm.py +2692 -0
- sage/modular/arithgroup/congroup.cpython-314-darwin.so +0 -0
- sage/modular/arithgroup/congroup.pyx +334 -0
- sage/modular/arithgroup/congroup_gamma.py +363 -0
- sage/modular/arithgroup/congroup_gamma0.py +692 -0
- sage/modular/arithgroup/congroup_gamma1.py +653 -0
- sage/modular/arithgroup/congroup_gammaH.py +1469 -0
- sage/modular/arithgroup/congroup_generic.py +628 -0
- sage/modular/arithgroup/congroup_sl2z.py +267 -0
- sage/modular/arithgroup/farey_symbol.cpython-314-darwin.so +0 -0
- sage/modular/arithgroup/farey_symbol.pyx +1066 -0
- sage/modular/arithgroup/tests.py +418 -0
- sage/modular/btquotients/all.py +4 -0
- sage/modular/btquotients/btquotient.py +3753 -0
- sage/modular/btquotients/pautomorphicform.py +2570 -0
- sage/modular/buzzard.py +100 -0
- sage/modular/congroup.py +29 -0
- sage/modular/congroup_element.py +13 -0
- sage/modular/cusps.py +1109 -0
- sage/modular/cusps_nf.py +1270 -0
- sage/modular/dims.py +569 -0
- sage/modular/dirichlet.py +3310 -0
- sage/modular/drinfeld_modform/all.py +2 -0
- sage/modular/drinfeld_modform/element.py +446 -0
- sage/modular/drinfeld_modform/ring.py +773 -0
- sage/modular/drinfeld_modform/tutorial.py +236 -0
- sage/modular/etaproducts.py +1065 -0
- sage/modular/hecke/algebra.py +746 -0
- sage/modular/hecke/all.py +20 -0
- sage/modular/hecke/ambient_module.py +1019 -0
- sage/modular/hecke/degenmap.py +119 -0
- sage/modular/hecke/element.py +325 -0
- sage/modular/hecke/hecke_operator.py +780 -0
- sage/modular/hecke/homspace.py +206 -0
- sage/modular/hecke/module.py +1767 -0
- sage/modular/hecke/morphism.py +174 -0
- sage/modular/hecke/submodule.py +989 -0
- sage/modular/hypergeometric_misc.cpython-314-darwin.so +0 -0
- sage/modular/hypergeometric_misc.pxd +4 -0
- sage/modular/hypergeometric_misc.pyx +166 -0
- sage/modular/hypergeometric_motive.py +2017 -0
- sage/modular/local_comp/all.py +2 -0
- sage/modular/local_comp/liftings.py +292 -0
- sage/modular/local_comp/local_comp.py +1071 -0
- sage/modular/local_comp/smoothchar.py +1825 -0
- sage/modular/local_comp/type_space.py +748 -0
- sage/modular/modform/all.py +30 -0
- sage/modular/modform/ambient.py +815 -0
- sage/modular/modform/ambient_R.py +177 -0
- sage/modular/modform/ambient_eps.py +306 -0
- sage/modular/modform/ambient_g0.py +124 -0
- sage/modular/modform/ambient_g1.py +204 -0
- sage/modular/modform/constructor.py +545 -0
- sage/modular/modform/cuspidal_submodule.py +708 -0
- sage/modular/modform/defaults.py +14 -0
- sage/modular/modform/eis_series.py +505 -0
- sage/modular/modform/eisenstein_submodule.py +663 -0
- sage/modular/modform/element.py +4131 -0
- sage/modular/modform/find_generators.py +59 -0
- sage/modular/modform/half_integral.py +154 -0
- sage/modular/modform/hecke_operator_on_qexp.py +247 -0
- sage/modular/modform/j_invariant.py +47 -0
- sage/modular/modform/l_series_gross_zagier.py +133 -0
- sage/modular/modform/l_series_gross_zagier_coeffs.cpython-314-darwin.so +0 -0
- sage/modular/modform/l_series_gross_zagier_coeffs.pyx +177 -0
- sage/modular/modform/notes.py +45 -0
- sage/modular/modform/numerical.py +514 -0
- sage/modular/modform/periods.py +14 -0
- sage/modular/modform/ring.py +1257 -0
- sage/modular/modform/space.py +1860 -0
- sage/modular/modform/submodule.py +118 -0
- sage/modular/modform/tests.py +64 -0
- sage/modular/modform/theta.py +110 -0
- sage/modular/modform/vm_basis.py +381 -0
- sage/modular/modform/weight1.py +220 -0
- sage/modular/modform_hecketriangle/abstract_ring.py +1932 -0
- sage/modular/modform_hecketriangle/abstract_space.py +2528 -0
- sage/modular/modform_hecketriangle/all.py +30 -0
- sage/modular/modform_hecketriangle/analytic_type.py +590 -0
- sage/modular/modform_hecketriangle/constructor.py +416 -0
- sage/modular/modform_hecketriangle/element.py +351 -0
- sage/modular/modform_hecketriangle/functors.py +752 -0
- sage/modular/modform_hecketriangle/graded_ring.py +541 -0
- sage/modular/modform_hecketriangle/graded_ring_element.py +2225 -0
- sage/modular/modform_hecketriangle/hecke_triangle_group_element.py +3352 -0
- sage/modular/modform_hecketriangle/hecke_triangle_groups.py +1432 -0
- sage/modular/modform_hecketriangle/readme.py +1214 -0
- sage/modular/modform_hecketriangle/series_constructor.py +580 -0
- sage/modular/modform_hecketriangle/space.py +1037 -0
- sage/modular/modform_hecketriangle/subspace.py +423 -0
- sage/modular/modsym/all.py +17 -0
- sage/modular/modsym/ambient.py +3846 -0
- sage/modular/modsym/boundary.py +1420 -0
- sage/modular/modsym/element.py +336 -0
- sage/modular/modsym/g1list.py +178 -0
- sage/modular/modsym/ghlist.py +182 -0
- sage/modular/modsym/hecke_operator.py +73 -0
- sage/modular/modsym/manin_symbol.cpython-314-darwin.so +0 -0
- sage/modular/modsym/manin_symbol.pxd +5 -0
- sage/modular/modsym/manin_symbol.pyx +497 -0
- sage/modular/modsym/manin_symbol_list.py +1295 -0
- sage/modular/modsym/modsym.py +400 -0
- sage/modular/modsym/modular_symbols.py +384 -0
- sage/modular/modsym/p1list.cpython-314-darwin.so +0 -0
- sage/modular/modsym/p1list.pxd +29 -0
- sage/modular/modsym/p1list.pyx +1372 -0
- sage/modular/modsym/p1list_nf.py +1241 -0
- sage/modular/modsym/relation_matrix.py +591 -0
- sage/modular/modsym/relation_matrix_pyx.cpython-314-darwin.so +0 -0
- sage/modular/modsym/relation_matrix_pyx.pyx +108 -0
- sage/modular/modsym/space.py +2468 -0
- sage/modular/modsym/subspace.py +455 -0
- sage/modular/modsym/tests.py +375 -0
- sage/modular/multiple_zeta.py +2632 -0
- sage/modular/multiple_zeta_F_algebra.py +786 -0
- sage/modular/overconvergent/all.py +6 -0
- sage/modular/overconvergent/genus0.py +1878 -0
- sage/modular/overconvergent/hecke_series.py +1187 -0
- sage/modular/overconvergent/weightspace.py +778 -0
- sage/modular/pollack_stevens/all.py +4 -0
- sage/modular/pollack_stevens/distributions.py +874 -0
- sage/modular/pollack_stevens/fund_domain.py +1572 -0
- sage/modular/pollack_stevens/manin_map.py +859 -0
- sage/modular/pollack_stevens/modsym.py +1593 -0
- sage/modular/pollack_stevens/padic_lseries.py +417 -0
- sage/modular/pollack_stevens/sigma0.py +534 -0
- sage/modular/pollack_stevens/space.py +1076 -0
- sage/modular/quasimodform/all.py +3 -0
- sage/modular/quasimodform/element.py +845 -0
- sage/modular/quasimodform/ring.py +828 -0
- sage/modular/quatalg/all.py +3 -0
- sage/modular/quatalg/brandt.py +1642 -0
- sage/modular/ssmod/all.py +8 -0
- sage/modular/ssmod/ssmod.py +827 -0
- sage/rings/all__sagemath_schemes.py +1 -0
- sage/rings/polynomial/all__sagemath_schemes.py +1 -0
- sage/rings/polynomial/binary_form_reduce.py +585 -0
- sage/schemes/all.py +41 -0
- sage/schemes/berkovich/all.py +6 -0
- sage/schemes/berkovich/berkovich_cp_element.py +2582 -0
- sage/schemes/berkovich/berkovich_space.py +748 -0
- sage/schemes/curves/affine_curve.py +2928 -0
- sage/schemes/curves/all.py +33 -0
- sage/schemes/curves/closed_point.py +434 -0
- sage/schemes/curves/constructor.py +381 -0
- sage/schemes/curves/curve.py +542 -0
- sage/schemes/curves/plane_curve_arrangement.py +1283 -0
- sage/schemes/curves/point.py +463 -0
- sage/schemes/curves/projective_curve.py +3026 -0
- sage/schemes/curves/zariski_vankampen.py +1932 -0
- sage/schemes/cyclic_covers/all.py +2 -0
- sage/schemes/cyclic_covers/charpoly_frobenius.py +320 -0
- sage/schemes/cyclic_covers/constructor.py +137 -0
- sage/schemes/cyclic_covers/cycliccover_finite_field.py +1309 -0
- sage/schemes/cyclic_covers/cycliccover_generic.py +310 -0
- sage/schemes/elliptic_curves/BSD.py +1036 -0
- sage/schemes/elliptic_curves/Qcurves.py +592 -0
- sage/schemes/elliptic_curves/addition_formulas_ring.py +94 -0
- sage/schemes/elliptic_curves/all.py +49 -0
- sage/schemes/elliptic_curves/cardinality.py +609 -0
- sage/schemes/elliptic_curves/cm.py +1102 -0
- sage/schemes/elliptic_curves/constructor.py +1552 -0
- sage/schemes/elliptic_curves/ec_database.py +175 -0
- sage/schemes/elliptic_curves/ell_curve_isogeny.py +3972 -0
- sage/schemes/elliptic_curves/ell_egros.py +459 -0
- sage/schemes/elliptic_curves/ell_field.py +2836 -0
- sage/schemes/elliptic_curves/ell_finite_field.py +3359 -0
- sage/schemes/elliptic_curves/ell_generic.py +3760 -0
- sage/schemes/elliptic_curves/ell_local_data.py +1207 -0
- sage/schemes/elliptic_curves/ell_modular_symbols.py +775 -0
- sage/schemes/elliptic_curves/ell_number_field.py +4220 -0
- sage/schemes/elliptic_curves/ell_padic_field.py +107 -0
- sage/schemes/elliptic_curves/ell_point.py +4787 -0
- sage/schemes/elliptic_curves/ell_rational_field.py +7368 -0
- sage/schemes/elliptic_curves/ell_tate_curve.py +671 -0
- sage/schemes/elliptic_curves/ell_torsion.py +436 -0
- sage/schemes/elliptic_curves/ell_wp.py +352 -0
- sage/schemes/elliptic_curves/formal_group.py +760 -0
- sage/schemes/elliptic_curves/gal_reps.py +1459 -0
- sage/schemes/elliptic_curves/gal_reps_number_field.py +1669 -0
- sage/schemes/elliptic_curves/gp_simon.py +152 -0
- sage/schemes/elliptic_curves/heegner.py +7335 -0
- sage/schemes/elliptic_curves/height.py +2109 -0
- sage/schemes/elliptic_curves/hom.py +1406 -0
- sage/schemes/elliptic_curves/hom_composite.py +934 -0
- sage/schemes/elliptic_curves/hom_frobenius.py +522 -0
- sage/schemes/elliptic_curves/hom_scalar.py +531 -0
- sage/schemes/elliptic_curves/hom_sum.py +682 -0
- sage/schemes/elliptic_curves/hom_velusqrt.py +1290 -0
- sage/schemes/elliptic_curves/homset.py +271 -0
- sage/schemes/elliptic_curves/isogeny_class.py +1521 -0
- sage/schemes/elliptic_curves/isogeny_small_degree.py +2797 -0
- sage/schemes/elliptic_curves/jacobian.py +237 -0
- sage/schemes/elliptic_curves/kodaira_symbol.py +344 -0
- sage/schemes/elliptic_curves/kraus.py +1014 -0
- sage/schemes/elliptic_curves/lseries_ell.py +943 -0
- sage/schemes/elliptic_curves/mod5family.py +105 -0
- sage/schemes/elliptic_curves/mod_poly.py +197 -0
- sage/schemes/elliptic_curves/mod_sym_num.cpython-314-darwin.so +0 -0
- sage/schemes/elliptic_curves/mod_sym_num.pyx +3796 -0
- sage/schemes/elliptic_curves/modular_parametrization.py +305 -0
- sage/schemes/elliptic_curves/padic_lseries.py +1793 -0
- sage/schemes/elliptic_curves/padics.py +1816 -0
- sage/schemes/elliptic_curves/period_lattice.py +2234 -0
- sage/schemes/elliptic_curves/period_lattice_region.cpython-314-darwin.so +0 -0
- sage/schemes/elliptic_curves/period_lattice_region.pyx +722 -0
- sage/schemes/elliptic_curves/saturation.py +715 -0
- sage/schemes/elliptic_curves/sha_tate.py +1158 -0
- sage/schemes/elliptic_curves/weierstrass_morphism.py +1117 -0
- sage/schemes/elliptic_curves/weierstrass_transform.py +200 -0
- sage/schemes/hyperelliptic_curves/all.py +6 -0
- sage/schemes/hyperelliptic_curves/constructor.py +291 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py +1914 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_g2.py +192 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py +954 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py +1332 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_rational_field.py +84 -0
- sage/schemes/hyperelliptic_curves/invariants.py +410 -0
- sage/schemes/hyperelliptic_curves/jacobian_endomorphism_utils.py +315 -0
- sage/schemes/hyperelliptic_curves/jacobian_g2.py +32 -0
- sage/schemes/hyperelliptic_curves/jacobian_generic.py +419 -0
- sage/schemes/hyperelliptic_curves/jacobian_homset.py +186 -0
- sage/schemes/hyperelliptic_curves/jacobian_morphism.py +875 -0
- sage/schemes/hyperelliptic_curves/kummer_surface.py +99 -0
- sage/schemes/hyperelliptic_curves/mestre.py +302 -0
- sage/schemes/hyperelliptic_curves/monsky_washnitzer.py +3871 -0
- sage/schemes/jacobians/abstract_jacobian.py +277 -0
- sage/schemes/jacobians/all.py +2 -0
- sage/schemes/overview.py +161 -0
- sage/schemes/plane_conics/all.py +22 -0
- sage/schemes/plane_conics/con_field.py +1296 -0
- sage/schemes/plane_conics/con_finite_field.py +158 -0
- sage/schemes/plane_conics/con_number_field.py +456 -0
- sage/schemes/plane_conics/con_rational_field.py +406 -0
- sage/schemes/plane_conics/con_rational_function_field.py +580 -0
- sage/schemes/plane_conics/constructor.py +249 -0
- sage/schemes/plane_quartics/all.py +2 -0
- sage/schemes/plane_quartics/quartic_constructor.py +71 -0
- sage/schemes/plane_quartics/quartic_generic.py +73 -0
- sage/schemes/riemann_surfaces/all.py +1 -0
- sage/schemes/riemann_surfaces/riemann_surface.py +4117 -0
- sage_wheels/share/cremona/cremona_mini.db +0 -0
- sage_wheels/share/ellcurves/rank0 +30427 -0
- sage_wheels/share/ellcurves/rank1 +31871 -0
- sage_wheels/share/ellcurves/rank10 +6 -0
- sage_wheels/share/ellcurves/rank11 +6 -0
- sage_wheels/share/ellcurves/rank12 +1 -0
- sage_wheels/share/ellcurves/rank14 +1 -0
- sage_wheels/share/ellcurves/rank15 +1 -0
- sage_wheels/share/ellcurves/rank17 +1 -0
- sage_wheels/share/ellcurves/rank19 +1 -0
- sage_wheels/share/ellcurves/rank2 +2388 -0
- sage_wheels/share/ellcurves/rank20 +1 -0
- sage_wheels/share/ellcurves/rank21 +1 -0
- sage_wheels/share/ellcurves/rank22 +1 -0
- sage_wheels/share/ellcurves/rank23 +1 -0
- sage_wheels/share/ellcurves/rank24 +1 -0
- sage_wheels/share/ellcurves/rank28 +1 -0
- sage_wheels/share/ellcurves/rank3 +836 -0
- sage_wheels/share/ellcurves/rank4 +10 -0
- sage_wheels/share/ellcurves/rank5 +5 -0
- sage_wheels/share/ellcurves/rank6 +5 -0
- sage_wheels/share/ellcurves/rank7 +5 -0
- sage_wheels/share/ellcurves/rank8 +6 -0
- sage_wheels/share/ellcurves/rank9 +7 -0
|
@@ -0,0 +1,2109 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-schemes
|
|
2
|
+
r"""
|
|
3
|
+
Canonical heights for elliptic curves over number fields
|
|
4
|
+
|
|
5
|
+
Also, rigorous lower bounds for the canonical height of non-torsion
|
|
6
|
+
points, implementing the algorithms in [CS2006]_ (over `\QQ`) and [Tho2010]_,
|
|
7
|
+
which also refer to [CPS2006]_.
|
|
8
|
+
|
|
9
|
+
AUTHORS:
|
|
10
|
+
|
|
11
|
+
- Robert Bradshaw (2010): initial version
|
|
12
|
+
|
|
13
|
+
- John Cremona (2014): added many docstrings and doctests
|
|
14
|
+
"""
|
|
15
|
+
##############################################################################
|
|
16
|
+
# Copyright (C) 2010 Robert Bradshaw <robertwb@math.washington.edu>
|
|
17
|
+
# 2014 John Cremona <john.cremona@gmail.com>
|
|
18
|
+
#
|
|
19
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
20
|
+
#
|
|
21
|
+
# This code is distributed in the hope that it will be useful,
|
|
22
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
23
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
24
|
+
# General Public License for more details.
|
|
25
|
+
#
|
|
26
|
+
# The full text of the GPL is available at:
|
|
27
|
+
#
|
|
28
|
+
# https://www.gnu.org/licenses/
|
|
29
|
+
##############################################################################
|
|
30
|
+
import numpy
|
|
31
|
+
import math
|
|
32
|
+
import bisect
|
|
33
|
+
|
|
34
|
+
from itertools import product
|
|
35
|
+
|
|
36
|
+
from sage.arith.functions import lcm
|
|
37
|
+
from sage.arith.misc import factorial
|
|
38
|
+
from sage.ext.fast_callable import fast_callable
|
|
39
|
+
from sage.misc.cachefunc import cached_method
|
|
40
|
+
from sage.misc.lazy_import import lazy_import
|
|
41
|
+
from sage.rings.cc import CC
|
|
42
|
+
from sage.rings.complex_double import CDF
|
|
43
|
+
from sage.rings.infinity import infinity
|
|
44
|
+
from sage.rings.integer_ring import ZZ
|
|
45
|
+
from sage.rings.rational_field import QQ
|
|
46
|
+
from sage.rings.real_double import RDF
|
|
47
|
+
from sage.rings.real_mpfr import RR
|
|
48
|
+
|
|
49
|
+
lazy_import("sage.functions.log", ["log", "exp"])
|
|
50
|
+
lazy_import("sage.rings.cif", "CIF")
|
|
51
|
+
lazy_import("sage.rings.real_mpfi", "RIF")
|
|
52
|
+
lazy_import("sage.symbolic.ring", "SR")
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class UnionOfIntervals:
|
|
56
|
+
r"""
|
|
57
|
+
A class representing a finite union of closed intervals in
|
|
58
|
+
`\RR` which can be scaled, shifted, intersected, etc.
|
|
59
|
+
|
|
60
|
+
The intervals are represented as an ordered list of their
|
|
61
|
+
endpoints, which may include `-\infty` and `+\infty`.
|
|
62
|
+
|
|
63
|
+
EXAMPLES::
|
|
64
|
+
|
|
65
|
+
sage: from sage.schemes.elliptic_curves.height import UnionOfIntervals
|
|
66
|
+
sage: R = UnionOfIntervals([1, 2, 3, infinity]); R
|
|
67
|
+
([1, 2] U [3, +Infinity])
|
|
68
|
+
sage: R + 5
|
|
69
|
+
([6, 7] U [8, +Infinity])
|
|
70
|
+
sage: ~R
|
|
71
|
+
([-Infinity, 1] U [2, 3])
|
|
72
|
+
sage: ~R | (10*R + 100)
|
|
73
|
+
([-Infinity, 1] U [2, 3] U [110, 120] U [130, +Infinity])
|
|
74
|
+
|
|
75
|
+
.. TODO::
|
|
76
|
+
|
|
77
|
+
Unify :class:`UnionOfIntervals` with the class ``RealSet``
|
|
78
|
+
introduced by :issue:`13125`; see :issue:`16063`.
|
|
79
|
+
"""
|
|
80
|
+
def __init__(self, endpoints):
|
|
81
|
+
r"""
|
|
82
|
+
An union of intervals is initialized by giving an increasing list
|
|
83
|
+
of endpoints, the first of which may be `-\infty` and the last of
|
|
84
|
+
which may be `+\infty`.
|
|
85
|
+
|
|
86
|
+
EXAMPLES::
|
|
87
|
+
|
|
88
|
+
sage: from sage.schemes.elliptic_curves.height import UnionOfIntervals
|
|
89
|
+
sage: UnionOfIntervals([0, 1])
|
|
90
|
+
([0, 1])
|
|
91
|
+
sage: UnionOfIntervals([-infinity, pi, 17, infinity]) # needs sage.symbolic
|
|
92
|
+
([-Infinity, pi] U [17, +Infinity])
|
|
93
|
+
sage: UnionOfIntervals([])
|
|
94
|
+
()
|
|
95
|
+
|
|
96
|
+
sage: UnionOfIntervals([1])
|
|
97
|
+
Traceback (most recent call last):
|
|
98
|
+
...
|
|
99
|
+
ValueError: an even number of endpoints must be given (got 1)
|
|
100
|
+
sage: UnionOfIntervals([3, 2, 1, 0])
|
|
101
|
+
Traceback (most recent call last):
|
|
102
|
+
...
|
|
103
|
+
ValueError: endpoints must be given in order
|
|
104
|
+
"""
|
|
105
|
+
if len(endpoints) % 2:
|
|
106
|
+
raise ValueError("an even number of endpoints must be given (got %s)" % len(endpoints))
|
|
107
|
+
if endpoints != sorted(endpoints):
|
|
108
|
+
raise ValueError("endpoints must be given in order")
|
|
109
|
+
self._endpoints = endpoints
|
|
110
|
+
|
|
111
|
+
def finite_endpoints(self):
|
|
112
|
+
r"""
|
|
113
|
+
Return the finite endpoints of this union of intervals.
|
|
114
|
+
|
|
115
|
+
EXAMPLES::
|
|
116
|
+
|
|
117
|
+
sage: from sage.schemes.elliptic_curves.height import UnionOfIntervals
|
|
118
|
+
sage: UnionOfIntervals([0, 1]).finite_endpoints()
|
|
119
|
+
[0, 1]
|
|
120
|
+
sage: UnionOfIntervals([-infinity, 0, 1, infinity]).finite_endpoints()
|
|
121
|
+
[0, 1]
|
|
122
|
+
"""
|
|
123
|
+
return [e for e in self._endpoints if -infinity < e < infinity]
|
|
124
|
+
|
|
125
|
+
def intervals(self):
|
|
126
|
+
r"""
|
|
127
|
+
Return the intervals in self, as a list of 2-tuples.
|
|
128
|
+
|
|
129
|
+
EXAMPLES::
|
|
130
|
+
|
|
131
|
+
sage: from sage.schemes.elliptic_curves.height import UnionOfIntervals
|
|
132
|
+
sage: UnionOfIntervals(list(range(10))).intervals()
|
|
133
|
+
[(0, 1), (2, 3), (4, 5), (6, 7), (8, 9)]
|
|
134
|
+
sage: UnionOfIntervals([-infinity, pi, 17, infinity]).intervals() # needs sage.symbolic
|
|
135
|
+
[(-Infinity, pi), (17, +Infinity)]
|
|
136
|
+
"""
|
|
137
|
+
return list(zip(self._endpoints[::2], self._endpoints[1::2]))
|
|
138
|
+
|
|
139
|
+
def is_empty(self):
|
|
140
|
+
r"""
|
|
141
|
+
Return whether ``self`` is empty.
|
|
142
|
+
|
|
143
|
+
EXAMPLES::
|
|
144
|
+
|
|
145
|
+
sage: from sage.schemes.elliptic_curves.height import UnionOfIntervals
|
|
146
|
+
sage: UnionOfIntervals([3, 4]).is_empty()
|
|
147
|
+
False
|
|
148
|
+
sage: all = UnionOfIntervals([-infinity, infinity])
|
|
149
|
+
sage: all.is_empty()
|
|
150
|
+
False
|
|
151
|
+
sage: (~all).is_empty()
|
|
152
|
+
True
|
|
153
|
+
sage: A = UnionOfIntervals([0, 1]) & UnionOfIntervals([2, 3])
|
|
154
|
+
sage: A.is_empty()
|
|
155
|
+
True
|
|
156
|
+
"""
|
|
157
|
+
return not self._endpoints
|
|
158
|
+
|
|
159
|
+
def __add__(left, right):
|
|
160
|
+
r"""
|
|
161
|
+
If both left and right are unions of intervals, take their union,
|
|
162
|
+
otherwise treat the non-union of intervals as a scalar and shift.
|
|
163
|
+
|
|
164
|
+
EXAMPLES::
|
|
165
|
+
|
|
166
|
+
sage: from sage.schemes.elliptic_curves.height import UnionOfIntervals
|
|
167
|
+
sage: A = UnionOfIntervals([0, 1/2, 2, infinity]); A
|
|
168
|
+
([0, 1/2] U [2, +Infinity])
|
|
169
|
+
sage: A + 1
|
|
170
|
+
([1, 3/2] U [3, +Infinity])
|
|
171
|
+
sage: pi + A # needs sage.symbolic
|
|
172
|
+
([pi, pi + 1/2] U [pi + 2, +Infinity])
|
|
173
|
+
sage: A + UnionOfIntervals([-infinity, -1])
|
|
174
|
+
([-Infinity, -1] U [0, 1/2] U [2, +Infinity])
|
|
175
|
+
"""
|
|
176
|
+
if not isinstance(left, UnionOfIntervals):
|
|
177
|
+
left, right = right, left
|
|
178
|
+
elif not isinstance(right, UnionOfIntervals):
|
|
179
|
+
return UnionOfIntervals([right + e for e in left._endpoints])
|
|
180
|
+
else:
|
|
181
|
+
return left.union([left, right])
|
|
182
|
+
|
|
183
|
+
def __mul__(left, right):
|
|
184
|
+
r"""
|
|
185
|
+
Scale a union of intervals on the left or right.
|
|
186
|
+
|
|
187
|
+
EXAMPLES::
|
|
188
|
+
|
|
189
|
+
sage: from sage.schemes.elliptic_curves.height import UnionOfIntervals
|
|
190
|
+
sage: A = UnionOfIntervals([0, 1/2, 2, infinity]); A
|
|
191
|
+
([0, 1/2] U [2, +Infinity])
|
|
192
|
+
sage: 2 * A
|
|
193
|
+
([0, 1] U [4, +Infinity])
|
|
194
|
+
sage: A * 100
|
|
195
|
+
([0, 50] U [200, +Infinity])
|
|
196
|
+
sage: 1.5 * A
|
|
197
|
+
([0.000000000000000, 0.750000000000000] U [3.00000000000000, +Infinity])
|
|
198
|
+
"""
|
|
199
|
+
if not isinstance(right, UnionOfIntervals):
|
|
200
|
+
return UnionOfIntervals([e*right for e in left._endpoints])
|
|
201
|
+
elif not isinstance(left, UnionOfIntervals):
|
|
202
|
+
return UnionOfIntervals([left*e for e in right._endpoints])
|
|
203
|
+
else:
|
|
204
|
+
return NotImplemented
|
|
205
|
+
|
|
206
|
+
def __rmul__(self, other):
|
|
207
|
+
r"""
|
|
208
|
+
Scale by an operand on the left.
|
|
209
|
+
|
|
210
|
+
TESTS::
|
|
211
|
+
|
|
212
|
+
sage: from sage.schemes.elliptic_curves.height import UnionOfIntervals
|
|
213
|
+
sage: A = UnionOfIntervals([0, 1/2, 2, infinity]); A
|
|
214
|
+
([0, 1/2] U [2, +Infinity])
|
|
215
|
+
sage: pi * A # needs sage.symbolic
|
|
216
|
+
([0, 1/2*pi] U [2*pi, +Infinity])
|
|
217
|
+
"""
|
|
218
|
+
return self * other
|
|
219
|
+
|
|
220
|
+
def __radd__(self, other):
|
|
221
|
+
r"""
|
|
222
|
+
Add a scalar operand on the left.
|
|
223
|
+
|
|
224
|
+
TESTS::
|
|
225
|
+
|
|
226
|
+
sage: from sage.schemes.elliptic_curves.height import UnionOfIntervals
|
|
227
|
+
sage: A = UnionOfIntervals([0, 1/2, 2, infinity]); A
|
|
228
|
+
([0, 1/2] U [2, +Infinity])
|
|
229
|
+
sage: 100 + A
|
|
230
|
+
([100, 201/2] U [102, +Infinity])
|
|
231
|
+
"""
|
|
232
|
+
return self + other
|
|
233
|
+
|
|
234
|
+
def __invert__(self):
|
|
235
|
+
r"""
|
|
236
|
+
Return the closure of the complement of ``self``.
|
|
237
|
+
|
|
238
|
+
.. NOTE::
|
|
239
|
+
|
|
240
|
+
We take the closure because open intervals are not supported.
|
|
241
|
+
|
|
242
|
+
EXAMPLES::
|
|
243
|
+
|
|
244
|
+
sage: from sage.schemes.elliptic_curves.height import UnionOfIntervals
|
|
245
|
+
sage: A = UnionOfIntervals([0, 1/2, 2, infinity]); A
|
|
246
|
+
([0, 1/2] U [2, +Infinity])
|
|
247
|
+
sage: ~A
|
|
248
|
+
([-Infinity, 0] U [1/2, 2])
|
|
249
|
+
sage: A | ~A
|
|
250
|
+
([-Infinity, +Infinity])
|
|
251
|
+
sage: A & ~A
|
|
252
|
+
([0, 0] U [1/2, 1/2] U [2, 2])
|
|
253
|
+
"""
|
|
254
|
+
endpoints = list(self._endpoints)
|
|
255
|
+
if endpoints[0] == -infinity:
|
|
256
|
+
del endpoints[0]
|
|
257
|
+
else:
|
|
258
|
+
endpoints.insert(0, -infinity)
|
|
259
|
+
if endpoints[-1] == infinity:
|
|
260
|
+
endpoints.pop()
|
|
261
|
+
else:
|
|
262
|
+
endpoints.append(infinity)
|
|
263
|
+
return UnionOfIntervals(endpoints)
|
|
264
|
+
|
|
265
|
+
@staticmethod
|
|
266
|
+
def join(L, condition):
|
|
267
|
+
r"""
|
|
268
|
+
Utility function to form the union or intersection of a list of UnionOfIntervals.
|
|
269
|
+
|
|
270
|
+
INPUT:
|
|
271
|
+
|
|
272
|
+
- ``L`` -- list of UnionOfIntervals instances
|
|
273
|
+
|
|
274
|
+
- ``condition`` -- function; either ``any`` or ``all``, or
|
|
275
|
+
some other boolean function of a list of boolean values
|
|
276
|
+
|
|
277
|
+
OUTPUT:
|
|
278
|
+
|
|
279
|
+
A new UnionOfIntervals instance representing the subset of
|
|
280
|
+
'\RR' equal to those reals in any/all/condition of the
|
|
281
|
+
UnionOfIntervals in the list.
|
|
282
|
+
|
|
283
|
+
.. NOTE::
|
|
284
|
+
|
|
285
|
+
This is a static method for the class.
|
|
286
|
+
|
|
287
|
+
EXAMPLES::
|
|
288
|
+
|
|
289
|
+
sage: from sage.schemes.elliptic_curves.height import UnionOfIntervals
|
|
290
|
+
sage: A = UnionOfIntervals([1,3,5,7]); A
|
|
291
|
+
([1, 3] U [5, 7])
|
|
292
|
+
sage: B = A + 1; B
|
|
293
|
+
([2, 4] U [6, 8])
|
|
294
|
+
sage: A.join([A,B], any) # union
|
|
295
|
+
([1, 4] U [5, 8])
|
|
296
|
+
sage: A.join([A,B], all) # intersection
|
|
297
|
+
([2, 3] U [6, 7])
|
|
298
|
+
sage: A.join([A,B], sum) # symmetric difference
|
|
299
|
+
([1, 2] U [3, 4] U [5, 6] U [7, 8])
|
|
300
|
+
"""
|
|
301
|
+
all = []
|
|
302
|
+
for ix, region in enumerate(L):
|
|
303
|
+
for i, e in enumerate(region._endpoints):
|
|
304
|
+
all.append((e, -(not (i % 2)), ix))
|
|
305
|
+
all.sort()
|
|
306
|
+
join = []
|
|
307
|
+
in_join = False
|
|
308
|
+
in_L = [False] * len(L)
|
|
309
|
+
for e, start, ix in all:
|
|
310
|
+
in_L[ix] = start
|
|
311
|
+
if condition(in_L) != in_join:
|
|
312
|
+
join.append(e)
|
|
313
|
+
in_join = not in_join
|
|
314
|
+
return UnionOfIntervals(join)
|
|
315
|
+
|
|
316
|
+
@classmethod
|
|
317
|
+
def union(cls, L):
|
|
318
|
+
r"""
|
|
319
|
+
Return the union of a list of UnionOfIntervals.
|
|
320
|
+
|
|
321
|
+
INPUT:
|
|
322
|
+
|
|
323
|
+
- ``L`` -- list of UnionOfIntervals instances
|
|
324
|
+
|
|
325
|
+
OUTPUT:
|
|
326
|
+
|
|
327
|
+
A new UnionOfIntervals instance representing the union of the
|
|
328
|
+
UnionOfIntervals in the list.
|
|
329
|
+
|
|
330
|
+
.. NOTE::
|
|
331
|
+
|
|
332
|
+
This is a class method.
|
|
333
|
+
|
|
334
|
+
EXAMPLES::
|
|
335
|
+
|
|
336
|
+
sage: from sage.schemes.elliptic_curves.height import UnionOfIntervals
|
|
337
|
+
sage: A = UnionOfIntervals([1,3,5,7]); A
|
|
338
|
+
([1, 3] U [5, 7])
|
|
339
|
+
sage: B = A + 1; B
|
|
340
|
+
([2, 4] U [6, 8])
|
|
341
|
+
sage: A.union([A,B])
|
|
342
|
+
([1, 4] U [5, 8])
|
|
343
|
+
"""
|
|
344
|
+
return cls.join(L, any)
|
|
345
|
+
|
|
346
|
+
@classmethod
|
|
347
|
+
def intersection(cls, L):
|
|
348
|
+
r"""
|
|
349
|
+
Return the intersection of a list of UnionOfIntervals.
|
|
350
|
+
|
|
351
|
+
INPUT:
|
|
352
|
+
|
|
353
|
+
- ``L`` -- list of UnionOfIntervals instances
|
|
354
|
+
|
|
355
|
+
OUTPUT:
|
|
356
|
+
|
|
357
|
+
A new UnionOfIntervals instance representing the intersection
|
|
358
|
+
of the UnionOfIntervals in the list.
|
|
359
|
+
|
|
360
|
+
.. NOTE::
|
|
361
|
+
|
|
362
|
+
This is a class method.
|
|
363
|
+
|
|
364
|
+
EXAMPLES::
|
|
365
|
+
|
|
366
|
+
sage: from sage.schemes.elliptic_curves.height import UnionOfIntervals
|
|
367
|
+
sage: A = UnionOfIntervals([1,3,5,7]); A
|
|
368
|
+
([1, 3] U [5, 7])
|
|
369
|
+
sage: B = A + 1; B
|
|
370
|
+
([2, 4] U [6, 8])
|
|
371
|
+
sage: A.intersection([A,B])
|
|
372
|
+
([2, 3] U [6, 7])
|
|
373
|
+
"""
|
|
374
|
+
for R in L:
|
|
375
|
+
if R.is_empty():
|
|
376
|
+
return R
|
|
377
|
+
return cls.join(L, all)
|
|
378
|
+
|
|
379
|
+
def __or__(left, right):
|
|
380
|
+
r"""
|
|
381
|
+
Return the union of a two UnionOfIntervals instances.
|
|
382
|
+
|
|
383
|
+
INPUT:
|
|
384
|
+
|
|
385
|
+
- ``left``, ``right`` -- two UnionOfIntervals instances
|
|
386
|
+
|
|
387
|
+
OUTPUT: a new UnionOfIntervals instance representing the union of ``left`` and ``right``
|
|
388
|
+
|
|
389
|
+
EXAMPLES::
|
|
390
|
+
|
|
391
|
+
sage: from sage.schemes.elliptic_curves.height import UnionOfIntervals
|
|
392
|
+
sage: A = UnionOfIntervals([1,3,5,7]); A
|
|
393
|
+
([1, 3] U [5, 7])
|
|
394
|
+
sage: B = A + 1; B
|
|
395
|
+
([2, 4] U [6, 8])
|
|
396
|
+
sage: A | B
|
|
397
|
+
([1, 4] U [5, 8])
|
|
398
|
+
"""
|
|
399
|
+
return left.union([left, right])
|
|
400
|
+
|
|
401
|
+
def __and__(left, right):
|
|
402
|
+
r"""
|
|
403
|
+
Return the intersection of a two UnionOfIntervals instances.
|
|
404
|
+
|
|
405
|
+
INPUT:
|
|
406
|
+
|
|
407
|
+
- ``left``, ``right`` -- two UnionOfIntervals instances
|
|
408
|
+
|
|
409
|
+
OUTPUT: a new UnionOfIntervals instance representing the intersection of ``left`` and ``right``
|
|
410
|
+
|
|
411
|
+
EXAMPLES::
|
|
412
|
+
|
|
413
|
+
sage: from sage.schemes.elliptic_curves.height import UnionOfIntervals
|
|
414
|
+
sage: A = UnionOfIntervals([1,3,5,7]); A
|
|
415
|
+
([1, 3] U [5, 7])
|
|
416
|
+
sage: B = A + 1; B
|
|
417
|
+
([2, 4] U [6, 8])
|
|
418
|
+
sage: A & B
|
|
419
|
+
([2, 3] U [6, 7])
|
|
420
|
+
"""
|
|
421
|
+
return left.intersection([left, right])
|
|
422
|
+
|
|
423
|
+
def __contains__(self, x):
|
|
424
|
+
r"""
|
|
425
|
+
Return ``True`` if ``x`` is in the UnionOfIntervals.
|
|
426
|
+
|
|
427
|
+
INPUT:
|
|
428
|
+
|
|
429
|
+
- ``x`` -- real number
|
|
430
|
+
|
|
431
|
+
OUTPUT: boolean; ``True`` if and only if `x` is in the union of intervals
|
|
432
|
+
|
|
433
|
+
EXAMPLES::
|
|
434
|
+
|
|
435
|
+
sage: from sage.schemes.elliptic_curves.height import UnionOfIntervals
|
|
436
|
+
sage: A = UnionOfIntervals([1,3,5,7]); A
|
|
437
|
+
([1, 3] U [5, 7])
|
|
438
|
+
sage: 1 in A
|
|
439
|
+
True
|
|
440
|
+
sage: 4 in A
|
|
441
|
+
False
|
|
442
|
+
sage: -infinity in A
|
|
443
|
+
False
|
|
444
|
+
"""
|
|
445
|
+
return x in self._endpoints or bisect.bisect_left(self._endpoints, x) % 2 == 1
|
|
446
|
+
|
|
447
|
+
def __str__(self):
|
|
448
|
+
r"""
|
|
449
|
+
Return the string representation of this UnionOfIntervals.
|
|
450
|
+
|
|
451
|
+
EXAMPLES::
|
|
452
|
+
|
|
453
|
+
sage: from sage.schemes.elliptic_curves.height import UnionOfIntervals
|
|
454
|
+
sage: A = UnionOfIntervals([1,3,5,7])
|
|
455
|
+
sage: str(A)
|
|
456
|
+
'([1, 3] U [5, 7])'
|
|
457
|
+
"""
|
|
458
|
+
return repr(self)
|
|
459
|
+
|
|
460
|
+
def __repr__(self):
|
|
461
|
+
r"""
|
|
462
|
+
Return the string representation of this UnionOfIntervals.
|
|
463
|
+
|
|
464
|
+
EXAMPLES::
|
|
465
|
+
|
|
466
|
+
sage: from sage.schemes.elliptic_curves.height import UnionOfIntervals
|
|
467
|
+
sage: A = UnionOfIntervals([1,3,5,7]); A
|
|
468
|
+
([1, 3] U [5, 7])
|
|
469
|
+
"""
|
|
470
|
+
return "(%s)" % " U ".join(str(list(I)) for I in self.intervals())
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
def nonneg_region(f):
|
|
474
|
+
r"""
|
|
475
|
+
Return the UnionOfIntervals representing the region where ``f`` is nonnegative.
|
|
476
|
+
|
|
477
|
+
INPUT:
|
|
478
|
+
|
|
479
|
+
- ``f`` -- a univariate polynomial over `\RR`
|
|
480
|
+
|
|
481
|
+
OUTPUT:
|
|
482
|
+
|
|
483
|
+
A UnionOfIntervals representing the set `\{x \in\RR mid f(x) \ge 0\}`.
|
|
484
|
+
|
|
485
|
+
EXAMPLES::
|
|
486
|
+
|
|
487
|
+
sage: from sage.schemes.elliptic_curves.height import nonneg_region
|
|
488
|
+
sage: x = polygen(RR)
|
|
489
|
+
sage: nonneg_region(x^2 - 1)
|
|
490
|
+
([-Infinity, -1.00000000000000] U [1.00000000000000, +Infinity])
|
|
491
|
+
sage: nonneg_region(1 - x^2)
|
|
492
|
+
([-1.00000000000000, 1.00000000000000])
|
|
493
|
+
sage: nonneg_region(1 - x^3)
|
|
494
|
+
([-Infinity, 1.00000000000000])
|
|
495
|
+
sage: nonneg_region(x^3 - 1)
|
|
496
|
+
([1.00000000000000, +Infinity])
|
|
497
|
+
sage: nonneg_region((x-1)*(x-2))
|
|
498
|
+
([-Infinity, 1.00000000000000] U [2.00000000000000, +Infinity])
|
|
499
|
+
sage: nonneg_region(-(x-1)*(x-2))
|
|
500
|
+
([1.00000000000000, 2.00000000000000])
|
|
501
|
+
sage: nonneg_region((x-1)*(x-2)*(x-3))
|
|
502
|
+
([1.00000000000000, 2.00000000000000] U [3.00000000000000, +Infinity])
|
|
503
|
+
sage: nonneg_region(-(x-1)*(x-2)*(x-3))
|
|
504
|
+
([-Infinity, 1.00000000000000] U [2.00000000000000, 3.00000000000000])
|
|
505
|
+
sage: nonneg_region(x^4 + 1)
|
|
506
|
+
([-Infinity, +Infinity])
|
|
507
|
+
sage: nonneg_region(-x^4 - 1)
|
|
508
|
+
()
|
|
509
|
+
"""
|
|
510
|
+
roots = sorted(f.roots())
|
|
511
|
+
sign_changes = [r for r,e in roots if e % 2 == 1]
|
|
512
|
+
if (f.leading_coefficient() * (-1)**f.degree()) > 0:
|
|
513
|
+
sign_changes = [-infinity] + sign_changes
|
|
514
|
+
if f.leading_coefficient() > 0:
|
|
515
|
+
sign_changes += [infinity]
|
|
516
|
+
return UnionOfIntervals(sign_changes)
|
|
517
|
+
|
|
518
|
+
|
|
519
|
+
def inf_max_abs(f, g, D):
|
|
520
|
+
r"""
|
|
521
|
+
Return `\inf_D(\max(|f|, |g|))`.
|
|
522
|
+
|
|
523
|
+
INPUT:
|
|
524
|
+
|
|
525
|
+
- ``f``, ``g`` -- real univariate polynomials
|
|
526
|
+
|
|
527
|
+
- ``D`` -- :class:`UnionOfIntervals`; a subset of `\RR`
|
|
528
|
+
|
|
529
|
+
OUTPUT:
|
|
530
|
+
|
|
531
|
+
A real number approximating the value of `\inf_D(\max(|f|, |g|))`.
|
|
532
|
+
|
|
533
|
+
ALGORITHM:
|
|
534
|
+
|
|
535
|
+
The extreme values must occur at an endpoint of a subinterval of
|
|
536
|
+
`D` or at a point where one of `f`, `f'`, `g`, `g'`, `f\pm g` is
|
|
537
|
+
zero.
|
|
538
|
+
|
|
539
|
+
EXAMPLES::
|
|
540
|
+
|
|
541
|
+
sage: from sage.schemes.elliptic_curves.height import inf_max_abs, UnionOfIntervals
|
|
542
|
+
sage: x = polygen(RR)
|
|
543
|
+
sage: f = (x-10)^4 + 1
|
|
544
|
+
sage: g = 2*x^3 + 100
|
|
545
|
+
sage: inf_max_abs(f, g, UnionOfIntervals([1,2,3,4,5,6]))
|
|
546
|
+
425.638201706391
|
|
547
|
+
sage: r0 = (f - g).roots()[0][0]
|
|
548
|
+
sage: r0
|
|
549
|
+
5.46053402234697
|
|
550
|
+
sage: max(abs(f(r0)), abs(g(r0)))
|
|
551
|
+
425.638201706391
|
|
552
|
+
"""
|
|
553
|
+
xs = f.roots() + f.derivative().roots()
|
|
554
|
+
xs += g.roots() + g.derivative().roots()
|
|
555
|
+
xs += (f - g).roots() + (f + g).roots()
|
|
556
|
+
xs = [r for r, _ in xs if r in D] # ignore multiplicities and points outside D
|
|
557
|
+
xs += D.finite_endpoints() # include endpoints of intervals
|
|
558
|
+
if xs:
|
|
559
|
+
return min(max(abs(f(r)), abs(g(r))) for r in xs)
|
|
560
|
+
return infinity
|
|
561
|
+
|
|
562
|
+
|
|
563
|
+
def min_on_disk(f, tol, max_iter=10000):
|
|
564
|
+
r"""
|
|
565
|
+
Return the minimum of a real-valued complex function on a square.
|
|
566
|
+
|
|
567
|
+
INPUT:
|
|
568
|
+
|
|
569
|
+
- ``f`` -- a function from CIF to RIF
|
|
570
|
+
|
|
571
|
+
- ``tol`` -- a positive real number
|
|
572
|
+
|
|
573
|
+
- ``max_iter`` -- integer (default: 10000); a positive integer
|
|
574
|
+
bounding the number of iterations to be used
|
|
575
|
+
|
|
576
|
+
OUTPUT:
|
|
577
|
+
|
|
578
|
+
A 2-tuple `(s,t)`, where `t=f(s)` and `s` is a CIF element
|
|
579
|
+
contained in the disk `|z|\le1`, at which `f` takes its minimum
|
|
580
|
+
value.
|
|
581
|
+
|
|
582
|
+
EXAMPLES::
|
|
583
|
+
|
|
584
|
+
sage: from sage.schemes.elliptic_curves.height import min_on_disk
|
|
585
|
+
sage: f = lambda x: (x^2 + 100).abs()
|
|
586
|
+
sage: s, t = min_on_disk(f, 0.0001)
|
|
587
|
+
sage: s, f(s), t
|
|
588
|
+
(0.01? + 1.00?*I, 99.01?, 99.0000000000000)
|
|
589
|
+
"""
|
|
590
|
+
# L holds a list of 4-tuples (mfs, ds, s, in_disk) where s is a
|
|
591
|
+
# subregion of the initial square, ds its relative diameter,
|
|
592
|
+
# mfs=-f(s) (actually minus the lower bound on f(s)) and in_disk
|
|
593
|
+
# is a flag indicating whether or not s is a subset of the unit
|
|
594
|
+
# disk.
|
|
595
|
+
|
|
596
|
+
# We store the negative of the lower bound on f(s) so that we can
|
|
597
|
+
# use the bisect module to sort these 4-tuples.
|
|
598
|
+
|
|
599
|
+
# Initially L contains one element, the whole unit box, which is
|
|
600
|
+
# not contained in the unit square.
|
|
601
|
+
|
|
602
|
+
s = CIF(RIF(-1,1), RIF(-1,1))
|
|
603
|
+
fs = f(s)
|
|
604
|
+
L = [(-fs.lower(), fs.relative_diameter(), s, False)]
|
|
605
|
+
|
|
606
|
+
# min_max holds the minimum over L of fs.upper().
|
|
607
|
+
|
|
608
|
+
min_max = fs.upper()
|
|
609
|
+
|
|
610
|
+
# We iterate at most max_iter times. At each step we look at the
|
|
611
|
+
# best so far and return it if is good enough, meaning that its
|
|
612
|
+
# relative diameter is less than the given tolerance; otherwise we
|
|
613
|
+
# bisect this best region (into 4 pieces) and replace the entry in
|
|
614
|
+
# L with at most 4 smaller entries.
|
|
615
|
+
|
|
616
|
+
for k in range(max_iter):
|
|
617
|
+
value, err, region, in_disk = L.pop()
|
|
618
|
+
if err < tol: # reached desired tolerance, so return
|
|
619
|
+
return region, -value
|
|
620
|
+
for s in region.bisection(): # 4 sub-regions
|
|
621
|
+
if in_disk:
|
|
622
|
+
s_in_disk = True # if the original region si in the disk so are all its children
|
|
623
|
+
else:
|
|
624
|
+
r = abs(s) # otherwise we test each one
|
|
625
|
+
if r > 1:
|
|
626
|
+
continue # skip this subregion if it is entirely outside the disk
|
|
627
|
+
s_in_disk = r < 1 # meaning it is entirely inside the disk
|
|
628
|
+
|
|
629
|
+
fs = f(s)
|
|
630
|
+
|
|
631
|
+
if fs.upper() < min_max: # we definitely beat the record
|
|
632
|
+
min_max = fs.upper()
|
|
633
|
+
unneeded = bisect.bisect(L, (-min_max,))
|
|
634
|
+
if unneeded > 100: # discard the worse entries (if there are many)
|
|
635
|
+
L = L[unneeded:]
|
|
636
|
+
|
|
637
|
+
if fs.lower() < min_max: # we may beat the record, cannot yet tell: insert this region
|
|
638
|
+
# into the list at the appropriate place to maintain sorting
|
|
639
|
+
bisect.insort(L, (-fs.lower(), fs.relative_diameter(), s, s_in_disk))
|
|
640
|
+
|
|
641
|
+
# If we get here, then even after max_iter iterations the tolerance has not been reached.
|
|
642
|
+
raise ValueError("too many iterations")
|
|
643
|
+
|
|
644
|
+
|
|
645
|
+
two_pi_i_CDF = CDF(0, 2 * RDF.pi())
|
|
646
|
+
two_pi_i_CIF = CIF(0, 2 * RIF.pi())
|
|
647
|
+
|
|
648
|
+
# Ideas: We know tau, so we know the direction of the diagonal.
|
|
649
|
+
# We can solve for x in p1, will this allow us to find the maxima exactly?
|
|
650
|
+
|
|
651
|
+
|
|
652
|
+
def rat_term_CIF(z, try_strict=True):
|
|
653
|
+
r"""
|
|
654
|
+
Compute the value of `u/(1-u)^2` in ``CIF``, where `u=\exp(2\pi i z)`.
|
|
655
|
+
|
|
656
|
+
INPUT:
|
|
657
|
+
|
|
658
|
+
- ``z`` -- complex; a CIF element
|
|
659
|
+
|
|
660
|
+
- ``try_strict`` -- boolean; flag
|
|
661
|
+
|
|
662
|
+
EXAMPLES::
|
|
663
|
+
|
|
664
|
+
sage: from sage.schemes.elliptic_curves.height import rat_term_CIF
|
|
665
|
+
sage: z = CIF(0.5,0.2)
|
|
666
|
+
sage: rat_term_CIF(z)
|
|
667
|
+
-0.172467461182437? + 0.?e-16*I
|
|
668
|
+
sage: rat_term_CIF(z, False)
|
|
669
|
+
-0.172467461182437? + 0.?e-16*I
|
|
670
|
+
"""
|
|
671
|
+
two_pi_i_z = two_pi_i_CIF * z
|
|
672
|
+
r = (two_pi_i_z.real()).exp() # = |u|
|
|
673
|
+
x, y = two_pi_i_z.imag().cos(), two_pi_i_z.imag().sin()
|
|
674
|
+
|
|
675
|
+
real_part = imag_part = None
|
|
676
|
+
|
|
677
|
+
# If there are no local minima the intervals are strictly
|
|
678
|
+
# determined by their values at the endpoints.
|
|
679
|
+
|
|
680
|
+
if try_strict:
|
|
681
|
+
|
|
682
|
+
# evaluate the function at the four corners:
|
|
683
|
+
|
|
684
|
+
corner_reals = []
|
|
685
|
+
corner_imags = []
|
|
686
|
+
for a, b in product(z.real().endpoints(), z.imag().endpoints()):
|
|
687
|
+
zz = CDF(a,b)
|
|
688
|
+
u = (two_pi_i_CDF*zz).exp()
|
|
689
|
+
f = u/(1-u)**2
|
|
690
|
+
corner_reals.append(f.real())
|
|
691
|
+
corner_imags.append(f.imag())
|
|
692
|
+
|
|
693
|
+
p1 = (((((r+2*x)*r - 6)*r + 2*x) * r) + 1)
|
|
694
|
+
# = r^4 + 2*r^3*x - 6*r^2 + 2*r*x + 1
|
|
695
|
+
p2 = (r*(x*(r+2*x)-4)+x)
|
|
696
|
+
# = r^2*x + 2*r*x^2 - 4*r + x
|
|
697
|
+
|
|
698
|
+
df_dr = (r**2-1) * p2
|
|
699
|
+
dg_dr = p1 * y
|
|
700
|
+
dg_dx = r * df_dr / y
|
|
701
|
+
|
|
702
|
+
if not dg_dr.contains_zero() or not dg_dx.contains_zero():
|
|
703
|
+
real_part = RIF(min(corner_reals), max(corner_reals))
|
|
704
|
+
|
|
705
|
+
if not dg_dr.contains_zero() or not dg_dx.contains_zero():
|
|
706
|
+
imag_part = RIF(min(corner_imags), max(corner_imags))
|
|
707
|
+
|
|
708
|
+
if real_part is None or imag_part is None:
|
|
709
|
+
denom = (1-r*(2*x-r))**2
|
|
710
|
+
if real_part is None:
|
|
711
|
+
real_part = r*(x*(1+r**2)-2*r)/denom
|
|
712
|
+
if imag_part is None:
|
|
713
|
+
imag_part = -(r**2-1)*y*r/denom
|
|
714
|
+
|
|
715
|
+
return CIF(real_part, imag_part)
|
|
716
|
+
|
|
717
|
+
|
|
718
|
+
def eps(err, is_real):
|
|
719
|
+
r"""
|
|
720
|
+
Return a Real or Complex interval centered on 0 with radius err.
|
|
721
|
+
|
|
722
|
+
INPUT:
|
|
723
|
+
|
|
724
|
+
- ``err`` -- a positive real number; the radius of the interval
|
|
725
|
+
|
|
726
|
+
- ``is_real`` -- boolean; if ``True``, returns a real interval in
|
|
727
|
+
RIF, else a complex interval in CIF
|
|
728
|
+
|
|
729
|
+
OUTPUT:
|
|
730
|
+
|
|
731
|
+
An element of RIF or CIF (as specified), centered on 0, with given radius.
|
|
732
|
+
|
|
733
|
+
EXAMPLES::
|
|
734
|
+
|
|
735
|
+
sage: from sage.schemes.elliptic_curves.height import eps
|
|
736
|
+
sage: eps(0.01, True)
|
|
737
|
+
0.0?
|
|
738
|
+
sage: eps(0.01, False)
|
|
739
|
+
0.0? + 0.0?*I
|
|
740
|
+
"""
|
|
741
|
+
e = RIF(-err, err)
|
|
742
|
+
if is_real:
|
|
743
|
+
return e
|
|
744
|
+
else:
|
|
745
|
+
return CIF(e, e)
|
|
746
|
+
|
|
747
|
+
|
|
748
|
+
class EllipticCurveCanonicalHeight:
|
|
749
|
+
r"""
|
|
750
|
+
Class for computing canonical heights of points on elliptic curves
|
|
751
|
+
defined over number fields, including rigorous lower bounds for
|
|
752
|
+
the canonical height of non-torsion points.
|
|
753
|
+
|
|
754
|
+
EXAMPLES::
|
|
755
|
+
|
|
756
|
+
sage: from sage.schemes.elliptic_curves.height import EllipticCurveCanonicalHeight
|
|
757
|
+
sage: E = EllipticCurve([0,0,0,0,1])
|
|
758
|
+
sage: EllipticCurveCanonicalHeight(E)
|
|
759
|
+
EllipticCurveCanonicalHeight object associated to
|
|
760
|
+
Elliptic Curve defined by y^2 = x^3 + 1 over Rational Field
|
|
761
|
+
|
|
762
|
+
Normally this object would be created like this::
|
|
763
|
+
|
|
764
|
+
sage: E.height_function()
|
|
765
|
+
EllipticCurveCanonicalHeight object associated to
|
|
766
|
+
Elliptic Curve defined by y^2 = x^3 + 1 over Rational Field
|
|
767
|
+
"""
|
|
768
|
+
|
|
769
|
+
def __init__(self, E):
|
|
770
|
+
r"""
|
|
771
|
+
Initialize the class with an elliptic curve.
|
|
772
|
+
|
|
773
|
+
INPUT:
|
|
774
|
+
|
|
775
|
+
- ``E`` -- an elliptic curve defined over a number field
|
|
776
|
+
|
|
777
|
+
EXAMPLES::
|
|
778
|
+
|
|
779
|
+
sage: from sage.schemes.elliptic_curves.height import EllipticCurveCanonicalHeight
|
|
780
|
+
sage: E = EllipticCurve([0,0,0,0,1])
|
|
781
|
+
sage: EllipticCurveCanonicalHeight(E)
|
|
782
|
+
EllipticCurveCanonicalHeight object associated to
|
|
783
|
+
Elliptic Curve defined by y^2 = x^3 + 1 over Rational Field
|
|
784
|
+
|
|
785
|
+
An example over a number field::
|
|
786
|
+
|
|
787
|
+
sage: K.<i> = QuadraticField(-1) # needs sage.rings.number_field
|
|
788
|
+
sage: E = EllipticCurve([0,i,0,i,i]) # needs sage.rings.number_field
|
|
789
|
+
sage: EllipticCurveCanonicalHeight(E) # needs sage.rings.number_field
|
|
790
|
+
EllipticCurveCanonicalHeight object associated to
|
|
791
|
+
Elliptic Curve defined by y^2 = x^3 + i*x^2 + i*x + i
|
|
792
|
+
over Number Field in i with defining polynomial x^2 + 1 with i = 1*I
|
|
793
|
+
|
|
794
|
+
TESTS:
|
|
795
|
+
|
|
796
|
+
The base field must be a number field (or `\QQ`)::
|
|
797
|
+
|
|
798
|
+
sage: from sage.schemes.elliptic_curves.height import EllipticCurveCanonicalHeight
|
|
799
|
+
sage: E = EllipticCurve(GF(7), [0,0,0,0,1])
|
|
800
|
+
sage: EllipticCurveCanonicalHeight(E)
|
|
801
|
+
Traceback (most recent call last):
|
|
802
|
+
...
|
|
803
|
+
ValueError: EllipticCurveCanonicalHeight class can only be created
|
|
804
|
+
from an elliptic curve defined over a number field
|
|
805
|
+
"""
|
|
806
|
+
from sage.schemes.elliptic_curves.ell_generic import EllipticCurve_generic
|
|
807
|
+
if isinstance(E, EllipticCurve_generic):
|
|
808
|
+
self.E = E
|
|
809
|
+
from sage.rings.number_field.number_field_base import NumberField
|
|
810
|
+
K = E.base_ring()
|
|
811
|
+
if isinstance(K, NumberField):
|
|
812
|
+
self.K = K
|
|
813
|
+
else:
|
|
814
|
+
raise ValueError("EllipticCurveCanonicalHeight class can only be created from an elliptic curve defined over a number field")
|
|
815
|
+
else:
|
|
816
|
+
raise ValueError("EllipticCurveCanonicalHeight class can only be created from an elliptic curve")
|
|
817
|
+
|
|
818
|
+
def __repr__(self):
|
|
819
|
+
r"""
|
|
820
|
+
Return the string representation.
|
|
821
|
+
|
|
822
|
+
EXAMPLES::
|
|
823
|
+
|
|
824
|
+
sage: E = EllipticCurve([0,0,0,0,1])
|
|
825
|
+
sage: E.height_function()
|
|
826
|
+
EllipticCurveCanonicalHeight object associated to
|
|
827
|
+
Elliptic Curve defined by y^2 = x^3 + 1 over Rational Field
|
|
828
|
+
"""
|
|
829
|
+
return "EllipticCurveCanonicalHeight object associated to %s" % self.E
|
|
830
|
+
|
|
831
|
+
def curve(self):
|
|
832
|
+
r"""
|
|
833
|
+
Return the elliptic curve.
|
|
834
|
+
|
|
835
|
+
EXAMPLES::
|
|
836
|
+
|
|
837
|
+
sage: E = EllipticCurve([0,0,0,0,1])
|
|
838
|
+
sage: H = E.height_function()
|
|
839
|
+
sage: H.curve()
|
|
840
|
+
Elliptic Curve defined by y^2 = x^3 + 1 over Rational Field
|
|
841
|
+
"""
|
|
842
|
+
return self.E
|
|
843
|
+
|
|
844
|
+
def base_field(self):
|
|
845
|
+
r"""
|
|
846
|
+
Return the base field.
|
|
847
|
+
|
|
848
|
+
EXAMPLES::
|
|
849
|
+
|
|
850
|
+
sage: E = EllipticCurve([0,0,0,0,1])
|
|
851
|
+
sage: H = E.height_function()
|
|
852
|
+
sage: H.base_field()
|
|
853
|
+
Rational Field
|
|
854
|
+
"""
|
|
855
|
+
return self.K
|
|
856
|
+
|
|
857
|
+
def __call__(self, P):
|
|
858
|
+
r"""
|
|
859
|
+
Return the canonical height of the point ``P``.
|
|
860
|
+
|
|
861
|
+
INPUT:
|
|
862
|
+
|
|
863
|
+
- ``P`` -- a point on the elliptic curve
|
|
864
|
+
|
|
865
|
+
OUTPUT: the canonical height of ``P``
|
|
866
|
+
|
|
867
|
+
EXAMPLES::
|
|
868
|
+
|
|
869
|
+
sage: E = EllipticCurve([0,0,1,-1,0])
|
|
870
|
+
sage: P = E(0,0)
|
|
871
|
+
sage: P.height()
|
|
872
|
+
0.0511114082399688
|
|
873
|
+
sage: H = E.height_function()
|
|
874
|
+
sage: H(P)
|
|
875
|
+
0.0511114082399688
|
|
876
|
+
sage: H([0,0])
|
|
877
|
+
0.0511114082399688
|
|
878
|
+
sage: H((0,0))
|
|
879
|
+
0.0511114082399688
|
|
880
|
+
|
|
881
|
+
Over a number field other than `\QQ`::
|
|
882
|
+
|
|
883
|
+
sage: # needs sage.rings.number_field
|
|
884
|
+
sage: K.<i> = QuadraticField(-1)
|
|
885
|
+
sage: E = EllipticCurve(K, [0,0,0,1,-27])
|
|
886
|
+
sage: H = E.height_function()
|
|
887
|
+
sage: H.base_field()
|
|
888
|
+
Number Field in i with defining polynomial x^2 + 1 with i = 1*I
|
|
889
|
+
sage: H((1, 5*i))
|
|
890
|
+
1.22257115164148
|
|
891
|
+
"""
|
|
892
|
+
return self.E(P).height()
|
|
893
|
+
|
|
894
|
+
@cached_method
|
|
895
|
+
def alpha(self, v, tol=0.01):
|
|
896
|
+
r"""
|
|
897
|
+
Return the constant `\alpha_v` associated to the embedding ``v``.
|
|
898
|
+
|
|
899
|
+
INPUT:
|
|
900
|
+
|
|
901
|
+
- ``v`` -- an embedding of the base field into `\RR` or `\CC`
|
|
902
|
+
|
|
903
|
+
OUTPUT:
|
|
904
|
+
|
|
905
|
+
The constant `\alpha_v`. In the notation of [CPS2006]_ and
|
|
906
|
+
[Tho2010]_ (section 3.2), `\alpha_v^3=\epsilon_v`. The result is
|
|
907
|
+
cached since it only depends on the curve.
|
|
908
|
+
|
|
909
|
+
EXAMPLES:
|
|
910
|
+
|
|
911
|
+
Example 1 from [CPS2006]_::
|
|
912
|
+
|
|
913
|
+
sage: # needs sage.rings.number_field
|
|
914
|
+
sage: K.<i> = QuadraticField(-1)
|
|
915
|
+
sage: E = EllipticCurve([0, 0, 0, 1 + 5*i, 3 + i])
|
|
916
|
+
sage: H = E.height_function()
|
|
917
|
+
sage: alpha = H.alpha(K.places()[0])
|
|
918
|
+
sage: alpha
|
|
919
|
+
1.12272013439355
|
|
920
|
+
|
|
921
|
+
Compare with `\log(\epsilon_v)=0.344562...` in [CPS2006]_::
|
|
922
|
+
|
|
923
|
+
sage: 3*alpha.log() # needs sage.rings.number_field
|
|
924
|
+
0.347263296676126
|
|
925
|
+
"""
|
|
926
|
+
from sage.rings.polynomial.polynomial_ring import polygen
|
|
927
|
+
b2, b4, b6, b8 = (v(b) for b in self.E.b_invariants())
|
|
928
|
+
x = polygen(v.codomain())
|
|
929
|
+
f = 4*x**3 + b2*x**2 + 2*b4*x + b6
|
|
930
|
+
g = x**4 - b4*x**2 - 2*b6*x - b8
|
|
931
|
+
F = f.reverse() << (4-f.degree())
|
|
932
|
+
G = g.reverse() << (4-g.degree())
|
|
933
|
+
|
|
934
|
+
if v(self.K.gen()) in RR:
|
|
935
|
+
I = UnionOfIntervals([-1,1])
|
|
936
|
+
min_fg = inf_max_abs(f, g, nonneg_region(f) & I)
|
|
937
|
+
min_FG = inf_max_abs(F, G, nonneg_region(F) & I)
|
|
938
|
+
return min(min_fg, min_FG) ** (-1/QQ(3))
|
|
939
|
+
|
|
940
|
+
else:
|
|
941
|
+
# def pair_max(f, g):
|
|
942
|
+
# f = f.change_ring(CIF)
|
|
943
|
+
# g = g.change_ring(CIF)
|
|
944
|
+
# max = type(RIF(0)).max
|
|
945
|
+
# def max_f_g(z):
|
|
946
|
+
# return max(abs(f(z)), abs(g(z)))
|
|
947
|
+
# return max_f_g
|
|
948
|
+
def pair_max(f, g):
|
|
949
|
+
f = f.change_ring(CDF)
|
|
950
|
+
g = g.change_ring(CDF)
|
|
951
|
+
dfn = [fast_callable(f.derivative(n)/factorial(n), CDF) for n in range(f.degree()+1)]
|
|
952
|
+
dgn = [fast_callable(g.derivative(n)/factorial(n), CDF) for n in range(g.degree()+1)]
|
|
953
|
+
|
|
954
|
+
def max_f_g(s):
|
|
955
|
+
(a,b), (c,d) = s.real().endpoints(), s.imag().endpoints()
|
|
956
|
+
dx = a - b
|
|
957
|
+
dy = c - d
|
|
958
|
+
eta = RDF(dx*dx + dy*dy).sqrt()
|
|
959
|
+
z = CDF(s.center())
|
|
960
|
+
err_f = sum(eta ** n * abs(df(z)) for n, df in enumerate(dfn) if n)
|
|
961
|
+
err_g = sum(eta ** n * abs(dg(z)) for n, dg in enumerate(dgn) if n)
|
|
962
|
+
return RIF(max(abs(f(z)), abs(g(z)))) + eps(max(err_f, err_g), True)
|
|
963
|
+
return max_f_g
|
|
964
|
+
_, min_fg = min_on_disk(pair_max(f, g), tol)
|
|
965
|
+
_, min_FG = min_on_disk(pair_max(F, G), tol)
|
|
966
|
+
return min(min_fg, min_FG) ** QQ((-1, 3))
|
|
967
|
+
|
|
968
|
+
@cached_method
|
|
969
|
+
def e_p(self, p):
|
|
970
|
+
r"""
|
|
971
|
+
Return the exponent of the group over the residue field at ``p``.
|
|
972
|
+
|
|
973
|
+
INPUT:
|
|
974
|
+
|
|
975
|
+
- ``p`` -- a prime ideal of `K` (or a prime number if `K=\QQ`)
|
|
976
|
+
|
|
977
|
+
OUTPUT:
|
|
978
|
+
|
|
979
|
+
A positive integer `e_p`, the exponent of the group of
|
|
980
|
+
nonsingular points on the reduction of the elliptic curve
|
|
981
|
+
modulo `p`. The result is cached.
|
|
982
|
+
|
|
983
|
+
EXAMPLES::
|
|
984
|
+
|
|
985
|
+
sage: # needs sage.rings.number_field
|
|
986
|
+
sage: K.<i> = QuadraticField(-1)
|
|
987
|
+
sage: E = EllipticCurve([0, 0, 0, 1 + 5*i, 3 + i])
|
|
988
|
+
sage: H = E.height_function()
|
|
989
|
+
sage: H.e_p(K.prime_above(2))
|
|
990
|
+
2
|
|
991
|
+
sage: H.e_p(K.prime_above(3))
|
|
992
|
+
10
|
|
993
|
+
sage: H.e_p(K.prime_above(5))
|
|
994
|
+
9
|
|
995
|
+
sage: E.conductor().norm().factor()
|
|
996
|
+
2^10 * 20921
|
|
997
|
+
sage: p1, p2 = K.primes_above(20921)
|
|
998
|
+
sage: E.local_data(p1)
|
|
999
|
+
Local data at Fractional ideal (-40*i + 139):
|
|
1000
|
+
Reduction type: bad split multiplicative
|
|
1001
|
+
...
|
|
1002
|
+
sage: H.e_p(p1)
|
|
1003
|
+
20920
|
|
1004
|
+
sage: E.local_data(p2)
|
|
1005
|
+
Local data at Fractional ideal (40*i + 139):
|
|
1006
|
+
Reduction type: good
|
|
1007
|
+
...
|
|
1008
|
+
sage: H.e_p(p2)
|
|
1009
|
+
20815
|
|
1010
|
+
"""
|
|
1011
|
+
kp = self.K.residue_field(p)
|
|
1012
|
+
if self.E.has_bad_reduction(p):
|
|
1013
|
+
if self.E.has_additive_reduction(p):
|
|
1014
|
+
ep = kp.characteristic()
|
|
1015
|
+
elif self.E.has_split_multiplicative_reduction(p):
|
|
1016
|
+
ep = len(kp) - 1
|
|
1017
|
+
else:
|
|
1018
|
+
ep = len(kp) + 1
|
|
1019
|
+
else:
|
|
1020
|
+
ep = self.E.reduction(p).abelian_group().exponent()
|
|
1021
|
+
return ZZ(ep)
|
|
1022
|
+
|
|
1023
|
+
@cached_method
|
|
1024
|
+
def DE(self, n):
|
|
1025
|
+
r"""
|
|
1026
|
+
Return the value `D_E(n)`.
|
|
1027
|
+
|
|
1028
|
+
INPUT:
|
|
1029
|
+
|
|
1030
|
+
- ``n`` -- positive integer
|
|
1031
|
+
|
|
1032
|
+
OUTPUT:
|
|
1033
|
+
|
|
1034
|
+
The value `D_E(n)` as defined in [Tho2010]_, section 4.
|
|
1035
|
+
|
|
1036
|
+
EXAMPLES::
|
|
1037
|
+
|
|
1038
|
+
sage: # needs sage.rings.number_field sage.symbolic
|
|
1039
|
+
sage: K.<i> = QuadraticField(-1)
|
|
1040
|
+
sage: E = EllipticCurve([0, 0, 0, 1+5*i, 3+i])
|
|
1041
|
+
sage: H = E.height_function()
|
|
1042
|
+
sage: [H.DE(n) for n in srange(1,6)]
|
|
1043
|
+
[0, 2*log(5) + 2*log(2), 0, 2*log(13) + 2*log(5) + 4*log(2), 0]
|
|
1044
|
+
"""
|
|
1045
|
+
s = 0
|
|
1046
|
+
B = (n+1) ** max(2, self.K.degree())
|
|
1047
|
+
for p in self.K.primes_of_bounded_norm_iter(B):
|
|
1048
|
+
ep = self.e_p(p)
|
|
1049
|
+
if ep.divides(n):
|
|
1050
|
+
kp = self.K.residue_field(p)
|
|
1051
|
+
s += 2*(1+(n/ep).valuation(kp.characteristic())) * log(len(kp))
|
|
1052
|
+
return s
|
|
1053
|
+
|
|
1054
|
+
@cached_method
|
|
1055
|
+
def ME(self):
|
|
1056
|
+
r"""
|
|
1057
|
+
Return the norm of the ideal `M_E`.
|
|
1058
|
+
|
|
1059
|
+
OUTPUT:
|
|
1060
|
+
|
|
1061
|
+
The norm of the ideal `M_E` as defined in [Tho2010]_, section 3.1.
|
|
1062
|
+
This is `1` if `E` is a global minimal model, and in general
|
|
1063
|
+
measures the non-minimality of `E`.
|
|
1064
|
+
|
|
1065
|
+
EXAMPLES::
|
|
1066
|
+
|
|
1067
|
+
sage: K.<i> = QuadraticField(-1) # needs sage.rings.number_field
|
|
1068
|
+
sage: E = EllipticCurve([0, 0, 0, 1+5*i, 3+i]) # needs sage.rings.number_field
|
|
1069
|
+
sage: H = E.height_function() # needs sage.rings.number_field
|
|
1070
|
+
sage: H.ME() # needs sage.rings.number_field
|
|
1071
|
+
1
|
|
1072
|
+
sage: E = EllipticCurve([0,0,0,0,1])
|
|
1073
|
+
sage: E.height_function().ME()
|
|
1074
|
+
1
|
|
1075
|
+
sage: E = EllipticCurve([0,0,0,0,64])
|
|
1076
|
+
sage: E.height_function().ME()
|
|
1077
|
+
4096
|
|
1078
|
+
sage: E.discriminant()/E.minimal_model().discriminant()
|
|
1079
|
+
4096
|
|
1080
|
+
"""
|
|
1081
|
+
from sage.misc.misc_c import prod
|
|
1082
|
+
if self.K is QQ:
|
|
1083
|
+
return prod([p ** (e - self.E.local_data(p).discriminant_valuation()) for p, e in self.E.discriminant().factor()], QQ.one())
|
|
1084
|
+
|
|
1085
|
+
ME = prod([p.norm() ** (e - self.E.local_data(p).discriminant_valuation()) for p, e in self.K.ideal(self.E.discriminant()).factor()], QQ.one())
|
|
1086
|
+
return ME.norm()
|
|
1087
|
+
|
|
1088
|
+
def B(self, n, mu):
|
|
1089
|
+
r"""
|
|
1090
|
+
Return the value `B_n(\mu)`.
|
|
1091
|
+
|
|
1092
|
+
INPUT:
|
|
1093
|
+
|
|
1094
|
+
- ``n`` -- positive integer
|
|
1095
|
+
|
|
1096
|
+
- ``mu`` -- positive real number
|
|
1097
|
+
|
|
1098
|
+
OUTPUT:
|
|
1099
|
+
|
|
1100
|
+
The real value `B_n(\mu)` as defined in [Tho2010]_, section 5.
|
|
1101
|
+
|
|
1102
|
+
EXAMPLES:
|
|
1103
|
+
|
|
1104
|
+
Example 10.2 from [Tho2010]_::
|
|
1105
|
+
|
|
1106
|
+
sage: K.<i> = QuadraticField(-1) # needs sage.rings.number_field
|
|
1107
|
+
sage: E = EllipticCurve([0, 1-i, i, -i, 0]) # needs sage.rings.number_field
|
|
1108
|
+
sage: H = E.height_function() # needs sage.rings.number_field
|
|
1109
|
+
|
|
1110
|
+
In [Tho2010]_ the value is given as 0.772::
|
|
1111
|
+
|
|
1112
|
+
sage: RealField(12)( H.B(5, 0.01) ) # needs sage.rings.number_field sage.symbolic
|
|
1113
|
+
0.777
|
|
1114
|
+
"""
|
|
1115
|
+
K = self.K
|
|
1116
|
+
B = exp(K.degree() * n**2 * mu - RDF(self.DE(n))) / self.ME() ** 6
|
|
1117
|
+
for v in K.places():
|
|
1118
|
+
if v(K.gen()) in RR:
|
|
1119
|
+
B *= self.alpha(v)
|
|
1120
|
+
else:
|
|
1121
|
+
B *= self.alpha(v) ** 2
|
|
1122
|
+
return B
|
|
1123
|
+
|
|
1124
|
+
######################################
|
|
1125
|
+
# Empty real intersection detection. #
|
|
1126
|
+
######################################
|
|
1127
|
+
|
|
1128
|
+
def psi(self, xi, v):
|
|
1129
|
+
r"""
|
|
1130
|
+
Return the normalised elliptic log of a point with this x-coordinate.
|
|
1131
|
+
|
|
1132
|
+
INPUT:
|
|
1133
|
+
|
|
1134
|
+
- ``xi`` -- real; the real x-coordinate of a point on the
|
|
1135
|
+
curve in the connected component with respect to a real
|
|
1136
|
+
embedding
|
|
1137
|
+
|
|
1138
|
+
- ``v`` -- a real embedding of the number field
|
|
1139
|
+
|
|
1140
|
+
OUTPUT:
|
|
1141
|
+
|
|
1142
|
+
A real number in the interval [0.5,1] giving the elliptic
|
|
1143
|
+
logarithm of a point on `E` with `x`-coordinate ``xi``, on the
|
|
1144
|
+
connected component with respect to the embedding `v`, scaled
|
|
1145
|
+
by the real period.
|
|
1146
|
+
|
|
1147
|
+
EXAMPLES:
|
|
1148
|
+
|
|
1149
|
+
An example over `\QQ`::
|
|
1150
|
+
|
|
1151
|
+
sage: E = EllipticCurve('389a')
|
|
1152
|
+
sage: v = QQ.places()[0]
|
|
1153
|
+
sage: L = E.period_lattice(v)
|
|
1154
|
+
sage: P = E.lift_x(10/9)
|
|
1155
|
+
sage: L(P)
|
|
1156
|
+
0.958696500380439
|
|
1157
|
+
sage: L(P) / L.real_period()
|
|
1158
|
+
0.384985810227885
|
|
1159
|
+
sage: H = E.height_function()
|
|
1160
|
+
sage: H.psi(10/9, v)
|
|
1161
|
+
0.615014189772115
|
|
1162
|
+
|
|
1163
|
+
An example over a number field::
|
|
1164
|
+
|
|
1165
|
+
sage: # needs sage.rings.number_field
|
|
1166
|
+
sage: x = polygen(ZZ, 'x')
|
|
1167
|
+
sage: K.<a> = NumberField(x^3 - 2)
|
|
1168
|
+
sage: E = EllipticCurve([0,0,0,0,a])
|
|
1169
|
+
sage: P = E.lift_x(1/3*a^2 + a + 5/3)
|
|
1170
|
+
sage: v = K.real_places()[0]
|
|
1171
|
+
sage: L = E.period_lattice(v)
|
|
1172
|
+
sage: L(P)
|
|
1173
|
+
3.51086196882538
|
|
1174
|
+
sage: L(P) / L.real_period()
|
|
1175
|
+
0.867385122699931
|
|
1176
|
+
sage: xP = v(P.x())
|
|
1177
|
+
sage: H = E.height_function()
|
|
1178
|
+
sage: H.psi(xP, v)
|
|
1179
|
+
0.867385122699931
|
|
1180
|
+
sage: H.psi(1.23, v)
|
|
1181
|
+
0.785854718241495
|
|
1182
|
+
"""
|
|
1183
|
+
if xi > 1e9:
|
|
1184
|
+
return 1
|
|
1185
|
+
L = self.E.period_lattice(v)
|
|
1186
|
+
w1, w2 = L.basis()
|
|
1187
|
+
from sage.schemes.elliptic_curves.constructor import EllipticCurve
|
|
1188
|
+
ER = EllipticCurve([v(ai) for ai in self.E.a_invariants()])
|
|
1189
|
+
xP, yP = ER.lift_x(xi).xy()
|
|
1190
|
+
t = L.e_log_RC(xP,yP) / w1
|
|
1191
|
+
if t < 0.5:
|
|
1192
|
+
t = 1 - t
|
|
1193
|
+
return t
|
|
1194
|
+
|
|
1195
|
+
def S(self, xi1, xi2, v):
|
|
1196
|
+
r"""
|
|
1197
|
+
Return the union of intervals `S^{(v)}(\xi_1,\xi_2)`.
|
|
1198
|
+
|
|
1199
|
+
INPUT:
|
|
1200
|
+
|
|
1201
|
+
- ``xi1``, ``xi2`` -- real numbers with `\xi_1\le\xi_2`
|
|
1202
|
+
|
|
1203
|
+
- ``v`` -- a real embedding of the field
|
|
1204
|
+
|
|
1205
|
+
OUTPUT:
|
|
1206
|
+
|
|
1207
|
+
The union of intervals `S^{(v)}(\xi_1,\xi_2)` defined in [Tho2010]_
|
|
1208
|
+
section 6.1.
|
|
1209
|
+
|
|
1210
|
+
EXAMPLES:
|
|
1211
|
+
|
|
1212
|
+
An example over `\QQ`::
|
|
1213
|
+
|
|
1214
|
+
sage: E = EllipticCurve('389a')
|
|
1215
|
+
sage: v = QQ.places()[0]
|
|
1216
|
+
sage: H = E.height_function()
|
|
1217
|
+
sage: H.S(2, 3, v)
|
|
1218
|
+
([0.224512677391895, 0.274544821597130] U [0.725455178402870, 0.775487322608105])
|
|
1219
|
+
|
|
1220
|
+
An example over a number field::
|
|
1221
|
+
|
|
1222
|
+
sage: # needs sage.rings.number_field
|
|
1223
|
+
sage: x = polygen(ZZ, 'x')
|
|
1224
|
+
sage: K.<a> = NumberField(x^3 - 2)
|
|
1225
|
+
sage: E = EllipticCurve([0,0,0,0,a])
|
|
1226
|
+
sage: v = K.real_places()[0]
|
|
1227
|
+
sage: H = E.height_function()
|
|
1228
|
+
sage: H.S(9, 10, v)
|
|
1229
|
+
([0.078119444725347..., 0.082342373201640...] U [0.91765762679836..., 0.92188055527465...])
|
|
1230
|
+
"""
|
|
1231
|
+
L = self.E.period_lattice(v)
|
|
1232
|
+
w1, w2 = L.basis(prec=v.codomain().prec())
|
|
1233
|
+
beta = L.elliptic_exponential(w1/2)[0]
|
|
1234
|
+
if xi2 < beta:
|
|
1235
|
+
return UnionOfIntervals([])
|
|
1236
|
+
elif xi1 < beta <= xi2:
|
|
1237
|
+
a = self.psi(xi2, v)
|
|
1238
|
+
return UnionOfIntervals([1-a, a])
|
|
1239
|
+
else:
|
|
1240
|
+
a, b = self.psi(xi1, v), self.psi(xi2, v)
|
|
1241
|
+
return UnionOfIntervals([1-b, 1-a, a, b])
|
|
1242
|
+
|
|
1243
|
+
def Sn(self, xi1, xi2, n, v):
|
|
1244
|
+
r"""
|
|
1245
|
+
Return the union of intervals `S_n^{(v)}(\xi_1,\xi_2)`.
|
|
1246
|
+
|
|
1247
|
+
INPUT:
|
|
1248
|
+
|
|
1249
|
+
- ``xi1``, ``xi2`` -- real numbers with `\xi_1\le\xi_2`
|
|
1250
|
+
|
|
1251
|
+
- ``n`` -- positive integer
|
|
1252
|
+
|
|
1253
|
+
- ``v`` -- a real embedding of the field
|
|
1254
|
+
|
|
1255
|
+
OUTPUT:
|
|
1256
|
+
|
|
1257
|
+
The union of intervals `S_n^{(v)}(\xi_1,\xi_2)` defined in [Tho2010]_
|
|
1258
|
+
(Lemma 6.1).
|
|
1259
|
+
|
|
1260
|
+
EXAMPLES:
|
|
1261
|
+
|
|
1262
|
+
An example over `\QQ`::
|
|
1263
|
+
|
|
1264
|
+
sage: E = EllipticCurve('389a')
|
|
1265
|
+
sage: v = QQ.places()[0]
|
|
1266
|
+
sage: H = E.height_function()
|
|
1267
|
+
sage: H.S(2, 3, v), H.Sn(2, 3, 1, v)
|
|
1268
|
+
(([0.224512677391895, 0.274544821597130] U [0.725455178402870, 0.775487322608105]),
|
|
1269
|
+
([0.224512677391895, 0.274544821597130] U [0.725455178402870, 0.775487322608105]))
|
|
1270
|
+
sage: H.Sn(2, 3, 6, v)
|
|
1271
|
+
([0.0374187795653158, 0.0457574702661884] U [0.120909196400478, 0.129247887101351] U [0.204085446231982, 0.212424136932855] U [0.287575863067145, 0.295914553768017] U [0.370752112898649, 0.379090803599522] U [0.454242529733812, 0.462581220434684] U [0.537418779565316, 0.545757470266188] U [0.620909196400478, 0.629247887101351] U [0.704085446231982, 0.712424136932855] U [0.787575863067145, 0.795914553768017] U [0.870752112898649, 0.879090803599522] U [0.954242529733812, 0.962581220434684])
|
|
1272
|
+
|
|
1273
|
+
An example over a number field::
|
|
1274
|
+
|
|
1275
|
+
sage: # needs sage.rings.number_field
|
|
1276
|
+
sage: x = polygen(ZZ, 'x')
|
|
1277
|
+
sage: K.<a> = NumberField(x^3 - 2)
|
|
1278
|
+
sage: E = EllipticCurve([0,0,0,0,a])
|
|
1279
|
+
sage: v = K.real_places()[0]
|
|
1280
|
+
sage: H = E.height_function()
|
|
1281
|
+
sage: H.S(2, 3, v), H.Sn(2, 3, 1, v)
|
|
1282
|
+
(([0.142172065860075, 0.172845716928584] U [0.827154283071416, 0.857827934139925]),
|
|
1283
|
+
([0.142172065860075, 0.172845716928584] U [0.827154283071416, 0.857827934139925]))
|
|
1284
|
+
sage: H.Sn(2, 3, 6, v)
|
|
1285
|
+
([0.0236953443100124, 0.0288076194880974] U [0.137859047178569, 0.142971322356654] U [0.190362010976679, 0.195474286154764] U [0.304525713845236, 0.309637989023321] U [0.357028677643346, 0.362140952821431] U [0.471192380511903, 0.476304655689988] U [0.523695344310012, 0.528807619488097] U [0.637859047178569, 0.642971322356654] U [0.690362010976679, 0.695474286154764] U [0.804525713845236, 0.809637989023321] U [0.857028677643346, 0.862140952821431] U [0.971192380511903, 0.976304655689988])
|
|
1286
|
+
"""
|
|
1287
|
+
SS = 1/ZZ(n) * self.S(xi1, xi2, v)
|
|
1288
|
+
return UnionOfIntervals.union([t/ZZ(n) + SS for t in range(n)])
|
|
1289
|
+
|
|
1290
|
+
def real_intersection_is_empty(self, Bk, v):
|
|
1291
|
+
r"""
|
|
1292
|
+
Return ``True`` iff an intersection of `S_n^{(v)}` sets is empty.
|
|
1293
|
+
|
|
1294
|
+
INPUT:
|
|
1295
|
+
|
|
1296
|
+
- ``Bk`` -- list of reals
|
|
1297
|
+
|
|
1298
|
+
- ``v`` -- a real embedding of the number field
|
|
1299
|
+
|
|
1300
|
+
OUTPUT:
|
|
1301
|
+
|
|
1302
|
+
``True`` or ``False``, according as the intersection of the unions of
|
|
1303
|
+
intervals `S_n^{(v)}(-b,b)` for `b` in the list ``Bk`` is
|
|
1304
|
+
empty or not. When ``Bk`` is the list of `b=B_n(\mu)` for
|
|
1305
|
+
`n=1,2,3,\dots` for some `\mu>0` this means that all
|
|
1306
|
+
non-torsion points on `E` with everywhere good reduction have
|
|
1307
|
+
canonical height strictly greater than `\mu`, by [Tho2010]_,
|
|
1308
|
+
Proposition 6.2.
|
|
1309
|
+
|
|
1310
|
+
EXAMPLES:
|
|
1311
|
+
|
|
1312
|
+
An example over `\QQ`::
|
|
1313
|
+
|
|
1314
|
+
sage: E = EllipticCurve('389a')
|
|
1315
|
+
sage: v = QQ.places()[0]
|
|
1316
|
+
sage: H = E.height_function()
|
|
1317
|
+
|
|
1318
|
+
The following two lines prove that the heights of non-torsion
|
|
1319
|
+
points on `E` with everywhere good reduction have canonical
|
|
1320
|
+
height strictly greater than 0.2, but fail to prove the same
|
|
1321
|
+
for 0.3::
|
|
1322
|
+
|
|
1323
|
+
sage: H.real_intersection_is_empty([H.B(n,0.2) for n in srange(1,10)], v) # needs sage.symbolic
|
|
1324
|
+
True
|
|
1325
|
+
sage: H.real_intersection_is_empty([H.B(n,0.3) for n in srange(1,10)], v) # needs sage.symbolic
|
|
1326
|
+
False
|
|
1327
|
+
|
|
1328
|
+
An example over a number field::
|
|
1329
|
+
|
|
1330
|
+
sage: # needs sage.rings.number_field
|
|
1331
|
+
sage: x = polygen(ZZ, 'x')
|
|
1332
|
+
sage: K.<a> = NumberField(x^3 - 2)
|
|
1333
|
+
sage: E = EllipticCurve([0,0,0,0,a])
|
|
1334
|
+
sage: v = K.real_places()[0]
|
|
1335
|
+
sage: H = E.height_function()
|
|
1336
|
+
|
|
1337
|
+
The following two lines prove that the heights of non-torsion
|
|
1338
|
+
points on `E` with everywhere good reduction have canonical
|
|
1339
|
+
height strictly greater than 0.07, but fail to prove the same
|
|
1340
|
+
for 0.08::
|
|
1341
|
+
|
|
1342
|
+
sage: H.real_intersection_is_empty([H.B(n,0.07) for n in srange(1,5)], v) # long time, needs sage.rings.number_field sage.symbolic
|
|
1343
|
+
True
|
|
1344
|
+
sage: H.real_intersection_is_empty([H.B(n,0.08) for n in srange(1,5)], v) # needs sage.rings.number_field sage.symbolic
|
|
1345
|
+
False
|
|
1346
|
+
"""
|
|
1347
|
+
return UnionOfIntervals.intersection([self.Sn(-B, B, k+1, v) for k,B in enumerate(Bk)]).is_empty()
|
|
1348
|
+
|
|
1349
|
+
########################################
|
|
1350
|
+
# Empty complex intersection detection.#
|
|
1351
|
+
########################################
|
|
1352
|
+
|
|
1353
|
+
def tau(self, v):
|
|
1354
|
+
r"""
|
|
1355
|
+
Return the normalised upper half-plane parameter `\tau` for
|
|
1356
|
+
the period lattice with respect to the embedding `v`.
|
|
1357
|
+
|
|
1358
|
+
INPUT:
|
|
1359
|
+
|
|
1360
|
+
- ``v`` -- a real or complex embedding of the number field
|
|
1361
|
+
|
|
1362
|
+
OUTPUT:
|
|
1363
|
+
|
|
1364
|
+
(Complex) `\tau = \omega_1/\omega_2` in the fundamental region
|
|
1365
|
+
of the upper half-plane.
|
|
1366
|
+
|
|
1367
|
+
EXAMPLES::
|
|
1368
|
+
|
|
1369
|
+
sage: E = EllipticCurve('37a')
|
|
1370
|
+
sage: H = E.height_function()
|
|
1371
|
+
sage: H.tau(QQ.places()[0])
|
|
1372
|
+
1.22112736076463*I
|
|
1373
|
+
"""
|
|
1374
|
+
return self.E.period_lattice(v).tau()
|
|
1375
|
+
|
|
1376
|
+
def wp_c(self, v):
|
|
1377
|
+
r"""
|
|
1378
|
+
Return a bound for the Weierstrass `\wp`-function.
|
|
1379
|
+
|
|
1380
|
+
INPUT:
|
|
1381
|
+
|
|
1382
|
+
- ``v`` -- a real or complex embedding of the number field
|
|
1383
|
+
|
|
1384
|
+
OUTPUT:
|
|
1385
|
+
|
|
1386
|
+
(Real) `c>0` such that
|
|
1387
|
+
|
|
1388
|
+
.. MATH::
|
|
1389
|
+
|
|
1390
|
+
|\wp(z) - z^-2| \le \frac{c^2|z|^2}{1-c|z|^2}
|
|
1391
|
+
|
|
1392
|
+
whenever `c|z|^2<1`. Given the recurrence relations for the
|
|
1393
|
+
Laurent series expansion of `\wp`, it is easy to see that
|
|
1394
|
+
there is such a constant `c`. [Reference?]
|
|
1395
|
+
|
|
1396
|
+
EXAMPLES::
|
|
1397
|
+
|
|
1398
|
+
sage: E = EllipticCurve('37a')
|
|
1399
|
+
sage: H = E.height_function()
|
|
1400
|
+
sage: H.wp_c(QQ.places()[0])
|
|
1401
|
+
2.68744508779950
|
|
1402
|
+
|
|
1403
|
+
sage: # needs sage.rings.number_field
|
|
1404
|
+
sage: K.<i> = QuadraticField(-1)
|
|
1405
|
+
sage: E = EllipticCurve([0, 0, 0, 1 + 5*i, 3 + i])
|
|
1406
|
+
sage: H = E.height_function()
|
|
1407
|
+
sage: H.wp_c(K.places()[0])
|
|
1408
|
+
2.66213425640096
|
|
1409
|
+
"""
|
|
1410
|
+
# Note that we normalise w1, w2 differently from [Tho2010]_!
|
|
1411
|
+
w2, w1 = self.E.period_lattice(v).normalised_basis()
|
|
1412
|
+
return max(abs(v(self.E.c4()/240)) ** 0.5,
|
|
1413
|
+
abs(v(self.E.c6()/6048)) ** (1.0/3)) * abs(w1)**2
|
|
1414
|
+
|
|
1415
|
+
def fk_intervals(self, v=None, N=20, domain=CIF):
|
|
1416
|
+
r"""
|
|
1417
|
+
Return a function approximating the Weierstrass function, with error.
|
|
1418
|
+
|
|
1419
|
+
INPUT:
|
|
1420
|
+
|
|
1421
|
+
- ``v`` -- an embedding of the number field. If
|
|
1422
|
+
``None`` (default) use the real embedding if the field is `\QQ`
|
|
1423
|
+
and raise an error for other fields.
|
|
1424
|
+
|
|
1425
|
+
- ``N`` -- integer; the number of terms to use in the
|
|
1426
|
+
`q`-expansion of `\wp`
|
|
1427
|
+
|
|
1428
|
+
- ``domain`` -- (complex field) the model of `\CC` to use, for
|
|
1429
|
+
example ``CDF`` of ``CIF`` (default)
|
|
1430
|
+
|
|
1431
|
+
OUTPUT:
|
|
1432
|
+
|
|
1433
|
+
A pair of functions fk, err which can be evaluated at complex
|
|
1434
|
+
numbers `z` (in the correct ``domain``) to give an
|
|
1435
|
+
approximation to `\wp(z)` and an upper bound on the error,
|
|
1436
|
+
respectively. The Weierstrass function returned is with
|
|
1437
|
+
respect to the normalised lattice `[1,\tau]` associated to the
|
|
1438
|
+
given embedding.
|
|
1439
|
+
|
|
1440
|
+
EXAMPLES::
|
|
1441
|
+
|
|
1442
|
+
sage: E = EllipticCurve('37a')
|
|
1443
|
+
sage: L = E.period_lattice()
|
|
1444
|
+
sage: w1, w2 = L.normalised_basis()
|
|
1445
|
+
sage: z = CDF(0.3, 0.4)
|
|
1446
|
+
|
|
1447
|
+
Compare the value give by the standard elliptic exponential
|
|
1448
|
+
(scaled since ``fk`` is with respect to the normalised
|
|
1449
|
+
lattice)::
|
|
1450
|
+
|
|
1451
|
+
sage: L.elliptic_exponential(z*w2, to_curve=False)[0] * w2 ** 2
|
|
1452
|
+
-1.82543539306049 - 2.49336319992847*I
|
|
1453
|
+
|
|
1454
|
+
to the value given by this function, and see the error::
|
|
1455
|
+
|
|
1456
|
+
sage: fk, err = E.height_function().fk_intervals(N=10)
|
|
1457
|
+
sage: fk(CIF(z))
|
|
1458
|
+
-1.82543539306049? - 2.49336319992847?*I
|
|
1459
|
+
sage: err(CIF(z))
|
|
1460
|
+
2.71750621458744e-31
|
|
1461
|
+
|
|
1462
|
+
The same, but in the domain ``CDF`` instead of ``CIF``::
|
|
1463
|
+
|
|
1464
|
+
sage: fk, err = E.height_function().fk_intervals(N=10, domain=CDF)
|
|
1465
|
+
sage: fk(z)
|
|
1466
|
+
-1.8254353930604... - 2.493363199928...*I
|
|
1467
|
+
"""
|
|
1468
|
+
if v is None:
|
|
1469
|
+
if self.K is QQ:
|
|
1470
|
+
v = QQ.hom(RR)
|
|
1471
|
+
else:
|
|
1472
|
+
raise ValueError("must specify embedding")
|
|
1473
|
+
# pre-compute some constants
|
|
1474
|
+
tau = self.tau(v)
|
|
1475
|
+
const_term = 1/CC(12)
|
|
1476
|
+
qn = q = (2 * CC.gen() * CC.pi() * tau).exp()
|
|
1477
|
+
for n in range(1, N):
|
|
1478
|
+
const_term -= 2 * qn/(1-qn) ** 2
|
|
1479
|
+
qn *= q
|
|
1480
|
+
|
|
1481
|
+
two_pi_i = 2 * domain.gen() * domain.pi()
|
|
1482
|
+
neg_four_pi2 = -4 * domain.pi() ** 2
|
|
1483
|
+
const_term = domain(const_term)
|
|
1484
|
+
tau = domain(tau)
|
|
1485
|
+
|
|
1486
|
+
abs_q = abs(domain(q))
|
|
1487
|
+
abs_qN = abs(domain(qn))
|
|
1488
|
+
err_factor = abs(neg_four_pi2) / (1-abs_q)
|
|
1489
|
+
err_term = 2*abs_qN/(1-abs_qN) ** 2
|
|
1490
|
+
|
|
1491
|
+
# choose u/(1-u)^2 evaluation method
|
|
1492
|
+
if domain is CIF:
|
|
1493
|
+
rat_term = rat_term_CIF
|
|
1494
|
+
else:
|
|
1495
|
+
def rat_term(z):
|
|
1496
|
+
u = (two_pi_i*z).exp()
|
|
1497
|
+
return u/(1-u)**2
|
|
1498
|
+
|
|
1499
|
+
# the actual series
|
|
1500
|
+
def fk(z):
|
|
1501
|
+
return (const_term +
|
|
1502
|
+
sum([rat_term(z+n*tau) for n in range(1-N,N)])
|
|
1503
|
+
) * neg_four_pi2
|
|
1504
|
+
|
|
1505
|
+
# the error function
|
|
1506
|
+
def err(z):
|
|
1507
|
+
alpha = z.imag() / tau.imag()
|
|
1508
|
+
qNa = abs_q**(N+alpha)
|
|
1509
|
+
qNai = abs_q**(N-alpha)
|
|
1510
|
+
return (err_factor * (qNa/(1-qNa) ** 2 + qNai/(1-qNai) ** 2 + err_term)).upper()
|
|
1511
|
+
|
|
1512
|
+
return fk, err
|
|
1513
|
+
|
|
1514
|
+
@cached_method
|
|
1515
|
+
def wp_intervals(self, v=None, N=20, abs_only=False):
|
|
1516
|
+
r"""
|
|
1517
|
+
Return a function approximating the Weierstrass function.
|
|
1518
|
+
|
|
1519
|
+
INPUT:
|
|
1520
|
+
|
|
1521
|
+
- ``v`` -- an embedding of the number field; if
|
|
1522
|
+
``None`` (default) use the real embedding if the field is `\QQ`
|
|
1523
|
+
and raise an error for other fields
|
|
1524
|
+
|
|
1525
|
+
- ``N`` -- integer (default: 20); The number of terms to use in the
|
|
1526
|
+
`q`-expansion of `\wp`
|
|
1527
|
+
|
|
1528
|
+
- ``abs_only``-- boolean (default: ``False``); flag to determine
|
|
1529
|
+
whether (if ``True``) the error adjustment should use the
|
|
1530
|
+
absolute value or (if ``False``) the real and imaginary parts
|
|
1531
|
+
|
|
1532
|
+
OUTPUT:
|
|
1533
|
+
|
|
1534
|
+
A function wp which can be evaluated at complex numbers `z` to
|
|
1535
|
+
give an approximation to `\wp(z)`. The Weierstrass function
|
|
1536
|
+
returned is with respect to the normalised lattice `[1,\tau]`
|
|
1537
|
+
associated to the given embedding. For `z` which are not near
|
|
1538
|
+
a lattice point the function ``fk`` is used, otherwise a
|
|
1539
|
+
better approximation is used.
|
|
1540
|
+
|
|
1541
|
+
EXAMPLES::
|
|
1542
|
+
|
|
1543
|
+
sage: E = EllipticCurve('37a')
|
|
1544
|
+
sage: wp = E.height_function().wp_intervals()
|
|
1545
|
+
sage: z = CDF(0.3, 0.4)
|
|
1546
|
+
sage: wp(CIF(z))
|
|
1547
|
+
-1.82543539306049? - 2.4933631999285?*I
|
|
1548
|
+
|
|
1549
|
+
sage: L = E.period_lattice()
|
|
1550
|
+
sage: w1, w2 = L.normalised_basis()
|
|
1551
|
+
sage: L.elliptic_exponential(z*w2, to_curve=False)[0] * w2^2
|
|
1552
|
+
-1.82543539306049 - 2.49336319992847*I
|
|
1553
|
+
|
|
1554
|
+
sage: z = CDF(0.3, 0.1)
|
|
1555
|
+
sage: wp(CIF(z))
|
|
1556
|
+
8.5918243572165? - 5.4751982004351?*I
|
|
1557
|
+
sage: L.elliptic_exponential(z*w2, to_curve=False)[0] * w2^2
|
|
1558
|
+
8.59182435721650 - 5.47519820043503*I
|
|
1559
|
+
"""
|
|
1560
|
+
if v is None:
|
|
1561
|
+
if self.K is QQ:
|
|
1562
|
+
v = QQ.hom(RR)
|
|
1563
|
+
else:
|
|
1564
|
+
raise ValueError("must specify embedding")
|
|
1565
|
+
|
|
1566
|
+
tau = self.tau(v)
|
|
1567
|
+
fk, fk_err = self.fk_intervals(v, N)
|
|
1568
|
+
c = self.wp_c(v)
|
|
1569
|
+
|
|
1570
|
+
def wp(z):
|
|
1571
|
+
|
|
1572
|
+
# center around origin
|
|
1573
|
+
offset = (z.imag().lower() / tau.imag()).round()
|
|
1574
|
+
if offset:
|
|
1575
|
+
z -= CIF(offset * tau)
|
|
1576
|
+
offset = z.real().lower().round()
|
|
1577
|
+
if offset:
|
|
1578
|
+
z -= offset
|
|
1579
|
+
|
|
1580
|
+
# estimate using the series
|
|
1581
|
+
approx = fk(z)
|
|
1582
|
+
err = fk_err(z)
|
|
1583
|
+
if abs_only:
|
|
1584
|
+
approx = abs(approx)
|
|
1585
|
+
approx += eps(err, abs_only)
|
|
1586
|
+
|
|
1587
|
+
# refine using an estimate that's better near the pole
|
|
1588
|
+
z_bound = abs(z).upper()
|
|
1589
|
+
cz2 = c * z_bound ** 2
|
|
1590
|
+
if cz2 < 1:
|
|
1591
|
+
err = (c * cz2) / (1 - cz2)
|
|
1592
|
+
if abs_only:
|
|
1593
|
+
pole_approx = abs(z) ** -2
|
|
1594
|
+
else:
|
|
1595
|
+
pole_approx = z ** -2
|
|
1596
|
+
approx = approx.intersection(pole_approx + eps(err, abs_only))
|
|
1597
|
+
return approx
|
|
1598
|
+
return wp
|
|
1599
|
+
|
|
1600
|
+
@cached_method
|
|
1601
|
+
def wp_on_grid(self, v, N, half=False):
|
|
1602
|
+
r"""
|
|
1603
|
+
Return an array of the values of `\wp` on an `N\times N` grid.
|
|
1604
|
+
|
|
1605
|
+
INPUT:
|
|
1606
|
+
|
|
1607
|
+
- ``v`` -- an embedding of the number field
|
|
1608
|
+
|
|
1609
|
+
- ``N`` -- integer; the number of terms to use in the
|
|
1610
|
+
`q`-expansion of `\wp`
|
|
1611
|
+
|
|
1612
|
+
- ``half``-- boolean (default: ``False``); if ``True``, use an array of
|
|
1613
|
+
size `N\times N/2` instead of `N\times N`
|
|
1614
|
+
|
|
1615
|
+
OUTPUT:
|
|
1616
|
+
|
|
1617
|
+
An array of size either `N\times N/2` or `N\times N` whose
|
|
1618
|
+
`(i,j)` entry is the value of the Weierstrass `\wp`-function
|
|
1619
|
+
at `(i+.5)/N + (j+.5)*\tau/N`, a grid of points in the
|
|
1620
|
+
fundamental region for the lattice `[1,\tau]`.
|
|
1621
|
+
|
|
1622
|
+
EXAMPLES::
|
|
1623
|
+
|
|
1624
|
+
sage: E = EllipticCurve('37a')
|
|
1625
|
+
sage: H = E.height_function()
|
|
1626
|
+
sage: v = QQ.places()[0]
|
|
1627
|
+
|
|
1628
|
+
The array of values on the grid shows symmetry, since `\wp` is
|
|
1629
|
+
even::
|
|
1630
|
+
|
|
1631
|
+
sage: H.wp_on_grid(v, 4) # needs sage.symbolic
|
|
1632
|
+
array([[25.43920182, 5.28760943, 5.28760943, 25.43920182],
|
|
1633
|
+
[ 6.05099485, 1.83757786, 1.83757786, 6.05099485],
|
|
1634
|
+
[ 6.05099485, 1.83757786, 1.83757786, 6.05099485],
|
|
1635
|
+
[25.43920182, 5.28760943, 5.28760943, 25.43920182]])
|
|
1636
|
+
|
|
1637
|
+
The array of values on the half-grid::
|
|
1638
|
+
|
|
1639
|
+
sage: H.wp_on_grid(v, 4, True) # needs sage.symbolic
|
|
1640
|
+
array([[25.43920182, 5.28760943],
|
|
1641
|
+
[ 6.05099485, 1.83757786],
|
|
1642
|
+
[ 6.05099485, 1.83757786],
|
|
1643
|
+
[25.43920182, 5.28760943]])
|
|
1644
|
+
"""
|
|
1645
|
+
tau = self.tau(v)
|
|
1646
|
+
fk, err = self.fk_intervals(v, 15, CDF)
|
|
1647
|
+
var_z = SR.var('z')
|
|
1648
|
+
ff = fast_callable(fk(var_z), CDF, [var_z])
|
|
1649
|
+
N_or_half = N // (1+half) # array is NxN or Nx(N/2)
|
|
1650
|
+
vals = numpy.empty((N,N_or_half)) # empty array tp hold values
|
|
1651
|
+
for i in range(N):
|
|
1652
|
+
for j in range(N_or_half):
|
|
1653
|
+
vals[i,j] = abs(ff((i+.5)/N + (j+.5)*tau/N))
|
|
1654
|
+
return vals
|
|
1655
|
+
|
|
1656
|
+
def complex_intersection_is_empty(self, Bk, v, verbose=False, use_half=True):
|
|
1657
|
+
r"""
|
|
1658
|
+
Return ``True`` iff an intersection of `T_n^{(v)}` sets is empty.
|
|
1659
|
+
|
|
1660
|
+
INPUT:
|
|
1661
|
+
|
|
1662
|
+
- ``Bk`` -- list of reals
|
|
1663
|
+
|
|
1664
|
+
- ``v`` -- a complex embedding of the number field
|
|
1665
|
+
|
|
1666
|
+
- ``verbose``-- boolean (default: ``False``); verbosity flag
|
|
1667
|
+
|
|
1668
|
+
- ``use_half``-- boolean (default: ``False``); if ``True``, use only half
|
|
1669
|
+
the fundamental region
|
|
1670
|
+
|
|
1671
|
+
OUTPUT:
|
|
1672
|
+
|
|
1673
|
+
``True`` or ``False``, according as the intersection of the unions of
|
|
1674
|
+
intervals `T_n^{(v)}(-b,b)` for `b` in the list ``Bk`` (see
|
|
1675
|
+
[Tho2010]_, section 7) is empty or not. When ``Bk`` is the list of
|
|
1676
|
+
`b=\sqrt{B_n(\mu)}` for `n=1,2,3,\dots` for some `\mu>0` this
|
|
1677
|
+
means that all non-torsion points on `E` with everywhere good
|
|
1678
|
+
reduction have canonical height strictly greater than `\mu`,
|
|
1679
|
+
by [Tho2010]_, Proposition 7.8.
|
|
1680
|
+
|
|
1681
|
+
EXAMPLES::
|
|
1682
|
+
|
|
1683
|
+
sage: # needs sage.rings.number_field
|
|
1684
|
+
sage: x = polygen(ZZ, 'x')
|
|
1685
|
+
sage: K.<a> = NumberField(x^3 - 2)
|
|
1686
|
+
sage: E = EllipticCurve([0,0,0,0,a])
|
|
1687
|
+
sage: v = K.complex_embeddings()[0]
|
|
1688
|
+
sage: H = E.height_function()
|
|
1689
|
+
|
|
1690
|
+
The following two lines prove that the heights of non-torsion
|
|
1691
|
+
points on `E` with everywhere good reduction have canonical
|
|
1692
|
+
height strictly greater than 0.02, but fail to prove the same
|
|
1693
|
+
for 0.03. For the first proof, using only `n=1,2,3` is not
|
|
1694
|
+
sufficient::
|
|
1695
|
+
|
|
1696
|
+
sage: H.complex_intersection_is_empty([H.B(n, 0.02) for n in [1,2,3]], v) # long time, needs sage.rings.number_field sage.symbolic
|
|
1697
|
+
False
|
|
1698
|
+
sage: H.complex_intersection_is_empty([H.B(n, 0.02) for n in [1,2,3,4]], v) # needs sage.rings.number_field sage.symbolic
|
|
1699
|
+
True
|
|
1700
|
+
sage: H.complex_intersection_is_empty([H.B(n, 0.03) for n in [1,2,3,4]], v) # long time, needs sage.rings.number_field sage.symbolic
|
|
1701
|
+
False
|
|
1702
|
+
|
|
1703
|
+
Using `n\le6` enables us to prove the lower bound 0.03. Note
|
|
1704
|
+
that it takes longer when the result is ``False`` than when it
|
|
1705
|
+
is ``True``::
|
|
1706
|
+
|
|
1707
|
+
sage: H.complex_intersection_is_empty([H.B(n, 0.03) for n in [1..6]], v) # needs sage.rings.number_field sage.symbolic
|
|
1708
|
+
True
|
|
1709
|
+
"""
|
|
1710
|
+
from sage.schemes.elliptic_curves.period_lattice_region import PeriodicRegion
|
|
1711
|
+
|
|
1712
|
+
b2 = v(self.E.b2())
|
|
1713
|
+
# Note that we normalise w1, w2 differently from [Tho2010]_!
|
|
1714
|
+
w2, w1 = self.E.period_lattice(v).normalised_basis()
|
|
1715
|
+
tau = w2/w1
|
|
1716
|
+
bounds = [RDF((B.sqrt() + abs(b2)/12) * abs(w1) ** 2) for B in Bk]
|
|
1717
|
+
vals = self.wp_on_grid(v, 30, half=use_half)
|
|
1718
|
+
wp = self.wp_intervals(v, abs_only=True)
|
|
1719
|
+
|
|
1720
|
+
k = len(bounds)
|
|
1721
|
+
|
|
1722
|
+
# First try and prove a negative result (cheap).
|
|
1723
|
+
if verbose:
|
|
1724
|
+
print("trying to prove negative result...")
|
|
1725
|
+
intersection = None
|
|
1726
|
+
for B, n in sorted(zip(bounds, ZZ.range(1, k+1))):
|
|
1727
|
+
T = PeriodicRegion(CDF(1), CDF(tau), vals < B, full=not use_half)
|
|
1728
|
+
if intersection is None:
|
|
1729
|
+
intersection = PeriodicRegion(CDF(1), CDF(tau), vals < B, full=not use_half)
|
|
1730
|
+
else:
|
|
1731
|
+
intersection &= T/n
|
|
1732
|
+
if intersection.is_empty():
|
|
1733
|
+
break
|
|
1734
|
+
else:
|
|
1735
|
+
z = CIF(intersection.innermost_point())
|
|
1736
|
+
if all(wp((k+1)*z).upper() < B for k, B in enumerate(bounds)):
|
|
1737
|
+
return False
|
|
1738
|
+
|
|
1739
|
+
# Now try to prove a positive result.
|
|
1740
|
+
if verbose:
|
|
1741
|
+
print("trying to prove positive result...")
|
|
1742
|
+
intersection = None
|
|
1743
|
+
for B, n in sorted(zip(bounds, ZZ.range(1, k+1))):
|
|
1744
|
+
|
|
1745
|
+
T = PeriodicRegion(CDF(1), CDF(tau), vals < B, full=not use_half).expand().refine()
|
|
1746
|
+
B = RIF(B)
|
|
1747
|
+
leaning_right = tau.real() / tau.imag() >= 0
|
|
1748
|
+
|
|
1749
|
+
def check_line(z):
|
|
1750
|
+
wpz = wp(z)
|
|
1751
|
+
if wpz > B:
|
|
1752
|
+
return True
|
|
1753
|
+
# Try refining once before we declare failure.
|
|
1754
|
+
z00, z01, z10, z11 = z.bisection()
|
|
1755
|
+
if leaning_right:
|
|
1756
|
+
start, end = z00, z11
|
|
1757
|
+
else:
|
|
1758
|
+
start, end = z01, z10
|
|
1759
|
+
if wp(start) > B and wp(end) > B:
|
|
1760
|
+
return True
|
|
1761
|
+
return False
|
|
1762
|
+
|
|
1763
|
+
# This step here is the bottleneck.
|
|
1764
|
+
while not T.verify(check_line):
|
|
1765
|
+
if verbose:
|
|
1766
|
+
print("bad")
|
|
1767
|
+
T = T.expand()
|
|
1768
|
+
if intersection is None:
|
|
1769
|
+
intersection = T
|
|
1770
|
+
else:
|
|
1771
|
+
intersection &= T/n
|
|
1772
|
+
if intersection.is_empty():
|
|
1773
|
+
return True
|
|
1774
|
+
|
|
1775
|
+
return False
|
|
1776
|
+
|
|
1777
|
+
def test_mu(self, mu, N, verbose=True):
|
|
1778
|
+
r"""
|
|
1779
|
+
Return ``True`` if we can prove that `\mu` is a lower bound.
|
|
1780
|
+
|
|
1781
|
+
INPUT:
|
|
1782
|
+
|
|
1783
|
+
- ``mu`` -- positive real number
|
|
1784
|
+
|
|
1785
|
+
- ``N`` -- integer; upper bound on the multiples to be used
|
|
1786
|
+
|
|
1787
|
+
- ``verbose``-- boolean (default: ``True``); verbosity flag
|
|
1788
|
+
|
|
1789
|
+
OUTPUT:
|
|
1790
|
+
|
|
1791
|
+
``True`` or ``False``, according to whether we succeed in
|
|
1792
|
+
proving that `\mu` is a lower bound for the canonical heights
|
|
1793
|
+
of points of infinite order with everywhere good reduction.
|
|
1794
|
+
|
|
1795
|
+
.. NOTE::
|
|
1796
|
+
|
|
1797
|
+
A ``True`` result is rigorous; ``False`` only means that
|
|
1798
|
+
the attempt failed: trying again with larger `N` may yield
|
|
1799
|
+
``True``.
|
|
1800
|
+
|
|
1801
|
+
EXAMPLES::
|
|
1802
|
+
|
|
1803
|
+
sage: x = polygen(ZZ, 'x')
|
|
1804
|
+
sage: K.<a> = NumberField(x^3 - 2) # needs sage.rings.number_field
|
|
1805
|
+
sage: E = EllipticCurve([0,0,0,0,a]) # needs sage.rings.number_field
|
|
1806
|
+
sage: H = E.height_function() # needs sage.rings.number_field
|
|
1807
|
+
|
|
1808
|
+
This curve does have a point of good reduction whose canonical
|
|
1809
|
+
point is approximately 1.68::
|
|
1810
|
+
|
|
1811
|
+
sage: P = E.gens(lim3=5)[0]; P # needs sage.rings.number_field
|
|
1812
|
+
(1/3*a^2 + a + 5/3 : -2*a^2 - 4/3*a - 5/3 : 1)
|
|
1813
|
+
sage: P.height() # needs sage.rings.number_field
|
|
1814
|
+
1.68038085233673
|
|
1815
|
+
sage: P.has_good_reduction() # needs sage.rings.number_field
|
|
1816
|
+
True
|
|
1817
|
+
|
|
1818
|
+
Using `N=5` we can prove that 0.1 is a lower bound (in fact we
|
|
1819
|
+
only need `N=2`), but not that 0.2 is::
|
|
1820
|
+
|
|
1821
|
+
sage: H.test_mu(0.1, 5) # needs sage.rings.number_field sage.symbolic
|
|
1822
|
+
B_1(0.100000000000000) = 1.51580969677387
|
|
1823
|
+
B_2(0.100000000000000) = 0.932072561526720
|
|
1824
|
+
True
|
|
1825
|
+
sage: H.test_mu(0.2, 5) # needs sage.rings.number_field sage.symbolic
|
|
1826
|
+
B_1(0.200000000000000) = 2.04612906979932
|
|
1827
|
+
B_2(0.200000000000000) = 3.09458988474327
|
|
1828
|
+
B_3(0.200000000000000) = 27.6251108409484
|
|
1829
|
+
B_4(0.200000000000000) = 1036.24722370223
|
|
1830
|
+
B_5(0.200000000000000) = 3.67090854562318e6
|
|
1831
|
+
False
|
|
1832
|
+
|
|
1833
|
+
Since 0.1 is a lower bound we can deduce that the point `P` is
|
|
1834
|
+
either primitive or divisible by either 2 or 3. In fact it is
|
|
1835
|
+
primitive::
|
|
1836
|
+
|
|
1837
|
+
sage: (P.height()/0.1).sqrt() # needs sage.rings.number_field
|
|
1838
|
+
4.09924487233530
|
|
1839
|
+
sage: P.division_points(2) # needs sage.rings.number_field
|
|
1840
|
+
[]
|
|
1841
|
+
sage: P.division_points(3) # needs sage.rings.number_field
|
|
1842
|
+
[]
|
|
1843
|
+
"""
|
|
1844
|
+
# Compute the list of values `B_n(\mu)` for n in 1..N. If any
|
|
1845
|
+
# of these is 1 we can return True right away (see [Tho2010]_,
|
|
1846
|
+
# Proposition 5.1).
|
|
1847
|
+
Bk = []
|
|
1848
|
+
for n in ZZ.range(1, N + 1):
|
|
1849
|
+
b = self.B(n, mu)
|
|
1850
|
+
if verbose:
|
|
1851
|
+
print("B_%s(%s) = %s" % (n, mu, b))
|
|
1852
|
+
if b < 1:
|
|
1853
|
+
return True
|
|
1854
|
+
Bk.append(b)
|
|
1855
|
+
|
|
1856
|
+
# Each real or complex embedding of the number field gives us
|
|
1857
|
+
# a chance to prove the lower bound. We try each in turn,
|
|
1858
|
+
# stopping if one gives a True result.
|
|
1859
|
+
|
|
1860
|
+
from sage.rings.number_field.number_field import refine_embedding
|
|
1861
|
+
for v in self.K.places():
|
|
1862
|
+
ok = False
|
|
1863
|
+
while not ok:
|
|
1864
|
+
try:
|
|
1865
|
+
if v(self.K.gen()) in RR:
|
|
1866
|
+
if self.real_intersection_is_empty(Bk, v):
|
|
1867
|
+
return True
|
|
1868
|
+
else:
|
|
1869
|
+
if self.complex_intersection_is_empty(Bk, v):
|
|
1870
|
+
return True
|
|
1871
|
+
ok = True
|
|
1872
|
+
except ArithmeticError:
|
|
1873
|
+
v = refine_embedding(v)
|
|
1874
|
+
if verbose:
|
|
1875
|
+
print("Refining embedding, codomain now {}".format(v.codomain()))
|
|
1876
|
+
return False # Couldn't prove it...
|
|
1877
|
+
|
|
1878
|
+
def min_gr(self, tol, n_max, verbose=False):
|
|
1879
|
+
r"""
|
|
1880
|
+
Return a lower bound for points of infinite order with good reduction.
|
|
1881
|
+
|
|
1882
|
+
INPUT:
|
|
1883
|
+
|
|
1884
|
+
- ``tol`` -- tolerance in output (see below)
|
|
1885
|
+
|
|
1886
|
+
- ``n_max`` -- how many multiples to use in iteration
|
|
1887
|
+
|
|
1888
|
+
- ``verbose``-- boolean (default: ``False``); verbosity flag
|
|
1889
|
+
|
|
1890
|
+
OUTPUT:
|
|
1891
|
+
|
|
1892
|
+
A positive real `\mu` for which it has been established
|
|
1893
|
+
rigorously that every point of infinite order on the elliptic
|
|
1894
|
+
curve (defined over its ground field), which has good
|
|
1895
|
+
reduction at all primes, has canonical height greater than
|
|
1896
|
+
`\mu`, and such that it is not possible (at least without
|
|
1897
|
+
increasing ``n_max``) to prove the same for
|
|
1898
|
+
`\mu\cdot\text{tol}`.
|
|
1899
|
+
|
|
1900
|
+
EXAMPLES:
|
|
1901
|
+
|
|
1902
|
+
Example 1 from [CS2006]_ (where a lower bound of 1.9865 was
|
|
1903
|
+
given)::
|
|
1904
|
+
|
|
1905
|
+
sage: E = EllipticCurve([1, 0, 1, 421152067, 105484554028056]) # 60490d1
|
|
1906
|
+
sage: E.height_function().min_gr(.0001, 5) # needs sage.symbolic
|
|
1907
|
+
1.98684388146518
|
|
1908
|
+
|
|
1909
|
+
Example 10.1 from [Tho2010]_ (where a lower bound of 0.18 was
|
|
1910
|
+
given)::
|
|
1911
|
+
|
|
1912
|
+
sage: # needs sage.rings.number_field
|
|
1913
|
+
sage: K.<i> = QuadraticField(-1)
|
|
1914
|
+
sage: E = EllipticCurve([0, 0, 0, 91 - 26*i, -144 - 323*i])
|
|
1915
|
+
sage: H = E.height_function()
|
|
1916
|
+
sage: H.min_gr(0.1, 4) # long time, needs sage.symbolic
|
|
1917
|
+
0.1621049443313762
|
|
1918
|
+
|
|
1919
|
+
Example 10.2 from [Tho2010]_::
|
|
1920
|
+
|
|
1921
|
+
sage: # needs sage.rings.number_field
|
|
1922
|
+
sage: K.<i> = QuadraticField(-1)
|
|
1923
|
+
sage: E = EllipticCurve([0, 1 - i, i, -i, 0])
|
|
1924
|
+
sage: H = E.height_function()
|
|
1925
|
+
sage: H.min_gr(0.01, 5) # long time, needs sage.symbolic
|
|
1926
|
+
0.020153685521979152
|
|
1927
|
+
|
|
1928
|
+
In this example the point `P=(0,0)` has height 0.023 so our
|
|
1929
|
+
lower bound is quite good::
|
|
1930
|
+
|
|
1931
|
+
sage: P = E((0,0)) # needs sage.rings.number_field
|
|
1932
|
+
sage: P.has_good_reduction() # needs sage.rings.number_field
|
|
1933
|
+
True
|
|
1934
|
+
sage: P.height() # needs sage.rings.number_field
|
|
1935
|
+
0.0230242154471211
|
|
1936
|
+
|
|
1937
|
+
Example 10.3 from [Tho2010]_ (where the same bound of 0.25 is
|
|
1938
|
+
given)::
|
|
1939
|
+
|
|
1940
|
+
sage: # needs sage.rings.number_field
|
|
1941
|
+
sage: x = polygen(ZZ, 'x')
|
|
1942
|
+
sage: K.<a> = NumberField(x^3 - 2)
|
|
1943
|
+
sage: E = EllipticCurve([0, 0, 0, -3*a - a^2, a^2])
|
|
1944
|
+
sage: H = E.height_function()
|
|
1945
|
+
sage: H.min_gr(0.1, 5) # long time, needs sage.symbolic
|
|
1946
|
+
0.25
|
|
1947
|
+
|
|
1948
|
+
TESTS:
|
|
1949
|
+
|
|
1950
|
+
This example from the LMFDB gave problems before the fix in :issue:`8829`::
|
|
1951
|
+
|
|
1952
|
+
sage: # needs sage.rings.number_field
|
|
1953
|
+
sage: x = polygen(ZZ, 'x')
|
|
1954
|
+
sage: K.<phi> = NumberField(x^2 - x - 1)
|
|
1955
|
+
sage: E = EllipticCurve([phi + 1, -phi + 1, 1, 20*phi - 39, 196*phi + 237])
|
|
1956
|
+
sage: H = E.height_function()
|
|
1957
|
+
sage: H.min_gr(.1, 5, verbose=True) # long time, needs sage.symbolic
|
|
1958
|
+
B_1(1) = 1540.199246369678
|
|
1959
|
+
...
|
|
1960
|
+
halving mu to 0.25 and increasing n_max to 6
|
|
1961
|
+
...
|
|
1962
|
+
halving mu to 0.001953125 and increasing n_max to 13
|
|
1963
|
+
doubling mu to 0.0078125
|
|
1964
|
+
doubling mu to 0.015625
|
|
1965
|
+
height bound in [0.0078125, 0.015625] using n_max = 13
|
|
1966
|
+
...
|
|
1967
|
+
height bound in [0.012048522073499539, 0.01313900648833929] using n_max = 13
|
|
1968
|
+
0.012048522073499539
|
|
1969
|
+
"""
|
|
1970
|
+
test = self.test_mu
|
|
1971
|
+
if test(1, n_max, verbose):
|
|
1972
|
+
mu = 2.0
|
|
1973
|
+
while test(mu, n_max, False):
|
|
1974
|
+
mu *= 2
|
|
1975
|
+
mu *= 0.5
|
|
1976
|
+
else:
|
|
1977
|
+
mu = 0.5
|
|
1978
|
+
while not test(mu, n_max, False):
|
|
1979
|
+
mu *= 0.5
|
|
1980
|
+
n_max += 1
|
|
1981
|
+
if verbose:
|
|
1982
|
+
print("halving mu to %r and increasing n_max to %r" % (mu, n_max))
|
|
1983
|
+
# now we have (mu,n_max) which work we can try to increase
|
|
1984
|
+
# mu again using this larger n_max:
|
|
1985
|
+
mu *= 2
|
|
1986
|
+
while test(mu, n_max, False):
|
|
1987
|
+
mu *= 2
|
|
1988
|
+
if verbose:
|
|
1989
|
+
print("doubling mu to %r" % mu)
|
|
1990
|
+
mu *= 0.5
|
|
1991
|
+
|
|
1992
|
+
# The true value lies between mu and eps * mu.
|
|
1993
|
+
eps = 2.0
|
|
1994
|
+
while eps > tol + 1:
|
|
1995
|
+
if verbose:
|
|
1996
|
+
print("height bound in [%r, %r] using n_max = %r"
|
|
1997
|
+
% (mu, mu * eps, n_max))
|
|
1998
|
+
eps = math.sqrt(eps)
|
|
1999
|
+
if test(mu * eps, n_max, False):
|
|
2000
|
+
mu = mu * eps
|
|
2001
|
+
if verbose:
|
|
2002
|
+
print("height bound in [%r, %r] using n_max = %r"
|
|
2003
|
+
% (mu, mu * eps, n_max))
|
|
2004
|
+
return RDF(mu)
|
|
2005
|
+
|
|
2006
|
+
def min(self, tol, n_max, verbose=False):
|
|
2007
|
+
r"""
|
|
2008
|
+
Return a lower bound for all points of infinite order.
|
|
2009
|
+
|
|
2010
|
+
INPUT:
|
|
2011
|
+
|
|
2012
|
+
- ``tol`` -- tolerance in output (see below)
|
|
2013
|
+
|
|
2014
|
+
- ``n_max`` -- how many multiples to use in iteration
|
|
2015
|
+
|
|
2016
|
+
- ``verbose``-- boolean (default: ``False``); verbosity flag
|
|
2017
|
+
|
|
2018
|
+
OUTPUT:
|
|
2019
|
+
|
|
2020
|
+
A positive real `\mu` for which it has been established
|
|
2021
|
+
rigorously that every point of infinite order on the elliptic
|
|
2022
|
+
curve (defined over its ground field) has canonical height
|
|
2023
|
+
greater than `\mu`, and such that it is not possible (at least
|
|
2024
|
+
without increasing ``n_max``) to prove the same for
|
|
2025
|
+
`\mu\cdot\text{tol}`.
|
|
2026
|
+
|
|
2027
|
+
EXAMPLES:
|
|
2028
|
+
|
|
2029
|
+
Example 1 from [CS2006]_ (where the same lower bound of 0.1126 was
|
|
2030
|
+
given)::
|
|
2031
|
+
|
|
2032
|
+
sage: E = EllipticCurve([1, 0, 1, 421152067, 105484554028056]) # 60490d1
|
|
2033
|
+
sage: E.height_function().min(.0001, 5) # needs sage.symbolic
|
|
2034
|
+
0.0011263287309893311
|
|
2035
|
+
|
|
2036
|
+
Example 10.1 from [Tho2010]_ (where a lower bound of 0.18 was
|
|
2037
|
+
given)::
|
|
2038
|
+
|
|
2039
|
+
sage: # needs sage.rings.number_field
|
|
2040
|
+
sage: K.<i> = QuadraticField(-1)
|
|
2041
|
+
sage: E = EllipticCurve([0, 0, 0, 91 - 26*i, -144 - 323*i])
|
|
2042
|
+
sage: H = E.height_function()
|
|
2043
|
+
sage: H.min(0.1, 4) # long time
|
|
2044
|
+
0.1621049443313762
|
|
2045
|
+
|
|
2046
|
+
Example 10.2 from [Tho2010]_::
|
|
2047
|
+
|
|
2048
|
+
sage: # needs sage.rings.number_field
|
|
2049
|
+
sage: K.<i> = QuadraticField(-1)
|
|
2050
|
+
sage: E = EllipticCurve([0, 1 - i, i, -i, 0])
|
|
2051
|
+
sage: H = E.height_function()
|
|
2052
|
+
sage: H.min(0.01, 5) # long time
|
|
2053
|
+
0.020153685521979152
|
|
2054
|
+
|
|
2055
|
+
In this example the point `P=(0,0)` has height 0.023 so our
|
|
2056
|
+
lower bound is quite good::
|
|
2057
|
+
|
|
2058
|
+
sage: P = E((0,0)) # needs sage.rings.number_field
|
|
2059
|
+
sage: P.height() # needs sage.rings.number_field
|
|
2060
|
+
0.0230242154471211
|
|
2061
|
+
|
|
2062
|
+
Example 10.3 from [Tho2010]_ (where the same bound of 0.0625 is
|
|
2063
|
+
given)::
|
|
2064
|
+
|
|
2065
|
+
sage: # needs sage.rings.number_field
|
|
2066
|
+
sage: x = polygen(ZZ, 'x')
|
|
2067
|
+
sage: K.<a> = NumberField(x^3 - 2)
|
|
2068
|
+
sage: E = EllipticCurve([0, 0, 0, -3*a - a^2, a^2])
|
|
2069
|
+
sage: H = E.height_function()
|
|
2070
|
+
sage: H.min(0.1, 5) # long time
|
|
2071
|
+
0.0625
|
|
2072
|
+
|
|
2073
|
+
More examples over `\QQ`::
|
|
2074
|
+
|
|
2075
|
+
sage: E = EllipticCurve('37a')
|
|
2076
|
+
sage: h = E.height_function()
|
|
2077
|
+
sage: h.min(.01, 5) # needs sage.symbolic
|
|
2078
|
+
0.03987318057488725
|
|
2079
|
+
sage: E.gen(0).height()
|
|
2080
|
+
0.0511114082399688
|
|
2081
|
+
|
|
2082
|
+
After base change the lower bound can decrease::
|
|
2083
|
+
|
|
2084
|
+
sage: K.<a> = QuadraticField(-5) # needs sage.rings.number_field
|
|
2085
|
+
sage: E.change_ring(K).height_function().min(0.5, 10) # long time, needs sage.rings.number_field sage.symbolic
|
|
2086
|
+
0.04419417382415922
|
|
2087
|
+
|
|
2088
|
+
sage: E = EllipticCurve('389a')
|
|
2089
|
+
sage: h = E.height_function()
|
|
2090
|
+
sage: h.min(0.1, 5) # needs sage.symbolic
|
|
2091
|
+
0.05731275270029196
|
|
2092
|
+
sage: [P.height() for P in E.gens()]
|
|
2093
|
+
[0.686667083305587, 0.327000773651605]
|
|
2094
|
+
"""
|
|
2095
|
+
# The lcm of the exponents of all the component groups at
|
|
2096
|
+
# finite places (allowing for everywhere good reduction!)
|
|
2097
|
+
tp = lcm([L.tamagawa_exponent() for L in self.E.local_data()] + [ZZ(1)])
|
|
2098
|
+
|
|
2099
|
+
# Include infinite places:
|
|
2100
|
+
if tp % 2 == 1:
|
|
2101
|
+
if self.K == QQ:
|
|
2102
|
+
if self.E.real_components() == 2:
|
|
2103
|
+
tp *= 2
|
|
2104
|
+
elif any(v(self.E.discriminant()) > 0
|
|
2105
|
+
for v in self.K.real_places()):
|
|
2106
|
+
tp *= 2
|
|
2107
|
+
# Now tp is such that tp*P has good reduction at all places
|
|
2108
|
+
# for all points P:
|
|
2109
|
+
return self.min_gr(tol, n_max, verbose) / tp ** 2
|