/*******************************************************************/
/*******************************************************************/
/*                                                                 */
/*                       BASE D'ENTIERS                            */
/*                                                                 */
/*******************************************************************/
/*******************************************************************/
/* $Id: base2.c,v 2.0.0.2 1997/12/14 20:11:49 karim Exp karim $ */
#include "genpari.h"

GEN element_muli(GEN nf, GEN x, GEN y);
GEN element_mulid(GEN nf, GEN x, long i);
GEN element_mulid_intern(GEN nf, GEN x, long i, GEN myzero);
GEN eleval(GEN f,GEN h,GEN a);
long int_elt_val(GEN nf, GEN x, GEN p, GEN bp, long w, long v, long N);
GEN ker_spec(GEN x,GEN myzero,GEN myun);
GEN nfidealdet1(GEN nf, GEN a, GEN b);
GEN nfker(GEN nf, GEN R, GEN prhall);
GEN nfsuppl(GEN nf, GEN x, long n, GEN prhall);
GEN pol_to_monic(GEN pol, GEN *lead);
GEN respm(GEN f1,GEN f2,GEN pm);
GEN subresall(GEN x, GEN y, GEN *sol);

/* finds an equation for the d-th degree subfield of Q(zeta_n).
 * (Z/nZ)* must be cyclic.
 */
GEN
subcyclo(GEN n, GEN dd, int v)
{
  long av=avma,tetpil,j,k,necprec,q,d,p,al;
  GEN a,om,pol,fa,polpro,polnormal;

  if (typ(dd)!=t_INT || signe(dd)<=0) err(typeer,"subcyclo");
  d=itos(dd); if (d==1) return polx[v];
  if (typ(n)!=t_INT) err(typeer,"subcyclo");
  n=absi(n);
  if (cmpsi(2,n)>=0) err(talker,"degree does not divide phi(p) in subcyclo");
  if (mod4(n) == 2) n=shifti(n,-1);
  fa=factor(n);
  if (lg((GEN)fa[1])>2) err(impl,"subcyclo for non prime powers");
  p=itos(gmael(fa,1,1)); al=itos(gmael(fa,2,1));
  if (p==2)
  {
    if (al>2) err(impl,"subcyclo for powers of 2 greater than 4");
    if (d>2) err(talker,"degree does not divide phi(n) in subcyclo");
    pol=gsqr(polx[v]); tetpil=avma;
    return gerepile(av,tetpil,gaddsg(1,pol));
  }

  a=gener(n);
  necprec = max(5, ((d + 2*gexpo(n))>>TWOPOTBITS_IN_LONG)+2);
  om=cgetg(3,t_COMPLEX);
  om[1]=zero;
  om[2]=ldivri(gmul2n(mppi(necprec),1),n);
  om=gexp(om,necprec); q=itos(divis(n,p))*(p-1);
  if (q % d)
    err(talker,"degree does not divide phi(n) in subcyclo");
  polnormal=polx[v];polpro=polx[v];
  for (j=1; j<al; j++)
  {
    polpro=gpuigs(polpro,p); polnormal=gadd(polnormal,polpro);
  }
  q /= d; pol=gun;
  for (k=0; k<d; k++)
  {
    GEN p1 = gzero;
    long e = k;

    for (j=0; j<q; j++)
    {
      p1=gadd(p1,gsubst(polnormal,v,gpui(om,(GEN)gpuigs(a,e)[2],necprec)));
      e += d;
    }
    pol=gmul(pol,gsub(polx[v],p1));
  }
  pol=greal(pol); tetpil=avma;
  return gerepile(av,tetpil,ground(pol));
}

/*******************************************************************/
/*                                                                 */
/*                            ROUND 2                              */
/*                                                                 */
/*******************************************************************/

static GEN matinv(GEN x, GEN d);
static GEN mtran(GEN v, GEN w, GEN q, GEN m);
static GEN ordmax(GEN f, GEN p, long epsilon, GEN *ptdelta);
static GEN rquot(GEN x, GEN y);
static GEN rtran(GEN v, GEN w, GEN q);
static void rowred(GEN a, long rlim, GEN rmod);

#define coef1(a,i,j)  ( ((GEN) ((GEN) a)[j+1]) [i+1]) 
#define gcoef1(a,i,j) (GEN)coef1(a,i,j)

static void
allbase_check_args(GEN f, long code, GEN *y, GEN *ptw1, GEN *ptw2)
{
  long templevel,i,h;
  GEN w,w1,w2,q;

  if (typ(f)!=t_POL) err(notpoler,"allbase");
  if (lgef(f)<=3) err(constpoler,"allbase");
  *y=discsr(f);
  if (DEBUGLEVEL) { timer2(); templevel=DEBUGLEVEL; DEBUGLEVEL=5; }
  switch(code)
  {
    case 0: case 1:
      w=auxdecomp(absi(*y),1-code);
      w1=(GEN)w[1]; w2=(GEN)w[2]; break;
    default: w=(GEN)code;
      if (typ(w)!=t_MAT || lg(w)!=3)
        err(talker,"not a n x 2 matrix as factorization in factoredbase");
      w1=(GEN)w[1]; w2=(GEN)w[2]; h=lg(w1); q=gun;
      for (i=1; i<h; i++)
	q=gmul(q,gpui((GEN)w1[i], (GEN)w2[i],0));
      if (gcmp(absi(q), absi(*y)))
        err(talker,"incorrect factorization in factoredbase");
  }
  if (DEBUGLEVEL) { DEBUGLEVEL=templevel; msgtimer("disc. factorisation"); }
  *ptw1=w1; *ptw2=w2;
}

/* 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
allbase(GEN f, long code, GEN *y)
{
  GEN w1,w2,a,at,bt,b,da,db,q,*gptr[2];
  long av=avma,tetpil,n,h,j,i,k,r,s,t,pro,v,mf;

  allbase_check_args(f,code,y, &w1,&w2);
  v = varn(f); n = lgef(f)-3; h = lg(w1)-1;
  a=idmat(n); da=gun;
  for (i=1; i<=h; i++)
  {
    mf=itos((GEN)w2[i]);
    if (mf>1)
    {
      if (DEBUGLEVEL)
      {
	fprintferr("On traite le cas p^k = ");
        bruterr((GEN)w1[i],'g',-1); fprintferr("^%ld\n",mf);
      }
      b=ordmax(f,(GEN)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=rquot(gcoeff(at,s,s),gcoeff(bt,s,r));
	    at[s]=(long)rtran((GEN)at[s],(GEN)bt[r],q);
	    for (t=s-1; t; t--)
	    {
	      q=rquot(gcoeff(at,t,s),gcoeff(at,t,t));
	      at[s]=(long)rtran((GEN)at[s],(GEN)at[t],q);
	    }
	    pro=at[s]; at[s]=bt[r]; bt[r]=pro;
	  }
      for (j=n; j; j--)
      {
	for (k=1; k<j; k++)
	{
	  while (signe(gcoeff(at,j,k)))
	  {
	    q=rquot(gcoeff(at,j,j),gcoeff(at,j,k));
	    at[j]=(long)rtran((GEN)at[j],(GEN)at[k],q);
	    pro=at[j]; at[j]=at[k]; at[k]=pro;
	  }
	}
	if (signe(gcoeff(at,j,j))<0)
	  for (k=1; k<=j; k++) coeff(at,k,j)=lnegi(gcoeff(at,k,j));
	for (k=j+1; k<=n; k++)
	{
	  q=rquot(gcoeff(at,j,k),gcoeff(at,j,j));
	  at[k]=(long)rtran((GEN)at[k],(GEN)at[j],q);
	}
      }
      for (j=2; j<=n; j++)
	if (!cmpii(gcoeff(at,j,j),gcoeff(at,j-1,j-1)))
	{
	  coeff(at,1,j)=zero;
	  for (k=2; k<=j; k++)
	    coeff(at,k,j)=coeff(at,k-1,j-1);
	}
      a=gtrans(at);
    }
  }
  for (j=1; j<=n; j++)
    *y = divii(mulii(*y,sqri(gcoeff(a,j,j))), sqri(da));
  tetpil=avma; *y=icopy(*y);
  at=cgetg(n+1,t_VEC); v=varn(f);
  for (k=1; k<=n; k++)
  {
    q=cgetg(k+2,t_POL); at[k]=(long)q;
    q[1] = evalsigne(1) | evallgef(2+k) | evalvarn(v);
    for (j=1; j<=k; j++) q[j+1]=ldiv(gcoeff(a,k,j),da);
  }
  gptr[0]=&at; gptr[1]=y;
  gerepilemanysp(av,tetpil,gptr,2);
  return at;
}

GEN
base2(GEN x, GEN *y)
{
  return allbase(x,0,y);
}

GEN
discf2(GEN x)
{
  GEN y;
  long av=avma,tetpil;

  allbase(x,0,&y); tetpil=avma;
  return gerepile(av,tetpil,icopy(y));
}

/*  Normalized quotient and remainder ( -1/2 < r = x-q*y <= 1/2 )  */
static GEN
rquot(GEN x, GEN y)
{
  GEN u,v,w,p;
  long av,av1;

  av=avma;
  u=absi(y); v=shifti(x,1); w=shifti(y,1);
  if (cmpii(u,v)>0) p=subii(v,u);
  else p=addsi(-1,addii(u,v));
  av1=avma; return gerepile(av,av1,divii(p,w));
}

static GEN
rrmdr(GEN x, GEN y)
{
  long av=avma,av1;
  GEN p;

  p=mulii(rquot(x,y),y); av1=avma; 
  return gerepile(av,av1,subii(x,p));
}

static GEN
rgcd(GEN x, GEN y)
{
  long av=avma,av1;
  GEN z;

  while (signe(y)) { z=rrmdr(x,y); x=y; y=z; }
  av1=avma; return gerepile(av,av1,absi(x));
}

/*           Matrice compagnon du polynome unitaire x              */
static GEN
companion(GEN x) /* cf assmat */
{
  long i,j,l;
  GEN y;

  l=lgef(x)-2; y=cgetg(l,t_MAT);
  for (i=1; i<l; i++) y[i]=lgetg(l,t_COL);
  for (i=0; i<l-2; i++)
    for (j=0; j<l-1; j++) coef1(y,i,j)=((i+1)==j) ? un : zero;
  for (j=0; j<l-1; j++) coef1(y,l-2,j) = lneg((GEN)x[j+2]);
  return y;
}

static GEN
ordmax(GEN f, GEN p, long epsilon, GEN *ptdelta)
{
  GEN a,m,v,index,delta;
  GEN cf[100], *gptr[2];
  long j,k,n=lgef(f)-3,av=avma;

  a=cgetg(n*n+1,t_MAT);
  for (j=1; j<=n*n; j++)
  {
    a[j]=lgetg(n+1,t_COL);
    for (k=1; k<=n; k++) coeff(a,k,j)=zero;
  }
  v=cgetg(n+1,t_COL);
  cf[0]=idmat(n); cf[1]=companion(f);
  for (j=2; j<n; j++) cf[j]=gmul(cf[1],cf[j-1]);
  delta=gun;
  m=idmat(n);

  do
  {
    const GEN pp = sqri(p);
    GEN q,b,c,t,jp,w[100];
    long i,h,sp;

    b=matinv(m,delta);
    for (i=0; i<n; i++)
    {
      const GEN dd = sqri(delta), ppdd = mulii(dd,pp);

      t=gscalsmat(0,n); /* t = matrice nulle d'ordre n */
      for (h=0; h<n; h++)
        for (j=0; j<n; j++)
	  for (k=0; k<n; k++)
	    coef1(t,j,k) = (long) rrmdr(addii(gcoef1(t,j,k), mulii(gcoef1(m,i,h),gcoef1(cf[h],j,k))), ppdd);
      c=gmul(t,b); w[i]=gmul(m,c);
      for (j=0; j<n; j++)
	for (k=0; k<n; k++)
	  coef1(w[i],j,k)=(long)rrmdr(divii(gcoef1(w[i],j,k),dd),pp);
    }

    if (cmpis(p,n)>0)
    {
      for (i=0; i<n; i++)
	for (j=0; j<n; j++)
	{
	  coeff(t,i+1,j+1)=zero;
	  for (k=0; k<n; k++)
	    for (h=0; h<n; h++)
	    {
	      const GEN r=modii(gcoef1(w[i],k,h),p);
	      const GEN s=modii(gcoef1(w[j],h,k),p);

	      coef1(t,i,j)=lmodii(addii(gcoef1(t,i,j),mulii(r,s)),p);
	    }
	}
    }
    else
    {
      for (j=0; j<n; j++)
      {
	for (i=0; i<n; i++)
	  coef1(b,i,j)=(i==0)? un : zero;
	sp=itos(p);
	/* ici la boucle en k calcule la puissance p mod p de w[j] */
	for (k=0; k<sp; k++)
	{
	  for (i=0; i<n; i++)
	  {
	    v[i+1]=zero;
	    for (h=0; h<n; h++)
	      v[i+1]=lmodii(addii((GEN)v[i+1],
	                          mulii(gcoef1(b,h,j),gcoef1(w[j],h,i))),p);
	  }
	  for (i=0; i<n; i++) coef1(b,i,j)=v[i+1];
	}
      }
      q=p; t=b;
      while (cmpis(q,n)<0) { q=mulii(q,p); t=gmul(b,t); }
    }

    for (i=0; i<n; i++)
      for (j=0; j<n; j++)
      {
	coef1(a,j,i)=(i==j)? (long)p : zero;
	coef1(a,j,n+i)=lmodii(gcoef1(t,i,j),p);
      }
    rowred(a,2*n-1,pp);
    for (i=0; i<n; i++)
      for (j=0; j<n; j++)
	coef1(b,j,i)=coef1(a,j,i);
    jp=matinv(b,p);
    for (k=0; k<n; k++)
    {
      t=gmul(jp,w[k]); t=gmul(t,b);
      for (i=0; i<n; i++)
	for (j=0; j<n; j++)
	  coef1(t,i,j)=ldivii(gcoef1(t,i,j),p);
      h=0;
      for (i=0; i<n; i++)
	for (j=0; j<n; j++) { coef1(a,k,h)=coef1(t,i,j); h++; }
    }
    rowred(a,n*n-1,pp); index=gun;
    for (i=0; i<n; i++)
      index=mulii(index,gcoef1(a,i,i));
    if (cmpsi(1,index))
    {
      GEN hh;

      delta=mulii(index,delta);
      for (i=0; i<n; i++)
	for (j=0; j<n; j++)
	  coef1(c,i,j)=coef1(a,i,j);
      b=matinv(c,index);
      m=gmul(b,m);
      hh=delta;
      for (i=0; i<n; i++)
	for (j=0; j<n; j++)
	  hh=rgcd(gcoef1(m,i,j),hh);
      if (cmpis(hh,1)>1)
      {
	delta=divii(delta,hh);
	for (i=0; i<n; i++)
	  for (j=0; j<n; j++)
	    coef1(m,i,j)=ldivii(gcoef1(m,i,j),hh);
      }
      q=index;
      while (!signe(modii(q,p))) { q=divii(q,p); epsilon=epsilon-2; }
    }
  }
  while (!gcmp1(index) && epsilon>=2);

  gptr[0]=&delta; gptr[1]=&m;
  gerepilemany(av,gptr,2);
  *ptdelta=delta; return m;
}

static void
rowred(GEN a, long rlim, GEN rmod)
{
  long j,k,n,pro;
  GEN q;

  n=lg(a[1])-1;
  for (j=0; j<n; j++)
  {
    for (k=j+1; k<=rlim; k++)
      while (signe(gcoef1(a,j,k)))
      {
	q=rquot(gcoef1(a,j,j),gcoef1(a,j,k));
	a[j+1]=(long)mtran((GEN)a[j+1],(GEN)a[k+1],q,rmod);
	pro=a[j+1]; a[j+1]=a[k+1]; a[k+1]=pro;
      }
    if (signe(gcoef1(a,j,j))<0)
      for (k=j; k<n; k++) coef1(a,k,j)=lnegi(gcoef1(a,k,j));
    for (k=0; k<j; k++)
    {
      q=rquot(gcoef1(a,j,k),gcoef1(a,j,j));
      a[k+1]=(long)mtran((GEN)a[k+1],(GEN)a[j+1],q,rmod);
    }
  }
}

