// 32-4.magma // Version 1.0 // 14 April 2010 /* The code in this file will compute the largest number of rational points possible on a genus-4 curve over F_32 that is a double cover of the elliptic curve E defined by y^2 + x*y = x^3 + x. This is of interest because the package IsogenyClasses.magma shows the following: * A genus-4 curve over F_32 can have at most 74 points. * If a genus-4 curve over F_32 has 74 points, it is a double cover of E. * If a genus-4 curve over F_32 has 73 points, it is a double cover of E. * If a genus-4 curve over F_32 has 72 points and is *not* a double cover of E, then its real Weil polynomial is (x + 11)^2 * (x^2 + 17*x + 71). On the other hand, there exist genus-4 curves over F_32 that have 71 rational points. (We will run across some of them below, and several are exhibited in a comment at the end of the file.) Thus, if we enumerate the genus-4 double covers of E and don't find any with more than 71 points, we will have shown that N_32(4) is either 71 or 72, and if it is 72 we will know the Weil polynomial of all curves with the maximal number of points. To break the suspense: We find no curves with more than 71 points. Suppose C is a genus-4 curve over F_32 that is a double cover of E. Consider the map C --> E. The degree of the different is 6, and a ramification point contributes an even number to the degree of the different. So either * there are 3 ramification points, each contributing 2; * there are 2 ramification points, one contributing 4 and the other 2; or * there is 1 ramification point, contributing 6. We will divide our search according to these possible ramification structures. */ /* Define basic objects to be used throughout. */ K:=GF(32); Kstar := [a : a in K | a ne 0]; E := EllipticCurve([K|1,0,0,1,0]); finite_points := [[P[1],P[2]] : P in E | P[3] eq 1]; assert #finite_points eq 43; /* A histogram of the point counts we observe. */ histogram := [0 : i in [1..74]]; /* First we enumerate the double covers with three ramification points P1, P2, and P3. Since #E(K) = 44, which is coprime to 3, we can compose the double cover C --> E with translation by Q, where -3Q = P1 + P2 + P3. This has the effect of replacing the original double cover with a new double cover for which the sum of the P's is equal to oo. First we suppose that none of the P's is equal to oo. Our double cover is given by z^2 + z = f, for a function f on E. By modifying f by Artin-Schreier elements, we can assume that * f has simple poles at the P's, and no other poles outside oo; * f has at worst a double pole at oo; * the Laurent expansion of f at oo is a^2*u^-2 + a*u^-1 + O(1), where u is a uniformizer at oo. Since our three ramification points sum to oo, the divisor P1 + P2 + P3 is the divisor of zeros of a degree-3 function y + a*x + b. If we take u to be the uniformizer x/y at infinity, then we check that the following functions are in the Rieman-Roch space L(P1 + P2 + P3 + 2oo), and have Laurent expansions as follows: 1 / (y + a*x + b) = u^3 + O(u^4) x / (y + a*x + b) = u + O(u^2) 1 = 1 x^2 / (y + a*x + b) = u^-1 + (a+1) + O(u) x = u^-2 + u^-1 + O(u) Let's started enumerating: */ for a, b in K do /* We will only need to look at functions f up to the action of the Galois group of F_32 over F_2 and up to +/- 1 on E, so we can eliminate some a,b pairs right off the bat. Also, we should make sure that y + a*x + b has three distinct zeros. A computation shows that this is equivalent to requiring that a*(a+1)*(b+1) != b^2. Note that -1 on E takes the line y = a*x + b to y = (a+1)*x + b. */ if a*(a+1)*(b+1) ne b^2 and [a,b] eq Sort([ [a^(2^i) + c ,b^(2^i)] : i in [0..4], c in [0..1] ])[1] then print a,b; finite_non_ram := [P : P in finite_points | P[2]+a*P[1]+b ne 0]; rational_ram := 43 - #finite_non_ram; /* For each finite non-ramified point, compute the values of the five functions in L(P1+P2+P3+2oo) listed above. For the infinite point, compute the contant terms in the Laurent expansions. */ veclist := [ Vector([K|0,0,1,a+1,0]) ]; // The infinite point. for P in finite_non_ram do val := 1/(P[2] + a*P[1] + b); veclist cat:= [ Vector( [val, P[1]*val, 1, P[1]^2*val, P[1]] ) ]; end for; /* Now go through all linear combinations of the five functions that have at least one finite pole and that have the right expansion at oo. We only have to enumerate up to addition of constants with trace 0. */ for c1, c2, d in K, c3 in {K|0,1} do c5 := d^2; c4 := d^2 + d; if not (c1 eq 0 and c2 eq 0 and c4 eq 0) then // Take f to be c1*f1 + c2*f2 + c3*f3 + c4*f4 + c5*f5. v := Vector( [c1,c2,c3,c4,c5] ); rhs := [Trace(InnerProduct(v,w)) : w in veclist]; point_count := rational_ram + 2*#[a : a in rhs | a eq 0]; histogram[point_count] +:= 1; if point_count ge 71 then print point_count, a, b, c1, c2, c3, c4, c5; end if; end if; end for; end if; end for; /* Now consider the case where we have three ramification points that sum to oo, but where one of the ramification points is itself oo. This means that the other two are negatives of one another, so they will be the zeros of x + a for some nonzero a. Now we may assume that our f satisfies these conditions: * f has simple poles at the finite ramification points, and no other poles outside oo; * f has at worst a double pole at oo; * the Laurent expansion of f at oo is b2*u^-2 + b1*u^-1 + O(1), where u = x/y is a uniformizer at oo and where b2 != b1^2. The following functions are in L(P1 + P2 + 2oo): 1/(x + a) = u^2 + O(u^3) 1 = 1 y/(x + a) = u^-1 + a*u + O(u^2) x = u^-2 + u^-1 + u^2 + O(u^3) */ for a in Kstar do /* Again, we need only look up to the action of the Galois group. This time -1 on E acts trivially. */ if a eq Sort( [a^(2^i) : i in [0..4] ] )[1] then finite_non_ram := [P : P in finite_points | P[1] + a ne 0]; rational_ram := 44 - #finite_non_ram; /* For each finite non-ramified point, compute the values of the four functions in L(P1+P2+2oo) listed above. */ veclist := []; for P in finite_non_ram do val := 1/(P[1] + a); veclist cat:= [ Vector( [val, 1, P[2]*val, P[1]] ) ]; end for; /* Now go through all linear combinations of the four functions that have the right expansion at oo. We only have to enumerate up to addition of constants with trace 0. */ for c1, c3, c4 in K, c2 in {K|0,1} do if (c3+c4)^2 ne c4 then // We're taking f = c1*f1 + c2*f2 + c3*f3 + c4*f4. v := Vector( [c1,c2,c3,c4] ); rhs := [Trace(InnerProduct(v,w)) : w in veclist]; point_count := rational_ram + 2*#[a : a in rhs | a eq 0]; histogram[point_count] +:= 1; if point_count ge 71 then print point_count, a, c1, c2, c3, c4; end if; end if; end for; end if; end for; /* Next we consider the case of two ramification points, one contributing 4 to the degree of the different, one contributing 2. By translation, we may assume that the point that contributes 4 is equal to oo. We loop over rational points P, and let P be the other ramification point. Now we may assume that * f has a simple pole at P, and no other poles outside oo; * f has at a triple pole at oo. So our f lie in L(P + 3oo). If P = [x0,y0], then L(P + 3oo) is spanned by: 1 x y (y + x0 + y0)/(x + x0) If P != (0,0), then the value of the fourth function at -P is equal to (y0 + x0^2 + x0 + 1)/x0. */ for P in finite_points do if P eq Sort( [ [P[1]^(2^i), P[2]^(2^i)] : i in [0..4] ] )[1] then finite_non_ram_non_neg_ram := [Q : Q in finite_points | Q[1] ne P[1]]; rational_ram := 2; if P eq [0,0] then veclist := []; else // Value of functions at -P: veclist := [ Vector([1,P[1],P[1]+P[2],(P[2]+P[1]^2+P[1]+1)/P[1]]) ]; end if; for Q in finite_non_ram_non_neg_ram do veclist cat:= [ Vector( [1,Q[1],Q[2],(Q[2]+P[1]+P[2])/(Q[1]+P[1])] ) ]; end for; for c1 in {K|0,1}, c2, c3 in K, c4 in Kstar do // We're taking f = c1*f1 + c2*f2 + c3*f3 + c4*f4. v := Vector( [c1,c2,c3,c4] ); rhs := [Trace(InnerProduct(v,w)) : w in veclist]; point_count := rational_ram + 2*#[a : a in rhs | a eq 0]; histogram[point_count] +:= 1; if point_count ge 71 then print point_count, P, c1, c2, c3, c4; end if; end for; end if; end for; /* Finally we consider the case of a single ramification point that contributes 6 to the degree of the different. Our cover is z^2 + z = f, where f has a pole of order 5 at infinity and no other poles. L(5oo) is spanned by 1, x, y, x^2, x*y. By Artin-Schreier transformations, we can eliminate any appearance of x^2. */ finite_non_ram := finite_points; rational_ram := 1; veclist := []; for Q in finite_non_ram do veclist cat:= [ Vector( [1, Q[1], Q[2], Q[1]*Q[2]] ) ]; end for; for c4 in Kstar do if c4 eq Sort( [c4^(2^i) : i in [0..4]] )[1] then for c1 in {K|0,1}, c2, c3 in K do // We're taking f = c1*f1 + c2*f2 + c3*f3 + c4*f4. v := Vector( [c1,c2,c3,c4] ); rhs := [Trace(InnerProduct(v,w)) : w in veclist]; point_count := rational_ram + 2*#[a : a in rhs | a eq 0]; histogram[point_count] +:= 1; if point_count ge 71 then print point_count, c1, c2, c3, c4; end if; end for; end if; end for; /* The largest number of points we find is 71. Let's take a closer look at the eight curves found that had 71 points. We'll redefine some of the objects from before to help people who are cutting and pasting. */ K:=GF(32); Kstar := [a : a in K | a ne 0]; E := EllipticCurve([K|1,0,0,1,0]); R:=PolynomialRing(K,3); A:=AffinePlane(K); f := y^2 + x*y + x^3 + x; curve_list := []; rhs_list := []; // The curves from the first section of the program. for vec in [ [r , r^28, r^26, r^21, 0, r^29, r^14], [r^3 , r^6 , r^7 , r^25, 0, r , r^6 ], [r^3 , r^7 , r^21, r^27, 0, r^25, r ], [r^3 , r^15, r^28, r^8 , 1, r^28, r^16], [r^7 , r^5 , r^15, r^15, 1, r^30, r^7 ], [r^7 , r^26, r^18, r^11, 0, r^4 , r^24], [0 , r^11, r^21, r , 1, r^8 , r^17] ] do a := vec[1]; b := vec[2]; c1 := vec[3]; c2 := vec[4]; c3 := vec[5]; c4 := vec[6]; c5 := vec[7]; rhs := (c1 + c2*x + c4*x^2)/(y + a*x + b) + c3 + c5*x; rhs_list cat:= [rhs]; g := Numerator(z^2 + z + rhs); I := ideal; h := Basis(EliminationIdeal(I,{z,y}))[1]; C := Curve(A,Evaluate(h,[0,u,v])); curve_list cat:= [C]; print Genus(C), #Places(C,1),#Places(C,2), #Places(C,3); end for; // The one curve from the second section. a:=r; c1:=1; c2:=1; c3:=0; c4:=r^14; rhs := (c1 + c3*y)/(x + a) + c2 + c4*x; rhs_list cat:= [rhs]; g := Numerator(z^2 + z + rhs); I := ideal; h := Basis(EliminationIdeal(I,{z,y}))[1]; C := Curve(A,Evaluate(h,[0,u,v])); curve_list cat:= [C]; print Genus(C), #Places(C,1),#Places(C,2), #Places(C,3); /* The curves all have genus 4, as expected. The place counts are as follows: 71 419 10928 71 419 10928 71 419 10926 71 419 10926 71 419 10928 71 419 10926 71 423 10856 71 423 10856 Comparing these numbers with the allowable isogeny classes found by IsogenyClasses.magma, we see that we have found examples with three different Weil polynomials. The first, third, and eighth curves can be written as follows: f = (r^27*x^2 + r^13*x*y + r^14*x + r^25)/(x + r^30*y + r^27) f = (r^26*x^2 + r^29*x*y + r^16*x + r^18)/(x + r^28*y + r^4) f = (r^14*x^2 + r^24*x + r^18)/(x + r) and their real Weil polynomials are equal to (x + 7) * (x + 9) * (x + 11)^2 (x + 11) * (x^3 + 27*x^2 + 239*x + 691) (x + 9)^3 * (x + 11) respectively. */