Path: blob/master/src/sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py
8820 views
r"""1Hyperelliptic curves over a finite field23EXAMPLES::45sage: K.<a> = GF(9, 'a')6sage: x = polygen(K)7sage: C = HyperellipticCurve(x^7 - x^5 - 2, x^2 + a)8sage: C._points_fast_sqrt()9[(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)]1011"""1213#*****************************************************************************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 Gresham17# <[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#*****************************************************************************2122from sage.rings.all import ZZ, RR, binomial23import hyperelliptic_generic24from sage.schemes.hyperelliptic_curves.hypellfrob import hypellfrob25from sage.misc.cachefunc import cached_method26from sage.matrix.constructor import identity_matrix, matrix27from sage.misc.functional import rank282930class HyperellipticCurve_finite_field(hyperelliptic_generic.HyperellipticCurve_generic):3132def _frobenius_coefficient_bound(self):33"""34Computes bound on number of p-adic digits needed to recover35frobenius polynomial, i.e. returns B so that knowledge of36a_1, ..., a_g modulo p^B determine frobenius polynomial uniquely.3738TESTS::3940sage: R.<t> = PolynomialRing(GF(37))41sage: HyperellipticCurve(t^3 + t + 1)._frobenius_coefficient_bound()42143sage: HyperellipticCurve(t^5 + t + 1)._frobenius_coefficient_bound()44245sage: HyperellipticCurve(t^7 + t + 1)._frobenius_coefficient_bound()4634748sage: R.<t> = PolynomialRing(GF(next_prime(10^9)))49sage: HyperellipticCurve(t^3 + t + 1)._frobenius_coefficient_bound()50151sage: HyperellipticCurve(t^5 + t + 1)._frobenius_coefficient_bound()52253sage: HyperellipticCurve(t^7 + t + 1)._frobenius_coefficient_bound()54255sage: HyperellipticCurve(t^9 + t + 1)._frobenius_coefficient_bound()56357sage: HyperellipticCurve(t^11 + t + 1)._frobenius_coefficient_bound()58359sage: HyperellipticCurve(t^13 + t + 1)._frobenius_coefficient_bound()60461"""62assert self.base_ring().is_finite()63p = self.base_ring().characteristic()64q = self.base_ring().order()65sqrtq = RR(q).sqrt()66g = self.genus()6768# note: this bound is from Kedlaya's paper, but he tells me it's not69# the best possible70M = 2 * binomial(2*g, g) * sqrtq**g71B = ZZ(M.ceil()).exact_log(p)72if p**B < M:73B += 174return B757677def _frobenius_matrix(self, N=None):78"""79Compute p-adic frobenius matrix to precision p^N. If N not supplied,80a default value is selected, which is the minimum needed to recover81the charpoly unambiguously.8283Currently only implemented using hypellfrob, which means only works84over GF(p^1), and must have p > (2g+1)(2N-1).8586TESTS::8788sage: R.<t> = PolynomialRing(GF(37))89sage: H = HyperellipticCurve(t^5 + t + 2)90sage: 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)]9596"""97p = self.base_ring().characteristic()98f, h = self.hyperelliptic_polynomials()99if h != 0:100# need y^2 = f(x)101raise NotImplementedError, "only implemented for curves y^2 = f(x)"102103sign = 1104if not f.is_monic():105# at this time we need a monic f106c = f.leading_coefficient()107f = f / c108if c.is_square():109# solutions of $y^2 = c * f(x)$ correspond naturally to110# solutions of $(sqrt(c) y)^2 = f(x)$111pass112else:113# we'll count points on a twist and then correct by untwisting...114sign = -1115assert f.is_monic()116117if N is None:118N = self._frobenius_coefficient_bound()119120matrix_of_frobenius = hypellfrob(p, N, f)121matrix_of_frobenius = sign * matrix_of_frobenius122return matrix_of_frobenius123124125def frobenius_polynomial(self):126"""127Charpoly of frobenius, as an element of ZZ[x].128129TESTS::130131sage: R.<t> = PolynomialRing(GF(37))132sage: H = HyperellipticCurve(t^5 + t + 2)133sage: H.frobenius_polynomial()134x^4 + x^3 - 52*x^2 + 37*x + 1369135136A quadratic twist:137138::139140sage: H = HyperellipticCurve(2*t^5 + 2*t + 4)141sage: H.frobenius_polynomial()142x^4 - x^3 - 52*x^2 - 37*x + 1369143144"""145p = self.base_ring().characteristic()146g = self.genus()147N = self._frobenius_coefficient_bound()148# compute chapoly over ZZ and then reduce back149# (because charpoly of p-adic matrices sometimes loses precision)150M = self._frobenius_matrix(N=N).change_ring(ZZ)151152# get a_g, ..., a_0 in ZZ (i.e. with correct signs)153f = M.charpoly().list()[g:2*g+1]154ppow = p**N155f = [x % ppow for x in f]156f = [x if 2*x < ppow else x - ppow for x in f]157158# get a_{2g}, ..., a_{g+1}159f = [f[g-i] * p**(g-i) for i in range(g)] + f160161return ZZ['x'](f)162163164165def _points_fast_sqrt(self):166"""167Count points by enumerating over x and solving the resulting168quadratic for y.169170EXAMPLES::171172sage: K.<a> = GF(9, 'a')173sage: x = polygen(K)174sage: C = HyperellipticCurve(x^7 - 1, x^2 + a)175sage: C._points_fast_sqrt()176[(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)]177sage: K.<a> = GF(49, 'a')178sage: x = polygen(K)179sage: C = HyperellipticCurve(x^5 - x^2 - 1, x^2 + a)180sage: len(C._points_fast_sqrt())18131182183TESTS::184185sage: x = polygen(GF(16, 'a'))186sage: C = HyperellipticCurve(x^5 - x + 1, x^2 + x + 1)187sage: set(C._points_fast_sqrt()) == set(C._points_cache_sqrt())188True189sage: x = polygen(GF(19))190sage: C = HyperellipticCurve(x^5 + 5*x^2 + 1, x + 1)191sage: set(C._points_fast_sqrt()) == set(C._points_cache_sqrt())192True193sage: x = polygen(GF(13))194sage: C = HyperellipticCurve(x^3 + x^2 - 1)195sage: 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)]197sage: set(C._points_fast_sqrt()) == set(C._points_cache_sqrt())198True199"""200# For givaro finite fields, taking square roots is very fast201# so no need to cache as in prime case202K = self.base_ring()203f, h = self.hyperelliptic_polynomials()204one = K(1)205206# start with the points at infinity207P = self.defining_polynomial()208if not P(K(0), K(1), K(0)):209# (0:1:0) is a point on the curve210points = [self.point([K(0), K(1), K(0)], check=True)]211else:212points=[]213if P.degree() > 2:214# P(1, y, 0) = r*y + s215s = P(K(1), K(0), K(0))216r = P(K(1), K(1), K(0)) - s217if r: # r not zero218points.append(self.point([K(1), -s/r, K(0)], check=True))219# the case r = 0 need not be considered220elif K.characteristic() == 2: # deg(P) = 2 and char(K) = 2221# quadratic equation doesn't work in characteristic 2 so use brute222# force223points += [self.point([K(1), y, K(0)], check=True) for y in K \224if not P(K(1), y, K(0))]225else: # deg(P) = 2 and char(K) not 2226# P(1, y, 0) = y^2 + r*y + s227s = -f[2]228r = h[1]229d = r**2/4 - s230if not d: # d = 0231points.append(self.point([K(1), -r/2, K(0)], check=True))232elif d.is_square():233sqrtd = d.sqrt()234points.append(self.point([K(1), -r/2+sqrtd, K(0)], check=True))235points.append(self.point([K(1), -r/2-sqrtd, K(0)], check=True))236237if K.characteristic() == 2:238# quadratic equation doesn't work in characteristic 2239if h.is_zero():240for x in K:241points.append(self.point([x, f(x).sqrt(), one], check=True))242else:243R = f.base_ring()244a_sqrts = { } # Artin-Schreier 2-roots245for x in K:246a_sqrts[x**2 + x] = x # char 2 => x^2 - x == x^2 + x247for x in K:248b = h(x)249c = f(x)250if b:251try:252r = a_sqrts[c / b**2]253points.append(self.point([x, r*b, one], check=True))254points.append(self.point([x, r*b+b, one], check=True))255except KeyError:256# y^2 + by + c irreducible, so yields no points257pass258else: # b == 0259points.append(self.point([x, c.sqrt(), one], check=True))260elif h.is_zero():261# special case to save work if we are of the form y^2 = f(x)262for x in K:263y2 = f(x)264if not y2: # y = 0265points.append(self.point([x, y2, one], check=True))266elif y2.is_square():267y = y2.sqrt()268points.append(self.point([x, y, one], check=True))269points.append(self.point([x, -y, one], check=True))270else:271b = -h/2272D = b*b + f273for x in K:274Dval = D(x)275if not Dval: # D(x) = 0276points.append(self.point([x, b(x), one], check=True))277elif Dval.is_square():278sqrtD = Dval.sqrt()279v = b(x)280points.append(self.point([x, v+sqrtD, one], check=True))281points.append(self.point([x, v-sqrtD, one], check=True))282return points283284def _points_cache_sqrt(self, brute_force=False):285"""286Count points by enumerating over x and solving the resulting287quadratic for y.288289Caches all square roots ahead of time by squaring every element of290the field. Elements must have an __index__ method.291292EXAMPLES::293294sage: x = polygen(GF(7))295sage: C = HyperellipticCurve(x^3 + x^2 - 1)296sage: 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)]298sage: set(C._points_cache_sqrt()) == set(C._points_cache_sqrt(brute_force=True))299True300"""301K = self.base_ring()302if K.characteristic() != 2:303# cache the squares (faster than O(p) sqrts)304square_roots = [None] * len(K)305for x in K:306square_roots[x*x] = x307f, h = self.hyperelliptic_polynomials()308one = K(1)309310# start with the points at infinity311P = self.defining_polynomial()312if not P(K(0), K(1), K(0)):313# (0:1:0) is a point on the curve314points = [self.point([K(0), K(1), K(0)], check=True)]315else:316points=[]317if P.degree() > 2:318# P(1, y, 0) = r*y + s319s = P(K(1), K(0), K(0))320r = P(K(1), K(1), K(0)) - s321if r: # r not zero322points.append(self.point([K(1), -s/r, K(0)], check=True))323# the case r = 0 need not be considered324elif K.characteristic() == 2: # deg(P) = 2 and char(K) = 2325# quadratic equation doesn't work in characteristic 2 so use brute326# force327points += [self.point([K(1), y, K(0)], check=True) for y in K \328if not P(K(1), y, K(0))]329else: # deg(P) = 2 and char(K) not 2330# P(1, y, 0) = y^2 + r*y + s331s = -f[2]332r = h[1]333d = r**2/4 - s334sqrtd = square_roots[d]335if not d: # d = 0336points.append(self.point([K(1), -r/2, K(0)], check=True))337elif sqrtd is not None:338points.append(self.point([K(1), -r/2+sqrtd, K(0)], check=True))339points.append(self.point([K(1), -r/2-sqrtd, K(0)], check=True))340341if K.characteristic() == 2 or brute_force:342# quadratic equation doesn't work in characteristic 2343# but there are only 4 affine points, so just test them344f = self.defining_polynomial()345points += [self.point([x, y, one], check=True) for x in K for y in K if not f(x, y, one)]346elif h.is_zero():347# special case to save work if we are of the form y^2 = f(x)348for x in K:349y2 = f(x)350y = square_roots[y2]351if not y2: # y = 0352points.append(self.point([x, y2, one], check=True))353elif y is not None:354points.append(self.point([x, y, one], check=True))355points.append(self.point([x, -y, one], check=True))356else:357b = -h/2358D = b*b + f # this is really disc/4359for x in K:360Dval = D(x)361sqrtD = square_roots[Dval]362if not Dval: # D(x) = 0363points.append(self.point([x, b(x), one], check=True))364elif sqrtD is not None:365v = b(x)366points.append(self.point([x, v+sqrtD, one], check=True))367points.append(self.point([x, v-sqrtD, one], check=True))368return points369370371def points(self):372r"""373All the points on this hyperelliptic curve.374375EXAMPLES::376377sage: x = polygen(GF(7))378sage: C = HyperellipticCurve(x^7 - x^2 - 1)379sage: 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)]381382::383384sage: x = polygen(GF(121, 'a'))385sage: C = HyperellipticCurve(x^5 + x - 1, x^2 + 2)386sage: len(C.points())387122388389Conics are allowed (the issue reported at #11800 has been resolved)::390391sage: R.<x> = GF(7)[]392sage: H = HyperellipticCurve(3*x^2 + 5*x + 1)393sage: 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)]395396The method currently lists points on the plane projective model, that397is the closure in $\mathbb{P}^2$ of the curve defined by $y^2+hy=f$.398This means that one point $(0:1:0)$ at infinity is returned if the399degree of the curve is at least 4 and $\deg(f)>\deg(h)+1$. This point400is a singular point of the plane model. Later implementations may401consider a smooth model instead since that would be a more relevant402object. Then, for a curve whose only singularity is at $(0:1:0)$, the403point at infinity would be replaced by a number of rational points of404the smooth model. We illustrate this with an example of a genus 2405hyperelliptic curve::406407sage: R.<x>=GF(11)[]408sage: H = HyperellipticCurve(x*(x+1)*(x+2)*(x+3)*(x+4)*(x+5))409sage: 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)]411412The plane model of the genus 2 hyperelliptic curve in the above example413is the curve in $\mathbb{P}^2$ defined by $y^2z^4=g(x,z)$ where414$g(x,z)=x(x+z)(x+2z)(x+3z)(x+4z)(x+5z).$ This model has one point at415infinity $(0:1:0)$ which is also the only singular point of the plane416model. In contrast, the hyperelliptic curve is smooth and imbeds via417the equation $y^2=g(x,z)$ into weighted projected space418$\mathbb{P}(1,3,1)$. The latter model has two points at infinity:419$(1:1:0)$ and $(1:-1:0)$.420"""421from sage.rings.finite_rings.constructor import zech_log_bound422try:423return self.__points424except AttributeError: pass425426if self.base_ring().is_prime_field():427self.__points = self._points_cache_sqrt()428else:429if self.base_ring().order() < zech_log_bound:430self.__points = self._points_fast_sqrt() # this is fast using Zech logarithms431else:432self.__points = self._points_cache_sqrt()433434return self.__points435436437#This where Cartier Matrix is actually computed. This is either called by E.Cartier_matrix, E.a_number, or E.Hasse_Witt438@cached_method439def _Cartier_matrix_cached(self):440r"""441INPUT:442443- 'E' - Hyperelliptic Curve of the form `y^2 = f(x)` over a444finite field, `\mathbb{F}_q`445446OUTPUT:447448- 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-Witt452- 'p' is the char(Fq), this is needed for Hasse-Witt.453- 'E' The initial elliptic curve to check some caching conditions.454455EXAMPLES::456457sage: K.<x>=GF(9,'x')[]458sage: C=HyperellipticCurve(x^7-1,0)459sage: 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 + 2464)465sage: K.<x>=GF(49,'x')[]466sage: C=HyperellipticCurve(x^5+1,0)467sage: 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 + 1471)472473474sage: P.<x>=GF(9,'a')[]475sage: C=HyperellipticCurve(x^29+1,0)476sage: 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 + 1492)493494TESTS::495496sage: K.<x>=GF(2,'x')[]497sage: C=HyperellipticCurve(x^7-1,x)498sage: C._Cartier_matrix_cached()499Traceback (most recent call last):500...501ValueError: p must be odd502503504sage: K.<x>=GF(5,'x')[]505sage: C=HyperellipticCurve(x^7-1,4)506sage: C._Cartier_matrix_cached()507Traceback (most recent call last):508...509ValueError: E must be of the form y^2 = f(x)510511512sage: K.<x>=GF(5,'x')[]513sage: C=HyperellipticCurve(x^8-1,0)514sage: C._Cartier_matrix_cached()515Traceback (most recent call last):516...517ValueError: In this implementation the degree of f must be odd518519520sage: K.<x>=GF(5,'x')[]521sage: C=HyperellipticCurve(x^5+1,0,check_squarefree=False)522sage: C._Cartier_matrix_cached()523Traceback (most recent call last):524...525ValueError: curve is not smooth526527"""528529#Compute the finite field and prime p.530Fq=self.base_ring();531p=Fq.characteristic()532#checks533534if p == 2:535raise ValueError, "p must be odd";536537538g = self.genus()539540#retrieve the function f(x) ,where y^2=f(x)541f,h = self.hyperelliptic_polynomials()542#This implementation only deals with h=0543if h!=0:544raise ValueError, "E must be of the form y^2 = f(x)"545546d = f.degree()547#this implementation is for odd degree only, even degree will be handled later.548if d%2 == 0:549raise ValueError, "In this implementation the degree of f must be odd"550#Compute resultant to make sure no repeated roots551df=f.derivative()552R=df.resultant(f)553if R == 0:554raise ValueError, "curve is not smooth"555556#computing F, since the entries of the matrix are c_i where F= \sum c_i x^i557558F = f**((p-1)/2)559560#coefficients returns a_0, ... , a_n where f(x) = a_n x^n + ... + a_0561562Coeff = F.list()563564#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 matrix566#So we don't have enough coefficients we add extra zeros to have the same poly,567#but enough coeff.568569zeros = [0 for i in range(p*g-len(Coeff))]570Coeff = Coeff + zeros571572# compute each row of matrix as list and then M=list of lists(rows)573574M=[];575for j in range(1,g+1):576H=[Coeff[i] for i in range((p*j-1), (p*j-g-1),-1)]577M.append(H);578return matrix(Fq,M), Coeff, g, Fq,p, self579580581#This is what is called from command line582def Cartier_matrix(self):583r"""584INPUT:585586- ``E`` : Hyperelliptic Curve of the form `y^2 = f(x)` over a finite field, `\mathbb{F}_q`587588OUTPUT:589590591- ``M``: The matrix `M = (c_{pi-j})`, where `c_i` are the coeffients of `f(x)^{(p-1)/2} = \sum c_i x^i`592593Reference-N. Yui. On the Jacobian varieties of hyperelliptic curves over fields of characteristic `p > 2`.594595EXAMPLES::596597sage: K.<x>=GF(9,'x')[]598sage: C=HyperellipticCurve(x^7-1,0)599sage: C.Cartier_matrix()600[0 0 2]601[0 0 0]602[0 1 0]603604sage: K.<x>=GF(49,'x')[]605sage: C=HyperellipticCurve(x^5+1,0)606sage: C.Cartier_matrix()607[0 3]608[0 0]609610sage: P.<x>=GF(9,'a')[]611sage: E=HyperellipticCurve(x^29+1,0)612sage: 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]627628TESTS::629630sage: K.<x>=GF(2,'x')[]631sage: C=HyperellipticCurve(x^7-1,x)632sage: C.Cartier_matrix()633Traceback (most recent call last):634...635ValueError: p must be odd636637638sage: K.<x>=GF(5,'x')[]639sage: C=HyperellipticCurve(x^7-1,4)640sage: C.Cartier_matrix()641Traceback (most recent call last):642...643ValueError: E must be of the form y^2 = f(x)644645646sage: K.<x>=GF(5,'x')[]647sage: C=HyperellipticCurve(x^8-1,0)648sage: C.Cartier_matrix()649Traceback (most recent call last):650...651ValueError: In this implementation the degree of f must be odd652653654sage: K.<x>=GF(5,'x')[]655sage: C=HyperellipticCurve(x^5+1,0,check_squarefree=False)656sage: C.Cartier_matrix()657Traceback (most recent call last):658...659ValueError: curve is not smooth660661"""662#checking first that Cartier matrix is not already cached. Since663#it can be called by either Hasse_Witt or a_number.664#This way it does not matter which function is called first665#in the code.666# Trac Ticket #11115: Why shall we waste time by studying667# the cache manually? We only need to check whether the cached668# data belong to self.669M, Coeffs,g, Fq, p, E= self._Cartier_matrix_cached()670if E!=self:671self._Cartier_matrix_cached.clear_cache()672M, Coeffs,g, Fq, p, E= self._Cartier_matrix_cached()673return M674675#This where Hasse_Witt is actually computed. This is either called by E.Hasse_Witt or p_rank676@cached_method677def _Hasse_Witt_cached(self):678r"""679INPUT:680681- ``E`` : Hyperelliptic Curve of the form `y^2 = f(x)` over a finite field, `\mathbb{F}_q`682683OUTPUT:684685- ``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.687688EXAMPLES::689690sage: K.<x>=GF(9,'x')[]691sage: C=HyperellipticCurve(x^7-1,0)692sage: 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 + 2697)698699sage: K.<x>=GF(49,'x')[]700sage: C=HyperellipticCurve(x^5+1,0)701sage: 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 + 1705)706707sage: P.<x>=GF(9,'a')[]708sage: C=HyperellipticCurve(x^29+1,0)709sage: 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 + 1725)726727"""728729730731# 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 to733#compute.734735#We use caching here since Cartier matrix is needed to compute Hasse Witt. So if the Cartier736#is already computed it is stored in list A. If it was not cached (i.e. A is empty), we simply737#compute it. If it is cached then we need to make sure that we have the correct one. So check738#which curve does the matrix correspond to. Since caching stores a lot of stuff, we only check739#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 methods742#that don't accept arguments. Anyway, the easiest is to call743#the cached method and simply see whether the data belong to self.744M, Coeffs,g, Fq, p, E= self._Cartier_matrix_cached()745if E!=self:746self._Cartier_matrix_cached.clear_cache()747M, Coeffs,g, Fq, p, E= self._Cartier_matrix_cached()748749#This compute the action of p^kth Frobenius on list of coefficients750def frob_mat(Coeffs, k):751a = p**k752mat = []753Coeffs_pow = [c**a for c in Coeffs]754for i in range(1,g+1):755H=[(Coeffs[j]) for j in range((p*i-1), (p*i - g-1), -1)]756mat.append(H);757return matrix(Fq,mat)758759#Computes all the different possible action of frobenius on matrix M and stores in list Mall760Mall = [M] + [frob_mat(Coeffs,k) for k in range(1,g)]761762#initial N=I, so we can go through Mall and multiply all matrices with I and763#get the Hasse-Witt matrix.764N = identity_matrix(Fq,g)765for l in Mall:766N = N*l;767return N, E768769#This is the function which is actually called by command line770def Hasse_Witt(self):771r"""772INPUT:773774- ``E`` : Hyperelliptic Curve of the form `y^2 = f(x)` over a finite field, `\mathbb{F}_q`775776OUTPUT:777778- ``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`779780781782Reference-N. Yui. On the Jacobian varieties of hyperelliptic curves over fields of characteristic `p > 2`.783784EXAMPLES::785786sage: K.<x>=GF(9,'x')[]787sage: C=HyperellipticCurve(x^7-1,0)788sage: C.Hasse_Witt()789[0 0 0]790[0 0 0]791[0 0 0]792793sage: K.<x>=GF(49,'x')[]794sage: C=HyperellipticCurve(x^5+1,0)795sage: C.Hasse_Witt()796[0 0]797[0 0]798799sage: P.<x>=GF(9,'a')[]800sage: E=HyperellipticCurve(x^29+1,0)801sage: 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]816817818"""819# Since Trac Ticket #11115, there is a special820# type of cached for those methods that don't821# accept arguments. We want to get Hasse-Witt822# from the cache - but apparently it could be823# that the cached value does not belong to self.824# So, the easiest is:825N, E= self._Hasse_Witt_cached()826if E!=self:827self._Hasse_Witt_cached.clear_cache()828N, E= self._Hasse_Witt_cached()829return N830831def a_number(self):832r"""833INPUT:834835- ``E``: Hyperelliptic Curve of the form `y^2 = f(x)` over a finite field, `\mathbb{F}_q`836837OUTPUT:838839- ``a`` : a-number840841842EXAMPLES::843844sage: K.<x>=GF(49,'x')[]845sage: C=HyperellipticCurve(x^5+1,0)846sage: C.a_number()8471848849sage: K.<x>=GF(9,'x')[]850sage: C=HyperellipticCurve(x^7-1,0)851sage: C.a_number()8521853854sage: P.<x>=GF(9,'a')[]855sage: E=HyperellipticCurve(x^29+1,0)856sage: E.a_number()8575858859860861"""862#We use caching here since Cartier matrix is needed to compute a_number. So if the Cartier863#is already computed it is stored in list A. If it was not cached (i.e. A is empty), we simply864#compute it. If it is cached then we need to make sure that we have the correct one. So check865#which curve does the matrix correspond to. Since caching stores a lot of stuff, we only check866#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 methods868# that don't accept arguments. The easiest is: Call the cached869# method, and test whether the last entry is self.870M,Coeffs,g, Fq, p,E= self._Cartier_matrix_cached()871if E != self:872self._Cartier_matrix_cached.clear_cache()873M,Coeffs,g, Fq, p,E= self._Cartier_matrix_cached()874a=g-rank(M);875return a;876877def p_rank(self):878r"""879INPUT:880881- ``E`` : Hyperelliptic Curve of the form `y^2 = f(x)` over a finite field, `\mathbb{F}_q`882883OUTPUT:884885- ``pr`` :p-rank886887888EXAMPLES::889890sage: K.<x>=GF(49,'x')[]891sage: C=HyperellipticCurve(x^5+1,0)892sage: C.p_rank()8930894895sage: K.<x>=GF(9,'x')[]896sage: C=HyperellipticCurve(x^7-1,0)897sage: C.p_rank()8980899900sage: P.<x>=GF(9,'a')[]901sage: E=HyperellipticCurve(x^29+1,0)902sage: E.p_rank()9030904"""905#We use caching here since Hasse Witt is needed to compute p_rank. So if the Hasse Witt906#is already computed it is stored in list A. If it was not cached (i.e. A is empty), we simply907#compute it. If it is cached then we need to make sure that we have the correct one. So check908#which curve does the matrix correspond to. Since caching stores a lot of stuff, we only check909#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 cache911# -- See Trac Ticket #11115912N,E= self._Hasse_Witt_cached()913if E!=self:914self._Hasse_Witt_cached.clear_cache()915N,E= self._Hasse_Witt_cached()916pr=rank(N);917return pr918919920921