passagemath-schemes 10.6.47__cp312-cp312-macosx_13_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- passagemath_schemes/.dylibs/libflint.22.0.dylib +0 -0
- passagemath_schemes/.dylibs/libgmp.10.dylib +0 -0
- passagemath_schemes/.dylibs/libgmpxx.4.dylib +0 -0
- passagemath_schemes/.dylibs/libmpfr.6.dylib +0 -0
- passagemath_schemes/__init__.py +3 -0
- passagemath_schemes-10.6.47.dist-info/METADATA +204 -0
- passagemath_schemes-10.6.47.dist-info/METADATA.bak +205 -0
- passagemath_schemes-10.6.47.dist-info/RECORD +311 -0
- passagemath_schemes-10.6.47.dist-info/WHEEL +6 -0
- passagemath_schemes-10.6.47.dist-info/top_level.txt +3 -0
- sage/all__sagemath_schemes.py +23 -0
- sage/databases/all__sagemath_schemes.py +7 -0
- sage/databases/cremona.py +1723 -0
- sage/dynamics/all__sagemath_schemes.py +2 -0
- sage/dynamics/arithmetic_dynamics/affine_ds.py +1083 -0
- sage/dynamics/arithmetic_dynamics/all.py +14 -0
- sage/dynamics/arithmetic_dynamics/berkovich_ds.py +1101 -0
- sage/dynamics/arithmetic_dynamics/dynamical_semigroup.py +1543 -0
- sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py +2426 -0
- sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py +1169 -0
- sage/dynamics/arithmetic_dynamics/generic_ds.py +663 -0
- sage/dynamics/arithmetic_dynamics/product_projective_ds.py +339 -0
- sage/dynamics/arithmetic_dynamics/projective_ds.py +9558 -0
- sage/dynamics/arithmetic_dynamics/projective_ds_helper.cpython-312-darwin.so +0 -0
- sage/dynamics/arithmetic_dynamics/projective_ds_helper.pyx +301 -0
- sage/dynamics/arithmetic_dynamics/wehlerK3.py +2576 -0
- sage/lfunctions/all.py +18 -0
- sage/lfunctions/dokchitser.py +745 -0
- sage/lfunctions/pari.py +818 -0
- sage/lfunctions/zero_sums.cpython-312-darwin.so +0 -0
- sage/lfunctions/zero_sums.pyx +1847 -0
- sage/modular/abvar/abvar.py +5135 -0
- sage/modular/abvar/abvar_ambient_jacobian.py +413 -0
- sage/modular/abvar/abvar_newform.py +244 -0
- sage/modular/abvar/all.py +8 -0
- sage/modular/abvar/constructor.py +186 -0
- sage/modular/abvar/cuspidal_subgroup.py +371 -0
- sage/modular/abvar/finite_subgroup.py +896 -0
- sage/modular/abvar/homology.py +720 -0
- sage/modular/abvar/homspace.py +998 -0
- sage/modular/abvar/lseries.py +415 -0
- sage/modular/abvar/morphism.py +935 -0
- sage/modular/abvar/torsion_point.py +274 -0
- sage/modular/abvar/torsion_subgroup.py +740 -0
- sage/modular/all.py +43 -0
- sage/modular/arithgroup/all.py +20 -0
- sage/modular/arithgroup/arithgroup_element.cpython-312-darwin.so +0 -0
- sage/modular/arithgroup/arithgroup_element.pyx +474 -0
- sage/modular/arithgroup/arithgroup_generic.py +1402 -0
- sage/modular/arithgroup/arithgroup_perm.py +2692 -0
- sage/modular/arithgroup/congroup.cpython-312-darwin.so +0 -0
- sage/modular/arithgroup/congroup.pyx +334 -0
- sage/modular/arithgroup/congroup_gamma.py +363 -0
- sage/modular/arithgroup/congroup_gamma0.py +692 -0
- sage/modular/arithgroup/congroup_gamma1.py +653 -0
- sage/modular/arithgroup/congroup_gammaH.py +1469 -0
- sage/modular/arithgroup/congroup_generic.py +628 -0
- sage/modular/arithgroup/congroup_sl2z.py +267 -0
- sage/modular/arithgroup/farey_symbol.cpython-312-darwin.so +0 -0
- sage/modular/arithgroup/farey_symbol.pyx +1066 -0
- sage/modular/arithgroup/tests.py +418 -0
- sage/modular/btquotients/all.py +4 -0
- sage/modular/btquotients/btquotient.py +3753 -0
- sage/modular/btquotients/pautomorphicform.py +2570 -0
- sage/modular/buzzard.py +100 -0
- sage/modular/congroup.py +29 -0
- sage/modular/congroup_element.py +13 -0
- sage/modular/cusps.py +1109 -0
- sage/modular/cusps_nf.py +1270 -0
- sage/modular/dims.py +569 -0
- sage/modular/dirichlet.py +3310 -0
- sage/modular/drinfeld_modform/all.py +2 -0
- sage/modular/drinfeld_modform/element.py +446 -0
- sage/modular/drinfeld_modform/ring.py +773 -0
- sage/modular/drinfeld_modform/tutorial.py +236 -0
- sage/modular/etaproducts.py +1065 -0
- sage/modular/hecke/algebra.py +746 -0
- sage/modular/hecke/all.py +20 -0
- sage/modular/hecke/ambient_module.py +1019 -0
- sage/modular/hecke/degenmap.py +119 -0
- sage/modular/hecke/element.py +325 -0
- sage/modular/hecke/hecke_operator.py +780 -0
- sage/modular/hecke/homspace.py +206 -0
- sage/modular/hecke/module.py +1767 -0
- sage/modular/hecke/morphism.py +174 -0
- sage/modular/hecke/submodule.py +989 -0
- sage/modular/hypergeometric_misc.cpython-312-darwin.so +0 -0
- sage/modular/hypergeometric_misc.pxd +4 -0
- sage/modular/hypergeometric_misc.pyx +166 -0
- sage/modular/hypergeometric_motive.py +2017 -0
- sage/modular/local_comp/all.py +2 -0
- sage/modular/local_comp/liftings.py +292 -0
- sage/modular/local_comp/local_comp.py +1071 -0
- sage/modular/local_comp/smoothchar.py +1825 -0
- sage/modular/local_comp/type_space.py +748 -0
- sage/modular/modform/all.py +30 -0
- sage/modular/modform/ambient.py +815 -0
- sage/modular/modform/ambient_R.py +177 -0
- sage/modular/modform/ambient_eps.py +306 -0
- sage/modular/modform/ambient_g0.py +124 -0
- sage/modular/modform/ambient_g1.py +204 -0
- sage/modular/modform/constructor.py +545 -0
- sage/modular/modform/cuspidal_submodule.py +708 -0
- sage/modular/modform/defaults.py +14 -0
- sage/modular/modform/eis_series.py +505 -0
- sage/modular/modform/eisenstein_submodule.py +663 -0
- sage/modular/modform/element.py +4131 -0
- sage/modular/modform/find_generators.py +59 -0
- sage/modular/modform/half_integral.py +154 -0
- sage/modular/modform/hecke_operator_on_qexp.py +247 -0
- sage/modular/modform/j_invariant.py +47 -0
- sage/modular/modform/l_series_gross_zagier.py +133 -0
- sage/modular/modform/l_series_gross_zagier_coeffs.cpython-312-darwin.so +0 -0
- sage/modular/modform/l_series_gross_zagier_coeffs.pyx +177 -0
- sage/modular/modform/notes.py +45 -0
- sage/modular/modform/numerical.py +514 -0
- sage/modular/modform/periods.py +14 -0
- sage/modular/modform/ring.py +1257 -0
- sage/modular/modform/space.py +1860 -0
- sage/modular/modform/submodule.py +118 -0
- sage/modular/modform/tests.py +64 -0
- sage/modular/modform/theta.py +110 -0
- sage/modular/modform/vm_basis.py +381 -0
- sage/modular/modform/weight1.py +220 -0
- sage/modular/modform_hecketriangle/abstract_ring.py +1932 -0
- sage/modular/modform_hecketriangle/abstract_space.py +2528 -0
- sage/modular/modform_hecketriangle/all.py +30 -0
- sage/modular/modform_hecketriangle/analytic_type.py +590 -0
- sage/modular/modform_hecketriangle/constructor.py +416 -0
- sage/modular/modform_hecketriangle/element.py +351 -0
- sage/modular/modform_hecketriangle/functors.py +752 -0
- sage/modular/modform_hecketriangle/graded_ring.py +541 -0
- sage/modular/modform_hecketriangle/graded_ring_element.py +2225 -0
- sage/modular/modform_hecketriangle/hecke_triangle_group_element.py +3352 -0
- sage/modular/modform_hecketriangle/hecke_triangle_groups.py +1432 -0
- sage/modular/modform_hecketriangle/readme.py +1214 -0
- sage/modular/modform_hecketriangle/series_constructor.py +580 -0
- sage/modular/modform_hecketriangle/space.py +1037 -0
- sage/modular/modform_hecketriangle/subspace.py +423 -0
- sage/modular/modsym/all.py +17 -0
- sage/modular/modsym/ambient.py +3846 -0
- sage/modular/modsym/boundary.py +1420 -0
- sage/modular/modsym/element.py +336 -0
- sage/modular/modsym/g1list.py +178 -0
- sage/modular/modsym/ghlist.py +182 -0
- sage/modular/modsym/hecke_operator.py +73 -0
- sage/modular/modsym/manin_symbol.cpython-312-darwin.so +0 -0
- sage/modular/modsym/manin_symbol.pxd +5 -0
- sage/modular/modsym/manin_symbol.pyx +497 -0
- sage/modular/modsym/manin_symbol_list.py +1295 -0
- sage/modular/modsym/modsym.py +400 -0
- sage/modular/modsym/modular_symbols.py +384 -0
- sage/modular/modsym/p1list_nf.py +1241 -0
- sage/modular/modsym/relation_matrix.py +591 -0
- sage/modular/modsym/relation_matrix_pyx.cpython-312-darwin.so +0 -0
- sage/modular/modsym/relation_matrix_pyx.pyx +108 -0
- sage/modular/modsym/space.py +2468 -0
- sage/modular/modsym/subspace.py +455 -0
- sage/modular/modsym/tests.py +375 -0
- sage/modular/multiple_zeta.py +2632 -0
- sage/modular/multiple_zeta_F_algebra.py +786 -0
- sage/modular/overconvergent/all.py +6 -0
- sage/modular/overconvergent/genus0.py +1878 -0
- sage/modular/overconvergent/hecke_series.py +1187 -0
- sage/modular/overconvergent/weightspace.py +778 -0
- sage/modular/pollack_stevens/all.py +4 -0
- sage/modular/pollack_stevens/distributions.py +874 -0
- sage/modular/pollack_stevens/fund_domain.py +1572 -0
- sage/modular/pollack_stevens/manin_map.py +859 -0
- sage/modular/pollack_stevens/modsym.py +1593 -0
- sage/modular/pollack_stevens/padic_lseries.py +417 -0
- sage/modular/pollack_stevens/sigma0.py +534 -0
- sage/modular/pollack_stevens/space.py +1076 -0
- sage/modular/quasimodform/all.py +3 -0
- sage/modular/quasimodform/element.py +845 -0
- sage/modular/quasimodform/ring.py +828 -0
- sage/modular/quatalg/all.py +3 -0
- sage/modular/quatalg/brandt.py +1642 -0
- sage/modular/ssmod/all.py +8 -0
- sage/modular/ssmod/ssmod.py +827 -0
- sage/rings/all__sagemath_schemes.py +1 -0
- sage/rings/polynomial/all__sagemath_schemes.py +1 -0
- sage/rings/polynomial/binary_form_reduce.py +585 -0
- sage/schemes/all.py +41 -0
- sage/schemes/berkovich/all.py +6 -0
- sage/schemes/berkovich/berkovich_cp_element.py +2582 -0
- sage/schemes/berkovich/berkovich_space.py +748 -0
- sage/schemes/curves/affine_curve.py +2928 -0
- sage/schemes/curves/all.py +33 -0
- sage/schemes/curves/closed_point.py +434 -0
- sage/schemes/curves/constructor.py +381 -0
- sage/schemes/curves/curve.py +542 -0
- sage/schemes/curves/plane_curve_arrangement.py +1283 -0
- sage/schemes/curves/point.py +463 -0
- sage/schemes/curves/projective_curve.py +3026 -0
- sage/schemes/curves/zariski_vankampen.py +1932 -0
- sage/schemes/cyclic_covers/all.py +2 -0
- sage/schemes/cyclic_covers/charpoly_frobenius.py +320 -0
- sage/schemes/cyclic_covers/constructor.py +137 -0
- sage/schemes/cyclic_covers/cycliccover_finite_field.py +1309 -0
- sage/schemes/cyclic_covers/cycliccover_generic.py +310 -0
- sage/schemes/elliptic_curves/BSD.py +1036 -0
- sage/schemes/elliptic_curves/Qcurves.py +592 -0
- sage/schemes/elliptic_curves/addition_formulas_ring.py +94 -0
- sage/schemes/elliptic_curves/all.py +49 -0
- sage/schemes/elliptic_curves/cardinality.py +609 -0
- sage/schemes/elliptic_curves/cm.py +1102 -0
- sage/schemes/elliptic_curves/constructor.py +1552 -0
- sage/schemes/elliptic_curves/ec_database.py +175 -0
- sage/schemes/elliptic_curves/ell_curve_isogeny.py +3972 -0
- sage/schemes/elliptic_curves/ell_egros.py +459 -0
- sage/schemes/elliptic_curves/ell_field.py +2836 -0
- sage/schemes/elliptic_curves/ell_finite_field.py +3359 -0
- sage/schemes/elliptic_curves/ell_generic.py +3760 -0
- sage/schemes/elliptic_curves/ell_local_data.py +1207 -0
- sage/schemes/elliptic_curves/ell_modular_symbols.py +775 -0
- sage/schemes/elliptic_curves/ell_number_field.py +4220 -0
- sage/schemes/elliptic_curves/ell_padic_field.py +107 -0
- sage/schemes/elliptic_curves/ell_point.py +4787 -0
- sage/schemes/elliptic_curves/ell_rational_field.py +7368 -0
- sage/schemes/elliptic_curves/ell_tate_curve.py +671 -0
- sage/schemes/elliptic_curves/ell_torsion.py +436 -0
- sage/schemes/elliptic_curves/ell_wp.py +352 -0
- sage/schemes/elliptic_curves/formal_group.py +760 -0
- sage/schemes/elliptic_curves/gal_reps.py +1459 -0
- sage/schemes/elliptic_curves/gal_reps_number_field.py +1669 -0
- sage/schemes/elliptic_curves/gp_simon.py +152 -0
- sage/schemes/elliptic_curves/heegner.py +7335 -0
- sage/schemes/elliptic_curves/height.py +2109 -0
- sage/schemes/elliptic_curves/hom.py +1406 -0
- sage/schemes/elliptic_curves/hom_composite.py +934 -0
- sage/schemes/elliptic_curves/hom_frobenius.py +522 -0
- sage/schemes/elliptic_curves/hom_scalar.py +531 -0
- sage/schemes/elliptic_curves/hom_sum.py +682 -0
- sage/schemes/elliptic_curves/hom_velusqrt.py +1290 -0
- sage/schemes/elliptic_curves/homset.py +271 -0
- sage/schemes/elliptic_curves/isogeny_class.py +1521 -0
- sage/schemes/elliptic_curves/isogeny_small_degree.py +2797 -0
- sage/schemes/elliptic_curves/jacobian.py +237 -0
- sage/schemes/elliptic_curves/kodaira_symbol.py +344 -0
- sage/schemes/elliptic_curves/kraus.py +1014 -0
- sage/schemes/elliptic_curves/lseries_ell.py +943 -0
- sage/schemes/elliptic_curves/mod5family.py +105 -0
- sage/schemes/elliptic_curves/mod_poly.py +197 -0
- sage/schemes/elliptic_curves/mod_sym_num.cpython-312-darwin.so +0 -0
- sage/schemes/elliptic_curves/mod_sym_num.pyx +3796 -0
- sage/schemes/elliptic_curves/modular_parametrization.py +305 -0
- sage/schemes/elliptic_curves/padic_lseries.py +1793 -0
- sage/schemes/elliptic_curves/padics.py +1816 -0
- sage/schemes/elliptic_curves/period_lattice.py +2234 -0
- sage/schemes/elliptic_curves/period_lattice_region.cpython-312-darwin.so +0 -0
- sage/schemes/elliptic_curves/period_lattice_region.pyx +722 -0
- sage/schemes/elliptic_curves/saturation.py +715 -0
- sage/schemes/elliptic_curves/sha_tate.py +1158 -0
- sage/schemes/elliptic_curves/weierstrass_morphism.py +1117 -0
- sage/schemes/elliptic_curves/weierstrass_transform.py +200 -0
- sage/schemes/hyperelliptic_curves/all.py +6 -0
- sage/schemes/hyperelliptic_curves/constructor.py +291 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py +1914 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_g2.py +192 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py +954 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py +1332 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_rational_field.py +84 -0
- sage/schemes/hyperelliptic_curves/invariants.py +410 -0
- sage/schemes/hyperelliptic_curves/jacobian_endomorphism_utils.py +315 -0
- sage/schemes/hyperelliptic_curves/jacobian_g2.py +32 -0
- sage/schemes/hyperelliptic_curves/jacobian_generic.py +419 -0
- sage/schemes/hyperelliptic_curves/jacobian_homset.py +186 -0
- sage/schemes/hyperelliptic_curves/jacobian_morphism.py +875 -0
- sage/schemes/hyperelliptic_curves/kummer_surface.py +99 -0
- sage/schemes/hyperelliptic_curves/mestre.py +302 -0
- sage/schemes/hyperelliptic_curves/monsky_washnitzer.py +3871 -0
- sage/schemes/jacobians/abstract_jacobian.py +277 -0
- sage/schemes/jacobians/all.py +2 -0
- sage/schemes/overview.py +161 -0
- sage/schemes/plane_conics/all.py +22 -0
- sage/schemes/plane_conics/con_field.py +1296 -0
- sage/schemes/plane_conics/con_finite_field.py +158 -0
- sage/schemes/plane_conics/con_number_field.py +456 -0
- sage/schemes/plane_conics/con_rational_field.py +406 -0
- sage/schemes/plane_conics/con_rational_function_field.py +580 -0
- sage/schemes/plane_conics/constructor.py +249 -0
- sage/schemes/plane_quartics/all.py +2 -0
- sage/schemes/plane_quartics/quartic_constructor.py +71 -0
- sage/schemes/plane_quartics/quartic_generic.py +73 -0
- sage/schemes/riemann_surfaces/all.py +1 -0
- sage/schemes/riemann_surfaces/riemann_surface.py +4117 -0
- sage_wheels/share/cremona/cremona_mini.db +0 -0
- sage_wheels/share/ellcurves/rank0 +30427 -0
- sage_wheels/share/ellcurves/rank1 +31871 -0
- sage_wheels/share/ellcurves/rank10 +6 -0
- sage_wheels/share/ellcurves/rank11 +6 -0
- sage_wheels/share/ellcurves/rank12 +1 -0
- sage_wheels/share/ellcurves/rank14 +1 -0
- sage_wheels/share/ellcurves/rank15 +1 -0
- sage_wheels/share/ellcurves/rank17 +1 -0
- sage_wheels/share/ellcurves/rank19 +1 -0
- sage_wheels/share/ellcurves/rank2 +2388 -0
- sage_wheels/share/ellcurves/rank20 +1 -0
- sage_wheels/share/ellcurves/rank21 +1 -0
- sage_wheels/share/ellcurves/rank22 +1 -0
- sage_wheels/share/ellcurves/rank23 +1 -0
- sage_wheels/share/ellcurves/rank24 +1 -0
- sage_wheels/share/ellcurves/rank28 +1 -0
- sage_wheels/share/ellcurves/rank3 +836 -0
- sage_wheels/share/ellcurves/rank4 +10 -0
- sage_wheels/share/ellcurves/rank5 +5 -0
- sage_wheels/share/ellcurves/rank6 +5 -0
- sage_wheels/share/ellcurves/rank7 +5 -0
- sage_wheels/share/ellcurves/rank8 +6 -0
- sage_wheels/share/ellcurves/rank9 +7 -0
|
@@ -0,0 +1,592 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-schemes
|
|
2
|
+
r"""
|
|
3
|
+
Testing whether elliptic curves over number fields are `\QQ`-curves
|
|
4
|
+
|
|
5
|
+
AUTHORS:
|
|
6
|
+
|
|
7
|
+
- John Cremona (February 2021)
|
|
8
|
+
|
|
9
|
+
The code here implements the algorithm of Cremona and Najman presented
|
|
10
|
+
in [CrNa2020]_.
|
|
11
|
+
"""
|
|
12
|
+
##############################################################################
|
|
13
|
+
# Copyright (C) 2020-2021 John Cremona <john.cremona@gmail.com>
|
|
14
|
+
#
|
|
15
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
16
|
+
#
|
|
17
|
+
# This code is distributed in the hope that it will be useful,
|
|
18
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
19
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
20
|
+
# General Public License for more details.
|
|
21
|
+
#
|
|
22
|
+
# The full text of the GPL is available at:
|
|
23
|
+
#
|
|
24
|
+
# https://www.gnu.org/licenses/
|
|
25
|
+
##############################################################################
|
|
26
|
+
from sage.rings.rational_field import QQ
|
|
27
|
+
from sage.rings.polynomial.polynomial_ring import polygen
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def is_Q_curve(E, maxp=100, certificate=False, verbose=False):
|
|
31
|
+
r"""
|
|
32
|
+
Return whether ``E`` is a `\QQ`-curve, with optional certificate.
|
|
33
|
+
|
|
34
|
+
INPUT:
|
|
35
|
+
|
|
36
|
+
- ``E`` -- elliptic curve over a number field
|
|
37
|
+
|
|
38
|
+
- ``maxp`` -- integer (default: 100); bound on primes used for checking
|
|
39
|
+
necessary local conditions. The result will not depend on this,
|
|
40
|
+
but using a larger value may return ``False`` faster.
|
|
41
|
+
|
|
42
|
+
- ``certificate`` -- boolean (default: ``False``); if ``True`` then a
|
|
43
|
+
second value is returned giving a certificate for the
|
|
44
|
+
`\QQ`-curve property
|
|
45
|
+
|
|
46
|
+
OUTPUT:
|
|
47
|
+
|
|
48
|
+
If ``certificate`` is ``False``: either ``True`` (if `E` is a
|
|
49
|
+
`\QQ`-curve), or ``False``.
|
|
50
|
+
|
|
51
|
+
If ``certificate`` is ``True``: a tuple consisting of a boolean
|
|
52
|
+
flag as before and a certificate, defined as follows:
|
|
53
|
+
|
|
54
|
+
- when the flag is ``True``, so `E` is a `\QQ`-curve:
|
|
55
|
+
|
|
56
|
+
- either {'CM':`D`} where `D` is a negative discriminant, when
|
|
57
|
+
`E` has potential CM with discriminant `D`;
|
|
58
|
+
|
|
59
|
+
- otherwise {'CM': `0`, 'core_poly': `f`, 'rho': `\rho`, 'r':
|
|
60
|
+
`r`, 'N': `N`}, when `E` is a non-CM `\QQ`-curve, where the
|
|
61
|
+
core polynomial `f` is an irreducible monic polynomial over
|
|
62
|
+
`QQ` of degree `2^\rho`, all of whose roots are
|
|
63
|
+
`j`-invariants of curves isogenous to `E`, the core level
|
|
64
|
+
`N` is a square-free integer with `r` prime factors which is
|
|
65
|
+
the LCM of the degrees of the isogenies between these
|
|
66
|
+
conjugates. For example, if there exists a curve `E'`
|
|
67
|
+
isogenous to `E` with `j(E')=j\in\QQ`, then the certificate
|
|
68
|
+
is {'CM':0, 'r':0, 'rho':0, 'core_poly': x-j, 'N':1}.
|
|
69
|
+
|
|
70
|
+
- when the flag is ``False``, so `E` is not a `\QQ`-curve, the
|
|
71
|
+
certificate is a prime `p` such that the reductions of `E` at
|
|
72
|
+
the primes dividing `p` are inconsistent with the property of
|
|
73
|
+
being a `\QQ`-curve. See the ALGORITHM section for details.
|
|
74
|
+
|
|
75
|
+
ALGORITHM:
|
|
76
|
+
|
|
77
|
+
See [CrNa2020]_ for details.
|
|
78
|
+
|
|
79
|
+
1. If `E` has rational `j`-invariant, or has CM, then return
|
|
80
|
+
``True``.
|
|
81
|
+
|
|
82
|
+
2. Replace `E` by a curve defined over `K=\QQ(j(E))`. Let `N` be
|
|
83
|
+
the conductor norm.
|
|
84
|
+
|
|
85
|
+
3. For all primes `p\mid N` check that the valuations of `j` at
|
|
86
|
+
all `P\mid p` are either all negative or all nonnegative; if not,
|
|
87
|
+
return ``False``.
|
|
88
|
+
|
|
89
|
+
4. For `p\le maxp`, `p\not\mid N`, check that either `E` is
|
|
90
|
+
ordinary mod `P` for all `P\mid p`, or `E` is supersingular mod
|
|
91
|
+
`P` for all `P\mid p`; if neither, return ``False``. If all are
|
|
92
|
+
ordinary, check that the integers `a_P(E)^2-4N(P)` have the same
|
|
93
|
+
square-free part; if not, return ``False``.
|
|
94
|
+
|
|
95
|
+
5. Compute the `K`-isogeny class of `E` using the "heuristic"
|
|
96
|
+
option (which is faster, but not guaranteed to be complete).
|
|
97
|
+
Check whether the set of `j`-invariants of curves in the class of
|
|
98
|
+
`2`-power degree contains a complete Galois orbit. If so, return
|
|
99
|
+
``True``.
|
|
100
|
+
|
|
101
|
+
6. Otherwise repeat step 4 for more primes, and if still
|
|
102
|
+
undecided, repeat Step 5 without the "heuristic" option, to get
|
|
103
|
+
the complete `K`-isogeny class (which will probably be no bigger
|
|
104
|
+
than before). Now return ``True`` if the set of `j`-invariants of
|
|
105
|
+
curves in the class contains a complete Galois orbit, otherwise
|
|
106
|
+
return ``False``.
|
|
107
|
+
|
|
108
|
+
EXAMPLES:
|
|
109
|
+
|
|
110
|
+
A non-CM curve over `\QQ` and a CM curve over `\QQ` are both
|
|
111
|
+
trivially `\QQ`-curves::
|
|
112
|
+
|
|
113
|
+
sage: from sage.schemes.elliptic_curves.Qcurves import is_Q_curve
|
|
114
|
+
sage: E = EllipticCurve([1,2,3,4,5])
|
|
115
|
+
sage: flag, cert = is_Q_curve(E, certificate=True)
|
|
116
|
+
sage: flag
|
|
117
|
+
True
|
|
118
|
+
sage: cert
|
|
119
|
+
{'CM': 0, 'N': 1, 'core_poly': x, 'r': 0, 'rho': 0}
|
|
120
|
+
|
|
121
|
+
sage: E = EllipticCurve(j=8000)
|
|
122
|
+
sage: flag, cert = is_Q_curve(E, certificate=True)
|
|
123
|
+
sage: flag
|
|
124
|
+
True
|
|
125
|
+
sage: cert
|
|
126
|
+
{'CM': -8}
|
|
127
|
+
|
|
128
|
+
A non-`\QQ`-curve over a quartic field. The local data at bad
|
|
129
|
+
primes above `3` is inconsistent::
|
|
130
|
+
|
|
131
|
+
sage: from sage.schemes.elliptic_curves.Qcurves import is_Q_curve
|
|
132
|
+
sage: R.<x> = PolynomialRing(QQ)
|
|
133
|
+
sage: K.<a> = NumberField(R([3, 0, -5, 0, 1])) # needs sage.rings.number_field
|
|
134
|
+
sage: E = EllipticCurve([K([-3,-4,1,1]), K([4,-1,-1,0]), K([-2,0,1,0]), # needs sage.rings.number_field
|
|
135
|
+
....: K([-621,778,138,-178]), K([9509,2046,-24728,10380])])
|
|
136
|
+
sage: is_Q_curve(E, certificate=True, verbose=True) # needs sage.rings.number_field
|
|
137
|
+
Checking whether Elliptic Curve defined by y^2 + (a^3+a^2-4*a-3)*x*y + (a^2-2)*y = x^3 + (-a^2-a+4)*x^2 + (-178*a^3+138*a^2+778*a-621)*x + (10380*a^3-24728*a^2+2046*a+9509) over Number Field in a with defining polynomial x^4 - 5*x^2 + 3 is a Q-curve
|
|
138
|
+
No: inconsistency at the 2 primes dividing 3
|
|
139
|
+
- potentially multiplicative: [True, False]
|
|
140
|
+
(False, 3)
|
|
141
|
+
|
|
142
|
+
A non-`\QQ`-curve over a quadratic field. The local data at bad
|
|
143
|
+
primes is consistent, but the local test at good primes above `13`
|
|
144
|
+
is not::
|
|
145
|
+
|
|
146
|
+
sage: K.<a> = NumberField(R([-10, 0, 1])) # needs sage.rings.number_field
|
|
147
|
+
sage: E = EllipticCurve([K([0,1]), K([-1,-1]), K([0,0]), # needs sage.rings.number_field
|
|
148
|
+
....: K([-236,40]), K([-1840,464])])
|
|
149
|
+
sage: is_Q_curve(E, certificate=True, verbose=True) # needs sage.rings.number_field
|
|
150
|
+
Checking whether Elliptic Curve defined by y^2 + a*x*y = x^3 + (-a-1)*x^2 + (40*a-236)*x + (464*a-1840) over Number Field in a with defining polynomial x^2 - 10 is a Q-curve
|
|
151
|
+
Applying local tests at good primes above p<=100
|
|
152
|
+
No: inconsistency at the 2 ordinary primes dividing 13
|
|
153
|
+
- Frobenius discriminants mod squares: [-1, -3]
|
|
154
|
+
No: local test at p=13 failed
|
|
155
|
+
(False, 13)
|
|
156
|
+
|
|
157
|
+
A quadratic `\QQ`-curve with CM discriminant `-15` (`j`-invariant not in `\QQ`)::
|
|
158
|
+
|
|
159
|
+
sage: from sage.schemes.elliptic_curves.Qcurves import is_Q_curve
|
|
160
|
+
sage: R.<x> = PolynomialRing(QQ)
|
|
161
|
+
sage: K.<a> = NumberField(R([-1, -1, 1])) # needs sage.rings.number_field
|
|
162
|
+
sage: E = EllipticCurve([K([1,0]), K([-1,0]), K([0,1]), K([0,-2]), K([0,1])]) # needs sage.rings.number_field
|
|
163
|
+
sage: is_Q_curve(E, certificate=True, verbose=True) # needs sage.rings.number_field
|
|
164
|
+
Checking whether Elliptic Curve defined by y^2 + x*y + a*y = x^3 + (-1)*x^2 + (-2*a)*x + a over Number Field in a with defining polynomial x^2 - x - 1 is a Q-curve
|
|
165
|
+
Yes: E is CM (discriminant -15)
|
|
166
|
+
(True, {'CM': -15})
|
|
167
|
+
|
|
168
|
+
An example over `\QQ(\sqrt{2},\sqrt{3})`. The `j`-invariant is in
|
|
169
|
+
`\QQ(\sqrt{6})`, so computations will be done over that field, and
|
|
170
|
+
in fact there is an isogenous curve with rational `j`, so we have
|
|
171
|
+
a so-called rational `\QQ`-curve::
|
|
172
|
+
|
|
173
|
+
sage: # needs sage.rings.number_field
|
|
174
|
+
sage: K.<a> = NumberField(R([1, 0, -4, 0, 1]))
|
|
175
|
+
sage: E = EllipticCurve([K([-2,-4,1,1]), K([0,1,0,0]), K([0,1,0,0]),
|
|
176
|
+
....: K([-4780,9170,1265,-2463]),
|
|
177
|
+
....: K([163923,-316598,-43876,84852])])
|
|
178
|
+
sage: flag, cert = is_Q_curve(E, certificate=True)
|
|
179
|
+
sage: flag
|
|
180
|
+
True
|
|
181
|
+
sage: cert
|
|
182
|
+
{'CM': 0, 'N': 1, 'core_degs': [1], 'core_poly': x - 85184/3, 'r': 0, 'rho': 0}
|
|
183
|
+
|
|
184
|
+
Over the same field, a so-called strict `\QQ`-curve which is not
|
|
185
|
+
isogenous to one with rational `j`, but whose core field is
|
|
186
|
+
quadratic. In fact the isogeny class over `K` consists of `6`
|
|
187
|
+
curves, four with conjugate quartic `j`-invariants and `2` with
|
|
188
|
+
quadratic conjugate `j`-invariants in `\QQ(\sqrt{3})` (but which
|
|
189
|
+
are not base-changes from the quadratic subfield)::
|
|
190
|
+
|
|
191
|
+
sage: # needs sage.rings.number_field
|
|
192
|
+
sage: E = EllipticCurve([K([0,-3,0,1]), K([1,4,0,-1]), K([0,0,0,0]),
|
|
193
|
+
....: K([-2,-16,0,4]), K([-19,-32,4,8])])
|
|
194
|
+
sage: flag, cert = is_Q_curve(E, certificate=True)
|
|
195
|
+
sage: flag
|
|
196
|
+
True
|
|
197
|
+
sage: cert
|
|
198
|
+
{'CM': 0,
|
|
199
|
+
'N': 2,
|
|
200
|
+
'core_degs': [1, 2],
|
|
201
|
+
'core_poly': x^2 - 840064*x + 1593413632,
|
|
202
|
+
'r': 1,
|
|
203
|
+
'rho': 1}
|
|
204
|
+
|
|
205
|
+
TESTS::
|
|
206
|
+
|
|
207
|
+
sage: E = EllipticCurve([GF(5)(t) for t in [2,3,5,7,11]])
|
|
208
|
+
sage: is_Q_curve(E)
|
|
209
|
+
Traceback (most recent call last):
|
|
210
|
+
...
|
|
211
|
+
TypeError: Elliptic Curve defined by ... must be an elliptic curve
|
|
212
|
+
defined over a number field
|
|
213
|
+
"""
|
|
214
|
+
from sage.rings.number_field.number_field_base import NumberField
|
|
215
|
+
|
|
216
|
+
if verbose:
|
|
217
|
+
print(f"Checking whether {E} is a Q-curve")
|
|
218
|
+
|
|
219
|
+
try:
|
|
220
|
+
assert isinstance(E.base_field(), NumberField)
|
|
221
|
+
except (AttributeError, AssertionError):
|
|
222
|
+
raise TypeError(f"{E} must be an elliptic curve defined over a number field")
|
|
223
|
+
|
|
224
|
+
from sage.rings.integer_ring import ZZ
|
|
225
|
+
from sage.arith.functions import lcm
|
|
226
|
+
from sage.libs.pari import pari
|
|
227
|
+
from sage.rings.number_field.number_field import NumberField
|
|
228
|
+
from sage.schemes.elliptic_curves.constructor import EllipticCurve
|
|
229
|
+
from sage.schemes.elliptic_curves.cm import cm_j_invariants_and_orders, is_cm_j_invariant
|
|
230
|
+
|
|
231
|
+
# Step 1
|
|
232
|
+
|
|
233
|
+
# all curves with rational j-invariant are Q-curves:
|
|
234
|
+
jE = E.j_invariant()
|
|
235
|
+
if jE in QQ:
|
|
236
|
+
if verbose:
|
|
237
|
+
print("Yes: j(E) is in QQ")
|
|
238
|
+
if certificate:
|
|
239
|
+
# test for CM
|
|
240
|
+
for d, f, j in cm_j_invariants_and_orders(QQ):
|
|
241
|
+
if jE == j:
|
|
242
|
+
return True, {'CM': d * f**2}
|
|
243
|
+
# else not CM
|
|
244
|
+
return True, {'CM': ZZ(0), 'r': ZZ(0), 'rho': ZZ(0), 'N': ZZ(1), 'core_poly': polygen(QQ)}
|
|
245
|
+
else:
|
|
246
|
+
return True
|
|
247
|
+
|
|
248
|
+
# CM curves are Q-curves:
|
|
249
|
+
flag, df = is_cm_j_invariant(jE)
|
|
250
|
+
if flag:
|
|
251
|
+
d, f = df
|
|
252
|
+
D = d * f**2
|
|
253
|
+
if verbose:
|
|
254
|
+
print("Yes: E is CM (discriminant {})".format(D))
|
|
255
|
+
if certificate:
|
|
256
|
+
return True, {'CM': D}
|
|
257
|
+
else:
|
|
258
|
+
return True
|
|
259
|
+
|
|
260
|
+
# Step 2: replace E by a curve defined over Q(j(E)):
|
|
261
|
+
|
|
262
|
+
K = E.base_field()
|
|
263
|
+
jpoly = jE.minpoly()
|
|
264
|
+
if jpoly.degree() < K.degree():
|
|
265
|
+
if verbose:
|
|
266
|
+
print("switching to smaller base field: j's minpoly is {}".format(jpoly))
|
|
267
|
+
f = pari(jpoly).polredbest().sage({'x': jpoly.parent().gen()})
|
|
268
|
+
K2 = NumberField(f, 'b')
|
|
269
|
+
jE = jpoly.roots(K2)[0][0]
|
|
270
|
+
if verbose:
|
|
271
|
+
print("New j is {} over {}, with minpoly {}".format(jE, K2, jE.minpoly()))
|
|
272
|
+
# assert jE.minpoly() == jpoly
|
|
273
|
+
E = EllipticCurve(j=jE)
|
|
274
|
+
K = K2
|
|
275
|
+
if verbose:
|
|
276
|
+
print("New test curve is {}".format(E))
|
|
277
|
+
|
|
278
|
+
# Step 3: check primes of bad reduction
|
|
279
|
+
|
|
280
|
+
NN = E.conductor().norm()
|
|
281
|
+
for p in NN.support():
|
|
282
|
+
Plist = K.primes_above(p)
|
|
283
|
+
if len(Plist) < 2:
|
|
284
|
+
continue
|
|
285
|
+
# pot_mult = potential multiplicative reduction
|
|
286
|
+
pot_mult = [jE.valuation(P) < 0 for P in Plist]
|
|
287
|
+
consistent = all(pot_mult) or not any(pot_mult)
|
|
288
|
+
if not consistent:
|
|
289
|
+
if verbose:
|
|
290
|
+
print(f"No: inconsistency at the {len(Plist)} primes dividing {p}")
|
|
291
|
+
print(" - potentially multiplicative: {}".format(pot_mult))
|
|
292
|
+
if certificate:
|
|
293
|
+
return False, p
|
|
294
|
+
else:
|
|
295
|
+
return False
|
|
296
|
+
|
|
297
|
+
# Step 4 check: primes P of good reduction above p<=B:
|
|
298
|
+
|
|
299
|
+
if verbose:
|
|
300
|
+
print("Applying local tests at good primes above p<={}".format(maxp))
|
|
301
|
+
|
|
302
|
+
res4, p = Step4Test(E, B=maxp, oldB=0, verbose=verbose)
|
|
303
|
+
if not res4:
|
|
304
|
+
if verbose:
|
|
305
|
+
print("No: local test at p={} failed".format(p))
|
|
306
|
+
if certificate:
|
|
307
|
+
return False, p
|
|
308
|
+
else:
|
|
309
|
+
return False
|
|
310
|
+
|
|
311
|
+
if verbose:
|
|
312
|
+
print("...all local tests pass for p<={}".format(maxp))
|
|
313
|
+
|
|
314
|
+
# Step 5: compute the (partial) K-isogeny class of E and test the
|
|
315
|
+
# set of j-invariants in the class:
|
|
316
|
+
|
|
317
|
+
C = E.isogeny_class(algorithm='heuristic', minimal_models=False)
|
|
318
|
+
jC = [E2.j_invariant() for E2 in C]
|
|
319
|
+
centrejpols = conjugacy_test(jC, verbose=verbose)
|
|
320
|
+
if centrejpols:
|
|
321
|
+
if verbose:
|
|
322
|
+
print("Yes: the isogeny class contains a complete conjugacy class of j-invariants")
|
|
323
|
+
if certificate:
|
|
324
|
+
for f in centrejpols:
|
|
325
|
+
rho = f.degree().valuation(2)
|
|
326
|
+
centre_indices = [i for i, j in enumerate(jC) if f(j) == 0]
|
|
327
|
+
M = C.matrix()
|
|
328
|
+
core_degs = [M[centre_indices[0], i] for i in centre_indices]
|
|
329
|
+
level = lcm(core_degs)
|
|
330
|
+
if level.is_squarefree():
|
|
331
|
+
r = len(level.prime_divisors())
|
|
332
|
+
cert = {'CM': ZZ(0), 'core_poly': f, 'rho': rho,
|
|
333
|
+
'r': r, 'N': level, 'core_degs': core_degs}
|
|
334
|
+
return True, cert
|
|
335
|
+
print("No central curve found")
|
|
336
|
+
else:
|
|
337
|
+
return True
|
|
338
|
+
|
|
339
|
+
# Now we are undecided. This can happen if either (1) E is not a
|
|
340
|
+
# Q-curve but we did not use enough primes in Step 4 to detect
|
|
341
|
+
# this, or (2) E is a Q-curve but in Step 5 we did not compute the
|
|
342
|
+
# complete isogeny class. Case (2) is most unlikely since the
|
|
343
|
+
# heuristic bound used in computing isogeny classes means that we
|
|
344
|
+
# have all isogenous curves linked to E by an isogeny of degree
|
|
345
|
+
# supported on primes<1000.
|
|
346
|
+
|
|
347
|
+
# We first rerun Step 4 with a larger bound.
|
|
348
|
+
|
|
349
|
+
xmaxp = 10 * maxp
|
|
350
|
+
if verbose:
|
|
351
|
+
print("Undecided after first round, so we apply more local tests, up to {}".format(xmaxp))
|
|
352
|
+
|
|
353
|
+
res4, p = Step4Test(E, B=xmaxp, oldB=maxp, verbose=verbose)
|
|
354
|
+
if not res4:
|
|
355
|
+
if verbose:
|
|
356
|
+
print("No: local test at p={} failed".format(p))
|
|
357
|
+
if certificate:
|
|
358
|
+
return False, p
|
|
359
|
+
else:
|
|
360
|
+
return False
|
|
361
|
+
|
|
362
|
+
# Now we rerun Step 5 using a rigorous computation of the complete
|
|
363
|
+
# isogeny class. This will probably contain no more curves than
|
|
364
|
+
# before, in which case -- since we already tested that the set of
|
|
365
|
+
# j-invariants does not contain a complete Galois conjugacy class
|
|
366
|
+
# -- we can deduce that E is not a Q-curve.
|
|
367
|
+
|
|
368
|
+
if verbose:
|
|
369
|
+
print("...all local tests pass for p<={}".format(xmaxp))
|
|
370
|
+
print("We now compute the complete isogeny class...")
|
|
371
|
+
|
|
372
|
+
Cfull = E.isogeny_class(minimal_models=False)
|
|
373
|
+
jCfull = [E2.j_invariant() for E2 in Cfull]
|
|
374
|
+
|
|
375
|
+
if len(jC) == len(jCfull):
|
|
376
|
+
if verbose:
|
|
377
|
+
print("...and find that we already had the complete class:so No")
|
|
378
|
+
if certificate:
|
|
379
|
+
return False, 0
|
|
380
|
+
else:
|
|
381
|
+
return False
|
|
382
|
+
if verbose:
|
|
383
|
+
print("...and find that the class contains {} curves, not just the {} we computed originally".format(len(jCfull), len(jC)))
|
|
384
|
+
centrejpols = conjugacy_test(jCfull, verbose=verbose)
|
|
385
|
+
if cert:
|
|
386
|
+
if verbose:
|
|
387
|
+
print("Yes: the isogeny class contains a complete conjugacy class of j-invariants")
|
|
388
|
+
if certificate:
|
|
389
|
+
return True, centrejpols
|
|
390
|
+
else:
|
|
391
|
+
return True
|
|
392
|
+
if verbose:
|
|
393
|
+
print("No: the isogeny class does *not* contain a complete conjugacy class of j-invariants")
|
|
394
|
+
if certificate:
|
|
395
|
+
return False, 0
|
|
396
|
+
else:
|
|
397
|
+
return False
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
def Step4Test(E, B, oldB=0, verbose=False):
|
|
401
|
+
r"""
|
|
402
|
+
Apply local Q-curve test to E at all primes up to B.
|
|
403
|
+
|
|
404
|
+
INPUT:
|
|
405
|
+
|
|
406
|
+
- ``E`` -- elliptic curve defined over a number field
|
|
407
|
+
|
|
408
|
+
- ``B`` -- integer; upper bound on primes to test
|
|
409
|
+
|
|
410
|
+
- ``oldB`` -- integer (default: 0); lower bound on primes to test
|
|
411
|
+
|
|
412
|
+
- ``verbose`` -- boolean (default: ``False``); verbosity flag
|
|
413
|
+
|
|
414
|
+
OUTPUT:
|
|
415
|
+
|
|
416
|
+
Either (``False``, `p`), if the local test at `p` proves that `E`
|
|
417
|
+
is not a `\QQ`-curve, or (``True``, `0`) if all local tests at
|
|
418
|
+
primes between ``oldB`` and ``B`` fail to prove that `E` is not a
|
|
419
|
+
`\QQ`-curve.
|
|
420
|
+
|
|
421
|
+
ALGORITHM (see [CrNa2020]_ for details):
|
|
422
|
+
|
|
423
|
+
This local test at `p` only applies if `E` has good reduction at
|
|
424
|
+
all of the primes lying above `p` in the base field `K` of `E`. It
|
|
425
|
+
tests whether (1) `E` is either ordinary at all `P\mid p`, or
|
|
426
|
+
supersingular at all; (2) if ordinary at all, it tests that the
|
|
427
|
+
squarefree part of `a_P^2-4N(P)` is the same for all `P\mid p`.
|
|
428
|
+
|
|
429
|
+
EXAMPLES:
|
|
430
|
+
|
|
431
|
+
A non-`\QQ`-curve over a quartic field (with LMFDB label
|
|
432
|
+
'4.4.8112.1-12.1-a1') fails this test at `p=13`::
|
|
433
|
+
|
|
434
|
+
sage: from sage.schemes.elliptic_curves.Qcurves import Step4Test
|
|
435
|
+
sage: R.<x> = PolynomialRing(QQ)
|
|
436
|
+
sage: K.<a> = NumberField(R([3, 0, -5, 0, 1])) # needs sage.rings.number_field
|
|
437
|
+
sage: E = EllipticCurve([K([-3,-4,1,1]), K([4,-1,-1,0]), K([-2,0,1,0]), # needs sage.rings.number_field
|
|
438
|
+
....: K([-621,778,138,-178]), K([9509,2046,-24728,10380])])
|
|
439
|
+
sage: Step4Test(E, 100, verbose=True) # needs sage.rings.number_field
|
|
440
|
+
No: inconsistency at the 2 ordinary primes dividing 13
|
|
441
|
+
- Frobenius discriminants mod squares: [-3, -1]
|
|
442
|
+
(False, 13)
|
|
443
|
+
|
|
444
|
+
A `\QQ`-curve over a sextic field (with LMFDB label
|
|
445
|
+
'6.6.1259712.1-64.1-a6') passes this test for all `p<100`::
|
|
446
|
+
|
|
447
|
+
sage: from sage.schemes.elliptic_curves.Qcurves import Step4Test
|
|
448
|
+
sage: R.<x> = PolynomialRing(QQ)
|
|
449
|
+
sage: K.<a> = NumberField(R([-3, 0, 9, 0, -6, 0, 1])) # needs sage.rings.number_field
|
|
450
|
+
sage: E = EllipticCurve([K([1,-3,0,1,0,0]), K([5,-3,-6,1,1,0]), # needs sage.rings.number_field
|
|
451
|
+
....: K([1,-3,0,1,0,0]), K([-139,-129,331,277,-76,-63]),
|
|
452
|
+
....: K([2466,1898,-5916,-4582,1361,1055])])
|
|
453
|
+
sage: Step4Test(E, 100, verbose=True) # needs sage.rings.number_field
|
|
454
|
+
(True, 0)
|
|
455
|
+
"""
|
|
456
|
+
from sage.arith.misc import primes
|
|
457
|
+
K = E.base_field()
|
|
458
|
+
NN = E.conductor().norm()
|
|
459
|
+
for p in primes(B):
|
|
460
|
+
if p <= oldB or p.divides(NN):
|
|
461
|
+
continue
|
|
462
|
+
Plist = K.primes_above(p)
|
|
463
|
+
if len(Plist) < 2:
|
|
464
|
+
continue
|
|
465
|
+
|
|
466
|
+
EmodP = [E.reduction(P) for P in Plist]
|
|
467
|
+
|
|
468
|
+
# (a) Check all are ordinary or all supersingular:
|
|
469
|
+
ordinary = [Ei.is_ordinary() for Ei in EmodP]
|
|
470
|
+
consistent = all(ordinary) or not any(ordinary)
|
|
471
|
+
if not consistent:
|
|
472
|
+
if verbose:
|
|
473
|
+
print(f"No: inconsistency at the {len(Plist)} primes dividing {p} ")
|
|
474
|
+
print(" - ordinary: {}".format(ordinary))
|
|
475
|
+
return False, p
|
|
476
|
+
|
|
477
|
+
# (b) Skip if all are supersingular:
|
|
478
|
+
if not ordinary[0]:
|
|
479
|
+
continue
|
|
480
|
+
|
|
481
|
+
# else compare a_P^2-4*N(P) which should have the same squarefree part:
|
|
482
|
+
|
|
483
|
+
discs = [(Ei.trace_of_frobenius()**2 - 4 * P.norm()).squarefree_part() for P, Ei in zip(Plist, EmodP)]
|
|
484
|
+
if any(d != discs[0] for d in discs[1:]):
|
|
485
|
+
if verbose:
|
|
486
|
+
print("No: inconsistency at the {} ordinary primes dividing {} ".format(len(Plist), p))
|
|
487
|
+
print(" - Frobenius discriminants mod squares: {}".format(discs))
|
|
488
|
+
return False, p
|
|
489
|
+
# Now we have failed to prove that E is not a Q-curve
|
|
490
|
+
return True, 0
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
def conjugacy_test(jlist, verbose=False):
|
|
494
|
+
r"""
|
|
495
|
+
Test whether a list of algebraic numbers contains a complete
|
|
496
|
+
conjugacy class of 2-power degree.
|
|
497
|
+
|
|
498
|
+
INPUT:
|
|
499
|
+
|
|
500
|
+
- ``jlist`` -- list of algebraic numbers in the same field
|
|
501
|
+
|
|
502
|
+
- ``verbose`` -- boolean (default: ``False``); verbosity flag
|
|
503
|
+
|
|
504
|
+
OUTPUT:
|
|
505
|
+
|
|
506
|
+
A possibly empty list of irreducible polynomials over `\QQ` of
|
|
507
|
+
2-power degree all of whose roots are in the list.
|
|
508
|
+
|
|
509
|
+
EXAMPLES::
|
|
510
|
+
|
|
511
|
+
sage: # needs sage.rings.number_field
|
|
512
|
+
sage: from sage.schemes.elliptic_curves.Qcurves import conjugacy_test
|
|
513
|
+
sage: conjugacy_test([3])
|
|
514
|
+
[x - 3]
|
|
515
|
+
sage: K.<a> = QuadraticField(2)
|
|
516
|
+
sage: conjugacy_test([K(3), a])
|
|
517
|
+
[x - 3]
|
|
518
|
+
sage: conjugacy_test([K(3), 3 + a])
|
|
519
|
+
[x - 3]
|
|
520
|
+
sage: conjugacy_test([3 + a])
|
|
521
|
+
[]
|
|
522
|
+
sage: conjugacy_test([3 + a, 3 - a])
|
|
523
|
+
[x^2 - 6*x + 7]
|
|
524
|
+
sage: x = polygen(QQ)
|
|
525
|
+
sage: f = x^3 - 3
|
|
526
|
+
sage: K.<a> = f.splitting_field()
|
|
527
|
+
sage: js = f.roots(K, multiplicities=False)
|
|
528
|
+
sage: conjugacy_test(js)
|
|
529
|
+
[]
|
|
530
|
+
sage: f = x^4 - 3
|
|
531
|
+
sage: K.<a> = NumberField(f)
|
|
532
|
+
sage: js = f.roots(K, multiplicities=False)
|
|
533
|
+
sage: conjugacy_test(js)
|
|
534
|
+
[]
|
|
535
|
+
sage: K.<a> = f.splitting_field()
|
|
536
|
+
sage: js = f.roots(K, multiplicities=False)
|
|
537
|
+
sage: conjugacy_test(js)
|
|
538
|
+
[x^4 - 3]
|
|
539
|
+
"""
|
|
540
|
+
from sage.sets.set import Set
|
|
541
|
+
|
|
542
|
+
# First test to see if the list contains a rational
|
|
543
|
+
|
|
544
|
+
jQ = next((j for j in jlist if j in QQ), None)
|
|
545
|
+
if jQ:
|
|
546
|
+
if verbose:
|
|
547
|
+
print("Yes: an isogenous curve has rational j-invariant {}".format(jQ))
|
|
548
|
+
x = polygen(QQ)
|
|
549
|
+
return [x - jQ]
|
|
550
|
+
|
|
551
|
+
# If the degree d is odd then we know that none of the
|
|
552
|
+
# j-invariants in the class have 2-power degree, so we can exit.
|
|
553
|
+
|
|
554
|
+
K = jlist[0].parent()
|
|
555
|
+
if K.degree() % 2:
|
|
556
|
+
if verbose:
|
|
557
|
+
print("Odd-degree case: no rational j-invariant in the class {}".format(jlist))
|
|
558
|
+
return []
|
|
559
|
+
|
|
560
|
+
# If K has no quadratic subfields we can similarly conclude right
|
|
561
|
+
# away. This is one way of determining this.
|
|
562
|
+
|
|
563
|
+
if K(1).descend_mod_power(QQ, 2) == [1]:
|
|
564
|
+
if verbose:
|
|
565
|
+
print("No-quadratic-subfield case: no rational j-invariant in the class {}".format(jlist))
|
|
566
|
+
return []
|
|
567
|
+
|
|
568
|
+
# compute the minimum polynomials of the j-invariants in the class
|
|
569
|
+
pols = (j.minpoly() for j in jlist)
|
|
570
|
+
|
|
571
|
+
# pick out those of 2-power degree
|
|
572
|
+
pols = [f for f in pols if f.degree().prime_to_m_part(2) == 1]
|
|
573
|
+
|
|
574
|
+
# If none, there is nothing to do
|
|
575
|
+
if not pols:
|
|
576
|
+
return []
|
|
577
|
+
|
|
578
|
+
# see if there's a poly of degree d appearing d times. NB There
|
|
579
|
+
# may be more than one of these, possibly including some conjugacy
|
|
580
|
+
# classes defined over the core field but not central, so we
|
|
581
|
+
# return all those with the minimal degree.
|
|
582
|
+
|
|
583
|
+
mindeg = min(f.degree() for f in pols)
|
|
584
|
+
minpols = [f for f in pols if f.degree() == mindeg]
|
|
585
|
+
centrepols = list(Set([f for f in pols if f.degree() == minpols.count(f)]))
|
|
586
|
+
if centrepols:
|
|
587
|
+
if verbose:
|
|
588
|
+
print("Yes: the isogeny class contains all j-invariants with min poly {}".format(centrepols))
|
|
589
|
+
return centrepols
|
|
590
|
+
if verbose:
|
|
591
|
+
print("No complete conjugacy class of 2-power size found in {}".format(jlist))
|
|
592
|
+
return []
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-schemes
|
|
2
|
+
r"""
|
|
3
|
+
Addition formula for elliptic curves over rings
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def _add(E, P, Q):
|
|
8
|
+
r"""
|
|
9
|
+
Addition formulas for elliptic curves over general rings
|
|
10
|
+
with trivial Picard group.
|
|
11
|
+
|
|
12
|
+
This function returns a generator which yields tuples of projective
|
|
13
|
+
coordinates. Some linear combination of those coordinate tuples is
|
|
14
|
+
guaranteed to form a valid projective point.
|
|
15
|
+
|
|
16
|
+
.. NOTE::
|
|
17
|
+
|
|
18
|
+
This function is for internal use. To add two elliptic-curve
|
|
19
|
+
points, users should simply use the `+` operator.
|
|
20
|
+
|
|
21
|
+
REFERENCES:
|
|
22
|
+
|
|
23
|
+
These formulas were derived by Bosma and Lenstra [BL1995]_,
|
|
24
|
+
with corrections by Best [Best2021]_ (Appendix A).
|
|
25
|
+
|
|
26
|
+
EXAMPLES::
|
|
27
|
+
|
|
28
|
+
sage: from sage.schemes.elliptic_curves.addition_formulas_ring import _add
|
|
29
|
+
sage: M = Zmod(13*17*19)
|
|
30
|
+
sage: R.<U,V> = M[]
|
|
31
|
+
sage: S.<u,v> = R.quotient(U*V - 17)
|
|
32
|
+
sage: E = EllipticCurve(S, [1,2,3,4,5])
|
|
33
|
+
sage: P = E(817, 13, 19)
|
|
34
|
+
sage: Q = E(425, 123, 17)
|
|
35
|
+
sage: PQ1, PQ2 = _add(E, P, Q)
|
|
36
|
+
sage: PQ1
|
|
37
|
+
(1188, 1674, 540)
|
|
38
|
+
sage: PQ2
|
|
39
|
+
(582, 2347, 1028)
|
|
40
|
+
sage: E(PQ1) == E(PQ2)
|
|
41
|
+
True
|
|
42
|
+
|
|
43
|
+
TESTS:
|
|
44
|
+
|
|
45
|
+
We ensure that these formulas return the same result as the ones over a field::
|
|
46
|
+
|
|
47
|
+
sage: from sage.schemes.elliptic_curves.addition_formulas_ring import _add
|
|
48
|
+
sage: F = GF(2^127-1)
|
|
49
|
+
sage: E = EllipticCurve(j=F.random_element())
|
|
50
|
+
sage: E = choice(E.twists())
|
|
51
|
+
sage: P = E.random_point()
|
|
52
|
+
sage: Q = E.random_point()
|
|
53
|
+
sage: PQ1, PQ2 = _add(E, P, Q)
|
|
54
|
+
sage: assert E(*PQ1) == P + Q
|
|
55
|
+
sage: assert E(*PQ2) == P + Q
|
|
56
|
+
"""
|
|
57
|
+
a1, a2, a3, a4, a6 = E.a_invariants()
|
|
58
|
+
b2, b4, b6, b8 = E.b_invariants()
|
|
59
|
+
|
|
60
|
+
if P not in E:
|
|
61
|
+
raise ValueError('P must be in E')
|
|
62
|
+
if Q not in E:
|
|
63
|
+
raise ValueError('Q must be in E')
|
|
64
|
+
X1, Y1, Z1 = P
|
|
65
|
+
X2, Y2, Z2 = Q
|
|
66
|
+
|
|
67
|
+
# TODO: I've made a half-hearted attempt at simplifying the formulas
|
|
68
|
+
# by caching common subexpressions. This could almost certainly be
|
|
69
|
+
# sped up significantly with some more serious optimization effort.
|
|
70
|
+
|
|
71
|
+
XYdif = X1*Y2 - X2*Y1
|
|
72
|
+
XYsum = X1*Y2 + X2*Y1
|
|
73
|
+
XZdif = X1*Z2 - X2*Z1
|
|
74
|
+
XZsum = X1*Z2 + X2*Z1
|
|
75
|
+
YZdif = Y1*Z2 - Y2*Z1
|
|
76
|
+
YZsum = Y1*Z2 + Y2*Z1
|
|
77
|
+
|
|
78
|
+
a1sq, a2sq, a3sq, a4sq = (a**2 for a in (a1, a2, a3, a4))
|
|
79
|
+
|
|
80
|
+
X31 = XYdif*YZsum+XZdif*Y1*Y2+a1*X1*X2*YZdif+a1*XYdif*XZsum-a2*X1*X2*XZdif+a3*XYdif*Z1*Z2+a3*XZdif*YZsum-a4*XZsum*XZdif-3*a6*XZdif*Z1*Z2
|
|
81
|
+
|
|
82
|
+
Y31 = -3*X1*X2*XYdif-Y1*Y2*YZdif-2*a1*XZdif*Y1*Y2+(a1sq+3*a2)*X1*X2*YZdif-(a1sq+a2)*XYsum*XZdif+(a1*a2-3*a3)*X1*X2*XZdif-(2*a1*a3+a4)*XYdif*Z1*Z2+a4*XZsum*YZdif+(a1*a4-a2*a3)*XZsum*XZdif+(a3sq+3*a6)*YZdif*Z1*Z2+(3*a1*a6-a3*a4)*XZdif*Z1*Z2
|
|
83
|
+
|
|
84
|
+
Z31 = 3*X1*X2*XZdif-YZsum*YZdif+a1*XYdif*Z1*Z2-a1*XZdif*YZsum+a2*XZsum*XZdif-a3*YZdif*Z1*Z2+a4*XZdif*Z1*Z2
|
|
85
|
+
|
|
86
|
+
yield (X31, Y31, Z31)
|
|
87
|
+
|
|
88
|
+
X32 = Y1*Y2*XYsum+a1*(2*X1*Y2+X2*Y1)*X2*Y1+a1sq*X1*X2**2*Y1-a2*X1*X2*XYsum-a1*a2*X1**2*X2**2+a3*X2*Y1*(YZsum+Y2*Z1)+a1*a3*X1*X2*YZdif-a1*a3*XYsum*XZdif-a4*X1*X2*YZsum-a4*XYsum*XZsum-a1sq*a3*X1**2*X2*Z2-a1*a4*X1*X2*(X1*Z2+XZsum)-a2*a3*X1*X2**2*Z1-a3sq*X1*Z2*(Y2*Z1+YZsum)-3*a6*XYsum*Z1*Z2-3*a6*XZsum*YZsum-a1*a3sq*X1*Z2*(XZsum+X2*Z1)-3*a1*a6*X1*Z2*(XZsum+X2*Z1)-a3*a4*(X1*Z2+XZsum)*X2*Z1-b8*YZsum*Z1*Z2-a1*b8*X1*Z1*Z2**2-a3**3*XZsum*Z1*Z2-3*a3*a6*(XZsum+X2*Z1)*Z1*Z2-a3*b8*Z1**2*Z2**2
|
|
89
|
+
|
|
90
|
+
Y32 = Y1**2*Y2**2+a1*X2*Y1**2*Y2+(a1*a2-3*a3)*X1*X2**2*Y1+a3*Y1**2*Y2*Z2-(a2sq-3*a4)*X1**2*X2**2+(a1*a4-a2*a3)*(2*X1*Z2+X2*Z1)*X2*Y1+(a1sq*a4-2*a1*a2*a3+3*a3sq)*X1**2*X2*Z2-(a2*a4-9*a6)*X1*X2*XZsum+(3*a1*a6-a3*a4)*(XZsum+X2*Z1)*Y1*Z2+(3*a1sq*a6-2*a1*a3*a4+a2*a3sq+3*a2*a6-a4sq)*X1*Z2*(XZsum+X2*Z1)+(3*a2*a6-a4sq)*X2*Z1*(2*X1*Z2+Z1*X2)+(a1**3*a6-a1sq*a3*a4+a1*a2*a3sq-a1*a4sq+4*a1*a2*a6-a3**3-3*a3*a6)*Y1*Z1*Z2**2+(a1**4*a6-a1**3*a3*a4+5*a1sq*a2*a6+a1sq*a2*a3sq-a1*a2*a3*a4-a1*a3**3-3*a1*a3*a6-a1sq*a4sq+a2sq*a3sq-a2*a4sq+4*a2sq*a6-a3**2*a4-3*a4*a6)*X1*Z1*Z2**2+(a1sq*a2*a6-a1*a2*a3*a4+3*a1*a3*a6+a2sq*a3sq-a2*a4sq+4*a2sq*a6-2*a3sq*a4-3*a4*a6)*X2*Z1**2*Z2+(a1**3*a3*a6-a1sq*a3sq*a4+a1sq*a4*a6+a1*a2*a3**3+4*a1*a2*a3*a6-2*a1*a3*a4sq+a2*a3sq*a4+4*a2*a4*a6-a3**4-6*a3**2*a6-a4**3-9*a6**2)*Z1**2*Z2**2
|
|
91
|
+
|
|
92
|
+
Z32 = 3*X1*X2*XYsum+Y1*Y2*YZsum+3*a1*X1**2*X2**2+a1*(2*X1*Y2+Y1*X2)*Y1*Z2+a1sq*X1*Z2*(2*X2*Y1+X1*Y2)+a2*X1*X2*YZsum+a2*XYsum*XZsum+a1**3*X1**2*X2*Z2+a1*a2*X1*X2*(2*X1*Z2+X2*Z1)+3*a3*X1*X2**2*Z1+a3*Y1*Z2*(YZsum+Y2*Z1)+2*a1*a3*X1*Z2*YZsum+2*a1*a3*X2*Y1*Z1*Z2+a4*XYsum*Z1*Z2+a4*XZsum*YZsum+(a1sq*a3+a1*a4)*X1*Z2*(XZsum+X2*Z1)+a2*a3*X2*Z1*(2*X1*Z2+X2*Z1)+a3sq*Y1*Z1*Z2**2+(a3sq+3*a6)*YZsum*Z1*Z2+a1*a3sq*(2*X1*Z2+X2*Z1)*Z1*Z2+3*a1*a6*X1*Z1*Z2**2+a3*a4*(XZsum+X2*Z1)*Z1*Z2+(a3**3+3*a3*a6)*Z1**2*Z2**2
|
|
93
|
+
|
|
94
|
+
yield (X32, Y32, Z32)
|