static GEN
rtran(GEN v, GEN w, GEN q)
{
  long av,tetpil;
  GEN p1;

  if (signe(q))
  {
    av=avma; p1=gmul(q,w); tetpil=avma;
    return gerepile(av,tetpil,gsub(v,p1));
  }
  return v;
}

static GEN
mtran(GEN v, GEN w, GEN q, GEN m)
{
  long k;

  if (signe(q))
    for (k=1; k<lg(v); k++)
      v[k]=(long)rrmdr(subii((GEN)v[k],modii(mulii(q,(GEN)w[k]),m)),m);
  return v;
}

/* Calcule d/x  ou  d est entier et x matrice triangulaire inferieure
 * entiere dont les coeff diagonaux divisent d (resultat entier).
 */
static GEN
matinv(GEN x, GEN d)
{
  long n,i,j,k,av,av1;
  GEN y,h;

  n=lg(x)-1; y=idmat(n);
  for (i=1; i<=n; i++)
    coeff(y,i,i)=ldivii(d,gcoeff(x,i,i));
  av=avma; 
  for (i=2; i<=n; i++)
    for (j=i-1; j; j--)
    {
      for (h=gzero,k=j+1; k<=i; k++)
	h=addii(h,mulii(gcoeff(y,i,k),gcoeff(x,k,j)));
      setsigne(h,-signe(h)); av1=avma;
      coeff(y,i,j) = lpile(av,av1,divii(h,gcoeff(x,j,j)));
      av = avma;
    }
  return y;
}

/*******************************************************************/
/*                                                                 */
/*                            ROUND 4                              */
/*                                                                 */
/*******************************************************************/

static GEN Decomp(GEN p,GEN f,long mf,GEN theta,GEN chi,GEN nu);
static GEN dbasis(GEN p, GEN f, long mf, GEN alpha, GEN U);
static GEN eltppm(GEN f,GEN pd,GEN theta,GEN k);
static GEN maxord(GEN p,GEN f,long mf);
static GEN nbasis(GEN ibas,GEN pd);
static GEN nilord(GEN p,GEN fx,long mf,GEN gx);
static GEN testd(GEN p,GEN fa,long c,long Da,GEN alph2,long Ma,GEN theta);
static long clcm(long a,long b);

static int
fnz(GEN x,long j)
{
  long i=1; while (!signe(x[i])) i++;
  return i==j;
}

/* retourne la base, dans y le discf et dans ptw la factorisation (peut
 etre partielle) de discf */
GEN
allbase4(GEN f,long code, GEN *y, GEN *ptw)
{
  GEN w,w1,w2,a,da,b,db,bas,q,p1,*gptr[3];
  long v,n,mf,h,lfa,i,j,k,l,first,tetpil,av = avma;

  allbase_check_args(f,code,y, &w1,&w2);
  first=1; v = varn(f); n = lgef(f)-3; h = lg(w1)-1;
  for (i=1; i<=h; i++)
  {
    mf=itos((GEN)w2[i]);
    if (mf>1)
    {
      if (DEBUGLEVEL) fprintferr("On traite le cas p^k = %Z^%ld\n",w1[i],mf);
      b=maxord((GEN)w1[i],f,mf);
      p1=cgetg(n+1,t_VEC); for (j=1; j<=n; j++) p1[j]=coeff(b,j,j);
      db=denom(p1);
      if (! gcmp1(db))
      {
	if (first==1) { da=db; a=gmul(b,db); first=0; }
        else
	{
          da=mulii(da,db); b=gmul(da,b); a=gmul(db,a);
          j=1; while (j<=n && fnz((GEN)a[j],j) && fnz((GEN)b[j],j)) j++;
	  k=j-1; p1=cgetg(2*n-k+1,t_MAT);
	  for (j=1; j<=k; j++)
	  {
	    p1[j]=a[j];
	    coeff(p1,j,j) = lmppgcd(gcoeff(a,j,j),gcoeff(b,j,j));
	  }
	  for (  ; j<=n; j++) p1[j]=a[j];
	  for (  ; j<=2*n-k; j++) p1[j]=b[j+k-n];
	  a=hnfmod(p1,detint(p1));
	}
      }
      if (DEBUGLEVEL>=3)
      {
	fprintferr("Le resultat pour ce nombre p est : \n ");
	outerr(b); fprintferr("\n");
      }
    }
  }
  if (!first)
  {
    for (j=1; j<=n; j++)
      *y = mulii(divii(*y,sqri(da)),sqri(gcoeff(a,j,j)));
    for (j=n-1; j; j--)
      if (cmpis(gcoeff(a,j,j),2) > 0)
      {
        p1=shifti(gcoeff(a,j,j),-1);
        for (k=j+1; k<=n; k++)
          if (cmpii(gcoeff(a,j,k),p1) > 0)
            for (l=1; l<=j; l++)
              coeff(a,l,k)=lsubii(gcoeff(a,l,k),gcoeff(a,l,j));
      }
  }
  if (ptw)
  {
    lfa=0;
    for (j=1; j<=h; j++)
    {
      k=ggval(*y,(GEN)w1[j]);
      if (k) { lfa++; w1[lfa]=w1[j]; w2[lfa]=k; }
    }
  }
  tetpil=avma; *y=icopy(*y);
  bas=cgetg(n+1,t_VEC); v=varn(f);
  for (k=1; k<=n; k++)
  {
    q=cgetg(k+2,t_POL); bas[k]=(long)q;
    q[1] = evalsigne(1) | evallgef(k+2) | evalvarn(v);
    if (!first)
      for (j=1; j<=k; j++) q[j+1]=ldiv(gcoeff(a,j,k),da);
    else
    {
      for (j=2; j<=k; j++) q[j]=zero;
      q[j]=un; 
    }
  }
  if (ptw)
  {
    *ptw=w=cgetg(3,t_MAT); w[1]=lgetg(lfa+1,t_COL); w[2]=lgetg(lfa+1,t_COL);
    for (j=1; j<=lfa; j++)
    { 
      coeff(w,j,1)=(long)icopy((GEN)w1[j]);
      coeff(w,j,2)=lstoi(w2[j]);
    }
    gptr[2]=ptw;
  }
  gptr[0]=&bas; gptr[1]=y;
  gerepilemanysp(av,tetpil,gptr, ptw?3:2);
  return bas;
}

/* if y is non-NULL, it receives the discriminant
 * return basis if (ret_basis != 0), discriminant otherwise
 */
static GEN
nfbasis00(GEN x, long flag, GEN p, long ret_basis, GEN *y)
{
  GEN disc, basis, lead;
  GEN *gptr[2];
  long k, tetpil, av = avma, n = lgef(x)-3, small;

  if (typ(x)!=t_POL) err(typeer,"nfbasis00");
  if (n<=0) err(zeropoler,"nfbasis00");
  for (k=n+2; k>=2; k--)
    if (typ(x[k])!=t_INT) err(talker,"polynomial not in Z[X] in nfbasis");

  x = pol_to_monic(x,&lead);

  if (gcmp0(p))
    small = (flag & 1)? 1:0; /* small basis */
  else 
    small = (long) p;        /* factored basis */

  if (flag & 2) 
    basis = allbase(x,small,&disc); /* round 2 */
  else
    basis = allbase4(x,small,&disc,NULL); /* round 4 */

  tetpil=avma;
  if (!ret_basis)
    return gerepile(av,tetpil,gcopy(disc));

  if (!lead) basis = gcopy(basis);
  else
  {
    long v = varn(x);
    GEN pol = gmul(polx[v],lead);

    tetpil = avma; basis = gsubst(basis,v,pol);
  }
  if (!y)
    return gerepile(av,tetpil,basis);

  *y = gcopy(disc);
  gptr[0]=&basis; gptr[1]=y;
  gerepilemanysp(av,tetpil,gptr,2);
  return basis;
}

GEN
nfbasis(GEN x, GEN *y, long flag, GEN p)
{
  return nfbasis00(x,flag,p,1,y);
}

GEN
nfbasis0(GEN x, long flag, GEN p)
{
  return nfbasis00(x,flag,p,1,NULL);
}

GEN
nfdiscf0(GEN x, long flag, GEN p)
{
  return nfbasis00(x,flag,p,0,&p);
}

GEN
base(GEN x, GEN *y)
{
  return allbase4(x,0,y,NULL);
}

GEN
smallbase(GEN x, GEN *y)
{
  return allbase4(x,1,y,NULL);
}

GEN
factoredbase(GEN x, GEN p, GEN *y)
{
  return allbase4(x,(long)p,y,NULL);
}

GEN
discf(GEN x)
{
  GEN y;
  long av=avma,tetpil;

  allbase4(x,0,&y,NULL); tetpil=avma;
  return gerepile(av,tetpil,icopy(y));
}

GEN
smalldiscf(GEN x)
{
  GEN y;
  long av=avma,tetpil;

  allbase4(x,1,&y,NULL); tetpil=avma;
  return gerepile(av,tetpil,icopy(y));
}

GEN
factoreddiscf(GEN x, GEN p)
{
  GEN y;
  long av=avma,tetpil;

  allbase4(x,(long)p,&y,NULL); tetpil=avma;
  return gerepile(av,tetpil,icopy(y));
}

/* return U if Z[alpha] is not maximal or 2*dU < m-1; else return NULL */
static GEN
dedek(GEN f, long mf, GEN p,GEN g)
{
  GEN fmp,k,h,unmodp;
  long dk;

  if (DEBUGLEVEL>=3)
  {
    fprintferr(" On est dans Dedekind ");
    if (DEBUGLEVEL>=4)
    {
      fprintferr(" avec les parametres\n" );
      fprintferr(" p=%Z, f=%Z",(long)p,(long)f);
    }
    fprintferr("\n");
  }
  unmodp=gmodulsg(1,p); g=gmul(g,unmodp); fmp=gmul(f,unmodp);
  h=gdeuc(fmp,g); k=gdiv(gsub(f,gmul(lift(g),lift(h))),p);
  k=srgcd(gmul(k,unmodp),srgcd(g,h));

  dk=lgef(k)-3;
  if (DEBUGLEVEL>=4) fprintferr(" Le pgcd est de degre %ld \n",dk );
  if (2*dk >= mf-1) { f=gdeuc(fmp,k); return lift(f); } 
  return dk? (GEN)NULL: f;
}

/* p-maximal order of Af; p^m does not divide Df  */
static GEN
maxord(GEN p,GEN f,long mf)
{
  GEN w,g,h,res,fmp;
  long j,r,v=varn(f),n=lgef(f)-3,av=avma,flw;

  flw = (cmpsi(n,p)<0);
  if (flw)
  {
    fmp=gmul(gmodulsg(1,p),f);
    g=gdeuc(fmp,srgcd(fmp,deriv(fmp,v)));
  }
  else
  {
    w=factmod(f,p); r=lg(w[1])-1; g=gun;
    for (j=1; j<=r; j++) g=gmul(gcoeff(w,j,1),g);
  }
  res=dedek(f,mf,p,g);
  if (res) 
    res = dbasis(p,f,mf,polx[v],res);
  else
  {
    if (flw) { w=factmod(f,p); r=lg(w[1])-1; }
    h = bestnu((GEN)w[1]);
    res = (r==1)?  nilord(p,f,mf,h): Decomp(p,f,mf,polx[v],f,h);
  }
  return gerepileupto(av,res);
}

/* do a centermod on integer or rational number */
static GEN
polmodiaux(GEN x, GEN y, GEN ys2)
{
  if (typ(x)!=t_INT)
    x = mulii((GEN)x[1], mpinvmod((GEN)x[2],y));
  x = resii(x,y); if (cmpii(x,ys2) > 0) x = subii(x,y);
  return x;
}

/* x polynomial with integer or rational coeff. Reduce them mod y IN PLACE */
static GEN
polmodi(GEN x, GEN y)
{
  long lx=lgef(x), i;
  GEN ys2 = shifti(y,-1);
  for (i=2; i<lx; i++) x[i]=(long)polmodiaux((GEN)x[i],y,ys2);
  return x;
}

/* same but not in place */
static GEN
polmodi_keep(GEN x, GEN y)
{
  long lx=lgef(x), i;
  GEN ys2 = shifti(y,-1);
  GEN z = cgetg(lx,t_POL);
  for (i=2; i<lx; i++) z[i]=(long)polmodiaux((GEN)x[i],y,ys2);
  z[1]=x[1]; return x;
}

static GEN
dbasis(GEN p, GEN f, long mf, GEN alpha, GEN U)
{
  long n=lgef(f)-3,dU=lgef(U)-3,c,i,dh;
  GEN b,p1,ha,pd,pdp;

  if (DEBUGLEVEL>=3)
  {
    fprintferr(" On est dans Dedekind Basis");
    if (DEBUGLEVEL>=4)
    {
      fprintferr(" avec les parametres\n");
      fprintferr(" p=%Z, f=%Z, alpha=%Z",(long)p,(long)f,(long)alpha);
    }
    fprintferr("\n");
  }
  pd = gpuigs(p,mf/2); pdp = mulii(pd,p);

  b=cgetg(n+1,t_MAT); /* Z[a] + U/p Z[a] is maximal */
  ha = pd;

  p1=cgetg(n+1,t_COL); b[1]=(long)p1;
  p1[1]=(long)pd; for (i=2; i<=n; i++) p1[i]=zero;
  for (c=2; c<=n; c++)
  {
    p1=cgetg(n+1,t_COL); b[c]=(long)p1;
    if (c == dU+1)
      ha = gdiv(gmul(pd,eleval(f,U,alpha)),p);
    else
      ha = gmod(gmul(ha,alpha),f);
    ha = polmodi(ha,pdp); dh = lgef(ha)-2;
    for (i=1; i<=dh; i++) p1[i]=ha[i+1];
    for (   ; i<=n;  i++) p1[i]=zero;
  }
  if (DEBUGLEVEL>=4)
  {
    fprintferr(" On construit un nouvel ordre  \n" );
    if (DEBUGLEVEL>=5) outerr(b);
    fprintferr(" On fait sa HNF \n");
  }
  b=hnfmodid(b,pd);
  if (DEBUGLEVEL>=4)
  {
    fprintferr(" Sa HNF est finie \n");
    if (DEBUGLEVEL>=5) outerr(b);
  }
  return gdiv(b,pd);
}

static GEN
get_partial_order_as_pols(GEN p, GEN f)
{
  long i,j,v,n=lgef(f)-3, vf = varn(f);
  GEN b,ib,h,col;
  
  v=ggval(discsr(f),p); b=maxord(p,f,v);
  ib=cgetg(n+1,t_VEC);
  for (i=1; i<=n; i++)
  {
    h=cgetg(i+2,t_POL); ib[i]=(long)h; col=(GEN)b[i];
    h[1]=evalsigne(1)|evallgef(i+2)|evalvarn(vf);
    for (j=1;j<=i;j++) h[j+1]=col[j];
  }
  return ib;
}

