Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/schemes/elliptic_curves/cm.py
4127 views
1
"""
2
Complex multiplication for elliptic curves
3
4
This module implements the functions
5
6
- ``hilbert_class_polynomial``
7
- ``cm_j_invariants``
8
- ``cm_orders``
9
- ``discriminants_with_bounded_class_number``
10
- ``cm_j_invariants_and_orders``
11
- ``largest_fundamental_disc_with_class_number``
12
13
AUTHORS:
14
15
- Robert Bradshaw
16
- John Cremona
17
- William Stein
18
19
"""
20
21
#*****************************************************************************
22
# Copyright (C) 2005-2012 William Stein <[email protected]>
23
#
24
# Distributed under the terms of the GNU General Public License (GPL)
25
#
26
# This code is distributed in the hope that it will be useful,
27
# but WITHOUT ANY WARRANTY; without even the implied warranty of
28
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
29
# General Public License for more details.
30
#
31
# The full text of the GPL is available at:
32
#
33
# http://www.gnu.org/licenses/
34
#*****************************************************************************
35
36
from sage.interfaces.all import magma
37
from sage.rings.all import (Integer,
38
QQ,
39
IntegerRing,
40
is_fundamental_discriminant,
41
PolynomialRing)
42
43
def hilbert_class_polynomial(D, algorithm=None):
44
r"""
45
Returns the Hilbert class polynomial for discriminant `D`.
46
47
INPUT:
48
49
- ``D`` (int) -- a negative integer congruent to 0 or 1 modulo 4.
50
51
- ``algorithm`` (string, default None) -- if "sage" then use the Sage implementation; if "magma" then call Magma (if available).
52
53
OUTPUT:
54
55
(integer polynomial) The Hilbert class polynomial for the
56
discriminant `D`.
57
58
ALGORITHM:
59
60
- If ``algorithm`` = "sage": Use complex approximations to the roots.
61
62
- If ``algorithm`` = "magma": Call the appropriate Magma function.
63
64
AUTHORS:
65
66
- Sage implementation originally by Eduardo Ocampo Alvarez and
67
AndreyTimofeev
68
69
- Sage implementation corrected by John Cremona (using corrected precision bounds from Andreas Enge)
70
71
- Magma implementation by David Kohel
72
73
EXAMPLES::
74
75
sage: hilbert_class_polynomial(-4)
76
x - 1728
77
sage: hilbert_class_polynomial(-7)
78
x + 3375
79
sage: hilbert_class_polynomial(-23)
80
x^3 + 3491750*x^2 - 5151296875*x + 12771880859375
81
sage: hilbert_class_polynomial(-37*4)
82
x^2 - 39660183801072000*x - 7898242515936467904000000
83
sage: hilbert_class_polynomial(-37*4, algorithm="magma") # optional - magma
84
x^2 - 39660183801072000*x - 7898242515936467904000000
85
sage: hilbert_class_polynomial(-163)
86
x + 262537412640768000
87
sage: hilbert_class_polynomial(-163, algorithm="magma") # optional - magma
88
x + 262537412640768000
89
90
"""
91
if algorithm is None:
92
algorithm = "sage"
93
94
D = Integer(D)
95
if D >= 0:
96
raise ValueError, "D (=%s) must be negative"%D
97
if not (D%4 in [0,1]):
98
raise ValueError, "D (=%s) must be a discriminant"%D
99
100
if algorithm == "magma":
101
magma.eval("R<x> := PolynomialRing(IntegerRing())")
102
f = str(magma.eval("HilbertClassPolynomial(%s)"%D))
103
return IntegerRing()['x'](f)
104
105
if algorithm != "sage":
106
raise ValueError, "%s is not a valid algorithm"%algorithm
107
108
from sage.quadratic_forms.binary_qf import BinaryQF_reduced_representatives
109
from sage.rings.all import RR, ZZ, ComplexField
110
from sage.functions.all import elliptic_j
111
112
# get all primitive reduced quadratic forms, (necessary to exclude
113
# imprimitive forms when D is not a fundamental discriminant):
114
115
rqf = BinaryQF_reduced_representatives(D, primitive_only=True)
116
117
# compute needed precision
118
#
119
# NB: [http://arxiv.org/abs/0802.0979v1], quoting Enge (2006), is
120
# incorrect. Enge writes (2009-04-20 email to John Cremona) "The
121
# source is my paper on class polynomials
122
# [http://hal.inria.fr/inria-00001040] It was pointed out to me by
123
# the referee after ANTS that the constant given there was
124
# wrong. The final version contains a corrected constant on p.7
125
# which is consistent with your example. It says:
126
127
# "The logarithm of the absolute value of the coefficient in front
128
# of X^j is bounded above by
129
#
130
# log (2*k_2) * h + pi * sqrt(|D|) * sum (1/A_i)
131
#
132
# independently of j", where k_2 \approx 10.163.
133
134
h = len(rqf) # class number
135
c1 = 3.05682737291380 # log(2*10.63)
136
c2 = sum([1/RR(qf[0]) for qf in rqf], RR(0))
137
prec = c2*RR(3.142)*RR(D).abs().sqrt() + h*c1 # bound on log
138
prec = prec * 1.45 # bound on log_2 (1/log(2) = 1.44..)
139
prec = 10 + prec.ceil() # allow for rounding error
140
141
# set appropriate precision for further computing
142
143
Dsqrt = D.sqrt(prec=prec)
144
R = ComplexField(prec)['t']
145
t = R.gen()
146
pol = R(1)
147
for qf in rqf:
148
a, b, c = list(qf)
149
tau = (b+Dsqrt)/(a<<1)
150
pol *= (t - elliptic_j(tau))
151
152
coeffs = [cof.real().round() for cof in pol.coeffs()]
153
return IntegerRing()['x'](coeffs)
154
155
156
def cm_j_invariants(K, proof=None):
157
r"""
158
Return a list of all CM `j`-invariants in the field `K`.
159
160
INPUT:
161
162
- ``K`` -- a number field
163
- ``proof`` -- (default: proof.number_field())
164
165
OUTPUT:
166
167
(list) -- A list of CM `j`-invariants in the field `K`.
168
169
EXAMPLE::
170
171
sage: cm_j_invariants(QQ)
172
[-262537412640768000, -147197952000, -884736000, -12288000, -884736, -32768, -3375, 0, 1728, 8000, 54000, 287496, 16581375]
173
174
Over imaginary quadratic fields there are no more than over `QQ`::
175
176
sage: cm_j_invariants(QuadraticField(-1, 'i')) # sorted differently since QQ[i] sorts funny
177
[-12288000, 54000, 0, 287496, 1728, 16581375, -3375, 8000, -32768, -884736, -884736000, -147197952000, -262537412640768000]
178
179
Over real quadratic fields there may be more, for example::
180
181
sage: len(cm_j_invariants(QuadraticField(5, 'a')))
182
31
183
184
Over number fields K of many higher degrees this also works::
185
186
sage: K.<a> = NumberField(x^3 - 2)
187
sage: cm_j_invariants(K)
188
[-12288000, 54000, 0, 287496, 1728, 16581375, -3375, 8000, -32768, -884736, -884736000, -147197952000, -262537412640768000, 31710790944000*a^2 + 39953093016000*a + 50337742902000]
189
sage: K.<a> = NumberField(x^4 - 2)
190
sage: len(cm_j_invariants(K))
191
23
192
"""
193
return list(sorted([j for D,f,j in cm_j_invariants_and_orders(K, proof=proof)]))
194
195
def cm_j_invariants_and_orders(K, proof=None):
196
r"""
197
Return a list of all CM `j`-invariants in the field `K`, together with the associated orders.
198
199
INPUT:
200
201
- ``K`` -- a number field
202
- ``proof`` -- (default: proof.number_field())
203
204
OUTPUT:
205
206
(list) A list of 3-tuples `(D,f,j)` where `j` is a CM
207
`j`-invariant in `K` with quadratic fundamental discriminant `D`
208
and conductor `f`.
209
210
EXAMPLE::
211
212
sage: cm_j_invariants_and_orders(QQ)
213
[(-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)]
214
215
Over an imaginary quadratic field there are no more than over `QQ`::
216
217
sage: cm_j_invariants_and_orders(QuadraticField(-1, 'i'))
218
[(-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)]
219
220
Over real quadratic fields there may be more::
221
222
sage: v = cm_j_invariants_and_orders(QuadraticField(5,'a')); len(v)
223
31
224
sage: [(D,f) for D,f,j in v if j not in QQ]
225
[(-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)]
226
227
Over number fields K of many higher degrees this also works::
228
229
sage: K.<a> = NumberField(x^3 - 2)
230
sage: cm_j_invariants_and_orders(K)
231
[(-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)]
232
"""
233
# Get the list of CM orders that could possibly have Hilbert class
234
# polynomial F(x) with a root in K. If F(x) has a root alpha in K,
235
# then F is the minimal polynomial of alpha in K, so the degree of
236
# F(x) is at most [K:QQ].
237
dlist = sum([v for h,v in discriminants_with_bounded_class_number(K.degree(), proof=proof).iteritems()], [])
238
239
return [(D,f,j) for D, f in dlist
240
for j in hilbert_class_polynomial(D*f*f).roots(K, multiplicities=False)]
241
242
243
def cm_orders(h, proof=None):
244
"""
245
Return a list of all pairs `(D,f)` where there is a CM order of
246
discriminant `D f^2` with class number h, with `D` a fundamental
247
discriminant.
248
249
INPUT:
250
251
- `h` -- positive integer
252
- ``proof`` -- (default: proof.number_field())
253
254
OUTPUT:
255
256
- list of 2-tuples `(D,f)`
257
258
EXAMPLES::
259
260
sage: cm_orders(0)
261
[]
262
sage: v = cm_orders(1); v
263
[(-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)]
264
sage: type(v[0][0]), type(v[0][1])
265
(<type 'sage.rings.integer.Integer'>, <type 'sage.rings.integer.Integer'>)
266
sage: v = cm_orders(2); v
267
[(-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)]
268
sage: len(v)
269
29
270
sage: set([hilbert_class_polynomial(D*f^2).degree() for D,f in v])
271
set([2])
272
273
Any degree up to 100 is implemented, but may be prohibitively slow::
274
275
sage: cm_orders(3)
276
[(-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)]
277
sage: len(cm_orders(4))
278
84
279
"""
280
h = Integer(h)
281
T = None
282
if h <= 0:
283
# trivial case
284
return []
285
# Get information for all discriminants then throw away everything
286
# but for h. If this is replaced by a table it will be faster,
287
# but not now. (David Kohel is rumored to have a large table.)
288
return discriminants_with_bounded_class_number(h, proof=proof)[h]
289
290
# Table from Mark Watkins paper "Class numbers of imaginary quadratic fields".
291
# I extracted this by cutting/pasting from the pdf, and running this program:
292
# z = {}
293
# for X in open('/Users/wstein/tmp/a.txt').readlines():
294
# if len(X.strip()):
295
# v = [int(a) for a in X.split()]
296
# for i in range(5):
297
# z[v[3*i]]=(v[3*i+2], v[3*i+1])
298
watkins_table = {1: (163, 9), 2: (427, 18), 3: (907, 16), 4: (1555, 54), 5: (2683, 25),
299
6: (3763, 51), 7: (5923, 31), 8: (6307, 131), 9: (10627, 34), 10:
300
(13843, 87), 11: (15667, 41), 12: (17803, 206), 13: (20563, 37), 14:
301
(30067, 95), 15: (34483, 68), 16: (31243, 322), 17: (37123, 45), 18:
302
(48427, 150), 19: (38707, 47), 20: (58507, 350), 21: (61483, 85), 22:
303
(85507, 139), 23: (90787, 68), 24: (111763, 511), 25: (93307, 95), 26:
304
(103027, 190), 27: (103387, 93), 28: (126043, 457), 29: (166147, 83),
305
30: (134467, 255), 31: (133387, 73), 32: (164803, 708), 33: (222643, 101),
306
34: (189883, 219), 35: (210907, 103), 36: (217627, 668), 37:
307
(158923, 85), 38: (289963, 237), 39: (253507, 115), 40: (260947, 912),
308
41: (296587, 109), 42: (280267, 339), 43: (300787, 106), 44: (319867, 691),
309
45: (308323, 154), 46: (462883, 268), 47: (375523, 107), 48:
310
(335203, 1365), 49: (393187, 132), 50: (389467, 345), 51: (546067, 159),
311
52: (439147, 770), 53: (425107, 114), 54: (532123, 427), 55: (452083,163),
312
56: (494323, 1205), 57: (615883, 179), 58: (586987, 291),
313
59:(474307, 128), 60: (662803, 1302), 61: (606643, 132), 62: (647707, 323),
314
63: (991027, 216), 64: (693067, 1672), 65: (703123, 164), 66: (958483, 530),
315
67: (652723, 120), 68: (819163, 976), 69: (888427, 209), 70:(811507, 560),
316
71: (909547, 150), 72: (947923, 1930), 73: (886867, 119),
317
74: (951043, 407), 75: (916507, 237), 76: (1086187, 1075), 77: (1242763, 216),
318
78: (1004347, 561), 79: (1333963, 175), 80: (1165483, 2277), 81: (1030723, 228),
319
82: (1446547, 402), 83: (1074907, 150), 84: (1225387,1715),
320
85: (1285747, 221), 86: (1534723, 472), 87: (1261747, 222),
321
88:(1265587, 1905), 89: (1429387, 192), 90: (1548523, 801),
322
91: (1391083,214), 92: (1452067, 1248), 93: (1475203, 262), 94: (1587763, 509),
323
95:(1659067, 241), 96: (1684027, 3283), 97: (1842523, 185), 98: (2383747,580),
324
99: (1480627, 289), 100: (1856563, 1736)}
325
326
def largest_fundamental_disc_with_class_number(h):
327
"""
328
Return largest absolute value of any fundamental discriminant with
329
class number `h`, and the number of fundamental discriminants with
330
that class number. This is known for `h` up to 100, by work of Mark
331
Watkins.
332
333
INPUT:
334
335
- `h` -- integer
336
337
EXAMPLES::
338
339
sage: sage.schemes.elliptic_curves.cm.largest_fundamental_disc_with_class_number(0)
340
(0, 0)
341
sage: sage.schemes.elliptic_curves.cm.largest_fundamental_disc_with_class_number(1)
342
(163, 9)
343
sage: sage.schemes.elliptic_curves.cm.largest_fundamental_disc_with_class_number(2)
344
(427, 18)
345
sage: sage.schemes.elliptic_curves.cm.largest_fundamental_disc_with_class_number(10)
346
(13843, 87)
347
sage: sage.schemes.elliptic_curves.cm.largest_fundamental_disc_with_class_number(100)
348
(1856563, 1736)
349
sage: sage.schemes.elliptic_curves.cm.largest_fundamental_disc_with_class_number(101)
350
Traceback (most recent call last):
351
...
352
NotImplementedError: largest discriminant not known for class number 101
353
"""
354
h = Integer(h)
355
if h <= 0:
356
# very easy special case
357
return Integer(0), Integer(0)
358
try:
359
# simply look up the answer in Watkins's table.
360
B, c = watkins_table[h]
361
return (Integer(B), Integer(c))
362
except KeyError:
363
# nobody knows, since I guess Watkins's is state of the art.
364
raise NotImplementedError, "largest discriminant not known for class number %s"%h
365
366
def discriminants_with_bounded_class_number(hmax, B=None, proof=None):
367
"""
368
Return dictionary with keys class numbers `h\le hmax` and values the
369
list of all pairs `(D, f)`, with `D<0` a fundamental discriminant such
370
that `Df^2` has class number `h`. If the optional bound `B` is given,
371
return only those pairs with fundamental `|D| \le B`, though `f` can
372
still be arbitrarily large.
373
374
INPUT:
375
376
- ``hmax`` -- integer
377
- `B` -- integer or None; if None returns all pairs
378
- ``proof`` -- this code calls the PARI function ``qfbclassno``, so it
379
could give wrong answers when ``proof``==``False``. The default is
380
whatever ``proof.number_field()`` is. If ``proof==False`` and `B` is
381
``None``, at least the number of discriminants is correct, since it
382
is double checked with Watkins's table.
383
384
OUTPUT:
385
386
- dictionary
387
388
In case `B` is not given, we use Mark Watkins's: "Class numbers of
389
imaginary quadratic fields" to compute a `B` that captures all `h`
390
up to `hmax` (only available for `hmax\le100`).
391
392
EXAMPLES::
393
394
sage: v = sage.schemes.elliptic_curves.cm.discriminants_with_bounded_class_number(3)
395
sage: v.keys()
396
[1, 2, 3]
397
sage: v[1]
398
[(-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)]
399
sage: v[2]
400
[(-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)]
401
sage: v[3]
402
[(-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)]
403
sage: v = sage.schemes.elliptic_curves.cm.discriminants_with_bounded_class_number(8, proof=False)
404
sage: [len(v[h]) for h in v.keys()]
405
[13, 29, 25, 84, 29, 101, 38, 208]
406
407
Find all class numbers for discriminant up to 50::
408
409
sage: sage.schemes.elliptic_curves.cm.discriminants_with_bounded_class_number(hmax=5, B=50)
410
{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)]}
411
"""
412
# imports that are needed only for this function
413
from sage.structure.proof.proof import get_flag
414
from sage.libs.pari.gen import pari
415
import math
416
from sage.misc.functional import round
417
418
# deal with input defaults and type checking
419
proof = get_flag(proof, 'number_field')
420
hmax = Integer(hmax)
421
422
# T stores the output
423
T = {}
424
425
# Easy case -- instead of giving error, give meaningful output
426
if hmax < 1:
427
return T
428
429
if B is None:
430
# Determine how far we have to go by applying Watkins's theorem.
431
v = [largest_fundamental_disc_with_class_number(h) for h in range(1, hmax+1)]
432
B = max([b for b,_ in v])
433
fund_count = [0] + [cnt for _,cnt in v]
434
else:
435
# Nothing to do -- set to None so we can use this later to know not
436
# to do a double check about how many we find.
437
fund_count = None
438
B = Integer(B)
439
440
if B <= 2:
441
# This is an easy special case, since there are no fundamental discriminants
442
# this small.
443
return T
444
445
# This lower bound gets used in an inner loop below.
446
from math import log
447
def lb(f):
448
"""Lower bound on euler_phi."""
449
# 1.79 > e^gamma = 1.7810724...
450
if f <= 1: return 0 # don't do log(log(1)) = log(0)
451
return f/(1.79*log(log(f)) + 3.0/log(log(f)))
452
453
# We define a little function to compute the class number of
454
# discriminant d quickly, using pari, with proof inherited from
455
# the containing scope. Fast classno functionality should
456
# probably be moved elsewhere in Sage, but I'm not sure where.
457
# The same line also occurs in the number fields code, but to use
458
# it requires making a number field, which is very slow, and this
459
# function must be fast, since it is the main bottleneck.
460
def classno(d):
461
"""Return the class number of the order of discriminant d."""
462
# There is currently no qfbclassno method in gen.pyx, hence the string.
463
return Integer(pari('qfbclassno(%s,%s)'%(d, 1 if proof else 0)))
464
465
for D in range(-B, -2):
466
if is_fundamental_discriminant(D):
467
h_D = classno(D)
468
# For each fundamental discrimant D, loop through the f's such
469
# that h(D*f^2) could possibly be <= hmax. As explained to me by Cremona,
470
# we have h(D*f^2) >= (1/c)*h(D)*phi_D(f) >= (1/c)*h(D)*euler_phi(f), where
471
# phi_D(f) is like euler_phi(f) but the factor (1-1/p) is replaced
472
# by a factor of (1-kr(D,p)*p), where kr(D/p) is the Kronecker symbol.
473
# The factor c is 1 unless D=-4 and f>1 (when c=2) or D=-3 and f>1 (when c=3).
474
# Since (1-1/p) <= 1 and (1-1/p) <= (1+1/p), we see that
475
# euler_phi(f) <= phi_D(f).
476
#
477
# We have the following analytic lower bound on euler_phi:
478
#
479
# euler_phi(f) >= lb(f) = f / (exp(euler_gamma)*log(log(n)) + 3/log(log(n))).
480
#
481
# See Theorem 8 of Peter Clark's
482
# http://math.uga.edu/~pete/4400arithmeticorders.pdf
483
# which is a consequence of Theorem 15 of
484
# [Rosser and Schoenfeld, 1962].
485
#
486
# By Calculus, we see that the lb(f) is an increasing function of f >= 2.
487
#
488
# NOTE: You can visibly "see" that it is a lower bound in Sage with
489
# lb(n) = n/(exp(euler_gamma)*log(log(n)) + 3/log(log(n)))
490
# plot(lb, (n, 1, 10^4), color='red') + plot(lambda x: euler_phi(int(x)), 1, 10^4).show()
491
#
492
# So we consider f=1,2,..., until the first f with lb(f)*h_D > c*h_max.
493
# (Note that lb(f) is <= 0 for f=1,2, so nothing special is needed there.)
494
#
495
# TODO: Maybe we could do better using a bound for for phi_D(f).
496
#
497
f = 1
498
chmax=hmax
499
if D==-3:
500
chmax*=3
501
else:
502
if D==-4:
503
chmax*=2
504
while lb(f)*h_D <= chmax:
505
if f == 1:
506
h = h_D
507
else:
508
h = classno(D*f*f)
509
# If the class number of this order is within the range, then
510
# use it. (NOTE: In some cases there is a simple relation between
511
# the class number for D and D*f^2, and this could be used to
512
# optimize this inner loop a little.)
513
if h <= hmax:
514
z = (Integer(D), Integer(f))
515
if T.has_key(h):
516
T[h].append(z)
517
else:
518
T[h] = [z]
519
f += 1
520
521
for h in T.keys():
522
T[h] = list(reversed(T[h]))
523
524
if fund_count is not None:
525
# Double check that we found the right number of fundamental
526
# discriminants; we might as well, since Watkins provides this
527
# data.
528
for h in T.keys():
529
if len([D for D,f in T[h] if f==1]) != fund_count[h]:
530
raise RuntimeError, "number of discriminants inconsistent with Watkins's table"
531
532
return T
533
534
535
536
537
538