passagemath-schemes 10.6.38__cp314-cp314t-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.21.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.38.dist-info/METADATA +204 -0
- passagemath_schemes-10.6.38.dist-info/METADATA.bak +205 -0
- passagemath_schemes-10.6.38.dist-info/RECORD +314 -0
- passagemath_schemes-10.6.38.dist-info/WHEEL +6 -0
- passagemath_schemes-10.6.38.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-314t-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-314t-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-314t-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-314t-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-314t-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-314t-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-314t-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-314t-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-314t-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-314t-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-314t-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-314t-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,1102 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-schemes
|
|
2
|
+
"""
|
|
3
|
+
Complex multiplication for elliptic curves
|
|
4
|
+
|
|
5
|
+
This module implements the functions
|
|
6
|
+
|
|
7
|
+
- ``hilbert_class_polynomial``
|
|
8
|
+
- ``is_HCP``
|
|
9
|
+
- ``cm_j_invariants``
|
|
10
|
+
- ``cm_orders``
|
|
11
|
+
- ``discriminants_with_bounded_class_number``
|
|
12
|
+
- ``cm_j_invariants_and_orders``
|
|
13
|
+
- ``largest_fundamental_disc_with_class_number``
|
|
14
|
+
- ``is_cm_j_invariant``
|
|
15
|
+
|
|
16
|
+
AUTHORS:
|
|
17
|
+
|
|
18
|
+
- Robert Bradshaw
|
|
19
|
+
- John Cremona
|
|
20
|
+
- William Stein
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
# ****************************************************************************
|
|
24
|
+
# Copyright (C) 2005-2012 William Stein <wstein@gmail.com>
|
|
25
|
+
#
|
|
26
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
27
|
+
#
|
|
28
|
+
# This code is distributed in the hope that it will be useful,
|
|
29
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
30
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
31
|
+
# General Public License for more details.
|
|
32
|
+
#
|
|
33
|
+
# The full text of the GPL is available at:
|
|
34
|
+
#
|
|
35
|
+
# https://www.gnu.org/licenses/
|
|
36
|
+
# ****************************************************************************
|
|
37
|
+
|
|
38
|
+
from sage.rings.integer import Integer
|
|
39
|
+
from sage.rings.rational_field import QQ
|
|
40
|
+
from sage.rings.integer_ring import ZZ
|
|
41
|
+
from sage.rings.integer_ring import IntegerRing
|
|
42
|
+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
|
|
43
|
+
|
|
44
|
+
from sage.misc.cachefunc import cached_function
|
|
45
|
+
from sage.rings.number_field.number_field_element_base import NumberFieldElement_base
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@cached_function
|
|
49
|
+
def hilbert_class_polynomial(D, algorithm=None):
|
|
50
|
+
r"""
|
|
51
|
+
Return the Hilbert class polynomial for discriminant `D`.
|
|
52
|
+
|
|
53
|
+
INPUT:
|
|
54
|
+
|
|
55
|
+
- ``D`` -- negative integer congruent to 0 or 1 modulo 4
|
|
56
|
+
|
|
57
|
+
- ``algorithm`` -- string (default: ``None``)
|
|
58
|
+
|
|
59
|
+
OUTPUT:
|
|
60
|
+
|
|
61
|
+
(integer polynomial) The Hilbert class polynomial for the
|
|
62
|
+
discriminant `D`.
|
|
63
|
+
|
|
64
|
+
ALGORITHM:
|
|
65
|
+
|
|
66
|
+
- If ``algorithm`` = "arb" (default): Use FLINT's implementation inherited
|
|
67
|
+
from Arb which uses complex interval arithmetic.
|
|
68
|
+
|
|
69
|
+
- If ``algorithm`` = "sage": Use complex approximations to the roots.
|
|
70
|
+
|
|
71
|
+
- If ``algorithm`` = "magma": Call the appropriate Magma function (if available).
|
|
72
|
+
|
|
73
|
+
AUTHORS:
|
|
74
|
+
|
|
75
|
+
- Sage implementation originally by Eduardo Ocampo Alvarez and
|
|
76
|
+
AndreyTimofeev
|
|
77
|
+
|
|
78
|
+
- Sage implementation corrected by John Cremona (using corrected precision bounds from Andreas Enge)
|
|
79
|
+
|
|
80
|
+
- Magma implementation by David Kohel
|
|
81
|
+
|
|
82
|
+
EXAMPLES::
|
|
83
|
+
|
|
84
|
+
sage: # needs sage.libs.flint
|
|
85
|
+
sage: hilbert_class_polynomial(-4)
|
|
86
|
+
x - 1728
|
|
87
|
+
sage: hilbert_class_polynomial(-7)
|
|
88
|
+
x + 3375
|
|
89
|
+
sage: hilbert_class_polynomial(-23)
|
|
90
|
+
x^3 + 3491750*x^2 - 5151296875*x + 12771880859375
|
|
91
|
+
sage: hilbert_class_polynomial(-37*4)
|
|
92
|
+
x^2 - 39660183801072000*x - 7898242515936467904000000
|
|
93
|
+
sage: hilbert_class_polynomial(-37*4, algorithm='magma') # optional - magma
|
|
94
|
+
x^2 - 39660183801072000*x - 7898242515936467904000000
|
|
95
|
+
sage: hilbert_class_polynomial(-163)
|
|
96
|
+
x + 262537412640768000
|
|
97
|
+
sage: hilbert_class_polynomial(-163, algorithm='sage')
|
|
98
|
+
x + 262537412640768000
|
|
99
|
+
sage: hilbert_class_polynomial(-163, algorithm='magma') # optional - magma
|
|
100
|
+
x + 262537412640768000
|
|
101
|
+
|
|
102
|
+
TESTS::
|
|
103
|
+
|
|
104
|
+
sage: all(hilbert_class_polynomial(d, algorithm='arb') ==
|
|
105
|
+
....: hilbert_class_polynomial(d, algorithm='sage')
|
|
106
|
+
....: for d in range(-1,-100,-1) if d % 4 in [0, 1])
|
|
107
|
+
True
|
|
108
|
+
"""
|
|
109
|
+
if algorithm is None:
|
|
110
|
+
algorithm = "arb"
|
|
111
|
+
|
|
112
|
+
D = Integer(D)
|
|
113
|
+
if D >= 0:
|
|
114
|
+
raise ValueError("D (=%s) must be negative" % D)
|
|
115
|
+
if (D % 4) not in [0, 1]:
|
|
116
|
+
raise ValueError("D (=%s) must be a discriminant" % D)
|
|
117
|
+
|
|
118
|
+
if algorithm == "arb":
|
|
119
|
+
import sage.libs.arb.arith
|
|
120
|
+
return sage.libs.arb.arith.hilbert_class_polynomial(D)
|
|
121
|
+
|
|
122
|
+
if algorithm == "magma":
|
|
123
|
+
from sage.interfaces.magma import magma
|
|
124
|
+
magma.eval("R<x> := PolynomialRing(IntegerRing())")
|
|
125
|
+
f = str(magma.eval("HilbertClassPolynomial(%s)" % D))
|
|
126
|
+
return IntegerRing()['x'](f)
|
|
127
|
+
|
|
128
|
+
if algorithm != "sage":
|
|
129
|
+
raise ValueError("%s is not a valid algorithm" % algorithm)
|
|
130
|
+
|
|
131
|
+
from sage.quadratic_forms.binary_qf import BinaryQF_reduced_representatives
|
|
132
|
+
from sage.rings.real_mpfr import RR
|
|
133
|
+
from sage.rings.complex_mpfr import ComplexField
|
|
134
|
+
from sage.functions.all import elliptic_j
|
|
135
|
+
|
|
136
|
+
# get all primitive reduced quadratic forms, (necessary to exclude
|
|
137
|
+
# imprimitive forms when D is not a fundamental discriminant):
|
|
138
|
+
|
|
139
|
+
rqf = BinaryQF_reduced_representatives(D, primitive_only=True)
|
|
140
|
+
|
|
141
|
+
# compute needed precision
|
|
142
|
+
#
|
|
143
|
+
# NB: [https://arxiv.org/abs/0802.0979v1], quoting Enge (2006), is
|
|
144
|
+
# incorrect. Enge writes (2009-04-20 email to John Cremona) "The
|
|
145
|
+
# source is my paper on class polynomials
|
|
146
|
+
# [https://hal.inria.fr/inria-00001040] It was pointed out to me by
|
|
147
|
+
# the referee after ANTS that the constant given there was
|
|
148
|
+
# wrong. The final version contains a corrected constant on p.7
|
|
149
|
+
# which is consistent with your example. It says:
|
|
150
|
+
|
|
151
|
+
# "The logarithm of the absolute value of the coefficient in front
|
|
152
|
+
# of X^j is bounded above by
|
|
153
|
+
#
|
|
154
|
+
# log (2*k_2) * h + pi * sqrt(|D|) * sum (1/A_i)
|
|
155
|
+
#
|
|
156
|
+
# independently of j", where k_2 \approx 10.163.
|
|
157
|
+
|
|
158
|
+
h = len(rqf) # class number
|
|
159
|
+
c1 = 3.05682737291380 # log(2*10.63)
|
|
160
|
+
c2 = sum([1/RR(qf[0]) for qf in rqf], RR(0))
|
|
161
|
+
prec = c2 * RR(3.142) * RR(D).abs().sqrt() + h * c1 # bound on log
|
|
162
|
+
prec = prec * 1.45 # bound on log_2 (1/log(2) = 1.44..)
|
|
163
|
+
prec = 10 + prec.ceil() # allow for rounding error
|
|
164
|
+
|
|
165
|
+
# set appropriate precision for further computing
|
|
166
|
+
|
|
167
|
+
Dsqrt = D.sqrt(prec=prec)
|
|
168
|
+
R = ComplexField(prec)['t']
|
|
169
|
+
t = R.gen()
|
|
170
|
+
pol = R(1)
|
|
171
|
+
for qf in rqf:
|
|
172
|
+
a, b, c = list(qf)
|
|
173
|
+
tau = (b + Dsqrt) / (a << 1)
|
|
174
|
+
pol *= (t - elliptic_j(tau))
|
|
175
|
+
|
|
176
|
+
coeffs = [cof.real().round() for cof in pol.coefficients(sparse=False)]
|
|
177
|
+
return IntegerRing()['x'](coeffs)
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def is_HCP(f, check_monic_irreducible=True):
|
|
181
|
+
r"""
|
|
182
|
+
Determine whether a polynomial is a Hilbert Class Polynomial.
|
|
183
|
+
|
|
184
|
+
INPUT:
|
|
185
|
+
|
|
186
|
+
- ``f`` -- a polynomial in `\ZZ[X]`
|
|
187
|
+
- ``check_monic_irreducible`` -- boolean (default: ``True``); if ``True``,
|
|
188
|
+
check that ``f`` is a monic, irreducible, integer polynomial
|
|
189
|
+
|
|
190
|
+
OUTPUT:
|
|
191
|
+
|
|
192
|
+
(integer) -- either `D` if ``f`` is the Hilbert Class Polynomial
|
|
193
|
+
`H_D` for discriminant `D`, or `0` if not an HCP.
|
|
194
|
+
|
|
195
|
+
ALGORITHM:
|
|
196
|
+
|
|
197
|
+
Cremona and Sutherland: Algorithm 2 of [CreSuth2023]_.
|
|
198
|
+
|
|
199
|
+
EXAMPLES:
|
|
200
|
+
|
|
201
|
+
Even for large degrees this is fast. We test the largest
|
|
202
|
+
discriminant of class number 100, for which the HCP has coefficients
|
|
203
|
+
with thousands of digits::
|
|
204
|
+
|
|
205
|
+
sage: from sage.schemes.elliptic_curves.cm import is_HCP
|
|
206
|
+
sage: D = -1856563
|
|
207
|
+
sage: D.class_number() # needs sage.libs.pari
|
|
208
|
+
100
|
|
209
|
+
|
|
210
|
+
sage: # needs sage.libs.flint
|
|
211
|
+
sage: H = hilbert_class_polynomial(D)
|
|
212
|
+
sage: H.degree()
|
|
213
|
+
100
|
|
214
|
+
sage: max(H).ndigits()
|
|
215
|
+
2774
|
|
216
|
+
sage: is_HCP(H)
|
|
217
|
+
-1856563
|
|
218
|
+
|
|
219
|
+
Testing polynomials which are not HCPs is faster::
|
|
220
|
+
|
|
221
|
+
sage: is_HCP(H+1) # needs sage.libs.flint
|
|
222
|
+
0
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
TESTS::
|
|
226
|
+
|
|
227
|
+
sage: # needs sage.libs.flint
|
|
228
|
+
sage: from sage.schemes.elliptic_curves.cm import is_HCP
|
|
229
|
+
sage: all(is_HCP(hilbert_class_polynomial(D)) == D
|
|
230
|
+
....: for D in srange(-4,-100,-1) if D.is_discriminant())
|
|
231
|
+
True
|
|
232
|
+
sage: all(not is_HCP(hilbert_class_polynomial(D) + 1)
|
|
233
|
+
....: for D in srange(-4,-100,-1) if D.is_discriminant())
|
|
234
|
+
True
|
|
235
|
+
|
|
236
|
+
Ensure that :issue:`37471` is fixed::
|
|
237
|
+
|
|
238
|
+
sage: from sage.schemes.elliptic_curves.cm import is_HCP
|
|
239
|
+
sage: set_random_seed(297388353221545796156853787333338705098)
|
|
240
|
+
sage: is_HCP(hilbert_class_polynomial(-55))
|
|
241
|
+
-55
|
|
242
|
+
"""
|
|
243
|
+
zero = ZZ(0)
|
|
244
|
+
# optional check that input is monic and irreducible
|
|
245
|
+
if check_monic_irreducible:
|
|
246
|
+
try:
|
|
247
|
+
if not (all(c in ZZ for c in f) and f.is_monic()):
|
|
248
|
+
return zero
|
|
249
|
+
f = f.change_ring(ZZ)
|
|
250
|
+
except AttributeError:
|
|
251
|
+
return zero
|
|
252
|
+
|
|
253
|
+
from sage.rings.real_mpfr import RR
|
|
254
|
+
from sage.rings.finite_rings.finite_field_constructor import GF
|
|
255
|
+
|
|
256
|
+
h = f.degree()
|
|
257
|
+
h2list = [d for d in h.divisors()
|
|
258
|
+
if (d-h) % 2 == 0 and d.prime_to_m_part(2) == 1]
|
|
259
|
+
pmin = 33 * (h**2 * (RR(h+2).log().log()+2)**2).ceil()
|
|
260
|
+
# Guarantees 4*p > |D| for fundamental D under GRH
|
|
261
|
+
p = pmin-1
|
|
262
|
+
n = 0
|
|
263
|
+
from sage.arith.misc import next_prime
|
|
264
|
+
from sage.schemes.elliptic_curves.constructor import EllipticCurve
|
|
265
|
+
|
|
266
|
+
while True:
|
|
267
|
+
p = next_prime(p)
|
|
268
|
+
n += 1
|
|
269
|
+
fp = f.change_ring(GF(p))
|
|
270
|
+
# Compute X^p-X mod fp
|
|
271
|
+
z = fp.parent().gen()
|
|
272
|
+
r = pow(z, p, fp) - z
|
|
273
|
+
r = r.gcd(fp)
|
|
274
|
+
d = r.degree() # number of roots mod p
|
|
275
|
+
if d == 0:
|
|
276
|
+
continue
|
|
277
|
+
if not r.is_squarefree():
|
|
278
|
+
continue
|
|
279
|
+
if d < h and d not in h2list:
|
|
280
|
+
return zero
|
|
281
|
+
jp = r.any_root(degree=1, assume_squarefree=True, assume_equal_deg=True)
|
|
282
|
+
E = EllipticCurve(j=jp)
|
|
283
|
+
if E.is_supersingular():
|
|
284
|
+
continue
|
|
285
|
+
try:
|
|
286
|
+
D = E.endomorphism_discriminant_from_class_number(h)
|
|
287
|
+
except ValueError:
|
|
288
|
+
return zero
|
|
289
|
+
return D if f == hilbert_class_polynomial(D) else zero
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
def OrderClassNumber(D0, h0, f):
|
|
293
|
+
r"""
|
|
294
|
+
Return the class number h(f**2 * D0), given h(D0)=h0.
|
|
295
|
+
|
|
296
|
+
INPUT:
|
|
297
|
+
|
|
298
|
+
- ``D0`` -- integer; a negative fundamental discriminant
|
|
299
|
+
- ``h0`` -- integer; the class number of the (maximal) imaginary quadratic order of discriminant ``D0``
|
|
300
|
+
- ``f`` -- positive integer
|
|
301
|
+
|
|
302
|
+
OUTPUT:
|
|
303
|
+
|
|
304
|
+
(integer) the class number of the imaginary quadratic order of discriminant ``D0*f**2``
|
|
305
|
+
|
|
306
|
+
ALGORITHM:
|
|
307
|
+
|
|
308
|
+
We use the formula for the class number of the order `\mathcal{O}_{D}` in terms of the class number of the
|
|
309
|
+
maximal order `\mathcal{O}_{D_0}`; see [Cox1989]_ Theorem 7.24:
|
|
310
|
+
|
|
311
|
+
.. MATH::
|
|
312
|
+
|
|
313
|
+
h(D) = \frac{h(D_0)f}{[\mathcal{O}_{D_0}^\times:\mathcal{O}_{D}^\times]}\prod_{p\,|\,f}\left(1-\left(\frac{D_0}{p}\right)\frac{1}{p}\right)
|
|
314
|
+
|
|
315
|
+
EXAMPLES::
|
|
316
|
+
|
|
317
|
+
sage: # needs sage.libs.pari
|
|
318
|
+
sage: from sage.schemes.elliptic_curves.cm import OrderClassNumber
|
|
319
|
+
sage: D0 = -4
|
|
320
|
+
sage: h = D0.class_number()
|
|
321
|
+
sage: [OrderClassNumber(D0,h,f) for f in srange(1,20)]
|
|
322
|
+
[1, 1, 2, 2, 2, 4, 4, 4, 6, 4, 6, 8, 6, 8, 8, 8, 8, 12, 10]
|
|
323
|
+
sage: all([OrderClassNumber(D0,h,f) == (D0*f**2).class_number() for f in srange(1,20)])
|
|
324
|
+
True
|
|
325
|
+
"""
|
|
326
|
+
if not D0.is_fundamental_discriminant():
|
|
327
|
+
raise ValueError("{} is not a fundamental discriminant".format(D0))
|
|
328
|
+
if f <= 0:
|
|
329
|
+
raise ValueError("{} is not a positive integer".format(f))
|
|
330
|
+
if f == 1:
|
|
331
|
+
return h0
|
|
332
|
+
ps = f.prime_divisors()
|
|
333
|
+
from sage.misc.misc_c import prod
|
|
334
|
+
from sage.arith.misc import kronecker as kronecker_symbol
|
|
335
|
+
n = (f // prod(ps)) * prod(p - kronecker_symbol(D0, p) for p in ps)
|
|
336
|
+
if D0 == -3:
|
|
337
|
+
# assert h0 == 1 and n % 3 == 0
|
|
338
|
+
return n // 3
|
|
339
|
+
if D0 == -4:
|
|
340
|
+
# assert h0 == 1 and n % 2 == 0
|
|
341
|
+
return n // 2
|
|
342
|
+
return n * h0
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
@cached_function
|
|
346
|
+
def cm_j_invariants(K, proof=None):
|
|
347
|
+
r"""
|
|
348
|
+
Return a list of all CM `j`-invariants in the field `K`.
|
|
349
|
+
|
|
350
|
+
INPUT:
|
|
351
|
+
|
|
352
|
+
- ``K`` -- a number field
|
|
353
|
+
- ``proof`` -- (default: proof.number_field())
|
|
354
|
+
|
|
355
|
+
OUTPUT:
|
|
356
|
+
|
|
357
|
+
(list) -- A list of CM `j`-invariants in the field `K`.
|
|
358
|
+
|
|
359
|
+
EXAMPLES::
|
|
360
|
+
|
|
361
|
+
sage: cm_j_invariants(QQ)
|
|
362
|
+
[-262537412640768000, -147197952000, -884736000, -12288000, -884736,
|
|
363
|
+
-32768, -3375, 0, 1728, 8000, 54000, 287496, 16581375]
|
|
364
|
+
|
|
365
|
+
Over imaginary quadratic fields there are no more than over `QQ`::
|
|
366
|
+
|
|
367
|
+
sage: cm_j_invariants(QuadraticField(-1, 'i')) # needs sage.rings.number_field
|
|
368
|
+
[-262537412640768000, -147197952000, -884736000, -12288000, -884736,
|
|
369
|
+
-32768, -3375, 0, 1728, 8000, 54000, 287496, 16581375]
|
|
370
|
+
|
|
371
|
+
Over real quadratic fields there may be more, for example::
|
|
372
|
+
|
|
373
|
+
sage: len(cm_j_invariants(QuadraticField(5, 'a'))) # needs sage.rings.number_field
|
|
374
|
+
31
|
|
375
|
+
|
|
376
|
+
Over number fields K of many higher degrees this also works::
|
|
377
|
+
|
|
378
|
+
sage: # needs sage.rings.number_field
|
|
379
|
+
sage: x = polygen(ZZ, 'x')
|
|
380
|
+
sage: K.<a> = NumberField(x^3 - 2)
|
|
381
|
+
sage: cm_j_invariants(K)
|
|
382
|
+
[-262537412640768000, -147197952000, -884736000, -884736, -32768,
|
|
383
|
+
8000, -3375, 16581375, 1728, 287496, 0, 54000, -12288000,
|
|
384
|
+
31710790944000*a^2 + 39953093016000*a + 50337742902000]
|
|
385
|
+
sage: K.<a> = NumberField(x^4 - 2)
|
|
386
|
+
sage: len(cm_j_invariants(K))
|
|
387
|
+
23
|
|
388
|
+
"""
|
|
389
|
+
return sorted(j for D, f, j in cm_j_invariants_and_orders(K, proof=proof))
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
@cached_function
|
|
393
|
+
def cm_j_invariants_and_orders(K, proof=None):
|
|
394
|
+
r"""
|
|
395
|
+
Return a list of all CM `j`-invariants in the field `K`, together with the associated orders.
|
|
396
|
+
|
|
397
|
+
INPUT:
|
|
398
|
+
|
|
399
|
+
- ``K`` -- a number field
|
|
400
|
+
- ``proof`` -- (default: proof.number_field())
|
|
401
|
+
|
|
402
|
+
OUTPUT:
|
|
403
|
+
|
|
404
|
+
A list of 3-tuples `(D,f,j)` where `j` is a CM `j`-invariant in `K` with
|
|
405
|
+
quadratic fundamental discriminant `D` and conductor `f`.
|
|
406
|
+
|
|
407
|
+
EXAMPLES::
|
|
408
|
+
|
|
409
|
+
sage: cm_j_invariants_and_orders(QQ)
|
|
410
|
+
[(-3, 3, -12288000), (-3, 2, 54000), (-3, 1, 0), (-4, 2, 287496), (-4, 1, 1728),
|
|
411
|
+
(-7, 2, 16581375), (-7, 1, -3375), (-8, 1, 8000), (-11, 1, -32768),
|
|
412
|
+
(-19, 1, -884736), (-43, 1, -884736000), (-67, 1, -147197952000),
|
|
413
|
+
(-163, 1, -262537412640768000)]
|
|
414
|
+
|
|
415
|
+
Over an imaginary quadratic field there are no more than over `QQ`::
|
|
416
|
+
|
|
417
|
+
sage: cm_j_invariants_and_orders(QuadraticField(-1, 'i')) # needs sage.rings.number_field
|
|
418
|
+
[(-163, 1, -262537412640768000), (-67, 1, -147197952000),
|
|
419
|
+
(-43, 1, -884736000), (-19, 1, -884736), (-11, 1, -32768),
|
|
420
|
+
(-8, 1, 8000), (-7, 1, -3375), (-7, 2, 16581375), (-4, 1, 1728),
|
|
421
|
+
(-4, 2, 287496), (-3, 1, 0), (-3, 2, 54000), (-3, 3, -12288000)]
|
|
422
|
+
|
|
423
|
+
Over real quadratic fields there may be more::
|
|
424
|
+
|
|
425
|
+
sage: v = cm_j_invariants_and_orders(QuadraticField(5,'a')); len(v) # needs sage.rings.number_field
|
|
426
|
+
31
|
|
427
|
+
sage: [(D, f) for D, f, j in v if j not in QQ] # needs sage.rings.number_field
|
|
428
|
+
[(-235, 1), (-235, 1), (-115, 1), (-115, 1), (-40, 1), (-40, 1),
|
|
429
|
+
(-35, 1), (-35, 1), (-20, 1), (-20, 1), (-15, 1), (-15, 1), (-15, 2),
|
|
430
|
+
(-15, 2), (-4, 5), (-4, 5), (-3, 5), (-3, 5)]
|
|
431
|
+
|
|
432
|
+
Over number fields K of many higher degrees this also works::
|
|
433
|
+
|
|
434
|
+
sage: x = polygen(ZZ, 'x')
|
|
435
|
+
sage: K.<a> = NumberField(x^3 - 2) # needs sage.rings.number_field
|
|
436
|
+
sage: cm_j_invariants_and_orders(K) # needs sage.rings.number_field
|
|
437
|
+
[(-163, 1, -262537412640768000), (-67, 1, -147197952000),
|
|
438
|
+
(-43, 1, -884736000), (-19, 1, -884736), (-11, 1, -32768),
|
|
439
|
+
(-8, 1, 8000), (-7, 1, -3375), (-7, 2, 16581375), (-4, 1, 1728),
|
|
440
|
+
(-4, 2, 287496), (-3, 1, 0), (-3, 2, 54000), (-3, 3, -12288000),
|
|
441
|
+
(-3, 6, 31710790944000*a^2 + 39953093016000*a + 50337742902000)]
|
|
442
|
+
"""
|
|
443
|
+
if K == QQ:
|
|
444
|
+
return [(ZZ(d), ZZ(f), ZZ(j)) for d, f, j in [
|
|
445
|
+
(-3, 3, -12288000),
|
|
446
|
+
(-3, 2, 54000),
|
|
447
|
+
(-3, 1, 0),
|
|
448
|
+
(-4, 2, 287496),
|
|
449
|
+
(-4, 1, 1728),
|
|
450
|
+
(-7, 2, 16581375),
|
|
451
|
+
(-7, 1, -3375),
|
|
452
|
+
(-8, 1, 8000),
|
|
453
|
+
(-11, 1, -32768),
|
|
454
|
+
(-19, 1, -884736),
|
|
455
|
+
(-43, 1, -884736000),
|
|
456
|
+
(-67, 1, -147197952000),
|
|
457
|
+
(-163, 1, -262537412640768000)]]
|
|
458
|
+
|
|
459
|
+
# Get the list of CM orders that could possibly have Hilbert class
|
|
460
|
+
# polynomial F(x) with a root in K. If F(x) has a root alpha in K,
|
|
461
|
+
# then F is the minimal polynomial of alpha in K, so the degree of
|
|
462
|
+
# F(x) divides [K:QQ].
|
|
463
|
+
n = K.absolute_degree()
|
|
464
|
+
T = discriminants_with_bounded_class_number(n, proof=proof)
|
|
465
|
+
dlist = sorted(sum((Dflist for h,Dflist in T.items() if h.divides(n)), []))
|
|
466
|
+
|
|
467
|
+
return [(D, f, j) for D, f in dlist
|
|
468
|
+
for j in hilbert_class_polynomial(D*f*f).roots(K, multiplicities=False)]
|
|
469
|
+
|
|
470
|
+
|
|
471
|
+
@cached_function
|
|
472
|
+
def cm_orders(h, proof=None):
|
|
473
|
+
"""
|
|
474
|
+
Return a list of all pairs `(D,f)` where there is a CM order of
|
|
475
|
+
discriminant `D f^2` with class number h, with `D` a fundamental
|
|
476
|
+
discriminant.
|
|
477
|
+
|
|
478
|
+
INPUT:
|
|
479
|
+
|
|
480
|
+
- ``h`` -- positive integer
|
|
481
|
+
- ``proof`` -- (default: proof.number_field())
|
|
482
|
+
|
|
483
|
+
OUTPUT: list of 2-tuples `(D,f)` sorted lexicographically by `(|D|, f)`
|
|
484
|
+
|
|
485
|
+
EXAMPLES::
|
|
486
|
+
|
|
487
|
+
sage: cm_orders(0)
|
|
488
|
+
[]
|
|
489
|
+
sage: v = cm_orders(1); v
|
|
490
|
+
[(-3, 1), (-3, 2), (-3, 3), (-4, 1), (-4, 2), (-7, 1), (-7, 2), (-8, 1),
|
|
491
|
+
(-11, 1), (-19, 1), (-43, 1), (-67, 1), (-163, 1)]
|
|
492
|
+
sage: type(v[0][0]), type(v[0][1])
|
|
493
|
+
(<... 'sage.rings.integer.Integer'>, <... 'sage.rings.integer.Integer'>)
|
|
494
|
+
sage: # needs sage.libs.pari
|
|
495
|
+
sage: v = cm_orders(2); v
|
|
496
|
+
[(-3, 4), (-3, 5), (-3, 7), (-4, 3), (-4, 4), (-4, 5), (-7, 4), (-8, 2),
|
|
497
|
+
(-8, 3), (-11, 3), (-15, 1), (-15, 2), (-20, 1), (-24, 1), (-35, 1),
|
|
498
|
+
(-40, 1), (-51, 1), (-52, 1), (-88, 1), (-91, 1), (-115, 1), (-123, 1),
|
|
499
|
+
(-148, 1), (-187, 1), (-232, 1), (-235, 1), (-267, 1), (-403, 1), (-427, 1)]
|
|
500
|
+
sage: len(v)
|
|
501
|
+
29
|
|
502
|
+
sage: set([hilbert_class_polynomial(D*f^2).degree() for D,f in v])
|
|
503
|
+
{2}
|
|
504
|
+
|
|
505
|
+
Any degree up to 100 is implemented, but may be slow::
|
|
506
|
+
|
|
507
|
+
sage: # needs sage.libs.pari
|
|
508
|
+
sage: cm_orders(3)
|
|
509
|
+
[(-3, 6), (-3, 9), (-11, 2), (-19, 2), (-23, 1), (-23, 2), (-31, 1), (-31, 2),
|
|
510
|
+
(-43, 2), (-59, 1), (-67, 2), (-83, 1), (-107, 1), (-139, 1), (-163, 2),
|
|
511
|
+
(-211, 1), (-283, 1), (-307, 1), (-331, 1), (-379, 1), (-499, 1), (-547, 1),
|
|
512
|
+
(-643, 1), (-883, 1), (-907, 1)]
|
|
513
|
+
sage: len(cm_orders(4))
|
|
514
|
+
84
|
|
515
|
+
"""
|
|
516
|
+
h = Integer(h)
|
|
517
|
+
if h <= 0:
|
|
518
|
+
# trivial case
|
|
519
|
+
return []
|
|
520
|
+
|
|
521
|
+
if h in hDf_dict:
|
|
522
|
+
return hDf_dict[h]
|
|
523
|
+
else: # Get all discriminants for all class numbers up to h (which will
|
|
524
|
+
# be stored in hDf_dict), and return just those with class number h.
|
|
525
|
+
return discriminants_with_bounded_class_number(h, proof=proof)[h]
|
|
526
|
+
|
|
527
|
+
# Table from Mark Watkins paper "Class numbers of imaginary quadratic fields".
|
|
528
|
+
|
|
529
|
+
# WAS extracted this by cutting/pasting from the pdf, and running this program:
|
|
530
|
+
# z = {}
|
|
531
|
+
# for X in open('/Users/wstein/tmp/a.txt').readlines():
|
|
532
|
+
# if len(X.strip()):
|
|
533
|
+
# v = [int(a) for a in X.split()]
|
|
534
|
+
# for i in range(5):
|
|
535
|
+
# z[v[3*i]]=(v[3*i+2], v[3*i+1])
|
|
536
|
+
|
|
537
|
+
# The keys are integers 1--100 and the value for each h is (|D|,n)
|
|
538
|
+
# where |D| is the largest absolute discriminant of an imaginary
|
|
539
|
+
# quadratic field with class number h, and n is the number of such
|
|
540
|
+
# fields. These are all *unconditional* (not dependent on GRH).
|
|
541
|
+
|
|
542
|
+
|
|
543
|
+
watkins_table = {1: (163, 9), 2: (427, 18), 3: (907, 16), 4: (1555, 54), 5: (2683, 25),
|
|
544
|
+
6: (3763, 51), 7: (5923, 31), 8: (6307, 131), 9: (10627, 34), 10:
|
|
545
|
+
(13843, 87), 11: (15667, 41), 12: (17803, 206), 13: (20563, 37), 14:
|
|
546
|
+
(30067, 95), 15: (34483, 68), 16: (31243, 322), 17: (37123, 45), 18:
|
|
547
|
+
(48427, 150), 19: (38707, 47), 20: (58507, 350), 21: (61483, 85), 22:
|
|
548
|
+
(85507, 139), 23: (90787, 68), 24: (111763, 511), 25: (93307, 95), 26:
|
|
549
|
+
(103027, 190), 27: (103387, 93), 28: (126043, 457), 29: (166147, 83),
|
|
550
|
+
30: (134467, 255), 31: (133387, 73), 32: (164803, 708), 33: (222643, 101),
|
|
551
|
+
34: (189883, 219), 35: (210907, 103), 36: (217627, 668), 37:
|
|
552
|
+
(158923, 85), 38: (289963, 237), 39: (253507, 115), 40: (260947, 912),
|
|
553
|
+
41: (296587, 109), 42: (280267, 339), 43: (300787, 106), 44: (319867, 691),
|
|
554
|
+
45: (308323, 154), 46: (462883, 268), 47: (375523, 107), 48:
|
|
555
|
+
(335203, 1365), 49: (393187, 132), 50: (389467, 345), 51: (546067, 159),
|
|
556
|
+
52: (439147, 770), 53: (425107, 114), 54: (532123, 427), 55: (452083,163),
|
|
557
|
+
56: (494323, 1205), 57: (615883, 179), 58: (586987, 291),
|
|
558
|
+
59:(474307, 128), 60: (662803, 1302), 61: (606643, 132), 62: (647707, 323),
|
|
559
|
+
63: (991027, 216), 64: (693067, 1672), 65: (703123, 164), 66: (958483, 530),
|
|
560
|
+
67: (652723, 120), 68: (819163, 976), 69: (888427, 209), 70:(811507, 560),
|
|
561
|
+
71: (909547, 150), 72: (947923, 1930), 73: (886867, 119),
|
|
562
|
+
74: (951043, 407), 75: (916507, 237), 76: (1086187, 1075), 77: (1242763, 216),
|
|
563
|
+
78: (1004347, 561), 79: (1333963, 175), 80: (1165483, 2277), 81: (1030723, 228),
|
|
564
|
+
82: (1446547, 402), 83: (1074907, 150), 84: (1225387,1715),
|
|
565
|
+
85: (1285747, 221), 86: (1534723, 472), 87: (1261747, 222),
|
|
566
|
+
88:(1265587, 1905), 89: (1429387, 192), 90: (1548523, 801),
|
|
567
|
+
91: (1391083,214), 92: (1452067, 1248), 93: (1475203, 262), 94: (1587763, 509),
|
|
568
|
+
95:(1659067, 241), 96: (1684027, 3283), 97: (1842523, 185), 98: (2383747,580),
|
|
569
|
+
99: (1480627, 289), 100: (1856563, 1736)}
|
|
570
|
+
|
|
571
|
+
# Table from Janis Klaise [Klaise2012]_
|
|
572
|
+
|
|
573
|
+
# Extracted by converting pdf to text via pdf2ps and ps2txt, cutting/pasting
|
|
574
|
+
# and running this code:
|
|
575
|
+
|
|
576
|
+
# klaise_table = {}
|
|
577
|
+
# for X in open('klaise_table.txt').readlines():
|
|
578
|
+
# if len(X.strip()):
|
|
579
|
+
# v = [int(a) for a in X.split()]
|
|
580
|
+
# for i in range(4):
|
|
581
|
+
# klaise_table[v[3*i]]=(v[3*i+2], v[3*i+1])
|
|
582
|
+
|
|
583
|
+
# The keys are integers 1--100 and the value for each h is (|D|,n)
|
|
584
|
+
# where |D| is the largest discriminant of an imaginary quadratic
|
|
585
|
+
# order with class number h, and n is the number of such orders.
|
|
586
|
+
# These are all *unconditional* (not dependent on GRH).
|
|
587
|
+
|
|
588
|
+
klaise_table = {1: (163, 13), 2: (427, 29), 3: (907, 25), 4: (1555, 84), 5: (2683, 29), 6: (4075, 101),
|
|
589
|
+
7: (5923, 38), 8: (7987, 208), 9: (10627, 55), 10: (13843, 123), 11: (15667, 46),
|
|
590
|
+
12: (19723, 379), 13: (20563, 43), 14: (30067, 134), 15: (34483, 95), 16: (35275, 531),
|
|
591
|
+
17: (37123, 50), 18: (48427, 291), 19: (38707, 59), 20: (58843, 502), 21: (61483, 118),
|
|
592
|
+
22: (85507, 184), 23: (90787, 78), 24: (111763, 1042), 25: (93307, 101), 26: (103027, 227),
|
|
593
|
+
27: (103387, 136), 28: (126043, 623), 29: (166147, 94), 30: (137083, 473), 31: (133387, 83),
|
|
594
|
+
32: (164803, 1231), 33: (222643, 158), 34: (189883, 262), 35: (210907, 111), 36: (217627, 1306),
|
|
595
|
+
37: (158923, 96), 38: (289963, 284), 39: (253507, 162), 40: (274003, 1418), 41: (296587, 125),
|
|
596
|
+
42: (301387, 596), 43: (300787, 123), 44: (319867, 911), 45: (308323, 231), 46: (462883, 330),
|
|
597
|
+
47: (375523, 117), 48: (335203, 2895), 49: (393187, 146), 50: (389467, 445), 51: (546067, 217),
|
|
598
|
+
52: (457867, 1006), 53: (425107, 130), 54: (532123, 812), 55: (452083, 177), 56: (494323, 1812),
|
|
599
|
+
57: (615883, 237), 58: (586987, 361), 59: (474307, 144), 60: (662803, 2361), 61: (606643, 149),
|
|
600
|
+
62: (647707, 386), 63: (991027, 311), 64: (693067, 2919), 65: (703123, 192), 66: (958483, 861),
|
|
601
|
+
67: (652723, 145), 68: (819163, 1228), 69: (888427, 292), 70: (821683, 704), 71: (909547, 176),
|
|
602
|
+
72: (947923, 4059), 73: (886867, 137), 74: (951043, 474), 75: (916507, 353), 76: (1086187, 1384),
|
|
603
|
+
77: (1242763, 236), 78: (1004347, 925), 79: (1333963, 200), 80: (1165483, 3856), 81: (1030723, 339),
|
|
604
|
+
82: (1446547, 487), 83: (1074907, 174), 84: (1225387, 2998), 85: (1285747, 246), 86: (1534723, 555),
|
|
605
|
+
87: (1261747, 313), 88: (1265587, 2771), 89: (1429387, 206), 90: (1548523, 1516), 91: (1391083, 249),
|
|
606
|
+
92: (1452067, 1591), 93: (1475203, 354), 94: (1587763, 600), 95: (1659067, 273), 96: (1684027, 7276),
|
|
607
|
+
97: (1842523, 208), 98: (2383747, 710), 99: (1480627, 396), 100: (1856563, 2311)}
|
|
608
|
+
|
|
609
|
+
|
|
610
|
+
def largest_fundamental_disc_with_class_number(h):
|
|
611
|
+
r"""
|
|
612
|
+
Return largest absolute value of any fundamental negative discriminant with
|
|
613
|
+
class number `h`, and the number of fundamental negative discriminants with
|
|
614
|
+
that class number. This is known (unconditionally) for `h` up to 100,
|
|
615
|
+
by work of Mark Watkins ([Watkins2004]_).
|
|
616
|
+
|
|
617
|
+
.. NOTE::
|
|
618
|
+
|
|
619
|
+
The class number of a fundamental negative discriminant `D` is
|
|
620
|
+
the same as the class number of the imaginary quadratic field
|
|
621
|
+
`\QQ(\sqrt{D})`, so this function gives the number of such
|
|
622
|
+
fields of each class number `h\le100`. It is easy to extend
|
|
623
|
+
this to larger class number conditional on the GRH, but much
|
|
624
|
+
harder to obtain unconditional results.
|
|
625
|
+
|
|
626
|
+
INPUT:
|
|
627
|
+
|
|
628
|
+
- ``h`` -- integer
|
|
629
|
+
|
|
630
|
+
EXAMPLES::
|
|
631
|
+
|
|
632
|
+
sage: from sage.schemes.elliptic_curves.cm import largest_fundamental_disc_with_class_number
|
|
633
|
+
sage: largest_fundamental_disc_with_class_number(0)
|
|
634
|
+
(0, 0)
|
|
635
|
+
sage: largest_fundamental_disc_with_class_number(1)
|
|
636
|
+
(163, 9)
|
|
637
|
+
sage: largest_fundamental_disc_with_class_number(2)
|
|
638
|
+
(427, 18)
|
|
639
|
+
sage: largest_fundamental_disc_with_class_number(10)
|
|
640
|
+
(13843, 87)
|
|
641
|
+
sage: largest_fundamental_disc_with_class_number(100)
|
|
642
|
+
(1856563, 1736)
|
|
643
|
+
sage: largest_fundamental_disc_with_class_number(101)
|
|
644
|
+
Traceback (most recent call last):
|
|
645
|
+
...
|
|
646
|
+
NotImplementedError: largest fundamental discriminant not available for class number 101
|
|
647
|
+
"""
|
|
648
|
+
h = Integer(h)
|
|
649
|
+
if h <= 0:
|
|
650
|
+
return Integer(0), Integer(0)
|
|
651
|
+
try:
|
|
652
|
+
B, c = watkins_table[h]
|
|
653
|
+
return (Integer(B), Integer(c))
|
|
654
|
+
except KeyError:
|
|
655
|
+
raise NotImplementedError("largest fundamental discriminant not available for class number %s" % h)
|
|
656
|
+
|
|
657
|
+
|
|
658
|
+
def largest_disc_with_class_number(h):
|
|
659
|
+
r"""
|
|
660
|
+
Return largest absolute value of any negative discriminant with
|
|
661
|
+
class number `h`, and the number of fundamental negative
|
|
662
|
+
discriminants with that class number. This is known
|
|
663
|
+
(unconditionally) for `h` up to 100, by work of Mark Watkins
|
|
664
|
+
[Watkins2004]_ for fundamental discriminants, extended to all
|
|
665
|
+
discriminants of class number `h\le100` by Klaise [Klaise2012]_.
|
|
666
|
+
|
|
667
|
+
.. NOTE::
|
|
668
|
+
|
|
669
|
+
The class number of a negative discriminant `D` is
|
|
670
|
+
the same as the class number of the unique imaginary quadratic order
|
|
671
|
+
of discriminant `D`, so this function gives the number of such
|
|
672
|
+
orders of each class number `h\le100`. It is easy to extend
|
|
673
|
+
this to larger class number conditional on the GRH, but much
|
|
674
|
+
harder to obyain unconditional results.
|
|
675
|
+
|
|
676
|
+
INPUT:
|
|
677
|
+
|
|
678
|
+
- ``h`` -- integer
|
|
679
|
+
|
|
680
|
+
EXAMPLES::
|
|
681
|
+
|
|
682
|
+
sage: from sage.schemes.elliptic_curves.cm import largest_disc_with_class_number
|
|
683
|
+
sage: largest_disc_with_class_number(0)
|
|
684
|
+
(0, 0)
|
|
685
|
+
sage: largest_disc_with_class_number(1)
|
|
686
|
+
(163, 13)
|
|
687
|
+
sage: largest_disc_with_class_number(2)
|
|
688
|
+
(427, 29)
|
|
689
|
+
sage: largest_disc_with_class_number(10)
|
|
690
|
+
(13843, 123)
|
|
691
|
+
sage: largest_disc_with_class_number(100)
|
|
692
|
+
(1856563, 2311)
|
|
693
|
+
sage: largest_disc_with_class_number(101)
|
|
694
|
+
Traceback (most recent call last):
|
|
695
|
+
...
|
|
696
|
+
NotImplementedError: largest discriminant not available for class number 101
|
|
697
|
+
|
|
698
|
+
For most `h\le100`, the largest fundamental discriminant with
|
|
699
|
+
class number `h` is also the largest discriminant, but this is not
|
|
700
|
+
the case for some `h`::
|
|
701
|
+
|
|
702
|
+
sage: from sage.schemes.elliptic_curves.cm import largest_disc_with_class_number, largest_fundamental_disc_with_class_number
|
|
703
|
+
sage: [h for h in range(1,101) if largest_disc_with_class_number(h)[0] != largest_fundamental_disc_with_class_number(h)[0]]
|
|
704
|
+
[6, 8, 12, 16, 20, 30, 40, 42, 52, 70]
|
|
705
|
+
sage: largest_fundamental_disc_with_class_number(6)
|
|
706
|
+
(3763, 51)
|
|
707
|
+
sage: largest_disc_with_class_number(6)
|
|
708
|
+
(4075, 101)
|
|
709
|
+
"""
|
|
710
|
+
h = Integer(h)
|
|
711
|
+
if h <= 0:
|
|
712
|
+
return Integer(0), Integer(0)
|
|
713
|
+
try:
|
|
714
|
+
B, c = klaise_table[h]
|
|
715
|
+
return (Integer(B), Integer(c))
|
|
716
|
+
except KeyError:
|
|
717
|
+
raise NotImplementedError("largest discriminant not available for class number %s" % h)
|
|
718
|
+
|
|
719
|
+
# This dict has class numbers h as keys, the value at h is a complete
|
|
720
|
+
# list of pairs (D0,f) such that D=D0*f**2 has class number h. We
|
|
721
|
+
# initialise it with h=1 only; other values will be added by calls to
|
|
722
|
+
# discriminants_with_bounded_class_number().
|
|
723
|
+
|
|
724
|
+
|
|
725
|
+
hDf_dict = {ZZ(1): [(ZZ(D), ZZ(h)) for D,h in
|
|
726
|
+
[(-3, 1), (-3, 2), (-3, 3), (-4, 1), (-4, 2), (-7, 1), (-7, 2),
|
|
727
|
+
(-8, 1), (-11, 1), (-19, 1), (-43, 1), (-67, 1), (-163, 1)]]}
|
|
728
|
+
|
|
729
|
+
|
|
730
|
+
def discriminants_with_bounded_class_number(hmax, B=None, proof=None):
|
|
731
|
+
r"""Return a dictionary with keys class numbers `h\le hmax` and values the
|
|
732
|
+
list of all pairs `(D_0, f)`, with `D_0<0` a fundamental discriminant such
|
|
733
|
+
that `D=D_0f^2` has class number `h`. If the optional bound `B` is given,
|
|
734
|
+
return only those pairs with `|D| \le B`.
|
|
735
|
+
|
|
736
|
+
INPUT:
|
|
737
|
+
|
|
738
|
+
- ``hmax`` -- integer
|
|
739
|
+
- ``B`` -- integer or ``None``; if ``None`` returns all pairs
|
|
740
|
+
- ``proof`` -- this code calls the PARI function :pari:`qfbclassno`, so it
|
|
741
|
+
could give wrong answers when ``proof``==``False`` (though only for
|
|
742
|
+
discriminants greater than `2\cdot10^{10}`). The default is
|
|
743
|
+
the current value of ``proof.number_field()``.
|
|
744
|
+
|
|
745
|
+
OUTPUT: dictionary
|
|
746
|
+
|
|
747
|
+
.. NOTE::
|
|
748
|
+
|
|
749
|
+
In case `B` is not given, then ``hmax`` must be at most 100; we
|
|
750
|
+
use the tables from [Watkins2004]_ and [Klaise2012]_ to compute
|
|
751
|
+
a `B` that captures all `h` up to `hmax`.
|
|
752
|
+
|
|
753
|
+
EXAMPLES::
|
|
754
|
+
|
|
755
|
+
sage: # needs sage.libs.pari
|
|
756
|
+
sage: from sage.schemes.elliptic_curves.cm import discriminants_with_bounded_class_number
|
|
757
|
+
sage: v = discriminants_with_bounded_class_number(3)
|
|
758
|
+
sage: sorted(v)
|
|
759
|
+
[1, 2, 3]
|
|
760
|
+
sage: v[1]
|
|
761
|
+
[(-3, 1), (-3, 2), (-3, 3), (-4, 1), (-4, 2), (-7, 1), (-7, 2), (-8, 1),
|
|
762
|
+
(-11, 1), (-19, 1), (-43, 1), (-67, 1), (-163, 1)]
|
|
763
|
+
sage: v[2]
|
|
764
|
+
[(-3, 4), (-3, 5), (-3, 7), (-4, 3), (-4, 4), (-4, 5), (-7, 4), (-8, 2),
|
|
765
|
+
(-8, 3), (-11, 3), (-15, 1), (-15, 2), (-20, 1), (-24, 1), (-35, 1), (-40, 1),
|
|
766
|
+
(-51, 1), (-52, 1), (-88, 1), (-91, 1), (-115, 1), (-123, 1), (-148, 1),
|
|
767
|
+
(-187, 1), (-232, 1), (-235, 1), (-267, 1), (-403, 1), (-427, 1)]
|
|
768
|
+
sage: v[3]
|
|
769
|
+
[(-3, 6), (-3, 9), (-11, 2), (-19, 2), (-23, 1), (-23, 2), (-31, 1), (-31, 2),
|
|
770
|
+
(-43, 2), (-59, 1), (-67, 2), (-83, 1), (-107, 1), (-139, 1), (-163, 2),
|
|
771
|
+
(-211, 1), (-283, 1), (-307, 1), (-331, 1), (-379, 1), (-499, 1), (-547, 1),
|
|
772
|
+
(-643, 1), (-883, 1), (-907, 1)]
|
|
773
|
+
sage: v = discriminants_with_bounded_class_number(8, proof=False)
|
|
774
|
+
sage: sorted(len(v[h]) for h in v)
|
|
775
|
+
[13, 25, 29, 29, 38, 84, 101, 208]
|
|
776
|
+
|
|
777
|
+
Find all class numbers for discriminant up to 50::
|
|
778
|
+
|
|
779
|
+
sage: sage.schemes.elliptic_curves.cm.discriminants_with_bounded_class_number(hmax=5, B=50)
|
|
780
|
+
{1: [(-3, 1), (-3, 2), (-3, 3), (-4, 1), (-4, 2), (-7, 1), (-7, 2), (-8, 1), (-11, 1), (-19, 1), (-43, 1)], 2: [(-3, 4), (-4, 3), (-8, 2), (-15, 1), (-20, 1), (-24, 1), (-35, 1), (-40, 1)], 3: [(-11, 2), (-23, 1), (-31, 1)], 4: [(-39, 1)], 5: [(-47, 1)]}
|
|
781
|
+
"""
|
|
782
|
+
hmax = Integer(hmax)
|
|
783
|
+
global hDf_dict
|
|
784
|
+
|
|
785
|
+
# Easy case where we have already computed and cached the relevant values
|
|
786
|
+
if hDf_dict and hmax <= max(hDf_dict):
|
|
787
|
+
T = {h:Dflist for h,Dflist in hDf_dict.items() if h <= hmax}
|
|
788
|
+
if B:
|
|
789
|
+
for h in T:
|
|
790
|
+
T[h] = [Df for Df in T[h] if Df[0].abs()*Df[1]**2 <= B]
|
|
791
|
+
return T
|
|
792
|
+
|
|
793
|
+
# imports that are needed only for this function
|
|
794
|
+
from sage.arith.srange import xsrange
|
|
795
|
+
from sage.structure.proof.proof import get_flag
|
|
796
|
+
proof = get_flag(proof, 'number_field')
|
|
797
|
+
|
|
798
|
+
if B is None:
|
|
799
|
+
if hmax <= 100:
|
|
800
|
+
# Determine how far we have to go by applying Watkins + Klaise's results.
|
|
801
|
+
v = [largest_disc_with_class_number(h) for h in range(1, hmax+1)]
|
|
802
|
+
B = max([b for b,_ in v])
|
|
803
|
+
#print("Testing all discriminants up to {}".format(B))
|
|
804
|
+
count = [0] + [cnt for _,cnt in v]
|
|
805
|
+
else:
|
|
806
|
+
raise ValueError("if hmax>100 you must specify a discriminant bound B")
|
|
807
|
+
else:
|
|
808
|
+
# Nothing to do -- set to None so we can use this later to know not
|
|
809
|
+
# to do a double check about how many we find.
|
|
810
|
+
count = None
|
|
811
|
+
B = Integer(B)
|
|
812
|
+
|
|
813
|
+
if B <= 2:
|
|
814
|
+
# This is an easy special case, since there are no fundamental discriminants
|
|
815
|
+
# this small.
|
|
816
|
+
return {}
|
|
817
|
+
|
|
818
|
+
# T stores the values found, to be returned. It will also be used
|
|
819
|
+
# to update the global hDf_dict *provided that* the parameter B
|
|
820
|
+
# was not provided. Note that we only reach this point if we have
|
|
821
|
+
# not already computed data for at least one class number, hmax.
|
|
822
|
+
|
|
823
|
+
# To avoid recomputing class numbers, we initialise T with the
|
|
824
|
+
# global hDf_dict, only including those (D,f) for which |D|*f**2
|
|
825
|
+
# <= B if B was provided:
|
|
826
|
+
|
|
827
|
+
# h_dict caches the class number h of all discriminants previously
|
|
828
|
+
# encountered; we will use the function OrderClassNumber() to
|
|
829
|
+
# quickly compute the class number of non-fundamental discriminants
|
|
830
|
+
# from the fundamental ones. Note that in the initialisation, the
|
|
831
|
+
# keys of h_dict include nonfundamental discriminants, but we only
|
|
832
|
+
# update it with fundamental ones.
|
|
833
|
+
|
|
834
|
+
from collections import defaultdict
|
|
835
|
+
T = defaultdict(set)
|
|
836
|
+
h_dict = {}
|
|
837
|
+
for h, Dflist in hDf_dict.items():
|
|
838
|
+
for D0,f in Dflist:
|
|
839
|
+
h_dict[D0*f**2] = h
|
|
840
|
+
if not count:
|
|
841
|
+
Dflist = [Df for Df in Dflist if Df[0].abs()*Df[1]**2 <= B]
|
|
842
|
+
T[h] = set(Dflist)
|
|
843
|
+
|
|
844
|
+
# We do not need to certify the class number from :pari:`qfbclassno` for discriminants under 2*10^10
|
|
845
|
+
if B < 2*10**10:
|
|
846
|
+
proof = False
|
|
847
|
+
|
|
848
|
+
for D in xsrange(-3, -B-1, -1):
|
|
849
|
+
if not D.is_discriminant():
|
|
850
|
+
continue
|
|
851
|
+
D0 = D.squarefree_part()
|
|
852
|
+
if D0 % 4 != 1:
|
|
853
|
+
D0 *= 4
|
|
854
|
+
f = (D//D0).isqrt()
|
|
855
|
+
|
|
856
|
+
# Now D0 is the fundamental discriminant and f the conductor
|
|
857
|
+
|
|
858
|
+
if D in h_dict:
|
|
859
|
+
h = h_dict[D]
|
|
860
|
+
else:
|
|
861
|
+
if f == 1: # D itself is fundamental
|
|
862
|
+
h = D.class_number(proof)
|
|
863
|
+
h_dict[D] = h
|
|
864
|
+
else:
|
|
865
|
+
h = OrderClassNumber(D0,h_dict[D0],f)
|
|
866
|
+
|
|
867
|
+
# If the class number of this order is within the range, then store (D0,f)
|
|
868
|
+
if h <= hmax:
|
|
869
|
+
T[h].add((D0,f))
|
|
870
|
+
|
|
871
|
+
# sort each list of (D,f) pairs by (|D|,f)
|
|
872
|
+
|
|
873
|
+
for h in T:
|
|
874
|
+
T[h] = list(T[h])
|
|
875
|
+
T[h].sort(key=lambda Df: (Df[0].abs(), Df[1]))
|
|
876
|
+
|
|
877
|
+
# count is None precisely when the user provided a value of B
|
|
878
|
+
if count is not None:
|
|
879
|
+
# 1. Check that we found the right number of discriminants
|
|
880
|
+
for h in T:
|
|
881
|
+
if len(T[h]) != count[h]:
|
|
882
|
+
raise RuntimeError("number of discriminants inconsistent with Watkins's table")
|
|
883
|
+
# 2. Update the global dict
|
|
884
|
+
hDf_dict.update(dict(T))
|
|
885
|
+
|
|
886
|
+
return T
|
|
887
|
+
|
|
888
|
+
|
|
889
|
+
@cached_function
|
|
890
|
+
def is_cm_j_invariant(j, algorithm='CremonaSutherland', method=None):
|
|
891
|
+
r"""Return whether or not this is a CM `j`-invariant, and the CM discriminant if it is.
|
|
892
|
+
|
|
893
|
+
INPUT:
|
|
894
|
+
|
|
895
|
+
- ``j`` -- an element of a number field `K`
|
|
896
|
+
|
|
897
|
+
- ``algorithm`` -- string (default: ``'CremonaSutherland'``); the algorithm
|
|
898
|
+
used, either ``'CremonaSutherland'`` (the default, very much faster
|
|
899
|
+
for all but very small degrees), ``'exhaustive'`` or ``'reduction'``
|
|
900
|
+
|
|
901
|
+
- ``method`` -- string; deprecated name for ``algorithm``
|
|
902
|
+
|
|
903
|
+
OUTPUT:
|
|
904
|
+
|
|
905
|
+
A pair (bool, (d,f)) which is either (False, None) if `j` is not a
|
|
906
|
+
CM j-invariant or (True, (d,f)) if `j` is the `j`-invariant of the
|
|
907
|
+
imaginary quadratic order of discriminant `D=df^2` where `d` is
|
|
908
|
+
the associated fundamental discriminant and `f` the index.
|
|
909
|
+
|
|
910
|
+
ALGORITHM:
|
|
911
|
+
|
|
912
|
+
The default algorithm used is to test whether the minimal
|
|
913
|
+
polynomial of ``j`` is a Hilbert CLass Polynomail, using
|
|
914
|
+
:func:`is_HCP` which implements Algorithm 2 of [CreSuth2023]_ by
|
|
915
|
+
Cremona and Sutherland.
|
|
916
|
+
|
|
917
|
+
Two older algorithms are available, both of which are much slower
|
|
918
|
+
except for very small degrees.
|
|
919
|
+
|
|
920
|
+
Method 'exhaustive' makes use of the complete and unconditionsl classification of
|
|
921
|
+
all orders of class number up to 100, and hence will raise an
|
|
922
|
+
error if `j` is an algebraic integer of degree greater than
|
|
923
|
+
this.
|
|
924
|
+
|
|
925
|
+
Method 'reduction' constructs an elliptic curve over the number
|
|
926
|
+
field `\QQ(j)` and computes its traces of Frobenius at several
|
|
927
|
+
primes of degree 1.
|
|
928
|
+
|
|
929
|
+
EXAMPLES::
|
|
930
|
+
|
|
931
|
+
sage: from sage.schemes.elliptic_curves.cm import is_cm_j_invariant
|
|
932
|
+
sage: is_cm_j_invariant(0)
|
|
933
|
+
(True, (-3, 1))
|
|
934
|
+
sage: is_cm_j_invariant(8000)
|
|
935
|
+
(True, (-8, 1))
|
|
936
|
+
|
|
937
|
+
sage: # needs sage.rings.number_field
|
|
938
|
+
sage: K.<a> = QuadraticField(5)
|
|
939
|
+
sage: is_cm_j_invariant(282880*a + 632000)
|
|
940
|
+
(True, (-20, 1))
|
|
941
|
+
sage: x = polygen(ZZ, 'x')
|
|
942
|
+
sage: K.<a> = NumberField(x^3 - 2)
|
|
943
|
+
sage: is_cm_j_invariant(31710790944000*a^2 + 39953093016000*a + 50337742902000)
|
|
944
|
+
(True, (-3, 6))
|
|
945
|
+
|
|
946
|
+
An example of large degree. This is only possible using the default algorithm::
|
|
947
|
+
|
|
948
|
+
sage: from sage.schemes.elliptic_curves.cm import is_cm_j_invariant
|
|
949
|
+
sage: D = -1856563
|
|
950
|
+
sage: H = hilbert_class_polynomial(D) # needs sage.libs.flint
|
|
951
|
+
sage: H.degree() # needs sage.libs.flint
|
|
952
|
+
100
|
|
953
|
+
sage: K.<j> = NumberField(H) # needs sage.libs.flint sage.rings.number_field
|
|
954
|
+
sage: is_cm_j_invariant(j) # needs sage.libs.flint sage.rings.number_field
|
|
955
|
+
(True, (-1856563, 1))
|
|
956
|
+
|
|
957
|
+
TESTS::
|
|
958
|
+
|
|
959
|
+
sage: from sage.schemes.elliptic_curves.cm import is_cm_j_invariant
|
|
960
|
+
sage: all(is_cm_j_invariant(j) == (True, (d,f)) for d,f,j in cm_j_invariants_and_orders(QQ))
|
|
961
|
+
True
|
|
962
|
+
"""
|
|
963
|
+
if method:
|
|
964
|
+
if not algorithm:
|
|
965
|
+
algorithm = method
|
|
966
|
+
raise DeprecationWarning("'method' is deprecated, use 'algorithm instead'")
|
|
967
|
+
|
|
968
|
+
# First we check that j is an algebraic number:
|
|
969
|
+
if not isinstance(j, NumberFieldElement_base) and j not in QQ:
|
|
970
|
+
raise NotImplementedError("is_cm_j_invariant() is only implemented for number field elements")
|
|
971
|
+
|
|
972
|
+
# for j in ZZ we have a lookup-table:
|
|
973
|
+
|
|
974
|
+
if j in ZZ:
|
|
975
|
+
j = ZZ(j)
|
|
976
|
+
table = {jj: (d,f) for d,f,jj in cm_j_invariants_and_orders(QQ)}
|
|
977
|
+
if j in table:
|
|
978
|
+
return True, table[j]
|
|
979
|
+
return False, None
|
|
980
|
+
|
|
981
|
+
# Otherwise if j is in Q then it is not integral so is not CM:
|
|
982
|
+
|
|
983
|
+
if j in QQ:
|
|
984
|
+
return False, None
|
|
985
|
+
|
|
986
|
+
# Next we find its minimal polynomial of j:
|
|
987
|
+
|
|
988
|
+
if j.parent().absolute_degree() == 2:
|
|
989
|
+
jpol = j.absolute_minpoly() # no algorithm parameter
|
|
990
|
+
else:
|
|
991
|
+
jpol = j.absolute_minpoly(algorithm='pari')
|
|
992
|
+
|
|
993
|
+
# If it does not have integer coefficients then j is not integral, hence not CM:
|
|
994
|
+
|
|
995
|
+
if not all(c in ZZ for c in jpol):
|
|
996
|
+
return False, None
|
|
997
|
+
|
|
998
|
+
# Otherwise test whether it is a Hilbert Class Polynomial
|
|
999
|
+
# (using the fact that we know that it is monic and irreducible):
|
|
1000
|
+
|
|
1001
|
+
if algorithm == 'CremonaSutherland':
|
|
1002
|
+
D = is_HCP(jpol, check_monic_irreducible=False)
|
|
1003
|
+
if D:
|
|
1004
|
+
D0 = D.squarefree_part()
|
|
1005
|
+
if D0 % 4 != 1:
|
|
1006
|
+
D0 *= 4
|
|
1007
|
+
f = ZZ(D // D0).isqrt()
|
|
1008
|
+
return (True, (D0, f))
|
|
1009
|
+
else:
|
|
1010
|
+
return (False, None)
|
|
1011
|
+
|
|
1012
|
+
h = jpol.degree()
|
|
1013
|
+
if algorithm in ['exhaustive', 'old']:
|
|
1014
|
+
if h > 100:
|
|
1015
|
+
raise NotImplementedError("CM data only available for class numbers up to 100")
|
|
1016
|
+
for d,f in cm_orders(h):
|
|
1017
|
+
if jpol == hilbert_class_polynomial(d*f**2):
|
|
1018
|
+
return (True, (d,f))
|
|
1019
|
+
return (False, None)
|
|
1020
|
+
|
|
1021
|
+
if algorithm not in ['reduction', 'new']:
|
|
1022
|
+
raise ValueError("Invalid algorithm {} in is_cm_j_invariant".format(algorithm))
|
|
1023
|
+
|
|
1024
|
+
# Now we use the reduction algorithm
|
|
1025
|
+
|
|
1026
|
+
# If the degree h is less than the degree of j.parent() we recreate j as an element
|
|
1027
|
+
# of Q(j, and replace j by a clone whose parent is Q(j), if necessary:
|
|
1028
|
+
|
|
1029
|
+
K = j.parent()
|
|
1030
|
+
if h < K.absolute_degree():
|
|
1031
|
+
from sage.rings.number_field.number_field import NumberField
|
|
1032
|
+
|
|
1033
|
+
K = NumberField(jpol, 'j')
|
|
1034
|
+
j = K.gen()
|
|
1035
|
+
|
|
1036
|
+
# Construct an elliptic curve with j-invariant j, with
|
|
1037
|
+
# integral model:
|
|
1038
|
+
|
|
1039
|
+
from sage.schemes.elliptic_curves.constructor import EllipticCurve
|
|
1040
|
+
E = EllipticCurve(j=j).integral_model()
|
|
1041
|
+
D = E.discriminant()
|
|
1042
|
+
prime_bound = 1000 # test primes of degree 1 up to this norm
|
|
1043
|
+
max_primes = 20 # test at most this many primes
|
|
1044
|
+
num_prime = 0
|
|
1045
|
+
cmd = 0
|
|
1046
|
+
cmf = 0
|
|
1047
|
+
|
|
1048
|
+
# Test primes of good reduction. If E has CM then for half the
|
|
1049
|
+
# primes P we will have a_P=0, and for all other prime P the CM
|
|
1050
|
+
# field is Q(sqrt(a_P^2-4N(P))). Hence if these fields are
|
|
1051
|
+
# different for two primes then E does not have CM. If they are
|
|
1052
|
+
# all equal for the primes tested, then we have a candidate CM
|
|
1053
|
+
# field. Moreover the discriminant of the endomorphism ring
|
|
1054
|
+
# divides all the values a_P^2-4N(P), since that is the
|
|
1055
|
+
# discriminant of the order containing the Frobenius at P. So we
|
|
1056
|
+
# end up with a finite number (usually one) of candidate
|
|
1057
|
+
# discriminants to test. Each is tested by checking that its class
|
|
1058
|
+
# number is h, and if so then that j is a root of its Hilbert
|
|
1059
|
+
# class polynomial. In practice non CM curves will be eliminated
|
|
1060
|
+
# by the local test at a small number of primes (probably just 2).
|
|
1061
|
+
|
|
1062
|
+
for P in K.primes_of_degree_one_iter(prime_bound):
|
|
1063
|
+
if num_prime > max_primes:
|
|
1064
|
+
if cmd: # we have a candidate CM field already
|
|
1065
|
+
break
|
|
1066
|
+
else: # we need to try more primes
|
|
1067
|
+
max_primes *= 2
|
|
1068
|
+
if D.valuation(P) > 0: # skip bad primes
|
|
1069
|
+
continue
|
|
1070
|
+
aP = E.reduction(P).trace_of_frobenius()
|
|
1071
|
+
if aP == 0: # skip supersingular primes
|
|
1072
|
+
continue
|
|
1073
|
+
num_prime += 1
|
|
1074
|
+
DP = aP**2 - 4*P.norm()
|
|
1075
|
+
dP = DP.squarefree_part()
|
|
1076
|
+
fP = ZZ(DP//dP).isqrt()
|
|
1077
|
+
if cmd == 0: # first one, so store d and f
|
|
1078
|
+
cmd = dP
|
|
1079
|
+
cmf = fP
|
|
1080
|
+
elif cmd != dP: # inconsistent with previous
|
|
1081
|
+
return (False, None)
|
|
1082
|
+
else: # consistent d, so update f
|
|
1083
|
+
cmf = cmf.gcd(fP)
|
|
1084
|
+
|
|
1085
|
+
if cmd == 0: # no conclusion, we found no degree 1 primes, revert to default algorithm
|
|
1086
|
+
return is_cm_j_invariant(j)
|
|
1087
|
+
|
|
1088
|
+
# it looks like cm by disc cmd * f**2 where f divides cmf
|
|
1089
|
+
|
|
1090
|
+
if cmd % 4 != 1:
|
|
1091
|
+
cmd = cmd * 4
|
|
1092
|
+
cmf = cmf // 2
|
|
1093
|
+
|
|
1094
|
+
# Now we must check if h(cmd*f**2)==h for f|cmf; if so we check
|
|
1095
|
+
# whether j is a root of the associated Hilbert class polynomial.
|
|
1096
|
+
h0 = cmd.class_number()
|
|
1097
|
+
for f in cmf.divisors(): # only positive divisors
|
|
1098
|
+
if h != OrderClassNumber(cmd,h0,f):
|
|
1099
|
+
continue
|
|
1100
|
+
if jpol == hilbert_class_polynomial(cmd*f**2):
|
|
1101
|
+
return (True, (cmd, f))
|
|
1102
|
+
return (False, None)
|