static GEN
Decomp(GEN p,GEN f,long mf,GEN theta,GEN chi,GEN nu)
{
  long n1,n2,j;
  GEN pk,ph,pmr,pdr,unmodp;
  GEN b1,b2,b3,a2,a1,e,f1,f2,ib1,ib2,ibas;

  if (DEBUGLEVEL>=3)
  {
    fprintferr(" On entre dans Decomp ");
    if (DEBUGLEVEL>=4)
    {
      fprintferr(" avec les parametres suivants \n ");
      fprintferr(" p=%Z, f=%Z, exposant=%ld",(long)p,(long)f,mf);
    }
    fprintferr("\n");
  }
  unmodp=gmodulsg(1,p);
  pdr=respm(f,deriv(f,varn(f)),gpuigs(p,mf));
  pmr=mulii(p,sqri(pdr));

  b1=gmul(chi,unmodp); a1=gun;
  b2=unmodp; b3=gmul(nu,unmodp);
  while (lgef(b3) > 3)
  {
    b1=gdeuc(b1,b3); b2=gmul(b2,b3);
    b3=lift_intern(gbezout(b2,b1,&a1,&a2));
  }
  e=eleval(f,lift_intern(gmul(a1,b2)),theta);
  e=gdiv(polmodi(gmul(pdr,e), mulii(pdr,p)),pdr);

  pk=p; ph=mulii(pdr,pmr);

  /* E(t)- e(t) belongs to p^k Op, which is contained in p^(k-df)*Zp[xi] */
  while (cmpii(pk,ph) == -1)
  {
    e = gmul(gsqr(e), gsubsg(3,gmul2n(e,1)));
    e = gmod(e,f); pk = gsqr(pk); 
    e=gdiv(polmodi(gmul(pdr,e), mulii(pk,pdr)), pdr);
  }
  f1 = gcdpm(f,gmul(pdr,gsubsg(1,e)), mulii(pmr,pdr));
  f1 = polmodi(gmod(f1,f),pmr); f2=gdeuc(f,f1);
  f2 = polmodi(gmod(f2,f),pmr);

  if (DEBUGLEVEL>=4)
  {
    fprintferr(" Fin de la fonction Decomp avec les parametres ");
    fprintferr(" f1=%Z f2=%Z e=%Z\n",(long)f1,(long)f2,(long)e);
  }
  ib1 = get_partial_order_as_pols(p,f1); n1=lg(ib1)-1;
  ib2 = get_partial_order_as_pols(p,f2); n2=lg(ib2)-1;
  ibas=cgetg(n1+n2+1,t_VEC);

  for (j=1; j<=n1; j++)
    ibas[j]=(long)polmodi(gmod(gmul(gmul(pdr,(GEN)ib1[j]),e),f), pdr);
  e=gsubsg(1,e);
  for (   ; j<=n1+n2; j++)
    ibas[j]=(long)polmodi(gmod(gmul(gmul(pdr,(GEN)ib2[j-n1]),e),f), pdr);
  return nbasis(ibas,pdr);
}

/* minimum extension valuation: res[0]/res[1] (both are longs) */
long *
vstar(GEN p,GEN h)
{
  static long res[2];
  long m,first,j,k,v,w;

  m=lgef(h)-3; first=1; k=1; v=0;
  for (j=1; j<=m; j++)
    if (! gcmp0((GEN)h[m-j+2]))
    {
      w = ggval((GEN)h[m-j+2],p);
      if (first || w*k < v*j) { v=w; k=j; }
      first=0;
    }
  m = cgcd(v,k);
  res[0]=v/m; res[1]=k/m; return res;
}

/* returns a polynomial in variable v, whose coeffs corresponding to the
 * digits of m (in base p). If p is 0 return constant pol m.
 */
static GEN
stopoly(long m, long p, long v)
{
  long l=2,i,c[100];
  GEN y;

  if (p)
    do { c[l++]=m%p; m=m/p; } while (m);
  else 
    { l=3; c[2]=m; }
  y=cgetg(l,t_POL); for (i=2; i<l; i++) y[i]=lstoi(c[i]);
  y[1]=evalsigne(1)|evallgef(l)|evalvarn(v); return y;
}

/* Returns [theta,chi,nu] with theta non-primary */
static GEN
csrch(GEN p,GEN fa,GEN gamma)
{
  GEN b,h,theta,w;
  long pp,t,v=varn(fa);

  pp = p[2]; if (lgef(p)>3 || pp<0) pp=0;
  for (t=1; ; t++)
  {
    h = stopoly(t,pp,v);
    theta = gadd(gamma,gmod(h,fa));
    w=factcp(p,fa,theta); h=(GEN)w[3];
    if (h[2] > 1)
    {
      b=cgetg(5,t_VEC); b[1]=un; b[2]=(long)theta;
      b[3]=w[1]; b[4]=w[2]; return b;
    }
  }
}

/* Returns
 *  [1,theta,chi,nu] if theta non-primary
 *  [2,phi, * , * ]  if D_phi > D_alpha or M_phi > M_alpha
 */
GEN
bsrch(GEN p,GEN fa,long ka,GEN eta,long Ma)
{
  long n=lgef(fa)-3,Da=lgef(eta)-3;
  long c,r,j,MaVb,deg,av=avma,tetpil;
  GEN pc,pcc,beta,gamma,delta,pik,w,h;

  pc=respm(fa,deriv(fa,varn(fa)),gpuigs(p,ka));
  c=ggval(pc,p); pcc=gsqr(pc);

  r=1+(long)ceil(c/(double)(Da)+gtodouble(gdivsg(c*n-2,mulsi(Da,subis(p,1)))));

  beta=gdiv(lift_intern(gpuigs(gmodulcp(eta,fa),Ma)),p);

  for(;;)
  {
    beta=gdiv(polmodi(gmul(pc,beta),pcc), pc);
    tetpil=avma; w=testd(p,fa,c,Da,eta,Ma,beta);
    h=(GEN)w[1]; if (h[2] < 3) return gerepile(av,tetpil,w);

    w = vstar(p,(GEN)w[3]); 
    MaVb = (w[0]*Ma) / w[1];
    pik=lift_intern(gpuigs(gmodulcp(eta,fa),MaVb));

    gamma=gmod(gmul(beta,(GEN)(vecbezout(pik,fa))[1]),fa);
    gamma=gdiv(polmodi(gmul(pc,gamma),pcc),pc);
    tetpil=avma; w=testd(p,fa,c,Da,eta,Ma,gamma);
    h=(GEN)w[1]; if (h[2] < 3) return gerepile(av,tetpil,w);

    delta=eltppm(fa,pc,gamma,gpuigs(p,r*Da));
    delta=gdiv(polmodi(gmul(pc,delta),pcc),pc);
    tetpil=avma; w=testd(p,fa,c,Da,eta,Ma,delta);
    h=(GEN)w[1]; if (h[2] < 3) return gerepile(av,tetpil,w);

    deg=lgef(delta)-3;
    for (j=0; j<=deg; j++)
      if (typ(delta[j+2]) != t_INT)
      {
        w = csrch(p,fa,gamma); tetpil=avma;
        return gerepile(av,tetpil,gcopy(w));
      }
    beta=gsub(beta,gmod(gmul(pik,delta),fa));
  }
}

/* USED TO Return [theta_1,theta_2,L_theta,M_theta] with theta non-primary */
/* Now return theta_2 */
GEN
setup(GEN p,GEN f,GEN theta,GEN nut, long *La, long *Ma)
{
  GEN t1,t2,v,dt,pv;
  long Lt,Mt,r,s,av=avma,tetpil,m,n,k, vf = varn(f);

  n=lgef(nut)-1; v=gun; pv=p;
  for (m=1; ; m++) /* compute mod p^(2^m) */
  {
    t1=gzero; pv = gsqr(pv);
    for (k=n; k>=2; k--)
    {
      t1 = gres(gadd(gmul(t1,theta),(GEN)nut[k]), f);
      dt = denom(content(t1));
      if (gcmp1(dt))
        t1 = polmodi(t1,pv);
      else
        t1 = gdiv(polmodi(gmul(t1,dt),mulii(dt,pv)),dt);
    }
    v = vstar(p, lift_intern(caradj0(gmodulcp(t1,f), vf)));
    if (v[0] < (v[1]<<m)) break;
  }
  Lt=v[0]; Mt=v[1]; cbezout(Lt,-Mt,&r,&s);
  if (r<=0) { long q = (-r) / Mt; q++; r += q*Mt; s += q*Lt; }
  t2 = lift_intern(gpuigs(gmodulcp(t1,f),r));
  p = gpuigs(p,s); tetpil=avma; *La=Lt; *Ma=Mt;
  return gerepile(av,tetpil,gdiv(t2,p));
}

static GEN
nilord(GEN p,GEN fx,long mf,GEN gx)
{
  long La,Ma,first=1,v=varn(fx);
  GEN h,res,alpha,chi,nu,eta,w,phi,pm,Dchi;

  if (DEBUGLEVEL>=3)
  {
    fprintferr(" On entre dans Nilord ");
    if (DEBUGLEVEL>=4)
    {
      fprintferr(" avec les parametres suivants \n ");
      fprintferr(" p="); bruterr(p,'g',-1);
      fprintferr(",  fx="); bruterr(fx,'g',-1);
      fprintferr(",  exposant=%ld,  gx= ",mf); bruterr(gx,'g',-1);
    }
    fprintferr("\n");
  }
  pm=gpuigs(p,mf+1); alpha=polx[v];
  chi=fx; nu=gx; Dchi=gpuigs(p,mf);

  for(;;)
  {
    if (gcmp0(Dchi)) alpha=gadd(alpha,gmul(p,polx[v]));
    else
    {
      if (first) first=0;
      else 
      {
        res=dedek(chi,mf,p,nu);
        if (res) return dbasis(p,fx,mf,alpha,res);
      }
      if (vstar(p,chi)[0] > 0)
      {
	alpha=gadd(alpha,gun);
	chi=gsubst(chi,v,gsub(polx[v],gun));
	nu=polmodi(gsubst(nu,v,gsub(polx[v],gun)), p);
      }
      eta=setup(p,chi,polx[v],nu, &La,&Ma);
      if (La>1)
	alpha=gadd(alpha,eleval(fx,eta,alpha));
      else
      {
	w=bsrch(p,chi,ggval(Dchi,p),eta,Ma);
	phi=eleval(fx,(GEN)w[2],alpha);
	if (gcmp1((GEN)w[1]))
	  return Decomp(p,fx,mf,phi,(GEN)w[3],(GEN)w[4]);
	alpha=gdiv(polmodi(gmul(pm,phi), mulii(pm,p)),pm);
      }
    }
    w=factcp(p,fx,alpha); chi=(GEN)w[1]; nu=(GEN)w[2];
    h = (GEN)w[3]; if (h[2] > 1) return Decomp(p,fx,mf,alpha,chi,nu);
    Dchi=modii(discsr(polmodi_keep(chi,pm)), pm);
    if (gcmp0(Dchi)) Dchi=discsr(chi);
  }
}

/* Returns [1,phi,chi,nu] if phi non-primary
 *         [2,phi,chi,nu] if D_phi = lcm (D_alpha, D_theta)
 */
static GEN
testb(GEN p,GEN fa,long Da,GEN theta,long Dt)
{
  long pp,Dat,t,v=varn(fa);
  GEN b,w,phi,h;

  Dat=clcm(Da,Dt)+3; b=cgetg(5,t_VEC);
  pp = p[2]; if (lgef(p)>3 || pp<0) pp=0;
  for (t=1; ; t++)
  {
    h = stopoly(t,pp,v);
    phi = gadd(theta,gmod(h,fa));
    w=factcp(p,fa,phi); h=(GEN)w[3];
    if (h[2] > 1)
    {
      b[1]=un; b[2]=(long)phi;
      b[3]=w[1]; b[4]=w[2]; return b;
    }
    if (lgef(w[2]) == Dat)
    {
      b[1]=deux; b[2]=(long)phi;
      b[3]=w[1]; b[4]=w[2]; return b;
    }
  }
}

/* Returns [1,phi,chi,nu] if phi non-primary
 *         [2,phi,chi,nu] if D_phi = lcm (D_alpha, D_theta)
 */
static GEN
testc(GEN p, GEN fa, long c, GEN alph2, long Ma, GEN thet2, long Mt)
{
  GEN b,pc,ppc,c1,c2,c3,psi,phi,w;
  long r,s,t,v=varn(fa);

  b=cgetg(5,t_VEC); pc=gpuigs(p,c); ppc=mulii(pc,p);

  cbezout(Ma,Mt,&r,&s); t=0;
  while (r<0) { r=r+Mt; t++; }
  while (s<0) { s=s+Ma; t++; }

  c1=lift_intern(gpuigs(gmodulcp(alph2,fa),s));
  c2=lift_intern(gpuigs(gmodulcp(thet2,fa),r));
  c3=gdiv(gmod(gmul(c1,c2),fa),gpuigs(p,t));
  psi=gdiv(polmodi(gmul(pc,c3),ppc),pc);
  phi=gadd(polx[v],psi);

  w=factcp(p,fa,phi);
  b[1] = (cmpis((GEN)w[3],1)==1)? un: deux;
  b[2]=(long)phi; b[3]=w[1]; b[4]=w[2];
  return b;
}

/* Returns
 *  [1,phi,chi,nu] if theta non-primary
 *  [2,phi,chi,nu] if D_phi > D_aplha or M_phi > M_alpha
 *  [3,phi,chi,nu] otherwise
 */
static GEN
testd(GEN p,GEN fa,long c,long Da,GEN alph2,long Ma,GEN theta)
{
  long Lt,Mt,Dt,av=avma,tetpil;
  GEN chi,nu,thet2,b,w;

  b=cgetg(5,t_VEC); w=factcp(p,fa,theta);
  chi=(GEN)w[1]; nu=(GEN)w[2]; Dt=lgef(nu)-3;
  if (cmpis((GEN)w[3],1)==1)
  {
    b[1]=un; b[2]=(long)theta; b[3]=(long)chi; b[4]=(long)nu;
  }
  else
  {
    if (Da < clcm(Da,Dt)) b = testb(p,fa,Da,theta,Dt);
    else
    {
      thet2=setup(p,fa,theta,nu, &Lt,&Mt);
      if (Ma < clcm(Ma,Mt)) b = testc(p,fa,c,alph2,Ma,thet2,Mt);
      else
      {
        b[1]=lstoi(3); b[2]=(long)theta; b[3]=(long)chi; b[4]=(long)nu;
      }
    }
  }
  tetpil=avma; return gerepile(av,tetpil,gcopy(b));
}

/* Factorize characteristic polynomial of beta mod p */
GEN
factcp(GEN p,GEN f,GEN beta)
{
  GEN chi,nu, b = cgetg(4,t_VEC);
  long l,tetpil, av = avma;

  f=caradj0(gmodulcp(beta,f),varn(f)); tetpil=avma;
  chi=gerepile(av,tetpil,lift(f)); av=avma; 

  nu=lift_intern(factmod(chi,p)); l=lg(nu[1])-1; tetpil=avma;
  nu=gerepile(av,tetpil,gcopy(gcoeff(nu,1,1)));

  b[1]=(long)chi; b[2]=(long)nu; b[3]=lstoi(l);
  return b;
}

/* evaluate h(a) mod f */
GEN
eleval(GEN f,GEN h,GEN a)
{
  long n,av,tetpil;
  GEN y;

  if (typ(h) != t_POL) return gcopy(h);
  av = tetpil = avma;
  n=lgef(h)-1; y=(GEN)h[n];
  for (n--; n>=2; n--)
  { 
    y = gadd(gmul(y,a),(GEN)h[n]);
    tetpil=avma; y = gmod(y,f);
  }
  return gerepile(av,tetpil,y);
}

/* Modular power of an elment */
static GEN
eltppm(GEN f,GEN pd,GEN theta,GEN k)
{
  GEN pdd,phi,psi,q;
  long av=avma,tetpil;

  pdd=gsqr(pd);
  phi=pd; psi=gmul(pd,theta); q=k;

  for(;;)
  {
    if (mod2(q))
    {
      phi=gmod(gdiv(gmul(phi,psi),pd),f);
      phi=polmodi(phi,pdd);
    }
    q=shifti(q,-1);
    if (!signe(q))
    {
      tetpil=avma;
      return gerepile(av,tetpil,gdiv(phi,pd));
    }
    psi=gmod(gdiv(gsqr(psi),pd),f);
    psi=polmodi(psi,pdd);
  }
}

