From 24b6fe94424561dce5e9f97e656c82c486aa6c78 Mon Sep 17 00:00:00 2001 From: Peter Bruin Date: Tue, 11 Feb 2014 18:58:48 +0000 Subject: [PATCH] Update Denis Simon's GP scripts to versions of 06/04/2011 (ell.gp) resp. 13/01/2014 (ellQ.gp, ellcommon.gp, qfsolve.gp, resultant3.gp) --- src/ext/pari/simon/ell.gp | 1809 ++++++------ src/ext/pari/simon/ellQ.gp | 2553 ++++++++++------- src/ext/pari/simon/ellcommon.gp | 126 + src/ext/pari/simon/qfsolve.gp | 1447 ++++++---- src/ext/pari/simon/resultant3.gp | 466 +-- src/sage/quadratic_forms/qfsolve.py | 31 +- .../elliptic_curves/ell_number_field.py | 61 +- .../elliptic_curves/ell_rational_field.py | 14 +- src/sage/schemes/elliptic_curves/gp_simon.py | 4 +- .../schemes/hyperelliptic_curves/mestre.py | 2 +- src/sage/schemes/plane_conics/con_field.py | 4 +- .../plane_conics/con_rational_field.py | 14 +- 12 files changed, 3737 insertions(+), 2794 deletions(-) create mode 100644 src/ext/pari/simon/ellcommon.gp diff --git a/src/ext/pari/simon/ell.gp b/src/ext/pari/simon/ell.gp index d121ae14279..503daf21636 100644 --- a/src/ext/pari/simon/ell.gp +++ b/src/ext/pari/simon/ell.gp @@ -1,5 +1,5 @@ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ -\\ Copyright (C) 2007 Denis Simon +\\ Copyright (C) 2011 Denis Simon \\ \\ Distributed under the terms of the GNU General Public License (GPL) \\ @@ -13,173 +13,170 @@ \\ http://www.gnu.org/licenses/ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ -\\ -\\ Auteur: -\\ Denis SIMON -> simon@math.unicaen.fr -\\ adresse du fichier: -\\ www.math.unicaen.fr/~simon/ell.gp -\\ -\\ ********************************************* -\\ * VERSION 25/03/2009 * -\\ ********************************************* -\\ -\\ Programme de calcul du rang des courbes elliptiques -\\ dans les corps de nombres. -\\ langage: GP -\\ pour l'utiliser, lancer gp, puis taper -\\ \r ell.gp -\\ -\\ -\\ Explications succintes : -\\ definition du corps : -\\ bnf=bnfinit(y^2+1); -\\ (il est indispensable que la variable soit y). -\\ on peut ensuite poser : -\\ X = Mod(y,bnf.pol); -\\ -\\ La fonction bnfellrank() accepte toutes les courbes sous la forme -\\ [a1,a2,a3,a4,a6] -\\ Les coefficients peuvent etre entiers ou non. -\\ L'algorithme utilise est celui de la 2-descente. -\\ La 2-torsion peut etre quelconque. -\\ Il suffit de taper : -\\ -\\ gp > ell = [a1,a2,a3,a4,a6]; -\\ gp > bnfellrank(bnf,ell) -\\ -\\ Retourne un vecteur [r,s,vec] -\\ ou r est le rang probable (c'est toujours une minoration du rang), -\\ s est le 2-rang du groupe de Selmer, -\\ vec est une liste de points dans E(K)/2E(K). -\\ -\\ Courbes avec #E[2](K) >= 2: -\\ ell doit etre sous la forme -\\ y^2 = x^3 + A*^2 + B*x -\\ avec A et B entiers algebriques -\\ gp > ell = [0,A,0,B,0] -\\ gp > bnfell2descent_viaisog(ell) -\\ = algorithme de la 2-descente par isogenies -\\ Attention A et B doivent etre entiers -\\ -\\ Courbes avec #E[2](K) = 4: y^2 = (x-e1)*(x-e2)*(x-e3) -\\ -> bnfell2descent_complete(bnf,e1,e2,e3); -\\ = algorithme de la 2-descente complete -\\ Attention: les ei doivent etre entiers algebriques. -\\ -\\ -\\ On peut avoir plus ou moins de details de calculs avec -\\ DEBUGLEVEL_ell = 0; -\\ DEBUGLEVEL_ell = 1; 2; 3;... -\\ +/* + Auteur : + Denis SIMON -> simon@math.unicaen.fr + adresse du fichier : + www.math.unicaen.fr/~simon/ell.gp + + ********************************************* + * VERSION 06/04/2011 * + ********************************************* + + \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ + \\ Comment utiliser ce programme ? \\ + \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ + + Programme de calcul du rang des courbes elliptiques + dans les corps de nombres. + langage: GP + pour l'utiliser, lancer gp, puis taper + \r ell.gp + + \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ + \\ Description des principales fonctions \\ + \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ + + Explications succintes : + definition du corps : + bnf=bnfinit(y^2+1); + (il est indispensable que la variable soit y). + on peut ensuite poser : + X = Mod(y,bnf.pol); + + La fonction bnfellrank() accepte toutes les courbes sous la forme + [a1,a2,a3,a4,a6] + Les coefficients peuvent etre entiers ou non. + L'algorithme utilise est celui de la 2-descente. + La 2-torsion peut etre quelconque. + Il suffit de taper : + + gp > ell = [a1,a2,a3,a4,a6]; + gp > bnfellrank(bnf,ell) + + Retourne un vecteur [r,s,vec] + ou r est le rang probable (c'est toujours une minoration du rang), + s est le 2-rang du groupe de Selmer, + vec est une liste de points dans E(K)/2E(K). + + Courbes avec #E[2](K) >= 2: + ell doit etre sous la forme + y^2 = x^3 + A*^2 + B*x + avec A et B entiers algebriques + gp > ell = [0,A,0,B,0] + gp > bnfell2descent_viaisog(ell) + = algorithme de la 2-descente par isogenies + Attention A et B doivent etre entiers + + Courbes avec #E[2](K) = 4: y^2 = (x-e1)*(x-e2)*(x-e3) + -> bnfell2descent_complete(bnf,e1,e2,e3); + = algorithme de la 2-descente complete + Attention: les ei doivent etre entiers algebriques. + + + \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ + \\ Affichage des calculs \\ + \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ + + On peut avoir plus ou moins de details de calculs avec + DEBUGLEVEL_ell = 0; + DEBUGLEVEL_ell = 1; 2; 3;... + +*/ { \\ -\\ Variables globales usuelles +\\ Usual global variables \\ - DEBUGLEVEL_ell = 1; \\ pour avoir plus ou moins de details - LIM1 = 2; \\ limite des points triviaux sur les quartiques - LIM3 = 4; \\ limite des points sur les quartiques ELS - LIMTRIV = 2; \\ limite des points triviaux sur la courbe elliptique +global(DEBUGLEVEL_ell, LIM1, LIM3, LIMTRIV):small; + + DEBUGLEVEL_ell = 0; \\ From 0 to 5 : choose a higher value to have + \\ more details printed. + LIM1 = 2; \\ Limit for the search of trivial points on quartics + LIM3 = 4; \\ Limit for the search of points on ELS quartics + LIMTRIV = 2; \\ Limit for the search of trivial points on the elliptic curve \\ -\\ Variables globales techniques +\\ Technical global variables \\ - BIGINT = 32000; \\ l'infini - MAXPROB = 20; - LIMBIGPRIME = 30; \\ pour distinguer un petit nombre premier d'un grand - \\ utilise un test probabiliste pour les grands - \\ si LIMBIGPRIME = 0, n'utilise aucun test probabiliste - NBIDEAUX = 10; +global(MAXPROB, LIMBIGPRIME):small; + MAXPROB = 20; + LIMBIGPRIME = 30; \\ for primes larger than this limit: use a probabilistic test + \\ LIMBIGPRIME = 0 means: only deterministic tests } -\\ -\\ Programmes -\\ +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ +\\ SCRIPT \\ +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ -\\ -\\ Fonctions communes ell.gp et ellQ.gp -\\ +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ +\\ MANIPULATION OF GLOBAL VARIABLES \\ +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ -{ -ellinverturst(urst) = -local(u = urst[1], r = urst[2], s = urst[3], t = urst[4]); - [1/u,-r/u^2,-s/u,(r*s-t)/u^3]; -} -{ -ellchangecurveinverse(ell,v) = ellchangecurve(ell,ellinverturst(v)); -} -{ -ellchangepointinverse(pt,v) = ellchangepoint(pt,ellinverturst(v)); -} -{ -ellcomposeurst(urst1,urst2) = -local(u1 = urst1[1], r1 = urst1[2], s1 = urst1[3], t1 = urst1[4], - u2 = urst2[1], r2 = urst2[2], s2 = urst2[3], t2 = urst2[4]); - [u1*u2,u1^2*r2+r1,u1*s2+s1,u1^3*t2+s1*u1^2*r2+t1]; -} -if( DEBUGLEVEL_ell >= 4, print("mysubst")); -{ -mysubst(polsu,subsx) = - if( type(lift(polsu)) == "t_POL", - return(simplify(subst(lift(polsu),variable(lift(polsu)),subsx)) ) - , return(simplify(lift(polsu)))); -} -if( DEBUGLEVEL_ell >= 4, print("nfsign")); -{ -nfsign(nf,a,i) = -\\ return the sign of the algebraic number a in the i-th real embedding. -local(nf_roots,ay,def); +{default_ell( + DEBUGLEVEL_ell_val:small = 0, + LIM1_val:small = 2, + LIM3_val:small = 4, + LIMTRIV_val:small = 2, + MAXPROB_val:small = 20, + LIMBIGPRIME_val:small = 30 + ) = - if( a == 0, return(0)); + DEBUGLEVEL_ell = DEBUGLEVEL_ell_val; + print(" DEBUGLEVEL_ell = ",DEBUGLEVEL_ell); - a = lift(a); - if( type(a) != "t_POL", - return(sign(a))); + LIM1 = LIM1_val; + print(" LIM1 = ",LIM1); - nf_roots = nf.roots; - def = default(realprecision); + LIM3 = LIM3_val; + print(" LIM3 = ",LIM3); - ay = 0; - while( ay == 0 || precision(ay) < 10, + LIMTRIV = LIMTRIV_val; + print(" LIMTRIV = ",LIMTRIV); - ay = subst(a,variable(a),nf_roots[i]); + MAXPROB = MAXPROB_val; + print(" MAXPROB = ",MAXPROB); - if( ay == 0 || precision(ay) < 10, -if( DEBUGLEVEL_ell >= 3, - print(" **** Warning: doubling the real precision in nfsign **** ", - 2*default(realprecision))); - default(realprecision,2*default(realprecision)); - nf_roots = real(polroots(nf.pol)) - ) - ); - default(realprecision,def); + LIMBIGPRIME = LIMBIGPRIME_val; + print(" LIMBIGPRIME = ",LIMBIGPRIME); +} - return(sign(ay)); +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ +\\ COMMON FUNCTIONS TO ell.gp AND ellQ.gp \\ +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ + +{ellcomposeurst(urst1,urst2) = +local(u1 = urst1[1], r1 = urst1[2], s1 = urst1[3], t1 = urst1[4], + u2 = urst2[1], r2 = urst2[2], s2 = urst2[3], t2 = urst2[4]); + [u1*u2,u1^2*r2+r1,u1*s2+s1,u1^3*t2+s1*u1^2*r2+t1]; } -if( DEBUGLEVEL_ell >= 4, print("degre")); -{ -degre(idegre) = +{ellinverturst(urst) = +local(u = urst[1], r = urst[2], s = urst[3], t = urst[4]); + [1/u,-r/u^2,-s/u,(r*s-t)/u^3]; +} +{mysubst(polsu,subsx) = + if( type(lift(polsu)) == "t_POL", + return(simplify(subst(lift(polsu),variable(lift(polsu)),subsx))) + , return(simplify(lift(polsu)))); +} +{degre(idegre) = local(ideg = idegre, jdeg = 0); while( ideg >>= 1, jdeg++); return(jdeg); } -if( DEBUGLEVEL_ell >= 4, print("nfissquare")); -{ -nfissquare(nf, a) = #nfsqrt(nf,a) > 0; +{nfissquare(nf, a) = #nfsqrt(nf,a) > 0; } -if( DEBUGLEVEL_ell >= 4, print("nfsqrt")); -{ -nfsqrt( nf, a) = -\\ si a est un carre, renvoie [sqrt(a)], sinon []. -local(alift,ta,res,pfact); +{nfsqrt( nf, a) = +\\ if a is a square in the number field nf returns [sqrt(a)], otherwise []. +local(alift,ta,py,pfact); -if( DEBUGLEVEL_ell >= 5, print("entree dans nfsqrt ",a)); - if( a==0 || a==1, -if( DEBUGLEVEL_ell >= 5, print("fin de nfsqrt")); +if( DEBUGLEVEL_ell >= 5, print(" starting nfsqrt ",a)); + if( a==0 || a==1, +if( DEBUGLEVEL_ell >= 5, print(" end of nfsqrt ",a)); return([a])); alift = lift(a); @@ -187,119 +184,122 @@ if( DEBUGLEVEL_ell >= 5, print("fin de nfsqrt")); if( !poldegree(alift), alift = polcoeff(alift,0)); if( type(alift) != "t_POL", - if( issquare(alift), -if( DEBUGLEVEL_ell >= 5, print("fin de nfsqrt")); + if( issquare(alift), +if( DEBUGLEVEL_ell >= 5, print(" end of nfsqrt ",sqrtrat(alift))); return([sqrtrat(alift)]))); if( poldegree(nf.pol) <= 1, -if( DEBUGLEVEL_ell >= 5, print("fin de nfsqrt")); +if( DEBUGLEVEL_ell >= 5, print(" end of nfsqrt ",[])); return([])); if( ta == "t_POL", a = Mod(a,nf.pol)); -\\ tous les plgements reels doivent etre >0 +\\ the norm should be a square + + if( !issquare(norm(a)), +if( DEBUGLEVEL_ell >= 5, print(" end of nfsqrt ",[])); + return([])); + +\\ the real embeddings must all be >0 for( i = 1, nf.r1, - if( nfsign(nf,a,i) < 0, -if( DEBUGLEVEL_ell >= 5, print("fin de nfsqrt")); + if( nfrealsign(nf,a,i) < 0, +if( DEBUGLEVEL_ell >= 5, print(" end of nfsqrt ",[])); return([]))); -\\ factorisation sur K du polynome X^2-a : +\\ factorization over nf of the polynomial X^2-a - if( variable(nf.pol) == x, - py = subst(nf.pol,x,y); - pfact = lift(factornf(x^2-mysubst(alift,Mod(y,py)),py)[1,1]) + if( variable(nf.pol) == 'x, + py = subst(nf.pol,'x,'y); + pfact = lift(factornf('x^2-mysubst(alift,Mod('y,py)),py)[1,1]) , - pfact = lift(factornf(x^2-a,nf.pol)[1,1])); + pfact = lift(factornf('x^2-a,nf.pol)[1,1])); if( poldegree(pfact) == 2, -if( DEBUGLEVEL_ell >= 5, print("fin de nfsqrt")); +if( DEBUGLEVEL_ell >= 5, print(" end of nfsqrt ",[])); return([])); -if( DEBUGLEVEL_ell >= 5, print("fin de nfsqrt")); - return([subst(polcoeff(pfact,0),y,Mod(variable(nf.pol),nf.pol))]); +if( DEBUGLEVEL_ell >= 5, print(" end of nfsqrt ",pfact)); + return([subst(polcoeff(pfact,0),'y,Mod(variable(nf.pol),nf.pol))]); } -if( DEBUGLEVEL_ell >= 4, print("sqrtrat")); -{ -sqrtrat(a) = +{nfrealsign(nf,a,i) = +\\ return the sign of the algebraic number a in the i-th real embedding. +local(nf_roots,ay,prec0); + + if( a == 0, return(0)); + + a = lift(a); + if( type(a) != "t_POL", + return(sign(a))); + + nf_roots = nf.roots; + prec0 = default(realprecision); + + ay = 0; + while( ay == 0 || precision(ay) < 10, + + ay = subst(a,variable(a),nf_roots[i]); + + if( ay == 0 || precision(ay) < 10, +if( DEBUGLEVEL_ell >= 3, + print(" **** Warning: doubling the real precision in nfrealsign **** ", + 2*default(realprecision))); + default(realprecision,2*default(realprecision)); + nf_roots = real(polroots(nf.pol)) + ) + ); + default(realprecision,prec0); + + return(sign(ay)); +} +{sqrtrat(a) = sqrtint(numerator(a))/sqrtint(denominator(a)); } +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ +\\ FUNCTIONS SPECIFIC TO ell.gp \\ +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ -\\ -\\ Fonctions propres a ell.gp -\\ - -if( DEBUGLEVEL_ell >= 4, print("nfpolratroots")); -{ -nfpolratroots(nf,pol) = +{nfpolratroots(nf,pol) = local(f,ans); f = nffactor(nf,lift(pol))[,1]; ans = []; - for( j = 1, #f, + for( j = 1, #f, if( poldegree(f[j]) == 1, ans = concat(ans,[-polcoeff(f[j],0)/polcoeff(f[j],1)]))); return(ans); } -if( DEBUGLEVEL_ell >= 4, print("nfmodid2")); -{ -nfmodid2(nf,a,ideal) = -if( DEBUGLEVEL_ell >= 5, print("entree dans nfmodid2")); -\\ ideal doit etre sous la forme primedec - if( #nf.zk == 1, -if( DEBUGLEVEL_ell >= 5, print("fin de nfmodid2")); - return(a*Mod(1,ideal.p))); - a = mynfeltmod(nf,a,nfbasistoalg(nf,ideal[2])); - if( gcd(denominator(content(lift(a))),ideal.p) == 1, -if( DEBUGLEVEL_ell >= 5, print("fin de nfmodid2")); - return(a*Mod(1,ideal.p))); -if( DEBUGLEVEL_ell >= 5, print("fin de nfmodid2")); - return(a); -} -if( DEBUGLEVEL_ell >= 4, print("nfhilb2")); -{ -nfhilb2(nf,a,b,p) = -local(res); +{mynfhilbert2(nf,a,b,p) = +\\ p is a prime output by idealprimedec() above 2 +local(v,res); + +if( DEBUGLEVEL_ell >= 5, print(" starting mynfhilbert2")); + v = idealval(nf,a,p)\2; + if( v, a *= nfbasistoalg(nf,p[2])^(-2*v)); -if( DEBUGLEVEL_ell >= 5, print("entree dans nfhilb2")); - if( nfqpsoluble(nf,a*x^2+b,initp(nf,p)), res = 1, res = -1); -if( DEBUGLEVEL_ell >= 5, print("fin de nfhilb2")); + v = idealval(nf,b,p)\2; + if( v, b *= nfbasistoalg(nf,p[2])^(-2*v)); + + if( nfqp_soluble(nf,a*'x^2+b,initp(nf,p)), res = 1, res = -1); +if( DEBUGLEVEL_ell >= 5, print(" end of mynfhilbert2",res)); return(res); } -if( DEBUGLEVEL_ell >= 4, print("mynfhilbertp")); -{ -mynfhilbertp(nf,a,b,p) = +{mynfhilbertp(nf,a,b,p) = \\ calcule le symbole de Hilbert quadratique local (a,b)_p \\ * en l'ideal premier p du corps nf, \\ * a et b sont des elements non nuls de nf, sous la forme -\\ * de polymods ou de polynomes, et p renvoye par primedec. -local(alpha,beta,sig,aux,aux2,rep); +\\ * de polmods ou de polynomes, et p renvoye par idealprimedec(). -if( DEBUGLEVEL_ell >= 5, print("entree dans mynfhilbertp ",p)); - if( a == 0 || b == 0, print("0 argument in mynfhilbertp")); +if( DEBUGLEVEL_ell >= 5, print(" starting mynfhilbertp at ",p)); + if( a == 0 || b == 0, error("mynfhilbertp: argument = 0")); if( p.p == 2, -if( DEBUGLEVEL_ell >= 5, print("fin de mynfhilbertp")); - return(nfhilb2(nf,a,b,p))); +if( DEBUGLEVEL_ell >= 5, print(" end of mynfhilbertp")); + return(mynfhilbert2(nf,a,b,p))); if( type(a) != "t_POLMOD", a = Mod(a,nf.pol)); if( type(b) != "t_POLMOD", b = Mod(b,nf.pol)); - - alpha = idealval(nf,a,p); beta = idealval(nf,b,p); -if( DEBUGLEVEL_ell >= 5, print("[alpha,beta] = ",[alpha,beta])); - if( (alpha%2 == 0) && (beta%2 == 0), -if( DEBUGLEVEL_ell >= 5, print("fin de mynfhilbertp")); - return(1)); - aux2 = idealnorm(nf,p)\2; - if( alpha%2 && beta%2 && aux2%2, sig = 1, sig = -1); - if( beta, aux = nfmodid2(nf,a^beta/b^alpha,p), aux = nfmodid2(nf,b^alpha,p)); - aux = aux^aux2 + sig; - aux = lift(lift(aux)); - if( aux == 0, rep = 1, rep = (idealval(nf,aux,p) >= 1) ); -if( DEBUGLEVEL_ell >= 5, print("fin de mynfhilbertp")); - if( rep, return(1), return(-1)); +return(nfhilbert(nf,a,b,p)); } -if( DEBUGLEVEL_ell >= 4, print("ideallistfactor")); -{ -ideallistfactor(nf,listfact) = -local(Slist,S1,test,i,j,k); +{ideallistfactor(nf,listfact) = +local(Slist,S1,test,k); -if( DEBUGLEVEL_ell >= 5, print("entree dans ideallistfactor")); +if( DEBUGLEVEL_ell >= 5, print(" starting ideallistfactor")); Slist = []; test = 1; for( i = 1, #listfact, if( listfact[i] == 0, next); @@ -309,28 +309,26 @@ if( DEBUGLEVEL_ell >= 5, print("entree dans ideallistfactor")); if( Slist[k] == S1[j], test = 0; break)); if( test, Slist = concat(Slist,[S1[j]]), test = 1); )); -if( DEBUGLEVEL_ell >= 5, print("fin de ideallistfactor")); +if( DEBUGLEVEL_ell >= 5, print(" end of ideallistfactor")); return(Slist); } -if( DEBUGLEVEL_ell >= 4, print("mynfhilbert")); -{ -mynfhilbert(nf,a,b) = +{mynfhilbert(nf,a,b) = \\ calcule le symbole de Hilbert quadratique global (a,b): \\ =1 si l'equation X^2-aY^2-bZ^2=0 a une solution non triviale, \\ =-1 sinon, \\ a et b doivent etre non nuls. local(al,bl,S); -if( DEBUGLEVEL_ell >= 4, print("entree dans mynfhilbert ",[a,b])); +if( DEBUGLEVEL_ell >= 4, print(" starting mynfhilbert ",[a,b])); if( a == 0 || b == 0, error("mynfhilbert : argument = 0")); al = lift(a); bl = lift(b); -\\ solutions locales aux places reelles +\\ solutions locales aux places reelles for( i = 1, nf.r1, - if( nfsign(nf,al,i) < 0 && nfsign(nf,bl,i) < 0, -if( DEBUGLEVEL_ell >= 3, print("mynfhilbert non soluble a l'infini")); -if( DEBUGLEVEL_ell >= 4, print("fin de mynfhilbert")); + if( nfrealsign(nf,al,i) < 0 && nfrealsign(nf,bl,i) < 0, +if( DEBUGLEVEL_ell >= 3, print(" mynfhilbert: no solution at infinity")); +if( DEBUGLEVEL_ell >= 4, print(" end of mynfhilbert")); return(-1)) ); @@ -341,39 +339,35 @@ if( DEBUGLEVEL_ell >= 4, print("fin de mynfhilbert")); S = ideallistfactor(nf,[2,a,b]); forstep ( i = #S, 2, -1, -\\ d'apres la formule du produit on peut eviter un premier +\\ d'apres la formule du produit on peut eviter un premier if( mynfhilbertp(nf,a,b, S[i]) == -1, -if( DEBUGLEVEL_ell >= 3, print("mynfhilbert non soluble en : ",S[i])); -if( DEBUGLEVEL_ell >= 4, print("fin de mynfhilbert")); +if( DEBUGLEVEL_ell >= 3, print(" mynfhilbert: no solution at: ",S[i])); +if( DEBUGLEVEL_ell >= 4, print(" end of mynfhilbert")); return(-1))); -if( DEBUGLEVEL_ell >= 4, print("fin de mynfhilbert")); +if( DEBUGLEVEL_ell >= 4, print(" end of mynfhilbert")); return(1); } -if( DEBUGLEVEL_ell >= 4, print("initp")); -{ -initp( nf, p) = -\\ pp[1] est l'ideal sous forme reduite +{initp( nf, p) = +\\ pp[1] est l'ideal sous forme reduite \\ pp[2] est un entier de Zk avec une valuation 1 en p \\ pp[3] est la valuation de 2 en p -\\ pp[4] sert a detecter les carres dans Qp +\\ pp[4] sert a detecter les carres dans Qp \\ si p|2 il faut la structure de Zk/p^(1+2v) d'apres Hensel -\\ sinon il suffit de calculer x^(N(p)-1)/2 -\\ pp[5] est un systeme de representants de Zk/p +\\ sinon il suffit de calculer x^(N(p)-1)/2 +\\ pp[5] est un systeme de representants de Zk/p \\ c'est donc un ensemble de cardinal p^f . local(idval,pp); -if( DEBUGLEVEL_ell >= 5, print("entree dans initp")); +if( DEBUGLEVEL_ell >= 5, print(" starting initp for p = ",p)); idval = idealval(nf,2,p); pp=[ p, nfbasistoalg(nf,p[2]), idval, 0, repres(nf,p) ]; if( idval, pp[4] = idealstar(nf,idealpow(nf,p,1+2*idval)), pp[4] = p.p^p.f\2 ); -if( DEBUGLEVEL_ell >= 5, print("fin de initp")); +if( DEBUGLEVEL_ell >= 5, print(" end of initp")); return(pp); } -if( DEBUGLEVEL_ell >= 4, print("deno")); -{ -deno(num) = +{deno(num) = \\ calcule un denominateur du polynome num if( num == 0, return(1)); @@ -381,24 +375,25 @@ deno(num) = return(denominator(content(num)))); return(denominator(num)); } -if( DEBUGLEVEL_ell >= 4, print("nfratpoint")); -{ -nfratpoint(nf,pol,lim,singlepoint=1) = +{nfratpoint(nf,pol,lim,singlepoint=1) = \\ Si singlepoint == 1, cherche un seul point, sinon plusieurs. -local(compt1,compt2,deg,n,AA,point,listpoints,denoz,vectx,xx,evpol,sq); +local(compt1,compt2,deg,n,AA,point,listpoints,vectx,evpol,sq,xpol); + +if( DEBUGLEVEL_ell >= 4, + print(" starting nfratpoint with pol = ",pol); + print(" lim = ",lim)); -if( DEBUGLEVEL_ell >= 4, print("entree dans nfratpoint avec pol = ",pol); print("lim = ",lim)); compt1 = 0; compt2 = 0; deg = poldegree(pol); n = poldegree(nf.pol); AA = lim<<1; if( !singlepoint, listpoints = []); -\\ cas triviaux +\\ cas triviaux sq = nfsqrt(nf,polcoeff(pol,0)); if( sq!= [], point = [ 0, sq[1], 1]; if( singlepoint, -if( DEBUGLEVEL_ell >= 4, print("fin de nfratpoint")); +if( DEBUGLEVEL_ell >= 4, print(" end of nfratpoint")); return(point)); listpoints = concat(listpoints,[point]) ); @@ -406,19 +401,21 @@ if( DEBUGLEVEL_ell >= 4, print("fin de nfratpoint")); if( sq != [], point = [ 1, sq[1], 0]; if( singlepoint, -if( DEBUGLEVEL_ell >= 4, print("fin de nfratpoint")); +if( DEBUGLEVEL_ell >= 4, print(" end of nfratpoint")); return(point)); listpoints = concat(listpoints,[point]) ); - + \\ boucle generale point = []; vectx = vector(n,i,[-lim,lim]); for( denoz = 1, lim, + if( poldegree(pol)%2 == 0 && + !issquare(Mod(norm(pollead(pol)),denoz)), next); forvec( xx = vectx, if( denoz == 1 || gcd(content(xx),denoz) == 1, xpol = nfbasistoalg(nf,xx~); - evpol = subst(pol,x,xpol/denoz); + evpol = subst(pol,'x,xpol/denoz); sq = nfsqrt(nf,evpol); if( sq != [], point = [xpol/denoz, sq[1], 1]; @@ -427,21 +424,19 @@ if( DEBUGLEVEL_ell >= 4, print("fin de nfratpoint")); )); if( singlepoint, listpoints = point); -if( DEBUGLEVEL_ell >= 4, print("sortie de nfratpoint")); -if( DEBUGLEVEL_ell >= 3, print("points trouves par nfratpoint = ",listpoints)); - return(listpoints); +if( DEBUGLEVEL_ell >= 3, print(" points found by nfratpoint = ",listpoints)); +if( DEBUGLEVEL_ell >= 4, print(" end of nfratpoint")); + return(Vec(listpoints)); } -if( DEBUGLEVEL_ell >= 4, print("repres")); -{ -repres(nf,p) = +{repres(nf,p) = \\ calcule un systeme de representants Zk/p -local(fond,mat,i,j,k,f,rep,pp,ppi,pp2,jppi,gjf); +local(fond,mat,f,rep,pp,ppi,pp2,jppi,gjf); -if( DEBUGLEVEL_ell >= 5, print("entree dans repres")); +if( DEBUGLEVEL_ell >= 5, print(" starting repres")); fond = []; mat = idealhnf(nf,p); for( i = 1, #mat, - if( mat[i,i] != 1, fond = concat(fond,nf.zk[i]))); + if( mat[i,i] != 1, fond = concat(fond,nf.nf[7][i]))); f = #fond; pp = p.p; rep = vector(pp^f,i,0); @@ -454,148 +449,60 @@ if( DEBUGLEVEL_ell >= 5, print("entree dans repres")); jppi = j*ppi; for( k = 0, ppi-1, rep[jppi+k+1] = rep[k+1]+gjf )); ppi *= pp); -if( DEBUGLEVEL_ell >= 5, print("fin de repres")); +if( DEBUGLEVEL_ell >= 5, print(" end of repres")); return(Mod(rep,nf.pol)); } -if( DEBUGLEVEL_ell >= 4, print("val")); -{ -val(nf,num,p) = - if( num == 0, BIGINT, idealval(nf,lift(num),p)); +{val(nf,num,p) = + if( num == 0, 32000, idealval(nf,lift(num),p)); } -if( DEBUGLEVEL_ell >= 4, print("nfissquarep")); -{ -nfissquarep(nf,a,p,q) = -\\ suppose que a est un carre modulo p^q -\\ et renvoie sqrt(a) mod p^q (ou plutot p^(q/2)) -local(pherm,f,aaa,n,pp,qq,e,z,xx,yy,r,aux,b,m,vp,inv2x,zinit,zlog,expo); - -if( DEBUGLEVEL_ell >= 5, print("entree dans nfissquarep ",a,p,q)); - if( a == 0 || a == 1, -if( DEBUGLEVEL_ell >= 4, print("fin de nfissquarep")); - return(a)); - pherm = idealhnf(nf,p); -if( DEBUGLEVEL_ell >= 5, print("pherm = ",pherm)); - f = idealval(nf,a,p); - if( f >= q, - if( f > q, aaa = nfbasistoalg(nf,p[2])^((q+1)>>1), aaa = 0); -if( DEBUGLEVEL_ell >= 4, print("fin de nfissquarep")); - return(aaa)); - if( f, aaa = a*nfbasistoalg(nf,p[5]/p.p)^f, aaa = a); - if( pherm[1,1] != 2, -\\ cas ou p ne divise pas 2 -\\ algorithme de Shanks - n = nfrandintmodid(nf,pherm); - while( nfpsquareodd(nf,n,p), n = nfrandintmodid(nf,pherm)); - pp = Mod(1,p.p); - n *= pp; - qq = idealnorm(nf,pherm)\2; - e = 1; while( !(qq%2), e++; qq \= 2); - z = mynfeltreduce(nf,lift(lift(n^qq)),pherm); - yy = z;r = e; - xx = mynfeltreduce(nf,lift(lift((aaa*pp)^(qq\2))),pherm); - aux = mynfeltreduce(nf,aaa*xx,pherm); - b = mynfeltreduce(nf,aux*xx,pherm); - xx = aux; - aux = b;m = 0; - while( !val(nf,aux-1,p), m++; aux = mynfeltreduce(nf,aux^2,pherm)); - while( m, - if( m == r, error("nfissquarep : m = r")); - yy *= pp; - aux = mynfeltreduce(nf,lift(lift(yy^(1<<(r-m-1)))),pherm); - yy = mynfeltreduce(nf,aux^2,pherm); - r = m; - xx = mynfeltreduce(nf,xx*aux,pherm); - b = mynfeltreduce(nf,b*yy,pherm); - aux = b;m = 0; - while( !val(nf,aux-1,p), m++; aux = mynfeltreduce(nf,aux^2,pherm)); - ); -\\ lift de Hensel -\\ - if( q > 1, - vp = idealval(nf,xx^2-aaa,p); - if( vp < q-f, - yy = 2*xx; - inv2x = nfbasistoalg(nf,idealaddtoone(nf,yy,p)[1])/yy; - while( vp < q, vp++; xx -= (xx^2-aaa)*inv2x); - ); - if( f, xx *= nfbasistoalg(nf,p[2])^(f>>1)); - ); - xx = mynfeltreduce(nf,xx,idealpow(nf,p,q)) - , -\\ cas ou p divise 2 */ - if( q-f > 1, id = idealpow(nf,p,q-f), id = pherm); - zinit = idealstar(nf,id,2); - zlog = ideallog(nf,aaa,zinit); - xx = 1; - for( i = 1, #zlog, - expo = zlog[i]; - if( expo, - if( !expo%2, - expo = expo>>1 - , aux = zinit[2][i]; - expo = expo*((aux+1)>>1)%aux - ); - xx *= nfbasistoalg(nf,zinit[2][3][i])^expo - ) - ); - if( f, - xx *= nfbasistoalg(nf,p[2])^(f>>1); - id = idealpow(nf,p,q)); - xx = mynfeltreduce(nf,xx,id); - ); -if( DEBUGLEVEL_ell >= 4, print("fin de nfissquarep ",xx)); - return(xx); -} -if( DEBUGLEVEL_ell >= 4, print("nfpsquareodd")); -{ -nfpsquareodd( nf, a, p) = -\\ renvoie 1 si a est un carre dans ZK_p 0 sinon -\\ seulement pour p premier avec 2 +{nfissquaremodpodd( nf, a, p) = +\\ Return 1 if a is a p-adic square, 0 otherwise. +\\ Only for a prime ideal p coprime to 2. +\\ a = t_POLMOD local(v,ap,norme,den); -if( DEBUGLEVEL_ell >= 5, print("entree dans nfpsquareodd")); +if( DEBUGLEVEL_ell >= 5, print(" starting nfissquaremodpodd")); if( a == 0, -if( DEBUGLEVEL_ell >= 5, print("fin de nfpsquareodd")); +if( DEBUGLEVEL_ell >= 5, print(" end of nfissquaremodpodd")); return(1)); v = idealval(nf,lift(a),p); if( v%2, -if( DEBUGLEVEL_ell >= 5, print("fin de nfpsquareodd")); +if( DEBUGLEVEL_ell >= 5, print(" end of nfissquaremodpodd")); return(0)); ap = a/nfbasistoalg(nf,p[2])^v; - norme = idealnorm(nf,p)\2; + norme = (p.p^p.f-1)/2; den = denominator(content(lift(ap)))%p.p; - if(sign(den), ap*=Mod(1,p.p)); + if( sign(den), ap *= Mod(1,p.p)); ap = ap^norme-1; if( ap == 0, -if( DEBUGLEVEL_ell >= 5, print("fin de nfpsquareodd")); +if( DEBUGLEVEL_ell >= 5, print(" end of nfissquaremodpodd")); return(1)); ap = lift(lift(ap)); if( idealval(nf,ap,p) > 0, -if( DEBUGLEVEL_ell >= 5, print("fin de nfpsquareodd")); +if( DEBUGLEVEL_ell >= 5, print(" end of nfissquaremodpodd")); return(1)); -if( DEBUGLEVEL_ell >= 5, print("fin de nfpsquareodd")); +if( DEBUGLEVEL_ell >= 5, print(" end of nfissquaremodpodd")); return(0); } -if( DEBUGLEVEL_ell >= 4, print("nfpsquare")); -{ -nfpsquare( nf, a, p, zinit) = -\\ a est un entier de K -\\ renvoie 1 si a est un carre dans ZKp 0 sinon -local(valap,zlog,i); +{nfissquaremodp( nf, a, p, zinit) = +\\ a is an algebraic integer of nf +\\ returns 1 if a is a square modulo the prime ideal p, 0 otherwise +\\ a = t_POLMOD +local(valap,zlog); -if( DEBUGLEVEL_ell >= 5, print("entree dans nfpsquare ",[a,p,zinit])); +if( DEBUGLEVEL_ell >= 5, print(" starting nfissquaremodp ",[a,p,zinit])); if( a == 0, -if( DEBUGLEVEL_ell >= 5, print("fin de nfpsquare")); +if( DEBUGLEVEL_ell >= 5, print(" end of nfissquaremodp")); return(1)); if( p.p != 2, -if( DEBUGLEVEL_ell >= 5, print("fin de nfpsquare")); - return(nfpsquareodd(nf,a,p))); +if( DEBUGLEVEL_ell >= 5, print(" end of nfissquaremodp")); + return(nfissquaremodpodd(nf,a,p))); valap = idealval(nf,a,p); if( valap%2, -if( DEBUGLEVEL_ell >= 5, print("fin de nfpsquare")); +if( DEBUGLEVEL_ell >= 5, print(" end of nfissquaremodp")); return(0)); if( valap, zlog = ideallog(nf,a*(nfbasistoalg(nf,p[5])/p.p)^valap,zinit) @@ -603,72 +510,163 @@ if( DEBUGLEVEL_ell >= 5, print("fin de nfpsquare")); zlog = ideallog(nf,a,zinit)); for( i = 1, #zinit[2][2], if( !(zinit[2][2][i]%2) && (zlog[i]%2), -if( DEBUGLEVEL_ell >= 5, print("fin de nfpsquare")); +if( DEBUGLEVEL_ell >= 5, print(" end of nfissquaremodp")); return(0))); -if( DEBUGLEVEL_ell >= 5, print("fin de nfpsquare")); +if( DEBUGLEVEL_ell >= 5, print(" end of nfissquaremodp")); return(1); } -if( DEBUGLEVEL_ell >= 4, print("nfpsquareq")); -{ -nfpsquareq( nf, a, p, q) = +{nfissquaremodpq( nf, a, p, q) = \\ cette fonction renvoie 1 si a est un carre \\ ?inversible? modulo P^q et 0 sinon. \\ P divise 2, et ?(a,p)=1?. -local(vala,zinit,zlog,i); +local(vala,zinit,zlog); -if( DEBUGLEVEL_ell >= 5, print("entree dans nfpsquareq ",[a,p,q])); +if( DEBUGLEVEL_ell >= 5, print(" starting nfissquaremodpq ",[a,p,q])); if( a == 0, -if( DEBUGLEVEL_ell >= 5, print("fin de nfpsquareq")); +if( DEBUGLEVEL_ell >= 5, print(" end of nfissquaremodpq")); return(1)); vala = idealval(nf,a,p); if( vala >= q, -if( DEBUGLEVEL_ell >= 5, print("fin de nfpsquareq")); +if( DEBUGLEVEL_ell >= 5, print(" end of nfissquaremodpq")); return(1)); if( vala%2, -if( DEBUGLEVEL_ell >= 5, print("fin de nfpsquareq")); +if( DEBUGLEVEL_ell >= 5, print(" end of nfissquaremodpq")); return(0)); zinit = idealstar(nf,idealpow(nf,p,q-vala),2); zlog = ideallog(nf,a*nfbasistoalg(nf,p[5]/2)^vala,zinit); for( i = 1, #zinit[2][2], if( !(zinit[2][2][i]%2) && (zlog[i]%2), -if( DEBUGLEVEL_ell >= 5, print("fin de nfpsquareq")); +if( DEBUGLEVEL_ell >= 5, print(" end of nfissquaremodpq")); return(0))); -if( DEBUGLEVEL_ell >= 5, print("fin de nfpsquareq")); +if( DEBUGLEVEL_ell >= 5, print(" end of nfissquaremodpq")); return(1); } -if( DEBUGLEVEL_ell >= 4, print("nflemma6")); -{ -nflemma6( nf, pol, p, nu, xx) = +{nfsqrtmodpq(nf,a,p,q) = +\\ suppose que a est un carre modulo p^q +\\ et renvoie x tel que x^2 = a mod p^q. +local(p_hnf,f,aaa,qq,e,xx,yy,r,aux,b,m,vp,inv2x,zinit,zlog,expo,p_ini,non_sq,id); + +if( DEBUGLEVEL_ell >= 5, print(" starting nfsqrtmodpq ",a,p,q)); + if( a == 0 || a == 1, +if( DEBUGLEVEL_ell >= 5, print(" end of nfsqrtmodpq")); + return(a)); + f = idealval(nf,a,p); + if( f >= q, +if( DEBUGLEVEL_ell >= 5, print(" end of nfsqrtmodpq")); + return(0)); +if( f%2, error("nfsqrtmodpq: a is not a square, odd valuation")); + a = nfalgtobasis(nf,a); + if( f, aaa = nfeltpow(nf,nfeltdiv(nf,a,p[5]/p.p),f), aaa = a); + p_hnf = idealhnf(nf,p); + p_ini = nfmodprinit(nf,p); +if( DEBUGLEVEL_ell >= 5, print(" p_hnf = ",p_hnf)); +if( DEBUGLEVEL_ell >= 5, print(" p_ini = ",p_ini)); + + if( p.p != 2, +\\ first case : p is odd + +\\ Shanks sqrt algorithm +if( DEBUGLEVEL_ell >= 5, print(" Shanks sqrt algorithm")); + non_sq = nfrandintmodid(nf,p_hnf); + while( nfissquaremodpodd(nf,non_sq,p), non_sq = nfrandintmodid(nf,p_hnf)); + non_sq = nfalgtobasis(nf,non_sq); + qq = ( p.p^p.f -1) \ 2; + e = 1; while( !(qq%2), e++; qq \= 2); + non_sq = nfeltpowmodpr(nf,non_sq,qq,p_ini); + yy = non_sq; r = e; + xx = nfeltpowmodpr(nf,aaa,qq\2,p_ini); + aux = nfeltmulmodpr(nf,aaa,xx,p_ini); + b = nfeltmulmodpr(nf,aux,xx,p_ini); + xx = aux; + aux = b; m = 0; + while( !val(nf,nfbasistoalg(nf,aux)-1,p), + m++; + aux = nfeltpowmodpr(nf,aux,2,p_ini) + ); + while( m, + if( m == r, error("nfsqrtmodpq: m = r")); + aux = nfeltpowmodpr(nf,yy,1<<(r-m-1),p_ini); + yy = nfeltpowmodpr(nf,aux,2,p_ini); + r = m; + xx = nfeltmulmodpr(nf,xx,aux,p_ini); + b = nfeltmulmodpr(nf,b,yy,p_ini); + aux = b;m = 0; + while( !val(nf,nfbasistoalg(nf,aux)-1,p), + m++; + aux = nfeltpowmodpr(nf,aux,2,p_ini) + ) + ); + +\\ lift de Hensel +\\ + + xx = nfbasistoalg(nf,xx); + aaa= nfbasistoalg(nf,aaa); + if( q > 1, +if( DEBUGLEVEL_ell >= 5, print(" Hensel lifting")); + vp = idealval(nf,xx^2-aaa,p); + if( vp < q-f, + yy = 2*xx; + inv2x = nfbasistoalg(nf,idealaddtoone(nf,yy,p)[1])/yy; + while( vp < q, vp++; xx -= (xx^2-aaa)*inv2x); + ); + if( f, xx *= nfbasistoalg(nf,p[2])^(f\2)); + ); + xx = mynfeltreduce(nf,xx,idealpow(nf,p,q)) + , +\\ cas ou p divise 2 */ + if( q-f > 1, id = idealpow(nf,p,q-f), id = p_hnf); + zinit = idealstar(nf,id,2); + zlog = ideallog(nf,aaa,zinit); + xx = 1; + for( i = 1, #zlog, + expo = zlog[i]; + if( expo, + if( !expo%2, + expo = expo>>1 + , aux = zinit[2][i]; + expo = expo*((aux+1)>>1)%aux + ); + xx *= nfbasistoalg(nf,zinit[2][3][i])^expo + ) + ); + if( f, + xx *= nfbasistoalg(nf,p[2])^(f>>1); + id = idealpow(nf,p,q)); + xx = mynfeltreduce(nf,xx,id); + ); +if( DEBUGLEVEL_ell >= 5, print(" end of nfsqrtmodpq ",xx)); + return(xx); +} +{nflemma6( nf, pol, p, nu, xx) = local(gx,gpx,lambda,mu); -if( DEBUGLEVEL_ell >= 5, print("entree dans nflemma6")); - gx = subst( pol, x, xx); - if( nfpsquareodd(nf,gx,p), -if( DEBUGLEVEL_ell >= 5, print("fin de nflemma6")); +if( DEBUGLEVEL_ell >= 5, print(" starting nflemma6")); + gx = subst( pol, 'x, xx); + if( nfissquaremodpodd(nf,gx,p), +if( DEBUGLEVEL_ell >= 5, print(" end of nflemma6")); return(1)); - gpx = subst( pol', x, xx); + gpx = subst( pol', 'x, xx); lambda = val(nf,gx,p);mu = val(nf,gpx,p); if( lambda>2*mu, -if( DEBUGLEVEL_ell >= 5, print("fin de nflemma6")); +if( DEBUGLEVEL_ell >= 5, print(" end of nflemma6")); return(1)); if( (lambda >= 2*nu) && (mu >= nu), -if( DEBUGLEVEL_ell >= 5, print("fin de nflemma6")); +if( DEBUGLEVEL_ell >= 5, print(" end of nflemma6")); return(0)); -if( DEBUGLEVEL_ell >= 5, print("fin de nflemma6")); +if( DEBUGLEVEL_ell >= 5, print(" end of nflemma6")); return(-1); } -if( DEBUGLEVEL_ell >= 4, print("nflemma7")); -{ -nflemma7( nf, pol, p, nu, xx, zinit) = +{nflemma7( nf, pol, p, nu, xx, zinit) = local(gx,gpx,v,lambda,mu,q); if( DEBUGLEVEL_ell >= 5, print("entree dans nflemma7 ",[xx,nu])); - gx = subst( pol, x, xx); - if( nfpsquare(nf,gx,p,zinit), + gx = subst( pol, 'x, xx); + if( nfissquaremodp(nf,gx,p,zinit), if( DEBUGLEVEL_ell >= 5, print("fin de nflemma7")); return(1)); - gpx = subst( pol', x, xx); + gpx = subst( pol', 'x, xx); v = p[3]; lambda = val(nf,gx,p);mu = val(nf,gpx,p); if( lambda>2*mu, @@ -682,7 +680,7 @@ if( DEBUGLEVEL_ell >= 5, print("fin de nflemma7")); if( q > 2*v, if( DEBUGLEVEL_ell >= 5, print("fin de nflemma7")); return(-1)); - if( nfpsquareq(nf,gx*nfbasistoalg(nf,p[5]/2)^lambda,p,q), + if( nfissquaremodpq(nf,gx*nfbasistoalg(nf,p[5]/2)^lambda,p,q), if( DEBUGLEVEL_ell >= 5, print("fin de nflemma7")); return(1)) , @@ -696,55 +694,47 @@ if( DEBUGLEVEL_ell >= 5, print("fin de nflemma7")); if( q > 2*v, if( DEBUGLEVEL_ell >= 5, print("fin de nflemma7")); return(-1)); - if( nfpsquareq(nf,gx*nfbasistoalg(nf,p[5]/2)^lambda,p,q), + if( nfissquaremodpq(nf,gx*nfbasistoalg(nf,p[5]/2)^lambda,p,q), if( DEBUGLEVEL_ell >= 5, print("fin de nflemma7")); return(0)) ); if( DEBUGLEVEL_ell >= 5, print("fin de nflemma7")); return(-1); } -if( DEBUGLEVEL_ell >= 4, print("nfzpsoluble")); -{ -nfzpsoluble( nf, pol, p, nu, pnu, x0) = +{nfzp_soluble( nf, pol, p, nu, pnu, x0) = local(result,pnup,lrep); -if( DEBUGLEVEL_ell >= 5, print("entree dans nfzpsoluble ",[lift(x0),nu])); +if( DEBUGLEVEL_ell >= 5, print("entree dans nfzp_soluble ",[lift(x0),nu])); if( p[3] == 0, result = nflemma6(nf,pol,p[1],nu,x0), result = nflemma7(nf,pol,p[1],nu,x0,p[4])); if( result == +1, -if( DEBUGLEVEL_ell >= 5, print("fin de nfzpsoluble")); +if( DEBUGLEVEL_ell >= 5, print("fin de nfzp_soluble")); return(1)); if( result == -1, -if( DEBUGLEVEL_ell >= 5, print("fin de nfzpsoluble")); +if( DEBUGLEVEL_ell >= 5, print("fin de nfzp_soluble")); return(0)); pnup = pnu*p[2]; lrep = #p[5]; nu++; for( i = 1, lrep, - if( nfzpsoluble(nf,pol,p,nu,pnup,x0+pnu*p[5][i]), -if( DEBUGLEVEL_ell >= 5, print("fin de nfzpsoluble")); + if( nfzp_soluble(nf,pol,p,nu,pnup,x0+pnu*p[5][i]), +if( DEBUGLEVEL_ell >= 5, print("fin de nfzp_soluble")); return(1))); -if( DEBUGLEVEL_ell >= 5, print("fin de nfzpsoluble")); +if( DEBUGLEVEL_ell >= 5, print("fin de nfzp_soluble")); return(0); } -if( DEBUGLEVEL_ell >= 4, print("mynfeltmod")); -{ -mynfeltmod(nf,a,b) = +{mynfeltmod(nf,a,b) = local(qred); qred = round(nfalgtobasis(nf,a/b)); qred = a-b*nfbasistoalg(nf,qred); return(qred); } -if( DEBUGLEVEL_ell >= 4, print("mynfeltreduce")); -{ -mynfeltreduce(nf,a,id) = +{mynfeltreduce(nf,a,id) = nfbasistoalg(nf,nfeltreduce(nf,nfalgtobasis(nf,a),id)); } -if( DEBUGLEVEL_ell >= 4, print("nfrandintmodid")); -{ -nfrandintmodid( nf, id) = +{nfrandintmodid( nf, id) = local(res); if( DEBUGLEVEL_ell >= 5, print("entree dans nfrandintmodid")); @@ -755,33 +745,27 @@ if( DEBUGLEVEL_ell >= 5, print("entree dans nfrandintmodid")); if( DEBUGLEVEL_ell >= 5, print("fin de nfrandintmodid")); return(res); } -if( DEBUGLEVEL_ell >= 4, print("nfrandint")); -{ -nfrandint( nf, borne) = -local(l,res,i); +{nfrandint( nf, borne) = +local(d,res); -if( DEBUGLEVEL_ell >= 5, print("entree dans nfrandint")); - l = #nf.zk; - res = vectorv(l,i,0); - for( i = 1, l, - if( borne, res[i] = random(borne<<1)-borne, res[i] = random() )); +if( DEBUGLEVEL_ell >= 5, print(" starting nfrandint")); + d = poldegree(nf.pol); + res = vectorv(d,i,if( borne, random(borne<<1)-borne, random())); res = nfbasistoalg(nf,res); -if( DEBUGLEVEL_ell >= 5, print("fin de nfrandint")); +if( DEBUGLEVEL_ell >= 5, print(" end of nfrandint")); return(res); } -if( DEBUGLEVEL_ell >= 4, print("nfqpsolublebig")); -{ -nfqpsolublebig( nf, pol, p,ap=0,b=1) = -local(deg,i,xx,z,Px,j,cont,pi,pol2,Roots); +{nfqp_solublebig( nf, pol, p,ap=0,b=1) = +local(deg,xx,z,Px,cont,pi,pol2,Roots); -if( DEBUGLEVEL_ell >= 4, print("entree dans nfqpsolublebig avec ",p.p)); +if( DEBUGLEVEL_ell >= 4, print(" starting nfqp_solublebig avec ",p.p)); deg = poldegree(pol); - if( nfpsquareodd(nf,polcoeff(pol,0),p), -if( DEBUGLEVEL_ell >= 4, print("fin de nfqpsolublebig")); + if( nfissquaremodpodd(nf,polcoeff(pol,0),p), +if( DEBUGLEVEL_ell >= 4, print(" end of nfqp_solublebig")); return(1)); - if( nfpsquareodd(nf,pollead(pol),p), -if( DEBUGLEVEL_ell >= 4, print("fin de nfqpsolublebig")); + if( nfissquaremodpodd(nf,pollead(pol),p), +if( DEBUGLEVEL_ell >= 4, print(" end of nfqp_solublebig")); return(1)); \\ on tient compte du contenu de pol @@ -801,9 +785,9 @@ if( DEBUGLEVEL_ell >= 4, print("fin de nfqpsolublebig")); xx = -ap*z+b*xx; Px=polcoeff(pol,deg); forstep (j=deg-1,0,-1,Px=Px*xx+polcoeff(pol,j)); - Px *= z^(deg); - if( nfpsquareodd(nf,Px,p), -if( DEBUGLEVEL_ell >= 4, print("fin de nfqpsolublebig")); + Px *= z^deg; + if( nfissquaremodpodd(nf,Px,p), +if( DEBUGLEVEL_ell >= 4, print(" end of nfqp_solublebig")); return(1)); ) ); @@ -812,15 +796,14 @@ if( DEBUGLEVEL_ell >= 4, print("fin de nfqpsolublebig")); Roots = nfpolrootsmod(nf,pol2,p); pi = nfbasistoalg(nf,p[2]); for( i = 1, #Roots, - if( nfqpsolublebig(nf,subst(pol,x,pi*x+Roots[i]),p), + if( nfqp_solublebig(nf,subst(pol,'x,pi*'x+Roots[i]),p), +if( DEBUGLEVEL_ell >= 4, print("fin de nfqp_solublebig")); return(1))); -if( DEBUGLEVEL_ell >= 4, print("fin de nfqpsolublebig")); +if( DEBUGLEVEL_ell >= 4, print(" end of nfqp_solublebig")); return(0); } -if( DEBUGLEVEL_ell >= 4, print("nfpolrootsmod")); -{ -nfpolrootsmod(nf,pol,p) = +{nfpolrootsmod(nf,pol,p) = \\ calcule les racines modulo l'ideal p du polynome pol. \\ p est un ideal premier de nf, sous la forme idealprimedec local(factlist,sol); @@ -832,37 +815,38 @@ local(factlist,sol); sol = concat(sol, [-polcoeff(factlist[i],0)/polcoeff(factlist[i],1)]))); return(sol); } -if( DEBUGLEVEL_ell >= 4, print("nfqpsoluble")); -{ -nfqpsoluble( nf, pol, p) = - -if( DEBUGLEVEL_ell >= 4, print("entree dans nfqpsoluble ",p)); -if( DEBUGLEVEL_ell >= 5, print("pol = ",pol)); - if( nfpsquare(nf,pollead(pol),p[1],p[4]), -if( DEBUGLEVEL_ell >= 5, print("fin de nfqpsoluble")); +{nfqp_soluble( nf, pol, p) = +\\ p is a prime output by initp() +\\ return 1 if pol(x) = y^2 has a p-adic rational solution +\\ (possibly oo) +\\ coeff of nfqfsoluble must be integers. + +if( DEBUGLEVEL_ell >= 5, print(" starting nfqp_soluble ",p)); +if( DEBUGLEVEL_ell >= 5, print(" pol = ",pol)); + if( nfissquaremodp(nf,pollead(pol),p[1],p[4]), +if( DEBUGLEVEL_ell >= 5, print(" end of nfqp_soluble")); return(1)); - if( nfpsquare(nf,polcoeff(pol,0),p[1],p[4]), -if( DEBUGLEVEL_ell >= 5, print("fin de nfqpsoluble")); + if( nfissquaremodp(nf,polcoeff(pol,0),p[1],p[4]), +if( DEBUGLEVEL_ell >= 5, print(" end of nfqp_soluble")); return(1)); - if( nfzpsoluble(nf,pol,p,0,1,0), -if( DEBUGLEVEL_ell >= 5, print("fin de nfqpsoluble")); + if( nfzp_soluble(nf,pol,p,0,1,0), +if( DEBUGLEVEL_ell >= 5, print(" end of nfqp_soluble")); return(1)); - if( nfzpsoluble(nf,polrecip(pol),p,1, p[2],0), -if( DEBUGLEVEL_ell >= 5, print("fin de nfqpsoluble")); + if( nfzp_soluble(nf,polrecip(pol),p,1, p[2],0), +if( DEBUGLEVEL_ell >= 5, print(" end of nfqp_soluble")); return(1)); -if( DEBUGLEVEL_ell >= 5, print("fin de nfqpsoluble")); +if( DEBUGLEVEL_ell >= 5, print(" end of nfqp_soluble")); return(0); } -if( DEBUGLEVEL_ell >= 4, print("nflocallysoluble")); -{ -nflocallysoluble( nf, pol, r=0,a=1,b=1) = +{nflocallysoluble( nf, pol, r=0,a=1,b=1) = +\\ Test whether Y^2 = pol is Everywhere Locally Soluble local(pol0,plist,add,ff,p,Delta,vecpol,vecpolr,Sturmr); -if( DEBUGLEVEL_ell >= 4, print("entree dans nflocallysoluble ",[pol,r,a,b])); +if( DEBUGLEVEL_ell >= 4, print(" starting nflocallysoluble ",[pol,r,a,b])); pol0 = pol; -\\ -\\ places finies de plist */ -\\ + +\\ places finies + pol *= deno(content(lift(pol)))^2; for( ii = 1, 3, if( ii == 1, plist = idealprimedec(nf,2)); @@ -872,45 +856,45 @@ if( DEBUGLEVEL_ell >= 4, print("entree dans nflocallysoluble ",[pol,r,a,b])); add = idealadd(nf,a,b); ff = factor(idealnorm(nf,add))[,1]; addprimes(ff); -if( DEBUGLEVEL_ell >= 4, print("liste de premiers = ",ff)); +if( DEBUGLEVEL_ell >= 4, print(" list of primes = ",ff)); plist = idealfactor(nf,add)[,1]); for( i = 1, #plist, - p = plist[i]; -if( DEBUGLEVEL_ell >= 3, print("p = ",p)); - if( p.p < LIMBIGPRIME, - if( !nfqpsoluble(nf,pol,initp(nf,p)), -if( DEBUGLEVEL_ell >= 2, print(" non ELS en ",p)); -if( DEBUGLEVEL_ell >= 4, print("fin de nflocallysoluble")); + p = plist[i]; +if( DEBUGLEVEL_ell >= 3, print(" p = ",p)); + if( p.p < LIMBIGPRIME || !LIMBIGPRIME, + if( !nfqp_soluble(nf,pol,initp(nf,p)), +if( DEBUGLEVEL_ell >= 2, print(" not ELS at ",p)); +if( DEBUGLEVEL_ell >= 4, print(" end of nflocallysoluble")); return(0)), - if( !nfqpsolublebig(nf,pol,p,r/a,b), -if( DEBUGLEVEL_ell >= 2, print(" non ELS en ",p.p," ( = grand premier )")); -if( DEBUGLEVEL_ell >= 4, print("fin de nflocallysoluble")); + if( !nfqp_solublebig(nf,pol,p,r/a,b), +if( DEBUGLEVEL_ell >= 2, print(" not ELS at ",p.p," ( = big prime )")); +if( DEBUGLEVEL_ell >= 4, print(" end of nflocallysoluble")); return(0)))); -); -\\ places reelles + ); + +\\ places reelles + if( nf.r1, Delta = poldisc(pol); vecpol = Vec(pol); for( i = 1, nf.r1, - if( nfsign(nf,pollead(pol),i) > 0, next); - if( nfsign(nf,polcoeff(pol,0),i) > 0, next); - if( nfsign(nf,Delta,i) < 0, next); + if( nfrealsign(nf,pollead(pol),i) > 0, next); + if( nfrealsign(nf,polcoeff(pol,0),i) > 0, next); + if( nfrealsign(nf,Delta,i) < 0, next); vecpolr = vector(#vecpol,j,mysubst(vecpol[j],nf.roots[i])); Sturmr = polsturm(Pol(vecpolr)); - if( Sturmr == 0, -if( DEBUGLEVEL_ell >= 2, print(" non ELS a l'infini")); -if( DEBUGLEVEL_ell >= 4, print("fin de nflocallysoluble")); + if( Sturmr == 0, +if( DEBUGLEVEL_ell >= 2, print(" not ELS at infinity")); +if( DEBUGLEVEL_ell >= 4, print(" end of nflocallysoluble")); return(0)); )); -if( DEBUGLEVEL_ell >= 2, print(" quartique ELS ")); -if( DEBUGLEVEL_ell >= 4, print("fin de nflocallysoluble")); +if( DEBUGLEVEL_ell >= 2, print(" quartic ELS ")); +if( DEBUGLEVEL_ell >= 4, print(" end of nflocallysoluble")); return(1); } -if( DEBUGLEVEL_ell >= 4, print("nfellcount")); -{ -nfellcount( nf, c, d, KS2gen, pointstriv) = -local(found,listgen,listpointscount,m1,m2,lastloc,mask,i,d1,iaux,j,triv,pol,point,deuxpoints); +{nfellcount( nf, c, d, KS2gen, pointstriv) = +local(found,listgen,listpointscount,m1,m2,lastloc,mask,i,d1,iaux,j,triv,pol,point,deuxpoints,aux,v); -if( DEBUGLEVEL_ell >= 4, print("entree dans nfellcount ",[c,d])); +if( DEBUGLEVEL_ell >= 4, print(" starting nfellcount ",[c,d])); found = 0; listgen = KS2gen; listpointscount = []; @@ -921,26 +905,27 @@ if( DEBUGLEVEL_ell >= 4, print("entree dans nfellcount ",[c,d])); i = 1; while( i < mask, d1 = 1; iaux = i; j = 1; - while( iaux, + while( iaux, if( iaux%2, d1 *= listgen[j]); iaux >>= 1; j++); -if( DEBUGLEVEL_ell >= 2, print("d1 = ",d1)); +if( DEBUGLEVEL_ell >= 2, print(" d1 = ",d1)); triv = 0; for( j = 1, #pointstriv, if( pointstriv[j][3]*pointstriv[j][1] && nfissquare(nf,d1*pointstriv[j][1]*pointstriv[j][3]), listpointscount = concat(listpointscount,[pointstriv[j]]); -if( DEBUGLEVEL_ell >= 2, print("point trivial")); +if( DEBUGLEVEL_ell >= 2, print(" comes from a trivial point")); triv = 1; m1++; if( degre(i) > lastloc, m2++); - found = 1; lastloc = -1; break)); + found = 1; lastloc = -1; break + )); if( !triv, pol = Pol([d1,0,c,0,d/d1]); -if( DEBUGLEVEL_ell >= 3, print("quartique = y^2 = ",pol)); +if( DEBUGLEVEL_ell >= 3, print(" quartic: y^2 = ",pol)); point = nfratpoint(nf,pol,LIM1,1); if( point != [], -if( DEBUGLEVEL_ell >= 2, print("point sur la quartique")); -if( DEBUGLEVEL_ell >= 3, print(point)); +if( DEBUGLEVEL_ell >= 2, print(" point on the quartic")); +if( DEBUGLEVEL_ell >= 3, print(" ",point)); m1++; if( point[3] != 0, aux = d1*point[1]/point[3]^2; @@ -955,8 +940,8 @@ if( DEBUGLEVEL_ell >= 3, print(point)); if( degre(i) > lastloc, m2++; lastloc = degre(i)); point = nfratpoint(nf,pol,LIM3,1); if( point != [], -if( DEBUGLEVEL_ell >= 2, print("point sur la quartique")); -if( DEBUGLEVEL_ell >= 3, print(point)); +if( DEBUGLEVEL_ell >= 2, print(" point on the quartic")); +if( DEBUGLEVEL_ell >= 3, print(" ",point)); m1++; aux = d1*point[1]/point[3]^2; deuxpoints = [ aux*point[1], aux*point[2]/point[3] ]; @@ -964,7 +949,7 @@ if( DEBUGLEVEL_ell >= 3, print(point)); if( degre(i) > lastloc, m2++); found = 1; lastloc = -1 , -if( DEBUGLEVEL_ell >= 2, print("pas de point trouve sur la quartique")); +if( DEBUGLEVEL_ell >= 2, print(" no point found on the quartic")); )))); if( found, found = 0; @@ -977,14 +962,12 @@ if( DEBUGLEVEL_ell >= 2, print("pas de point trouve sur la quartique")); ); for( i = 1, #listpointscount, if( #listpointscount[i] > 1, - if( subst(x^3+c*x^2+d*x,x,listpointscount[i][1])-listpointscount[i][2]^2 != 0, - error("nfellcount : MAUVAIS POINT = ",listpointscount[i])))); -if( DEBUGLEVEL_ell >= 4, print("fin de nfellcount")); + if( subst('x^3+c*'x^2+d*'x,'x,listpointscount[i][1])-listpointscount[i][2]^2 != 0, + error("nfellcount: WRONG POINT = ",listpointscount[i])))); +if( DEBUGLEVEL_ell >= 4, print(" end of nfellcount")); return([listpointscount,[m1,m2]]); } -if( DEBUGLEVEL_ell >= 4, print("bnfell2descent_viaisog")); -{ -bnfell2descent_viaisog( bnf, ell) = +{bnfell2descent_viaisog( bnf, ell) = \\ Calcul du rang des courbes elliptiques avec 2-torsion \\ dans le corps de nombres bnf \\ par la methode des 2-isogenies. @@ -995,20 +978,20 @@ bnfell2descent_viaisog( bnf, ell) = \\ ell doit etre sous la forme \\ y^2=x^3+ax^2+bx -> ell = [0,a,0,b,0] \\ avec a et b entiers. -local(i,P,Pfact,tors,pointstriv,apinit,bpinit,plist,KS2prod,oddclass,KS2gen,listpoints,pointgen,n1,n2,certain,np1,np2,listpoints2,aux1,aux2,certainp,rang,strange); +local(P,Pfact,tors,pointstriv,apinit,bpinit,plist,KS2prod,oddclass,KS2gen,listpoints,pointgen,n1,n2,certain,np1,np2,listpoints2,aux1,aux2,certainp,rang,strange); -if( DEBUGLEVEL_ell >= 2, print("Algorithme de la 2-descente par isogenies")); -if( DEBUGLEVEL_ell >= 3, print("entree dans bnfell2descent_viaisog")); - if( variable(bnf.pol) != y, - error(" bnfell2descent_viaisog : la variable du corps de nombres doit etre y ")); +if( DEBUGLEVEL_ell >= 2, print(" Algorithm of 2-descent via isogenies")); +if( DEBUGLEVEL_ell >= 3, print(" starting bnfell2descent_viaisog")); + if( variable(bnf.pol) != 'y, + error("bnfell2descent_viaisog: the variable of the number field must be y")); ell = ellinit(Mod(lift(ell),bnf.pol),1); if( ell.disc == 0, - error(" bnfell2descent_viaisog : courbe singuliere !!")); + error("bnfell2descent_viaisog: singular curve !!")); if( ell.a1 != 0 || ell.a3 != 0 || ell.a6 != 0, - error(" bnfell2descent_viaisog : la courbe n'est pas sous la forme [0,a,0,b,0]")); + error("bnfell2descent_viaisog: curve not of the form [0,a,0,b,0]")); if( denominator(nfalgtobasis(bnf,ell.a2)) > 1 || denominator(nfalgtobasis(bnf,ell.a4)) > 1, - error(" bnfell2descent_viaisog : coefficients non entiers")); + error("bnfell2descent_viaisog: non integral coefficients")); P = Pol([1,ell.a2,ell.a4])*Mod(1,bnf.pol); Pfact = factornf(P,bnf.pol)[,1]; @@ -1023,11 +1006,11 @@ if( DEBUGLEVEL_ell >= 3, print("entree dans bnfell2descent_viaisog")); \\ et de quelques renseignements associes plist = idealfactor(bnf,6*ell.disc)[,1]; -if( DEBUGLEVEL_ell >= 3, print(" Recherche de points triviaux sur la courbe")); - P *= x; -if( DEBUGLEVEL_ell >= 3, print("Y^2 = ",P)); +if( DEBUGLEVEL_ell >= 3, print(" Search for trivial points on the curve")); + P *= 'x; +if( DEBUGLEVEL_ell >= 3, print(" Y^2 = ",P)); pointstriv = concat( pointstriv, nfratpoint(bnf.nf,P,LIMTRIV,0)); -if( DEBUGLEVEL_ell >= 1, print("points triviaux sur E(K) = "); +if( DEBUGLEVEL_ell >= 1, print(" trivial points on E(K) = "); print(lift(pointstriv)); print()); KS2prod = ell.a4; @@ -1039,17 +1022,18 @@ if( DEBUGLEVEL_ell >= 1, print("points triviaux sur E(K) = "); KS2prod = idealmul(bnf,KS2prod,(KS2gen[5][3][1]))); ); KS2gen = KS2gen[1]; -\\ A CHANGER : KS2gen = matbasistoalg(bnf,KS2gen); for( i = 1, #KS2gen, KS2gen[i] = nfbasistoalg(bnf, KS2gen[i])); KS2gen = concat(Mod(lift(bnf.tufu),bnf.pol),KS2gen); if( DEBUGLEVEL_ell >= 2, - print("#K(b,2)gen = ",#KS2gen); - print("K(b,2)gen = ",KS2gen)); + print(" #K(b,2)gen = ",#KS2gen); + print(" K(b,2)gen = ",KS2gen)); listpoints = nfellcount(bnf.nf,ell.a2,ell.a4,KS2gen,pointstriv); pointgen = listpoints[1]; -if( DEBUGLEVEL_ell >= 1, print("points sur E(K) = ",lift(pointgen)); print()); +if( DEBUGLEVEL_ell >= 1, + print(" points on E(K) = ",lift(pointgen)); + print()); n1 = listpoints[2][1]; n2 = listpoints[2][2]; certain = (n1 == n2); @@ -1072,13 +1056,12 @@ if( DEBUGLEVEL_ell >= 1, if( !oddclass, KS2prod = idealmul(bnf,KS2prod,(KS2gen[5][3][1])))); KS2gen = KS2gen[1]; -\\ A CHANGER KS2gen = matbasistoalg(bnf,KS2gen); for( i = 1, #KS2gen, KS2gen[i] = nfbasistoalg(bnf, KS2gen[i])); KS2gen = concat(Mod(lift(bnf.tufu),bnf.pol),KS2gen); if( DEBUGLEVEL_ell >= 2, - print("#K(a^2-4b,2)gen = ",#KS2gen); - print("K(a^2-4b,2)gen = ",KS2gen)); + print(" #K(a^2-4b,2)gen = ",#KS2gen); + print(" K(a^2-4b,2)gen = ",KS2gen)); P = Pol([1,apinit,bpinit])*Mod(1,bnf.pol); Pfact= factornf(P,bnf.pol)[,1]; @@ -1086,15 +1069,15 @@ if( DEBUGLEVEL_ell >= 2, pointstriv=[[0,0,1],[-polcoeff(Pfact[1],0),0,1],[-polcoeff(Pfact[2],0),0,1]] , pointstriv = [[0,0,1]]); -if( DEBUGLEVEL_ell >= 3, print(" Recherche de points triviaux sur la courbe")); - P *= x; -if( DEBUGLEVEL_ell >= 3, print("Y^2 = ",P)); +if( DEBUGLEVEL_ell >= 3, print(" Search for trivial points on the curve")); + P *= 'x; +if( DEBUGLEVEL_ell >= 3, print(" Y^2 = ",P)); pointstriv = concat( pointstriv, nfratpoint(bnf.nf,P,LIMTRIV,0)); -if( DEBUGLEVEL_ell >= 1, print("points triviaux sur E'(K) = "); +if( DEBUGLEVEL_ell >= 1, print(" trivial points on E'(K) = "); print(lift(pointstriv)); print()); listpoints = nfellcount(bnf.nf,apinit,bpinit,KS2gen,pointstriv); -if( DEBUGLEVEL_ell >= 1, print("points sur E'(K) = ",lift(listpoints[1]))); +if( DEBUGLEVEL_ell >= 1, print(" points on E'(K) = ",lift(listpoints[1]))); np1 = listpoints[2][1]; np2 = listpoints[2][2]; listpoints2 = vector(#listpoints[1],i,0); for( i = 1, #listpoints[1], @@ -1105,7 +1088,7 @@ if( DEBUGLEVEL_ell >= 1, print("points sur E'(K) = ",lift(listpoints[1]))); listpoints2[i][1] = aux2^2/aux1/4; listpoints2[i][2] = aux2*(bpinit-aux1)/aux1/8 , listpoints2[i] = listpoints[1][i])); -if( DEBUGLEVEL_ell >= 1, print("points sur E(K) = ",lift(listpoints2)); print()); +if( DEBUGLEVEL_ell >= 1, print(" points on E(K) = ",lift(listpoints2)); print()); pointgen = concat(pointgen,listpoints2); certainp = (np1 == np2); @@ -1130,16 +1113,16 @@ if( DEBUGLEVEL_ell >= 1, if( DEBUGLEVEL_ell >= 1, if( certain && certainp, print("#E(K)/2E(K) = ",(1<<(rang+tors))); - print("rang = ",rang); print() + print("rank = ",rang); print() , print("#E(K)/2E(K) >= ",(1<<(rang+tors))); print(); - print(rang," <= rang <= ",n2+np2-2); print() + print(rang," <= rank <= ",n2+np2-2); print() )); strange = (n2+np2-n1-np1)%2; if( strange, if( DEBUGLEVEL_ell >= 1, - print(" !!! III doit etre un carre !!!"); print("donc")); + print(" !!! III should be a square !!!"); print("hence")); if( certain, np1++; certainp = (np1 == np2); @@ -1181,79 +1164,76 @@ if( DEBUGLEVEL_ell >= 1, if( DEBUGLEVEL_ell >= 1, if( certain && certainp, print("#E(K)/2E(K) = ",(1<<(rang+tors))); print(); - print("rang = ",rang); print() + print("rank = ",rang); print() , print("#E(K)/2E(K) >= ",(1<<(rang+tors))); print(); - print(rang," <= rang <= ",n2+np2-2); print()) + print(rang," <= rank <= ",n2+np2-2); print()) )); -\\ fin de strange +\\ end of strange -if( DEBUGLEVEL_ell >= 1, print("points = ",pointgen)); -if( DEBUGLEVEL_ell >= 3, print("fin de bnfell2descent_viaisog")); +if( DEBUGLEVEL_ell >= 1, print(" points = ",pointgen)); +if( DEBUGLEVEL_ell >= 3, print(" end of bnfell2descent_viaisog")); return([rang,n2+np2-2+tors,pointgen]); } -if( DEBUGLEVEL_ell >= 4, print("nfchinremain")); -{ -nfchinremain( nf, b, fact) = +{nfchinese( nf, b, fact) = \\ Chinese Remainder Theorem -local(l,fact2,i); +local(l,fact2); -if( DEBUGLEVEL_ell >= 4, print("entree dans nfchinremain")); +if( DEBUGLEVEL_ell >= 4, print(" starting nfchinese")); l = #fact[,1]; fact2 = vector(l,i,idealdiv(nf,b,idealpow(nf,fact[i,1],fact[i,2]))); -\\ for( i = 1, l, -\\ fact2[i] = idealdiv(nf,b,idealpow(nf,fact[i,1],fact[i,2]))); fact2 = idealaddtoone(nf,fact2); -\\ A CHANGER : fact2 = matbasistoalg(nf,fact2); for( i = 1, l, fact2[i] = nfbasistoalg(nf,fact2[i])); -if( DEBUGLEVEL_ell >= 4, print("fin de nfchinremain")); +if( DEBUGLEVEL_ell >= 4, print(" end of nfchinese")); return(fact2); } -if( DEBUGLEVEL_ell >= 4, print("bnfqfsolve2")); -{ -bnfqfsolve2(bnf, aleg, bleg, auto=[y]) = +{bnfqfsolve2(bnf, aleg, bleg, aut=['y]) = \\ Solves Legendre Equation x^2-aleg*Y^2=bleg*Z^2 \\ Using quadratic norm equations -\\ auto contient les automorphismes de bnf sous forme de polynomes -\\ en y, avec auto[1]=y . -local(aux,solvepolrel,auxsolve,solvepolabs,exprxy,rrrnf,bbbnf,SL0,i,SL1,SL,sunL,fondsunL,normfondsunL,SK,sunK,fondsunK,vecbleg,matnorm,matnormmod,expsolution,solution,reste,carre,verif); - -if( DEBUGLEVEL_ell >= 3, print("entree dans bnfqfsolve2")); - solvepolrel = x^2-aleg; -if( DEBUGLEVEL_ell >= 4, print("aleg = ",aleg)); -if( DEBUGLEVEL_ell >= 4, print("bleg = ",bleg)); - - if( #auto > 1, -if( DEBUGLEVEL_ell >= 4, print("factorisation du discriminant avec les automorhpismes de bnf")); - for( i = 2, #auto, - aux = abs(polresultant(lift(aleg)-subst(lift(aleg),y,auto[i]),bnf.pol)); +\\ aut contains the Galois automorphisms of bnf ( as polynomials in y) +\\ with aut[1] = y. +local(aux,solvepolrel,auxsolve,solvepolabs,exprxy,rrrnf,bbbnf,SL0,SL1,SL,sunL,fondsunL,normfondsunL,SK,sunK,fondsunK,vecbleg,matnorm,matnormmod,expsolution,solution,reste,carre,verif,x0,x1); + +if( DEBUGLEVEL_ell >= 3, print(" starting bnfqfsolve2")); + solvepolrel = 'x^2-aleg; +if( DEBUGLEVEL_ell >= 4, print(" aleg = ",aleg)); +if( DEBUGLEVEL_ell >= 4, print(" bleg = ",bleg)); + + if( nfissquare(bnf,aleg), +if( DEBUGLEVEL_ell >= 4, print(" aleg is a square !!")); + aleg = nfsqrt(bnf,aleg)[1]; + return([aleg,1,0]~) + ); + + if( #aut > 1, +if( DEBUGLEVEL_ell >= 4, print(" factorization of the discriminant using the automorphisms of bnf")); + for( i = 2, #aut, + aux = abs(polresultant(lift(aleg)-subst(lift(aleg),'y,aut[i]),bnf.pol)); if( aux, addprimes(factor(aux)[,1])))); auxsolve = rnfequation(bnf,solvepolrel,1); solvepolabs = auxsolve[1]; exprxy = auxsolve[2]; if( auxsolve[3], -if( DEBUGLEVEL_ell >=5, print(" CECI EST LE NOUVEAU CAS auxsolve[3] != 0"))); -if( DEBUGLEVEL_ell >= 4, print(" bbbnfinit ",solvepolabs)); +if( DEBUGLEVEL_ell >= 5, print(" case with auxsolve[3] != 0"))); +if( DEBUGLEVEL_ell >= 4, print(" bbbnfinit ",solvepolabs)); rrrnf = rnfinit(bnf,solvepolrel); bbbnf = bnfinit(solvepolabs,1); -if( DEBUGLEVEL_ell >= 4, print(" done")); +if( DEBUGLEVEL_ell >= 4, print(" done")); SL0 = 1; -if( DEBUGLEVEL_ell >= 4, print("bbbnf.clgp = ",bbbnf.clgp)); +if( DEBUGLEVEL_ell >= 4, print(" bbbnf.clgp = ",bbbnf.clgp)); for( i = 1, #bbbnf.clgp[2], if( bbbnf.clgp[2][i]%2 == 0, SL0 = idealmul(bbbnf,SL0,bbbnf.clgp[3][i][1,1]))); SL1 = idealmul(bbbnf,SL0,rnfeltup(rrrnf,bleg)); SL = idealfactor(bbbnf,SL1)[,1]~; sunL = bnfsunit(bbbnf,SL); -\\ A CHANGER : fondsunL = concat(bbbnf.futu,matbasistoalg(bbbnf,sunL[1])); fondsunL = concat(bbbnf.futu,vector(#sunL[1],i,nfbasistoalg(bbbnf,sunL[1][i]))); normfondsunL = norm(rnfeltabstorel( rrrnf,fondsunL)); SK = idealfactor(bnf,idealnorm(bbbnf,SL1))[,1]~; sunK = bnfsunit(bnf,SK); -\\ A CHANGER : fondsunK = concat(bnf.futu,matbasistoalg(bnf,sunK[1])); fondsunK = concat(bnf.futu,vector(#sunK[1],i,nfbasistoalg(bnf,sunK[1][i]))); vecbleg = bnfissunit(bnf,sunK,bleg); matnorm = matrix(#fondsunK,#normfondsunL,i,j,0); @@ -1261,38 +1241,37 @@ if( DEBUGLEVEL_ell >= 4, print("bbbnf.clgp = ",bbbnf.clgp)); matnorm[,i] = lift(bnfissunit( bnf,sunK,normfondsunL[i] ))); matnormmod = matnorm*Mod(1,2); expsolution = lift(matinverseimage( matnormmod, vecbleg*Mod(1,2))); -if( expsolution == []~, error(" bnfqfsolve2 : IL N'Y A PAS DE SOLUTION ")); + if( !length(expsolution), error("bnfqfsolve2 : NO SOLUTION !! ")); solution = prod( i = 1, #expsolution, fondsunL[i]^expsolution[i]); solution = rnfeltabstorel(rrrnf,solution); reste = (lift(vecbleg) - matnorm*expsolution)/2; carre = prod( i = 1, #vecbleg, fondsunK[i]^reste[i]); solution *= carre; - x1=polcoeff(lift(solution),1,x);x0=polcoeff(lift(solution),0,x); + x1 = polcoeff(lift(solution),1,'x); + x0 = polcoeff(lift(solution),0,'x); verif = x0^2 - aleg*x1^2-bleg; -if( verif, error(" bnfqfsolve2 : MAUVAIS POINT")); -if( DEBUGLEVEL_ell >= 3, print("fin de bnfqfsolve2")); - return([x0,x1,1]); +if( verif, error("bnfqfsolve2: WRONG POINT")); +if( DEBUGLEVEL_ell >= 3, print(" end of bnfqfsolve2")); + return([x0,x1,1]~); } -if( DEBUGLEVEL_ell >= 4, print("bnfqfsolve")); -{ -bnfqfsolve(bnf, aleg, bleg, flag3, auto=[y]) = +{bnfqfsolve(bnf, aleg, bleg, flag3, aut=['y]) = \\ cette fonction resout l'equation X^2-aleg*Y^2=bleg*Z^2 \\ dans le corps de nombres nf. \\ la solution est [X,Y,Z], \\ [0,0,0] sinon. -local(nf,aa,bb,na,nb,maxna,maxnb,mat,resl,t,sq,pol,vecrat,alpha,xx,yy,borne,test,sun,fact,suni,k,f,l,aux,alpha2,maxnbiter,idbb,rem,nbiter,mask,oldnb,newnb,bor,testici,de,xxp,yyp,rap,verif); +local(nf,aa,bb,na,nb,maxnb,mat,resl,t,sq,pol,vecrat,alpha,xx,yy,borne,test,sun,fact,suni,f,l,aux,alpha2,maxnbiter,idbb,rem,nbiter,mask,oldnb,newnb,bor,testici,de,xxp,yyp,rap,verif); -if( DEBUGLEVEL_ell >=5, print("entree dans bnfqfsolve")); -if( DEBUGLEVEL_ell >= 3, print("(a,b) = (",aleg,",",bleg,")")); +if( DEBUGLEVEL_ell >= 5, print(" starting bnfqfsolve")); +if( DEBUGLEVEL_ell >= 3, print(" (a,b) = (",aleg,",",bleg,")")); nf = bnf.nf; aleg = Mod(lift(aleg),nf.pol); aa = aleg; bleg = Mod(lift(bleg),nf.pol); bb = bleg; - if( aa == 0, -if( DEBUGLEVEL_ell >= 5, print("fin de bnfqfsolve")); + if( aa == 0, +if( DEBUGLEVEL_ell >= 5, print(" end of bnfqfsolve")); return([0,1,0]~)); if( bb == 0, -if( DEBUGLEVEL_ell >= 5, print("fin de bnfqfsolve")); +if( DEBUGLEVEL_ell >= 5, print(" end of bnfqfsolve")); return([0,0,1]~)); na = abs(norm(aa)); nb = abs(norm(bb)); @@ -1302,10 +1281,10 @@ if( DEBUGLEVEL_ell >= 5, print("fin de bnfqfsolve")); test = 0; nbiter = 0; while( 1, - if( flag3 && bnf.clgp[1]>1, resl = bnfqfsolve2(bnf,aa,bb,auto)~; break); -if( DEBUGLEVEL_ell >= 4, print("(na,nb,a,b) = ",lift([na,nb,aa,bb,norm(aa),norm(bb)]))); -if( DEBUGLEVEL_ell >= 5, print("***",nb,"*** ")); - if( nb >= maxnb, + if( flag3 && bnf.clgp[1]>1, resl = bnfqfsolve2(bnf,aa,bb,aut); break); +if( DEBUGLEVEL_ell >= 4, print(" (na,nb,a,b) = ",lift([na,nb,aa,bb,norm(aa),norm(bb)]))); +if( DEBUGLEVEL_ell >= 5, print(" ***",nb,"*** ")); + if( nb >= maxnb, mat = Mod(matid(3),nf.pol); aa = aleg; bb = bleg; na = abs(norm(aleg)); nb = abs(norm(bleg))); if( aa == 1, resl = [1,1,0]~; break); @@ -1327,19 +1306,19 @@ if( DEBUGLEVEL_ell >= 5, print("***",nb,"*** ")); t = na; na = nb; nb = t; t = mat[,3]; mat[,3] = mat[,2]; mat[,2] = t); if( nb == 1, -if( DEBUGLEVEL_ell >= 4, print("(a,b) = ",lift([aa,bb]))); -if( DEBUGLEVEL_ell >= 4, print("(na,nb) = ",lift([na,nb]))); +if( DEBUGLEVEL_ell >= 4, print(" (a,b) = ",lift([aa,bb]))); +if( DEBUGLEVEL_ell >= 4, print(" (na,nb) = ",lift([na,nb]))); if( aleg == aa && bleg == bb, mat = Mod(matid(3),nf.pol)); - if( flag3, resl = bnfqfsolve2(bnf,aa,bb,auto)~; break); - pol = aa*x^2+bb; + if( flag3, resl = bnfqfsolve2(bnf,aa,bb,aut); break); + pol = aa*'x^2+bb; vecrat = nfratpoint(nf,pol,borne++,1); if( vecrat != 0, resl=[vecrat[2],vecrat[1],vecrat[3]]~; break); alpha = 0; -if( DEBUGLEVEL_ell >= 4, print("borne = ",borne)); +if( DEBUGLEVEL_ell >= 4, print(" bound = ",borne)); while( alpha==0, xx = nfrandint(nf,borne); yy = nfrandint(nf,borne); - borne++; + borne++; alpha = xx^2-aa*yy^2 ); bb *= alpha; nb *= abs(norm(alpha)); t = xx*mat[,1]+yy*mat[,2]; @@ -1354,21 +1333,21 @@ if( DEBUGLEVEL_ell >= 4, print("on factorise bb = ",bb)); if( DEBUGLEVEL_ell >= 4, print("fact = ",fact)); suni = concat(bnf.futu,vector(#sun[1],i,nfbasistoalg(bnf,sun[1][i]))); for( i = 1, #suni, - if( (f = fact[i]>>1), + if( (f = fact[i]>>1), test =0; for( k = 1, 3, mat[k,3] /= suni[i]^f); nb /= abs(norm(suni[i]))^(2*f); bb /= suni[i]^(2*f))); -if( DEBUGLEVEL_ell >= 4, print("on factorise bb = ",bb)); +if( DEBUGLEVEL_ell >= 4, print(" factorization of bb = ",bb)); fact = idealfactor(nf,bb); -if( DEBUGLEVEL_ell >= 4, print("fact = ",fact)); +if( DEBUGLEVEL_ell >= 4, print(" fact = ",fact)); l = #fact[,1]; if( test, aux = 1; for( i = 1, l, if( (f = fact[i,2]>>1) && - !(fact[i,1][1]%2) && !nfpsquareodd(nf,aa,fact[i,1]), + !(fact[i,1][1]%2) && !nfissquaremodpodd(nf,aa,fact[i,1]), aux=idealmul(nf,aux,idealpow(nf,fact[i,1],f)))); if( aux != 1, test = 0; @@ -1378,28 +1357,31 @@ if( DEBUGLEVEL_ell >= 4, print("fact = ",fact)); mat[,3] *= alpha)); if( test, maxnbiter = 1<= 4, print("sq = ",sq); print("fact = ",fact); print("l = ",l)); - if( l > 1, +if( DEBUGLEVEL_ell >= 4, + print(" sq = ",sq); + print(" fact = ",fact); + print(" l = ",l)); + if( l > 1, idbb = idealhnf(nf,bb); - rem = nfchinremain(nf,idbb,fact)); + rem = nfchinese(nf,idbb,fact)); test = 1; nbiter = 1; while( test && nbiter <= maxnbiter, if( l > 1, mask = nbiter; xx = 0; for( i = 1, l, if( mask%2, xx += rem[i]*sq[i], xx -= rem[i]*sq[i] ); mask >>= 1) - , + , test = 0; xx = sq[1]); xx = mynfeltmod(nf,xx,bb); alpha = xx^2-aa; if( alpha == 0, resl=[xx,1,0]~; break(2)); t = alpha/bb; -if( DEBUGLEVEL_ell >= 4, print("[alpha,bb] = ",[alpha,bb])); +if( DEBUGLEVEL_ell >= 4, print(" [alpha,bb] = ",[alpha,bb])); oldnb = nb; newnb = abs(norm(t)); -if( DEBUGLEVEL_ell >= 4, print("[oldnb,newnb,oldnb/newnb] = ",[oldnb,newnb,oldnb/newnb+0.])); +if( DEBUGLEVEL_ell >= 4, print(" [oldnb,newnb,oldnb/newnb] = ",[oldnb,newnb,oldnb/newnb+0.])); while( nb > newnb, mat[,3] *= t; bb = t; nb = newnb; @@ -1414,8 +1396,8 @@ if( DEBUGLEVEL_ell >= 4, print("[oldnb,newnb,oldnb/newnb] = ",[oldnb,newnb,oldnb if( nb == oldnb, nbiter++, test = 0); ); if( nb == oldnb, - if( flag3, resl = bnfqfsolve2(bnf,aa,bb,auto)~; break); - pol = aa*x^2+bb; + if( flag3, resl = bnfqfsolve2(bnf,aa,bb,aut); break); + pol = aa*'x^2+bb; vecrat =nfratpoint(nf,pol,borne++<<1,1); if( vecrat != 0, resl = [vecrat[2],vecrat[1],vecrat[3]]~; break); @@ -1425,18 +1407,18 @@ if( DEBUGLEVEL_ell >= 4, print("[oldnb,newnb,oldnb/newnb] = ",[oldnb,newnb,oldnb xxp = mynfeltmod(bnf,de*xx,bb); yyp = mynfeltmod(bnf,de*yy,bb); rap = (norm(xxp^2-aa*yyp^2)/nb^2+0.); if( abs(rap) < 1, -if( DEBUGLEVEL_ell >= 4, print("********** \n \n MIRACLE ",rap," \n \n ***")); +if( DEBUGLEVEL_ell >= 4, print(" ********** \n \n MIRACLE ",rap," \n \n ***")); t = (xxp^2-aa*yyp^2)/bb; mat[,3] *= t; bb = t; nb = abs(norm(bb)); -if( DEBUGLEVEL_ell >= 4, print("newnb = ",nb)); +if( DEBUGLEVEL_ell >= 4, print(" newnb = ",nb)); t = xxp*mat[,1]+yyp*mat[,2]; mat[,2] = aa*yyp*mat[,1] + xxp*mat[,2]; mat[,1] = t; xx = xxp; yy = -yyp; testici = 0; )); - if( testici, + if( testici, alpha = 0; while( alpha == 0, xx = nfrandint(nf,4*borne); yy = nfrandint(nf,4*borne); @@ -1448,31 +1430,29 @@ if( DEBUGLEVEL_ell >= 4, print("newnb = ",nb)); mat[,1] = t; mat[,3] *= alpha;))))); resl = lift(mat*resl); -if( DEBUGLEVEL_ell >= 5, print("resl1 = ",resl)); -if( DEBUGLEVEL_ell >= 5, print("content = ",content(resl))); +if( DEBUGLEVEL_ell >= 5, print(" resl1 = ",resl)); +if( DEBUGLEVEL_ell >= 5, print(" content = ",content(resl))); resl /= content(resl); resl = Mod(lift(resl),nf.pol); -if( DEBUGLEVEL_ell >=5, print("resl3 = ",resl)); +if( DEBUGLEVEL_ell >=5, print(" resl3 = ",resl)); fact = idealadd(nf,idealadd(nf,resl[1],resl[2]),resl[3]); fact = bnfisprincipal(bnf,fact,3); resl *=1/nfbasistoalg(nf,fact[2]); -if( DEBUGLEVEL_ell >= 5, print("resl4 = ",resl)); -if( DEBUGLEVEL_ell >= 3, print("resl = ",resl)); +if( DEBUGLEVEL_ell >= 5, print(" resl4 = ",resl)); +if( DEBUGLEVEL_ell >= 3, print(" resl = ",resl)); verif = (resl[1]^2-aleg*resl[2]^2-bleg*resl[3]^2 == 0); - if( !verif && DEBUGLEVEL_ell >= 0, error(" bnfqfsolve : MAUVAIS POINT")); -if( DEBUGLEVEL_ell >= 3, print("fin de bnfqfsolve")); + if( !verif, error("bnfqfsolve: WRONG POINT")); +if( DEBUGLEVEL_ell >= 3, print(" end of bnfqfsolve")); return(resl); } -if( DEBUGLEVEL_ell >= 4, print("bnfredquartique2")); -{ -bnfredquartique2( bnf, pol, r,a,b) = +{bnfredquartique( bnf, pol, r,a,b) = \\ reduction d'une quartique issue de la 2-descente -\\ en connaissant les valeurs de r, a et b. -local(gcc,princ,den,ap,rp,pol2); +\\ en connaissant les valeurs de r, a et b. +local(gcc,princ,rp,pol2); -if( DEBUGLEVEL_ell >= 4, print("entree dans bnfredquartique2")); -if( DEBUGLEVEL_ell >= 4, print([r,a,b])); -if( DEBUGLEVEL_ell >= 3, print(" reduction de la quartique ",pol)); +if( DEBUGLEVEL_ell >= 4, print(" starting bnfredquartique")); +if( DEBUGLEVEL_ell >= 4, print(" ",[r,a,b])); +if( DEBUGLEVEL_ell >= 3, print(" reduction of the quartic ",pol)); if( a == 0, rp = 0 @@ -1485,210 +1465,214 @@ if( DEBUGLEVEL_ell >= 3, print(" reduction de la quartique ",pol)); princ = bnfisprincipal(bnf,gcc,3); if( princ[1] == 0, gcc = nfbasistoalg(bnf,princ[2]) , -if( DEBUGLEVEL_ell >= 3, print(" quartique non reduite")); -if( DEBUGLEVEL_ell >= 4, print("fin de bnfredquartique2")); +if( DEBUGLEVEL_ell >= 3, print(" quartic not reduced")); +if( DEBUGLEVEL_ell >= 4, print(" end of bnfredquartique")); return([pol,0,1])); rp = nfbasistoalg(bnf,idealaddtoone(bnf.nf,a/gcc,b/gcc)[1])/(a/gcc); rp = mynfeltmod(bnf,r*rp,b)/gcc; b /= gcc; ) ); - pol2 = subst(pol/b,x,rp+b*x)/b^3; -if( DEBUGLEVEL_ell >= 3, print(" quartique reduite = ",pol2)); -if( DEBUGLEVEL_ell >= 4, print("fin de bnfredquartique2")); + pol2 = subst(pol/b,'x,rp+b*'x)/b^3; +if( DEBUGLEVEL_ell >= 3, print(" quartic reduced: ",pol2)); +if( DEBUGLEVEL_ell >= 4, print(" end of bnfredquartique")); return([pol2,rp,b]); } -if( DEBUGLEVEL_ell >= 4, print("bnfell2descent_gen")); -{ -bnfell2descent_gen( bnf, ell, ext, help=[], bigflag=1, flag3=1, auto=[y]) = +{bnfell2descent_gen( bnf, ell, ext, help=[], bigflag=1, flag3=1, aut=['y]) = \\ bnf a un polynome en y. \\ si ell= y^2=P(x), alors ext est \\ ext[1] est une equation relative du corps (=P(x)), -\\ ext[2] est le resultat rnfequation(bnf,P,2); -\\ ext[3] est le buchinitfu (sur Q) de l'extension. +\\ ext[2] est le resultat rnfequation(bnf,P,1); +\\ ext[3] est le bnfinit (sur Q) de l'extension. \\ dans la suite ext est note L = K(theta). \\ help est une liste de points deja connus sur ell. \\ si bigflag !=0 alors on applique bnfredquartique. \\ si flag3 ==1 alors on utilise bnfqfsolve2 (equation aux normes) pour resoudre Legendre -\\ auto est une liste d'automorphismes connus de bnf +\\ aut est une liste d'automorphismes connus de bnf \\ (ca peut aider a factoriser certains discriminiants). \\ ell est de la forme y^2=x^3+A*x^2+B*x+C \\ ie ell=[0,A,0,B,C], avec A,B et C entiers. \\ -local(nf,unnf,ellnf,A,B,C,S,plist,Lrnf,SLprod,oddclass,SLlist,LS2gen,polrel,alpha,ttheta,KS2gen,LS2genunit,normLS2,normcoord,LS2coordtilda,LS2tilda,i,aux,j,listgen,listpoints,listpointstriv,listpointsmwr,list,m1,m2,loc,lastloc,maskwhile,iwhile,zc,iaux,liftzc,ispointtriv,point,c,b,a,sol,found,alphac,r,denc,dena,cp,alphacp,beta,mattr,vec,z1,ff,cont,d,e,polorig,pol,redq,transl,multip,UVW,pointxx,point2,v,rang); +local(nf,unnf,ellnf,A,B,C,S,plist,Lrnf,SLprod,LS2,LS2gen,polrel,alpha,ttheta,KS2gen,normLS2,normcoord,LS2coordtilda,LS2tilda,aux,listgen,listpointstriv,listpoints,m1,m2,loc,lastloc,maskwhile,iwhile,zc,iaux,liftzc,ispointtriv,point,c,b,a,found,alphac,r,denc,dena,cp,alphacp,beta,mattr,vec,z1,cont,d,e,polorig,pol,redq,transl,multip,UVW,pointxx,point2,rang,listELS,listnotELS); -if( DEBUGLEVEL_ell >= 4, print("entree dans bnfell2descent_gen")); - -\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ -\\ construction de L(S,2) \\ -\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ +if( DEBUGLEVEL_ell >= 4, print(" starting bnfell2descent_gen")); nf = bnf.nf; unnf = Mod(1,nf.pol); ellnf = ell*unnf; if( #ellnf <= 5, ellnf = ellinit(ellnf,1)); - A = ellnf.a2; if( DEBUGLEVEL_ell >= 2, print("A = ",A)); - B = ellnf.a4; if( DEBUGLEVEL_ell >= 2, print("B = ",B)); - C = ellnf.a6; if( DEBUGLEVEL_ell >= 2, print("C = ",C)); + + A = ellnf.a2; if( DEBUGLEVEL_ell >= 2, print(" A = ",A)); + B = ellnf.a4; if( DEBUGLEVEL_ell >= 2, print(" B = ",B)); + C = ellnf.a6; if( DEBUGLEVEL_ell >= 2, print(" C = ",C)); + +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ +\\ Construction of L(S,2) \\ +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ + +if( DEBUGLEVEL_ell >= 2, print(); print(" Computing L(S,2)")); + + polrel = ext[1]; + alpha = Mod(Mod('y,nf.pol),polrel); \\ alpha est l'element primitif de K + ttheta = Mod('x,polrel); \\ ttheta est la racine de P(x) S = 6*lift(ellnf.disc); plist = idealfactor(nf,S)[,1]; Lrnf = ext[3]; - SLprod = subst(lift(ext[1]'),y,lift(ext[2][2])); -if( DEBUGLEVEL_ell >= 3, print(ext[2])); - oddclass = 0; - while( !oddclass, -\\ Constructoin de S: - SLlist = idealfactor(Lrnf,SLprod)[,1]~; + SLprod = subst(lift(polrel'),'y,lift(ext[2][2])); +if( DEBUGLEVEL_ell >= 3, print(" ",ext[2])); + + while( 1, \\ Construction des S-unites - LS2gen = bnfsunit(Lrnf,SLlist); -if( DEBUGLEVEL_ell >= 4, print("LS2gen = ",LS2gen)); -\\ on ajoute la partie paire du groupe de classes. - oddclass = LS2gen[5][1]%2; - if( !oddclass, -if( DEBUGLEVEL_ell >= 3, print("2-class group ",LS2gen[5][3][1][1,1])); - S *= LS2gen[5][3][1][1,1]; - SLprod = idealmul(Lrnf,SLprod,(LS2gen[5][3][1]))); + LS2gen = bnfsunit(Lrnf, idealfactor(Lrnf,SLprod)[,1]~); +if( DEBUGLEVEL_ell >= 4, print(" LS2gen = ",LS2gen)); +\\ si le groupe de classes est impair, on a fini. + if( LS2gen[5][1]%2, break); +if( DEBUGLEVEL_ell >= 3, print(" 2-class group ",LS2gen[5][3][1][1,1])); + S *= LS2gen[5][3][1][1,1]; + SLprod = idealmul(Lrnf,SLprod,(LS2gen[5][3][1])); ); - polrel = ext[1]; - alpha = Mod(Mod(y,nf.pol),polrel); \\ alpha est l'element primitif de K - ttheta = Mod(x,polrel); \\ ttheta est la racine de P(x) - KS2gen = bnfsunit(bnf,idealfactor(nf,S)[,1]~); + +if( DEBUGLEVEL_ell >= 3, print(" #KS2gen = ",#KS2gen[1])); +if( DEBUGLEVEL_ell >= 3, print(" KS2gen = ",KS2gen[1])); -if( DEBUGLEVEL_ell >= 3, print("#KS2gen = ",#KS2gen[1])); -if( DEBUGLEVEL_ell >= 3, print("KS2gen = ",KS2gen[1])); + LS2gen = LS2gen[1]; + LS2 = vector(#LS2gen,i,lift(nfbasistoalg(Lrnf,LS2gen[i]))); + LS2 = concat(lift(Lrnf.futu),LS2); - LS2genunit = lift(Lrnf.futu); -\\ A CHANGER : LS2genunit = concat(LS2genunit,lift(matbasistoalg(Lrnf,LS2gen[1]))); - LS2genunit = concat(LS2genunit,vector(#LS2gen[1],i,lift(nfbasistoalg(Lrnf,LS2gen[1][i])))); + LS2 = subst(LS2,'x,ttheta); + LS2 = LS2*Mod(1,polrel); +if( DEBUGLEVEL_ell >= 3, print(" #LS2 = ",#LS2)); +if( DEBUGLEVEL_ell >= 3, print(" LS2 = ",LS2)); +if( DEBUGLEVEL_ell >= 2, print(" L(S,2) = ",LS2)); - LS2genunit = subst(LS2genunit,x,ttheta); - LS2genunit = LS2genunit*Mod(1,polrel); -if( DEBUGLEVEL_ell >= 3, print("#LS2genunit = ",#LS2genunit)); -if( DEBUGLEVEL_ell >= 3, print("LS2genunit = ",LS2genunit)); +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ +\\ Construction of the Selmer group \\ +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ + +if( DEBUGLEVEL_ell >= 2, print(); print(" Computing the Selmer group")); \\ dans LS2gen, on ne garde que ceux dont la norme est un carre. - normLS2gen = norm(LS2genunit); -if( DEBUGLEVEL_ell >= 4, print("normLS2gen = ",normLS2gen)); + normLS2 = norm(LS2); +if( DEBUGLEVEL_ell >= 4, print(" normLS2 = ",normLS2)); \\ matrice de l'application norme - normcoord = matrix(#KS2gen[1]+#bnf[8][5]+1,#normLS2gen,i,j,0); - for( i = 1, #normLS2gen, - normcoord[,i] = bnfissunit(bnf,KS2gen,normLS2gen[i])); -if( DEBUGLEVEL_ell >= 4, print("normcoord = ",normcoord)); + normcoord = matrix(#KS2gen[1]+#bnf[8][5]+1,#normLS2,i,j,0); + for( i = 1, #normLS2, + normcoord[,i] = bnfissunit(bnf,KS2gen,normLS2[i])); +if( DEBUGLEVEL_ell >= 4, print(" normcoord = ",normcoord)); \\ construction du noyau de la norme LS2coordtilda = lift(matker(normcoord*Mod(1,2))); -if( DEBUGLEVEL_ell >= 4, print("LS2coordtilda = ",LS2coordtilda)); +if( DEBUGLEVEL_ell >= 4, print(" LS2coordtilda = ",LS2coordtilda)); LS2tilda = vector(#LS2coordtilda[1,],i,0); for( i = 1, #LS2coordtilda[1,], aux = 1; for( j = 1, #LS2coordtilda[,i], if( sign(LS2coordtilda[j,i]), - aux *= LS2genunit[j])); + aux *= LS2[j])); LS2tilda[i] = aux; ); -if( DEBUGLEVEL_ell >= 3, print("LS2tilda = ",LS2tilda)); -if( DEBUGLEVEL_ell >= 3, print("norm(LS2tilda) = ",norm(LS2tilda))); +if( DEBUGLEVEL_ell >= 3, print(" LS2tilda = ",LS2tilda)); +if( DEBUGLEVEL_ell >= 3, print(" norm(LS2tilda) = ",norm(LS2tilda))); \\ Fin de la construction de L(S,2) listgen = LS2tilda; -if( DEBUGLEVEL_ell >= 2, print("LS2gen = ",listgen)); -if( DEBUGLEVEL_ell >= 2, print("#LS2gen = ",#listgen)); - listpoints = []; +if( DEBUGLEVEL_ell >= 2, print(" #LS2gen = ",#listgen)); +if( DEBUGLEVEL_ell >= 2, print(" LS2gen = ",listgen)); -if( DEBUGLEVEL_ell >= 3, print("(A,B,C) = ",[A,B,C])); +if( DEBUGLEVEL_ell >= 3, print(" (A,B,C) = ",[A,B,C])); \\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ \\ Recherche de points triviaux \\ \\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ -if( DEBUGLEVEL_ell >= 2, print(" Recherche de points triviaux sur la courbe ")); - listpointstriv = nfratpoint(nf,x^3+A*x^2+B*x+C,LIMTRIV,0); +if( DEBUGLEVEL_ell >= 2, print(" Search for trivial points on the curve")); + listpointstriv = nfratpoint(nf,'x^3+A*'x^2+B*'x+C,LIMTRIV,0); listpointstriv = concat(help,listpointstriv); -if( DEBUGLEVEL_ell >= 1, print("points triviaux sur la courbe = ",listpointstriv)); +if( DEBUGLEVEL_ell >= 1, print(" Trivial points on the curve = ",listpointstriv)); \\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ \\ parcours de L(S,2) \\ \\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ - listpointsmwr = []; - list = [ 6, ellnf.disc, 0]; + listpoints = []; m1 = 0; m2 = 0; lastloc = -1; maskwhile = 1<<#listgen; listELS = [0]; listnotELS = []; iwhile = 1; + while( iwhile < maskwhile, -if( DEBUGLEVEL_ell >= 4, print("iwhile = ",iwhile); print("listgen = ",listgen)); +if( DEBUGLEVEL_ell >= 4, + print(" iwhile = ",iwhile); + print(" listgen = ",listgen) +); \\ utilise la structure de groupe pour detecter une eventuelle solubilite locale. -if( DEBUGLEVEL_ell >= 4, print("listELS = ",listELS); - print("listnotELS = ",listnotELS)); - sol = 1; loc = 0; + loc = 0; for( i = 1, #listELS, for( j = 1, #listnotELS, if( bitxor(listELS[i],listnotELS[j]) == iwhile, -if( DEBUGLEVEL_ell >= 3, print(" Non ELS d'apres la structure de groupe")); +if( DEBUGLEVEL_ell >= 3, print(" Not ELS from group structure")); listnotELS = concat(listnotELS,[iwhile]); - sol = 0; break(2)))); - if( !sol, iwhile++; next); + iwhile++; + next(3) + ))); for( i = 1, #listELS, for( j = i+1, #listELS, if( bitxor(listELS[i],listELS[j]) == iwhile, -if( DEBUGLEVEL_ell >= 3, print(" ELS d'aptres la structure de ")); +if( DEBUGLEVEL_ell >= 3, print(" ELS from group structure")); listELS = concat(listELS,[iwhile]); - loc = 2; - break(2)))); + loc = 1; + break(2) + ))); - iaux = vector(#listgen,i,bittest(iwhile,i-1))~; + iaux = vectorv(#listgen,i,bittest(iwhile,i-1)); iaux = (LS2coordtilda*iaux)%2; + zc = unnf*prod( i = 1, #LS2, LS2[i]^iaux[i]); - zc = unnf*prod( i = 1, #LS2genunit,LS2genunit[i]^iaux[i]); - -if( DEBUGLEVEL_ell >= 2, print("zc = ",zc)); +if( DEBUGLEVEL_ell >= 2, print(" zc = ",zc)); liftzc = lift(zc); \\ Est-ce un point trivial ? + found = 0; ispointtriv = 0; for( i = 1, #listpointstriv, point = listpointstriv[i]; if( #point == 2 || point[3] != 0, - if( nfissquare(Lrnf.nf,subst((lift(point[1])-x)*lift(liftzc),y,lift(ext[2][2]))), -if( DEBUGLEVEL_ell >= 2, print(" vient du point trivial ",point)); - listpointsmwr = concat(listpointsmwr,[point]); - m1++; - listELS = concat(listELS,[iwhile]); - if( degre(iwhile) > lastloc, m2++); - sol = found = ispointtriv = 1; break - ))); + if( nfissquare(Lrnf.nf,subst((lift(point[1])-'x)*lift(liftzc),'y,lift(ext[2][2]))), +if( DEBUGLEVEL_ell >= 2, print(" comes from the trivial point ",point)); + listpoints = concat(listpoints,[point]); + found = 1; ispointtriv = 1; break + ))); -\\ Ce n'est pas un point trivial - if( !ispointtriv, - c = polcoeff(liftzc,2); - b = -polcoeff(liftzc,1); - a = polcoeff(liftzc,0); - sol = 0; found = 0; \\ \\\\\\\\\\\\\ \\ On cherche a ecrire zc sous la forme a-b*theta \\ \\\\\\\\\\\\\ - if( c == 0, sol = 1, + + if( !found, \\ si ce n'est pas un point trivial + a = polcoeff(liftzc,0); + b =-polcoeff(liftzc,1); + c = polcoeff(liftzc,2); + + if( c != 0, alphac = (A*b+B*c-a)*c+b^2; -if( DEBUGLEVEL_ell >= 3, print("alphac = ",alphac)); +if( DEBUGLEVEL_ell >= 3, print(" alphac = ",alphac)); r = nfsqrt(nf,norm(zc))[1]; if( alphac == 0, \\ cas particulier -if( DEBUGLEVEL_ell >= 3, print(" on continue avec 1/zc")); - sol = 1; zc = norm(zc)*(1/zc); -if( DEBUGLEVEL_ell >= 2, print(" zc = ",zc)) +if( DEBUGLEVEL_ell >= 3, print(" continuing with 1/zc")); + zc = norm(zc)*(1/zc); +if( DEBUGLEVEL_ell >= 2, print(" zc = ",zc)) , \\ Il faut resoudre une forme quadratique \\ Existence (locale = globale) d'une solution : @@ -1696,151 +1680,149 @@ if( DEBUGLEVEL_ell >= 2, print(" zc = ",zc)) if( denc != 1, cp = c*denc^2, cp = c); dena = deno(lift(alphac)); if( dena != 1, alphacp = alphac*dena^2, alphacp = alphac); -if( DEBUGLEVEL_ell >= 2, print1(" symbole de Hilbert (",alphacp,",",cp,") = ")); - sol = loc || (mynfhilbert(nf, alphacp,cp)+1); -if( DEBUGLEVEL_ell >= 2, print(sol-1)); - if( sol, - beta = A*(A*b*c+B*c^2+b^2)-C*c^2+a*b; - mattr = matid(3); - mattr[1,1] = c ;mattr[2,2] = alphac ; - mattr[3,3] = r ;mattr[2,3] = -beta; - mattr[1,2] = -(b +A*c) ;mattr[1,3] = a-B*c+A*(A*c+b); -if( DEBUGLEVEL_ell >= 2, print1(" sol de Legendre = ")); - vec = bnfqfsolve(bnf,alphacp,cp,flag3,auto); +if( DEBUGLEVEL_ell >= 2, print(" Hilbert symbol (",alphacp,",",cp,") = ")); + if( !loc && mynfhilbert(nf, alphacp,cp) < 0, +if( DEBUGLEVEL_ell >= 3, print(" no local solution")); + listnotELS = concat(listnotELS,[iwhile]); + iwhile++; + next + ); +\\ Ici on a l'existence locale + beta = A*(A*b*c+B*c^2+b^2)-C*c^2+a*b; + mattr = matid(3); + mattr[1,1] = c ;mattr[2,2] = alphac ; + mattr[3,3] = r ;mattr[2,3] = -beta; + mattr[1,2] = -(b +A*c) ;mattr[1,3] = a-B*c+A*(A*c+b); +if( DEBUGLEVEL_ell >= 2, print1(" sol of quadratic equation = ")); + vec = bnfqfsolve(bnf,alphacp,cp,flag3,aut); if( DEBUGLEVEL_ell >= 2, print(lift(vec))); - aux = vec[2]*dena; - vec[2] = vec[1];vec[1] = aux; - vec[3] = vec[3]*denc; - vec = (mattr^(-1))*vec; - vec /= content(lift(vec)); - z1 = (vec[3]*ttheta+vec[2])*ttheta+vec[1]; -if( DEBUGLEVEL_ell >= 3, print(" z1 = ",z1)); - zc *= z1^2; -if( DEBUGLEVEL_ell >= 2, print(" zc*z1^2 = ",zc)); - ) - ) + aux = vec[2]*dena; + vec[2] = vec[1];vec[1] = aux; + vec[3] = vec[3]*denc; + vec = (mattr^(-1))*vec; + vec /= content(lift(vec)); + z1 = (vec[3]*ttheta+vec[2])*ttheta+vec[1]; +if( DEBUGLEVEL_ell >= 3, print(" z1 = ",z1)); + zc *= z1^2; +if( DEBUGLEVEL_ell >= 2, print(" zc*z1^2 = ",zc)); + ) ) ); - if( !sol, - listnotELS = concat(listnotELS,[iwhile]); - iwhile++; - next - ); - \\ \\\\\\\\\\ \\ Maintenant zc est de la forme a-b*theta \\ \\\\\\\\\\ - if( !ispointtriv, + + if( !found, + +if( DEBUGLEVEL_ell >= 3, print(" zc = ",zc)); liftzc = lift(zc); -if( DEBUGLEVEL_ell >= 3, print(" zc = ",liftzc)); -if( DEBUGLEVEL_ell >= 4, print(" N(zc) = ",norm(zc))); - if( poldegree(liftzc) >= 2, error(" bnfell2descent_gen : c <> 0")); - b = -polcoeff(liftzc,1); a = polcoeff(liftzc,0); -if( DEBUGLEVEL_ell >= 4, print(" on factorise (a,b) = ",idealadd(nf,a,b))); - ff = idealfactor(nf,idealadd(nf,a,b)); -if( DEBUGLEVEL_ell >= 4, print(" ff = ",ff)); - cont = 1; - for( i = 1, #ff[,1], - cont = idealmul(nf,cont,idealpow(nf,ff[i,1],ff[i,2]\2))); - cont = idealinv(nf,cont); - cont = nfbasistoalg(nf,bnfisprincipal(bnf,cont,3)[2])^2; - a *= cont; b *= cont; zc *= cont; -if( DEBUGLEVEL_ell >= 4, print(" [a,b] = ",[a,b])); + b =-polcoeff(liftzc,1); + c = polcoeff(liftzc,2); +if( c, error("bnfell2descent_gen : c <> 0")); + +\\ remove denominators and try to simplify zc + cont = idealadd(nf,a,b); + if( cont != 1, + cont = idealfactor(nf,cont); + cont[,2] \= 2; + aux = 1; + for( i = 1, #cont[,1], +\\ ***************************************************************** +\\ aux = idealmul(nf,aux,idealpow(nf,cont[i,1],cont[i,2])) + aux = idealmul(nf,aux,idealpow(nf,idealhnf(nf,cont[i,1]),cont[i,2])) +\\ ***************************************************************** + ); + cont = nfbasistoalg(nf,bnfisprincipal(bnf,aux)[2])^2; + a /= cont; + b /= cont; + zc/= cont; + liftzc = lift(zc); +if( DEBUGLEVEL_ell >= 3, print(" new zc = ",zc)); + ); + if( nfissquare(nf,b), -if( DEBUGLEVEL_ell >= 3, print(" b est un carre")); +if( DEBUGLEVEL_ell >= 3, print(" b is a square")); point = [a/b,nfsqrt(nf,(a/b)^3+A*(a/b)^2+B*(a/b)+C)[1]]; -if( DEBUGLEVEL_ell >= 2, print("point trouve = ",point)); - listpointsmwr = concat(listpointsmwr,[point]); - m1++; - if( degre(iwhile) > lastloc, m2++); - found = ispointtriv = 1 +if( DEBUGLEVEL_ell >= 2, print(" point found = ",point)); + listpoints = concat(listpoints,[point]); + found = 1; ispointtriv = 1 ) ); \\ \\\\\\\\\\\ -\\ Construction de la quartique +\\ Construction de la quartique \\ \\\\\\\\\\\ - if( !ispointtriv, + + if( !found, \\ si ce n'est pas un point trivial r = nfsqrt(nf,norm(zc))[1]; -if( DEBUGLEVEL_ell >= 4, print(" r = ",r)); +if( DEBUGLEVEL_ell >= 4, print(" r = ",r)); c = -2*(A*b+3*a); -if( DEBUGLEVEL_ell >= 4, print(" c = ",c)); +if( DEBUGLEVEL_ell >= 4, print(" c = ",c)); d = 8*r; -if( DEBUGLEVEL_ell >= 4, print(" d = ",d)); +if( DEBUGLEVEL_ell >= 4, print(" d = ",d)); e = (A^2*b^2 - 2*A*a*b-4*B*b^2-3*a^2); -if( DEBUGLEVEL_ell >= 4, print(" e = ",e)); - polorig = b*(x^4+c*x^2+d*x+e)*unnf; -if( DEBUGLEVEL_ell >= 2, print(" quartique : (",lift(b),")*Y^2 = ",lift(polorig/b))); - list[3] = b; +if( DEBUGLEVEL_ell >= 4, print(" e = ",e)); + polorig = b*('x^4+c*'x^2+d*'x+e)*unnf; +if( DEBUGLEVEL_ell >= 2, print(" quartic: (",lift(b),")*Y^2 = ",lift(polorig/b))); pol = polorig; if( bigflag, - redq = bnfredquartique2(bnf,pol,r,a,b); -if( DEBUGLEVEL_ell >= 2, print(" reduite: Y^2 = ",lift(redq[1]))); + redq = bnfredquartique(bnf,pol,r,a,b); +if( DEBUGLEVEL_ell >= 2, print(" reduced: Y^2 = ",lift(redq[1]))); pol = redq[1]; transl = redq[2]; multip = redq[3] ); + +\\ Search for a point on the quartic point = nfratpoint(nf,pol,LIM1,1); - if( point != [], -if( DEBUGLEVEL_ell >= 2, print("point = ",point)); - m1++; + found = point != []; +\\ If no point is found, check if it is ELS + if( !found && !loc, if( bigflag, - point[1] = point[1]*multip+transl; - point[2] = nfsqrt(nf,subst(polorig,x,point[1]/point[3]))[1]); - mattr = matid(3); - mattr[1,1] = -2*b^2; mattr[1,2] = (A*b+a)*b; - mattr[1,3] = a^2+(2*B-A^2)*b^2; mattr[2,2] = -b; - mattr[2,3] = a+A*b; mattr[3,3] =r; - UVW = [point[1]^2,point[3]^2,point[1]*point[3]]~; - vec = (mattr^(-1))*UVW; - z1 = (vec[3]*ttheta+vec[2])*ttheta+vec[1]; - zc *= z1^2; - zc /= -polcoeff(lift(zc),1); -if( DEBUGLEVEL_ell >= 3, print("zc*z1^2 = ",zc)); - pointxx = polcoeff(lift(zc),0); - point2 = [ pointxx, nfsqrt(nf,subst(x^3+A*x^2+B*x+C,x,pointxx))[1]]; -if( DEBUGLEVEL_ell >= 1, print(" point trouve = ",point2)); - listpointsmwr = concat(listpointsmwr,[point2]); - if( degre(iwhile) > lastloc, m2++); - found = 1; lastloc = -1 - , - if( loc - || (!bigflag && nflocallysoluble(nf,pol,r,a,b)) - || (bigflag && nflocallysoluble(nf,pol,0,1,1)), - - if( !loc, listlistELS=concat(listELS,[iwhile])); - if( degre(iwhile) > lastloc, m2++; lastloc = degre(iwhile)); - point = nfratpoint(nf,pol,LIM3,1); - if( point != [], - m1++; - if( bigflag, - point[1] = point[1]*multip+transl; - point[2] = nfsqrt(nf,subst(polorig,x,point[1]/point[3]))[1]; - ); - mattr = matid(3); - mattr[1,1] = -2*b^2; mattr[1,2] = (A*b+a)*b; - mattr[1,3] = a^2+(2*B-A^2)*b^2; mattr[2,2] = -b; - mattr[2,3] = a+A*b; mattr[3,3] =r; - UVW = [point[1]^2,point[3]^2,point[1]*point[3]]~; - vec = (mattr^(-1))*UVW; - z1 = (vec[3]*ttheta+vec[2])*ttheta+vec[1]; - zc *= z1^2; - zc /= -polcoeff(lift(zc),1); -if( DEBUGLEVEL_ell >= 3, print(" zc*z1^2 = ",zc)); - pointxx = polcoeff(lift(zc),0); - point2 = [ pointxx, nfsqrt(nf,subst(x^3+A*x^2+B*x+C,x,pointxx))[1]]; -if( DEBUGLEVEL_ell >= 1, print(" point trouve = ",point2)); - listpointsmwr = concat(listpointsmwr,[point2]); - found = 1; lastloc = -1; - ) - , listnotELS = concat(listnotELS,[iwhile]) - ) + loc = nflocallysoluble(nf,pol,r,a,b) + , loc = nflocallysoluble(nf,pol,0,1,1) + )); + if( !loc, + listnotELS = concat(listnotELS,[iwhile]); + iwhile++; + next ) ); + +\\ If no point is found, search harder + if( !found, +if( DEBUGLEVEL_ell >= 2, print("quartic is ELS")); + point = nfratpoint(nf,pol,LIM3,1); + found = point != [] + ); + + if( found && !ispointtriv, + if( bigflag, + point[1] = point[1]*multip+transl; + point[2] = nfsqrt(nf,subst(polorig,'x,point[1]/point[3]))[1]); + mattr = matid(3); + mattr[1,1] = -2*b^2; mattr[1,2] = (A*b+a)*b; + mattr[1,3] = a^2+(2*B-A^2)*b^2; mattr[2,2] = -b; + mattr[2,3] = a+A*b; mattr[3,3] =r; + UVW = [point[1]^2,point[3]^2,point[1]*point[3]]~; + vec = (mattr^(-1))*UVW; + z1 = (vec[3]*ttheta+vec[2])*ttheta+vec[1]; + zc *= z1^2; + zc /= -polcoeff(lift(zc),1); +if( DEBUGLEVEL_ell >= 3, print(" zc*z1^2 = ",zc)); + pointxx = polcoeff(lift(zc),0); + point2 = [ pointxx, nfsqrt(nf,subst('x^3+A*'x^2+B*'x+C,'x,pointxx))[1]]; +if( DEBUGLEVEL_ell >= 1, print(" point found = ",point2)); + listpoints = concat(listpoints,[point2]); + ); + + listELS = concat(listELS,[iwhile]); + if( degre(iwhile) > lastloc, m2++; lastloc = degre(iwhile)); + if( found, + m1++; found = 0; lastloc = -1; - v = degre(iwhile); - iwhile = 1<>= 1; LS2coordtilda = vecextract(LS2coordtilda,1<<#listgen-iwhile-1); listgen = vecextract(listgen,1<<#listgen-iwhile-1); @@ -1853,56 +1835,55 @@ if( DEBUGLEVEL_ell >= 1, print(" point trouve = ",point2)); ); if( DEBUGLEVEL_ell >= 2, - print("m1 = ",m1); - print("m2 = ",m2)); + print(" m1 = ",m1); + print(" m2 = ",m2)); if( DEBUGLEVEL_ell >= 1, print("#S(E/K)[2] = ",1<= 1, print("#E(K)/2E(K) = ",1<= ",1<= ",m1)); + print("rank(E/K) >= ",m1)); rang = m1; if( (m2-m1)%2, if( DEBUGLEVEL_ell >= 1, - print(" III devrait etre un carre, donc "); + print(" III should be a square, hence "); if( m2-m1 > 1, print("#E(K)/2E(K) >= ",1<<(m1+1)); print("#III(E/K)[2] <= ",1<<(m2-m1-1)); - print("rang(E/K) >= ",m1+1) + print("rank(E/K) >= ",m1+1) , print("#E(K)/2E(K) = ",1<<(m1+1)); print("#III(E/K)[2] = 1"); - print("rang(E/K) = ",m1+1))); + print("rank(E/K) = ",m1+1))); rang = m1+1) ); -if( DEBUGLEVEL_ell >= 1, print("listpointsmwr = ",listpointsmwr)); - for( i = 1, #listpointsmwr, - if( #listpointsmwr[i] == 3, - listpointsmwr[i] = vecextract(listpointsmwr[i],3)); - if( !ellisoncurve(ellnf,listpointsmwr[i]), - error("bnfell2descent : MAUVAIS POINT "))); -if( DEBUGLEVEL_ell >= 4, print("fin de bnfell2descent_gen")); - return([rang,m2,listpointsmwr]); + +if( DEBUGLEVEL_ell >= 1, print(" listpoints = ",listpoints)); + for( i = 1, #listpoints, + if( #listpoints[i] == 3, + listpoints[i] = vecextract(listpoints[i],3)); + if( !ellisoncurve(ellnf,listpoints[i]), + error("bnfell2descent: WRONG POINT "))); +if( DEBUGLEVEL_ell >= 4, print(" end of bnfell2descent_gen")); + return([rang,m2,listpoints]); } -if( DEBUGLEVEL_ell >= 4, print("bnfellrank")); -{ -bnfellrank(bnf,ell,help=[],bigflag=1,flag3=1) = +{bnfellrank(bnf,ell,help=[],bigflag=1,flag3=1) = \\ Algorithme de la 2-descente sur la courbe elliptique ell. \\ help est une liste de points connus sur ell. \\ attention bnf a un polynome en y. \\ si bigflag !=0, on reduit les quartiques \\ si flag3 != 0, on utilise bnfqfsolve2 -local(urst,urst1,den,factden,eqtheta,rnfeq,bbnf,ext,rang); +local(urst,urst1,den,factden,eqtheta,rnfeq,bbnf,ext,rang,f); -if( DEBUGLEVEL_ell >= 3, print("entree dans bnfellrank")); +if( DEBUGLEVEL_ell >= 3, print(" starting bnfellrank")); if( #ell <= 5, ell = ellinit(ell,1)); \\ removes the coefficients a1 and a3 @@ -1930,27 +1911,27 @@ if( DEBUGLEVEL_ell >= 3, print("entree dans bnfellrank")); \\ choix de l'algorithme suivant la 2-torsion ell *= Mod(1,bnf.pol); eqtheta = Pol([1,ell.a2,ell.a4,ell.a6]); -if( DEBUGLEVEL_ell >= 1, print("courbe elliptique : Y^2 = ",eqtheta)); +if( DEBUGLEVEL_ell >= 1, print(" elliptic curve: Y^2 = ",eqtheta)); f = nfpolratroots(bnf,eqtheta); if( #f == 0, \\ cas 1: 2-torsion triviale rnfeq = rnfequation(bnf,eqtheta,1); - urst1 = [1,-rnfeq[3]*Mod(y,bnf.pol),0,0]; - if( rnfeq[3] != 0, + urst1 = [1,-rnfeq[3]*Mod('y,bnf.pol),0,0]; + if( rnfeq[3] != 0, ell = ellchangecurve(ell,urst1); urst = ellcomposeurst(urst,urst1); - eqtheta = subst(eqtheta,x,x-rnfeq[3]*Mod(y,bnf.pol)); + eqtheta = subst(eqtheta,'x,'x-rnfeq[3]*Mod('y,bnf.pol)); rnfeq = rnfequation(bnf,eqtheta,1); -if( DEBUGLEVEL_ell >= 2, print("translation : on travaille avec Y^2 = ",eqtheta)); +if( DEBUGLEVEL_ell >= 2, print(" translation: working with Y^2 = ",eqtheta)); ); -if( DEBUGLEVEL_ell >= 3, print1("bbnfinit ")); +if( DEBUGLEVEL_ell >= 3, print1(" bbnfinit ")); bbnf = bnfinit(rnfeq[1],1); -if( DEBUGLEVEL_ell >= 3, print("done")); +if( DEBUGLEVEL_ell >= 3, print(" done")); ext = [eqtheta, rnfeq, bbnf]; rang = bnfell2descent_gen(bnf,ell,ext,help,bigflag,flag3) , if( #f == 1, \\ cas 2: 2-torsion = Z/2Z - if( f[1] != 0, + if( f[1] != 0, urst1 = [1,f[1],0,0]; ell = ellchangecurve(ell,urst1); urst = ellcomposeurst(urst,urst1) @@ -1959,28 +1940,26 @@ if( DEBUGLEVEL_ell >= 3, print("done")); , \\ cas 3: 2-torsion = Z/2Z*Z/2Z rang = bnfell2descent_complete(bnf,f[1],f[2],f[3],flag3) )); - - rang[3] = ellchangepointinverse(rang[3],urst); -if( DEBUGLEVEL_ell >= 3, print("fin de bnfellrank")); + + rang[3] = ellchangepoint(rang[3],ellinverturst(urst)); +if( DEBUGLEVEL_ell >= 3, print(" end of bnfellrank")); return(rang); } -if( DEBUGLEVEL_ell >= 4, print("bnfell2descent_complete")); -{ -bnfell2descent_complete(bnf,e1,e2,e3,flag3=1,auto=[y]) = +{bnfell2descent_complete(bnf,e1,e2,e3,flag3=1,aut=['y]) = \\ calcul du rang d'une courbe elliptique \\ par la methode de 2-descente complete. \\ Y^2 = (x-e1)*(x-e2)*(x-e3); \\ en suivant la methode decrite par J.Silverman \\ si flag3 ==1 alors on utilise bnfqfsolve2 (equation aux normes) -\\ pour resoudre Legendre -\\ on pourra alors utiliser auto=nfgaloisconj(bnf.pol) +\\ pour resoudre Legendre +\\ on pourra alors utiliser aut=nfgaloisconj(bnf.pol) \\ e1, e2 et e3 sont des entiers algebriques de bnf. -local(KS2prod,oddclass,KS2gen,i,vect,selmer,rang,X,Y,b1,b2,vec,z1,z2,d31,quart0,quart,cont,fa,point,solx,soly,listepoints); +local(KS2prod,oddclass,KS2gen,vect,selmer,rang,b1,b2,vec,z1,z2,d31,quart0,quart,cont,fa,point,solx,soly,listepoints,strange); -if( DEBUGLEVEL_ell >= 2, print("Algorithme de la 2-descente complete")); +if( DEBUGLEVEL_ell >= 2, print(" Algorithm of complete 2-descent")); \\ calcul de K(S,2) @@ -1993,13 +1972,13 @@ if( DEBUGLEVEL_ell >= 2, print("Algorithme de la 2-descente complete")); KS2prod = idealmul(bnf,KS2prod,(KS2gen[5][3][1]))); ); KS2gen = KS2gen[1]; -\\ A CHANGER : KS2gen = matbasistoalg(bnf,KS2gen); for( i = 1, #KS2gen, KS2gen[i] = nfbasistoalg(bnf, KS2gen[i])); KS2gen = concat(Mod(lift(bnf.tufu),bnf.pol),KS2gen); if( DEBUGLEVEL_ell >= 2, - print("#K(S,2)gen = ",#KS2gen); - print("K(S,2)gen = ",KS2gen)); + print(" #K(S,2)gen = ",#KS2gen); + print(" K(S,2)gen = ",KS2gen) +); \\ parcours de K(S,2)*K(S,2) @@ -2013,24 +1992,24 @@ if( DEBUGLEVEL_ell >= 2, forvec( Y = vect, b2 = prod( i = 1, #KS2gen, KS2gen[i]^Y[i]); -if( DEBUGLEVEL_ell >= 3, print("[b1,b2] = ",lift([b1,b2]))); +if( DEBUGLEVEL_ell >= 3, print(" [b1,b2] = ",lift([b1,b2]))); \\ points triviaux provenant de la 2-torsion - if( b1==1 && b2==1, -if( DEBUGLEVEL_ell >= 2, print(" point trivial [0]")); + if( b1==1 && b2==1, +if( DEBUGLEVEL_ell >= 2, print(" trivial point [0]")); selmer++; rang++; next); if( nfissquare(bnf.nf,(e2-e1)*b1) && nfissquare(bnf.nf,(e2-e3)*(e2-e1)*b2), -if( DEBUGLEVEL_ell >= 2, print(" point trivial [e2,0]")); +if( DEBUGLEVEL_ell >= 2, print(" trivial point [e2,0]")); selmer++; rang++; next); if( nfissquare(bnf.nf,(e1-e2)*b2) && nfissquare(bnf.nf,(e1-e3)*(e1-e2)*b1), -if( DEBUGLEVEL_ell >= 2, print(" point trivial [e1,0]")); +if( DEBUGLEVEL_ell >= 2, print(" trivial point [e1,0]")); selmer++; rang++; next); if( nfissquare(bnf.nf,(e3-e1)*b1) && nfissquare(bnf.nf,(e3-e2)*b2), -if( DEBUGLEVEL_ell >= 2, print(" point trivial [e3,0]")); +if( DEBUGLEVEL_ell >= 2, print(" trivial point [e3,0]")); selmer++; rang++; next); \\ premier critere local : sur les formes quadratiques @@ -2039,58 +2018,58 @@ if( DEBUGLEVEL_ell >= 2, print(" point trivial [e3,0]")); || mynfhilbert(bnf.nf,b2,b1*(e3-e1)) < 0 || mynfhilbert(bnf.nf,b1,b2*(e3-e2)) < 0 , -if( DEBUGLEVEL_ell >= 3, print("non ELS")); +if( DEBUGLEVEL_ell >= 3, print(" not ELS")); next); -if( DEBUGLEVEL_ell >= 2, print("[b1,b2] = ",lift([b1,b2]))); -if( DEBUGLEVEL_ell >= 2, print("qf loc soluble")); +if( DEBUGLEVEL_ell >= 2, print(" [b1,b2] = ",lift([b1,b2]))); +if( DEBUGLEVEL_ell >= 2, print(" quadratic forms locally soluble")); \\ solution de la premiere forme quadratique if( b1 != b2, vec = bnfqfsolve(bnf,b1*b2,b1*(e2-e1),flag3); -if( DEBUGLEVEL_ell >= 3, print("sol part = ",vec)); - if( vec[3] == 0, error("bnfell2descent_complete : BUG !!! : vec[3]=0 ")); +if( DEBUGLEVEL_ell >= 3, print(" sol part = ",vec)); + if( vec[3] == 0, error("bnfell2descent_complete: BUG !!! : vec[3]=0 ")); z1 = vec[1]/vec[3]/b1; z2 = vec[2]/vec[3] , z1 = (1+(e2-e1)/b1)/2; z2 = z1-1 ); d31 = e3-e1; - quart0 = b2^2*(z1^2*b1 - d31)*x^4 - 4*z1*b2^2*z2*b1*x^3 - + 2*b1*b2*(z1^2*b1 + 2*b2*z2^2 + d31)*x^2 - 4*z1*b2*z2*b1^2*x + quart0 = b2^2*(z1^2*b1 - d31)*'x^4 - 4*z1*b2^2*z2*b1*'x^3 + + 2*b1*b2*(z1^2*b1 + 2*b2*z2^2 + d31)*'x^2 - 4*z1*b2*z2*b1^2*'x + b1^2*(z1^2*b1 - d31); quart = quart0*b1*b2; -if( DEBUGLEVEL_ell >= 4, print("quart = ",quart)); +if( DEBUGLEVEL_ell >= 4, print(" quart = ",quart)); quart *= denominator(simplify(content(quart)))^2; cont = simplify(content(lift(quart))); fa = factor(cont); for( i = 1, #fa[,1], quart /= fa[i,1]^(2*(fa[i,2]\2))); -if( DEBUGLEVEL_ell >= 3, print("quart red = ",quart)); +if( DEBUGLEVEL_ell >= 3, print(" quartic reduced = ",quart)); \\ la quartique est-elle localement soluble ? - + if( !nflocallysoluble(bnf.nf,quart), -if( DEBUGLEVEL_ell >= 2, print(" quartique non ELS ")); +if( DEBUGLEVEL_ell >= 2, print(" quartic not ELS")); next); selmer++; \\ recherche de points sur la quartique. point = nfratpoint(bnf.nf,quart,LIM3,1); - if( point != [], -if( DEBUGLEVEL_ell >= 2, print("point trouve sur la quartique !!")); -if( DEBUGLEVEL_ell >= 3, print(point)); - if( point[3], + if( point != [], +if( DEBUGLEVEL_ell >= 2, print(" point found on the quartic !!")); +if( DEBUGLEVEL_ell >= 3, print(" ",point)); + if( point[3], point /= point[3]; z1 = (2*b2*point[1]*z2-z1*(b1+b2*point[1]^2))/(b1-b2*point[1]^2); solx = b1*z1^2+e1; soly = nfsqrt(bnf.nf,(solx-e1)*(solx-e2)*(solx-e3))[1]; listepoints = concat(listepoints,[[solx,soly]]); -if( DEBUGLEVEL_ell >= 1, print("point sur la courbe elliptique =",[solx,soly])) +if( DEBUGLEVEL_ell >= 1, print(" point on the elliptic curve =",[solx,soly])) ); rang++ , -if( DEBUGLEVEL_ell >= 2, print("aucun point trouve sur la quartique")) +if( DEBUGLEVEL_ell >= 2, print(" no point found on the quartic")) ) ) ); @@ -2111,10 +2090,22 @@ if( DEBUGLEVEL_ell >= 1, selmer = valuation(selmer,2); if( DEBUGLEVEL_ell >= 1, if( strange, - print(selmer-2," >= rang >= ",rang) -, print("rang = ",rang)); + print(selmer-2," >= rank >= ",rang) +, print("rank = ",rang)); if( rang, print("points = ",listepoints)); ); return([rang,selmer,listepoints]); } + +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ +\\ HELP MESSAGES \\ +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ + +{ + addhelp(bnfellrank, + "bnfellrank(K,E,help=[]): E is a 5-component vector defining an elliptic curve defined over the number field K (output by bnfinit()). Returns a vector [r,s,v], where r is a lower bound for the rank of E(K), s is the rank of its 2-Selmer group and v is a list of independant points in E(K)/2E(K). If help is a vector of nontrivial points on E(K), the result might be faster. See also ?default_ell"); +\\ others + addhelp(default_ell, + "default_ell(DEBUGLEVEL_ell, LIM1, LIM3, LIMTRIV, MAXPROB, LIMBIGPRIME): output/set the value of the global variables used for ellrank() and other related functions. DEBUGLEVEL_ell: 0-5 : choose the quantity of information printed during the computation (default=0: print nothing); LIM1 (resp LIM3): search limit for easy (resp hard) points on quartics; LIMTRIV: search limit for trivial points on elliptic curves; MAXPROB, LIMBIGPRIME: technical."); +} diff --git a/src/ext/pari/simon/ellQ.gp b/src/ext/pari/simon/ellQ.gp index 3c147ef9898..c114534ff13 100644 --- a/src/ext/pari/simon/ellQ.gp +++ b/src/ext/pari/simon/ellQ.gp @@ -1,5 +1,5 @@ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ -\\ Copyright (C) 2008 Denis Simon +\\ Copyright (C) 2014 Denis Simon \\ \\ Distributed under the terms of the GNU General Public License (GPL) \\ @@ -13,496 +13,657 @@ \\ http://www.gnu.org/licenses/ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ -\\ -\\ Auteur: -\\ Denis SIMON -> simon@math.unicaen.fr -\\ adresse du fichier: -\\ www.math.unicaen.fr/~simon/ellQ.gp -\\ -\\ ********************************************* -\\ * VERSION 29/04/2008 * -\\ ********************************************* -\\ -\\ Programme de calcul du rang des courbes elliptiques sur Q. -\\ langage: GP -\\ pour l'utiliser, lancer gp, puis taper -\\ \r ellQ.gp -\\ -\\ Ce programme utilise le module de resolution des formes quadratiques -\\ situe a l'adresse -\\ www.math.unicaen.fr/~simon/qfsolve.gp -\\ Il faut donc aussi taper: -\\ \r qfsolve.gp -\\ -\\ Explications succintes : -\\ La fonction ellrank() accepte toutes les courbes sous la forme -\\ [a1,a2,a3,a4,a6] -\\ Les coefficients peuvent etre entiers ou non. -\\ L'algorithme utilise est celui de la 2-descente. -\\ La 2-torsion peut etre quelconque. -\\ Il suffit de taper : -\\ -\\ gp > ell = [a1,a2,a3,a4,a6]; -\\ gp > ellrank(ell) -\\ -\\ Retourne un vecteur [r,s,vec] -\\ ou r est le rang probable (c'est toujours une minoration du rang), -\\ s est le 2-rang du groupe de Selmer, -\\ vec est une liste de points independants dans E(Q)/2E(Q). -\\ -\\ Courbes de la forme: k*y^2 = x^3+A*x^2+B*x+C -\\ sans 2-torsion, A,B,C entiers. -\\ gp > bnf = bnfinit(x^3+A*x^2+B*x+C); -\\ gp > ell = ellinit([0,A,0,B,C],1); -\\ gp > rank = ell2descent_gen(ell,bnf,k); -\\ -\\ Courbes avec #E[2](Q) >= 2: -\\ ell doit etre sous la forme -\\ y^2 = x^3 + A*^2 + B*x -\\ avec A et B entiers. -\\ gp > ell = [0,A,0,B,0] -\\ gp > ell2descent_viaisog(ell) -\\ = algorithme de la 2-descente par isogenies -\\ Attention A et B doivent etre entiers -\\ -\\ Courbes avec #E[2](Q) = 4: y^2 = (x-e1)*(x-e2)*(x-e3) -\\ gp > ell2descent_complete(e1,e2,e3) -\\ = algorithme de la 2-descente complete -\\ Attention: les ei doivent etre entiers. -\\ -\\ -\\ On peut avoir plus ou moins de details de calculs avec -\\ DEBUGLEVEL_ell = 0; -\\ DEBUGLEVEL_ell = 1; 2; 3;... -\\ -\\ -\\ +/* + Auteur : + Denis SIMON -> simon@math.unicaen.fr + adresse du fichier : + www.math.unicaen.fr/~simon/ellQ.gp + + ********************************************* + * VERSION 13/01/2014 * + ********************************************* + + + \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ + \\ English \\ + \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ + + This package provides functions to compute the rank of elliptic + curves over Q using 2-descent. + This package requires the other package qfsolve.gp downloadable at + www.math.unicaen.fr/~simon/qfsolve.gp + It also requires the package ellcommon.gp downloadable at + www.math.unicaen.fr/~simon/ellcommon.gp + + They can be run under GP by the commands + gp > \r qfsolve.gp + gp > \r ellcommon.gp + gp > \r ellQ.gp + + The main function is ellrank(), which takes as an argument + any elliptic curve in the form [a1,a2,a3,a4,a6] + the result is a vector [r,s,v], where + r is a lower bound for the rank, + s is the rank of the 2-Selmer group + v is a set of independant points in E(Q)/2E(Q). + + Example: + + gp > ell = [1,2,3,4,5]; + gp > ellrank(ell) + %1 = [1, 1, [[1,2]] + In this example, the rank is exactly 1, and [1,2] has infinite order. + + more details on the computations may be obtained by setting + DEBUGLEVEL_ell = 1 (the higher value, the more details) + + Other functions: + + ell2descent_complete, ell2descent_gen, ell2descent_viaisog, + ellhalf, ellredgen, ellsort, elltors2, elltorseven, + locallysoluble, ratpoint, redquartic, + bnfpSelmer, reducemodsquares + + Quick information is obtained by typing + gp > ?NameOfTheFunction + + \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ + \\ Comment utiliser ce programme ? \\ + \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ + + Ce module contient des fonctions pour calculer le rang des courbes + elliptiques sur Q, en utilisant la 2-descente. + langage : GP + + Ce module utilise les modules complementaires suivants : + qfsolve.gp + ellcommon.gp + qui sont disponibles a l'adresse + www.math.unicaen.fr/~simon/qfsolve.gp + www.math.unicaen.fr/~simon/ellcommon.gp + + Pour l'utiliser, lancer gp, puis taper + \r qfsolve.gp + \r ellcommon.gp + \r ellQ.gp + + \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ + \\ Description des principales fonctions \\ + \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ + + Explications succintes : + La fonction ellrank() accepte toutes les courbes sous la forme + [a1,a2,a3,a4,a6] + Les coefficients peuvent etre entiers ou non. + L'algorithme utilise est celui de la 2-descente. + La 2-torsion peut etre quelconque. + Il suffit de taper : + + gp > ell = [a1,a2,a3,a4,a6]; + gp > ellrank(ell) + + Retourne un vecteur [r,s,v] ou + r est le rang probable (c'est toujours une minoration du rang), + s est le 2-rang du groupe de Selmer, + v est une liste de points independants dans E(Q)/2E(Q). + + Exemple : + + gp > ell = [1,2,3,4,5]; + gp > ellrank(ell) + %1 = [1, 1, [[1,2]] + Ici, le rang est exactement 1, et le point [1,2] est d'ordre infini. + + Courbes de la forme : k*y^2 = x^3+A*x^2+B*x+C + sans 2-torsion, A,B,C entiers. + gp > bnf = bnfinit(x^3+A*x^2+B*x+C); + gp > ell = ellinit([0,A,0,B,C],1); + gp > rank = ell2descent_gen(ell,bnf,k); + + Courbes avec #E[2](Q) >= 2 : + ell doit etre sous la forme + y^2 = x^3 + A*x^2 + B*x + avec A et B entiers. + gp > ell = [0,A,0,B,0] + gp > ell2descent_viaisog(ell) + = algorithme de la 2-descente par isogenies + Attention A et B doivent etre entiers + + Courbes avec #E[2](Q) = 4 : y^2 = (x-e1)*(x-e2)*(x-e3) + gp > ell2descent_complete(e1,e2,e3) + = algorithme de la 2-descente complete + Attention : les ei doivent etre entiers. + + \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ + \\ Autres fonctions utiles \\ + \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ + + elltors2(E) : determine le groupe E[2](Q) + elltorseven(E) : determine le groupe E[2^*](Q) + ellhalf(E,P) : liste les points Q tels que 2Q = P + ellredgen(E,v) : reduction des points de v sur E + + locallysoluble(pol): teste si y^2=pol(x) est ELS + ratpoint(pol,lim): cherche un point sur y^2=pol(x) + redquartic(pol): reduction de la quartique pol + + + Aide en ligne : + ?NomDeLaFonction + + + \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ + \\ Affichage des calculs \\ + \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ + + On peut avoir plus ou moins de details de calculs avec + DEBUGLEVEL_ell = 0; + DEBUGLEVEL_ell = 1; 2; 3;... + +*/ { \\ -\\ Variables globales usuelles +\\ Usual global variables \\ - DEBUGLEVEL_ell = 1; \\ pour avoir plus ou moins de details - LIM1 = 5; \\ limite des points triviaux sur les quartiques - LIM3 = 50; \\ limite des points sur les quartiques ELS - LIMTRIV = 50; \\ limite des points triviaux sur la courbe elliptique +global(DEBUGLEVEL_ell, LIM1, LIM3, LIMTRIV, ELLREDGENFLAG, COMPLETE):small; + + DEBUGLEVEL_ell = 0; \\ From 0 to 5: choose a higher value to have + \\ more details printed. + LIM1 = 5; \\ Limit for the search of trivial points on quartics + LIM3 = 50; \\ Limit for the search of points on ELS quartics + LIMTRIV = 3; \\ Limit for the search of trivial points on the elliptic curve + ELLREDGENFLAG = 1; \\ to reduce the generators at the end + COMPLETE = 0; \\ Use Complete 2-descent when full 2-torsion, + \\ otherwise 2-descent via isogenies. \\ -\\ Variables globales techniques +\\ Technical global variables \\ +global(MAXPROB, LIMBIGPRIME):small; + MAXPROB = 20; - LIMBIGPRIME = 30; \\ pour distinguer un petit nombre premier d'un grand - \\ utilise un test probabiliste pour les grands - \\ si LIMBIGPRIME = 0, n'utilise aucun test probabiliste - ELLREDGENFLAG = 1;\\ pour reduire les genereteurs a la fin de l'algorithme + LIMBIGPRIME = 30; \\ for primes larger than this limit: use a probabilistic test + \\ LIMBIGPRIME = 0 means: only deterministic tests } -\\ -\\ Programmes -\\ +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ +\\ SCRIPT \\ +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ -\\ -\\ Fonctions communes ell.gp et ellQ.gp -\\ -{ -ellinverturst(urst) = -local(u = urst[1], r = urst[2], s = urst[3], t = urst[4]); - [1/u,-r/u^2,-s/u,(r*s-t)/u^3]; -} -{ -ellchangecurveinverse(ell,v) = ellchangecurve(ell,ellinverturst(v)); -} -{ -ellchangepointinverse(pt,v) = ellchangepoint(pt,ellinverturst(v)); -} -{ -ellcomposeurst(urst1,urst2) = -local(u1 = urst1[1], r1 = urst1[2], s1 = urst1[3], t1 = urst1[4], - u2 = urst2[1], r2 = urst2[2], s2 = urst2[3], t2 = urst2[4]); - [u1*u2,u1^2*r2+r1,u1*s2+s1,u1^3*t2+s1*u1^2*r2+t1]; -} -{ -ellinverturst(urst) = -local(u = urst[1], r = urst[2], s = urst[3], t = urst[4]); - [1/u,-r/u^2,-s/u,(r*s-t)/u^3]; -} -{ -ellchangecurveinverse(ell,v) = ellchangecurve(ell,ellinverturst(v)); -} -{ -ellchangepointinverse(pt,v) = ellchangepoint(pt,ellinverturst(v)); -} -{ -ellcomposeurst(urst1,urst2) = -local(u1 = urst1[1], r1 = urst1[2], s1 = urst1[3], t1 = urst1[4], - u2 = urst2[1], r2 = urst2[2], s2 = urst2[3], t2 = urst2[4]); - [u1*u2,u1^2*r2+r1,u1*s2+s1,u1^3*t2+s1*u1^2*r2+t1]; -} -{ -polratroots(pol) = -local(f,ans); - f = factor(pol)[,1]; - ans = []; - for( j = 1, #f, - if( poldegree(f[j]) == 1, - ans = concat(ans,[-polcoeff(f[j],0)/polcoeff(f[j],1)]))); - return(ans); -} -if( DEBUGLEVEL_ell >= 4, print("mysubst")); -{ -mysubst(polsu,subsx) = - if( type(lift(polsu)) == "t_POL", - return(simplify(subst(lift(polsu),variable(lift(polsu)),subsx))) - , return(simplify(lift(polsu)))); -} -if( DEBUGLEVEL_ell >= 4, print("degre")); -{ -degre(idegre) = -local(ideg,jdeg); +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ +\\ MANIPULATION OF GLOBAL VARIABLES \\ +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ - ideg = idegre; jdeg = 0; - while( ideg >>= 1, jdeg++); - return(jdeg); -} -if( DEBUGLEVEL_ell >= 4, print("nfissquare")); -{ -nfissquare(nf, a) = #nfsqrt(nf,a) > 0; -} -if( DEBUGLEVEL_ell >= 4, print("nfsqrt")); -{ -nfsqrt( nf, a) = -\\ si a est un carre, renvoie [sqrt(a)], sinon []. -local(alift,ta,res,pfact,r1,py); - -if( DEBUGLEVEL_ell >= 5, print("entree dans nfsqrt ",a)); - if( a==0 || a==1, -if( DEBUGLEVEL_ell >= 5, print("fin de nfsqrt")); - return([a])); - - alift = lift(a); - ta = type(a); - if( !poldegree(alift), alift = polcoeff(alift,0)); - - if( type(alift) != "t_POL", - if( issquare(alift), -if( DEBUGLEVEL_ell >= 5, print("fin de nfsqrt")); - return([sqrtrat(alift)]))); - - if( poldegree(nf.pol) <= 1, -if( DEBUGLEVEL_ell >= 5, print("fin de nfsqrt")); - return([])); - if( ta == "t_POL", a = Mod(a,nf.pol)); - -\\ tous les plgements reels doivent etre >0 -\\ - r1 = nf.sign[1]; - for( i = 1, r1, - py = mysubst(alift,nf.roots[i]); - if( sign(py) < 0, -if( DEBUGLEVEL_ell >= 5, print("fin de nfsqrt")); - return([]))); -\\ factorisation sur K du polynome X^2-a : - if( variable(nf.pol) == x, - py = subst(nf.pol,x,y); - pfact = lift(factornf(x^2-mysubst(alift,Mod(y,py)),py)[1,1]) - , - pfact = lift(factornf(x^2-a,nf.pol)[1,1])); - if( poldegree(pfact) == 2, -if( DEBUGLEVEL_ell >= 5, print("fin de nfsqrt")); - return([])); -if( DEBUGLEVEL_ell >= 5, print("fin de nfsqrt")); - return([subst(polcoeff(pfact,0),y,Mod(variable(nf.pol),nf.pol))]); -} -if( DEBUGLEVEL_ell >= 4, print("sqrtrat")); -{ -sqrtrat(a) = - sqrtint(numerator(a))/sqrtint(denominator(a)); -} -\\ -\\ Fonctions propres a ellQ.gp -\\ +{default_ellQ( + DEBUGLEVEL_ell_val:small = 0, + LIM1_val:small = 5, + LIM3_val:small = 50, + LIMTRIV_val:small = 3, + ELLREDGENFLAG_val:small = 1, + COMPLETE_val:small = 0, + MAXPROB_val:small = 20, + LIMBIGPRIME_val:small = 30 + ) = -if( DEBUGLEVEL_ell >= 4, print("ellhalf")); -{ -ellhalf(ell,P)= -\\ renvoie tous les points Q sur ell tels que 2Q = P. -local(pol2,ratroots,half,x2,y2,P2); + DEBUGLEVEL_ell = DEBUGLEVEL_ell_val; + print(" DEBUGLEVEL_ell = ",DEBUGLEVEL_ell); - if(#ell < 13, ell=ellinit(ell,1)); + LIM1 = LIM1_val; + print(" LIM1 = ",LIM1); - pol2 = Pol([4,ell.b2,2*ell.b4,ell.b6]); \\ polynome de 2-division + LIM3 = LIM3_val; + print(" LIM3 = ",LIM3); - if( P == [0], - ratroots = polratroots(pol2); - half = vector(#ratroots,i,[ratroots[i],ellordinate(ell,ratroots[i])[1]]); - half = concat( [[0]], half); - return(half) - ); + LIMTRIV = LIMTRIV_val; + print(" LIMTRIV = ",LIMTRIV); - x2=Pol([1,0,-ell.b4,-2*ell.b6,-ell.b8]); \\ x(2P) = x2/pol2 + ELLREDGENFLAG = ELLREDGENFLAG_val; + print(" ELLREDGENFLAG = ",ELLREDGENFLAG); - half = []; - ratroots = polratroots(x2-P[1]*pol2); - if( #ratroots == 0, return(half)); - for( i = 1, #ratroots, - y2 = ellordinate(ell,ratroots[i]); - for( j = 1, #y2, - P2 = [ratroots[i],y2[j]]; - if( ellpow(ell,P2,2) == P, half = concat(half,[P2])) - ) - ); - return(half); -} -if( DEBUGLEVEL_ell >= 4, print("elltors2")); -{ -elltors2(ell)= -\\ Calcule le sous-groupe de 2-torsion de la courbe elliptique ell. -local(pol2,ratroots,tors2); + COMPLETE = COMPLETE_val; + print(" COMPLETE = ",COMPLETE); -if( DEBUGLEVEL_ell >= 4, print("calcul de la 2-torsion")); - if(#ell < 13, ell=ellinit(ell,1)); - tors2 = ellhalf(ell,[0]); - if( #tors2 == 1, - tors2 = [1, [], []], - if( #tors2 == 2, - tors2 = [2, [2], [tors2[2]]] - , tors2 = [4, [2,2], [tors2[2],tors2[3]]] - )); -if( DEBUGLEVEL_ell >= 4, print("E[2] = ",tors2)); - return(tors2); + MAXPROB = MAXPROB_val; + print(" MAXPROB = ",MAXPROB); + + LIMBIGPRIME = LIMBIGPRIME_val; + print(" LIMBIGPRIME = ",LIMBIGPRIME); } -if( DEBUGLEVEL_ell >= 4, print("elltorseven")); -{ -elltorseven(ell)= -\\ Calcule le 2-Sylow sous-groupe de torsion de la courbe elliptique ell. -local(torseven,P2); -if( DEBUGLEVEL_ell >= 4, print("calcul de la 2^n-torsion")); - if(#ell < 13, ell=ellinit(ell,1)); - torseven = elltors2(ell); +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ +\\ FUNCTIONS FOR POLYNOMIALS \\ +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ - while( torseven[1] != 1, - P2 = ellhalf(ell,torseven[3][1]); - if( #P2 > 0, - torseven[1] *= 2; - torseven[2][1] *= 2; - torseven[3][1] = P2[1]; - next - ); - if( #torseven[3] == 1, break()); - - P2 = ellhalf(ell,torseven[3][2]); - if( #P2 > 0, - torseven[1] *= 2; - torseven[2][2] *= 2; - torseven[3][2] = P2[1]; - next - ); - P2 = ellhalf(ell,elladd(ell,torseven[3][1],torseven[3][2])); - if( #P2 > 0, - torseven[1] *= 2; - torseven[2][1] *= 2; - torseven[3][1] = P2[1]; - next - ); - break() - ); +{ratpoint( pol, lim:small = 1, singlepoint = 1, infinity = 1) = +\\ Search for points on y^2=pol(x). +\\ The coeff of pol must be integers. +\\ If singlepoint >= 1, stop after a first point is found. -if( DEBUGLEVEL_ell >= 4, print("E[2^n] = ",torseven)); - return(torseven); -} -if( DEBUGLEVEL_ell >= 4, print("polratroots")); -{ -polratroots(pol) = -local(f,ans); - f = factor(pol)[,1]; - ans=[]; - for( j = 1, #f, - if( poldegree(f[j]) == 1, - ans = concat(ans,[-polcoeff(f[j],0)/polcoeff(f[j],1)]))); - return(ans); -} -if( DEBUGLEVEL_ell >= 4, print("ratpoint")); -{ -ratpoint(pol,lim=1,singlepoint=1,tryhard=0) = -\\ Recherche de points sur y^2=pol(x). -\\ Les coeff de pol sont entiers. -\\ Si singlepoint >= 1, cherche un seul point, sinon plusieurs. -\\ Si tryhard == 1, on essaye une autre strategie quand pol est imprimitif. +my(listpoints,point1,odd,deg4,pol16,tab16,pol9,tab9,pol5,tab5,pol0,vecz,vecx,lead,zz,xx,evpol,iz,factpol,deg,vz,epsmax); -local(listpoints,point1,odd,deg4,pol16,tab16,pol9,tab9,pol5,tab5,pol0,vecz,vecx,lead,zz,xx,x16,x9,x5,evpol,ix,iz,K,factK,e,cont,ind,p,sol,factpol,r,M,U); +if( DEBUGLEVEL_ell >= 4, + print(" Starting ratpoint with pol = ",pol); + print(" lim = ",lim);); -if( DEBUGLEVEL_ell >= 4, print("entree dans ratpoint avec pol = ",pol); print("lim = ",lim);); if( !singlepoint, listpoints = []); point1 = []; -\\ cas triviaux - if( issquare(pollead(pol)), +\\ +\\ trivial solutions +\\ + +\\ the leading coeff is a square + if( infinity && issquare(pollead(pol)), point1 = [ 1, sqrtrat(pollead(pol)), 0]; -if( DEBUGLEVEL_ell >= 3, print("solution triviale: a est un carre")); +if( DEBUGLEVEL_ell >= 3, print(" trivial solution: lead(pol) is a square")); if( singlepoint, -if( DEBUGLEVEL_ell >= 4, print("fin de ratpoint")); +if( DEBUGLEVEL_ell >= 4, print(" end of ratpoint")); return(point1)); listpoints = concat(listpoints,[point1])); + +\\ the constant coeff is a square if( issquare(polcoeff(pol,0)), point1 = [ 0, sqrtrat(polcoeff(pol,0)) ]; -if( DEBUGLEVEL_ell >= 3, print("solution triviale: e est un carre")); +if( DEBUGLEVEL_ell >= 3, print(" trivial solution: pol(0) is a square")); if( singlepoint, -if( DEBUGLEVEL_ell >= 4, print("fin de ratpoint")); +if( DEBUGLEVEL_ell >= 4, print(" end of ratpoint")); return(point1)); listpoints = concat(listpoints,[point1])); - odd = poldegree(pol)%2; - deg4 = poldegree(pol) == 4; -\\ initialisation du crible modulo 16, 9 et 5 +\\ roots of pol ? + factpol = nfroots(,pol); + if( #factpol, +if( DEBUGLEVEL_ell >= 3, print(" trivial solution: roots of pol",factpol)); + if( singlepoint, +if( DEBUGLEVEL_ell >= 4, print(" end of ratpoint")); + return([factpol[1],0])); + listpoints = concat(listpoints,vector(#factpol,i,[factpol[i],0])) + ); + +\\ +\\ Sieve +\\ + +\\ initialisation of the sieve modulo 16, 9 and 5 +\\ used only with even degree when lim is large + + deg = poldegree(pol); + odd = deg%2; + deg4 = ( !odd && lim > 20); if( deg4, + pol16 = (Vec(pol)*Mod(1,16))~; tab16 = matrix(16,16); - for(xx = 0, 16-1, + for(xx = 0, 16-1, for(zz = 0, 16-1, - tab16[xx+1,zz+1] = !issquare([xx^4,xx^3*zz,xx^2*zz^2,xx*zz^3,zz^4]*pol16))); + tab16[xx+1,zz+1] = !issquare(vector(deg+1,i,xx^(deg+1-i)*zz^(i-1))*pol16))); pol9 = (Vec(pol)~)*Mod(1,9); tab9 = matrix(9,9); - for(xx = 0, 9-1, + for(xx = 0, 9-1, for(zz = 0, 9-1, - tab9[xx+1,zz+1] = !issquare([xx^4,xx^3*zz,xx^2*zz^2,xx*zz^3,zz^4]*pol9))); + tab9[xx+1,zz+1] = !issquare(vector(deg+1,i,xx^(deg+1-i)*zz^(i-1))*pol9))); pol5 = (Vec(pol)~)*Mod(1,5); tab5 = matrix(5,5); - for(xx = 0, 5-1, + for(xx = 0, 5-1, for(zz = 0, 5-1, - tab5[xx+1,zz+1] = !issquare([xx^4,xx^3*zz,xx^2*zz^2,xx*zz^3,zz^4]*pol5))) + tab5[xx+1,zz+1] = !issquare(vector(deg+1,i,xx^(deg+1-i)*zz^(i-1))*pol5))); ); - lead = pollead(pol); - pol0 = polcoeff(pol,0); - - if( odd, +\\ if the degree is odd, search only for square denominators + if( odd, vecz = vector(lim,i,i^2); , -\\ si le degre de pol est pair, il faut que le coeff dominant soit -\\ un carre mod zz. +\\ if the degree is even, the leading coeff must be +\\ a square modulo zz. + lead = pollead(pol); vecz = vector(lim); zz = 0; for( i = 1, lim, zz++; while( !issquare(Mod(lead,zz)),zz++); vecz[i] = zz )); -\\ le coeff constant doit etre un carre mod xx. + +\\ the constant coeff must be a square modulo xx. + pol0 = polcoeff(pol,0); vecx = vector(lim); xx = 0; for( i = 1, lim, xx++; while( !issquare(Mod(pol0,xx)),xx++); vecx[i] = xx); -if( DEBUGLEVEL_ell >= 4, print("xmax = ",vecx[lim])); -if( DEBUGLEVEL_ell >= 4, print("zmax = ",vecz[lim])); +if( DEBUGLEVEL_ell >= 4, print(" xmax = ",vecx[lim])); +if( DEBUGLEVEL_ell >= 4, print(" zmax = ",vecz[lim])); + +if( DEBUGLEVEL_ell >= 5, print(" vecx = ",vecx)); +if( DEBUGLEVEL_ell >= 5, print(" vecz = ",vecz)); + + if( deg4, + vz = vector(lim,i,Pol( + vector(deg+1,j,polcoeff(pol,deg+1-j)*vecz[i]^(j-1)))); + ); -if( DEBUGLEVEL_ell >= 5, print("vecx = ",vecx)); -if( DEBUGLEVEL_ell >= 5, print("vecz = ",vecz)); +\\ if deg is even and pol has no odd terms, +\\ it is enough to consider xx > 0 + if( !odd && subst(pol,x,-x)==pol, epsmax = 1, epsmax = 2); -\\ boucle sur x = xx/zz +\\ loop over x = xx/zz +\\ the loop on [xx,zz] is done diagonally +\\ to start with the smallest values of both xx and zz. for( somme = 2, 2*lim, for( ix = max(1,somme-lim), min(lim,somme-1), xx = vecx[ix]; iz = somme-ix; zz = vecz[iz]; - if( gcd(zz,xx) > 1, next); - if( odd && !issquare(lead*Mod(xx,zz)), next); - for( eps = 1, 2, if( eps == 2, zz = -zz); - if( deg4 && - (tab16[xx%16+1,zz%16+1] || tab9[xx%9+1,zz%9+1] || tab5[xx%5+1,zz%5+1]) - , next); - evpol = subst(pol,variable(pol),xx/zz); - if( issquare(evpol), - point1 = [xx/zz,sqrtrat(evpol)]; - if( singlepoint, break(3)); - listpoints = concat(listpoints,[point1]) - )))); - - if( point1 != [], -if( DEBUGLEVEL_ell >= 3, print("point trouve par ratpoint = ",point1)); -if( DEBUGLEVEL_ell >= 4, print("sortie de ratpoint ")); + if( gcd(zz,xx) != 1, next); + for( eps = 1, epsmax, +\\ when eps = 1, xx > 0; when eps = 2, xx < 0. + if( deg4, + if( tab16[xx%16+1,zz%16+1], xx=-xx;next); + if( tab9[xx%9+1,zz%9+1], xx=-xx;next); + if( tab5[xx%5+1,zz%5+1], xx=-xx;next); + evpol = subst(vz[iz],'x,xx) + , + evpol = subst(pol,variable(pol),xx/zz) + ); + if( issquare(evpol), + point1 = [xx/zz,sqrtrat(subst(pol,variable(pol),xx/zz))]; +if( DEBUGLEVEL_ell >= 4, print(" point found by ratpoint = ",point1)); + if( singlepoint, break(3)); + listpoints = concat(listpoints,[point1]) + ); + xx = -xx + ))); + + if( point1 != [], +if( DEBUGLEVEL_ell >= 3, print(" point found by ratpoint = ",point1)); +if( DEBUGLEVEL_ell >= 4, print(" end of ratpoint ")); if( singlepoint, return(point1), return(listpoints)) ); -\\ -\\ Essaye une autre strategie quand pol a un content non trivial -\\ +return([]); +} +{redquartic(pol) = +\\ reduction of the quartic polynomial. +\\ (also works with other degrees) +my(localprec,prec0,d,disc2,test,r,normderiv,disc2v,q,M); - if( !odd && tryhard, -if( DEBUGLEVEL_ell >= 4, print(" Autre strategie dans ratpoint **********")); - K = content(pol); +if( DEBUGLEVEL_ell >= 4, print(" starting redquartic")); +if( DEBUGLEVEL_ell >= 3, print(" reduction of the quartic ",pol)); + +\\ choice of the real precision used in the computation + localprec = prec0 = default(realprecision); + d = poldegree(pol); + disc2 = poldisc(pol)^2; + test = 0; + while( test == 0, +if( DEBUGLEVEL_ell >= 4, print(" precision = ",localprec)); + r = polroots(pol); + normderiv = vector( d, i, norm(subst(pol',variable(pol),r[i]))); + disc2v = prod( i = 1, d, normderiv[i]) * pollead(pol)^(2*d-4); + test = abs(disc2v-disc2) < 10^(-localprec\2); + if( !test, default(realprecision, localprec *= 2)) + ); + +\\ former choice of the quadratic form +\\ q = Vec(sum( i = 1, d, norm(x-r[i]))); +\\ Now, uses the quadratic form normalized as in Cremona-Stoll + q = Vec(sum( i = 1, d, norm('x-r[i]) / normderiv[i]^(1/(d-2)))); + M = qfbreduce([q[1],q[2]/2;q[2]/2,q[3]]); + pol = subst(pol,variable(pol),Pol(M[1,])/Pol(M[2,]))*Pol(M[2,])^poldegree(pol); + + if( localprec != prec0, default(realprecision,prec0)); + +if( DEBUGLEVEL_ell >= 3, print(" reduced quartic = ",pol)); +if( DEBUGLEVEL_ell >= 4, print(" end of redquartic")); + + return([pol,M]); +} +{listratpoint( pol, redflag = 0) = +my(list,i,K,ff,C,p,M,U,newpol,factpol,ll,listf,rr); + +if( DEBUGLEVEL_ell >= 5, print(" Starting listratpoint with ",pol)); + list = [[pol,matid(2),1,1]]; + i = 1; + while( i <= #list, + + pol = list[i][1]; + + K = abs(content(pol)); if( K != 1, - pol /= K; - factK = factor(K); - e = factK[,2]\2; - cont = factorback(factK[,1],e); - K /= cont^2; - if(K != 1, - e = factK[,2]%2; - ind = #e; while( !e[ind], ind--); - p = factK[ind,1]; - if( valuation( pollead(pol), p) == 1 || - ( valuation( pollead(pol), p) >= 2 && valuation( polcoeff(pol,poldegree(pol)-1), p) == 0), -if( DEBUGLEVEL_ell >= 4, print(" utilise une racine de pol mod p = ",p)); - sol = ratpoint(K/p^2*subst(polrecip(pol),variable(pol),p*variable(pol)),lim,singlepoint,1); - if( #sol > 0, - point1 = [ 1/(sol[1]*p), - sol[2]*cont*p/(p*sol[1])^(poldegree(pol)/2) ]; -if( DEBUGLEVEL_ell >= 4, print("sortie de ratpoint ",point1)); - return(point1) - ) - ); - factpol = factormod(pol,p)[,1]; - for( i = 1, #factpol, - if( poldegree(factpol[i]) !=1, next); -if( DEBUGLEVEL_ell >= 4, print(" utilise une racine de pol mod p = ",p)); - r = -centerlift(polcoeff(factpol[i],0)); - if( valuation(subst(pol,variable(pol),r),p) > 2, next); - M = [p,r;0,1]; - U = redquartique(subst(K*pol,variable(pol),p*variable(pol)+r)); - if( content(U[1]) != p, next); - sol = ratpoint(K/p^2*U[1],lim,singlepoint,1); - if( #sol > 0, - M = (M*U[2])*[sol[1], #sol == 2]~; - point1 = [ M[1]/M[2], sol[2]*cont*p/M[2]^(poldegree(pol)/2) ]; -if( DEBUGLEVEL_ell >= 4, print("sortie de ratpoint ",point1)); - return(point1) - ) - ) + pol = (list[i][1] /= K); + list[i][3] *= K + ); + + K = list[i][3]; + if( K == 1, i++; next); + + ff = factor(K); + if( vecmax(ff[,2]) > 1, + ff[,2] \= 2; + C = factorback(ff); + list[i][4] *= C; + K = ( list[i][3] /= C^2); + if( K == 1, i++; next); + ff = factor(K); + ); + + p = ff[1,1]; + M = list[i][2]; + C = list[i][4]; + + if( pollead(pol)%p == 0, + U = M*[1,0;0,p]; + if( content(U) == 1, + newpol = subst(pol,'x,'x/p)*p^(poldegree(pol)-1); + list = concat(list, [[newpol,U,K/p,C*p]]) ) + ); + + factpol = centerlift(polrootsmod(pol,p)); + for( j = 1, #factpol, + U = M*[p,factpol[j];0,1]; + if( content(U) == 1, + newpol = subst(pol,'x,p*'x+factpol[j])/p; + list = concat(list, [[newpol,U,K/p,C*p]]) + )); + + i++; + ); + + ll = sum( i = 1, #list, list[i][3] == 1); + listf = vector(ll); + i = 1; + for( j = 1, #list, + if( list[j][3] == 1, + listf[i] = list[j]; i++)); + + if( redflag, + for( i = 1, #listf, + rr = redquartic(listf[i][1]); + listf[i][1] = rr[1]; + listf[i][2] = listf[i][2]*rr[2] ) ); - return([]); +if( DEBUGLEVEL_ell >= 5, print(" Output of listratpoint = ",listf)); + +return(listf); } -if( DEBUGLEVEL_ell >= 5, print("psquare")); -{ -psquare( a, p) = -local(ap,v); +{ratpoint2( pol, lim:small = 1, singlepoint = 1, redflag = 0) = +my(listpoints,list,rr,y2,aux); -if( DEBUGLEVEL_ell >= 5, print("entree dans psquare ",[a,p])); -\\ a est un entier -\\ renvoie 1 si a est un carre dans Zp 0 sinon + listpoints = []; + list = listratpoint(pol,redflag); + for( i = 1, #list, + rr = ratpoint(list[i][1],lim,singlepoint); + if( singlepoint && #rr, rr=[rr]); + for( j = 1, #rr, + y2 = rr[j][2]*list[i][4]; + if( #rr[j] == 2, + aux = [rr[j][1],1]~ + , aux = [rr[j][1],rr[j][3]]~ + ); + aux = list[i][2] * aux; + if( aux[2] == 0, + rr[j] = [aux[1],y2,0] + , rr[j] = [aux[1]/aux[2],y2/aux[2]^(poldegree(pol)\2)] + ); + ); + if( singlepoint && #rr, return(rr[1])); + listpoints = concat(listpoints,rr); + ); + listpoints = vecsort(listpoints,,2); +return(listpoints); +} +{polrealrootsisolate(pol) = +\\ pol is a squarefree polynomial in Z[x]. +\\ Returns a list of vectors [a,b] with a and b rationals +\\ such that the intervals ]a,b] are disjoints and contain +\\ all the real roots of pol, and excatly one in each interval. +my(st,a,res,ind,b,c,stab,stac); + +if( DEBUGLEVEL_ell >= 5, print(" starting polrealrootsisolate with pol = ",pol)); + st = polsturm(pol); + if( !st, return([])); + a = 1; + while( polsturm(pol,-a,a) < st, a <<= 1); + res = [[-a,a,st]]; + ind = 1; + while( #res < st, + while( res[ind][3] == 1, ind++); + a = res[ind][1]; b = res[ind][2]; stab = res[ind][3]; + c = (a+b)/2; + stac = polsturm(pol,a,c); + if( stac == 0, res[ind][1] = c; next); + if( stac == stab, res[ind][2] = c; next); + res[ind] = [a,c,stac]; + res = concat(res,[[c,b,stab-stac]]); + ); + res = vector(st,i,[res[i][1],res[i][2]]); + res = vecsort(res,1); +if( DEBUGLEVEL_ell >= 5, print(" end of polrealrootsisolate with res = ",res)); + return(res); +} +{polrealrootsimprove(pol,v) = +\\ pol is a polynomial and v is a vector v=[a,b] +\\ such that pol contains exactly one root in the interval ]a,b]. +\\ Returns another interval with the same property, but with half length. +\\ (dichotomy) +my(c,v2,vc); + + c = (v[1]+v[2])/2; + v2 = subst(pol,variable(pol),v[2]); + if( v2 == 0, return([c,v[2]])); + vc = subst(pol,variable(pol),c); + if( sign(v2)*sign(vc) >= 0, v[2] = c, v[1] = c); + return(v); +} +{polrootsmodpn(pol,p) = +\\ Compute a list v. Each element of v is of the form +\\ [a,b], with maximal b <= valuation(poldisc(pol),p) +\\ and a is a root of pol modulo p^b. +my(vd,rac,i,pol2,r,newrac); + +if( DEBUGLEVEL_ell >= 5, print(" starting polrootsmodpn ",p,":",pol)); + + vd = valuation(poldisc(pol),p); + rac = [[0,0]]; + i = 1; + while (i <= #rac, +\\ if( rac[i][2] > vd, i++; next); + if( rac[i][2] >= vd, i++; next); + pol2 = subst(pol,'x,rac[i][1]+'x*p^rac[i][2]); + pol2 /= content(pol2); + r = lift(polrootsmod(pol2,p)); + if( #r == 0, i++; next); + newrac = vector(#r,j,[rac[i][1] + p^rac[i][2]*r[j],rac[i][2]+1]); + rac = concat(rac, vector(#r-1,j,newrac[j+1])); + rac[i] = newrac[1]; + ); +if( DEBUGLEVEL_ell >= 5, print(" end of polrootsmodpn ",rac)); + return(rac); +} + +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ +\\ FUNCTIONS FOR LOCAL COMPUTATIONS \\ +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ + +{ppinit( nf, p) = +\\ a little more structure than idealprimedec() +my(pdec,pp); + + pdec = idealprimedec(nf,p); + pp = vector(#pdec,i, + [ pdec[i] + , nfbasistoalg(nf,pdec[i][2]) + , if( p == 2, idealstar(nf,idealpow(nf,pdec[i],1+2*pdec[i].e)),0) + , nfmodprinit(nf,pdec[i]) + ]); + return(pp); +} +{nfpsquareodd( nf, a, pr) = +\\ pr is a prime ideal of nf as output by nfmodprinit +\\ a is an element of nf. +\\ Returns 1 if a is a square in the p-adics, 0 otherwise +\\ works only for p odd. +my(p,v,ap,den,norme); + +if( DEBUGLEVEL_ell >= 5, print(" starting nfpsquareodd(",a,",",pr)); if( a == 0, -if( DEBUGLEVEL_ell >= 5, print("fin de psquare 1")); +if( DEBUGLEVEL_ell >= 5, print(" end of nfpsquareodd")); return(1)); -\\ + + p = pr[3]; + v = idealval(nf,lift(a),p); + if( v%2, +if( DEBUGLEVEL_ell >= 5, print(" end of nfpsquareodd")); + return(0)); + ap = nfalgtobasis(nf,a/nfbasistoalg(nf,p[2])^v); + den = valuation(denominator(content(ap)),p.p); + if( den, + den += den%2; + ap = p.p^den*nfeltmul(nf,ap,nfeltpow(nf,p[2],-den*p.e)) + ); + + norme = (p.p^p.f-1)/2; + ap = nfeltpowmodpr(nf,ap,norme,pr); + ap[1] -= 1; + if( ap == 0, +if( DEBUGLEVEL_ell >= 5, print(" end of nfpsquareodd")); + return(1)); + if( idealval(nf,ap,p) > 0, +if( DEBUGLEVEL_ell >= 5, print(" end of nfpsquareodd")); + return(1)); +if( DEBUGLEVEL_ell >= 5, print(" end of nfpsquareodd")); + return(0); +} +{psquare( a, p) = +\\ a is an integer. +\\ p is a prime integer. +\\ Returns 1 if a is a square in the p-adics, 0 otherwise. +my(v,ap); + +if( DEBUGLEVEL_ell >= 5, print(" starting psquare ",[a,p])); + + if( a == 0, +if( DEBUGLEVEL_ell >= 5, print(" end of psquare 1")); + return(1)); + v = valuation(a,p); if( v%2, -if( DEBUGLEVEL_ell >= 5, print("fin de psquare 0")); +if( DEBUGLEVEL_ell >= 5, print(" end of psquare 0")); return(0)); - if( p == 2, + if( p == 2, ap = (a>>v)%8-1, ap = kronecker(a/p^v,p)-1 ); -if( DEBUGLEVEL_ell >= 5, print("fin de psquare ", !ap)); +if( DEBUGLEVEL_ell >= 5, print(" end of psquare ", !ap)); return(!ap); } -if( DEBUGLEVEL_ell >= 4, print("lemma6")); -{ -lemma6(pol, p, nu, xx) = -local(gx,gpx,lambda,mu); +{lemma6(pol, p, nu, xx) = +\\ technical lemma for local solubility of quartics +\\ Only for p <> 2. +my(gx,gpx,lambda,mu); -\\ pour les p <> 2 gx = subst( pol, variable(pol), xx); if( psquare(gx,p), return(1)); gpx = subst( pol', variable(pol), xx); @@ -513,12 +674,11 @@ local(gx,gpx,lambda,mu); if( (lambda >= 2*nu) && (mu >= nu), return(0)); return(-1); } -if( DEBUGLEVEL_ell >= 4, print("lemma7")); -{ -lemma7( pol, nu, xx) = -local(gx,gpx,lambda,mu,q); +{lemma7( pol, nu, xx) = +\\ technical lemma for local solubility of quartics +\\ at p = 2. +my(gx,gpx,lambda,mu,q); -\\ pour p = 2 gx = subst( pol, variable(pol), xx); if( psquare(gx,2), return(1)); gpx = subst( pol', variable(pol), xx); @@ -535,27 +695,25 @@ local(gx,gpx,lambda,mu,q); if( q == -2 && (gx>>lambda)%4 == 1, return(0)); return(-1); } -if( DEBUGLEVEL_ell >= 4, print("zpsoluble")); -{ -zpsoluble(pol, p, nu, pnu, x0, pnup) = -local(result,pol2,fact,x1); +{zp_soluble(pol, p, nu, pnu, x0, pnup) = +my(result,pol2,fact,x1); -if( DEBUGLEVEL_ell >= 5, print("entree dans zpsoluble ",[pol,p,x0,nu])); +if( DEBUGLEVEL_ell >= 5, print(" starting zp_soluble ",[pol,p,x0,nu])); if( p == 2, result = lemma7(pol,nu,x0), result = lemma6(pol,p,nu,x0)); if( result == +1, -if( DEBUGLEVEL_ell >= 5, print("fin de zpsoluble 1 lemma")); +if( DEBUGLEVEL_ell >= 5, print(" end of zp_soluble 1 lemma")); return(1)); if( result == -1, -if( DEBUGLEVEL_ell >= 5, print("fin de zpsoluble 0 lemma")); +if( DEBUGLEVEL_ell >= 5, print(" end of zp_soluble 0 lemma")); return(0)); pnup = pnu*p; nu++; - if( p< LIMBIGPRIME || !LIMBIGPRIME, + if( p < LIMBIGPRIME || !LIMBIGPRIME, for( i = 0, p-1, - if( zpsoluble(pol,p,nu,pnup,x0+pnu*i), -if( DEBUGLEVEL_ell >= 5, print("fin de zpsoluble")); + if( zp_soluble(pol,p,nu,pnup,x0+pnu*i), +if( DEBUGLEVEL_ell >= 5, print(" end of zp_soluble")); return(1))) , pol2 = subst(pol,variable(pol),x0+pnu*variable(pol)); @@ -565,594 +723,865 @@ if( DEBUGLEVEL_ell >= 5, print("fin de zpsoluble")); fact = factormod(pol2,p)[,1]; for( i = 1, #fact, x1 = -centerlift(polcoeff(fact[i],0)); - if( zpsoluble(pol,p,nu,pnup,x0+pnu*x1), -if( DEBUGLEVEL_ell >= 5, print("fin de zpsoluble")); + if( zp_soluble(pol,p,nu,pnup,x0+pnu*x1), +if( DEBUGLEVEL_ell >= 5, print(" end of zp_soluble")); return(1))); for( i = 1, MAXPROB, x1 = random(p); - if( zpsoluble(pol,p,nu,pnup,x0+pnu*x1), -if( DEBUGLEVEL_ell >= 5, print("fin de zpsoluble")); + if( zp_soluble(pol,p,nu,pnup,x0+pnu*x1), +if( DEBUGLEVEL_ell >= 5, print(" end of zp_soluble")); return(1))) ); if( DEBUGLEVEL_ell >= 2, - if( p >= LIMBIGPRIME, - print("******* test probabiliste en p = ",p,"*******"))); -if( DEBUGLEVEL_ell >= 5, print("fin de zpsoluble")); + if( p >= LIMBIGPRIME, + print(" ******* probabilistic test at p = ",p,"*******"))); +if( DEBUGLEVEL_ell >= 5, print(" end of zp_soluble")); return(0); } -if( DEBUGLEVEL_ell >= 4, print("qpsoluble")); -{ -qpsoluble(pol, p) = -if( DEBUGLEVEL_ell >= 5, print("entree dans qpsoluble ",p); print("pol = ",pol)); +{qp_soluble(pol, p) = +if( DEBUGLEVEL_ell >= 5, + print(" starting qp_soluble ",p); + print(" pol = ",pol)); if( psquare(pollead(pol),p), -if( DEBUGLEVEL_ell >= 5, print("fin de qpsoluble 1")); +if( DEBUGLEVEL_ell >= 5, print(" end of qp_soluble 1")); return(1)); if( psquare(polcoeff(pol,0),p), -if( DEBUGLEVEL_ell >= 5, print("fin de qpsoluble 1")); +if( DEBUGLEVEL_ell >= 5, print(" end of qp_soluble 1")); return(1)); - if( zpsoluble(pol,p,0,1,0), -if( DEBUGLEVEL_ell >= 5, print("fin de qpsoluble 1")); + if( zp_soluble(pol,p,0,1,0), +if( DEBUGLEVEL_ell >= 5, print(" end of qp_soluble 1")); return(1)); - if( zpsoluble(polrecip(pol),p,1,p,0), -if( DEBUGLEVEL_ell >= 5, print("fin de qpsoluble 1")); + if( zp_soluble(polrecip(pol),p,1,p,0), +if( DEBUGLEVEL_ell >= 5, print(" end of qp_soluble 1")); return(1)); -if( DEBUGLEVEL_ell >= 5, print("fin de qpsoluble 0")); +if( DEBUGLEVEL_ell >= 5, print(" end of qp_soluble 0")); return(0); } -if( DEBUGLEVEL_ell >= 4, print("locallysoluble")); -{ -locallysoluble(pol) = -\\ teste l'existence locale de solutions de y^2 = pol(x,z) -local(plist,disc0,p,c,vc); +{locallysoluble(pol) = +\\ Determines if y^2 = pol(x,z) is everywhere locally soluble +my(c,disc0,plist,p,vc); -if( DEBUGLEVEL_ell >= 4, print("entree dans locallysoluble :",pol)); +if( DEBUGLEVEL_ell >= 4, print(" starting locallysoluble: ",pol)); -\\ place reelle - if( !(poldegree(pol)%2) && sign(pollead(pol)) < 0 +\\ real place + if( !(poldegree(pol)%2) && sign(pollead(pol)) < 0 && sign(polcoeff(pol,0)) < 0 && polsturm(pol) == 0, -if( DEBUGLEVEL_ell >= 3, print(" non ELS a l'infini")); -if( DEBUGLEVEL_ell >= 4, print("fin de locallysoluble")); +if( DEBUGLEVEL_ell >= 3, print(" not ELS at infinity")); +if( DEBUGLEVEL_ell >= 4, print(" end of locallysoluble")); return(0)); \\ -\\ places finies de plist */ +\\ finite places \\ pol *= denominator(content(pol))^2; c = content(pol); disc0 = poldisc(pol); plist = factor (abs(2*disc0)); -if( DEBUGLEVEL_ell >= 4, print("liste de premiers = ",plist)); +if( DEBUGLEVEL_ell >= 4, print(" list of bad primes = ",plist)); for( i = 1, #plist[,1], p = plist[i,1]; -if( DEBUGLEVEL_ell >= 4, print("p = ",p)); +if( DEBUGLEVEL_ell >= 4, print(" p = ",p)); vc = valuation(c,p); - if( vc >= 2, + if( vc >= 2, pol /= p^(2*(vc\2)); plist[i,2] -= 2*(vc\2)*(2*poldegree(pol)-2) ); if( poldegree(pol) == 4 && p != 2 && plist[i,2] < 2, next); - if( !qpsoluble(pol,p), -if( DEBUGLEVEL_ell >= 3, print(" non ELS en ",p)); -if( DEBUGLEVEL_ell >= 4, print("fin de locallysoluble")); + if( !qp_soluble(pol,p), +if( DEBUGLEVEL_ell >= 3, print(" not ELS at ",p)); +if( DEBUGLEVEL_ell >= 4, print(" end of locallysoluble")); return(0))); -if( DEBUGLEVEL_ell >= 2, print(" quartique ELS")); -if( DEBUGLEVEL_ell >= 4, print("fin de locallysoluble")); +if( DEBUGLEVEL_ell >= 2, print(" quartic ELS: Y^2 = ",pol)); +if( DEBUGLEVEL_ell >= 4, print(" end of locallysoluble")); return(1); } -if( DEBUGLEVEL_ell >= 4, print("redquartique")); -{ -redquartique(pol) = -\\ reduction d'une quartique. -\\ ou plus generalement d'un polynome de degre deg. -local(prec,prec0,d,disc2,test,normderiv,disc2v,r,q,M); +{LS2localimage(nf,gen,pp) = +my(p,LS2image,ph,ival,delta); + +if( DEBUGLEVEL_ell >= 4, print(" starting LS2localimage")); + + p = pp[1][1].p; + LS2image = matrix( if( p == 2, sum(i=1,#pp,1+#pp[i][3].cyc), 2*#pp), #gen); + + for( j = 1, #gen, + ph = []; + for( i = 1, #pp, + ival = idealval(nf,gen[j],pp[i][1]); + ph = concat(ph,[ival]); + delta = gen[j]/pp[i][2]^ival; + if( p == 2, + ph = concat(ph,ideallog(nf,delta,pp[i][3])~); + , ph = concat(ph,[1-nfpsquareodd(nf,delta,pp[i][4])]); + ) + ); + LS2image[,j] = ph~ + ); + LS2image *= Mod(1,2); -if( DEBUGLEVEL_ell >= 4, print("entree dans redquartique")); -if( DEBUGLEVEL_ell >= 3, print(" reduction de la quartique ",pol)); +if( DEBUGLEVEL_ell >= 4, print(" LS2image = ",lift(LS2image))); +if( DEBUGLEVEL_ell >= 4, print(" end of LS2localimage")); + return(LS2image); +} -\\ choix de la precision des calculs. - prec = prec0 = default(realprecision); - d = poldegree(pol); - disc2 = poldisc(pol)^2; - test = 0; - while( test == 0, -if( DEBUGLEVEL_ell >= 4, print(" precision = ",prec)); - r = polroots(pol); - normderiv = vector( d, i, norm(subst(pol',variable(pol),r[i]))); - disc2v = prod( i = 1, d, normderiv[i]) * pollead(pol)^(2*d-4); - test = abs(disc2v-disc2) < 10^(-prec\2); - if( !test, default(realprecision, prec *= 2)) +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ +\\ GENERIC FUNCTIONS FOR ELLIPTIC CURVES \\ +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ + +{ellhalf(ell,P)= +\\ returns all the points Q on ell such that 2Q = P. +my(pol2,ratroots,half,x2,y2,P2); + + if(#ell < 13, ell=ellinit(ell,1)); + + pol2 = Pol([4,ell.b2,2*ell.b4,ell.b6]); \\ 2-division polynomial + + if( P == [0], + ratroots = nfroots(,pol2); + half = vector(#ratroots,i,[ratroots[i],-(ell.a1*ratroots[i]+ell.a3)/2]); + half = concat( [[0]], half); + return(half) ); -\\ On n'utilise plus -\\ q = Vec(sum( i = 1, d, norm(x-r[i]))); -\\ mais la normalisation de Cremona-Stoll - q = Vec(sum( i = 1, d, norm(x-r[i]) / normderiv[i]^(1/(d-2)))); - M = QfbReduce([q[1],q[2]/2;q[2]/2,q[3]]); - pol = subst(pol,variable(pol),Pol(M[1,])/Pol(M[2,]))*Pol(M[2,])^poldegree(pol); + x2 = Pol([1,0,-ell.b4,-2*ell.b6,-ell.b8]); \\ x(2P) = x2/pol2 - if( prec != prec0, default(realprecision,prec0)); + half = []; + ratroots = nfroots(,x2-P[1]*pol2); + if( #ratroots == 0, return(half)); + for( i = 1, #ratroots, + y2 = ellordinate(ell,ratroots[i]); + for( j = 1, #y2, + P2 = [ratroots[i],y2[j]]; + if( ellpow(ell,P2,2) == P, half = concat(half,[P2])) + ) + ); -if( DEBUGLEVEL_ell >= 3, print(" quartique reduite = ",pol)); -if( DEBUGLEVEL_ell >= 4, print("sortie de redquartique")); + return(half); +} +{elltors2(ell)= +\\ Compute the 2-torsion subgroup of the elliptic curve ell. +my(tors2); - return([pol,M]); +if( DEBUGLEVEL_ell >= 3, print(" computing the 2-torsion")); + + tors2 = ellhalf(ell,[0]); + if( #tors2 == 1, + tors2 = [1, [], []], + if( #tors2 == 2, + tors2 = [2, [2], [tors2[2]]] + , tors2 = [4, [2,2], [tors2[2],tors2[3]]] + )); +if( DEBUGLEVEL_ell >= 3, print(" E[2] = ",tors2)); + return(tors2); } -if( DEBUGLEVEL_ell >= 4, print("reducemodsquares")); -{ -reducemodsquares(delta,d) = -\\ reduction du coefficient de x^d dans ( delta modulo les carres ) -local(deg,xx,z,qd,Qd,reduc); - - deg = poldegree(delta.mod); - xx = Mod(x,delta.mod); - z = subst(Pol(vector(deg,i,eval(Str("a"i)))),x,xx); - qd = polcoeff(lift(delta*z^2),d,x); - Qd = simplify(matrix(deg,deg,i,j,deriv(deriv(qd,eval(Str("a"i))),eval(Str("a"j)))/2)); +{elltorseven(ell)= +\\ Compute the 2-Sylow subgroup of the torsion of the elliptic curve ell. +my(torseven,P2); - reduc = IndefiniteLLL(Qd); - if( #reduc == 2, reduc = reduc[2][,1]); +if( DEBUGLEVEL_ell >= 4, print(" computing the 2^n-torsion")); + if(#ell < 13, ell=ellinit(ell,1)); + torseven = elltors2(ell); + + while( torseven[1] != 1, + P2 = ellhalf(ell,torseven[3][1]); + if( #P2 > 0, + torseven[1] *= 2; + torseven[2][1] *= 2; + torseven[3][1] = P2[1]; + next + ); + if( #torseven[3] == 1, break()); - return(delta*subst(Pol(reduc),x,xx)^2); + P2 = ellhalf(ell,torseven[3][2]); + if( #P2 > 0, + torseven[1] *= 2; + torseven[2][2] *= 2; + torseven[3][2] = P2[1]; + next + ); + P2 = ellhalf(ell,elladd(ell,torseven[3][1],torseven[3][2])); + if( #P2 > 0, + torseven[1] *= 2; + torseven[2][1] *= 2; + torseven[3][1] = P2[1]; + next + ); + break() + ); + +if( DEBUGLEVEL_ell >= 4, print(" E[2^n] = ",torseven)); + return(torseven); } -if( DEBUGLEVEL_ell >= 4, print("ellsort")); -{ -ellsort(listpts) = -\\ tri des points listpts sur une courbe elliptique -\\ suivant la hauteur naive. -local(n,v,aux,ord); +{ellsort(listpts) = +\\ Sorting the points listpts on an elliptic curve +\\ using the naive height. +my(n,v,aux,ord); v = vector(n = #listpts); - for( i = 1, n, + for( i = 1, n, if( listpts[i] == [0], v[i] = [0,0,0]; next); aux = denominator(listpts[i][2])/denominator(listpts[i][1]); v[i] = vecsort(abs([listpts[i][1]*aux^2, listpts[i][2]*aux^3,aux]),,4); ); - ord = vecsort(v,,3); + ord = Vec(vecsort(v,,3)); \\ ord = vecsort(v,,3); return(vector(n,i,listpts[ord[i]])); } -if( DEBUGLEVEL_ell >= 4, print("ellredgen")); -{ -ellredgen(ell,listgen,K=1) = -\\ reduction des generateurs de listgen -\\ sur la courbe ell = [a1,a2,a3,a4,a6] -\\ ou K*y^2 = x^3 + a2*x^2 + a4*x + a6 (lorsque a1 = a3 = 0); -local(d,sqrtK,urst,M,U,limgoodrelations,listgen2); - -if( DEBUGLEVEL_ell >= 3, print("Reduction des generateurs ",listgen)); -if( DEBUGLEVEL_ell >= 5, print("ell=",ell)); +{ellremovetorsion(ell,listgen) = +\\ Extracting the points of infinite order from listgen +my(d,extra); + +if( DEBUGLEVEL_ell >= 5, print(" removing torsion from ",listgen)); + d = #listgen; + extra = 0; + for( i = 1, d, +\\ points of order 1 or 2 + if( listgen[i] == [0] + || listgen[i] == ellpow(ell,listgen[i],-1) + , extra += 1<<(i-1); + next + ); +\\ detection of infinite order points by looking at +\\ 8*9*5*7*P modulo the prime 1048583 + if( ell.disc%1048583 != 0 + && denominator(listgen[i])%1048583 != 0 + && ellpow(ell,listgen[i]*Mod(1,1048583),2520) != [0] + , next + ); +\\ detection of torsion points by ellorder() + if( ellorder(ell,listgen[i]), + extra += 1<<(i-1) + ) + ); + if( extra, + listgen = vecextract(listgen,1<<#listgen-1-extra); + ); +if( DEBUGLEVEL_ell >= 5, print(" without torsion = ",listgen)); + return(listgen); +} +{ellredgen(ell0,listgen,K=1) = +\\ reduction of the generators of points in listgen +\\ on the elliptic curve ell = [a1,a2,a3,a4,a6] +\\ or K*y^2 = x^3 + a2*x^2 + a4*x + a6 (when a1 = a3 = 0); +\\ using the canonical height. +my(d,ell=ell0,sqrtK,urst,extra,M,U,listgen2,tors2,vt); + +if( DEBUGLEVEL_ell >= 3, print(" Reduction of the generators ",listgen)); +if( DEBUGLEVEL_ell >= 5, print(" ell=",ell)); d = #listgen; if( d == 0, return([])); - if( #ell < 19, ell = ellinit(ell)); +\\ removing torsion points from listgen + listgen = ellremovetorsion(ell0,listgen); + d = #listgen; + if( d == 0, return([])); + + if( #ell < 13, ell = ellinit(ell,1)); + if( K != 1, - if( ell.a1 != 0 || ell.a3 != 0, error(" ellredgen : a1*a3 != 0")); + if( ell.a1 != 0 || ell.a3 != 0, error(" ellredgen: a1*a3 != 0")); ell[2] *= K; ell[4] *= K^2; ell[5] *= K^3; ell[6] *= K; ell[7] *= K^2; ell[8] *= K^3; ell[9] *= K^4; ell[10] *= K^2; ell[11] *= K^3; ell[12] *= K^6; sqrtK = sqrt(K); - ell[14] *= K; - ell[15] /= sqrtK; ell[16] /= sqrtK; - ell[17] *= sqrtK; ell[18] *= sqrtK; - ell[19] /= K; + if( #ell == 19, + ell[14] *= K; + ell[15] /= sqrtK; ell[16] /= sqrtK; + ell[17] *= sqrtK; ell[18] *= sqrtK; + ell[19] /= K + ); for( i = 1, d, for( j = 1, #listgen[i], listgen[i][j] *= K^j)) ); +if( d == 1, + urst = [1,0,0,0]; +, + if( #ell < 19, ell = ellinit(ell)); ell = ellminimalmodel(ell,&urst); listgen = ellchangepoint(listgen,urst); +if( DEBUGLEVEL_ell >= 5, print(" ell = ",ell)); +if( DEBUGLEVEL_ell >= 5, print(" listgen = ",listgen)); -\\ Recherche des relations entre les points de listgen -\\ par recherche du noyau de la matrice des hauteurs - - M = ellheightmatrix(ell,listgen); -if( DEBUGLEVEL_ell >= 4, print("matrice des hauteurs = ",M)); - M = round( M*10^(default(realprecision)-10) ); - U = qflll(M,4); - U = concat(U[1],U[2]); +\\ Looking for relations between the points in listgen +\\ using LLL on the height matrix - /* BEGIN patch to work with PARI 2.4.4 */ - /* AUTHORS: John Cremona, Jeroen Demeyer (Sage Trac #11130) */ + extra = 1; + while( extra, + M = ellheightmatrix(ell,listgen); +if( DEBUGLEVEL_ell >= 4, print(" height matrix = ",M)); + if( abs(matdet(M)) > 10^(-default(realprecision)+10),break); + U = qflll(round(M*10^(default(realprecision)-10)),4); + U = concat(U[1],U[2]); if( DEBUGLEVEL_ell >= 4, print(" change of basis proposed by LLL = ",U)); - \\ The columns of U that have very small coefficients (coeff < 20) - \\ are either exact relations or reductions. These are the ones we - \\ want to keep, the other ones are irrelevant. - keep = 0; - for( i = 1, d, - if( vecmax(abs(U[,i])) < 20, keep += 1<<(i-1)) - ); - U = vecextract(U, keep); - /* END patch from Sage Ticket #11130 to work with PARI 2.4.4 */ +\\ the columns of U that have very small coefficients +\\ are either exact relations or reductions (coeff <= 20) +\\ the other ones are irrelevant. + extra = 0; + for( i = 1, d, + if( vecmax(abs(U[,i])) > 20, extra += 1<<(i-1)) + ); + U = vecextract(U,1<= 4, print(" change of basis 1 = ",U)); - U = completebasis(U); -if( DEBUGLEVEL_ell >= 4, print("changement de base = ",U)); + listgen2 = vector(d); + for( i = 1, d, + listgen2[i] = [0]; + for( j = 1, d, + listgen2[i] = elladd(ell,listgen2[i],ellpow(ell,listgen[j],U[j,i])))); + listgen = listgen2; + ); - listgen2 = vector(d); - for( i = 1, d, - listgen2[i] = [0]; - for( j = 1, d, - listgen2[i] = elladd(ell,listgen2[i],ellpow(ell,listgen[j],U[j,i])))); - listgen = listgen2; +\\ Extracting the points of infinite order -\\ Tri des points d'ordre infini +\\ removing torsion points from listgen + listgen = ellremovetorsion(ell,listgen); + d = #listgen; + if( d == 0, return([])); + ); - listgen2 = []; - for( i = 1, d, - if( !ellorder(ell,listgen[i]), - listgen2 = concat(listgen2,[listgen[i]]))); - listgen = listgen2; -if( DEBUGLEVEL_ell >= 3, print("points d'ordre infini = ",listgen)); - d = #listgen; - if( d == 0, return([])); +if( DEBUGLEVEL_ell >= 3, print(" infinite order points = ",listgen)); -\\ Reduction des points d'ordre infini +\\ Now, the points should be of infinite order and independant +\\ Reducing the points of infinite order if( d > 1, M = ellheightmatrix(ell,listgen); -if( DEBUGLEVEL_ell >= 4, print("matrice des hauteurs = ",M)); +if( DEBUGLEVEL_ell >= 4, print(" height matrix = ",M)); U = qflllgram(M); -if( DEBUGLEVEL_ell >= 4, print("changement de base = ",U)); +if( DEBUGLEVEL_ell >= 4, print(" change of basis 2 = ",U)); listgen2 = vector(d); for( i = 1, d, listgen2[i] = [0]; for( j = 1, d, listgen2[i] = elladd(ell,listgen2[i],ellpow(ell,listgen[j],U[j,i])))); - listgen = listgen2 + listgen = listgen2; ); - listgen = ellsort(listgen); -if( DEBUGLEVEL_ell >= 4, print("generateurs tries = ",listgen)); +if( DEBUGLEVEL_ell >= 3, print(" infinite order points = ",listgen)); + + listgen = ellchangepoint(listgen,ellinverturst(urst)); + +\\ Reducing modulo the 2-torsion + + tors2 = elltorseven(ell0); + if( tors2[1] > 1, + vt = vector(tors2[2][1],j,ellpow(ell0,tors2[3][1],j-1)); + if( #tors2[2] == 2, + vt = concat(vt,vector(#vt,j,elladd(ell0,vt[j],tors2[3][2]))) + ); + for( i = 1, d, + listgen[i] = ellsort(vector(#vt,j,elladd(ell0,listgen[i],vt[j])))[1]; + ); + ); - listgen = ellchangepointinverse(listgen,urst); +if( DEBUGLEVEL_ell >= 3, print(" infinite order points = ",listgen)); + if( K != 1, for( i = 1, d, for( j = 1, 2, listgen[i][j] /= K^j))); -\\ on ne garde que les points (x,y) avec y >= 0 +\\ keep only the points (x,y) with y >= 0 - if( ell.a1 == 0 && ell.a3 == 0, + if( ell0.a1 == 0 && ell0.a3 == 0, for( i = 1, d, if( #listgen[i] == 2, listgen[i][2] = abs(listgen[i][2])))); -if( DEBUGLEVEL_ell >= 2, print("generateurs reduits = ",listgen)); +if( DEBUGLEVEL_ell >= 2, print(" reduced generators = ",listgen)); return(listgen); } -if( DEBUGLEVEL_ell >= 4, print("ell2descent_gen")); -{ -ell2descent_gen(ell,ext,K=1,help=[],redflag=0) = -\\ si ell= K*y^2=P(x), alors ext est le buchinitfu de l'extension. -\\ theta est une racine de P. -\\ dans la suite ext est note L = Q(theta). -\\ help est une liste de points deja connus sur ell. -\\ ell est de la forme K*y^2=x^3+A*x^2+B*x+C */ -\\ ie ell=[0,A,0,B,C], avec A,B et C entiers */ -\\ -\\ si redflag != 0, on utilise la reduction modulo les carres. -\\ -local(A,B,C,S,SLprod,SLlist,aux,oddclass,LS2gen,fact,trouve,i,polrel,ttheta,polprime,KS2gen,LS2genunit,normLS2gen,normcoord,LS2coordtilda,LS2,listgen,listpoints,listpointstriv,listpointsmwr,list,m1,m2,lastloc,maskwhile,iwhile,zc,j,iaux,liftzc,den,ispointtriv,point,found,idealfactorzc,idealzc,baseidealzc,q2,sol,q1,param,pol,redq,q0,pointxx,point2,v,rang); +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ +\\ FUNCTIONS FOR NUMBER FIELDS \\ +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ -if( DEBUGLEVEL_ell >= 4, print("entree dans ell2descent_gen")); +{reducemodsquares(delta,d) = +\\ Uses LLL to find z such that delta*z^2 has a small coefficient in x^d. +\\ delta must be a t_POLMOD +my(deg,xx,z,qd,Qd,reduc); -\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ -\\ construction de L(S,2) \\ -\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ - - if( #ell < 13, ell = ellinit(ell,1)); - - if( ell.a1 != 0 || ell.a3 != 0, - error(" ell2descent_gen : la courbe n'est pas sous la forme [0,a,0,b,c]")); - if( denominator(ell.a2) > 1 || denominator(ell.a4) > 1 || denominator(ell.a6) >1, - error(" ell2descent_gen : coefficients non entiers")); + deg = poldegree(component(delta,1)); \\ deg = poldegree(delta.mod); + xx = Mod('x,component(delta,1)); \\ xx = Mod(x,delta.mod); + z = subst(Pol(vector(deg,i,eval(Str("a"i)))),'x,xx); + qd = polcoeff(lift(delta*z^2),d,'x); + Qd = simplify(matrix(deg,deg,i,j,deriv(deriv(qd,eval(Str("a"i))),eval(Str("a"j)))/2)); - A = ell.a2; if( DEBUGLEVEL_ell >= 2, print("A = ",A)); - B = ell.a4; if( DEBUGLEVEL_ell >= 2, print("B = ",B)); - C = ell.a6; if( DEBUGLEVEL_ell >= 2, print("C = ",C)); + reduc = qflllgram_indef(Qd); + if( #reduc == 2, reduc = reduc[2][,1]); - polrel = Pol([1,A,B,C]); - if( !ext, -if( DEBUGLEVEL_ell >= 2, print("bnfinit(",polrel,")")); - ext = bnfinit(polrel,1)); - - S = -abs(K*ext.index); - SLprod = idealmul(ext,K,idealadd(ext,ext.pol',ext.index)); - SLlist = idealfactor(ext,SLprod)[,1]~; - aux = []; SLprod = 1; - for( i = 1, #SLlist, - if( !(K%SLlist[i][1]) || valuation(ext.index,SLlist[i][1]), - SLprod = idealmul(ext,SLprod,SLlist[i]); - aux = concat(aux,[SLlist[i]]))); - SLlist = aux; - oddclass = 0; + return(delta*subst(Pol(reduc),'x,xx)^2); +} +{bnfpSelmer(bnf,S=1,p) = +\\ p is a prime integer and bnf a big number field. +\\ Compute the p-Selmer group of the number field bnf +\\ relative to the prime ideals dividing S. +\\ This group is denoted by LS2 in the sequel. +\\ Returns [gen,S'] where gen is a vector containing the generators +\\ of the p-Selmer group, represented has elements of bnf modulo p-powers, +\\ and S' is the support of gen. +my(S1,oddclass,multS,Slist,LS2gen,newprimes,newprimesval,kerval); + +if( DEBUGLEVEL_ell >= 3, print(" Constructing the field Selmer group: L(S,",p,")")); + S1 = idealhnf(bnf,S); + + oddclass = 0; multS = 1; while( !oddclass, -\\ Constructoin de S: -if( DEBUGLEVEL_ell >= 4, print("SLlist = ",SLlist)); -\\ Construction des S-unites - LS2gen = bnfsunit(ext,SLlist); -if( DEBUGLEVEL_ell >= 4, print("LS2gen = ",LS2gen)); -\\ on ajoute la partie paire du groupe de classes. - oddclass = LS2gen[5][1]%2; + if( multS != 1, S1 = idealmul(bnf,S1,multS)); + Slist = idealfactor(bnf,S1)[,1]~; +if( DEBUGLEVEL_ell >= 4, print(" constructing the S-units ")); +if( DEBUGLEVEL_ell >= 4, print(" S1 = ",Slist)); + LS2gen = bnfsunit(bnf,Slist); + +\\ If the class group is divisible by p, +\\ need to enlarge S1. + oddclass = LS2gen[5].no % p; if( !oddclass, -if( DEBUGLEVEL_ell >= 3, print("Groupe de classes pair")); -if( DEBUGLEVEL_ell >= 4, print(LS2gen[5])); - S *= LS2gen[5][3][1][1,1]; - SLprod = idealmul(ext,SLprod,LS2gen[5][3][1]); - fact = idealfactor(ext,LS2gen[5][3][1])[,1]; - trouve = 0; i = 0; - while( !trouve, - i++; trouve = 1; - for( j = 1, #SLlist, - if( SLlist[j] == fact[i], trouve = 0; break))); - SLlist = concat(SLlist,[fact[i]])) +if( DEBUGLEVEL_ell >= 4, print(" class group divisible by p = ",LS2gen[5].no)); + multS = idealmul(bnf,S,LS2gen[5].gen[1]); + ) + ); + LS2gen = Mod(LS2gen[1],bnf.pol); + +\\ The valuation of the generators must be divisible by p outside S. + newprimes = []; + for( i = 1, #Slist, + if( idealadd(bnf,S,Slist[i]) == 1, + newprimes = concat(newprimes,[Slist[i]]))); +if( DEBUGLEVEL_ell >= 4, print(" newprimes = ",newprimes)); + newprimesval = matrix(#newprimes,#LS2gen,i,j, + idealval(bnf,LS2gen[j],newprimes[i])); +if( DEBUGLEVEL_ell >= 4, print(" newprimesval = ",newprimesval)); + kerval = lift(matker(newprimesval*Mod(1,p))); +if( DEBUGLEVEL_ell >= 4, print(" kerval = ",kerval)); + LS2gen = vector(#kerval,i, + prod( j = 1, #LS2gen, + LS2gen[j]^kerval[j,i])); + +\\ Add the units + LS2gen = concat(Mod(bnf[8][5],bnf.pol),LS2gen); \\ LS2gen = concat(bnf.fu,LS2gen); +\\ Add also the torsion unit if its order is divisible by p. + if( bnf[8][4][1]%p == 0, \\ if( bnf.tu[1]%p == 0, + LS2gen = concat( [Mod(bnf[8][4][2],bnf.pol)], LS2gen)); \\ LS2gen = concat( [Mod(bnf.tu[2],bnf.pol)], LS2gen)); +if( DEBUGLEVEL_ell >= 3, print(" #LS2gen = ",#LS2gen)); +if( DEBUGLEVEL_ell >= 4, print(" LS2gen = ",LS2gen)); + return([LS2gen,Slist]); +} +{kersign(gen,rootapprox) = +\\ Determine the kernel of the sign map +\\ restricted to the subgroup generated by gen, +\\ and relative to the real embedding corresponding to +\\ the root of pol contained in the interval rootapprox. +my(signs,elt,elt2,d,st,kers,compt); + +if( DEBUGLEVEL_ell >= 3, print(" Computing the kernel of the sign ",rootapprox)); + +\\ determination of the signs + + signs = vector(#gen); + for( i = 1, #gen, + elt = lift(gen[i]); +if( DEBUGLEVEL_ell >= 5, print(" Computing the sign of elt = ",elt)); + if( poldegree(elt) == 0, signs[i] = sign(simplify(elt)) < 0; next); + d = poldisc(elt); + if( poldegree(elt) == 2, + if( d <= 0, signs[i] = sign(pollead(elt)) < 0; next)); + elt2 = if( d == 0, elt/gcd(elt,elt'), elt); + st = 1; + compt = 0; + while( st, + st = polsturm(elt2,rootapprox[1],rootapprox[2]); + if( st, + rootapprox = polrealrootsimprove(component(gen[i],1),rootapprox); +\\ rootapprox = polrealrootsimprove(gen[i].mod,rootapprox); +\\ if the sign of elt is too difficult to determine, +\\ try a reduction modulo squares + if( compt++ == 5, gen[i] = reducemodsquares(gen[i]); i--; next(2)); +\\ if the sign of elt is still too difficult to determine, +\\ try the sign of 1/elt. + if( compt%5 == 0, gen[i] = 1/gen[i]; i--; next(2)) + )); + signs[i] = sign(subst(elt,variable(elt),rootapprox[2])) < 0 ); +if( DEBUGLEVEL_ell >= 4, print(" signs = ",signs)); -if( DEBUGLEVEL_ell >= 4, print("S = ",S)); +\\ construction of the kernel + kers = matker(Mat(signs*Mod(1,2)))*Mod(1,2); +if( DEBUGLEVEL_ell >= 4, print(" kers = ",lift(kers))); + return(kers); +} +{kernorm(gen,S,p) = +\\ gen is a generating set for a subgroup of K^* / K^p. +\\ Compute the kernel of the norm map. +\\ Uses the fact that all valuations are 0 mod p, +\\ except maybe at primes in S. +my(normgen,normmap,kern); + +if( DEBUGLEVEL_ell >= 3, print(" Computing the kernel of the norm map")); + + if( p == 2, S = concat([-1],S)); + normgen = norm(gen); +if( DEBUGLEVEL_ell >= 4, print(" normgen = ",normgen)); + +\\ matrix of the norm map + normmap = matrix(#S,#normgen,i,j, + if( i == 1 && p == 2, + sign(normgen[j]) < 0 + , valuation(normgen[j],S[i]))); +if( DEBUGLEVEL_ell >= 4, print(" normmap = ",normmap)); + +\\ construction of the kernel + kern = matker(normmap*Mod(1,p))*Mod(1,p); +if( DEBUGLEVEL_ell >= 4, print(" ker = ",lift(kern))); + return(kern); +} - ttheta = Mod(x,polrel); \\ ttheta est la racine de P(x) - polprime = Mod(polrel',polrel); +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ +\\ FUNCTIONS FOR 2-DESCENT \\ +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ + +{elllocalimage( nf, pp, K = 1) = +\\ pol is the cubic polynomial defining the elliptic curve, +\\ nf is nfinit(pol), +\\ p is a prime integer, and pp = ppinit(p). +\\ Returns the image of the p-adic points +\\ E(Qp)/2E(Qp) in Kp/Kp^2. +\\ The algorithm consists of choosing random p-adic points in E(Qp) +\\ until the number of images is equal to #E(Qp)[2] / |2|_p +my(X,p,prank,rac,pts,bound,essai,mrank,r,xx,delta,ph,delta2,localprec,ival); + +if( DEBUGLEVEL_ell >= 4, print(" starting elllocalimage")); + + X = Mod('x,nf.pol); + p = pp[1][1][1]; + prank = #pp - (p != 2); +if( DEBUGLEVEL_ell >= 4, print(" prank = ",prank)); + + rac = polrootsmodpn(K*nf.pol,p); +if( DEBUGLEVEL_ell >= 5, print(" rac = ",rac)); + + pts = matrix(0,0); + bound = p+6; + essai = 0; + mrank = 0; + while( mrank < prank, + + essai ++; + if( essai%16 == 0, + pts = matimage(pts); + bound *= p; + ); - KS2gen = factor(S)[,1]~; + r = random(#rac)+1; localprec = random(rac[r][2]+3)-2; + xx = rac[r][1]+p^localprec*random(bound); +if( DEBUGLEVEL_ell >= 5, print(" xx = ",xx)); + delta = K*(xx-X); + +\\ rem: K*pol(xx) = norm(delta) ( = y^2 for a point on the elliptic curve) + if( !psquare(K*subst(nf.pol,'x,xx),p), next); + ph = []; + for( i = 1, #pp, + ph = concat(ph,[ ival = idealval(nf,delta,pp[i][1])]); + delta2 = delta/pp[i][2]^ival; + if( p == 2, + ph = concat(ph,ideallog(nf,delta2,pp[i][3])~); + , ph = concat(ph,[1-nfpsquareodd(nf,delta2,pp[i][4])]) + ) + ); +if( DEBUGLEVEL_ell >= 5, print(" ph = ",ph)); -if( DEBUGLEVEL_ell >= 3, print("#KS2gen = ",#KS2gen)); -if( DEBUGLEVEL_ell >= 3, print("KS2gen = ",KS2gen)); + pts = concat(pts,ph~*Mod(1,2)); + mrank = matrank(pts*Mod(1,2)); +if( DEBUGLEVEL_ell >= 5, print(" pts = ",lift(pts))); +if( DEBUGLEVEL_ell >= 5, print(" matrank = ",mrank)); + ); - LS2genunit = ext.tufu; - LS2genunit = concat(LS2gen[1],LS2genunit); + pts = matimage(pts); +if( DEBUGLEVEL_ell >= 5, print(" essai = ",essai)); +if( DEBUGLEVEL_ell >= 4, print(" end of elllocalimage")); + return(pts); +} +{ell2descent_gen(ell,bnf,K=1,help=[],redflag=0) = +\\ This algorithm performs 2-descent on the elliptic curve ell +\\ when ell has trivial 2-torsion. - LS2genunit = subst(LS2genunit,x,ttheta); - LS2genunit = LS2genunit*Mod(1,polrel); -if( DEBUGLEVEL_ell >= 3, print("#LS2genunit = ",#LS2genunit)); -if( DEBUGLEVEL_ell >= 3, print("LS2genunit = ",LS2genunit)); +\\ ell must be of the form K*y^2=x^3+A*x^2+B*x+C +\\ ie ell=[0,A,0,B,C], with K,A,B,C integers. +\\ bnf is bnfinit(x^3+A*x^2+B*x+C,1). -\\ dans LS2gen, on ne garde que ceux dont la norme -\\ est un carre. +\\ +\\ help is a list of known points (maybe empty) on ell. +\\ if redflag != 0, reduces the elements +\\ of the field Selmer group modulo squares. - normLS2gen = norm(LS2genunit); -if( DEBUGLEVEL_ell >= 4, print("normLS2gen = ",normLS2gen)); +my(A,B,C,polrel,polprime,ttheta,badprimes,S,LS2,selmer,rootapprox,p,pp,locimage,LS2image,listpointstriv,listpoints,iwhile,expo,zc,liftzc,den,point,idealfactorzc,idealzc,baseidealzc,q2,sol,param,q1,pol,redq,q0,pointxx,point2,rang); -\\ matrice de l'application norme +if( DEBUGLEVEL_ell >= 4, print(" starting ell2descent_gen")); - normcoord = matrix(#KS2gen,#normLS2gen); - for( j = 1, #normLS2gen, - normcoord[1,j] = (sign(normLS2gen[j]) < 0); - for( i = 2, #KS2gen, - normcoord[i,j] = valuation(normLS2gen[j],KS2gen[i]))); -if( DEBUGLEVEL_ell >= 4, print("normcoord = ",normcoord)); + if( #ell < 13, ell = ellinit(ell,1)); -\\ construction du noyau de la norme + if( ell.a1 != 0 || ell.a3 != 0, + error(" ell2descent_gen: the curve is not of the form [0,a,0,b,c]")); + if( denominator(ell.a2) > 1 || denominator(ell.a4) > 1 || denominator(ell.a6) >1, + error(" ell2descent_gen: non integral coefficients")); - LS2coordtilda = lift(matker(normcoord*Mod(1,2))); -if( DEBUGLEVEL_ell >= 4, print("LS2coordtilda = ",LS2coordtilda)); - LS2 = vector(#LS2coordtilda[1,],i,0); - for( i = 1, #LS2coordtilda[1,], - aux = 1; - for( j = 1, #LS2coordtilda[,i], - if( sign(LS2coordtilda[j,i]), - aux *= LS2genunit[j])); - LS2[i] = aux - ); -if( DEBUGLEVEL_ell >= 3, print("LS2 = ",LS2)); -if( DEBUGLEVEL_ell >= 3, print("norm(LS2) = ",norm(LS2))); + A = ell.a2; if( DEBUGLEVEL_ell >= 2, print(" A = ",A)); + B = ell.a4; if( DEBUGLEVEL_ell >= 2, print(" B = ",B)); + C = ell.a6; if( DEBUGLEVEL_ell >= 2, print(" C = ",C)); + +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ +\\ Construction of L(S,2) \\ +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ -\\ Reduction des generateurs de LS2 +if( DEBUGLEVEL_ell >= 2, print(); print(" Computing L(S,2)")); - if( redflag, - for( i = 1, #LS2, - LS2[i] = reducemodsquares(LS2[i],2))); + polrel = Pol([1,A,B,C]); + polprime = polrel'; + ttheta = Mod('x,polrel); -\\ Fin de la construction de LS2 + if( !bnf, +if( DEBUGLEVEL_ell >= 3, print(" bnfinit(",polrel,")")); + bnf = bnfinit(polrel,1)); - listgen = LS2; -if( DEBUGLEVEL_ell >= 2, print("LS2gen = ",listgen)); -if( DEBUGLEVEL_ell >= 2, print("#LS2gen = ",#listgen)); - listpoints = []; + badprimes = abs(K*idealadd(bnf,polprime,bnf.index)); +if( DEBUGLEVEL_ell >= 5, print(" badprimes = ",badprimes[1,1])); + S = bnfpSelmer(bnf,badprimes,2); + LS2 = S[1]; S = S[2]; -if( DEBUGLEVEL_ell >= 3, print("(A,B,C) = ",[A,B,C])); +if( DEBUGLEVEL_ell >= 2, print(" L(S,2) = ",LS2)); + +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ +\\ Construction of the Selmer group \\ +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ + +if( DEBUGLEVEL_ell >= 2, print(); print(" Computing the Selmer group")); + +\\ elements with square norm + selmer = kernorm(LS2,vector(#S,i,S[i].p),2); +if( DEBUGLEVEL_ell >= 3, print(" selmer = ",lift(selmer))); + +\\ the first real embedding must be > 0 +\\ since the norm is a square, this is automatic +\\ if there is a single real embedding. + if( bnf.r1 == 3, + rootapprox = polrealrootsisolate(polrel)[1]; + selmer = matintersect(selmer,kersign(LS2,rootapprox))*Mod(1,2); +if( DEBUGLEVEL_ell >= 3, print(" selmer = ",lift(selmer))); + ); + +\\ p-adic points +if( DEBUGLEVEL_ell >= 3, print(" p-adic points")); + badprimes = factorint(badprimes[1,1]*2)[,1]; +if( DEBUGLEVEL_ell >= 2, print(" badprimes = ",badprimes)); + for( i = 1, #badprimes, + p = badprimes[i]; +if( DEBUGLEVEL_ell >= 4, print(" p = ",p)); + pp = ppinit(bnf.nf,p); + locimage = elllocalimage(bnf.nf,pp,K); + LS2image = LS2localimage(bnf.nf,LS2,pp); + locimage = matintersect(LS2image,locimage); + selmer = matintersect( + selmer, + concat( + matker(LS2image), + matinverseimage(LS2image,locimage)*Mod(1,2))); + selmer = matimage(selmer*Mod(1,2)); +if( DEBUGLEVEL_ell >= 4, print(" selmer = ",lift(selmer))); + if( !#selmer, break); + ); + +if( DEBUGLEVEL_ell >= 2, print(" selmer = ",lift(selmer))); +if( DEBUGLEVEL_ell >= 2, print(" Selmer rank = ",#selmer)); \\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ -\\ Recherche de points triviaux. \\ +\\ Search for trivial points \\ \\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ -if( DEBUGLEVEL_ell >= 2, print("Recherche de points triviaux sur la courbe")); - listpointstriv = ratpoint(K^3*subst(polrel,x,x/K),LIMTRIV,0,0); - for( i = 1, #listpointstriv, - if( #listpointstriv[i] == 3, - listpointstriv[i] = [0] - , for( j = 1, 2, listpointstriv[i][j] /= K^j)) - ); - listpointstriv = concat(help,listpointstriv); -if( DEBUGLEVEL_ell >= 1, print("Points triviaux sur la courbe = ",listpointstriv)); - - -\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ -\\ parcours de L(S,2) \\ -\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ - - listpointsmwr = []; - list = [ 6, ell.disc, 0 ]; - m1 = 0; m2 = 0; lastloc = -1; - maskwhile = 1<<#listgen; + if( #selmer, +if( DEBUGLEVEL_ell >= 2, print(); print(" Search for trivial points on the curve")); + listpointstriv = ratpoint(K^3*subst(polrel,'x,'x/K),LIMTRIV,0); + for( i = 1, #listpointstriv, + if( #listpointstriv[i] == 3, + listpointstriv[i] = [0] + , for( j = 1, 2, listpointstriv[i][j] /= K^j)) + ); + listpointstriv = concat(help,listpointstriv); +if( DEBUGLEVEL_ell >= 2, print(" Trivial points on the curve = ",listpointstriv)); + ); + +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ +\\ Run through the Selmer group \\ +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ + +if( DEBUGLEVEL_ell >= 2, print(); print(" Run through the Selmer group")); + + listpoints = []; + selmer = lift(selmer); iwhile = 1; - while( iwhile < maskwhile, -if( DEBUGLEVEL_ell >= 4, print("iwhile = ",iwhile); print("listgen = ",listgen)); - zc = Mod(1,polrel); j = 1; iaux = iwhile; - while( iaux, - if( iaux%2, zc *= listgen[j]); - iaux >>= 1; j++); -if( DEBUGLEVEL_ell >= 2, print(); print("zc = ",zc)); + while( iwhile < 1<<#selmer, +if( DEBUGLEVEL_ell >= 2, print()); +if( DEBUGLEVEL_ell >= 4, print(" iwhile = ",iwhile)); + +\\ the next element zc as an algebraic number modulo squares + + expo = selmer*vectorv(#selmer,i,bittest(iwhile,i-1)); + zc = prod( i = 1, #LS2, LS2[i]^expo[i]); +if( DEBUGLEVEL_ell >= 2, print(" zc = ",zc)); liftzc = lift(zc); - if( redflag, + +\\ Reduction modulo squares + + if( redflag, zc = reducemodsquares(zc,2); liftzc = lift(zc); den = denominator(content(liftzc))^2; zc *= den; liftzc *= den; -if( DEBUGLEVEL_ell >= 2, print("zcred = ",zc)) +if( DEBUGLEVEL_ell >= 2, print(" zc reduced = ",zc)) ); -\\ Est-ce un point trivial ? - ispointtriv = 0; +\\ Does it come from a trivial point ? + for( i = 1, #listpointstriv, point = listpointstriv[i]; if( #point == 2, - if( nfissquare(ext.nf,K*(point[1]-x)*liftzc), -if( DEBUGLEVEL_ell >= 2, print(" vient du point trivial ",point)); - listpointsmwr = concat(listpointsmwr,[point]); - m1++; - if( degre(iwhile) > lastloc, m2++); - found = (ispointtriv = 1); - break + if( nfissquare(bnf.nf,K*(point[1]-'x)*liftzc), +if( DEBUGLEVEL_ell >= 2, print(" comes from the trivial point ",point)); + listpoints = concat(listpoints,[point]); + iwhile = 1 << (degre(iwhile)+1); + next(2) ))); - -\\ Ce n'est pas un point trivial - if( !ispointtriv, -\\ Il faut resoudre une forme quadratique -\\ q2 = matrix(3,3,i,j,trace(zc*ttheta^(i+j-2)/polprime)); -\\if( DEBUGLEVEL_ell >= 4, print("q2 = ",q2)); - idealfactorzc = idealfactor(ext,zc); - idealfactorzc[,2] *= -1; - idealfactorzc[,2] \= 2; - idealzc = idealfactorback(ext,idealfactorzc); - if( idealzc == 1, idealzc = matid(3)); - baseidealzc = vector(3,i,nfbasistoalg(ext,idealzc[,i])); - q2 = matrix(3,3,i,j,trace(zc*baseidealzc[i]*baseidealzc[j]/polprime)); -if( DEBUGLEVEL_ell >= 4, print("q2 = ",q2)); -\\ q2 *= ext.index; -\\ if( DEBUGLEVEL_ell >= 4, print("q2 = ",q2)); -if( DEBUGLEVEL_ell >= 4, print("q2/content(q2) = ",q2/content(q2))); - sol = Qfsolve(q2/content(q2)); -if( DEBUGLEVEL_ell >= 4,print("sol = ",sol)); - if( type(sol) == "t_INT", -if( DEBUGLEVEL_ell >= 3, print("non ELS en ",sol)); - iwhile++; next - ); - -\\ \\\\\\\\\\\ -\\ Construction de la quartique -\\ \\\\\\\\\\\ - q1 = -matrix(3,3,i,j,trace(zc*baseidealzc[i]*baseidealzc[j]*(ttheta+A)/polprime)); - param = Qfparam(q2,sol)*[x^2,x,1]~; - param /= content(param); - pol = param~*q1*param; -if( DEBUGLEVEL_ell >= 2, print(" quartique: ",K,"*Y^2 = ",pol)); - redq = redquartique(pol); -if( DEBUGLEVEL_ell >= 2, print(" reduite: ",K,"*Y^2 = ",redq[1])); - pol = redq[1]; - den = denominator(content(K*pol)); - pol *= den^2; - -\\ \\\\\\\\\\\ -\\ Recherche de points sur la quartique -\\ \\\\\\\\\\\ - - point = ratpoint(K*pol,LIM1,1,0); - if( point != [], - m1++; - if( #point == 2, point = concat(point,[1])); - point = concat(redq[2]*[point[1],point[3]]~,[point[2]/den]~); - param = subst(param,x,x/y)*y^2; - param = subst(subst(param,x,point[1]),y,point[2]); -if( DEBUGLEVEL_ell >= 2, print(" point sur la quartique = ",point)); - param *= K/point[3]; -if( DEBUGLEVEL_ell >= 3, print("reconstruction du point sur la courbe")); - q0 = matrix(3,3,i,j,trace(zc*baseidealzc[i]*baseidealzc[j]*(ttheta^2+A*ttheta+B)/polprime)); - pointxx = param~*q0*param/K; - point2 = [ pointxx, sqrtrat(subst(x^3+A*x^2+B*x+C,x,pointxx)/K)]; -if( DEBUGLEVEL_ell >= 1, print("point sur la courbe = ",point2)); - listpointsmwr = concat(listpointsmwr,[point2]); - if( degre(iwhile) > lastloc, m2++); - found = 1 - , - if( locallysoluble(K*pol), - if( degre(iwhile) > lastloc, m2++; lastloc = degre(iwhile)); - point = ratpoint(K*pol,LIM3,1,1); - if( #point > 0, - m1++; - if( #point == 2, point = concat(point,[1])); - point = concat(redq[2]*[point[1],point[3]]~,[point[2]/den]~); - param = subst(param,x,x/y)*y^2; - param = subst(subst(param,x,point[1]),y,point[2]); -if( DEBUGLEVEL_ell >= 3, print(" point sur la quartique = ",point)); - param *= K/point[3]; -if( DEBUGLEVEL_ell >= 3, print("reconstruction du point sur la courbe")); - q0 = matrix(3,3,i,j,trace(zc*baseidealzc[i]*baseidealzc[j]*(ttheta^2+A*ttheta+B)/polprime)); - pointxx = param~*q0*param/K; - point2 = [ pointxx, sqrtrat(subst(x^3+A*x^2+B*x+C,x,pointxx)/K)]; -if( DEBUGLEVEL_ell >= 1, print("point sur la courbe = ",point2)); - listpointsmwr = concat(listpointsmwr,[point2]); - found = 1 - ) - ) - ) + +if( DEBUGLEVEL_ell >= 2, print(" does not come from a trivial point")); + +\\ Construction of the quadratic form q2 +\\ Change the basis using the square factors of zc + + idealfactorzc = idealfactor(bnf,zc); + idealfactorzc[,2] *= -1; + idealfactorzc[,2] \= 2; +\\ idealzc = idealfactorback(bnf,idealfactorzc); + idealzc = matid(3); + for( i = 1, #idealfactorzc[,1], + idealzc = idealmul(bnf,idealzc,idealpow(bnf,idealfactorzc[i,1],idealfactorzc[i,2])); ); - if( found || ispointtriv, - found = 0; lastloc = -1; - v = 0; iaux = (iwhile>>1); - while( iaux, iaux >>= 1; v++); - maskwhile >>= 1; - listgen = vecextract(listgen,1<<#listgen-1<= 4, print(" q2 = ",q2)); +if( DEBUGLEVEL_ell >= 4, print(" q2/content(q2) = ",q2/content(q2))); + +\\ Solution of the quadratic equation q2=0 + + sol = qfsolve(q2/content(q2)); +if( DEBUGLEVEL_ell >= 4,print(" sol = ",sol)); + if( type(sol) == "t_INT", + error(" ell2descent_gen: WRONG ELEMENT IN THE SELMER GROUP, please report")); + + +\\ Parametrizing the solutions of q2=0 + + param = qfparam(q2,sol)*['x^2,'x,1]~; + param /= content(param); + +\\ Construction of the quartic + + q1 = -matrix(3,3,i,j,trace(zc*baseidealzc[i]*baseidealzc[j]*(ttheta+A)/polprime)); + pol = param~*q1*param; +if( DEBUGLEVEL_ell >= 2, print(" quartic: ",K,"*Y^2 = ",pol)); + redq = redquartic(pol); + pol = redq[1]; + den = denominator(content(K*pol)); + pol *= den^2; +if( DEBUGLEVEL_ell >= 2, print(" reduced: ",K,"*Y^2 = ",pol)); + +\\ Search for points on the quartic + + point = ratpoint(K*pol,LIM1,1); + if( point == [], point = ratpoint2(K*pol,LIM3,1)); + if( point == [], iwhile ++; next ); + + if( #point == 2, point = concat(point,[1])); +if( DEBUGLEVEL_ell >= 2, print(" point on the reduced quartic = ",point)); + point = concat(redq[2]*[point[1],point[3]]~,[point[2]/den]~); +if( DEBUGLEVEL_ell >= 2, print(" point on the quartic = ",point)); + +\\ Construction of the point on the elliptic curve from the point on the quartic + + param = subst(param,'x,'x/'y)*'y^2; + param = subst(subst(param,'x,point[1]),'y,point[2]); + param *= K/point[3]; +if( DEBUGLEVEL_ell >= 3, print(" reconstruction of the point on the curve")); + q0 = matrix(3,3,i,j,trace(zc*baseidealzc[i]*baseidealzc[j]*(ttheta^2+A*ttheta+B)/polprime)); + pointxx = param~*q0*param/K; + point2 = [ pointxx, sqrtrat(subst(polrel,'x,pointxx)/K)]; +if( DEBUGLEVEL_ell >= 1, print(" point on the curve = ",point2)); + listpoints = concat(listpoints,[point2]); + iwhile = 1 << (degre(iwhile)+1) ); +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ +\\ Conclusion report \\ +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ + + rang = #listpoints; + if( DEBUGLEVEL_ell >= 2, print(); - print("rang des points trouves = ",m1); - print("rang du groupe de Selmer = ",m2)); -if( DEBUGLEVEL_ell >= 1, - print("#S(E/Q)[2] = ",1<= 1, - print("#E(Q)/2E(Q) = ",1<= 1, print("listpoints = ",listpoints)); + for( i = 1, #listpoints, + if( subst(polrel,'x,listpoints[i][1])-K*listpoints[i][2]^2, + error(" ell2descent_gen: WRONG POINT = ",listpoints[i]," please report"))); + +\\ Reduction of the points + + listpoints = vecsort(listpoints,,2); + if( #listpoints >= 2 && ELLREDGENFLAG, + listpoints = ellredgen(ell,listpoints,K)); + +if( DEBUGLEVEL_ell >= 4, print(" end of ell2descent_gen")); + return([rang,#selmer,listpoints]); +} +{afficheselmer(m1,m2,tors2) = + + print("#E(Q)[2] = ",1<= ",1<= ",m1)); - rang = m1; - if( (m2-m1)%2, -if( DEBUGLEVEL_ell >= 1, - print(" III devrait etre un carre, donc "); - if( m2-m1 > 1, - print("#E(Q)/2E(Q) >= ",1<<(m1+1)); - print("#III(E/Q)[2] <= ",1<<(m2-m1-1)); - print("rang(E/Q) >= ",m1+1) - , - print("#E(Q)/2E(Q) = ",1<<(m1+1)); - print("#III(E/Q)[2] = 1"); - print("rang(E/Q) = ",m1+1))); - rang = m1+1 - ) + print("#E(Q)/2E(Q) >= ",1<<(m1+tors2)); + print("#III(E/Q)[2] <= ",1<<(m2-m1-tors2)); + print("rank(E/Q) >= ",m1) ); -if( DEBUGLEVEL_ell >= 1, print("listpointsmwr = ",listpointsmwr)); - for( i = 1, #listpointsmwr, - if( subst(polrel,x,listpointsmwr[i][1])-K*listpointsmwr[i][2]^2, - error(" ell2descent_gen : MAUVAIS POINT = ",listpointsmwr[i]))); - if( #listpointsmwr >= 2, - listpointsmwr = ellredgen(ell,listpointsmwr,K)); -if( DEBUGLEVEL_ell >= 4, print("fin de ell2descent_gen")); - return([rang,m2,listpointsmwr]); } -if( DEBUGLEVEL_ell >= 4, print("ellrank")); -{ -ellrank(ell,help=[]) = -\\ Algorithme de la 2-descente sur la courbe elliptique ell. -\\ help est une liste de points connus sur ell. -local(urst,urst1,den,eqell,tors2,bnf,rang,time1); +{ellrank(ell,help=[]) = +\\ Algorithm of 2-descent on the elliptic curve ell. +\\ help is a list of known points on ell. +my(urst,urst1,den,eqell,tors2,bnf,rang,time1); -if( DEBUGLEVEL_ell >= 3, print("entree dans ellrank")); +if( DEBUGLEVEL_ell >= 3, print(" starting ellrank")); if( #ell < 13, ell = ellinit(ell,1)); -\\ supprime les coefficients a1 et a3 +\\ kill the coefficients a1 and a3 urst = [1,0,0,0]; if( ell.a1 != 0 || ell.a3 != 0, urst1 = [1,0,-ell.a1/2,-ell.a3/2]; @@ -1160,7 +1589,7 @@ if( DEBUGLEVEL_ell >= 3, print("entree dans ellrank")); urst = ellcomposeurst(urst,urst1) ); -\\ supprime les denominateurs +\\ kill denominators while( (den = denominator([ell.a2,ell.a4,ell.a6])) > 1, den = factor(den); den[,2] = vectorv(#den[,2],i,1); den = factorback(den); @@ -1171,159 +1600,193 @@ if( DEBUGLEVEL_ell >= 3, print("entree dans ellrank")); help = ellchangepoint(help,urst); eqell = Pol([1,ell.a2,ell.a4,ell.a6]); -if( DEBUGLEVEL_ell >= 1, print("courbe elliptique : Y^2 = ",eqell)); +if( DEBUGLEVEL_ell >= 1, print(" Elliptic curve: Y^2 = ",eqell)); -\\ choix de l'algorithme suivant la 2-torsion +\\ Choice of the algorithm depending on the 2-torsion structure tors2 = ellhalf(ell,[0]); -if( DEBUGLEVEL_ell >= 1, print("E[2] = ",tors2)); +if( DEBUGLEVEL_ell >= 1, print(" E[2] = ",tors2)); - if( #tors2 == 1, \\ cas 1: 2-torsion triviale -if( DEBUGLEVEL_ell >= 3, print1("bnfinit ")); + if( #tors2 == 1, \\ case 1: 2-torsion trivial +if( DEBUGLEVEL_ell >= 3, print1(" bnfinit(",eqell,")")); if( DEBUGLEVEL_ell >= 4, gettime()); bnf = bnfinit(eqell,1); if( DEBUGLEVEL_ell >= 4, time1 = gettime()); -if( DEBUGLEVEL_ell >= 3, print("ok")); +if( DEBUGLEVEL_ell >= 3, print(" done")); rang = ell2descent_gen(ell,bnf,1,help); -if( DEBUGLEVEL_ell >= 4, print("temps dans bnfinit = ",time1)); -if( DEBUGLEVEL_ell >= 4, print("temps pour le reste = ",gettime())); +if( DEBUGLEVEL_ell >= 4, print(" time for bnfinit = ",time1)); +if( DEBUGLEVEL_ell >= 4, print(" time for the rest = ",gettime())); , - if( #tors2 >= 2, \\ cas 2: 2-torsion >= Z/2Z + if( #tors2 == 2 || !COMPLETE, \\ case 2: 2-torsion >= Z/2Z if( ell.a6 != 0, urst1 = [1,tors2[2][1],0,0]; ell = ellchangecurve(ell,urst1); urst = ellcomposeurst(urst,urst1) ); eqell = Pol([1,ell.a2,ell.a4,ell.a6]); -if( DEBUGLEVEL_ell >= 1, print("courbe elliptique : Y^2 = ",eqell)); +if( DEBUGLEVEL_ell >= 1, print(" Elliptic curve: Y^2 = ",eqell)); rang = ell2descent_viaisog(ell,help) - , \\ cas 3: 2-torsion = Z/2Z*Z/2Z -\\ rang = ell2descent_complete(tors2[2][1],tors2[3][2],tors2[4][3]) + , \\ case 3: 2-torsion = Z/2Z*Z/2Z + rang = ell2descent_complete(tors2[2][1],tors2[3][1],tors2[4][1]) )); - rang[3] = ellchangepointinverse(rang[3],urst); -if( DEBUGLEVEL_ell >= 3, print("fin de ellrank")); + rang[3] = ellchangepoint(rang[3],ellinverturst(urst)); +if( DEBUGLEVEL_ell >= 3, print(" end of ellrank")); -return(rang); + return(rang); } -if( DEBUGLEVEL_ell >= 4, print("ell2descent_complete")); -{ -ell2descent_complete(e1,e2,e3) = -\\ calcul du rang d'une courbe elliptique -\\ par la methode de 2-descente complete. -\\ Y^2 = (x-e1)*(x-e2)*(x-e3); -\\ en suivant la methode decrite par J.Silverman -\\ renvoie [r,s,v] avec -\\ r est une borne inferieure du rang de E(Q) -\\ s est le rang du 2-groupe de Selmer -\\ v est un systeme de points independants dans E(Q)/2E(Q) +{ell2descent_complete(e1,e2,e3,help) = +\\ Compute the rank of the elliptic curve +\\ E: Y^2 = (x-e1)*(x-e2)*(x-e3) +\\ using the complete 2-descent algorithm (see J.Silverman). +\\ Returns [r,s,v] with +\\ r is a lower bound for the rank of E(Q) +\\ s is the rank of Selmer[2] +\\ v is a system of independant points on E(Q)/2E(Q) -\\ e1, e2 et e3 sont des entiers. +\\ e1, e2, e3 must be integers. +\\ help is a list of known points on E. -local(d32,d31,d21,G1,G2,vect1,vect2,selmer,rang,listepoints,b1,b2,q1,q2,sol1,param1,param1x,sol2,quart,point,z1,solx,soly,strange); +my(ee,d32,d31,d21,G1,G2,G3,vect1,vect2,vect3,selmer,rang,listpoints,b1,b2,q1,sol1,param1,param1x,quart,point,z1,solx,soly,strange,ell); -if( DEBUGLEVEL_ell >= 2, print("Algorithme de la 2-descente complete")); +if( DEBUGLEVEL_ell >= 2, print(" Algorithm of complete 2-descent")); -\\ calcul des groupes G1 et G2 +\\ sort the integers e1, e2, e3 in increasing order + + ee = vecsort([e1,e2,e3]); + e1 = ee[1]; e2 = ee[2]; e3 = ee[3]; + +\\ Computation of the groups G1 and G2 d32 = e3-e2; d31 = e3-e1; d21 = e2-e1; - G1 = factor(-abs(d31*d21))[,1]; - G2 = factor(-abs(d32*d21))[,1]; + G1 = factor(d31*d21)[,1]; \\ (G1 > 0) + G2 = factor(-d32*d21)[,1]; \\ (G2 < 0) + G3 = d31*d32; -if( DEBUGLEVEL_ell >= 3, print("G1 = ",G1)); -if( DEBUGLEVEL_ell >= 3, print("G2 = ",G2)); +if( DEBUGLEVEL_ell >= 3, print(" G1 = ",G1)); +if( DEBUGLEVEL_ell >= 3, print(" G2 = ",G2)); -\\ parcours de G1*G2 +\\ Run through G1*G2 vect1 = vector(#G1,i,[0,1]); vect2 = vector(#G2,i,[0,1]); selmer = 0; rang = 0; - listepoints = []; + listpoints = []; forvec( X = vect1, b1 = prod( i = 1, #G1, G1[i]^X[i]); - forvec( Y = vect2, + +\\ b1*b2*b3 must be a square, where b3 is a divisor of d32*d31 + vect3 = vect2; + for( i = 2, #G2, + if( G3%G2[i] !=0, + vect3[i] = [1,1]*valuation(b1,G2[i]))); + + forvec( Y = vect3, b2 = prod( i = 1, #G2, G2[i]^Y[i]); -if( DEBUGLEVEL_ell >= 3, print("[b1,b2] = ",lift([b1,b2]))); +if( DEBUGLEVEL_ell >= 3, print(" [b1,b2] = ",lift([b1,b2]))); -\\ points triviaux provenant de la 2-torsion +\\ Trivial points coming from the 2-torsion if( b1==1 && b2==1, -if( DEBUGLEVEL_ell >= 4, print(" point trivial [0]")); +if( DEBUGLEVEL_ell >= 4, print(" trivial point [0]")); selmer++; rang++; next); if( issquare(-d21*b2) && issquare(d31*d21*b1), -if( DEBUGLEVEL_ell >= 3, print(" point trivial [e1,0]")); - selmer++; rang++; listepoints = concat(listepoints,[[e1,0]]); next); +if( DEBUGLEVEL_ell >= 3, print(" trivial point [e1,0]")); + selmer++; rang++; listpoints = concat(listpoints,[[e1,0]]); next); if( issquare(d21*b1) && issquare(-d32*d21*b2), -if( DEBUGLEVEL_ell >= 3, print(" point trivial [e2,0]")); - selmer++; rang++; listepoints = concat(listepoints,[[e2,0]]); next); +if( DEBUGLEVEL_ell >= 3, print(" trivial point [e2,0]")); + selmer++; rang++; listpoints = concat(listpoints,[[e2,0]]); next); if( issquare(d31*b1) && issquare(d32*b2), -if( DEBUGLEVEL_ell >= 3, print(" point trivial [e3,0]")); - selmer++; rang++; listepoints = concat(listepoints,[[e3,0]]); next); +if( DEBUGLEVEL_ell >= 3, print(" trivial point [e3,0]")); + selmer++; rang++; listpoints = concat(listpoints,[[e3,0]]); next); -\\ il faut resoudre 2 equations quadratiques: -\\ (1) b1*z1^2-b2*z2^2 = e2-e1 -\\ (2) b1*z1^2-b1*b2*z3^2 = e3-e1 -\\ on aura alors (x,y) = (b1*z1^2+e1,b1*b2*z1*z2*z3) +\\ Trivial points coming from help - q1 = matdiagonal([b1,-b2,-d21]); -if( DEBUGLEVEL_ell >= 3, print(" q1 = ",q1)); - q2 = matdiagonal([b1,-b1*b2,-d31]); -if( DEBUGLEVEL_ell >= 3, print(" q2 = ",q2)); + for( i = 1, #help, + if( #help[i] != 2 || help[i][2] == 0, next); + if( issquare(b1*(help[i][1]-e1)) && issquare(b2*(help[i][1]-e2)), +if( DEBUGLEVEL_ell >= 3, print(" trivial point from help ",help[i])); + selmer++; rang++; + listpoints = concat(listpoints,[help[i]]); next(2)); + ); -\\ solution de la premiere forme quadratique +\\ If one can solve 2 quadratic equations +\\ (1) q1: b1*z1^2-b2*z2^2 = e2-e1 +\\ (2) q2: b1*z1^2-b1*b2*z3^2 = e3-e1 +\\ then (x,y) = (b1*z1^2+e1,b1*b2*z1*z2*z3) is a point on E +\\ we also have +\\ (3) q3 = q1-q2: b1*b2*z3^2-b2*z2^2=e2-e3 - sol1 = Qfsolve(q1); +\\ Solution of the q1 + + q1 = matdiagonal([b1,-b2,-d21]); +if( DEBUGLEVEL_ell >= 3, print(" q1 = ",q1)); + sol1 = qfsolve(q1); if( type(sol1) == "t_INT", -if( DEBUGLEVEL_ell >= 3, print(" q1 non ELS en ",sol1)); - next); -if( DEBUGLEVEL_ell >= 3, print(" sol part de q1 = ",sol1)); - param1 = Qfparam(q1,sol1,1); -if( DEBUGLEVEL_ell >= 3, print(" param de q1 = ",param1)); - param1x = param1*[x^2,x,1]~; - - sol2 = Qfsolve(q2); - if( type(sol2) == "t_INT", -if( DEBUGLEVEL_ell >= 3, print(" q2 non ELS en ",sol2)); +if( DEBUGLEVEL_ell >= 3, print(" q1 not ELS at ",sol1)); next); +if( DEBUGLEVEL_ell >= 3, print(" solution of q1 = ",sol1)); + param1 = qfparam(q1,sol1,1); + param1 /= content(param1); +if( DEBUGLEVEL_ell >= 3, print(" parametrization of q1 = ",param1)); + param1x = param1*['x^2,'x,1]~; + +\\ Solution of the q2 +\\ only useful to detect local non solubility + +\\ my(q2,sol2); +\\ q2 = matdiagonal([b1,-b1*b2,-d31]); +\\if( DEBUGLEVEL_ell >= 3, print(" q2 = ",q2)); +\\ sol2 = qfsolve(q2); +\\ if( type(sol2) == "t_INT", +\\if( DEBUGLEVEL_ell >= 3, print(" q2 not ELS at ",sol2)); +\\ next); + +\\ Construction of the quartic + + quart = b1*b2/gcd(b1,b2)^2*(b1*param1x[1]^2-d31*param1x[3]^2); +if( DEBUGLEVEL_ell >= 3, print(" quart = ",quart)); - quart = b1*b2*(b1*param1x[1]^2-d31*param1x[3]^2); -if( DEBUGLEVEL_ell >= 3, print(" quart = ",quart)); +\\ Search for trivial points on the quartic -\\ la quartique est-elle localement soluble ? + point = []; +\\ point = ratpoint(quart,LIM1,1); - if( !locallysoluble(quart), -if( DEBUGLEVEL_ell >= 3, print(" quartique non ELS ")); +\\ Local solubility of the quartic + + if( point == [] && !locallysoluble(quart), +if( DEBUGLEVEL_ell >= 3, print(" quartic not ELS ")); next); -if( DEBUGLEVEL_ell >= 2, print(" y^2 = ",quart)); +if( DEBUGLEVEL_ell >= 2, print(" y^2 = ",quart)); selmer++; -\\ recherche de points sur la quartique. +\\ Search for points on the quartic - point = ratpoint(quart,LIM3,1); - if( point != [], -if( DEBUGLEVEL_ell >= 2, print("point trouve sur la quartique !!")); -if( DEBUGLEVEL_ell >= 3, print(point)); + if( point == [], point = ratpoint2(quart,LIM3,1)); + if( point != [], +if( DEBUGLEVEL_ell >= 2, print(" point found on the quartic !!")); +if( DEBUGLEVEL_ell >= 3, print(" ",point)); if( #point == 2, - z1 = subst(param1x[1],x,point[1])/subst(param1x[3],x,point[1]) + z1 = subst(param1x[1],'x,point[1])/subst(param1x[3],'x,point[1]) , z1 = param1[1,1]/param1[3,1]); solx = b1*z1^2+e1; soly = sqrtrat((solx-e1)*(solx-e2)*(solx-e3)); - listepoints = concat(listepoints,[[solx,soly]]); -if( DEBUGLEVEL_ell >= 1, print("point sur la courbe elliptique = ",[solx,soly])); + listpoints = concat(listpoints,[[solx,soly]]); +if( DEBUGLEVEL_ell >= 1, print(" point on the elliptic curve = ",[solx,soly])); rang++ , -if( DEBUGLEVEL_ell >= 2, print("aucun point trouve sur la quartique")) +if( DEBUGLEVEL_ell >= 2, print(" no point found on the quartic")) ) ) ); -\\ fin +\\ end -if( DEBUGLEVEL_ell >= 1, +if( DEBUGLEVEL_ell >= 1, print("#S^(2) = ",selmer)); if( rang > selmer/2, rang = selmer); if( DEBUGLEVEL_ell >= 1, @@ -1337,24 +1800,23 @@ if( DEBUGLEVEL_ell >= 1, selmer = valuation(selmer,2); if( DEBUGLEVEL_ell >= 1, if( strange, - print(selmer-2," >= rang >= ",rang) -, print("rang = ",rang)); - if( rang, print("points = ",listepoints)); + print(selmer-2," >= rank >= ",rang) +, print("rank = ",rang)); + if( rang, print("points = ",listpoints)); ); - ell = ellinit([0,-(e1+e2+e3),0,e1*e2+e2*e3+e3*e1,-e1*e2*e3]); - if( ELLREDGENFLAG, listepoints = ellredgen(ell,listepoints)); - listepoints = concat(ellsort(elltorseven(ell)[3]),listepoints); + ell = ellinit([0,-(e1+e2+e3),0,e1*e2+e2*e3+e3*e1,-e1*e2*e3],1); + listpoints = vecsort(listpoints,,2); + if( ELLREDGENFLAG, listpoints = ellredgen(ell,listpoints)); + listpoints = concat(ellsort(elltorseven(ell)[3]),listpoints); -return([rang,selmer,listepoints]); + return([rang,selmer,listpoints]); } -if( DEBUGLEVEL_ell >= 4, print("ellcount")); -{ -ellcount( c, d, KS2gen, listpointstriv=[]) = -local(found,listgen,listpointscount,m1,m2,lastloc,mask,i,d1,iaux,j,triv,pol,point,deuxpoints,v); +{ellcount( c, d, KS2gen, listpointstriv=[]) = +my(found,listgen,listpointscount,m1,m2,lastloc,mask,i,d1,iaux,j,triv,pol,point,qf,solqf,para,point1,v); -if( DEBUGLEVEL_ell >= 4, print("entree dans ellcount ",[c,d])); -if( DEBUGLEVEL_ell >= 4, print("KS2gen = ",KS2gen)); -if( DEBUGLEVEL_ell >= 4, print("listpointstriv = ",listpointstriv)); +if( DEBUGLEVEL_ell >= 4, print(" starting ellcount ",[c,d])); +if( DEBUGLEVEL_ell >= 4, print(" KS2gen = ",KS2gen)); +if( DEBUGLEVEL_ell >= 4, print(" listpointstriv = ",listpointstriv)); found = 0; listgen = KS2gen; @@ -1366,25 +1828,25 @@ if( DEBUGLEVEL_ell >= 4, print("listpointstriv = ",listpointstriv)); i = 1; while( i < mask, d1 = 1; iaux = i; j = 1; - while( iaux, + while( iaux, if( iaux%2, d1 *= listgen[j]); iaux >>= 1; j++); -if( DEBUGLEVEL_ell >= 2, print("d1 = ",d1)); +if( DEBUGLEVEL_ell >= 3, print(" d1 = ",d1)); triv = 0; for( j = 1, #listpointstriv, if( listpointstriv[j][1] && issquare(d1*listpointstriv[j][1]), listpointscount = concat(listpointscount,[listpointstriv[j]]); -if( DEBUGLEVEL_ell >= 2, print("point trivial")); +if( DEBUGLEVEL_ell >= 2, print(" trivial point")); triv = 1; m1++; if( degre(i) > lastloc, m2++); found = 1; lastloc = -1; break)); if( !triv, pol = Pol([d1,0,c,0,d/d1]); -if( DEBUGLEVEL_ell >= 3, print("quartique = y^2 = ",pol)); +if( DEBUGLEVEL_ell >= 3, print(" quartic = y^2 = ",pol)); point = ratpoint(pol,LIM1,1); if( point != [], -if( DEBUGLEVEL_ell >= 2, print("point sur la quartique")); -if( DEBUGLEVEL_ell >= 3, print(point)); +if( DEBUGLEVEL_ell >= 2, print(" point on the quartic")); +if( DEBUGLEVEL_ell >= 3, print( point)); m1++; listpointscount = concat(listpointscount,[d1*point[1]*point]); if( degre(i) > lastloc, m2++); @@ -1392,16 +1854,37 @@ if( DEBUGLEVEL_ell >= 3, print(point)); , if( locallysoluble(pol), if( degre(i) > lastloc, m2++; lastloc = degre(i)); - point = ratpoint(pol,LIM3,1); +\\ point = ratpoint2(pol,LIM3,1); +\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ +\\ Instead of solving directly y^2 = d1*x^4+c*x^2+d/d1, +\\ we solve first y^2 = d1*X^2+c*X+d/d1, then solve the quartic X = x^2 +\\ which gives a new quartic + qf = 2*[d1,c/2,0;c/2,d/d1,0;0,0,-1]; + solqf = qfsolve(qf); + para = qfparam(qf,solqf,2)*['x^2,'x,1]~; +if( DEBUGLEVEL_ell >= 3, + print(" the conic y^2 = ",Pol([d1,c,d/d1])); + print(" is parametrized by [x,y] = "subst([para[1]/para[2],para[3]/para[2]],'x,'t))); + point1 = ratpoint2(para[1]*para[2],LIM3,1); + if( point1 != [], + if(#point1 == 2, + para = subst(para,'x,point1[1]) + , point1 = [1,point1[2]/point1[1]^2,0]; + para = vector(3,ii,polcoeff(para[ii],2)) + ); + point = [point1[2]/para[2],para[3]/para[2]]; + , point = []; + ); +\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ if( point != [], -if( DEBUGLEVEL_ell >= 2, print("point sur la quartique")); -if( DEBUGLEVEL_ell >= 3, print(point)); +if( DEBUGLEVEL_ell >= 2, print(" point on the quartic")); +if( DEBUGLEVEL_ell >= 3, print( point)); m1++; listpointscount = concat(listpointscount,[d1*point[1]*point]); if( degre(i) > lastloc, m2++); found = 1; lastloc = -1 , -if( DEBUGLEVEL_ell >= 2, print(" pas de point trouve sur la quartique")) +if( DEBUGLEVEL_ell >= 2, print(" no point found on the quartic")) )))); if( found, found = 0; @@ -1415,66 +1898,67 @@ if( DEBUGLEVEL_ell >= 2, print(" pas de point trouve sur la quartique")) for( i = 1, #listpointscount, if( #listpointscount[i] > 1, - if( subst(x^3+c*x^2+d*x,x,listpointscount[i][1])-listpointscount[i][2]^2 != 0, - error(" ellcount : MAUVAIS POINT ")))); -if( DEBUGLEVEL_ell >= 4, print("fin de ellcount")); + if( subst('x^3+c*'x^2+d*'x,'x,listpointscount[i][1])-listpointscount[i][2]^2 != 0, + error(" ellcount: WRONG POINT, please report ",i)))); +if( DEBUGLEVEL_ell >= 4, print(" end of ellcount")); + return([listpointscount,[m1,m2]]); } -if( DEBUGLEVEL_ell >= 4, print("ell2descent_viaisog")); -{ -ell2descent_viaisog(ell,help=[]) = -\\ Calcul du rang des courbes elliptiques avec 2-torsion -\\ par la methode des 2-isogenies. -\\ -\\ ell = [a1,a2,a3,a4,a6] -\\ y^2+a1xy+a3y=x^3+a2x^2+a4x+a6 +{ell2descent_viaisog(ell,help=[]) = +\\ Computation of the rank of the elliptic curve ell +\\ having rational 2-torsion, using the algorithm via 2-isogenies. \\ -\\ ell doit etre sous la forme +\\ ell must be on the form \\ y^2=x^3+ax^2+bx -> ell = [0,a,0,b,0] -\\ avec a et b entiers. -local(i,P,Pfact,tors,listpointstriv,apinit,bpinit,plist,KS2prod,oddclass,KS2gen,listpoints,pointgen,n1,n2,certain,np1,np2,listpoints2,aux1,aux2,certainp,rang,strange); +\\ with a and b integers. + +my(P,Pfact,tors,listpointstriv,KS2prod,KS2gen,listpoints,pointgen,n1,n2,certain,apinit,bpinit,np1,np2,listpoints2,aux1,aux2,certainp,rang,strange); -if( DEBUGLEVEL_ell >= 2, print("Algorithme de la 2-descente par isogenies")); +if( DEBUGLEVEL_ell >= 2, print(" Algorithm of 2-descent via isogenies")); if( #ell < 13, ell = ellinit(ell,1)); if( ell.disc == 0, - error(" ell2descent_viaisog : courbe singuliere !!")); - if( ell.a1 != 0 || ell.a3 != 0 || ell.a6 != 0, - error(" ell2descent_viaisog : la courbe n'est pas sous la forme [0,a,0,b,0]")); + error(" ell2descent_viaisog: singular curve !!")); + if( ell.a1 != 0 || ell.a3 != 0 || ell.a6 != 0, + error(" ell2descent_viaisog: the curve is not on the form [0,a,0,b,0]")); if( denominator(ell.a2) > 1 || denominator(ell.a4) > 1, - error(" ell2descent_viaisog : coefficients non entiers")); + error(" ell2descent_viaisog: non-integral coefficients")); + +\\ +\\ Working with the initial curve +\\ + +\\ Construction of trivial points: torsion P = Pol([1,ell.a2,ell.a4]); Pfact = factor(P)[,1]; tors = #Pfact; listpointstriv = concat(help,elltorseven(ell)[3]); - apinit = -2*ell.a2; bpinit = ell.a2^2-4*ell.a4; - - plist = factor(6*ell.disc)[,1]; +\\ Construction of trivial points: small naive height -if( DEBUGLEVEL_ell >= 3, print(" Recherche de points triviaux sur la courbe")); - P *= x; -if( DEBUGLEVEL_ell >= 3, print("Y^2 = ",P)); +if( DEBUGLEVEL_ell >= 3, print(" Search for trivial points on the curve")); + P *= 'x; +if( DEBUGLEVEL_ell >= 3, print(" Y^2 = ",P)); listpointstriv = concat( listpointstriv, ratpoint(P,LIMTRIV,0)); -if( DEBUGLEVEL_ell >= 1, print("points triviaux sur E(Q) = ",listpointstriv); print()); +if( DEBUGLEVEL_ell >= 1, print(" trivial points on E(Q) = ",listpointstriv); print()); KS2prod = -abs(ell.a4); - if( bpinit < 0, KS2prod = -KS2prod); + if( ell.a2^2-4*ell.a4 < 0, KS2prod *= -1); KS2gen = factor(KS2prod)[,1]; if( DEBUGLEVEL_ell >= 2, - print("#K(b,2)gen = ",#KS2gen); - print("K(b,2)gen = ",KS2gen)); + print(" #K(b,2)gen = ",#KS2gen); + print(" K(b,2)gen = ",KS2gen)); listpoints = ellcount(ell.a2,ell.a4,KS2gen,listpointstriv); pointgen = listpoints[1]; -if( DEBUGLEVEL_ell >= 1, print("points sur E(Q) = ",pointgen); print()); +if( DEBUGLEVEL_ell >= 1, print(" points on E(Q) = ",pointgen); print()); n1 = listpoints[2][1]; n2 = listpoints[2][2]; certain = (n1 == n2); if( DEBUGLEVEL_ell >= 1, - if( certain, + if( certain, print("[E(Q):phi'(E'(Q))] = ",1<= 1, print("#III(E'/Q)[phi'] <= ",1<<(n2-n1)); print()) ); +\\ +\\ Working with the isogeneous curve +\\ + + apinit = -2*ell.a2; bpinit = ell.a2^2-4*ell.a4; KS2prod = -abs(bpinit); - if( ell.a4 < 0, KS2prod = -KS2prod); + if( ell.a4 < 0, KS2prod *= -1); KS2gen = factor(KS2prod)[,1]; if( DEBUGLEVEL_ell >= 2, - print("#K(a^2-4b,2)gen = ",#KS2gen); - print("K(a^2-4b,2)gen = ",KS2gen)); + print(" #K(a^2-4b,2)gen = ",#KS2gen); + print(" K(a^2-4b,2)gen = ",KS2gen)); + +\\ Construction of trivial points: torsion P = Pol([1,apinit,bpinit]); listpointstriv = elltorseven([0,apinit,0,bpinit,0])[3]; + +\\ Construction of trivial points: small naive height -if( DEBUGLEVEL_ell >= 3, print(" Recherche de points triviaux sur la courbe")); - P *= x; -if( DEBUGLEVEL_ell >= 3, print("Y^2 = ",P)); +if( DEBUGLEVEL_ell >= 3, print(" Search for trivial points on the curve")); + P *= 'x; +if( DEBUGLEVEL_ell >= 3, print(" Y^2 = ",P)); listpointstriv = concat( listpointstriv, ratpoint(P,LIMTRIV,0)); -if( DEBUGLEVEL_ell >= 1, print("points triviaux sur E'(Q) = ",listpointstriv); print()); +if( DEBUGLEVEL_ell >= 1, print(" trivial points on E'(Q) = ",listpointstriv); print()); listpoints = ellcount(apinit,bpinit,KS2gen,listpointstriv); -if( DEBUGLEVEL_ell >= 1, print("points sur E'(Q) = ",listpoints[1])); + +if( DEBUGLEVEL_ell >= 1, print(" points on E'(Q) = ",listpoints[1])); np1 = listpoints[2][1]; np2 = listpoints[2][2]; listpoints2 = vector(#listpoints[1],i,0); for( i = 1, #listpoints[1], @@ -1513,7 +2007,7 @@ if( DEBUGLEVEL_ell >= 1, print("points sur E'(Q) = ",listpoints[1])); listpoints2[i][1] = aux2^2/aux1/4; listpoints2[i][2] = aux2*(bpinit-aux1)/aux1/8 , listpoints2[i] = listpoints[1][i])); -if( DEBUGLEVEL_ell >= 1, print("points sur E(Q) = ",listpoints2); print()); +if( DEBUGLEVEL_ell >= 1, print(" points on E(Q) = ",listpoints2); print()); pointgen = concat(pointgen,listpoints2); certainp = (np1 == np2); @@ -1538,17 +2032,17 @@ if( DEBUGLEVEL_ell >= 1, if( DEBUGLEVEL_ell >= 1, if( certain && certainp, print("#E(Q)/2E(Q) = ",(1<<(rang+tors))); - print("rang = ",rang); print() + print("rank = ",rang); print() , print("#E(Q)/2E(Q) >= ",(1<<(rang+tors))); print(); - print(rang," <= rang <= ",n2+np2-2); print() + print("",rang," <= rank <= ",n2+np2-2); print() )); strange = (n2+np2-n1-np1)%2; - if( strange, + if( strange, if( DEBUGLEVEL_ell >= 1, - print(" !!! III doit etre un carre !!!"); print("donc")); - if( certain, + print(" !!! III should be a square !!!"); print("hence")); + if( certain, np1++; certainp = (np1 == np2); if( DEBUGLEVEL_ell >= 1, @@ -1565,7 +2059,7 @@ if( DEBUGLEVEL_ell >= 1, if( certainp, n1++; certain = (n1 == n2); -if( DEBUGLEVEL_ell >= 1, +if( DEBUGLEVEL_ell >= 1, if( certain, print("[E(Q):phi'(E'(Q))] = ",1<= ",(1<<(rang+tors))); print(); - print(rang," <= rang <= ",n2+np2-2); print()) + print(rang," <= rank <= ",n2+np2-2); print()) )); -\\ fin de strange - +\\ end of strange + + pointgen = vecsort(pointgen,,2); if( ELLREDGENFLAG, pointgen = ellredgen(ell,pointgen)); pointgen = concat(ellsort(elltorseven(ell)[3]),pointgen); if( DEBUGLEVEL_ell >= 1, print("points = ",pointgen)); -if( DEBUGLEVEL_ell >= 3, print("fin de ell2descent_viaisog")); +if( DEBUGLEVEL_ell >= 3, print(" end of ell2descent_viaisog")); + return([rang,n2+np2-2+tors,pointgen]); } +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ +\\ HELP MESSAGES \\ +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ + +{ +\\ functions for elliptic curves + addhelp(ell2descent_complete, + "ell2descent_complete(e1,e2,e3): Performs a complete 2-descent on the elliptic curve y^2 = (x-e1)*(x-e2)*(x-e3). See ?ellrank for the format of the output."); + addhelp(ell2descent_gen, + "ell2descent_gen((E,bnf,k=1,help=[]): E is a vector of the form [0,A,0,B,C], (or the result of ellinit of such a vector) A,B,C integers such that x^3+A*x^2+B*x+C; bnf is the corresponding bnfinit(,1); Performs 2-descent on the elliptic curve Ek: k*y^2=x^3+A*x^2+B*x+C. See ?ellrank for the format of the output."); + addhelp(ell2descent_viaisog, + "ell2descent_viaisog(E,help=[]): E is an elliptic curve of the form [0,a,0,b,0], with a, b integers. Performs a 2-descent via isogeny on E. See ?ellrank for the format of the output."); + addhelp(ellrank, + "ellrank(E,help=[]): E is any elliptic curve defined over Q. Returns a vector [r,s,v], where r is a lower bound for the rank of E, s is the rank of its 2-Selmer group and v is a list of independant points in E(Q)/2E(Q). If help is a vector of nontrivial points on E, the result might be faster. This function might be used in conjunction with elltors2(E). See also ?default_ellQ"); + addhelp(ellhalf, + "ellhalf(E,P): returns the vector of all points Q on the elliptic curve E such that 2Q = P"); + addhelp(ellredgen, + "ellredgen(E,v): returns a vector of smallest possible points on the elliptic curve E generating the same subgroup as v, up to torsion."); + addhelp(ellsort, + "ellsort(v): v being a vector of points on some elliptic curve, returns the vector v sorted according to the naive height."); + addhelp(elltors2, + "elltors2(E): for an elliptic curve E, returns the group E(K)[2], where K is the field of definition of the coefficients of E (Q, R, Qp or Fp)."); + addhelp(elltorseven, + "elltorseven(E): for an elliptic curve E, returns 2-Sylow subgroup of E(K)_tors, where K is the field of definition of the coefficients of E: (Q, R, Qp or Fp)."); + + +\\ functions for polynomials + addhelp(locallysoluble, + "locallysoluble(pol): returns 1 if y^2=pol(x) is everywhere locally soluble, 0 otherwise."); + addhelp(ratpoint, + "ratpoint(pol,lim=1,singlepoint=1): search for rational points on y^2=pol(x), for about within the bounds given by lim. The coefficients of pol must be integral. If singlepoint=1, returns at most one point, otherwise as many as possible."); + addhelp(redquartic, + "redquartic(pol): reduction of the quartic pol using Cremona-Stoll algorithm. Returns [p,M], where p is the reduced quartic and M is the GL2(Z) transformation. Also works with other degree polynomials."); + + +\\ functions for number fields + addhelp(bnfpSelmer, + "bnfpSelmer(K,S,p): K being a number field given by bnfinit, S an ideal of K, and p a prime number, computes a set of generators of the group K(S,p) = { x in K^* / K^*^p, v_P(x) = 0 (mod p) for all P coprime to S}"); + addhelp(reducemodsquares, + "reducemodsquares(delta,d): delta being a t_POLMOD, returns another delta'=delta*z^2, such that delta' has a small coefficient in x^d."); + + +\\ others + addhelp(default_ellQ, + "default_ellQ(DEBUGLEVEL_ell, LIM1, LIM3, LIMTRIV, ELLREDGENFLAG, COMPLETE, MAXPROB, LIMBIGPRIME): set the value of the global variables used for ellrank() and other related functions. DEBUGLEVEL_ell: 0-5: choose the quantity of information printed during the computation (default=0: print nothing); LIM1 (resp LIM3): search limit for easy (resp hard) points on quartics; LIMTRIV: search limit for trivial points on elliptic curves; ELLREDGENFLAG: if != 0, try to reduce the generators at the end; COMPLETE: if != 0 and full 2-torsion, use complete 2-descent, otherwise via 2-isogeny; MAXPROB, LIMBIGPRIME: technical."); +/* addhelp(DEBUGLEVEL_ell, + "DEBUGLEVEL_ell: Choose a higher value of this global variable to have more details of the computations printed during the 2-descent algorithm. 0 = don't print anything; 1 = (default) just print the result; 2 = print more details including the Selmer group and the nontrivial quartics."); +*/ +} diff --git a/src/ext/pari/simon/ellcommon.gp b/src/ext/pari/simon/ellcommon.gp new file mode 100644 index 00000000000..968e4cf5cf5 --- /dev/null +++ b/src/ext/pari/simon/ellcommon.gp @@ -0,0 +1,126 @@ +\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ +\\ Copyright (C) 2014 Denis Simon +\\ +\\ Distributed under the terms of the GNU General Public License (GPL) +\\ +\\ This code is distributed in the hope that it will be useful, +\\ but WITHOUT ANY WARRANTY; without even the implied warranty of +\\ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +\\ General Public License for more details. +\\ +\\ The full text of the GPL is available at: +\\ +\\ http://www.gnu.org/licenses/ +\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ + +/* + Auteur : + Denis SIMON -> simon@math.unicaen.fr + adresse du fichier : + www.math.unicaen.fr/~simon/ell.gp + + ********************************************* + * VERSION 13/01/2014 * + ********************************************* + +*/ + +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ +\\ SCRIPT \\ +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ + +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ +\\ COMMON FUNCTIONS TO ell.gp AND ellQ.gp \\ +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ + +{ellcomposeurst(urst1,urst2) = +my(u1 = urst1[1], r1 = urst1[2], s1 = urst1[3], t1 = urst1[4], + u2 = urst2[1], r2 = urst2[2], s2 = urst2[3], t2 = urst2[4]); + [u1*u2,u1^2*r2+r1,u1*s2+s1,u1^3*t2+s1*u1^2*r2+t1]; +} +{ellinverturst(urst) = +my(u = urst[1], r = urst[2], s = urst[3], t = urst[4]); + [1/u,-r/u^2,-s/u,(r*s-t)/u^3]; +} +{mysubst(polsu,subsx) = + if( type(lift(polsu)) == "t_POL", + return(simplify(subst(lift(polsu),variable(lift(polsu)),subsx))) + , return(simplify(lift(polsu)))); +} +{degre(idegre) = +my(ideg = idegre, jdeg = 0); + + while( ideg >>= 1, jdeg++); + return(jdeg); +} +{nfrealsign(nf,a,i) = +\\ return the sign of the algebraic number a in the i-th real embedding. +my(nf_roots,ay,prec0); + + if( a == 0, return(0)); + + a = lift(a); + if( type(a) != "t_POL", + return(sign(a))); + + nf_roots = nf.roots; + prec0 = default(realprecision); + + ay = 0; + while( ay == 0 || precision(ay) < 10, + + ay = subst(a,variable(a),nf_roots[i]); + + if( ay == 0 || precision(ay) < 10, +if( DEBUGLEVEL_ell >= 3, + print(" **** Warning: doubling the real precision in nfrealsign **** ", + 2*default(realprecision))); + default(realprecision,2*default(realprecision)); + nf_roots = real(polroots(nf.pol)) + ) + ); + default(realprecision,prec0); + + return(sign(ay)); +} +{nfsqrt( nf, a) = +\\ if a is a square in the number field nf returns [sqrt(a)], otherwise []. +my(alift,ta,minpola,py,pfact); + + if( a==0 || a==1, return([a])); + + alift = lift(a); + ta = type(a); + if( !poldegree(alift), alift = polcoeff(alift,0)); + + if( type(alift) != "t_POL", + if( issquare(alift), return([sqrtrat(alift)]))); + + if( poldegree(nf.pol) <= 1, return([])); + if( ta == "t_POL", a = Mod(a,nf.pol)); + +\\ the norm should be a square + + if( !issquare(norm(a)), return([])); + +\\ the real embeddings must all be >0 + + minpola = minpoly(a); + if( polsturm(minpola,,0), return([])); + +\\ factorization over nf of the polynomial X^2-a + + if( variable(nf.pol) == 'x, + py = subst(nf.pol,'x,'y); + pfact = lift(factornf('x^2-mysubst(alift,Mod('y,py)),py)[1,1]) + , + pfact = lift(factornf('x^2-a,nf.pol)[1,1])); + if( poldegree(pfact) == 2, return([])); + return([subst(polcoeff(pfact,0),'y,Mod(variable(nf.pol),nf.pol))]); +} +{nfissquare(nf, a) = #nfsqrt(nf,a) > 0; +} +{sqrtrat(a) = + sqrtint(numerator(a))/sqrtint(denominator(a)); +} + diff --git a/src/ext/pari/simon/qfsolve.gp b/src/ext/pari/simon/qfsolve.gp index 4d480b0cfb3..6dcfae85971 100644 --- a/src/ext/pari/simon/qfsolve.gp +++ b/src/ext/pari/simon/qfsolve.gp @@ -1,5 +1,5 @@ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ -\\ Copyright (C) 2007 Denis Simon +\\ Copyright (C) 2014 Denis Simon \\ \\ Distributed under the terms of the GNU General Public License (GPL) \\ @@ -13,336 +13,384 @@ \\ http://www.gnu.org/licenses/ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ -\\ -\\ Auteur: -\\ Denis SIMON -> simon@math.unicaen.fr -\\ adresse du fichier: -\\ www.math.unicaen.fr/~simon/qfsolve.gp -\\ -\\ ********************************************* -\\ * VERSION 02/10/2009 * -\\ ********************************************* -\\ -\\ Programme de resolution des equations quadratiques -\\ langage: GP -\\ pour l'utiliser, lancer gp, puis taper -\\ \r qfsolve.gp -\\ -\\ Ce fichier contient 4 principales fonctions: -\\ -\\ - Qfsolve(G,factD): pour resoudre l'equation quadratique X^t*G*X = 0 -\\ G doit etre une matrice symetrique n*n, a coefficients dans Z. -\\ S'il n'existe pas de solution, la reponse est un entier -\\ indiquant un corps local dans lequel aucune solution n'existe -\\ (-1 pour les reels, p pour Q_p). -\\ Si on connait la factorisation de -abs(2*matdet(G)), -\\ on peut la passer par le parametre factD pour gagner du temps. -\\ -\\ - Qfparam(G,sol,fl): pour parametrer les solutions de la forme -\\ quadratique ternaire G, en utilisant la solution particuliere sol. -\\ si fl>0, la 'fl'eme forme quadratique est reduite. -\\ -\\ - IndefiniteLLL(G,c): pour resoudre ou reduire la forme quadratique -\\ G a coefficients entiers. Il s'agit d'un algorithme type LLL, avec la -\\ constante 1/4 simon@math.unicaen.fr + address of the file: + www.math.unicaen.fr/~simon/qfsolve.gp + + ********************************************* + * VERSION 09/01/2014 * + ********************************************* + + \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ + \\ English help \\ + \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ + + This package provides functions to solve quadratic equations over Q. + language: GP + It can be run under GP by the command + gp > \r qfsolve.gp + + This package contains 4 main functions: + + - qfsolve(G,{factD}): Solve over Q the quadratic equation X~*G*X = 0. + G must be a symmetric matrix n*n, with coefficients in Z. + The solution might be a single vector (vectorv) + or a matrix (whose columns generate a totally isotropic subspace). + If no solution exists, the output is a prime number + indicating that there is no solution in the local field Q_p + (-1 for the reals, p for Q_p). + factD is an optional parameter. If present, it must be equal to + the factorization of -abs(2*matdet(G)). This saves a lot of time. + + Example: + gp > G = [1,0,0;0,1,0;0,0,-34]; + gp > qfsolve(G) + %1 = [-3, -5, 1]~ + + - qfparam(G,sol,fl): Coefficients of quadratic forms that parametrize the + solutions of the ternary quadratic form G, using the particular + solution sol. + fl is optional and can be 1, 2, or 3, in which case the 'fl'th form is + reduced. The default is fl=3. + + Example: + gp > qfparam(G,[-3,-5,1]~) + %2 = + [ 3 -10 -3] + + [-5 -6 5] + + [ 1 0 1] + Indeed, the solutions can be parametrized as + [3*x^2 - 10*y*x - 3*y^2, -5*x^2 - 6*y*x + 5*y^2, x^2 + y^2]~ + + - qflllgram_indef(G,c): Solve or reduce the quadratic form G with + integral coefficients. G might be definite or indefinite. + This is an lll-type algorithm with a constant 1/4 G = [1,0,0;0,1,0;0,0,-34]; + gp > qfsolve(G) + %1 = [-3, -5, 1]~ + + - qfparam(G,sol,fl): pour parametrer les solutions de la forme + quadratique ternaire G, en utilisant la solution particuliere sol. + fl est optionnel et peut prendre les valeurs 1,2 ou 3. + Il indique que la 'fl'eme forme quadratique est reduite. + Par defaut, fl=3 + + Exemple: + gp > qfparam(G,[-3,-5,1]~) + %2 = + [ 3 -10 -3] + + [-5 -6 5] + + [ 1 0 1] + Ici, les solutions sont parametrees par + [3*x^2 - 10*y*x - 3*y^2, -5*x^2 - 6*y*x + 5*y^2, x^2 + y^2]~ + + - qflllgram_indef(G,c): pour resoudre ou reduire la forme quadratique + G a coefficients entiers. Il s'agit d'un algorithme type LLL, avec la + constante 1/4= 5, print("entree dans QfbReduce avec ",M)); - - a = M[1,1]; b = M[1,2]; c = M[2,2]; - - H = matid(2); test = 1; - while( test && a, - di = divrem(b,a); q = di[1]; r = di[2]; - if( 2*r > abs(a), r -= abs(a); q += sign(a)); - H[,2] -= q*H[,1]; - nextc = a; nextb = -r; nexta= (nextb-b)*q+c; +\\ use the variable DEBUGLEVEL_qfsolve : +\\ From 0 to 5 : choose a higher value to have +\\ more details printed. - if( test = abs(nexta) < abs(a), - c = nextc; b = nextb; a = nexta; - aux = H[,1]; H[,1] = -H[,2]; H[,2] = aux - ) - ); -if( DEBUGLEVEL_qfsolve >= 5, print("sortie de QfbReduce avec ",H)); -return(H); -} -{IndefiniteLLL(G,c=1,base=0) = -\\ Performs first a LLL reduction on a positive definite -\\ quadratic form QD bounding the indefinite G. -\\ Then finishes the reduction with IndefiniteLLL2. +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ +\\ SCRIPT \\ +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ -local(n,M,QD,M1,S,red); +{default_qfsolve(DEBUGLEVEL_qfsolve_val = 0) = - n = length(G); - M = matid(n); - QD = G; - for( i = 1, n-1, - if( !QD[i,i], -return(IndefiniteLLL2(G,c,base)) - ); - M1 = matid(n); - M1[i,] = -QD[i,]/QD[i,i]; - M1[i,i] = 1; - M = M*M1; - QD = M1~*QD*M1 - ); - M = M^(-1); - QD = M~*abs(QD)*M; - S = qflllgram(QD/content(QD)); - red = IndefiniteLLL2(S~*G*S,c,base); - if( type(red) == "t_COL", -return(S*red)); - if( length(red) == 3, -return([red[1],S*red[2],S*red[3]])); -return([red[1],S*red[2]]); + DEBUGLEVEL_qfsolve = DEBUGLEVEL_qfsolve_val; + print(" DEBUGLEVEL_qfsolve = ",DEBUGLEVEL_qfsolve); } -{IndefiniteLLL2(G,c=1,base=0) = -\\ following Cohen's book p. 86 -\\ but without b and bstar: works on G -\\ returns [H~*G*H,H] where det(H) = 1 and H~*G*H is reduced. -\\ Exit with a norm 0 vector if one such is found. -\\ If base == 1 and norm 0 is obtained, returns [H~*G*H,H,sol] where -\\ sol is a norm 0 vector and is the 1st column of H. -local(n,H,M,A,aux,sol,k,nextk,swap,q,di,HM,aux1,aux2,Mkk1,bk1new,Mkk1new,newG); +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ +\\ TYPE CONVERSIONS \\ +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ - n = length(G); -if( DEBUGLEVEL_qfsolve >= 3, print("LLL dim ",n," avec G=",log(vecmax(abs(G)))/log(10))); -if( DEBUGLEVEL_qfsolve >= 4, print("LLL avec ");printp(G)); - - if( n <= 1, return([G,matid(n)])); - - H = M = matid(n); A = matrix(n,n); +\\ THIS FUNCTION WILL BE REPLACED BY matconcat(matdiagonal(v)) +\\ IN VERSION >= 2.6.0 +\\ build the matrix whose diagonal blocks are listed in the vector v. +{matdiagonalblock(v) = +my(M); +my(lv,lt=0); -\\ compute Gram-Schmidt + if( type(v) != "t_VEC" && type(v) != "t_COL", + error("wrong type in matdiagonalblock()")); - for( i = 1, n, - if( !(A[i,i] = G[i,i]), - if( base, - aux = H[,1]; H[,1] = H[,i]; H[,i] = -aux; - return([H~*G*H,H,H[,1]]) - , return(M[,i]))); - for( j = 1, i-1, - A[i,j] = G[i,j] - sum( k = 1, j-1, M[j,k]*A[i,k]); - M[i,j] = A[i,j]/A[j,j]; - A[i,i] -= M[i,j]*A[i,j]; - if( !A[i,i], - sol = (M^(-1))~[,i]; sol /= content(sol); - if( base, - H = completebasis(sol); - aux = H[,1]; H[,1] = H[,n]; H[,n]= -aux; - return([H~*G*H,H,H[,1]]) - , return(sol))) - ) + lv = length(v); + for( i = 1, lv, lt += length(v[i])); + M = matrix(lt,lt); + lt = 0; + for( i = 1, lv, + my( lvi = length(v[i])); + for( j = 1, lvi, + for( k = 1, lvi, + M[lt+j,lt+k] = v[i][j,k])); + lt += lvi ); +return(M); +} -\\ LLL loop - - k = 2; nextk = 1; - while( k <= n, - - swap = 1; - while( swap, - swap = 0; - -\\ red(k,k-1); - if( q = round(M[k,k-1]), - for( i = 1, k-2, M[k,i] -= q*M[k-1,i]); - M[k,k-1] -= q; - for( i = 1, n, - A[k,i] -= q*A[k-1,i]; - H[i,k] -= q*H[i,k-1] - ) - ); +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ +\\ LINEAR ALGEBRA \\ +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ -\\ preparation du swap(k,k-1) - - if( issquare( di = -A[k-1,k-1]*A[k,k]), -\\ di est le determinant de matr -\\ On trouve une solution - HM = (M^(-1))~; - aux1 = sqrtint(numerator(di)); - aux2 = sqrtint(denominator(di)); - sol = aux1*HM[,k-1]+aux2*A[k-1,k-1]*HM[,k]; - sol /= content(sol); - if( base, - H = H*completebasis(sol,1); - aux = H[,1]; H[,1] = H[,n]; H[,n] = -aux; - return([H~*G*H,H,H[,1]]) - , return(H*sol) - ) - ); +\\ Gives a unimodular matrix with the last column equal to v. +\\ redflag = 0 or 1. If redflag = 1, then the n-#v first columns are reduced. +{completebasis(v,redflag=0) = +my(Mv,U,re); +my(n); -\\ On reduit [k,k-1]. - Mkk1 = M[k,k-1]; - bk1new = Mkk1^2*A[k-1,k-1] + A[k,k]; - if( swap = abs(bk1new) < c*abs(A[k-1,k-1]), - Mkk1new = -Mkk1*A[k-1,k-1]/bk1new - ); + if( type(v) != "t_COL" && type(v) != "t_MAT", + error("wrong type in completebasis")); -\\ Calcul des nouvelles matrices apres le swap. - if( swap, - for( j = 1, n, - aux = H[j,k-1]; H[j,k-1] = H[j,k]; H[j,k] = -aux); - for( j = 1, k-2, - aux = M[k-1,j]; M[k-1,j] = M[k,j]; M[k,j] = -aux); - for( j = k+1, n, - aux = M[j,k]; M[j,k] = -M[j,k-1]+Mkk1*aux; M[j,k-1] = aux+Mkk1new*M[j,k]); - for( j = 1, n, if( j != k && j != k-1, - aux = A[k-1,j]; A[k-1,j] = A[k,j]; A[k,j] =- aux; - aux = A[j,k-1]; A[j,k-1] = Mkk1*aux+A[j,k]; A[j,k] = -aux-Mkk1new*A[j,k-1])); - - aux1 = A[k-1,k-1]; - aux2 = A[k,k-1]; - A[k,k-1] =-A[k-1,k] - Mkk1*aux1; - A[k-1,k-1]= A[k,k] + Mkk1*aux2; - A[k,k] = aux1 - Mkk1new*A[k,k-1]; - A[k-1,k] =-aux2 - Mkk1new*A[k-1,k-1]; - - M[k,k-1] = Mkk1new; - -if( DEBUGLEVEL_qfsolve >=4, newG=H~*G*H;print(vector(n,i,matdet(vecextract(newG,1<= 5, print("entree dans Qfparam")); - sol /= content(sol); -\\ construction de U telle que U[,3] est sol, et det(U) = +-1 - U = completebasis(sol,1); - G1 = U~*G*U; \\ G1 a un 0 en bas a droite. - G2 = [-2*G1[1,3],-2*G1[2,3],0; - 0,-2*G1[1,3],-2*G1[2,3]; - G1[1,1],2*G1[1,2],G1[2,2]]; - sol = U*G2; - if(fl && !issquare(matdet( U = [sol[fl,1],sol[fl,2]/2; - sol[fl,2]/2,sol[fl,3]])), - U = QfbReduce(U); - U = [U[1,1]^2,2*U[1,2]*U[1,1],U[1,2]^2; - U[2,1]*U[1,1],U[2,2]*U[1,1]+U[2,1]*U[1,2],U[1,2]*U[2,2]; - U[2,1]^2,2*U[2,1]*U[2,2],U[2,2]^2]; - sol = sol*U +\\ Given a symmetric matrix G over Z, compute the local invariant +\\ (=Witt invariant) of G at the prime p (at real place if p = -1) +\\ Assume that none of the determinant G[1..i,1..i] is 0. +{qflocalinvariant(G,p) = +my(vdet,diag); +my(n,c); + + n = length(G); +\\ Diagonalize G first. + vdet = vector( n+1, i, matdet(matrix(i-1,i-1,j,k,G[j,k]))); + diag = vector( n, i, vdet[i+1]*vdet[i]); + +\\ Then compute the product of the Hilbert symbols +\\ (diag[i],diag[j])_p for i < j + c = 1; + for( i = 1, n, + for( j = i+1, n, + c *= myhilbert( diag[i], diag[j], p))); +return(c); +} + +\\ G is a quadratic form, or a symmetrix matrix, +\\ or a list of quadratic forms with the same discriminant. +\\ If given, fa must be equal to factor(-abs(2*matdet(G)))[,1]. +{qflocalinvariants(G,fa=[]) = +my(vG,sol,vdet); +my(lG); + +if( DEBUGLEVEL_qfsolve >= 4, print(" starting qflocalinvariants ",G)); + +\\ convert G into a vector of symmetric matrices + if( type(G) == "t_VEC", vG = G , vG = [G]); + lG = length(vG); + for( j = 1, lG, + if( type(vG[j]) == "t_QFI" || type(vG[j]) == "t_QFR", + vG[j] = Mat(vG[j]))); + +\\ compute the factorization of -2*abs(det(G)) + if( !length(fa), + fa = (factor(-abs(2*matdet(vG[1])))[,1])); + +\\ in dimension 2, each invariant is a single Hilbert symbol. + if( length(vG[1]) == 2, + sol = matrix(length(fa),lG,i,j, + myhilbert(vG[j][1,1],-matdet(vG[1]),fa[i]) < 0); +if( DEBUGLEVEL_qfsolve >= 4, print(" end of qflocalinvariants")); + return([fa,sol]) ); -if( DEBUGLEVEL_qfsolve >= 5, print("sortie de Qfparam")); -return(sol); + + sol = matrix(length(fa),lG); + for( j = 1, lG, + my( n = length(vG[j])); +\\ in dimension n, we need to compute a product of n Hilbert symbols. + vdet = vector(n+1, i, matdet(matrix(i-1,i-1,k,m,vG[j][k,m]))); + for( i = 1, length(fa), + my( p = fa[i]); + my( h = 1); + for( k = 1, n-1, h *= myhilbert(-vdet[k],vdet[k+1],p)); + h *= myhilbert(vdet[n],vdet[n+1],p); + sol[i,j] = h < 0; + ) + ); +if( DEBUGLEVEL_qfsolve >= 4, print(" end of qflocalinvariants")); +return([fa,sol]); } -{LLLgoon3(G,c=1) = -\\ reduction LLL de la forme quadratique G (matrice de Gram) -\\ en dim 3 seulement avec detG = -1 et sign(G) = [1,2]; -local(red,U1,G2,bez,U2,G3,cc,U3); +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ +\\ QUADRATIC FORMS REDUCTION \\ +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ - red = IndefiniteLLL(G,c,1); -\\ On trouve toujours un vecteur isotrope. - U1 = [0,0,1;0,1,0;1,0,0]; - G2 = U1~*red[1]*U1; -\\ la matrice G2 a un 0 dans le coin en bas a droite. - bez = bezout(G2[3,1],G2[3,2]); - U2 = [bez[1],G2[3,2]/bez[3],0;bez[2],-G2[3,1]/bez[3],0;0,0,-1]; - G3 = U2~*G2*U2; -\\ la matrice G3 a des 0 sous l'anti-diagonale. - cc = G3[1,1]%2; - U3 = [1,0,0; cc,1,0; - round(-(G3[1,1]+cc*(2*G3[1,2]+G3[2,2]*cc))/2/G3[1,3]), - round(-(G3[1,2]+cc*G3[2,2])/G3[1,3]),1]; -return([U3~*G3*U3,red[2]*U1*U2*U3]); +\\ M = [a,b;b;c] has integral coefficients. +\\ Gauss reduction of the binary quadratic form +\\ qf = (a,b,c)=a*X^2+2*b*X*Y+c*Y^2 +\\ Returns the reduction matrix with det = +1. +{qfbreduce(M) = +my(H,di,aux); +my(a,b,c,q,r,nexta,nextb,nextc); +my(test); + +if( DEBUGLEVEL_qfsolve >= 5, print(" starting qfbreduce with ",M)); + + a = M[1,1]; b = M[1,2]; c = M[2,2]; + + H = matid(2); test = 1; + while( test && a, + di = divrem(b,a); q = di[1]; r = di[2]; + if( 2*r > abs(a), r -= abs(a); q += sign(a)); + H[,2] -= q*H[,1]; + nextc = a; nextb = -r; nexta= (nextb-b)*q+c; + + test = abs(nexta) < abs(a); + if( test, + c = nextc; b = nextb; a = nexta; + aux = H[,1]; H[,1] = -H[,2]; H[,2] = aux + ) + ); + +if( DEBUGLEVEL_qfsolve >= 5, print(" end of qfbreduce with ",H)); +return(H); } -{completebasis(v,redflag=0) = -\\ Donne une matrice unimodulaire dont la derniere colonne est v. -\\ Si redflag <> 0, alors en plus on reduit le reste. -local(U,n,re); +\\ Performs first a LLL reduction on a positive definite +\\ quadratic form QD bounding the indefinite G. +\\ Then finishes the reduction with qfsolvetriv(). +{qflllgram_indef(G,c=1,base=0) = +my(M,QD,M1,S,red); +my(n); - U = (mathnf(Mat(v~),1)[2]~)^-1; - n = length(v~); - if( n==1 || !redflag, return(U)); - re = qflll(vecextract(U,1<= 4, print(" qflllgram_indef with G = ",G)); + n = length(G); + M = matid(n); + QD = G; + for( i = 1, n-1, + if( !QD[i,i], + return(qfsolvetriv(G,base)) + ); + M1 = matid(n); + M1[i,] = -QD[i,]/QD[i,i]; + M1[i,i] = 1; + M = (M*M1); + QD = (M1~*QD*M1) + ); + M = (M^(-1)); + QD = (M~*abs(QD)*M); + S = qflllgram(QD/content(QD)); + if( #S < n, S = completebasis(S)); + red = qfsolvetriv(S~*G*S,base); + if( type(red) == "t_COL", + red = (S*red); + return(red)); + red[2] = S*red[2]; + if( length(red) == 3, + red[3] = S*red[3]); +return(red); } -{LLLgoon(G,c=1) = -\\ reduction LLL de la forme quadratique G (matrice de Gram) -\\ ou l'on continue meme si on trouve un vecteur isotrope -local(red,U1,G2,U2,G3,n,U3,G4,U,V,B,U4,G5,U5,G6); +\\ LLL reduction of the quadratic form G (Gram matrix) +\\ where we go on, even if an isotropic vector is found. +{qflllgram_indefgoon(G,c=1) = +my(red,U1,G2,U2,G3,U3,G4,U,V,B,U4,G5,U5,G6); +my(n); - red = IndefiniteLLL(G,c,1); -\\ si on ne trouve pas de vecteur isotrope, il n'y a rien a faire. + red = qflllgram_indef(G,c,1); +\\ If no isotropic vector is found, nothing to do. if( length(red) == 2, return(red)); -\\ sinon : +\\ otherwise a solution is found: U1 = red[2]; G2 = red[1]; \\ On a G2[1,1] = 0 U2 = mathnf(Mat(G2[1,]),4)[2]; G3 = U2~*G2*U2; -\\ la matrice de G3 a des 0 sur toute la 1ere ligne, -\\ sauf un 'g' au bout a droite, avec g^2| det G. +\\ The first line of the matrix G3 only contains 0, +\\ except some 'g' on the right, where g^2| det G. n = length(G); U3 = matid(n); U3[1,n] = round(-G3[n,n]/G3[1,n]/2); G4 = U3~*G3*U3; -\\ le coeff G4[n,n] est reduit modulo 2g +\\ The coeff G4[n,n] is reduced modulo 2g U = vecextract(G4,[1,n],[1,n]); if( n == 2, V = matrix(2,0) @@ -354,236 +402,202 @@ local(red,U1,G2,U2,G3,n,U3,G4,U,V,B,U4,G5,U5,G6); U4[n,j] = B[2,j-1] ); G5 = U4~*G4*U4; -\\ la derniere colonne de G5 est reduite +\\ The last column of G5 is reduced if( n < 4, return([G5,U1*U2*U3*U4])); - red = LLLgoon(matrix(n-2,n-2,i,j,G5[i+1,j+1]),c); + red = qflllgram_indefgoon(matrix(n-2,n-2,i,j,G5[i+1,j+1]),c); U5 = matdiagonalblock([Mat(1),red[2],Mat(1)]); G6 = U5~*G5*U5; return([G6,U1*U2*U3*U4*U5]); } -{QfWittinvariant(G,p) = -\\ calcule l'invariant c (=invariant de Witt) d'une forme quadratique, -\\ p-adique (reel si p = -1) -local(n,det,diag,c); +\\ LLL reduction of the quadratic form G (Gram matrix) +\\ in dim 3 only, with detG = -1 and sign(G) = [2,1]; +{qflllgram_indefgoon2(G,c=1) = +my(red,U1,G2,bez,U2,G3,U3); +my(cc); - n = length(G); -\\ On diagonalise d'abord G - det = vector( n+1, i, matdet(matrix(i-1,i-1,j,k,G[j,k]))); - diag = vector( n, i, det[i+1]/det[i]); - -\\ puis on calcule les symboles de Hilbert - c = prod( i = 1, n, - prod( j = i+1, n, - hilbert( diag[i], diag[j], p))); -return(c); -} -{Qflisteinvariants(G,fa=[]) = -\\ G est une forme quadratique, ou une matrice symetrique, -\\ ou un vecteur contenant des formes quadratiques de meme discriminant. -\\ fa = factor(-abs(2*matdet(G)))[,1] est facultatif. - -local(l,sol,n,det); - -if( DEBUGLEVEL_qfsolve >= 4, print("entree dans Qflisteinvariants",G)); - if( type(G) != "t_VEC", G = [G]); - l = length(G); - for( j = 1, l, - if( type(G[j]) == "t_QFI" || type(G[j]) == "t_QFR", - G[j] = mymat(G[j]))); - - if( !length(fa), - fa = factor(-abs(2*matdet(G[1])))[,1]); - - if( length(G[1]) == 2, -\\ En dimension 2, chaque invariant est un unique symbole de Hilbert. - det = -matdet(G[1]); - sol = matrix(length(fa),l,i,j,hilbert(G[j][1,1],det,fa[i])<0); -if( DEBUGLEVEL_qfsolve >= 4, print("sortie de Qflisteinvariants")); - return([fa,sol]) - ); + red = qflllgram_indef(G,c,1); +\\ We always find an isotropic vector. + U1 = [0,0,1;0,1,0;1,0,0]; + G2 = U1~*red[1]*U1; +\\ G2 has a 0 at the bottom right corner. + bez = bezout(G2[3,1],G2[3,2]); + U2 = [bez[1],G2[3,2]/bez[3],0;bez[2],-G2[3,1]/bez[3],0;0,0,-1]; + G3 = U2~*G2*U2; +\\ G3 has 0 under the co-diagonal. + cc = (G3[1,1])%2; + U3 = [1,0,0; cc,1,0; + round(-(G3[1,1]+cc*(2*G3[1,2]+G3[2,2]*cc))/2/G3[1,3]), + round(-(G3[1,2]+cc*G3[2,2])/G3[1,3]),1]; - sol = matrix(length(fa),l); - for( j = 1, l, - n = length(G[j]); -\\ En dimension n, on calcule un produit de n symboles de Hilbert. - det = vector(n+1, i, matdet(matrix(i-1,i-1,k,m,G[j][k,m]))); - for( i = 1, length(fa), - sol[i,j] = prod( k = 1, n-1, hilbert(-det[k],det[k+1],fa[i]))*hilbert(det[n],det[n+1],fa[i]) < 0; - ) - ); -if( DEBUGLEVEL_qfsolve >= 4, print("sortie de Qflisteinvariants")); -return([fa,sol]); +return([U3~*G3*U3,red[2]*U1*U2*U3]); } -{Qfsolvemodp(G,p) = -\\ p a prime number. -\\ finds a solution mod p for the quadatic form G -\\ such that det(G) !=0 mod p and dim G = n>=3; -local(n,vdet,G2,sol,x1,x2,x3,N1,N2,N3,s,r); - n = length(G); - vdet = [0,0,0]; - for( i = 1, 3, - G2 = vecextract(G,1<=2. On suppose que G est symetrique a coefficients entiers. -\\ Renvoit [G',U,factd] avec U \in GLn(Q) telle que G'=U~*G*U*constante est entiere -\\ de determinant minimal. -\\ Renvoit p si la reduction est impossible a cause de la non-solubilite locale -\\ en p (seulement en dimension 3-4). -\\ factd est la factorisation de abs(det(G')) -\\ Si on connait la factorisation de matdet(G), on peut la donner en parametre -\\ pour gagner du temps. -local(n,U,factd,detG,i,vp,Ker,dimKer,Ker2,dimKer2,sol,aux,p,di,m); +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ +\\ QUADRATIC FORMS MINIMIZATION \\ +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ + +\\ Minimization of the quadratic form G, with nonzero determinant. +\\ of dimension n>=2. +\\ G must by symmetric and have integral coefficients. +\\ Returns [G',U,factd] with U in GLn(Q) such that G'=U~*G*U*constant +\\ is integral and has minimal determinant. +\\ In dimension 3 or 4, may return a prime p +\\ if the reduction at p is impossible because of the local non solvability. +\\ If given, factdetG must be equal to factor(abs(det(G))). +{qfminimize(G,factdetG) = +my(factd,U,Ker,Ker2,sol,aux,di); +my(p); +my(n,lf,i,vp,dimKer,dimKer2,m); n = length(G); - U = matid(n); factd = matrix(0,2); - detG = matdet(G); - if( !factdetG, factdetG = factor(detG)); - i = 1; - while(i <= length(factdetG[,1]), - p = factdetG[i,1]; - if( p == -1, i++; next); -if( DEBUGLEVEL_qfsolve >= 4, print("p=",p,"^",factdetG[i,2])); + if( !factdetG, factdetG = factor(matdet(G))); + + lf = length(factdetG[,1]); + i = 1; U = matid(n); + + while(i <= lf, vp = factdetG[i,2]; if( vp == 0, i++; next); -\\ Le cas vp=1 n'est minimisable que si n est impair. + p = factdetG[i,1]; + if( p == -1, i++; next); +if( DEBUGLEVEL_qfsolve >= 4, print(" p = ",p,"^",vp)); + +\\ The case vp = 1 can be minimized only if n is odd. if( vp == 1 && n%2 == 0, factd = concat(factd~, Mat([p,1])~)~; i++; next ); Ker = kermodp(G,p); dimKer = Ker[1]; Ker = Ker[2]; -\\ Rem: on a toujours dimKer <= vp -if( DEBUGLEVEL_qfsolve >= 4, print("dimKer = ",dimKer)); -\\ cas trivial: G est divisible par p. - if( dimKer == n, + +\\ Rem: we must have dimKer <= vp +if( DEBUGLEVEL_qfsolve >= 4, print(" dimKer = ",dimKer)); +\\ trivial case: dimKer = n + if( dimKer == n, +if( DEBUGLEVEL_qfsolve >= 4, print(" case 0: dimKer = n")); G /= p; factdetG[i,2] -= n; next ); G = Ker~*G*Ker; U = U*Ker; -\\ 1er cas: la dimension du noyau est plus petite que la valuation -\\ alors le noyau mod p contient un noyau mod p^2 + +\\ 1st case: dimKer < vp +\\ then the kernel mod p contains a kernel mod p^2 if( dimKer < vp, -if( DEBUGLEVEL_qfsolve >= 4, print("cas 1")); - Ker2 = kermodp(matrix(dimKer,dimKer,j,k,G[j,k]/p),p); - dimKer2 = Ker2[1]; Ker2 = Ker2[2]; - for( j = 1, dimKer2, Ker2[,j] /= p); - Ker2 = matdiagonalblock([Ker2,matid(n-dimKer)]); - G = Ker2~*G*Ker2; - U = U*Ker2; - factdetG[i,2] -= 2*dimKer2; -if( DEBUGLEVEL_qfsolve >= 4, print("fin cas 1")); +if( DEBUGLEVEL_qfsolve >= 4, print(" case 1: dimker < vp")); + if( dimKer == 1, +\\ G[,1] /= p; G[1,] /= p; + G[,1] /= p; G[1,] = G[1,]/p; + U[,1] /= p; + factdetG[i,2] -= 2 + , + Ker2 = kermodp(matrix(dimKer,dimKer,j,k,G[j,k]/p),p); + dimKer2 = Ker2[1]; Ker2 = Ker2[2]; + for( j = 1, dimKer2, Ker2[,j] /= p); + Ker2 = matdiagonalblock([Ker2,matid(n-dimKer)]); + G = Ker2~*G*Ker2; + U = U*Ker2; + factdetG[i,2] -= 2*dimKer2 +); + +if( DEBUGLEVEL_qfsolve >= 4, print(" end of case 1")); next ); -\\ Maintenant, vp = dimKer -\\ 2eme cas: la dimension du noyau est >=2 et contient un element de norme 0 mod p^2 - if( dimKer > 2 || - (dimKer == 2 && issquare(di=Mod((G[1,2]^2-G[1,1]*G[2,2])/p^2,p))), -\\ on cherche dans le noyau un elt de norme p^2... +\\ Now, we have vp = dimKer +\\ 2nd case: the dimension of the kernel is >=2 +\\ and contains an element of norm 0 mod p^2 + +\\ search for an element of norm p^2... in the kernel + if( dimKer > 2 || + (dimKer == 2 && issquare( di = Mod((G[1,2]^2-G[1,1]*G[2,2])/p^2,p))), if( dimKer > 2, -if( DEBUGLEVEL_qfsolve >= 4, print("cas 2.1")); +if( DEBUGLEVEL_qfsolve >= 4, print(" case 2.1")); dimKer = 3; - sol = Qfsolvemodp(matrix(3,3,j,k,G[j,k]/p),p) + sol = qfsolvemodp(matrix(3,3,j,k,G[j,k]/p),p) , -if( DEBUGLEVEL_qfsolve >= 4, print("cas 2.2")); - if( G[1,1]%p^2 == 0, +if( DEBUGLEVEL_qfsolve >= 4, print(" case 2.2")); + if( G[1,1]%p^2 == 0, sol = [1,0]~ , sol = [-G[1,2]/p+sqrt(di),Mod(G[1,1]/p,p)]~ ) ); - sol = centerlift(sol); sol /= content(sol); -if( DEBUGLEVEL_qfsolve >= 4, print("sol=",sol)); - Ker = vectorv(n, j, if( j<= dimKer, sol[j], 0)); \\ on complete avec des 0 + sol = centerlift(sol); + sol /= content(sol); +if( DEBUGLEVEL_qfsolve >= 4, print(" sol = ",sol)); + Ker = vectorv(n, j, if( j<= dimKer, sol[j], 0)); \\ fill with 0's Ker = completebasis(Ker,1); Ker[,n] /= p; G = Ker~*G*Ker; U = U*Ker; factdetG[i,2] -= 2; -if( DEBUGLEVEL_qfsolve >= 4, print("fin cas 2")); +if( DEBUGLEVEL_qfsolve >= 4, print(" end of case 2")); next ); -\\ Maintenant, vp = dimKer <= 2 -\\ et le noyau ne contient pas de vecteur de norme p^2... +\\ Now, we have vp = dimKer <= 2 +\\ and the kernel contains no vector with norm p^2... -\\ Dans certains cas, on peut echanger le noyau et l'image -\\ pour continuer a reduire. +\\ In some cases, exchanging the kernel and the image +\\ makes the minimization easy. m = (n-1)\2-1; if( ( vp == 1 && issquare(Mod(-(-1)^m*matdet(G)/G[1,1],p))) || ( vp == 2 && n%2 == 1 && n >= 5) || ( vp == 2 && n%2 == 0 && !issquare(Mod((-1)^m*matdet(G)/p^2,p))) - , -if( DEBUGLEVEL_qfsolve >= 4, print("cas 3")); + , +if( DEBUGLEVEL_qfsolve >= 4, print(" case 3")); Ker = matid(n); for( j = dimKer+1, n, Ker[j,j] = p); G = Ker~*G*Ker/p; U = U*Ker; factdetG[i,2] -= 2*dimKer-n; -if( DEBUGLEVEL_qfsolve >= 4, print("fin cas 3")); +if( DEBUGLEVEL_qfsolve >= 4, print(" end of case 3")); next ); -\\ On n'a pas pu minimiser. -\\ Si n == 3 ou n == 4 cela demontre la non-solubilite locale en p. - if( n == 3 || n == 4, -if( DEBUGLEVEL_qfsolve >= 1, print("pas de solution locale en ",p)); +\\ Minimization was not possible se far. +\\ If n == 3 or 4, this proves the local non-solubility at p. + if( n == 3 || n == 4, +if( DEBUGLEVEL_qfsolve >= 1, print(" no local solution at ",p)); return(p)); -if( DEBUGLEVEL_qfsolve >= 4, print("plus de minimisation possible")); +if( DEBUGLEVEL_qfsolve >= 4, print(" prime ",p," finished")); factd = concat(factd~,Mat([p,vp])~)~; i++ ); -\\print("Un=",log(vecmax(abs(U)))); - aux = qflll(U); -\\print("Ur=",log(vecmax(abs(U*aux)))); +\\ apply LLL to avoid coefficients explosion + aux = qflll(U/content(U)); return([aux~*G*aux,U*aux,factd]); } -{mymat(qfb) = qfb = Vec(qfb);[qfb[1],qfb[2]/2;qfb[2]/2,qfb[3]]; -} -{Qfbsqrtgauss(G,factdetG) = -\\ pour l'instant, ca ne marche que pour detG sans facteur carre -\\ sauf en 2, ou la valuation est 2 ou 3. -\\ factdetG contient la factorisation de 2*abs(disc G) -local(a,b,c,d,m,n,p,aux,Q1,M); -if( DEBUGLEVEL_qfsolve >=3, print("entree dans Qfbsqrtgauss avec",G,factdetG)); - G = Vec(G); - a = G[1]; b = G[2]/2; c = G[3]; d = a*c-b^2; - -\\ 1ere etape: on resout m^2 = a (d), m*n = -b (d), n^2 = c (d) + +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ +\\ CLASS GROUP COMPUTATIONS \\ +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ + +\\ Compute the square root of the quadratic form qfb. +\\ This function is not fully implemented. +\\ For the moment it only works for detqfb squarefree +\\ (except at 2, where the valuation is 2 or 3). +\\ factdet must be given and equal to factor(2*abs(det qfb)) +{qfbsqrt(qfb,factdet) = +my(G,m,n); +my(a,b,c,d,p); +my(aux,Q1,M); + +if( DEBUGLEVEL_qfsolve >=3, print(" starting qfbsqrt with ",qfb,factdet)); + G = Vec(qfb); + a = G[1]; b = (G[2]/2); c = G[3]; d = a*c-b^2; + +\\ 1st step: solve m^2 = a (d), m*n = -b (d), n^2 = c (d) m = n = Mod(1,1); - factdetG[1,2] -= 3; - for( i = 1, length(factdetG[,1]), - if( !factdetG[i,2], next); - p = factdetG[i,1]; + factdet[1,2] -= 3; + for( i = 1, length(factdet[,1]), + if( !factdet[i,2], next); + p = factdet[i,1]; if( gcd(a,p) == 1, aux = sqrt(Mod(a,p)); m = chinese(m,aux); @@ -594,38 +608,40 @@ if( DEBUGLEVEL_qfsolve >=3, print("entree dans Qfbsqrtgauss avec",G,factdetG)); m = chinese(m,-b/aux) ) ); - m = centerlift(m); n = centerlift(n); -if( DEBUGLEVEL_qfsolve >=4, print("m=",m); print("n=",n)); + m = centerlift(m); + n = centerlift(n); +if( DEBUGLEVEL_qfsolve >=4, print(" m = ",m); print(" n = ",n)); -\\ 2eme etape: on construit Q1 de det -1 tq Q1(x,y,0) = G(x,y) +\\ 2nd step: build Q1, with det=-1 such that Q1(x,y,0) = G(x,y) Q1 = [(n^2-c)/d, (m*n+b)/d, n ; (m*n+b)/d, (m^2-a)/d, m ; n, m, d ]; Q1 = -matadjoint(Q1); -\\ 3eme etape: on reduit Q1 jusqu'a [0,0,-1;0,1,0;-1,0,0] - M = LLLgoon3(Q1)[2][3,]; +\\ 3rd step: reduce Q1 to [0,0,-1;0,1,0;-1,0,0] + M = qflllgram_indefgoon2(Q1)[2][3,]; if( M[1] < 0, M = -M); -if( DEBUGLEVEL_qfsolve >=3, print("fin de Qfbsqrtgauss ")); +if( DEBUGLEVEL_qfsolve >=3, print(" end of qfbsqrt")); if( M[1]%2, return(Qfb(M[1],2*M[2],2*M[3])) , return(Qfb(M[3],-2*M[2],2*M[1]))); } -{class2(D,factdetG,Winvariants,U2) = -\\ On suit l'algorithme de Shanks/Bosma-Stevenhagen -\\ pour construire tout le 2-groupe de classes -\\ seulement pour D discriminant fondamental. -\\ lorsque D = 1(4), on travaille avec 4D. -\\ Si on connait la factorisation de abs(2*D), -\\ on peut la donner dans factdetG, et dans ce cas le reste -\\ de l'algorithme est polynomial. -\\ Si Winvariants est donne, l'algorithme s'arrete des qu'un element d'invariants=Winvariants -\\ est trouve. - -local(factD,n,rang,m,listgen,vD,p,vp,aux,invgen,im,Ker,Kerim,listgen2,G2,struct,E,compteur,red); - -if( DEBUGLEVEL_qfsolve >= 1, print("Construction du 2-groupe de classe de discriminant ",D)); - if( D%4 == 2 || D%4 == 3, print("Discriminant not congruent to 0,1 mod 4");return(0)); + +\\ Implementation of Shanks/Bosma-Stevenhagen algorithm +\\ to compute the 2-Sylow of the class group of discriminant D. +\\ Only works for D = fundamental discriminant. +\\ When D = 1(4), work with 4D. +\\ If given, factdetG must be equal to factor(abs(2*D)). +\\ Apart from this factorization, the algorithm is polynomial time. +\\ If Winvariants is given, the algorithm stops as soon as +\\ an element having these W-invariants is found. +{quadclass2(D,factdetG,Winvariants,U2) = +my(factD,listgen,E,invgen,im,Ker,Kerim,listgen2,G2,clgp2,red,auxg); +my(p,aux); +my(n,rang,m,vD,vp); + +if( DEBUGLEVEL_qfsolve >= 1, print(" Construction of the 2-class group of discriminant ",D)); + if( D%4 == 2 || D%4 == 3, error("quadclass2: Discriminant not congruent to 0,1 mod 4")); if( D==-4, return([[1],[Qfb(1,0,1)]])); @@ -635,21 +651,26 @@ if( DEBUGLEVEL_qfsolve >= 1, print("Construction du 2-groupe de classe de discri n = length(factD); rang = n-3; if(D>0, m = rang+1, m = rang); -if( DEBUGLEVEL_qfsolve >= 3, print("factD = ",factD)); - listgen = vector(max(0,m)); + if(m<0, m=0); +if( DEBUGLEVEL_qfsolve >= 3, print(" factD = ",factD)); + listgen = vector(m); - if( vD = valuation(D,2), + vD = valuation(D,2); + if( vD, E = Qfb(1,0,-D/4) , E = Qfb(1,1,(1-D)/4) ); -if( DEBUGLEVEL_qfsolve >= 3, print("E = ",E)); +if( DEBUGLEVEL_qfsolve >= 3, print(" E = ",E)); - if( type(Winvariants) == "t_COL" && (Winvariants == 0 || length(matinverseimage(U2*Mod(1,2),Winvariants))>0), return([[1],[E]])); + if( type(Winvariants) == "t_COL" + && (Winvariants == 0 + || length(matinverseimage(U2*Mod(1,2),Winvariants))>0) + , return([[1],[E]])); - for( i = 1, m, \\ on ne regarde pas factD[1]=-1, ni factD[2]=2 + for( i = 1, m, \\ no need to look at factD[1]=-1, nor factD[2]=2 p = factD[i+2]; vp = valuation(D,p); - aux = p^vp; + aux = (p^vp); if( vD, listgen[i] = Qfb(aux,0,-D/4/aux) , listgen[i] = Qfb(aux,aux,(aux-D/aux)/4)) @@ -659,17 +680,17 @@ if( DEBUGLEVEL_qfsolve >= 3, print("E = ",E)); if( vD == 3, m++; rang++; listgen = concat(listgen,[Qfb(2^(vD-2),0,-D/2^vD)])); -if( DEBUGLEVEL_qfsolve >= 3, print("listgen = ",listgen)); -if( DEBUGLEVEL_qfsolve >= 2, print("rang = ",rang)); +if( DEBUGLEVEL_qfsolve >= 3, print(" listgen = ",listgen)); +if( DEBUGLEVEL_qfsolve >= 2, print(" rank = ",rang)); if( !rang, return([[1],[E]])); - invgen = Qflisteinvariants(listgen,factD)[2]*Mod(1,2); -if( DEBUGLEVEL_qfsolve >= 3, printp("invgen = ",lift(invgen))); + invgen = qflocalinvariants(listgen,factD)[2]*Mod(1,2); +if( DEBUGLEVEL_qfsolve >= 3, print(" invgen = ",lift(invgen))); - struct = vector(m,i,2); + clgp2 = vector(m,i,2); im = lift(matinverseimage(invgen,matimage(invgen))); - while( (length(im) < rang) + while( (length(im) < rang) || (type(Winvariants) == "t_COL" && length(matinverseimage(concat(invgen,U2),Winvariants) == 0)), Ker = lift(matker(invgen)); Kerim = concat(Ker,im); @@ -680,26 +701,26 @@ if( DEBUGLEVEL_qfsolve >= 3, printp("invgen = ",lift(invgen))); if( Kerim[j,i], listgen2[i] = qfbcompraw(listgen2[i],listgen[j]))); if( norml2(Kerim[,i]) > 1, - red = QfbReduce(aux=mymat(listgen2[i])); - aux = red~*aux*red; - listgen2[i] = Qfb(aux[1,1],2*aux[1,2],aux[2,2])) + red = qfbreduce(auxg=Mat(listgen2[i])); + auxg = red~*auxg*red; + listgen2[i] = Qfb(auxg[1,1],2*auxg[1,2],auxg[2,2])) ); listgen = listgen2; invgen = invgen*Kerim; -if( DEBUGLEVEL_qfsolve >= 4, print("listgen = ",listgen)); -if( DEBUGLEVEL_qfsolve >= 4, printp("invgen = ",lift(invgen))); +if( DEBUGLEVEL_qfsolve >= 4, print(" listgen = ",listgen)); +if( DEBUGLEVEL_qfsolve >= 4, print(" invgen = ",lift(invgen))); for( i = 1, length(Ker), - G2 = Qfbsqrtgauss(listgen[i],factdetG); - struct[i] <<= 1; + G2 = qfbsqrt(listgen[i],factdetG); + clgp2[i] <<= 1; listgen[i] = G2; - invgen[,i] = Qflisteinvariants(G2,factD)[2][,1]*Mod(1,2) + invgen[,i] = qflocalinvariants(G2,factD)[2][,1]*Mod(1,2) ); -if( DEBUGLEVEL_qfsolve >= 3, print("listgen = ",listgen)); -if( DEBUGLEVEL_qfsolve >= 3, printp("invgen = ",lift(invgen))); -if( DEBUGLEVEL_qfsolve >= 3, print("struct = ",struct)); +if( DEBUGLEVEL_qfsolve >= 3, print(" listgen = ",listgen)); +if( DEBUGLEVEL_qfsolve >= 3, print(" invgen = ",lift(invgen))); +if( DEBUGLEVEL_qfsolve >= 3, print(" clgp2 = ",clgp2)); im = lift(matinverseimage(invgen,matimage(invgen))) ); @@ -711,105 +732,232 @@ if( DEBUGLEVEL_qfsolve >= 3, print("struct = ",struct)); if( im[j,i], listgen2[i] = qfbcompraw(listgen2[i],listgen[j]))); if( norml2(im[,i]) > 1, - red = QfbReduce(aux=mymat(listgen2[i])); - aux = red~*aux*red; - listgen2[i] = Qfb(aux[1,1],2*aux[1,2],aux[2,2])) + red = qfbreduce(auxg=Mat(listgen2[i])); + auxg = red~*auxg*red; + listgen2[i] = Qfb(auxg[1,1],2*auxg[1,2],auxg[2,2])) ); listgen = listgen2; \\ listgen = vector(rang,i,listgen[m-rang+i]); - struct = vector(rang,i,struct[m-rang+i]); + clgp2 = vector(rang,i,clgp2[m-rang+i]); -if( DEBUGLEVEL_qfsolve >= 2, print("listgen = ",listgen)); -if( DEBUGLEVEL_qfsolve >= 2, print("struct = ",struct)); +if( DEBUGLEVEL_qfsolve >= 2, print(" listgen = ",listgen)); +if( DEBUGLEVEL_qfsolve >= 2, print(" clgp2 = ",clgp2)); -return([struct,listgen]); +return([clgp2,listgen]); } -{Qfsolve(G,factD) = -\\ Resolution de la forme quadratique X^tGX=0 de dimension n >= 3. -\\ On suppose que G est entiere et primitive. -\\ La solution peut etre un vectorv ou une matrice. -\\ S'il n'y a pas de solution, alors renvoit un p tel -\\ qu'il n'existe pas de solution locale en p. -\\ -\\ Si on connait la factorisation de -abs(2*matdet(G)), -\\ on peut la passer par le parametre factD pour gagner du temps. -local(n,M,signG,d,Min,U,codim,aux,G1,detG1,M1,subspace1,G2,subspace2,M2,solG2,Winvariants,dQ,factd,U2,clgp2,V,detG2,dimseti,solG1,sol,Q); +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ +\\ QUADRATIC EQUATIONS \\ +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ -if( DEBUGLEVEL_qfsolve >= 1, print("entree dans Qfsolve")); +\\ Try to solve G = 0 with small coefficients +\\ This is proved to work if +\\ - det(G) = 1, dim <= 6 and G is LLL reduced \\ -\\ 1ere reduction des coefficients de G +\\ Returns [G,matid] if no solution is found. +\\ Exit with a norm 0 vector if one such is found. +\\ If base == 1 and norm 0 is obtained, returns [H~*G*H,H,sol] where +\\ sol is a norm 0 vector and is the 1st column of H. +{qfsolvetriv(G,base=0) = +my(n); +my(H,sol,GG); + + n = length(G); + H = matid(n); + +\\ case 1: A basis vector is isotropic + for( i = 1, n, + if( G[i,i] == 0, + sol = H[,i]; + if( base == 0, return(sol)); + H[,i] = H[,1]; H[,1] = sol; + return([H~*G*H,H,sol]) + ) + ); + +\\ case 2: G has a block +- [1,0;0,-1] on the diagonal + for( i = 2, n, + if( G[i-1,i] == 0 && G[i-1,i-1]*G[i,i] == -1, + H[i-1,i] = -1; sol = H[,i]; + if( base == 0, return(sol)); + H[,i] = H[,1]; H[,1] = sol; + return([H~*G*H,H,sol]) + ) + ); + +\\ case 3: a principal minor is 0 + for( i = 1, n, + GG = vecextract(G,1<=3; +{qfsolvemodp(G,p) = +my(vdet,G2,sol,x1,x2,x3,N1,N2,N3,s); +my(r); +my(n); + + n = length(G); + vdet = [0,0,0]; + for( i = 1, 3, + G2 = vecextract(G,1<= 1, +\\ solves over Z the quadratic equation X^tGX = 0. +\\ G is assumed to have integral coprime coefficients. +\\ The solution might be a vectorv or a matrix. +\\ If no solution exists, returns an integer, that can +\\ be a prime p such that there is no local solution at p, +\\ or -1 if there is no real solution, +\\ or 0 in some rare cases. \\ +\\ If given, factD must be equal to factor(-abs(2*matdet(G))). +{qfsolve(G,factD=0) = +my(M,signG,Min,U,G1,auxg,M1,subspace1,G2,subspace2,M2,solG2,Winvariants,factd,U2,clgp2,V,solG1,sol,Q); +my(d,di,aux,detG1,dQ,detG2); +my(n,codim,dimseti); +if( DEBUGLEVEL_qfsolve >= 1, print(" starting qfsolve")); + + if( type(G) != "t_MAT", error(" wrong type in qfsolve: should be a t_MAT")); n = length(G); - M = IndefiniteLLL(G); + if( n == 0, error(" dimension should be > 0")); + if( n != length(G[,1]), error(" not a square matrix in qfsolve")); + +\\ Trivial case: det = 0 + + d = matdet(G); + + if( d == 0, +if( DEBUGLEVEL_qfsolve >= 1, print(" trivial case: det = 0")); + return(matker(G))); + +\\ Small dimension: n <= 2 + + if( n == 1, +if( DEBUGLEVEL_qfsolve >= 1, print(" trivial case: dim = 1")); + return(0)); + if( n == 2, +if( DEBUGLEVEL_qfsolve >= 1, print(" trivial case: dim = 2")); + if( !issquare(-d), return(0)); + di = sqrtint(-d); + return([-G[1,2]+di,G[1,1]]~) + ); + +\\ +\\ 1st reduction of the coefficients of G +\\ + + M = qflllgram_indef(G); if( type(M) == "t_COL", -if( DEBUGLEVEL_qfsolve >= 1, print("solution ",M)); +if( DEBUGLEVEL_qfsolve >= 1, print(" solution ",M)); +if( DEBUGLEVEL_qfsolve >= 1, print(" end of qfsolve")); return(M)); G = M[1]; M = M[2]; -\\ Solubilite reelle +\\ Real solubility signG = qfsign(G); if( signG[1] == 0 || signG[2] == 0, -if( DEBUGLEVEL_qfsolve >= 1, print("pas de solution reelle")); +if( DEBUGLEVEL_qfsolve >= 1, print(" no real solution")); +if( DEBUGLEVEL_qfsolve >= 1, print(" end of qfsolve")); return(-1)); if( signG[1] < signG[2], G = -G; signG = signG*[0,1;1,0]); -\\ Factorisation du determinant - d = matdet(G); - if( !factD, -if( DEBUGLEVEL_qfsolve >= 1, print("factorisation du determinant")); +\\ Factorization of the determinant + if( !factD, +if( DEBUGLEVEL_qfsolve >= 1, print1(" factorization of the determinant = ")); factD = factor(-abs(2*d)); + factD[1,2] = 0; + factD[2,2] --; if( DEBUGLEVEL_qfsolve >= 1, print(factD)) ); - factD[1,2] = 0; - factD[2,2] --; \\ -\\ Minimisation et solubilite locale. +\\ Minimization and local solubility \\ -if( DEBUGLEVEL_qfsolve >= 1, print("minimisation du determinant")); - Min = Qfminim(G,factD); +if( DEBUGLEVEL_qfsolve >= 1, print(" minimization of the determinant")); + Min = qfminimize(G,factD); if( type(Min) == "t_INT", -if( DEBUGLEVEL_qfsolve >= 1, print("pas de solution locale en ",Min)); +if( DEBUGLEVEL_qfsolve >= 1, print(" no local solution at ",Min)); +if( DEBUGLEVEL_qfsolve >= 1, print(" end of qfsolve")); return(Min)); M = M*Min[2]; G = Min[1]; -\\ Min[3] contient la factorisation de abs(matdet(G)); +\\ Min[3] contains the factorization of abs(matdet(G)); -if( DEBUGLEVEL_qfsolve >= 4, print("G minime = ",G)); -if( DEBUGLEVEL_qfsolve >= 4, print("d=",d)); +if( DEBUGLEVEL_qfsolve >= 4, print(" G minim = ",G)); +if( DEBUGLEVEL_qfsolve >= 4, print(" d = ",d)); -\\ Maintenant, on sait qu'il y a des solutions locales -\\ (sauf peut-etre en 2 si n==4), -\\ si n==3, det(G) = +-1 -\\ si n==4, ou si n est impair, det(G) est sans facteur carre. -\\ si n>=6, det(G) toutes les valuations sont <=2. +\\ Now, we know that local solutions exist +\\ (except maybe at 2 if n==4), +\\ if n==3, det(G) = +-1 +\\ if n==4, or n is odd, det(G) is squarefree. +\\ if n>=6, det(G) has all its valuations <=2. -\\ Reduction de G et recherche de solution triviales -\\ par exemple quand det G=+-1, il y en a toujours. +\\ Reduction of G and search for trivial solutions. +\\ When det G=+-1, such trivial solutions always exist. -if( DEBUGLEVEL_qfsolve >= 1, print("reduction")); - U = IndefiniteLLL(G); +if( DEBUGLEVEL_qfsolve >= 1, print(" reduction")); + U = qflllgram_indef(G); if(type(U) == "t_COL", -if( DEBUGLEVEL_qfsolve >= 1, print("solution ",M*U)); +if( DEBUGLEVEL_qfsolve >= 1, print(" solution = ",M*U)); +if( DEBUGLEVEL_qfsolve >= 1, print(" end of qfsolve")); return(M*U)); G = U[1]; M = M*U[2]; \\ -\\ Quand n >= 6 est pair, il faut passer en dimension n+1 -\\ pour supprimer tous les carres de det(G). +\\ If n >= 6 is even, need to increment the dimension by 1 +\\ to suppress all the squares of det(G). \\ if( n >= 6 && n%2 == 0 && matsize(Min[3])[1] != 0, -if( DEBUGLEVEL_qfsolve >= 1, print("On passe en dimension ",n+1)); +if( DEBUGLEVEL_qfsolve >= 1, print(" increase the dimension by 1 = ",n+1)); codim = 1; n++; -\\ On calcule le plus grand diviseur carre de d. - aux = prod( i = 1, matsize(Min[3])[1], if( Min[3][i,1] == 2, Min[3][i,1], 1)); -\\ On choisit le signe de aux pour que la signature de G1 -\\ soit la plus equilibree possible. +\\ largest square divisor of d. + aux = 1; + for( i = 1, matsize(Min[3])[1], + if( Min[3][i,1] == 2, aux *= Min[3][i,1])); +\\ Choose the sign of aux such that the signature of G1 +\\ is as balanced as possible if( signG[1] > signG[2], signG[2] ++; aux = -aux , signG[1] ++ @@ -819,7 +967,7 @@ if( DEBUGLEVEL_qfsolve >= 1, print("On passe en dimension ",n+1)); for( i = 2, length(factD[,1]), factD[i,2] = valuation(detG1,factD[i,1])); factD[2,2]--; - Min = Qfminim(G1,factD); + Min = qfminimize(G1,factD); G1 = Min[1]; M1 = Min[2]; subspace1 = matrix(n,n-1,i,j, i == j) @@ -827,161 +975,226 @@ if( DEBUGLEVEL_qfsolve >= 1, print("On passe en dimension ",n+1)); G1 = G; subspace1 = M1 = matid(n) ); -\\ Maintenant d est sans facteur carre. +\\ Now, d is squarefree -\\ -\\ Si d n'est pas +-1, il faut passer en dimension n+2 +\\ +\\ If d is not +-1, need to increment the dimension by 2 \\ if( matsize(Min[3])[1] == 0, \\ if( abs(d) == 1, -if( DEBUGLEVEL_qfsolve >= 2, print(" detG2 = 1")); +if( DEBUGLEVEL_qfsolve >= 2, print(" detG2 = 1")); G2 = G1; subspace2 = M2 = matid(n); - solG2 = LLLgoon(G2,1) + solG2 = qflllgram_indefgoon(G2) , -if( DEBUGLEVEL_qfsolve >= 1, print("On passe en dimension ",n+2)); +if( DEBUGLEVEL_qfsolve >= 1, print(" increase the dimension by 2 = ",n+2)); codim += 2; subspace2 = matrix( n+2, n, i, j, i == j); - d = prod( i = 1, matsize(Min[3])[1],Min[3][i,1]); \\ d = abs(matdet(G1)); + d = 1; + for( i = 1, matsize(Min[3])[1], + d *= Min[3][i,1]); \\ d = abs(matdet(G1)); if( signG[2]%2 == 1, d = -d); \\ d = matdet(G1); - if( Min[3][1,1] == 2, factD = [-1], factD = [-1,2]); \\ si d est pair ... + if( Min[3][1,1] == 2, factD = [-1], factD = [-1,2]); \\ if d is even ... factD = concat(factD, Min[3][,1]~); -if( DEBUGLEVEL_qfsolve >= 4, print("factD=",factD)); +if( DEBUGLEVEL_qfsolve >= 4, print(" factD = ",factD)); -\\ Solubilite locale en 2 (c'est le seul cas qui restait a traiter !!) +\\ Solubility at 2 (this is the only remaining bad prime). if( n == 4 && d%8 == 1, - if( QfWittinvariant(G,2) == 1, -if( DEBUGLEVEL_qfsolve >= 1, print("pas de solution locale en 2")); + if( qflocalinvariant(G,2) == 1, +if( DEBUGLEVEL_qfsolve >= 1, print(" no local solution at 2")); +if( DEBUGLEVEL_qfsolve >= 1, print(" end of qfsolve")); return(2))); \\ -\\ Construction d'une forme Q de dim 2, a partir de ces invariants. +\\ Build a binary quadratic form with given invariants \\ Winvariants = vectorv(length(factD)); -\\ choix de la signature de Q. -\\ invariant reel et signe du discriminant. +\\ choose the signature of Q. +\\ (real invariant and sign of the discriminant) dQ = abs(d); if( signG[1] ==signG[2], dQ = dQ; Winvariants[1] = 0); \\ signQ = [1,1]; if( signG[1] > signG[2], dQ =-dQ; Winvariants[1] = 0); \\ signQ = [2,0]; if( n == 4 && dQ%4 != 1, dQ *= 4); if( n >= 5, dQ *= 8); -\\ invariants p-adiques -\\ pour p = 2, on ne choisit pas. - if( n == 4, -if( DEBUGLEVEL_qfsolve >= 1, print("calcul des invariants locaux de G1")); - aux = Qflisteinvariants(-G1,factD)[2][,1]; - for( i = 3, length(factD), Winvariants[i] = aux[i]) +\\ p-adic invariants +\\ for p = 2, the choice is fixed from the product formula + if( n == 4, +if( DEBUGLEVEL_qfsolve >= 1, print(" compute the local invariants of G1")); + auxg = qflocalinvariants(-G1,factD)[2][,1]; + for( i = 3, length(factD), Winvariants[i] = auxg[i]) , - aux = (-1)^((n-3)/2)*dQ/d; \\ ici aux = 8 ou -8 - for( i = 3, length(factD), Winvariants[i] = hilbert(aux,factD[i],factD[i]) > 0) + aux = ((-1)^((n-3)/2)*dQ/d); \\ ici aux = 8 ou -8 + for( i = 3, length(factD), + Winvariants[i] = myhilbert(aux,factD[i],factD[i]) > 0) ); Winvariants[2] = sum( i = 1, length(factD), Winvariants[i])%2; if( DEBUGLEVEL_qfsolve >= 1, - print("Recherche d'un forme binaire de discriminant = ",dQ); - print("et d'invariants de Witt = ",Winvariants)); + print(" Search for a binary quadratic form of discriminant = ",dQ); + print(" and Witt invariants = ",Winvariants)); -\\ On construit le 2-groupe de classes de disc dQ, -\\ jusqu'a obtenir une combinaison des generateurs qui donne les bons invariants. -\\ En dim 4, il faut chercher parmi les formes du type q, 2*q -\\ car Q peut etre imprimitive. +\\ Construction of the 2-class group of discriminant dQ +\\ until some product of the generators gives the desired invariants. +\\ In dim 4, need to look among the forms of the type q or 2*q +\\ because Q might be imprimitive. factd = matrix(length(factD)-1,2); for( i = 1, length(factD)-1, factd[i,1] = factD[i+1]; factd[i,2] = valuation(dQ,factd[i,1])); factd[1,2]++; - U2 = matrix(length(factD), n == 4, i,j, hilbert(2,dQ,factD[i])<0); - clgp2 = class2(dQ,factd,Winvariants,U2); -if( DEBUGLEVEL_qfsolve >= 4, print("clgp2=",clgp2)); + U2 = matrix(length(factD), n == 4, i,j, myhilbert(2,dQ,factD[i])<0); + clgp2 = quadclass2(dQ,factd,Winvariants,U2); +if( DEBUGLEVEL_qfsolve >= 4, print(" clgp2 = ",clgp2)); clgp2 = clgp2[2]; - U = Qflisteinvariants(clgp2,factD)[2]; + U = qflocalinvariants(clgp2,factD)[2]; if( n == 4, U = concat(U,U2)); -if( DEBUGLEVEL_qfsolve >= 4, printp("U=",U)); +if( DEBUGLEVEL_qfsolve >= 4, print(" U = ",U)); V = lift(matinverseimage(U*Mod(1,2),Winvariants*Mod(1,2))); - if( !length(V), next); -if( DEBUGLEVEL_qfsolve >= 4, print("V=",V)); +if( DEBUGLEVEL_qfsolve >= 4, print(" V = ",V)); if( dQ%2 == 1, Q = qfbprimeform(4*dQ,1), Q = qfbprimeform(dQ,1)); - for( i = 1, length(clgp2), + for( i = 1, length(clgp2), if( V[i], Q = qfbcompraw(Q,clgp2[i]))); - Q = mymat(Q); - if( norml2(V) > 1, aux = QfbReduce(Q); Q = aux~*Q*aux); + Q = Mat(Q); + if( norml2(V) > 1, auxg = qfbreduce(Q); Q = auxg~*Q*auxg); if( n == 4 && V[length(V)], Q*= 2); -if( DEBUGLEVEL_qfsolve >= 2, print("Q=",Q)); -if( DEBUGLEVEL_qfsolve >= 3, print("invariants de Witt de Q=",Qflisteinvariants(Q,factD))); +if( DEBUGLEVEL_qfsolve >= 2, print(" Q = ",Q)); +if( DEBUGLEVEL_qfsolve >= 3, print(" Witt invariants of Q = ",qflocalinvariants(Q,factD))); \\ -\\ Construction d'une forme de dim=n+2 potentiellement unimodulaire +\\ Build a form of dim=n+2 potentially unimodular \\ G2 = matdiagonalblock([G1,-Q]); -if( DEBUGLEVEL_qfsolve >= 4, print("G2=",G2)); +if( DEBUGLEVEL_qfsolve >= 4, print(" G2 = ",G2)); -if( DEBUGLEVEL_qfsolve >= 2, print("minimisation de la forme quadratique de dimension ",length(G2))); -\\ Minimisation de G2 +if( DEBUGLEVEL_qfsolve >= 2, print(" minimization of the form of dimension ",length(G2))); +\\ Minimization of G2 detG2 = matdet(G2); factd = matrix(length(factD)-1,2); for( i = 1, length(factD)-1, factd[i,2] = valuation(detG2, factd[i,1] = factD[i+1])); -if( DEBUGLEVEL_qfsolve >= 3, print("det(G2) = ",factd)); - Min = Qfminim(G2,factd); +if( DEBUGLEVEL_qfsolve >= 3, print(" det(G2) = ",factd)); + Min = qfminimize(G2,factd); M2 = Min[2]; G2 = Min[1]; -if( abs(matdet(G2)) > 2, print("******* ERREUR dans Qfsolve: det(G2) <> +-1 *******",matdet(G2));return(0)); -if( DEBUGLEVEL_qfsolve >= 4, print("G2=",G2)); +if( abs(matdet(G2)) > 2, error("qfsolve: det(G2) <> +-1 *******")); +if( DEBUGLEVEL_qfsolve >= 4, print(" G2 = ",G2)); -\\ Maintenant det(G2) = +-1 +\\ Now, we have det(G2) = +-1 -\\ On construit un seti pour G2 (Sous-Espace Totalement Isotrope) -if( DEBUGLEVEL_qfsolve >= 2, print("recherche d'un espace de solutions pour G2")); - solG2 = LLLgoon(G2,1); +\\ Find a seti for G2 (Totally isotropic subspace, Sous-Espace Totalement Isotrope) +if( DEBUGLEVEL_qfsolve >= 2, print(" Search a subspace of solutions for G2")); + solG2 = qflllgram_indefgoon(G2); if( matrix(codim+1,codim+1,i,j,solG2[1][i,j]) != 0, -if( DEBUGLEVEL_qfsolve >= 2, print(" pas assez de solutions dans G2"));return(0)) + error("qfsolve: not enough solutions in G2")); ); -\\ G2 doit avoir un espace de solutions de dimension > codim +\\ G2 must have a subspace of solutions of dimension > codim dimseti = 0; while( matrix(dimseti+1,dimseti+1,i,j,solG2[1][i,j]) == 0, dimseti ++); if( dimseti <= codim, -print("dimseti = ",dimseti," <= codim = ",codim); -print("************* ERREUR : pas assez de solutions pour G2"); return(0)); + error("qfsolve: not enough solutions for G2")); solG2 = matrix(length(G2),dimseti,i,j,solG2[2][i,j]); -if( DEBUGLEVEL_qfsolve >= 3, print("solG2=",solG2)); +if( DEBUGLEVEL_qfsolve >= 3, print(" solG2 = ",solG2)); -\\ La solution de G1 se trouve a la fois dans solG2 et dans subspace2 -if( DEBUGLEVEL_qfsolve >= 1, print("Reconstruction de la solution de G1")); +\\ The solution of G1 is simultaneously in solG2 and subspace2 +if( DEBUGLEVEL_qfsolve >= 1, print(" Reconstruction of a solution of G1")); solG1 = matintersect(subspace2,M2*solG2); solG1 = subspace2~*solG1; -if( DEBUGLEVEL_qfsolve >= 3, print("solG1 = ",solG1)); +if( DEBUGLEVEL_qfsolve >= 3, print(" solG1 = ",solG1)); -\\ La solution de G se trouve a la fois dans solG et dans subspace1 -if( DEBUGLEVEL_qfsolve >= 1, print("Reconstruction de la solution de G")); +\\ The solution of G is simultaneously in solG and subspace1 +if( DEBUGLEVEL_qfsolve >= 1, print(" Reconstruction of a solution of G")); sol = matintersect(subspace1,M1*solG1); sol = subspace1~*sol; sol = M*sol; sol /= content(sol); if( length(sol) == 1, sol = sol[,1]); -if( DEBUGLEVEL_qfsolve >= 3, print("sol = ",sol)); -if( DEBUGLEVEL_qfsolve >= 1, print("fin de Qfsolve")); +if( DEBUGLEVEL_qfsolve >= 3, print(" sol = ",sol)); +if( DEBUGLEVEL_qfsolve >= 1, print(" end of qfsolve")); return(sol); } -{matdiagonalblock(v) = -local(lv,lt,M); - lv = length(v); - lt = sum( i = 1, lv, length(v[i])); - M = matrix(lt,lt); - lt = 0; - for( i = 1, lv, - for( j = 1, length(v[i]), - for( k = 1, length(v[i]), - M[lt+j,lt+k] = v[i][j,k])); - lt += length(v[i]) + +\\ G is a symmetric 3x3 matrix, and sol a solution of sol~*G*sol=0. +\\ Returns a parametrization of the solutions with the good invariants, +\\ as a matrix 3x3, where each line contains +\\ the coefficients of each of the 3 quadratic forms. +\\ If fl!=0, the fl-th form is reduced. +{qfparam(G,sol,fl=3) = +my(U,G1,G2); + +if( DEBUGLEVEL_qfsolve >= 5, print(" starting qfparam")); + sol /= content(sol); +\\ build U such that U[,3] = sol, and det(U) = +-1 + U = completebasis(sol,1); + G1 = U~*G*U; \\ G1 has a 0 at the bottom right corner + G2 = [-2*G1[1,3],-2*G1[2,3],0; + 0,-2*G1[1,3],-2*G1[2,3]; + G1[1,1],2*G1[1,2],G1[2,2]]; + sol = U*G2; + if(fl, + U = qflllgram_indef([sol[fl,1],sol[fl,2]/2; sol[fl,2]/2,sol[fl,3]],1,1)[2]; + U = [U[1,1]^2,2*U[1,2]*U[1,1],U[1,2]^2; + U[2,1]*U[1,1],U[2,2]*U[1,1]+U[2,1]*U[1,2],U[1,2]*U[2,2]; + U[2,1]^2,2*U[2,1]*U[2,2],U[2,2]^2]; + sol = sol*U ); -return(M); +if( DEBUGLEVEL_qfsolve >= 5, print(" end of qfparam")); +return(sol); +} + +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ +\\ HELP MESSAGES \\ +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ + +{ +addhelp(default_qfsolve, + "default_qfsolve(DEBUGLEVEL_qfsolve): + output or set the value of the global variable DEBUGLEVEL_qfsolve. + The higher the value, the more information you get about intermediate + results concerning functions related to qfsolve. + default is 0: print nothing."); +addhelp(qflllgram_indef, + "qflllgram_indef(G,{c}): Solve or reduce the quadratic form G with integral coefficients. G might be definite or indefinite. This is an lll-type algorithm with a constant 1/4 G=[1637490518557, -9118398255553, -17114399686722; -9118398255553, -40039266946520, 44178901566187; -17114399686722, 44178901566187, 150094052078168]; + gp > qflllgram_indef(G) + %1 = [-24749181067550, 1904107022307, -3382470700136]~ +"); +addhelp(qfsolve, + "Given a square matrix G of dimension n >= 1, solve over Q the quadratic equation X^tGX = 0. G is assumed to have integral coprime coefficients. + The solution might be a single vector (vectorv) or a matrix (whose columns generate a totally isotropic subspace). + If no solution exists, returns an integer, that can be a prime p such that there is no local solution at p, or -1 if there is no real solution, or 0 in some rare cases. + To save time, a second optional parameter factD can be given and must be equal to factor(-abs(2*matdet(G))). + Example: + gp > G = [1,0,0;0,1,0;0,0,-34]; + gp > qfsolve(G) + %1 = [-3, -5, 1]~"); +addhelp(qfparam, + "qfparam(G,sol,{fl}): Coefficients of quadratic forms that parametrize the + solutions of the ternary quadratic form G, using the particular + solution sol. + fl is optional and can be 1, 2, or 3, in which case the 'fl'th form is + reduced. The default is fl=3. + + Example: + gp > G = [1,0,0;0,1,0;0,0,-34]; + gp > qfparam(G,qfsolve(G)) + %2 = + [ 3 -10 -3] + + [-5 -6 5] + + [ 1 0 1] + Indeed, the solutions can be parametrized as + [3*x^2 - 10*y*x - 3*y^2, -5*x^2 - 6*y*x + 5*y^2, x^2 + y^2]~"); } diff --git a/src/ext/pari/simon/resultant3.gp b/src/ext/pari/simon/resultant3.gp index 14b9046d808..2c1e44e2e12 100644 --- a/src/ext/pari/simon/resultant3.gp +++ b/src/ext/pari/simon/resultant3.gp @@ -1,235 +1,307 @@ -\\ Ce fichier gp contient des fonctions pour calculer -\\ le resultant de trois polynomes p1,p2,p3 homogenes -\\ en trois variables (toujours x,y,z), ainsi que -\\ le discriminant d'un polynome homogene en ces trois variables. -\\ L'algorithme utilise est celui du sous-resultant. +\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ +\\ Copyright (C) 2014 Denis Simon \\ -\\ *********************************************** -\\ * Auteur: Denis SIMON * -\\ * mail: desimon@math.unicaen.fr.fr * -\\ * date: 12 Dec 2003 * -\\ *********************************************** +\\ Distributed under the terms of the GNU General Public License (GPL) \\ -\\ exemple d'utilisation : -\\ -\\ ? p1=x^2-3*z^2+y*z;p2=x-y+15*z;p3=y^2*x+z^3-x*y*z+x^2*z; -\\ ? resultant3([p1,p2,p3]) -\\ %2 = 521784 -\\ ? discriminant3(p3) -\\ %3 = -63 -\\ -\\ la fonction hom sert a rendre homogene un polynome en x et y: -\\ ? ell=y^2-y-x^3+x^2; -\\ ? discriminant3(hom(ell)) -\\ %5 = -11 +\\ This code is distributed in the hope that it will be useful, +\\ but WITHOUT ANY WARRANTY; without even the implied warranty of +\\ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +\\ General Public License for more details. \\ +\\ The full text of the GPL is available at: \\ +\\ http://www.gnu.org/licenses/ +\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ + +/* + Auteur : + Denis SIMON -> simon@math.unicaen.fr + adresse du fichier : + www.math.unicaen.fr/~simon/resultant3.gp + + ********************************************* + * VERSION 13/01/2014 * + ********************************************* + + Ce fichier gp contient des fonctions pour calculer + le resultant de trois polynomes p1, p2, p3 homogenes + en trois variables (toujours x,y,z), ainsi que + le discriminant d'un polynome homogene en ces trois variables. + L'algorithme utilise est celui du sous-resultant. + + + exemple d'utilisation : + + ? p1=x^2-3*z^2+y*z;p2=x-y+15*z;p3=y^2*x+z^3-x*y*z+x^2*z; + ? resultant3([p1,p2,p3]) + %2 = 521784 + ? discriminant3(p3) + %3 = -63 + + la fonction hom sert a rendre homogene un polynome en x et y: + ? ell=y^2-y-x^3+x^2; + ? discriminant3(hom(ell)) + %5 = -11 + +*/ + +global(DEBUGLEVEL_res):small; + + DEBUGLEVEL_res = 0; \\ si DEBUGLEVEL_res = 1 : afficher des resultats intermediaires. -{hom(p)= -p=subst(subst(z^100*p,x,x/z),y,y/z); -p/=z^myvaluation(p,z); +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ +\\ SCRIPT \\ +\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ + +{default_res( + DEBUGLEVEL_res_val:small = 0 + ) = + + DEBUGLEVEL_res = DEBUGLEVEL_res_val; + print(" DEBUGLEVEL_res = ",DEBUGLEVEL_res); +} +{hom(p) = + p = substvec(p,['x,'y],['x/'z,'y/'z]); + p /= 'z^valuation(p,'z); return(p); } -\\ +{degreetot(p) = \\ degre d'un polynome homogene. -\\ -{degreetot(p)= -local(auxdeg,auxp); -auxdeg=poldegree(p,x);auxp=pollead(p,x); -auxdeg+=poldegree(auxp,y);auxp=pollead(auxp,y); -auxdeg+=poldegree(auxp,z);auxp=pollead(auxp,z); +my(auxdeg,auxp); + + auxdeg = poldegree(p,'x); auxp = pollead(p,'x); + auxdeg += poldegree(auxp,'y); auxp = pollead(auxp,'y); + auxdeg += poldegree(auxp,'z); auxp = pollead(auxp,'z); return(auxdeg); } -\\ -{ex(vec,i,j)= -local(aux); -aux=vec[i];vec[i]=vec[j];vec[j]=aux; +{ex( vec, i, j) = +my(aux); + aux = vec[i]; vec[i] = vec[j]; vec[j] = aux; return(vec); } -{myvaluation(p,var)= -local(valp); -valp=0; -while(polcoeff(p,valp,var)==0,valp++); -return(valp); -} -{myvaluation2(p,var)= -local(pp,valp); -pp=p; -valp=0; -while(subst(pp,var,0)==0,valp++;pp/=var); -return(valp); +{mycontent(p) = +my(vz,co,dco); + vz = valuation(p,'z); + p = subst(p,'z,1); + co = content(p); + dco = poldegree(co,'y); + if( dco, co = subst(co,'y,'y/'z)*'z^dco); +return(co*'z^vz); } -{mycontent(p)= -local(vz,co,dco); -vz=myvaluation(p,z); -p=subst(p,z,1); -co=content(p); -dco=poldegree(co,y); -if(dco,co=subst(co,y,y/z)*z^dco); -return(co*z^vz); -} -{resultant2(p,q)= -local(dp,dq,valp,valq,auxr,auxp,auxq,res); -if(p==0 || q==0,return(0)); -dp=degreetot(p);dq=degreetot(q); -valp=myvaluation(p,y); -valq=myvaluation(q,y); -if(valp && valq,return(0)); -auxr=1; -if(valp, - if(dq%2 && valp%2,auxr=-1); - auxr*=pollead(q,x)^valp); -if(valq,auxr=pollead(p,x)^valq); -auxp=subst(p,y,1); -auxq=subst(q,y,1); -res=auxr*polresultant(auxp,auxq,x); +{myresultant2( p, q) = +my(dp,dq,valp,valq,auxr,auxp,auxq,res); + + if( p==0 || q==0, return(0)); + dp = degreetot(p); valp = valuation(p,'y); + dq = degreetot(q); valq = valuation(q,'y); + if( valp && valq, return(0)); + auxr = 1; + if( valp, + if(dq%2 && valp%2, auxr = -1); + auxr *= pollead(q,'x)^valp + ); + if( valq, + auxr = pollead(p,'x)^valq + ); + auxp = subst(p,'y,1); + auxq = subst(q,'y,1); + res = auxr*polresultant(auxp,auxq,'x); return(res); } -{resultantcomp(vp=[x,y,z])= +{resultantcomp(vp=['x,'y,'z]) = \\ les vp[i] sont des pol homogenes en x,y et z. \\ vp[3] ne depend que de y et z. -local(p,q,rt,dp,dq,drt,vy,vz,lrt,lp,res,aux,res2,dres2); -p=vp[1];q=vp[2];rt=vp[3]; -if(p==0 || q==0 || rt==0,return(0)); -dp=degreetot(p);dq=degreetot(q);drt=degreetot(rt); -if(drt==0,return(rt^(dp*dq))); -vy=myvaluation(rt,y);vz=myvaluation(rt,z); -rt=subst(rt,y,1);if(vz,rt/=z^vz); -lrt=polcoeff(rt,drt,z);lp=polcoeff(p,dp,x); -res=1; -if(lp==0, - aux=p;p=q;q=aux; - aux=dp;dp=dq;dq=aux; - if(dp%2 && dq%2 && drt%2,res=-res); - lp=polcoeff(p,dp,x); - if(lp==0,return(0))); -if(vy, - if(dp%2 && dq%2, res2=-1,res2=1); - res2*=resultant2(subst(subst(p,y,0),z,y),subst(subst(q,y,0),z,y)); - if(res2==0,return(0)); - res*=res2^vy); -if(vz, - res2=resultant2(subst(p,z,0),subst(q,z,0)); - if(res2==0,return(0)); - res*=res2^vz); -drt-=(vy+vz); -if(drt==0,return(res*rt^(dp*dq))); -res2=polresultant(subst(p,y,1),subst(q,y,1),x); -dres2=poldegree(res2,z); -res2=polresultant(rt,res2,z); -res*=res2; -if(dq!=poldegree(subst(q,y,1),x),res*=lp^(drt*(dq-poldegree(subst(q,y,1),x)))); -if(dres2!=dp*dq,res*=pollead(rt,z)^(dp*dq-dres2)); +my(p,q,rt,dp,dq,drt,vy,vz,lrt,lp,res,aux,res2,dres2); + + p = vp[1]; q = vp[2]; rt = vp[3]; + if( p==0 || q==0 || rt==0, return(0)); + dp = degreetot(p); dq = degreetot(q); drt = degreetot(rt); + if( drt == 0, return(rt^(dp*dq))); + vy = valuation(rt,'y); vz = valuation(rt,'z); + rt = subst(rt,'y,1); if( vz, rt /= 'z^vz); + lrt = polcoeff(rt,drt,'z); lp = polcoeff(p,dp,'x); + res = 1; + if( lp == 0, + aux = p; p = q; q = aux; + aux = dp; dp = dq; dq = aux; + if( dp%2 && dq%2 && drt%2, res = -res); + lp = polcoeff(p,dp,'x); + if( lp == 0, return(0)) + ); + if( vy, + if( dp%2 && dq%2, res2 = -1, res2 = 1); + res2 *= myresultant2(subst(subst(p,'y,0),'z,'y),subst(subst(q,'y,0),'z,'y)); + res2 *= myresultant2(subst(subst(p,'y,0),'z,'y),subst(subst(q,'y,0),'z,'y)); + if( res2 == 0, return(0)); + res *= res2^vy + ); + if( vz, + res2 = myresultant2(subst(p,'z,0),subst(q,'z,0)); + if( res2 == 0, return(0)); + res *= res2^vz + ); + drt -= vy+vz; + if( drt == 0, return(res*rt^(dp*dq))); + res2 = polresultant(subst(p,'y,1),subst(q,'y,1),'x); + dres2 = poldegree(res2,'z); + res2 = polresultant(rt,res2,'z); + res *= res2; + if( dq != poldegree(subst(q,'y,1),'x), + res *= lp^(drt*(dq-poldegree(subst(q,'y,1),'x)))); + if( dres2 != dp*dq, + res *= pollead(rt,'z)^(dp*dq-dres2)); return(res); } -{resultant3(vp=[x,y,z],fl)= +{resultant3(vp=['x,'y,'z]) = \\ resultant de 3 polynomes homogenes en x,y,z. -\\ fl=1 pour afficher des resultats intermediaires. \\ on travaille sur la variable x. -local(vdt,vdx,prodd,s,denom,nume,lp,p0,q0,r0,dd,cq,rm,res); +my(vdt,vdx,prodd,s,denom,nume,lp,p0,q0,r0,dd,cq,rm,res,delta); -for(i=1,3,if(vp[i]==0,return(0))); -vdt=vector(3,i,degreetot(vp[i])); -vdx=vector(3,i,poldegree(vp[i],x)); -if(vecmin(vdt-vdx),return(0)); + for( i = 1, 3, + if( vp[i] == 0, return(0))); + vdt = vector(3,i,degreetot(vp[i])); + vdx = vector(3,i,poldegree(vp[i],'x)); + if( vecmin(vdt-vdx), return(0)); \\ en effet, dans ce cas, les polynomes sont dans l'ideal -prodd=prod(i=1,3,vdt[i]); -s=1; -denom=1;nume=1; + prodd = prod( i = 1, 3, vdt[i]); + s = 1; + denom = 1; nume = 1; + \\ on echange pour que vdx[1] >= vdx[2] >= vdx[3] -if(vdx[1]0, la 'fl'eme forme quadratique est reduite. +# For the documentation of the corresponding GP functions, see +# src/ext/pari/simon/qfsolve.gp. def qfsolve(G, factD=None): r""" @@ -67,6 +58,10 @@ def qfsolve(G, factD=None): Otherwise, returns `-1` if no solutions exists over the reals or a prime `p` if no solution exists over the `p`-adic field `\QQ_p`. + ALGORITHM: + + Uses Denis Simon's GP script ``qfsolve``. + EXAMPLES:: sage: from sage.quadratic_forms.qfsolve import qfsolve @@ -91,12 +86,12 @@ def qfsolve(G, factD=None): sage: M = Matrix(QQ, [[3, 0, 0, 0], [0, 5, 0, 0], [0, 0, -7, 0], [0, 0, 0, -11]]) sage: qfsolve(M) - (-3, 4, 3, 2) + (3, -4, -3, -2) """ gp = _gp_for_simon() if factD is not None: raise NotImplementedError, "qfsolve not implemented with parameter factD" - ret = gp('Qfsolve(%s)' % G._pari_init_()) + ret = gp('qfsolve(%s)' % G._pari_init_()) if str(ret.type()) == 't_COL': # Need explicit str(), see #15522 return tuple(QQ(r) for r in ret) return ZZ(ret) @@ -119,7 +114,7 @@ def qfparam(G, sol): ALGORITHM: - Uses Denis Simon's pari script Qfparam. + Uses Denis Simon's GP script ``qfparam``. EXAMPLES:: @@ -130,13 +125,13 @@ def qfparam(G, sol): [-12 0 -1] sage: sol = qfsolve(M); sage: ret = qfparam(M, sol); ret - (-t^2 - 12, 24*t, 24*t^2) + (-12*t^2 - 1, 24*t, 24) sage: ret[0].parent() is QQ['t'] True """ gp = _gp_for_simon() R = QQ['t'] t = R.gen() - s = 'Qfparam((%s), (%s)~)*[t^2,t,1]~' % (G._pari_init_(), list(sol)) + s = 'qfparam((%s), (%s)~)*[t^2,t,1]~' % (G._pari_init_(), list(sol)) ret = gp(s) return tuple(R(str(r)) for r in ret) diff --git a/src/sage/schemes/elliptic_curves/ell_number_field.py b/src/sage/schemes/elliptic_curves/ell_number_field.py index 62af7c3f6a4..22c956cc164 100644 --- a/src/sage/schemes/elliptic_curves/ell_number_field.py +++ b/src/sage/schemes/elliptic_curves/ell_number_field.py @@ -219,45 +219,48 @@ def simon_two_descent(self, verbose=0, lim1=5, lim3=50, limtriv=10, maxprob=20, Elliptic Curve defined by y^2 = x^3 + x + a over Number Field in a with defining polynomial x^2 + 7 sage: v = E.simon_two_descent(verbose=1); v - courbe elliptique : Y^2 = x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7) - points triviaux sur la courbe = [[1, 1, 0], [Mod(1/2*y + 3/2, y^2 + 7), Mod(-y - 2, y^2 + 7), 1]] + elliptic curve: Y^2 = x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7) + Trivial points on the curve = [[1, 1, 0], [Mod(1/2*y + 3/2, y^2 + 7), Mod(-y - 2, y^2 + 7), 1]] #S(E/K)[2] = 2 #E(K)/2E(K) = 2 #III(E/K)[2] = 1 - rang(E/K) = 1 - listpointsmwr = [[Mod(1/2*y + 3/2, y^2 + 7), Mod(-y - 2, y^2 + 7), 1]] + rank(E/K) = 1 + listpoints = [[Mod(1/2*y + 3/2, y^2 + 7), Mod(-y - 2, y^2 + 7), 1]] (1, 1, [(1/2*a + 3/2 : -a - 2 : 1)]) - sage: v = E.simon_two_descent(verbose=2) # random output + sage: v = E.simon_two_descent(verbose=2) K = bnfinit(y^2 + 7); a = Mod(y,K.pol); bnfellrank(K, [0,0,0,1,a]); - courbe elliptique : Y^2 = x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7) - A = 0 - B = Mod(1, y^2 + 7) - C = Mod(y, y^2 + 7) - LS2gen = [Mod(Mod(-5, y^2 + 7)*x^2 + Mod(-3*y, y^2 + 7)*x + Mod(8, y^2 + 7), x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7)), Mod(Mod(1, y^2 + 7)*x^2 + Mod(1/2*y - 1/2, y^2 + 7)*x - 1, x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7))] - #LS2gen = 2 - Recherche de points triviaux sur la courbe - points triviaux sur la courbe = [[1, 1, 0], [Mod(1/2*y + 3/2, y^2 + 7), Mod(-y - 2, y^2 + 7), 1]] - zc = Mod(Mod(-5, y^2 + 7)*x^2 + Mod(-3*y, y^2 + 7)*x + Mod(8, y^2 + 7), x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7)) - symbole de Hilbert (Mod(2, y^2 + 7),Mod(-5, y^2 + 7)) = -1 - zc = Mod(Mod(1, y^2 + 7)*x^2 + Mod(1/2*y - 1/2, y^2 + 7)*x + Mod(-1, y^2 + 7), x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7)) - symbole de Hilbert (Mod(-2*y + 2, y^2 + 7),Mod(1, y^2 + 7)) = 0 - sol de Legendre = [1, 0, 1]~ - zc*z1^2 = Mod(Mod(2*y - 2, y^2 + 7)*x + Mod(2*y + 10, y^2 + 7), x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7)) - quartique : (-1/2*y + 1/2)*Y^2 = x^4 + (-3*y - 15)*x^2 + (-8*y - 16)*x + (-11/2*y - 15/2) - reduite: Y^2 = (-1/2*y + 1/2)*x^4 - 4*x^3 + (-3*y + 3)*x^2 + (2*y - 2)*x + (1/2*y + 3/2) - non ELS en [2, [0, 1]~, 1, 1, [1, 1]~] - zc = Mod(Mod(1, y^2 + 7)*x^2 + Mod(1/2*y + 1/2, y^2 + 7)*x + Mod(-1, y^2 + 7), x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7)) - vient du point trivial [Mod(1/2*y + 3/2, y^2 + 7), Mod(-y - 2, y^2 + 7), 1] - m1 = 1 - m2 = 1 + elliptic curve: Y^2 = x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7) + A = 0 + B = Mod(1, y^2 + 7) + C = Mod(y, y^2 + 7) + Computing L(S,2) + L(S,2) = [Mod(Mod(-1, y^2 + 7)*x^2 + Mod(-1/2*y + 1/2, y^2 + 7)*x + 1, x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7)), Mod(Mod(-1, y^2 + 7)*x^2 + Mod(-1/2*y - 1/2, y^2 + 7)*x + 1, x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7)), Mod(-1, x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7)), Mod(Mod(-1/2*y + 1/2, y^2 + 7)*x + Mod(-1/2*y + 3/2, y^2 + 7), x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7)), Mod(Mod(1, y^2 + 7)*x + Mod(1/2*y + 3/2, y^2 + 7), x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7)), Mod(Mod(-1, y^2 + 7)*x + Mod(-1/2*y + 3/2, y^2 + 7), x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7))] + Computing the Selmer group + #LS2gen = 2 + LS2gen = [Mod(Mod(-5, y^2 + 7)*x^2 + Mod(-3*y, y^2 + 7)*x + Mod(8, y^2 + 7), x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7)), Mod(Mod(1, y^2 + 7)*x^2 + Mod(1/2*y - 1/2, y^2 + 7)*x - 1, x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7))] + Search for trivial points on the curve + Trivial points on the curve = [[1, 1, 0], [Mod(1/2*y + 3/2, y^2 + 7), Mod(-y - 2, y^2 + 7), 1]] + zc = Mod(Mod(-5, y^2 + 7)*x^2 + Mod(-3*y, y^2 + 7)*x + Mod(8, y^2 + 7), x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7)) + Hilbert symbol (Mod(2, y^2 + 7),Mod(-5, y^2 + 7)) = + zc = Mod(Mod(1, y^2 + 7)*x^2 + Mod(1/2*y - 1/2, y^2 + 7)*x + Mod(-1, y^2 + 7), x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7)) + Hilbert symbol (Mod(-2*y + 2, y^2 + 7),Mod(1, y^2 + 7)) = + sol of quadratic equation = [1, 0, 1]~ + zc*z1^2 = Mod(Mod(2*y - 2, y^2 + 7)*x + Mod(2*y + 10, y^2 + 7), x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7)) + quartic: (-1/2*y + 1/2)*Y^2 = x^4 + (-3*y - 15)*x^2 + (-8*y - 16)*x + (-11/2*y - 15/2) + reduced: Y^2 = (-1/2*y + 1/2)*x^4 - 4*x^3 + (-3*y + 3)*x^2 + (2*y - 2)*x + (1/2*y + 3/2) + not ELS at [2, [0, 1]~, 1, 1, [1, 1]~] + zc = Mod(Mod(1, y^2 + 7)*x^2 + Mod(1/2*y + 1/2, y^2 + 7)*x + Mod(-1, y^2 + 7), x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7)) + comes from the trivial point [Mod(1/2*y + 3/2, y^2 + 7), Mod(-y - 2, y^2 + 7), 1] + m1 = 1 + m2 = 1 #S(E/K)[2] = 2 #E(K)/2E(K) = 2 #III(E/K)[2] = 1 - rang(E/K) = 1 - listpointsmwr = [[Mod(1/2*y + 3/2, y^2 + 7), Mod(-y - 2, y^2 + 7), 1]] + rank(E/K) = 1 + listpoints = [[Mod(1/2*y + 3/2, y^2 + 7), Mod(-y - 2, y^2 + 7), 1]] v = [1, 1, [[Mod(1/2*y + 3/2, y^2 + 7), Mod(-y - 2, y^2 + 7)]]] sage: v (1, 1, [(1/2*a + 3/2 : -a - 2 : 1)]) @@ -283,7 +286,7 @@ def simon_two_descent(self, verbose=0, lim1=5, lim3=50, limtriv=10, maxprob=20, *** in function bnfellrank: ...eqtheta,rnfeq,bbnf];rang= *** bnfell2descent_gen(b *** ^-------------------- - *** in function bnfell2descent_gen: ...riv,r=nfsqrt(nf,norm(zc)) + *** in function bnfell2descent_gen: ...und,r=nfsqrt(nf,norm(zc)) *** [1];if(DEBUGLEVEL_el *** ^-------------------- *** array index (1) out of allowed range [none]. diff --git a/src/sage/schemes/elliptic_curves/ell_rational_field.py b/src/sage/schemes/elliptic_curves/ell_rational_field.py index 857061b562f..ee8a34ca9a3 100644 --- a/src/sage/schemes/elliptic_curves/ell_rational_field.py +++ b/src/sage/schemes/elliptic_curves/ell_rational_field.py @@ -1461,11 +1461,11 @@ def simon_two_descent(self, verbose=0, lim1=5, lim3=50, limtriv=10, maxprob=20, sage: E = EllipticCurve('389a1') sage: set_random_seed(0) sage: E.simon_two_descent() - (2, 2, [(1 : 0 : 1), (-11/9 : -55/27 : 1)]) + (2, 2, [(1 : 0 : 1), (-11/9 : 28/27 : 1)]) sage: E = EllipticCurve('5077a1') sage: set_random_seed(0) sage: E.simon_two_descent() - (3, 3, [(1 : -1 : 1), (2 : 0 : 1), (0 : 2 : 1)]) + (3, 3, [(1 : 0 : 1), (2 : 0 : 1), (0 : 2 : 1)]) In this example Simon's program does not find any points, though it does correctly compute the rank of the 2-Selmer group. @@ -1485,11 +1485,11 @@ def simon_two_descent(self, verbose=0, lim1=5, lim3=50, limtriv=10, maxprob=20, sage: E = EllipticCurve([1, -1, 0, -79, 289]) sage: set_random_seed(0) sage: E.simon_two_descent() - (4, 4, [(4 : 3 : 1), (5 : -2 : 1), (6 : -1 : 1), (8 : 7 : 1)]) + (4, 4, [(6 : -1 : 1), (4 : 3 : 1), (5 : -2 : 1), (8 : 7 : 1)]) sage: E = EllipticCurve([0, 0, 1, -79, 342]) sage: set_random_seed(0) sage: E.simon_two_descent() # long time (9s on sage.math, 2011) - (5, 5, [(5 : 8 : 1), (4 : 9 : 1), (3 : 11 : 1), (-1 : 20 : 1), (-6 : -25 : 1)]) + (5, 5, [(7 : 11 : 1), (-1 : 20 : 1), (0 : 18 : 1), (3 : 11 : 1), (-3 : 23 : 1)]) sage: E = EllipticCurve([1, 1, 0, -2582, 48720]) sage: set_random_seed(0) sage: r, s, G = E.simon_two_descent(); r,s @@ -1507,11 +1507,11 @@ def simon_two_descent(self, verbose=0, lim1=5, lim3=50, limtriv=10, maxprob=20, sage: E = EllipticCurve([1,0,0,-6664,86543]) sage: E.simon_two_descent() - (2, 3, [(-73 : -394 : 1), (323/4 : 1891/8 : 1)]) + (2, 3, [(-1/4 : 2377/8 : 1), (323/4 : 1891/8 : 1)]) sage: E.rank() 2 sage: E.gens() - [(-73 : -394 : 1), (323/4 : 1891/8 : 1)] + [(-1/4 : 2377/8 : 1), (323/4 : 1891/8 : 1)] Example where the lower bound is known to be 1 despite that the algorithm has not found any @@ -1529,7 +1529,7 @@ def simon_two_descent(self, verbose=0, lim1=5, lim3=50, limtriv=10, maxprob=20, sage: E = EllipticCurve([3,0]) sage: E.simon_two_descent() - (1, 2, [(3 : 6 : 1)]) + (1, 2, [(1 : 2 : 1)]) """ verbose = int(verbose) diff --git a/src/sage/schemes/elliptic_curves/gp_simon.py b/src/sage/schemes/elliptic_curves/gp_simon.py index 06b3aef86eb..19ce2db15fa 100644 --- a/src/sage/schemes/elliptic_curves/gp_simon.py +++ b/src/sage/schemes/elliptic_curves/gp_simon.py @@ -52,9 +52,7 @@ def simon_two_descent(E, verbose=0, lim1=5, lim3=50, limtriv=10, maxprob=20, lim sage: import sage.schemes.elliptic_curves.gp_simon sage: E=EllipticCurve('389a1') sage: sage.schemes.elliptic_curves.gp_simon.simon_two_descent(E) - [2, 2, [(1 : 0 : 1), (-11/9 : -55/27 : 1)]] - sage: E.simon_two_descent() - (2, 2, [(1 : 0 : 1), (-11/9 : -55/27 : 1)]) + [2, 2, [(1 : 0 : 1), (-11/9 : 28/27 : 1)]] TESTS:: diff --git a/src/sage/schemes/hyperelliptic_curves/mestre.py b/src/sage/schemes/hyperelliptic_curves/mestre.py index 03207d0a75c..fbca19f1992 100644 --- a/src/sage/schemes/hyperelliptic_curves/mestre.py +++ b/src/sage/schemes/hyperelliptic_curves/mestre.py @@ -69,7 +69,7 @@ def HyperellipticCurve_from_invariants(i, reduced=True, precision=None, ... NotImplementedError: Reduction of hyperelliptic curves not yet implemented. See trac #14755 and #14756. sage: HyperellipticCurve_from_invariants([3840,414720,491028480,2437709561856],reduced = False) - Hyperelliptic Curve over Rational Field defined by y^2 = -x^6 + 4410*x^5 - 540*x^4 + 4320*x^3 - 19440*x^2 + 46656*x - 46656 + Hyperelliptic Curve over Rational Field defined by y^2 = -46656*x^6 + 46656*x^5 - 19440*x^4 + 4320*x^3 - 540*x^2 + 4410*x - 1 sage: HyperellipticCurve_from_invariants([21, 225/64, 22941/512, 1]) Traceback (most recent call last): ... diff --git a/src/sage/schemes/plane_conics/con_field.py b/src/sage/schemes/plane_conics/con_field.py index c1fb190d39f..00a6c3c89d3 100644 --- a/src/sage/schemes/plane_conics/con_field.py +++ b/src/sage/schemes/plane_conics/con_field.py @@ -145,7 +145,7 @@ def cache_point(self, p): (15/8 : 17/8 : 1) sage: c.cache_point(c.rational_point(read_cache = False)) sage: c.rational_point() - (1 : 1 : 0) + (-1 : 1 : 0) """ if isinstance(p, (tuple, list)): p = self.point(p) @@ -882,7 +882,7 @@ def point(self, v, check=True): (15/8 : 17/8 : 1) sage: d = Conic([1, -1, 1]) sage: d.rational_point() - (1 : 1 : 0) + (-1 : 1 : 0) """ if is_Vector(v): v = Sequence(v) diff --git a/src/sage/schemes/plane_conics/con_rational_field.py b/src/sage/schemes/plane_conics/con_rational_field.py index 19f0c1f00c6..16ebd6065fc 100644 --- a/src/sage/schemes/plane_conics/con_rational_field.py +++ b/src/sage/schemes/plane_conics/con_rational_field.py @@ -96,7 +96,7 @@ def has_rational_point(self, point = False, obstruction = False, The parameter ``algorithm`` specifies the algorithm to be used: - - ``'qfsolve'`` -- Use Denis Simon's pari script Qfsolve + - ``'qfsolve'`` -- Use Denis Simon's GP script ``qfsolve`` (see ``sage.quadratic_forms.qfsolve.qfsolve``) - ``'rnfisnorm'`` -- Use PARI's function rnfisnorm @@ -314,7 +314,7 @@ def parametrization(self, point=None, morphism=True): ALGORITHM: - Uses Denis Simon's pari script Qfparam. + Uses Denis Simon's GP script ``qfparam``. See ``sage.quadratic_forms.qfsolve.qfparam``. EXAMPLES :: @@ -325,12 +325,12 @@ def parametrization(self, point=None, morphism=True): From: Projective Space of dimension 1 over Rational Field To: Projective Conic Curve over Rational Field defined by x^2 + y^2 - z^2 Defn: Defined on coordinates by sending (x : y) to - (2*x*y : x^2 - y^2 : x^2 + y^2), + (2*x*y : -x^2 + y^2 : x^2 + y^2), Scheme morphism: - From: Projective Conic Curve over Rational Field defined by x^2 + y^2 - z^2 - To: Projective Space of dimension 1 over Rational Field - Defn: Defined on coordinates by sending (x : y : z) to - (1/2*x : -1/2*y + 1/2*z)) + From: Projective Conic Curve over Rational Field defined by x^2 + y^2 - z^2 + To: Projective Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x : y : z) to + (1/2*x : 1/2*y + 1/2*z)) An example with ``morphism = False`` ::