passagemath-schemes 10.6.40__cp314-cp314-macosx_13_0_arm64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of passagemath-schemes might be problematic. Click here for more details.

Files changed (314) hide show
  1. passagemath_schemes/.dylibs/libflint.22.0.dylib +0 -0
  2. passagemath_schemes/.dylibs/libgmp.10.dylib +0 -0
  3. passagemath_schemes/.dylibs/libgmpxx.4.dylib +0 -0
  4. passagemath_schemes/.dylibs/libmpfr.6.dylib +0 -0
  5. passagemath_schemes/__init__.py +3 -0
  6. passagemath_schemes-10.6.40.dist-info/METADATA +204 -0
  7. passagemath_schemes-10.6.40.dist-info/METADATA.bak +205 -0
  8. passagemath_schemes-10.6.40.dist-info/RECORD +314 -0
  9. passagemath_schemes-10.6.40.dist-info/WHEEL +6 -0
  10. passagemath_schemes-10.6.40.dist-info/top_level.txt +3 -0
  11. sage/all__sagemath_schemes.py +23 -0
  12. sage/databases/all__sagemath_schemes.py +7 -0
  13. sage/databases/cremona.py +1723 -0
  14. sage/dynamics/all__sagemath_schemes.py +2 -0
  15. sage/dynamics/arithmetic_dynamics/affine_ds.py +1083 -0
  16. sage/dynamics/arithmetic_dynamics/all.py +14 -0
  17. sage/dynamics/arithmetic_dynamics/berkovich_ds.py +1101 -0
  18. sage/dynamics/arithmetic_dynamics/dynamical_semigroup.py +1543 -0
  19. sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py +2426 -0
  20. sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py +1169 -0
  21. sage/dynamics/arithmetic_dynamics/generic_ds.py +663 -0
  22. sage/dynamics/arithmetic_dynamics/product_projective_ds.py +339 -0
  23. sage/dynamics/arithmetic_dynamics/projective_ds.py +9558 -0
  24. sage/dynamics/arithmetic_dynamics/projective_ds_helper.cpython-314-darwin.so +0 -0
  25. sage/dynamics/arithmetic_dynamics/projective_ds_helper.pyx +301 -0
  26. sage/dynamics/arithmetic_dynamics/wehlerK3.py +2576 -0
  27. sage/lfunctions/all.py +18 -0
  28. sage/lfunctions/dokchitser.py +745 -0
  29. sage/lfunctions/pari.py +818 -0
  30. sage/lfunctions/zero_sums.cpython-314-darwin.so +0 -0
  31. sage/lfunctions/zero_sums.pyx +1847 -0
  32. sage/modular/abvar/abvar.py +5135 -0
  33. sage/modular/abvar/abvar_ambient_jacobian.py +413 -0
  34. sage/modular/abvar/abvar_newform.py +244 -0
  35. sage/modular/abvar/all.py +8 -0
  36. sage/modular/abvar/constructor.py +186 -0
  37. sage/modular/abvar/cuspidal_subgroup.py +371 -0
  38. sage/modular/abvar/finite_subgroup.py +896 -0
  39. sage/modular/abvar/homology.py +720 -0
  40. sage/modular/abvar/homspace.py +998 -0
  41. sage/modular/abvar/lseries.py +415 -0
  42. sage/modular/abvar/morphism.py +935 -0
  43. sage/modular/abvar/torsion_point.py +274 -0
  44. sage/modular/abvar/torsion_subgroup.py +740 -0
  45. sage/modular/all.py +43 -0
  46. sage/modular/arithgroup/all.py +20 -0
  47. sage/modular/arithgroup/arithgroup_element.cpython-314-darwin.so +0 -0
  48. sage/modular/arithgroup/arithgroup_element.pyx +474 -0
  49. sage/modular/arithgroup/arithgroup_generic.py +1402 -0
  50. sage/modular/arithgroup/arithgroup_perm.py +2692 -0
  51. sage/modular/arithgroup/congroup.cpython-314-darwin.so +0 -0
  52. sage/modular/arithgroup/congroup.pyx +334 -0
  53. sage/modular/arithgroup/congroup_gamma.py +363 -0
  54. sage/modular/arithgroup/congroup_gamma0.py +692 -0
  55. sage/modular/arithgroup/congroup_gamma1.py +653 -0
  56. sage/modular/arithgroup/congroup_gammaH.py +1469 -0
  57. sage/modular/arithgroup/congroup_generic.py +628 -0
  58. sage/modular/arithgroup/congroup_sl2z.py +267 -0
  59. sage/modular/arithgroup/farey_symbol.cpython-314-darwin.so +0 -0
  60. sage/modular/arithgroup/farey_symbol.pyx +1066 -0
  61. sage/modular/arithgroup/tests.py +418 -0
  62. sage/modular/btquotients/all.py +4 -0
  63. sage/modular/btquotients/btquotient.py +3753 -0
  64. sage/modular/btquotients/pautomorphicform.py +2570 -0
  65. sage/modular/buzzard.py +100 -0
  66. sage/modular/congroup.py +29 -0
  67. sage/modular/congroup_element.py +13 -0
  68. sage/modular/cusps.py +1109 -0
  69. sage/modular/cusps_nf.py +1270 -0
  70. sage/modular/dims.py +569 -0
  71. sage/modular/dirichlet.py +3310 -0
  72. sage/modular/drinfeld_modform/all.py +2 -0
  73. sage/modular/drinfeld_modform/element.py +446 -0
  74. sage/modular/drinfeld_modform/ring.py +773 -0
  75. sage/modular/drinfeld_modform/tutorial.py +236 -0
  76. sage/modular/etaproducts.py +1065 -0
  77. sage/modular/hecke/algebra.py +746 -0
  78. sage/modular/hecke/all.py +20 -0
  79. sage/modular/hecke/ambient_module.py +1019 -0
  80. sage/modular/hecke/degenmap.py +119 -0
  81. sage/modular/hecke/element.py +325 -0
  82. sage/modular/hecke/hecke_operator.py +780 -0
  83. sage/modular/hecke/homspace.py +206 -0
  84. sage/modular/hecke/module.py +1767 -0
  85. sage/modular/hecke/morphism.py +174 -0
  86. sage/modular/hecke/submodule.py +989 -0
  87. sage/modular/hypergeometric_misc.cpython-314-darwin.so +0 -0
  88. sage/modular/hypergeometric_misc.pxd +4 -0
  89. sage/modular/hypergeometric_misc.pyx +166 -0
  90. sage/modular/hypergeometric_motive.py +2017 -0
  91. sage/modular/local_comp/all.py +2 -0
  92. sage/modular/local_comp/liftings.py +292 -0
  93. sage/modular/local_comp/local_comp.py +1071 -0
  94. sage/modular/local_comp/smoothchar.py +1825 -0
  95. sage/modular/local_comp/type_space.py +748 -0
  96. sage/modular/modform/all.py +30 -0
  97. sage/modular/modform/ambient.py +815 -0
  98. sage/modular/modform/ambient_R.py +177 -0
  99. sage/modular/modform/ambient_eps.py +306 -0
  100. sage/modular/modform/ambient_g0.py +124 -0
  101. sage/modular/modform/ambient_g1.py +204 -0
  102. sage/modular/modform/constructor.py +545 -0
  103. sage/modular/modform/cuspidal_submodule.py +708 -0
  104. sage/modular/modform/defaults.py +14 -0
  105. sage/modular/modform/eis_series.py +505 -0
  106. sage/modular/modform/eisenstein_submodule.py +663 -0
  107. sage/modular/modform/element.py +4131 -0
  108. sage/modular/modform/find_generators.py +59 -0
  109. sage/modular/modform/half_integral.py +154 -0
  110. sage/modular/modform/hecke_operator_on_qexp.py +247 -0
  111. sage/modular/modform/j_invariant.py +47 -0
  112. sage/modular/modform/l_series_gross_zagier.py +133 -0
  113. sage/modular/modform/l_series_gross_zagier_coeffs.cpython-314-darwin.so +0 -0
  114. sage/modular/modform/l_series_gross_zagier_coeffs.pyx +177 -0
  115. sage/modular/modform/notes.py +45 -0
  116. sage/modular/modform/numerical.py +514 -0
  117. sage/modular/modform/periods.py +14 -0
  118. sage/modular/modform/ring.py +1257 -0
  119. sage/modular/modform/space.py +1860 -0
  120. sage/modular/modform/submodule.py +118 -0
  121. sage/modular/modform/tests.py +64 -0
  122. sage/modular/modform/theta.py +110 -0
  123. sage/modular/modform/vm_basis.py +381 -0
  124. sage/modular/modform/weight1.py +220 -0
  125. sage/modular/modform_hecketriangle/abstract_ring.py +1932 -0
  126. sage/modular/modform_hecketriangle/abstract_space.py +2528 -0
  127. sage/modular/modform_hecketriangle/all.py +30 -0
  128. sage/modular/modform_hecketriangle/analytic_type.py +590 -0
  129. sage/modular/modform_hecketriangle/constructor.py +416 -0
  130. sage/modular/modform_hecketriangle/element.py +351 -0
  131. sage/modular/modform_hecketriangle/functors.py +752 -0
  132. sage/modular/modform_hecketriangle/graded_ring.py +541 -0
  133. sage/modular/modform_hecketriangle/graded_ring_element.py +2225 -0
  134. sage/modular/modform_hecketriangle/hecke_triangle_group_element.py +3352 -0
  135. sage/modular/modform_hecketriangle/hecke_triangle_groups.py +1432 -0
  136. sage/modular/modform_hecketriangle/readme.py +1214 -0
  137. sage/modular/modform_hecketriangle/series_constructor.py +580 -0
  138. sage/modular/modform_hecketriangle/space.py +1037 -0
  139. sage/modular/modform_hecketriangle/subspace.py +423 -0
  140. sage/modular/modsym/all.py +17 -0
  141. sage/modular/modsym/ambient.py +3846 -0
  142. sage/modular/modsym/boundary.py +1420 -0
  143. sage/modular/modsym/element.py +336 -0
  144. sage/modular/modsym/g1list.py +178 -0
  145. sage/modular/modsym/ghlist.py +182 -0
  146. sage/modular/modsym/hecke_operator.py +73 -0
  147. sage/modular/modsym/manin_symbol.cpython-314-darwin.so +0 -0
  148. sage/modular/modsym/manin_symbol.pxd +5 -0
  149. sage/modular/modsym/manin_symbol.pyx +497 -0
  150. sage/modular/modsym/manin_symbol_list.py +1295 -0
  151. sage/modular/modsym/modsym.py +400 -0
  152. sage/modular/modsym/modular_symbols.py +384 -0
  153. sage/modular/modsym/p1list.cpython-314-darwin.so +0 -0
  154. sage/modular/modsym/p1list.pxd +29 -0
  155. sage/modular/modsym/p1list.pyx +1372 -0
  156. sage/modular/modsym/p1list_nf.py +1241 -0
  157. sage/modular/modsym/relation_matrix.py +591 -0
  158. sage/modular/modsym/relation_matrix_pyx.cpython-314-darwin.so +0 -0
  159. sage/modular/modsym/relation_matrix_pyx.pyx +108 -0
  160. sage/modular/modsym/space.py +2468 -0
  161. sage/modular/modsym/subspace.py +455 -0
  162. sage/modular/modsym/tests.py +375 -0
  163. sage/modular/multiple_zeta.py +2632 -0
  164. sage/modular/multiple_zeta_F_algebra.py +786 -0
  165. sage/modular/overconvergent/all.py +6 -0
  166. sage/modular/overconvergent/genus0.py +1878 -0
  167. sage/modular/overconvergent/hecke_series.py +1187 -0
  168. sage/modular/overconvergent/weightspace.py +778 -0
  169. sage/modular/pollack_stevens/all.py +4 -0
  170. sage/modular/pollack_stevens/distributions.py +874 -0
  171. sage/modular/pollack_stevens/fund_domain.py +1572 -0
  172. sage/modular/pollack_stevens/manin_map.py +859 -0
  173. sage/modular/pollack_stevens/modsym.py +1593 -0
  174. sage/modular/pollack_stevens/padic_lseries.py +417 -0
  175. sage/modular/pollack_stevens/sigma0.py +534 -0
  176. sage/modular/pollack_stevens/space.py +1076 -0
  177. sage/modular/quasimodform/all.py +3 -0
  178. sage/modular/quasimodform/element.py +845 -0
  179. sage/modular/quasimodform/ring.py +828 -0
  180. sage/modular/quatalg/all.py +3 -0
  181. sage/modular/quatalg/brandt.py +1642 -0
  182. sage/modular/ssmod/all.py +8 -0
  183. sage/modular/ssmod/ssmod.py +827 -0
  184. sage/rings/all__sagemath_schemes.py +1 -0
  185. sage/rings/polynomial/all__sagemath_schemes.py +1 -0
  186. sage/rings/polynomial/binary_form_reduce.py +585 -0
  187. sage/schemes/all.py +41 -0
  188. sage/schemes/berkovich/all.py +6 -0
  189. sage/schemes/berkovich/berkovich_cp_element.py +2582 -0
  190. sage/schemes/berkovich/berkovich_space.py +748 -0
  191. sage/schemes/curves/affine_curve.py +2928 -0
  192. sage/schemes/curves/all.py +33 -0
  193. sage/schemes/curves/closed_point.py +434 -0
  194. sage/schemes/curves/constructor.py +381 -0
  195. sage/schemes/curves/curve.py +542 -0
  196. sage/schemes/curves/plane_curve_arrangement.py +1283 -0
  197. sage/schemes/curves/point.py +463 -0
  198. sage/schemes/curves/projective_curve.py +3026 -0
  199. sage/schemes/curves/zariski_vankampen.py +1932 -0
  200. sage/schemes/cyclic_covers/all.py +2 -0
  201. sage/schemes/cyclic_covers/charpoly_frobenius.py +320 -0
  202. sage/schemes/cyclic_covers/constructor.py +137 -0
  203. sage/schemes/cyclic_covers/cycliccover_finite_field.py +1309 -0
  204. sage/schemes/cyclic_covers/cycliccover_generic.py +310 -0
  205. sage/schemes/elliptic_curves/BSD.py +1036 -0
  206. sage/schemes/elliptic_curves/Qcurves.py +592 -0
  207. sage/schemes/elliptic_curves/addition_formulas_ring.py +94 -0
  208. sage/schemes/elliptic_curves/all.py +49 -0
  209. sage/schemes/elliptic_curves/cardinality.py +609 -0
  210. sage/schemes/elliptic_curves/cm.py +1102 -0
  211. sage/schemes/elliptic_curves/constructor.py +1552 -0
  212. sage/schemes/elliptic_curves/ec_database.py +175 -0
  213. sage/schemes/elliptic_curves/ell_curve_isogeny.py +3972 -0
  214. sage/schemes/elliptic_curves/ell_egros.py +459 -0
  215. sage/schemes/elliptic_curves/ell_field.py +2836 -0
  216. sage/schemes/elliptic_curves/ell_finite_field.py +3359 -0
  217. sage/schemes/elliptic_curves/ell_generic.py +3760 -0
  218. sage/schemes/elliptic_curves/ell_local_data.py +1207 -0
  219. sage/schemes/elliptic_curves/ell_modular_symbols.py +775 -0
  220. sage/schemes/elliptic_curves/ell_number_field.py +4220 -0
  221. sage/schemes/elliptic_curves/ell_padic_field.py +107 -0
  222. sage/schemes/elliptic_curves/ell_point.py +4787 -0
  223. sage/schemes/elliptic_curves/ell_rational_field.py +7368 -0
  224. sage/schemes/elliptic_curves/ell_tate_curve.py +671 -0
  225. sage/schemes/elliptic_curves/ell_torsion.py +436 -0
  226. sage/schemes/elliptic_curves/ell_wp.py +352 -0
  227. sage/schemes/elliptic_curves/formal_group.py +760 -0
  228. sage/schemes/elliptic_curves/gal_reps.py +1459 -0
  229. sage/schemes/elliptic_curves/gal_reps_number_field.py +1669 -0
  230. sage/schemes/elliptic_curves/gp_simon.py +152 -0
  231. sage/schemes/elliptic_curves/heegner.py +7335 -0
  232. sage/schemes/elliptic_curves/height.py +2109 -0
  233. sage/schemes/elliptic_curves/hom.py +1406 -0
  234. sage/schemes/elliptic_curves/hom_composite.py +934 -0
  235. sage/schemes/elliptic_curves/hom_frobenius.py +522 -0
  236. sage/schemes/elliptic_curves/hom_scalar.py +531 -0
  237. sage/schemes/elliptic_curves/hom_sum.py +682 -0
  238. sage/schemes/elliptic_curves/hom_velusqrt.py +1290 -0
  239. sage/schemes/elliptic_curves/homset.py +271 -0
  240. sage/schemes/elliptic_curves/isogeny_class.py +1521 -0
  241. sage/schemes/elliptic_curves/isogeny_small_degree.py +2797 -0
  242. sage/schemes/elliptic_curves/jacobian.py +237 -0
  243. sage/schemes/elliptic_curves/kodaira_symbol.py +344 -0
  244. sage/schemes/elliptic_curves/kraus.py +1014 -0
  245. sage/schemes/elliptic_curves/lseries_ell.py +943 -0
  246. sage/schemes/elliptic_curves/mod5family.py +105 -0
  247. sage/schemes/elliptic_curves/mod_poly.py +197 -0
  248. sage/schemes/elliptic_curves/mod_sym_num.cpython-314-darwin.so +0 -0
  249. sage/schemes/elliptic_curves/mod_sym_num.pyx +3796 -0
  250. sage/schemes/elliptic_curves/modular_parametrization.py +305 -0
  251. sage/schemes/elliptic_curves/padic_lseries.py +1793 -0
  252. sage/schemes/elliptic_curves/padics.py +1816 -0
  253. sage/schemes/elliptic_curves/period_lattice.py +2234 -0
  254. sage/schemes/elliptic_curves/period_lattice_region.cpython-314-darwin.so +0 -0
  255. sage/schemes/elliptic_curves/period_lattice_region.pyx +722 -0
  256. sage/schemes/elliptic_curves/saturation.py +715 -0
  257. sage/schemes/elliptic_curves/sha_tate.py +1158 -0
  258. sage/schemes/elliptic_curves/weierstrass_morphism.py +1117 -0
  259. sage/schemes/elliptic_curves/weierstrass_transform.py +200 -0
  260. sage/schemes/hyperelliptic_curves/all.py +6 -0
  261. sage/schemes/hyperelliptic_curves/constructor.py +291 -0
  262. sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py +1914 -0
  263. sage/schemes/hyperelliptic_curves/hyperelliptic_g2.py +192 -0
  264. sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py +954 -0
  265. sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py +1332 -0
  266. sage/schemes/hyperelliptic_curves/hyperelliptic_rational_field.py +84 -0
  267. sage/schemes/hyperelliptic_curves/invariants.py +410 -0
  268. sage/schemes/hyperelliptic_curves/jacobian_endomorphism_utils.py +315 -0
  269. sage/schemes/hyperelliptic_curves/jacobian_g2.py +32 -0
  270. sage/schemes/hyperelliptic_curves/jacobian_generic.py +419 -0
  271. sage/schemes/hyperelliptic_curves/jacobian_homset.py +186 -0
  272. sage/schemes/hyperelliptic_curves/jacobian_morphism.py +875 -0
  273. sage/schemes/hyperelliptic_curves/kummer_surface.py +99 -0
  274. sage/schemes/hyperelliptic_curves/mestre.py +302 -0
  275. sage/schemes/hyperelliptic_curves/monsky_washnitzer.py +3871 -0
  276. sage/schemes/jacobians/abstract_jacobian.py +277 -0
  277. sage/schemes/jacobians/all.py +2 -0
  278. sage/schemes/overview.py +161 -0
  279. sage/schemes/plane_conics/all.py +22 -0
  280. sage/schemes/plane_conics/con_field.py +1296 -0
  281. sage/schemes/plane_conics/con_finite_field.py +158 -0
  282. sage/schemes/plane_conics/con_number_field.py +456 -0
  283. sage/schemes/plane_conics/con_rational_field.py +406 -0
  284. sage/schemes/plane_conics/con_rational_function_field.py +580 -0
  285. sage/schemes/plane_conics/constructor.py +249 -0
  286. sage/schemes/plane_quartics/all.py +2 -0
  287. sage/schemes/plane_quartics/quartic_constructor.py +71 -0
  288. sage/schemes/plane_quartics/quartic_generic.py +73 -0
  289. sage/schemes/riemann_surfaces/all.py +1 -0
  290. sage/schemes/riemann_surfaces/riemann_surface.py +4117 -0
  291. sage_wheels/share/cremona/cremona_mini.db +0 -0
  292. sage_wheels/share/ellcurves/rank0 +30427 -0
  293. sage_wheels/share/ellcurves/rank1 +31871 -0
  294. sage_wheels/share/ellcurves/rank10 +6 -0
  295. sage_wheels/share/ellcurves/rank11 +6 -0
  296. sage_wheels/share/ellcurves/rank12 +1 -0
  297. sage_wheels/share/ellcurves/rank14 +1 -0
  298. sage_wheels/share/ellcurves/rank15 +1 -0
  299. sage_wheels/share/ellcurves/rank17 +1 -0
  300. sage_wheels/share/ellcurves/rank19 +1 -0
  301. sage_wheels/share/ellcurves/rank2 +2388 -0
  302. sage_wheels/share/ellcurves/rank20 +1 -0
  303. sage_wheels/share/ellcurves/rank21 +1 -0
  304. sage_wheels/share/ellcurves/rank22 +1 -0
  305. sage_wheels/share/ellcurves/rank23 +1 -0
  306. sage_wheels/share/ellcurves/rank24 +1 -0
  307. sage_wheels/share/ellcurves/rank28 +1 -0
  308. sage_wheels/share/ellcurves/rank3 +836 -0
  309. sage_wheels/share/ellcurves/rank4 +10 -0
  310. sage_wheels/share/ellcurves/rank5 +5 -0
  311. sage_wheels/share/ellcurves/rank6 +5 -0
  312. sage_wheels/share/ellcurves/rank7 +5 -0
  313. sage_wheels/share/ellcurves/rank8 +6 -0
  314. 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)