/* Sylvester's matrix, mod p^m (assumes f1 monic) */
static GEN
sylpm(GEN f1,GEN f2,GEN pm)
{
  long n,deg,k,j,v=varn(f1);
  GEN a,h;

  n=lgef(f1)-3; a=cgetg(n+1,t_MAT);
  h = polmodi(gmod(f2,f1),pm);
  for (k=1; k<=n; k++)
    a[k]=lgetg(n+1,t_COL);
  for (j=1; j<=n; j++)
  {
    deg=lgef(h)-3;
    for (k=1; k<=deg+1; k++) coeff(a,k,j)=h[k+1];
    for (   ; k<=n; k++) coeff(a,k,j)=zero;

    if (j<n) h=polmodi(gmod(gmul(polx[v],h),f1),pm);
  }
  return hnfmodid(a,pm);
}

/* polynomial gcd mod p^m (assumes f1 monic) */
GEN
gcdpm(GEN f1,GEN f2,GEN pm)
{
  long n,c,v=varn(f1),av=avma,tetpil;
  GEN a,col;

  n=lgef(f1)-3; a=sylpm(f1,f2,pm);
  for (c=1; c<=n; c++)
    if (signe(resii(gcoeff(a,c,c),pm))) break;
  if (c > n) { avma=av; return zeropol(v); }

  col = gdiv((GEN)a[c], gcoeff(a,c,c)); tetpil=avma;
  return gerepile(av,tetpil, gtopolyrev(col,v));
}

/* reduced resultant mod p^m (assumes x monic) */
GEN
respm(GEN x,GEN y,GEN pm)
{
  long av=avma,tetpil;
  
  x = sylpm(x,y,pm); tetpil=avma;
  return gerepile(av,tetpil, icopy(gcoeff(x,1,1)));
}

/* Normalized integral basis */
static GEN
nbasis(GEN ibas,GEN pd)
{
  long n,j,k,m;
  GEN a;

  n=lg(ibas)-1; m=lgef(ibas[1])-2;
  a=cgetg(n+1,t_MAT);
  for (k=1; k<=n; k++)
  {
    m=lgef(ibas[k])-2; a[k]=lgetg(n+1,t_COL);
    for (j=1; j<=m; j++) coeff(a,j,k)=coeff(ibas,j+1,k);
    for (   ; j<=n; j++) coeff(a,j,k)=zero;
  }
  return gdiv(hnfmodid(a,pd), pd);
}

/* Pick best divisor of chi */
GEN
bestnu(GEN w)
{
  long r,j;
  GEN g,h;

  r=lg(w)-1; g=polun[0];
  for (j=1; j<=r; j++)
  {
    h=(GEN)w[j];
    if (lgef(h) > lgef(g)) g=h;
  }
  return lift_intern(g);
}

static long
clcm(long a,long b)
{
  long d,r,v1;

  d=a; r=b;
  for(;;)
  {
    if (!r) return (a*b)/d;
    v1=r; r=d%r; d=labs(v1);
  }
}

/*******************************************************************/
/*                                                                 */
/*                   BUCHMANN-LENSTRA ALGORITHM                    */
/*                                                                 */
/*******************************************************************/
static GEN lens(GEN nf,GEN p,GEN a);
static GEN two_elt(GEN nf,GEN p,GEN ideal);

/* Calcule une F_p base du p-radical de Z_K */
static GEN
pradical(GEN nf, GEN p, GEN idmodp, GEN *frobenius)
{
  long i,N=lgef(nf[1])-3;
  GEN p1,m,zmodp,unmodp,frob;

  zmodp=gmael(idmodp,1,2); unmodp=gmael(idmodp,1,1);
  frob = cgetg(N+1,t_MAT);
  for (i=1; i<=N; i++)
    frob[i] = (long) element_pow(nf,(GEN)idmodp[i],p);

  p1=p; while (cmpis(p1,N)<0) p1=mulii(p1,p);
  if (p1==p) m = frob;
  else
  {
    m=cgetg(N+1,t_MAT); 
    for (i=1; i<=N; i++)
      m[i]=(long)element_pow(nf,(GEN)idmodp[i],p1);
  }
  *frobenius=frob; return ker_spec(m,zmodp,unmodp);
}

static GEN
project(GEN algebre, GEN x, long k, long kbar)
{
  x = inverseimage(algebre,x);
  x += k; x[0] = evaltyp(t_COL) | evallg(kbar+1);
  return x;
}

/* Calcule le polynome minimal de alpha dans algebre (coeffs dans F_p) */
static GEN
pol_min(GEN alpha,GEN nf,GEN algebre,GEN algebre1,GEN idmodp)
{
  long av=avma,tetpil,i,N,k,kbar;
  GEN p1,zmodp,unmodp,puiss;

  zmodp=gmael(idmodp,1,2); unmodp=gmael(idmodp,1,1);
  N = lg(idmodp)-1; puiss=cgetg(N+2,t_MAT);
  kbar = lg(algebre1)-1; k = N-kbar;
  p1=alpha;
  for (i=2; i<=N+1; i++)
  {
    if (i>2) p1 = element_mul(nf,p1,alpha);
    puiss[i] = (long) project(algebre,p1,k,kbar);
  }
  puiss[1]=idmodp[1]; setlg(puiss[1],kbar+1);
  p1=ker_spec(puiss,zmodp,unmodp); p1=(GEN)p1[1];
  setlg(puiss[1],N+1); tetpil=avma;
  return gerepile(av,tetpil,gtopolyrev(p1,0));
}

/* Evalue le polynome pol en alpha,element de nf */
static GEN
eval_pol(GEN nf,GEN pol,GEN alpha,GEN algebre,GEN algebre1,GEN idmodp)
{
  long av=avma,tetpil,i,kbar,k, lx = lgef(pol)-1;
  GEN res, first = (GEN)idmodp[1];

  kbar = lg(algebre1)-1; k = lg(idmodp)-1-kbar;
  res=(GEN)idmodp[1]; res[1]=pol[lx];
  for (i=2; i<lx; i++)
  {
    res = element_mul(nf,alpha,res);
    res[1] = ladd((GEN)res[1],(GEN)pol[i]);
  }
  res = project(algebre,res,k,kbar);
  idmodp[1]=(long)first; tetpil=avma;
  return gerepile(av,tetpil,gmul(algebre1,res));
}

static GEN
kerlens2(GEN x, GEN p)
{
  long i,j,k,t,nbc,nbl,av,av1;
  GEN a,c,l,d,y,q;

  av=avma; a=gmul(x,gmodulsg(1,p));
  nbl=nbc=lg(x)-1;
  c=cgetg(nbl+1,t_VEC); for (i=1; i<=nbl; i++) c[i]=0;
  l=cgetg(nbc+1,t_VEC);
  d=cgetg(nbc+1,t_VEC);
  k=1; t=1;
  while (t<=nbl && k<=nbc)
  {
    for (j=1; j<k; j++)
      for (i=1; i<=nbl; i++)
	if (i!=l[j])
	  coeff(a,i,k)=lsub(gmul((GEN)d[j],gcoeff(a,i,k)),
	                    gmul(gcoeff(a,l[j],k),gcoeff(a,i,j)));
    t=1; while (t<=nbl && (c[t] || gcmp0(gcoeff(a,t,k)))) t++;
    if (t<=nbl) { d[k]=coeff(a,t,k); c[t]=k; l[k]=t; k++; }
  }
  if (k>nbc) err(bugparier,"kerlens2");
  y=cgetg(nbc+1,t_COL);
  y[1]=(k>1)?coeff(a,l[1],k):un;
  for (q=gun,j=2; j<k; j++)
  {
    q=gmul(q,(GEN)d[j-1]);
    y[j]=lmul(gcoeff(a,l[j],k),q);
  }
  if (k>1) y[k]=lneg(gmul(q,(GEN)d[k-1]));
  for (j=k+1; j<=nbc; j++) y[j]=zero;
  av1=avma; return gerepile(av,av1,lift(y));
}

static GEN
kerlens(GEN x, GEN pgen)
{
  long av = avma, i,j,k,t,nbc,nbl,p,q,*c,*l,*d,**a;
  GEN y;

  if (cmpis(pgen, MAXHALFULONG>>1) > 0)
    return kerlens2(x,pgen);
  /* ici p <= (MAXHALFULONG>>1) ==> long du C */
  p=itos(pgen); nbl=nbc=lg(x)-1;
  a=(long**)cgeti(nbc+1);
  for (j=1; j<=nbc; j++)
  {
    c=a[j]=cgeti(nbl+1);
    for (i=1; i<=nbl; i++) c[i]=smodis(gcoeff(x,i,j),p);
  }
  c=cgeti(nbl+1); l=cgeti(nbc+1); d=cgeti(nbc+1);
  for (i=1; i<=nbl; i++) c[i]=0;
  k=1; t=1;
  while (t<=nbl && k<=nbc)
  {
    for (j=1; j<k; j++)
      for (i=1; i<=nbl; i++)
	if (i!=l[j]) 
          a[k][i] = (d[j]*a[k][i] - a[j][i]*a[k][l[j]]) % p;
    t=1; while (t<=nbl && (c[t] || !a[k][t])) t++;
    if (t<=nbl) { d[k]=a[k][t]; c[t]=k; l[k++]=t; }
  }
  if (k>nbc) err(bugparier,"kerlens");
  avma=av; y=cgetg(nbc+1,t_COL);
  t=(k>1) ? a[k][l[1]]:1;
  y[1]=(t>0)? lstoi(t):lstoi(t+p);
  for (q=1,j=2; j<k; j++)
  {
    q = (q*d[j-1]) % p;
    t = (a[k][l[j]]*q) % p;
    y[j] = (t>0) ? lstoi(t) : lstoi(t+p);
  }
  if (k>1)
  {
    t = (q*d[k-1]) % p;
    y[k] = (t>0) ? lstoi(p-t) : lstoi(-t);
  }
  for (j=k+1; j<=nbc; j++) y[j]=zero;
  return y;
}

/* Calcule la constante de lenstra de l'ideal p.Z_K+a.Z_K ou a est un
vecteur sur la base d'entiers */
static GEN
lens(GEN nf, GEN p, GEN a)
{
  long av=avma,tetpil,N=lgef(nf[1])-3,j;
  GEN mat=cgetg(N+1,t_MAT);
  for (j=1; j<=N; j++) mat[j]=(long)element_mulid(nf,a,j);
  tetpil=avma; return gerepile(av,tetpil,kerlens(mat,p));
}

/* Recoit un ideal (mod p) et calcule une representation a deux
 elements (ideal non egal a Z_K) */
static GEN
two_elt(GEN nf, GEN p, GEN ideal)
{
  long av=avma,av1,tetpil,N=lgef(nf[1])-3,m,i;
  GEN beta,alpha,lambda,norme,pf;

  m=lg(ideal)-1;
  if (!m)
  {
    alpha=cgetg(N+1,t_COL); alpha[1]=(long)p;
    for (i=2; i<=N; i++) alpha[i]=zero;
    return alpha;
  }

  beta=gmodulcp(gmul((GEN)nf[7],lift(ideal)),(GEN)nf[1]);
  pf=gpuigs(p,N-m);
  for(i=1; ; i++)
  {
    alpha=(GEN)beta[i]; norme=gnorm(alpha);
    if (signe(modii(divii(norme,pf),p))) break;
    alpha=gadd(alpha,p); norme=gnorm(alpha);
    if (signe(modii(divii(norme,pf),p))) break;
    if (i==m)
    {
      lambda=cgeti(m+1); av1=avma;
      for(;;)
      {
	avma=av1;
	for (i=1; i<=m; i++)
	{
	  lambda[i] = mymyrand() >> (BITS_IN_RANDOM-3); /* in [0,7] */
	  if (lambda[i]>=2) lambda[i]=-1;
	}
	alpha=gmodulsg(0,(GEN)nf[1]);
	for (i=1; i<=m; i++) alpha=gadd(alpha,gmulsg(lambda[i],(GEN)beta[i]));
	norme=gnorm(alpha);
	if (signe(modii(divii(norme,pf),p))) break;
	else
	{
	  alpha=gadd(alpha,p); norme=gnorm(alpha);
	  if (signe(modii(divii(norme,pf),p))) break;
	}
      }
      break;
    }
  }
  alpha=algtobasis_intern(nf,lift_intern(alpha),gzero);
  alpha=gmul(gmodulsg(1,p),alpha);
  alpha=centerlift(alpha);
  if (!signe(modii(divii(subres(gmul((GEN)nf[7],alpha),(GEN)nf[1]),pf),p)))
    alpha[1]=ladd((GEN)alpha[1],p);
  tetpil=avma; return gerepile(av,tetpil,gcopy(alpha));
}

static GEN
apply_kummer(GEN nf,GEN f,GEN ex,GEN f1,GEN p,long N,long i,GEN *beta)
{
  GEN T,p1,p2, res = cgetg(6,t_VEC), pol = (GEN)f[i];
  long j, l = lgef(pol)-3;

  res[1]=(long)p; 
  res[3]=ex[i];
  res[4]=lstoi(l);
  if (l == N) /* inert */
  {
    if (beta) err(talker,"bugbeta in primedec");
    p1=cgetg(N+1,t_COL); 
    p2=cgetg(N+1,t_COL);
    res[2]=(long)p1; p1[1]=(long)p; 
    res[5]=(long)p2; p2[1]=un;
    for (j=2; j<=N; j++) p1[j]=p2[j]=zero;
  }
  else
  {
    T = (GEN) nf[1];
    if (ggval(subres(pol,T),p) > l) 
      pol[2] = laddii((GEN)pol[2],p);
    res[2] = (long) algtobasis_intern(nf,pol,gzero);

    pol=gdiv(T,(GEN)f1[i]);
    res[5] = (long) centerlift(algtobasis_intern(nf,pol,gzero));

    if (beta)
      if (*beta == NULL) *beta = pol;
      else *beta = gdiv(*beta,(GEN)f1[i]);
  }
  return res;
}

