Path: blob/master/src/sage/schemes/elliptic_curves/cm.py
8821 views
"""1Complex multiplication for elliptic curves23This module implements the functions45- ``hilbert_class_polynomial``6- ``cm_j_invariants``7- ``cm_orders``8- ``discriminants_with_bounded_class_number``9- ``cm_j_invariants_and_orders``10- ``largest_fundamental_disc_with_class_number``1112AUTHORS:1314- Robert Bradshaw15- John Cremona16- William Stein1718"""1920#*****************************************************************************21# Copyright (C) 2005-2012 William Stein <[email protected]>22#23# Distributed under the terms of the GNU General Public License (GPL)24#25# This code is distributed in the hope that it will be useful,26# but WITHOUT ANY WARRANTY; without even the implied warranty of27# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU28# General Public License for more details.29#30# The full text of the GPL is available at:31#32# http://www.gnu.org/licenses/33#*****************************************************************************3435from sage.interfaces.all import magma36from sage.rings.all import (Integer,37QQ,38IntegerRing,39is_fundamental_discriminant,40PolynomialRing)4142def hilbert_class_polynomial(D, algorithm=None):43r"""44Returns the Hilbert class polynomial for discriminant `D`.4546INPUT:4748- ``D`` (int) -- a negative integer congruent to 0 or 1 modulo 4.4950- ``algorithm`` (string, default None) -- if "sage" then use the Sage implementation; if "magma" then call Magma (if available).5152OUTPUT:5354(integer polynomial) The Hilbert class polynomial for the55discriminant `D`.5657ALGORITHM:5859- If ``algorithm`` = "sage": Use complex approximations to the roots.6061- If ``algorithm`` = "magma": Call the appropriate Magma function.6263AUTHORS:6465- Sage implementation originally by Eduardo Ocampo Alvarez and66AndreyTimofeev6768- Sage implementation corrected by John Cremona (using corrected precision bounds from Andreas Enge)6970- Magma implementation by David Kohel7172EXAMPLES::7374sage: hilbert_class_polynomial(-4)75x - 172876sage: hilbert_class_polynomial(-7)77x + 337578sage: hilbert_class_polynomial(-23)79x^3 + 3491750*x^2 - 5151296875*x + 1277188085937580sage: hilbert_class_polynomial(-37*4)81x^2 - 39660183801072000*x - 789824251593646790400000082sage: hilbert_class_polynomial(-37*4, algorithm="magma") # optional - magma83x^2 - 39660183801072000*x - 789824251593646790400000084sage: hilbert_class_polynomial(-163)85x + 26253741264076800086sage: hilbert_class_polynomial(-163, algorithm="magma") # optional - magma87x + 2625374126407680008889"""90if algorithm is None:91algorithm = "sage"9293D = Integer(D)94if D >= 0:95raise ValueError, "D (=%s) must be negative"%D96if not (D%4 in [0,1]):97raise ValueError, "D (=%s) must be a discriminant"%D9899if algorithm == "magma":100magma.eval("R<x> := PolynomialRing(IntegerRing())")101f = str(magma.eval("HilbertClassPolynomial(%s)"%D))102return IntegerRing()['x'](f)103104if algorithm != "sage":105raise ValueError, "%s is not a valid algorithm"%algorithm106107from sage.quadratic_forms.binary_qf import BinaryQF_reduced_representatives108from sage.rings.all import RR, ZZ, ComplexField109from sage.functions.all import elliptic_j110111# get all primitive reduced quadratic forms, (necessary to exclude112# imprimitive forms when D is not a fundamental discriminant):113114rqf = BinaryQF_reduced_representatives(D, primitive_only=True)115116# compute needed precision117#118# NB: [http://arxiv.org/abs/0802.0979v1], quoting Enge (2006), is119# incorrect. Enge writes (2009-04-20 email to John Cremona) "The120# source is my paper on class polynomials121# [http://hal.inria.fr/inria-00001040] It was pointed out to me by122# the referee after ANTS that the constant given there was123# wrong. The final version contains a corrected constant on p.7124# which is consistent with your example. It says:125126# "The logarithm of the absolute value of the coefficient in front127# of X^j is bounded above by128#129# log (2*k_2) * h + pi * sqrt(|D|) * sum (1/A_i)130#131# independently of j", where k_2 \approx 10.163.132133h = len(rqf) # class number134c1 = 3.05682737291380 # log(2*10.63)135c2 = sum([1/RR(qf[0]) for qf in rqf], RR(0))136prec = c2*RR(3.142)*RR(D).abs().sqrt() + h*c1 # bound on log137prec = prec * 1.45 # bound on log_2 (1/log(2) = 1.44..)138prec = 10 + prec.ceil() # allow for rounding error139140# set appropriate precision for further computing141142Dsqrt = D.sqrt(prec=prec)143R = ComplexField(prec)['t']144t = R.gen()145pol = R(1)146for qf in rqf:147a, b, c = list(qf)148tau = (b+Dsqrt)/(a<<1)149pol *= (t - elliptic_j(tau))150151coeffs = [cof.real().round() for cof in pol.coeffs()]152return IntegerRing()['x'](coeffs)153154155def cm_j_invariants(K, proof=None):156r"""157Return a list of all CM `j`-invariants in the field `K`.158159INPUT:160161- ``K`` -- a number field162- ``proof`` -- (default: proof.number_field())163164OUTPUT:165166(list) -- A list of CM `j`-invariants in the field `K`.167168EXAMPLE::169170sage: cm_j_invariants(QQ)171[-262537412640768000, -147197952000, -884736000, -12288000, -884736, -32768, -3375, 0, 1728, 8000, 54000, 287496, 16581375]172173Over imaginary quadratic fields there are no more than over `QQ`::174175sage: cm_j_invariants(QuadraticField(-1, 'i'))176[-262537412640768000, -147197952000, -884736000, -12288000, -884736, -32768, -3375, 0, 1728, 8000, 54000, 287496, 16581375]177178Over real quadratic fields there may be more, for example::179180sage: len(cm_j_invariants(QuadraticField(5, 'a')))18131182183Over number fields K of many higher degrees this also works::184185sage: K.<a> = NumberField(x^3 - 2)186sage: cm_j_invariants(K)187[-12288000, 54000, 0, 287496, 1728, 16581375, -3375, 8000, -32768, -884736, -884736000, -147197952000, -262537412640768000, 31710790944000*a^2 + 39953093016000*a + 50337742902000]188sage: K.<a> = NumberField(x^4 - 2)189sage: len(cm_j_invariants(K))19023191"""192return list(sorted([j for D,f,j in cm_j_invariants_and_orders(K, proof=proof)]))193194def cm_j_invariants_and_orders(K, proof=None):195r"""196Return a list of all CM `j`-invariants in the field `K`, together with the associated orders.197198INPUT:199200- ``K`` -- a number field201- ``proof`` -- (default: proof.number_field())202203OUTPUT:204205(list) A list of 3-tuples `(D,f,j)` where `j` is a CM206`j`-invariant in `K` with quadratic fundamental discriminant `D`207and conductor `f`.208209EXAMPLE::210211sage: cm_j_invariants_and_orders(QQ)212[(-3, 3, -12288000), (-3, 2, 54000), (-3, 1, 0), (-4, 2, 287496), (-4, 1, 1728), (-7, 2, 16581375), (-7, 1, -3375), (-8, 1, 8000), (-11, 1, -32768), (-19, 1, -884736), (-43, 1, -884736000), (-67, 1, -147197952000), (-163, 1, -262537412640768000)]213214Over an imaginary quadratic field there are no more than over `QQ`::215216sage: cm_j_invariants_and_orders(QuadraticField(-1, 'i'))217[(-3, 3, -12288000), (-3, 2, 54000), (-3, 1, 0), (-4, 2, 287496), (-4, 1, 1728), (-7, 2, 16581375), (-7, 1, -3375), (-8, 1, 8000), (-11, 1, -32768), (-19, 1, -884736), (-43, 1, -884736000), (-67, 1, -147197952000), (-163, 1, -262537412640768000)]218219Over real quadratic fields there may be more::220221sage: v = cm_j_invariants_and_orders(QuadraticField(5,'a')); len(v)22231223sage: [(D,f) for D,f,j in v if j not in QQ]224[(-3, 5), (-3, 5), (-4, 5), (-4, 5), (-15, 2), (-15, 2), (-15, 1), (-15, 1), (-20, 1), (-20, 1), (-35, 1), (-35, 1), (-40, 1), (-40, 1), (-115, 1), (-115, 1), (-235, 1), (-235, 1)]225226Over number fields K of many higher degrees this also works::227228sage: K.<a> = NumberField(x^3 - 2)229sage: cm_j_invariants_and_orders(K)230[(-3, 3, -12288000), (-3, 2, 54000), (-3, 1, 0), (-4, 2, 287496), (-4, 1, 1728), (-7, 2, 16581375), (-7, 1, -3375), (-8, 1, 8000), (-11, 1, -32768), (-19, 1, -884736), (-43, 1, -884736000), (-67, 1, -147197952000), (-163, 1, -262537412640768000), (-3, 6, 31710790944000*a^2 + 39953093016000*a + 50337742902000)]231"""232# Get the list of CM orders that could possibly have Hilbert class233# polynomial F(x) with a root in K. If F(x) has a root alpha in K,234# then F is the minimal polynomial of alpha in K, so the degree of235# F(x) is at most [K:QQ].236dlist = sum([v for h,v in discriminants_with_bounded_class_number(K.degree(), proof=proof).iteritems()], [])237238return [(D,f,j) for D, f in dlist239for j in hilbert_class_polynomial(D*f*f).roots(K, multiplicities=False)]240241242def cm_orders(h, proof=None):243"""244Return a list of all pairs `(D,f)` where there is a CM order of245discriminant `D f^2` with class number h, with `D` a fundamental246discriminant.247248INPUT:249250- `h` -- positive integer251- ``proof`` -- (default: proof.number_field())252253OUTPUT:254255- list of 2-tuples `(D,f)`256257EXAMPLES::258259sage: cm_orders(0)260[]261sage: v = cm_orders(1); v262[(-3, 3), (-3, 2), (-3, 1), (-4, 2), (-4, 1), (-7, 2), (-7, 1), (-8, 1), (-11, 1), (-19, 1), (-43, 1), (-67, 1), (-163, 1)]263sage: type(v[0][0]), type(v[0][1])264(<type 'sage.rings.integer.Integer'>, <type 'sage.rings.integer.Integer'>)265sage: v = cm_orders(2); v266[(-3, 7), (-3, 5), (-3, 4), (-4, 5), (-4, 4), (-4, 3), (-7, 4), (-8, 3), (-8, 2), (-11, 3), (-15, 2), (-15, 1), (-20, 1), (-24, 1), (-35, 1), (-40, 1), (-51, 1), (-52, 1), (-88, 1), (-91, 1), (-115, 1), (-123, 1), (-148, 1), (-187, 1), (-232, 1), (-235, 1), (-267, 1), (-403, 1), (-427, 1)]267sage: len(v)26829269sage: set([hilbert_class_polynomial(D*f^2).degree() for D,f in v])270set([2])271272Any degree up to 100 is implemented, but may be prohibitively slow::273274sage: cm_orders(3)275[(-3, 9), (-3, 6), (-11, 2), (-19, 2), (-23, 2), (-23, 1), (-31, 2), (-31, 1), (-43, 2), (-59, 1), (-67, 2), (-83, 1), (-107, 1), (-139, 1), (-163, 2), (-211, 1), (-283, 1), (-307, 1), (-331, 1), (-379, 1), (-499, 1), (-547, 1), (-643, 1), (-883, 1), (-907, 1)]276sage: len(cm_orders(4))27784278"""279h = Integer(h)280T = None281if h <= 0:282# trivial case283return []284# Get information for all discriminants then throw away everything285# but for h. If this is replaced by a table it will be faster,286# but not now. (David Kohel is rumored to have a large table.)287return discriminants_with_bounded_class_number(h, proof=proof)[h]288289# Table from Mark Watkins paper "Class numbers of imaginary quadratic fields".290# I extracted this by cutting/pasting from the pdf, and running this program:291# z = {}292# for X in open('/Users/wstein/tmp/a.txt').readlines():293# if len(X.strip()):294# v = [int(a) for a in X.split()]295# for i in range(5):296# z[v[3*i]]=(v[3*i+2], v[3*i+1])297watkins_table = {1: (163, 9), 2: (427, 18), 3: (907, 16), 4: (1555, 54), 5: (2683, 25),2986: (3763, 51), 7: (5923, 31), 8: (6307, 131), 9: (10627, 34), 10:299(13843, 87), 11: (15667, 41), 12: (17803, 206), 13: (20563, 37), 14:300(30067, 95), 15: (34483, 68), 16: (31243, 322), 17: (37123, 45), 18:301(48427, 150), 19: (38707, 47), 20: (58507, 350), 21: (61483, 85), 22:302(85507, 139), 23: (90787, 68), 24: (111763, 511), 25: (93307, 95), 26:303(103027, 190), 27: (103387, 93), 28: (126043, 457), 29: (166147, 83),30430: (134467, 255), 31: (133387, 73), 32: (164803, 708), 33: (222643, 101),30534: (189883, 219), 35: (210907, 103), 36: (217627, 668), 37:306(158923, 85), 38: (289963, 237), 39: (253507, 115), 40: (260947, 912),30741: (296587, 109), 42: (280267, 339), 43: (300787, 106), 44: (319867, 691),30845: (308323, 154), 46: (462883, 268), 47: (375523, 107), 48:309(335203, 1365), 49: (393187, 132), 50: (389467, 345), 51: (546067, 159),31052: (439147, 770), 53: (425107, 114), 54: (532123, 427), 55: (452083,163),31156: (494323, 1205), 57: (615883, 179), 58: (586987, 291),31259:(474307, 128), 60: (662803, 1302), 61: (606643, 132), 62: (647707, 323),31363: (991027, 216), 64: (693067, 1672), 65: (703123, 164), 66: (958483, 530),31467: (652723, 120), 68: (819163, 976), 69: (888427, 209), 70:(811507, 560),31571: (909547, 150), 72: (947923, 1930), 73: (886867, 119),31674: (951043, 407), 75: (916507, 237), 76: (1086187, 1075), 77: (1242763, 216),31778: (1004347, 561), 79: (1333963, 175), 80: (1165483, 2277), 81: (1030723, 228),31882: (1446547, 402), 83: (1074907, 150), 84: (1225387,1715),31985: (1285747, 221), 86: (1534723, 472), 87: (1261747, 222),32088:(1265587, 1905), 89: (1429387, 192), 90: (1548523, 801),32191: (1391083,214), 92: (1452067, 1248), 93: (1475203, 262), 94: (1587763, 509),32295:(1659067, 241), 96: (1684027, 3283), 97: (1842523, 185), 98: (2383747,580),32399: (1480627, 289), 100: (1856563, 1736)}324325def largest_fundamental_disc_with_class_number(h):326"""327Return largest absolute value of any fundamental discriminant with328class number `h`, and the number of fundamental discriminants with329that class number. This is known for `h` up to 100, by work of Mark330Watkins.331332INPUT:333334- `h` -- integer335336EXAMPLES::337338sage: sage.schemes.elliptic_curves.cm.largest_fundamental_disc_with_class_number(0)339(0, 0)340sage: sage.schemes.elliptic_curves.cm.largest_fundamental_disc_with_class_number(1)341(163, 9)342sage: sage.schemes.elliptic_curves.cm.largest_fundamental_disc_with_class_number(2)343(427, 18)344sage: sage.schemes.elliptic_curves.cm.largest_fundamental_disc_with_class_number(10)345(13843, 87)346sage: sage.schemes.elliptic_curves.cm.largest_fundamental_disc_with_class_number(100)347(1856563, 1736)348sage: sage.schemes.elliptic_curves.cm.largest_fundamental_disc_with_class_number(101)349Traceback (most recent call last):350...351NotImplementedError: largest discriminant not known for class number 101352"""353h = Integer(h)354if h <= 0:355# very easy special case356return Integer(0), Integer(0)357try:358# simply look up the answer in Watkins's table.359B, c = watkins_table[h]360return (Integer(B), Integer(c))361except KeyError:362# nobody knows, since I guess Watkins's is state of the art.363raise NotImplementedError, "largest discriminant not known for class number %s"%h364365def discriminants_with_bounded_class_number(hmax, B=None, proof=None):366"""367Return dictionary with keys class numbers `h\le hmax` and values the368list of all pairs `(D, f)`, with `D<0` a fundamental discriminant such369that `Df^2` has class number `h`. If the optional bound `B` is given,370return only those pairs with fundamental `|D| \le B`, though `f` can371still be arbitrarily large.372373INPUT:374375- ``hmax`` -- integer376- `B` -- integer or None; if None returns all pairs377- ``proof`` -- this code calls the PARI function ``qfbclassno``, so it378could give wrong answers when ``proof``==``False``. The default is379whatever ``proof.number_field()`` is. If ``proof==False`` and `B` is380``None``, at least the number of discriminants is correct, since it381is double checked with Watkins's table.382383OUTPUT:384385- dictionary386387In case `B` is not given, we use Mark Watkins's: "Class numbers of388imaginary quadratic fields" to compute a `B` that captures all `h`389up to `hmax` (only available for `hmax\le100`).390391EXAMPLES::392393sage: v = sage.schemes.elliptic_curves.cm.discriminants_with_bounded_class_number(3)394sage: v.keys()395[1, 2, 3]396sage: v[1]397[(-3, 3), (-3, 2), (-3, 1), (-4, 2), (-4, 1), (-7, 2), (-7, 1), (-8, 1), (-11, 1), (-19, 1), (-43, 1), (-67, 1), (-163, 1)]398sage: v[2]399[(-3, 7), (-3, 5), (-3, 4), (-4, 5), (-4, 4), (-4, 3), (-7, 4), (-8, 3), (-8, 2), (-11, 3), (-15, 2), (-15, 1), (-20, 1), (-24, 1), (-35, 1), (-40, 1), (-51, 1), (-52, 1), (-88, 1), (-91, 1), (-115, 1), (-123, 1), (-148, 1), (-187, 1), (-232, 1), (-235, 1), (-267, 1), (-403, 1), (-427, 1)]400sage: v[3]401[(-3, 9), (-3, 6), (-11, 2), (-19, 2), (-23, 2), (-23, 1), (-31, 2), (-31, 1), (-43, 2), (-59, 1), (-67, 2), (-83, 1), (-107, 1), (-139, 1), (-163, 2), (-211, 1), (-283, 1), (-307, 1), (-331, 1), (-379, 1), (-499, 1), (-547, 1), (-643, 1), (-883, 1), (-907, 1)]402sage: v = sage.schemes.elliptic_curves.cm.discriminants_with_bounded_class_number(8, proof=False)403sage: [len(v[h]) for h in v.keys()]404[13, 29, 25, 84, 29, 101, 38, 208]405406Find all class numbers for discriminant up to 50::407408sage: sage.schemes.elliptic_curves.cm.discriminants_with_bounded_class_number(hmax=5, B=50)409{1: [(-3, 3), (-3, 2), (-3, 1), (-4, 2), (-4, 1), (-7, 2), (-7, 1), (-8, 1), (-11, 1), (-19, 1), (-43, 1)], 2: [(-3, 7), (-3, 5), (-3, 4), (-4, 5), (-4, 4), (-4, 3), (-7, 4), (-8, 3), (-8, 2), (-11, 3), (-15, 2), (-15, 1), (-20, 1), (-24, 1), (-35, 1), (-40, 1)], 3: [(-3, 9), (-3, 6), (-11, 2), (-19, 2), (-23, 2), (-23, 1), (-31, 2), (-31, 1), (-43, 2)], 4: [(-3, 13), (-3, 11), (-3, 8), (-4, 10), (-4, 8), (-4, 7), (-4, 6), (-7, 8), (-7, 6), (-7, 3), (-8, 6), (-8, 4), (-11, 5), (-15, 4), (-19, 5), (-19, 3), (-20, 3), (-20, 2), (-24, 2), (-35, 3), (-39, 2), (-39, 1), (-40, 2), (-43, 3)], 5: [(-47, 2), (-47, 1)]}410"""411# imports that are needed only for this function412from sage.structure.proof.proof import get_flag413from sage.libs.pari.all import pari414import math415from sage.misc.functional import round416417# deal with input defaults and type checking418proof = get_flag(proof, 'number_field')419hmax = Integer(hmax)420421# T stores the output422T = {}423424# Easy case -- instead of giving error, give meaningful output425if hmax < 1:426return T427428if B is None:429# Determine how far we have to go by applying Watkins's theorem.430v = [largest_fundamental_disc_with_class_number(h) for h in range(1, hmax+1)]431B = max([b for b,_ in v])432fund_count = [0] + [cnt for _,cnt in v]433else:434# Nothing to do -- set to None so we can use this later to know not435# to do a double check about how many we find.436fund_count = None437B = Integer(B)438439if B <= 2:440# This is an easy special case, since there are no fundamental discriminants441# this small.442return T443444# This lower bound gets used in an inner loop below.445from math import log446def lb(f):447"""Lower bound on euler_phi."""448# 1.79 > e^gamma = 1.7810724...449if f <= 1: return 0 # don't do log(log(1)) = log(0)450return f/(1.79*log(log(f)) + 3.0/log(log(f)))451452# We define a little function to compute the class number of453# discriminant d quickly, using pari, with proof inherited from454# the containing scope. Fast classno functionality should455# probably be moved elsewhere in Sage, but I'm not sure where.456# The same line also occurs in the number fields code, but to use457# it requires making a number field, which is very slow, and this458# function must be fast, since it is the main bottleneck.459def classno(d):460"""Return the class number of the order of discriminant d."""461# There is currently no qfbclassno method in gen.pyx, hence the string.462return Integer(pari('qfbclassno(%s,%s)'%(d, 1 if proof else 0)))463464for D in range(-B, -2):465if is_fundamental_discriminant(D):466h_D = classno(D)467# For each fundamental discrimant D, loop through the f's such468# that h(D*f^2) could possibly be <= hmax. As explained to me by Cremona,469# we have h(D*f^2) >= (1/c)*h(D)*phi_D(f) >= (1/c)*h(D)*euler_phi(f), where470# phi_D(f) is like euler_phi(f) but the factor (1-1/p) is replaced471# by a factor of (1-kr(D,p)*p), where kr(D/p) is the Kronecker symbol.472# The factor c is 1 unless D=-4 and f>1 (when c=2) or D=-3 and f>1 (when c=3).473# Since (1-1/p) <= 1 and (1-1/p) <= (1+1/p), we see that474# euler_phi(f) <= phi_D(f).475#476# We have the following analytic lower bound on euler_phi:477#478# euler_phi(f) >= lb(f) = f / (exp(euler_gamma)*log(log(n)) + 3/log(log(n))).479#480# See Theorem 8 of Peter Clark's481# http://math.uga.edu/~pete/4400arithmeticorders.pdf482# which is a consequence of Theorem 15 of483# [Rosser and Schoenfeld, 1962].484#485# By Calculus, we see that the lb(f) is an increasing function of f >= 2.486#487# NOTE: You can visibly "see" that it is a lower bound in Sage with488# lb(n) = n/(exp(euler_gamma)*log(log(n)) + 3/log(log(n)))489# plot(lb, (n, 1, 10^4), color='red') + plot(lambda x: euler_phi(int(x)), 1, 10^4).show()490#491# So we consider f=1,2,..., until the first f with lb(f)*h_D > c*h_max.492# (Note that lb(f) is <= 0 for f=1,2, so nothing special is needed there.)493#494# TODO: Maybe we could do better using a bound for for phi_D(f).495#496f = 1497chmax=hmax498if D==-3:499chmax*=3500else:501if D==-4:502chmax*=2503while lb(f)*h_D <= chmax:504if f == 1:505h = h_D506else:507h = classno(D*f*f)508# If the class number of this order is within the range, then509# use it. (NOTE: In some cases there is a simple relation between510# the class number for D and D*f^2, and this could be used to511# optimize this inner loop a little.)512if h <= hmax:513z = (Integer(D), Integer(f))514if T.has_key(h):515T[h].append(z)516else:517T[h] = [z]518f += 1519520for h in T.keys():521T[h] = list(reversed(T[h]))522523if fund_count is not None:524# Double check that we found the right number of fundamental525# discriminants; we might as well, since Watkins provides this526# data.527for h in T.keys():528if len([D for D,f in T[h] if f==1]) != fund_count[h]:529raise RuntimeError, "number of discriminants inconsistent with Watkins's table"530531return T532533534535536537538