/* $Id: base1.c,v 1.248.2.2 2007/03/11 22:48:52 kb Exp $ Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /**************************************************************/ /* */ /* NUMBER FIELDS */ /* */ /**************************************************************/ #include "pari.h" #include "paripriv.h" int new_galois_format = 0; void checkrnf(GEN rnf) { if (typ(rnf)!=t_VEC || lg(rnf)!=13) pari_err(typeer,"checkrnf"); } GEN checkbnf_i(GEN bnf) { if (typ(bnf) == t_VEC) switch (lg(bnf)) { case 11: return bnf; case 7: return checkbnf_i(gel(bnf,1)); } return NULL; } GEN checknf_i(GEN nf) { if (typ(nf)==t_VEC) switch(lg(nf)) { case 10: return nf; case 11: return checknf_i(gel(nf,7)); case 7: return checknf_i(gel(nf,1)); case 3: if (typ(nf[2]) == t_POLMOD) return checknf_i(gel(nf,1)); } return NULL; } GEN checkbnf(GEN x) { GEN bnf = checkbnf_i(x); if (!bnf) { if (checknf_i(x)) pari_err(talker,"please apply bnfinit first"); pari_err(typeer,"checkbnf"); } return bnf; } GEN checknf(GEN x) { GEN nf = checknf_i(x); if (!nf) { if (typ(x)==t_POL) pari_err(talker,"please apply nfinit first"); pari_err(typeer,"checknf"); } return nf; } void checkbnr(GEN bnr) { if (typ(bnr)!=t_VEC || lg(bnr)!=7) pari_err(talker,"incorrect bigray field"); (void)checkbnf(gel(bnr,1)); } void checkbnrgen(GEN bnr) { checkbnr(bnr); if (lg(bnr[5])<=3) pari_err(talker,"please apply bnrinit(,,1) and not bnrinit(,)"); } GEN check_units(GEN BNF, char *f) { GEN bnf = checkbnf(BNF), x = gel(bnf,8); if (lg(x) < 6 || lg(x[5]) != lg(bnf[3])) pari_err(talker,"missing units in %s", f); return gel(x,5); } void checkid(GEN x, long N) { if (typ(x)!=t_MAT) pari_err(talker,"incorrect ideal"); if (lg(x) == 1 || lg(x[1]) != N+1) pari_err(talker,"incorrect matrix for ideal"); } void checkbid(GEN bid) { if (typ(bid)!=t_VEC || lg(bid)!=6 || lg(bid[1])!=3) pari_err(talker,"incorrect bigideal"); } void checkprimeid(GEN id) { if (typ(id) != t_VEC || lg(id) != 6 || typ(id[2]) != t_COL) pari_err(talker,"incorrect prime ideal"); } static int _check_ZX(GEN x) { long k = lg(x)-1; for ( ; k>1; k--) if (typ(x[k])!=t_INT) return 0; return 1; } void check_ZX(GEN x, char *s) { if (! _check_ZX(x)) pari_err(talker,"polynomial not in Z[X] in %s",s); } void check_ZXY(GEN x, char *s) { long k = lg(x)-1; for ( ; k>1; k--) { GEN t = gel(x,k); switch(typ(t)) { case t_INT: break; case t_POL: if (_check_ZX(t)) break; /* fall through */ default: pari_err(talker,"polynomial not in Z[X,Y] in %s",s); } } } GEN checknfelt_mod(GEN nf, GEN x, char *s) { if (!gequal(gel(x,1),gel(nf,1))) pari_err(talker,"incompatible modulus in %s:\n mod = %Z,\n nf = %Z", s, x[1], nf[1]); return gel(x,2); } GEN get_primeid(GEN x) { if (typ(x) != t_VEC) return NULL; if (lg(x) == 3) x = gel(x,1); if (lg(x) != 6 || typ(x[3]) != t_INT) return NULL; return x; } GEN get_bnf(GEN x, long *t) { switch(typ(x)) { case t_POL: *t = typ_POL; return NULL; case t_QUAD: *t = typ_Q ; return NULL; case t_VEC: switch(lg(x)) { case 3: if (typ(x[2]) != t_POLMOD) break; return get_bnf(gel(x,1),t); case 5 : *t = typ_QUA; return NULL; case 6 : if (typ(x[1]) != t_VEC || typ(x[3]) != t_MAT) break; *t = typ_BID; return NULL; case 10: *t = typ_NF; return NULL; case 11: *t = typ_BNF; return x; case 7 : *t = typ_BNR; x = gel(x,1); if (typ(x)!=t_VEC || lg(x)!=11) break; return x; } case t_MAT: if (lg(x)==2) switch(lg(x[1])) { case 7: case 10: *t = typ_CLA; return NULL; } } *t = typ_NULL; return NULL; } GEN get_nf(GEN x, long *t) { switch(typ(x)) { case t_POL : *t = typ_POL; return NULL; case t_QUAD: *t = typ_Q ; return NULL; case t_VEC: switch(lg(x)) { case 3: if (typ(x[2]) != t_POLMOD) break; return get_nf(gel(x,1),t); case 10: *t = typ_NF; return x; case 11: *t = typ_BNF; x = gel(x,7); if (typ(x)!=t_VEC || lg(x)!=10) break; return x; case 7 : *t = typ_BNR; x = gel(x,1); if (typ(x)!=t_VEC || lg(x)!=11) break; x = gel(x,7); if (typ(x)!=t_VEC || lg(x)!=10) break; return x; case 6 : if (typ(x[1]) != t_VEC || typ(x[3]) != t_MAT) break; *t = typ_BID; return NULL; case 9 : x = gel(x,2); if (typ(x) == t_VEC && lg(x) == 4) *t = typ_GAL; return NULL; case 14: case 20: *t = typ_ELL; return NULL; }break; case t_MAT: if (lg(x)==2) switch(lg(x[1])) { case 7: case 10: *t = typ_CLA; return NULL; } } *t = typ_NULL; return NULL; } /*************************************************************************/ /** **/ /** GALOIS GROUP **/ /** **/ /*************************************************************************/ /* exchange elements i and j in vector x */ static GEN transroot(GEN x, int i, int j) { long k; x = shallowcopy(x); k=x[i]; x[i]=x[j]; x[j]=k; return x; } GEN tschirnhaus(GEN x) { pari_sp av = avma, av2; long a, v = varn(x); GEN u, p1 = cgetg(5,t_POL); if (typ(x)!=t_POL) pari_err(notpoler,"tschirnhaus"); if (lg(x) < 4) pari_err(constpoler,"tschirnhaus"); if (v) { u=shallowcopy(x); setvarn(u,0); x=u; } p1[1] = evalsigne(1)|evalvarn(0); do { a = random_bits(2); if (a==0) a = 1; gel(p1,4) = stoi(a); a = random_bits(3); if (a>=4) a -= 8; gel(p1,3) = stoi(a); a = random_bits(3); if (a>=4) a -= 8; gel(p1,2) = stoi(a); u = caract2(x,p1,v); av2 = avma; } while (degpol(srgcd(u,derivpol(u)))); /* while u not separable */ if (DEBUGLEVEL>1) fprintferr("Tschirnhaus transform. New pol: %Z",u); avma=av2; return gerepileupto(av,u); } int gpolcomp(GEN p1, GEN p2) { long j = lg(p1)-2; int s; if (lg(p2)-2 != j) pari_err(bugparier,"gpolcomp (different degrees)"); for (; j>=2; j--) { s = absi_cmp(gel(p1,j), gel(p2,j)); if (s) return s; } return 0; } /* assume pol in Z[X]. Find C, L in Z such that POL = C pol(x/L) monic in Z[X]. * Return POL and set *ptlead = L */ GEN primitive_pol_to_monic(GEN pol, GEN *ptlead) { long i,j,n = degpol(pol); GEN lead,fa,e,a, POL = shallowcopy(pol); a = POL + 2; lead = gel(a,n); if (signe(lead) < 0) { POL = gneg_i(POL); a = POL+2; lead = negi(lead); } if (is_pm1(lead)) { if (ptlead) *ptlead = NULL; return POL; } fa = auxdecomp(lead,0); lead = gen_1; e = gel(fa,2); fa = gel(fa,1); for (i=lg(e)-1; i>0;i--) e[i] = itos(gel(e,i)); for (i=lg(fa)-1; i>0; i--) { GEN p = gel(fa,i), pk, pku; long k = (long)ceil((double)e[i] / n); long d = k * n - e[i], v, j0; /* find d, k such that p^d pol(x / p^k) monic */ for (j=n-1; j>0; j--) { if (!signe(a[j])) continue; v = Z_pval(gel(a,j), p); while (v + d < k * j) { k++; d += n; } } pk = powiu(p,k); j0 = d/k; pku = powiu(p,d - k*j0); /* a[j] *= p^(d - kj) */ for (j=j0; j>=0; j--) { if (j < j0) pku = mulii(pku, pk); gel(a,j) = mulii(gel(a,j), pku); } j0++; pku = powiu(p,k*j0 - d); /* a[j] /= p^(kj - d) */ for (j=j0; j<=n; j++) { if (j > j0) pku = mulii(pku, pk); gel(a,j) = diviiexact(gel(a,j), pku); } lead = mulii(lead, pk); } if (ptlead) *ptlead = lead; return POL; } /* x1*x2^2 + x2*x3^2 + x3*x4^2 + x4*x1^2 */ static GEN F4(GEN x) { return gadd( gmul(gel(x,1), gadd(gsqr(gel(x,2)), gmul(gel(x,4),gel(x,1)))), gmul(gel(x,3), gadd(gsqr(gel(x,4)), gmul(gel(x,2),gel(x,3))))); } static GEN roots_to_ZX(GEN z, long *e) { GEN a = roots_to_pol(z,0); GEN b = grndtoi(real_i(a),e); long e1 = gexpo(imag_i(a)); if (e1 > *e) *e = e1; return b; } GEN polgaloisnames(long a, long b) { const char * const t[]={"S1", "S2", "A3", "S3", "C(4) = 4", "E(4) = 2[x]2", "D(4)", "A4", "S4", "C(5) = 5", "D(5) = 5:2", "F(5) = 5:4", "A5", "S5", "C(6) = 6 = 3[x]2", "D_6(6) = [3]2", "D(6) = S(3)[x]2", "A_4(6) = [2^2]3", "F_18(6) = [3^2]2 = 3 wr 2", "2A_4(6) = [2^3]3 = 2 wr 3", "S_4(6d) = [2^2]S(3)", "S_4(6c) = 1/2[2^3]S(3)", "F_18(6):2 = [1/2.S(3)^2]2", "F_36(6) = 1/2[S(3)^2]2", "2S_4(6) = [2^3]S(3) = 2 wr S(3)", "L(6) = PSL(2,5) = A_5(6)", "F_36(6):2 = [S(3)^2]2 = S(3) wr 2", "L(6):2 = PGL(2,5) = S_5(6)", "A6", "S6", "C(7) = 7", "D(7) = 7:2", "F_21(7) = 7:3", "F_42(7) = 7:6", "L(7) = L(3,2)", "A7", "S7"}; const long idx[]={0,1,2,4,9,14,30}; return strtoGENstr(t[idx[a-1]+b-1]); } static GEN galois_res(long d, long n, long s, long k) { long kk = k; GEN z = cgetg(5,t_VEC); if (!new_galois_format) { switch (d) { case 6: kk = (k == 6 || k == 2)? 2: 1; break; case 3: kk = (k == 2)? 1: 2; break; default: kk = 1; } } gel(z,1) = stoi(n); gel(z,2) = stoi(s); gel(z,3) = stoi(kk); gel(z,4) = polgaloisnames(d,k); return z; } GEN polgalois(GEN x, long prec) { pari_sp av = avma, av1; long i,j,k,n,f,l,l2,e,e1,pr,ind; GEN x1,p1,p2,p3,p4,p5,w,z,ee; static int ind5[20]={2,5,3,4, 1,3,4,5, 1,5,2,4, 1,2,3,5, 1,4,2,3}; static int ind6[60]={3,5,4,6, 2,6,4,5, 2,3,5,6, 2,4,3,6, 2,5,3,4, 1,4,5,6, 1,5,3,6, 1,6,3,4, 1,3,4,5, 1,6,2,5, 1,2,4,6, 1,5,2,4, 1,3,2,6, 1,2,3,5, 1,4,2,3}; if (typ(x)!=t_POL) pari_err(notpoler,"galois"); n=degpol(x); if (n<=0) pari_err(constpoler,"galois"); if (n>11) pari_err(impl,"galois of degree higher than 11"); x = primpart(x); check_ZX(x, "galois"); if (gisirreducible(x) != gen_1) pari_err(impl,"galois of reducible polynomial"); if (n<4) { if (n == 1) { avma = av; return galois_res(n,1, 1,1); } if (n == 2) { avma = av; return galois_res(n,2,-1,1); } /* n = 3 */ f = Z_issquare(ZX_disc(x)); avma = av; return f? galois_res(n,3,1,1): galois_res(n,6,-1,2); } x1 = x = primitive_pol_to_monic(x,NULL); av1=avma; if (n > 7) return galoisbig(x, prec); for(;;) { double cb = cauchy_bound(x); switch(n) { case 4: z = cgetg(7,t_VEC); prec = DEFAULTPREC + (long)(cb*(18./ LOG2 / BITS_IN_LONG)); for(;;) { p1=cleanroots(x,prec); gel(z,1) = F4(p1); gel(z,2) = F4(transroot(p1,1,2)); gel(z,3) = F4(transroot(p1,1,3)); gel(z,4) = F4(transroot(p1,1,4)); gel(z,5) = F4(transroot(p1,2,3)); gel(z,6) = F4(transroot(p1,3,4)); p5 = roots_to_ZX(z, &e); if (e <= -10) break; prec = (prec<<1)-2; } if (!ZX_is_squarefree(p5)) goto tchi; p2 = (GEN)factor(p5)[1]; switch(lg(p2)-1) { case 1: f = Z_issquare(ZX_disc(x)); avma = av; return f? galois_res(n,12,1,4): galois_res(n,24,-1,5); case 2: avma = av; return galois_res(n,8,-1,3); case 3: avma = av; return (degpol(p2[1])==2)? galois_res(n,4,1,2): galois_res(n,4,-1,1); default: pari_err(bugparier,"galois (bug1)"); } case 5: z = cgetg(7,t_VEC); ee= cgetg(7,t_VECSMALL); w = cgetg(7,t_VECSMALL); prec = DEFAULTPREC + (long)(cb*(21. / LOG2/ BITS_IN_LONG)); for(;;) { for(;;) { p1=cleanroots(x,prec); for (l=1; l<=6; l++) { p2=(l==1)?p1: ((l<6)?transroot(p1,1,l): transroot(p1,2,5)); p3=gen_0; for (k=0,i=1; i<=5; i++,k+=4) { p5 = gadd(gmul(gel(p2,ind5[k]),gel(p2,ind5[k+1])), gmul(gel(p2,ind5[k+2]),gel(p2,ind5[k+3]))); p3 = gadd(p3, gmul(gsqr(gel(p2,i)),p5)); } gel(w,l) = grndtoi(real_i(p3),&e); e1 = gexpo(imag_i(p3)); if (e1>e) e=e1; ee[l]=e; gel(z,l) = p3; } p5 = roots_to_ZX(z, &e); if (e <= -10) break; prec = (prec<<1)-2; } if (!ZX_is_squarefree(p5)) goto tchi; p3=(GEN)factor(p5)[1]; f=Z_issquare(ZX_disc(x)); if (lg(p3)-1==1) { avma = av; return f? galois_res(n,60,1,4): galois_res(n,120,-1,5); } if (!f) { avma = av; return galois_res(n,20,-1,3); } pr = - (bit_accuracy(prec) >> 1); for (l=1; l<=6; l++) if (ee[l] <= pr && gcmp0(poleval(p5,gel(w,l)))) break; if (l>6) pari_err(bugparier,"galois (bug4)"); p2=(l==6)? transroot(p1,2,5):transroot(p1,1,l); p3=gen_0; for (i=1; i<=5; i++) { j = i+1; if (j>5) j -= 5; p3 = gadd(p3,gmul(gmul(gel(p2,i),gel(p2,j)), gsub(gel(p2,j),gel(p2,i)))); } p5=gsqr(p3); p4=grndtoi(real_i(p5),&e); e1 = gexpo(imag_i(p5)); if (e1>e) e=e1; if (e <= -10) { if (gcmp0(p4)) goto tchi; f = Z_issquare(p4); avma = av; return f? galois_res(n,5,1,1): galois_res(n,10,1,2); } prec=(prec<<1)-2; } case 6: z = cgetg(7, t_VEC); prec = DEFAULTPREC + (long)(cb * (42. / LOG2 / BITS_IN_LONG)); for(;;) { for(;;) { p1=cleanroots(x,prec); for (l=1; l<=6; l++) { p2=(l==1)?p1:transroot(p1,1,l); p3=gen_0; k=0; for (i=1; i<=5; i++) for (j=i+1; j<=6; j++) { p5=gadd(gmul(gel(p2,ind6[k]),gel(p2,ind6[k+1])), gmul(gel(p2,ind6[k+2]),gel(p2,ind6[k+3]))); p3=gadd(p3,gmul(gsqr(gmul(gel(p2,i),gel(p2,j))),p5)); k += 4; } gel(z,l) = p3; } p5 = roots_to_ZX(z, &e); if (e <= -10) break; prec=(prec<<1)-2; } if (!ZX_is_squarefree(p5)) goto tchi; p2=(GEN)factor(p5)[1]; switch(lg(p2)-1) { case 1: z = cgetg(11,t_VEC); ind=0; p3=gadd(gmul(gmul(gel(p1,1),gel(p1,2)),gel(p1,3)), gmul(gmul(gel(p1,4),gel(p1,5)),gel(p1,6))); gel(z,++ind) = p3; for (i=1; i<=3; i++) for (j=4; j<=6; j++) { p2=transroot(p1,i,j); p3=gadd(gmul(gmul(gel(p2,1),gel(p2,2)),gel(p2,3)), gmul(gmul(gel(p2,4),gel(p2,5)),gel(p2,6))); gel(z,++ind) = p3; } p5 = roots_to_ZX(z, &e); if (e <= -10) { if (!ZX_is_squarefree(p5)) goto tchi; p2 = (GEN)factor(p5)[1]; f = Z_issquare(ZX_disc(x)); avma = av; if (lg(p2)-1==1) return f? galois_res(n,360,1,15): galois_res(n,720,-1,16); else return f? galois_res(n,36,1,10): galois_res(n,72,-1,13); } prec=(prec<<1)-2; break; case 2: l2=degpol(p2[1]); if (l2>3) l2=6-l2; switch(l2) { case 1: f = Z_issquare(ZX_disc(x)); avma = av; return f? galois_res(n,60,1,12): galois_res(n,120,-1,14); case 2: f = Z_issquare(ZX_disc(x)); if (f) { avma = av; return galois_res(n,24,1,7); } p3 = (degpol(p2[1])==2)? gel(p2,2): gel(p2,1); f = Z_issquare(ZX_disc(p3)); avma = av; return f? galois_res(n,24,-1,6): galois_res(n,48,-1,11); case 3: f = Z_issquare(ZX_disc(gel(p2,1))) || Z_issquare(ZX_disc(gel(p2,2))); avma = av; return f? galois_res(n,18,-1,5): galois_res(n,36,-1,9); } case 3: for (l2=1; l2<=3; l2++) if (degpol(p2[l2]) >= 3) p3 = gel(p2,l2); if (degpol(p3) == 3) { f = Z_issquare(ZX_disc(p3)); avma = av; return f? galois_res(n,6,-1,1): galois_res(n,12,-1,3); } else { f = Z_issquare(ZX_disc(x)); avma = av; return f? galois_res(n,12,1,4): galois_res(n,24,-1,8); } case 4: avma = av; return galois_res(n,6,-1,2); default: pari_err(bugparier,"galois (bug3)"); } } case 7: z = cgetg(36,t_VEC); prec = DEFAULTPREC + (long)(cb*(7. / LOG2 / BITS_IN_LONG)); for(;;) { ind = 0; p1=cleanroots(x,prec); for (i=1; i<=5; i++) for (j=i+1; j<=6; j++) { GEN t = gadd(gel(p1,i),gel(p1,j)); for (k=j+1; k<=7; k++) gel(z,++ind) = gadd(t, gel(p1,k)); } p5 = roots_to_ZX(z, &e); if (e <= -10) break; prec = (prec<<1)-2; } if (!ZX_is_squarefree(p5)) goto tchi; p2=(GEN)factor(p5)[1]; switch(lg(p2)-1) { case 1: f = Z_issquare(ZX_disc(x)); avma = av; return f? galois_res(n,2520,1,6): galois_res(n,5040,-1,7); case 2: f = degpol(p2[1]); avma = av; return (f==7 || f==28)? galois_res(n,168,1,5): galois_res(n,42,-1,4); case 3: avma = av; return galois_res(n,21,1,3); case 4: avma = av; return galois_res(n,14,-1,2); case 5: avma = av; return galois_res(n,7,1,1); default: pari_err(bugparier,"galois (bug2)"); } } tchi: avma = av1; x = tschirnhaus(x1); } } #undef _res /*Deprecated*/ GEN galois(GEN x, long prec) {return polgalois(x,prec);} GEN galoisapply(GEN nf, GEN aut, GEN x) { pari_sp av = avma; long lx, j, N; GEN p, p1, y, pol; nf=checknf(nf); pol=gel(nf,1); if (typ(aut)==t_POL) aut = gmodulo(aut,pol); else { if (typ(aut)!=t_POLMOD || !gequal(gel(aut,1),pol)) pari_err(talker,"incorrect galois automorphism in galoisapply"); } switch(typ(x)) { case t_INT: case t_INTMOD: case t_FRAC: case t_PADIC: avma=av; return gcopy(x); case t_POLMOD: x = gel(x,2); /* fall through */ case t_POL: p1 = gsubst(x,varn(pol),aut); if (typ(p1)!=t_POLMOD || !gequal(gel(p1,1),pol)) p1 = gmodulo(p1,pol); return gerepileupto(av,p1); case t_VEC: if (lg(x)==3) { y=cgetg(3,t_VEC); gel(y,1) = galoisapply(nf,aut,gel(x,1)); gel(y,2) = gcopy(gel(x,2)); return gerepileupto(av, y); } if (lg(x)!=6) pari_err(typeer,"galoisapply"); y=cgetg(6,t_VEC); y[1]=x[1]; y[3]=x[3]; y[4]=x[4]; p = gel(x,1); p1=centermod(galoisapply(nf,aut,gel(x,2)), p); if (is_pm1(x[3])) if (Z_pval(subres(coltoliftalg(nf,p1),pol), p) > itos(gel(x,4))) gel(p1,1) = (signe(p1[1]) > 0)? subii(gel(p1,1), p) : addii(gel(p1,1), p); gel(y,2) = p1; gel(y,5) = centermod(galoisapply(nf,aut,gel(x,5)), p); return gerepilecopy(av,y); case t_COL: N = degpol(pol); if (lg(x)!=N+1) pari_err(typeer,"galoisapply"); p1 = gsubst(coltoliftalg(nf,x), varn(pol), aut); return gerepileupto(av, algtobasis(nf,p1)); case t_MAT: lx=lg(x); if (lx==1) return cgetg(1,t_MAT); N=degpol(pol); if (lg(x[1])!=N+1) pari_err(typeer,"galoisapply"); p1=cgetg(lx,t_MAT); for (j=1; j> 1; for (i=1; i<=r1; i++) gel(roo,i) = real_i(gel(roo,i)); for ( ; i<=ru; i++) roo[i] = roo[(i<<1)-r1]; roo[0]=evaltyp(t_VEC)|evallg(ru+1); return roo; } /* For internal use. compute trace(x mod pol), sym=polsym(pol,deg(pol)-1) */ GEN quicktrace(GEN x, GEN sym) { GEN p1 = gen_0; long i; if (typ(x) != t_POL) return gmul(x, gel(sym,1)); if (signe(x)) { sym--; for (i=lg(x)-1; i>1; i--) p1 = gadd(p1, gmul(gel(x,i),gel(sym,i))); } return p1; } /* T = trace(w[i]), x = sum x[i] w[i], x[i] integer */ static GEN trace_col(GEN x, GEN T) { pari_sp av = avma; GEN t = gen_0; long i, l = lg(x); t = mulii(gel(x,1),gel(T,1)); for (i=2; i ax+b)) set lead = NULL if pol was monic (after dividing * by the content), and to to leading coefficient otherwise. * No garbage collecting done. */ GEN pol_to_monic(GEN pol, GEN *lead) { long n = lg(pol)-1; if (n==1 || gcmp1(gel(pol,n))) { *lead = NULL; return pol; } return primitive_pol_to_monic(primpart(pol), lead); } /* assume lg(nf) > 3 && typ(nf) = container [hopefully a genuine nf] */ long nf_get_r1(GEN nf) { GEN x = gel(nf,2); if (typ(x) != t_VEC || lg(x) != 3 || typ(x[1]) != t_INT) pari_err(talker,"false nf in nf_get_r1"); return itos(gel(x,1)); } long nf_get_r2(GEN nf) { GEN x = gel(nf,2); if (typ(x) != t_VEC || lg(x) != 3 || typ(x[2]) != t_INT) pari_err(talker,"false nf in nf_get_r2"); return itos(gel(x,2)); } void nf_get_sign(GEN nf, long *r1, long *r2) { GEN x = gel(nf,2); if (typ(x) != t_VEC || lg(x) != 3 || typ(x[1]) != t_INT || typ(x[2]) != t_INT) pari_err(talker,"false nf in nf_get_sign"); *r1 = itos(gel(x,1)); *r2 = (degpol(nf[1]) - *r1) >> 1; } static GEN get_Tr(GEN mul, GEN x, GEN basden) { GEN tr,T,T1,sym, bas = gel(basden,1), den = gel(basden,2); long i,j,n = lg(bas)-1; T = cgetg(n+1,t_MAT); T1 = cgetg(n+1,t_COL); sym = polsym(x, n-1); gel(T1,1) = utoipos(n); for (i=2; i<=n; i++) { tr = quicktrace(gel(bas,i), sym); if (den && den[i]) tr = diviiexact(tr,gel(den,i)); gel(T1,i) = tr; /* tr(w[i]) */ } gel(T,1) = T1; for (i=2; i<=n; i++) { gel(T,i) = cgetg(n+1,t_COL); gcoeff(T,1,i) = gel(T1,i); for (j=2; j<=i; j++) gcoeff(T,i,j) = gcoeff(T,j,i) = trace_col(gel(mul,j+(i-1)*n), T1); } return T; } /* return [bas[i]*denom(bas[i]), denom(bas[i])], denom 1 is given as NULL */ GEN get_bas_den(GEN bas) { GEN b,d,den, dbas = shallowcopy(bas); long i, l = lg(bas); int power = 1; den = cgetg(l,t_VEC); for (i=1; i= prec [also holds for G] */ static void get_roots_for_M(nffp_t *F) { long n, eBD, PREC; if (F->extraprec < 0) { /* not initialized yet */ double er; n = degpol(F->x); eBD = 1 + gexpo(gel(F->basden,1)); er = F->ro? (1+gexpo(F->ro)): cauchy_bound(F->x)/LOG2; if (er < 0) er = 0; F->extraprec = (long)((n*er + eBD + log2(n)) / BITS_IN_LONG); } PREC = F->prec + F->extraprec; if (F->ro && gprecision(gel(F->ro,1)) >= PREC) return; F->ro = get_roots(F->x, F->r1, PREC); } /* [bas[i]/den[i]]= integer basis. roo = real part of the roots */ static void make_M(nffp_t *F, int trunc) { GEN bas = gel(F->basden,1), den = gel(F->basden,2), ro = F->ro; GEN m, d, M; long i, j, l = lg(ro), n = lg(bas); M = cgetg(n,t_MAT); m = cgetg(l, t_COL); gel(M,1) = m; for (i=1; iprec + F->extraprec); for (j=2; j F->prec) { M = gprec_w(M, F->prec); F->ro = gprec_w(ro,F->prec); } if (DEBUGLEVEL>4) msgtimer("matrix M"); F->M = M; } /* return G real such that G~ * G = T_2 */ static void make_G(nffp_t *F) { GEN G, M = F->M; long i, j, k, r1 = F->r1, l = lg(M); G = cgetg(l, t_MAT); for (j=1; jG = G; } static void make_M_G(nffp_t *F, int trunc) { get_roots_for_M(F); make_M(F, trunc); make_G(F); } void remake_GM(GEN nf, nffp_t *F, long prec) { F->x = gel(nf,1); F->ro = NULL; F->r1 = nf_get_r1(nf); F->basden = get_bas_den(gel(nf,7)); F->extraprec = -1; F->prec = prec; make_M_G(F, 1); } static void nffp_init(nffp_t *F, nfbasic_t *T, GEN ro, long prec) { F->x = T->x; F->ro = ro; F->r1 = T->r1; if (!T->basden) T->basden = get_bas_den(T->bas); F->basden = T->basden; F->extraprec = -1; F->prec = prec; } static void get_nf_fp_compo(nfbasic_t *T, nffp_t *F, GEN ro, long prec) { nffp_init(F,T,ro,prec); make_M_G(F, 1); } static GEN get_sign(long r1, long n) { return mkvec2s(r1, (n-r1)>>1); } GEN nfbasic_to_nf(nfbasic_t *T, GEN ro, long prec) { GEN nf = cgetg(10,t_VEC); GEN x = T->x; GEN absdK, invbas, Tr, D, TI, A, dA, MDI, mat = cgetg(8,t_VEC); nffp_t F; get_nf_fp_compo(T, &F, ro, prec); gel(nf,1) = T->x; gel(nf,2) = get_sign(T->r1, degpol(T->x)); gel(nf,3) = T->dK; gel(nf,4) = T->index; gel(nf,6) = F.ro; gel(nf,5) = mat; gel(nf,7) = T->bas; gel(mat,1) = F.M; gel(mat,2) = F.G; invbas = QM_inv(RgXV_to_RgM(T->bas, lg(T->bas)-1), gen_1); gel(nf,8) = invbas; gel(nf,9) = get_mul_table(x, F.basden, invbas); if (DEBUGLEVEL) msgtimer("mult. table"); Tr = get_Tr(gel(nf,9), x, F.basden); absdK = T->dK; if (signe(absdK) < 0) absdK = negi(absdK); TI = ZM_inv(Tr, absdK); /* dK T^-1 */ A = Q_primitive_part(TI, &dA); gel(mat,6) = A; /* primitive part of codifferent, dA its denominator */ dA = dA? diviiexact(absdK, dA): absdK; A = hnfmodid(A, dA); MDI = ideal_two_elt(nf, A); gel(MDI,2) = eltmul_get_table(nf, gel(MDI,2)); gel(mat,7) = MDI; if (is_pm1(T->index)) D = idealhermite_aux(nf, derivpol(x)); else D = gmul(dA, idealinv(nf, A)); gel(mat,3) = gen_0; /* FIXME: was gram matrix of current mat[2]. Useless */ gel(mat,4) = Tr; gel(mat,5) = D; if (DEBUGLEVEL) msgtimer("matrices"); return nf; } static GEN hnffromLLL(GEN nf) { GEN d, x; x = RgXV_to_RgM(gel(nf,7), degpol(nf[1])); x = Q_remove_denom(x, &d); if (!d) return x; /* power basis */ return gauss(hnfmodid(x, d), x); } static GEN nfbasechange(GEN u, GEN x) { long i,lx; GEN y; switch(typ(x)) { case t_COL: /* nfelt */ return gmul(u, x); case t_MAT: /* ideal */ y = shallowcopy(x); lx = lg(x); for (i=1; ix), MARKED = 1; nffp_t F; extraprec = (long) (0.25 * n / (sizeof(long) / 4)); prec = DEFAULTPREC + extraprec; nffp_init(&F, T, *pro, prec); av = avma; for (i=1; ; i++) { F.prec = prec; make_M_G(&F, 0); G = F.G; if (u0) G = gmul(G, u0); if (DEBUGLEVEL) fprintferr("get_red_G: starting LLL, prec = %ld (%ld + %ld)\n", prec + F.extraprec, prec, F.extraprec); if ((u = lllfp_marked(&MARKED, G, 100, 2, prec, 0))) { if (typ(u) == t_MAT) break; u = gel(u,1); if (u0) u0 = gerepileupto(av, gmul(u0,u)); else u0 = gerepilecopy(av, u); } prec = (prec<<1)-2 + (gexpo(u0) >> TWOPOTBITS_IN_LONG); F.ro = NULL; if (DEBUGLEVEL) pari_warn(warnprec,"get_red_G", prec); } *pro = F.ro; if (u0) u = gmul(u0,u); if (MARKED != 1) lswap(u[1], u[MARKED]); return u; } /* Return the base change matrix giving an LLL-reduced basis for the * integer basis of nf(T). * *ro = roots of x, computed to precision prec [or NULL] */ static GEN get_LLL_basis(nfbasic_t *T, GEN *pro) { GEN u; if (T->r1 != degpol(T->x)) u = get_red_G(T, pro); else { long MARKED = 1; u = lllfp_marked(&MARKED, make_Tr(T->x, T->bas), 100, 0, DEFAULTPREC, 1); if (!u) u = matid(1); else if (MARKED != 1) lswap(u[1], u[MARKED]); } return u; } static void set_LLL_basis(nfbasic_t *T, GEN *pro) { T->bas = gmul(T->bas, get_LLL_basis(T, pro)); T->basden = NULL; /* recompute */ if (DEBUGLEVEL) msgtimer("LLL basis"); } typedef struct { GEN xbest, dxbest; long ind, indmax, indbest; } ok_pol_t; /* is xn better than x ? */ static int better_pol(GEN xn, GEN dxn, GEN x, GEN dx) { int fl; if (!x) return 1; fl = absi_cmp(dxn, dx); return (fl < 0 || (!fl && gpolcomp(xn, x) < 0)); } static GEN ok_pol(void *TT, GEN xn) { ok_pol_t *T = (ok_pol_t*)TT; GEN dxn; if (++T->ind > T->indmax && T->xbest) return T->xbest; if (!ZX_is_squarefree(xn)) return (T->ind == T->indmax)? T->xbest: NULL; if (DEBUGLEVEL>3) outerr(xn); dxn = ZX_disc(xn); if (better_pol(xn, dxn, T->xbest, T->dxbest)) { T->dxbest = dxn; T->xbest = xn; T->indbest = T->ind; } if (T->ind >= T->indmax) return T->xbest; return NULL; } /* z in Z[X] with positive leading coefficient. Set z := z(-X) or z(X) so that * second coefficient is > 0. In place. */ static int canon_pol(GEN z) { long i,s; for (i=lg(z)-2; i>=2; i-=2) { s = signe(z[i]); if (s > 0) { for (; i>=2; i-=2) gel(z,i) = negi(gel(z,i)); return -1; } if (s) return 1; } return 0; } static GEN _polred(GEN x, GEN a, GEN *pta, FP_chk_fun *CHECK); /* Seek a simpler, polynomial pol defining the same number field as * x (assumed to be monic at this point) */ static GEN nfpolred(int part, nfbasic_t *T) { GEN x = T->x, dx = T->dx, a = T->bas; GEN phi, xbest, dxbest, mat, d, rev; long i, n = lg(a)-1, v = varn(x); ok_pol_t O; FP_chk_fun chk = { &ok_pol, NULL, NULL, NULL, 0 }; if (degpol(x) == 1) { T->x = gsub(pol_x[v],gen_1); return gen_1; } if (!dx) dx = mulii(T->dK, sqri(T->index)); O.ind = 0; O.indmax = part? min(n,3): n; O.xbest = NULL; chk.data = (void*)&O; if (!_polred(x, a, NULL, &chk)) pari_err(talker,"you found a counter-example to a conjecture, please report!"); xbest = O.xbest; dxbest = O.dxbest; if (!better_pol(xbest, dxbest, x, dx)) return NULL; /* no improvement */ /* update T */ phi = gel(a, O.indbest); if (canon_pol(xbest) < 0) phi = gneg_i(phi); if (DEBUGLEVEL>1) fprintferr("xbest = %Z\n",xbest); rev = modreverse_i(phi, x); for (i=1; i<=n; i++) gel(a,i) = RgX_RgXQ_compo(gel(a,i), rev, xbest); mat = RgXV_to_RgM(Q_remove_denom(a, &d), n); if (d) mat = gdiv(hnfmodid(mat,d), d); else mat = matid(n); (void)Z_issquarerem(diviiexact(dxbest,T->dK), &(T->index)); T->bas= RgM_to_RgXV(mat, v); T->dx = dxbest; T->x = xbest; return rev; } GEN get_nfindex(GEN bas) { pari_sp av = avma; long n = lg(bas)-1; GEN d, mat = RgXV_to_RgM(Q_remove_denom(bas, &d), n); if (!d) { avma = av; return gen_1; } return gerepileuptoint(av, diviiexact(powiu(d, n), det(mat))); } void nfbasic_init(GEN x, long flag, GEN fa, nfbasic_t *T) { GEN bas, dK, dx, index; long r1; T->basden = NULL; T->lead = NULL; if (DEBUGLEVEL) (void)timer2(); if (typ(x) == t_POL) { check_ZX(x, "nfinit"); if (gisirreducible(x) == gen_0) pari_err(redpoler, "nfinit"); x = pol_to_monic(x, &(T->lead)); bas = allbase(x, flag, &dx, &dK, &index, &fa); if (DEBUGLEVEL) msgtimer("round4"); r1 = sturm(x); } else if (typ(x) == t_VEC && lg(x)==3 && typ(x[1])==t_POL && lg(x[2])-1 == degpol(x[1])) { /* monic integral polynomial + integer basis */ GEN mat; bas = gel(x,2); x = gel(x,1); if (typ(bas) == t_MAT) { mat = bas; bas = RgM_to_RgXV(mat,varn(x)); } else mat = RgXV_to_RgM(bas, lg(bas)-1); index = get_nfindex(bas); dx = ZX_disc(x); dK = diviiexact(dx, sqri(index)); r1 = sturm(x); } else { /* nf, bnf, bnr */ GEN nf = checknf(x); x = gel(nf,1); dK = gel(nf,3); index = gel(nf,4); bas = gel(nf,7); r1 = nf_get_r1(nf); dx = NULL; } T->x = x; T->r1 = r1; T->dx = dx; T->dK = dK; T->bas = bas; T->index = index; } /* Initialize the number field defined by the polynomial x (in variable v) * flag & nf_RED: try a polred first. * flag & nf_PARTRED: as nf_RED but check the first two elements only. * flag & nf_ORIG * do a polred and return [nfinit(x), Mod(a,red)], where * Mod(a,red) = Mod(v,x) (i.e return the base change). */ GEN initalg_i(GEN x, long flag, long prec) { const pari_sp av = avma; GEN nf, rev = NULL, ro = NULL; nfbasic_t T; nfbasic_init(x, flag, NULL, &T); set_LLL_basis(&T, &ro); if (T.lead && !(flag & (nf_RED|nf_PARTRED))) { pari_warn(warner,"non-monic polynomial. Result of the form [nf,c]"); flag |= nf_PARTRED | nf_ORIG; } if (flag & (nf_RED|nf_PARTRED)) { rev = nfpolred(flag & nf_PARTRED, &T); if (DEBUGLEVEL) msgtimer("polred"); if (rev) { ro = NULL; set_LLL_basis(&T, &ro); } /* changed T.x */ if (flag & nf_ORIG) { if (!rev) rev = pol_x[varn(T.x)]; /* no improvement */ if (T.lead) rev = gdiv(rev, T.lead); rev = mkpolmod(rev, T.x); } } nf = nfbasic_to_nf(&T, ro, prec); if (flag & nf_ORIG) nf = mkvec2(nf, rev); return gerepilecopy(av, nf); } GEN initalgred(GEN x, long prec) { return initalg_i(x, nf_RED, prec); } GEN initalgred2(GEN x, long prec) { return initalg_i(x, nf_RED|nf_ORIG, prec); } GEN initalg(GEN x, long prec) { return initalg_i(x, 0, prec); } GEN nfinit0(GEN x, long flag,long prec) { switch(flag) { case 0: case 1: return initalg_i(x,0,prec); case 2: return initalg_i(x,nf_RED,prec); case 3: return initalg_i(x,nf_RED|nf_ORIG,prec); case 4: return initalg_i(x,nf_PARTRED,prec); case 5: return initalg_i(x,nf_PARTRED|nf_ORIG,prec); default: pari_err(flagerr,"nfinit"); } return NULL; /* not reached */ } /* assume x a bnr/bnf/nf */ long nfgetprec(GEN x) { GEN nf = checknf(x), ro = gel(nf,6); return (typ(ro)==t_VEC)? precision(gel(ro,1)): DEFAULTPREC; } /* assume nf is an nf */ GEN nfnewprec_i(GEN nf, long prec) { GEN NF = shallowcopy(nf); nffp_t F; gel(NF,5) = shallowcopy(gel(NF,5)); remake_GM(NF, &F, prec); gel(NF,6) = F.ro; gmael(NF,5,1) = F.M; gmael(NF,5,2) = F.G; return NF; } static GEN _nfnewprec(GEN nf, long prec) { pari_sp av = avma; return gerepilecopy(av, nfnewprec_i(nf, prec)); } GEN nfnewprec(GEN nf, long prec) { long l = lg(nf); GEN z, res = NULL; if (typ(nf) != t_VEC) pari_err(talker,"incorrect nf in nfnewprec"); if (l == 3) { res = cgetg(3, t_VEC); gel(res,2) = gcopy(gel(nf,2)); nf = gel(nf,1); l = lg(nf); } switch(l) { case 11: z = bnfnewprec(nf,prec); break; case 7: z = bnrnewprec(nf,prec); break; default: z = _nfnewprec(checknf(nf),prec); break; } if (res) gel(res,1) = z; else res = z; return res; } /********************************************************************/ /** **/ /** POLRED **/ /** **/ /********************************************************************/ /* remove duplicate polynomials in y, updating a (same indexes), in place */ static void remove_duplicates(GEN y, GEN a) { long k, i, l = lg(y); pari_sp av = avma; GEN z; if (l < 2) return; z = new_chunk(3); gel(z,1) = y; gel(z,2) = a; (void)sort_factor(z, gcmp); for (k=1, i=2; if(CHECK->data, pol) != 0; return NULL if there are no such pol */ static GEN _polred(GEN x, GEN a, GEN *pta, FP_chk_fun *CHECK) { long i, v = varn(x), l = lg(a); GEN ch, d, y = cgetg(l,t_VEC); for (i=1; i2) { fprintferr("i = %ld\n",i); flusherr(); } ch = ZX_caract(x, gel(a,i), v); if (CHECK) { ch = CHECK->f(CHECK->data, ch); if (!ch) continue; return ch; } d = modulargcd(derivpol(ch), ch); if (degpol(d)) ch = gdivexact(ch,d); if (canon_pol(ch) < 0 && pta) gel(a,i) = gneg_i(gel(a,i)); if (DEBUGLEVEL > 3) outerr(ch); gel(y,i) = ch; } if (CHECK) return NULL; /* no suitable polynomial found */ remove_duplicates(y,a); if (pta) *pta = a; return y; } static GEN allpolred(GEN x, long flag, GEN fa, GEN *pta, FP_chk_fun *CHECK) { GEN ro = NULL; nfbasic_t T; nfbasic_init(x, flag, fa, &T); set_LLL_basis(&T, &ro); if (T.lead) pari_err(impl,"polred for non-monic polynomial"); return _polred(T.x, T.bas, pta, CHECK); } /* FIXME: backward compatibility */ #define red_PARTIAL 1 #define red_ORIG 2 GEN polred0(GEN x, long flag, GEN fa) { pari_sp av = avma; GEN y, a; long fl = 0; if (fa && gcmp0(fa)) fa = NULL; /* compatibility */ if (flag & red_PARTIAL) fl |= nf_PARTIALFACT; if (flag & red_ORIG) fl |= nf_ORIG; y = allpolred(x, fl, fa, &a, NULL); if (fl & nf_ORIG) y = mkmat2(a,y); return gerepilecopy(av, y); } GEN ordred(GEN x) { pari_sp av = avma; GEN y; if (typ(x) != t_POL) pari_err(typeer,"ordred"); if (!gcmp1(leading_term(x))) pari_err(impl,"ordred"); if (!signe(x)) return gcopy(x); y = mkvec2(x, matid(degpol(x))); return gerepileupto(av, polred(y)); } GEN polredfirstpol(GEN x, long flag, FP_chk_fun *CHECK) { return allpolred(x,flag,NULL,NULL,CHECK); } GEN polred(GEN x) { return polred0(x, 0, NULL); } GEN smallpolred(GEN x) { return polred0(x, red_PARTIAL, NULL); } GEN factoredpolred(GEN x, GEN fa) { return polred0(x, 0, fa); } GEN polred2(GEN x) { return polred0(x, red_ORIG, NULL); } GEN smallpolred2(GEN x) { return polred0(x, red_PARTIAL|red_ORIG, NULL); } GEN factoredpolred2(GEN x, GEN fa) { return polred0(x, red_PARTIAL, fa); } /********************************************************************/ /** **/ /** POLREDABS **/ /** **/ /********************************************************************/ GEN T2_from_embed_norm(GEN x, long r1) { GEN p = sum(x, 1, r1); GEN q = sum(x, r1+1, lg(x)-1); if (q != gen_0) p = gadd(p, gmul2n(q,1)); return p; } GEN T2_from_embed(GEN x, long r1) { return T2_from_embed_norm(gnorm(x), r1); } typedef struct { long r1, v, prec; GEN ZKembed; /* embeddings of fincke-pohst-reduced Zk basis */ GEN u; /* matrix giving fincke-pohst-reduced Zk basis */ GEN M; /* embeddings of initial (LLL-reduced) Zk basis */ GEN bound; /* T2 norm of the polynomial defining nf */ } CG_data; /* characteristic pol of x (given by embeddings) */ static GEN get_pol(CG_data *d, GEN x) { long e; GEN g = grndtoi(roots_to_pol_r1r2(x, d->r1, d->v), &e); if (e > -5) pari_err(precer, "get_pol"); return g; } /* characteristic pol of x (given as vector on (w_i)) */ static GEN get_polchar(CG_data *d, GEN x) { return get_pol(d, gmul(d->ZKembed,x)); } /* return a defining polynomial for Q(w_i) */ static GEN get_polmin_w(CG_data *d, long k) { GEN g = get_pol(d, gel(d->ZKembed,k)); GEN h = modulargcd(g, derivpol(g)); if (degpol(h)) g = gdivexact(g,h); return g; } /* does x generate the correct field ? */ static GEN chk_gen(void *data, GEN x) { pari_sp av = avma, av1; GEN h, g = get_polchar((CG_data*)data,x); av1 = avma; h = modulargcd(g, derivpol(g)); if (degpol(h)) { avma = av; return NULL; } if (DEBUGLEVEL>3) fprintferr(" generator: %Z\n",g); avma = av1; return gerepileupto(av, g); } /* set V[k] := matrix of multiplication by nk.zk[k] */ static GEN set_mulid(GEN V, GEN M, GEN Mi, long r1, long r2, long N, long k) { GEN v, Mk = cgetg(N+1, t_MAT); long i, e; for (i = 1; i < k; i++) gel(Mk,i) = gmael(V, i, k); for ( ; i <=N; i++) { v = vecmul(gel(M,k), gel(M,i)); v = gmul(Mi, split_realimag(v, r1, r2)); gel(Mk,i) = grndtoi(v, &e); if (e > -5) return NULL; } gel(V,k) = Mk; return Mk; } static long chk_gen_prec(long N, long bit) { return nbits2prec(10 + (long)log2((double)N) + bit); } /* U = base change matrix, R = Cholesky form of the quadratic form [matrix * Q from algo 2.7.6] */ static GEN chk_gen_init(FP_chk_fun *chk, GEN R, GEN U) { CG_data *d = (CG_data*)chk->data; GEN P, V, S, inv, bound, M; long N = lg(U)-1, r1 = d->r1, r2 = (N-r1)>>1; long i, j, prec, firstprim = 0, skipfirst = 0; pari_sp av; d->u = U; d->ZKembed = gmul(d->M, U); av = avma; bound = d->bound; S = cgetg(N+1, t_VECSMALL); for (i = 1; i <= N; i++) { P = get_polmin_w(d, i); S[i] = degpol(P); if (S[i] == N) { /* primitive element */ GEN B = T2_from_embed(gel(d->ZKembed,i), r1); if (gcmp(B,bound) < 0) bound = B ; if (!firstprim) firstprim = i; /* index of first primitive element */ if (DEBUGLEVEL>2) fprintferr("chk_gen_init: generator %Z\n",P); } else { if (DEBUGLEVEL>2) fprintferr("chk_gen_init: subfield %Z\n",P); if (firstprim) { /* cycle basis vectors so that primitive elements come last */ GEN u = d->u, e = d->ZKembed; GEN te = gel(e,i), tu = gel(u,i), tR = gel(R,i); long tS = S[i]; for (j = i; j > firstprim; j--) { u[j] = u[j-1]; e[j] = e[j-1]; R[j] = R[j-1]; S[j] = S[j-1]; } gel(u,firstprim) = tu; gel(e,firstprim) = te; gel(R,firstprim) = tR; S[firstprim] = tS; firstprim++; } } } if (!firstprim) { /* try (a little) to find primitive elements to improve bound */ GEN x = cgetg(N+1, t_COL), e, B; if (DEBUGLEVEL>1) fprintferr("chk_gen_init: difficult field, trying random elements\n"); for (i = 0; i < 10; i++) { for (j = 1; j <= N; j++) gel(x,j) = stoi( (pari_rand31() % 7) - 3 ); e = gmul(d->ZKembed, x); P = get_pol(d, e); if (!ZX_is_squarefree(P)) continue; if (DEBUGLEVEL>2) fprintferr("chk_gen_init: generator %Z\n",P); B = T2_from_embed(e, r1); if (gcmp(B,bound) < 0) bound = B ; } } if (firstprim > 1) { inv = ginv( split_realimag(d->ZKembed, r1, r2) ); /*TODO: use QR?*/ V = gel(inv,1); for (i = 2; i <= r1+r2; i++) V = gadd(V, gel(inv,i)); /* V corresponds to 1_Z */ V = grndtoi(V, &j); if (j > -5) err(bugparier,"precision too low in chk_gen_init"); M = mkmat(V); /* 1 */ V = cgetg(N+1, t_VEC); for (i = 1; i <= N; i++) { /* M = Q-basis of subfield generated by nf.zk[1..i-1] */ GEN Mx, M2; long j, k, h, rkM, dP = S[i]; if (dP == N) break; /* primitive */ Mx = set_mulid(V, d->ZKembed, inv, r1, r2, N, i); if (!Mx) break; /* prec. problem. Stop */ if (dP == 1) continue; rkM = lg(M)-1; M2 = cgetg(N+1, t_MAT); /* we will add to M the elts of M2 */ gel(M2,1) = col_ei(N, i); /* nf.zk[i] */ k = 2; for (h = 1; h < dP; h++) { long r; /* add to M2 the elts of M * nf.zk[i] */ for (j = 1; j <= rkM; j++) gel(M2,k++) = gmul(Mx, gel(M,j)); setlg(M2, k); k = 1; M = image(shallowconcat(M, M2)); r = lg(M) - 1; if (r == rkM) break; if (r > rkM) { rkM = r; if (rkM == N) break; } } if (rkM == N) break; /* Q(w[1],...,w[i-1]) is a strict subfield of nf */ skipfirst++; } } /* x_1,...,x_skipfirst generate a strict subfield [unless N=skipfirst=1] */ chk->skipfirst = skipfirst; if (DEBUGLEVEL>2) fprintferr("chk_gen_init: skipfirst = %ld\n",skipfirst); /* should be DEF + gexpo( max_k C^n_k (bound/k)^(k/2) ) */ bound = gerepileuptoleaf(av, bound); prec = chk_gen_prec(N, (gexpo(bound)*N)/2); if (DEBUGLEVEL) fprintferr("chk_gen_init: new prec = %ld (initially %ld)\n", prec, d->prec); if (prec > d->prec) pari_err(bugparier, "polredabs (precision problem)"); if (prec < d->prec) d->ZKembed = gprec_w(d->ZKembed, prec); return bound; } /* store phi(beta mod z). */ static GEN storeeval(GEN a, GEN x, GEN z, GEN lead) { GEN beta = modreverse_i(a, x); if (lead) beta = gdiv(beta, lead); return mkvec2(z, mkpolmod(beta,z)); } static void findmindisc(GEN *py, GEN *pa) { GEN v, dmin, z, b, discs, y = *py, a = *pa; long i,k, l = lg(y); if (l == 2) { *py = gel(y,1); *pa = gel(a,1); return; } discs = cgetg(l,t_VEC); for (i=1; ix); GEN v, ro = NULL; FP_chk_fun chk = { &chk_gen, &chk_gen_init, NULL, NULL, 0 }; nffp_t F; CG_data d; chk.data = (void*)&d; set_LLL_basis(T, &ro); /* || polchar ||_oo < 2^e */ e = n * (long)(cauchy_bound(T->x) / LOG2 + log2((double)n)) + 1; prec = chk_gen_prec(n, e); get_nf_fp_compo(T, &F, ro, prec); d.v = varn(T->x); d.r1= T->r1; d.bound = T2_from_embed(F.ro, T->r1); for (;;) { GEN R = R_from_QR(F.G, prec); if (R) { d.prec = prec; d.M = F.M; v = fincke_pohst(mkvec(R),NULL,-1, 0, &chk); if (v) break; } prec = (prec<<1)-2; get_nf_fp_compo(T, &F, NULL, prec); if (DEBUGLEVEL) pari_warn(warnprec,"polredabs0",prec); } *u = d.u; return v; } GEN polredabs0(GEN x, long flag) { pari_sp av = avma; long i, l, vx; GEN y, a, u; nfbasic_t T; nfbasic_init(x, flag & nf_PARTIALFACT, NULL, &T); x = T.x; vx = varn(x); if (degpol(x) == 1) { u = NULL; y = mkvec(pol_x[vx]); a = mkvec(gsub(gel(y,1), gel(x,2))); } else { GEN v = _polredabs(&T, &u); y = gel(v,1); a = gel(v,2); } l = lg(a); for (i=1; i 1) a = gmul(T.bas, gmul(u, a)); y = storepol(x, y, a, T.lead, flag); if (flag & nf_ADDZK) { GEN t, y0 = y, B = RgXV_to_RgM(T.bas, lg(T.bas)-1); t = (flag & nf_ORIG)? lift_intern(gel(y,2)): modreverse_i(a, x); t = gmul(RgX_powers(t, z, degpol(z)-1), B); y = mkvec2(y0, t); } } return gerepilecopy(av, y); } GEN polredabsall(GEN x, long flun) { return polredabs0(x, flun | nf_ALL); } GEN polredabs(GEN x) { return polredabs0(x,0); } GEN polredabs2(GEN x) { return polredabs0(x,nf_ORIG); } static long nf_pm1(GEN y) { long i,l; if (!is_pm1(y[1])) return 0; l = lg(y); for (i=2; i 0) /* y = 1 */ { if (p!=2 || !gcmp1(gcoeff(fa,i,2))) return NULL; x = gneg_i(x); } } return x; } /* only roots of 1 are +/- 1 */ static GEN trivroots(GEN nf) { GEN y = cgetg(3, t_VEC); gel(y,1) = gen_2; gel(y,2) = gscalcol_i(gen_m1, degpol(nf[1])); return y; } GEN rootsof1(GEN nf) { pari_sp av = avma; long N, k, i, ws, prec; GEN z, y, d, list, w; nf = checknf(nf); if ( nf_get_r1(nf) ) return trivroots(nf); N = degpol(nf[1]); prec = nfgetprec(nf); for (;;) { GEN R = R_from_QR(gmael(nf,5,2), prec); if (R) { y = fincke_pohst(mkvec(R), utoipos(N), 1000, 0, NULL); if (y) break; } prec = (prec<<1)-2; if (DEBUGLEVEL) pari_warn(warnprec,"rootsof1",prec); nf = nfnewprec(nf,prec); } if (itos(ground(gel(y,2))) != N) pari_err(bugparier,"rootsof1 (bug1)"); w = gel(y,1); ws = itos(w); if (ws == 2) { avma = av; return trivroots(nf); } d = Z_factor(w); list = gel(y,3); k = lg(list); for (i=1; i 0) break; q = p = (ulong)N[2]; limk = N0/q; for (k=2; k <= N0; k++) c2[k] = c[k]; while (q <= (ulong)N0) { LOCAL_HIREMAINDER; for (k=1; k<=limk; k++) c2[k*q] += c[k]; q = mulll(q, p); if (hiremainder) break; limk /= p; } N = c; c = c2; c2 = N; } avma = av; } free(c2); return c; } GEN dirzetak(GEN nf, GEN b) { GEN z, c; long n; if (typ(b) != t_INT) pari_err(talker,"not an integer type in dirzetak"); if (signe(b) <= 0) return cgetg(1,t_VEC); nf = checknf(nf); n = itos_or_0(b); if (!n) pari_err(talker,"too many terms in dirzetak"); c = dirzetak0(nf, n); z = vecsmall_to_vec(c); free(c); return z; } GEN zeta_get_limx(long r1, long r2, long bit) { pari_sp av = avma; GEN p1, p2, c0, c1, A0; long r = r1 + r2, N = r + r2; /* c1 = N 2^(-2r2 / N) */ c1 = mulrs(powrfrac(real2n(1, DEFAULTPREC), -2*r2, N), N); p1 = gpowgs(Pi2n(1, DEFAULTPREC), r - 1); p2 = gmul2n(mpmul(powuu(N,r), p1), -r2); c0 = sqrtr( mpdiv(p2, gpowgs(c1, r+1)) ); A0 = logr_abs( gmul2n(c0, bit) ); p2 = gdiv(A0, c1); p1 = divrr(mulsr(N*(r+1), logr_abs(p2)), addsr(2*(r+1), gmul2n(A0,2))); return gerepileuptoleaf(av, divrr(addrs(p1, 1), powrshalf(p2, N))); } /* N_0 = floor( C_K / limx ) */ long zeta_get_N0(GEN C, GEN limx) { long e; pari_sp av = avma; GEN z = gcvtoi(gdiv(C, limx), &e); /* avoid truncation error */ if (e >= 0 || is_bigint(z)) pari_err(talker, "need %Z coefficients in initzeta: computation impossible", z); if (DEBUGLEVEL>1) fprintferr("\ninitzeta: N0 = %Z\n", z); avma = av; return itos(z); } static long get_i0(long r1, long r2, GEN B, GEN limx) { long imin = 1, imax = 1400; while(imax - imin >= 4) { long i = (imax + imin) >> 1; GEN t = gpowgs(limx, i); t = gmul(t, gpowgs(mpfactr(i/2, DEFAULTPREC), r1)); t = gmul(t, gpowgs(mpfactr(i , DEFAULTPREC), r2)); if (gcmp(t, B) >= 0) imax = i; else imin = i; } return imax & ~1; /* make it even */ } /* assume limx = zeta_get_limx(r1, r2, bit) */ long zeta_get_i0(long r1, long r2, long bit, GEN limx) { pari_sp av = avma; GEN B = gmul(sqrtr( gdiv(gpowgs(mppi(DEFAULTPREC), r2-3), limx) ), gmul2n(powuu(5, r1), bit + r2)); long i0 = get_i0(r1, r2, B, limx); if (DEBUGLEVEL>1) { fprintferr("i0 = %ld\n",i0); flusherr(); } avma = av; return i0; } GEN initzeta(GEN pol, long prec) { GEN nfz, nf, gr1, gr2, gru, p1, p2, cst, coef, bnf = checkbnf_i(pol); GEN limx, resi,zet,C,coeflog,racpi,aij,tabj,colzero, *tabcstn, *tabcstni; GEN c_even, ck_even, c_odd, ck_odd, serie_even, serie_odd, serie_exp, Pi; long N0, i0, r1, r2, r, R, N, i, j, k, n, bit = bit_accuracy(prec) + 6; pari_sp av, av2; long court[] = {evaltyp(t_INT)|_evallg(3), evalsigne(1)|evallgefint(3),0}; stackzone *zone, *zone0, *zone1; /*************** residue & constants ***************/ nfz = cgetg(10,t_VEC); if (!bnf || nfgetprec(bnf) < prec ) bnf = bnfinit0(pol, 2, NULL, prec); prec = (prec<<1) - 2; Pi = mppi(prec); racpi = sqrtr(Pi); /* class number & regulator */ nf = gel(bnf,7); N = degpol(nf[1]); nf_get_sign(nf, &r1, &r2); gr1 = gmael(nf,2,1); gr2 = gmael(nf,2,2); r = r1 + r2; R = r+2; av = avma; p1 = gel(bnf,8); p2 = gmul(gmul2n(gmael(p1,1,1),r1), gel(p1,2)); resi = gerepileupto(av, gdiv(p2, gmael(p1,4,1))); av = avma; p1 = sqrtr_abs(itor(gel(nf,3), prec)); p2 = gmul2n(gpowgs(racpi,N), r2); cst = gerepileuptoleaf(av, divrr(p1,p2)); /* N0, i0 */ limx = zeta_get_limx(r1, r2, bit); N0 = zeta_get_N0(cst, limx); i0 = zeta_get_i0(r1, r2, bit + 4, limx); /* Array of i/cst (i=1..N0) */ av = avma; i = prec*N0; zone = switch_stack(NULL,i + 2*(N0+1) + 6*prec); zone1 = switch_stack(NULL,2*i); zone0 = switch_stack(NULL,2*i); (void)switch_stack(zone,1); tabcstn = (GEN*) cgetg(N0+1,t_VEC); tabcstni = (GEN*) cgetg(N0+1,t_VEC); p1 = ginv(cst); for (i=1; i<=N0; i++) tabcstni[i] = tabcstn[i] = mulsr(i,p1); (void)switch_stack(zone,0); /********** compute a(i,j) **********/ zet = cgetg(R,t_VEC); gel(zet,1) = mpeuler(prec); for (i=2; i1) msgtimer("a(i,j)"); p1=cgetg(5,t_VEC); gel(p1,1) = stoi(r1); gel(p1,2) = stoi(r2); gel(p1,3) = stoi(i0); gel(p1,4) = bnf; gel(nfz,1) = p1; gel(nfz,2) = resi; gel(nfz,5) = cst; gel(nfz,6) = glog(cst,prec); gel(nfz,7) = aij; /************* Calcul du nombre d'ideaux de norme donnee *************/ coef = dirzetak0(nf,N0); tabj = cgetg(N0+1,t_MAT); if (DEBUGLEVEL>1) msgtimer("coef"); colzero = zerocol(r+1); for (i=1; i<=N0; i++) if (coef[i]) { GEN t = cgetg(r+2,t_COL); p1 = logr_abs(gel(tabcstn,i)); setsigne(p1, -signe(p1)); gel(t,1) = utoi(coef[i]); gel(t,2) = mulur(coef[i], p1); for (j=2; j<=r; j++) { pari_sp av2 = avma; gel(t,j+1) = gerepileuptoleaf(av2, divrs(mulrr(gel(t,j), p1), j)); } gel(tabj,i) = t; /* tabj[n,j] = coef(n)*ln(c/n)^(j-1)/(j-1)! */ } else gel(tabj,i) = colzero; if (DEBUGLEVEL>1) msgtimer("a(n)"); coeflog=cgetg(N0+1,t_VEC); gel(coeflog,1) = gen_0; for (i=2; i<=N0; i++) if (coef[i]) { court[2] = i; p1 = glog(court,prec); setsigne(p1, -1); gel(coeflog,i) = p1; } else gel(coeflog,i) = gen_0; if (DEBUGLEVEL>1) msgtimer("log(n)"); gel(nfz,3) = tabj; gel(nfz,8) = vecsmall_copy(coef); gel(nfz,9) = coeflog; /******************** Calcul des coefficients Cik ********************/ C = cgetg(r+1,t_MAT); for (k=1; k<=r; k++) gel(C,k) = cgetg(i0+1,t_COL); av2 = avma; for (i=1; i<=i0; i++) { GEN aiji = gel(aij,i); stackzone *z; for (k=1; k<=r; k++) { p1 = NULL; for (n=1; n<=N0; n++) if (coef[n]) { GEN tabjn = gel(tabj,n), p2 = mpmul(gel(aiji,1+k), gel(tabjn,1)); for (j=2; j<=r-k+1; j++) p2 = mpadd(p2, mpmul(gel(aiji,j+k), gel(tabjn,j))); if (i > 1) p2 = mpmul(p2, tabcstni[n]); p1 = p1? mpadd(p1,p2): p2; } gcoeff(C,i,k) = gerepileuptoleaf(av2,p1); av2 = avma; } if (i > 1 && i < i0) { /* use a parallel stack */ z = i&1? zone1: zone0; (void)switch_stack(z, 1); for (n=1; n<=N0; n++) if (coef[n]) tabcstni[n] = mpmul(tabcstni[n],tabcstn[n]); /* come back */ (void)switch_stack(z, 0); } } gel(nfz,4) = C; if (DEBUGLEVEL>1) msgtimer("Cik"); free((void*)zone); free((void*)zone1); free((void*)zone0); free((void*)coef); return nfz; } GEN gzetakall(GEN nfz, GEN s, long flag, long prec2) { GEN resi,C,cst,cstlog,coeflog,cs,coef; GEN lambd,gammas,gammaunmoins,gammas2,gammaunmoins2,var1,var2; GEN smoinun,unmoins,gexpro,gar,val,valm,valk,valkm; long ts = typ(s), r1,r2,ru,i0,i,j,k,N0,sl,prec,bigprec; pari_sp av = avma; if (typ(nfz)!=t_VEC || lg(nfz)!=10 || typ(nfz[1]) != t_VEC) pari_err(talker,"not a zeta number field in zetakall"); if (! is_intreal_t(ts) && ts != t_COMPLEX && ts != t_FRAC) pari_err(typeer,"gzetakall"); resi=gel(nfz,2); C=gel(nfz,4); cst=gel(nfz,5); cstlog=gel(nfz,6); coef=gel(nfz,8); coeflog=gel(nfz,9); r1 = itos(gmael(nfz,1,1)); r2 = itos(gmael(nfz,1,2)); ru = r1+r2; i0 = itos(gmael(nfz,1,3)); N0 = lg(coef)-1; bigprec = precision(cst); prec = prec2+1; if (ts==t_COMPLEX && gcmp0(imag_i(s))) { s=real_i(s); ts = typ(s); } if (ts==t_REAL && !signe(gfrac(s))) { s=mptrunc(s); ts = t_INT; } if (ts==t_INT) { sl = itos(s); if (sl==1) pari_err(talker,"s = 1 is a pole (gzetakall)"); if (sl==0) { avma = av; if (flag) pari_err(talker,"s = 0 is a pole (gzetakall)"); if (ru == 1) return gneg(r1? ghalf: resi); return gen_0; } if (sl<0 && (r2 || !odd(sl))) { if (!flag) return gen_0; s = subsi(1,s); sl = 1-sl; } unmoins=subsi(1,s); lambd = gdiv(resi, mulis(s,sl-1)); gammas2=ggamma(gmul2n(s,-1),prec); gar=gpowgs(gammas2,r1); cs=gexp(gmul(cstlog,s),prec); val=s; valm=unmoins; if (sl < 0) /* r2 = 0 && odd(sl) */ { gammaunmoins2 = ggamma(gmul2n(unmoins,-1),prec); var1 = var2 = gen_1; for (i=2; i<=N0; i++) if (coef[i]) { gexpro=gexp(gmul(gel(coeflog,i),s),bigprec); var1 = gadd(var1,gmulsg(coef[i],gexpro)); var2 = gadd(var2,gdivsg(coef[i],gmulsg(i,gexpro))); } lambd=gadd(lambd,gmul(gmul(var1,cs),gar)); lambd=gadd(lambd,gmul(gmul(var2,gdiv(cst,cs)), gpowgs(gammaunmoins2,r1))); var1 = gen_0; for (i=1; i<=i0; i+=2) { valk = val; valkm = valm; for (k=1; k<=ru; k++) { GEN c = gcoeff(C,i,k); var1 = gsub(var1,gdiv(c,valk )); valk = mulii(val,valk); var1 = gsub(var1,gdiv(c,valkm)); valkm = mulii(valm,valkm); } val = addis(val, 2); valm = addis(valm,2); } } else { GEN tabj=gel(nfz,3), aij=gel(nfz,7); gar = gmul(gar,gpowgs(ggamma(s,prec),r2)); var1=var2=gen_0; for (i=1; i<=N0; i++) if (coef[i]) { gexpro=gexp(gmul(gel(coeflog,i),s),bigprec); var1 = gadd(var1,gmulsg(coef[i],gexpro)); if (sl <= i0) { GEN t=gen_0; for (j=1; j<=ru+1; j++) t = gadd(t, gmul(gmael(aij,sl,j), gmael(tabj,i,j))); var2=gadd(var2,gdiv(t,gmulsg(i,gexpro))); } } lambd=gadd(lambd,gmul(gmul(var1,cs),gar)); lambd=gadd(lambd,gmul(var2,gdiv(cst,cs))); var1 = gen_0; for (i=1; i<=i0; i++) { valk = val; valkm = valm; if (i == sl) for (k=1; k<=ru; k++) { GEN c = gcoeff(C,i,k); var1 = gsub(var1,gdiv(c,valk)); valk = mulii(val,valk); } else for (k=1; k<=ru; k++) { GEN c = gcoeff(C,i,k); var1 = gsub(var1,gdiv(c,valk )); valk = mulii(val,valk); var1 = gsub(var1,gdiv(c,valkm)); valkm = mulii(valm,valkm); } val = addis(val,1); valm = addis(valm,1); } } } else { GEN Pi = mppi(bigprec); if (ts == t_FRAC) s = gmul(s, real_1(bigprec)); else s = gprec_w(s, bigprec); smoinun = gsubgs(s,1); unmoins = gneg(smoinun); lambd = gdiv(resi,gmul(s,smoinun)); gammas = ggamma(s,prec); gammas2= ggamma(gmul2n(s,-1),prec); gar = gmul(gpowgs(gammas,r2),gpowgs(gammas2,r1)); cs = gexp(gmul(cstlog,s),prec); var1 = gmul(Pi,s); gammaunmoins = gdiv(Pi, gmul(gsin(var1,prec),gammas)); gammaunmoins2= gdiv(gmul(gmul(sqrtr(Pi),gpow(gen_2,smoinun,prec)), gammas2), gmul(gcos(gmul2n(var1,-1),prec),gammas)); var1 = var2 = gen_1; for (i=2; i<=N0; i++) if (coef[i]) { gexpro = gexp(gmul(gel(coeflog,i),s),bigprec); var1 = gadd(var1,gmulsg(coef[i], gexpro)); var2 = gadd(var2,gdivsg(coef[i], gmulsg(i,gexpro))); } lambd = gadd(lambd,gmul(gmul(var1,cs),gar)); lambd = gadd(lambd,gmul(gmul(gmul(var2,gdiv(cst,cs)), gpowgs(gammaunmoins,r2)), gpowgs(gammaunmoins2,r1))); val = s; valm = unmoins; var1 = gen_0; for (i=1; i<=i0; i++) { valk = val; valkm = valm; for (k=1; k<=ru; k++) { GEN c = gcoeff(C,i,k); var1 = gsub(var1,gdiv(c,valk )); valk = gmul(val, valk); var1 = gsub(var1,gdiv(c,valkm)); valkm = gmul(valm,valkm); } if (r2) { val = gaddgs(val, 1); valm = gaddgs(valm,1); } else { val = gaddgs(val, 2); valm = gaddgs(valm,2); i++; } } } lambd = gadd(lambd, var1); if (!flag) lambd = gdiv(lambd,gmul(gar,cs)); /* zetak */ if (gprecision(lambd) > prec2) lambd = gprec_w(lambd, prec2); return gerepileupto(av, lambd); } GEN gzetak(GEN nfz, GEN s, long prec) { return gzetakall(nfz,s,0,prec); } GEN glambdak(GEN nfz, GEN s, long prec) { return gzetakall(nfz,s,1,prec); }