Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py
8820 views
1
r"""
2
Hyperelliptic curves over a finite field
3
4
EXAMPLES::
5
6
sage: K.<a> = GF(9, 'a')
7
sage: x = polygen(K)
8
sage: C = HyperellipticCurve(x^7 - x^5 - 2, x^2 + a)
9
sage: C._points_fast_sqrt()
10
[(0 : 1 : 0), (a + 1 : a : 1), (a + 1 : a + 1 : 1), (2 : a + 1 : 1), (2*a : 2*a + 2 : 1), (2*a : 2*a : 1), (1 : a + 1 : 1)]
11
12
"""
13
14
#*****************************************************************************
15
# Copyright (C) 2006 David Kohel <[email protected]>
16
# Copyright (C) 2007 Robert Bradshaw <[email protected]>
17
# Copyright (C) 2010 Alyson Deines <[email protected]>, Marina Gresham
18
# <[email protected]>, Gagan Sekhon <[email protected]>
19
# Distributed under the terms of the GNU General Public License (GPL)
20
# http://www.gnu.org/licenses/
21
#*****************************************************************************
22
23
from sage.rings.all import ZZ, RR, binomial
24
import hyperelliptic_generic
25
from sage.schemes.hyperelliptic_curves.hypellfrob import hypellfrob
26
from sage.misc.cachefunc import cached_method
27
from sage.matrix.constructor import identity_matrix, matrix
28
from sage.misc.functional import rank
29
30
31
class HyperellipticCurve_finite_field(hyperelliptic_generic.HyperellipticCurve_generic):
32
33
def _frobenius_coefficient_bound(self):
34
"""
35
Computes bound on number of p-adic digits needed to recover
36
frobenius polynomial, i.e. returns B so that knowledge of
37
a_1, ..., a_g modulo p^B determine frobenius polynomial uniquely.
38
39
TESTS::
40
41
sage: R.<t> = PolynomialRing(GF(37))
42
sage: HyperellipticCurve(t^3 + t + 1)._frobenius_coefficient_bound()
43
1
44
sage: HyperellipticCurve(t^5 + t + 1)._frobenius_coefficient_bound()
45
2
46
sage: HyperellipticCurve(t^7 + t + 1)._frobenius_coefficient_bound()
47
3
48
49
sage: R.<t> = PolynomialRing(GF(next_prime(10^9)))
50
sage: HyperellipticCurve(t^3 + t + 1)._frobenius_coefficient_bound()
51
1
52
sage: HyperellipticCurve(t^5 + t + 1)._frobenius_coefficient_bound()
53
2
54
sage: HyperellipticCurve(t^7 + t + 1)._frobenius_coefficient_bound()
55
2
56
sage: HyperellipticCurve(t^9 + t + 1)._frobenius_coefficient_bound()
57
3
58
sage: HyperellipticCurve(t^11 + t + 1)._frobenius_coefficient_bound()
59
3
60
sage: HyperellipticCurve(t^13 + t + 1)._frobenius_coefficient_bound()
61
4
62
"""
63
assert self.base_ring().is_finite()
64
p = self.base_ring().characteristic()
65
q = self.base_ring().order()
66
sqrtq = RR(q).sqrt()
67
g = self.genus()
68
69
# note: this bound is from Kedlaya's paper, but he tells me it's not
70
# the best possible
71
M = 2 * binomial(2*g, g) * sqrtq**g
72
B = ZZ(M.ceil()).exact_log(p)
73
if p**B < M:
74
B += 1
75
return B
76
77
78
def _frobenius_matrix(self, N=None):
79
"""
80
Compute p-adic frobenius matrix to precision p^N. If N not supplied,
81
a default value is selected, which is the minimum needed to recover
82
the charpoly unambiguously.
83
84
Currently only implemented using hypellfrob, which means only works
85
over GF(p^1), and must have p > (2g+1)(2N-1).
86
87
TESTS::
88
89
sage: R.<t> = PolynomialRing(GF(37))
90
sage: H = HyperellipticCurve(t^5 + t + 2)
91
sage: H._frobenius_matrix()
92
[1258 + O(37^2) 925 + O(37^2) 132 + O(37^2) 587 + O(37^2)]
93
[1147 + O(37^2) 814 + O(37^2) 241 + O(37^2) 1011 + O(37^2)]
94
[1258 + O(37^2) 1184 + O(37^2) 1105 + O(37^2) 482 + O(37^2)]
95
[1073 + O(37^2) 999 + O(37^2) 772 + O(37^2) 929 + O(37^2)]
96
97
"""
98
p = self.base_ring().characteristic()
99
f, h = self.hyperelliptic_polynomials()
100
if h != 0:
101
# need y^2 = f(x)
102
raise NotImplementedError, "only implemented for curves y^2 = f(x)"
103
104
sign = 1
105
if not f.is_monic():
106
# at this time we need a monic f
107
c = f.leading_coefficient()
108
f = f / c
109
if c.is_square():
110
# solutions of $y^2 = c * f(x)$ correspond naturally to
111
# solutions of $(sqrt(c) y)^2 = f(x)$
112
pass
113
else:
114
# we'll count points on a twist and then correct by untwisting...
115
sign = -1
116
assert f.is_monic()
117
118
if N is None:
119
N = self._frobenius_coefficient_bound()
120
121
matrix_of_frobenius = hypellfrob(p, N, f)
122
matrix_of_frobenius = sign * matrix_of_frobenius
123
return matrix_of_frobenius
124
125
126
def frobenius_polynomial(self):
127
"""
128
Charpoly of frobenius, as an element of ZZ[x].
129
130
TESTS::
131
132
sage: R.<t> = PolynomialRing(GF(37))
133
sage: H = HyperellipticCurve(t^5 + t + 2)
134
sage: H.frobenius_polynomial()
135
x^4 + x^3 - 52*x^2 + 37*x + 1369
136
137
A quadratic twist:
138
139
::
140
141
sage: H = HyperellipticCurve(2*t^5 + 2*t + 4)
142
sage: H.frobenius_polynomial()
143
x^4 - x^3 - 52*x^2 - 37*x + 1369
144
145
"""
146
p = self.base_ring().characteristic()
147
g = self.genus()
148
N = self._frobenius_coefficient_bound()
149
# compute chapoly over ZZ and then reduce back
150
# (because charpoly of p-adic matrices sometimes loses precision)
151
M = self._frobenius_matrix(N=N).change_ring(ZZ)
152
153
# get a_g, ..., a_0 in ZZ (i.e. with correct signs)
154
f = M.charpoly().list()[g:2*g+1]
155
ppow = p**N
156
f = [x % ppow for x in f]
157
f = [x if 2*x < ppow else x - ppow for x in f]
158
159
# get a_{2g}, ..., a_{g+1}
160
f = [f[g-i] * p**(g-i) for i in range(g)] + f
161
162
return ZZ['x'](f)
163
164
165
166
def _points_fast_sqrt(self):
167
"""
168
Count points by enumerating over x and solving the resulting
169
quadratic for y.
170
171
EXAMPLES::
172
173
sage: K.<a> = GF(9, 'a')
174
sage: x = polygen(K)
175
sage: C = HyperellipticCurve(x^7 - 1, x^2 + a)
176
sage: C._points_fast_sqrt()
177
[(0 : 1 : 0), (a : 2*a + 1 : 1), (2 : a + 1 : 1), (2*a + 2 : 2*a : 1), (2*a + 2 : 1 : 1), (1 : 2*a + 2 : 1), (1 : 0 : 1)]
178
sage: K.<a> = GF(49, 'a')
179
sage: x = polygen(K)
180
sage: C = HyperellipticCurve(x^5 - x^2 - 1, x^2 + a)
181
sage: len(C._points_fast_sqrt())
182
31
183
184
TESTS::
185
186
sage: x = polygen(GF(16, 'a'))
187
sage: C = HyperellipticCurve(x^5 - x + 1, x^2 + x + 1)
188
sage: set(C._points_fast_sqrt()) == set(C._points_cache_sqrt())
189
True
190
sage: x = polygen(GF(19))
191
sage: C = HyperellipticCurve(x^5 + 5*x^2 + 1, x + 1)
192
sage: set(C._points_fast_sqrt()) == set(C._points_cache_sqrt())
193
True
194
sage: x = polygen(GF(13))
195
sage: C = HyperellipticCurve(x^3 + x^2 - 1)
196
sage: C._points_fast_sqrt()
197
[(0 : 1 : 0), (0 : 5 : 1), (0 : 8 : 1), (1 : 1 : 1), (1 : 12 : 1), (3 : 3 : 1), (3 : 10 : 1), (4 : 1 : 1), (4 : 12 : 1), (6 : 2 : 1), (6 : 11 : 1), (7 : 1 : 1), (7 : 12 : 1), (8 : 4 : 1), (8 : 9 : 1), (9 : 4 : 1), (9 : 9 : 1), (12 : 5 : 1), (12 : 8 : 1)]
198
sage: set(C._points_fast_sqrt()) == set(C._points_cache_sqrt())
199
True
200
"""
201
# For givaro finite fields, taking square roots is very fast
202
# so no need to cache as in prime case
203
K = self.base_ring()
204
f, h = self.hyperelliptic_polynomials()
205
one = K(1)
206
207
# start with the points at infinity
208
P = self.defining_polynomial()
209
if not P(K(0), K(1), K(0)):
210
# (0:1:0) is a point on the curve
211
points = [self.point([K(0), K(1), K(0)], check=True)]
212
else:
213
points=[]
214
if P.degree() > 2:
215
# P(1, y, 0) = r*y + s
216
s = P(K(1), K(0), K(0))
217
r = P(K(1), K(1), K(0)) - s
218
if r: # r not zero
219
points.append(self.point([K(1), -s/r, K(0)], check=True))
220
# the case r = 0 need not be considered
221
elif K.characteristic() == 2: # deg(P) = 2 and char(K) = 2
222
# quadratic equation doesn't work in characteristic 2 so use brute
223
# force
224
points += [self.point([K(1), y, K(0)], check=True) for y in K \
225
if not P(K(1), y, K(0))]
226
else: # deg(P) = 2 and char(K) not 2
227
# P(1, y, 0) = y^2 + r*y + s
228
s = -f[2]
229
r = h[1]
230
d = r**2/4 - s
231
if not d: # d = 0
232
points.append(self.point([K(1), -r/2, K(0)], check=True))
233
elif d.is_square():
234
sqrtd = d.sqrt()
235
points.append(self.point([K(1), -r/2+sqrtd, K(0)], check=True))
236
points.append(self.point([K(1), -r/2-sqrtd, K(0)], check=True))
237
238
if K.characteristic() == 2:
239
# quadratic equation doesn't work in characteristic 2
240
if h.is_zero():
241
for x in K:
242
points.append(self.point([x, f(x).sqrt(), one], check=True))
243
else:
244
R = f.base_ring()
245
a_sqrts = { } # Artin-Schreier 2-roots
246
for x in K:
247
a_sqrts[x**2 + x] = x # char 2 => x^2 - x == x^2 + x
248
for x in K:
249
b = h(x)
250
c = f(x)
251
if b:
252
try:
253
r = a_sqrts[c / b**2]
254
points.append(self.point([x, r*b, one], check=True))
255
points.append(self.point([x, r*b+b, one], check=True))
256
except KeyError:
257
# y^2 + by + c irreducible, so yields no points
258
pass
259
else: # b == 0
260
points.append(self.point([x, c.sqrt(), one], check=True))
261
elif h.is_zero():
262
# special case to save work if we are of the form y^2 = f(x)
263
for x in K:
264
y2 = f(x)
265
if not y2: # y = 0
266
points.append(self.point([x, y2, one], check=True))
267
elif y2.is_square():
268
y = y2.sqrt()
269
points.append(self.point([x, y, one], check=True))
270
points.append(self.point([x, -y, one], check=True))
271
else:
272
b = -h/2
273
D = b*b + f
274
for x in K:
275
Dval = D(x)
276
if not Dval: # D(x) = 0
277
points.append(self.point([x, b(x), one], check=True))
278
elif Dval.is_square():
279
sqrtD = Dval.sqrt()
280
v = b(x)
281
points.append(self.point([x, v+sqrtD, one], check=True))
282
points.append(self.point([x, v-sqrtD, one], check=True))
283
return points
284
285
def _points_cache_sqrt(self, brute_force=False):
286
"""
287
Count points by enumerating over x and solving the resulting
288
quadratic for y.
289
290
Caches all square roots ahead of time by squaring every element of
291
the field. Elements must have an __index__ method.
292
293
EXAMPLES::
294
295
sage: x = polygen(GF(7))
296
sage: C = HyperellipticCurve(x^3 + x^2 - 1)
297
sage: C._points_cache_sqrt()
298
[(0 : 1 : 0), (1 : 6 : 1), (1 : 1 : 1), (2 : 5 : 1), (2 : 2 : 1), (3 : 0 : 1), (4 : 4 : 1), (4 : 3 : 1), (5 : 4 : 1), (5 : 3 : 1)]
299
sage: set(C._points_cache_sqrt()) == set(C._points_cache_sqrt(brute_force=True))
300
True
301
"""
302
K = self.base_ring()
303
if K.characteristic() != 2:
304
# cache the squares (faster than O(p) sqrts)
305
square_roots = [None] * len(K)
306
for x in K:
307
square_roots[x*x] = x
308
f, h = self.hyperelliptic_polynomials()
309
one = K(1)
310
311
# start with the points at infinity
312
P = self.defining_polynomial()
313
if not P(K(0), K(1), K(0)):
314
# (0:1:0) is a point on the curve
315
points = [self.point([K(0), K(1), K(0)], check=True)]
316
else:
317
points=[]
318
if P.degree() > 2:
319
# P(1, y, 0) = r*y + s
320
s = P(K(1), K(0), K(0))
321
r = P(K(1), K(1), K(0)) - s
322
if r: # r not zero
323
points.append(self.point([K(1), -s/r, K(0)], check=True))
324
# the case r = 0 need not be considered
325
elif K.characteristic() == 2: # deg(P) = 2 and char(K) = 2
326
# quadratic equation doesn't work in characteristic 2 so use brute
327
# force
328
points += [self.point([K(1), y, K(0)], check=True) for y in K \
329
if not P(K(1), y, K(0))]
330
else: # deg(P) = 2 and char(K) not 2
331
# P(1, y, 0) = y^2 + r*y + s
332
s = -f[2]
333
r = h[1]
334
d = r**2/4 - s
335
sqrtd = square_roots[d]
336
if not d: # d = 0
337
points.append(self.point([K(1), -r/2, K(0)], check=True))
338
elif sqrtd is not None:
339
points.append(self.point([K(1), -r/2+sqrtd, K(0)], check=True))
340
points.append(self.point([K(1), -r/2-sqrtd, K(0)], check=True))
341
342
if K.characteristic() == 2 or brute_force:
343
# quadratic equation doesn't work in characteristic 2
344
# but there are only 4 affine points, so just test them
345
f = self.defining_polynomial()
346
points += [self.point([x, y, one], check=True) for x in K for y in K if not f(x, y, one)]
347
elif h.is_zero():
348
# special case to save work if we are of the form y^2 = f(x)
349
for x in K:
350
y2 = f(x)
351
y = square_roots[y2]
352
if not y2: # y = 0
353
points.append(self.point([x, y2, one], check=True))
354
elif y is not None:
355
points.append(self.point([x, y, one], check=True))
356
points.append(self.point([x, -y, one], check=True))
357
else:
358
b = -h/2
359
D = b*b + f # this is really disc/4
360
for x in K:
361
Dval = D(x)
362
sqrtD = square_roots[Dval]
363
if not Dval: # D(x) = 0
364
points.append(self.point([x, b(x), one], check=True))
365
elif sqrtD is not None:
366
v = b(x)
367
points.append(self.point([x, v+sqrtD, one], check=True))
368
points.append(self.point([x, v-sqrtD, one], check=True))
369
return points
370
371
372
def points(self):
373
r"""
374
All the points on this hyperelliptic curve.
375
376
EXAMPLES::
377
378
sage: x = polygen(GF(7))
379
sage: C = HyperellipticCurve(x^7 - x^2 - 1)
380
sage: C.points()
381
[(0 : 1 : 0), (2 : 5 : 1), (2 : 2 : 1), (3 : 0 : 1), (4 : 6 : 1), (4 : 1 : 1), (5 : 0 : 1), (6 : 5 : 1), (6 : 2 : 1)]
382
383
::
384
385
sage: x = polygen(GF(121, 'a'))
386
sage: C = HyperellipticCurve(x^5 + x - 1, x^2 + 2)
387
sage: len(C.points())
388
122
389
390
Conics are allowed (the issue reported at #11800 has been resolved)::
391
392
sage: R.<x> = GF(7)[]
393
sage: H = HyperellipticCurve(3*x^2 + 5*x + 1)
394
sage: H.points()
395
[(0 : 6 : 1), (0 : 1 : 1), (1 : 4 : 1), (1 : 3 : 1), (2 : 4 : 1), (2 : 3 : 1), (3 : 6 : 1), (3 : 1 : 1)]
396
397
The method currently lists points on the plane projective model, that
398
is the closure in $\mathbb{P}^2$ of the curve defined by $y^2+hy=f$.
399
This means that one point $(0:1:0)$ at infinity is returned if the
400
degree of the curve is at least 4 and $\deg(f)>\deg(h)+1$. This point
401
is a singular point of the plane model. Later implementations may
402
consider a smooth model instead since that would be a more relevant
403
object. Then, for a curve whose only singularity is at $(0:1:0)$, the
404
point at infinity would be replaced by a number of rational points of
405
the smooth model. We illustrate this with an example of a genus 2
406
hyperelliptic curve::
407
408
sage: R.<x>=GF(11)[]
409
sage: H = HyperellipticCurve(x*(x+1)*(x+2)*(x+3)*(x+4)*(x+5))
410
sage: H.points()
411
[(0 : 1 : 0), (0 : 0 : 1), (1 : 7 : 1), (1 : 4 : 1), (5 : 7 : 1), (5 : 4 : 1), (6 : 0 : 1), (7 : 0 : 1), (8 : 0 : 1), (9 : 0 : 1), (10 : 0 : 1)]
412
413
The plane model of the genus 2 hyperelliptic curve in the above example
414
is the curve in $\mathbb{P}^2$ defined by $y^2z^4=g(x,z)$ where
415
$g(x,z)=x(x+z)(x+2z)(x+3z)(x+4z)(x+5z).$ This model has one point at
416
infinity $(0:1:0)$ which is also the only singular point of the plane
417
model. In contrast, the hyperelliptic curve is smooth and imbeds via
418
the equation $y^2=g(x,z)$ into weighted projected space
419
$\mathbb{P}(1,3,1)$. The latter model has two points at infinity:
420
$(1:1:0)$ and $(1:-1:0)$.
421
"""
422
from sage.rings.finite_rings.constructor import zech_log_bound
423
try:
424
return self.__points
425
except AttributeError: pass
426
427
if self.base_ring().is_prime_field():
428
self.__points = self._points_cache_sqrt()
429
else:
430
if self.base_ring().order() < zech_log_bound:
431
self.__points = self._points_fast_sqrt() # this is fast using Zech logarithms
432
else:
433
self.__points = self._points_cache_sqrt()
434
435
return self.__points
436
437
438
#This where Cartier Matrix is actually computed. This is either called by E.Cartier_matrix, E.a_number, or E.Hasse_Witt
439
@cached_method
440
def _Cartier_matrix_cached(self):
441
r"""
442
INPUT:
443
444
- 'E' - Hyperelliptic Curve of the form `y^2 = f(x)` over a
445
finite field, `\mathbb{F}_q`
446
447
OUTPUT:
448
449
- matrix(Fq,M)' The matrix $M = (c_(pi-j)), f(x)^((p-1)/2) = \sum c_i x^i$
450
- 'Coeff' List of Coeffs of F, this is needed for Hasse-Witt function.
451
- 'g' genus of the curve self, this is needed by a-number.
452
- 'Fq' is the base field of self, and it is needed for Hasse-Witt
453
- 'p' is the char(Fq), this is needed for Hasse-Witt.
454
- 'E' The initial elliptic curve to check some caching conditions.
455
456
EXAMPLES::
457
458
sage: K.<x>=GF(9,'x')[]
459
sage: C=HyperellipticCurve(x^7-1,0)
460
sage: C._Cartier_matrix_cached()
461
(
462
[0 0 2]
463
[0 0 0]
464
[0 1 0], [2, 0, 0, 0, 0, 0, 0, 1, 0], 3, Finite Field in x of size 3^2, 3, Hyperelliptic Curve over Finite Field in x of size 3^2 defined by y^2 = x^7 + 2
465
)
466
sage: K.<x>=GF(49,'x')[]
467
sage: C=HyperellipticCurve(x^5+1,0)
468
sage: C._Cartier_matrix_cached()
469
(
470
[0 3]
471
[0 0], [1, 0, 0, 0, 0, 3, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1], 2, Finite Field in x of size 7^2, 7, Hyperelliptic Curve over Finite Field in x of size 7^2 defined by y^2 = x^5 + 1
472
)
473
474
475
sage: P.<x>=GF(9,'a')[]
476
sage: C=HyperellipticCurve(x^29+1,0)
477
sage: C._Cartier_matrix_cached()
478
(
479
[0 0 1 0 0 0 0 0 0 0 0 0 0 0]
480
[0 0 0 0 0 1 0 0 0 0 0 0 0 0]
481
[0 0 0 0 0 0 0 0 1 0 0 0 0 0]
482
[0 0 0 0 0 0 0 0 0 0 0 1 0 0]
483
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
484
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
485
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
486
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
487
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
488
[1 0 0 0 0 0 0 0 0 0 0 0 0 0]
489
[0 0 0 1 0 0 0 0 0 0 0 0 0 0]
490
[0 0 0 0 0 0 1 0 0 0 0 0 0 0]
491
[0 0 0 0 0 0 0 0 0 1 0 0 0 0]
492
[0 0 0 0 0 0 0 0 0 0 0 0 1 0], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 14, Finite Field in a of size 3^2, 3, Hyperelliptic Curve over Finite Field in a of size 3^2 defined by y^2 = x^29 + 1
493
)
494
495
TESTS::
496
497
sage: K.<x>=GF(2,'x')[]
498
sage: C=HyperellipticCurve(x^7-1,x)
499
sage: C._Cartier_matrix_cached()
500
Traceback (most recent call last):
501
...
502
ValueError: p must be odd
503
504
505
sage: K.<x>=GF(5,'x')[]
506
sage: C=HyperellipticCurve(x^7-1,4)
507
sage: C._Cartier_matrix_cached()
508
Traceback (most recent call last):
509
...
510
ValueError: E must be of the form y^2 = f(x)
511
512
513
sage: K.<x>=GF(5,'x')[]
514
sage: C=HyperellipticCurve(x^8-1,0)
515
sage: C._Cartier_matrix_cached()
516
Traceback (most recent call last):
517
...
518
ValueError: In this implementation the degree of f must be odd
519
520
521
sage: K.<x>=GF(5,'x')[]
522
sage: C=HyperellipticCurve(x^5+1,0,check_squarefree=False)
523
sage: C._Cartier_matrix_cached()
524
Traceback (most recent call last):
525
...
526
ValueError: curve is not smooth
527
528
"""
529
530
#Compute the finite field and prime p.
531
Fq=self.base_ring();
532
p=Fq.characteristic()
533
#checks
534
535
if p == 2:
536
raise ValueError, "p must be odd";
537
538
539
g = self.genus()
540
541
#retrieve the function f(x) ,where y^2=f(x)
542
f,h = self.hyperelliptic_polynomials()
543
#This implementation only deals with h=0
544
if h!=0:
545
raise ValueError, "E must be of the form y^2 = f(x)"
546
547
d = f.degree()
548
#this implementation is for odd degree only, even degree will be handled later.
549
if d%2 == 0:
550
raise ValueError, "In this implementation the degree of f must be odd"
551
#Compute resultant to make sure no repeated roots
552
df=f.derivative()
553
R=df.resultant(f)
554
if R == 0:
555
raise ValueError, "curve is not smooth"
556
557
#computing F, since the entries of the matrix are c_i where F= \sum c_i x^i
558
559
F = f**((p-1)/2)
560
561
#coefficients returns a_0, ... , a_n where f(x) = a_n x^n + ... + a_0
562
563
Coeff = F.list()
564
565
#inserting zeros when necessary-- that is, when deg(F) < p*g-1, (simplified if p <2g-1)
566
#which is the highest powered coefficient needed for our matrix
567
#So we don't have enough coefficients we add extra zeros to have the same poly,
568
#but enough coeff.
569
570
zeros = [0 for i in range(p*g-len(Coeff))]
571
Coeff = Coeff + zeros
572
573
# compute each row of matrix as list and then M=list of lists(rows)
574
575
M=[];
576
for j in range(1,g+1):
577
H=[Coeff[i] for i in range((p*j-1), (p*j-g-1),-1)]
578
M.append(H);
579
return matrix(Fq,M), Coeff, g, Fq,p, self
580
581
582
#This is what is called from command line
583
def Cartier_matrix(self):
584
r"""
585
INPUT:
586
587
- ``E`` : Hyperelliptic Curve of the form `y^2 = f(x)` over a finite field, `\mathbb{F}_q`
588
589
OUTPUT:
590
591
592
- ``M``: The matrix `M = (c_{pi-j})`, where `c_i` are the coeffients of `f(x)^{(p-1)/2} = \sum c_i x^i`
593
594
Reference-N. Yui. On the Jacobian varieties of hyperelliptic curves over fields of characteristic `p > 2`.
595
596
EXAMPLES::
597
598
sage: K.<x>=GF(9,'x')[]
599
sage: C=HyperellipticCurve(x^7-1,0)
600
sage: C.Cartier_matrix()
601
[0 0 2]
602
[0 0 0]
603
[0 1 0]
604
605
sage: K.<x>=GF(49,'x')[]
606
sage: C=HyperellipticCurve(x^5+1,0)
607
sage: C.Cartier_matrix()
608
[0 3]
609
[0 0]
610
611
sage: P.<x>=GF(9,'a')[]
612
sage: E=HyperellipticCurve(x^29+1,0)
613
sage: E.Cartier_matrix()
614
[0 0 1 0 0 0 0 0 0 0 0 0 0 0]
615
[0 0 0 0 0 1 0 0 0 0 0 0 0 0]
616
[0 0 0 0 0 0 0 0 1 0 0 0 0 0]
617
[0 0 0 0 0 0 0 0 0 0 0 1 0 0]
618
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
619
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
620
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
621
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
622
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
623
[1 0 0 0 0 0 0 0 0 0 0 0 0 0]
624
[0 0 0 1 0 0 0 0 0 0 0 0 0 0]
625
[0 0 0 0 0 0 1 0 0 0 0 0 0 0]
626
[0 0 0 0 0 0 0 0 0 1 0 0 0 0]
627
[0 0 0 0 0 0 0 0 0 0 0 0 1 0]
628
629
TESTS::
630
631
sage: K.<x>=GF(2,'x')[]
632
sage: C=HyperellipticCurve(x^7-1,x)
633
sage: C.Cartier_matrix()
634
Traceback (most recent call last):
635
...
636
ValueError: p must be odd
637
638
639
sage: K.<x>=GF(5,'x')[]
640
sage: C=HyperellipticCurve(x^7-1,4)
641
sage: C.Cartier_matrix()
642
Traceback (most recent call last):
643
...
644
ValueError: E must be of the form y^2 = f(x)
645
646
647
sage: K.<x>=GF(5,'x')[]
648
sage: C=HyperellipticCurve(x^8-1,0)
649
sage: C.Cartier_matrix()
650
Traceback (most recent call last):
651
...
652
ValueError: In this implementation the degree of f must be odd
653
654
655
sage: K.<x>=GF(5,'x')[]
656
sage: C=HyperellipticCurve(x^5+1,0,check_squarefree=False)
657
sage: C.Cartier_matrix()
658
Traceback (most recent call last):
659
...
660
ValueError: curve is not smooth
661
662
"""
663
#checking first that Cartier matrix is not already cached. Since
664
#it can be called by either Hasse_Witt or a_number.
665
#This way it does not matter which function is called first
666
#in the code.
667
# Trac Ticket #11115: Why shall we waste time by studying
668
# the cache manually? We only need to check whether the cached
669
# data belong to self.
670
M, Coeffs,g, Fq, p, E= self._Cartier_matrix_cached()
671
if E!=self:
672
self._Cartier_matrix_cached.clear_cache()
673
M, Coeffs,g, Fq, p, E= self._Cartier_matrix_cached()
674
return M
675
676
#This where Hasse_Witt is actually computed. This is either called by E.Hasse_Witt or p_rank
677
@cached_method
678
def _Hasse_Witt_cached(self):
679
r"""
680
INPUT:
681
682
- ``E`` : Hyperelliptic Curve of the form `y^2 = f(x)` over a finite field, `\mathbb{F}_q`
683
684
OUTPUT:
685
686
- ``N`` : The matrix `N = M M^p \dots M^{p^{g-1}}` where `M = c_{pi-j}, f(x)^{(p-1)/2} = \sum c_i x^i`
687
- ``E`` : The initial curve to check some caching conditions.
688
689
EXAMPLES::
690
691
sage: K.<x>=GF(9,'x')[]
692
sage: C=HyperellipticCurve(x^7-1,0)
693
sage: C._Hasse_Witt_cached()
694
(
695
[0 0 0]
696
[0 0 0]
697
[0 0 0], Hyperelliptic Curve over Finite Field in x of size 3^2 defined by y^2 = x^7 + 2
698
)
699
700
sage: K.<x>=GF(49,'x')[]
701
sage: C=HyperellipticCurve(x^5+1,0)
702
sage: C._Hasse_Witt_cached()
703
(
704
[0 0]
705
[0 0], Hyperelliptic Curve over Finite Field in x of size 7^2 defined by y^2 = x^5 + 1
706
)
707
708
sage: P.<x>=GF(9,'a')[]
709
sage: C=HyperellipticCurve(x^29+1,0)
710
sage: C._Hasse_Witt_cached()
711
(
712
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
713
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
714
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
715
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
716
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
717
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
718
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
719
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
720
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
721
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
722
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
723
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
724
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
725
[0 0 0 0 0 0 0 0 0 0 0 0 0 0], Hyperelliptic Curve over Finite Field in a of size 3^2 defined by y^2 = x^29 + 1
726
)
727
728
"""
729
730
731
732
# If Cartier Matrix is already cached for this curve, use that or evaluate it to get M,
733
#Coeffs, genus, Fq=base field of self, p=char(Fq). This is so we have one less matrix to
734
#compute.
735
736
#We use caching here since Cartier matrix is needed to compute Hasse Witt. So if the Cartier
737
#is already computed it is stored in list A. If it was not cached (i.e. A is empty), we simply
738
#compute it. If it is cached then we need to make sure that we have the correct one. So check
739
#which curve does the matrix correspond to. Since caching stores a lot of stuff, we only check
740
#the last entry in A. If it does not match, clear A and compute Cartier.
741
#
742
#Since Trac Ticket #11115, there is a different cache for methods
743
#that don't accept arguments. Anyway, the easiest is to call
744
#the cached method and simply see whether the data belong to self.
745
M, Coeffs,g, Fq, p, E= self._Cartier_matrix_cached()
746
if E!=self:
747
self._Cartier_matrix_cached.clear_cache()
748
M, Coeffs,g, Fq, p, E= self._Cartier_matrix_cached()
749
750
#This compute the action of p^kth Frobenius on list of coefficients
751
def frob_mat(Coeffs, k):
752
a = p**k
753
mat = []
754
Coeffs_pow = [c**a for c in Coeffs]
755
for i in range(1,g+1):
756
H=[(Coeffs[j]) for j in range((p*i-1), (p*i - g-1), -1)]
757
mat.append(H);
758
return matrix(Fq,mat)
759
760
#Computes all the different possible action of frobenius on matrix M and stores in list Mall
761
Mall = [M] + [frob_mat(Coeffs,k) for k in range(1,g)]
762
763
#initial N=I, so we can go through Mall and multiply all matrices with I and
764
#get the Hasse-Witt matrix.
765
N = identity_matrix(Fq,g)
766
for l in Mall:
767
N = N*l;
768
return N, E
769
770
#This is the function which is actually called by command line
771
def Hasse_Witt(self):
772
r"""
773
INPUT:
774
775
- ``E`` : Hyperelliptic Curve of the form `y^2 = f(x)` over a finite field, `\mathbb{F}_q`
776
777
OUTPUT:
778
779
- ``N`` : The matrix `N = M M^p \dots M^{p^{g-1}}` where `M = c_{pi-j}`, and `f(x)^{(p-1)/2} = \sum c_i x^i`
780
781
782
783
Reference-N. Yui. On the Jacobian varieties of hyperelliptic curves over fields of characteristic `p > 2`.
784
785
EXAMPLES::
786
787
sage: K.<x>=GF(9,'x')[]
788
sage: C=HyperellipticCurve(x^7-1,0)
789
sage: C.Hasse_Witt()
790
[0 0 0]
791
[0 0 0]
792
[0 0 0]
793
794
sage: K.<x>=GF(49,'x')[]
795
sage: C=HyperellipticCurve(x^5+1,0)
796
sage: C.Hasse_Witt()
797
[0 0]
798
[0 0]
799
800
sage: P.<x>=GF(9,'a')[]
801
sage: E=HyperellipticCurve(x^29+1,0)
802
sage: E.Hasse_Witt()
803
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
804
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
805
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
806
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
807
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
808
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
809
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
810
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
811
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
812
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
813
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
814
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
815
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
816
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
817
818
819
"""
820
# Since Trac Ticket #11115, there is a special
821
# type of cached for those methods that don't
822
# accept arguments. We want to get Hasse-Witt
823
# from the cache - but apparently it could be
824
# that the cached value does not belong to self.
825
# So, the easiest is:
826
N, E= self._Hasse_Witt_cached()
827
if E!=self:
828
self._Hasse_Witt_cached.clear_cache()
829
N, E= self._Hasse_Witt_cached()
830
return N
831
832
def a_number(self):
833
r"""
834
INPUT:
835
836
- ``E``: Hyperelliptic Curve of the form `y^2 = f(x)` over a finite field, `\mathbb{F}_q`
837
838
OUTPUT:
839
840
- ``a`` : a-number
841
842
843
EXAMPLES::
844
845
sage: K.<x>=GF(49,'x')[]
846
sage: C=HyperellipticCurve(x^5+1,0)
847
sage: C.a_number()
848
1
849
850
sage: K.<x>=GF(9,'x')[]
851
sage: C=HyperellipticCurve(x^7-1,0)
852
sage: C.a_number()
853
1
854
855
sage: P.<x>=GF(9,'a')[]
856
sage: E=HyperellipticCurve(x^29+1,0)
857
sage: E.a_number()
858
5
859
860
861
862
"""
863
#We use caching here since Cartier matrix is needed to compute a_number. So if the Cartier
864
#is already computed it is stored in list A. If it was not cached (i.e. A is empty), we simply
865
#compute it. If it is cached then we need to make sure that we have the correct one. So check
866
#which curve does the matrix correspond to. Since caching stores a lot of stuff, we only check
867
#the last entry in A. If it does not match, clear A and compute Cartier.
868
# Since Trac Ticket #11115, there is a special cache for methods
869
# that don't accept arguments. The easiest is: Call the cached
870
# method, and test whether the last entry is self.
871
M,Coeffs,g, Fq, p,E= self._Cartier_matrix_cached()
872
if E != self:
873
self._Cartier_matrix_cached.clear_cache()
874
M,Coeffs,g, Fq, p,E= self._Cartier_matrix_cached()
875
a=g-rank(M);
876
return a;
877
878
def p_rank(self):
879
r"""
880
INPUT:
881
882
- ``E`` : Hyperelliptic Curve of the form `y^2 = f(x)` over a finite field, `\mathbb{F}_q`
883
884
OUTPUT:
885
886
- ``pr`` :p-rank
887
888
889
EXAMPLES::
890
891
sage: K.<x>=GF(49,'x')[]
892
sage: C=HyperellipticCurve(x^5+1,0)
893
sage: C.p_rank()
894
0
895
896
sage: K.<x>=GF(9,'x')[]
897
sage: C=HyperellipticCurve(x^7-1,0)
898
sage: C.p_rank()
899
0
900
901
sage: P.<x>=GF(9,'a')[]
902
sage: E=HyperellipticCurve(x^29+1,0)
903
sage: E.p_rank()
904
0
905
"""
906
#We use caching here since Hasse Witt is needed to compute p_rank. So if the Hasse Witt
907
#is already computed it is stored in list A. If it was not cached (i.e. A is empty), we simply
908
#compute it. If it is cached then we need to make sure that we have the correct one. So check
909
#which curve does the matrix correspond to. Since caching stores a lot of stuff, we only check
910
#the last entry in A. If it does not match, clear A and compute Hasse Witt.
911
# However, it seems a waste of time to manually analyse the cache
912
# -- See Trac Ticket #11115
913
N,E= self._Hasse_Witt_cached()
914
if E!=self:
915
self._Hasse_Witt_cached.clear_cache()
916
N,E= self._Hasse_Witt_cached()
917
pr=rank(N);
918
return pr
919
920
921