{kedlaya(Qpolydach,p,fdach,debug)= /* This program computes the rational points of a hyperelliptic curve y^2 = Q(x) following a algorithm of Kedlaya[2001]. Input: Qpolydach: The seperable polynomial Q(x) from F_q[x] with y^2 = Q(x). p: The characteristic of F_q. n: The power of p, ie. q = p^n. fdach: The polynomial f(x) from F_p[x] with F_q ~ F_p[x] / . debug: The debug-modus, 0 is no debugging up to ??? Output: The number of rational points of the hyperelliptic curve. Dieses Programm berechnet die rationalen Punkte auf einer hyperelliptischen Kurve y^2 = Q(x) nach dem Algorithmus von Kedlaya[2001]. Eingabe: Qpolydach: (Polynom) Das seperable Polynom Q(x) aus F_q[x] mit y^2 = Q(x). p: (Primzahl) Die Charakteristik von F_q. n: (positiver Integer) Der Exponent von p, dh.q = p^n. fdach: (Polynom) Das Polynom f(x) aus F_p[x] mit F_q ~ F_p[x] / . debug: (Boolean??) Der Debugger-Modus, von 0 (kein debugging) bis ??. Ausgabe: Die Anzahl der rationalen Punkte der hyperelliptischen Kurve in F_q. */ local(Qpoly,mod,modulou,Qpolydachv,vorlaeufigpraezisionN,ggT,SUM,vek,prez,frobprez); y; Y; w; v; u; /* Die benoetigte Ordnung der Variablen fuer die GP-Funktion Mod */ /* Ich veraendere die Variablen, weil x in PARI eine fuer mich ungeeignete Sonderstellung hat... Also fdach(z) -> fdach(u) und Qpolydach(z,x) -> Qpolydach(u,v). */ print(" "); print("----------------------------------------------------------------------------------------------------------------"); print("in kedlaya.gp "); print("----------------------------------------------------------------------------------------------------------------"); modulou = subst( fdach , variable( fdach ) , u ); Qpolydachv = subst( subst( lift(Qpolydach) , variable( lift(Qpolydach) ) , v) , variable(fdach) , u )* Mod( 1 , modulou ); ggT = bezout(Qpolydachv, deriv(Qpolydachv,v)); /* - Hier untersuchen wir, ob Qpolydach und fdach geeignet sind. */ if( poldegree(lift(ggT[3]),u) == 0, /* Falls der Grad vom ggT Null ist, so ist der ggT eine Konstante, also invertierbar und somit 1. */ if( issquarefree( modulou ), if( length(factormod( modulou , p )) != 2, /* Falls mehrere Faktoren auftauchen */ error( "Das erzeugende Polynom f(x)= "fdach" ist nicht irreduzibel! " ), ), /* Falls doppelte Faktoren auftauchen */ error("Das erzeugende Polynom f(x)= "fdach" ist nicht irreduzibel! "); /* endif */ ); /* endif */ print("Polynom in Ordung, Erzeuger auch"), error("Polynom Q(x) hat mehrfache Nullstellen"); ); /* endif */ vorlaeufigpraezisionN = ceil( ( poldegree( Qpolydachv , v ) ) * log(2) / log(p) + poldegree( modulou , u )*( poldegree( Qpolydachv , v ) - 1 ) / 4); prez = vorlaeufigpraezisionN + valuation( poldegree( Qpolydachv , v ) , p ) + ceil( log( poldegree( Qpolydachv , v ) - (2 / p)) / log(p) ) + ceil(log(poldegree( Qpolydachv , v ) - 2)/log(p)); frobprez = 0; /* Da die Praezision > 0 und floor(0) = 0. */ while( frobprez -floor( log( 2*frobprez + 1 ) / log(p) ) < prez, frobprez++ ); /* endwhile */ frobprez = frobprez + debug; /* Lifte die Daten nach Zp bzw. Zq */ mod = lift(modulou)+O(p^prez); Qpoly = Mod(1+O(p^prez),mod)*(lift(lift(Qpolydachv))); vektor=frob(ggT[2],Qpoly,mod,p,prez,frobprez); matrize(vektor,Qpoly,mod,p,prez) } {addhelp(kedlaya,"kedlaya(Qpol,p,modulo,{b}) counts the points of the hyperelliptic curve y^2=Q(x) " "over F_q ~ F_p[z]/ using the algorithm of Kedlaya[2001]. Therefore the prime " "has to be odd. It returns a vector with the number of points in the first entry " "and in the second the Zeta-function of the curve."); } {yinverse(Qpoly,modulo,p,prez,frobprez)= /* This part computes the frobeniusaction on 1/y. Here we use y instead of 1/y. Input: Qpoly = The lifted polynomial in Zq[v] with y^2 = Qpoly. modulo = Tthe lifted polynomial in Zp[u] with Qq ~ Qp[u]/(modulo(u)). p = The characteristic of the residue field of Qq. prez = The necessary precision for the computation in Qq. frobprez = The necessary number of summands in the frobeniusexpansion. Output: inv = The Polynomial with the frobeniusaction on y. Dieser Teil berechnet die Frobeniusaktion auf 1/y. Wir benutzen y anstatt 1/y. Eingabe: Qpoly = Das geliftete Polynom in Zq[v] mit y^2 = Qpoly. modulo = Das geliftete Polynom in Zp[u] mit Qq ~ Qp[u]/(modulo(u)). p = Die Charakteristik des Restklassenkoerpers Fq. prez = Die benoetigte Praezision fuer die Rechnungen in Qq. frobprez = Die Anzahl der benoetigten Summanden in der Frobeniusaktion. Hier invertiere ich y^2 von y^2=Q(x). Hier benutze ich zum ersten mal die Variable y! Y := y^(-1) */ local(inv,zwischen,zwischen2,E,zwischen3,testzwischen,bi,pow); print("----------------------------------------------------------------------------------------"); print("In yinverse"); print("----------------------------------------------------------------------------------------"); gettime(); E = smallfrob(Qpoly,u+O(p^prez),modulo,p,prez,1); inv = Mod(1+O(p^prez),modulo); zwischen = substpol(E,Qpoly,x^2); zwischen = Mod(1+O(p^prez),modulo) + subst( zwischen,x,Y)*y^(2*p); zwischen = sorting(zwischen,Qpoly,modulo,p,prez,frobprez); bi = length(binary(2*p*frobprez+1)); forstep( b = bi-1, 0, -1, print("In yinverse:: In forstep-Schleife "b" bis 0"); pow = ceil((2*p*frobprez+1)/(1< 0, forstep( h = poldegree(lift(lift(ser)),Y), 1, -2, if(lift(lift(polcoeff(ser,h,Y)))==0, /* Falls der Koeffizient Null ist, tue nichts */ , SER = SER + (polcoeff(ser,h,Y)*Qpoly^((h-1)/2 + 1)); /* Ansosnsten hebe den Koeffizienten an */ ); /* endif */ ); /* endforstep */ ); /* endif */ SER = lift(lift(SER))*Mod(1+O(p^(padicprec(SER,p))),modulo); forstep( k = poldegree(lift(lift(SER)),v), poldegree(Qpoly,v), -1, Koeff =2*deriv(v^(k+1-poldegree(Qpoly,v)),v)*Qpoly + v^(k+1 -poldegree(Qpoly,v))*dQpoly; SER = SER - ((polcoeff(SER,k,v)/(pollead(Koeff,v)))*(2*deriv(v^(k+1-poldegree(Qpoly,v)),v)*Qpoly + v^(k+1 -poldegree(Qpoly,v))*dQpoly)); /* Hier reduziere ich die Grade in v */ ); /* endforstep */ if( poldegree(lift(lift(SER)),v) >= poldegree(Qpoly,v), gradmesser = poldegree(dQpoly,v), gradmesser = poldegree(lift(lift(SER)),v); ); /* Weil poldegree manchmal die Grd nicht richtig zurueck gibt, setze ich ihn hier notgedrungen */ if( gradmesser==poldegree(dQpoly,v), SER = SER - (polcoeff(SER,poldegree(dQpoly),v)/poldegree(Qpoly,v))*dQpoly; /* Hier benutze ich dy = Qpoly'(dx/2y) */ ); /* Nun ist SER auf die Basis reduziert und wird somit zurueck gegeben */ print("Verlasse reduktion "); return(SER); } {sorting(pol,Qpoly,modulo,p,prez,frobprez)= /* This part sorts the Y, which is 1/y, in a Polynomial in y. Input: pol = A polynomial in Qq[v,y,Y]. Qpoly = The lifted polynomial in Zq[v] with y^2 = Qpoly. modulo = Tthe lifted polynomial in Zp[u] with Qq ~ Qp[u]/(modulo(u)). p = The characteristic of the residue field of Qq. prez = The necessary precision for the computation in Qq. frobprez = The necessary number of summands in the frobeniusexpansion. Output: zwischen = The sorted polynomial. Dieser Teil des Programms sortiert die Y in das Polynom pol ein, dabei ist Y eigentlich 1/y. Eingabe: pol = Ein Polynom in Qq[v,y,Y]. Qpoly = Das geliftete Polynom in Zq[v] mit y^2 = Qpoly. modulo = Das geliftete Polynom in Zp[u] mit Qq ~ Qp[u]/(modulo(u)). p = Die Charakteristik des Restklassenkoerpers Fq. prez = Die benoetigte Praezision fuer die Rechnungen in Qq. frobprez = Die Anzahl der benoetigten Summanden in der Frobeniusaktion. Output: zwischen = Das sortierte Polynom. */ local(zwischen); print("----------------------------------------------------------------------------------------"); print("In sorting"); print("----------------------------------------------------------------------------------------"); gettime(); zwischen = 0; for(z = 0, poldegree(lift(lift(pol)),y), if( poldegree(polcoeff(lift(lift(pol)),z,y),Y) > 0, if( poldegree(polcoeff(lift(lift(pol)),z,y),Y) <= z, for( q = 0, poldegree(polcoeff(lift(lift(pol)),z,y),Y), zwischen = zwischen + polcoeff(polcoeff(pol,z,y),q,Y)*y^(z-q); ), /* endfor */ for( q = 0, z, zwischen = zwischen + polcoeff(polcoeff(pol,z,y),q,Y)*y^(z-q); ); /* endfor */ for( q = z+1, poldegree(polcoeff(pol,z,y),Y), zwischen = zwischen + polcoeff(polcoeff(pol,z,y),q,Y)*Y^(q-z); ); /* endfor */ ), /* endif */ if( poldegree(polcoeff(pol,z,y),Y) == 0, zwischen = zwischen + polcoeff(pol,z,y)*y^z; ); /* endif */ ); /* endif */ ); /* endfor */ return(zwischen); } {smallfrob(Qpoly,zero,modulo,p,prez,bool)= /* This part computes the frobenius on Qq or the E= sigma_p(Qpoly)-Q^p. Input: Qpoly = The lifted polynomial in Zq[v] with y^2 = Qpoly. zero = A generator of the extension Qq/Qp. modulo = Tthe lifted polynomial in Zp[u] with Qq ~ Qp[u]/(modulo(u)). p = The characteristic of the residue field of Qq. prez = The necessary precision for the computation in Qq. bool = A boolean variable. Output: if bool = 0, then it gives zeromodp back, which is the the generator of Qq/Qp with zeromodp = zero^p mod p. if bool = 1, then it gives E back. Dieser Teil des Programms berechnet den Frobenius auf Qq oder das E = sigma_p(Qpoly)-Q^p. Eingabe: Qpoly = Das geliftete Polynom in Zq[v] mit y^2 = Qpoly. zero = Ein Erzeuger der Erweiterung Qq/Qp. modulo = Das geliftete Polynom in Zp[u] mit Qq ~ Qp[u]/(modulo(u)). p = Die Charakteristik des Restklassenkoerpers Fq. prez = Die benoetigte Praezision fuer die Rechnungen in Qq. Output: Falls bool = 0, so gibt das Programm zeromodp zurueck, welches ein Erzeuger von Qq/Qp mit zeromodp = zero^p mod p. */ local(summe,zeromodp,E,sigmaQpoly,coeff,Qhochp,dmodulo,inverse,bi,testost); dmodulo = deriv( modulo , u ); bi = binary(prez); liftmodulo = lift(modulo); zeromodp = Mod(lift(lift(Mod(1,p)*Mod(lift(lift(zero))^p, modulo))),liftmodulo); /* Die Initialisierung von der Nullstelle */ inverse = Mod(lift(lift(Mod(1,p)*subst(lift(dmodulo),u,zeromodp)^(-1))),liftmodulo); /* Die Initialisierung von modulo(zero)'^(-1) */ forstep( i= length(bi)-1, 0, -1, pow = ceil((prez)/(1< p = The characteristic of the residue field Fq of Zq prez = The necessary precision for the computation in Zq. Output: [Mu,Lambda] = the vector with the bezout-coefficients of the gcd(Qpoly,deriv(Qpoly,v)), hence Mu*Qpoly + Lambda*deriv(Qpoly,v)= gcd. Dieser Teil berechnet die Bezoutkoeffizienten des ggT(Qpoly,Qpoly') mittels einer Newton-Iteration von dem ggT mod p. Eingabe: Qpoly = Das geliftete Polynom in Zq[v] mit y^2 = Qpoly. lambda = Das Polynom in Fq[v], das der Bezoutkoeffizient vor Qpolymodp ist. mod = Das geliftete Polynom in Zp[u] mit Qq ~ Qp[u]/(mod(u)). p = Die Charakteristik des Restklassenkoerpers Fq. prez = Die benoetigte Praezision fuer die Rechnungen in Qq. Output: [Mu,Lambda] = Der Vektor mit den gelifteten Bezoutkoeffizienten des ggTs. */ local(modmodp,inv,grad,liftlambda,liftQpoly,dliftQpoly,liftprez); liftlambda = lift(lift(lambda)); /* liftlambda ist ein Polynom in 2 Variablen aus Z[v] */ liftQpoly = lift(lift(Qpoly)); dliftQpoly = deriv(liftQpoly,v); dQpoly = deriv(Qpoly,v); liftmod = lift(mod); liftprez = length(binary(prez))-1; inv = [0,Mod(1,mod)*(liftlambda+O(p^prez))]; forstep( i= liftprez, 0, -1, print("In liftbezout:: In Newton Iteration Nr. "i); powprez = ceil(liftprez/(1< var2, var1 = var1 - p^pow; if(debug==1, print("Musste das Vorzeichen anpassen"); ), ); /* endif */ print("var1 :"var1); Ypol = Ypol + y^(poldegree(Qpoly,v)-1) + var1*y^((poldegree(Qpoly,v)-1)/2) + p^(poldegree(mod,u)*((poldegree(Qpoly)-1)/2)); if( abs(polcoeff(Ypol,1,y)) > p^(poldegree(mod,u)), var1 = p^(poldegree(mod,u)) + polcoeff(Ypol,poldegree(Qpoly)-2,y) + 1, var = p^(poldegree(mod,u)) + polcoeff(Ypol,1) + 1; ); /* Da polcoeff in meinen Beispielen den Koeffizienten hier (und nur hier...) nicht immer (eigentlich nie) richtig ausgibt, ist diese seltsame Abfrage notwendig! */ return([polrecip(Ypol),var1]); }