Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/schemes/plane_curves/projective_curve.py
4130 views
1
"""
2
Projective plane curves over a general ring
3
4
AUTHORS:
5
6
- William Stein (2005-11-13)
7
8
- David Joyner (2005-11-13)
9
10
- David Kohel (2006-01)
11
12
- Moritz Minzlaff (2010-11)
13
"""
14
15
#*****************************************************************************
16
# Copyright (C) 2005 William Stein <[email protected]>
17
#
18
# Distributed under the terms of the GNU General Public License (GPL)
19
#
20
# The full text of the GPL is available at:
21
#
22
# http://www.gnu.org/licenses/
23
#*****************************************************************************
24
25
from sage.interfaces.all import singular
26
from sage.misc.all import add, sage_eval
27
from sage.rings.all import degree_lowest_rational_function
28
29
from sage.schemes.generic.projective_space import is_ProjectiveSpace
30
31
from curve import Curve_generic_projective
32
33
class ProjectiveSpaceCurve_generic(Curve_generic_projective):
34
def _repr_type(self):
35
return "Projective Space"
36
37
def __init__(self, A, X):
38
if not is_ProjectiveSpace(A):
39
raise TypeError, "A (=%s) must be a projective space"%A
40
Curve_generic_projective.__init__(self, A, X)
41
d = self.dimension()
42
if d != 1:
43
raise ValueError, "defining equations (=%s) define a scheme of dimension %s != 1"%(X,d)
44
45
class ProjectiveCurve_generic(Curve_generic_projective):
46
def __init__(self, A, f):
47
if not (is_ProjectiveSpace(A) and A.dimension != 2):
48
raise TypeError, "Argument A (= %s) must be a projective plane."%A
49
Curve_generic_projective.__init__(self, A, [f])
50
51
def _repr_type(self):
52
return "Projective"
53
54
def arithmetic_genus(self):
55
r"""
56
Return the arithmetic genus of this curve.
57
58
This is the arithmetic genus `g_a(C)` as defined in
59
Hartshorne. If the curve has degree `d` then this is simply
60
`(d-1)(d-2)/2`. It need *not* equal the geometric genus
61
(the genus of the normalization of the curve).
62
63
EXAMPLE::
64
65
sage: x,y,z = PolynomialRing(GF(5), 3, 'xyz').gens()
66
sage: C = Curve(y^2*z^7 - x^9 - x*z^8); C
67
Projective Curve over Finite Field of size 5 defined by -x^9 + y^2*z^7 - x*z^8
68
sage: C.arithmetic_genus()
69
28
70
sage: C.genus()
71
4
72
"""
73
d = self.defining_polynomial().total_degree()
74
return int((d-1)*(d-2)/2)
75
76
def divisor_of_function(self, r):
77
"""
78
Return the divisor of a function on a curve.
79
80
INPUT: r is a rational function on X
81
82
OUTPUT:
83
84
85
- ``list`` - The divisor of r represented as a list of
86
coefficients and points. (TODO: This will change to a more
87
structural output in the future.)
88
89
90
EXAMPLES::
91
92
sage: FF = FiniteField(5)
93
sage: P2 = ProjectiveSpace(2, FF, names = ['x','y','z'])
94
sage: R = P2.coordinate_ring()
95
sage: x, y, z = R.gens()
96
sage: f = y^2*z^7 - x^9 - x*z^8
97
sage: C = Curve(f)
98
sage: K = FractionField(R)
99
sage: r = 1/x
100
sage: C.divisor_of_function(r) # todo: not implemented !!!!
101
[[-1, (0, 0, 1)]]
102
sage: r = 1/x^3
103
sage: C.divisor_of_function(r) # todo: not implemented !!!!
104
[[-3, (0, 0, 1)]]
105
"""
106
F = self.base_ring()
107
f = self.defining_polynomial()
108
x, y, z = f.parent().gens()
109
pnts = self.rational_points()
110
divf = []
111
for P in pnts:
112
if P[2] != F(0):
113
# What is the '5' in this line and the 'r()' in the next???
114
lcs = self.local_coordinates(P,5)
115
ldg = degree_lowest_rational_function(r(lcs[0],lcs[1]),z)
116
if ldg[0] != 0:
117
divf.append([ldg[0],P])
118
return divf
119
120
121
def local_coordinates(self, pt, n):
122
r"""
123
Return local coordinates to precision n at the given point.
124
125
Behaviour is flaky - some choices of `n` are worst that
126
others.
127
128
129
INPUT:
130
131
132
- ``pt`` - an F-rational point on X which is not a
133
point of ramification for the projection (x,y) - x.
134
135
- ``n`` - the number of terms desired
136
137
138
OUTPUT: x = x0 + t y = y0 + power series in t
139
140
EXAMPLES::
141
142
sage: FF = FiniteField(5)
143
sage: P2 = ProjectiveSpace(2, FF, names = ['x','y','z'])
144
sage: x, y, z = P2.coordinate_ring().gens()
145
sage: C = Curve(y^2*z^7-x^9-x*z^8)
146
sage: pt = C([2,3,1])
147
sage: C.local_coordinates(pt,9) # todo: not implemented !!!!
148
[2 + t, 3 + 3*t^2 + t^3 + 3*t^4 + 3*t^6 + 3*t^7 + t^8 + 2*t^9 + 3*t^11 + 3*t^12]
149
"""
150
151
f = self.defining_polynomial()
152
R = f.parent()
153
F = self.base_ring()
154
p = F.characteristic()
155
x0 = F(pt[0])
156
y0 = F(pt[1])
157
astr = ["a"+str(i) for i in range(1,2*n)]
158
x,y = R.gens()
159
R0 = PolynomialRing(F,2*n+2,names = [str(x),str(y),"t"]+astr)
160
vars0 = R0.gens()
161
t = vars0[2]
162
yt = y0*t**0 + add([vars0[i]*t**(i-2) for i in range(3,2*n+2)])
163
xt = x0+t
164
ft = f(xt,yt)
165
S = singular
166
S.eval('ring s = '+str(p)+','+str(R0.gens())+',lp;')
167
S.eval('poly f = '+str(ft))
168
cmd = 'matrix c = coeffs ('+str(ft)+',t)'
169
S.eval(cmd)
170
N = int(S.eval('size(c)'))
171
b = ["c["+str(i)+",1]," for i in range(2,N/2-4)]
172
b = ''.join(b)
173
b = b[:len(b)-1] #to cut off the trailing comma
174
cmd = 'ideal I = '+b
175
S.eval(cmd)
176
c = S.eval('slimgb(I)')
177
d = c.split("=")
178
d = d[1:]
179
d[len(d)-1] += "\n"
180
e = [x[:x.index("\n")] for x in d]
181
vals = []
182
for x in e:
183
for y in vars0:
184
if str(y) in x:
185
if len(x.replace(str(y),"")) != 0:
186
i = x.find("-")
187
if i>0:
188
vals.append([eval(x[1:i]),x[:i],F(eval(x[i+1:]))])
189
i = x.find("+")
190
if i>0:
191
vals.append([eval(x[1:i]),x[:i],-F(eval(x[i+1:]))])
192
else:
193
vals.append([eval(str(y)[1:]),str(y),F(0)])
194
vals.sort()
195
k = len(vals)
196
v = [x0+t,y0+add([vals[i][2]*t**(i+1) for i in range(k)])]
197
return v
198
199
def plot(self, *args, **kwds):
200
"""
201
Plot the real points of an affine patch of this projective
202
plane curve.
203
204
205
INPUT:
206
207
208
- ``self`` - an affine plane curve
209
210
- ``patch`` - (optional) the affine patch to be plotted; if not
211
specified, the patch corresponding to the last projective
212
coordinate being nonzero
213
214
- ``*args`` - optional tuples (variable, minimum, maximum) for
215
plotting dimensions
216
217
- ``**kwds`` - optional keyword arguments passed on to
218
``implicit_plot``
219
220
221
EXAMPLES:
222
223
A cuspidal curve::
224
225
sage: R.<x, y, z> = QQ[]
226
sage: C = Curve(x^3 - y^2*z)
227
sage: C.plot()
228
229
The other affine patches of the same curve::
230
231
sage: C.plot(patch=0)
232
sage: C.plot(patch=1)
233
234
An elliptic curve::
235
236
sage: E = EllipticCurve('101a')
237
sage: C = Curve(E)
238
sage: C.plot()
239
sage: C.plot(patch=0)
240
sage: C.plot(patch=1)
241
242
A hyperelliptic curve::
243
244
sage: P.<x> = QQ[]
245
sage: f = 4*x^5 - 30*x^3 + 45*x - 22
246
sage: C = HyperellipticCurve(f)
247
sage: C.plot()
248
sage: C.plot(patch=0)
249
sage: C.plot(patch=1)
250
"""
251
# if user hasn't specified a favourite affine patch, take the
252
# one avoiding "infinity", i.e. the one corresponding to the
253
# last projective coordinate being nonzero
254
patch = kwds.pop('patch', self.ngens() - 1)
255
from constructor import Curve
256
C = Curve(self.affine_patch(patch))
257
return C.plot(*args, **kwds)
258
259
def is_singular(C):
260
r"""
261
Returns whether the curve is singular or not.
262
263
EXAMPLES:
264
265
Over `\QQ`::
266
267
sage: F = QQ
268
sage: P2.<X,Y,Z> = ProjectiveSpace(F,2)
269
sage: C = Curve(X^3-Y^2*Z)
270
sage: C.is_singular()
271
True
272
273
Over a finite field::
274
275
sage: F = GF(19)
276
sage: P2.<X,Y,Z> = ProjectiveSpace(F,2)
277
sage: C = Curve(X^3+Y^3+Z^3)
278
sage: C.is_singular()
279
False
280
sage: D = Curve(X^4-X*Z^3)
281
sage: D.is_singular()
282
True
283
sage: E = Curve(X^5+19*Y^5+Z^5)
284
sage: E.is_singular()
285
True
286
sage: E = Curve(X^5+9*Y^5+Z^5)
287
sage: E.is_singular()
288
False
289
290
Over `\CC`::
291
292
sage: F = CC
293
sage: P2.<X,Y,Z> = ProjectiveSpace(F,2)
294
sage: C = Curve(X)
295
sage: C.is_singular()
296
False
297
sage: D = Curve(Y^2*Z-X^3)
298
sage: D.is_singular()
299
True
300
sage: E = Curve(Y^2*Z-X^3+Z^3)
301
sage: E.is_singular()
302
False
303
304
Showing that ticket #12187 is fixed::
305
306
sage: F.<X,Y,Z> = GF(2)[]
307
sage: G = Curve(X^2+Y*Z)
308
sage: G.is_singular()
309
False
310
"""
311
poly = C.defining_polynomial()
312
return poly.parent().ideal(poly.gradient()+[poly]).dimension()> 0
313
314
315
class ProjectiveCurve_finite_field(ProjectiveCurve_generic):
316
def rational_points_iterator(self):
317
r"""
318
Return a generator object for the rational points on this curve.
319
320
INPUT:
321
322
- ``self`` -- a projective curve
323
324
OUTPUT:
325
326
A generator of all the rational points on the curve defined over its base field.
327
328
EXAMPLE::
329
330
sage: F = GF(37)
331
sage: P2.<X,Y,Z> = ProjectiveSpace(F,2)
332
sage: C = Curve(X^7+Y*X*Z^5*55+Y^7*12)
333
sage: len(list(C.rational_points_iterator()))
334
37
335
336
::
337
338
sage: F = GF(2)
339
sage: P2.<X,Y,Z> = ProjectiveSpace(F,2)
340
sage: C = Curve(X*Y*Z)
341
sage: a = C.rational_points_iterator()
342
sage: a.next()
343
(1 : 0 : 0)
344
sage: a.next()
345
(0 : 1 : 0)
346
sage: a.next()
347
(1 : 1 : 0)
348
sage: a.next()
349
(0 : 0 : 1)
350
sage: a.next()
351
(1 : 0 : 1)
352
sage: a.next()
353
(0 : 1 : 1)
354
sage: a.next()
355
Traceback (most recent call last):
356
...
357
StopIteration
358
359
::
360
361
sage: F = GF(3^2,'a')
362
sage: P2.<X,Y,Z> = ProjectiveSpace(F,2)
363
sage: C = Curve(X^3+5*Y^2*Z-33*X*Y*X)
364
sage: b = C.rational_points_iterator()
365
sage: b.next()
366
(0 : 1 : 0)
367
sage: b.next()
368
(0 : 0 : 1)
369
sage: b.next()
370
(2*a + 2 : 2*a : 1)
371
sage: b.next()
372
(2 : a + 1 : 1)
373
sage: b.next()
374
(a + 1 : a + 2 : 1)
375
sage: b.next()
376
(1 : 2 : 1)
377
sage: b.next()
378
(2*a + 2 : a : 1)
379
sage: b.next()
380
(2 : 2*a + 2 : 1)
381
sage: b.next()
382
(a + 1 : 2*a + 1 : 1)
383
sage: b.next()
384
(1 : 1 : 1)
385
sage: b.next()
386
Traceback (most recent call last):
387
...
388
StopIteration
389
390
"""
391
g = self.defining_polynomial()
392
K = g.parent().base_ring()
393
from sage.rings.polynomial.all import PolynomialRing
394
R = PolynomialRing(K,'X')
395
X = R.gen()
396
one = K.one_element()
397
zero = K.zero_element()
398
399
# the point with Z = 0 = Y
400
try:
401
t = self.point([one,zero,zero])
402
yield(t)
403
except TypeError:
404
pass
405
406
# points with Z = 0, Y = 1
407
g10 = R(g(X,one,zero))
408
if g10.is_zero():
409
for x in K:
410
yield(self.point([x,one,zero]))
411
else:
412
for x in g10.roots(multiplicities=False):
413
yield(self.point([x,one,zero]))
414
415
# points with Z = 1
416
for y in K:
417
gy1 = R(g(X,y,one))
418
if gy1.is_zero():
419
for x in K:
420
yield(self.point([x,y,one]))
421
else:
422
for x in gy1.roots(multiplicities=False):
423
yield(self.point([x,y,one]))
424
425
def rational_points(self, algorithm="enum", sort=True):
426
r"""
427
Return the rational points on this curve computed via enumeration.
428
429
430
INPUT:
431
432
- ``algorithm`` (string, default: 'enum') -- the algorithm to
433
use. Currently this is ignored.
434
435
- ``sort`` (boolean, default ``True``) -- whether the output
436
points should be sorted. If False, the order of the output
437
is non-deterministic.
438
439
OUTPUT:
440
441
A list of all the rational points on the curve defined over
442
its base field, possibly sorted.
443
444
.. note::
445
446
This is a slow Python-level implementation.
447
448
449
EXAMPLES::
450
451
sage: F = GF(7)
452
sage: P2.<X,Y,Z> = ProjectiveSpace(F,2)
453
sage: C = Curve(X^3+Y^3-Z^3)
454
sage: C.rational_points()
455
[(0 : 1 : 1), (0 : 2 : 1), (0 : 4 : 1), (1 : 0 : 1), (2 : 0 : 1), (3 : 1 : 0), (4 : 0 : 1), (5 : 1 : 0), (6 : 1 : 0)]
456
457
458
::
459
460
sage: F = GF(1237)
461
sage: P2.<X,Y,Z> = ProjectiveSpace(F,2)
462
sage: C = Curve(X^7+7*Y^6*Z+Z^4*X^2*Y*89)
463
sage: len(C.rational_points())
464
1237
465
466
::
467
468
sage: F = GF(2^6,'a')
469
sage: P2.<X,Y,Z> = ProjectiveSpace(F,2)
470
sage: C = Curve(X^5+11*X*Y*Z^3 + X^2*Y^3 - 13*Y^2*Z^3)
471
sage: len(C.rational_points())
472
104
473
474
::
475
476
sage: R.<x,y,z> = GF(2)[]
477
sage: f = x^3*y + y^3*z + x*z^3
478
sage: C = Curve(f); pts = C.rational_points()
479
sage: pts
480
[(0 : 0 : 1), (0 : 1 : 0), (1 : 0 : 0)]
481
482
"""
483
points = list(self.rational_points_iterator())
484
if sort:
485
points.sort()
486
return points
487
488
class ProjectiveCurve_prime_finite_field(ProjectiveCurve_finite_field):
489
def _points_via_singular(self, sort=True):
490
r"""
491
Return all rational points on this curve, computed using Singular's
492
Brill-Noether implementation.
493
494
INPUT:
495
496
497
- ``sort`` - bool (default: True), if True return the
498
point list sorted. If False, returns the points in the order
499
computed by Singular.
500
501
502
EXAMPLE::
503
504
sage: x, y, z = PolynomialRing(GF(5), 3, 'xyz').gens()
505
sage: f = y^2*z^7 - x^9 - x*z^8
506
sage: C = Curve(f); C
507
Projective Curve over Finite Field of size 5 defined by
508
-x^9 + y^2*z^7 - x*z^8
509
sage: C._points_via_singular()
510
[(0 : 0 : 1), (0 : 1 : 0), (2 : 2 : 1), (2 : 3 : 1),
511
(3 : 1 : 1), (3 : 4 : 1)]
512
sage: C._points_via_singular(sort=False) #random
513
[(0 : 1 : 0), (3 : 1 : 1), (3 : 4 : 1), (2 : 2 : 1),
514
(0 : 0 : 1), (2 : 3 : 1)]
515
516
517
.. note::
518
519
The Brill-Noether package does not always work (i.e., the
520
'bn' algorithm. When it fails a RuntimeError exception is
521
raised.
522
"""
523
f = self.defining_polynomial()._singular_()
524
singular = f.parent()
525
singular.lib('brnoeth')
526
try:
527
X1 = f.Adj_div()
528
except (TypeError, RuntimeError), s:
529
raise RuntimeError, str(s) + "\n\n ** Unable to use the\
530
Brill-Noether Singular package to\
531
compute all points (see above)."
532
533
X2 = singular.NSplaces(1, X1)
534
R = X2[5][1][1]
535
singular.set_ring(R)
536
537
# We use sage_flattened_str_list since iterating through
538
# the entire list through the sage/singular interface directly
539
# would involve hundreds of calls to singular, and timing issues with
540
# the expect interface could crop up. Also, this is vastly
541
# faster (and more robust).
542
v = singular('POINTS').sage_flattened_str_list()
543
pnts = [self(int(v[3*i]), int(v[3*i+1]), int(v[3*i+2]))
544
for i in range(len(v)/3)]
545
# singular always dehomogenizes with respect to the last variable
546
# so if this variable divides the curve equation, we need to add
547
# points at infinity
548
F = self.defining_polynomial()
549
z = F.parent().gens()[-1]
550
if z.divides(F):
551
pnts += [self(1,a,0) for a in self.base_ring()]
552
pnts += [self(0,1,0)]
553
# remove multiple points
554
pnts = list(set(pnts))
555
if sort:
556
pnts.sort()
557
return pnts
558
559
def riemann_roch_basis(self, D):
560
r"""
561
Return a basis for the Riemann-Roch space corresponding to
562
`D`.
563
564
This uses Singular's Brill-Noether implementation.
565
566
INPUT:
567
568
- ``D`` - a divisor
569
570
OUTPUT:
571
572
A list of function field elements that form a basis of the Riemann-Roch space
573
574
EXAMPLE::
575
576
sage: R.<x,y,z> = GF(2)[]
577
sage: f = x^3*y + y^3*z + x*z^3
578
sage: C = Curve(f); pts = C.rational_points()
579
sage: D = C.divisor([ (4, pts[0]), (4, pts[2]) ])
580
sage: C.riemann_roch_basis(D)
581
[x/y, 1, z/y, z^2/y^2, z/x, z^2/(x*y)]
582
583
::
584
585
sage: R.<x,y,z> = GF(5)[]
586
sage: f = x^7 + y^7 + z^7
587
sage: C = Curve(f); pts = C.rational_points()
588
sage: D = C.divisor([ (3, pts[0]), (-1,pts[1]), (10, pts[5]) ])
589
sage: C.riemann_roch_basis(D)
590
[(-2*x + y)/(x + y), (-x + z)/(x + y)]
591
592
593
.. NOTE::
594
Currently this only works over prime field and divisors supported on rational points.
595
"""
596
f = self.defining_polynomial()._singular_()
597
singular = f.parent()
598
singular.lib('brnoeth')
599
try:
600
X1 = f.Adj_div()
601
except (TypeError, RuntimeError), s:
602
raise RuntimeError, str(s) + "\n\n ** Unable to use the Brill-Noether Singular package to compute all points (see above)."
603
X2 = singular.NSplaces(1, X1)
604
# retrieve list of all computed closed points (possibly of degree >1)
605
v = X2[3].sage_flattened_str_list() # We use sage_flattened_str_list since iterating through
606
# the entire list through the sage/singular interface directly
607
# would involve hundreds of calls to singular, and timing issues with
608
# the expect interface could crop up. Also, this is vastly
609
# faster (and more robust).
610
v = [ v[i].partition(',') for i in range(len(v)) ]
611
pnts = [ ( int(v[i][0]), int(v[i][2])-1 ) for i in range(len(v))]
612
# retrieve coordinates of rational points
613
R = X2[5][1][1]
614
singular.set_ring(R)
615
v = singular('POINTS').sage_flattened_str_list()
616
coords = [self(int(v[3*i]), int(v[3*i+1]), int(v[3*i+2])) for i in range(len(v)/3)]
617
# build correct representation of D for singular
618
Dsupport = D.support()
619
Dcoeffs = []
620
for x in pnts:
621
if x[0] == 1:
622
Dcoeffs.append(D.coefficient(coords[x[1]]))
623
else:
624
Dcoeffs.append(0)
625
Dstr = str(tuple(Dcoeffs))
626
G = singular(','.join([str(x) for x in Dcoeffs]), type='intvec')
627
# call singular's brill noether routine and return
628
T = X2[1][2]
629
T.set_ring()
630
LG = G.BrillNoether(X2)
631
LG = [X.split(',\n') for X in LG.sage_structured_str_list()]
632
x,y,z = self.ambient_space().coordinate_ring().gens()
633
vars = {'x':x, 'y':y, 'z':z}
634
V = [(sage_eval(a, vars)/sage_eval(b, vars)) for a, b in LG]
635
return V
636
637
def rational_points(self, algorithm="enum", sort=True):
638
r"""
639
INPUT:
640
641
642
- ``algorithm`` - string:
643
644
- ``'enum'`` - straightforward enumeration
645
646
- ``'bn'`` - via Singular's brnoeth package.
647
648
649
EXAMPLE::
650
651
sage: x, y, z = PolynomialRing(GF(5), 3, 'xyz').gens()
652
sage: f = y^2*z^7 - x^9 - x*z^8
653
sage: C = Curve(f); C
654
Projective Curve over Finite Field of size 5 defined by
655
-x^9 + y^2*z^7 - x*z^8
656
sage: C.rational_points()
657
[(0 : 0 : 1), (0 : 1 : 0), (2 : 2 : 1), (2 : 3 : 1),
658
(3 : 1 : 1), (3 : 4 : 1)]
659
sage: C = Curve(x - y + z)
660
sage: C.rational_points()
661
[(0 : 1 : 1), (1 : 1 : 0), (1 : 2 : 1), (2 : 3 : 1),
662
(3 : 4 : 1), (4 : 0 : 1)]
663
sage: C = Curve(x*z+z^2)
664
sage: C.rational_points('all')
665
[(0 : 1 : 0), (1 : 0 : 0), (1 : 1 : 0), (2 : 1 : 0),
666
(3 : 1 : 0), (4 : 0 : 1), (4 : 1 : 0), (4 : 1 : 1),
667
(4 : 2 : 1), (4 : 3 : 1), (4 : 4 : 1)]
668
669
.. note::
670
671
The Brill-Noether package does not always work (i.e., the
672
'bn' algorithm. When it fails a RuntimeError exception is
673
raised.
674
"""
675
if algorithm == "enum":
676
677
return ProjectiveCurve_finite_field.rational_points(self,
678
algorithm="enum",
679
sort=sort)
680
681
elif algorithm == "bn":
682
683
return self._points_via_singular(sort=sort)
684
685
elif algorithm == "all":
686
687
S_enum = self.rational_points(algorithm = "enum")
688
S_bn = self.rational_points(algorithm = "bn")
689
if S_enum != S_bn:
690
raise RuntimeError, "Bug in rational_points -- different\
691
algorithms give different answers for\
692
curve %s!"%self
693
return S_enum
694
695
else:
696
697
raise ValueError, "No algorithm '%s' known"%algorithm
698
699
def Hasse_bounds(q, genus=1):
700
r"""
701
Return the Hasse-Weil bounds for the cardinality of a nonsingular
702
curve defined over `\GF{q}` of given ``genus``.
703
704
INPUT:
705
706
- ``q`` (int) -- a prime power
707
708
- ``genus`` (int, default 1) -- a non-negative integer,
709
710
OUTPUT:
711
712
(tuple) The Hasse bounds (lb,ub) for the cardinality of a curve of
713
genus ``genus`` defined over `\GF{q}`.
714
715
EXAMPLES::
716
717
sage: Hasse_bounds(2)
718
(1, 5)
719
sage: Hasse_bounds(next_prime(10^30))
720
(999999999999998000000000000058, 1000000000000002000000000000058)
721
"""
722
if genus==1:
723
rq = (4*q).isqrt()
724
else:
725
rq = (4*(genus**2)*q).isqrt()
726
return (q+1-rq,q+1+rq)
727
728
729