/* prime ideal decomposition of p sorted by increasing residual degree */
GEN
primedec(GEN nf, GEN p)
{
  long av=avma,tetpil,i,j,k,kbar,np,c,indice,N,lp,keepseed;
  GEN ex,f,ff,list,ip,elementh,h;
  GEN frob,algebre,algebre1,b,mat1,mat2,T,nfp;
  GEN alpha,beta,p1,p2,unmodp,zmodp,idmodp;

  if (DEBUGLEVEL>=3) timer2();
  nf=checknf(nf); T=(GEN)nf[1]; N=lgef(T)-3;
  keepseed=pari_randseed; pari_randseed=1;
  ff=factmod(T,p); ex=(GEN)ff[2]; ff=(GEN)ff[1];
  np=lg(ff); f=centerlift(ff); 
  if (DEBUGLEVEL>=6) msgtimer("factmod");

  if (signe(modii((GEN)nf[4],p))) /* p doesn't divide index */
  {
    list=cgetg(np,t_VEC);
    for (i=1; i<np; i++)
      list[i] = (long) apply_kummer(nf,f,ex,ff,p,N,i, NULL);
    if (DEBUGLEVEL>=6) msgtimer("simple primedec");
    p1=stoi(4); pari_randseed=keepseed; tetpil=avma;
    return gerepile(av,tetpil,vecsort(list,p1));
  }

  unmodp=gmodulsg(1,p); zmodp=gmodulsg(0,p);
  p1=(GEN)ff[1]; for (i=2; i<np; i++) p1=gmul(p1,(GEN)ff[i]);
  p1 = gdiv(gsub(gmul(lift(p1),lift(gdeuc(T,p1))), T),p);
  p1 = gmul(unmodp,p1); list=cgetg(N+1,t_VEC);
  indice=0; beta=NULL;
  for (i=1; i<np; i++)
    if (gcmp1((GEN)ex[i]) || !gdivise(p1,(GEN)ff[i]))
      list[++indice] = (long) apply_kummer(nf,f,ex,ff,p,N,i,&beta);
  if (DEBUGLEVEL>=3) msgtimer("unramified factors");

  idmodp = idmat_intern(N,unmodp,zmodp);
  ip = pradical(nf,p,idmodp,&frob);
  if (DEBUGLEVEL>=3) msgtimer("pradical");

  if (indice)
  {
    beta = algtobasis_intern(nf,beta,zmodp);
    lp=lg(ip)-1; p1=cgetg(2*lp+N+1,t_MAT);
    for (i=1; i<=N; i++) p1[i]=(long)element_mulid_intern(nf,beta,i,zmodp);
    beta=lift(beta);
    for (   ; i<=N+lp; i++)
    {
      p2 = (GEN) ip[i-N];
      p1[i+lp] = (long) p2;
      p2 = gdiv(element_mul(nf,lift(p2),beta),p);
      p1[i] = lmul(p2,unmodp);
    }
    ip=image(p1);
    if (lg(ip)>N) err(talker,"bug pradical in primedec");
  }
  nfp = cgetg(N+1,t_COL); nfp[1]=(long)p; coeff(frob,1,1)=(long)zmodp;
  for (i=2; i<=N; i++)
  {
    nfp[i]=zero; coeff(frob,i,i) = lsub(gcoeff(frob,i,i),unmodp);
  }

  h=cgetg(N+1,t_VEC); h[1]=(long)ip;
  for (c=1; c; c--)
  {
    elementh=(GEN)h[c]; k=lg(elementh)-1; kbar=N-k;
    p1 = concatsp(elementh,(GEN)idmodp[1]);
    algebre = suppl_intern(p1,idmodp);
    algebre1 = cgetg(kbar+1,t_MAT);
    for (i=1; i<=kbar; i++) algebre1[i]=algebre[i+k];
    /* frob = modified Frobenius: x -> x^p - x mod p */
    b = gmul(frob,algebre1);
    for (i=1;i<=kbar;i++)
      b[i] = (long) project(algebre,(GEN) b[i],k,kbar);
    mat1=ker(b);
    if (lg(mat1)>2)
    {
      mat2=cgetg(k+N+1,t_MAT);
      for (i=1; i<=k; i++) mat2[i]=elementh[i];
      alpha=gmul(algebre1,(GEN)mat1[2]);
      p1=pol_min(alpha,nf,algebre,algebre1,idmodp);
      p1=(GEN)factmod(p1,p)[1];
      for (i=1; i<lg(p1); i++)
      {
	beta=eval_pol(nf,(GEN)p1[i],alpha,algebre,algebre1,idmodp);
	for (j=1; j<=N; j++)
	  mat2[k+j]=(long)element_mulid_intern(nf,beta,j,zmodp);
	h[c] = (long) image(mat2); c++;
      }
    }
    else
    { 
      long av1;
      indice++; p1=(GEN)(list[indice]=lgetg(6,t_VEC));
      p1[1]=(long)p; p1[4]=lstoi(kbar);
      p1[2]=(long)two_elt(nf,p,elementh);
      p1[5]=(long)lens(nf,p,(GEN)p1[2]);
      av1=avma;
      i = int_elt_val(nf,nfp,p,(GEN)p1[5],0,N,N);
      avma=av1;
      p1[3]=lstoi(i);
    }
    if (DEBUGLEVEL>=3) msgtimer("h[%ld]",c);
  }
  setlg(list,indice+1);
  p1=stoi(4); pari_randseed=keepseed; tetpil=avma;
  return gerepile(av,tetpil,vecsort(list,p1));
}

/* recoit un ideal ix et un ideal premier vp dans le format
donne par primedec et calcule la valuation de ix en vp */
long
idealval(GEN nf, GEN ix, GEN vp)
{
  long N,v,vd,w,av=avma,e,i,j, tx = typ(ix);
  GEN mat,x,d,bp,p,p1,r,denx;

  nf=checknf(nf); checkprimeid(vp);
  if (is_extscalar_t(tx) || tx==t_COL) return element_val(nf,ix,vp);

  N=lgef(nf[1])-3; p=(GEN)vp[1];
  x = (typ(ix)==t_VEC && lg(ix)==3) ? (GEN) ix[1] : ix;
  checkid(x,N);

  denx=denom(x);
  if (!gcmp1(denx)) x=gmul(denx,x);
  if (lg(x) != N+1) x=idealmul(nf,x,idmat(N));
  for (d=gun,i=1; i<=N; i++) d=mulii(d,gcoeff(x,i,i));
  v=ggval(d,p); vd=ggval(denx,p); e=itos((GEN)vp[3]);
  if (!v) return -vd*e;

  bp=(GEN)vp[5]; mat=cgetg(N+1,t_MAT);
  for (i=1; i<=N; i++)
    mat[i]=(long)element_mulh(nf,i,N,(GEN)x[i],bp);
  for (w=0; w<v; w++)
  {
    if (w)
      for (i=1; i<=N; i++)
	mat[i]=(long)element_muli(nf,(GEN)mat[i],bp);
    for (j=N; j; j--)
      for (i=N; i; i--)
      {
	p1=dvmdii(gcoeff(mat,i,j),p,&r);
	if (signe(r)) { avma=av; return w-vd*e; }
	coeff(mat,i,j)=(long)p1;
      }
  }
  avma=av; return w-vd*e;
}

/*                        ROUND 2 relatif
 *
 *  Entree:   nf = corps de base K dans le format initalg.
 *    x polynome unitaire a coefficients dans Z_K de deg n
 *    definissant une extension relative L=K(theta);
 *    La variable de x doit etre de numero strictement
 *    inferieur a celle de nf[1].
 *  Sortie:   retourne une pseudo-base [A,I] de Z_L, ou A est une matrice
 *    nxn a coefficients dans nf[1] sous forme HNF et I un vecteur
 *    d'ideaux a n composantes
 */
static GEN rnfordmax(GEN nf, GEN pol, GEN pr, long sep, GEN unnf, GEN zeronf, GEN id, GEN psid, GEN powbasis);

/* given MODULES x and y by their pseudo-bases in HNF, gives a
 * pseudo-basis of the module generated by x and y. A usage interne,
 * pas de verifications, mais gestion de pile.
 */
static GEN
rnfjoinmodules(GEN nf, GEN x, GEN y)
{
  long i,lx,ly;
  GEN p1,p2,z,Hx,Hy,Ix,Iy;

  Hx=(GEN)x[1]; lx=lg(Hx); Ix=(GEN)x[2];
  Hy=(GEN)y[1]; ly=lg(Hy); Iy=(GEN)y[2];
  i = lx+ly-1;
  z = (GEN)gpmalloc(sizeof(long*)*(3+2*i));
  *z = evaltyp(t_VEC)|evallg(3);
  p1 =  z+3; z[1]=(long)p1; *p1 = evaltyp(t_MAT)|evallg(i);
  p2 = p1+i; z[2]=(long)p2; *p2 = evaltyp(t_VEC)|evallg(i);

  for (i=1; i<lx; i++) { p1[i]=Hx[i]; p2[i]=Ix[i]; }
  for (   ; i<lx+ly-1; i++) { p1[i]=Hy[i-lx+1]; p2[i]=Iy[i-lx+1]; }
  x = nfhermite(nf,z); free(z); return x;
}

static GEN
rnfround2all(GEN nf, GEN pol, long all)
{
  long av=avma,tetpil,i,j,n,N,nbidp,ipr,vpol,cpt,*ep;
  GEN p1,p2,p3,p4,polnf,list,unnf,zeronf,id,A,I,W,pseudo,y,discpol;
  GEN psid,powbasis,d,D;

  nf=checknf(nf); polnf=(GEN)nf[1]; vpol=varn(pol);
  if (typ(pol)!=t_POL || vpol>=varn(polnf))
    err(talker,"incorrect polynomial in relativeround2");
  N=lgef(polnf)-3; n=lgef(pol)-3; discpol=discsr(pol);
  list=idealfactor(nf,discpol); ep=(long*)list[2]; list=(GEN)list[1];
  nbidp=lg(list)-1; for(i=1;i<=nbidp;i++) ep[i]=itos((GEN)ep[i]);
  if (DEBUGLEVEL>1)
  {
    fprintferr(" Ideaux a considerer :\n");
    for (i=1; i<=nbidp; i++)
      if (ep[i]>1) fprintferr("%Z^%ld\n",list[i],ep[i]); 
    flusherr();
  }
  id=idmat(N); unnf=gscalcol_i(gun,N); zeronf=gscalcol_i(gzero,N);
  A=idmat_intern(n,unnf,zeronf);
  I=cgetg(n+1,t_VEC); for (i=1; i<=n; i++) I[i]=(long)id;
  pseudo=cgetg(3,t_VEC); pseudo[1]=(long)A; pseudo[2]=(long)I;

  psid=gcopy(pseudo);
  powbasis=cgetg(n+1,t_VEC); powbasis[1]=(long)polun[vpol];
  for (i=2; i<=n; i++) powbasis[i]=lmul((GEN)powbasis[i-1],polx[vpol]);
  cpt=0;
  for (ipr=1; ipr<=nbidp; ipr++)
    if (ep[ipr] != 1)
    {
      y=rnfordmax(nf,pol,(GEN)list[ipr],ep[ipr],unnf,zeronf,id,psid,powbasis);
      if (cpt) pseudo = rnfjoinmodules(nf,pseudo,y); else { cpt=1; pseudo=y; }
    }
  W=gmodulcp(gmul(powbasis,basistoalg(nf,(GEN)pseudo[1])),pol);
  I=(GEN)pseudo[2];
  p2=cgetg(n+1,t_MAT); for (j=1; j<=n; j++) p2[j]=lgetg(n+1,t_COL);
  for (j=1; j<=n; j++) 
    for (i=j+1; i<=n; i++)
    {
      coeff(p2,i,j)=ltrace(gmul((GEN)W[i],(GEN)W[j]));
      coeff(p2,j,i)=coeff(p2,i,j);
    }
  for (i=1; i<=n; i++) coeff(p2,i,i)=ltrace(gsqr((GEN)W[i]));

  i=1; while (i<=n && gegal((GEN)I[i],id)) i++;
  if (i>n) D=id;
  else
  {
    D=(GEN)I[i];
    for (i++; i<=n; i++)
      if (!gegal((GEN)I[i],id)) D = idealmul(nf,D,(GEN)I[i]);
    D = idealpow(nf,D,gdeux);
  }
  d=algtobasis_intern(nf,det(p2),gzero);
  p4=gun; p3=auxdecomp(content(d),0);
  for (i=1; i<lg(p3[1]); i++)
    p4 = gmul(p4, gpuigs(gcoeff(p3,i,1), itos(gcoeff(p3,i,2))>>1));
  p4 = gsqr(p4); tetpil=avma;
  if (all)
  {
    p1=cgetg(5,t_VEC);
    p1[1]=lcopy((GEN)pseudo[1]); p1[2]=lcopy(I);
    p1[3]=(long)idealmul(nf,D,d); p1[4]=ldiv(d,p4);
  }
  else
  {
    p1=cgetg(3,t_VEC);
    p1[1]=(long)idealmul(nf,D,d); p1[2]=ldiv(d,p4);
  }
  return gerepile(av,tetpil,p1);
}

GEN
rnfpseudobasis(GEN nf, GEN pol)
{
  return rnfround2all(nf,pol,1);
}

GEN
rnfdiscf(GEN nf, GEN pol)
{
  return rnfround2all(nf,pol,0);
}

/* a usage interne, pas de gestion de pile */
GEN
nfreducemodpr(GEN nf, GEN x, GEN prhall)
{
  long N=lg(x)-1,i,v;
  GEN p,prh,den;

  for (i=1; i<=N; i++)
    if (typ(x[i]) == t_INTMOD) { x=lift(x); break; }
  prh=(GEN)prhall[1]; p=gcoeff(prh,1,1);
  if (gcmp1(p)) err(talker,"bug in reducemodpr");
  den=denom(x);
  if (!gcmp1(den))
  {
    v=ggval(den,p);
    if (v) x=element_mul(nf,x,element_pow(nf,(GEN)prhall[2],stoi(v)));
  }
  x=gmod(x,p);
  for (i=N; i>=1; i--)
    if (gcmp1(gcoeff(prh,i,i))) x=gsub(x,gmul((GEN)x[i],(GEN)prh[i]));
  return gmul(gmodulsg(1,p),x);
}

/* a usage interne, pas de gestion de pile : x et y sont des vecteurs dont
 * les coefficients sont les composantes sur nf[7]; avec reduction mod pr sauf
 * si prhall=gzero
 */
static GEN
rnfelement_mulmod(GEN nf, GEN multab, GEN zeronf, GEN unnf, GEN x, GEN y, GEN prhall)
{
  long i,j,k,n;
  GEN p1,p2,z,s;

  n=lg(x)-1; x=lift(x); y=lift(y); z=cgetg(n+1,t_COL);
  for (k=1; k<=n; k++)
  {
    s=zeronf;
    for (i=1; i<=n; i++)
      for (j=1; j<=n; j++)
      {
	p2=gcoeff(multab,k,(i-1)*n+j);
	if (!gcmp0(p2))
	{
	  p1=element_mul(nf,(GEN)x[i],(GEN)y[j]);
	  if (gegal(p2,unnf)) s=gadd(s,p1);
	  else s=gadd(s,element_mul(nf,p1,p2));
	}
      }
    if (!gcmp0(prhall)) z[k]=(long)nfreducemodpr(nf,s,prhall);
    else z[k]=(long)s;
  }
  return z;
}

/* a usage interne, pas de gestion de pile : x est un vecteur dont
 * les coefficients sont les composantes sur nf[7]
 */
static GEN
rnfelement_sqrmod(GEN nf, GEN multab, GEN zeronf, GEN unnf, GEN x, GEN prhall)
{
  long i,j,k,n;
  GEN p1,p2,z,s;

  n=lg(x)-1; x=lift(x);
  z=cgetg(n+1,t_COL);
  for (k=1; k<=n; k++)
  {
    s=zeronf;
    for (i=1; i<=n; i++)
    {
      if (!gcmp0(p2=gcoeff(multab,k,(i-1)*n+i)))
      {
	p1=element_sqr(nf,(GEN)x[i]);
	if (gegal(p2,unnf)) s=gadd(s,p1);
	else s=gadd(s,element_mul(nf,p1,p2));
      }
    }
    for (i=1; i<=n; i++)
      for (j=i+1; j<=n; j++)
      {
	p2=gcoeff(multab,k,(i-1)*n+j);
	if (!gcmp0(p2))
	{
	  p1=gmul2n(element_mul(nf,(GEN)x[i],(GEN)x[j]),1);
	  if (gegal(p2,unnf)) s=gadd(s,p1);
	  else s=gadd(s,element_mul(nf,p1,p2));
	}
      }
    if (!gcmp0(prhall)) z[k]=(long)nfreducemodpr(nf,s,prhall);
    else z[k]=(long)s;
  }
  return z;
}

/* Calcule x^k mod pr dans l'extension . */
static GEN
rnfelement_powmod(GEN nf, GEN multab, GEN zeronf, GEN unnf, GEN x, GEN k, GEN prhall)
{
  long i,n,av=avma,tetpil;
  GEN k1,y,z;

  n=lg(x)-1; k1=k; z=x; y=cgetg(n+1,t_COL);
  for (i=2; i<=n; i++) y[i]=(long)zeronf; y[1]=(long)unnf;
  for(;;)
  {
    if (mpodd(k1)) y=rnfelement_mulmod(nf,multab,zeronf,unnf,z,y,prhall);
    k1=shifti(k1,-1); if (!signe(k1)) break;
    z=rnfelement_sqrmod(nf,multab,zeronf,unnf,z,prhall);
  }
  tetpil=avma; return gerepile(av,tetpil,gcopy(y));
}

