// Genus4.magma, version 2.3, 8 March 2012. /* The Magma programs in this file are associated with the paper New bounds on the maximum number of points on genus-4 curves over small finite fields by Everett W. Howe The function double_covers_genus_4 takes as input a curve C over a finite field of characteristic greater than 2; the curve C must be either an elliptic curve or a curve of genus 2. The function enumerates all isomorphism classes genus-4 double covers of C, and counts the number of points on these double covers. If a curve is a record-breaking or record-tying curve --- that it, if it has at least as many points as all of the curves already seen --- the procedure prints out the number of points and information sufficient to reconstruct the cover. The function returns the largest number of points it finds. The function ECs takes as input a finite field K of characteristic > 3 and an integer t. It returns a list of [a,b] pairs such that the curves y^2 = x^3 + a*x + b give all of the elliptic curves of trace t over K, up to Galois conjugacy over the prime field. The function double_covers_given_trace takes as input a power q of a prime greater than 3 and a trace t, and then runs the function double_covers_genus_4 on all of the elliptic curves over GF(q) that have trace t. It return the largest number of points that it finds. The function hyperelliptic takes as input a power q of a prime greater than 3, and enumerates all of the genus-4 hyperelliptic curves over GF(q) that have an automorphism of order 4, and counts the number of points on these curves. If a curve is a record-breaking or record-tying, the procedure prints out the number of points and the polynomial that defined the curve. The function returns the largest number of points it finds. And finally, the function check_examples checks to see whether the curves given in the paper as examples of genus-4 curves with many points actually do have as many points as they are supposed to. */ /* Version history: ------------------------------------------------------------------------ Version 1.0, 7 March 2011. First published version. ------------------------------------------------------------------------ Version 1.1, 30 July 2011. Edited some comments to more clearly express what the programs are intended to do. ------------------------------------------------------------------------ Version 2.0, 5 August 2011 1. Revised the function double_covers_genus_4 so that it will find genus-4 double covers of genus-2 curves as well as of elliptic curves. 2. Added a utility function "value" used in "double_covers_genus_4". 3. Added a function "hyperelliptic" that finds the largest number of points on a genus-4 curve over a given base field that has an automorphism of order 4. 4. Added the function "check_examples". ------------------------------------------------------------------------ Version 2.1, 29 August 2011 Added code to "check_examples" to check the examples for q = 13 and q = 19, which had been inadvertently omitted from the code and the paper. ------------------------------------------------------------------------ Version 2.2, 1 November 2011 Modified "double_cover_genus_4" so that it will accept input curves over fields of characteristic 3. ------------------------------------------------------------------------ Version 2.3, 8 March 2012 Simplified the function "hyperelliptic". It had previously included a pair of (related) parameters (a,b), but in the current version of the paper, we show that we may take a = -1 and b = 1. */ function ECs(K,t) /* K is a finite field of characteristic greater than 3, and t is an integer. We will return a list of pairs [a,b] such that * each curve y^2 = x^3 + a*x + b has the given trace, * no two curves on the list have Galois conjugates (over the prime field) that are isomorphic over the base field, and * up to Galois conjugacy, every curve over K of trace t is represented in the list. To generate the list, we will loop through all pairs [a,b] of elements of K that define elliptic curves y^2 = x^3 + a*x + b, check to see whether any curve isomorphic to a Galois conjugate of the new curve has already been tested. If the pair is new, we will check to see whether the associated curve has the right trace, and if it does, we will add it to the list. */ p := Characteristic(K); assert p gt 3; answer :=[]; taken := {}; for a,b in K do if not [a,b] in taken then if 4*a^3 + 27*b^2 ne 0 then E := EllipticCurve([0,0,0,a,b]); if Trace(E) eq t then answer cat:= [[a,b]]; end if; new := {}; isomorphs := { [a*c^4,b*c^6] : c in K | c ne 0}; repeat count := #new; new join:= isomorphs; isomorphs := {[ab[1]^p,ab[2]^p] : ab in isomorphs}; until count eq #new; taken join:= new; end if; end if; end for; return answer; end function; function value(f,place) /* Given a function f on a curve C, and a degree-1 place of C corresponding to a point P, return the value (f/u^n)(P), where u is a uniformizer at P, and n is the largest *even* integer such that f/u^n has no pole at P. (This quantity determines how many points lie over P in the extension z^2 = f.) */ d := Valuation(f,place); if d eq 0 then return f(RepresentativePoint(place)); end if; if IsOdd(d) then return 0; end if; u := UniformizingParameter(place); return (f/u^d)(RepresentativePoint(place)); end function; function double_covers_genus_4(C : verbose:=true) /* Given a curve C of genus 1 or 2 over a finite field of characteristic greater than 2, compute all genus-4 double covers of C. Keep track of the largest number of points that occurs on these double covers. Return the largest number of points found. */ K := BaseRing(C); p := Characteristic(K); q := #K; // Find a nonsquare in K. If K is not a prime field, Magma's // generator for K will do. If K is a prime field, find the // smallest positive integer whose image in K is a nonsquare. ns := K.1; if ns eq 1 then repeat ns+:=1; until not IsSquare(ns); end if; assert not IsSquare(ns); // Construct representatives for P^1(K): projective_line := [ [a,1] : a in K ] cat [ [K|1,0] ]; // Branch depending on the genus of C. case Genus(C): when 1: // We are in the elliptic case. // // First, we let E be a simplified Weierstrass model for C, so that // E is defined by y^2 = x^3 + a*x + b. // // A genus-4 double cover E can be written z^2 = f for a function // f on E with // // div f = P1 + ... + P6 + 2*Q - 8*oo. // // Here Q need only range over a set of representatives for E(K) // modulo // * translation by elements of 3*E(K), and // * the action of Aut(E). // // Note that one of the P's may be equal to oo, and that Q can be // equal to one of the P's, or to oo. // Get a simplified Weierstrass model for our curve. // In characteristic > 3, this is a model of the form // y^2 = x^3 + a*x + b. In characteristic 3, it is a // model of the form y^2 = cubic. E := SimplifiedModel(C); rhs := HyperellipticPolynomials(E); assert (p eq 3) or (Coefficient(rhs,2) eq 0); // Compute the automorphisms of E of the form // (x,y) --> (u*x,v*y) for pairs [u,v] in K. // Usually the only such automorphisms are [1,1] and [1,-1]. // The exceptions are enumerated below. if Coefficient(rhs,0) eq 0 and 1 eq q mod 4 then // We have y^2 = x^3 + a*x, with CM by Z[i]. i := Roots(Parent(rhs).1^2 + 1)[1][1]; autos := [ [-1,i], [1,-1], [-1,-i], [1,1] ]; elif Coefficient(rhs,1) eq 0 and 1 eq q mod 3 then // We have y^2 = x^3 + b, with CM by Z[zeta_3]. omega := Roots(Parent(rhs).1^2 + Parent(rhs).1 + 1)[1][1]; autos := [ [omega, 1],[omega^2, 1],[1, 1], [omega,-1],[omega^2,-1],[1,-1] ]; else // The generic case. autos := [ [1,1],[1,-1] ]; end if; // The variable maxcount keeps track of the highest number // of points we have found so far. maxcount := 0; // First compute the double covers where we may take Q = oo, so // that we look at covers z^2 = f where the only pole of f is at oo // and where the order of the pole of f at infinity is 5 or 6. // We only need to look at the f up to multiplication by squares // and up to the action of the automorphism group. F:=FunctionField(E); oo := Identity(E); finite_points := [[P[1],P[2]] : P in E | not P eq oo]; // Our functions f will be in L(6*oo). We will use the basis // {x^3, x*y, x^2, y, x, 1} for this Riemann-Roch space. // "values" will be a list of vectors that give the values of // these basis functions on the elements of E. However, the // first element of "value" will be (1,0,0,0,0,0), which // gives the coeffient of u^-6 in the Laurent expansion of // these basis functions at oo, where u is a uniformizer at oo. // This will let us obtain the correct number of points lying // over oo. values := [Vector([K|1,0,0,0,0,0])]; for P in finite_points do values cat:= [Vector([P[1]^3, P[1]*P[2], P[1]^2, P[2], P[1], 1])]; end for; // Start with by looking at the f with a pole of order 6. Up to a // constant factor, our f will be // x^3 + c5*x*y + c4*x^2 + c3*y + c2*x + c1. // Suppose an automorphism multiplies x by u and y by v. Then the // function // x^3 + c5*x*y + c4*x^2 + c3*y + c2*x + c1 // gets taken to // u^3*x^3 + c5*u*v*x*y + ... // which differs by a scalar from // x^3 + c5*v/u^2 * x*y + ... // We only need let c5 range over a set of representatives of K // modulo this action of the automorphism group. case #autos: when 2: roots_of_1 := [K!1,-1]; when 4: roots_of_1 := [1,i,-1,-i]; when 6: roots_of_1 := [1,-omega,omega^2,-omega^3,omega^4,-omega^5]; end case; // So roots_of_1 consists of the elements of the form v/u^2 for // automorphism [u,v] of E. // We will compute the number of points on z^2 = f and z^2 = ns*f // at the same time, and only consider the larger of the two. c5reps := [a : a in K | a eq Sort([a*w : w in roots_of_1])[1]]; for c5 in c5reps, c4, c3, c2, c1 in K do w := Vector([1,c5,c4,c3,c2,c1]); // Initialize the number of square, nonsquare, and zero values of f. // Since the leading term of is x^3, f splits at infinity, so we // initial the number of squares to 1. square := 0; nonsquare := 0; zero := 0; for v in values do u := InnerProduct(v,w); if u eq 0 then zero +:= 1; elif IsSquare(u) then square +:= 1; else nonsquare +:=1; end if; end for; count1 := zero + 2*square; // The number of points on z^2 = f. count2 := zero + 2*nonsquare; // The number of points on z^2 = ns*f. count := Max(count1, count2); if count ge maxcount then // It looks like we have a cover with more points than the last // maximum. But is it irreducible, and of genus 4? Check by // looking at the decomposition of the divisor of f. f := w[1]*x^3 + w[2]*x*y + w[3]*x^2 + w[4]*y + w[5]*x + w[6]; D := Decomposition(Divisor(f)); ramification := &+([0] cat [Degree(d[1]) : d in D | IsOdd(d[2])]); if ramification eq 6 then // OK, it looks like we've got an actual curve. maxcount := count; if count eq count2 then f := ns*f; end if; if verbose then printf "%o: y^2 = %o, z^2 = %o\n", count, rhs, f; end if; end if; end if; end for; // Now look for f's where one of the ramification points is oo. // There are fewer of these than there are of the preceding form, // so we don't bother modding out by the automorphism group. for c4, c3, c2, c1 in K do w := Vector([0,1,c4,c3,c2,c1]); square := 0; nonsquare := 0; zero := 0; for v in values do u := InnerProduct(v,w); if u eq 0 then zero +:= 1; elif IsSquare(u) then square +:= 1; else nonsquare +:=1; end if; end for; count1 := zero + 2*square; count2 := zero + 2*nonsquare; count := Max(count1, count2); if count ge maxcount then f := w[1]*x^3 + w[2]*x*y + w[3]*x^2 + w[4]*y + w[5]*x + w[6]; D := Decomposition(Divisor(f)); ramification := &+([0] cat [Degree(d[1]) : d in D | IsOdd(d[2])]); if ramification eq 6 then maxcount := count; if count eq count2 then f := ns*f; end if; if verbose then printf "%o: y^2 = %o, z^2 = %o\n", count, rhs, f; end if; end if; end if; end for; // Q should range over the classes of E(K) modulo 3*E(K) // up to the automorphism group of E. We've already // considered the case of the class of oo. So now // we must compute representatives for the other classes. // But we'd like to avoid taking a representative that is a // 2-torsion point, because that would introduce some special // cases in later computations. replist := []; threeE := [P : P in {3*Q : Q in E}]; taken := Set(threeE); while #taken ne #E do remainder := Sort([ [P[1],P[2],P[3]] : P in E | not P in taken ]); index := 0; repeat index +:= 1; Q := E!remainder[index]; until not 2*Q eq oo; replist cat:= [Q]; taken join:= { (E![Q[1]*A[1],Q[2]*A[2]]) + T : A in autos, T in threeE }; end while; // Now for each representative point Q, we modify the model // of E so that the x-coordinate of Q is 0. Our curve will // then be of the form y^2 = x^3 + a*x^2 + b*x + c^2. for Q in replist do // Announce what Q we are looking at, to provide some feedback. if verbose then print Q; end if; rhsQ := Evaluate(rhs,Parent(rhs).1 + Q[1]); a := Coefficient(rhsQ,2); b := Coefficient(rhsQ,1); c := Q[2]; assert c^2 eq Coefficient(rhsQ,0); // New curve, new function field, new coordinates for Q... EQ := EllipticCurve(rhsQ); FQ:=FunctionField(EQ); QQ := EQ![0,c]; ooQ := Identity(EQ); m := b/(2*c); // The tangent line to EQ at QQ is y = m*x + c. // The points on EQ other than ooQ and QQ: finite_points_Q := [[P[1],P[2]] : P in EQ | not P eq ooQ and not P eq QQ]; // Now we take f to lie in L(8*ooQ - 2*QQ). This space is // spanned by x^4, x^2*(y-c), x^3, x*(y-c), x^2, and y - m*x - c. values := [Vector([K!1,0,0,0,0,0]), Vector([0,0,0,b/(2*c),1,(4*a*c^2-b^2)/(8*c^3)])]; // The first value vector gives the coefficient of u^-8 in the // Laurent expansion of the basis functions at ooQ, for a uniformizer // u at ooQ. The second value vector gives the coefficient of u^2 // in the Laurent expansion of the basis function at QQ, for a // uniformizer u at QQ. // Assuming that the genus of the double cover z^2 = f is actually // equal to 4, these leading terms of the expansions at ooQ and QQ // are what we need in order to detemine whether ooQ and QQ split, // are inert, or are ramified in the cover. for P in finite_points_Q do values cat:= [Vector([P[1]^4, P[1]^2*(P[2]-c), P[1]^3, P[1]*(P[2]-c), P[1]^2, P[2]-m*P[1]-c])]; end for; // The point-counting strategy is as before: for c5, c4, c3, c2, c1 in K do w := Vector([1,c5,c4,c3,c2,c1]); square := 0; nonsquare := 0; zero := 0; for v in values do u := InnerProduct(v,w); if u eq 0 then zero +:= 1; elif IsSquare(u) then square +:= 1; else nonsquare +:=1; end if; end for; count1 := zero + 2*square; count2 := zero + 2*nonsquare; count := Max(count1, count2); if count ge maxcount then f := w[1]*x^4 + w[2]*x^2*(y-c) + w[3]*x^3 + w[4]*x*(y-c) + w[5]*x^2 + w[6]*(y-m*x-c); D := Decomposition(Divisor(f)); ramification := &+([0] cat [Degree(d[1]) : d in D | IsOdd(d[2])]); if ramification eq 6 then maxcount := count; if count eq count2 then f := ns*f; end if; if verbose then printf "%o: y^2 = %o, z^2 = %o\n", count, rhsQ, f; end if; end if; end if; end for; // Now look for f's where one of the ramification points is oo. for c4, c3, c2, c1 in K do w := Vector([0,1,c4,c3,c2,c1]); square := 0; nonsquare := 0; zero := 0; for v in values do u := InnerProduct(v,w); if u eq 0 then zero +:= 1; elif IsSquare(u) then square +:= 1; else nonsquare +:=1; end if; end for; count1 := zero + 2*square; count2 := zero + 2*nonsquare; count := Max(count1, count2); if count ge maxcount then f := w[1]*x^4 + w[2]*x^2*(y-c) + w[3]*x^3 + w[4]*x*(y-c) + w[5]*x^2 + w[6]*(y-m*x-c); D := Decomposition(Divisor(f)); ramification := &+([0] cat [Degree(d[1]) : d in D | IsOdd(d[2])]); if ramification eq 6 then maxcount := count; if count eq count2 then f := ns*f; end if; if verbose then printf "%o: y^2 = %o, z^2 = %o\n", count, rhs, f; end if; end if; end if; end for; end for; when 2: // We are in the case where we are looking for genus-4 double // covers of a genus-2 curve. // These are defined by z^2 = f, where // div f = P1 + P2 + 2*D - 6*oo // where D is effective of degree 2. // We find such f by looping over D, and computing the // Riemann-Roch space L(6*oo - 2*D). F:=FunctionField(C); places1 := Places(C,1); // Choose a base point for the Jacobian. oo := places1[1]; places2 := Places(C,2); degree2 := [Divisor(p) : p in places2] cat [Divisor(places1[i]) + Divisor(places1[j]): i,j in [1..#places1] | i le j]; // Separate the elements of degree2 into those for which // the dimension of the Riemann-Roch space L(6*oo - D) is 1 // and those for which it is 2. dim1 :=[]; dim2 :=[]; for D in degree2 do L := RiemannRochSpace(6*oo - 2*D); case Dimension(L): when 1: dim1 cat:= [D]; when 2: dim2 cat:= [D]; else error "Impossible dimension of Riemann-Roch space."; end case; end for; maxcount := 0; for D in dim1 do L,phi := RiemannRochSpace(6*oo - 2*D); f := phi(Basis(L)[1]); // We want the extension z^2 = f to define a geometrically // reduced curve, so f should not be a square when the base // field is extended to the algebraic closure. if not IsSquare(f) and not IsSquare(ns*f) then // Count the number of degree-1 places of C where // value(f) is a square, a nonsquare, or zero. zero := 0; square := 0; nonsquare := 0; for P in places1 do v := value(f,P); if v eq 0 then zero +:= 1; elif IsSquare(v) then square +:= 1; else nonsquare +:=1; end if; end for; count1 := zero + 2*square; count2 := zero + 2*nonsquare; count := Max(count1, count2); if count ge maxcount then maxcount := count; if verbose then print maxcount, f; end if; end if; end if; end for; // Next, the f coming from the 2-dimensional Riemann-Roch spaces. for D in dim2 do L,phi := RiemannRochSpace(6*oo - 2*D); f1 := phi(Basis(L)[1]); f2 := phi(Basis(L)[2]); for c in projective_line do f := c[1]*f1 + c[2]*f2; if not IsSquare(f) and not IsSquare(ns*f) then zero := 0; square := 0; nonsquare := 0; for P in places1 do v := value(f,P); if v eq 0 then zero +:= 1; elif IsSquare(v) then square +:= 1; else nonsquare +:=1; end if; end for; count1 := zero + 2*square; count2 := zero + 2*nonsquare; count := Max(count1, count2); if count ge maxcount then maxcount := count; if verbose then print maxcount, f; end if; end if; end if; end for; end for; // Almost finished with our case statement. // Just add an error if the input curve is not genus 1 or 2. else error "The input curve must be an elliptic curve or a curve of genus 2."; end case; return maxcount; end function; function double_covers_given_trace(q,t:verbose := true) /* Given a power q of a prime p with p > 3, and given an integer t, find all ellipic curves over GF(q) with trace t (up to isomorphism and up to the action of the Galois group of GF(q) over GF(p)). For each curve E, compute the maximal number of points on a genus-4 double cover of E. */ K:=GF(q); R:=PolynomialRing(K); ab_list := ECs(K,t); maxcount := 0; for ab in ab_list do E := EllipticCurve(x^3 + ab[1]*x + ab[2]); count := double_covers_genus_4(E:verbose:=verbose); if count gt maxcount then maxcount := count; end if; if verbose then print "======================="; end if; end for; return maxcount; end function; function hyperelliptic(q : verbose := true); /* Given a power q of a prime that is greater than 3, run through all genus-4 hyperelliptic curves C over GF(q) that have an automorphism of order 4, and count the number of points on C. If a curve is a record-breaking or record-tying, print the number of points and the polynomial that defines the curve. Return the largest number of points found. */ fq := Factorization(q); assert #fq eq 1 and fq[1][1] gt 3; K := GF(q); R:=PolynomialRing(K); // Find a nonsquare in K. If K is not a prime field, Magma's // generator for K will do. If K is a prime field, find the // smallest positive integer whose image in K is a nonsquare. ns := K.1; if ns eq 1 then repeat ns+:=1; until not IsSquare(ns); end if; assert not IsSquare(ns); first_two_coeffs := [ [K|0,1] ] cat [ [1,a] : a in K ]; maxcount := 0; // Our curves are of the form // y^2 = f // where f is in the span of the following functions: basis := [x^10 + 1 , x^9 - x , x^8 + x^2, x^7 - x^3, x^6 + x^4]; for c in first_two_coeffs, c3, c4, c5 in K do f := c[1]*basis[1] + c[2]*basis[2] + c3*basis[3] + c4 *basis[4] + c5*basis[5]; if Discriminant(f) ne 0 then C := HyperellipticCurve(f); // The number of points on C: n1 := #C; // The number of points on the twist: n2 := 2*(q+1) - n1; n := Max(n1,n2); if n ge maxcount then maxcount := n; if verbose then if n eq n1 then print n,f; else print n, ns*f; end if; end if; end if; end if; end for; return maxcount; end function; function check_examples(); /* Check to see that the curves listed in the paper that are supposed to attain the stated lower bounds on N_q(4) actually *do* attain the lower bounds on N_q(4). */ badlist := []; q := 13; N := 38; K:=GF(q); R:=PolynomialRing(K,3); A:=AffinePlane(K); f := y^2 - (x^3 + 4); g := z^2 - (x^3 + x^2 - 4*x - 3); h := Basis(EliminationIdeal(ideal,{y,z}))[1]; C := Curve(A,Evaluate(h,[0,u,v])); if not (Genus(C) eq 4 and N eq #Places(C,1)) then badlist cat:= [q]; end if; q := 17; N := 46; K:=GF(q); R:=PolynomialRing(K,3); A:=AffinePlane(K); f := y^2 - (x^3 + x + 8); g := z^2 - (x^3 - 5*x^2 - 2*x - 8); h := Basis(EliminationIdeal(ideal,{y,z}))[1]; C := Curve(A,Evaluate(h,[0,u,v])); if not (Genus(C) eq 4 and N eq #Places(C,1)) then badlist cat:= [q]; end if; q := 19; N := 48; K:=GF(q); R:=PolynomialRing(K,3); A:=AffinePlane(K); f := y^2 - (x^3 + 8); g := z^2 - (x^3 - 9*x^2 - 5); h := Basis(EliminationIdeal(ideal,{y,z}))[1]; C := Curve(A,Evaluate(h,[0,u,v])); if not (Genus(C) eq 4 and N eq #Places(C,1)) then badlist cat:= [q]; end if; q := 23; N := 57; K:=GF(q); R:=PolynomialRing(K,3); A:=AffinePlane(K); f := y^2 - (x^3 - 6*x^2 - 3*x - 7); g := z^2 - (x*y + 2*x^3 - 11*x^2 + 7*x + 1); h := Basis(EliminationIdeal(ideal,{y,z}))[1]; C := Curve(A,Evaluate(h,[0,u,v])); if not (Genus(C) eq 4 and N eq #Places(C,1)) then badlist cat:= [q]; end if; q := 29; N := 67; K:=GF(q); R:=PolynomialRing(K,3); A:=AffinePlane(K); f := y^2 - (x^3 - 3*x + 18); g := z^2 - (y + 7*x^3 + 6*x^2 + 2*x - 10); h := Basis(EliminationIdeal(ideal,{y,z}))[1]; C := Curve(A,Evaluate(h,[0,u,v])); if not (Genus(C) eq 4 and N eq #Places(C,1)) then badlist cat:= [q]; end if; q := 31; N := 72; K:=GF(q); R:=PolynomialRing(K,3); A:=AffinePlane(K); f := y^2 - (x^3 + x + 10); g := z^2 - (x^3 + 7*x^2 - 13*x - 13); h := Basis(EliminationIdeal(ideal,{y,z}))[1]; C := Curve(A,Evaluate(h,[0,u,v])); if not (Genus(C) eq 4 and N eq #Places(C,1)) then badlist cat:= [q]; end if; q := 37; N := 82; K:=GF(q); R:=PolynomialRing(K,3); A:=AffinePlane(K); f := y^2 - (x^3 + 2*x); g := z^2 - (x^3 + x^2 - 10*x - 13); h := Basis(EliminationIdeal(ideal,{y,z}))[1]; C := Curve(A,Evaluate(h,[0,u,v])); if not (Genus(C) eq 4 and N eq #Places(C,1)) then badlist cat:= [q]; end if; q := 41; N := 88; K:=GF(q); R:=PolynomialRing(K,3); A:=AffinePlane(K); f := y^2 - (x^3 + 6*x + 5); g := z^2 - (3*x^3 - 17*x^2 - 11*x); h := Basis(EliminationIdeal(ideal,{y,z}))[1]; C := Curve(A,Evaluate(h,[0,u,v])); if not (Genus(C) eq 4 and N eq #Places(C,1)) then badlist cat:= [q]; end if; q := 43; N := 92; K:=GF(q); R:=PolynomialRing(K,3); A:=AffinePlane(K); f := y^2 - (x^3 + 2*x + 1); g := z^2 - (x^3 - 6*x^2 + 11*x); h := Basis(EliminationIdeal(ideal,{y,z}))[1]; C := Curve(A,Evaluate(h,[0,u,v])); if not (Genus(C) eq 4 and N eq #Places(C,1)) then badlist cat:= [q]; end if; q := 47; N := 98; K:=GF(q); R:=PolynomialRing(K,3); A:=AffinePlane(K); f := y^2 - (x^5 - 6*x^3 + 8*x^2 - 5*x + 12); g := z^2 - (y + 6*x^3 + 6*x^2 - x - 3); h := Basis(EliminationIdeal(ideal,{y,z}))[1]; C := Curve(A,Evaluate(h,[0,u,v])); if not (Genus(C) eq 4 and N eq #Places(C,1)) then badlist cat:= [q]; end if; q := 49; N := 102; K:=GF(q); R:=PolynomialRing(K,3); A:=AffinePlane(K); f := y^2 - (x^3 + x); g := z^2 - (x^3 + x^2 + x + 4); h := Basis(EliminationIdeal(ideal,{y,z}))[1]; C := Curve(A,Evaluate(h,[0,u,v])); if not (Genus(C) eq 4 and N eq #Places(C,1)) then badlist cat:= [q]; end if; q := 53; N := 108; K:=GF(q); R:=PolynomialRing(K,3); A:=AffinePlane(K); f := y^2 - (x^3 + 4*x + 10); g := z^2 - (x^3 + 12*x^2 + 17*x + 9); h := Basis(EliminationIdeal(ideal,{y,z}))[1]; C := Curve(A,Evaluate(h,[0,u,v])); if not (Genus(C) eq 4 and N eq #Places(C,1)) then badlist cat:= [q]; end if; q := 59; N := 116; K:=GF(q); R:=PolynomialRing(K,3); A:=AffinePlane(K); f := y^2 - (x^3 + 2*x + 22); g := z^2 - (2*x^3 + x^2 - x + 9); h := Basis(EliminationIdeal(ideal,{y,z}))[1]; C := Curve(A,Evaluate(h,[0,u,v])); if not (Genus(C) eq 4 and N eq #Places(C,1)) then badlist cat:= [q]; end if; q := 61; N := 118; K:=GF(q); R:=PolynomialRing(K,3); A:=AffinePlane(K); f := y^2 - (x^3 + 4); g := z^2 - (x^3 + 23*x^2 + 25*x + 36); h := Basis(EliminationIdeal(ideal,{y,z}))[1]; C := Curve(A,Evaluate(h,[0,u,v])); if not (Genus(C) eq 4 and N eq #Places(C,1)) then badlist cat:= [q]; end if; q := 67; N := 129; K:=GF(q); R:=PolynomialRing(K,3); A:=AffinePlane(K); f := y^2 - (x^3 + 25); g := z^2 - (x*y - 8*x^3 - 27*x + 4); h := Basis(EliminationIdeal(ideal,{y,z}))[1]; C := Curve(A,Evaluate(h,[0,u,v])); if not (Genus(C) eq 4 and N eq #Places(C,1)) then badlist cat:= [q]; end if; q := 71; N := 134; K:=GF(q); R:=PolynomialRing(K,3); A:=AffinePlane(K); f := y^2 - (x^3 + x + 9); g := z^2 - (x^3 + 9*x^2 + 24*x - 9); h := Basis(EliminationIdeal(ideal,{y,z}))[1]; C := Curve(A,Evaluate(h,[0,u,v])); if not (Genus(C) eq 4 and N eq #Places(C,1)) then badlist cat:= [q]; end if; q := 73; N := 138; K:=GF(q); R:=PolynomialRing(K,3); A:=AffinePlane(K); f := y^2 - (x^3 + 3*x + 11); g := z^2 - (x^3 + 34*x^2 + 18*x + 40); h := Basis(EliminationIdeal(ideal,{y,z}))[1]; C := Curve(A,Evaluate(h,[0,u,v])); if not (Genus(C) eq 4 and N eq #Places(C,1)) then badlist cat:= [q]; end if; q := 79; N := 148; K:=GF(q); R:=PolynomialRing(K,3); A:=AffinePlane(K); f := y^2 - (x^3 + x + 6); g := z^3 - (y + 33*x + 2); h := Basis(EliminationIdeal(ideal,{y,z}))[1]; C := Curve(A,Evaluate(h,[0,u,v])); if not (Genus(C) eq 4 and N eq #Places(C,1)) then badlist cat:= [q]; end if; q := 83; N := 152; K:=GF(q); R:=PolynomialRing(K,3); A:=AffinePlane(K); f := y^2 - (x^3 + 2*x + 19); g := z^2 - (x^3 + 38*x^2 - 6*x + 39); h := Basis(EliminationIdeal(ideal,{y,z}))[1]; C := Curve(A,Evaluate(h,[0,u,v])); if not (Genus(C) eq 4 and N eq #Places(C,1)) then badlist cat:= [q]; end if; q := 89; N := 160; K:=GF(q); R:=PolynomialRing(K,3); A:=AffinePlane(K); f := y^2 - (x^3 + 3*x); g := z^2 - (x^3 + 13*x^2 - 22*x + 28); h := Basis(EliminationIdeal(ideal,{y,z}))[1]; C := Curve(A,Evaluate(h,[0,u,v])); if not (Genus(C) eq 4 and N eq #Places(C,1)) then badlist cat:= [q]; end if; q := 97; N := 174; K:=GF(q); R:=PolynomialRing(K,3); A:=AffinePlane(K); f := y^2 - (x^3 + 5*x + 26); g := z^3 - (y + 37*x + 16); h := Basis(EliminationIdeal(ideal,{y,z}))[1]; C := Curve(A,Evaluate(h,[0,u,v])); if not (Genus(C) eq 4 and N eq #Places(C,1)) then badlist cat:= [q]; end if; if #badlist eq 0 then print "All of the examples check out."; return true; end if; print "There were problems with the examples for these q:"; print badlist; return false; end function;