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