static GEN
rnfordmax(GEN nf, GEN pol, GEN pr, long sep, GEN unnf, GEN zeronf, GEN id, GEN psid, GEN powbasis)
{
  long av=avma,tetpil,av1,lim,i,j,k,n,v1,v2,vpol,m,cmpt;
  GEN polnf,p,q,q1,prh,prhall,A,Aa,Aaa,A1,den,I,R,p1,p2,p3,multab,Aainv;
  GEN pip,baseIp,baseOp,alpha,matprod,alphainv,matC,matG,matV,vecpro,matH;
  GEN neworder,matId,H,Hid,alphalistinv,epr,betae,alphalist;

  polnf=(GEN)nf[1]; n=lgef(pol)-3; vpol=varn(pol);
  p=(GEN)pr[1]; q=gpui(p,(GEN)pr[4],0); pip=(GEN)pr[2];
  q1=q; while (cmpis(q1,n)<0) q1=mulii(q1,q);
  prh=prime_to_ideal(nf,pr);
  epr=(GEN)pr[3];
  betae=gdiv(element_pow(nf,(GEN)pr[5],epr),gpui(p,addis(epr,-1),0));
  p1=cgetg(2,t_MAT); p1[1]=(long)betae;
  p1=idealadd(nf,gmul(p,id),idealmul(nf,p1,id));
  prhall=cgetg(3,t_VEC); prhall[1]=(long)prh;
  prhall[2]=idealaddtoone(nf,pr,p1)[2];
  /* i.e. an a = 1 mod pr, a = 0 mod q^{e_q} for all other primes q above p */

  A=(GEN)psid[1]; I=(GEN)psid[2]; matId=(GEN)psid[1];
  if (DEBUGLEVEL>1) { fprintferr(" Ideal traite : "); outerr(pr); }
  av1=avma; lim=(bot+av1)>>1;
  for(cmpt=1; ; cmpt++)
  {
    if (DEBUGLEVEL>1)
    {
      if (cmpt>1) fprintferr("    %ld eme passe \n",cmpt);
      else fprintferr("    1 ere passe \n");
      flusherr();
    }
    alphalist=cgetg(n+1,t_VEC); alphalistinv=cgetg(n+1,t_VEC);
    for (i=1; i<=n; i++)
    {
      if (gegal((GEN)I[i],id)) alphalist[i]=alphalistinv[i]=(long)unnf;
      else
      {
	den=denom((GEN)I[i]); p1=gcmp1(den)? (GEN)I[i]:gmul(den,(GEN)I[i]);
	p1=gdiv(ideal_two_elt(nf,p1),den);
	v1=gcmp0((GEN)p1[1])? EXP220
                            : element_val(nf,p2=gmul((GEN)p1[1],unnf),pr);
	v2=gcmp0((GEN)p1[2])? EXP220:
                              element_val(nf,(GEN)p1[2],pr);
	if (v1>v2) p2=(GEN)p1[2];
	alphalist[i]=(long)p2; alphalistinv[i]=(long)element_inv(nf,p2);
      }
    }
    A1=cgetg(n+1,t_MAT);
    for (j=1; j<=n; j++)
    {
      p1=cgetg(n+1,t_COL); A1[j]=(long)p1;
      for (i=1; i<=n; i++)
	p1[i]=(long)element_mul(nf,gcoeff(A,i,j),(GEN)alphalist[j]);
    }
    Aa=basistoalg(nf,A1); Aainv=ginv(Aa);
    Aaa=gmodulcp(gmul(powbasis,Aa),pol);
    multab=cgetg(n*n+1,t_MAT);
    for (j=1; j<=n*n; j++) multab[j]=lgetg(n+1,t_COL);
    for (i=1; i<=n; i++) for (j=i; j<=n; j++)
    {
      long tp;
      p1=gmul((GEN)Aaa[i],(GEN)Aaa[j]); p2=cgetg(n+1,t_COL);
      tp=typ(p1);

      if (tp==t_POLMOD && varn(p1[1])==vpol) { p1=(GEN)p1[2]; tp=typ(p1); }
      if (gcmp0(p1) || is_scalar_t(tp) || (tp==t_POL && varn(p1)>vpol))
      { 
	p2[1]=(long)p1;
	for (k=2; k<=n; k++) p2[k]=(long)gmodulsg(0,polnf);
      }
      else for (k=1; k<=n; k++) p2[k]=(long)truecoeff(p1,k-1);
      p3=algtobasis(nf,gmul(Aainv,p2));
      for (k=1; k<=n; k++)
      { 
	coeff(multab,k,(i-1)*n+j)=(long)p3[k];
	coeff(multab,k,(j-1)*n+i)=(long)p3[k];
      }
    }
    R=cgetg(n+1,t_MAT);
    for (j=1; j<=n; j++)
      R[j] = (long) rnfelement_powmod(nf,multab,zeronf,unnf,
                                      (GEN) matId[j],q1,prhall);
    baseIp = nfker(nf,R,prhall);
    baseOp = nfsuppl(nf,baseIp,n,prhall);
    alpha=cgetg(n+1,t_MAT);
    for (j=1; j<lg(baseIp); j++) alpha[j]=(long)lift((GEN)baseOp[j]);
    for (   ; j<=n; j++)
    {
      p1=cgetg(n+1,t_COL); alpha[j]=(long)p1;
      for (i=1; i<=n; i++)
	p1[i]=(long)element_mul(nf,pip,lift(gcoeff(baseOp,i,j)));
    }
    matprod=cgetg(n+1,t_MAT);
    for (j=1; j<=n; j++)
    {
      p1=cgetg(n+1,t_COL); matprod[j]=(long)p1;
      for (i=1; i<=n; i++)
	p1[i] = (long) rnfelement_mulmod(nf,multab,zeronf,unnf,
	                                 (GEN)matId[j],(GEN)alpha[i],gzero);
    }
    p1=basistoalg(nf,alpha); alphainv=ginv(p1);
    matC=cgetg(n+1,t_MAT);
    for (j=1; j<=n; j++)
    {
      p1=cgetg(n*n+1,t_COL); matC[j]=(long)p1;
      for (i=1; i<=n; i++)
      {
	p2=gmul(alphainv,basistoalg(nf,gcoeff(matprod,i,j)));
	for (k=1; k<=n; k++)
	  p1[(i-1)*n+k]=(long)nfreducemodpr(nf,algtobasis(nf,(GEN)p2[k]),prhall);
      }
    }
    matG=nfker(nf,matC,prhall); m=lg(matG)-1;
    matV=cgetg(n+m+1,t_MAT);
    for (j=1; j<=m; j++) matV[j]=(long)lift((GEN)matG[j]);
    for (j=1; j<=n; j++)
    {
      p1=cgetg(n+1,t_COL); matV[j+m]=(long)p1;
      for (k=1; k<=n; k++) matV[j+m]=(long)matId[j];
    }
    vecpro=cgetg(3,t_VEC); vecpro[1]=(long)matV;
    p1=cgetg(n+m+1,t_VEC); vecpro[2]=(long)p1;
    p2 = idealinv(nf,prh);
    for (i=1; i<=m; i++) p1[i]=(long)p2;
    for (   ; i<=m+n; i++)
      p1[i]=(long)idealmul(nf,(GEN)I[i-m],(GEN)alphalistinv[i-m]);
    matH=nfhermite(nf,vecpro);
    p1=algtobasis(nf,gmul(basistoalg(nf,A1),basistoalg(nf,(GEN)matH[1])));
    p2=(GEN)matH[2]; 
    
    tetpil=avma; neworder=cgetg(3,t_VEC);
    H=cgetg(n+1,t_MAT); Hid=cgetg(n+1,t_VEC);
    for (j=1; j<=n; j++)
    {
      p3=cgetg(n+1,t_COL); H[j]=(long)p3;
      for (i=1; i<=n; i++)
	p3[i]=(long)element_mul(nf,gcoeff(p1,i,j),(GEN)alphalistinv[j]);
      Hid[j]=(long)idealmul(nf,(GEN)p2[j],(GEN)alphalist[j]);
    }
    if (DEBUGLEVEL>3)
      { fprintferr(" Nouvel ordre :\n"); outerr((GEN)H); outerr((GEN)Hid); }

    for(i=1; i<=n; i++)
    {
      if (sep>2 && !gegal((GEN)I[i],(GEN)Hid[i])) break;
      if (sep==2 || i==n)
      {
	neworder[1]=(long)H; neworder[2]=(long)Hid;
	return gerepile(av,tetpil,neworder);
      }
    }
    A=H; I=Hid;
    if (low_stack(lim, (av1+bot)>>1))
    {
      GEN *gptr[2];
      if(DEBUGMEM>1) err(warnmem,"rnfordmax");
      gptr[0]=&A; gptr[1]=&I;
      gerepilemany(av1,gptr,2);
    }
  }
}

/* given bnf as output by buchinit 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 order)
{
  long av=avma,tetpil,j,N,n;
  GEN p1,id,Az,Iz,nf,A,I;

  checkbnf(bnf);
  if (typ(order)!=t_VEC || lg(order)<3)
    err(talker,"not a pseudo-basis in nfsimplifybasis");
  A=(GEN)order[1]; I=(GEN)order[2]; n=lg(A)-1; nf=(GEN)bnf[7];
  N=lgef(nf[1])-3; id=idmat(N); Iz=cgetg(n+1,t_VEC); Az=cgetg(n+1,t_MAT);
  for (j=1; j<=n; j++)
  {
    if (gegal((GEN)I[j],id)) { Iz[j]=(long)id; Az[j]=A[j]; }
    else
    {
      p1=content((GEN)I[j]);
      if (!gcmp1(p1))
      {
	Iz[j]=(long)gdiv((GEN)I[j],p1); Az[j]=lmul((GEN)A[j],p1);
      }
      else Az[j]=A[j];
      if (!gegal((GEN)Iz[j],id))
      {
	p1=isprincipalgen(bnf,(GEN)Iz[j]);
	if (gcmp0((GEN)p1[1]))
	{
	  p1=(GEN)p1[2]; Iz[j]=(long)id;
	  Az[j]=(long)element_mulvec(nf,p1,(GEN)Az[j]);
	}
      }
    }
  }
  tetpil=avma; p1=cgetg(lg(order),t_VEC); p1[1]=lcopy(Az); p1[2]=lcopy(Iz);
  for (j=3; j<lg(order); j++) p1[j]=lcopy((GEN)order[j]);
  return gerepile(av,tetpil,p1);
}

GEN
rnfdet2(GEN nf, GEN A, GEN I)
{
  long av,tetpil,i;
  GEN p1;

  nf=checknf(nf); av = tetpil = avma;
  p1=idealhermite(nf,det(matbasistoalg(nf,A)));
  for(i=1;i<lg(I);i++) { tetpil=avma; p1=idealmul(nf,p1,(GEN)I[i]); }
  tetpil=avma; return gerepile(av,tetpil,p1);
}

GEN
rnfdet(GEN nf, GEN order)
{
  if (typ(order)!=t_VEC || lg(order)<3)
    err(talker,"not a pseudo-matrix in rnfdet");
  return rnfdet2(nf,(GEN)order[1],(GEN)order[2]);
}

GEN
rnfdet0(GEN nf, GEN x, GEN y)
{
  return (gcmp0(y))? rnfdet(nf,x) : rnfdet2(nf,x,y);
}

/* given a pseudo-basis of an order in HNF [A,I] (or [A,I,D,d] it does
 * not matter), gives an nxn matrix (not in HNF) of a pseudo-basis and
 * an ideal vector [id,id,...,id,I] such that order=nf[7]^(n-1)xI.
 * Since it uses the approximation theorem, can be long.
 */
GEN
rnfsteinitz(GEN nf, GEN order)
{
  long av=avma,tetpil,N,j,n;
  GEN id,A,I,p1,p2,a,b;

  nf=checknf(nf);
  N=lgef(nf[1])-3; id=idmat(N);
  if (typ(order)==t_POL) order=rnfpseudobasis(nf,order);
  if (typ(order)!=t_VEC || lg(order)<3)
    err(talker,"not a pseudo-matrix in rnfsteinitz");
  A=gcopy((GEN)order[1]); I=gcopy((GEN)order[2]); n=lg(A)-1;
  for (j=1; j<=n-1; j++)
  {
    a=(GEN)I[j];
    if (!gegal(a,id))
    {
      b=(GEN)I[j+1];
      if (gegal(b,id))
      {
	p1=(GEN)A[j]; A[j]=A[j+1]; A[j+1]=lneg(p1);
	I[j]=(long)b; I[j+1]=(long)a;
      }
      else
      {
	p2=nfidealdet1(nf,a,b);
	p1=gadd(element_mulvec(nf,(GEN)p2[1],(GEN)A[j]),
		element_mulvec(nf,(GEN)p2[2],(GEN)A[j+1]));
	A[j+1]= (long) gadd(element_mulvec(nf,(GEN)p2[3],(GEN)A[j]),
	                    element_mulvec(nf,(GEN)p2[4],(GEN)A[j+1]));
	A[j]=(long)p1;
	I[j]=(long)id; I[j+1]=(long)idealmul(nf,a,b);
	p1=content((GEN)I[j+1]);
	if (!gcmp1(p1))
	{ 
	  I[j+1] = (long) gdiv((GEN)I[j+1],p1); 
	  A[j+1]=lmul(p1,(GEN)A[j+1]);
	}
      }
    }
  }
  tetpil=avma; p1=cgetg(lg(order),t_VEC);
  p1[1]=lcopy(A); p1[2]=lcopy(I);
  for (j=3; j<lg(order); j++) p1[j]=lcopy((GEN)order[j]);
  return gerepile(av,tetpil,p1);
}

/* Given bnf as output by buchinit and either an order as output by
 * rnfpseudobasis or a polynomial, and outputs a basis if it is free,
 * an n+1-generating set if it is not
 */
GEN
rnfbasis(GEN bnf, GEN order)
{
  long av=avma,tetpil,j,N,n;
  GEN nf,A,I,classe,p1,p2,id;

  checkbnf(bnf);
  nf=(GEN)bnf[7]; N=lgef(nf[1])-3; id=idmat(N);
  if (typ(order)==t_POL) order=rnfpseudobasis(nf,order);
  if (typ(order)!=t_VEC || lg(order)<3)
    err(talker,"not a pseudo-matrix in rnfbasis");
  A=(GEN)order[1]; I=(GEN)order[2]; n=lg(A)-1;
  j=1; while (j<=(n-1) && gegal((GEN)I[j],id)) j++;
  if (j<n) order=rnfsteinitz(nf,order);
  A=(GEN)order[1]; I=(GEN)order[2]; classe=(GEN)I[n];
  p1=isprincipalgen(bnf,classe);
  if (gcmp0((GEN)p1[1]))
  {
    tetpil=avma; p2=cgetg(n+1,t_MAT);
    for (j=1; j<=n-1; j++) p2[j]=lcopy((GEN)A[j]);
    p2[n]=(long)element_mulvec(nf,(GEN)p1[2],(GEN)A[n]);
  }
  else
  {
    p1=ideal_two_elt(nf,classe);
    tetpil=avma; p2=cgetg(n+2,t_MAT);
    for (j=1; j<=n-1; j++) p2[j]=lcopy((GEN)A[j]);
    p2[n]=lmul((GEN)p1[1],(GEN)A[n]);
    p2[n+1]=(long)element_mulvec(nf,(GEN)p1[2],(GEN)A[n]);
  }
  return gerepile(av,tetpil,p2);
}

/* Given bnf as output by buchinit and either an order as output by
 * rnfpseudobasis or a polynomial, and outputs a basis (not pseudo)
 * in Hermite Normal Form if it exists, zero if not
 */
