/* $Id: base2.c,v 1.383.2.1 2007/03/27 15:07:03 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. */ /*******************************************************************/ /* */ /* MAXIMAL ORDERS */ /* */ /*******************************************************************/ #include "pari.h" #include "paripriv.h" /* FIXME: backward compatibility. Should use the proper nf_* equivalents */ #define compat_PARTIAL 1 #define compat_ROUND2 2 static void allbase_check_args(GEN f, long flag, GEN *dx, GEN *ptw) { GEN w = *ptw; if (DEBUGLEVEL) (void)timer2(); if (typ(f)!=t_POL) pari_err(notpoler,"allbase"); if (degpol(f) <= 0) pari_err(constpoler,"allbase"); *dx = w? factorback(w, NULL): ZX_disc(f); if (!signe(*dx)) pari_err(talker,"reducible polynomial in allbase"); if (!w) *ptw = auxdecomp(absi(*dx), (flag & nf_PARTIALFACT)? 0: 1); if (DEBUGLEVEL) msgtimer("disc. factorisation"); } /*******************************************************************/ /* */ /* ROUND 2 */ /* */ /*******************************************************************/ /* companion matrix of unitary polynomial x */ static GEN companion(GEN x) /* cf assmat */ { long i,j,l; GEN y; l=degpol(x)+1; y=cgetg(l,t_MAT); for (j=1; j= k0; k--) { pari_sp av = avma; p1 = subii(gel(v,k), mulii(q,gel(w,k))); p1 = centermodii(p1, m, mo2); gel(v,k) = gerepileuptoint(av, p1); } return v; } /* entries of v and w are C small integers */ static GEN mtran_long(GEN v, GEN w, long q, long m, long k0) { long k, p1; if (q) { for (k=lg(v)-1; k>= k0; k--) { p1 = v[k] - q * w[k]; v[k] = p1 % m; } } return v; } /* coeffs of a are C-long integers */ static void rowred_long(GEN a, long rmod) { long q,j,k,pro, c = lg(a), r = lg(a[1]); for (j=1; j1) pari_warn(warnmem,"rowred j=%ld", j); p1 = gerepilecopy(av,a); for (j1=1; j1 0) { hard_case_exponent = NULL; sp = 0; /* gcc -Wall */ } else { long k; k = sp = itos(p); i=1; while (k < n) { k *= sp; i++; } hard_case_exponent = utoipos(i); } T=cgetg(n+1,t_MAT); for (i=1; i<=n; i++) gel(T,i) = cgetg(n+1,t_COL); T2=cgetg(2*n+1,t_MAT); for (i=1; i<=2*n; i++) gel(T2,i) = cgetg(n+1,t_COL); Tn=cgetg(n*n+1,t_MAT); for (i=1; i<=n*n; i++) gel(Tn,i) = cgetg(n+1,t_COL); v = new_chunk(n+1); w = (GEN*)new_chunk(n+1); av2 = avma; limit = stack_lim(av2,1); delta=gen_1; m=matid(n); for(;;) { long j, k, h; pari_sp av0 = avma; GEN t,b,jp,hh,index,p1, dd = sqri(delta), ppdd = mulii(dd,pp); GEN ppddo2 = shifti(ppdd,-1); if (DEBUGLEVEL > 3) fprintferr("ROUND2: epsilon = %ld\tavma = %ld\n",epsilon,avma); b=matinv(m,delta); for (i=1; i<=n; i++) { for (j=1; j<=n; j++) for (k=1; k<=n; k++) { p1 = j==k? gcoeff(m,i,1): gen_0; for (h=2; h<=n; h++) { GEN p2 = mulii(gcoeff(m,i,h),gcoeff(cf[h],j,k)); if (p2!=gen_0) p1 = addii(p1,p2); } gcoeff(T,j,k) = centermodii(p1, ppdd, ppddo2); } p1 = mulmati(m, mulmati(T,b)); for (j=1; j<=n; j++) for (k=1; k<=n; k++) gcoeff(p1,j,k) = centermodii(diviiexact(gcoeff(p1,j,k),dd),pp,ppo2); w[i] = p1; } if (hard_case_exponent) { for (j=1; j<=n; j++) { for (i=1; i<=n; i++) gcoeff(T,i,j) = gcoeff(w[j],1,i); /* ici la boucle en k calcule la puissance p mod p de w[j] */ for (k=1; k1) pari_warn(warnmem,"ordmax"); gerepileall(av2, 2, &m, &delta); } } gerepileall(av, 2, &m, &delta); *ptdelta = delta; return m; } /* Input: * x normalized integral polynomial of degree n, defining K=Q(theta). * * code 0, 1 or (long)p if we want base, smallbase ou factoredbase (resp.). * y is GEN *, which will receive the discriminant of K. * * Output * 1) A t_COL whose n components are rationnal polynomials (with degree * 0,1...n-1) : integral basis for K (putting x=theta). * Rem: common denominator is in da. * * 2) discriminant of K (in *y). */ static GEN allbase2(GEN f, long flag, GEN *dx, GEN *dK, GEN *ptw) { GEN w,w1,w2,a,pro,at,bt,b,da,db,q, *cf,*gptr[2]; pari_sp av=avma,tetpil; long n,h,j,i,k,r,s,t,mf; w = ptw? *ptw: NULL; allbase_check_args(f,flag,dx, &w); w1 = gel(w,1); w2 = gel(w,2); n = degpol(f); h = lg(w1)-1; cf = (GEN*)cgetg(n+1,t_VEC); cf[2]=companion(f); for (i=3; i<=n; i++) cf[i]=mulmati(cf[2],cf[i-1]); a=matid(n); da=gen_1; for (i=1; i<=h; i++) { pari_sp av1 = avma; mf=itos(gel(w2,i)); if (mf==1) continue; if (DEBUGLEVEL) fprintferr("Treating p^k = %Z^%ld\n",w1[i],mf); b=ordmax(cf,gel(w1,i),mf,&db); a=gmul(db,a); b=gmul(da,b); da=mulii(db,da); at=gtrans(a); bt=gtrans(b); for (r=n; r; r--) for (s=r; s; s--) while (signe(gcoeff(bt,s,r))) { q=diviiround(gcoeff(at,s,s),gcoeff(bt,s,r)); pro=rtran(gel(at,s),gel(bt,r),q); for (t=s-1; t; t--) { q=diviiround(gcoeff(at,t,s),gcoeff(at,t,t)); pro=rtran(pro,gel(at,t),q); } at[s]=bt[r]; gel(bt,r) = pro; } for (j=n; j; j--) { for (k=1; k 0) db = t; } if (db == gen_1) continue; /* db = denom(b), (da,db) = 1. Compute da Im(b) + db Im(a) */ b = Q_muli_to_int(b,db); if (!da) { da = db; a = b; } else { /* optimization: easy as long as both matrix are diagonal */ j=2; while (j<=n && fnz(gel(a,j),j) && fnz(gel(b,j),j)) j++; k = j-1; M = cgetg(2*n-k+1,t_MAT); for (j=1; j<=k; j++) { gel(M,j) = gel(a,j); gcoeff(M,j,j) = mulii(gcoeff(a,j,j),gcoeff(b,j,j)); } /* could reduce mod M(j,j) but not worth it: usually close to da*db */ for ( ; j<=n; j++) gel(M,j) = gmul(db, gel(a,j)); for ( ; j<=2*n-k; j++) gel(M,j) = gmul(da, gel(b,j+k-n)); da = mulii(da,db); a = hnfmodid(M, da); } if (DEBUGLEVEL>5) fprintferr("Result for prime %Z is:\n%Z\n",w1[i],b); } if (da) { *index = diviiexact(da, gcoeff(a,1,1)); for (j=2; j<=n; j++) *index = mulii(*index, diviiexact(da, gcoeff(a,j,j))); a = gdiv(hnfcenter_ip(a), da); } else { *index = gen_1; a = matid(n); } *dK = diviiexact(*dx, sqri(*index)); if (ptw) { long lfa = 1; GEN W1, W2, D = *dK; W1 = cgetg(lw, t_COL); W2 = cgetg(lw, t_COL); for (j=1; j2) { fprintferr(" dedek: gcd has degree %ld\n", dk); if (DEBUGLEVEL>5) fprintferr("initial parameters p=%Z,\n f=%Z\n",p,f); } if (2*dk >= mf-1) return FpX_div(f,k,p); return dk? (GEN)NULL: f; } /* p-maximal order of Af; mf = v_p(Disc(f)) */ static GEN maxord(GEN p,GEN f,long mf) { const pari_sp av = avma; GEN w = NULL, g, res, fp = FpX_red(f, p); if (cmpui(degpol(f),p) < 0) g = FpX_div(fp, FpX_gcd(fp,derivpol(fp), p), p); else { w = (GEN)FpX_factor(fp,p)[1]; g = FpXV_prod(w, p); } res = dedek(f, mf, p, g); if (res) res = dbasis(p, f, mf, pol_x[varn(f)], res); else { if (!w) w = (GEN)FpX_factor(fp,p)[1]; res = maxord_i(p, f, mf, w, 0); } return gerepileupto(av,res); } /* Sylvester's matrix, mod p^m (assumes f1 monic) */ static GEN sylpm(GEN f1, GEN f2, GEN pm) { long j, n = degpol(f1); GEN h, a = cgetg(n+1,t_MAT); h = FpX_rem(f2,f1,pm); for (j=1;; j++) { gel(a,j) = RgX_to_RgV(h, n); if (j == n) break; h = FpX_rem(RgX_shift_shallow(h, 1), f1, pm); } return hnfmodidpart(a, pm); } /* polynomial gcd mod p^m (assumes f1 monic) */ GEN gcdpm(GEN f1, GEN f2, GEN pm) { pari_sp av = avma; long c, n = degpol(f1), v = varn(f1); GEN col, a = sylpm(f1,f2,pm); for (c = 1; c <= n; c++) if (!equalii(gcoeff(a,c,c), pm)) { col = gdiv(gel(a,c), gcoeff(a,c,c)); return gerepilecopy(av, RgV_to_RgX(col,v)); } avma = av; return zeropol(v); } /* reduced resultant mod p^m (assumes x monic) */ GEN respm(GEN x, GEN y, GEN pm) { pari_sp av = avma; GEN z = sylpm(x,y,pm); z = gcoeff(z,1,1); if (equalii(z,pm)) { avma = av; return gen_0; } return gerepileuptoint(av, icopy(z)); } static void update_den(GEN *e, GEN *de, GEN *pp) { GEN ce = Q_content(*e); if (ce != gen_1) { ce = gcdii(*de, ce); *de = diviiexact(*de, ce); *e = gdivexact(*e, ce); if (pp) *pp =diviiexact(*pp, ce); } } /* f o g mod (T,p) */ static GEN compmod(GEN f, GEN g, GEN T, GEN p) { GEN D = NULL, z, df, dg, q; f = Q_remove_denom(f, &df); g = Q_remove_denom(g, &dg); if (df) D = df; if (dg) D = mul_content(D, powiu(dg, degpol(f))); q = D ? mulii(p, D): p; if (dg) f = FpX_rescale(f, dg, q); z = FpX_FpXQ_compo(f, g, T, q); if (!D) return z; update_den(&z, &D, NULL); return gdiv( FpX_center(z, mulii(D,p)), D ); } static GEN dbasis(GEN p, GEN f, long mf, GEN a, GEN U) { long n = degpol(f), dU, i; GEN b, ha, pd, pdp; if (n == 1) return gscalmat(gen_1, 1); if (DEBUGLEVEL>5) { fprintferr(" entering Dedekind Basis with parameters p=%Z\n",p); fprintferr(" f = %Z,\n a = %Z\n",f,a); } ha = pd = powiu(p,mf/2); pdp = mulii(pd,p); dU = U ? degpol(U): 0; b = cgetg(n, t_MAT); /* Z[a] + U/p Z[a] is maximal */ /* skip first column = [pd, 0,...,0] */ for (i=1; i5) fprintferr(" new order: %Z\n",b); return gdiv(b, pd); } static GEN get_partial_order_as_pols(GEN p, GEN f, GEN *d) { GEN b = maxord(p,f, Z_pval(ZX_disc(f),p)); GEN z = Q_remove_denom( RgM_to_RgXV(b, varn(f)), d ); if (!*d) *d = gen_1; return z; } long FpX_val(GEN x0, GEN t, GEN p, GEN *py) { long k; GEN r, y, x = x0; for (k=0; ; k++) { y = FpX_divrem(x, t, p, &r); if (signe(r)) break; x = y; } *py = x; return k; } #if 0 /* e in Qp, f i Zp. Return r = e mod (f, pk) */ static GEN QpX_mod(GEN e, GEN f, GEN pk) { GEN mod, d; e = Q_remove_denom(e, &d); mod = d? mulii(pk,d): pk; e = FpX_rem(e, centermod(f, mod), mod); e = FpX_center(e, mod); if (d) e = gdiv(e, d); return e; } #endif typedef struct __decomp { /* constants */ GEN p, f; /* goal: factor f p-adically */ long df; /* p^df = reduced discriminant of f */ /* these are updated along the way */ GEN phi; /* a p-integer, in Q[X] */ GEN phi0; /* a p-integer, in Q[X] from testb2 / testc2, to be composed with * phi when correct precision is known */ GEN chi; /* characteristic polynomial of phi (mod p^*), in Z[X] */ GEN nu; /* irreducible divisor of chi mod p, in Z[X] */ GEN invnu; /* numerator ( 1/ Mod(nu, chi) mod pmr ) */ GEN Dinvnu;/* denominator ( ... ) */ GEN pdr, pmr, pmf; } decomp_t; /* if flag = 0, maximal order, else factorization to precision r = flag */ static GEN Decomp(decomp_t *S, long flag) { GEN fred, res, pr, pk, ph, b1, b2, a, e, de, f1, f2, dt, th; GEN p = S->p; long k, r = flag? flag: 2*S->df + 1; if (DEBUGLEVEL>2) { fprintferr(" entering Decomp"); if (DEBUGLEVEL>5) fprintferr(", parameters: %Z^%ld\n f = %Z",p, r, S->f); fprintferr("\n"); } if (!FpX_val(S->chi, S->nu, p, &b1)) pari_err(talker, "bug in Decomp (not a factor), is p = %Z a prime?", p); b2 = FpX_div(S->chi, b1, p); a = FpX_mul(FpXQ_inv(b2, b1, p), b2, p); /* E = e / de, e in Z[X], de in Z, E = a(phi) mod (f, p) */ th = Q_remove_denom(S->phi, &dt); if (!dt) dt = gen_1; de = powiu(dt, degpol(a)); pr = mulii(p, de); e = FpX_FpXQ_compo(FpX_rescale(a, dt, pr), th, S->f, pr); update_den(&e, &de, NULL); pk = p; k = 1; /* E, (1 - E) tend to orthogonal idempotents in Zp[X]/(f) */ while (k < r + Z_pval(de, p)) { /* E <-- E^2(3-2E) mod p^2k, with E = e/de */ GEN D; pk = sqri(pk); k <<= 1; e = gmul(gsqr(e), gsub(mulsi(3,de), gmul2n(e,1))); de= mulii(de, sqri(de)); D = mulii(pk, de); e = FpX_rem(e, centermod(S->f, D), D); /* e/de defined mod pk */ update_den(&e, &de, NULL); } pr = powiu(p, r); /* required precision of the factors */ ph = mulii(de, pr); fred = centermod(S->f, ph); e = centermod(e, ph); f1 = gcdpm(fred, gsub(de, e), ph); /* p-adic gcd(f, 1-e) */ fred = centermod(fred, pr); f1 = centermod(f1, pr); f2 = FpX_div(fred,f1, pr); f2 = FpX_center(f2, pr); if (DEBUGLEVEL>5) fprintferr(" leaving Decomp: f1 = %Z\nf2 = %Z\ne = %Z\nde= %Z\n", f1,f2,e,de); if (flag) return concat_factor(ZX_monic_factorpadic(f1, p, flag), ZX_monic_factorpadic(f2, p, flag)); else { GEN D = de, d1, d2, ib1, ib2; long n, n1, n2, i; ib1 = get_partial_order_as_pols(p,f1, &d1); n1 = lg(ib1)-1; ib2 = get_partial_order_as_pols(p,f2, &d2); n2 = lg(ib2)-1; n = n1+n2; i = cmpii(d1, d2); if (i < 0) { ib1 = gmul(ib1, diviiexact(d2, d1)); d1 = d2; } else if (i > 0) { ib2 = gmul(ib2, diviiexact(d1, d2)); } D = mulii(d1, D); fred = centermod(S->f, D); res = cgetg(n+1, t_VEC); for (i=1; i<=n1; i++) gel(res,i) = FpX_center(FpX_rem(gmul(gel(ib1,i),e), fred, D), D); e = gsub(de, e); ib2 -= n1; for ( ; i<=n; i++) gel(res,i) = FpX_center(FpX_rem(gmul(gel(ib2,i),e), fred, D), D); res = RgXV_to_RgM(res, n); return gdiv(hnfmodid(res,D), D); /* normalized integral basis */ } } /* minimum extension valuation: L/E */ static void vstar(GEN p,GEN h, long *L, long *E) { long first, j, k, v, w, m = degpol(h); first = 1; k = 1; v = 0; for (j=1; j<=m; j++) if (! gcmp0(gel(h,m-j+2))) { w = Z_pval(gel(h,m-j+2),p); if (first || w*k < v*j) { v = w; k = j; } first = 0; } w = cgcd(v,k); *L = v/w; *E = k/w; } static GEN redelt_i(GEN a, GEN N, GEN p, GEN *pda) { GEN z; a = Q_remove_denom(a, pda); if (*pda) { long v = Z_pvalrem(*pda, p, &z); if (v) { *pda = powiu(p, v); N = mulii(*pda, N); } else *pda = NULL; if (!is_pm1(z)) a = gmul(a, Fp_inv(z, N)); } return centermod(a, N); } /* reduce the element a modulo N [ a power of p ], taking first care of the * denominators */ static GEN redelt(GEN a, GEN N, GEN p) { GEN da; a = redelt_i(a, N, p, &da); if (da) a = gdiv(a, da); return a; } /* compute the Newton sums of g(x) mod p, assume deg g > 0 */ GEN polsymmodp(GEN g, GEN p) { pari_sp av1, av2; long d = degpol(g), i, k; GEN s , y; y = cgetg(d + 1, t_COL); gel(y,1) = utoipos(d); for (k = 1; k < d; k++) { av1 = avma; s = centermod(mulsi(k, polcoeff0(g,d-k,-1)), p); for (i = 1; i < k; i++) s = addii(s, mulii(gel(y,k-i+1), polcoeff0(g,d-i,-1))); av2 = avma; gel(y,k+1) = gerepile(av1, av2, centermod(negi(s), p)); } return y; } /* no GC */ static GEN manage_cache(GEN chi, GEN pp, GEN ns) { if (lgefint(pp) > lg(ns[1])) { if (DEBUGLEVEL > 4) fprintferr("newtonsums: result doesn't fit in cache\n"); return polsymmodp(chi, pp); } if (!signe(ns[1])) { GEN ns2 = polsymmodp(chi, pp); long j, l = lg(ns); for (j = 1; j < l; j++) affii(gel(ns2,j), gel(ns,j)); } return ns; } /* compute the c first Newton sums modulo pp of the characteristic polynomial of a/d mod chi, d > 0 power of p (NULL = gen_1), a, chi in Zp[X] ns = Newton sums of chi */ static GEN newtonsums(GEN a, GEN da, GEN chi, long c, GEN pp, GEN ns) { GEN va, pa, dpa, s; long j, k, n = degpol(chi); pari_sp av, lim; a = centermod(a, pp); av = avma; lim = stack_lim(av, 1); pa = pol_1[varn(a)]; dpa = gen_1; va = zerovec(c); for (j = 1; j <= c; j++) { /* pa/dpa = (a/d)^(j-1) mod (chi, pp) */ pa = FpX_rem(FpX_mul(pa, a, pp), chi, pp); s = gen_0; for (k = 0; k < n; k++) s = addii(s, mulii(polcoeff0(pa, k, -1), gel(ns,k+1))); if (da) { dpa = mulii(dpa, da); s = gdiv(s, dpa); if (typ(s) != t_INT) return NULL; update_den(&pa, &dpa, &pp); } gel(va,j) = centermod(s, pp); if (low_stack(lim, stack_lim(av, 1))) { if(DEBUGMEM>1) pari_warn(warnmem, "newtonsums"); gerepileall(av, 4, &pa, &va, &pp, &dpa); } } return va; } /* compute the characteristic polynomial of a/da mod chi (a in Z[X]), given * by its Newton sums to a precision of pp using Newton sums */ static GEN newtoncharpoly(GEN pp, GEN p, GEN NS) { long n = lg(NS)-1, j, k; GEN c = cgetg(n + 2, t_VEC); if (!NS) return NULL; gel(c,1) = (n & 1 ? gen_m1: gen_1); for (k = 2; k <= n+1; k++) gel(c,k) = gen_0; for (k = 2; k <= n+1; k++) { pari_sp av2 = avma; GEN s = gen_0; ulong z; long v = u_pvalrem(k - 1, p, &z); for (j = 1; j < k; j++) { GEN t = mulii(gel(NS,j), gel(c,k-j)); if (!odd(j)) t = negi(t); s = addii(s, t); } if (v) { s = gdiv(s, powiu(p, v)); if (typ(s) != t_INT) return NULL; } s = mulii(s, Fp_inv(utoipos(z), pp)); gel(c,k) = gerepileuptoint(av2, centermod(s, pp)); } for (k = odd(n)? 1: 2; k <= n+1; k += 2) gel(c,k) = negi(gel(c,k)); return gtopoly(c, 0); } /* guess if a mod chi has positive valuation by looking at the newton sums */ static long fastvalpos(GEN a, GEN chi, GEN p, GEN ns, long E) { GEN v, d, pp; long m, n = degpol(chi), j, c; c = equaliu(p, 2)? 2*n/3 : min(2*E, n); if (c < 2) c = 2; a = Q_remove_denom(a, &d); m = d? Z_pval(d, p): 0; /* >= 0 */ pp = powiu(p, (m+1)*c+1); ns = manage_cache(chi, pp, ns); v = newtonsums(a, d, chi, c, pp, ns); if (!v) return 0; for (j = 1; j <= c; j++) if (signe(gel(v,j)) && E*Z_pval(gel(v,j), p) - j*(E*m+1) < 0) return 0; return 1; } /* return v_p(n!) */ long val_fact(ulong n, ulong p) { ulong q = p, v = 0; do { v += n/q; q *= p; } while (n >= q); return (long)v; } /* return NULL if a mod f is not an integer * if dr >= 0, a mod f is an integer and the denominator of any integer * in Zp[X]/(f) divides p^dr */ static GEN mycaract(GEN f, GEN a, GEN p, GEN pp, long dr, GEN ns) { pari_sp av = avma; GEN d, chi, npp, NPP, nspp; long n = degpol(f); if (gcmp0(a)) return zeropol(varn(f)); a = Q_remove_denom(a, &d); npp = pp; if (lgefint(p) == 3) npp = mulii(npp, powiu(p, val_fact(n, itou(p)))); nspp = NPP = npp; if (d) { NPP = mulii(NPP, powiu(d, n)); nspp = (dr < 0)? NPP: mulii(nspp, powiu(p, dr)); } ns = newtonsums(a, d, f, n, NPP, manage_cache(f, nspp, ns)); if (!ns) return NULL; chi = newtoncharpoly(npp, p, ns); if (!chi) return NULL; setvarn(chi, varn(f)); return gerepileupto(av, centermod(chi, pp)); } static GEN get_nu(GEN chi, GEN p, long *ptl) { GEN P = (GEN)FpX_factor(chi, p)[1]; *ptl = lg(P) - 1; return gel(P,*ptl); } /* Factor characteristic polynomial of S->phi mod (p, S->chi) */ static long factcp(decomp_t *S, GEN ns) { GEN chi = mycaract(S->chi, S->phi, S->p, S->pmf, -1, ns); long l; S->chi= chi; S->nu = get_nu(chi, S->p, &l); return l; } /* Compute nu_beta in Fp[X]. If something unexpected happens, return NULL */ static GEN fastnu(GEN p, GEN f, GEN beta, GEN pdr) { long j, k, l, n = degpol(f), v = varn(f), N = 2*n+1, av = avma; GEN p1, p2, c, d, B, G, V, nu, h; G = cgetg(N+1, t_MAT); c = gen_0; d = mulii(pdr, sqri(p)); beta = gmul(pdr, beta); B = beta; for (k = 1; k <= n; k++) { V = zerocol(N); gel(G,N-k) = V; gel(V,n+1-k) = gen_1; for (j = n+1; j <= N; j++) { p2 = polcoeff0(B, N-j, -1); if (signe(p2)) c = gcdii(c, p2); gel(V,j) = p2; } if (k < n) { B = gdiv(grem(gmul(B, beta), f), pdr); if (!gcmp1(Q_denom(B))) { avma = av; return NULL; } B = centermod(B, d); } } if (DEBUGLEVEL >= 6) fprintferr(" content in fastnu is %Z\n", c); for (k = 1; k <= n; k++) { p1 = gel(G,N-k); for (j = n+1; j <= N; j++) { p2 = gel(p1,j); if (signe(p2)) { p2 = diviiexact(p2, c); gel(p1,j) = p2; } } } pdr = diviiexact(pdr, c); d = diviiexact(d, c); V = zerocol(N); gel(G,N) = V; gel(V,N) = pdr; gel(V,n+1) = gen_1; p1 = mulii(pdr, p); for (k = 1; k <= n; k++) { V = zerocol(N); gel(G,k) = V; gel(V,n+k+1) = p1; } if (DEBUGLEVEL >= 6) fprintferr(" fastnu: G is computed\n"); G = hnfmodidpart(G, d); if (DEBUGLEVEL >= 6) fprintferr(" fastnu: HNF(G) is computed\n"); setlg(G, n+2); G = rowslice(G, 1, n+1); h = gtopoly(gel(G,n+1), v); for (j = 1; j <= n; j++) h = FpX_gcd(h, gtopoly(gel(G,j), v), p); if (!degpol(h)) { avma = av; return NULL; } nu = get_nu(h, p, &l); if (l > 1) { avma = av; return NULL; } return gerepilecopy(av, nu); } /* return the prime element in Zp[phi], nup, chip in Z[X] * if *Ep < oE or Ep divides Ediv (!=0) return NULL (not interesting) * */ static GEN getprime(decomp_t *S, GEN phi, GEN chip, GEN nup, long *Lp, long *Ep, long oE, long Ediv) { GEN chin, q; long r, s; if (degpol(nup) == 1) { GEN c = gel(nup,2); /* nup = X + c */ chin = signe(c)? translate_pol(chip, negi(c)): chip; } else chin = ZX_caract(chip, nup, varn(chip)); vstar(S->p, chin, Lp, Ep); if (*Ep < oE || (Ediv && Ediv % *Ep == 0)) return NULL; if (*Ep == 1) return S->p; (void)cbezout(*Lp, -*Ep, &r, &s); /* = 1 */ if (r <= 0) { long t = 1 + ((-r) / *Ep); r += t * *Ep; s += t * *Lp; } /* r > 0 minimal such that r L/E - s = 1/E * pi = nu^r / p^s is an element of valuation 1/E, * so is pi + O(p) since 1/E < 1. May compute nu^r mod p^(s+1) */ q = powiu(S->p, s+1); nup = FpXQ_pow(nup, utoipos(r), S->chi, q); return gdiv(compmod(nup, phi, S->chi, q), powiu(S->p, s)); } static void kill_cache(GEN ns) { setsigne(ns[1], 0); } /* S->phi := T o T0 mod (p, f) */ static void composemod(decomp_t *S, GEN T, GEN T0) { S->phi = compmod(T, T0, S->f, S->p); } static int update_phi(decomp_t *S, GEN ns, long *ptl, long flag) { GEN PHI = NULL, pdr, pmr = S->pmr, X = pol_x[ varn(S->f) ]; long k; if (!S->chi) { kill_cache(ns); S->chi = mycaract(S->f, S->phi, S->p, pmr, S->df, ns); S->nu = get_nu(S->chi, S->p, ptl); if (*ptl > 1) return 0; /* we can get a decomposition */ } for (k = 1;; k++) { kill_cache(ns); pdr = respm(S->chi, derivpol(S->chi), pmr); if (signe(pdr)) break; pmr = sqri(pmr); /* try a larger precision */ PHI = S->phi0? compmod(S->phi, S->phi0, S->f, pmr): S->phi; PHI = gadd(PHI, gmul(mulsi(k, S->p), X)); S->chi = mycaract(S->f, PHI, S->p, pmr, S->df, ns); } pmr = mulii(sqri(pdr), S->p); S->chi = FpX_red(S->chi, pmr); if (!PHI) /* ok above for k = 0 */ PHI = S->phi0? compmod(S->phi, S->phi0, S->f, pmr): S->phi; S->phi = PHI; if (is_pm1(pdr)) { /* may happen if p is unramified */ if (!flag) { *ptl = 1; return 0; } S->nu = get_nu(S->chi, S->p, ptl); return 0; } S->pmr = pmr; S->pdr = mulii(pdr, S->p); return 1; } /* return 1 if at least 2 factors mod p ==> chi can be split * Replace S->phi such that F increases (to D) */ static int testb2(decomp_t *S, long D, GEN theta, GEN ns) { long v = varn(S->chi), dlim = degpol(S->chi)-1; GEN T0 = S->phi, chi0 = S->chi; if (DEBUGLEVEL>4) fprintferr(" Increasing Fa\n"); for (;;) { S->phi = gadd(theta, FpX_rand(dlim, v, S->p)); /* phi non-primary ? */ if (factcp(S, ns) > 1) { composemod(S, S->phi, T0); return 1; } if (degpol(S->nu) == D) break; S->chi = chi0; } S->phi0 = T0; return 0; /* F_phi=lcm(F_alpha, F_theta)=D and E_phi=E_alpha */ } /* return 1 if at least 2 factors mod p ==> chi can be split. * compute a new S->phi such that E = lcm(Ea, Et) */ static int testc2(decomp_t *S, GEN A, long Ea, GEN T, long Et, GEN ns) { GEN c, T0 = S->phi; long r, s, t; if (DEBUGLEVEL>4) fprintferr(" Increasing Ea\n"); (void)cbezout(Ea, Et, &r, &s); t = 0; while (r < 0) { r = r + Et; t++; } while (s < 0) { s = s + Ea; t++; } c = RgX_mul(RgXQ_u_pow(A, s, S->chi), RgXQ_u_pow(T, r, S->chi)); c = gdiv(RgX_rem(c, S->chi), powiu(S->p, t)); S->phi = gadd( pol_x[ varn(S->chi) ], redelt(c, S->pmr, S->p) ); if (factcp(S, ns) > 1) { composemod(S, S->phi, T0); return 1; } S->phi0 = T0; return 0; /* E_phi = lcm(E_alpha,E_theta) */ } /* used to cache the newton sums of chi */ static GEN init_NS(long N, GEN pp, GEN pmf, GEN pmr) { GEN q, ns = cgetg(N+1, t_COL); long i, l, p = itos_or_0(pp); q = p? powiu(pp, (ulong)ceil( N * 1. / (p * (p-1)) )): pp; q = sqri(mulii(q, mulii(pmf, powiu(pmr, N)))); l = lgefint(q); /* should be more than enough ... */ for (i = 1; i <= N; i++) gel(ns,i) = cgeti(l); kill_cache(ns); return ns; } static GEN ch_var(GEN x, long v) { if (typ(x) == t_POL) { x = shallowcopy(x); setvarn(x, v); } return x; } /* x p^-eq nu^-er mod p */ static GEN get_gamma(decomp_t *S, GEN x, long eq, long er) { GEN q, g = x, Dg = powiu(S->p, eq); if (er) { if (!S->invnu) { while (gdvd(S->chi, S->nu)) S->nu = gadd(S->nu, S->p); S->invnu = QXQ_inv(S->nu, S->chi); S->invnu = redelt_i(S->invnu, S->pmr, S->p, &(S->Dinvnu)); } if (S->Dinvnu) Dg = mulii(Dg, powiu(S->Dinvnu, er)); q = mulii(S->p, Dg); g = gmul(g, FpXQ_pow(S->invnu, stoi(er), S->chi, q)); g = FpX_rem(g, S->chi, q); update_den(&g, &Dg, NULL); g = centermod(g, mulii(S->p, Dg)); } if (!is_pm1(Dg)) g = gdiv(g, Dg); return g; } /* return 1 if at least 2 factors mod p ==> chi can be split */ static int loop(decomp_t *S, long nv, long Ea, long Fa, GEN ns) { pari_sp av2 = avma, limit = stack_lim(av2, 1); GEN w, chib, beta, gamm, chig, nug, delt = NULL; long i, l, Fg, fm = 0, go_fm = 2, eq = 0, er = 0; long N = degpol(S->f), v = varn(S->f); beta = FpXQ_pow(S->nu, stoi(Ea), S->chi, S->p); S->invnu = NULL; chib = chig = NULL; /* -Wall */ for (;;) { /* beta tends to a factor of chi */ if (DEBUGLEVEL>4) fprintferr(" beta = %Z\n", beta); if (fm == -1) { if (DEBUGLEVEL>4) fprintferr(" ** switching to normal mode\n"); fm = 0; go_fm = eq + 2; } else if (!fm && eq > go_fm && !er) { if (DEBUGLEVEL>4) fprintferr(" ** switching to fast mode\n"); fm = 1; } if (fm) { er++; if (er % Ea == 0) { er = 0; eq++; } gamm = get_gamma(S, beta, eq, er); /* = beta p^-eq nu^-er (a unit) */ nug = fastnu(S->p, S->chi, gamm, S->pdr); if (!nug) { fm = -1; continue; } } else { GEN R = modii(ZX_resultant(beta, S->chi), S->pmf); long L, E; if (signe(R)) { chib = NULL; L = Z_pval(R, S->p); E = N; } else { /* pmf | norm(beta) ==> useless */ chib = ZX_caract(S->chi, beta, v); vstar(S->p, chib, &L, &E); } eq = (long)(L / E); er = (long)(L*Ea / E - eq*Ea); if (DEBUGLEVEL>4) fprintferr(" (eq,er) = (%ld,%ld)\n", eq,er); if (er || !chib) { /* gamm might not be an integer ==> chig = NULL */ gamm = get_gamma(S, beta, eq, er); /* = beta p^-eq nu^-er (a unit) */ chig = mycaract(S->chi, gamm, S->p, S->pmr, -1, ns); } else { /* gamm = beta/p^eq, special case of the above */ GEN h = powiu(S->p, eq); gamm = gdiv(beta, h); chig = gdiv(RgX_unscale(chib, h), powiu(h, N)); chig = gcmp1(Q_denom(chig))? FpX_red(chig, S->pmf): NULL; } if (!chig) { /* Valuation of beta was wrong ==> gamma fails the v*-test */ chib = ZX_caract(S->chi, beta, v); vstar(S->p, chib, &L, &E); eq = (long)(L / E); er = (long)(L*Ea / E - eq*Ea); gamm = get_gamma(S, beta, eq, er); /* an integer */ chig = mycaract(S->chi, gamm, S->p, S->pmf, -1, ns); } nug = get_nu(chig, S->p, &l); if (l > 1) { S->chi = chig; S->nu = nug; composemod(S, gamm, S->phi); return 1; } Fg = degpol(nug); if (Fa % Fg) return testb2(S, clcm(Fa,Fg), gamm, ns); } /* nug irreducible mod p */ w = FpX_factorff_irred(nug, ch_var(S->nu, nv), S->p); if (degpol(w[1]) != 1) { if (fm) { fm = -1; continue; } pari_err(talker, "no root in nilord. Is p = %Z a prime?", S->p); } for (i = 1; i < lg(w); i++) { /* Look for a root delt of nug in Fp[phi] such that vp(gamma - delta) > 0 Can be used to improve beta */ GEN eta, chie, nue, W = gel(w,i); /* monic linear polynomial */ delt = gneg_i( ch_var(gel(W,2), v) ); eta = gsub(gamm, delt); if (fm) { if (fastvalpos(eta, S->chi, S->p, ns, Ea)) break; continue; } if (typ(delt) == t_INT) chie = translate_pol(chig, delt); /* frequent special case */ else { if (!dvdii(ZX_QX_resultant(S->chi, eta), S->p)) continue; chie = mycaract(S->chi, eta, S->p, S->pmr, -1, ns); } nue = get_nu(chie, S->p, &l); if (l > 1) { S->nu = nue; S->chi= chie; composemod(S, eta, S->phi); return 1; } if (ismonome(nue)) { /* vp(eta) = vp(gamma - delta) > 0 */ long Le, Ee; GEN pie; if (dvdii(constant_term(chie), S->pmr)) chie = mycaract(S->chi, eta, S->p, S->pmf, -1, ns); pie = getprime(S, eta, chie, nue, &Le, &Ee, 0,Ea); if (pie) return testc2(S, S->nu, Ea, pie, Ee, ns); break; } } if (i == lg(w)) { if (fm) { fm = -1; continue; } pari_err(talker, "no root in nilord. Is p = %Z a prime?", S->p); } if (eq) delt = gmul(delt, powiu(S->p, eq)); if (er) delt = gmul(delt, gpowgs(S->nu, er)); beta = gsub(beta, delt); if (low_stack(limit,stack_lim(av2,1))) { if (DEBUGMEM > 1) pari_warn(warnmem, "nilord"); gerepileall(av2, S->invnu? 3: 1, &beta, &(S->invnu), &(S->Dinvnu)); } } } /* flag != 0 iff we're looking for the p-adic factorization, in which case it is the p-adic precision we want */ static GEN nilord(decomp_t *S, GEN dred, long mf, long flag) { GEN p = S->p; long Fa, La, Ea, oE, l, N = degpol(S->f), v = varn(S->f), nv = fetch_var(); GEN ns, pia, opa; if (DEBUGLEVEL>2) { fprintferr(" entering Nilord"); if (DEBUGLEVEL>4) { fprintferr(" with parameters: %Z^%ld\n", p, S->df); fprintferr(" fx = %Z, gx = %Z", S->f, S->nu); } fprintferr("\n"); } S->pmr = mulii(sqri(dred), p); S->pdr = mulii(dred, p); S->chi = centermod(S->f, S->pmr); S->pmf = powiu(p, mf + 1); ns = init_NS(N, p, S->pmf, S->pmr); oE = 0; opa = NULL; for(;;) { l = 2; /* Decomp by default */ S->phi0 = NULL; /* no delayed composition */ Fa = degpol(S->nu); for(;;) { pia = getprime(S, pol_x[v], S->chi, S->nu, &La, &Ea, oE,0); if (pia) break; S->phi = gadd(S->phi, opa); S->chi = NULL; if (!update_phi(S, ns, &l, flag)) break; } if (!pia) break; oE = Ea; opa = RgX_RgXQ_compo(pia, S->phi, S->f); if (La > 1) { /* change phi such that nu = pia */ S->phi = gadd(S->phi, opa); S->chi = NULL; if (!update_phi(S, ns, &l, flag)) break; } if (DEBUGLEVEL>5) fprintferr(" (Fa, Ea) = (%ld,%ld)\n", Fa, Ea); if (Ea*Fa == N) { /* O = Zp[phi] */ if (!flag) S->phi = redelt(S->phi, sqri(p), p); S->chi = NULL; l = 1; break; } l = 2; if (loop(S, nv, Ea, Fa, ns)) break; if (!update_phi(S, ns, &l, flag)) break; } (void)delete_var(); if (l == 1) return flag? NULL: dbasis(p, S->f, mf, S->phi, S->chi); return Decomp(S, flag); } /* Assume respm(f,g) divides p^M. Return respm(f, g), using dynamic p-adic * precision (until result is non-zero or p^M). */ GEN fast_respm(GEN f, GEN g, GEN p, long M) { long m = 32 / expi(p); /* p^m ~ 2^32 for initial value of m */ GEN R, q = NULL; if (!m) m = 1; for(;; m <<= 1) { if (M < 2*m) break; q = q? sqri(q): powiu(p, m); /* p^m */ R = respm(f,g, q); if (signe(R)) return R; } q = powiu(p, M); R = respm(f,g, q); return signe(R)? R: q; } GEN maxord_i(GEN p, GEN f, long mf, GEN w, long flag) { long l = lg(w)-1; GEN h = gel(w,l); /* largest factor */ GEN D = fast_respm(f, derivpol(f), p, mf); decomp_t S; S.f = f; S.p = p; S.nu = h; S.df = Z_pval(D, p); S.phi = pol_x[varn(f)]; if (l == 1) return nilord(&S, D, mf, flag); if (flag && flag <= mf) flag = mf + 1; S.chi = f; return Decomp(&S, flag); } /* DP = multiple of disc(P) or NULL * Return a multiple of the denominator of an algebraic integer (in Q[X]/(P)) * when expressed in terms of the power basis */ GEN indexpartial(GEN P, GEN DP) { pari_sp av = avma; long i, nb; GEN fa, res = gen_1, dP = derivpol(P); pari_timer T; if(DEBUGLEVEL>=5) (void)TIMER(&T); if (!DP) DP = ZX_disc(P); DP = mpabs(DP); if(DEBUGLEVEL>=5) msgTIMER(&T,"IndexPartial: discriminant"); fa = auxdecomp(DP, 0); if(DEBUGLEVEL>=5) msgTIMER(&T,"IndexPartial: factorization"); nb = lg(fa[1])-1; for (i = 1; i <= nb; i++) { long E = itos(gmael(fa,2,i)), e = E >> 1; GEN p = gmael(fa,1,i), q = p; if (i == nb) q = powiu(p, (odd(E) && !BSW_psp(p))? e+1: e); else if (e >= 2) { if(DEBUGLEVEL>=5) fprintferr("IndexPartial: factor %Z^%ld ",p,E); q = fast_respm(P, dP, p, e); if(DEBUGLEVEL>=5) { fprintferr("--> %Z : ",q); msgTIMER(&T,""); } } res = mulii(res, q); } return gerepileuptoint(av,res); } /*******************************************************************/ /* */ /* 2-ELT REPRESENTATION FOR PRIME IDEALS (dividing index) */ /* */ /*******************************************************************/ /* to compute norm of elt in algtobasis form */ typedef struct { long r1; GEN M; /* via norm_by_embed */ GEN D, w, T; /* via resultant if M = NULL */ } norm_S; static GEN get_norm(norm_S *S, GEN a) { if (S->M) { long e; GEN N = grndtoi( norm_by_embed(S->r1, gmul(S->M, a)), &e ); if (e > -5) pari_err(precer, "get_norm"); return N; } if (S->w) a = gmul(S->w, a); return ZX_resultant_all(S->T, a, S->D, 0); } /* q = p^(f+1). a/D in pr | p, norm(pr) = pf. * Return 1 if (a/D,p) = pr, and 0 otherwise */ static int is_uniformizer(GEN a, GEN q, norm_S *S) { return (remii(get_norm(S,a), q) != gen_0); } /* return x * y, x, y are t_MAT (Fp-basis of in O_K/p), assume (x,y)=1. * x or y may be NULL (= ok), not both */ static GEN mul_intersect(GEN x, GEN y, GEN p) { if (!x) return y; if (!y) return x; return FpM_intersect(x, y, p); } static GEN Fp_basis(GEN nf, GEN pr) { long i, j, l; GEN x, y; if (typ(pr) == t_MAT) return pr; x = prime_to_ideal(nf, pr); l = lg(x); y = cgetg(l, t_MAT); for (i=j=1; i=2; i--) gel(B,i-1) = mul_intersect(gel(B,i), gel(LW,i), p); for (i=1; i<=l; i++) gel(LV,i) = mul_intersect(gel(A,i), gel(B,i), p); return LV; } static void errprime(GEN p) { pari_err(talker, "primedec: %Z is not prime", p); } /* P = Fp-basis (over O_K/p) for pr. * V = Z-basis for I_p/pr. ramif != 0 iff some pr|p is ramified. * Return a p-uniformizer for pr. */ static GEN uniformizer(GEN nf, norm_S *S, GEN P, GEN V, GEN p, int ramif) { long i, l, f, m = lg(P)-1, N = degpol(nf[1]); GEN u, Mv, x, q; if (!m) return gscalcol_i(p,N); /* we want v_p(Norm(x)) = p^f, f = N-m */ f = N - m; q = powiu(p,f+1); u = FpM_invimage(shallowconcat(P, V), col_ei(N,1), p); setlg(u, lg(P)); u = centermod(gmul(P, u), p); if (is_uniformizer(u, q, S)) return u; if (signe(u[1]) <= 0) /* make sure u[1] in ]-p,p] */ gel(u,1) = addii(gel(u,1), p); /* try u + p */ else gel(u,1) = subii(gel(u,1), p); /* try u - p */ if (!ramif || is_uniformizer(u, q, S)) return u; /* P/p ramified, u in P^2, not in Q for all other Q|p */ Mv = eltmul_get_table(nf, unnf_minus_x(u)); l = lg(P); for (i=1; iM = NULL; if (typ(nf[5]) == t_VEC) /* beware dummy nf from padicff */ { GEN M = gmael(nf,5,1); long ex = gexpo(M) + gexpo(mulsi(8 * N, p)); if (N * ex <= bit_accuracy(gprecision(M))) { /* enough prec to use norm_by_embed */ S->M = M; S->r1 = nf_get_r1(nf); } } if (!S->M) { GEN D, w = Q_remove_denom(gel(nf,7), &D), Dp = sqri(p); long i; if (!D) w = shallowcopy(w); else { GEN w1 = D; long v = Z_pval(D, p); D = powiu(p, v); Dp = mulii(D, Dp); gel(w, 1) = remii(w1, Dp); } for (i=2; i<=N; i++) gel(w,i) = FpX_red(gel(w,i), Dp); S->D = D; S->w = w; S->T = T; } } /* Assuming P = (p,u) prime, return tau such that p Z + tau Z = p P^(-1)*/ static GEN anti_uniformizer(GEN nf, GEN p, GEN u) { pari_sp av = avma; GEN mat = eltmul_get_table(nf, u); return gerepileupto(av, FpM_deplin(mat,p)); } /*******************************************************************/ /* */ /* BUCHMANN-LENSTRA ALGORITHM */ /* */ /*******************************************************************/ static GEN mk_pr(GEN p, GEN u, long e, long f, GEN t) { GEN pr = cgetg(6, t_VEC); gel(pr,1) = p; gel(pr,2) = u; gel(pr,3) = utoipos(e); gel(pr,4) = utoipos(f); gel(pr,5) = t; return pr; } /* pr = (p,u) of ramification index e */ GEN primedec_apply_kummer(GEN nf,GEN u,long e,GEN p) { GEN t, T = gel(nf,1); long f = degpol(u), N = degpol(T); if (f == N) /* inert */ { u = gscalcol_i(p,N); t = gscalcol_i(gen_1,N); } else { /* make sure v_pr(u) = 1 (automatic if e>1) */ t = poltobasis(nf, FpX_div(T,u,p)); t = centermod(t, p); u = FpX_center(u, p); if (e == 1) { norm_S S; S.D = S.w = S.M = NULL; S.T = T; if (!is_uniformizer(u, powiu(p,f+1), &S)) gel(u,2) = addii(gel(u,2), p); } u = poltobasis(nf,u); } return mk_pr(p,u,e,f,t); } /* return a Z basis of Z_K's p-radical, phi = x--> x^p-x */ static GEN pradical(GEN nf, GEN p, GEN *phi) { long i,N = degpol(nf[1]); GEN q,m,frob,rad; /* matrix of Frob: x->x^p over Z_K/p */ frob = cgetg(N+1,t_MAT); for (i=1; i<=N; i++) gel(frob,i) = element_powid_mod_p(nf,i,p, p); m = frob; q = p; while (cmpiu(q,N) < 0) { q = mulii(q,p); m = FpM_mul(m, frob, p); } rad = FpM_ker(m, p); /* m = Frob^k, s.t p^k >= N */ for (i=1; i<=N; i++) gcoeff(frob,i,i) = subis(gcoeff(frob,i,i), 1); *phi = frob; return rad; } /* return powers of a: a^0, ... , a^d, d = dim A */ static GEN get_powers(GEN mul, GEN p) { long i, d = lg(mul[1]); GEN z, pow = cgetg(d+2,t_MAT), P = pow+1; gel(P,0) = gscalcol_i(gen_1, d-1); z = gel(mul,1); for (i=1; i<=d; i++) { gel(P,i) = z; /* a^i */ if (i!=d) z = FpM_FpC_mul(mul, z, p); } return pow; } /* minimal polynomial of a in A (dim A = d). * mul = multiplication table by a in A */ static GEN pol_min(GEN mul, GEN p) { pari_sp av = avma; GEN z, pow = get_powers(mul, p); z = FpM_deplin(pow, p); if (!z) errprime(p); return gerepilecopy(av, RgV_to_RgX(z,0)); } static GEN get_pr(GEN nf, norm_S *S, GEN p, GEN P, GEN V, int ramif) { GEN u, t; long e, f; if (typ(P) == t_VEC) return P; /* already done (Kummer) */ u = uniformizer(nf, S, P, V, p, ramif); t = anti_uniformizer(nf,p,u); if (!t) errprime(p); e = ramif? 1 + int_elt_val(nf,t,p,t,NULL): 1; f = degpol(nf[1]) - (lg(P)-1); return mk_pr(p,u,e,f,t); } /* prime ideal decomposition of p */ static GEN _primedec(GEN nf, GEN p) { GEN E, F, L, Ip, H, phi, mat1, f, g, h, p1, UN, T = gel(nf,1); long i, k, c, iL, N; F = FpX_factor(T, p); E = gel(F,2); F = gel(F,1); k = lg(F); if (k == 1) errprime(p); if (signe(modii(gel(nf,4),p))) /* p doesn't divide index */ { L = cgetg(k,t_VEC); for (i=1; i x^p - x in algebra Z_K/p */ Ip = pradical(nf,p,&phi); /* split etale algebra Z_K / (p,Ip) */ h = cgetg(N+1,t_VEC); if (iL > 1) { /* split off Kummer factors */ GEN mulbeta, beta = NULL; for (i=1; i M2 * Mi2 projector A --> A2 */ GEN M, Mi, M2, Mi2, phi2; long dim; H = gel(h,c); k = lg(H)-1; M = FpM_suppl(shallowconcat(H,UN), p); Mi = FpM_inv(M, p); M2 = vecslice(M, k+1,N); /* M = (H|M2) invertible */ Mi2 = rowslice(Mi,k+1,N); /* FIXME: FpM_mul(,M2) could be done with vecpermute */ phi2 = FpM_mul(Mi2, FpM_mul(phi,M2, p), p); mat1 = FpM_ker(phi2, p); dim = lg(mat1)-1; /* A2 product of 'dim' fields */ if (dim > 1) { /* phi2 v = 0 <==> a = M2 v in Ker phi */ GEN I, R, r, a, mula, mul2, v = gel(mat1,2); long n; a = FpM_FpC_mul(M2,v, p); mula = FpM_red(eltmul_get_table(nf, a), p); mul2 = FpM_mul(Mi2, FpM_mul(mula,M2, p), p); R = FpX_roots(pol_min(mul2,p), p); /* totally split mod p */ n = lg(R)-1; for (i=1; i<=n; i++) { r = lift_intern(gel(R,i)); I = gaddmat_i(negi(r), mula); gel(h,c++) = FpM_image(shallowconcat(H, I), p); } if (n == dim) for (i=1; i<=n; i++) { H = gel(h,--c); gel(L,iL++) = H; } } else /* A2 field ==> H maximal, f = N-k = dim(A2) */ gel(L,iL++) = H; } setlg(L, iL); { GEN Lpr = cgetg(iL, t_VEC); GEN LV = get_LV(nf, L,p,N); int ramif = dvdii(gel(nf,3), p); norm_S S; init_norm(&S, nf, p); for (i=1; ix^p over Z_K/pr = < w[c1], ..., w[cf] > over Fp */ frob = cgetg(f+1, t_MAT); for (i=1; i<=f; i++) { x = element_powid_mod_p(nf,c[i],p, p); gel(frob,i) = FpM_FpC_mul(ffproj, x, p); } u = col_ei(f,2); k = 2; deg1 = ffdegree(u, frob, p); while (deg1 < f) { k++; u2 = col_ei(f, k); deg2 = ffdegree(u2, frob, p); deg = clcm(deg1,deg2); if (deg == deg1) continue; if (deg == deg2) { deg1 = deg2; u = u2; continue; } u = gadd(u, u2); while (ffdegree(u, frob, p) < deg) u = gadd(u, u2); deg1 = deg; } v = lift_to_zk(u,c,N); mul = cgetg(f+1,t_MAT); gel(mul,1) = v; /* assume w_1 = 1 */ for (i=2; i<=f; i++) gel(mul,i) = element_mulid(nf,v,c[i]); } /* Z_K/pr = Fp(v), mul = mul by v */ mul = FpM_red(mul, p); mul = FpM_mul(ffproj, mul, p); pow = get_powers(mul, p); T = RgV_to_RgX(FpM_deplin(pow, p), varn(nf[1])); nfproj = cgetg(f+1, t_MAT); for (i=1; i<=f; i++) gel(nfproj,i) = lift_to_zk(gel(pow,i), c, N); nfproj = coltoliftalg(nf, nfproj); setlg(pow, f+1); ffproj = FpM_mul(FpM_inv(pow, p), ffproj, p); res = cgetg(LARGEMODPR, t_COL); gel(res,mpr_TAU) = tau; gel(res,mpr_FFP) = ffproj; gel(res,mpr_PR) = pr; gel(res,mpr_T) = T; gel(res,mpr_NFP) = nfproj; return gerepilecopy(av, res); } GEN nfmodprinit(GEN nf, GEN pr) { return modprinit(nf, pr, 0); } GEN zkmodprinit(GEN nf, GEN pr) { return modprinit(nf, pr, 1); } void checkmodpr(GEN modpr) { if (typ(modpr) != t_COL || lg(modpr) < SMALLMODPR) pari_err(talker,"incorrect modpr format"); checkprimeid(gel(modpr,mpr_PR)); } static GEN to_ff_init(GEN nf, GEN *pr, GEN *T, GEN *p, int zk) { GEN modpr = (typ(*pr) == t_COL)? *pr: modprinit(nf, *pr, zk); *T = lg(modpr)==SMALLMODPR? NULL: gel(modpr,mpr_T); *pr = gel(modpr,mpr_PR); *p = gel(*pr,1); return modpr; } GEN nf_to_ff_init(GEN nf, GEN *pr, GEN *T, GEN *p) { GEN modpr = to_ff_init(nf,pr,T,p,0); GEN tau = modpr_TAU(modpr); if (!tau) gel(modpr,mpr_TAU) = anti_uniformizer2(nf, *pr); return modpr; } GEN zk_to_ff_init(GEN nf, GEN *pr, GEN *T, GEN *p) { return to_ff_init(nf,pr,T,p,1); } /* assume x in 'basis' form (t_COL) */ GEN zk_to_ff(GEN x, GEN modpr) { GEN pr = gel(modpr,mpr_PR); GEN p = gel(pr,1); GEN y = gmul(gel(modpr,mpr_FFP), x); if (lg(modpr) == SMALLMODPR) return modii(y,p); y = FpC_red(y, p); return col_to_ff(y, varn(modpr[mpr_T])); } /* REDUCTION Modulo a prime ideal */ /* assume x in t_COL form, v_pr(x) >= 0 */ static GEN kill_denom(GEN x, GEN nf, GEN p, GEN modpr) { GEN cx, den = denom(x); long v; if (gcmp1(den)) return x; v = Z_pval(den,p); if (v) { GEN tau = modpr_TAU(modpr); if (!tau) pari_err(talker,"modpr initialized for integers only!"); x = element_mul(nf,x, element_pow(nf, tau, utoipos(v))); } x = Q_primitive_part(x, &cx); if (cx) x = gmul(Rg_to_Fp(cx, p), x); return FpC_red(x, p); } /* x integral, reduce mod prh in HNF */ GEN nfreducemodpr_i(GEN x, GEN prh) { GEN p = gcoeff(prh,1,1); long i,j; x = shallowcopy(x); for (i=lg(x)-1; i>=2; i--) { GEN t = gel(prh,i), p1 = remii(gel(x,i), p); gel(x,i) = p1; if (signe(p1) && is_pm1(t[i])) { for (j=1; jmultab,x,D->h) : element_mulidid(D->multab,D->h,D->h); (void)y; return FqV_red(z,D->T,D->p); } static GEN _sqr(void *data, GEN x) { rnfeltmod_muldata *D = (rnfeltmod_muldata *) data; GEN z = x? sqr_by_tab(D->multab,x) : element_mulidid(D->multab,D->h,D->h); return FqV_red(z,D->T,D->p); } /* Compute W[h]^n mod pr in the extension, assume n >= 0 */ static GEN rnfelementid_powmod(GEN multab, long h, GEN n, GEN T, GEN p) { pari_sp av = avma; GEN y; rnfeltmod_muldata D; if (!signe(n)) return gen_1; D.multab = multab; D.h = h; D.T = T; D.p = p; y = leftright_pow(NULL, n, (void*)&D, &_sqr, &_mul); return gerepilecopy(av, y); } /* Relative Dedekind criterion over nf, applied to the order defined by a * root of irreducible polynomial P, modulo the prime ideal pr. Assume * vdisc = v_pr( disc(P) ). * Return NULL if nf[X]/P is pr-maximal. Otherwise, return [flag, O, v]: * O = enlarged order, given by a pseudo-basis * flag = 1 iff O is pr-maximal * v = v_pr(disc(O)). */ static GEN rnfdedekind_i(GEN nf, GEN P, GEN pr, long vdisc) { long vt, r, d, n, m, i, j; pari_sp av = avma; GEN Prd, A, I, p, tau, g, matid; GEN modpr, h, k, base, nfT, T, gzk, hzk, prinvp, X, pal; P = lift(P); nf = checknf(nf); nfT = gel(nf,1); modpr = nf_to_ff_init(nf,&pr, &T, &p); tau = coltoliftalg(nf, gel(pr,5)); n = degpol(nfT); m = degpol(P); Prd = modprX(P, nf, modpr); A = (GEN)FqX_factor(Prd,T,p)[1]; r = lg(A); if (r < 2) pari_err(constpoler,"rnfdedekind"); g = gel(A,1); for (i=2; i1) fprintferr(" treating %Z\n",pr); modpr = nf_to_ff_init(nf,&pr,&T,&p); p1 = rnfdedekind_i(nf, pol, modpr, vdisc); if (!p1) { avma = av; return NULL; } if (gcmp1(gel(p1,1))) return gerepilecopy(av,gel(p1,2)); sep = itos(gel(p1,3)); W = gmael(p1,2,1); I = gmael(p1,2,2); pip = coltoalg(nf, gel(pr,2)); nfT = gel(nf,1); n = degpol(pol); vpol = varn(pol); q = T? powiu(p,degpol(T)): p; q1 = q; while (cmpiu(q1,n) < 0) q1 = mulii(q1,q); rnfId = matid(n); id = matid(degpol(nfT)); prhinv = idealinv(nf, pr); C = cgetg(n+1, t_MAT); for (j=1; j<=n; j++) gel(C,j) = cgetg(n*n+1, t_COL); MW = cgetg(n*n+1, t_MAT); for (j=1; j<=n*n; j++) gel(MW,j) = cgetg(n+1, t_COL); Tauinv = cgetg(n+1, t_VEC); Tau = cgetg(n+1, t_VEC); av1 = avma; lim = stack_lim(av1,1); for(cmpt=1; ; cmpt++) { GEN I0 = shallowcopy(I), W0 = shallowcopy(W); GEN Wa, Wainv, Waa, Ip, A, Ainv, MWmod, F, pseudo, G; if (DEBUGLEVEL>1) fprintferr(" pass no %ld\n",cmpt); for (j=1; j<=n; j++) { GEN tau, tauinv; long v1, v2; if (gequal(gel(I,j),id)) { gel(Tau,j) = gel(Tauinv,j) = gen_1; continue; } p1 = ideal_two_elt(nf,gel(I,j)); v1 = element_val(nf,gel(p1,1),pr); v2 = element_val(nf,gel(p1,2),pr); tau = (v1 > v2)? gel(p1,2): gel(p1,1); tauinv = element_inv(nf, tau); gel(Tau,j) = tau; gel(Tauinv,j) = tauinv; gel(W,j) = element_mulvec(nf, tau, gel(W,j)); gel(I,j) = idealmul(nf, tauinv, gel(I,j)); } /* W = (Z_K/pr)-basis of O/pr. O = (W0,I0) ~ (W, I) */ Wa = matbasistoalg(nf,W); /* compute MW: W_i*W_j = sum MW_k,(i,j) W_k */ Waa = lift_intern(RgM_to_RgXV(Wa,vpol)); Wainv = lift_intern(ginv(Wa)); for (i=1; i<=n; i++) for (j=i; j<=n; j++) { GEN z = RgXQX_rem(gmul(gel(Waa,i),gel(Waa,j)), pol, nfT); long tz = typ(z); if (is_scalar_t(tz) || (tz == t_POL && varncmp(varn(z), vpol) > 0)) z = gmul(z, gel(Wainv,1)); else z = mulmat_pol(Wainv, z); for (k=1; k<=n; k++) { GEN c = grem(gel(z,k), nfT); gcoeff(MW, k, (i-1)*n+j) = c; gcoeff(MW, k, (j-1)*n+i) = c; } } /* compute Ip = pr-radical [ could use Ker(trace) if q large ] */ MWmod = modprM(MW,nf,modpr); F = cgetg(n+1, t_MAT); F[1] = rnfId[1]; for (j=2; j<=n; j++) gel(F,j) = rnfelementid_powmod(MWmod, j, q1, T,p); Ip = FqM_ker(F,T,p); if (lg(Ip) == 1) { W = W0; I = I0; break; } /* Fill C: W_k A_j = sum_i C_(i,j),k A_i */ A = modprM_lift(FqM_suppl(Ip,T,p), modpr); for (j=1; j3) fprintferr(" new order:\n%Z\n%Z\n", W, I); if (sep <= 3 || gequal(I,I0)) break; if (low_stack(lim, stack_lim(av1,1)) || (cmpt & 3) == 0) { if(DEBUGMEM>1) pari_warn(warnmem,"rnfordmax"); gerepileall(av1,2, &W,&I); } } return gerepilecopy(av, mkvec2(W, I)); } static void check_pol(GEN x, long v) { long i,tx, lx = lg(x); if (varn(x) != v) pari_err(talker,"incorrect variable in rnf function"); for (i=2; i= 0) pari_err(talker,"incorrect polynomial in rnf function"); x = shallowcopy(x); for (i=2; i1) { fprintferr("Ideals to consider:\n"); for (i=1; i < l; i++) if (ep[i]>1) fprintferr("%Z^%ld\n",P[i],ep[i]); flusherr(); } id = matid(N); z = NULL; for (i=1; i < l; i++) if (ep[i] > 1) { GEN y = rnfordmax(nf, pol, gel(P,i), ep[i]); z = rnfjoinmodules(nf, z, y); } if (!z) z = triv_order(n, N); A = gel(z,1); I = gel(z,2); d = get_d(nf, pol, A); i=1; while (i<=n && gequal(gel(I,i), id)) i++; if (i > n) { D = gen_1; if (pf) *pf = gen_1; } else { D = gel(I,i); for (i++; i<=n; i++) D = idealmul(nf,D,gel(I,i)); if (pf) *pf = idealinv(nf, D); D = idealpow(nf,D,gen_2); } p1 = core2partial(Q_content(d), 0); *pd = gdiv(d, sqri(gel(p1,2))); *pD = idealmul(nf,D,d); return z; } GEN rnfpseudobasis(GEN nf, GEN pol) { pari_sp av = avma; GEN D, d, y = cgetg(5, t_VEC), z = rnfallbase(nf,pol, &D, &d, NULL); y[1] = z[1]; y[2] = z[2]; gel(y,3) = D; gel(y,4) = d; return gerepilecopy(av, y); } GEN rnfdiscf(GEN nf, GEN pol) { pari_sp av = avma; GEN D, d; (void)rnfallbase(nf,pol, &D, &d, NULL); return gerepilecopy(av, mkvec2(D,d)); } GEN gen_if_principal(GEN bnf, GEN x) { pari_sp av = avma; GEN z = isprincipalall(bnf,x, nf_GEN_IF_PRINCIPAL | nf_FORCE); if (typ(z) == t_INT) { avma = av; return NULL; } return z; } /* given bnf and a pseudo-basis of an order in HNF [A,I] (or [A,I,D,d] it * does not matter), tries to simplify the HNF as much as possible. The * resulting matrix will be upper triangular but the diagonal coefficients * will not be equal to 1. The ideals are guaranteed to be integral and * primitive. */ GEN rnfsimplifybasis(GEN bnf, GEN x) { pari_sp av = avma; long i, l; GEN p1, id, Az, Iz, nf, A, I; bnf = checkbnf(bnf); nf = gel(bnf,7); if (typ(x)!=t_VEC || lg(x)<3) pari_err(talker,"not a pseudo-basis in nfsimplifybasis"); x = shallowcopy(x); A = gel(x,1); I = gel(x,2); l = lg(I); id = matid(degpol(nf[1])); Az = cgetg(l, t_MAT); gel(x,1) = Az; Iz = cgetg(l, t_VEC); gel(x,2) = Iz; for (i = 1; i < l; i++) { if (gequal(gel(I,i),id)) { gel(Iz,i) = id; Az[i] = A[i]; continue; } gel(Iz,i) = Q_primitive_part(gel(I,i), &p1); gel(Az,i) = p1? gmul(gel(A,i),p1): gel(A,i); if (p1 && gequal(gel(Iz,i), id)) continue; p1 = gen_if_principal(bnf, gel(Iz,i)); if (p1) { gel(Iz,i) = id; gel(Az,i) = element_mulvec(nf,p1,gel(Az,i)); } } return gerepilecopy(av, x); } GEN rnfdet2(GEN nf, GEN A, GEN I) { pari_sp av = avma; GEN p1; nf = checknf(nf); if (typ(I) != t_VEC) pari_err(typeer,"rnfdet2"); p1 = idealmul(nf, det(matbasistoalg(nf, A)), prodid(nf, I)); return gerepileupto(av, p1); } GEN rnfdet(GEN nf, GEN order) { if (typ(order)!=t_VEC || lg(order)<3) pari_err(talker,"not a pseudo-matrix in rnfdet"); return rnfdet2(nf,gel(order,1),gel(order,2)); } GEN rnfdet0(GEN nf, GEN x, GEN y) { return y? rnfdet2(nf,x,y): rnfdet(nf,x); } /* Given two fractional ideals a and b, gives x in a, y in b, z in b^-1, t in a^-1 such that xt-yz=1. In the present version, z is in Z. */ static GEN nfidealdet1(GEN nf, GEN a, GEN b) { pari_sp av = avma; GEN x,p1,res,u,v,da,db; a = idealinv(nf,a); da = denom(a); if (!gcmp1(da)) a = gmul(da,a); db = denom(b); if (!gcmp1(db)) b = gmul(db,b); x = idealcoprime(nf,a,b); p1 = idealaddtoone(nf, idealmul(nf,x,a), b); u = gel(p1,1); v = gel(p1,2); res = cgetg(5,t_VEC); gel(res,1) = gmul(x,da); gel(res,2) = gdiv(v,db); gel(res,3) = negi(db); gel(res,4) = element_div(nf, u, gel(res,1)); return gerepilecopy(av,res); } static GEN get_order(GEN nf, GEN O, char *s) { if (typ(O) == t_POL) return rnfpseudobasis(nf, O); if (typ(O)!=t_VEC || lg(O) < 3 || typ(O[1]) != t_MAT || typ(O[2]) != t_VEC || lg(O[1]) != lg(O[2])) pari_err(talker,"not a pseudo-matrix in %s", s); return O; } /* given a pseudo-basis of an order in HNF [A,I] (or [A,I,D,d]), gives an * n x n matrix (not in HNF) of a pseudo-basis and an ideal vector * [id,id,...,id,I] such that order = nf[7]^(n-1) x I. * Uses the approximation theorem ==> slow. */ GEN rnfsteinitz(GEN nf, GEN order) { pari_sp av = avma; long i,n,l; GEN Id,A,I,p1,a,b; nf = checknf(nf); Id = matid(degpol(nf[1])); order = get_order(nf, order, "rnfsteinitz"); A = matalgtobasis(nf, gel(order,1)); I = shallowcopy(gel(order,2)); n=lg(A)-1; for (i=1; in) return 1; p1 = gel(I,j); for (j++; j<=n; j++) if (!gequal(gel(I,j),id)) p1 = idealmul(nf,p1,gel(I,j)); return gcmp0( isprincipal(bnf,p1) ); } long rnfisfree(GEN bnf, GEN order) { pari_sp av = avma; long n = _rnfisfree(bnf, order); avma = av; return n; } /**********************************************************************/ /** **/ /** COMPOSITUM OF TWO NUMBER FIELDS **/ /** **/ /**********************************************************************/ /* modular version */ GEN polcompositum0(GEN A, GEN B, long flall) { pari_sp av = avma; int same = (A == B || gequal(A,B)); long v, k; GEN C, D, LPRS; if (typ(A)!=t_POL || typ(B)!=t_POL) pari_err(typeer,"polcompositum0"); if (degpol(A)<=0 || degpol(B)<=0) pari_err(constpoler,"compositum"); v = varn(A); if (varn(B) != v) pari_err(talker,"not the same variable in compositum"); A = Q_primpart(A); check_ZX(A,"compositum"); if (!ZX_is_squarefree(A)) pari_err(talker,"compositum: %Z inseparable", A); if (!same) { B = Q_primpart(B); check_ZX(B,"compositum"); if (!ZX_is_squarefree(B)) pari_err(talker,"compositum: %Z inseparable", B); } D = NULL; /* -Wall */ k = same? -1: 1; C = ZY_ZXY_resultant_all(A, B, &k, flall? &LPRS: NULL); if (same) { D = RgX_rescale(A, stoi(1 - k)); C = gdivexact(C, D); if (degpol(C) <= 0) C = mkvec(D); else C = shallowconcat(ZX_DDF(C, 0), D); } else C = ZX_DDF(C, 0); /* C = Res_Y (A, B(X + kY)) guaranteed squarefree */ C = sort_vecpol(C, &cmpii); if (flall) { long i,l = lg(C); GEN w,a,b; /* a,b,c root of A,B,C = compositum, c = b - k a */ for (i=1; i= lA) gel(B,k) = grem(gel(B,k),A); if (!nfissquarefree(A,B)) pari_err(talker,"inseparable relative equation in rnfequation"); *pk = 0; C = ZY_ZXY_resultant_all(A, B, pk, pLPRS); if (gsigne(leading_term(C)) < 0) C = gneg_i(C); *pk = -*pk; return primpart(C); } GEN rnfequation0(GEN A, GEN B, long flall) { pari_sp av = avma; long k; GEN LPRS, nf, C; A = get_nfpol(A, &nf); C = rnfequation_i(A, B, &k, flall? &LPRS: NULL); if (flall) { /* a,b,c root of A,B,C = compositum, c = b + k a */ GEN a = gmul(gel(LPRS,1), QXQ_inv(gel(LPRS,2), C));/* inv is costly !*/ a = gneg_i(RgX_rem(a, C)); /* b = gadd(pol_x[varn(A)], gmulsg(k,a)); */ C = mkvec3(C, mkpolmod(a, C), stoi(k)); } return gerepilecopy(av, C); } GEN rnfequation(GEN nf,GEN pol2) { return rnfequation0(nf,pol2,0); } GEN rnfequation2(GEN nf,GEN pol2) { return rnfequation0(nf,pol2,1); } static GEN nftau(long r1, GEN x) { long i, l = lg(x); GEN s = r1? gel(x,1): gmul2n(real_i(gel(x,1)),1); for (i=2; i<=r1; i++) s = gadd(s, gel(x,i)); for ( ; i < l; i++) s = gadd(s, gmul2n(real_i(gel(x,i)),1)); return s; } static GEN initmat(long l) { GEN x = cgetg(l, t_MAT); long i; for (i = 1; i < l; i++) gel(x,i) = cgetg(l, t_COL); return x; } static GEN nftocomplex(GEN nf, GEN x) { return gmul(gmael(nf,5,1), algtobasis_i(nf, x)); } /* assume x a square t_MAT, return a t_VEC of embeddings of its columns */ static GEN mattocomplex(GEN nf, GEN x) { long i,j, l = lg(x); GEN v = cgetg(l, t_VEC); for (j=1; j= 0) return NULL; /* precision problem */ if (cx) m = gmul(m, cx); return gerepileupto(av, gmul(x,m)); } static int RED(long k, long l, GEN U, GEN mu, GEN MC, GEN nf, GEN I, GEN *Ik_inv) { GEN x, xc, ideal; long i; if (!*Ik_inv) *Ik_inv = idealinv(nf, gel(I,k)); ideal = idealmul(nf,gel(I,l), *Ik_inv); x = findmin(nf, ideal, gcoeff(mu,k,l)); if (!x) return 0; if (gcmp0(x)) return 1; xc = nftocomplex(nf,x); gel(MC,k) = gsub(gel(MC,k), vecmul(xc,gel(MC,l))); gel(U,k) = gsub(gel(U,k), gmul(coltoalg(nf,x), gel(U,l))); gcoeff(mu,k,l) = gsub(gcoeff(mu,k,l), xc); for (i=1; i 0) return 0; lswap(MC[k-1],MC[k]); lswap(h[k-1], h[k]); lswap(I[k-1], I[k]); for (j=1; j<=k-2; j++) swap(gcoeff(mu,k-1,j),gcoeff(mu,k,j)); muf = gcoeff(mu,k,k-1); mufc = gconj(muf); Bf = gadd(gel(B,k), vecmul(real_i(vecmul(muf,mufc)), gel(B,k-1))); if (check_0(Bf)) return 1; /* precision problem */ p1 = vecdiv(gel(B,k-1),Bf); gcoeff(mu,k,k-1) = vecmul(mufc,p1); temp = gel(MCS,k-1); gel(MCS,k-1) = gadd(gel(MCS,k), vecmul(muf,gel(MCS,k-1))); gel(MCS,k) = gsub(vecmul(vecdiv(gel(B,k),Bf), temp), vecmul(gcoeff(mu,k,k-1), gel(MCS,k))); gel(B,k) = vecmul(gel(B,k),p1); gel(B,k-1) = Bf; for (i=k+1; i<=kmax; i++) { temp = gcoeff(mu,i,k); gcoeff(mu,i,k) = gsub(gcoeff(mu,i,k-1), vecmul(muf, gcoeff(mu,i,k))); gcoeff(mu,i,k-1) = gadd(temp, vecmul(gcoeff(mu,k,k-1),gcoeff(mu,i,k))); } return 1; } static GEN rel_T2(GEN nf, GEN pol, long lx, long prec) { long ru, i, j, k, l; GEN T2, s, unro, roorder, powreorder; roorder = nf_all_roots(nf, pol, prec); if (!roorder) return NULL; ru = lg(roorder); unro = cgetg(lx,t_COL); for (i=1; i kmax) { /* Incremental Gram-Schmidt */ kmax = k; MCS[k] = MC[k]; for (j=1; j 2) k--; } else { for (l=k-2; l; l--) if (!RED(k, l, h, mu, MC, nf, I, &Ik_inv)) goto PRECPB; k++; } if (low_stack(lim, stack_lim(av,2))) { if(DEBUGMEM>1) pari_warn(warnmem,"rnflllgram"); gerepileall(av, H?10:9, &nf,&mth,&h,&MPOL,&B,&MC,&MCS,&mu,&I,&H); } } while (k < lx); MPOL = gmul(MPOL,h); if (H) h = gmul(H, h); if (DEBUGLEVEL) fprintferr("\n"); y = cgetg(3,t_VEC); gel(y,1) = mkvec2(algtobasis(nf,MPOL), gcopy(I)); gel(y,2) = algtobasis(nf,h); return gerepileupto(av, y); } GEN rnfpolred(GEN nf, GEN pol, long prec) { pari_sp av = avma; long i, j, n, v = varn(pol); GEN id, al, w, I, O, bnf, nfpol; if (typ(pol)!=t_POL) pari_err(typeer,"rnfpolred"); bnf = nf; nf = checknf(bnf); bnf = (nf == bnf)? NULL: checkbnf(bnf); if (degpol(pol) <= 1) return mkvec(pol_x[v]); nfpol = gel(nf,1); id = rnfpseudobasis(nf,pol); if (bnf && gcmp1(gmael3(bnf,8,1,1))) /* if bnf is principal */ { GEN newI, newO, zk = matid(degpol(nfpol)); O = gel(id,1); I = gel(id,2); n = lg(I)-1; newI = cgetg(n+1,t_VEC); newO = cgetg(n+1,t_MAT); for (j=1; j<=n; j++) { gel(newI,j) = zk; al = gen_if_principal(bnf,gel(I,j)); gel(newO,j) = element_mulvec(nf, al, gel(O,j)); } id = mkvec2(newO, newI); } id = (GEN)rnflllgram(nf,pol,id,prec)[1]; O = gel(id,1); I = gel(id,2); n = lg(I)-1; w = cgetg(n+1,t_VEC); pol = lift(pol); for (j=1; j<=n; j++) { GEN p1, newpol; p1 = gel(I,j); al = gmul(gcoeff(p1,1,1),gel(O,j)); p1 = coltoalg(nf,gel(al,n)); for (i=n-1; i; i--) p1 = gadd(coltoalg(nf,gel(al,i)), gmul(pol_x[v],p1)); newpol = RgXQX_red(caract2(pol,lift(p1),v), nfpol); newpol = Q_primpart(newpol); p1 = nfgcd(newpol, derivpol(newpol), nfpol, gel(nf,4)); if (degpol(p1) > 0) newpol = RgXQX_div(newpol, p1, nfpol); p1 = leading_term(newpol); if (typ(p1) != t_POL) p1 = scalarpol(p1, varn(nfpol)); newpol = RgXQX_div(newpol, p1, nfpol); gel(w,j) = newpol; } return gerepilecopy(av,w); } /* given a relative polynomial pol over nf, compute a pseudo-basis for the * extension, then an absolute basis */ static GEN makebasis(GEN nf, GEN pol, GEN rnfeq) { GEN elts,ids,polabs,plg,plg0,B,bs,p1,den,vbs,d,vpro; pari_sp av = avma; long n,N,m,i,j,k, v = varn(pol); polabs= gel(rnfeq,1); plg = gel(rnfeq,2); plg = lift_intern(plg); p1 = rnfpseudobasis(nf,pol); elts= gel(p1,1); ids = gel(p1,2); if (DEBUGLEVEL>1) fprintferr("relative basis computed\n"); N = degpol(pol); n = degpol(nf[1]); m = n*N; plg0= Q_remove_denom(plg, &den); /* plg = plg0/den */ /* nf = K = Q(a), vbs[i+1] = a^i as an elt of L = Q[X] / polabs */ vbs = RgX_powers(plg0, polabs, n-1); if (den) { /* restore denominators */ gel(vbs,2) = plg; d = den; for (i=3; i<=n; i++) { d = mulii(d,den); gel(vbs,i) = gdiv(gel(vbs,i), d); } } /* bs = integer basis of K, as elements of L */ bs = gmul(vbs, RgXV_to_RgM(gel(nf,7),n)); vpro = cgetg(N+1,t_VEC); for (i=1; i<=N; i++) gel(vpro,i) = monomial(gen_1, i-1, v); vpro = gmul(vpro, elts); B = cgetg(m+1, t_MAT); for(i=k=1; i<=N; i++) { GEN w = element_mulvec(nf, gel(vpro,i), gel(ids,i)); for(j=1; j<=n; j++) { p1 = grem(gmul(bs, gel(w,j)), polabs); gel(B,k++) = RgX_to_RgV(p1, m); } } B = Q_remove_denom(B, &den); if (den) { B = hnfmodid(B, den); B = gdiv(B, den); } else B = matid(m); return gerepilecopy(av, mkvec2(polabs, B)); } /* relative polredabs. Returns relative polynomial by default (flag = 0) * flag & nf_ORIG: + element (base change) * flag & nf_ADDZK: + integer basis * flag & nf_ABSOLUTE: absolute polynomial */ GEN rnfpolredabs(GEN nf, GEN relpol, long flag) { GEN red, bas, elt, POL, pol, T, a; long v, fl = (flag & nf_ADDZK)? nf_ADDZK: nf_RAW; pari_sp av = avma; if (typ(relpol)!=t_POL) pari_err(typeer,"rnfpolredabs"); nf = checknf(nf); v = varn(relpol); if (DEBUGLEVEL>1) (void)timer2(); relpol = unifpol(nf, relpol, t_POLMOD); T = gel(nf,1); if ((flag & nf_ADDZK) && !(flag & nf_ABSOLUTE)) pari_err(impl,"this combination of flags in rnfpolredabs"); if (flag & nf_PARTIALFACT) { long sa; fl |= nf_PARTIALFACT; POL = rnfequation_i(nf, relpol, &sa, NULL); bas = POL; a = stoi(sa); } else { GEN rel, eq = rnfequation2(nf,relpol); POL = gel(eq,1); a = gel(eq,3); rel = poleval(relpol, gsub(pol_x[v], gmul(a, gmodulo(pol_x[varn(T)],T)))); bas = makebasis(nf, rel, eq); if (DEBUGLEVEL>1) { msgtimer("absolute basis"); fprintferr("original absolute generator: %Z\n", POL); } } red = polredabs0(bas, fl); pol = gel(red,1); if (DEBUGLEVEL>1) fprintferr("reduced absolute generator: %Z\n",pol); if (flag & nf_ABSOLUTE) { if (flag & nf_ADDZK) pol = mkvec2(pol, gel(red,2)); return gerepilecopy(av, pol); } elt = eltabstorel(gel(red,2), T, relpol, a); pol = rnfcharpoly(nf,relpol,elt,v); if (!(flag & nf_ORIG)) return gerepileupto(av, pol); elt = mkpolmod(modreverse_i(gel(elt,2),gel(elt,1)), pol); return gerepilecopy(av, mkvec2(pol, elt)); }