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,3760 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-schemes
|
|
2
|
+
r"""
|
|
3
|
+
Elliptic curves over a general ring
|
|
4
|
+
|
|
5
|
+
Sage defines an elliptic curve over a ring `R` as a *Weierstrass Model* with
|
|
6
|
+
five coefficients `[a_1,a_2,a_3,a_4,a_6]` in `R` given by
|
|
7
|
+
|
|
8
|
+
.. MATH::
|
|
9
|
+
|
|
10
|
+
y^2 + a_1 xy + a_3 y = x^3 + a_2 x^2 + a_4 x + a_6.
|
|
11
|
+
|
|
12
|
+
Note that the (usual) scheme-theoretic definition of an elliptic curve over `R`
|
|
13
|
+
would require the discriminant to be a unit in `R`; Sage only imposes that the
|
|
14
|
+
discriminant is nonzero. Also note that in Magma, "Weierstrass Model" refers
|
|
15
|
+
to a model with `a_1=a_2=a_3=0`, which is called *Short Weierstrass Model* in
|
|
16
|
+
Sage; these do not always exist in characteristics 2 and 3.
|
|
17
|
+
|
|
18
|
+
EXAMPLES:
|
|
19
|
+
|
|
20
|
+
We construct an elliptic curve over an elaborate base ring::
|
|
21
|
+
|
|
22
|
+
sage: p, a, b = 97, 1, 3
|
|
23
|
+
sage: R.<u> = GF(p)[]
|
|
24
|
+
sage: S.<v> = R[]
|
|
25
|
+
sage: T = S.fraction_field()
|
|
26
|
+
sage: E = EllipticCurve(T, [a, b]); E
|
|
27
|
+
Elliptic Curve defined by y^2 = x^3 + x + 3 over Fraction Field of Univariate
|
|
28
|
+
Polynomial Ring in v over Univariate Polynomial Ring in u over Finite Field of size 97
|
|
29
|
+
sage: latex(E)
|
|
30
|
+
y^2 = x^{3} + x + 3
|
|
31
|
+
|
|
32
|
+
AUTHORS:
|
|
33
|
+
|
|
34
|
+
- William Stein (2005): Initial version
|
|
35
|
+
|
|
36
|
+
- Robert Bradshaw et al....
|
|
37
|
+
|
|
38
|
+
- John Cremona (2008-01): isomorphisms, automorphisms and twists in all characteristics
|
|
39
|
+
|
|
40
|
+
- Julian Rueth (2014-04-11): improved caching
|
|
41
|
+
|
|
42
|
+
- Lorenz Panny (2022-04-14): added ``.montgomery_model()``
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
# ****************************************************************************
|
|
46
|
+
# Copyright (C) 2005 William Stein <wstein@gmail.com>
|
|
47
|
+
# Copyright (C) 2014 Julian Rueth <julian.rueth@fsfe.org>
|
|
48
|
+
#
|
|
49
|
+
# This program is free software: you can redistribute it and/or modify
|
|
50
|
+
# it under the terms of the GNU General Public License as published by
|
|
51
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
52
|
+
# (at your option) any later version.
|
|
53
|
+
# https://www.gnu.org/licenses/
|
|
54
|
+
# ****************************************************************************
|
|
55
|
+
|
|
56
|
+
import math
|
|
57
|
+
from sage.arith.misc import valuation
|
|
58
|
+
|
|
59
|
+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
|
|
60
|
+
from sage.rings.polynomial.polynomial_ring import polygen, polygens
|
|
61
|
+
from sage.rings.polynomial.polynomial_element import polynomial_is_variable
|
|
62
|
+
from sage.rings.polynomial.polynomial_quotient_ring_element import PolynomialQuotientRingElement
|
|
63
|
+
from sage.rings.finite_rings.finite_field_base import FiniteField
|
|
64
|
+
import sage.groups.additive_abelian.additive_abelian_group as groups
|
|
65
|
+
import sage.groups.generic as generic
|
|
66
|
+
|
|
67
|
+
from sage.arith.functions import lcm
|
|
68
|
+
from sage.rings.integer import Integer
|
|
69
|
+
from sage.rings.rational import Rational
|
|
70
|
+
from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF
|
|
71
|
+
from sage.rings.rational_field import RationalField
|
|
72
|
+
from sage.rings.real_mpfr import RealField
|
|
73
|
+
from sage.misc.cachefunc import cached_method
|
|
74
|
+
from sage.misc.fast_methods import WithEqualityById
|
|
75
|
+
|
|
76
|
+
# Schemes
|
|
77
|
+
import sage.schemes.projective.projective_space as projective_space
|
|
78
|
+
from sage.schemes.projective.projective_homset import SchemeHomset_points_abelian_variety_field
|
|
79
|
+
import sage.schemes.curves.projective_curve as plane_curve
|
|
80
|
+
|
|
81
|
+
from . import ell_point
|
|
82
|
+
from . import ell_torsion
|
|
83
|
+
from . import constructor
|
|
84
|
+
from . import formal_group
|
|
85
|
+
from . import weierstrass_morphism as wm
|
|
86
|
+
|
|
87
|
+
sqrt = math.sqrt
|
|
88
|
+
exp = math.exp
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def is_EllipticCurve(x):
|
|
92
|
+
r"""
|
|
93
|
+
Utility function to test if ``x`` is an instance of an Elliptic Curve class.
|
|
94
|
+
|
|
95
|
+
EXAMPLES::
|
|
96
|
+
|
|
97
|
+
sage: from sage.schemes.elliptic_curves.ell_generic import is_EllipticCurve
|
|
98
|
+
sage: E = EllipticCurve([1,2,3/4,7,19])
|
|
99
|
+
sage: is_EllipticCurve(E)
|
|
100
|
+
doctest:warning...
|
|
101
|
+
DeprecationWarning: The function is_EllipticCurve is deprecated; use 'isinstance(..., EllipticCurve_generic)' instead.
|
|
102
|
+
See https://github.com/sagemath/sage/issues/38022 for details.
|
|
103
|
+
True
|
|
104
|
+
sage: is_EllipticCurve(0)
|
|
105
|
+
False
|
|
106
|
+
"""
|
|
107
|
+
from sage.misc.superseded import deprecation
|
|
108
|
+
deprecation(38022, "The function is_EllipticCurve is deprecated; use 'isinstance(..., EllipticCurve_generic)' instead.")
|
|
109
|
+
return isinstance(x, EllipticCurve_generic)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class EllipticCurve_generic(WithEqualityById, plane_curve.ProjectivePlaneCurve):
|
|
113
|
+
r"""
|
|
114
|
+
Elliptic curve over a generic base ring.
|
|
115
|
+
|
|
116
|
+
EXAMPLES::
|
|
117
|
+
|
|
118
|
+
sage: E = EllipticCurve([1,2,3/4,7,19]); E
|
|
119
|
+
Elliptic Curve defined by y^2 + x*y + 3/4*y = x^3 + 2*x^2 + 7*x + 19 over Rational Field
|
|
120
|
+
sage: loads(E.dumps()) == E
|
|
121
|
+
True
|
|
122
|
+
sage: E = EllipticCurve([1,3])
|
|
123
|
+
sage: P = E([-1,1,1])
|
|
124
|
+
sage: -5*P
|
|
125
|
+
(179051/80089 : -91814227/22665187 : 1)
|
|
126
|
+
"""
|
|
127
|
+
def __init__(self, K, ainvs, category=None):
|
|
128
|
+
r"""
|
|
129
|
+
Construct an elliptic curve from Weierstrass `a`-coefficients.
|
|
130
|
+
|
|
131
|
+
INPUT:
|
|
132
|
+
|
|
133
|
+
- ``K`` -- a ring
|
|
134
|
+
|
|
135
|
+
- ``ainvs`` -- list or tuple `[a_1, a_2, a_3, a_4, a_6]` of
|
|
136
|
+
Weierstrass coefficients
|
|
137
|
+
|
|
138
|
+
.. NOTE::
|
|
139
|
+
|
|
140
|
+
This class should not be called directly; use
|
|
141
|
+
:class:`sage.constructor.EllipticCurve` to construct
|
|
142
|
+
elliptic curves.
|
|
143
|
+
|
|
144
|
+
EXAMPLES::
|
|
145
|
+
|
|
146
|
+
sage: E = EllipticCurve([1,2,3,4,5]); E
|
|
147
|
+
Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5
|
|
148
|
+
over Rational Field
|
|
149
|
+
sage: E = EllipticCurve(GF(7), [1,2,3,4,5]); E
|
|
150
|
+
Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5
|
|
151
|
+
over Finite Field of size 7
|
|
152
|
+
|
|
153
|
+
Constructor from `[a_4,a_6]` sets `a_1=a_2=a_3=0`::
|
|
154
|
+
|
|
155
|
+
sage: EllipticCurve([4,5]).ainvs()
|
|
156
|
+
(0, 0, 0, 4, 5)
|
|
157
|
+
|
|
158
|
+
The base ring need not be a field::
|
|
159
|
+
|
|
160
|
+
sage: EllipticCurve(IntegerModRing(91), [1,2,3,4,5])
|
|
161
|
+
Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5
|
|
162
|
+
over Ring of integers modulo 91
|
|
163
|
+
"""
|
|
164
|
+
self.__base_ring = K
|
|
165
|
+
self.__ainvs = tuple(K(a) for a in ainvs)
|
|
166
|
+
if self.discriminant() == 0:
|
|
167
|
+
raise ArithmeticError(self._equation_string() + " defines a singular curve")
|
|
168
|
+
PP = projective_space.ProjectiveSpace(2, K, names='xyz')
|
|
169
|
+
x, y, z = PP.coordinate_ring().gens()
|
|
170
|
+
a1, a2, a3, a4, a6 = ainvs
|
|
171
|
+
f = y**2*z + (a1*x + a3*z)*y*z \
|
|
172
|
+
- (x**3 + a2*x**2*z + a4*x*z**2 + a6*z**3)
|
|
173
|
+
plane_curve.ProjectivePlaneCurve.__init__(self, PP, f, category=category)
|
|
174
|
+
|
|
175
|
+
self.__divpolys = ({}, {}, {})
|
|
176
|
+
|
|
177
|
+
_point = ell_point.EllipticCurvePoint
|
|
178
|
+
|
|
179
|
+
def assume_base_ring_is_field(self, flag=True):
|
|
180
|
+
r"""
|
|
181
|
+
Set a flag to pretend that this elliptic curve is defined over a
|
|
182
|
+
field while doing arithmetic, which is useful in some algorithms.
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
.. WARNING::
|
|
186
|
+
|
|
187
|
+
The flag affects all points created while the flag is set. Note
|
|
188
|
+
that elliptic curves are unique parents, hence setting this flag
|
|
189
|
+
may break seemingly unrelated parts of Sage.
|
|
190
|
+
|
|
191
|
+
.. NOTE::
|
|
192
|
+
|
|
193
|
+
This method is a **hack** provided for educational purposes.
|
|
194
|
+
|
|
195
|
+
EXAMPLES::
|
|
196
|
+
|
|
197
|
+
sage: E = EllipticCurve(Zmod(35), [1,1])
|
|
198
|
+
sage: P = E(-5, 9)
|
|
199
|
+
sage: 4*P
|
|
200
|
+
(23 : 26 : 1)
|
|
201
|
+
sage: 9*P
|
|
202
|
+
(10 : 11 : 5)
|
|
203
|
+
sage: E.assume_base_ring_is_field()
|
|
204
|
+
sage: P = E(-5, 9)
|
|
205
|
+
sage: 4*P
|
|
206
|
+
(23 : 26 : 1)
|
|
207
|
+
sage: 9*P
|
|
208
|
+
Traceback (most recent call last):
|
|
209
|
+
...
|
|
210
|
+
ZeroDivisionError: Inverse of 5 does not exist (characteristic = 35 = 5*7)
|
|
211
|
+
"""
|
|
212
|
+
if flag:
|
|
213
|
+
if self.__base_ring.is_finite():
|
|
214
|
+
self._point = ell_point.EllipticCurvePoint_finite_field
|
|
215
|
+
else:
|
|
216
|
+
self._point = ell_point.EllipticCurvePoint_field
|
|
217
|
+
else:
|
|
218
|
+
self._point = ell_point.EllipticCurvePoint
|
|
219
|
+
|
|
220
|
+
def _defining_params_(self):
|
|
221
|
+
r"""
|
|
222
|
+
Internal function. Return a tuple of the base ring of this
|
|
223
|
+
elliptic curve and its `a`-invariants, from which it can be
|
|
224
|
+
reconstructed.
|
|
225
|
+
|
|
226
|
+
EXAMPLES::
|
|
227
|
+
|
|
228
|
+
sage: E = EllipticCurve(QQ,[1,1])
|
|
229
|
+
sage: E._defining_params_()
|
|
230
|
+
(Rational Field, [0, 0, 0, 1, 1])
|
|
231
|
+
sage: EllipticCurve(*E._defining_params_()) == E
|
|
232
|
+
True
|
|
233
|
+
"""
|
|
234
|
+
return (self.__base_ring, list(self.__ainvs))
|
|
235
|
+
|
|
236
|
+
def _equation_string(self):
|
|
237
|
+
"""
|
|
238
|
+
String representation of the equation of elliptic curve.
|
|
239
|
+
|
|
240
|
+
EXAMPLES::
|
|
241
|
+
|
|
242
|
+
sage: E = EllipticCurve([1,2,3,4,5]); E._equation_string()
|
|
243
|
+
'y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5'
|
|
244
|
+
"""
|
|
245
|
+
b = self.ainvs()
|
|
246
|
+
a = [z._coeff_repr() for z in b]
|
|
247
|
+
s = "y^2"
|
|
248
|
+
if a[0] == "-1":
|
|
249
|
+
s += " - x*y"
|
|
250
|
+
elif a[0] == '1':
|
|
251
|
+
s += " + x*y"
|
|
252
|
+
elif b[0]:
|
|
253
|
+
s += " + %s*x*y" % a[0]
|
|
254
|
+
if a[2] == "-1":
|
|
255
|
+
s += " - y"
|
|
256
|
+
elif a[2] == '1':
|
|
257
|
+
s += " + y"
|
|
258
|
+
elif b[2]:
|
|
259
|
+
s += " + %s*y" % a[2]
|
|
260
|
+
s += " = x^3"
|
|
261
|
+
if a[1] == "-1":
|
|
262
|
+
s += " - x^2"
|
|
263
|
+
elif a[1] == '1':
|
|
264
|
+
s += " + x^2"
|
|
265
|
+
elif b[1]:
|
|
266
|
+
s += " + %s*x^2" % a[1]
|
|
267
|
+
if a[3] == "-1":
|
|
268
|
+
s += " - x"
|
|
269
|
+
elif a[3] == '1':
|
|
270
|
+
s += " + x"
|
|
271
|
+
elif b[3]:
|
|
272
|
+
s += " + %s*x" % a[3]
|
|
273
|
+
if a[4] == '-1':
|
|
274
|
+
s += " - 1"
|
|
275
|
+
elif a[4] == '1':
|
|
276
|
+
s += " + 1"
|
|
277
|
+
elif b[4]:
|
|
278
|
+
s += " + %s" % a[4]
|
|
279
|
+
return s.replace("+ -","- ")
|
|
280
|
+
|
|
281
|
+
def _repr_(self):
|
|
282
|
+
"""
|
|
283
|
+
String representation of elliptic curve.
|
|
284
|
+
|
|
285
|
+
EXAMPLES::
|
|
286
|
+
|
|
287
|
+
sage: E = EllipticCurve([1,2,3,4,5]); E._repr_()
|
|
288
|
+
'Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Rational Field'
|
|
289
|
+
|
|
290
|
+
::
|
|
291
|
+
|
|
292
|
+
sage: R.<x> = QQ['x']
|
|
293
|
+
sage: K.<a> = NumberField(x^3 - 17) # needs sage.rings.number_field
|
|
294
|
+
sage: EllipticCurve([a^2 - 3, -2/3*a + 3]) # needs sage.rings.number_field
|
|
295
|
+
Elliptic Curve defined by y^2 = x^3 + (a^2-3)*x + (-2/3*a+3)
|
|
296
|
+
over Number Field in a
|
|
297
|
+
with defining polynomial x^3 - 17
|
|
298
|
+
"""
|
|
299
|
+
s = "Elliptic Curve defined by "
|
|
300
|
+
s += self._equation_string()
|
|
301
|
+
s += " over %s" % self.base_ring()
|
|
302
|
+
return s
|
|
303
|
+
|
|
304
|
+
def _latex_(self):
|
|
305
|
+
"""
|
|
306
|
+
Internal function. Return a latex string for this elliptic curve.
|
|
307
|
+
|
|
308
|
+
Users will normally use :func:`latex` instead.
|
|
309
|
+
|
|
310
|
+
EXAMPLES::
|
|
311
|
+
|
|
312
|
+
sage: E = EllipticCurve(QQ, [1,1])
|
|
313
|
+
sage: E._latex_()
|
|
314
|
+
'y^2 = x^{3} + x + 1 '
|
|
315
|
+
|
|
316
|
+
sage: E = EllipticCurve(QQ, [1,2,3,4,5])
|
|
317
|
+
sage: E._latex_()
|
|
318
|
+
'y^2 + x y + 3 y = x^{3} + 2 x^{2} + 4 x + 5 '
|
|
319
|
+
|
|
320
|
+
Check that :issue:`12524` is solved::
|
|
321
|
+
|
|
322
|
+
sage: x = polygen(ZZ, 'x')
|
|
323
|
+
sage: K.<phi> = NumberField(x^2 - x - 1) # needs sage.rings.number_field
|
|
324
|
+
sage: E = EllipticCurve([0, 0, phi, 27*phi - 43, -80*phi + 128]) # needs sage.rings.number_field
|
|
325
|
+
sage: E._latex_() # needs sage.rings.number_field
|
|
326
|
+
'y^2 + \\phi y = x^{3} + \\left(27 \\phi - 43\\right) x - 80 \\phi + 128 '
|
|
327
|
+
"""
|
|
328
|
+
from sage.rings.polynomial.polynomial_ring import polygen
|
|
329
|
+
a = self.ainvs()
|
|
330
|
+
x, y = polygen(self.base_ring(), 'x, y')
|
|
331
|
+
s = "y^2"
|
|
332
|
+
if a[0] or a[2]:
|
|
333
|
+
s += " + " + (a[0]*x*y + a[2]*y)._latex_()
|
|
334
|
+
s += " = "
|
|
335
|
+
s += (x**3 + a[1]*x**2 + a[3]*x + a[4])._latex_()
|
|
336
|
+
s += " "
|
|
337
|
+
s = s.replace("+ -","- ")
|
|
338
|
+
return s
|
|
339
|
+
|
|
340
|
+
def _pari_init_(self):
|
|
341
|
+
"""
|
|
342
|
+
Internal function. Return a string to initialize this elliptic
|
|
343
|
+
curve in the PARI system.
|
|
344
|
+
|
|
345
|
+
EXAMPLES::
|
|
346
|
+
|
|
347
|
+
sage: E = EllipticCurve(QQ,[1,1])
|
|
348
|
+
sage: E._pari_init_()
|
|
349
|
+
'ellinit([0/1,0/1,0/1,1/1,1/1])'
|
|
350
|
+
"""
|
|
351
|
+
return 'ellinit([%s])' % (','.join(x._pari_init_()
|
|
352
|
+
for x in self.ainvs()))
|
|
353
|
+
|
|
354
|
+
def _magma_init_(self, magma):
|
|
355
|
+
"""
|
|
356
|
+
Internal function. Return a string to initialize this elliptic
|
|
357
|
+
curve in the Magma subsystem.
|
|
358
|
+
|
|
359
|
+
EXAMPLES::
|
|
360
|
+
|
|
361
|
+
sage: # optional - magma
|
|
362
|
+
sage: E = EllipticCurve(QQ, [1,1])
|
|
363
|
+
sage: E._magma_init_(magma)
|
|
364
|
+
'EllipticCurve([_sage_ref...|0/1,0/1,0/1,1/1,1/1])'
|
|
365
|
+
sage: E = EllipticCurve(GF(41), [2,5])
|
|
366
|
+
sage: E._magma_init_(magma)
|
|
367
|
+
'EllipticCurve([_sage_ref...|GF(41)!0,GF(41)!0,GF(41)!0,GF(41)!2,GF(41)!5])'
|
|
368
|
+
sage: E = EllipticCurve(GF(25,'a'), [0,0,1,4,0]) # needs sage.rings.finite_rings
|
|
369
|
+
sage: magma(E) # needs sage.rings.finite_rings
|
|
370
|
+
Elliptic Curve defined by y^2 + y = x^3 + 4*x over GF(5^2)
|
|
371
|
+
sage: magma(EllipticCurve([1/2,2/3,-4/5,6/7,8/9]))
|
|
372
|
+
Elliptic Curve defined by y^2 + 1/2*x*y - 4/5*y = x^3 + 2/3*x^2 + 6/7*x + 8/9 over Rational Field
|
|
373
|
+
sage: R.<x> = Frac(QQ['x'])
|
|
374
|
+
sage: magma(EllipticCurve([x, 1 + x]))
|
|
375
|
+
Elliptic Curve defined by y^2 = x^3 + x*x + (x + 1)
|
|
376
|
+
over Univariate rational function field over Rational Field
|
|
377
|
+
"""
|
|
378
|
+
kmn = magma(self.base_ring())._ref()
|
|
379
|
+
return 'EllipticCurve([%s|%s])' % (kmn,','.join(x._magma_init_(magma)
|
|
380
|
+
for x in self.ainvs()))
|
|
381
|
+
|
|
382
|
+
def _symbolic_(self, SR):
|
|
383
|
+
r"""
|
|
384
|
+
Many elliptic curves can be converted into a symbolic expression
|
|
385
|
+
using the ``symbolic_expression`` command.
|
|
386
|
+
|
|
387
|
+
EXAMPLES: We find a torsion point on 11a.
|
|
388
|
+
|
|
389
|
+
::
|
|
390
|
+
|
|
391
|
+
sage: E = EllipticCurve('11a')
|
|
392
|
+
sage: E._symbolic_(SR) # needs sage.symbolic
|
|
393
|
+
y^2 + y == x^3 - x^2 - 10*x - 20
|
|
394
|
+
sage: E.torsion_subgroup().gens() # needs sage.symbolic
|
|
395
|
+
((5 : 5 : 1),)
|
|
396
|
+
|
|
397
|
+
We find the corresponding symbolic equality::
|
|
398
|
+
|
|
399
|
+
sage: eqn = symbolic_expression(E); eqn # needs sage.symbolic
|
|
400
|
+
y^2 + y == x^3 - x^2 - 10*x - 20
|
|
401
|
+
|
|
402
|
+
We verify that the given point is on the curve::
|
|
403
|
+
|
|
404
|
+
sage: eqn(x=5, y=5) # needs sage.symbolic
|
|
405
|
+
30 == 30
|
|
406
|
+
sage: bool(eqn(x=5, y=5)) # needs sage.symbolic
|
|
407
|
+
True
|
|
408
|
+
|
|
409
|
+
We create a single expression::
|
|
410
|
+
|
|
411
|
+
sage: F = eqn.lhs() - eqn.rhs(); F # needs sage.symbolic
|
|
412
|
+
-x^3 + x^2 + y^2 + 10*x + y + 20
|
|
413
|
+
sage: y = var('y') # needs sage.symbolic
|
|
414
|
+
sage: F.solve(y) # needs sage.symbolic
|
|
415
|
+
[y == -1/2*sqrt(4*x^3 - 4*x^2 - 40*x - 79) - 1/2,
|
|
416
|
+
y == 1/2*sqrt(4*x^3 - 4*x^2 - 40*x - 79) - 1/2]
|
|
417
|
+
|
|
418
|
+
You can also solve for x in terms of y, but the result is
|
|
419
|
+
horrendous. Continuing with the above example, we can explicitly
|
|
420
|
+
find points over random fields by substituting in values for x::
|
|
421
|
+
|
|
422
|
+
sage: # needs sage.symbolic
|
|
423
|
+
sage: v = F.solve(y)[0].rhs(); v
|
|
424
|
+
-1/2*sqrt(4*x^3 - 4*x^2 - 40*x - 79) - 1/2
|
|
425
|
+
sage: v = v.function(x)
|
|
426
|
+
sage: v(3)
|
|
427
|
+
-1/2*sqrt(-127) - 1/2
|
|
428
|
+
sage: v(7)
|
|
429
|
+
-1/2*sqrt(817) - 1/2
|
|
430
|
+
sage: v(-7)
|
|
431
|
+
-1/2*sqrt(-1367) - 1/2
|
|
432
|
+
sage: v(sqrt(2))
|
|
433
|
+
-1/2*sqrt(-32*sqrt(2) - 87) - 1/2
|
|
434
|
+
|
|
435
|
+
We can even do arithmetic with them, as follows::
|
|
436
|
+
|
|
437
|
+
sage: # needs sage.symbolic
|
|
438
|
+
sage: E2 = E.change_ring(SR); E2
|
|
439
|
+
Elliptic Curve defined by y^2 + y = x^3 + (-1)*x^2 + (-10)*x + (-20)
|
|
440
|
+
over Symbolic Ring
|
|
441
|
+
sage: P = E2.point((3, v(3), 1), check=False) # the check=False option doesn't verify that y^2 = f(x)
|
|
442
|
+
sage: P
|
|
443
|
+
(3 : -1/2*sqrt(-127) - 1/2 : 1)
|
|
444
|
+
sage: P + P
|
|
445
|
+
(-756/127 : 41143/32258*sqrt(-127) - 1/2 : 1)
|
|
446
|
+
|
|
447
|
+
We can even throw in a transcendental::
|
|
448
|
+
|
|
449
|
+
sage: w = E2.point((pi,v(pi),1), check=False); w # needs sage.symbolic
|
|
450
|
+
(pi : -1/2*sqrt(-40*pi + 4*pi^3 - 4*pi^2 - 79) - 1/2 : 1)
|
|
451
|
+
sage: x, y, z = w; ((y^2 + y) - (x^3 - x^2 - 10*x - 20)).expand() # needs sage.symbolic
|
|
452
|
+
0
|
|
453
|
+
|
|
454
|
+
sage: 2*w # needs sage.symbolic
|
|
455
|
+
(-2*pi - (2*pi - 3*pi^2 + 10)^2/(40*pi - 4*pi^3 + 4*pi^2 + 79) + 1 : (3*pi + (2*pi - 3*pi^2 + 10)^2/(40*pi - 4*pi^3 + 4*pi^2 + 79) - 1)*(2*pi - 3*pi^2 + 10)/sqrt(-40*pi + 4*pi^3 - 4*pi^2 - 79) + 1/2*sqrt(-40*pi + 4*pi^3 - 4*pi^2 - 79) - 1/2 : 1)
|
|
456
|
+
|
|
457
|
+
sage: x, y, z = 2*w; temp = ((y^2 + y) - (x^3 - x^2 - 10*x - 20)) # needs sage.symbolic
|
|
458
|
+
|
|
459
|
+
This is a point on the curve::
|
|
460
|
+
|
|
461
|
+
sage: bool(temp == 0) # needs sage.symbolic
|
|
462
|
+
True
|
|
463
|
+
"""
|
|
464
|
+
a = [SR(x) for x in self.a_invariants()]
|
|
465
|
+
x, y = SR.var('x, y')
|
|
466
|
+
return y**2 + a[0]*x*y + a[2]*y == x**3 + a[1]*x**2 + a[3]*x + a[4]
|
|
467
|
+
|
|
468
|
+
def __contains__(self, P):
|
|
469
|
+
"""
|
|
470
|
+
Return ``True`` if and only if P is a point on the elliptic curve.
|
|
471
|
+
|
|
472
|
+
P just has to be something that can be coerced to a point.
|
|
473
|
+
|
|
474
|
+
EXAMPLES::
|
|
475
|
+
|
|
476
|
+
sage: E = EllipticCurve([0, 0, 1, -1, 0])
|
|
477
|
+
sage: (0,0) in E
|
|
478
|
+
True
|
|
479
|
+
sage: (1,3) in E
|
|
480
|
+
False
|
|
481
|
+
sage: E = EllipticCurve([GF(7)(0), 1])
|
|
482
|
+
sage: [0,0] in E
|
|
483
|
+
False
|
|
484
|
+
sage: [0,8] in E
|
|
485
|
+
True
|
|
486
|
+
sage: P = E(0,8)
|
|
487
|
+
sage: P
|
|
488
|
+
(0 : 1 : 1)
|
|
489
|
+
sage: P in E
|
|
490
|
+
True
|
|
491
|
+
"""
|
|
492
|
+
if not isinstance(P, ell_point.EllipticCurvePoint):
|
|
493
|
+
try:
|
|
494
|
+
P = self(P)
|
|
495
|
+
except TypeError:
|
|
496
|
+
return False
|
|
497
|
+
return P.curve() == self
|
|
498
|
+
|
|
499
|
+
def __call__(self, *args, **kwds):
|
|
500
|
+
r"""
|
|
501
|
+
EXAMPLES::
|
|
502
|
+
|
|
503
|
+
sage: E = EllipticCurve([0, 0, 1, -1, 0])
|
|
504
|
+
|
|
505
|
+
The point at infinity, which is the 0 element of the group::
|
|
506
|
+
|
|
507
|
+
sage: E(0)
|
|
508
|
+
(0 : 1 : 0)
|
|
509
|
+
|
|
510
|
+
The origin is a point on our curve::
|
|
511
|
+
|
|
512
|
+
sage: P = E([0,0])
|
|
513
|
+
sage: P
|
|
514
|
+
(0 : 0 : 1)
|
|
515
|
+
|
|
516
|
+
The curve associated to a point::
|
|
517
|
+
|
|
518
|
+
sage: P.curve()
|
|
519
|
+
Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
|
|
520
|
+
|
|
521
|
+
Points can be specified by given a 2-tuple or 3-tuple::
|
|
522
|
+
|
|
523
|
+
sage: E([0,0])
|
|
524
|
+
(0 : 0 : 1)
|
|
525
|
+
sage: E([0,1,0])
|
|
526
|
+
(0 : 1 : 0)
|
|
527
|
+
|
|
528
|
+
Over a field, points are normalized so the 3rd entry (if nonzero)
|
|
529
|
+
is 1::
|
|
530
|
+
|
|
531
|
+
sage: E(105, -69, 125)
|
|
532
|
+
(21/25 : -69/125 : 1)
|
|
533
|
+
|
|
534
|
+
We create points on an elliptic curve over a prime finite field::
|
|
535
|
+
|
|
536
|
+
sage: E = EllipticCurve([GF(7)(0), 1])
|
|
537
|
+
sage: E([2,3])
|
|
538
|
+
(2 : 3 : 1)
|
|
539
|
+
sage: E([0,0])
|
|
540
|
+
Traceback (most recent call last):
|
|
541
|
+
...
|
|
542
|
+
TypeError: Coordinates [0, 0, 1] do not define a point
|
|
543
|
+
on Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 7
|
|
544
|
+
|
|
545
|
+
We create a point on an elliptic curve over a number field::
|
|
546
|
+
|
|
547
|
+
sage: # needs sage.rings.number_field
|
|
548
|
+
sage: x = polygen(RationalField())
|
|
549
|
+
sage: K = NumberField(x**3 + x + 1, 'a'); a = K.gen()
|
|
550
|
+
sage: E = EllipticCurve([a, a])
|
|
551
|
+
sage: E
|
|
552
|
+
Elliptic Curve defined by y^2 = x^3 + a*x + a
|
|
553
|
+
over Number Field in a with defining polynomial x^3 + x + 1
|
|
554
|
+
sage: E = EllipticCurve([K(1), 1])
|
|
555
|
+
sage: E
|
|
556
|
+
Elliptic Curve defined by y^2 = x^3 + x + 1
|
|
557
|
+
over Number Field in a with defining polynomial x^3 + x + 1
|
|
558
|
+
sage: P = E([a,0,1])
|
|
559
|
+
sage: P
|
|
560
|
+
(a : 0 : 1)
|
|
561
|
+
sage: P + P
|
|
562
|
+
(0 : 1 : 0)
|
|
563
|
+
|
|
564
|
+
Another example involving `p`-adics::
|
|
565
|
+
|
|
566
|
+
sage: E = EllipticCurve('37a1')
|
|
567
|
+
sage: P = E([0,0]); P
|
|
568
|
+
(0 : 0 : 1)
|
|
569
|
+
sage: R = pAdicField(3, 20) # needs sage.rings.padics
|
|
570
|
+
sage: Ep = E.base_extend(R); Ep # needs sage.rings.padics
|
|
571
|
+
Elliptic Curve defined by
|
|
572
|
+
y^2 + (1+O(3^20))*y = x^3 + (2+2*3+2*3^2+2*3^3+2*3^4+2*3^5+2*3^6+2*3^7+2*3^8+2*3^9+2*3^10+2*3^11+2*3^12+2*3^13+2*3^14+2*3^15+2*3^16+2*3^17+2*3^18+2*3^19+O(3^20))*x
|
|
573
|
+
over 3-adic Field with capped relative precision 20
|
|
574
|
+
sage: Ep(P) # needs sage.rings.padics
|
|
575
|
+
(0 : 0 : 1 + O(3^20))
|
|
576
|
+
|
|
577
|
+
Constructing points from the torsion subgroup (which is an abstract
|
|
578
|
+
abelian group)::
|
|
579
|
+
|
|
580
|
+
sage: E = EllipticCurve('14a1')
|
|
581
|
+
sage: T = E.torsion_subgroup()
|
|
582
|
+
sage: [E(t) for t in T]
|
|
583
|
+
[(0 : 1 : 0),
|
|
584
|
+
(9 : 23 : 1),
|
|
585
|
+
(2 : 2 : 1),
|
|
586
|
+
(1 : -1 : 1),
|
|
587
|
+
(2 : -5 : 1),
|
|
588
|
+
(9 : -33 : 1)]
|
|
589
|
+
|
|
590
|
+
::
|
|
591
|
+
|
|
592
|
+
sage: E = EllipticCurve([0,0,0,-49,0])
|
|
593
|
+
sage: T = E.torsion_subgroup()
|
|
594
|
+
sage: [E(t) for t in T]
|
|
595
|
+
[(0 : 1 : 0), (0 : 0 : 1), (-7 : 0 : 1), (7 : 0 : 1)]
|
|
596
|
+
|
|
597
|
+
::
|
|
598
|
+
|
|
599
|
+
sage: E = EllipticCurve('37a1')
|
|
600
|
+
sage: T = E.torsion_subgroup()
|
|
601
|
+
sage: [E(t) for t in T]
|
|
602
|
+
[(0 : 1 : 0)]
|
|
603
|
+
"""
|
|
604
|
+
if len(args) == 1 and args[0] == 0:
|
|
605
|
+
R = self.base_ring()
|
|
606
|
+
return self.point([R(0),R(1),R(0)], check=False)
|
|
607
|
+
P = args[0]
|
|
608
|
+
if isinstance(P, groups.AdditiveAbelianGroupElement) and isinstance(P.parent(),ell_torsion.EllipticCurveTorsionSubgroup):
|
|
609
|
+
return self(P.element())
|
|
610
|
+
if isinstance(args[0], ell_point.EllipticCurvePoint):
|
|
611
|
+
if P.curve() is self:
|
|
612
|
+
return P
|
|
613
|
+
# check if denominator of the point contains a factor of the
|
|
614
|
+
# characteristic of the base ring. if so, coerce the point to
|
|
615
|
+
# infinity.
|
|
616
|
+
characteristic = self.base_ring().characteristic()
|
|
617
|
+
if characteristic != 0 and isinstance(args[0][0], Rational) and isinstance(args[0][1], Rational):
|
|
618
|
+
if characteristic.divides(args[0][0].denominator()) or characteristic.divides(args[0][1].denominator()):
|
|
619
|
+
return self._reduce_point(args[0], characteristic)
|
|
620
|
+
args = tuple(args[0])
|
|
621
|
+
|
|
622
|
+
return plane_curve.ProjectivePlaneCurve.__call__(self, *args, **kwds)
|
|
623
|
+
|
|
624
|
+
def _reduce_point(self, R, p):
|
|
625
|
+
r"""
|
|
626
|
+
Reduces a point R on an elliptic curve to the corresponding point on
|
|
627
|
+
the elliptic curve reduced modulo p.
|
|
628
|
+
|
|
629
|
+
Used to coerce points between
|
|
630
|
+
curves when p is a factor of the denominator of one of the
|
|
631
|
+
coordinates.
|
|
632
|
+
|
|
633
|
+
This functionality is used internally in the ``call`` method for
|
|
634
|
+
elliptic curves.
|
|
635
|
+
|
|
636
|
+
INPUT:
|
|
637
|
+
|
|
638
|
+
- ``R`` -- a point on an elliptic curve
|
|
639
|
+
- ``p`` -- a prime
|
|
640
|
+
|
|
641
|
+
OUTPUT: S; the corresponding point of the elliptic curve containing
|
|
642
|
+
R, but reduced modulo p
|
|
643
|
+
|
|
644
|
+
EXAMPLES:
|
|
645
|
+
|
|
646
|
+
Suppose we have a point with large height on a rational elliptic curve
|
|
647
|
+
whose denominator contains a factor of 11::
|
|
648
|
+
|
|
649
|
+
sage: E = EllipticCurve([1,-1,0,94,9])
|
|
650
|
+
sage: R = E([0,3]) + 5*E([8,31])
|
|
651
|
+
sage: factor(R.x().denominator())
|
|
652
|
+
2^2 * 11^2 * 1457253032371^2
|
|
653
|
+
|
|
654
|
+
Since 11 is a factor of the denominator, this point corresponds to the
|
|
655
|
+
point at infinity on the same curve but reduced modulo 11. The reduce
|
|
656
|
+
function tells us this::
|
|
657
|
+
|
|
658
|
+
sage: E11 = E.change_ring(GF(11))
|
|
659
|
+
sage: S = E11._reduce_point(R, 11)
|
|
660
|
+
sage: E11(S)
|
|
661
|
+
(0 : 1 : 0)
|
|
662
|
+
|
|
663
|
+
The 0 point reduces as expected::
|
|
664
|
+
|
|
665
|
+
sage: E11._reduce_point(E(0), 11)
|
|
666
|
+
(0 : 1 : 0)
|
|
667
|
+
|
|
668
|
+
Note that one need not explicitly call
|
|
669
|
+
\code{EllipticCurve._reduce_point}
|
|
670
|
+
"""
|
|
671
|
+
if R.is_zero():
|
|
672
|
+
return R.curve().change_ring(GF(p))(0)
|
|
673
|
+
x, y = R.xy()
|
|
674
|
+
d = lcm(x.denominator(), y.denominator())
|
|
675
|
+
return R.curve().change_ring(GF(p))([x*d, y*d, d])
|
|
676
|
+
|
|
677
|
+
def is_x_coord(self, x):
|
|
678
|
+
r"""
|
|
679
|
+
Return ``True`` if ``x`` is the `x`-coordinate of a point on this curve.
|
|
680
|
+
|
|
681
|
+
.. NOTE::
|
|
682
|
+
|
|
683
|
+
See also :meth:`lift_x` to find the point(s) with a given
|
|
684
|
+
`x`-coordinate. This function may be useful in cases where
|
|
685
|
+
testing an element of the base field for being a square is
|
|
686
|
+
faster than finding its square root.
|
|
687
|
+
|
|
688
|
+
EXAMPLES::
|
|
689
|
+
|
|
690
|
+
sage: E = EllipticCurve('37a'); E
|
|
691
|
+
Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
|
|
692
|
+
sage: E.is_x_coord(1)
|
|
693
|
+
True
|
|
694
|
+
sage: E.is_x_coord(2)
|
|
695
|
+
True
|
|
696
|
+
|
|
697
|
+
There are no rational points with x-coordinate 3::
|
|
698
|
+
|
|
699
|
+
sage: E.is_x_coord(3)
|
|
700
|
+
False
|
|
701
|
+
|
|
702
|
+
However, there are such points in `E(\RR)`::
|
|
703
|
+
|
|
704
|
+
sage: E.change_ring(RR).is_x_coord(3)
|
|
705
|
+
True
|
|
706
|
+
|
|
707
|
+
And of course it always works in `E(\CC)`::
|
|
708
|
+
|
|
709
|
+
sage: E.change_ring(RR).is_x_coord(-3)
|
|
710
|
+
False
|
|
711
|
+
sage: E.change_ring(CC).is_x_coord(-3)
|
|
712
|
+
True
|
|
713
|
+
|
|
714
|
+
AUTHORS:
|
|
715
|
+
|
|
716
|
+
- John Cremona (2008-08-07): adapted from :meth:`lift_x`
|
|
717
|
+
|
|
718
|
+
TESTS::
|
|
719
|
+
|
|
720
|
+
sage: E = EllipticCurve('5077a1')
|
|
721
|
+
sage: [x for x in srange(-10,10) if E.is_x_coord (x)]
|
|
722
|
+
[-3, -2, -1, 0, 1, 2, 3, 4, 8]
|
|
723
|
+
|
|
724
|
+
::
|
|
725
|
+
|
|
726
|
+
sage: F = GF(32,'a') # needs sage.rings.finite_rings
|
|
727
|
+
sage: E = EllipticCurve(F,[1,0,0,0,1]) # needs sage.rings.finite_rings
|
|
728
|
+
sage: set(P[0] for P in E.points() if P!=E(0)) == set(x for x in F if E.is_x_coord(x)) # needs sage.rings.finite_rings
|
|
729
|
+
True
|
|
730
|
+
"""
|
|
731
|
+
K = self.base_ring()
|
|
732
|
+
try:
|
|
733
|
+
x = K(x)
|
|
734
|
+
except TypeError:
|
|
735
|
+
raise TypeError('x must be coercible into the base ring of the curve')
|
|
736
|
+
a1, a2, a3, a4, a6 = self.ainvs()
|
|
737
|
+
fx = ((x + a2) * x + a4) * x + a6
|
|
738
|
+
if a1.is_zero() and a3.is_zero():
|
|
739
|
+
return fx.is_square()
|
|
740
|
+
b = (a1*x + a3)
|
|
741
|
+
if K.characteristic() == 2:
|
|
742
|
+
R = PolynomialRing(K, 'y')
|
|
743
|
+
F = R([-fx,b,1])
|
|
744
|
+
return bool(F.roots())
|
|
745
|
+
D = b*b + 4*fx
|
|
746
|
+
return D.is_square()
|
|
747
|
+
|
|
748
|
+
def lift_x(self, x, all=False, extend=False):
|
|
749
|
+
r"""
|
|
750
|
+
Return one or all points with given `x`-coordinate.
|
|
751
|
+
|
|
752
|
+
This method is deterministic: It returns the same data each
|
|
753
|
+
time when called again with the same `x`.
|
|
754
|
+
|
|
755
|
+
INPUT:
|
|
756
|
+
|
|
757
|
+
- ``x`` -- an element of the base ring of the curve, or of an extension
|
|
758
|
+
|
|
759
|
+
- ``all`` -- boolean (default: ``False``); if ``True``, return a
|
|
760
|
+
(possibly empty) list of all points; if ``False``, return just one
|
|
761
|
+
point, or raise a :exc:`ValueError` if there are none.
|
|
762
|
+
|
|
763
|
+
- ``extend`` -- boolean (default: ``False``);
|
|
764
|
+
|
|
765
|
+
- if ``False``, extend the base if necessary and possible to
|
|
766
|
+
include `x`, and only return point(s) defined over this
|
|
767
|
+
ring, or raise an error when there are none with this
|
|
768
|
+
`x`-coordinate;
|
|
769
|
+
|
|
770
|
+
- If ``True``, the base ring will be extended if necessary
|
|
771
|
+
to contain the `y`-coordinates of the point(s) with this
|
|
772
|
+
`x`-coordinate, in addition to a possible base change to
|
|
773
|
+
include `x`.
|
|
774
|
+
|
|
775
|
+
OUTPUT:
|
|
776
|
+
|
|
777
|
+
A point or list of up to 2 points on this curve, or a
|
|
778
|
+
base-change of this curve to a larger ring.
|
|
779
|
+
|
|
780
|
+
.. SEEALSO::
|
|
781
|
+
|
|
782
|
+
:meth:`is_x_coord`
|
|
783
|
+
|
|
784
|
+
EXAMPLES::
|
|
785
|
+
|
|
786
|
+
sage: E = EllipticCurve('37a'); E
|
|
787
|
+
Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
|
|
788
|
+
sage: E.lift_x(1)
|
|
789
|
+
(1 : -1 : 1)
|
|
790
|
+
sage: E.lift_x(2)
|
|
791
|
+
(2 : -3 : 1)
|
|
792
|
+
sage: E.lift_x(1/4, all=True)
|
|
793
|
+
[(1/4 : -5/8 : 1), (1/4 : -3/8 : 1)]
|
|
794
|
+
|
|
795
|
+
There are no rational points with `x`-coordinate 3::
|
|
796
|
+
|
|
797
|
+
sage: E.lift_x(3)
|
|
798
|
+
Traceback (most recent call last):
|
|
799
|
+
...
|
|
800
|
+
ValueError: No point with x-coordinate 3
|
|
801
|
+
on Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
|
|
802
|
+
|
|
803
|
+
We can use the ``extend`` parameter to make the necessary
|
|
804
|
+
quadratic extension. Note that in such cases the returned
|
|
805
|
+
point is a point on a new curve object, the result of changing
|
|
806
|
+
the base ring to the parent of `x`::
|
|
807
|
+
|
|
808
|
+
sage: P = E.lift_x(3, extend=True); P # needs sage.rings.number_field
|
|
809
|
+
(3 : -y - 1 : 1)
|
|
810
|
+
sage: P.curve() # needs sage.rings.number_field
|
|
811
|
+
Elliptic Curve defined by y^2 + y = x^3 + (-1)*x
|
|
812
|
+
over Number Field in y with defining polynomial y^2 + y - 24
|
|
813
|
+
|
|
814
|
+
Or we can extend scalars. There are two such points in `E(\RR)`::
|
|
815
|
+
|
|
816
|
+
sage: E.change_ring(RR).lift_x(3, all=True)
|
|
817
|
+
[(3.00000000000000 : -5.42442890089805 : 1.00000000000000),
|
|
818
|
+
(3.00000000000000 : 4.42442890089805 : 1.00000000000000)]
|
|
819
|
+
|
|
820
|
+
And of course it always works in `E(\CC)`::
|
|
821
|
+
|
|
822
|
+
sage: E.change_ring(RR).lift_x(.5, all=True)
|
|
823
|
+
[]
|
|
824
|
+
sage: E.change_ring(CC).lift_x(.5)
|
|
825
|
+
(0.500000000000000 : -0.500000000000000 - 0.353553390593274*I : 1.00000000000000)
|
|
826
|
+
|
|
827
|
+
In this example we start with a curve defined over `\QQ`
|
|
828
|
+
which has no rational points with `x=0`, but using
|
|
829
|
+
``extend = True`` we can construct such a point over a quadratic
|
|
830
|
+
field::
|
|
831
|
+
|
|
832
|
+
sage: E = EllipticCurve([0,0,0,0,2]); E
|
|
833
|
+
Elliptic Curve defined by y^2 = x^3 + 2 over Rational Field
|
|
834
|
+
sage: P = E.lift_x(0, extend=True); P # needs sage.rings.number_field
|
|
835
|
+
(0 : -y : 1)
|
|
836
|
+
sage: P.curve() # needs sage.rings.number_field
|
|
837
|
+
Elliptic Curve defined by y^2 = x^3 + 2
|
|
838
|
+
over Number Field in y with defining polynomial y^2 - 2
|
|
839
|
+
|
|
840
|
+
We can perform these operations over finite fields too::
|
|
841
|
+
|
|
842
|
+
sage: E = EllipticCurve('37a').change_ring(GF(17)); E
|
|
843
|
+
Elliptic Curve defined by y^2 + y = x^3 + 16*x over Finite Field of size 17
|
|
844
|
+
sage: E.lift_x(7)
|
|
845
|
+
(7 : 5 : 1)
|
|
846
|
+
sage: E.lift_x(3)
|
|
847
|
+
Traceback (most recent call last):
|
|
848
|
+
...
|
|
849
|
+
ValueError: No point with x-coordinate 3 on
|
|
850
|
+
Elliptic Curve defined by y^2 + y = x^3 + 16*x over Finite Field of size 17
|
|
851
|
+
|
|
852
|
+
Note that there is only one lift with `x`-coordinate 10 in
|
|
853
|
+
`E(\GF{17})`::
|
|
854
|
+
|
|
855
|
+
sage: E.lift_x(10, all=True)
|
|
856
|
+
[(10 : 8 : 1)]
|
|
857
|
+
|
|
858
|
+
We can lift over more exotic rings too. If the supplied x
|
|
859
|
+
value is in an extension of the base, note that the point
|
|
860
|
+
returned is on the base-extended curve::
|
|
861
|
+
|
|
862
|
+
sage: E = EllipticCurve('37a')
|
|
863
|
+
sage: P = E.lift_x(pAdicField(17, 5)(6)); P # needs sage.rings.padics
|
|
864
|
+
(6 + O(17^5) : 14 + O(17^5) : 1 + O(17^5))
|
|
865
|
+
sage: P.curve() # needs sage.rings.padics
|
|
866
|
+
Elliptic Curve defined by
|
|
867
|
+
y^2 + (1+O(17^5))*y = x^3 + (16+16*17+16*17^2+16*17^3+16*17^4+O(17^5))*x
|
|
868
|
+
over 17-adic Field with capped relative precision 5
|
|
869
|
+
sage: K.<t> = PowerSeriesRing(QQ, 't', 5)
|
|
870
|
+
sage: P = E.lift_x(1 + t); P
|
|
871
|
+
(1 + t : -1 - 2*t + t^2 - 5*t^3 + 21*t^4 + O(t^5) : 1)
|
|
872
|
+
sage: K.<a> = GF(16) # needs sage.rings.finite_rings
|
|
873
|
+
sage: P = E.change_ring(K).lift_x(a^3); P # needs sage.rings.finite_rings
|
|
874
|
+
(a^3 : a^3 + a : 1)
|
|
875
|
+
sage: P.curve() # needs sage.rings.finite_rings
|
|
876
|
+
Elliptic Curve defined by y^2 + y = x^3 + x over Finite Field in a of size 2^4
|
|
877
|
+
|
|
878
|
+
We can extend the base field to include the associated `y` value(s)::
|
|
879
|
+
|
|
880
|
+
sage: E = EllipticCurve([0,0,0,0,2]); E
|
|
881
|
+
Elliptic Curve defined by y^2 = x^3 + 2 over Rational Field
|
|
882
|
+
sage: x = polygen(QQ)
|
|
883
|
+
sage: P = E.lift_x(x, extend=True); P
|
|
884
|
+
(x : -y : 1)
|
|
885
|
+
|
|
886
|
+
This point is a generic point on E::
|
|
887
|
+
|
|
888
|
+
sage: P.curve()
|
|
889
|
+
Elliptic Curve defined by y^2 = x^3 + 2
|
|
890
|
+
over Univariate Quotient Polynomial Ring in y
|
|
891
|
+
over Fraction Field of Univariate Polynomial Ring in x over Rational Field
|
|
892
|
+
with modulus y^2 - x^3 - 2
|
|
893
|
+
sage: -P
|
|
894
|
+
(x : y : 1)
|
|
895
|
+
sage: 2*P
|
|
896
|
+
((1/4*x^4 - 4*x)/(x^3 + 2) : ((-1/8*x^6 - 5*x^3 + 4)/(x^6 + 4*x^3 + 4))*y : 1)
|
|
897
|
+
|
|
898
|
+
Check that :issue:`30297` is fixed::
|
|
899
|
+
|
|
900
|
+
sage: K = Qp(5) # needs sage.rings.padics
|
|
901
|
+
sage: E = EllipticCurve([K(0), K(1)]) # needs sage.rings.padics
|
|
902
|
+
sage: E.lift_x(1, extend=True) # needs sage.rings.padics
|
|
903
|
+
(1 + O(5^20) : y + O(5^20) : 1 + O(5^20))
|
|
904
|
+
|
|
905
|
+
AUTHORS:
|
|
906
|
+
|
|
907
|
+
- Robert Bradshaw (2007-04-24)
|
|
908
|
+
- John Cremona (2017-11-10)
|
|
909
|
+
|
|
910
|
+
TESTS::
|
|
911
|
+
|
|
912
|
+
sage: E = EllipticCurve('37a').short_weierstrass_model().change_ring(GF(17))
|
|
913
|
+
sage: E.lift_x(3, all=True)
|
|
914
|
+
[]
|
|
915
|
+
sage: E.lift_x(7, all=True)
|
|
916
|
+
[(7 : 3 : 1), (7 : 14 : 1)]
|
|
917
|
+
|
|
918
|
+
Check determinism::
|
|
919
|
+
|
|
920
|
+
sage: F.<t> = GF((101,3))
|
|
921
|
+
sage: {(t+1).sqrt() for _ in range(1000)} # both square roots can occur
|
|
922
|
+
{29*t^2 + 56*t + 26, 72*t^2 + 45*t + 75}
|
|
923
|
+
sage: E = EllipticCurve(F, [1,1])
|
|
924
|
+
sage: {E.lift_x(t+1) for _ in range(1000)} # but .lift_x() uses a fixed one
|
|
925
|
+
{(t + 1 : 39*t^2 + 14*t + 12 : 1)}
|
|
926
|
+
"""
|
|
927
|
+
K = self.base_ring()
|
|
928
|
+
L = x.parent()
|
|
929
|
+
E = self
|
|
930
|
+
|
|
931
|
+
# Check that the x-coordinate is in K and extend otherwise if possible:
|
|
932
|
+
phi = K.coerce_map_from(L)
|
|
933
|
+
if phi:
|
|
934
|
+
x = phi(x)
|
|
935
|
+
L = K # new parent of x
|
|
936
|
+
else:
|
|
937
|
+
if L.coerce_map_from(K):
|
|
938
|
+
E = E.change_ring(L)
|
|
939
|
+
L = E.base_ring()
|
|
940
|
+
x = L(x)
|
|
941
|
+
else:
|
|
942
|
+
raise TypeError("Unable to construct a point with x in {} over {}".format(L,K))
|
|
943
|
+
|
|
944
|
+
# Now E is defined over L, possibly an extension of K, and x is in L
|
|
945
|
+
|
|
946
|
+
a1, a2, a3, a4, a6 = E.ainvs()
|
|
947
|
+
b = (a1*x + a3)
|
|
948
|
+
f = ((x + a2) * x + a4) * x + a6
|
|
949
|
+
|
|
950
|
+
# If possible find the associated y coordinates in L:
|
|
951
|
+
|
|
952
|
+
if K.characteristic() == 2:
|
|
953
|
+
R = PolynomialRing(L, 'y')
|
|
954
|
+
F = R([-f,b,1])
|
|
955
|
+
ys = F.roots(L, multiplicities=False)
|
|
956
|
+
else:
|
|
957
|
+
D = b*b+4*f
|
|
958
|
+
ys = []
|
|
959
|
+
if D.is_square(): # avoid automatic creation of sqrts
|
|
960
|
+
ys = [(-b+d)/2 for d in D.sqrt(all=True)]
|
|
961
|
+
|
|
962
|
+
ys.sort() # ensure deterministic behavior
|
|
963
|
+
|
|
964
|
+
# Return the point(s) if any:
|
|
965
|
+
|
|
966
|
+
if ys:
|
|
967
|
+
one = L.one()
|
|
968
|
+
if all:
|
|
969
|
+
return [E.point([x, y, one], check=False) for y in ys]
|
|
970
|
+
else:
|
|
971
|
+
return E.point([x, ys[0], one], check=False)
|
|
972
|
+
|
|
973
|
+
# otherwise if the additional extension was not requested return the empty list or raise an error:
|
|
974
|
+
|
|
975
|
+
if not extend:
|
|
976
|
+
if all:
|
|
977
|
+
return []
|
|
978
|
+
else:
|
|
979
|
+
raise ValueError("No point with x-coordinate {} on {}".format(x, self))
|
|
980
|
+
|
|
981
|
+
# Now make the extension needed to contain the y-coordinates:
|
|
982
|
+
|
|
983
|
+
if K.characteristic() != 2: # else we already defined F
|
|
984
|
+
R = PolynomialRing(L, 'y')
|
|
985
|
+
F = R([-f,b,1])
|
|
986
|
+
M = L.fraction_field().extension(F, names='y')
|
|
987
|
+
EM = E.change_ring(M)
|
|
988
|
+
y1 = M.gen()
|
|
989
|
+
y2 = -b-y1
|
|
990
|
+
if y2 == y1:
|
|
991
|
+
ys = [y1]
|
|
992
|
+
else:
|
|
993
|
+
ys = [y1, y2]
|
|
994
|
+
ys.sort() # ensure deterministic behavior
|
|
995
|
+
x = M(x)
|
|
996
|
+
one = M.one()
|
|
997
|
+
if all:
|
|
998
|
+
return [EM.point([x, y, one], check=False) for y in ys]
|
|
999
|
+
else:
|
|
1000
|
+
return EM.point([x, ys[0], one], check=False)
|
|
1001
|
+
|
|
1002
|
+
def _point_homset(self, *args, **kwds):
|
|
1003
|
+
r"""
|
|
1004
|
+
Internal function. Return the (abstract) group of points on this
|
|
1005
|
+
elliptic curve over a ring.
|
|
1006
|
+
|
|
1007
|
+
EXAMPLES::
|
|
1008
|
+
|
|
1009
|
+
sage: E = EllipticCurve(GF(5),[1,1])
|
|
1010
|
+
sage: E._point_homset(Spec(GF(5^10,'a'), GF(5)), E) # needs sage.rings.finite_rings
|
|
1011
|
+
Abelian group of points on Elliptic Curve defined
|
|
1012
|
+
by y^2 = x^3 + x + 1 over Finite Field in a of size 5^10
|
|
1013
|
+
|
|
1014
|
+
Point sets of elliptic curves are unique (see :issue:`17008`)::
|
|
1015
|
+
|
|
1016
|
+
sage: E = EllipticCurve([2, 3])
|
|
1017
|
+
sage: E.point_homset() is E.point_homset(QQ)
|
|
1018
|
+
True
|
|
1019
|
+
|
|
1020
|
+
sage: @fork
|
|
1021
|
+
....: def compute_E():
|
|
1022
|
+
....: E = EllipticCurve([2, 3])
|
|
1023
|
+
....: p = E(3, 6, 1)
|
|
1024
|
+
....: return p
|
|
1025
|
+
sage: p = compute_E()
|
|
1026
|
+
sage: 2*p
|
|
1027
|
+
(-23/144 : 2827/1728 : 1)
|
|
1028
|
+
"""
|
|
1029
|
+
return SchemeHomset_points_abelian_variety_field(*args, **kwds)
|
|
1030
|
+
|
|
1031
|
+
def __getitem__(self, n):
|
|
1032
|
+
r"""
|
|
1033
|
+
Placeholder for standard indexing function.
|
|
1034
|
+
|
|
1035
|
+
EXAMPLES::
|
|
1036
|
+
|
|
1037
|
+
sage: E = EllipticCurve(QQ,[1,1])
|
|
1038
|
+
sage: E[2]
|
|
1039
|
+
Traceback (most recent call last):
|
|
1040
|
+
...
|
|
1041
|
+
NotImplementedError: not implemented.
|
|
1042
|
+
"""
|
|
1043
|
+
raise NotImplementedError("not implemented.")
|
|
1044
|
+
|
|
1045
|
+
def __is_over_RationalField(self):
|
|
1046
|
+
r"""
|
|
1047
|
+
Internal function. Return true iff the base ring of this elliptic
|
|
1048
|
+
curve is the field of rational numbers.
|
|
1049
|
+
|
|
1050
|
+
EXAMPLES::
|
|
1051
|
+
|
|
1052
|
+
sage: E = EllipticCurve(QQ,[1,1])
|
|
1053
|
+
sage: E._EllipticCurve_generic__is_over_RationalField()
|
|
1054
|
+
True
|
|
1055
|
+
sage: E = EllipticCurve(GF(5),[1,1])
|
|
1056
|
+
sage: E._EllipticCurve_generic__is_over_RationalField()
|
|
1057
|
+
False
|
|
1058
|
+
"""
|
|
1059
|
+
return isinstance(self.base_ring(), RationalField)
|
|
1060
|
+
|
|
1061
|
+
def is_on_curve(self, x, y):
|
|
1062
|
+
r"""
|
|
1063
|
+
Return ``True`` if `(x,y)` is an affine point on this curve.
|
|
1064
|
+
|
|
1065
|
+
INPUT:
|
|
1066
|
+
|
|
1067
|
+
- ``x``, ``y`` -- elements of the base ring of the curve
|
|
1068
|
+
|
|
1069
|
+
EXAMPLES::
|
|
1070
|
+
|
|
1071
|
+
sage: E = EllipticCurve(QQ,[1,1])
|
|
1072
|
+
sage: E.is_on_curve(0,1)
|
|
1073
|
+
True
|
|
1074
|
+
sage: E.is_on_curve(1,1)
|
|
1075
|
+
False
|
|
1076
|
+
"""
|
|
1077
|
+
a = self.ainvs()
|
|
1078
|
+
return y**2 + a[0]*x*y + a[2]*y == x**3 + a[1]*x**2 + a[3]*x + a[4]
|
|
1079
|
+
|
|
1080
|
+
def is_exact(self):
|
|
1081
|
+
"""
|
|
1082
|
+
Test whether elements of this elliptic curve are represented exactly.
|
|
1083
|
+
|
|
1084
|
+
EXAMPLES::
|
|
1085
|
+
|
|
1086
|
+
sage: EllipticCurve(QQ, [1, 2]).is_exact()
|
|
1087
|
+
True
|
|
1088
|
+
sage: EllipticCurve(RR, [1, 2]).is_exact()
|
|
1089
|
+
False
|
|
1090
|
+
"""
|
|
1091
|
+
return self.__base_ring.is_exact()
|
|
1092
|
+
|
|
1093
|
+
def a_invariants(self):
|
|
1094
|
+
r"""
|
|
1095
|
+
The `a`-invariants of this elliptic curve, as a tuple.
|
|
1096
|
+
|
|
1097
|
+
OUTPUT:
|
|
1098
|
+
|
|
1099
|
+
(tuple) - a 5-tuple of the `a`-invariants of this elliptic curve.
|
|
1100
|
+
|
|
1101
|
+
EXAMPLES::
|
|
1102
|
+
|
|
1103
|
+
sage: E = EllipticCurve([1,2,3,4,5])
|
|
1104
|
+
sage: E.a_invariants()
|
|
1105
|
+
(1, 2, 3, 4, 5)
|
|
1106
|
+
|
|
1107
|
+
sage: E = EllipticCurve([0,1]); E
|
|
1108
|
+
Elliptic Curve defined by y^2 = x^3 + 1 over Rational Field
|
|
1109
|
+
sage: E.a_invariants()
|
|
1110
|
+
(0, 0, 0, 0, 1)
|
|
1111
|
+
|
|
1112
|
+
sage: E = EllipticCurve([GF(7)(3),5])
|
|
1113
|
+
sage: E.a_invariants()
|
|
1114
|
+
(0, 0, 0, 3, 5)
|
|
1115
|
+
|
|
1116
|
+
TESTS::
|
|
1117
|
+
|
|
1118
|
+
sage: E = EllipticCurve([1,0,0,0,1])
|
|
1119
|
+
sage: E.a_invariants()[0] = 100000000
|
|
1120
|
+
Traceback (most recent call last):
|
|
1121
|
+
...
|
|
1122
|
+
TypeError: 'tuple' object does not support item assignment
|
|
1123
|
+
"""
|
|
1124
|
+
return self.__ainvs
|
|
1125
|
+
|
|
1126
|
+
ainvs = a_invariants
|
|
1127
|
+
|
|
1128
|
+
def a1(self):
|
|
1129
|
+
r"""
|
|
1130
|
+
Return the `a_1` invariant of this elliptic curve.
|
|
1131
|
+
|
|
1132
|
+
EXAMPLES::
|
|
1133
|
+
|
|
1134
|
+
sage: E = EllipticCurve([1,2,3,4,6])
|
|
1135
|
+
sage: E.a1()
|
|
1136
|
+
1
|
|
1137
|
+
"""
|
|
1138
|
+
return self.__ainvs[0]
|
|
1139
|
+
|
|
1140
|
+
def a2(self):
|
|
1141
|
+
r"""
|
|
1142
|
+
Return the `a_2` invariant of this elliptic curve.
|
|
1143
|
+
|
|
1144
|
+
EXAMPLES::
|
|
1145
|
+
|
|
1146
|
+
sage: E = EllipticCurve([1,2,3,4,6])
|
|
1147
|
+
sage: E.a2()
|
|
1148
|
+
2
|
|
1149
|
+
"""
|
|
1150
|
+
return self.__ainvs[1]
|
|
1151
|
+
|
|
1152
|
+
def a3(self):
|
|
1153
|
+
r"""
|
|
1154
|
+
Return the `a_3` invariant of this elliptic curve.
|
|
1155
|
+
|
|
1156
|
+
EXAMPLES::
|
|
1157
|
+
|
|
1158
|
+
sage: E = EllipticCurve([1,2,3,4,6])
|
|
1159
|
+
sage: E.a3()
|
|
1160
|
+
3
|
|
1161
|
+
"""
|
|
1162
|
+
return self.__ainvs[2]
|
|
1163
|
+
|
|
1164
|
+
def a4(self):
|
|
1165
|
+
r"""
|
|
1166
|
+
Return the `a_4` invariant of this elliptic curve.
|
|
1167
|
+
|
|
1168
|
+
EXAMPLES::
|
|
1169
|
+
|
|
1170
|
+
sage: E = EllipticCurve([1,2,3,4,6])
|
|
1171
|
+
sage: E.a4()
|
|
1172
|
+
4
|
|
1173
|
+
"""
|
|
1174
|
+
return self.__ainvs[3]
|
|
1175
|
+
|
|
1176
|
+
def a6(self):
|
|
1177
|
+
r"""
|
|
1178
|
+
Return the `a_6` invariant of this elliptic curve.
|
|
1179
|
+
|
|
1180
|
+
EXAMPLES::
|
|
1181
|
+
|
|
1182
|
+
sage: E = EllipticCurve([1,2,3,4,6])
|
|
1183
|
+
sage: E.a6()
|
|
1184
|
+
6
|
|
1185
|
+
"""
|
|
1186
|
+
return self.__ainvs[4]
|
|
1187
|
+
|
|
1188
|
+
@cached_method
|
|
1189
|
+
def b_invariants(self):
|
|
1190
|
+
r"""
|
|
1191
|
+
Return the `b`-invariants of this elliptic curve, as a tuple.
|
|
1192
|
+
|
|
1193
|
+
OUTPUT:
|
|
1194
|
+
|
|
1195
|
+
(tuple) - a 4-tuple of the `b`-invariants of this elliptic curve.
|
|
1196
|
+
|
|
1197
|
+
This method is cached.
|
|
1198
|
+
|
|
1199
|
+
EXAMPLES::
|
|
1200
|
+
|
|
1201
|
+
sage: E = EllipticCurve([0, -1, 1, -10, -20])
|
|
1202
|
+
sage: E.b_invariants()
|
|
1203
|
+
(-4, -20, -79, -21)
|
|
1204
|
+
|
|
1205
|
+
sage: E = EllipticCurve([-4,0])
|
|
1206
|
+
sage: E.b_invariants()
|
|
1207
|
+
(0, -8, 0, -16)
|
|
1208
|
+
|
|
1209
|
+
sage: E = EllipticCurve([1,2,3,4,5])
|
|
1210
|
+
sage: E.b_invariants()
|
|
1211
|
+
(9, 11, 29, 35)
|
|
1212
|
+
sage: E.b2()
|
|
1213
|
+
9
|
|
1214
|
+
sage: E.b4()
|
|
1215
|
+
11
|
|
1216
|
+
sage: E.b6()
|
|
1217
|
+
29
|
|
1218
|
+
sage: E.b8()
|
|
1219
|
+
35
|
|
1220
|
+
|
|
1221
|
+
ALGORITHM:
|
|
1222
|
+
|
|
1223
|
+
These are simple functions of the `a`-invariants.
|
|
1224
|
+
|
|
1225
|
+
AUTHORS:
|
|
1226
|
+
|
|
1227
|
+
- William Stein (2005-04-25)
|
|
1228
|
+
"""
|
|
1229
|
+
a1, a2, a3, a4, a6 = self.ainvs()
|
|
1230
|
+
return (a1*a1 + 4*a2,
|
|
1231
|
+
a1*a3 + 2*a4,
|
|
1232
|
+
a3**2 + 4*a6,
|
|
1233
|
+
a1**2 * a6 + 4*a2*a6 - a1*a3*a4 + a2*a3**2 - a4**2)
|
|
1234
|
+
|
|
1235
|
+
def b2(self):
|
|
1236
|
+
r"""
|
|
1237
|
+
Return the `b_2` invariant of this elliptic curve.
|
|
1238
|
+
|
|
1239
|
+
EXAMPLES::
|
|
1240
|
+
|
|
1241
|
+
sage: E = EllipticCurve([1,2,3,4,5])
|
|
1242
|
+
sage: E.b2()
|
|
1243
|
+
9
|
|
1244
|
+
"""
|
|
1245
|
+
return self.b_invariants()[0]
|
|
1246
|
+
|
|
1247
|
+
def b4(self):
|
|
1248
|
+
r"""
|
|
1249
|
+
Return the `b_4` invariant of this elliptic curve.
|
|
1250
|
+
|
|
1251
|
+
EXAMPLES::
|
|
1252
|
+
|
|
1253
|
+
sage: E = EllipticCurve([1,2,3,4,5])
|
|
1254
|
+
sage: E.b4()
|
|
1255
|
+
11
|
|
1256
|
+
"""
|
|
1257
|
+
return self.b_invariants()[1]
|
|
1258
|
+
|
|
1259
|
+
def b6(self):
|
|
1260
|
+
r"""
|
|
1261
|
+
Return the `b_6` invariant of this elliptic curve.
|
|
1262
|
+
|
|
1263
|
+
EXAMPLES::
|
|
1264
|
+
|
|
1265
|
+
sage: E = EllipticCurve([1,2,3,4,5])
|
|
1266
|
+
sage: E.b6()
|
|
1267
|
+
29
|
|
1268
|
+
"""
|
|
1269
|
+
return self.b_invariants()[2]
|
|
1270
|
+
|
|
1271
|
+
def b8(self):
|
|
1272
|
+
r"""
|
|
1273
|
+
Return the `b_8` invariant of this elliptic curve.
|
|
1274
|
+
|
|
1275
|
+
EXAMPLES::
|
|
1276
|
+
|
|
1277
|
+
sage: E = EllipticCurve([1,2,3,4,5])
|
|
1278
|
+
sage: E.b8()
|
|
1279
|
+
35
|
|
1280
|
+
"""
|
|
1281
|
+
return self.b_invariants()[3]
|
|
1282
|
+
|
|
1283
|
+
@cached_method
|
|
1284
|
+
def c_invariants(self):
|
|
1285
|
+
r"""
|
|
1286
|
+
Return the `c`-invariants of this elliptic curve, as a tuple.
|
|
1287
|
+
|
|
1288
|
+
This method is cached.
|
|
1289
|
+
|
|
1290
|
+
OUTPUT:
|
|
1291
|
+
|
|
1292
|
+
(tuple) - a 2-tuple of the `c`-invariants of the elliptic curve.
|
|
1293
|
+
|
|
1294
|
+
EXAMPLES::
|
|
1295
|
+
|
|
1296
|
+
sage: E = EllipticCurve([0, -1, 1, -10, -20])
|
|
1297
|
+
sage: E.c_invariants()
|
|
1298
|
+
(496, 20008)
|
|
1299
|
+
|
|
1300
|
+
sage: E = EllipticCurve([-4,0])
|
|
1301
|
+
sage: E.c_invariants()
|
|
1302
|
+
(192, 0)
|
|
1303
|
+
|
|
1304
|
+
ALGORITHM:
|
|
1305
|
+
|
|
1306
|
+
These are simple functions of the `a`-invariants.
|
|
1307
|
+
|
|
1308
|
+
AUTHORS:
|
|
1309
|
+
|
|
1310
|
+
- William Stein (2005-04-25)
|
|
1311
|
+
"""
|
|
1312
|
+
b2, b4, b6, b8 = self.b_invariants()
|
|
1313
|
+
# note: c6 is wrong in Silverman, but right in Cremona
|
|
1314
|
+
return (b2**2 - 24*b4,
|
|
1315
|
+
-b2**3 + 36*b2*b4 - 216*b6)
|
|
1316
|
+
|
|
1317
|
+
def c4(self):
|
|
1318
|
+
r"""
|
|
1319
|
+
Return the `c_4` invariant of this elliptic curve.
|
|
1320
|
+
|
|
1321
|
+
EXAMPLES::
|
|
1322
|
+
|
|
1323
|
+
sage: E = EllipticCurve([0, -1, 1, -10, -20])
|
|
1324
|
+
sage: E.c4()
|
|
1325
|
+
496
|
|
1326
|
+
"""
|
|
1327
|
+
return self.c_invariants()[0]
|
|
1328
|
+
|
|
1329
|
+
def c6(self):
|
|
1330
|
+
r"""
|
|
1331
|
+
Return the `c_6` invariant of this elliptic curve.
|
|
1332
|
+
|
|
1333
|
+
EXAMPLES::
|
|
1334
|
+
|
|
1335
|
+
sage: E = EllipticCurve([0, -1, 1, -10, -20])
|
|
1336
|
+
sage: E.c6()
|
|
1337
|
+
20008
|
|
1338
|
+
"""
|
|
1339
|
+
return self.c_invariants()[1]
|
|
1340
|
+
|
|
1341
|
+
@cached_method
|
|
1342
|
+
def discriminant(self):
|
|
1343
|
+
r"""
|
|
1344
|
+
Return the discriminant of this elliptic curve.
|
|
1345
|
+
|
|
1346
|
+
This method is cached.
|
|
1347
|
+
|
|
1348
|
+
EXAMPLES::
|
|
1349
|
+
|
|
1350
|
+
sage: E = EllipticCurve([0,0,1,-1,0])
|
|
1351
|
+
sage: E.discriminant()
|
|
1352
|
+
37
|
|
1353
|
+
|
|
1354
|
+
sage: E = EllipticCurve([0, -1, 1, -10, -20])
|
|
1355
|
+
sage: E.discriminant()
|
|
1356
|
+
-161051
|
|
1357
|
+
|
|
1358
|
+
sage: E = EllipticCurve([GF(7)(2),1])
|
|
1359
|
+
sage: E.discriminant()
|
|
1360
|
+
1
|
|
1361
|
+
"""
|
|
1362
|
+
b2, b4, b6, b8 = self.b_invariants()
|
|
1363
|
+
return -b2**2*b8 - 8*b4**3 - 27*b6**2 + 9*b2*b4*b6
|
|
1364
|
+
|
|
1365
|
+
@cached_method
|
|
1366
|
+
def j_invariant(self):
|
|
1367
|
+
r"""
|
|
1368
|
+
Return the `j`-invariant of this elliptic curve.
|
|
1369
|
+
|
|
1370
|
+
This method is cached.
|
|
1371
|
+
|
|
1372
|
+
EXAMPLES::
|
|
1373
|
+
|
|
1374
|
+
sage: E = EllipticCurve([0,0,1,-1,0])
|
|
1375
|
+
sage: E.j_invariant()
|
|
1376
|
+
110592/37
|
|
1377
|
+
|
|
1378
|
+
sage: E = EllipticCurve([0, -1, 1, -10, -20])
|
|
1379
|
+
sage: E.j_invariant()
|
|
1380
|
+
-122023936/161051
|
|
1381
|
+
|
|
1382
|
+
sage: E = EllipticCurve([-4,0])
|
|
1383
|
+
sage: E.j_invariant()
|
|
1384
|
+
1728
|
|
1385
|
+
|
|
1386
|
+
sage: E = EllipticCurve([GF(7)(2),1])
|
|
1387
|
+
sage: E.j_invariant()
|
|
1388
|
+
1
|
|
1389
|
+
"""
|
|
1390
|
+
c4, _ = self.c_invariants()
|
|
1391
|
+
return c4**3 / self.discriminant()
|
|
1392
|
+
|
|
1393
|
+
def base_extend(self, R):
|
|
1394
|
+
r"""
|
|
1395
|
+
Return the base extension of ``self`` to `R`.
|
|
1396
|
+
|
|
1397
|
+
INPUT:
|
|
1398
|
+
|
|
1399
|
+
- ``R`` -- either a ring into which the `a`-invariants of
|
|
1400
|
+
``self`` may be converted, or a morphism which may be
|
|
1401
|
+
applied to them.
|
|
1402
|
+
|
|
1403
|
+
OUTPUT:
|
|
1404
|
+
|
|
1405
|
+
An elliptic curve over the new ring whose `a`-invariants are
|
|
1406
|
+
the images of the `a`-invariants of ``self``.
|
|
1407
|
+
|
|
1408
|
+
EXAMPLES::
|
|
1409
|
+
|
|
1410
|
+
sage: E = EllipticCurve(GF(5), [1,1]); E
|
|
1411
|
+
Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 5
|
|
1412
|
+
sage: E1 = E.base_extend(GF(125,'a')); E1 # needs sage.rings.finite_rings
|
|
1413
|
+
Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field in a of size 5^3
|
|
1414
|
+
|
|
1415
|
+
TESTS:
|
|
1416
|
+
|
|
1417
|
+
Check that we are correctly keeping track of known
|
|
1418
|
+
cardinalities when extending the base field::
|
|
1419
|
+
|
|
1420
|
+
sage: # needs sage.rings.finite_rings
|
|
1421
|
+
sage: E = EllipticCurve(j=GF(7)(5))
|
|
1422
|
+
sage: E.cardinality()
|
|
1423
|
+
10
|
|
1424
|
+
sage: EE = E.base_extend(GF(7^2))
|
|
1425
|
+
sage: EE._order
|
|
1426
|
+
60
|
|
1427
|
+
|
|
1428
|
+
Changing to a smaller field should not cache orders::
|
|
1429
|
+
|
|
1430
|
+
sage: EE = EllipticCurve(j=GF(7^3)(6)) # needs sage.rings.finite_rings
|
|
1431
|
+
sage: hasattr(EE.change_ring(GF(7)), '_order') # needs sage.rings.finite_rings
|
|
1432
|
+
False
|
|
1433
|
+
|
|
1434
|
+
Changing to a field of different characteristic should
|
|
1435
|
+
not cache orders::
|
|
1436
|
+
|
|
1437
|
+
sage: Elift = E.change_ring(QQ) # needs sage.rings.finite_rings
|
|
1438
|
+
sage: hasattr(Elift, '_order') # needs sage.rings.finite_rings
|
|
1439
|
+
False
|
|
1440
|
+
"""
|
|
1441
|
+
E = constructor.EllipticCurve([R(a) for a in self.a_invariants()])
|
|
1442
|
+
|
|
1443
|
+
if isinstance(R, FiniteField) and hasattr(self, '_order') and self.__base_ring.is_subring(R):
|
|
1444
|
+
# The cardinality over an extension field follows easily
|
|
1445
|
+
# from the cardinality over the smaller field.
|
|
1446
|
+
n = R.cardinality().log(self.__base_ring.cardinality())
|
|
1447
|
+
E._order = self.cardinality(extension_degree=n)
|
|
1448
|
+
|
|
1449
|
+
return E
|
|
1450
|
+
|
|
1451
|
+
def change_ring(self, R):
|
|
1452
|
+
"""
|
|
1453
|
+
Return the base change of ``self`` to `R`.
|
|
1454
|
+
|
|
1455
|
+
This has the same effect as ``self.base_extend(R)``.
|
|
1456
|
+
|
|
1457
|
+
EXAMPLES::
|
|
1458
|
+
|
|
1459
|
+
sage: # needs sage.rings.finite_rings
|
|
1460
|
+
sage: F2 = GF(5^2,'a'); a = F2.gen()
|
|
1461
|
+
sage: F4 = GF(5^4,'b'); b = F4.gen()
|
|
1462
|
+
sage: roots = a.charpoly().roots(ring=F4, multiplicities=False)
|
|
1463
|
+
sage: h = F2.hom([roots[0]], F4)
|
|
1464
|
+
sage: E = EllipticCurve(F2, [1,a]); E
|
|
1465
|
+
Elliptic Curve defined by y^2 = x^3 + x + a
|
|
1466
|
+
over Finite Field in a of size 5^2
|
|
1467
|
+
sage: E.change_ring(h)
|
|
1468
|
+
Elliptic Curve defined by y^2 = x^3 + x + (4*b^3+4*b^2+4*b+3)
|
|
1469
|
+
over Finite Field in b of size 5^4
|
|
1470
|
+
"""
|
|
1471
|
+
return self.base_extend(R)
|
|
1472
|
+
|
|
1473
|
+
def base_ring(self):
|
|
1474
|
+
r"""
|
|
1475
|
+
Return the base ring of the elliptic curve.
|
|
1476
|
+
|
|
1477
|
+
EXAMPLES::
|
|
1478
|
+
|
|
1479
|
+
sage: E = EllipticCurve(GF(49, 'a'), [3,5]) # needs sage.rings.finite_rings
|
|
1480
|
+
sage: E.base_ring() # needs sage.rings.finite_rings
|
|
1481
|
+
Finite Field in a of size 7^2
|
|
1482
|
+
|
|
1483
|
+
::
|
|
1484
|
+
|
|
1485
|
+
sage: E = EllipticCurve([1,1])
|
|
1486
|
+
sage: E.base_ring()
|
|
1487
|
+
Rational Field
|
|
1488
|
+
|
|
1489
|
+
::
|
|
1490
|
+
|
|
1491
|
+
sage: E = EllipticCurve(ZZ, [3,5])
|
|
1492
|
+
sage: E.base_ring()
|
|
1493
|
+
Integer Ring
|
|
1494
|
+
"""
|
|
1495
|
+
return self.__base_ring
|
|
1496
|
+
|
|
1497
|
+
def gens(self):
|
|
1498
|
+
r"""
|
|
1499
|
+
Placeholder function to return generators of an elliptic curve.
|
|
1500
|
+
|
|
1501
|
+
.. NOTE::
|
|
1502
|
+
|
|
1503
|
+
This functionality is implemented in certain derived
|
|
1504
|
+
classes, such as EllipticCurve_rational_field.
|
|
1505
|
+
|
|
1506
|
+
EXAMPLES::
|
|
1507
|
+
|
|
1508
|
+
sage: R.<a1,a2,a3,a4,a6> = QQ[]
|
|
1509
|
+
sage: E = EllipticCurve([a1,a2,a3,a4,a6])
|
|
1510
|
+
sage: E.gens()
|
|
1511
|
+
Traceback (most recent call last):
|
|
1512
|
+
...
|
|
1513
|
+
NotImplementedError: not implemented.
|
|
1514
|
+
sage: E = EllipticCurve(QQ, [1,1])
|
|
1515
|
+
sage: E.gens() # needs eclib
|
|
1516
|
+
[(0 : 1 : 1)]
|
|
1517
|
+
"""
|
|
1518
|
+
raise NotImplementedError("not implemented.")
|
|
1519
|
+
|
|
1520
|
+
def gen(self, i):
|
|
1521
|
+
r"""
|
|
1522
|
+
Function returning the i'th generator of this elliptic curve.
|
|
1523
|
+
|
|
1524
|
+
.. NOTE::
|
|
1525
|
+
|
|
1526
|
+
Relies on gens() being implemented.
|
|
1527
|
+
|
|
1528
|
+
EXAMPLES::
|
|
1529
|
+
|
|
1530
|
+
sage: R.<a1,a2,a3,a4,a6> = QQ[]
|
|
1531
|
+
sage: E = EllipticCurve([a1,a2,a3,a4,a6])
|
|
1532
|
+
sage: E.gen(0)
|
|
1533
|
+
Traceback (most recent call last):
|
|
1534
|
+
...
|
|
1535
|
+
NotImplementedError: not implemented.
|
|
1536
|
+
"""
|
|
1537
|
+
return self.gens()[i]
|
|
1538
|
+
|
|
1539
|
+
def rst_transform(self, r, s, t):
|
|
1540
|
+
r"""
|
|
1541
|
+
Return the transform of the curve by `(r,s,t)` (with `u=1`).
|
|
1542
|
+
|
|
1543
|
+
INPUT:
|
|
1544
|
+
|
|
1545
|
+
- ``r``, ``s``, ``t`` -- three elements of the base ring
|
|
1546
|
+
|
|
1547
|
+
OUTPUT:
|
|
1548
|
+
|
|
1549
|
+
The elliptic curve obtained from ``self`` by the standard
|
|
1550
|
+
Weierstrass transformation `(u,r,s,t)` with `u=1`.
|
|
1551
|
+
|
|
1552
|
+
.. NOTE::
|
|
1553
|
+
|
|
1554
|
+
This is just a special case of
|
|
1555
|
+
:meth:`change_weierstrass_model`, with `u=1`.
|
|
1556
|
+
|
|
1557
|
+
EXAMPLES::
|
|
1558
|
+
|
|
1559
|
+
sage: R.<r,s,t> = QQ[]
|
|
1560
|
+
sage: E = EllipticCurve([1,2,3,4,5])
|
|
1561
|
+
sage: E.rst_transform(r, s, t)
|
|
1562
|
+
Elliptic Curve defined by y^2 + (2*s+1)*x*y + (r+2*t+3)*y
|
|
1563
|
+
= x^3 + (-s^2+3*r-s+2)*x^2 + (3*r^2-r*s-2*s*t+4*r-3*s-t+4)*x
|
|
1564
|
+
+ (r^3+2*r^2-r*t-t^2+4*r-3*t+5)
|
|
1565
|
+
over Multivariate Polynomial Ring in r, s, t over Rational Field
|
|
1566
|
+
"""
|
|
1567
|
+
return self.change_weierstrass_model(1, r, s, t)
|
|
1568
|
+
|
|
1569
|
+
def scale_curve(self, u):
|
|
1570
|
+
r"""
|
|
1571
|
+
Return the transform of the curve by scale factor `u`.
|
|
1572
|
+
|
|
1573
|
+
INPUT:
|
|
1574
|
+
|
|
1575
|
+
- ``u`` -- an invertible element of the base ring
|
|
1576
|
+
|
|
1577
|
+
OUTPUT:
|
|
1578
|
+
|
|
1579
|
+
The elliptic curve obtained from ``self`` by the standard
|
|
1580
|
+
Weierstrass transformation `(u,r,s,t)` with `r=s=t=0`.
|
|
1581
|
+
|
|
1582
|
+
.. NOTE::
|
|
1583
|
+
|
|
1584
|
+
This is just a special case of
|
|
1585
|
+
:meth:`change_weierstrass_model`, with `r=s=t=0`.
|
|
1586
|
+
|
|
1587
|
+
EXAMPLES::
|
|
1588
|
+
|
|
1589
|
+
sage: K = Frac(PolynomialRing(QQ, 'u'))
|
|
1590
|
+
sage: u = K.gen()
|
|
1591
|
+
sage: E = EllipticCurve([1,2,3,4,5])
|
|
1592
|
+
sage: E.scale_curve(u)
|
|
1593
|
+
Elliptic Curve defined by
|
|
1594
|
+
y^2 + u*x*y + 3*u^3*y = x^3 + 2*u^2*x^2 + 4*u^4*x + 5*u^6
|
|
1595
|
+
over Fraction Field of Univariate Polynomial Ring in u over Rational Field
|
|
1596
|
+
"""
|
|
1597
|
+
if isinstance(u, int):
|
|
1598
|
+
u = self.base_ring()(u) # because otherwise 1/u would round!
|
|
1599
|
+
return self.change_weierstrass_model(1/u, 0, 0, 0)
|
|
1600
|
+
|
|
1601
|
+
def isomorphism(self, u, r=0, s=0, t=0, *, is_codomain=False):
|
|
1602
|
+
r"""
|
|
1603
|
+
Given four values `u,r,s,t` in the base ring of this curve, return
|
|
1604
|
+
the :class:`WeierstrassIsomorphism` defined by `u,r,s,t` with this
|
|
1605
|
+
curve as its codomain.
|
|
1606
|
+
(The value `u` must be a unit; the values `r,s,t` default to zero.)
|
|
1607
|
+
|
|
1608
|
+
Optionally, if the keyword argument ``is_codomain`` is set to ``True``,
|
|
1609
|
+
return the isomorphism defined by `u,r,s,t` with this curve as its
|
|
1610
|
+
**co**\domain.
|
|
1611
|
+
|
|
1612
|
+
EXAMPLES::
|
|
1613
|
+
|
|
1614
|
+
sage: E = EllipticCurve([1, 2, 3, 4, 5])
|
|
1615
|
+
sage: iso = E.isomorphism(6); iso
|
|
1616
|
+
Elliptic-curve morphism:
|
|
1617
|
+
From: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Rational Field
|
|
1618
|
+
To: Elliptic Curve defined by y^2 + 1/6*x*y + 1/72*y = x^3 + 1/18*x^2 + 1/324*x + 5/46656 over Rational Field
|
|
1619
|
+
Via: (u,r,s,t) = (6, 0, 0, 0)
|
|
1620
|
+
sage: iso.domain() == E
|
|
1621
|
+
True
|
|
1622
|
+
sage: iso.codomain() == E.scale_curve(1 / 6)
|
|
1623
|
+
True
|
|
1624
|
+
|
|
1625
|
+
sage: iso = E.isomorphism(1, 7, 8, 9); iso
|
|
1626
|
+
Elliptic-curve morphism:
|
|
1627
|
+
From: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Rational Field
|
|
1628
|
+
To: Elliptic Curve defined by y^2 + 17*x*y + 28*y = x^3 - 49*x^2 - 54*x + 303 over Rational Field
|
|
1629
|
+
Via: (u,r,s,t) = (1, 7, 8, 9)
|
|
1630
|
+
sage: iso.domain() == E
|
|
1631
|
+
True
|
|
1632
|
+
sage: iso.codomain() == E.rst_transform(7, 8, 9)
|
|
1633
|
+
True
|
|
1634
|
+
|
|
1635
|
+
sage: iso = E.isomorphism(6, 7, 8, 9); iso
|
|
1636
|
+
Elliptic-curve morphism:
|
|
1637
|
+
From: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Rational Field
|
|
1638
|
+
To: Elliptic Curve defined by y^2 + 17/6*x*y + 7/54*y = x^3 - 49/36*x^2 - 1/24*x + 101/15552 over Rational Field
|
|
1639
|
+
Via: (u,r,s,t) = (6, 7, 8, 9)
|
|
1640
|
+
sage: iso.domain() == E
|
|
1641
|
+
True
|
|
1642
|
+
sage: iso.codomain() == E.rst_transform(7, 8, 9).scale_curve(1 / 6)
|
|
1643
|
+
True
|
|
1644
|
+
|
|
1645
|
+
The ``is_codomain`` argument reverses the role of domain and codomain::
|
|
1646
|
+
|
|
1647
|
+
sage: E = EllipticCurve([1, 2, 3, 4, 5])
|
|
1648
|
+
sage: iso = E.isomorphism(6, is_codomain=True); iso
|
|
1649
|
+
Elliptic-curve morphism:
|
|
1650
|
+
From: Elliptic Curve defined by y^2 + 6*x*y + 648*y = x^3 + 72*x^2 + 5184*x + 233280 over Rational Field
|
|
1651
|
+
To: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Rational Field
|
|
1652
|
+
Via: (u,r,s,t) = (6, 0, 0, 0)
|
|
1653
|
+
sage: iso.domain() == E.scale_curve(6)
|
|
1654
|
+
True
|
|
1655
|
+
sage: iso.codomain() == E
|
|
1656
|
+
True
|
|
1657
|
+
|
|
1658
|
+
sage: iso = E.isomorphism(1, 7, 8, 9, is_codomain=True); iso
|
|
1659
|
+
Elliptic-curve morphism:
|
|
1660
|
+
From: Elliptic Curve defined by y^2 - 15*x*y + 90*y = x^3 - 75*x^2 + 796*x - 2289 over Rational Field
|
|
1661
|
+
To: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Rational Field
|
|
1662
|
+
Via: (u,r,s,t) = (1, 7, 8, 9)
|
|
1663
|
+
sage: iso.domain().rst_transform(7, 8, 9) == E
|
|
1664
|
+
True
|
|
1665
|
+
sage: iso.codomain() == E
|
|
1666
|
+
True
|
|
1667
|
+
|
|
1668
|
+
sage: iso = E.isomorphism(6, 7, 8, 9, is_codomain=True); iso
|
|
1669
|
+
Elliptic-curve morphism:
|
|
1670
|
+
From: Elliptic Curve defined by y^2 - 10*x*y + 700*y = x^3 + 35*x^2 + 9641*x + 169486 over Rational Field
|
|
1671
|
+
To: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Rational Field
|
|
1672
|
+
Via: (u,r,s,t) = (6, 7, 8, 9)
|
|
1673
|
+
sage: iso.domain().rst_transform(7, 8, 9) == E.scale_curve(6)
|
|
1674
|
+
True
|
|
1675
|
+
sage: iso.codomain() == E
|
|
1676
|
+
True
|
|
1677
|
+
|
|
1678
|
+
.. SEEALSO::
|
|
1679
|
+
|
|
1680
|
+
- :class:`~sage.schemes.elliptic_curves.weierstrass_morphism.WeierstrassIsomorphism`
|
|
1681
|
+
- :meth:`rst_transform`
|
|
1682
|
+
- :meth:`scale_curve`
|
|
1683
|
+
"""
|
|
1684
|
+
from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism
|
|
1685
|
+
if is_codomain:
|
|
1686
|
+
return WeierstrassIsomorphism(None, (u,r,s,t), self)
|
|
1687
|
+
return WeierstrassIsomorphism(self, (u,r,s,t))
|
|
1688
|
+
|
|
1689
|
+
# ###########################################################
|
|
1690
|
+
#
|
|
1691
|
+
# Explanation of the division (also known as torsion) polynomial
|
|
1692
|
+
# functions in Sage.
|
|
1693
|
+
#
|
|
1694
|
+
# The main user function division_polynomial() (also aliased as
|
|
1695
|
+
# torsion_polynomial()) is used to compute polynomials whose roots
|
|
1696
|
+
# determine the m-torsion points on the curve. Three options are
|
|
1697
|
+
# available, which effect the result when m is even and also the
|
|
1698
|
+
# parent ring of the returned value. The function can return either a
|
|
1699
|
+
# polynomial or the evaluation of that polynomial at a point,
|
|
1700
|
+
# depending on the input. Values are cached.
|
|
1701
|
+
#
|
|
1702
|
+
# The options are controlled by the value of the parameter
|
|
1703
|
+
# two_torsion_multiplicity, which may be 0, 1 or 2. If it is 0 or 2,
|
|
1704
|
+
# then a univariate polynomial will be returned (or evaluated at the
|
|
1705
|
+
# parameter x if x is not None). This is the polynomial whose roots
|
|
1706
|
+
# are the values of x(P) at the nonzero points P where m*P=0
|
|
1707
|
+
# (when two_torsion_multiplicity==2), or the points where m*P=0 but
|
|
1708
|
+
# 2*P\not=0 (when two_torsion_multiplicity==0).
|
|
1709
|
+
#
|
|
1710
|
+
# If two_torsion_multiplicity==1, then a bivariate polynomial is
|
|
1711
|
+
# returned, which (as a function on the curve) has a simple zero at
|
|
1712
|
+
# each nonzero point P such that m*P=0. When m is odd this is a
|
|
1713
|
+
# polynomial in x alone, but is still returned as an element of a
|
|
1714
|
+
# polynomial ring in two variables; when m is even it has a factor
|
|
1715
|
+
# 2y+a_1x+a_3. In this case if the parameter x is not None then it
|
|
1716
|
+
# should be a tuple of length 2, or a point P on the curve, and the
|
|
1717
|
+
# returned value is the value of the bivariate polynomial at this
|
|
1718
|
+
# point.
|
|
1719
|
+
#
|
|
1720
|
+
# Comparison with Magma: Magma's function DivisionPolynomial(E,m)
|
|
1721
|
+
# returns a triple of univariate polynomials f,g,h where f is
|
|
1722
|
+
# \code{E.division_polynomial(m,two_torsion_multiplicity=2)}, g is
|
|
1723
|
+
# \code{E.division_polynomial(m,two_torsion_multiplicity=0)} and h
|
|
1724
|
+
# is the quotient, so that h=1 when m is odd.
|
|
1725
|
+
|
|
1726
|
+
# ###########################################################
|
|
1727
|
+
|
|
1728
|
+
def division_polynomial_0(self, n, x=None):
|
|
1729
|
+
r"""
|
|
1730
|
+
Return the `n`-th torsion (division) polynomial, without
|
|
1731
|
+
the 2-torsion factor if `n` is even, as a polynomial in `x`.
|
|
1732
|
+
|
|
1733
|
+
These are the polynomials `g_n` defined in [MT1991]_, but with
|
|
1734
|
+
the sign flipped for even `n`, so that the leading coefficient is
|
|
1735
|
+
always positive.
|
|
1736
|
+
|
|
1737
|
+
.. NOTE::
|
|
1738
|
+
|
|
1739
|
+
This function is intended for internal use; users should use
|
|
1740
|
+
:meth:`division_polynomial`.
|
|
1741
|
+
|
|
1742
|
+
.. SEEALSO::
|
|
1743
|
+
|
|
1744
|
+
- :meth:`division_polynomial`
|
|
1745
|
+
- :meth:`_multiple_x_numerator`
|
|
1746
|
+
- :meth:`_multiple_x_denominator`
|
|
1747
|
+
|
|
1748
|
+
INPUT:
|
|
1749
|
+
|
|
1750
|
+
- ``n`` -- positive integer, or the special values ``-1`` and ``-2``
|
|
1751
|
+
which mean `B_6 = (2y + a_1 x + a_3)^2` and `B_6^2` respectively (in
|
|
1752
|
+
the notation of [MT1991]_), or a list of integers
|
|
1753
|
+
|
|
1754
|
+
- ``x`` -- a ring element to use as the "x" variable or ``None``
|
|
1755
|
+
(default: ``None``); if ``None``, then a new polynomial ring will
|
|
1756
|
+
be constructed over the base ring of the elliptic curve, and its
|
|
1757
|
+
generator will be used as ``x``. Note that ``x`` does not need to
|
|
1758
|
+
be a generator of a polynomial ring; any ring element is ok. This
|
|
1759
|
+
permits fast calculation of the torsion polynomial *evaluated* on
|
|
1760
|
+
any element of a ring.
|
|
1761
|
+
|
|
1762
|
+
ALGORITHM:
|
|
1763
|
+
|
|
1764
|
+
Recursion described in [MT1991]_. The recursive
|
|
1765
|
+
formulae are evaluated `O(\log^2 n)` times.
|
|
1766
|
+
|
|
1767
|
+
AUTHORS:
|
|
1768
|
+
|
|
1769
|
+
- David Harvey (2006-09-24): initial version
|
|
1770
|
+
|
|
1771
|
+
- John Cremona (2008-08-26): unified division polynomial code
|
|
1772
|
+
|
|
1773
|
+
EXAMPLES::
|
|
1774
|
+
|
|
1775
|
+
sage: E = EllipticCurve("37a")
|
|
1776
|
+
sage: E.division_polynomial_0(1)
|
|
1777
|
+
1
|
|
1778
|
+
sage: E.division_polynomial_0(2)
|
|
1779
|
+
1
|
|
1780
|
+
sage: E.division_polynomial_0(3)
|
|
1781
|
+
3*x^4 - 6*x^2 + 3*x - 1
|
|
1782
|
+
sage: E.division_polynomial_0(4)
|
|
1783
|
+
2*x^6 - 10*x^4 + 10*x^3 - 10*x^2 + 2*x + 1
|
|
1784
|
+
sage: E.division_polynomial_0(5)
|
|
1785
|
+
5*x^12 - 62*x^10 + 95*x^9 - 105*x^8 - 60*x^7 + 285*x^6 - 174*x^5 - 5*x^4 - 5*x^3 + 35*x^2 - 15*x + 2
|
|
1786
|
+
sage: E.division_polynomial_0(6)
|
|
1787
|
+
3*x^16 - 72*x^14 + 168*x^13 - 364*x^12 + 1120*x^10 - 1144*x^9 + 300*x^8 - 540*x^7 + 1120*x^6 - 588*x^5 - 133*x^4 + 252*x^3 - 114*x^2 + 22*x - 1
|
|
1788
|
+
sage: E.division_polynomial_0(7)
|
|
1789
|
+
7*x^24 - 308*x^22 + 986*x^21 - 2954*x^20 + 28*x^19 + 17171*x^18 - 23142*x^17 + 511*x^16 - 5012*x^15 + 43804*x^14 - 7140*x^13 - 96950*x^12 + 111356*x^11 - 19516*x^10 - 49707*x^9 + 40054*x^8 - 124*x^7 - 18382*x^6 + 13342*x^5 - 4816*x^4 + 1099*x^3 - 210*x^2 + 35*x - 3
|
|
1790
|
+
sage: E.division_polynomial_0(8)
|
|
1791
|
+
4*x^30 - 292*x^28 + 1252*x^27 - 5436*x^26 + 2340*x^25 + 39834*x^24 - 79560*x^23 + 51432*x^22 - 142896*x^21 + 451596*x^20 - 212040*x^19 - 1005316*x^18 + 1726416*x^17 - 671160*x^16 - 954924*x^15 + 1119552*x^14 + 313308*x^13 - 1502818*x^12 + 1189908*x^11 - 160152*x^10 - 399176*x^9 + 386142*x^8 - 220128*x^7 + 99558*x^6 - 33528*x^5 + 6042*x^4 + 310*x^3 - 406*x^2 + 78*x - 5
|
|
1792
|
+
|
|
1793
|
+
::
|
|
1794
|
+
|
|
1795
|
+
sage: E.division_polynomial_0(18) % E.division_polynomial_0(6) == 0
|
|
1796
|
+
True
|
|
1797
|
+
|
|
1798
|
+
An example to illustrate the relationship with torsion points::
|
|
1799
|
+
|
|
1800
|
+
sage: F = GF(11)
|
|
1801
|
+
sage: E = EllipticCurve(F, [0, 2]); E
|
|
1802
|
+
Elliptic Curve defined by y^2 = x^3 + 2 over Finite Field of size 11
|
|
1803
|
+
sage: f = E.division_polynomial_0(5); f
|
|
1804
|
+
5*x^12 + x^9 + 8*x^6 + 4*x^3 + 7
|
|
1805
|
+
sage: f.factor()
|
|
1806
|
+
(5) * (x^2 + 5) * (x^2 + 2*x + 5) * (x^2 + 5*x + 7)
|
|
1807
|
+
* (x^2 + 7*x + 7) * (x^2 + 9*x + 5) * (x^2 + 10*x + 7)
|
|
1808
|
+
|
|
1809
|
+
This indicates that the `x`-coordinates of all the 5-torsion points of
|
|
1810
|
+
`E` are in `\GF{11^2}`, and therefore the `y`-coordinates are in
|
|
1811
|
+
`\GF{11^4}`::
|
|
1812
|
+
|
|
1813
|
+
sage: # needs sage.rings.finite_rings
|
|
1814
|
+
sage: K = GF(11^4, 'a')
|
|
1815
|
+
sage: X = E.change_ring(K)
|
|
1816
|
+
sage: f = X.division_polynomial_0(5)
|
|
1817
|
+
sage: x_coords = f.roots(multiplicities=False); x_coords
|
|
1818
|
+
[10*a^3 + 4*a^2 + 5*a + 6,
|
|
1819
|
+
9*a^3 + 8*a^2 + 10*a + 8,
|
|
1820
|
+
8*a^3 + a^2 + 4*a + 10,
|
|
1821
|
+
8*a^3 + a^2 + 4*a + 8,
|
|
1822
|
+
8*a^3 + a^2 + 4*a + 4,
|
|
1823
|
+
6*a^3 + 9*a^2 + 3*a + 4,
|
|
1824
|
+
5*a^3 + 2*a^2 + 8*a + 7,
|
|
1825
|
+
3*a^3 + 10*a^2 + 7*a + 8,
|
|
1826
|
+
3*a^3 + 10*a^2 + 7*a + 3,
|
|
1827
|
+
3*a^3 + 10*a^2 + 7*a + 1,
|
|
1828
|
+
2*a^3 + 3*a^2 + a + 7,
|
|
1829
|
+
a^3 + 7*a^2 + 6*a]
|
|
1830
|
+
|
|
1831
|
+
Now we check that these are exactly the `x`-coordinates of the
|
|
1832
|
+
5-torsion points of `E`::
|
|
1833
|
+
|
|
1834
|
+
sage: for x in x_coords: # needs sage.rings.finite_rings
|
|
1835
|
+
....: assert X.lift_x(x).order() == 5
|
|
1836
|
+
|
|
1837
|
+
The roots of the polynomial are the `x`-coordinates of the points `P`
|
|
1838
|
+
such that `mP=0` but `2P\not=0`::
|
|
1839
|
+
|
|
1840
|
+
sage: E = EllipticCurve('14a1')
|
|
1841
|
+
sage: T = E.torsion_subgroup()
|
|
1842
|
+
sage: [n*T.0 for n in range(6)]
|
|
1843
|
+
[(0 : 1 : 0),
|
|
1844
|
+
(9 : 23 : 1),
|
|
1845
|
+
(2 : 2 : 1),
|
|
1846
|
+
(1 : -1 : 1),
|
|
1847
|
+
(2 : -5 : 1),
|
|
1848
|
+
(9 : -33 : 1)]
|
|
1849
|
+
sage: pol = E.division_polynomial_0(6)
|
|
1850
|
+
sage: xlist = pol.roots(multiplicities=False); xlist
|
|
1851
|
+
[9, 2, -1/3, -5]
|
|
1852
|
+
sage: [E.lift_x(x, all=True) for x in xlist]
|
|
1853
|
+
[[(9 : -33 : 1), (9 : 23 : 1)], [(2 : -5 : 1), (2 : 2 : 1)], [], []]
|
|
1854
|
+
|
|
1855
|
+
.. NOTE::
|
|
1856
|
+
|
|
1857
|
+
The point of order 2 and the identity do not appear.
|
|
1858
|
+
The points with `x=-1/3` and `x=-5` are not rational.
|
|
1859
|
+
"""
|
|
1860
|
+
if x is None:
|
|
1861
|
+
# The generic division polynomials should be cached "forever".
|
|
1862
|
+
cache = self.__divpolys[0]
|
|
1863
|
+
x = polygen(self.base_ring())
|
|
1864
|
+
else:
|
|
1865
|
+
# For other inputs, we use a temporary cache.
|
|
1866
|
+
cache = {}
|
|
1867
|
+
|
|
1868
|
+
b2, b4, b6, b8 = self.b_invariants()
|
|
1869
|
+
|
|
1870
|
+
def poly(n):
|
|
1871
|
+
try:
|
|
1872
|
+
return cache[n]
|
|
1873
|
+
except KeyError:
|
|
1874
|
+
pass
|
|
1875
|
+
if n == -2:
|
|
1876
|
+
ret = poly(-1)**2
|
|
1877
|
+
elif n == -1:
|
|
1878
|
+
ret = 4*x**3 + b2*x**2 + 2*b4*x + b6
|
|
1879
|
+
elif n <= 0:
|
|
1880
|
+
raise ValueError("n must be a positive integer (or -1 or -2)")
|
|
1881
|
+
elif n == 1 or n == 2:
|
|
1882
|
+
ret = x.parent().one()
|
|
1883
|
+
elif n == 3:
|
|
1884
|
+
ret = 3*x**4 + b2*x**3 + 3*b4*x**2 + 3*b6*x + b8
|
|
1885
|
+
elif n == 4:
|
|
1886
|
+
ret = -poly(-2) + (6*x**2 + b2*x + b4) * poly(3)
|
|
1887
|
+
elif n % 2 == 0:
|
|
1888
|
+
m = (n-2) // 2
|
|
1889
|
+
ret = poly(m+1) * (poly(m+3) * poly(m)**2 - poly(m-1) * poly(m+2)**2)
|
|
1890
|
+
else:
|
|
1891
|
+
m = (n-1) // 2
|
|
1892
|
+
if m % 2 == 0:
|
|
1893
|
+
ret = poly(-2) * poly(m+2) * poly(m)**3 - poly(m-1) * poly(m+1)**3
|
|
1894
|
+
else:
|
|
1895
|
+
ret = poly(m+2) * poly(m)**3 - poly(-2) * poly(m-1) * poly(m+1)**3
|
|
1896
|
+
cache[n] = ret
|
|
1897
|
+
return ret
|
|
1898
|
+
|
|
1899
|
+
if not isinstance(n, (list, tuple)):
|
|
1900
|
+
return poly(int(n))
|
|
1901
|
+
else:
|
|
1902
|
+
return [poly(int(k)) for k in n]
|
|
1903
|
+
|
|
1904
|
+
def two_division_polynomial(self, x=None):
|
|
1905
|
+
r"""
|
|
1906
|
+
Return the 2-division polynomial of this elliptic curve evaluated
|
|
1907
|
+
at ``x``.
|
|
1908
|
+
|
|
1909
|
+
INPUT:
|
|
1910
|
+
|
|
1911
|
+
- ``x`` -- (optional) ring element to use as the `x` variable.
|
|
1912
|
+
If ``x`` is ``None``, then a new polynomial ring will be
|
|
1913
|
+
constructed over the base ring of the elliptic curve, and
|
|
1914
|
+
its generator will be used as ``x``. Note that ``x`` does
|
|
1915
|
+
not need to be a generator of a polynomial ring; any ring
|
|
1916
|
+
element is acceptable. This permits fast calculation of the
|
|
1917
|
+
torsion polynomial *evaluated* on any element of a ring.
|
|
1918
|
+
|
|
1919
|
+
EXAMPLES::
|
|
1920
|
+
|
|
1921
|
+
sage: E = EllipticCurve('5077a1')
|
|
1922
|
+
sage: E.two_division_polynomial()
|
|
1923
|
+
4*x^3 - 28*x + 25
|
|
1924
|
+
sage: E = EllipticCurve(GF(3^2,'a'), [1,1,1,1,1]) # needs sage.rings.finite_rings
|
|
1925
|
+
sage: E.two_division_polynomial() # needs sage.rings.finite_rings
|
|
1926
|
+
x^3 + 2*x^2 + 2
|
|
1927
|
+
sage: E.two_division_polynomial().roots() # needs sage.rings.finite_rings
|
|
1928
|
+
[(2, 1), (2*a, 1), (a + 2, 1)]
|
|
1929
|
+
"""
|
|
1930
|
+
return self.division_polynomial_0(-1,x)
|
|
1931
|
+
|
|
1932
|
+
def division_polynomial(self, m, x=None, two_torsion_multiplicity=2, force_evaluate=None):
|
|
1933
|
+
r"""
|
|
1934
|
+
Return the `m`-th division polynomial of this elliptic
|
|
1935
|
+
curve evaluated at `x`.
|
|
1936
|
+
|
|
1937
|
+
The division polynomial is cached if `x` is ``None``.
|
|
1938
|
+
|
|
1939
|
+
INPUT:
|
|
1940
|
+
|
|
1941
|
+
- ``m`` -- positive integer
|
|
1942
|
+
|
|
1943
|
+
- ``x`` -- (optional) ring element to use as the `x` variable.
|
|
1944
|
+
If `x` is ``None`` (omitted), then a new polynomial ring will be
|
|
1945
|
+
constructed over the base ring of the elliptic curve, and its
|
|
1946
|
+
generator will be used as `x`. Note that `x` does not need to
|
|
1947
|
+
be a generator of a polynomial ring; any ring element works. This
|
|
1948
|
+
permits fast calculation of the torsion polynomial *evaluated* on
|
|
1949
|
+
any element of a ring.
|
|
1950
|
+
|
|
1951
|
+
- ``two_torsion_multiplicity`` -- 0, 1, or 2
|
|
1952
|
+
|
|
1953
|
+
If 0: For even `m` when `x` is ``None``, a univariate polynomial
|
|
1954
|
+
over the base ring of the curve is returned, which omits factors
|
|
1955
|
+
whose roots are the `x`-coordinates of the `2`-torsion points.
|
|
1956
|
+
When `x` is not ``None``, the evaluation of such a polynomial at
|
|
1957
|
+
`x` is returned.
|
|
1958
|
+
|
|
1959
|
+
If 2: For even `m` when `x` is ``None``, a univariate polynomial
|
|
1960
|
+
over the base ring of the curve is returned, which includes a
|
|
1961
|
+
factor of degree 3 whose roots are the `x`-coordinates of the
|
|
1962
|
+
`2`-torsion points.
|
|
1963
|
+
Similarly, when `x` is not ``None``, the evaluation of such a
|
|
1964
|
+
polynomial at `x` is returned.
|
|
1965
|
+
|
|
1966
|
+
If 1: For even `m` when `x` is ``None``, a bivariate polynomial
|
|
1967
|
+
over the base ring of the curve is returned, which includes a
|
|
1968
|
+
factor `2y+a_1x+a_3` having simple zeros at the `2`-torsion points.
|
|
1969
|
+
When `x` is not ``None``, it should be a tuple of length 2, and
|
|
1970
|
+
the evaluation of such a polynomial at `x` is returned.
|
|
1971
|
+
|
|
1972
|
+
- ``force_evaluate`` -- (optional) 0, 1, or 2
|
|
1973
|
+
|
|
1974
|
+
By default, this method makes use of previously cached generic
|
|
1975
|
+
division polynomials to compute the value of the polynomial at
|
|
1976
|
+
a given element `x` whenever it appears beneficial to do so.
|
|
1977
|
+
Explicitly setting this flag overrides the default behavior.
|
|
1978
|
+
|
|
1979
|
+
Note that the complexity of evaluating a generic division
|
|
1980
|
+
polynomial scales much worse than that of computing the value
|
|
1981
|
+
at a point directly (using the recursive formulas), hence
|
|
1982
|
+
setting this flag can be detrimental to performance.
|
|
1983
|
+
|
|
1984
|
+
If 0: Do not use cached generic division polynomials.
|
|
1985
|
+
|
|
1986
|
+
If 1: If the generic division polynomial for this `m` has been
|
|
1987
|
+
cached before, evaluate it at `x` to compute the result.
|
|
1988
|
+
|
|
1989
|
+
If 2: Compute the value at `x` by evaluating the generic
|
|
1990
|
+
division polynomial. If the generic `m`-division polynomial
|
|
1991
|
+
has not yet been cached, compute and cache it first.
|
|
1992
|
+
|
|
1993
|
+
EXAMPLES::
|
|
1994
|
+
|
|
1995
|
+
sage: E = EllipticCurve([0,0,1,-1,0])
|
|
1996
|
+
sage: E.division_polynomial(1)
|
|
1997
|
+
1
|
|
1998
|
+
sage: E.division_polynomial(2, two_torsion_multiplicity=0)
|
|
1999
|
+
1
|
|
2000
|
+
sage: E.division_polynomial(2, two_torsion_multiplicity=1)
|
|
2001
|
+
2*y + 1
|
|
2002
|
+
sage: E.division_polynomial(2, two_torsion_multiplicity=2)
|
|
2003
|
+
4*x^3 - 4*x + 1
|
|
2004
|
+
sage: E.division_polynomial(2)
|
|
2005
|
+
4*x^3 - 4*x + 1
|
|
2006
|
+
sage: [E.division_polynomial(3, two_torsion_multiplicity=i) for i in range(3)]
|
|
2007
|
+
[3*x^4 - 6*x^2 + 3*x - 1, 3*x^4 - 6*x^2 + 3*x - 1, 3*x^4 - 6*x^2 + 3*x - 1]
|
|
2008
|
+
sage: [type(E.division_polynomial(3, two_torsion_multiplicity=i)) for i in range(3)]
|
|
2009
|
+
[<... 'sage.rings.polynomial.polynomial_rational_flint.Polynomial_rational_flint'>,
|
|
2010
|
+
<... 'sage.rings.polynomial.multi_polynomial_libsingular.MPolynomial_libsingular'>,
|
|
2011
|
+
<... 'sage.rings.polynomial.polynomial_rational_flint.Polynomial_rational_flint'>]
|
|
2012
|
+
|
|
2013
|
+
::
|
|
2014
|
+
|
|
2015
|
+
sage: E = EllipticCurve([0, -1, 1, -10, -20])
|
|
2016
|
+
sage: R.<z> = PolynomialRing(QQ)
|
|
2017
|
+
sage: E.division_polynomial(4, z, 0)
|
|
2018
|
+
2*z^6 - 4*z^5 - 100*z^4 - 790*z^3 - 210*z^2 - 1496*z - 5821
|
|
2019
|
+
sage: E.division_polynomial(4, z)
|
|
2020
|
+
8*z^9 - 24*z^8 - 464*z^7 - 2758*z^6 + 6636*z^5 + 34356*z^4
|
|
2021
|
+
+ 53510*z^3 + 99714*z^2 + 351024*z + 459859
|
|
2022
|
+
|
|
2023
|
+
This does not work, since when two_torsion_multiplicity is 1, we
|
|
2024
|
+
compute a bivariate polynomial, and must evaluate at a tuple of
|
|
2025
|
+
length 2::
|
|
2026
|
+
|
|
2027
|
+
sage: E.division_polynomial(4,z,1)
|
|
2028
|
+
Traceback (most recent call last):
|
|
2029
|
+
...
|
|
2030
|
+
ValueError: x should be a tuple of length 2 (or None)
|
|
2031
|
+
when two_torsion_multiplicity is 1
|
|
2032
|
+
sage: R.<z,w> = PolynomialRing(QQ, 2)
|
|
2033
|
+
sage: E.division_polynomial(4, (z,w), 1).factor()
|
|
2034
|
+
(2*w + 1) * (2*z^6 - 4*z^5 - 100*z^4 - 790*z^3 - 210*z^2 - 1496*z - 5821)
|
|
2035
|
+
|
|
2036
|
+
We can also evaluate this bivariate polynomial at a point::
|
|
2037
|
+
|
|
2038
|
+
sage: P = E(5,5)
|
|
2039
|
+
sage: E.division_polynomial(4,P,two_torsion_multiplicity=1)
|
|
2040
|
+
-1771561
|
|
2041
|
+
|
|
2042
|
+
TESTS:
|
|
2043
|
+
|
|
2044
|
+
Check that :issue:`33164` is fixed::
|
|
2045
|
+
|
|
2046
|
+
sage: E = EllipticCurve('11a3')
|
|
2047
|
+
sage: R.<X> = QQ[]
|
|
2048
|
+
sage: S.<Y> = R.quotient(X^2)
|
|
2049
|
+
sage: E.division_polynomial(5, x=Y)
|
|
2050
|
+
-5*Y
|
|
2051
|
+
sage: E.division_polynomial(5, x=X)
|
|
2052
|
+
5*X^12 - 20*X^11 + 16*X^10 + 95*X^9 - 285*X^8 + 360*X^7 - 255*X^6 + 94*X^5 + 15*X^4 - 45*X^3 + 25*X^2 - 5*X
|
|
2053
|
+
|
|
2054
|
+
Tests for the ``force_evaluate`` argument::
|
|
2055
|
+
|
|
2056
|
+
sage: E.division_polynomial(5, x=Y, force_evaluate=0)
|
|
2057
|
+
-5*Y
|
|
2058
|
+
sage: E.division_polynomial(5, x=Y, force_evaluate=1)
|
|
2059
|
+
-5*Y
|
|
2060
|
+
sage: E.division_polynomial(5, x=Y, force_evaluate=2)
|
|
2061
|
+
-5*Y
|
|
2062
|
+
sage: E._EllipticCurve_generic__divpolys[2]
|
|
2063
|
+
{5: 5*x^12 - 20*x^11 + 16*x^10 + 95*x^9 - 285*x^8 + 360*x^7 - 255*x^6 + 94*x^5 + 15*x^4 - 45*x^3 + 25*x^2 - 5*x}
|
|
2064
|
+
sage: E._EllipticCurve_generic__divpolys[2][5] += 1 # poison cache
|
|
2065
|
+
sage: E.division_polynomial(5, x=Y, force_evaluate=0)
|
|
2066
|
+
-5*Y
|
|
2067
|
+
sage: E.division_polynomial(5, x=Y, force_evaluate=1)
|
|
2068
|
+
-5*Y + 1
|
|
2069
|
+
sage: E.division_polynomial(5, x=Y, force_evaluate=2)
|
|
2070
|
+
-5*Y + 1
|
|
2071
|
+
"""
|
|
2072
|
+
if two_torsion_multiplicity not in (0, 1, 2):
|
|
2073
|
+
raise ValueError("two_torsion_multiplicity must be 0, 1, or 2")
|
|
2074
|
+
|
|
2075
|
+
if x is not None and two_torsion_multiplicity == 1:
|
|
2076
|
+
if isinstance(x, ell_point.EllipticCurvePoint_field):
|
|
2077
|
+
x = x.xy()
|
|
2078
|
+
if not (isinstance(x, tuple) and len(x) == 2):
|
|
2079
|
+
raise ValueError("x should be a tuple of length 2 (or None) when two_torsion_multiplicity is 1")
|
|
2080
|
+
|
|
2081
|
+
m = Integer(m)
|
|
2082
|
+
|
|
2083
|
+
if x is None:
|
|
2084
|
+
try:
|
|
2085
|
+
return self.__divpolys[two_torsion_multiplicity][m]
|
|
2086
|
+
except KeyError:
|
|
2087
|
+
pass
|
|
2088
|
+
|
|
2089
|
+
evaluate = False
|
|
2090
|
+
if force_evaluate is not None:
|
|
2091
|
+
evaluate = force_evaluate
|
|
2092
|
+
elif x is not None:
|
|
2093
|
+
# Univariate polynomials are much faster---this signals that the
|
|
2094
|
+
# result should first be computed as an univariate polynomial and
|
|
2095
|
+
# only then converted, even if it is not yet cached.
|
|
2096
|
+
if polynomial_is_variable(x) and x.base_ring() is self.base_ring():
|
|
2097
|
+
evaluate = 2
|
|
2098
|
+
|
|
2099
|
+
# Evaluating a precomputed polynomial is linear in the degree,
|
|
2100
|
+
# while the recursive definition is only logarithmic. For small
|
|
2101
|
+
# inputs, evaluation can be better nevertheless.
|
|
2102
|
+
# The following cutoffs were estimated based on experiments in
|
|
2103
|
+
# January 2022 (using Sage version 9.5.rc0).
|
|
2104
|
+
elif x in self.base_ring():
|
|
2105
|
+
evaluate = m < 100
|
|
2106
|
+
elif isinstance(x, PolynomialQuotientRingElement) and x.lift().is_gen() \
|
|
2107
|
+
and x.lift().base_ring() is self.base_ring():
|
|
2108
|
+
d = x.parent().modulus().degree()
|
|
2109
|
+
evaluate = m < 220 or \
|
|
2110
|
+
(d < 10 and m < 420) or (d < 15 and m < 340) or \
|
|
2111
|
+
(d < 30 and m < 280) or (d < 100 and m < 250) or \
|
|
2112
|
+
m <= min(250, d)
|
|
2113
|
+
|
|
2114
|
+
# Check if we should (attempt to) compute the result by simply
|
|
2115
|
+
# evaluating a cached polynomial at the given input.
|
|
2116
|
+
if evaluate:
|
|
2117
|
+
try:
|
|
2118
|
+
return self.__divpolys[two_torsion_multiplicity][m](x)
|
|
2119
|
+
except KeyError:
|
|
2120
|
+
if evaluate == 2:
|
|
2121
|
+
return self.division_polynomial(m, two_torsion_multiplicity=two_torsion_multiplicity)(x)
|
|
2122
|
+
|
|
2123
|
+
# If not, .division_polynomial_0() will do the real work for us.
|
|
2124
|
+
if two_torsion_multiplicity == 0:
|
|
2125
|
+
return self.division_polynomial_0(m, x)
|
|
2126
|
+
|
|
2127
|
+
should_cache = x is None
|
|
2128
|
+
|
|
2129
|
+
if two_torsion_multiplicity == 1:
|
|
2130
|
+
x,y = x if x is not None else (None,None)
|
|
2131
|
+
|
|
2132
|
+
if evaluate and m in self.__divpolys[0]:
|
|
2133
|
+
f = self.__divpolys[0][m](x)
|
|
2134
|
+
else:
|
|
2135
|
+
f = self.division_polynomial_0(m, x)
|
|
2136
|
+
|
|
2137
|
+
if two_torsion_multiplicity == 2:
|
|
2138
|
+
if m % 2 == 0:
|
|
2139
|
+
f *= self.division_polynomial_0(-1, x)
|
|
2140
|
+
elif two_torsion_multiplicity == 1:
|
|
2141
|
+
if x is y is None:
|
|
2142
|
+
x,y = polygens(self.base_ring(), 'x,y')
|
|
2143
|
+
f = f(x)
|
|
2144
|
+
if m % 2 == 0:
|
|
2145
|
+
f *= 2*y + self.a1()*x + self.a3()
|
|
2146
|
+
|
|
2147
|
+
if should_cache:
|
|
2148
|
+
self.__divpolys[two_torsion_multiplicity][m] = f
|
|
2149
|
+
return f
|
|
2150
|
+
|
|
2151
|
+
torsion_polynomial = division_polynomial
|
|
2152
|
+
|
|
2153
|
+
def _multiple_x_numerator(self, n, x=None):
|
|
2154
|
+
r"""
|
|
2155
|
+
Return the numerator of the `x`-coordinate of the `n\th` multiple of a
|
|
2156
|
+
point, using torsion polynomials (division polynomials).
|
|
2157
|
+
|
|
2158
|
+
INPUT:
|
|
2159
|
+
|
|
2160
|
+
- ``n``, ``x`` -- as described in :meth:`division_polynomial_0`
|
|
2161
|
+
|
|
2162
|
+
If ``x`` is ``None``, the result is cached. This is so that on calling
|
|
2163
|
+
``P.division_points(n)`` for the same `n` and different points `P` (on
|
|
2164
|
+
the same curve), we do not have to recompute the polynomials.
|
|
2165
|
+
|
|
2166
|
+
.. WARNING::
|
|
2167
|
+
|
|
2168
|
+
There may of course be cancellation between the numerator and the
|
|
2169
|
+
denominator (:meth:`_multiple_x_denominator`). Be careful. E.g. if
|
|
2170
|
+
a point on an elliptic curve with coefficients in `\ZZ` reduces to
|
|
2171
|
+
a singular point modulo a prime, then there will be cancellation,
|
|
2172
|
+
otherwise not, see [Wu2004]_.
|
|
2173
|
+
|
|
2174
|
+
.. SEEALSO::
|
|
2175
|
+
|
|
2176
|
+
:meth:`_multiple_x_denominator`
|
|
2177
|
+
|
|
2178
|
+
AUTHORS:
|
|
2179
|
+
|
|
2180
|
+
- David Harvey (2006-09-24)
|
|
2181
|
+
|
|
2182
|
+
EXAMPLES::
|
|
2183
|
+
|
|
2184
|
+
sage: E = EllipticCurve([1,2])
|
|
2185
|
+
sage: E._multiple_x_numerator(3)
|
|
2186
|
+
x^9 - 12*x^7 - 192*x^6 + 30*x^5 - 48*x^4 + 228*x^3 + 96*x^2 + 393*x + 528
|
|
2187
|
+
sage: E._multiple_x_numerator(-3)
|
|
2188
|
+
x^9 - 12*x^7 - 192*x^6 + 30*x^5 - 48*x^4 + 228*x^3 + 96*x^2 + 393*x + 528
|
|
2189
|
+
|
|
2190
|
+
::
|
|
2191
|
+
|
|
2192
|
+
sage: E = EllipticCurve("37a")
|
|
2193
|
+
sage: P = E.gens()[0] # needs eclib
|
|
2194
|
+
sage: x = P[0] # needs eclib
|
|
2195
|
+
|
|
2196
|
+
::
|
|
2197
|
+
|
|
2198
|
+
sage: # needs eclib
|
|
2199
|
+
sage: (35*P)[0]
|
|
2200
|
+
-804287518035141565236193151/1063198259901027900600665796
|
|
2201
|
+
sage: E._multiple_x_numerator(35, x)
|
|
2202
|
+
-804287518035141565236193151
|
|
2203
|
+
sage: E._multiple_x_denominator(35, x)
|
|
2204
|
+
1063198259901027900600665796
|
|
2205
|
+
|
|
2206
|
+
::
|
|
2207
|
+
|
|
2208
|
+
sage: # needs eclib
|
|
2209
|
+
sage: (36*P)[0]
|
|
2210
|
+
54202648602164057575419038802/15402543997324146892198790401
|
|
2211
|
+
sage: E._multiple_x_numerator(36, x)
|
|
2212
|
+
54202648602164057575419038802
|
|
2213
|
+
sage: E._multiple_x_denominator(36, x)
|
|
2214
|
+
15402543997324146892198790401
|
|
2215
|
+
|
|
2216
|
+
An example where cancellation occurs::
|
|
2217
|
+
|
|
2218
|
+
sage: E = EllipticCurve("88a1")
|
|
2219
|
+
sage: P = E([2,2]) # fixed choice of generator
|
|
2220
|
+
sage: n = E._multiple_x_numerator(11, P[0]); n
|
|
2221
|
+
442446784738847563128068650529343492278651453440
|
|
2222
|
+
sage: d = E._multiple_x_denominator(11, P[0]); d
|
|
2223
|
+
1427247692705959881058285969449495136382746624
|
|
2224
|
+
sage: n/d
|
|
2225
|
+
310
|
|
2226
|
+
sage: 11*P
|
|
2227
|
+
(310 : -5458 : 1)
|
|
2228
|
+
|
|
2229
|
+
TESTS:
|
|
2230
|
+
|
|
2231
|
+
Check that the results are cached::
|
|
2232
|
+
|
|
2233
|
+
sage: E = EllipticCurve("88a1")
|
|
2234
|
+
sage: E._multiple_x_numerator(11) is E._multiple_x_numerator(11)
|
|
2235
|
+
True
|
|
2236
|
+
|
|
2237
|
+
Check for :issue:`33156`::
|
|
2238
|
+
|
|
2239
|
+
sage: # needs sage.rings.finite_rings
|
|
2240
|
+
sage: E = EllipticCurve(GF(65537), [5,5])
|
|
2241
|
+
sage: R.<x> = E.base_field()[]
|
|
2242
|
+
sage: E._multiple_x_numerator(5, x=R.quotient(x^2).gen())
|
|
2243
|
+
10220*xbar + 42539
|
|
2244
|
+
sage: E._multiple_x_numerator(5)
|
|
2245
|
+
x^25 + 65037*x^23 + 55137*x^22 + ... + 813*x^2 + 10220*x + 42539
|
|
2246
|
+
"""
|
|
2247
|
+
n = Integer(n).abs()
|
|
2248
|
+
if not n:
|
|
2249
|
+
raise ValueError("n must be nonzero")
|
|
2250
|
+
|
|
2251
|
+
if x is None:
|
|
2252
|
+
try:
|
|
2253
|
+
cache = self.__mulxnums
|
|
2254
|
+
except AttributeError:
|
|
2255
|
+
cache = self.__mulxnums = {}
|
|
2256
|
+
try:
|
|
2257
|
+
return cache[n]
|
|
2258
|
+
except KeyError:
|
|
2259
|
+
pass
|
|
2260
|
+
xx = polygen(self.base_ring())
|
|
2261
|
+
else:
|
|
2262
|
+
cache = None
|
|
2263
|
+
xx = x
|
|
2264
|
+
|
|
2265
|
+
if n == 1:
|
|
2266
|
+
return xx
|
|
2267
|
+
|
|
2268
|
+
polys = self.division_polynomial_0([-2,-1,n-1,n,n+1], x)
|
|
2269
|
+
|
|
2270
|
+
if n % 2 == 0:
|
|
2271
|
+
ret = xx * polys[1] * polys[3]**2 - polys[2] * polys[4]
|
|
2272
|
+
else:
|
|
2273
|
+
ret = xx * polys[3]**2 - polys[1] * polys[2] * polys[4]
|
|
2274
|
+
|
|
2275
|
+
if cache is not None:
|
|
2276
|
+
cache[n] = ret
|
|
2277
|
+
return ret
|
|
2278
|
+
|
|
2279
|
+
def _multiple_x_denominator(self, n, x=None):
|
|
2280
|
+
r"""
|
|
2281
|
+
Return the denominator of the `x`-coordinate of the `n\th` multiple of
|
|
2282
|
+
a point, using torsion polynomials (division polynomials).
|
|
2283
|
+
|
|
2284
|
+
INPUT:
|
|
2285
|
+
|
|
2286
|
+
- ``n``, ``x`` -- as described in :meth:`division_polynomial_0`
|
|
2287
|
+
|
|
2288
|
+
If ``x`` is ``None``, the result is cached. This is so that on calling
|
|
2289
|
+
``P.division_points(n)`` for the same `n` and different points `P` (on
|
|
2290
|
+
the same curve), we do not have to recompute the polynomials.
|
|
2291
|
+
|
|
2292
|
+
AUTHORS:
|
|
2293
|
+
|
|
2294
|
+
- David Harvey (2006-09-24)
|
|
2295
|
+
|
|
2296
|
+
.. SEEALSO::
|
|
2297
|
+
|
|
2298
|
+
:meth:`multiple_x_numerator`
|
|
2299
|
+
|
|
2300
|
+
.. TODO::
|
|
2301
|
+
|
|
2302
|
+
The numerator and denominator versions share a calculation, namely
|
|
2303
|
+
squaring `\psi_n`. Maybe would be good to offer a combined version
|
|
2304
|
+
to make this more efficient.
|
|
2305
|
+
|
|
2306
|
+
EXAMPLES::
|
|
2307
|
+
|
|
2308
|
+
sage: E = EllipticCurve([1,2])
|
|
2309
|
+
sage: E._multiple_x_denominator(3)
|
|
2310
|
+
9*x^8 + 36*x^6 + 144*x^5 + 30*x^4 + 288*x^3 + 564*x^2 - 48*x + 1
|
|
2311
|
+
sage: E._multiple_x_denominator(-3)
|
|
2312
|
+
9*x^8 + 36*x^6 + 144*x^5 + 30*x^4 + 288*x^3 + 564*x^2 - 48*x + 1
|
|
2313
|
+
|
|
2314
|
+
::
|
|
2315
|
+
|
|
2316
|
+
sage: # needs eclib
|
|
2317
|
+
sage: E = EllipticCurve("43a")
|
|
2318
|
+
sage: P = E.gens()[0]
|
|
2319
|
+
sage: x = P[0]
|
|
2320
|
+
sage: (31*P)[0]
|
|
2321
|
+
-33058398375463796474831580/154693637754223970056975321
|
|
2322
|
+
sage: E._multiple_x_numerator(31, x)
|
|
2323
|
+
-33058398375463796474831580
|
|
2324
|
+
sage: E._multiple_x_denominator(31, x)
|
|
2325
|
+
154693637754223970056975321
|
|
2326
|
+
|
|
2327
|
+
TESTS:
|
|
2328
|
+
|
|
2329
|
+
Check that the results are cached::
|
|
2330
|
+
|
|
2331
|
+
sage: E = EllipticCurve("88a1")
|
|
2332
|
+
sage: E._multiple_x_denominator(11) is E._multiple_x_denominator(11)
|
|
2333
|
+
True
|
|
2334
|
+
|
|
2335
|
+
Check for :issue:`33156`::
|
|
2336
|
+
|
|
2337
|
+
sage: # needs sage.rings.finite_rings
|
|
2338
|
+
sage: E = EllipticCurve(GF(65537), [5,5])
|
|
2339
|
+
sage: R.<x> = E.base_field()[]
|
|
2340
|
+
sage: E._multiple_x_denominator(5, x=R.quotient(x^2).gen())
|
|
2341
|
+
52039*xbar + 56726
|
|
2342
|
+
sage: E._multiple_x_denominator(5)
|
|
2343
|
+
25*x^24 + 3100*x^22 + 19000*x^21 + ... + 24111*x^2 + 52039*x + 56726
|
|
2344
|
+
"""
|
|
2345
|
+
n = Integer(n).abs()
|
|
2346
|
+
if not n:
|
|
2347
|
+
raise ValueError("n must be nonzero")
|
|
2348
|
+
|
|
2349
|
+
if x is None:
|
|
2350
|
+
try:
|
|
2351
|
+
cache = self.__mulxdens
|
|
2352
|
+
except AttributeError:
|
|
2353
|
+
cache = self.__mulxdens = {}
|
|
2354
|
+
try:
|
|
2355
|
+
return cache[n]
|
|
2356
|
+
except KeyError:
|
|
2357
|
+
pass
|
|
2358
|
+
else:
|
|
2359
|
+
cache = None
|
|
2360
|
+
|
|
2361
|
+
ret = self.division_polynomial_0(n, x)**2
|
|
2362
|
+
if n % 2 == 0:
|
|
2363
|
+
ret *= self.division_polynomial_0(-1, x)
|
|
2364
|
+
|
|
2365
|
+
if cache is not None:
|
|
2366
|
+
cache[n] = ret
|
|
2367
|
+
return ret
|
|
2368
|
+
|
|
2369
|
+
def multiplication_by_m(self, m, x_only=False):
|
|
2370
|
+
r"""
|
|
2371
|
+
Return the multiplication-by-`m` map from ``self`` to ``self``.
|
|
2372
|
+
|
|
2373
|
+
The result is a pair of rational functions in two variables
|
|
2374
|
+
`x`, `y` (or a rational function in one variable `x` if
|
|
2375
|
+
``x_only`` is ``True``).
|
|
2376
|
+
|
|
2377
|
+
INPUT:
|
|
2378
|
+
|
|
2379
|
+
- ``m`` -- nonzero integer
|
|
2380
|
+
|
|
2381
|
+
- ``x_only`` -- boolean (default: ``False``); if ``True``, return only
|
|
2382
|
+
the `x`-coordinate of the map (as a rational function in one variable)
|
|
2383
|
+
|
|
2384
|
+
OUTPUT:
|
|
2385
|
+
|
|
2386
|
+
- a pair `(f(x), g(x,y))`, where `f` and `g` are rational
|
|
2387
|
+
functions with the degree of `y` in `g(x,y)` exactly 1,
|
|
2388
|
+
|
|
2389
|
+
- or just `f(x)` if ``x_only`` is ``True``
|
|
2390
|
+
|
|
2391
|
+
.. NOTE::
|
|
2392
|
+
|
|
2393
|
+
- The result is not cached.
|
|
2394
|
+
|
|
2395
|
+
- ``m`` is allowed to be negative (but not 0).
|
|
2396
|
+
|
|
2397
|
+
EXAMPLES::
|
|
2398
|
+
|
|
2399
|
+
sage: E = EllipticCurve([-1,3])
|
|
2400
|
+
|
|
2401
|
+
We verify that multiplication by 1 is just the identity::
|
|
2402
|
+
|
|
2403
|
+
sage: E.multiplication_by_m(1)
|
|
2404
|
+
(x, y)
|
|
2405
|
+
|
|
2406
|
+
Multiplication by 2 is more complicated::
|
|
2407
|
+
|
|
2408
|
+
sage: f = E.multiplication_by_m(2)
|
|
2409
|
+
sage: f
|
|
2410
|
+
((x^4 + 2*x^2 - 24*x + 1)/(4*x^3 - 4*x + 12),
|
|
2411
|
+
(8*x^6*y - 40*x^4*y + 480*x^3*y - 40*x^2*y + 96*x*y - 568*y)/(64*x^6 - 128*x^4 + 384*x^3 + 64*x^2 - 384*x + 576))
|
|
2412
|
+
|
|
2413
|
+
Grab only the x-coordinate (less work)::
|
|
2414
|
+
|
|
2415
|
+
sage: mx = E.multiplication_by_m(2, x_only=True); mx
|
|
2416
|
+
(1/4*x^4 + 1/2*x^2 - 6*x + 1/4)/(x^3 - x + 3)
|
|
2417
|
+
sage: mx.parent()
|
|
2418
|
+
Fraction Field of Univariate Polynomial Ring in x over Rational Field
|
|
2419
|
+
|
|
2420
|
+
We check that it works on a point::
|
|
2421
|
+
|
|
2422
|
+
sage: P = E([2,3])
|
|
2423
|
+
sage: eval = lambda f,P: [fi(P[0],P[1]) for fi in f]
|
|
2424
|
+
sage: assert E(eval(f,P)) == 2*P
|
|
2425
|
+
|
|
2426
|
+
We do the same but with multiplication by 3::
|
|
2427
|
+
|
|
2428
|
+
sage: f = E.multiplication_by_m(3)
|
|
2429
|
+
sage: assert E(eval(f,P)) == 3*P
|
|
2430
|
+
|
|
2431
|
+
And the same with multiplication by 4::
|
|
2432
|
+
|
|
2433
|
+
sage: f = E.multiplication_by_m(4)
|
|
2434
|
+
sage: assert E(eval(f,P)) == 4*P
|
|
2435
|
+
|
|
2436
|
+
And the same with multiplication by -1,-2,-3,-4::
|
|
2437
|
+
|
|
2438
|
+
sage: for m in [-1,-2,-3,-4]:
|
|
2439
|
+
....: f = E.multiplication_by_m(m)
|
|
2440
|
+
....: assert E(eval(f,P)) == m*P
|
|
2441
|
+
|
|
2442
|
+
TESTS:
|
|
2443
|
+
|
|
2444
|
+
Verify for this fairly random looking curve and point that
|
|
2445
|
+
multiplication by m returns the right result for the first 10
|
|
2446
|
+
integers::
|
|
2447
|
+
|
|
2448
|
+
sage: E = EllipticCurve([23,-105])
|
|
2449
|
+
sage: P = E([129/4, 1479/8])
|
|
2450
|
+
sage: for n in [1..10]:
|
|
2451
|
+
....: f = E.multiplication_by_m(n)
|
|
2452
|
+
....: Q = n*P
|
|
2453
|
+
....: assert Q == E(eval(f,P))
|
|
2454
|
+
....: f = E.multiplication_by_m(-n)
|
|
2455
|
+
....: Q = -n*P
|
|
2456
|
+
....: assert Q == E(eval(f,P))
|
|
2457
|
+
|
|
2458
|
+
The following test shows that :issue:`4364` is indeed fixed::
|
|
2459
|
+
|
|
2460
|
+
sage: # needs sage.rings.finite_rings
|
|
2461
|
+
sage: p = next_prime(2^30 - 41)
|
|
2462
|
+
sage: a = GF(p)(1)
|
|
2463
|
+
sage: b = GF(p)(1)
|
|
2464
|
+
sage: E = EllipticCurve([a, b])
|
|
2465
|
+
sage: P = E.random_point()
|
|
2466
|
+
sage: my_eval = lambda f,P: [fi(P[0],P[1]) for fi in f]
|
|
2467
|
+
sage: f = E.multiplication_by_m(2)
|
|
2468
|
+
sage: assert(E(eval(f,P)) == 2*P)
|
|
2469
|
+
|
|
2470
|
+
The following test shows that :issue:`6413` is fixed for elliptic curves over finite fields::
|
|
2471
|
+
sage: p = 7
|
|
2472
|
+
sage: K.<a> = GF(p^2)
|
|
2473
|
+
sage: E = EllipticCurve(K, [a + 3, 5 - a])
|
|
2474
|
+
sage: k = p^2 * 3
|
|
2475
|
+
sage: f, g = E.multiplication_by_m(k)
|
|
2476
|
+
sage: for _ in range(100):
|
|
2477
|
+
....: P = E.random_point()
|
|
2478
|
+
....: if P * k == 0:
|
|
2479
|
+
....: continue
|
|
2480
|
+
....: Qx = f.subs(x=P[0])
|
|
2481
|
+
....: Qy = g.subs(x=P[0], y=P[1])
|
|
2482
|
+
....: assert (P * k).xy() == (Qx, Qy)
|
|
2483
|
+
|
|
2484
|
+
However, it still fails for elliptic curves over positive-characteristic fields::
|
|
2485
|
+
|
|
2486
|
+
sage: F.<a> = FunctionField(GF(7))
|
|
2487
|
+
sage: E = EllipticCurve(F, [a, 1 / a])
|
|
2488
|
+
sage: E.multiplication_by_m(7)
|
|
2489
|
+
Traceback (most recent call last):
|
|
2490
|
+
...
|
|
2491
|
+
NotImplementedError: multiplication by integer not coprime to p is only implemented for curves over finite fields
|
|
2492
|
+
|
|
2493
|
+
::
|
|
2494
|
+
|
|
2495
|
+
sage: p = 7
|
|
2496
|
+
sage: K.<a> = GF(p^2)
|
|
2497
|
+
sage: E = EllipticCurve(j=K.random_element())
|
|
2498
|
+
sage: E.multiplication_by_m(p * 2)[0] == E.multiplication_by_m(p * 2, x_only=True)
|
|
2499
|
+
True
|
|
2500
|
+
"""
|
|
2501
|
+
# Coerce the input m to be an integer
|
|
2502
|
+
m = Integer(m)
|
|
2503
|
+
p = self.base_ring().characteristic()
|
|
2504
|
+
|
|
2505
|
+
if m == 0:
|
|
2506
|
+
raise ValueError("m must be a nonzero integer")
|
|
2507
|
+
|
|
2508
|
+
if x_only:
|
|
2509
|
+
x = polygen(self.base_ring(), 'x')
|
|
2510
|
+
else:
|
|
2511
|
+
from sage.rings.finite_rings.finite_field_base import FiniteField as FiniteField_generic
|
|
2512
|
+
if p != 0 and m % p == 0 and not isinstance(self.base_ring(), FiniteField_generic):
|
|
2513
|
+
# TODO: Implement the correct formula?
|
|
2514
|
+
raise NotImplementedError("multiplication by integer not coprime to p "
|
|
2515
|
+
"is only implemented for curves over finite fields")
|
|
2516
|
+
x, y = polygens(self.base_ring(), 'x,y')
|
|
2517
|
+
|
|
2518
|
+
# Special case of multiplication by 1 is easy.
|
|
2519
|
+
if m == 1:
|
|
2520
|
+
if not x_only:
|
|
2521
|
+
return (x, y)
|
|
2522
|
+
else:
|
|
2523
|
+
return x
|
|
2524
|
+
|
|
2525
|
+
# Grab curve invariants
|
|
2526
|
+
a1, _, a3, _, _ = self.a_invariants()
|
|
2527
|
+
|
|
2528
|
+
if m == -1:
|
|
2529
|
+
if not x_only:
|
|
2530
|
+
return (x, -y-a1*x-a3)
|
|
2531
|
+
else:
|
|
2532
|
+
return x
|
|
2533
|
+
|
|
2534
|
+
# If we only require the x coordinate, it is faster to use the recursive formula
|
|
2535
|
+
# since substituting polynomials is quite slow.
|
|
2536
|
+
v_p = 0 if p == 0 else valuation(m, p)
|
|
2537
|
+
if not x_only:
|
|
2538
|
+
m //= p**v_p
|
|
2539
|
+
|
|
2540
|
+
# the x-coordinate does not depend on the sign of m. The work
|
|
2541
|
+
# here is done by functions defined earlier:
|
|
2542
|
+
|
|
2543
|
+
mx = (x.parent()(self._multiple_x_numerator(m.abs(), x))
|
|
2544
|
+
/ x.parent()(self._multiple_x_denominator(m.abs(), x)))
|
|
2545
|
+
|
|
2546
|
+
if x_only:
|
|
2547
|
+
return mx
|
|
2548
|
+
|
|
2549
|
+
# Consideration of the invariant differential
|
|
2550
|
+
# w=dx/(2*y+a1*x+a3) shows that m*w = d(mx)/(2*my+a1*mx+a3)
|
|
2551
|
+
# and hence 2*my+a1*mx+a3 = (1/m)*(2*y+a1*x+a3)*d(mx)/dx
|
|
2552
|
+
my = ((2*y+a1*x+a3)*mx.derivative(x)/m - a1*mx-a3)/2
|
|
2553
|
+
|
|
2554
|
+
if v_p > 0:
|
|
2555
|
+
isog = self.multiplication_by_p_isogeny()**v_p
|
|
2556
|
+
fx, fy = isog.rational_maps()
|
|
2557
|
+
# slow...
|
|
2558
|
+
mx = mx.subs(x=fx)
|
|
2559
|
+
my = my.subs(x=fx, y=fy)
|
|
2560
|
+
|
|
2561
|
+
return mx, my
|
|
2562
|
+
|
|
2563
|
+
def scalar_multiplication(self, m):
|
|
2564
|
+
r"""
|
|
2565
|
+
Return the scalar-multiplication map `[m]` on this elliptic
|
|
2566
|
+
curve as a
|
|
2567
|
+
:class:`sage.schemes.elliptic_curves.hom_scalar.EllipticCurveHom_scalar`
|
|
2568
|
+
object.
|
|
2569
|
+
|
|
2570
|
+
EXAMPLES::
|
|
2571
|
+
|
|
2572
|
+
sage: E = EllipticCurve('77a1')
|
|
2573
|
+
sage: m = E.scalar_multiplication(-7); m
|
|
2574
|
+
Scalar-multiplication endomorphism [-7]
|
|
2575
|
+
of Elliptic Curve defined by y^2 + y = x^3 + 2*x over Rational Field
|
|
2576
|
+
sage: m.degree()
|
|
2577
|
+
49
|
|
2578
|
+
sage: P = E(2,3)
|
|
2579
|
+
sage: m(P)
|
|
2580
|
+
(-26/225 : -2132/3375 : 1)
|
|
2581
|
+
sage: m.rational_maps() == E.multiplication_by_m(-7)
|
|
2582
|
+
True
|
|
2583
|
+
|
|
2584
|
+
::
|
|
2585
|
+
|
|
2586
|
+
sage: E = EllipticCurve('11a1')
|
|
2587
|
+
sage: E.scalar_multiplication(7)
|
|
2588
|
+
Scalar-multiplication endomorphism [7]
|
|
2589
|
+
of Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field
|
|
2590
|
+
|
|
2591
|
+
TESTS:
|
|
2592
|
+
|
|
2593
|
+
Tests for :issue:`32490`::
|
|
2594
|
+
|
|
2595
|
+
sage: E = EllipticCurve(QQbar, [1,0]) # needs sage.rings.number_field
|
|
2596
|
+
sage: E.scalar_multiplication(1).rational_maps() # needs sage.rings.number_field
|
|
2597
|
+
(x, y)
|
|
2598
|
+
|
|
2599
|
+
::
|
|
2600
|
+
|
|
2601
|
+
sage: E = EllipticCurve_from_j(GF(31337).random_element()) # needs sage.rings.finite_rings
|
|
2602
|
+
sage: P = E.random_point() # needs sage.rings.finite_rings
|
|
2603
|
+
sage: [E.scalar_multiplication(m)(P) == m*P for m in (1,2,3,5,7,9)] # needs sage.rings.finite_rings
|
|
2604
|
+
[True, True, True, True, True, True]
|
|
2605
|
+
|
|
2606
|
+
::
|
|
2607
|
+
|
|
2608
|
+
sage: E = EllipticCurve('99.a1')
|
|
2609
|
+
sage: E.scalar_multiplication(5)
|
|
2610
|
+
Scalar-multiplication endomorphism [5]
|
|
2611
|
+
of Elliptic Curve defined by y^2 + x*y + y = x^3 - x^2 - 17*x + 30 over Rational Field
|
|
2612
|
+
sage: E.scalar_multiplication(2).rational_maps()
|
|
2613
|
+
((x^4 + 33*x^2 - 242*x + 363)/(4*x^3 - 3*x^2 - 66*x + 121),
|
|
2614
|
+
(-4*x^7 + 8*x^6*y - 28*x^6 - 12*x^5*y - 420*x^5 - 660*x^4*y + 5020*x^4 + 4840*x^3*y - 7568*x^3 - 14520*x^2*y - 42108*x^2 + 20328*x*y + 143264*x - 10648*y - 122452)/(64*x^6 - 96*x^5 - 2076*x^4 + 5456*x^3 + 14520*x^2 - 63888*x + 58564))
|
|
2615
|
+
"""
|
|
2616
|
+
from sage.schemes.elliptic_curves.hom_scalar import EllipticCurveHom_scalar
|
|
2617
|
+
return EllipticCurveHom_scalar(self, m)
|
|
2618
|
+
|
|
2619
|
+
def frobenius_isogeny(self, n=1):
|
|
2620
|
+
r"""
|
|
2621
|
+
Return the `n`-power Frobenius isogeny from this curve to
|
|
2622
|
+
its Galois conjugate.
|
|
2623
|
+
|
|
2624
|
+
The Frobenius *endo*\morphism is the special case where `n`
|
|
2625
|
+
is divisible by the degree of the base ring of the curve.
|
|
2626
|
+
|
|
2627
|
+
.. SEEALSO::
|
|
2628
|
+
|
|
2629
|
+
:meth:`~sage.schemes.elliptic_curves.ell_finite_field.EllipticCurve_finite_field.frobenius_endomorphism`
|
|
2630
|
+
|
|
2631
|
+
EXAMPLES::
|
|
2632
|
+
|
|
2633
|
+
sage: # needs sage.rings.finite_rings
|
|
2634
|
+
sage: z3, = GF(13^3).gens()
|
|
2635
|
+
sage: E = EllipticCurve([z3, z3^2])
|
|
2636
|
+
sage: E.frobenius_isogeny()
|
|
2637
|
+
Frobenius isogeny of degree 13:
|
|
2638
|
+
From: Elliptic Curve defined by y^2 = x^3 + z3*x + z3^2
|
|
2639
|
+
over Finite Field in z3 of size 13^3
|
|
2640
|
+
To: Elliptic Curve defined by y^2 = x^3 + (5*z3^2+7*z3+11)*x + (5*z3^2+12*z3+1)
|
|
2641
|
+
over Finite Field in z3 of size 13^3
|
|
2642
|
+
sage: E.frobenius_isogeny(3)
|
|
2643
|
+
Frobenius endomorphism of degree 2197 = 13^3:
|
|
2644
|
+
From: Elliptic Curve defined by y^2 = x^3 + z3*x + z3^2
|
|
2645
|
+
over Finite Field in z3 of size 13^3
|
|
2646
|
+
To: Elliptic Curve defined by y^2 = x^3 + z3*x + z3^2
|
|
2647
|
+
over Finite Field in z3 of size 13^3
|
|
2648
|
+
"""
|
|
2649
|
+
p = self.base_ring().characteristic()
|
|
2650
|
+
if not p:
|
|
2651
|
+
raise ValueError('Frobenius isogeny only exists in positive characteristic')
|
|
2652
|
+
from sage.schemes.elliptic_curves.hom_frobenius import EllipticCurveHom_frobenius
|
|
2653
|
+
return EllipticCurveHom_frobenius(self, n)
|
|
2654
|
+
|
|
2655
|
+
def identity_morphism(self):
|
|
2656
|
+
r"""
|
|
2657
|
+
Return the identity endomorphism of this elliptic curve
|
|
2658
|
+
as an :class:`EllipticCurveHom` object.
|
|
2659
|
+
|
|
2660
|
+
EXAMPLES::
|
|
2661
|
+
|
|
2662
|
+
sage: E = EllipticCurve(j=42)
|
|
2663
|
+
sage: E.identity_morphism()
|
|
2664
|
+
Elliptic-curve endomorphism of Elliptic Curve defined by y^2 = x^3 + 5901*x + 1105454 over Rational Field
|
|
2665
|
+
Via: (u,r,s,t) = (1, 0, 0, 0)
|
|
2666
|
+
sage: E.identity_morphism() == E.scalar_multiplication(1)
|
|
2667
|
+
True
|
|
2668
|
+
"""
|
|
2669
|
+
from sage.schemes.elliptic_curves.weierstrass_morphism import identity_morphism
|
|
2670
|
+
return identity_morphism(self)
|
|
2671
|
+
|
|
2672
|
+
def isomorphism_to(self, other):
|
|
2673
|
+
"""
|
|
2674
|
+
Given another weierstrass model ``other`` of ``self``, return an
|
|
2675
|
+
isomorphism from ``self`` to ``other``.
|
|
2676
|
+
|
|
2677
|
+
INPUT:
|
|
2678
|
+
|
|
2679
|
+
- ``other`` -- an elliptic curve isomorphic to ``self``
|
|
2680
|
+
|
|
2681
|
+
OUTPUT:
|
|
2682
|
+
|
|
2683
|
+
(Weierstrassmorphism) An isomorphism from ``self`` to ``other``.
|
|
2684
|
+
|
|
2685
|
+
.. NOTE::
|
|
2686
|
+
|
|
2687
|
+
If the curves in question are not isomorphic, a :exc:`ValueError`
|
|
2688
|
+
is raised.
|
|
2689
|
+
|
|
2690
|
+
EXAMPLES::
|
|
2691
|
+
|
|
2692
|
+
sage: E = EllipticCurve('37a')
|
|
2693
|
+
sage: F = E.short_weierstrass_model()
|
|
2694
|
+
sage: w = E.isomorphism_to(F); w
|
|
2695
|
+
Elliptic-curve morphism:
|
|
2696
|
+
From: Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
|
|
2697
|
+
To: Elliptic Curve defined by y^2 = x^3 - 16*x + 16 over Rational Field
|
|
2698
|
+
Via: (u,r,s,t) = (1/2, 0, 0, -1/2)
|
|
2699
|
+
sage: P = E(0,-1,1)
|
|
2700
|
+
sage: w(P)
|
|
2701
|
+
(0 : -4 : 1)
|
|
2702
|
+
sage: w(5*P)
|
|
2703
|
+
(1 : 1 : 1)
|
|
2704
|
+
sage: 5*w(P)
|
|
2705
|
+
(1 : 1 : 1)
|
|
2706
|
+
sage: 120*w(P) == w(120*P)
|
|
2707
|
+
True
|
|
2708
|
+
|
|
2709
|
+
We can also handle injections to different base rings::
|
|
2710
|
+
|
|
2711
|
+
sage: x = polygen(ZZ, 'x')
|
|
2712
|
+
sage: K.<a> = NumberField(x^3 - 7) # needs sage.rings.number_field
|
|
2713
|
+
sage: E.isomorphism_to(E.change_ring(K)) # needs sage.rings.number_field
|
|
2714
|
+
Elliptic-curve morphism:
|
|
2715
|
+
From: Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
|
|
2716
|
+
To: Elliptic Curve defined by y^2 + y = x^3 + (-1)*x
|
|
2717
|
+
over Number Field in a with defining polynomial x^3 - 7
|
|
2718
|
+
Via: (u,r,s,t) = (1, 0, 0, 0)
|
|
2719
|
+
"""
|
|
2720
|
+
return wm.WeierstrassIsomorphism(self, None, other)
|
|
2721
|
+
|
|
2722
|
+
def automorphisms(self, field=None):
|
|
2723
|
+
"""
|
|
2724
|
+
Return the set of isomorphisms from ``self`` to itself (as a list).
|
|
2725
|
+
|
|
2726
|
+
The identity and negation morphisms are guaranteed to appear
|
|
2727
|
+
as the first and second entry of the returned list.
|
|
2728
|
+
|
|
2729
|
+
INPUT:
|
|
2730
|
+
|
|
2731
|
+
- ``field`` -- (default: ``None``) a field into which the
|
|
2732
|
+
coefficients of the curve may be coerced (by default, uses
|
|
2733
|
+
the base field of the curve)
|
|
2734
|
+
|
|
2735
|
+
OUTPUT:
|
|
2736
|
+
|
|
2737
|
+
A list of :class:`~wm.WeierstrassIsomorphism` objects
|
|
2738
|
+
consisting of all the isomorphisms from the curve ``self`` to
|
|
2739
|
+
itself defined over ``field``.
|
|
2740
|
+
|
|
2741
|
+
EXAMPLES::
|
|
2742
|
+
|
|
2743
|
+
sage: E = EllipticCurve_from_j(QQ(0)) # a curve with j=0 over QQ
|
|
2744
|
+
sage: E.automorphisms()
|
|
2745
|
+
[Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3
|
|
2746
|
+
over Rational Field
|
|
2747
|
+
Via: (u,r,s,t) = (1, 0, 0, 0),
|
|
2748
|
+
Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3
|
|
2749
|
+
over Rational Field
|
|
2750
|
+
Via: (u,r,s,t) = (-1, 0, 0, -1)]
|
|
2751
|
+
|
|
2752
|
+
We can also find automorphisms defined over extension fields::
|
|
2753
|
+
|
|
2754
|
+
sage: x = polygen(ZZ, 'x')
|
|
2755
|
+
sage: K.<a> = NumberField(x^2 + 3) # adjoin roots of unity # needs sage.rings.number_field
|
|
2756
|
+
sage: E.automorphisms(K) # needs sage.rings.number_field
|
|
2757
|
+
[Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3
|
|
2758
|
+
over Number Field in a with defining polynomial x^2 + 3
|
|
2759
|
+
Via: (u,r,s,t) = (1, 0, 0, 0),
|
|
2760
|
+
Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3
|
|
2761
|
+
over Number Field in a with defining polynomial x^2 + 3
|
|
2762
|
+
Via: (u,r,s,t) = (-1, 0, 0, -1),
|
|
2763
|
+
Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3
|
|
2764
|
+
over Number Field in a with defining polynomial x^2 + 3
|
|
2765
|
+
Via: (u,r,s,t) = (-1/2*a - 1/2, 0, 0, 0),
|
|
2766
|
+
Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3
|
|
2767
|
+
over Number Field in a with defining polynomial x^2 + 3
|
|
2768
|
+
Via: (u,r,s,t) = (1/2*a + 1/2, 0, 0, -1),
|
|
2769
|
+
Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3
|
|
2770
|
+
over Number Field in a with defining polynomial x^2 + 3
|
|
2771
|
+
Via: (u,r,s,t) = (1/2*a - 1/2, 0, 0, 0),
|
|
2772
|
+
Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3
|
|
2773
|
+
over Number Field in a with defining polynomial x^2 + 3
|
|
2774
|
+
Via: (u,r,s,t) = (-1/2*a + 1/2, 0, 0, -1)]
|
|
2775
|
+
|
|
2776
|
+
::
|
|
2777
|
+
|
|
2778
|
+
sage: [len(EllipticCurve_from_j(GF(q,'a')(0)).automorphisms()) # needs sage.rings.finite_rings
|
|
2779
|
+
....: for q in [2,4,3,9,5,25,7,49]]
|
|
2780
|
+
[2, 24, 2, 12, 2, 6, 6, 6]
|
|
2781
|
+
|
|
2782
|
+
TESTS:
|
|
2783
|
+
|
|
2784
|
+
Random testing::
|
|
2785
|
+
|
|
2786
|
+
sage: # needs sage.rings.finite_rings
|
|
2787
|
+
sage: p = random_prime(100)
|
|
2788
|
+
sage: k = randrange(1,30)
|
|
2789
|
+
sage: F.<t> = GF((p,k))
|
|
2790
|
+
sage: while True:
|
|
2791
|
+
....: try:
|
|
2792
|
+
....: E = EllipticCurve(list((F^5).random_element()))
|
|
2793
|
+
....: except ArithmeticError:
|
|
2794
|
+
....: continue
|
|
2795
|
+
....: break
|
|
2796
|
+
sage: Aut = E.automorphisms()
|
|
2797
|
+
sage: Aut[0] == E.scalar_multiplication(1)
|
|
2798
|
+
True
|
|
2799
|
+
sage: Aut[1] == E.scalar_multiplication(-1)
|
|
2800
|
+
True
|
|
2801
|
+
sage: sorted(Aut) == Aut
|
|
2802
|
+
True
|
|
2803
|
+
"""
|
|
2804
|
+
if field is not None:
|
|
2805
|
+
self = self.change_ring(field)
|
|
2806
|
+
return self.isomorphisms(self)
|
|
2807
|
+
|
|
2808
|
+
def isomorphisms(self, other, field=None):
|
|
2809
|
+
"""
|
|
2810
|
+
Return the set of isomorphisms from ``self`` to ``other`` (as a list).
|
|
2811
|
+
|
|
2812
|
+
INPUT:
|
|
2813
|
+
|
|
2814
|
+
- ``other`` -- another elliptic curve
|
|
2815
|
+
|
|
2816
|
+
- ``field`` -- (default: ``None``) a field into which the
|
|
2817
|
+
coefficients of the curves may be coerced (by default, uses
|
|
2818
|
+
the base field of the curves)
|
|
2819
|
+
|
|
2820
|
+
OUTPUT:
|
|
2821
|
+
|
|
2822
|
+
A list of :class:`~wm.WeierstrassIsomorphism` objects consisting of all
|
|
2823
|
+
the isomorphisms from the curve ``self`` to the curve
|
|
2824
|
+
``other`` defined over ``field``.
|
|
2825
|
+
|
|
2826
|
+
EXAMPLES::
|
|
2827
|
+
|
|
2828
|
+
sage: E = EllipticCurve_from_j(QQ(0)) # a curve with j=0 over QQ
|
|
2829
|
+
sage: F = EllipticCurve('27a3') # should be the same one
|
|
2830
|
+
sage: E.isomorphisms(F)
|
|
2831
|
+
[Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3
|
|
2832
|
+
over Rational Field
|
|
2833
|
+
Via: (u,r,s,t) = (1, 0, 0, 0),
|
|
2834
|
+
Elliptic-curve endomorphism of Elliptic Curve defined by y^2 + y = x^3
|
|
2835
|
+
over Rational Field
|
|
2836
|
+
Via: (u,r,s,t) = (-1, 0, 0, -1)]
|
|
2837
|
+
|
|
2838
|
+
We can also find isomorphisms defined over extension fields::
|
|
2839
|
+
|
|
2840
|
+
sage: # needs sage.rings.finite_rings
|
|
2841
|
+
sage: E = EllipticCurve(GF(7), [0,0,0,1,1])
|
|
2842
|
+
sage: F = EllipticCurve(GF(7), [0,0,0,1,-1])
|
|
2843
|
+
sage: E.isomorphisms(F)
|
|
2844
|
+
[]
|
|
2845
|
+
sage: E.isomorphisms(F, GF(49,'a'))
|
|
2846
|
+
[Elliptic-curve morphism:
|
|
2847
|
+
From: Elliptic Curve defined by y^2 = x^3 + x + 1
|
|
2848
|
+
over Finite Field in a of size 7^2
|
|
2849
|
+
To: Elliptic Curve defined by y^2 = x^3 + x + 6
|
|
2850
|
+
over Finite Field in a of size 7^2
|
|
2851
|
+
Via: (u,r,s,t) = (a + 3, 0, 0, 0),
|
|
2852
|
+
Elliptic-curve morphism:
|
|
2853
|
+
From: Elliptic Curve defined by y^2 = x^3 + x + 1
|
|
2854
|
+
over Finite Field in a of size 7^2
|
|
2855
|
+
To: Elliptic Curve defined by y^2 = x^3 + x + 6
|
|
2856
|
+
over Finite Field in a of size 7^2
|
|
2857
|
+
Via: (u,r,s,t) = (6*a + 4, 0, 0, 0)]
|
|
2858
|
+
"""
|
|
2859
|
+
if field is not None:
|
|
2860
|
+
self = self.change_ring(field)
|
|
2861
|
+
other = other.change_ring(field)
|
|
2862
|
+
return sorted(wm.WeierstrassIsomorphism(self, urst, other)
|
|
2863
|
+
for urst in wm._isomorphisms(self, other))
|
|
2864
|
+
|
|
2865
|
+
def is_isomorphic(self, other, field=None):
|
|
2866
|
+
"""
|
|
2867
|
+
Return whether or not ``self`` is isomorphic to ``other``.
|
|
2868
|
+
|
|
2869
|
+
INPUT:
|
|
2870
|
+
|
|
2871
|
+
- ``other`` -- another elliptic curve
|
|
2872
|
+
|
|
2873
|
+
- ``field`` -- (default: ``None``) a field into which the
|
|
2874
|
+
coefficients of the curves may be coerced (by default, uses
|
|
2875
|
+
the base field of the curves).
|
|
2876
|
+
|
|
2877
|
+
OUTPUT:
|
|
2878
|
+
|
|
2879
|
+
boolean; ``True`` if there is an isomorphism from curve ``self`` to
|
|
2880
|
+
curve ``other`` defined over ``field``.
|
|
2881
|
+
|
|
2882
|
+
EXAMPLES::
|
|
2883
|
+
|
|
2884
|
+
sage: E = EllipticCurve('389a')
|
|
2885
|
+
sage: F = E.change_weierstrass_model([2,3,4,5]); F
|
|
2886
|
+
Elliptic Curve defined by y^2 + 4*x*y + 11/8*y = x^3 - 3/2*x^2 - 13/16*x
|
|
2887
|
+
over Rational Field
|
|
2888
|
+
sage: E.is_isomorphic(F)
|
|
2889
|
+
True
|
|
2890
|
+
sage: E.is_isomorphic(F.change_ring(CC))
|
|
2891
|
+
False
|
|
2892
|
+
"""
|
|
2893
|
+
if not isinstance(other, EllipticCurve_generic):
|
|
2894
|
+
return False
|
|
2895
|
+
if field is None:
|
|
2896
|
+
if self.base_ring() != other.base_ring():
|
|
2897
|
+
return False
|
|
2898
|
+
else:
|
|
2899
|
+
self = self.base_extend(field)
|
|
2900
|
+
other = other.base_extend(field)
|
|
2901
|
+
if self.j_invariant() != other.j_invariant(): # easy check
|
|
2902
|
+
return False
|
|
2903
|
+
try:
|
|
2904
|
+
next(wm._isomorphisms(self, other))
|
|
2905
|
+
except StopIteration:
|
|
2906
|
+
return False
|
|
2907
|
+
return True
|
|
2908
|
+
|
|
2909
|
+
def change_weierstrass_model(self, *urst):
|
|
2910
|
+
r"""
|
|
2911
|
+
Return a new Weierstrass model of ``self`` under the standard
|
|
2912
|
+
transformation `(u,r,s,t)`.
|
|
2913
|
+
|
|
2914
|
+
.. MATH::
|
|
2915
|
+
|
|
2916
|
+
(x,y) \mapsto (x',y') = (u^2x + r , u^3y + su^2x + t).
|
|
2917
|
+
|
|
2918
|
+
EXAMPLES::
|
|
2919
|
+
|
|
2920
|
+
sage: E = EllipticCurve('15a')
|
|
2921
|
+
sage: F1 = E.change_weierstrass_model([1/2,0,0,0]); F1
|
|
2922
|
+
Elliptic Curve defined by y^2 + 2*x*y + 8*y = x^3 + 4*x^2 - 160*x - 640
|
|
2923
|
+
over Rational Field
|
|
2924
|
+
sage: F2 = E.change_weierstrass_model([7,2,1/3,5]); F2
|
|
2925
|
+
Elliptic Curve defined by
|
|
2926
|
+
y^2 + 5/21*x*y + 13/343*y = x^3 + 59/441*x^2 - 10/7203*x - 58/117649
|
|
2927
|
+
over Rational Field
|
|
2928
|
+
sage: F1.is_isomorphic(F2)
|
|
2929
|
+
True
|
|
2930
|
+
"""
|
|
2931
|
+
if isinstance(urst[0], (tuple, list)):
|
|
2932
|
+
urst = urst[0]
|
|
2933
|
+
return constructor.EllipticCurve((wm.baseWI(*urst))(self.ainvs()))
|
|
2934
|
+
|
|
2935
|
+
def short_weierstrass_model(self, complete_cube=True):
|
|
2936
|
+
"""
|
|
2937
|
+
Return a short Weierstrass model for ``self``.
|
|
2938
|
+
|
|
2939
|
+
INPUT:
|
|
2940
|
+
|
|
2941
|
+
- ``complete_cube`` -- boolean (default: ``True``); for
|
|
2942
|
+
meaning, see below
|
|
2943
|
+
|
|
2944
|
+
OUTPUT: an elliptic curve
|
|
2945
|
+
|
|
2946
|
+
If ``complete_cube=True``: Return a model of the form
|
|
2947
|
+
`y^2 = x^3 + a*x + b` for this curve. The characteristic
|
|
2948
|
+
must not be 2; in characteristic 3, it is only possible if `b_2=0`.
|
|
2949
|
+
|
|
2950
|
+
If ``complete_cube=False``: Return a model of the form
|
|
2951
|
+
`y^2 = x^3 + ax^2 + bx + c` for this curve. The
|
|
2952
|
+
characteristic must not be 2.
|
|
2953
|
+
|
|
2954
|
+
EXAMPLES::
|
|
2955
|
+
|
|
2956
|
+
sage: E = EllipticCurve([1,2,3,4,5])
|
|
2957
|
+
sage: E
|
|
2958
|
+
Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Rational Field
|
|
2959
|
+
sage: F = E.short_weierstrass_model()
|
|
2960
|
+
sage: F
|
|
2961
|
+
Elliptic Curve defined by y^2 = x^3 + 4941*x + 185166 over Rational Field
|
|
2962
|
+
sage: E.is_isomorphic(F)
|
|
2963
|
+
True
|
|
2964
|
+
sage: F = E.short_weierstrass_model(complete_cube=False)
|
|
2965
|
+
sage: F
|
|
2966
|
+
Elliptic Curve defined by y^2 = x^3 + 9*x^2 + 88*x + 464 over Rational Field
|
|
2967
|
+
sage: E.is_isomorphic(F)
|
|
2968
|
+
True
|
|
2969
|
+
|
|
2970
|
+
::
|
|
2971
|
+
|
|
2972
|
+
sage: E = EllipticCurve(GF(3), [1,2,3,4,5])
|
|
2973
|
+
sage: E.short_weierstrass_model(complete_cube=False)
|
|
2974
|
+
Elliptic Curve defined by y^2 = x^3 + x + 2 over Finite Field of size 3
|
|
2975
|
+
|
|
2976
|
+
This used to be different see :issue:`3973`::
|
|
2977
|
+
|
|
2978
|
+
sage: E.short_weierstrass_model()
|
|
2979
|
+
Elliptic Curve defined by y^2 = x^3 + x + 2 over Finite Field of size 3
|
|
2980
|
+
|
|
2981
|
+
More tests in characteristic 3::
|
|
2982
|
+
|
|
2983
|
+
sage: E = EllipticCurve(GF(3), [0,2,1,2,1])
|
|
2984
|
+
sage: E.short_weierstrass_model()
|
|
2985
|
+
Traceback (most recent call last):
|
|
2986
|
+
...
|
|
2987
|
+
ValueError: short_weierstrass_model(): no short model for Elliptic Curve
|
|
2988
|
+
defined by y^2 + y = x^3 + 2*x^2 + 2*x + 1 over Finite Field of size 3
|
|
2989
|
+
(characteristic is 3)
|
|
2990
|
+
sage: E.short_weierstrass_model(complete_cube=False)
|
|
2991
|
+
Elliptic Curve defined by y^2 = x^3 + 2*x^2 + 2*x + 2
|
|
2992
|
+
over Finite Field of size 3
|
|
2993
|
+
sage: E.short_weierstrass_model(complete_cube=False).is_isomorphic(E)
|
|
2994
|
+
True
|
|
2995
|
+
"""
|
|
2996
|
+
from . import constructor
|
|
2997
|
+
K = self.base_ring()
|
|
2998
|
+
|
|
2999
|
+
# any curve of the form y^2 = x^3 +.. is singular in characteristic 2
|
|
3000
|
+
if K.characteristic() == 2:
|
|
3001
|
+
raise ValueError("short_weierstrass_model(): no short model for %s (characteristic is %s)" % (self, K.characteristic()))
|
|
3002
|
+
|
|
3003
|
+
# in characteristic 3 we can complete the square but we can only complete the cube if b2 is 0
|
|
3004
|
+
if K.characteristic() == 3:
|
|
3005
|
+
b2, b4, b6,_ = self.b_invariants()
|
|
3006
|
+
if complete_cube and b2 != 0:
|
|
3007
|
+
raise ValueError("short_weierstrass_model(): no short model for %s (characteristic is %s)" % (self,K.characteristic()))
|
|
3008
|
+
else:
|
|
3009
|
+
return constructor.EllipticCurve([0,b2,0,8*b4,16*b6])
|
|
3010
|
+
|
|
3011
|
+
a1,a2,a3,_,_ = self.a_invariants()
|
|
3012
|
+
if complete_cube:
|
|
3013
|
+
if a1 == 0 and a2 == 0 and a3 == 0:
|
|
3014
|
+
return self
|
|
3015
|
+
else:
|
|
3016
|
+
b2, b4, b6, _ = self.b_invariants()
|
|
3017
|
+
if b2 == 0:
|
|
3018
|
+
return constructor.EllipticCurve([0,0,0,8*b4,16*b6])
|
|
3019
|
+
else:
|
|
3020
|
+
c4, c6 = self.c_invariants()
|
|
3021
|
+
return constructor.EllipticCurve([0,0,0,-27*c4, -54*c6])
|
|
3022
|
+
else:
|
|
3023
|
+
if a1 == 0 and a3 == 0:
|
|
3024
|
+
return self
|
|
3025
|
+
else:
|
|
3026
|
+
b2, b4, b6, _ = self.b_invariants()
|
|
3027
|
+
return constructor.EllipticCurve([0,b2,0,8*b4,16*b6])
|
|
3028
|
+
|
|
3029
|
+
def montgomery_model(self, twisted=False, morphism=False):
|
|
3030
|
+
r"""
|
|
3031
|
+
Return a (twisted or untwisted) Montgomery model for this
|
|
3032
|
+
elliptic curve, if possible.
|
|
3033
|
+
|
|
3034
|
+
A Montgomery curve is a smooth projective curve of the form
|
|
3035
|
+
|
|
3036
|
+
.. MATH::
|
|
3037
|
+
|
|
3038
|
+
BY^2 = X^3 + AX^2 + X.
|
|
3039
|
+
|
|
3040
|
+
The Montgomery curve is called *untwisted* if `B=1`.
|
|
3041
|
+
|
|
3042
|
+
INPUT:
|
|
3043
|
+
|
|
3044
|
+
- ``twisted`` -- boolean (default: ``False``); allow `B \neq 1`
|
|
3045
|
+
|
|
3046
|
+
- ``morphism`` -- boolean (default: ``False``); also return an
|
|
3047
|
+
isomorphism from this curve to the computed Montgomery model
|
|
3048
|
+
|
|
3049
|
+
OUTPUT:
|
|
3050
|
+
|
|
3051
|
+
If ``twisted`` is ``False`` (the default), an
|
|
3052
|
+
:class:`EllipticCurve_generic` object encapsulating an untwisted
|
|
3053
|
+
Montgomery curve. Otherwise, a
|
|
3054
|
+
:class:`~sage.schemes.curves.projective_curve.ProjectivePlaneCurve`
|
|
3055
|
+
object encapsulating a (potentially twisted) Montgomery curve.
|
|
3056
|
+
|
|
3057
|
+
If ``morphism`` is ``True``, this method returns a tuple consisting of
|
|
3058
|
+
such a curve together with an isomorphism of suitable type (either
|
|
3059
|
+
:class:`~sage.schemes.elliptic_curves.weierstrass_morphism.WeierstrassIsomorphism`
|
|
3060
|
+
or
|
|
3061
|
+
:class:`~sage.schemes.elliptic_curves.weierstrass_transform.WeierstrassTransformationWithInverse`)
|
|
3062
|
+
from this curve to the Montgomery model.
|
|
3063
|
+
|
|
3064
|
+
EXAMPLES::
|
|
3065
|
+
|
|
3066
|
+
sage: E = EllipticCurve(QQbar, '11a1') # needs sage.rings.number_field
|
|
3067
|
+
sage: E.montgomery_model() # needs sage.rings.number_field
|
|
3068
|
+
Elliptic Curve defined by y^2 = x^3 + (-1.953522420987248?)*x^2 + x
|
|
3069
|
+
over Algebraic Field
|
|
3070
|
+
|
|
3071
|
+
::
|
|
3072
|
+
|
|
3073
|
+
sage: E = EllipticCurve(GF(431^2), [7,7]) # needs sage.rings.finite_rings
|
|
3074
|
+
sage: E.montgomery_model() # needs sage.rings.finite_rings
|
|
3075
|
+
Elliptic Curve defined by y^2 = x^3 + (51*z2+190)*x^2 + x
|
|
3076
|
+
over Finite Field in z2 of size 431^2
|
|
3077
|
+
|
|
3078
|
+
An isomorphism between the Montgomery and Weierstrass form can
|
|
3079
|
+
be obtained using the ``morphism`` parameter::
|
|
3080
|
+
|
|
3081
|
+
sage: E.montgomery_model(morphism=True) # needs sage.rings.finite_rings
|
|
3082
|
+
(Elliptic Curve defined by y^2 = x^3 + (51*z2+190)*x^2 + x
|
|
3083
|
+
over Finite Field in z2 of size 431^2,
|
|
3084
|
+
Elliptic-curve morphism:
|
|
3085
|
+
From: Elliptic Curve defined by y^2 = x^3 + 7*x + 7
|
|
3086
|
+
over Finite Field in z2 of size 431^2
|
|
3087
|
+
To: Elliptic Curve defined by y^2 = x^3 + (51*z2+190)*x^2 + x
|
|
3088
|
+
over Finite Field in z2 of size 431^2
|
|
3089
|
+
Via: (u,r,s,t) = (64*z2 + 407, 159, 0, 0))
|
|
3090
|
+
|
|
3091
|
+
Not all elliptic curves have a Montgomery model over their field
|
|
3092
|
+
of definition::
|
|
3093
|
+
|
|
3094
|
+
sage: E = EllipticCurve(GF(257), [1,1])
|
|
3095
|
+
sage: E.montgomery_model()
|
|
3096
|
+
Traceback (most recent call last):
|
|
3097
|
+
...
|
|
3098
|
+
ValueError: Elliptic Curve defined by y^2 = x^3 + x + 1
|
|
3099
|
+
over Finite Field of size 257 has no Montgomery model
|
|
3100
|
+
|
|
3101
|
+
::
|
|
3102
|
+
|
|
3103
|
+
sage: E = EllipticCurve(GF(257), [10,10])
|
|
3104
|
+
sage: E.montgomery_model()
|
|
3105
|
+
Traceback (most recent call last):
|
|
3106
|
+
...
|
|
3107
|
+
ValueError: Elliptic Curve defined by y^2 = x^3 + 10*x + 10
|
|
3108
|
+
over Finite Field of size 257 has no untwisted Montgomery model
|
|
3109
|
+
|
|
3110
|
+
However, as hinted by the error message, the latter curve does
|
|
3111
|
+
admit a *twisted* Montgomery model, which can be computed by
|
|
3112
|
+
passing ``twisted=True``::
|
|
3113
|
+
|
|
3114
|
+
sage: E.montgomery_model(twisted=True)
|
|
3115
|
+
Projective Plane Curve over Finite Field of size 257
|
|
3116
|
+
defined by -x^3 + 8*x^2*z - 127*y^2*z - x*z^2
|
|
3117
|
+
|
|
3118
|
+
Since Sage internally represents elliptic curves as (long) Weierstrass
|
|
3119
|
+
curves, which do not feature the Montgomery `B` coefficient, the
|
|
3120
|
+
returned curve in this case is merely a
|
|
3121
|
+
:class:`~sage.schemes.curves.projective_curve.ProjectivePlaneCurve`
|
|
3122
|
+
rather than the usual :class:`EllipticCurve_generic`.
|
|
3123
|
+
|
|
3124
|
+
Arithmetic on curves of this type is not implemented natively,
|
|
3125
|
+
but can easily be emulated by mapping back and forth to the
|
|
3126
|
+
corresponding Weierstrass curve::
|
|
3127
|
+
|
|
3128
|
+
sage: C, f = E.montgomery_model(twisted=True, morphism=True)
|
|
3129
|
+
sage: f
|
|
3130
|
+
Scheme morphism:
|
|
3131
|
+
From: Elliptic Curve defined by y^2 = x^3 + 10*x + 10
|
|
3132
|
+
over Finite Field of size 257
|
|
3133
|
+
To: Projective Plane Curve over Finite Field of size 257
|
|
3134
|
+
defined by -x^3 + 8*x^2*z - 127*y^2*z - x*z^2
|
|
3135
|
+
Defn: Defined on coordinates by sending (x : y : z) to
|
|
3136
|
+
(x + 116*z : -y : -85*z)
|
|
3137
|
+
sage: g = f.inverse(); g
|
|
3138
|
+
Scheme morphism:
|
|
3139
|
+
From: Projective Plane Curve over Finite Field of size 257
|
|
3140
|
+
defined by -x^3 + 8*x^2*z - 127*y^2*z - x*z^2
|
|
3141
|
+
To: Elliptic Curve defined by y^2 = x^3 + 10*x + 10
|
|
3142
|
+
over Finite Field of size 257
|
|
3143
|
+
Defn: Defined on coordinates by sending (x : y : z) to
|
|
3144
|
+
(-85*x - 116*z : 85*y : z)
|
|
3145
|
+
sage: P = C(70, 8)
|
|
3146
|
+
sage: Q = C(17, 17)
|
|
3147
|
+
sage: P + Q # this doesn't work...
|
|
3148
|
+
Traceback (most recent call last):
|
|
3149
|
+
...
|
|
3150
|
+
TypeError: unsupported operand parent(s) for +: ...
|
|
3151
|
+
sage: f(g(P) + g(Q)) # ...but this does
|
|
3152
|
+
(107 : 168 : 1)
|
|
3153
|
+
|
|
3154
|
+
Using the fact that the Weil pairing satisfies `e(\psi(P),\psi(Q)) =
|
|
3155
|
+
e(P,Q)^{\deg\psi}`, even pairings can be emulated in this way (note
|
|
3156
|
+
that isomorphisms have degree `1`)::
|
|
3157
|
+
|
|
3158
|
+
sage: # needs sage.rings.finite_rings
|
|
3159
|
+
sage: F.<z2> = GF(257^2)
|
|
3160
|
+
sage: C_ = C.change_ring(F)
|
|
3161
|
+
sage: g_ = g.change_ring(F)
|
|
3162
|
+
sage: g_(P).order()
|
|
3163
|
+
12
|
|
3164
|
+
sage: T = C_(-7 * z2 - 57, 31 * z2 - 52, 1)
|
|
3165
|
+
sage: g_(T).order()
|
|
3166
|
+
12
|
|
3167
|
+
sage: g_(P).weil_pairing(g_(T), 12)
|
|
3168
|
+
15*z2 + 204
|
|
3169
|
+
|
|
3170
|
+
Another alternative is to simply extend the base field enough
|
|
3171
|
+
for the curve to have an untwisted Montgomery model::
|
|
3172
|
+
|
|
3173
|
+
sage: C_ = E.change_ring(F).montgomery_model(); C_ # needs sage.rings.finite_rings
|
|
3174
|
+
Elliptic Curve defined by y^2 = x^3 + 249*x^2 + x
|
|
3175
|
+
over Finite Field in z2 of size 257^2
|
|
3176
|
+
sage: h = C.defining_polynomial().change_ring(F); h # needs sage.rings.finite_rings
|
|
3177
|
+
-x^3 + 8*x^2*z - 127*y^2*z - x*z^2
|
|
3178
|
+
sage: C_.is_isomorphic(EllipticCurve_from_cubic(h).codomain()) # needs sage.rings.finite_rings
|
|
3179
|
+
True
|
|
3180
|
+
|
|
3181
|
+
.. SEEALSO::
|
|
3182
|
+
|
|
3183
|
+
The inverse conversion --- computing a Weierstrass model for a
|
|
3184
|
+
given Montgomery curve --- can be performed using
|
|
3185
|
+
:func:`~sage.schemes.elliptic_curves.constructor.EllipticCurve_from_cubic`.
|
|
3186
|
+
|
|
3187
|
+
ALGORITHM: [CS2018]_, §2.4
|
|
3188
|
+
|
|
3189
|
+
REFERENCES:
|
|
3190
|
+
|
|
3191
|
+
- Original publication: [Mont1987]_, §10.3.1
|
|
3192
|
+
- More recent survey article: [CS2018]_
|
|
3193
|
+
"""
|
|
3194
|
+
Ew = self.short_weierstrass_model()
|
|
3195
|
+
_, _, _, a, b = Ew.a_invariants()
|
|
3196
|
+
|
|
3197
|
+
R = self.base_ring()
|
|
3198
|
+
P = PolynomialRing(R, 'v')
|
|
3199
|
+
|
|
3200
|
+
sols = []
|
|
3201
|
+
for r in P([b, a, 0, 1]).roots(multiplicities=False):
|
|
3202
|
+
for s in P([3 * r**2 + a, 0, -1]).roots(multiplicities=False):
|
|
3203
|
+
sols.append((r,s))
|
|
3204
|
+
|
|
3205
|
+
if not sols:
|
|
3206
|
+
raise ValueError(f'{self} has no Montgomery model')
|
|
3207
|
+
|
|
3208
|
+
# square s allows us to take B=1
|
|
3209
|
+
r,s = max(sols, key=lambda t: t[1].is_square())
|
|
3210
|
+
|
|
3211
|
+
A = 3 * r / s
|
|
3212
|
+
B = R.one() if s.is_square() else ~s
|
|
3213
|
+
|
|
3214
|
+
if not twisted:
|
|
3215
|
+
if B != 1:
|
|
3216
|
+
raise ValueError(f'{self} has no untwisted Montgomery model')
|
|
3217
|
+
from sage.schemes.elliptic_curves.constructor import EllipticCurve
|
|
3218
|
+
E = EllipticCurve([0, A, 0, 1, 0])
|
|
3219
|
+
if morphism:
|
|
3220
|
+
return E, self.isomorphism_to(E)
|
|
3221
|
+
return E
|
|
3222
|
+
|
|
3223
|
+
P2, (x, y, z) = self.ambient_space().objgens()
|
|
3224
|
+
f = B * y**2*z - x * (x * (x + A*z) + z**2)
|
|
3225
|
+
C = plane_curve.ProjectivePlaneCurve(P2, f)
|
|
3226
|
+
|
|
3227
|
+
if not morphism:
|
|
3228
|
+
return C
|
|
3229
|
+
|
|
3230
|
+
t = ~(B * s).sqrt()
|
|
3231
|
+
iso_maps = (x - r * z, t * y, s * z)
|
|
3232
|
+
inv_maps = (x * s + r * z, s * y / t, z)
|
|
3233
|
+
|
|
3234
|
+
w = self.isomorphism_to(Ew)
|
|
3235
|
+
wmap, winv = w.rational_maps(), (~w).rational_maps()
|
|
3236
|
+
wmap, winv = (tuple(f(x, y) for f in fs) + (z,) for fs in (wmap, winv))
|
|
3237
|
+
|
|
3238
|
+
iso = [f(*wmap) for f in iso_maps]
|
|
3239
|
+
inv = [f(*inv_maps) for f in winv]
|
|
3240
|
+
|
|
3241
|
+
from sage.schemes.elliptic_curves.weierstrass_transform \
|
|
3242
|
+
import WeierstrassTransformationWithInverse as WTI
|
|
3243
|
+
iso = WTI(self, C, iso, 1, inv, s**-3)
|
|
3244
|
+
return C, iso
|
|
3245
|
+
|
|
3246
|
+
def plot(self, xmin=None, xmax=None, components='both', **args):
|
|
3247
|
+
"""
|
|
3248
|
+
Draw a graph of this elliptic curve.
|
|
3249
|
+
|
|
3250
|
+
The plot method is only implemented when there is a natural coercion
|
|
3251
|
+
from the base ring of ``self`` to ``RR``. In this case, ``self`` is
|
|
3252
|
+
plotted as if it was defined over ``RR``.
|
|
3253
|
+
|
|
3254
|
+
INPUT:
|
|
3255
|
+
|
|
3256
|
+
- ``xmin``, ``xmax`` -- (optional) points will be computed at
|
|
3257
|
+
least within this range, but possibly farther
|
|
3258
|
+
|
|
3259
|
+
- ``components`` -- string; one of the following:
|
|
3260
|
+
|
|
3261
|
+
- ``both`` -- (default), scale so that both bounded and
|
|
3262
|
+
unbounded components appear
|
|
3263
|
+
|
|
3264
|
+
- ``bounded`` -- scale the plot to show the bounded
|
|
3265
|
+
component. Raises an error if there is only one real
|
|
3266
|
+
component.
|
|
3267
|
+
|
|
3268
|
+
- ``unbounded`` -- scale the plot to show the unbounded
|
|
3269
|
+
component, including the two flex points
|
|
3270
|
+
|
|
3271
|
+
- ``plot_points`` -- passed to
|
|
3272
|
+
:func:`sage.plot.generate_plot_points`
|
|
3273
|
+
|
|
3274
|
+
- ``adaptive_tolerance`` -- passed to
|
|
3275
|
+
:func:`sage.plot.generate_plot_points`
|
|
3276
|
+
|
|
3277
|
+
- ``adaptive_recursion`` -- passed to
|
|
3278
|
+
:func:`sage.plot.generate_plot_points`
|
|
3279
|
+
|
|
3280
|
+
- ``randomize`` -- passed to
|
|
3281
|
+
:func:`sage.plot.generate_plot_points`
|
|
3282
|
+
|
|
3283
|
+
- ``**args`` -- all other options are passed to
|
|
3284
|
+
:class:`sage.plot.line.Line`
|
|
3285
|
+
|
|
3286
|
+
EXAMPLES::
|
|
3287
|
+
|
|
3288
|
+
sage: E = EllipticCurve([0, -1])
|
|
3289
|
+
sage: plot(E, rgbcolor=hue(0.7)) # needs sage.plot
|
|
3290
|
+
Graphics object consisting of 1 graphics primitive
|
|
3291
|
+
sage: E = EllipticCurve('37a')
|
|
3292
|
+
sage: plot(E) # needs sage.plot
|
|
3293
|
+
Graphics object consisting of 2 graphics primitives
|
|
3294
|
+
sage: plot(E, xmin=25, xmax=26) # needs sage.plot
|
|
3295
|
+
Graphics object consisting of 2 graphics primitives
|
|
3296
|
+
|
|
3297
|
+
With :issue:`12766` we added the components keyword::
|
|
3298
|
+
|
|
3299
|
+
sage: E.real_components()
|
|
3300
|
+
2
|
|
3301
|
+
sage: E.plot(components='bounded') # needs sage.plot
|
|
3302
|
+
Graphics object consisting of 1 graphics primitive
|
|
3303
|
+
sage: E.plot(components='unbounded') # needs sage.plot
|
|
3304
|
+
Graphics object consisting of 1 graphics primitive
|
|
3305
|
+
|
|
3306
|
+
If there is only one component then specifying
|
|
3307
|
+
components='bounded' raises a ValueError::
|
|
3308
|
+
|
|
3309
|
+
sage: E = EllipticCurve('9990be2')
|
|
3310
|
+
sage: E.plot(components='bounded') # needs sage.plot
|
|
3311
|
+
Traceback (most recent call last):
|
|
3312
|
+
...
|
|
3313
|
+
ValueError: no bounded component for this curve
|
|
3314
|
+
|
|
3315
|
+
An elliptic curve defined over the Complex Field can not be plotted::
|
|
3316
|
+
|
|
3317
|
+
sage: E = EllipticCurve(CC, [0,0,1,-1,0])
|
|
3318
|
+
sage: E.plot() # needs sage.plot
|
|
3319
|
+
Traceback (most recent call last):
|
|
3320
|
+
...
|
|
3321
|
+
NotImplementedError: plotting of curves over Complex Field
|
|
3322
|
+
with 53 bits of precision is not implemented yet
|
|
3323
|
+
"""
|
|
3324
|
+
RR = RealField()
|
|
3325
|
+
K = self.base_ring()
|
|
3326
|
+
if not RR.has_coerce_map_from(K):
|
|
3327
|
+
raise NotImplementedError("plotting of curves over %s is not implemented yet" % K)
|
|
3328
|
+
if components not in ['both', 'bounded', 'unbounded']:
|
|
3329
|
+
raise ValueError("component must be one of 'both', 'bounded' or 'unbounded'")
|
|
3330
|
+
|
|
3331
|
+
a1, a2, a3, a4, a6 = self.ainvs()
|
|
3332
|
+
d = self.division_polynomial(2)
|
|
3333
|
+
|
|
3334
|
+
def f1(z):
|
|
3335
|
+
# Internal function for plotting first branch of the curve
|
|
3336
|
+
return (-(a1*z + a3) + sqrt(abs(d(z))))/2
|
|
3337
|
+
|
|
3338
|
+
def f2(z):
|
|
3339
|
+
# Internal function for plotting second branch of the curve
|
|
3340
|
+
return (-(a1*z + a3) - sqrt(abs(d(z))))/2
|
|
3341
|
+
|
|
3342
|
+
r = sorted(d.roots(RR, multiplicities=False))
|
|
3343
|
+
if components == 'bounded' and len(r) == 1:
|
|
3344
|
+
raise ValueError("no bounded component for this curve")
|
|
3345
|
+
if isinstance(xmin, (tuple, list)):
|
|
3346
|
+
if xmax is not None:
|
|
3347
|
+
raise ValueError("xmax must be None if xmin is a tuple")
|
|
3348
|
+
if len(xmin) != 2:
|
|
3349
|
+
raise ValueError("if xmin is a tuple it must have length 2")
|
|
3350
|
+
xmin, xmax = xmin
|
|
3351
|
+
if xmin is None or xmax is None:
|
|
3352
|
+
xmins = []
|
|
3353
|
+
xmaxs = []
|
|
3354
|
+
if components in ['both','bounded'] and len(r) > 1:
|
|
3355
|
+
xmins.append(r[0])
|
|
3356
|
+
xmaxs.append(r[1])
|
|
3357
|
+
|
|
3358
|
+
# The following 3 is an aesthetic choice. It's possible
|
|
3359
|
+
# that we should compute both of the following when
|
|
3360
|
+
# components=='both' and len(r) > 1 and take the maximum
|
|
3361
|
+
# generated xmax.
|
|
3362
|
+
if components == 'unbounded' or components == 'both' and (len(r) == 1 or r[2] - r[1] > 3*(r[1] - r[0])):
|
|
3363
|
+
flex = sorted(self.division_polynomial(3).roots(RR, multiplicities=False))
|
|
3364
|
+
flex = flex[-1]
|
|
3365
|
+
xmins.append(r[-1])
|
|
3366
|
+
# The doubling here is an aesthetic choice
|
|
3367
|
+
xmaxs.append(flex + 2*(flex - r[-1]))
|
|
3368
|
+
elif components == 'both':
|
|
3369
|
+
# First the easy part.
|
|
3370
|
+
xmins.append(r[-1])
|
|
3371
|
+
# There are two components and the unbounded component
|
|
3372
|
+
# is not too far from the bounded one. We scale so
|
|
3373
|
+
# that the unbounded component is twice as tall as the
|
|
3374
|
+
# bounded component. The y values corresponding to
|
|
3375
|
+
# horizontal tangent lines are determined as follows.
|
|
3376
|
+
# We implicitly differentiate the equation for this
|
|
3377
|
+
# curve and get
|
|
3378
|
+
# 2 yy' + a1 y + a1 xy' + a3 y' = 3 x^2 + 2a2 x + a4
|
|
3379
|
+
|
|
3380
|
+
R = RR['x']
|
|
3381
|
+
x = R.gen()
|
|
3382
|
+
if a1 == 0:
|
|
3383
|
+
# a horizontal tangent line can only occur at a root of
|
|
3384
|
+
Ederiv = 3*x**2 + 2*a2*x + a4
|
|
3385
|
+
else:
|
|
3386
|
+
# y' = 0 ==> y = (3*x^2 + 2*a2*x + a4) / a1
|
|
3387
|
+
y = (3*x**2 + 2*a2*x + a4) / a1
|
|
3388
|
+
Ederiv = y**2 + a1*x*y + a3*y - (x**3 + a2*x**2 + a4*x + a6)
|
|
3389
|
+
critx = [a for a in Ederiv.roots(RR, multiplicities=False)
|
|
3390
|
+
if r[0] < a < r[1]]
|
|
3391
|
+
if not critx:
|
|
3392
|
+
raise RuntimeError("No horizontal tangent lines on bounded component")
|
|
3393
|
+
# The 2.5 here is an aesthetic choice
|
|
3394
|
+
ymax = 2.5 * max([f1(a) for a in critx])
|
|
3395
|
+
ymin = 2.5 * min([f2(a) for a in critx])
|
|
3396
|
+
top_branch = ymax**2 + a1*x*ymax + a3*ymax - (x**3 + a2*x**2 + a4*x + a6)
|
|
3397
|
+
bottom_branch = ymin**2 + a1*x*ymin + a3*ymin - (x**3 + a2*x**2 + a4*x + a6)
|
|
3398
|
+
xmaxs.append(max(top_branch.roots(RR,multiplicities=False) + bottom_branch.roots(RR,multiplicities=False)))
|
|
3399
|
+
xmins = min(xmins)
|
|
3400
|
+
xmaxs = max(xmaxs)
|
|
3401
|
+
span = xmaxs - xmins
|
|
3402
|
+
if xmin is None:
|
|
3403
|
+
xmin = xmins - .02*span
|
|
3404
|
+
if xmax is None:
|
|
3405
|
+
xmax = xmaxs + .02*span
|
|
3406
|
+
elif xmin >= xmax:
|
|
3407
|
+
raise ValueError("xmin must be less than xmax")
|
|
3408
|
+
|
|
3409
|
+
I = []
|
|
3410
|
+
if components in ['unbounded', 'both'] and xmax > r[-1]:
|
|
3411
|
+
# one real root; 1 component
|
|
3412
|
+
if xmin <= r[-1]:
|
|
3413
|
+
I.append((r[-1],xmax,'<'))
|
|
3414
|
+
else:
|
|
3415
|
+
I.append((xmin, xmax,'='))
|
|
3416
|
+
if components in ['bounded','both'] and len(r) > 1 and (xmin < r[1] or xmax > r[0]):
|
|
3417
|
+
if xmin <= r[0]:
|
|
3418
|
+
if xmax >= r[1]:
|
|
3419
|
+
I.append((r[0],r[1],'o'))
|
|
3420
|
+
else:
|
|
3421
|
+
I.append((r[0],xmax,'<'))
|
|
3422
|
+
elif xmax >= r[1]:
|
|
3423
|
+
I.append((xmin, r[1], '>'))
|
|
3424
|
+
else:
|
|
3425
|
+
I.append((xmin, xmax, '='))
|
|
3426
|
+
|
|
3427
|
+
from sage.plot.graphics import Graphics
|
|
3428
|
+
from sage.plot.line import line
|
|
3429
|
+
from sage.plot.plot import generate_plot_points
|
|
3430
|
+
|
|
3431
|
+
g = Graphics()
|
|
3432
|
+
plot_points = int(args.pop('plot_points',200))
|
|
3433
|
+
adaptive_tolerance = args.pop('adaptive_tolerance',0.01)
|
|
3434
|
+
adaptive_recursion = args.pop('adaptive_recursion',5)
|
|
3435
|
+
randomize = args.pop('randomize',True)
|
|
3436
|
+
for j in range(len(I)):
|
|
3437
|
+
a, b, shape = I[j]
|
|
3438
|
+
v = generate_plot_points(f1, (a, b), plot_points, adaptive_tolerance, adaptive_recursion, randomize)
|
|
3439
|
+
w = generate_plot_points(f2, (a, b), plot_points, adaptive_tolerance, adaptive_recursion, randomize)
|
|
3440
|
+
if shape == 'o':
|
|
3441
|
+
g += line(v + list(reversed(w)) + [v[0]], **args)
|
|
3442
|
+
elif shape == '<':
|
|
3443
|
+
g += line(list(reversed(v)) + w, **args)
|
|
3444
|
+
elif shape == '>':
|
|
3445
|
+
g += line(v + list(reversed(w)), **args)
|
|
3446
|
+
else:
|
|
3447
|
+
g += line(v, **args)
|
|
3448
|
+
g += line(w, **args)
|
|
3449
|
+
return g
|
|
3450
|
+
|
|
3451
|
+
@cached_method
|
|
3452
|
+
def formal_group(self):
|
|
3453
|
+
r"""
|
|
3454
|
+
Return the formal group associated to this elliptic curve.
|
|
3455
|
+
|
|
3456
|
+
This method is cached.
|
|
3457
|
+
|
|
3458
|
+
EXAMPLES::
|
|
3459
|
+
|
|
3460
|
+
sage: E = EllipticCurve("37a")
|
|
3461
|
+
sage: E.formal_group()
|
|
3462
|
+
Formal Group associated to the Elliptic Curve
|
|
3463
|
+
defined by y^2 + y = x^3 - x over Rational Field
|
|
3464
|
+
"""
|
|
3465
|
+
return formal_group.EllipticCurveFormalGroup(self)
|
|
3466
|
+
|
|
3467
|
+
formal = formal_group
|
|
3468
|
+
|
|
3469
|
+
def _p_primary_torsion_basis(self, p, m=None):
|
|
3470
|
+
r"""
|
|
3471
|
+
Find a basis for the `p`-primary part of the torsion
|
|
3472
|
+
subgroup of this elliptic curve.
|
|
3473
|
+
|
|
3474
|
+
INPUT:
|
|
3475
|
+
|
|
3476
|
+
- ``p`` -- integer; a prime number
|
|
3477
|
+
|
|
3478
|
+
- ``m`` -- integer or ``None``; if not ``None``, the `p`-primary
|
|
3479
|
+
torsion will be assumed to have order at most `p^m`
|
|
3480
|
+
|
|
3481
|
+
OUTPUT:
|
|
3482
|
+
|
|
3483
|
+
A list of 0, 1 or 2 pairs `[T,k]` where `T` is a generator of
|
|
3484
|
+
order `p^k`. That is, either `[]` or `[[T_1,k_1]]` or
|
|
3485
|
+
`[[T_1,k_1],[T_2,k_2]]` with `[]`, `[T_1]`, or `[T_1,T_2]` a
|
|
3486
|
+
basis and `p^{k_1} \ge p^{k_2} \ge 1` their orders.
|
|
3487
|
+
|
|
3488
|
+
.. WARNING::
|
|
3489
|
+
|
|
3490
|
+
1. Do not call this on a curve whose group is
|
|
3491
|
+
`p`-divisible (i.e., whose `p`-primary part
|
|
3492
|
+
is infinite)!
|
|
3493
|
+
|
|
3494
|
+
2. The code uses division polynomials and will be slow for
|
|
3495
|
+
large `p`.
|
|
3496
|
+
|
|
3497
|
+
EXAMPLES::
|
|
3498
|
+
|
|
3499
|
+
sage: E = EllipticCurve('11a1')
|
|
3500
|
+
sage: E._p_primary_torsion_basis(5)
|
|
3501
|
+
[[(5 : -6 : 1), 1]]
|
|
3502
|
+
|
|
3503
|
+
sage: # needs sage.rings.number_field
|
|
3504
|
+
sage: x = polygen(ZZ, 'x')
|
|
3505
|
+
sage: K.<t> = NumberField(x^4 + x^3 + 11*x^2 + 41*x + 101)
|
|
3506
|
+
sage: EK = E.base_extend(K)
|
|
3507
|
+
sage: EK._p_primary_torsion_basis(5) # long time
|
|
3508
|
+
[[(16 : 60 : 1), 1], [(t : 1/11*t^3 + 6/11*t^2 + 19/11*t + 48/11 : 1), 1]]
|
|
3509
|
+
sage: EF = E.change_ring(GF(101)) # needs sage.rings.finite_rings
|
|
3510
|
+
sage: EF._p_primary_torsion_basis(5) # needs sage.rings.finite_rings
|
|
3511
|
+
[[(0 : 13 : 1), 1], [(5 : 5 : 1), 1]]
|
|
3512
|
+
|
|
3513
|
+
sage: F.<z> = CyclotomicField(21) # needs sage.rings.number_field
|
|
3514
|
+
sage: E = EllipticCurve([2, -z^7, -z^7, 0, 0]) # needs sage.rings.number_field
|
|
3515
|
+
sage: E._p_primary_torsion_basis(7,2) # long time # needs sage.rings.number_field
|
|
3516
|
+
[[(0 : z^7 : 1), 1],
|
|
3517
|
+
[(z^7 - z^6 + z^4 - z^3 + z^2 - 1
|
|
3518
|
+
: z^8 - 2*z^7 + z^6 + 2*z^5 - 3*z^4 + 2*z^3 - 2*z + 2 : 1), 1]]
|
|
3519
|
+
|
|
3520
|
+
TESTS:
|
|
3521
|
+
|
|
3522
|
+
This shows that the bug at :issue:`4937` is fixed::
|
|
3523
|
+
|
|
3524
|
+
sage: a = 804515977734860566494239770982282063895480484302363715494873
|
|
3525
|
+
sage: b = 584772221603632866665682322899297141793188252000674256662071
|
|
3526
|
+
sage: E = EllipticCurve(GF(10^60 + 3201), [0,a,0,b,0]) # needs sage.rings.finite_rings
|
|
3527
|
+
sage: [t[1] for t in E._p_primary_torsion_basis(2)] # long time, needs sage.rings.finite_rings
|
|
3528
|
+
[16, 1]
|
|
3529
|
+
"""
|
|
3530
|
+
p = Integer(p)
|
|
3531
|
+
if not p.is_prime():
|
|
3532
|
+
raise ValueError("p (=%s) should be prime" % p)
|
|
3533
|
+
|
|
3534
|
+
if m is None:
|
|
3535
|
+
from sage.rings.infinity import Infinity
|
|
3536
|
+
m = Infinity
|
|
3537
|
+
|
|
3538
|
+
if m == 0:
|
|
3539
|
+
return []
|
|
3540
|
+
|
|
3541
|
+
# First find the p-torsion:
|
|
3542
|
+
Ep = self(0).division_points(p)
|
|
3543
|
+
p_rank = Integer(len(Ep)).exact_log(p)
|
|
3544
|
+
assert p_rank in [0, 1, 2]
|
|
3545
|
+
|
|
3546
|
+
if p_rank == 0:
|
|
3547
|
+
return []
|
|
3548
|
+
|
|
3549
|
+
if p_rank == 1:
|
|
3550
|
+
P = Ep[0]
|
|
3551
|
+
if P.is_zero():
|
|
3552
|
+
P = Ep[1]
|
|
3553
|
+
k = 1
|
|
3554
|
+
if m == 1:
|
|
3555
|
+
return [[P, k]]
|
|
3556
|
+
pts = P.division_points(p) # length 0 or p
|
|
3557
|
+
while pts:
|
|
3558
|
+
k += 1
|
|
3559
|
+
P = pts[0]
|
|
3560
|
+
if m <= k:
|
|
3561
|
+
return [[P, k]]
|
|
3562
|
+
pts = P.division_points(p)
|
|
3563
|
+
# now P generates the p-power-torsion and has order p^k
|
|
3564
|
+
return [[P, k]]
|
|
3565
|
+
|
|
3566
|
+
Epi = iter(Ep) # used to iterate through Ep
|
|
3567
|
+
# Find P1,P2 which generate the p-torsion:
|
|
3568
|
+
P1 = next(Epi)
|
|
3569
|
+
while P1.is_zero():
|
|
3570
|
+
P1 = next(Epi)
|
|
3571
|
+
P2 = next(Epi)
|
|
3572
|
+
while generic.linear_relation(P1, P2, '+')[0] != 0:
|
|
3573
|
+
P2 = next(Epi)
|
|
3574
|
+
|
|
3575
|
+
k = 1
|
|
3576
|
+
log_order = 2
|
|
3577
|
+
if m <= log_order:
|
|
3578
|
+
return [[P1, 1], [P2, 1]]
|
|
3579
|
+
|
|
3580
|
+
pts1 = P1.division_points(p)
|
|
3581
|
+
pts2 = P2.division_points(p)
|
|
3582
|
+
while pts1 and pts2:
|
|
3583
|
+
k += 1
|
|
3584
|
+
P1 = pts1[0]
|
|
3585
|
+
P2 = pts2[0]
|
|
3586
|
+
log_order += 2
|
|
3587
|
+
if m <= log_order:
|
|
3588
|
+
return [[P1, k], [P2, k]]
|
|
3589
|
+
pts1 = P1.division_points(p)
|
|
3590
|
+
pts2 = P2.division_points(p)
|
|
3591
|
+
|
|
3592
|
+
# Now P1,P2 are a basis for the p^k torsion, which is
|
|
3593
|
+
# isomorphic to (Z/p^k)^2, and k is the maximal integer for
|
|
3594
|
+
# which this is the case.
|
|
3595
|
+
|
|
3596
|
+
# We now determine whether a combination (P2 or P1+a*P2 for
|
|
3597
|
+
# some a) can be further divided for some a mod p; if so,
|
|
3598
|
+
# replace P1 by that combination, set pts to be the list of
|
|
3599
|
+
# solutions Q to p*Q=P1. If no combination can be divided,
|
|
3600
|
+
# then the structure is (p^k,p^k) and we can stop.
|
|
3601
|
+
|
|
3602
|
+
if pts1:
|
|
3603
|
+
pts = pts1
|
|
3604
|
+
elif pts2:
|
|
3605
|
+
P1, P2 = P2, P1
|
|
3606
|
+
pts = pts2
|
|
3607
|
+
else:
|
|
3608
|
+
for Q in generic.multiples(P2, p-1, P1 + P2, operation='+'):
|
|
3609
|
+
# Q runs through P1+a*P2 for a=1,2,...,p-1
|
|
3610
|
+
pts = Q.division_points(p)
|
|
3611
|
+
if pts:
|
|
3612
|
+
P1 = Q
|
|
3613
|
+
break
|
|
3614
|
+
|
|
3615
|
+
if not pts:
|
|
3616
|
+
return [[P1, k], [P2, k]]
|
|
3617
|
+
|
|
3618
|
+
# Now the structure is (p^n,p^k) for some n>k. We need to
|
|
3619
|
+
# replace P1 by an element of maximal order p^n. So far we
|
|
3620
|
+
# have pts = list of Q satisfying p*Q=P1, and all such Q have
|
|
3621
|
+
# order p^{k+1}.
|
|
3622
|
+
|
|
3623
|
+
# We keep trying to divide P1 by p. At each step, if we
|
|
3624
|
+
# succeed, replace P1 by any of the results and increment n.
|
|
3625
|
+
# If we fails try again with P1+a*P2 for a in [1..p-1]. If any
|
|
3626
|
+
# succeed, replace P1 by one of the resulting divided points.
|
|
3627
|
+
# If all fail, the structure is (p^n,p^k) and P1,P2 are
|
|
3628
|
+
# generators.
|
|
3629
|
+
|
|
3630
|
+
n = k
|
|
3631
|
+
while True:
|
|
3632
|
+
P1 = pts[0]
|
|
3633
|
+
n += 1
|
|
3634
|
+
log_order += 1
|
|
3635
|
+
if m <= log_order:
|
|
3636
|
+
return [[P1, n], [P2, k]]
|
|
3637
|
+
pts = P1.division_points(p)
|
|
3638
|
+
if not pts:
|
|
3639
|
+
for Q in generic.multiples(P2, p-1, P1+P2, operation='+'):
|
|
3640
|
+
# Q runs through P1+a*P2 for a=1,2,...,p-1
|
|
3641
|
+
pts = Q.division_points(p)
|
|
3642
|
+
if pts:
|
|
3643
|
+
break
|
|
3644
|
+
if not pts:
|
|
3645
|
+
return [[P1, n], [P2, k]]
|
|
3646
|
+
|
|
3647
|
+
def hyperelliptic_polynomials(self):
|
|
3648
|
+
r"""
|
|
3649
|
+
Return a pair of polynomials `g(x)`, `h(x)` such that this elliptic
|
|
3650
|
+
curve can be defined by the standard hyperelliptic equation
|
|
3651
|
+
|
|
3652
|
+
.. MATH::
|
|
3653
|
+
|
|
3654
|
+
y^2 + h(x)y = g(x).
|
|
3655
|
+
|
|
3656
|
+
EXAMPLES::
|
|
3657
|
+
|
|
3658
|
+
sage: R.<a1,a2,a3,a4,a6>=QQ[]
|
|
3659
|
+
sage: E = EllipticCurve([a1,a2,a3,a4,a6])
|
|
3660
|
+
sage: E.hyperelliptic_polynomials()
|
|
3661
|
+
(x^3 + a2*x^2 + a4*x + a6, a1*x + a3)
|
|
3662
|
+
"""
|
|
3663
|
+
K = self.base_ring()
|
|
3664
|
+
R = PolynomialRing(K, 'x')
|
|
3665
|
+
a1, a2, a3, a4, a6 = self.ainvs()
|
|
3666
|
+
return R([a6, a4, a2, 1]), R([a3, a1])
|
|
3667
|
+
|
|
3668
|
+
# This caching is important since PARI also caches certain
|
|
3669
|
+
# things. This wouldn't work if we would call ellinit()
|
|
3670
|
+
# every time.
|
|
3671
|
+
@cached_method
|
|
3672
|
+
def pari_curve(self):
|
|
3673
|
+
"""
|
|
3674
|
+
Return the PARI curve corresponding to this elliptic curve.
|
|
3675
|
+
|
|
3676
|
+
The result is cached.
|
|
3677
|
+
|
|
3678
|
+
EXAMPLES::
|
|
3679
|
+
|
|
3680
|
+
sage: # needs sage.libs.pari
|
|
3681
|
+
sage: E = EllipticCurve([RR(0), RR(0), RR(1), RR(-1), RR(0)])
|
|
3682
|
+
sage: e = E.pari_curve()
|
|
3683
|
+
sage: type(e)
|
|
3684
|
+
<... 'cypari2.gen.Gen'>
|
|
3685
|
+
sage: e.type()
|
|
3686
|
+
't_VEC'
|
|
3687
|
+
sage: e.disc()
|
|
3688
|
+
37.0000000000000
|
|
3689
|
+
|
|
3690
|
+
Over a finite field::
|
|
3691
|
+
|
|
3692
|
+
sage: EllipticCurve(GF(41), [2,5]).pari_curve() # needs sage.libs.pari
|
|
3693
|
+
[Mod(0, 41), Mod(0, 41), Mod(0, 41), Mod(2, 41), Mod(5, 41),
|
|
3694
|
+
Mod(0, 41), Mod(4, 41), Mod(20, 41), Mod(37, 41), Mod(27, 41),
|
|
3695
|
+
Mod(26, 41), Mod(4, 41), Mod(11, 41),
|
|
3696
|
+
Vecsmall([3]),
|
|
3697
|
+
[41, [9, 31, [6, 0, 0, 0]]], [0, 0, 0, 0]]
|
|
3698
|
+
|
|
3699
|
+
Over a `p`-adic field::
|
|
3700
|
+
|
|
3701
|
+
sage: # needs sage.libs.pari sage.rings.padics
|
|
3702
|
+
sage: Qp = pAdicField(5, prec=3)
|
|
3703
|
+
sage: E = EllipticCurve(Qp, [3, 4])
|
|
3704
|
+
sage: E.pari_curve()
|
|
3705
|
+
[0, 0, 0, 3, 4, 0, 6, 16, -9, -144, -3456, -8640, 1728/5,
|
|
3706
|
+
Vecsmall([2]), [O(5^3)], [0, 0]]
|
|
3707
|
+
sage: E.j_invariant()
|
|
3708
|
+
3*5^-1 + O(5)
|
|
3709
|
+
|
|
3710
|
+
Over a number field::
|
|
3711
|
+
|
|
3712
|
+
sage: K.<a> = QuadraticField(2) # needs sage.libs.pari sage.rings.number_field
|
|
3713
|
+
sage: E = EllipticCurve([1,a]) # needs sage.libs.pari sage.rings.number_field
|
|
3714
|
+
sage: E.pari_curve() # needs sage.libs.pari sage.rings.number_field
|
|
3715
|
+
[0, 0, 0, Mod(1, y^2 - 2),
|
|
3716
|
+
Mod(y, y^2 - 2), 0, Mod(2, y^2 - 2), Mod(4*y, y^2 - 2),
|
|
3717
|
+
Mod(-1, y^2 - 2), Mod(-48, y^2 - 2), Mod(-864*y, y^2 - 2),
|
|
3718
|
+
Mod(-928, y^2 - 2), Mod(3456/29, y^2 - 2),
|
|
3719
|
+
Vecsmall([5]),
|
|
3720
|
+
[[y^2 - 2, [2, 0], 8, 1, [[1, -1.41421356237310; 1, 1.41421356237310],
|
|
3721
|
+
[1, -1.41421356237310; 1, 1.41421356237310],
|
|
3722
|
+
[16, -23; 16, 23], [2, 0; 0, 4], [4, 0; 0, 2], [2, 0; 0, 1],
|
|
3723
|
+
[2, [0, 2; 1, 0]], [2]], [-1.41421356237310, 1.41421356237310],
|
|
3724
|
+
[1, y], [1, 0; 0, 1], [1, 0, 0, 2; 0, 1, 1, 0]]], [0, 0, 0, 0, 0]]
|
|
3725
|
+
|
|
3726
|
+
PARI no longer requires that the `j`-invariant has negative `p`-adic valuation::
|
|
3727
|
+
|
|
3728
|
+
sage: E = EllipticCurve(Qp,[1, 1]) # needs sage.libs.pari sage.rings.padics
|
|
3729
|
+
sage: E.j_invariant() # the j-invariant is a p-adic integer # needs sage.libs.pari sage.rings.padics
|
|
3730
|
+
2 + 4*5^2 + O(5^3)
|
|
3731
|
+
sage: E.pari_curve() # needs sage.libs.pari sage.rings.padics
|
|
3732
|
+
[0, 0, 0, 1, 1, 0, 2, 4, -1, -48, -864, -496, 6912/31,
|
|
3733
|
+
Vecsmall([2]), [O(5^3)], [0, 0]]
|
|
3734
|
+
"""
|
|
3735
|
+
from sage.categories.number_fields import NumberFields
|
|
3736
|
+
from sage.libs.pari import pari
|
|
3737
|
+
if self.base_ring() in NumberFields():
|
|
3738
|
+
return pari.ellinit(self.a_invariants(), self.base_ring())
|
|
3739
|
+
else:
|
|
3740
|
+
return pari.ellinit(self.a_invariants())
|
|
3741
|
+
|
|
3742
|
+
# This method is defined so that pari(E) returns exactly the same
|
|
3743
|
+
# as E.pari_curve(). This works even for classes that inherit from
|
|
3744
|
+
# EllipticCurve_generic, such as EllipticCurve_rational_field.
|
|
3745
|
+
def __pari__(self):
|
|
3746
|
+
"""
|
|
3747
|
+
Return the PARI curve corresponding to this elliptic curve.
|
|
3748
|
+
|
|
3749
|
+
EXAMPLES::
|
|
3750
|
+
|
|
3751
|
+
sage: E = EllipticCurve('11a1')
|
|
3752
|
+
sage: pari(E) # needs sage.libs.pari
|
|
3753
|
+
[0, -1, 1, -10, -20, -4, -20, -79, -21, 496, 20008, -161051, -122023936/161051, Vecsmall([1]), [Vecsmall([64, -1])], [0, 0, 0, 0, 0, 0, 0, 0]]
|
|
3754
|
+
|
|
3755
|
+
Over a finite field::
|
|
3756
|
+
|
|
3757
|
+
sage: EllipticCurve(GF(2), [0,0,1,1,1]).__pari__() # needs sage.libs.pari
|
|
3758
|
+
[0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, Vecsmall([4]), [1, [[Vecsmall([0, 1]), Vecsmall([0, 1]), Vecsmall([0, 1])], Vecsmall([0, 1]), [Vecsmall([0, 1]), Vecsmall([0]), Vecsmall([0]), Vecsmall([0])]]], [0, 0, 0, 0]]
|
|
3759
|
+
"""
|
|
3760
|
+
return self.pari_curve()
|