GEN
rnfhermitebasis(GEN bnf, GEN order)
{
  long av=avma,tetpil,j,N,n;
  GEN nf,A,I,p1,id;

  checkbnf(bnf); nf=(GEN)bnf[7];
  N=lgef(nf[1])-3; id=idmat(N);
  if (typ(order)==t_POL)
  {
    order=rnfpseudobasis(nf,order);
    A=(GEN)order[1];
  }
  else
  {
    if (typ(order)!=t_VEC || lg(order)<3)
      err(talker,"not a pseudo-matrix in rnfbasis");
    A=gcopy((GEN)order[1]);
  }
  I=(GEN)order[2]; n=lg(A)-1;
  for (j=1; j<=n; j++)
  {
    if (!gegal((GEN)I[j],id))
    {
      p1=isprincipalgen(bnf,(GEN)I[j]);
      if (gcmp0((GEN)p1[1]))
	A[j]=(long)element_mulvec(nf,(GEN)p1[2],(GEN)A[j]);
      else { avma=av; return gzero; }
    }
  }
  tetpil=avma; return gerepile(av,tetpil,gcopy(A));
}

long
rnfisfree(GEN bnf, GEN order)
{
  long av=avma,n,N,j;
  GEN nf,p1,id,I;

  checkbnf(bnf);
  if (gcmp1(gmael3(bnf,8,1,1))) return 1;

  nf=(GEN)bnf[7]; N=lgef(nf[1])-3; id=idmat(N);
  if (typ(order)==t_POL) order=rnfpseudobasis(nf,order);
  if (typ(order)!=t_VEC || lg(order)<3)
    err(talker,"not a pseudo-matrix in rnfisfree");

  I=(GEN)order[2]; n=lg(I)-1;
  j=1; while (j<=n && gegal((GEN)I[j],id)) j++;
  if (j>n) { avma=av; return 1; }

  p1=(GEN)I[j];
  for (j++; j<=n; j++)
    if (!gegal((GEN)I[j],id)) p1=idealmul(nf,p1,(GEN)I[j]);
  j = gcmp0(isprincipal(bnf,p1));
  avma=av; return j;
}

/**********************************************************************/
/**								     **/
/**		      COMPOSITUM OF TWO NUMBER FIELDS                **/
/**								     **/
/**********************************************************************/

#define nexta(a) (a>0 ? -a : 1-a)

GEN
polcompositum0(GEN pol1, GEN pol2, long flall)
{
  long av=avma,tetpil,i,v,a,l;
  GEN pro1,p1,p2,p3,p4,p5,fa,rk,y;

  if (typ(pol1)!=t_POL || typ(pol2)!=t_POL) err(typeer,"polcompositum0");
  v=varn(pol1);
  if (varn(pol2)!=v) err(talker,"not the same variable in compositum");
  if (lgef(pol1)<=3 || lgef(pol2)<=3)
    err(constpoler,"compositum");
  if (lgef(ggcd(pol1,deriv(pol1,v)))>3 || lgef(ggcd(pol2,deriv(pol2,v)))>3)
    err(talker,"not a separable polynomial in compositum");

  for (a=1; ; a=nexta(a))
  {
    avma=av;
    if (DEBUGLEVEL>=2)
    {
      fprintferr("trying beta ");
      if (a>0) fprintferr("- "); else fprintferr("+ ");
      if (labs(a)>1) fprintferr("%ld ",labs(a));
      fprintferr("alpha\n"); flusherr();
    }
    pro1 = gadd(polx[MAXVARN],gmulsg(a,polx[v]));
    p1 = gsubst(pol2,v,pro1);
    p2 = subresall(pol1,p1,&rk);
    if (lgef(ggcd(p2,deriv(p2,MAXVARN)))==3)
    {
      p2 = gsubst(p2,MAXVARN,polx[v]);
      fa = factor(p2); fa = (GEN)fa[1];
      if (typ(rk)==t_POL && lgef(rk)==4)
      {
	if (flall)
	{
	  l=lg(fa); y=cgetg(l,t_VEC);
	  for (i=1; i<l; i++)
	  {
	    p3=cgetg(5,t_VEC); p3[1]=fa[i]; y[i]=(long)p3;
	    p4=gmodulcp(polx[v],(GEN)fa[i]);
	    p5=gneg(gdiv(gsubst((GEN)rk[2],MAXVARN,p4),
	                 gsubst((GEN)rk[3],MAXVARN,p4)));
	    p3[2]=(long)p5;
            p3[3]=ladd(p4,gmulsg(a,p5));
            p3[4]=lstoi(-a);
	  }
	}
	else y=fa;
	tetpil=avma; return gerepile(av,tetpil,gcopy(y));
      }
    }
  }
}

GEN
compositum(GEN pol1,GEN pol2)
{
  return polcompositum0(pol1,pol2,0);
}

GEN
compositum2(GEN pol1,GEN pol2)
{
  return polcompositum0(pol1,pol2,1);
}

GEN
rnfequationall(GEN nf, GEN pol2, long flall)
{
  long av=avma,av1,tetpil,v,vpol,a,l1,l2;
  GEN pol1,pro1,p1,p2,p4,p5,rk,y;

  if (typ(nf)==t_POL) pol1=nf; else { nf=checknf(nf); pol1=(GEN)nf[1]; }
  v=varn(pol1); vpol=varn(pol2);
  if (typ(pol2)!=t_POL || vpol>=v)
    err(talker,"incorrect polynomial in rnfequation");

  l1=lgef(pol1); l2=lgef(pol2);
  if (l1<=3 || l2<=3) err(constpoler,"rnfequation");

  p2=cgetg(l2,t_POL); p2[1]=pol2[1];
  for (a=2; a<l2; a++)
    p2[a] = (lgef(pol2[a]) < l1)? pol2[a]: lres((GEN)pol2[a],pol1);
  pol2=p2;
  if (lgef(ggcd(pol2,deriv(pol2,vpol)))>3)
    err(talker,"not a separable relative equation in rnfequation");
  pol2=lift_intern(pol2);

  a=0; av1=avma;
  for(;;)
  {
    avma=av1;
    if (DEBUGLEVEL>=2)
    {
      fprintferr("trying beta ");
      if (a)
      { 
	if (a>0) fprintferr("- "); else fprintferr("+ ");
	if (labs(a)>1) fprintferr("%ld alpha\n",labs(a));
	else fprintferr("alpha\n");
      }
      flusherr();
    }
    pro1=gadd(polx[MAXVARN],gmulsg(a,polx[v]));
    p1=gsubst(pol2,vpol,pro1);
    p2=subresall(pol1,p1,&rk);
    if (lgef(ggcd(p2,deriv(p2,MAXVARN)))==3)
    {
      p2=gsubst(p2,MAXVARN,polx[vpol]);
      if (gsigne(leadingcoeff(p2))<0) p2=gneg(p2);
      if (typ(rk)==t_POL && lgef(rk)==4)
      {
	if (flall)
	{
	  y=cgetg(4,t_VEC); y[1]=(long)p2;
	  p4=gmodulcp(polx[vpol],p2);
	  p5=gneg(gdiv(gsubst((GEN)rk[2],MAXVARN,p4),
	               gsubst((GEN)rk[3],MAXVARN,p4)));
	  y[3]=(long)stoi(-a);
          y[2]=lmul(gmodulcp(polun[vpol],p2),p5);
	}
	else y=p2;
	tetpil=avma; return gerepile(av,tetpil,gcopy(y));
      }
    }
    a=nexta(a);
  }
}

GEN
rnfequation(GEN nf,GEN pol2)
{
  return rnfequationall(nf,pol2,0);
}

GEN
rnfequation2(GEN nf,GEN pol2)
{
  return rnfequationall(nf,pol2,1);
}

static GEN
nftau(long r1, GEN x)
{
  long i, ru = lg(x);
  GEN s;

  s = r1 ? (GEN)x[1] : gmul2n(greal((GEN)x[1]),1);
  for (i=2; i<=r1; i++) s=gadd(s,(GEN)x[i]);
  for ( ; i<ru; i++) s=gadd(s,gmul2n(greal((GEN)x[i]),1));
  return s;
}

static GEN
nftocomplex(GEN nf, GEN x)
{
  long ru,vnf,k;
  GEN p2,p3,ronf;

  p2=gmul((GEN)nf[7],x); vnf=varn(nf[1]);
  ronf=(GEN)nf[6]; ru=lg(ronf); p3=cgetg(ru,t_COL);
  for (k=1; k<ru; k++) p3[k]=(long)gsubst(p2,vnf,(GEN)ronf[k]);
  return p3;
}

static GEN
rnfscal(GEN mth, GEN xth, GEN yth)
{
  long n,ru,i,j,kk;
  GEN x,y,m,res,p1,p2;

  n=lg(mth)-1; ru=lg(gcoeff(mth,1,1));
  res=cgetg(ru,t_COL);
  for (kk=1; kk<ru; kk++)
  {
    m=cgetg(n+1,t_MAT);
    for (j=1; j<=n; j++)
    {
      p1=cgetg(n+1,t_COL); m[j]=(long)p1;
      for (i=1; i<=n; i++) { p2=gcoeff(mth,i,j); p1[i]=p2[kk]; }
    }
    x=cgetg(n+1,t_VEC);
    for (j=1; j<=n; j++) x[j]=(long)gconj((GEN)((GEN)xth[j])[kk]);
    y=cgetg(n+1,t_COL);
    for (j=1; j<=n; j++) y[j]=((GEN)yth[j])[kk];
    res[kk]=(long)gmul(x,gmul(m,y));
  }
  return res;
}

static GEN
rnfdiv(GEN x, GEN y)
{
  long i, ru = lg(x);
  GEN z;

  z=cgetg(ru,t_COL);
  for (i=1; i<ru; i++) z[i]=(long)gdiv((GEN)x[i],(GEN)y[i]);
  return z;
}

static GEN
rnfmul(GEN x, GEN y)
{
  long i, ru = lg(x);
  GEN z;

  z=cgetg(ru,t_COL);
  for (i=1; i<ru; i++) z[i]=(long)gmul((GEN)x[i],(GEN)y[i]);
  return z;
}

static GEN
rnfvecmul(GEN x, GEN v)
{
  long i, lx = lg(v);
  GEN y;

  y=cgetg(lx,typ(v));
  for (i=1; i<lx; i++) y[i]=(long)rnfmul(x,(GEN)v[i]);
  return y;
}

static GEN
allonge(GEN v, long N)
{
  long r,r2,i;
  GEN y;

  r=lg(v)-1; r2=N-r;
  y=cgetg(N+1,t_COL);
  for (i=1; i<=r; i++) y[i]=v[i];
  for ( ; i<=N; i++) y[i]=(long)gconj((GEN)v[i-r2]);
  return y;
}

static GEN
findmin(GEN nf, GEN ideal, GEN muf,long prec)
{
  long av=avma,N,tetpil,i;
  GEN m,y;

  m = qf_base_change(gmael(nf,5,3), ideal); /* nf[5][3] = T2 */
  m = lllgram(m,prec); ideal=gmul(ideal,m);
  N=lg(ideal)-1; y=cgetg(N+1,t_MAT);
  for (i=1; i<=N; i++)
    y[i] = (long) allonge(nftocomplex(nf,(GEN)ideal[i]),N);
  m=ground(greal(gauss(y,allonge(muf,N))));
  tetpil=avma; return gerepile(av,tetpil,gmul(ideal,m));
}

/* given a base field nf (main variable y for example), a polynomial pol with
 * coefficients in nf (main variable x for example), and an order as output
 * by rnfpseudobasis, outputs a reduced order.
 */
GEN
rnflllgram(GEN nf, GEN pol, GEN order,long prec)
{
  long av=avma,tetpil,i,j,k,l,kk,kmax,r1,r2,ru,lx,N,n,vnf;
  GEN p1,p2,M,I,U,ronf,poll,r1r2,unro,roorder,powreorder,mth,s,MC,MPOL,MCS;
  GEN B,mu,Bf,temp,ideal,x,xc,xpol,muf,mufc,muno,y,z;

/* Initializations and verifications */

  nf=checknf(nf); N=lgef(nf[1])-3;
  if (typ(order)!=t_VEC || lg(order)<3)
    err(talker,"not a pseudo-matrix in rnflllgram");
  M=(GEN)order[1]; I=gcopy((GEN)order[2]); lx=lg(I); n=lg(I)-1;

/* Initialize U to the n x n identity matrix with coefficients in nf in
   the form of polymods */

  U=cgetg(n+1,t_MAT);
  for (j=1; j<=n; j++)
  {
    p1=cgetg(n+1,t_COL); U[j]=(long)p1;
    for (i=1; i<=n; i++) p1[i]=(i==j)?un:zero;
  }

/* Compute the relative T2 matrix of powers of theta */

  vnf=varn(nf[1]); ronf=(GEN)nf[6]; ru=lg(ronf); poll=lift(pol);
  r1r2=(GEN)nf[2]; r1=itos((GEN)r1r2[1]); r2=itos((GEN)r1r2[2]);
  if (r1+2*r2!=N) err(talker,"bug1 in rnflllgram");
  if (r1+r2!=ru-1) err(talker,"bug2 in rnflllgram");
  unro=cgetg(n+1,t_COL); for (i=1; i<=n; i++) unro[i]=un;
  roorder=cgetg(ru,t_VEC);
  for (i=1; i<ru; i++)
    roorder[i]=(long)roots(gsubst(poll,vnf,(GEN)ronf[i]),prec);
  powreorder=cgetg(n+1,t_MAT);
  p1=cgetg(ru,t_COL); powreorder[1]=(long)p1;
  for (i=1; i<ru; i++) p1[i]=(long)unro;
  for (k=2; k<=n; k++)
  {
    p1=cgetg(ru,t_COL); powreorder[k]=(long)p1;
    for (i=1; i<ru; i++)
    {
      p2=cgetg(n+1,t_COL); p1[i]=(long)p2;
      for (j=1; j<=n; j++)
	p2[j] = (long) gmul(gmael(roorder,i,j),gmael3(powreorder,k-1,i,j));
    }
  }
  mth=cgetg(n+1,t_MAT);
  for (l=1; l<=n; l++)
  {
    p1=cgetg(n+1,t_COL); mth[l]=(long)p1;
    for (k=1; k<=n; k++)
    {
      p2=cgetg(ru,t_COL); p1[k]=(long)p2;
      for (i=1; i<ru; i++)
      {
	s=gzero;
	for (j=1; j<=n; j++)
	  s = gadd(s,gmul(gconj(gmael3(powreorder,k,i,j)),
	                  gmael3(powreorder,l,i,j)));
	p2[i]=(long)s;
      }
    }
  }

/* Transform the matrix M into a matrix with coefficients in K and also
   with coefficients polymod */

  MC=cgetg(lx,t_MAT); MPOL=cgetg(lx,t_MAT);
  for (j=1; j<=n; j++)
  {
    p1=cgetg(lx,t_COL); MC[j]=(long)p1;
    p2=cgetg(lx,t_COL); MPOL[j]=(long)p2;
    for (i=1; i<=n; i++)
    {
      p1[i]=(long)nftocomplex(nf,gcoeff(M,i,j));
      p2[i]=(long)basistoalg(nf,gcoeff(M,i,j));
    }
  }
  MCS=cgetg(lx,t_MAT);

/* Start LLL algorithm */

  mu=cgetg(lx,t_MAT); B=cgetg(lx,t_COL);
  for (j=1; j<lx; j++)
  {
    p1=cgetg(lx,t_COL); mu[j]=(long)p1; for (i=1; i<lx; i++) p1[i]=zero;
    B[j]=zero;
  }
  kk=2; if (DEBUGLEVEL) fprintferr("kk = %ld ",kk);
  kmax=1; B[1]=(long)greal(rnfscal(mth,(GEN)MC[1],(GEN)MC[1]));
  MCS[1]=lcopy((GEN)MC[1]);
  do
  {
    if (kk>kmax)
    {
/* Incremental Gram-Schmidt */
      kmax=kk; MCS[kk]=lcopy((GEN)MC[kk]);
      for (j=1; j<kk; j++)
      {
	coeff(mu,kk,j) = (long) rnfdiv(rnfscal(mth,(GEN)MCS[j],(GEN)MC[kk]),
	                              (GEN) B[j]);
	MCS[kk] = (long) gsub((GEN) MCS[kk],
	                      rnfvecmul(gcoeff(mu,kk,j),(GEN)MCS[j]));
      }
      B[kk] = (long) greal(rnfscal(mth,(GEN)MCS[kk],(GEN)MCS[kk]));
      if (gcmp0((GEN)B[kk])) err(lllger3);
    }

/* RED(k,k-1) */
    l=kk-1;
    ideal=idealdiv(nf,(GEN)I[l],(GEN)I[kk]);
    
    /* doit retourner sur basis */
    x=findmin(nf,ideal,gcoeff(mu,kk,l),2*prec-2);
    xc=nftocomplex(nf,x); xpol=basistoalg(nf,x);
    if (!gcmp0(x))
    {
      MC[kk]=(long)gsub((GEN)MC[kk],rnfvecmul(xc,(GEN)MC[l]));
      U[kk]=(long)gsub((GEN)U[kk],gmul(xpol,(GEN)U[l]));
      coeff(mu,kk,l)=(long)gsub(gcoeff(mu,kk,l),xc);
      for (i=1; i<l; i++)
	coeff(mu,kk,i)=(long)gsub(gcoeff(mu,kk,i),rnfmul(xc,gcoeff(mu,l,i)));
    }
/* Test LLL condition */
    p1=nftau(r1,gadd((GEN) B[kk],
                     gmul(gnorml2(gcoeff(mu,kk,kk-1)),(GEN)B[kk-1])));
    p2=gdivgs(gmulsg(9,nftau(r1,(GEN)B[kk-1])),10);
    if (gcmp(p1,p2)<=0)
    {
/* Execute SWAP(k) */
      k=kk;
      temp=(GEN)MC[k]; MC[k]=MC[k-1]; MC[k-1]=(long)temp;
      temp=(GEN)U[k]; U[k]=U[k-1]; U[k-1]=(long)temp;
      temp=(GEN)I[k]; I[k]=I[k-1]; I[k-1]=(long)temp;
      for (j=1; j<=k-2; j++)
      {
	temp=gcoeff(mu,k,j); coeff(mu,k,j)=coeff(mu,k-1,j);
	coeff(mu,k-1,j)=(long)temp;
      }
      muf=gcoeff(mu,k,k-1);
      mufc=gconj(muf); muno=greal(rnfmul(muf,mufc));
      Bf=gadd((GEN)B[k],rnfmul(muno,(GEN)B[k-1]));
      p1=rnfdiv((GEN)B[k-1],Bf);
      coeff(mu,k,k-1)=(long)rnfmul(mufc,p1);
      temp=(GEN)MCS[k-1];
      MCS[k-1]=(long)gadd((GEN)MCS[k],rnfvecmul(muf,(GEN)MCS[k-1]));
      MCS[k]=(long)gsub(rnfvecmul(rnfdiv((GEN)B[k],Bf),temp),
			rnfvecmul(gcoeff(mu,k,k-1),(GEN)MCS[k]));
      B[k]=(long)rnfmul((GEN)B[k],p1); B[k-1]=(long)Bf;
      for (i=k+1; i<=kmax; i++)
      {
	temp=gcoeff(mu,i,k);
	coeff(mu,i,k)=(long)gsub(gcoeff(mu,i,k-1),rnfmul(muf,gcoeff(mu,i,k)));
	coeff(mu,i,k-1) = (long) gadd(temp,
	                              rnfmul(gcoeff(mu,k,k-1),gcoeff(mu,i,k)));
      }
      if (kk>2) { kk--; if (DEBUGLEVEL) fprintferr("%ld ",kk); }
    }
    else
    {
      for (l=kk-2; l; l--)
      {
/* RED(k,l) */
	ideal=idealdiv(nf,(GEN)I[l],(GEN)I[kk]);
	
	/* doit retourner sur basis */
	x=findmin(nf,ideal,gcoeff(mu,kk,l),2*prec-2);
	xc=nftocomplex(nf,x); xpol=basistoalg(nf,x);
	if (!gcmp0(x))
	{
	  MC[kk]=(long)gsub((GEN)MC[kk],rnfvecmul(xc,(GEN)MC[l]));
	  U[kk]=(long)gsub((GEN)U[kk],gmul(xpol,(GEN)U[l]));
	  coeff(mu,kk,l)=(long)gsub(gcoeff(mu,kk,l),xc);
	  for (i=1; i<l; i++)
	    coeff(mu,kk,i) = (long) gsub(gcoeff(mu,kk,i),
	                                 rnfmul(xc,gcoeff(mu,l,i)));
	}
      }
      kk++; if (DEBUGLEVEL) fprintferr("%ld ",kk);
    }
  }
  while (kk<=n);
  p1=gmul(MPOL,U); tetpil=avma;
  y=cgetg(3,t_VEC); z=cgetg(3,t_VEC); y[1]=(long)z;
  z[2]=lcopy(I); z[1]=(long)algtobasis(nf,p1);
  y[2]=(long)algtobasis(nf,U);
  return gerepile(av,tetpil,y);
}

GEN
rnfpolred(GEN nf, GEN pol, long prec)
{
  long av=avma,tetpil,i,j,k,n,N,vpol,flbnf;
  GEN id,id2,newid,newor,p1,p2,al,newpol,w,z;
  GEN bnf,zk,newideals,ideals,order,neworder;

  if (typ(nf)!=t_VEC) err(idealer1);
  switch(lg(nf))
  {
    case 10: flbnf=0; break;
    case 11: flbnf=1; bnf=nf; nf=checknf((GEN)nf[7]); break;
    default: err(idealer1);
  }
  id=rnfpseudobasis(nf,pol); N=lgef(nf[1])-3;
  if (flbnf && gcmp1(gmael3(bnf,8,1,1))) /* if bnf is principal */
  {
    ideals=(GEN)id[2]; n=lg(ideals)-1; order=(GEN)id[1];
    newideals=cgetg(n+1,t_VEC); neworder=cgetg(n+1,t_MAT);
    zk=idmat(N);
    for (j=1; j<=n; j++)
    {
      newideals[j]=(long)zk; p1=cgetg(n+1,t_COL); neworder[j]=(long)p1;
      p2=(GEN)order[j];
      al=(GEN)isprincipalgen(bnf,(GEN)ideals[j])[2];
      for (k=1; k<=n; k++)
	p1[k]=(long)element_mul(nf,(GEN)p2[k],al);
    }
    id=cgetg(3,t_VEC); id[1]=(long)neworder; id[2]=(long)newideals;
  }
  id2=rnflllgram(nf,pol,id,prec);
  z=(GEN)id2[1]; newid=(GEN)z[2]; newor=(GEN)z[1];
  n=lg(newor)-1; w=cgetg(n+1,t_VEC);
  for (j=1; j<=n; j++)
  {
    p1=(GEN)newid[j]; al=gmul(gcoeff(p1,1,1),(GEN)newor[j]);
    vpol=varn(pol);
    p1=basistoalg(nf,(GEN)al[n]);
    for (i=n-1; i; i--)
      p1=gadd(basistoalg(nf,(GEN)al[i]),gmul(polx[vpol],p1));
    newpol=gtopoly(gmodulcp(gtovec(caradj0(gmodulcp(lift(p1),lift(pol)),vpol)),
                            (GEN) nf[1]), vpol);
    p1=ggcd(newpol,deriv(newpol,vpol));
    if (degree(p1)>0)
    {
      newpol=gdiv(newpol,p1);
      newpol=gdiv(newpol,leading_term(newpol));
    }
    w[j]=(long)newpol;
    if (DEBUGLEVEL>=4) outerr(newpol);
  }
  tetpil=avma; return gerepile(av,tetpil,gcopy(w));
}

GEN
makebasis(GEN nf,GEN pol)
/* Etant donne un corps de nombres nf et un polynome relatif relpol,
   construit une pseudo-base de l'extension puis calcule une base absolue
   de cette extension pour une racine \theta de relpol. Renvoie le
   polynome irreductible de theta sur Q et la matrice de la base */
{
  GEN elts,ids,polabs,plg,B,bs,theta,p1,element,colonne,p2,rep,a;
  long av=avma,tetpil,n,N,m,i,j,k,v1,v2;
  
  v1=varn((GEN)nf[1]); v2=varn(pol);
  p1=rnfequation2(nf,pol);
  polabs=(GEN)p1[1];plg=(GEN)p1[2];
  a=(GEN)p1[3];
  if (signe(a))
    pol=gsubst(pol,v2,gsub(polx[v2],
				  gmul(a,gmodulcp(polx[v1],(GEN)nf[1]))));
  p1=rnfpseudobasis(nf,pol);
  elts=(GEN)p1[1];ids=(GEN)p1[2];
  N=lgef(pol)-3;n=lgef((GEN)nf[1])-3;m=n*N;
  bs=gsubst((GEN)nf[7],v1,plg);
  B=idmat(m);
  theta=gmodulcp(polx[v2],polabs);
  for(i=1;i<=N;i++)
  {
    element=gmul(bs,(GEN)coeff(elts,1,i));
    for(j=2;j<=N;j++)
      element=gadd(element,gmul(gmul(bs,(GEN)coeff(elts,j,i)),
				gpuigs(theta,j-1)));
    for(j=1;j<=n;j++)
    {
      colonne=gmul(element,gmul(bs,gmael(ids,i,j)));
      p1=gtovec(lift_intern(colonne));
      p2=cgetg(m+1,t_COL);
      for(k=1;k<lg(p1);k++) p2[lg(p1)-k]=p1[k];
      for(   ;k<=m;k++) p2[k]=zero;
      B[(i-1)*n+j]=(long)p2;
    }
  }
  rep=cgetg(3,t_VEC);
  rep[1]=(long)polabs;
  rep[2]=(long)B; tetpil=avma;
  return gerepile(av,tetpil,gcopy(rep));
}

static GEN
mkpoldirty(GEN rts,GEN elt)
{
  long i,av=avma,tetpil,v=varn(elt);
  GEN pol = gun;

  for (i=1; i<lg(rts); i++)
    pol = gmul(pol, gsub(polx[v], gsubst(elt,v,(GEN)rts[i])));
  pol = greal(pol); tetpil=avma;
  return gerepile(av,tetpil,ground(pol));
}

static int
checkgenerator2(GEN bs,GEN roots,GEN elt,GEN *ptp,long va)
{
  long fl;
  GEN p;

  p = mkpoldirty(roots,gtopolyrev(gmul(bs,elt),va));
  fl = (lgef(ggcd(p,deriv(p,varn(p))))==3);
  if (fl) *ptp = p; return fl;
}

GEN
rnfpolredabs(GEN nf, GEN relpol, long prec)
{
  GEN polabs,B,p1,rts,T2,p2,U,p3,listmin,eps,perm,ypro,y;
  GEN fact,wlim,bpol,b1,b2;
  long i,j,m,l,av=avma,tetpil,r1,ru,nbmin,c,nrel,lg,va,stop,av1,e;

  nf=checknf(nf);
  if (typ(relpol)!=t_POL) err(typeer,"rnfpolredabs");
  if (DEBUGLEVEL>=2) { fprintferr("Calcul de la base absolue\n"); flusherr(); }
  p1 = makebasis(nf, unifpol(nf,relpol,1));
  polabs = (GEN)p1[1]; B = (GEN)p1[2];
  va = varn(polabs); m = lgef(polabs)-3;
  r1 = sturm(polabs); ru = r1+((m-r1)>>1);
  eps=dbltor(0.000001); av1=avma; 
  for(;;)
  {
    if (DEBUGLEVEL>=2) 
      { fprintferr("\nCalcul de la matrice T2\n"); flusherr(); }
    rts=roots(polabs,prec); if (r1==m) rts=greal(rts);
    p1=cgetg(m+1,t_MAT); 
    for(j=1;j<=m;j++)
    {
      p2=cgetg(ru+1,t_COL); p1[j]=(long)p2;
      for (i=1; i<=ru; i++)
        p2[i] = (long) poleval((GEN)B[j], (GEN)rts[max(i,(i<<1)-r1)]);
    }
    p3=cgetg(ru+1,t_MAT);
    for(j=1;j<=ru;j++)
    {
      p2=cgetg(m+1,t_COL); p3[j]=(long)p2;
      for(i=1; i<=m; i++)
        p2[i]=(j<=r1)?lconj(gcoeff(p1,j,i)):lmul2n(gconj(gcoeff(p1,j,i)),1);
    }
    T2 = greal(gmul(p3,p1));
    if (r1!=m) U=lllgramintern(T2,1,(prec<<1)-2);
    else
    {
      T2 = grndtoi(T2,&e);
      U = (e>-10)? (GEN)NULL: lllgramint(T2);
    }
    if (U) break;
    avma=av1; prec=(prec<<1)-2;
    if (DEBUGLEVEL>=2) err(warnprec,"rnfpolredabs",prec);
  }
  B = gmul(B,U); T2 = qf_base_change(T2,U);
  if (DEBUGLEVEL>=2) { fprintferr("Recherche du minimum\n"); flusherr(); }
  b2=gun; stop=0;
  for(lg=2; ; lg++)
  {
    b1 = gceil(gcoeff(T2,lg,lg));
    if (expi(b1) > 31) { b1=stoi(1<<30); stop=1; }
    if (lg==m) stop=1;
    listmin=(GEN)fincke_pohst(T2,b1,stoi(1000),0,prec)[3];
    nbmin=lg(listmin);
    if (DEBUGLEVEL && nbmin>=1000)
    {
      fprintferr("warning: not enough storage in minimgenerator\n");
      flusherr();
    }
    p1=cgetg(nbmin,t_VEC);
    for(j=1;j<nbmin;j++) p1[j] = (long)qfeval(T2, (GEN)listmin[j]);
    perm=sindexsort(p1); ypro=cgetg(nbmin,t_VEC);c=0;
    for (j=1; j<nbmin; j++)
      if (gcmp((GEN)p1[perm[j]],b2) > 0)
	if (checkgenerator2(B,rts,(GEN)listmin[perm[j]], &bpol,va))
	{
	  if (!c)
	    wlim = gadd((GEN)p1[perm[j]],eps);
	  else
	    if (gcmp((GEN)p1[perm[j]], wlim) >= 0) break;
          ypro[++c] = (long)bpol;
	}
    if (c)
    {
      bpol=(GEN)ypro[1]; p1=discsr(bpol);
      for (i=2; i<=c; i++)
      {
        p2 = discsr((GEN)ypro[i]);
        if (absi_cmp(p1,p2) > 0) { p1 = p2; bpol = (GEN) ypro[i]; }
      }
      break;
    }
    if (stop)
    {
      if (DEBUGLEVEL>=2) { fprintferr("Reduction minimale...\n"); flusherr(); }
      p1=cgetg(m+1,t_COL); for(i=1;i<=m;i++) p1[i]=zero;
      for (i=2; i<=m; i++)
      {
	p1[i]=un; if (checkgenerator2(B,rts,p1,&bpol,va)) break;
	p1[i]=zero;
      }
      break;
    }
    if (cmpii(b1,b2) > 0) b2 = b1;
  }
  if (DEBUGLEVEL>=2)
    { fprintferr("Factorisation du polynome absolu\n"); outerr(bpol); }
  fact = (GEN)nffactor(nf,bpol)[1];
  l = lg(fact); y=cgetg(l,t_VEC);
  nrel=lgef(relpol);
  for(j=1,i=1; i<l; i++)
  {
    p1=(GEN)fact[i];
    if (lgef(p1) == nrel) y[j++]=(long)p1;
  }
  tetpil=avma; setlg(y,j);
  return gerepile(av,tetpil,gcopy(y));
}
