/********************************************************************/
/********************************************************************/
/**                                                                **/
/**                 LLL Algorithm and close friends                **/
/**                                                                **/
/**                     Copyright Babe Cool                        **/
/**                                                                **/
/********************************************************************/
/********************************************************************/
/* $Id: bibli1.c,v 2.0.0.2 1997/12/14 20:11:49 karim Exp karim $ */
#include "genpari.h"
#include "nf.h"
/* scalar product of x with himself x */
static GEN
sqscal(GEN x)
{
  GEN z,p;
  long i,av,tetpil,lx=lg(x);

  z=gzero; if (lx==1) return z;
  av=avma;
  for (i=1; i<lx; i++)
  {
    p=gsqr((GEN)x[i]);
    tetpil=avma; z=gadd(z,p);
  }
  return gerepile(av,tetpil,z);
}

/* scalar product x . y */
static GEN
gscal(GEN x,GEN y)
{
  GEN z,p;
  long i,av,tetpil,lx=lg(x);

  z=gzero; if (lx==1) return z;
  av=avma;
  for (i=1; i<lx; i++)
  {
    p=gmul((GEN)x[i],(GEN)y[i]);
    tetpil=avma; z=gadd(z,p);
  }
  return gerepile(av,tetpil,z);
}

static GEN
lllgramall_trivial(GEN x, long n, long flag)
{
  if (!n)
  {
    if (flag != lll_ALL) return cgetg(1,t_MAT);
    x=cgetg(3,t_VEC); x[1]=lgetg(1,t_MAT);
    x[2]=lgetg(1,t_MAT); return x;
  }
  /* here n = 1 */
  if (gcmp0(gcoeff(x,1,1)))
  {
    switch(flag)
    {
      case lll_KER: return idmat(1);
      case lll_IM : return cgetg(1,t_MAT);
      default:
        x=cgetg(3,t_VEC); x[1]=(long)idmat(1);
        x[2]=lgetg(1,t_MAT); return x;
    }
  }
  switch(flag)
  {
    case lll_KER: return cgetg(1,t_MAT);
    case lll_IM : return idmat(1);
    default:
      x=cgetg(3,t_VEC); x[1]=lgetg(1,t_MAT);
      x[2]=(long)idmat(1); return x;
  }
}

static GEN
lllgramall_finish(GEN h,GEN fl,long flag,long n)
{
  long i,k; 
  GEN y,p1;
  
  k=1; while (k<=n && !fl[k]) k++;
  switch(flag)
  {
    case lll_KER:
      y=cgetg(k,t_MAT);
      for (i=1; i<k; i++) y[i]=lcopy((GEN)h[i]);
      break;

    case lll_IM:
      y=cgetg(n-k+2,t_MAT);
      for (i=k; i<=n; i++) y[i-k+1]=lcopy((GEN)h[i]);
      break;

    default:
      y=cgetg(3,t_VEC); p1=cgetg(k,t_MAT);
      for (i=1; i<k; i++) p1[i]=lcopy((GEN)h[i]);
      y[1]=(long)p1; p1=cgetg(n-k+2,t_MAT); y[2]=(long)p1;
      for (i=k; i<=n; i++) p1[i-k+1]=lcopy((GEN)h[i]);
      break;
  }
  free(fl); return y;
}

/********************************************************************/
/**                                                                **/
/**                          LLL with content                      **/
/**                                                                **/
/********************************************************************/

/* real Gram matrix has coeffs X[i,j] = x[i,j]*veccon[i]*veccon[j] */
static GEN
lllgramintwithcontent(GEN x, GEN veccon, long flag)
{
  long av=avma,tetpil,lx=lg(x),i,j,k,l,n,lim,kmax;
  GEN u,u2,B,lam,q,r,h,la,bb,p1,p2,p3,p4,fl,corr,corr2,newcon;
  GEN *gptr[8];

  if (typ(x) != t_MAT) err(typeer,"lllgramintwithcontent");
  n=lx-1; if (n<=1) return lllgramall_trivial(x,n,flag);
  if (lg((GEN)x[1])!=lx) err(mattype1,"lllgramintwithcontent");

  fl = (GEN) gpmalloc(lx*sizeof(long));

  av=avma; lim=(av+bot)>>1;
  x=dummycopy(x); veccon=dummycopy(veccon);
  B=cgetg(lx+1,t_COL); B[1]=un;
  /* B[i+1]=B_i; le vrai B_i est B_i*prod(1,j=1,i,veccon[j]^2) */

  for (i=1; i<lx; i++) { B[i+1]=zero; fl[i]=0; }
  lam=cgetg(lx,t_MAT);
  for (j=1; j<lx; j++)
  { p2=cgetg(lx,t_COL); lam[j]=(long)p2; for (i=1; i<lx; i++) p2[i]=zero; }
/* le vrai lam[i,j] est
   lam[i,j]*veccon[i]*veccon[j]*prod(1,l=1,j-1,veccon[l]^2) */
  k=2; h=idmat(n); kmax=1; 
  u=gcoeff(x,1,1); if (typ(u)!=t_INT) err(lllger4);
  if (signe(u)) { B[2]=(long)u; coeff(lam,1,1)=un; fl[1]=1; }
  else { B[2]=un; fl[1]=0; }
  if (DEBUGLEVEL>5) { fprintferr("k = %ld",k); flusherr(); }
  for(;;)
  {
    if (k>kmax)
    {
      kmax=k;
      for (j=1; j<=k; j++)
      {
	if (j==k || fl[j])
	{
	  u=gcoeff(x,k,j); if (typ(u)!=t_INT) err(lllger4);
	  for (i=1; i<j; i++)
	    if (fl[i])
	      u=divii(subii(mulii((GEN)B[i+1],u),mulii(gcoeff(lam,k,i),gcoeff(lam,j,i))),(GEN)B[i]);
	  if (j<k) coeff(lam,k,j)=(long)u;
	  else
	  {
	    if (signe(u)) { B[k+1]=(long)u; coeff(lam,k,k)=un; fl[k]=1; }
	    else { B[k+1]=B[k]; fl[k]=0; }
	  }
	}
      }
      if (low_stack(lim, (av+bot)>>1))
      {
	if(DEBUGMEM>1) err(warnmem,"[1]: lllgramintwithcontent");
	gptr[0]=&B; gptr[1]=&lam; gptr[2]=&h;
	gptr[3]=&x; gptr[4]=&veccon; gerepilemany(av,gptr,5);
      }
    }
    u=shifti(mulii(gcoeff(lam,k,k-1),(GEN)veccon[k]),1);
    u2=mulii((GEN)B[k],(GEN)veccon[k-1]);
    if (cmpii(absi(u),u2)>0)
    {
      q=dvmdii(addii(u,u2),shifti(u2,1),&r);
      if (signe(r)<0) q=addsi(-1,q);
      h[k]=lsub((GEN)h[k],gmul(q,(GEN)h[k-1]));
      newcon=mppgcd((GEN)veccon[k],(GEN)veccon[k-1]);
      corr=divii((GEN)veccon[k],newcon); veccon[k]=(long)newcon;
      if(!gcmp1(corr))
      {
	corr2=sqri(corr);
	for (j=1; j<=n; j++)
	  coeff(x,j,k)=coeff(x,k,j)=lmulii(corr,gcoeff(x,k,j));
	coeff(x,k,k)=lmulii(corr,gcoeff(x,k,k));
	for (j=k; j<=kmax; j++) B[j+1]=lmulii(corr2,(GEN)B[j+1]);
	for (i=1; i<k; i++) coeff(lam,k,i)=lmulii(corr,gcoeff(lam,k,i));
	for (i=k+1; i<=kmax; i++)
	{
	  coeff(lam,i,k)=lmulii(corr,gcoeff(lam,i,k));
	  for (j=k+1; j<i; j++)
	    coeff(lam,i,j)=lmulii(corr2,gcoeff(lam,i,j));
	}
      }
      r=negi(mulii(q,divii((GEN)veccon[k-1],(GEN)veccon[k])));
      p1=gcoeff(x,k,k-1);
      for (j=1; j<=n; j++)
	coeff(x,j,k)=coeff(x,k,j)=laddii(gcoeff(x,j,k),mulii(r,(j==k)?p1:gcoeff(x,j,k-1)));
      coeff(x,k,k)=laddii(gcoeff(x,k,k),mulii(r,gcoeff(x,k-1,k)));
      coeff(lam,k,k-1)=laddii(gcoeff(lam,k,k-1),mulii(r,(GEN)B[k]));
      for (i=1; i<k-1; i++)
	coeff(lam,k,i)=laddii(gcoeff(lam,k,i),mulii(r,gcoeff(lam,k-1,i)));
    }
    if (low_stack(lim, (av+bot)>>1))
    {
      if(DEBUGMEM>1) err(warnmem,"[2]: lllgramintwithcontent");
      gptr[0]=&B; gptr[1]=&lam; gptr[2]=&h;
      gptr[3]=&x; gptr[4]=&veccon; gerepilemany(av,gptr,5);
    }
    p3=mulii((GEN)B[k-1],(GEN)B[k+1]);la=gcoeff(lam,k,k-1);p4=mulii(la,la);
    p2=mulsi(100,mulii(mulii((GEN)veccon[k],(GEN)veccon[k]),addii(p3,p4)));
    p1=mulii((GEN)veccon[k-1],(GEN)B[k]);p1=mulsi(99,mulii(p1,p1));
    if (fl[k-1] && (cmpii(p1,p2)>0 || !fl[k]))
    {
      if (DEBUGLEVEL>=4 && k==n)
	{ fprintferr(" (%ld)", expi(p1)-expi(p2)); flusherr(); }
      p1=(GEN)h[k-1]; h[k-1]=h[k]; h[k]=(long)p1;
      p1=(GEN)x[k-1]; x[k-1]=x[k]; x[k]=(long)p1;
      for (j=1; j<=n; j++)
      { p1=gcoeff(x,k-1,j); coeff(x,k-1,j)=coeff(x,k,j); coeff(x,k,j)=(long)p1; }
      p1=(GEN)veccon[k-1]; veccon[k-1]=veccon[k]; veccon[k]=(long)p1;
      for (j=1; j<=k-2; j++)
      { p1=gcoeff(lam,k-1,j); coeff(lam,k-1,j)=coeff(lam,k,j); coeff(lam,k,j)=(long)p1; }
      if (fl[k])
      {
	for (i=k+1; i<=kmax; i++)
	{
	  bb=gcoeff(lam,i,k);
	  coeff(lam,i,k)=ldivii(subii(mulii((GEN)B[k+1],gcoeff(lam,i,k-1)),mulii(la,bb)),(GEN)B[k]);
	  coeff(lam,i,k-1)=ldivii(addii(mulii(la,gcoeff(lam,i,k-1)),mulii((GEN)B[k-1],bb)),(GEN)B[k]);
          if (low_stack(lim, (av+bot)>>1))
	  {
	    if(DEBUGMEM>1) err(warnmem,"[3]: lllgramintwithcontent");
	    gptr[0]=&B; gptr[1]=&lam; gptr[2]=&h;
	    gptr[3]=&x; gptr[4]=&la; gptr[5]=&veccon; gptr[6]=&p3;
	    gptr[7]=&p4; gerepilemany(av,gptr,8);
	  }
	}
	B[k]=ldivii(addii(p3,p4),(GEN)B[k]);
      }
      else
      {
	if (signe(la))
	{
	  p2=(GEN)B[k]; p1=divii(p4,p2);
	  for (i=k+1; i<=kmax; i++)
	    coeff(lam,i,k-1)=ldivii(mulii(la,gcoeff(lam,i,k-1)),p2);
	  for (j=k+1; j<kmax; j++)
	  {
	    for (i=j+1; i<=kmax; i++)
	      coeff(lam,i,j)=ldivii(mulii(p1,gcoeff(lam,i,j)),p2);
            if (low_stack(lim, (av+bot)>>1))
	    {
	      if(DEBUGMEM>1) err(warnmem,"[4]: lllgramintwithcontent");
	      gptr[0]=&B; gptr[1]=&lam; gptr[2]=&h;
	      gptr[3]=&x; gptr[4]=&la; gptr[5]=&veccon; gptr[6]=&p1;
	      gptr[7]=&p2; gerepilemany(av,gptr,8);
	    }
	  }
	  B[k+1]=B[k]=(long)p1;
	  for (i=k+2; i<=lx; i++)
	    B[i]=ldivii(mulii(p1,(GEN)B[i]),p2);
	}
	else
	{
	  coeff(lam,k,k-1)=zero;
	  for (i=k+1; i<=kmax; i++)
	  { 
	    coeff(lam,i,k)=coeff(lam,i,k-1);
	    coeff(lam,i,k-1)=zero;
	  }
	  B[k]=B[k-1]; fl[k]=1; fl[k-1]=0;
	}

        if (low_stack(lim, (av+bot)>>1))
	{
	  if(DEBUGMEM>1) err(warnmem,"[5]: lllgramintwithcontent");
	  gptr[0]=&B; gptr[1]=&lam; gptr[2]=&h;
	  gptr[3]=&x; gptr[4]=&veccon;
	  gerepilemany(av,gptr,5);
	}
      }
      if (k>2) k--;
      if (DEBUGLEVEL>5) { fprintferr(" %ld",k); flusherr(); }
    }
    else
    {
      for (l=k-2; l>=1; l--)
      {
	u=shifti(mulii(gcoeff(lam,k,l),(GEN)veccon[k]),1);
	u2=mulii((GEN)B[l+1],(GEN)veccon[l]);
	if (cmpii(absi(u),u2)>0)
	{
	  q=dvmdii(addii(u,u2),shifti(u2,1),&r);
	  if (signe(r)<0) q=addsi(-1,q);
	  h[k]=lsub((GEN)h[k],gmul(q,(GEN)h[l]));
	  newcon=mppgcd((GEN)veccon[k],(GEN)veccon[l]);
	  corr=divii((GEN)veccon[k],newcon); veccon[k]=(long)newcon;
	  if(!gcmp1(corr))
	  {
	    corr2=sqri(corr);
	    for (j=1; j<=n; j++)
	      coeff(x,j,k)=coeff(x,k,j)=lmulii(corr,gcoeff(x,k,j));
	    coeff(x,k,k)=lmulii(corr,gcoeff(x,k,k));
	    for (j=k; j<=kmax; j++) B[j+1]=lmulii(corr2,(GEN)B[j+1]);
	    for (i=1; i<k; i++) coeff(lam,k,i)=lmulii(corr,gcoeff(lam,k,i));
	    for (i=k+1; i<=kmax; i++)
	    {
	      coeff(lam,i,k)=lmulii(corr,gcoeff(lam,i,k));
	      for (j=k+1; j<i; j++)
		coeff(lam,i,j)=lmulii(corr2,gcoeff(lam,i,j));
	    }
	  }
	  r=negi(mulii(q,divii((GEN)veccon[l],(GEN)veccon[k])));
	  p1=gcoeff(x,k,l);
	  for (j=1; j<=n; j++)
	    coeff(x,j,k)=coeff(x,k,j)=laddii(gcoeff(x,j,k),mulii(r,(j==k)?p1:gcoeff(x,j,l)));
	  coeff(x,k,k)=laddii(gcoeff(x,k,k),mulii(r,gcoeff(x,l,k)));
	  coeff(lam,k,l)=laddii(gcoeff(lam,k,l),mulii(r,(GEN)B[l+1]));
	  for (i=1; i<l; i++)
	    coeff(lam,k,i)=laddii(gcoeff(lam,k,i),mulii(r,gcoeff(lam,l,i)));
	}
        if (low_stack(lim, (av+bot)>>1))
	{
	  if(DEBUGMEM>1) err(warnmem,"[6]: lllgramintwithcontent");
	  gptr[0]=&B; gptr[1]=&lam; gptr[2]=&h;
	  gptr[3]=&x; gptr[4]=&veccon; gerepilemany(av,gptr,5);
	}
      }
      k++; if (DEBUGLEVEL>5) { fprintferr(" %ld",k); flusherr(); }
      if (k>n)
      { 
        if (DEBUGLEVEL>5) { fprintferr("\n"); flusherr(); }
	tetpil=avma; 
	return gerepile(av,tetpil,lllgramall_finish(h,fl,flag,n));
      }
    }
    if (low_stack(lim, (av+bot)>>1))
    {
      if(DEBUGMEM>1) err(warnmem,"[7]: lllgramintwithcontent");
      gptr[0]=&B; gptr[1]=&lam; gptr[2]=&h;
      gptr[3]=&x; gptr[4]=&veccon; gerepilemany(av,gptr,5);
    }
  }
}

static GEN
lllintwithcontent(GEN x)
{
  long lx=lg(x),i,j,av,tetpil;
  GEN veccon,con,xred,g;

  if (typ(x) != t_MAT) err(typeer,"lllintwithcontent");
  if (lx==1) return cgetg(1,t_MAT);
  av=avma; veccon=cgetg(lx,t_VEC); g=cgetg(lx,t_MAT); xred=cgetg(lx,t_MAT);
  for (j=1; j<lx; j++)
  {
    g[j]=lgetg(lx,t_COL); con=content((GEN)x[j]);
    xred[j]=ldiv((GEN)x[j],con); veccon[j]=(long)con;
  }
  for (i=1; i<lx; i++)
    for (j=1; j<=i; j++)
      coeff(g,i,j)=coeff(g,j,i)=(long)gscal((GEN)xred[i],(GEN)xred[j]);
  tetpil=avma;
  return gerepile(av,tetpil,lllgramintwithcontent(g,veccon,2));
}

/********************************************************************/
/**                                                                **/
/**                          LLL ALGORITHM                         **/
/**                                                                **/
/********************************************************************/

static GEN
lllgramall(GEN x, long flag)
{
  long av=avma,tetpil,lx=lg(x),i,j,k,l,n,lim,kmax;
  GEN u,B,lam,q,r,h,la,p1,p2,p3,p4,fl, *gptr[7];

  if (typ(x) != t_MAT) err(typeer,"lllgramall");
  n=lx-1; if (n<=1) return lllgramall_trivial(x,n,flag);
  if (lg((GEN)x[1])!=lx) err(mattype1,"lllgramall");

  fl = (GEN) gpmalloc(lx*sizeof(long));

  av=avma; lim=(av+bot)>>1; x=dummycopy(x);
  B=cgetg(lx+1,t_COL); B[1]=un;
  for (i=1; i<lx; i++) { B[i+1]=zero; fl[i]=0; }
  lam=cgetg(lx,t_MAT);
  for (j=1; j<lx; j++)
  { p2=cgetg(lx,t_COL); lam[j]=(long)p2; for (i=1; i<lx; i++) p2[i]=zero; }
  k=2; h=idmat(n); kmax=1; 
  u=gcoeff(x,1,1); if (typ(u)!=t_INT) err(lllger4);
  if (signe(u)) { B[2]=(long)u; coeff(lam,1,1)=un; fl[1]=1; }
  else { B[2]=un; fl[1]=0; }
  if (DEBUGLEVEL>5) { fprintferr("k = %ld",k); flusherr(); }
  for(;;)
  {
    if (k>kmax)
    {
      kmax=k;
      for (j=1; j<=k; j++)
      {
	if (j==k || fl[j])
	{
	  u=gcoeff(x,k,j); if (typ(u)!=t_INT) err(lllger4);
	  for (i=1; i<j; i++)
	    if (fl[i])
	      u = divii(subii(mulii((GEN)B[i+1],u),
                              mulii(gcoeff(lam,k,i),gcoeff(lam,j,i))),
                        (GEN)B[i]);
	  if (j<k) coeff(lam,k,j)=(long)u;
	  else
	  {
	    if (signe(u)) { B[k+1]=(long)u; coeff(lam,k,k)=un; fl[k]=1; }
	    else { B[k+1]=B[k]; fl[k]=0; }
	  }
	}
      }
      if (low_stack(lim, (av+bot)>>1))
      {
	if(DEBUGMEM>1) err(warnmem,"[1]: lllgramall");
	gptr[0]=&B; gptr[1]=&lam; gptr[2]=&h;
	gptr[3]=&x; gerepilemany(av,gptr,4);
      }
    }
    if (cmpii(absi(u=shifti(gcoeff(lam,k,k-1),1)),(GEN)B[k])>0)
    {
      q=dvmdii(addii(u,(GEN)B[k]),shifti((GEN)B[k],1),&r);
      if (signe(r)<0) q=addsi(-1,q);
      r=negi(q);
      h[k]=ladd((GEN)h[k],gmul(r,(GEN)h[k-1]));
      for (j=1; j<=n; j++)
        coeff(x,j,k) = ladd(gcoeff(x,j,k),gmul(r,gcoeff(x,j,k-1)));
      for (j=1; j<=n; j++)
        coeff(x,k,j) = ladd(gcoeff(x,k,j),gmul(r,gcoeff(x,k-1,j)));
      coeff(lam,k,k-1)=laddii(gcoeff(lam,k,k-1),mulii(r,(GEN)B[k]));
      for (i=1; i<k-1; i++)
	coeff(lam,k,i)=laddii(gcoeff(lam,k,i),mulii(r,gcoeff(lam,k-1,i)));
    }
    if (low_stack(lim, (av+bot)>>1))
    {
      if(DEBUGMEM>1) err(warnmem,"[2]: lllgramall");
      gptr[0]=&B; gptr[1]=&lam; gptr[2]=&h;
      gptr[3]=&x; gerepilemany(av,gptr,4);
    }
    if (fl[k-1] && 
     (cmpii(p1=mulsi(99,sqri((GEN)B[k])),
            p2=mulsi(100,addii(p3=mulii((GEN)B[k-1],(GEN)B[k+1]),
                               p4=sqri(la=gcoeff(lam,k,k-1))))) > 0 
      || !fl[k]))
    {
      if (DEBUGLEVEL>=4 && k==n)
	{ fprintferr(" (%ld)", expi(p1)-expi(p2)); flusherr(); }
      p1=(GEN)h[k-1]; h[k-1]=h[k]; h[k]=(long)p1;
      p1=(GEN)x[k-1]; x[k-1]=x[k]; x[k]=(long)p1;
      for (j=1; j<=n; j++)
      { 
	p1=gcoeff(x,k-1,j); 
        coeff(x,k-1,j)=coeff(x,k,j);
	coeff(x,k,j)=(long)p1;
      }
      for (j=1; j<=k-2; j++)
      { 
	p1=gcoeff(lam,k-1,j);
        coeff(lam,k-1,j)=coeff(lam,k,j);
	coeff(lam,k,j)=(long)p1;
      }
      if (fl[k])
      {
	for (i=k+1; i<=kmax; i++)
	{
	  GEN bb=gcoeff(lam,i,k);
	  coeff(lam,i,k) = ldivii(subii(mulii((GEN)B[k+1],gcoeff(lam,i,k-1)),
                                        mulii(la,bb)),
                                  (GEN)B[k]);
	  coeff(lam,i,k-1) = ldivii(addii(mulii(la,gcoeff(lam,i,k-1)),
                                          mulii((GEN)B[k-1],bb)),
                                    (GEN)B[k]);
          if (low_stack(lim, (av+bot)>>1))
	  {
	    if(DEBUGMEM>1) err(warnmem,"[3]: lllgramall");
	    gptr[0]=&B; gptr[1]=&lam; gptr[2]=&h;
	    gptr[3]=&x; gptr[4]=&la; gptr[5]=&p3; gptr[6]=&p4;
	    gerepilemany(av,gptr,7);
	  }
	}
	B[k]=ldivii(addii(p3,p4),(GEN)B[k]);
      }
      else
      {
	if (signe(la))
	{
	  p2=(GEN)B[k]; p1=divii(p4,p2);
	  for (i=k+1; i<=kmax; i++)
	    coeff(lam,i,k-1)=ldivii(mulii(la,gcoeff(lam,i,k-1)),p2);
	  for (j=k+1; j<kmax; j++)
	  {
	    for (i=j+1; i<=kmax; i++)
	      coeff(lam,i,j)=ldivii(mulii(p1,gcoeff(lam,i,j)),p2);
            if (low_stack(lim, (av+bot)>>1))
	    {
	      if(DEBUGMEM>1) err(warnmem,"[4]: lllgramall");
	      gptr[0]=&B; gptr[1]=&lam; gptr[2]=&h;
	      gptr[3]=&x; gptr[4]=&p1; gptr[5]=&p2;
	      gerepilemany(av,gptr,6);
	    }
	  }
	  B[k+1]=B[k]=(long)p1;
	  for (i=k+2; i<=lx; i++)
	    B[i]=ldivii(mulii(p1,(GEN)B[i]),p2);
	}
	else
	{
	  coeff(lam,k,k-1)=zero;
	  for (i=k+1; i<=kmax; i++)
	  { coeff(lam,i,k)=coeff(lam,i,k-1); coeff(lam,i,k-1)=zero; }
	  B[k]=B[k-1]; fl[k]=1; fl[k-1]=0;
	}

        if (low_stack(lim, (av+bot)>>1))
	{
	  if(DEBUGMEM>1) err(warnmem,"[5]: lllgramall");
	  gptr[0]=&B; gptr[1]=&lam; gptr[2]=&h;
	  gptr[3]=&x; gerepilemany(av,gptr,4);
	}
      }
      if (k>2) k--;
      if (DEBUGLEVEL>5) { fprintferr(" %ld",k); flusherr(); }
    }
    else
    {
      for (l=k-2; l>=1; l--)
      {
	if (cmpii(absi(u=shifti(gcoeff(lam,k,l),1)),(GEN)B[l+1])>0)
	{
	  q=dvmdii(addii(u,(GEN)B[l+1]),shifti((GEN)B[l+1],1),&r);
	  if (signe(r)<0) q=addsi(-1,q);
	  r=negi(q);
	  h[k]=ladd((GEN)h[k],gmul(r,(GEN)h[l]));
	  for (j=1; j<=n; j++)
	    coeff(x,j,k)=ladd(gcoeff(x,j,k),gmul(r,gcoeff(x,j,l)));
	  for (j=1; j<=n; j++)
	    coeff(x,k,j)=ladd(gcoeff(x,k,j),gmul(r,gcoeff(x,l,j)));
	  coeff(lam,k,l)=laddii(gcoeff(lam,k,l),mulii(r,(GEN)B[l+1]));
	  for (i=1; i<l; i++)
	    coeff(lam,k,i)=laddii(gcoeff(lam,k,i),mulii(r,gcoeff(lam,l,i)));
	}
        if (low_stack(lim, (av+bot)>>1))
	{
	  if(DEBUGMEM>1) err(warnmem,"[6]: lllgramall");
	  gptr[0]=&B; gptr[1]=&lam; gptr[2]=&h;
	  gptr[3]=&x; gerepilemany(av,gptr,4);
	}
      }
      k++; if (DEBUGLEVEL>5) { fprintferr(" %ld",k); flusherr(); }
      if (k>n)
      {
	tetpil=avma; 
	return gerepile(av,tetpil,lllgramall_finish(h,fl,flag,n));
      }
    }
    if (low_stack(lim, (av+bot)>>1))
    {
      if(DEBUGMEM>1) err(warnmem,"[7]: lllgramall");
      gptr[0]=&B; gptr[1]=&lam; gptr[2]=&h;
      gptr[3]=&x; gerepilemany(av,gptr,4);
    }
  }
}

static int
pslg(GEN x)
{
  long tx;
  if (gcmp0(x)) return 2;
  tx=typ(x); return is_scalar_t(tx)? 3: lgef(x);
}

static GEN
lllgramallgen(GEN x, long flag)
{
  long av=avma,tetpil,lx=lg(x),tu,i,j,k,l,n,lim;
  GEN u,B,lam,q,cq,h,la,bb,p1,p2,p3,p4,fl;
  int ps1,ps2,flc;

  if (typ(x) != t_MAT) err(typeer,"lllgramallgen");
  n=lx-1; if (n<=1) return lllgramall_trivial(x,n,flag);
  if (lg((GEN)x[1])!=lx) err(mattype1,"lllgramallgen");

  fl = (GEN) gpmalloc(lx*sizeof(long));

  av=avma; lim=(av+bot)>>1;
  B=cgetg(lx+1,t_COL);
  B[1]=un; lam=cgetg(lx,t_MAT);
  for (j=1; j<lx; j++) lam[j]=lgetg(lx,t_COL);
  for (i=1; i<lx; i++)
    for (j=1; j<=i; j++)
    {
      if (j<i && !fl[j]) coeff(lam,i,j)=coeff(lam,j,i)=zero;
      else
      {
	u=gcoeff(x,i,j); tu=typ(u);
	if (! is_scalar_t(tu) && tu != t_POL) err(lllger4);
	for (k=1; k<j; k++)
	  if (fl[k])
	    u=gdiv(gsub( gmul((GEN)B[k+1],u),
                         gmul(gcoeff(lam,i,k),gcoeff(lam,j,k)) ),
		   (GEN)B[k]);
	if (j<i) { coeff(lam,i,j)=(long)u; coeff(lam,j,i)=zero; }
	else
	{
	  if (!gcmp0(u)) { B[i+1]=(long)u; coeff(lam,i,i)=un; fl[i]=1; }
	  else { B[i+1]=B[i]; coeff(lam,i,i)=zero; fl[i]=0; }
	}
      }
    }
  k=2; h=idmat(n); flc=0;
  for(;;)
  {
    u=gcoeff(lam,k,k-1);
    if (pslg(u) >= pslg((GEN)B[k]))
    {
      q=gdeuc(u,(GEN)B[k]); cq=gdivsg(1,content(q)); q=gmul(q,cq); flc=1;
      h[k]=lsub(gmul(cq,(GEN)h[k]),gmul(q,(GEN)h[k-1]));
      coeff(lam,k,k-1)=lsub(gmul(cq,gcoeff(lam,k,k-1)),gmul(q,(GEN)B[k]));
      for (i=1; i<k-1; i++)
	coeff(lam,k,i)=lsub(gmul(cq,gcoeff(lam,k,i)),gmul(q,gcoeff(lam,k-1,i)));
    }
    ps1 = pslg(gsqr((GEN)B[k]));
    p3 = gmul((GEN)B[k-1],(GEN)B[k+1]);
    la=gcoeff(lam,k,k-1); p4 = gmul(la,gcoeff(lam,k,k-1));
    ps2=pslg(gadd(p3,p4));
    if (fl[k-1] && (ps1>ps2 || (ps1==ps2 && flc) || !fl[k]))
    {
      p1=(GEN)h[k-1]; h[k-1]=h[k]; h[k]=(long)p1;
      if (ps1==ps2 && flc) flc=0; else flc=1;
      for (j=1; j<=k-2; j++)
      {
	p1=gcoeff(lam,k-1,j); coeff(lam,k-1,j)=coeff(lam,k,j);
	coeff(lam,k,j)=(long)p1;
      }
      if (fl[k])
      {
	for (i=k+1; i<=n; i++)
	{
	  bb=gcoeff(lam,i,k);
	  coeff(lam,i,k)=ldiv(gsub(gmul((GEN)B[k+1],gcoeff(lam,i,k-1)),gmul(la,bb)),(GEN)B[k]);
	  coeff(lam,i,k-1)=ldiv(gadd(gmul(la,gcoeff(lam,i,k-1)),gmul((GEN)B[k-1],bb)),(GEN)B[k]);
	 }
	B[k]=ldiv(gadd(p3,p4),(GEN)B[k]);
      }
      else
      {
	if (!gcmp0(la))
	{
	  p2=(GEN)B[k]; p1=gdiv(p4,p2);
	  for (i=k+1; i<lx; i++)
	    coeff(lam,i,k-1)=ldiv(gmul(la,gcoeff(lam,i,k-1)),p2);
	  for (j=k+1; j<lx-1; j++)
	    for (i=j+1; i<lx; i++)
	      coeff(lam,i,j)=ldiv(gmul(p1,gcoeff(lam,i,j)),p2);
	  B[k+1]=B[k]=(long)p1;
	  for (i=k+2; i<=lx; i++)
	    B[i]=ldiv(gmul(p1,(GEN)B[i]),p2);
	 }
	else
	{
	  coeff(lam,k,k-1)=zero;
	  for (i=k+1; i<lx; i++)
	  { coeff(lam,i,k)=coeff(lam,i,k-1); coeff(lam,i,k-1)=zero; }
	  B[k]=B[k-1]; fl[k]=1; fl[k-1]=0;
	 }
      }
      if (k>2) k--;
    }
    else
    {
      for (l=k-2; l>=1; l--)
      {
	u=gcoeff(lam,k,l);
	if (pslg(u)>=pslg((GEN)B[l+1]))
	{
	  q=gdeuc(u,(GEN)B[l+1]); cq=gdivsg(1,content(q));
          q=gmul(q,cq); flc=1;
	  h[k]=lsub(gmul(cq,(GEN)h[k]),gmul(q,(GEN)h[l]));
	  coeff(lam,k,l)=lsub(gmul(cq,gcoeff(lam,k,l)),gmul(q,(GEN)B[l+1]));
	  for (i=1; i<l; i++)
            coeff(lam,k,i)=lsub(gmul(cq,gcoeff(lam,k,i)),gmul(q,gcoeff(lam,l,i)));
	}
      }
      k++;
      if (k>n)
      {
	tetpil=avma; 
	return gerepile(av,tetpil,lllgramall_finish(h,fl,flag,n));
      }
    }
    if (low_stack(lim, (av+bot)>>1))
    {
      GEN *gptr[4];
      if(DEBUGMEM>1) err(warnmem,"lllgramallgen");
      gptr[0]=&B; gptr[1]=&lam; gptr[2]=&h;
      gerepilemany(av,gptr,3);
    }
  }
}

/* x est ici la matrice de GRAM des bi. Si probleme de precision, erreur si
   flag=0, retourne zero sans erreur si flag=1. */
GEN
lllgramintern(GEN x, long flag, long prec)
{
  GEN mu,u,B,BB,BK,p,q,r,cst,unreel,mu1,mu2,p1,A,s,p2,xinit,*gptr[6];
  long av0,av,tetpil,lim,l,i,j,k,k1,lx=lg(x),n,temp,e,kmax,l1,l2,cmpt;

  if (typ(x) != t_MAT) err(typeer,"lllgram");
  if (lg((GEN)x[1])!=lx) err(mattype1,"lllgram"); n=lx-1;
  if (n<=1) return idmat(n);
  av0=avma; cmpt=0; xinit=x;

LABLLLGRAM:
  av=avma; lim=(av+bot)>>1; 
  l1=2; cst=gdivgs(stoi(99),100); /* LLL proposent 0.75 */
  for (j=1; j<lx; j++)
  {
    p2=(GEN)x[j];
    for (i=1; i<lx; i++)
    {
    /* A MODIFIER lg <-> expo */
      if (typ(p2[i]) == t_REAL) { l2=lg((GEN)p2[i]); if (l2>l1) l1=l2; }
    }
  }
  if (l1>2)
  {
    if (prec>l1) l1=prec;
    l2 = (long)((l1-2)*pariK);
    x = gprec(x,l2);
    cst = gprec(cst,l2);
  }
  else
  {
    if (prec)
    { 
      affsr(1,unreel=cgetr(prec+1));
      x=gmul(x,unreel); cst=gmul(cst,unreel);
    }
    else { avma=av0; return lllgramint(x); }
  }

  mu=cgetg(lx,t_MAT); B=cgetg(lx,t_COL); A=cgetg(lx,t_VEC);
  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; A[j]=zero;
  }
  u=idmat(n); k=2; kmax=1; B[1]=coeff(x,1,1);
  if (DEBUGLEVEL>5) { fprintferr("k = %ld",k); flusherr(); }
  do
  {
    if (k>kmax)
    {
      if (DEBUGLEVEL>=4) {fprintferr(" K%ld",k);flusherr();}
      kmax=k;
      for (j=1; j<k; j++)
      {
	s=gzero; for (i=1; i<j; i++) s=gadd(s,gmul(gcoeff(mu,j,i),(GEN)A[i]));
	s=gsub(gcoeff(x,k,j),s);
	A[j]=(long)s;
	coeff(mu,k,j)=ldiv(s,(GEN)B[j]);
      }
      s=gzero; for (i=1; i<k; i++) s=gadd(s,gmul(gcoeff(mu,k,i),(GEN)A[i]));
      s=gsub(gcoeff(x,k,k),s); B[k]=(long)s;
      if (gsigne(s)<=0)
      {
	cmpt++; avma=av0;
	if (cmpt<2)
	{
	  x=xinit; prec=(prec<<1)-2; avma=av;
	  if(DEBUGLEVEL) err(warnprec,"lllgramintern",prec);
	  goto LABLLLGRAM;
	}
        if (flag) return NULL;
        if (DEBUGLEVEL) outerr(xinit);
        err(lllger3);
      }
    }
    if (DEBUGLEVEL>9)
      fprintferr(" %ld",gexpo(gcoeff(mu,k,k-1))-bit_accuracy(lg(gcoeff(mu,k,k-1))));
    mu1=gcoeff(mu,k,k-1);
    if (!gcmp0(mu1) && 2*gexpo(mu1) > bit_accuracy(lg(mu1)))
    {
      if (DEBUGLEVEL>9)
      {
	fprintferr("\nRecalcul de Gram Schmidt dans lllgram pour kmax = %ld\n Valeurs de B avant :\n",kmax); outerr(B);
      }
      for (k1=1; k1<=kmax; k1++)
      {
	for (j=1; j<k1; j++)
	{
	  s=gzero; for (i=1; i<j; i++) s=gadd(s,gmul(gcoeff(mu,j,i),(GEN)A[i]));
	  s=gsub(gcoeff(x,k1,j),s); A[j]=(long)s;
          coeff(mu,k1,j)=ldiv(s,(GEN)B[j]);
	}
	s=gzero; for (i=1; i<k1; i++) s=gadd(s,gmul(gcoeff(mu,k1,i),(GEN)A[i]));
	s=gsub(gcoeff(x,k1,k1),s); B[k1]=(long)s;
	if (gcmp0(s))
	{
	  cmpt++; avma=av0;
	  if (cmpt<2)
	  {
	    x=xinit; prec=(prec<<1)-2; avma=av;
	    if (DEBUGLEVEL) err(warnprec,"lllgramintern",prec);
            goto LABLLLGRAM;
	  }
          if (flag) return NULL;
          if (DEBUGLEVEL) outerr(xinit);
          err(lllger3);
	}
      }
      if (low_stack(lim, (av+bot)>>1))
      {
	if(DEBUGMEM>1) err(warnmem,"[1]: lllgram");
	gptr[0]=&B; gptr[1]=&u; gptr[2]=&mu; gptr[3]=&A;
        gerepilemany(av,gptr,4);
      }
      mu1=gcoeff(mu,k,k-1);
      if (DEBUGLEVEL>9){ fprintferr("Valeurs de B apres :\n"); outerr(B); }
    }
    if (!gcmp0(r=grndtoi(mu1,&e)))
    {
      r=negi(r);
      for (j=1; j<=kmax; j++) 
        coeff(u,j,k)=laddii(gcoeff(u,j,k),mulii(r,gcoeff(u,j,k-1)));
      for (j=1; j<=n; j++) 
        coeff(x,j,k)=ladd(gcoeff(x,j,k),gmul(r,gcoeff(x,j,k-1)));
      for (j=1; j<=n; j++)
        coeff(x,k,j)=ladd(gcoeff(x,k,j),gmul(r,gcoeff(x,k-1,j)));
      for (j=1; j<k-1; j++)
        coeff(mu,k,j)=ladd(gcoeff(mu,k,j),gmul(r,gcoeff(mu,k-1,j)));
      mu1=(GEN)(coeff(mu,k,k-1)=ladd(mu1,r));
    }
    if (DEBUGLEVEL>9)
      fprintferr("bits d'erreur d'arrondi dans lllgram: %ld",e);
    q=gmul((GEN)B[k-1],gsub(cst,mu2=gsqr(mu1)));
    if (gcmp(q,(GEN)B[k])>0)
    {
      if (DEBUGLEVEL>=4)
        if (k==kmax)
          { fprintferr(" (%ld)",gexpo(q)-gexpo((GEN)B[k])); flusherr(); }
      BB=gadd((GEN)B[k],gmul((GEN)B[k-1],mu2));
      coeff(mu,k,k-1)=ldiv(gmul(mu1,(GEN)B[k-1]),BB);
      B[k]=lmul((GEN)B[k-1],BK=gdiv((GEN)B[k],BB)); B[k-1]=(long)BB;
      temp=u[k]; u[k]=u[k-1]; u[k-1]=temp;
      temp=x[k]; x[k]=x[k-1]; x[k-1]=temp;
      for (j=1; j<=n; j++)
      { 
        temp=coeff(x,k,j);
        coeff(x,k,j)=coeff(x,k-1,j);
        coeff(x,k-1,j)=temp;
      }
      for (j=1; j<=k-2; j++)
      { 
        temp=coeff(mu,k,j);
        coeff(mu,k,j)=coeff(mu,k-1,j);
        coeff(mu,k-1,j)=temp;
      }
      for (i=k+1; i<=kmax; i++)
      {
	p=gcoeff(mu,i,k); coeff(mu,i,k)=lsub(gcoeff(mu,i,k-1),gmul(mu1,p));
	coeff(mu,i,k-1)=ladd(gmul(BK,p),gmul(gcoeff(mu,k,k-1),gcoeff(mu,i,k-1)));
      }
      if (k>2) k--;
      if (DEBUGLEVEL>5) { fprintferr(" %ld",k); flusherr(); }
      if (DEBUGLEVEL>9 && k==2)
      {
	fprintferr("\n");
	for (i=1; i<lx; i++)
	{
	  fprintferr("%ld : ",i); outerr(qfeval(x,(GEN)u[i]));
	}
      }
    }
    else
    {
      for (l=k-2; l; l--)
      {
	if (DEBUGLEVEL>9)
	  fprintferr(" %ld",gexpo(gcoeff(mu,k,l))-bit_accuracy (lg(gcoeff(mu,k,l))));
	if (!gcmp0(r=grndtoi(gcoeff(mu,k,l),&e)))
	{
	  r=negi(r);
	  for (j=1; j<=kmax; j++)
	    coeff(u,j,k)=laddii(gcoeff(u,j,k),mulii(r,gcoeff(u,j,l)));
	  for (j=1; j<=n; j++)
	    coeff(x,j,k)=ladd(gcoeff(x,j,k),gmul(r,gcoeff(x,j,l)));
	  for (j=1; j<=n; j++)
	    coeff(x,k,j)=ladd(gcoeff(x,k,j),gmul(r,gcoeff(x,l,j)));
	  for (j=1; j<l; j++)
	    coeff(mu,k,j)=ladd(gcoeff(mu,k,j),gmul(r,gcoeff(mu,l,j)));
	  coeff(mu,k,l)=ladd(gcoeff(mu,k,l),r);
	 }
	if (DEBUGLEVEL>9)
	  fprintferr("bits d'erreur d'arrondi dans lllgram: %ld",e);
      }
      k++; if (DEBUGLEVEL>5) { fprintferr(" %ld",k); flusherr(); }
      if (DEBUGLEVEL>9)
      {
	fprintferr("\n k = %ld\n",k);
	for (i=1; i<lx; i++)
	{
	  fprintferr("%ld : ",i); outerr(qfeval(x,(GEN)u[i]));
	}
      }
    }
    if (low_stack(lim, (av+bot)>>1))
    {
      if(DEBUGMEM>1) err(warnmem,"[2]: lllgram");
      gptr[0]=&B; gptr[1]=&u; gptr[2]=&mu; gptr[3]=&A;
      gptr[4]=&cst; gptr[5]=&x; gerepilemany(av,gptr,6);
    }
  }
  while (k<=n);
  tetpil=avma; return gerepile(av0,tetpil,gcopy(u));
}

static GEN
lllgram_noerr(GEN x,long prec) { return lllgramintern(x,1,prec); }

GEN
lllgram(GEN x,long prec) { return lllgramintern(x,0,prec); }

GEN
qflll0(GEN x, long flag, long prec)
{
  switch(flag)
  {
    case 0: return lll(x,prec);
    case 1: return lllint(x);
    case 2: return lllintpartial(x);
    case 3: return lllrat(x);
    case 4: return lllkerim(x);
    case 5: return lllkerimgen(x);
    case 7: return lll1(x,prec);
    case 8: return lllgen(x);
    case 9: return lllintwithcontent(x);
    default: err(flagerr);
  }
  return NULL; /* not reached */
}

GEN
qflllgram0(GEN x, long flag, long prec)
{
  switch(flag)
  {
    case 0: return lllgram(x,prec);
    case 1: return lllgramint(x);
    case 4: return lllgramkerim(x);
    case 5: return lllgramkerimgen(x);
    case 7: return lllgram1(x,prec);
    case 8: return lllgramgen(x);
    default: err(flagerr);
  }
  return NULL; /* not reached */
}

/* x est la matrice d'une base b_i; retourne la matrice u (entiere
 * unimodulaire) d'une base LLL-reduite c_i en fonction des b_i (la base
 * reduite est c=b*u).
 */
static GEN
lll_proto(GEN x, GEN f(GEN, long), long prec)
{
  long lx=lg(x),i,j,av,av1;
  GEN g;

  if (typ(x) != t_MAT) err(typeer,"lll_proto");
  if (lx==1) return cgetg(1,t_MAT);
  av=avma; g=cgetg(lx,t_MAT);
  for (j=1; j<lx; j++) g[j]=lgetg(lx,t_COL);
  for (i=1; i<lx; i++)
    for (j=1; j<=i; j++)
      coeff(g,i,j)=coeff(g,j,i)=(long)gscal((GEN)x[i],(GEN)x[j]);
  av1=avma; x = f(g,prec);
  if (!x) { avma=av; return NULL; }
  return gerepile(av,av1,x);
}

GEN
lllintern(GEN x,long flag,long prec)
{ 
  return lll_proto(x,flag? lllgram_noerr: lllgram,prec);
}

GEN
lll(GEN x,long prec) { return lll_proto(x,lllgram,prec); }

GEN
lll1(GEN x,long prec) { return lll_proto(x,lllgram1,prec); }

GEN
lllrat(GEN x) { return lll_proto(x,lllgram,lll_ALL); }

GEN
lllint(GEN x) { return lll_proto(x,lllgramall,lll_IM); }

GEN
lllgen(GEN x) { return lll_proto(x,lllgramallgen,lll_IM); }

GEN
lllgramgen(GEN x) { return lllgramallgen(x,lll_IM); }

GEN
lllgramkerimgen(GEN x) { return lllgramallgen(x,lll_ALL); }

static GEN
lllkerim_proto(GEN x, GEN f(GEN,long))
{
  long lx=lg(x), i,j,av,av1;
  GEN g;

  if (typ(x) != t_MAT) err(typeer,"lllkerim_proto");
  if (lx==1)
  {
    g=cgetg(3,t_VEC); g[1]=lgetg(1,t_MAT); g[2]=lgetg(1,t_MAT); return g;
  }
  if (lg((GEN)x[1])==1)
  {
    g=cgetg(3,t_VEC); g[1]=(long)idmat(lx-1); g[2]=lgetg(1,t_MAT); return g;
  }
  av=avma; g=cgetg(lx,t_MAT);
  for (j=1; j<lx; j++) g[j]=lgetg(lx,t_COL);
  for (i=1; i<lx; i++)
    for (j=1; j<=i; j++)
      coeff(g,i,j)=coeff(g,j,i)=(long)gscal((GEN)x[i],(GEN)x[j]);
  av1=avma; return gerepile(av,av1,f(g,lll_ALL));
}

GEN
lllkerim(GEN x) { return lllkerim_proto(x,lllgramall); }

GEN
lllkerimgen(GEN x) { return lllkerim_proto(x,lllgramallgen); }

#if 0
/* x est ici la matrice de GRAM des bi. */
GEN
lllgramold(GEN x, long prec)
{
  GEN mu,u,B,BB,BK,p,q,r,cst,unreel,sv,mu1,mu2;
  long av,tetpil,lim,l,i,j,k,lx=lg(x),n,temp,e;

  if (typ(x) != t_MAT) err(typeer,"lllgramold");
  if (lg((GEN)x[1])!=lx) err(mattype1,"lllgramold"); n=lx-1;
  if (n<=1) return idmat(n);
  cst=gdivgs(stoi(99),100);
  if (prec)
  {
    affsr(1,unreel=cgetr(prec+1));
    x=gmul(x,unreel);
    cst=gmul(cst,unreel);
  }
  av=avma; lim=(av+bot)>>1;
  mu=sqred3(x); B=cgetg(lx,t_COL);
  for (i=1,l=0; i<=n; i++)
  {
    if (gsigne((GEN)(B[i]=coeff(mu,i,i)))>0) l++;
    coeff(mu,i,i)=un;
  }
  if (l<n)
  {
    if (DEBUGLEVEL) outerr(x);
    err(lllger3);
  }
  u=idmat(n);
  k=2;
  do
  {
    if (!gcmp0(r=grndtoi(gcoeff(mu,k,k-1),&e)))
    {
      u[k]=lsub((GEN)u[k],gmul(r,(GEN)u[k-1]));
      for (j=1; j<k-1; j++)
	coeff(mu,k,j)=lsub(gcoeff(mu,k,j),gmul(r,gcoeff(mu,k-1,j)));
      mu1=(GEN)(coeff(mu,k,k-1)=lsub(gcoeff(mu,k,k-1),r));
    }
    else mu1=gcoeff(mu,k,k-1);
    q=gmul((GEN)B[k-1],gsub(cst,mu2=gsqr(mu1)));
    if (gcmp(q,(GEN)B[k])>0)
    {
      BB=gadd((GEN)B[k],gmul((GEN)B[k-1],mu2));
      coeff(mu,k,k-1)=ldiv(gmul(mu1,(GEN)B[k-1]),BB);
      B[k]=lmul((GEN)B[k-1],BK=gdiv((GEN)B[k],BB));
      B[k-1]=(long)BB;
      temp=u[k]; u[k]=u[k-1]; u[k-1]=temp;
      for (j=1; j<=k-2; j++)
      {
	temp=(long)coeff(mu,k,j); coeff(mu,k,j)=coeff(mu,k-1,j);
	coeff(mu,k-1,j)=temp;
      }
      for (i=k+1; i<=n; i++)
      {
	p=gcoeff(mu,i,k);
	coeff(mu,i,k)=lsub(gcoeff(mu,i,k-1),gmul(mu1,p));
	coeff(mu,i,k-1)=ladd(gmul(BK,p),gmul(gcoeff(mu,k,k-1),gcoeff(mu,i,k-1)));
      }
      if (k>2) k--;
    }
    else
    {
      for (l=k-2; l; l--)
      {
	if (!gcmp0(r=grndtoi(gcoeff(mu,k,l),&e)))
	{
	  u[k]=lsub((GEN)u[k],gmul(r,(GEN)u[l]));
	  for (j=1; j<l; j++)
	    coeff(mu,k,j)=lsub(gcoeff(mu,k,j),gmul(r,gcoeff(mu,l,j)));
	  coeff(mu,k,l)=lsub(gcoeff(mu,k,l),r);
	 }
      }
      k++;
    }
    if (low_stack(lim, (av+bot)>>1))
    {
      if(DEBUGMEM>1) err(warnmem,"lllgramold");
      tetpil=avma;
      sv=cgetg(4,t_VEC);
      sv[1]=lcopy(B); sv[2]=lcopy(u); sv[3]=lcopy(mu);
      sv=gerepile(av,tetpil,sv);
      B=(GEN)sv[1]; u=(GEN)sv[2]; mu=(GEN)sv[3];
    }
  }
  while (k<=n);
  tetpil=avma; return gerepile(av,tetpil,gcopy(u));
}

/* x est ici la matrice de GRAM des bi.  */
GEN
lllgram_new(GEN x, long prec)
/* A DEBBUGER ...  A DEBBUGER ...  A DEBBUGER ...  A DEBBUGER ...  */
{
  GEN mu,u,B,BB,BK,p,q,r,cst,unreel,mu1,mu2,p1,A,s,p2,eps;
  GEN *gptr[6];
  long av0,av,tetpil,lim,l,i,j,k,k1,lx=lg(x),n,temp,e,kmax,l1,l2,cmpt;

  if (typ(x) != t_MAT) err(typeer,"lllgram_new");
  if (lg((GEN)x[1])!=lx) err(mattype1,"lllgram_new"); n=lx-1;
  if (n<=1) return idmat(n);
  av0=avma; cmpt=0; u=idmat(n); eps=dbltor(0.00000001);

LABLLLGRAM:
  av=avma; lim=(av+bot)>>1;
  l1=2; cst=gdivgs(stoi(99),100); /* LLL proposent 0.75 */
  for (j=1; j<lx; j++)
  {
    p2=(GEN)x[j];
    for (i=1; i<lx; i++)
      if (typ(p2[i])==t_REAL) { l2=lg((GEN)p2[i]); if (l2>l1) l1=l2; }
  }
  if (l1>2)
  {
    if (prec>l1) l1=prec;
    l2=(long)((l1-2)*pariK); x=gprec(x,l2); cst=gprec(cst,l2);
  }
  else
  {
    if (prec)
    {
      affsr(1, unreel=cgetr(prec+1)); x=gmul(x,unreel); cst=gmul(cst,unreel);
    }
    else { avma=av0; return lllgramint(x); }
  }
  mu=cgetg(lx,t_MAT); B=cgetg(lx,t_COL); A=cgetg(lx,t_VEC);
  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; A[j]=zero;
  }
  k=2; kmax=1; B[1]=coeff(x,1,1);
  if (DEBUGLEVEL>5) { fprintferr("k = %ld",k); flusherr(); }
  do
  {
    if (k>kmax)
    {
      kmax=k;
      for (j=1; j<k; j++)
      {
	s=gzero; for (i=1; i<j; i++) s=gadd(s,gmul(gcoeff(mu,j,i),(GEN)A[i]));
	s=gsub(gcoeff(x,k,j),s); A[j]=(long)s; coeff(mu,k,j)=ldiv(s,(GEN)B[j]);
      }
      s=gzero; for (i=1; i<k; i++) s=gadd(s,gmul(gcoeff(mu,k,i),(GEN)A[i]));
      s=gsub(gcoeff(x,k,k),s); B[k]=(long)s;
      if (gcmp(gabs(s,prec),eps)<0)
      {
	cmpt++;
	if (cmpt<3)
	{
	  tetpil=avma; x=gmul(x,u); u=gcopy(u);
	  gptr[0]=&x; gptr[1]=&u; gerepilemanysp(av,tetpil,gptr,2);
	  prec=(prec<<1)-2; goto LABLLLGRAM;
	}
	else { if (DEBUGLEVEL) outerr(x); avma=av0; err(lllger3); }
      }
    }
    if (DEBUGLEVEL>9)
      fprintferr(" %ld",gexpo(gcoeff(mu,k,k-1))-bit_accuracy(lg(gcoeff(mu,k,k-1))));
    mu1=gcoeff(mu,k,k-1);
    if (!gcmp0(mu1) && 2*gexpo(mu1) > bit_accuracy(lg(mu1)-2))
    {
      if (DEBUGLEVEL>9)
      {
	fprintferr("\nRecalcul de Gram Schmidt dans lllgram pour kmax = %ld\n Valeurs de B avant :\n",kmax); outerr(B);
      }
      for (k1=1; k1<=kmax; k1++)
      {
	for (j=1; j<k1; j++)
	{
	  s=gzero;
	  for (i=1; i<j; i++)
	    s=gadd(s,gmul(gcoeff(mu,j,i),(GEN)A[i]));
	  s=gsub(gcoeff(x,k1,j),s); A[j]=(long)s;
	  coeff(mu,k1,j)=ldiv(s,(GEN)B[j]);
	 }
	s=gzero;
	for (i=1; i<k1; i++)
	  s=gadd(s,gmul(gcoeff(mu,k1,i),(GEN)A[i]));
	s=gsub(gcoeff(x,k1,k1),s); B[k1]=(long)s;
	if (gcmp(gabs(s,prec),eps)<0)
	{
	  cmpt++;
	  if (cmpt<3)
	  {
	    tetpil=avma; x=gmul(x,u); u=gcopy(u);
	    gptr[0]=&x; gptr[1]=&u; gerepilemanysp(av,tetpil,gptr,2);
	    prec=(prec<<1)-2; goto LABLLLGRAM;
	  }
	  else{ if (DEBUGLEVEL) outerr(x); avma=av0; err(lllger3); }
	 }
      }
      if (low_stack(lim, (av+bot)>>1))
      {
	if(DEBUGMEM>1) err(warnmem,"[1]: lllgram_new");
	gptr[0]=&B; gptr[1]=&u; gptr[2]=&mu; gptr[3]=&A;
	gerepilemany(av,gptr,4);
      }
      mu1=gcoeff(mu,k,k-1);
      if (DEBUGLEVEL>9){ fprintferr("Valeurs de B apres :\n"); outerr(B); }
    }
    if (!gcmp0(r=grndtoi(mu1,&e)))
    {
      r=negi(r);
      for (j=1; j<=kmax; j++)
	coeff(u,j,k)=laddii(gcoeff(u,j,k),mulii(r,gcoeff(u,j,k-1)));
      for (j=1; j<=n; j++)
	coeff(x,j,k)=ladd(gcoeff(x,j,k),gmul(r,gcoeff(x,j,k-1)));
      for (j=1; j<=n; j++)
	coeff(x,k,j)=ladd(gcoeff(x,k,j),gmul(r,gcoeff(x,k-1,j)));
      for (j=1; j<k-1; j++)
	coeff(mu,k,j)=ladd(gcoeff(mu,k,j),gmul(r,gcoeff(mu,k-1,j)));
      mu1=(GEN)(coeff(mu,k,k-1)=ladd(mu1,r));
    }
    if (DEBUGLEVEL>9) fprintferr("bits d'erreur d'arrondi dans lllgram: %ld",e);
    q=gmul((GEN)B[k-1],gsub(cst,mu2=gsqr(mu1)));
    if (gcmp(q,(GEN)B[k])>0)
    {
      if (DEBUGLEVEL>4 && k==n)
      { fprintferr("ex = %ld",gexpo(gsub(q,(GEN)B[k]))); flusherr(); }
      BB=gadd((GEN)B[k],gmul((GEN)B[k-1],mu2));
      coeff(mu,k,k-1)=ldiv(gmul(mu1,(GEN)B[k-1]),BB);
      B[k]=lmul((GEN)B[k-1],BK=gdiv((GEN)B[k],BB)); B[k-1]=(long)BB;
      temp=u[k]; u[k]=u[k-1]; u[k-1]=temp;
      temp=x[k]; x[k]=x[k-1]; x[k-1]=temp;
      for (j=1; j<=n; j++)
      { 
	temp=coeff(x,k,j); coeff(x,k,j)=coeff(x,k-1,j);
	coeff(x,k-1,j)=temp;
      }
      for (j=1; j<=k-2; j++)
      {
	temp=coeff(mu,k,j); coeff(mu,k,j)=coeff(mu,k-1,j);
	coeff(mu,k-1,j)=temp;
      }
      for (i=k+1; i<=kmax; i++)
      {
	p=gcoeff(mu,i,k); coeff(mu,i,k)=lsub(gcoeff(mu,i,k-1),gmul(mu1,p));
	coeff(mu,i,k-1)=ladd(gmul(BK,p),gmul(gcoeff(mu,k,k-1),gcoeff(mu,i,k-1)));
      }
      if (k>2) k--;
      if (DEBUGLEVEL>5) { fprintferr(" %ld",k); flusherr(); }
      if (DEBUGLEVEL>9 && k==2)
      {
	fprintferr("\n");
	for (i=1; i<lx; i++)
	{
	  fprintferr("%ld : ",i); outerr(qfeval(x,(GEN)u[i]));
	}
      }
    }
    else
    {
      for (l=k-2; l; l--)
      {
	if (DEBUGLEVEL>9)
	  fprintferr(" %ld",gexpo(gcoeff(mu,k,l))-bit_accuracy(lg(gcoeff(mu,k,l))));
	if (!gcmp0(r=grndtoi(gcoeff(mu,k,l),&e)))
	{
	  r=negi(r);
	  for (j=1; j<=kmax; j++)
	    coeff(u,j,k)=laddii(gcoeff(u,j,k),mulii(r,gcoeff(u,j,l)));
	  for (j=1; j<=n; j++)
	    coeff(x,j,k)=ladd(gcoeff(x,j,k),gmul(r,gcoeff(x,j,l)));
	  for (j=1; j<=n; j++)
	    coeff(x,k,j)=ladd(gcoeff(x,k,j),gmul(r,gcoeff(x,l,j)));
	  for (j=1; j<l; j++)
	    coeff(mu,k,j)=ladd(gcoeff(mu,k,j),gmul(r,gcoeff(mu,l,j)));
	  coeff(mu,k,l)=ladd(gcoeff(mu,k,l),r);
	 }
	if (DEBUGLEVEL>9) fprintferr("bits d'erreur d'arrondi dans lllgram: %ld",e);
      }
      k++;
      if (DEBUGLEVEL>5) { fprintferr(" %ld",k); flusherr(); }
      if (DEBUGLEVEL>9)
      {
	fprintferr("\n k = %ld\n",k);
	for (i=1; i<lx; i++)
	{ 
	  fprintferr("%ld : ",i); outerr(qfeval(x,(GEN)u[i]));
	}
      }
    }
    if (low_stack(lim, (av+bot)>>1))
    {
      if(DEBUGMEM>1) err(warnmem,"[2]: lllgram_new");
      gptr[0]=&B; gptr[1]=&u; gptr[2]=&mu; gptr[3]=&A;
      gptr[4]=&cst; gptr[5]=&x; gerepilemany(av,gptr,6);
    }
  }
  while (k<=n);
  tetpil=avma; return gerepile(av0,tetpil,gcopy(u));
}
#endif

/* x est ici la matrice de GRAM des bi.  */
GEN
lllgram1(GEN x, long prec)
{
  GEN mu,u,B,BB,BK,p,q,r,cst,unreel,sv,mu1,mu2;
  long av,tetpil,lim,l,i,j,k,lx=lg(x),n,temp,e;

  if (typ(x) != t_MAT) err(typeer,"lllgram1");
  if (lg((GEN)x[1])!=lx) err(mattype1,"lllgram1"); n=lx-1;
  if (n<=1) return idmat(n);
  cst=gdivgs(stoi(99),100); /* LLL proposent 0.75 */
  if (prec)
  {
    affsr(1,unreel=cgetr(prec+1));
    x=gmul(x,unreel);
    cst=gmul(cst,unreel);
  }
  av=avma; lim=(av+bot)>>1;
  mu=gtrans(sqred(x)); B=cgetg(lx,t_COL);
  for (i=1,l=0; i<=n; i++)
  {
    if (gsigne((GEN)(B[i]=coeff(mu,i,i)))>0) l++;
    coeff(mu,i,i)=un;
  }
  if (l<n) err(lllger3);

  u=idmat(n); k=2;
  do
  {
    if (!gcmp0(r=grndtoi(gcoeff(mu,k,k-1),&e)))
    {
      u[k]=lsub((GEN)u[k],gmul(r,(GEN)u[k-1]));
      for (j=1; j<k-1; j++)
	coeff(mu,k,j)=lsub(gcoeff(mu,k,j),gmul(r,gcoeff(mu,k-1,j)));
      mu1=(GEN)(coeff(mu,k,k-1)=lsub(gcoeff(mu,k,k-1),r));
    }
    else mu1=gcoeff(mu,k,k-1);
    q=gmul((GEN)B[k-1],gsub(cst,mu2=gsqr(mu1)));
    if (gcmp(q,(GEN)B[k])>0)
    {
      BB=gadd((GEN)B[k],gmul((GEN)B[k-1],mu2));
      coeff(mu,k,k-1)=ldiv(gmul(mu1,(GEN)B[k-1]),BB);
      B[k]=lmul((GEN)B[k-1],BK=gdiv((GEN)B[k],BB));
      B[k-1]=(long)BB;
      temp=u[k]; u[k]=u[k-1]; u[k-1]=temp;
      for (j=1; j<=k-2; j++)
      {
	temp=(long)coeff(mu,k,j); coeff(mu,k,j)=coeff(mu,k-1,j);
	coeff(mu,k-1,j)=temp;
      }
      for (i=k+1; i<=n; i++)
      {
	p=gcoeff(mu,i,k);
	coeff(mu,i,k)=lsub(gcoeff(mu,i,k-1),gmul(mu1,p));
	coeff(mu,i,k-1)=ladd(gmul(BK,p),gmul(gcoeff(mu,k,k-1),gcoeff(mu,i,k-1)));
      }
      if (k>2) k--;
    }
    else
    {
      for (l=k-2; l; l--)
      {
	if (!gcmp0(r=grndtoi(gcoeff(mu,k,l),&e)))
	{
	  u[k]=lsub((GEN)u[k],gmul(r,(GEN)u[l]));
	  for (j=1; j<l; j++)
	    coeff(mu,k,j)=lsub(gcoeff(mu,k,j),gmul(r,gcoeff(mu,l,j)));
	  coeff(mu,k,l)=lsub(gcoeff(mu,k,l),r);
	 }
      }
      k++;
    }
    if (low_stack(lim, (av+bot)>>1))
    {
      if(DEBUGMEM>1) err(warnmem,"lllgram1");
      tetpil=avma;
      sv=cgetg(4,t_VEC);
      sv[1]=lcopy(B); sv[2]=lcopy(u); sv[3]=lcopy(mu);
      sv=gerepile(av,tetpil,sv);
      B=(GEN)sv[1]; u=(GEN)sv[2]; mu=(GEN)sv[3];
    }
  }
  while (k<=n);
  tetpil=avma; return gerepile(av,tetpil,gcopy(u));
}

#if 0
GEN
lllgramintindep(GEN x)
{
  long av=avma,tetpil,lx=lg(x),i,j,k,l,p1,n,lim;
  GEN u,B,lam,q,r,h,la,bb,sv;

  if (typ(x) != t_MAT) err(typeer,"lllgramintindep");
  n=lx-1; if (n<=1) return idmat(n);
  if (lg((GEN)x[1])!=lx) err(mattype1,"lllgramintindep");
  av=avma; lim=(avma+bot)>>1;
  B=cgetg(lx+1,t_COL);
  B[1]=un; lam=cgetg(lx,t_MAT);
  for (j=1; j<=n; j++) lam[j]=lgetg(lx,t_COL);
  for (i=1; i<=n; i++)
    for (j=1; j<=i; j++)
    {
      u=gcoeff(x,i,j);
      if (typ(u)!=t_INT) err(lllger4);
      for (k=1; k<j; k++)
	u=divii(subii(mulii((GEN)B[k+1],u),mulii(gcoeff(lam,i,k),gcoeff(lam,j,k))),(GEN)B[k]);
      if (j<i) coeff(lam,i,j)=(long)u;
      else
      {
	if (signe(u)) B[i+1]=(long)u;
	else err(talker,"linearly dependant vectors in lllintold");
      }
      coeff(lam,j,i)=zero;
    }
  k=2; h=idmat(n);
  for(;;)
  {
    if (cmpii(absi(u=shifti(gcoeff(lam,k,k-1),1)),(GEN)B[k])>0)
    {
      q=dvmdii(addii(u,(GEN)B[k]),shifti((GEN)B[k],1),&r);
      if (signe(r)<0) q=addsi(-1,q);
      h[k]=lsub((GEN)h[k],gmul(q,(GEN)h[k-1]));
      coeff(lam,k,k-1)=laddii(gcoeff(lam,k,k-1),mulii(r,(GEN)B[k]));
      for (i=1; i<k-1; i++) coeff(lam,k,i)=laddii(gcoeff(lam,k,i),mulii(r,gcoeff(lam,k-1,i)));
    }
    if (cmpii(mulsi(99,sqri((GEN)B[k])),mulsi(100,addii(mulii((GEN)B[k-1],(GEN)B[k+1]),mulii(gcoeff(lam,k,k-1),gcoeff(lam,k,k-1)))))>0)
    {
      la=gcoeff(lam,k,k-1); p1=h[k-1]; h[k-1]=h[k]; h[k]=p1;
      for (j=1; j<=k-2; j++)
      {
	p1=(long)coeff(lam,k-1,j); coeff(lam,k-1,j)=coeff(lam,k,j);
	coeff(lam,k,j)=p1;
      }
      for (i=k+1; i<=n; i++)
      {
	bb=gcoeff(lam,i,k);
	coeff(lam,i,k)=ldivii(subii(mulii((GEN)B[k+1],gcoeff(lam,i,k-1)),mulii(la,bb)),(GEN)B[k]);
	coeff(lam,i,k-1)=ldivii(addii(mulii(la,gcoeff(lam,i,k-1)),mulii((GEN)B[k-1],bb)),(GEN)B[k]);
      }
      B[k]=ldivii(addii(mulii((GEN)B[k-1],(GEN)B[k+1]),mulii(la,la)),(GEN)B[k]);
      if (k>2) k--;
    }
    else
    {
      for (l=k-2; l>=1; l--)
      {
	if (cmpii(absi(u=shifti(gcoeff(lam,k,l),1)),(GEN)B[l+1])>0)
	{
	  q=dvmdii(addii(u,(GEN)B[l+1]),shifti((GEN)B[l+1],1),&r);
	  if (signe(r)<0) q=addsi(-1,q);
	  h[k]=lsub((GEN)h[k],gmul(q,(GEN)h[l]));
	  coeff(lam,k,l)=lsubii(gcoeff(lam,k,l),mulii(q,(GEN)B[l+1]));
	  for (i=1; i<l; i++) coeff(lam,k,i)=lsubii(gcoeff(lam,k,i),mulii(q,gcoeff(lam,l,i)));
	 }
      }
      k++;
      if (k>n) { tetpil=avma; return gerepile(av,tetpil,gcopy(h)); }
    }
    if (low_stack(lim, (av+bot)>>1))
    {
      if(DEBUGMEM>1) err(warnmem,"lllgramintindep");
      tetpil=avma;
      sv=cgetg(4,t_VEC);
      sv[1]=lcopy(B); sv[2]=lcopy(h); sv[3]=lcopy(lam);
      sv=gerepile(av,tetpil,sv);
      B=(GEN)sv[1]; h=(GEN)sv[2]; lam=(GEN)sv[3];
    }
  }
}
#endif

GEN
lllgramint(GEN x)
{
  return lllgramall(x,lll_IM);
}

GEN
lllgramkerim(GEN x)
{
  return lllgramall(x,lll_ALL);
}

/*  This routine is functionally similar to lllint when all = 0.
 *
 *    The input is an integer matrix mat (not necessarily square) whose
 *  columns are linearly independent.  It outputs another matrix T such that
 *  mat * T is partially reduced.  If all = 0, the size of mat * T is the
 *  same as the size of mat.  If all = 1 the number of columns of mat * T
 *  is at most equal to its number of rows.  A matrix M is said to be
 *  -partially reduced- if | m1 +- m2 | >= |m1| for any two distinct
 *  columns m1, m2, in M.
 *
 *    This routine is designed to quickly reduce lattices in which one row
 *  is huge compared to the other rows.  For example, when searching for a
 *  polynomial of degree 3 with root a mod p, the four input vectors might
 *  be the coefficients of
 *      X^3 - (a^3 mod p), X^2 - (a^2 mod p), X - (a mod p), p.
 *  All four constant coefficients are O(p) and the rest are O(1). By the
 *  pigeon-hole principle, the coefficients of the smallest vector in the
 *  lattice are O(p^(1/4)), Hence significant reduction of vector lengths
 *  can be anticipated.
 *
 *  		Peter Montgomery (July, 1994)
 */
static GEN
lllintpartialall(GEN mat, long all)
{
  const long ncol = lg(mat)-1;
  const long ltop1 = avma;
  long ncolnz;
  GEN tmat1, tmat2, matmid, *gptr[4];

  if (typ(mat) != t_MAT) err(typeer,"lllintpartialall");

  if (ncol <= 1) return idmat(ncol);
  else
  {
    GEN dot11 = sqscal((GEN)mat[1]);
    GEN dot22 = sqscal((GEN)mat[2]);
    GEN dot12 = gscal((GEN)mat[1], (GEN)mat[2]);
    GEN tmat  = idmat(2); /* For first two columns only */

    int progress = 0;
    long npass2 = 0;

/* Try to row reduce the first two columns of mat.
 * Our best result so far is (first two columns of mat)*tmat.
 *
 * Initially tmat = 2 x 2 identity matrix.
 * The inner products of the reduced matrix are in
 * dot11, dot12, dot22.
 */
    while (npass2 < 2 || progress)
    {
      GEN gtemp;
      GEN q = gdivround(dot12, dot22);

      npass2++; progress = signe(q);
      if (progress)
      {
       /* Conceptually replace (v1, v2) by (v1 - q*v2, v2),
        * where v1 and v2 represent the reduced basis for the
        * first two columns of the matrix.
        *
        * We do this by updating tmat and the inner products.
        *
        * An improved algorithm would look only at the leading
        * digits of dot11, dot12, dot22.  It would use
        * single-precision calculations as much as possible.
        */
        GEN dot12new = subii(dot12, mulii(q, dot22));

        dot11 = subii(dot11, mulii(q, addii(dot12, dot12new)));
        dot12 = dot12new;
        tmat[1] = lsub((GEN)tmat[1], gmul(q, (GEN)tmat[2]));
      }

      /* Interchange the output vectors v1 and v2.  */
      gtemp = dot11; dot11 = dot22; dot22 = gtemp;
      gtemp = (GEN)tmat[1]; tmat[1] = tmat[2]; tmat[2] = (long)gtemp;

      /* Occasionally (including final pass) do garbage collection.  */
      if (npass2 % 8 == 0 || !progress)
      {
        gptr[0] = &dot11; gptr[1] = &dot12;
        gptr[2] = &dot22; gptr[3] = &tmat;
        gerepilemany(ltop1, gptr, 4);
      }
    } /* while npass2 < 2 || progress */

    {
      long icol;
      GEN det12 = gsub(gmul(dot11, dot22), gmul(dot12, dot12));

      tmat1 = idmat(ncol);
      matmid = cgetg(ncol+1, t_MAT);
      for (icol = 1; icol <= 2; icol++)
      {
        coeff(tmat1, 1, icol) = coeff(tmat, 1, icol);
	coeff(tmat1, 2, icol) = coeff(tmat, 2, icol);
        matmid[icol] = ladd(gmul((GEN)mat[1], gcoeff(tmat, 1, icol)),
                            gmul((GEN)mat[2], gcoeff(tmat, 2, icol)) );
      }
      for (icol = 3; icol <= ncol; icol++)
      {
        GEN curcol = (GEN)mat[icol];
	GEN dot1i = gscal((GEN)matmid[1], curcol);
        GEN dot2i = gscal((GEN)matmid[2], curcol);
       /* Try to solve
        *
        * ( dot11  dot12 ) (q1)    ( dot1i )
        * ( dot12  dot22 ) (q2)  = ( dot2i )
        *
        * Round -q1 and -q2 to the nearest integer.
        * Then compute curcol - q1*matmid[1] - q2*matmid[2].
        * This will be approximately orthogonal to the
        * first two vectors in the new basis.
        */
	GEN q1neg = gsub(gmul(dot12, dot2i), gmul(dot22, dot1i));
        GEN q2neg = gsub(gmul(dot12, dot1i), gmul(dot11, dot2i));

        q1neg = gdivround(q1neg, det12);
        q2neg = gdivround(q2neg, det12);
        coeff(tmat1, 1, icol) = ladd(gmul(q1neg, gcoeff(tmat, 1, 1)),
				     gmul(q2neg, gcoeff(tmat, 1, 2)));
        coeff(tmat1, 2, icol) = ladd(gmul(q1neg, gcoeff(tmat, 2, 1)),
				     gmul(q2neg, gcoeff(tmat, 2, 2)));
        matmid[icol] = ladd(curcol, gadd(gmul(q1neg, (GEN)matmid[1]),
                                         gmul(q2neg, (GEN)matmid[2])));
      } /* for icol */
    } /* local block */
  } /* else  ncol > 1*/
  if (DEBUGLEVEL>4)
  {
    fprintferr("tmat1 = "); outbeauterr(tmat1);
    fprintferr("matmid = "); outbeauterr(matmid);
  }
  gptr[0] = &tmat1; gptr[1] = &matmid;
  gerepilemany(ltop1, gptr, 2);
  {
   /* For each pair of column vectors v and w in matmid * tmat2,
    * try to replace (v, w) by (v, v - q*w) for some q.
    * We compute all inner products and check them repeatedly.
    */
    const long ltop3 = avma; /* Excludes region with tmat1 and matmid */
    long icol, lim, reductions, npass = 0;
    GEN dotprd = cgetg(ncol+1, t_MAT);

    tmat2 = idmat(ncol);
    for (icol = 1; icol <= ncol; icol++)
    {
      long jcol;

      dotprd[icol] = lgetg(ncol+1,t_COL);
      for (jcol = 1; jcol <= icol; jcol++)
      {
	coeff(dotprd, icol, jcol) = (long)gscal((GEN)matmid[icol],
			                        (GEN)matmid[jcol]);
	coeff(dotprd, jcol, icol) = coeff(dotprd, icol, jcol);
      }	/* for jcol */
    }  /* for icol */
    lim = (ltop3+bot)>>1;
    for(;;)
    {
      reductions = 0;
      for (icol = 1; icol <= ncol; icol++)
      {
	long ijdif, jcol, k1, k2;
	GEN codi, q;

        for (ijdif = 1; ijdif < ncol; ijdif++)
	{
          const long previous_avma = avma;

          jcol = (icol + ijdif - 1) % ncol; jcol++; /* Hack for NeXTgcc 2.5.8 */
          k1 = (gcmp(gcoeff(dotprd, icol, icol),
		     gcoeff(dotprd, jcol, jcol) ) > 0)
		? icol : jcol; 	/* index of larger column */
	  k2 = icol + jcol - k1; 	/* index of smaller column */
	  codi = gcoeff(dotprd, k2, k2);
	  q = gcmp0(codi)? gzero: gdivround(gcoeff(dotprd, k1, k2), codi);

	  /* Try to subtract a multiple of column k2 from column k1.  */
	  if (gcmp0(q)) avma = previous_avma;
          else
	  {
	    long dcol;

	    reductions++;
            if (gcmp1(q))
	    {   /* Case q = +1 */
	      tmat2[k1] = lsub((GEN)tmat2[k1], (GEN)tmat2[k2]);
	      dotprd[k1] = lsub((GEN)dotprd[k1], (GEN)dotprd[k2]);
	      coeff(dotprd, k1, k1) = lsub(gcoeff(dotprd, k1, k1),
				           gcoeff(dotprd, k2, k1));
	    }
	    else if (gcmp_1(q))
	    { 	/* Case q = -1 */
	      tmat2[k1] = ladd((GEN)tmat2[k1], (GEN)tmat2[k2]);
	      dotprd[k1] = ladd((GEN)dotprd[k1], (GEN)dotprd[k2]);
	      coeff(dotprd, k1, k1) = ladd(gcoeff(dotprd, k1, k1),
				           gcoeff(dotprd, k2, k1));
            }
	    else
	    { 	/* General q   */
	      tmat2[k1] = lsub((GEN)tmat2[k1], gmul(q, (GEN)tmat2[k2]));
	      dotprd[k1] = lsub((GEN)dotprd[k1], gmul(q, (GEN)dotprd[k2]));
	      coeff(dotprd, k1, k1) = lsub(gcoeff(dotprd, k1, k1),
				         gmul(q, gcoeff(dotprd, k2, k1)));
            }
	    for (dcol = 1; dcol <= ncol; dcol++)
	      coeff(dotprd, k1, dcol) = coeff(dotprd, dcol, k1);
	  } /* if q != 0 */
        } /* for ijdif */
        if (low_stack(lim, (ltop3+bot)>>1))
	{
          if(DEBUGMEM>1) err(warnmem,"lllintpartialall");
	  gptr[0] = &dotprd; gptr[1] = &tmat2;
	  gerepilemany(ltop3, gptr, 2);
        }
      } /* for icol */
      if (!reductions) break;
      if (DEBUGLEVEL>4)
      {
	GEN diag_prod = dbltor(1.0);
	for (icol = 1; icol <= ncol; icol++)
	  diag_prod = gmul(diag_prod, gcoeff(dotprd,icol,icol));
        npass++;
	fprintferr("npass = %ld, red. last time = %ld, diag_prod = %Z\n\n",
	            npass, reductions, (long)diag_prod);
      }
    } /* for(;;)*/

   /* Sort columns so smallest comes first in mat * tmat1 * tmat2.
    * Use insertion sort.
    */
    for (icol = 1; icol < ncol; icol++)
    {
      long jcol, smallest = icol;

      for (jcol = icol+1; jcol <= ncol; jcol++)
      {
	if (gcmp(gcoeff(dotprd,smallest,smallest),gcoeff(dotprd,jcol,jcol)) > 0)
	  smallest = jcol;
      }
      if (icol != smallest)
      { /* Exchange with proper column */
        /* Only diagonal of dotprd is updated */
	long ltemp;

        ltemp = tmat2[icol];
        tmat2[icol] = tmat2[smallest];
        tmat2[smallest] = ltemp;

        ltemp = coeff(dotprd, icol, icol);
        coeff(dotprd, icol, icol) = coeff(dotprd, smallest, smallest);
        coeff(dotprd, smallest, smallest) = ltemp;
      }
    } /* for icol */
    icol=1;
    while (icol <= ncol && gcmp0(gcoeff(dotprd, icol, icol))) icol++;
    ncolnz = ncol - icol + 1;
  } /* local block */

  {
    long lbot = avma;
    if (DEBUGLEVEL>4)
    {
      fprintferr("lllintpartial output = ");
      outbeauterr(gmul(matmid, tmat2));
      fprintferr("tmat1 = "); outbeauterr(tmat1);
      fprintferr("tmat2 = "); outbeauterr(tmat2);
    }
    if (all) return gerepile(ltop1, lbot, gmul(tmat1,tmat2));
    if (ncolnz == lg((GEN)mat[1])-1)
    {
      long icol;
      GEN tmat = cgetg(ncolnz+1,t_MAT);

      for (icol = 1; icol <= ncolnz; icol++)
	tmat[icol] = tmat2[icol + ncol - ncolnz];
      lbot = avma;
      return gerepile(ltop1, lbot, gmul(tmat1, tmat));
    }
    else
    {
      GEN tmat = gmul(mat, gmul(tmat1, tmat2));
      lbot = avma;
      return gerepile(ltop1, lbot, lllint(tmat));
    }
  }
}

GEN
lllintpartial(GEN mat)
{
  return lllintpartialall(mat,0);
}

/********************************************************************/
/**                                                                **/
/**                   LINEAR & ALGEBRAIC DEPENDANCE                **/
/**                                                                **/
/********************************************************************/

GEN
lindep0(GEN x,long bit,long prec)
{
  if (!bit) return lindep(x,prec);
  if (bit>0) return lindep2(x,bit);
  return deplin(x);
}

GEN
lindep2(GEN x, long bit)
{
  long tx=typ(x),lx=lg(x),ly,i,j,flag,e,tetpil, av = avma;
  GEN re,im,p1,p2;

  if (! is_vec_t(tx)) err(typeer,"lindep2");
  if (lx<=2) return cgetg(1,t_VEC);
  re=greal(x); im=gimag(x); flag = !gcmp0(im);
  ly = flag? lx+2: lx+1;
  p2=cgetg(lx,t_MAT); bit = (long) (bit/L2SL10);
  for (i=1; i<lx; i++)
  {
    p1=cgetg(ly,t_COL); p2[i]=(long)p1;
    for (j=1; j<lx; j++) p1[j]=(i==j) ? un : zero;
    p1[lx]=lcvtoi(gshift((GEN)re[i],bit),&e);
    if (flag) p1[lx+1]=lcvtoi(gshift((GEN)im[i],bit),&e);
  }
  p1=gmul(p2,lllint(p2)); p1=(GEN)p1[1];
  p1[0]=evaltyp(t_VEC) | evallg(lx); tetpil=avma;
  return gerepile(av,tetpil,gcopy(p1));
}

#define quazero(x) ( gcmp0(x) || ( typ(x)==t_REAL && expo(x) < EXP ) )
#define MAX 50
GEN
lindep(GEN x, long prec)
{
  GEN b[MAX],be[MAX],bn[MAX],m[MAX][MAX],c1,c2,c3,px,py,pxy;
  GEN re,im,p3,p4,p5,p6,p7,r,f,em;
  long qzer[MAX];
  long av1,tetpil,i,j,fl,i1;
  long av = avma, lx = lg(x), tx = typ(x), n = lx-1;
  const long EXP = - bit_accuracy(prec) + 2*n;

  if (! is_vec_t(tx)) err(typeer,"lindep");
  if (lx>=MAX) err(talker,"more than 50 numbers in lindep");
  if (lx<=2) return cgetg(1,t_VEC);
  re=greal(x); im=gimag(x);
  px=sqscal(re); py=sqscal(im); pxy=gscal(re,im);
  p3=mpsub(mpmul(px,py),gsqr(pxy));
  for (i=1; i<=n; i++)
  {
    bn[i]=cgetr(prec+1);
    for (j=1; j<i ; j++) m[i][j]=cgetr(prec+1);
    be[i]=cgetg(lx,t_COL); b[i]=cgetg(lx,t_COL);
    for (j=1; j<=n; j++) 
      { be[i][j]=lgetr(prec+1); b[i][j]=(i==j) ? un : zero;}
  }
  if (quazero(re)) { re=im; px=py; fl=1; } else fl=quazero(p3);
  av1=avma;
  for (i=1; i<=n; i++)
  {
    p4=gscal(b[i],re);
    if (fl) p4=gmul(gdiv(p4,px),re);
    else
    {
      p5=gscal(b[i],im);
      p6=gdiv(gsub(gmul(py,p4),gmul(pxy,p5)),p3);
      p7=gdiv(gsub(gmul(px,p5),gmul(pxy,p4)),p3);
      p4=gadd(gmul(p6,re),gmul(p7,im));
    }
    if (tx!=t_COL) p4=gtrans(p4);
    p4=gsub(b[i],p4);
    for (j=1; j<i; j++)
      if (qzer[j]) affrr(bn[j],m[i][j]);
      else
      {
        gdivz(gscal(b[i],be[j]),bn[j],m[i][j]);
        p4=gsub(p4,gmul(m[i][j],be[j]));
      }
    gaffect(p4,be[i]); affrr(sqscal(be[i]),bn[i]);
    qzer[i]=quazero(bn[i]); avma=av1;
  }
  while (qzer[n])
  {
    if (DEBUGLEVEL>8) printf("qzer[%ld]=%ld",n,qzer[n]);
    em=bn[1]; j=1; av1=avma;
    for (i=2; i<n; i++)
    {
      p3=shiftr(bn[i],i);
      if (cmprr(p3,em)>0) { em=p3; j=i; }
    }
    avma=av1;
    if (DEBUGLEVEL>9)
    {
      printf("\n");
      for (i1=1; i1<=n; i1++) 
	for (i=1; i<i1; i++) output(m[i1][i]);
    }
    i=j; i1=i+1;
    r=ground(m[i1][i]);
    f=subri(m[i1][i],r);
    p3=gsub(b[i1],gmul(r,b[i]));
    b[i1]=b[i]; b[i]=p3;
    for (j=1; j<i; j++)
      if (!qzer[j])
      {
        p3=mpsub(m[i1][j],mulir(r,m[i][j]));
        affrr(m[i][j],m[i1][j]); mpaff(p3,m[i][j]);
      }
    c1=addrr(bn[i1],mulrr(mulrr(f,f),bn[i]));
    fl=quazero(c1);
    if (!fl)
    {
      c2=divrr(mulrr(bn[i],f),c1); affrr(c2,m[i1][i]);
      c3=divrr(bn[i1],c1); mulrrz(c3,bn[i],bn[i1]);
      affrr(c1,bn[i]); qzer[i1]=quazero(bn[i1]); qzer[i]=0;
      for (j=i+2; j<=n; j++)
      {
        p3=addrr(mulrr(m[j][i1],c3),mulrr(m[j][i],c2));
        subrrz(m[j][i],mulrr(f,m[j][i1]),m[j][i1]);
        affrr(p3,m[j][i]);
      }
    }
    else
    {
      qzer[i1]=qzer[i]; affrr(bn[i],bn[i1]);
      affrr(c1,bn[i]); qzer[i]=1;
      for (j=i+2; j<=n; j++) affrr(m[j][i],m[j][i1]);
    }
  }
  p3=cgetg(lx,t_COL); p3[n]=un; for (i=1; i<n; i++) p3[i]=zero;
  p5 = (GEN)b; p5[0] = evaltyp(t_MAT) | evallg(lx);
  p4=gauss(gtrans(p5),p3); tetpil=avma;
  return gerepile(av,tetpil,gtrans(p4));
}
#undef MAX

GEN
algdep0(GEN x, long n, long bit, long prec)
{
  long tx=typ(x),av,tetpil,i,j,k;
  GEN y,p1;

  if (! is_scalar_t(tx)) err(typeer,"algdep0");
  if (tx==t_POLMOD) { y=forcecopy((GEN)x[1]); setvarn(y,0); return y; }
  if (gcmp0(x)) return gzero;
  if (!n) return gun;

  av=avma; p1=cgetg(n+2,t_COL); p1[1]=un;
  for (i=2; i<=n+1; i++) p1[i]=lmul((GEN)p1[i-1],x);

  p1 = bit? lindep2(p1,bit): lindep(p1,prec);

  tetpil=avma; y=cgetg(n+3,t_POL); 
  y[1] = evalsigne(1) | evalvarn(0);
  j=0; k=1; while (gcmp0((GEN)p1[k])) k++;
  for (i=0; i<=n+1-k; i++)
  {
    y[i+2]=lcopy((GEN)p1[k+i]);
    if (!gcmp0((GEN)p1[k+i])) j=i;
  }
  setlgef(y,j+3);
  if (gsigne((GEN)y[j+2])>0) return gerepile(av,tetpil,y);

  tetpil=avma; return gerepile(av,tetpil,gneg(y));
}

GEN
algdep2(GEN x, long n, long bit)
{
  return algdep0(x,n,bit,0);
}

GEN
algdep(GEN x, long n, long prec)
{
  return algdep0(x,n,0,prec);
}

/********************************************************************/
/**                                                                **/
/**                   INTEGRAL KERNEL (LLL REDUCED)                **/
/**                                                                **/
/********************************************************************/

GEN
matkerint0(GEN x, long flag)
{
  switch(flag)
  {
    case 0: return kerint(x);
    case 1: return kerint1(x);
    case 2: return kerint2(x);
    default: err(flagerr);
  }
  return NULL; /* not reached */
}

GEN
kerint1(GEN x)
{
  long av=avma,tetpil;
  GEN p1,p2;

  p1=matrixqz3(ker(x)); p2=lllint(p1); tetpil=avma;
  return gerepile(av,tetpil,gmul(p1,p2));
}

GEN
kerint2(GEN x)
{
  long lx=lg(x), i,j,av,av1;
  GEN g,p1;

  if (typ(x) != t_MAT) err(typeer,"kerint2");
  av=avma; g=cgetg(lx,t_MAT);
  for (j=1; j<lx; j++) g[j]=lgetg(lx,t_COL);
  for (i=1; i<lx; i++)
    for (j=1; j<=i; j++)
      coeff(g,i,j) = coeff(g,j,i) = (long)gscal((GEN)x[i],(GEN)x[j]);
  g=lllgramall(g,lll_KER); p1=lllint(g);
  av1=avma; return gerepile(av,av1,gmul(g,p1));
}

static GEN
lllall0(GEN x, long flag)
{
  long av=avma,tetpil,lx=lg(x),i,j,k,l,p1,n,lim,kmax;
  GEN u,B,lam,q,r,h,la,p2,p4,y,fl;

  if (typ(x) != t_MAT) err(typeer,"lllall0");
  n=lx-1;
  if (!n) return lllgramall_trivial(x,n,flag);
  if (n==1) /* slightly different from lllallgram_trivial */
  {
    if (gcmp0((GEN)x[1]))
    {
      switch(flag)
      {
        case lll_KER: return idmat(1);
        case lll_IM : return cgetg(1,t_MAT);
        default:
          y=cgetg(3,t_VEC); y[1]=(long)idmat(1);
          y[2]=lgetg(1,t_MAT); return y;
      }
    }
    switch(flag)
    {
      case lll_KER: return cgetg(1,t_MAT);
      case lll_IM : return idmat(1);
      default:
        y=cgetg(3,t_VEC); y[1]=lgetg(1,t_MAT);
        y[2]=lcopy(x); return y;
    }
  }
  fl = (GEN) gpmalloc(lx*sizeof(long));
  for (i=1; i<lx; i++) fl[i]=0;

  av=avma; lim=(av+bot)>>1; x=dummycopy(x);
  B=cgetg(lx+1,t_COL); for (i=1; i<=lx; i++) B[i]=zero;
  B[1]=un; lam=idmat(n);
  u=sqscal((GEN)x[1]);
  if (signe(u)) { B[2]=(long)u; fl[1]=1; }
  else { B[2]=un; coeff(lam,1,1)=zero; }
  k=2; h=idmat(n); kmax=1;
  for(;;)
  {
    if (k>kmax)
    {
      kmax=k;
      for (j=1; j<=k; j++)
      {
	if (j<k && !fl[j]) coeff(lam,k,j)=zero;
	else
	{
	  u=gscal((GEN)x[k],(GEN)x[j]);
	  if (typ(u)!=t_INT) err(lllger4);
	  for (i=1; i<j; i++)
	    if (fl[i]) u=divii(subii(mulii((GEN)B[i+1],u),mulii(gcoeff(lam,k,i),gcoeff(lam,j,i))),(GEN)B[i]);
	  if (j<k) coeff(lam,k,j)=(long)u;
	  else
	  {
	    if (signe(u)) { B[k+1]=(long)u; coeff(lam,k,k)=un; fl[k]=1; }
	    else { B[k+1]=B[k]; coeff(lam,k,k)=zero; fl[k]=0; }
	  }
	 }
      }
    }
    if (fl[k-1] && !fl[k])
    {
      if (cmpii(absi(u=shifti(gcoeff(lam,k,k-1),1)),(GEN)B[k])>0)
      {
	q=dvmdii(addii(u,(GEN)B[k]),shifti((GEN)B[k],1),&r);
	if (signe(r)<0) q=addsi(-1,q);
	h[k]=lsub((GEN)h[k],gmul(q,(GEN)h[k-1]));
	x[k]=lsub((GEN)x[k],gmul(q,(GEN)x[k-1]));
	coeff(lam,k,k-1)=lsubii(gcoeff(lam,k,k-1),mulii(q,(GEN)B[k]));
	for (i=1; i<k-1; i++)
	  coeff(lam,k,i)=lsubii(gcoeff(lam,k,i),mulii(q,gcoeff(lam,k-1,i)));
      }
      la=gcoeff(lam,k,k-1); p4=sqri(la);
      p1=h[k-1]; h[k-1]=h[k]; h[k]=p1;
      p1=x[k-1]; x[k-1]=x[k]; x[k]=p1;
      for (j=1; j<=k-2; j++)
      {
	p1=(long)coeff(lam,k-1,j); coeff(lam,k-1,j)=coeff(lam,k,j);
	coeff(lam,k,j)=p1;
      }
      if (signe(la))
      {
	p2=(GEN)B[k]; p1=ldivii(p4,p2);
	for (i=k+1; i<=kmax; i++)
	  coeff(lam,i,k-1)=ldivii(mulii(la,gcoeff(lam,i,k-1)),p2);
	for (j=k+1; j<kmax; j++)
	  for (i=j+1; i<=kmax; i++)
	    coeff(lam,i,j)=ldivii(mulii((GEN)p1,gcoeff(lam,i,j)),p2);
	B[k+1]=B[k]=p1;
	for (i=k+2; i<=kmax+1; i++)
	  B[i]=ldivii(mulii((GEN)p1,(GEN)B[i]),p2);
      }
      else
      {
	for (i=k+1; i<=kmax; i++)
	{ coeff(lam,i,k)=coeff(lam,i,k-1); coeff(lam,i,k-1)=zero; }
	B[k]=B[k-1]; fl[k]=1; fl[k-1]=0;
      }
      if (k>2) k--;
    }
    else
    {
      for (l=k-1; l>=1; l--)
      {
	if (cmpii(absi(u=shifti(gcoeff(lam,k,l),1)),(GEN)B[l+1])>0)
	{
	  q=dvmdii(addii(u,(GEN)B[l+1]),shifti((GEN)B[l+1],1),&r);
	  if (signe(r)<0) q=addsi(-1,q);
	  h[k]=lsub((GEN)h[k],gmul(q,(GEN)h[l]));
	  x[k]=lsub((GEN)x[k],gmul(q,(GEN)x[l]));
	  coeff(lam,k,l)=lsubii(gcoeff(lam,k,l),mulii(q,(GEN)B[l+1]));
	  for (i=1; i<l; i++)
	    coeff(lam,k,i)=lsubii(gcoeff(lam,k,i),mulii(q,gcoeff(lam,l,i)));
	 }
      }
      k++;
      if (k>n)
      {
	tetpil=avma; 
	return gerepile(av,tetpil,lllgramall_finish(h,fl,flag,n));
      }
    }
    if (low_stack(lim, (av+bot)>>1))
    {
      GEN *gptr[4];
      if(DEBUGMEM>1) err(warnmem,"lllall0");
      gptr[0]=&B; gptr[1]=&lam; gptr[2]=&h;
      gptr[3]=&x; gerepilemany(av,gptr,4);
    }
  }
}

GEN
kerint(GEN x)
{
  long av=avma,av1;
  GEN g,p1;

  g=lllall0(x,lll_KER); if (lg(g)==1) return g;
  p1=lllint(g); av1=avma;
  return gerepile(av,av1,gmul(g,p1));
}

/********************************************************************/
/**                                                                **/
/**                        POLRED & CO.                            **/
/**                                                                **/
/********************************************************************/
static void
neg_pol(GEN x)
{
  long i;
  for (i=2; i<lgef(x); i++)
  {
    GEN p1 = (GEN)x[i];
    if (is_universal_constant(p1)) x[i] = lneg(p1);
    else gnegz(p1,p1);
  }
}

static GEN
pols_for_polred(GEN x, GEN base, GEN p1, GEN *pta)
{
  long i,j,s, v = varn(x), n = lgef(x)-3;
  GEN p2,p3,y, a = cgetg(n+1,t_COL);

  for (i=1; i<=n; i++) a[i] = lmul(base,(GEN)p1[i]);

  y=cgetg(n+1,t_COL); /* no garbage is created beyond this point */
  for (i=1; i<=n; i++)
  {
    long av = avma, tetpil;

    if (DEBUGLEVEL>=3) { fprintferr("i = %ld\n",i); flusherr(); }
    p1=gmodulcp((GEN)a[i],x); p3=content((GEN)p1[2]);
    if (gcmp1(p3)) p1=caract(p1,v);
    else
    {
      p1=caract(gdiv(p1,p3),v); p2 = gun;
      for (j=lgef(p1)-2; j>=2; j--)
      {
        p2 = gmul(p2,p3); p1[j] = lmul((GEN)p1[j], p2);
      }
    }
    if (DEBUGLEVEL>=4) { outerr(p1); flusherr(); }

    p2=ggcd(deriv(p1,v),p1); p3=leading_term(p2);
    if (!gcmp1(p3)) p2=gdiv(p2,p3);

    tetpil=avma; p1=gerepile(av,tetpil,gdiv(p1,p2));
    y[i]=(long)p1;
    for (j=lgef(p1)-2; j>= 2; j-=2)
    {
      s = signe(p1[j]);
      if (s)
      {
        if (s > 0)
        {
          while (j>=2) { setsigne(p1[j],-signe(p1[j])); j-=2; }
          if (pta) neg_pol((GEN)a[i]);
        }
        break;
      }
    }
    if (DEBUGLEVEL>=4) { outerr(p1); flusherr(); }
  }
  if (pta) *pta = a;
  return y;
}

static GEN
get_T2(GEN x, GEN base, long n, long prec)
{
  long i,j;
  GEN p1,p2,p3=cgetg(n+1,t_MAT);

  p2=roots(x,prec);
  for (i=1; i<=n; i++)
  {
    p1=cgetg(n+1,t_COL); p3[i]=(long)p1;
    for (j=1; j<=n; j++)
      p1[j] = (long) poleval((GEN)base[i],(GEN)p2[j]);
  }
  return greal(gmul(gconj(gtrans(p3)),p3));
}

/* x can be a polynomial, but also an nf or a bnf */
static GEN
allpolred(GEN x, GEN *pta, long code, long prec)
{
  GEN y,p1,p2,p3,p4,base;
  long n,i,j,tetpil, av = avma, totally_real;

  if (typ(x) != t_POL)
  {
    p1=checknf(x); x=(GEN)p1[1];
    base=(GEN)p1[7]; n=lgef(x)-3;
    totally_real = !signe(gmael(p1,2,2));
    p2=gmael(p1,5,3); if (totally_real) p2 = ground(p2);
  }
  else
  {
    if (!signe(x)) return gcopy(x);
    n=lgef(x)-3;
    if (!gcmp1((GEN)x[n+2]))
      err(impl,"allpolred for nonmonic polynomials");
    base=allbase4(x,code,&p2,NULL); /* p2 is junk */
    n = lgef(x)-3; totally_real = (sturm(x)==n);
    if (!totally_real) p2=get_T2(x,base,n,prec);
    else
    { /* totally real */
      GEN ptrace=cgetg(n+2,t_VEC);
      long k;
    
      ptrace[2]=lstoi(n);
      for (k=2; k<=n; k++)
      {
	long l = n-k+1;

	p1=gmulsg(k-1,(GEN)x[l+2]);
	for (i=k; i>2; i--)
	  p1=gadd(p1,gmul((GEN)x[l+i],(GEN)ptrace[i]));
	ptrace[k+1]=lneg(p1);
      }
      p2=cgetg(n+1,t_MAT);
      for (i=1; i<=n; i++)
      {
	p1=cgetg(n+1,t_COL); p2[i]=(long)p1;
	for (j=1; j<i ; j++) p1[j]=lcopy(gcoeff(p2,i,j));
	for (   ; j<=n; j++)
	{
	  p4=gres(gmul((GEN)base[i],(GEN)base[j]),x); p3=gzero;
	  for (k=2; k<lgef(p4); k++)
	    p3=gadd(p3,gmul((GEN)p4[k],(GEN)ptrace[k]));
	  p1[j]=(long)p3;
	}
      }
    }
  }
  if (totally_real) p1=lllgramint(p2);
  else
  {
    for (i=1; ; i++)
    {
      p1=lllgramintern(p2,1,prec);
      if (p1) break;
      if (i == MAXITERPOL) err(accurer,"allpolred");
      prec=(prec<<1)-2; err(warnprec,"allpolred",prec);
      p2=get_T2(x,base,n,prec);
    }
  }

  tetpil=avma;
  y = pols_for_polred(x,base,p1,pta);

  if (pta)
  {
    GEN *gptr[2];

    gptr[0]=&y; gptr[1]=pta;
    gerepilemanysp(av,tetpil,gptr,2);
    return y;
  }
  return gerepileupto(av,y);
}

GEN
polred0(GEN x,long flag, GEN p, long prec)
{
  GEN y;
  long small = (flag & 1);

  if (!gcmp0(p)) small=(long) p; /* factored polred */
  if (flag & 2) /* polred2 */
  {
    y=cgetg(3,t_MAT);
    y[2]=(long)allpolred(x,(GEN*)(y+1),small,prec);
    return y;
  }
  return allpolred(x,NULL,small,prec);
}

GEN
ordred(GEN x, long prec)
{
  GEN p1,p2,p3,base;
  long n=lgef(x)-3,i,j,av=avma,v = varn(x),tetpil;

  if (typ(x) != t_POL) err(typeer,"ordred");
  if (!signe(x)) return gcopy(x);
  if (!gcmp1((GEN)x[n+2])) err(impl,"ordred for nonmonic polynomials");

  p2=roots(x,prec); p3=cgetg(n+1,t_MAT);

  base=cgetg(n+1,t_VEC); base[1]=(long)polun[v]; /* power basis */
  for (i=2; i<=n; i++)
    base[i]=lmul(polx[v],(GEN)base[i-1]);

  for (i=1; i<=n; i++)
  {
    p1=cgetg(n+1,t_COL); p3[i]=(long)p1;
    for (j=1; j<=n; j++)
      p1[j]=lpuigs((GEN)p2[j],i-1);
  }
  p2=greal(gmul(gconj(gtrans(p3)),p3));
  p1=lllgram(p2,prec);
  
  tetpil=avma;
  return gerepile(av,tetpil, pols_for_polred(x,base,p1,NULL));
}

static int
checkgenerator(GEN nf, GEN x, GEN *ptp)
{
  long v = varn((GEN)nf[1]);
  GEN p = caradj(gmodulcp(gmul((GEN)nf[7],x),(GEN)nf[1]), v, 0);

  if (lgef(ggcd(p,deriv(p,v))) == 3) { *ptp = p; return 1; }
  return 0;
}

GEN
polredabsfast(GEN x, long prec)
{
  long av=avma,tetpil,i,nv;
  GEN nf,t2,v,mres,w,per,charpol = NULL;

  if (typ(x) != t_POL) err(notpoler,"polredabs");
  if (lgef(x)==4) return gcopy(polx[varn(x)]);

  nf=initalgall0(x,nf_REDUCE|nf_SMALL,prec);

  t2=gmael(nf,5,3); nv=min(2,lg(t2)-1);
  v = minim(t2, gceil(gcoeff(t2,nv,nv)), stoi(10000));
  mres=(GEN)v[3]; nv=lg(mres);
  if (nv>=10000)
    err(warner,"not enough storage in minimgenerator");
  w=cgetg(nv,t_VEC);
  for (i=1; i<nv; i++) 
    w[i] = (long) qfeval(t2,(GEN)mres[i]);
  per=sindexsort(w);

  for (i=1; i<nv; i++)
    if (checkgenerator(nf,(GEN)mres[per[i]],&charpol)) break;

  if (charpol)
  {
    i=lgef(charpol)-2; while (i>=2 && !signe(charpol[i])) i-=2;
    if (i>=2 && signe(charpol[i])>0)
      for ( ; i>=2; i-=2) charpol[i]=lneg((GEN)charpol[i]);
    tetpil=avma; x = gcopy(charpol);
  } 
  else { tetpil=avma; x = gcopy((GEN)nf[1]); }
  return gerepile(av,tetpil,x);
}

/* no garbage collecting. It will be done in polredabs00intern */
static GEN
findmindisc(GEN nf, GEN y, GEN alpha, long c, GEN phimax)
{
  long i,ind;
  GEN dmin,z,beta, st = cgetg(c+1,t_VEC);
  
  dmin=gabs(discsr((GEN)y[1]),DEFAULTPREC);
  st[1]=(long)dmin; ind=1;
  for (i=2; i<=c; i++)
  {
    z=gabs(discsr((GEN)y[i]),DEFAULTPREC); st[i]=(long)z;
    if (gcmp(z,dmin) < 0) { dmin=z; ind=i; }
  }
  z=(GEN)y[ind];
  for (i=ind+1; i<=c; i++)
    if (gegal((GEN)st[i],dmin) && gpolcomp((GEN)y[i],z) < 0)
      { z=(GEN)y[i]; ind=i; }

  i=lgef(z)-2; while (i>=2 && !signe(z[i])) i-=2;
  beta=(GEN)alpha[ind];
  if (i>=2 && signe(z[i])>0)
  {
    for (; i>=2; i-=2) z[i]=lneg((GEN)z[i]);
    if (phimax) beta=gneg(beta);
  }

  if (!phimax) y=gcopy(z);
  else
  {
    GEN p1;

    if (typ(phimax)==t_POLMOD) phimax=(GEN)phimax[2];
    p1=polymodrecip(gmodulcp(gmul((GEN)nf[7],beta),(GEN)nf[1]));

    y=cgetg(3,t_VEC); y[1]=lcopy(z);
    y[2]=lsubst(phimax,varn(phimax),p1);
  }
  return y;
}

/* no garbage collecting. It will be done in polredabs00intern */
static GEN
storeallpols(GEN nf, GEN ypro, GEN alphapro, long c, GEN phimax)
{
  long i,vx;
  GEN p1,p2,y;

  y=cgetg(c+1,t_VEC);
  if (phimax)
  {
    if (typ(phimax)==t_POLMOD) phimax=(GEN)phimax[2];
    vx=varn(phimax);
    for (i=1; i<=c; i++)
    {
      p1=polymodrecip(gmodulcp(gmul((GEN)nf[7],(GEN)alphapro[i]),(GEN)nf[1]));
      p2=cgetg(3,t_VEC); y[i]=(long)p2;
      p2[1]=lcopy((GEN)ypro[i]); p2[2]=lsubst(phimax,vx,p1);
    }
  }
  else
  {
    for (i=1; i<=c; i++) y[i]=lcopy((GEN)ypro[i]);
  }
  return y;
}

static GEN
polredabs00intern(GEN x, long flun, long* ptstorage, long prec)
{
  long av=avma,j,nv,c;
  GEN p1,nf,t2,v,mres,w,per,charpol=NULL,eps,wlim,ypro,alphapro,phimax,BT2;

  if (typ(x)==t_VEC) { BT2=(GEN)x[2]; x=(GEN)x[1]; } else BT2=gzero;
  if (flun & nf_NORED)
  {
    nf=initalgall0(x,nf_SMALL|nf_REGULAR,prec);
    phimax = (flun & nf_ORIG)? polx[varn(x)]: (GEN)NULL;
  }
  else
  {
    if (flun & nf_ORIG)
    {
      p1=initalgall0(x,nf_REDUCE|nf_SMALL|nf_PARTIAL|nf_ORIG,prec);
      nf=(GEN)p1[1]; phimax=(GEN)p1[2];
    }
    else
    {
      nf=initalgall0(x,nf_REDUCE|nf_SMALL|nf_PARTIAL,prec);
      phimax=NULL;
    }
  }

  for (j=1; ; j++) 
  {
    t2=gmael(nf,5,3); nv=min(lg(t2)-1,2);
    if (gcmp0(BT2)) BT2=gcoeff(t2,nv,nv);
    if (DEBUGLEVEL)
    { 
      fprintferr("recherche T2-norme <= ");
      outerr(BT2); flusherr();
    }
    v=fincke_pohst(t2,gceil(BT2),stoi(10000),1,prec);
    if (v) break;
    if (j==MAXITERPOL) err(accurer,"polredabs00intern");
    prec=(prec<<2)-2;
    if (DEBUGLEVEL) err(warnprec,"polredabs00intern",prec);
    nf=nfnewprec(nf,prec);
  }
  
  mres=(GEN)v[3]; nv=lg(mres);
  *ptstorage=0;
  if (nv >= 10000) { *ptstorage=1; flun &= (~ nf_ALL); }
  if (DEBUGLEVEL) 
    { fprintferr("%ld minimaux trouves. j = :\n",nv); flusherr(); }
  w=cgetg(nv,t_VEC);
  for (j=1; j<nv; j++)
    w[j] = (long) qfeval(t2,(GEN)mres[j]);;
  per=sindexsort(w);

  alphapro=cgetg(max(2,nv),t_VEC); ypro=cgetg(max(2,nv),t_VEC);
  eps=dbltor(0.000001); c=0;
  for (j=1; j<nv; j++)
  {
    long jj=per[j];

    if (DEBUGLEVEL) { fprintferr(" %ld",j); flusherr(); }
    if (checkgenerator(nf,(GEN)mres[jj],&charpol))
    {
      if (!c)
	wlim=gadd((GEN)w[jj],eps);
      else
      {
	if (gcmp((GEN)w[jj],wlim) >= 0)
	{
	  if (flun & nf_ALL)
            x = storeallpols(nf,ypro,alphapro,c,phimax);
	  else
	    x = findmindisc(nf,ypro,alphapro,c,phimax);
          return gerepileupto(av,x);
	}
      }
      c++; ypro[c]=(long)charpol; alphapro[c]=mres[jj];
    }
  }
  if (DEBUGLEVEL) fprintferr("\n");
  if (!c)
  {
    c++; x=(GEN)nf[1]; ypro[c]=lcopy(x);
    alphapro[c]=(long)polx[varn(x)];
  }
  if (flun & nf_ALL)
    return gerepileupto(av,storeallpols(nf,ypro,alphapro,c,phimax));
  else
    return gerepileupto(av,findmindisc(nf,ypro,alphapro,c,phimax));
}

/* x can be a polynomial, an nf or a bnf */
static GEN
polredabs00(GEN x, long flun, long prec)
{
  long storage=1,nbiter=0,av=avma,tetpil,vx;
  GEN al,y,z;

  if ((typ(x)==t_VEC)&&(lg(x)==3)) y=(GEN)x[1]; else y=x;
  if (typ(y) != t_POL)
  {
    y=checknf(y); al=(GEN)y[1];
    vx=varn(al); al=gmodulcp(polx[vx],al);
  }
  else
  {
    vx=varn(y);
    if (flun & nf_ORIG) al=gmodulcp(polx[vx],y);
  }
  
  while (storage && (nbiter <= 2))
  {
    nbiter++;
    y=polredabs00intern(x,flun,&storage,prec);
    if (storage)
    {
      if (flun & nf_ORIG)
      {
	al=gsubst(lift(al),vx,(GEN)y[2]); x=(GEN)y[1];
      }
      else x=y;
    }
  }
  if (storage)
  {
    flun &= (~ nf_ALL);
    err(warner,"not enough storage in minimgenerator");
  }
  if (flun & nf_ORIG) al=lift(al);
  tetpil=avma;
  if (flun & nf_ALL)
  {
    if (flun & nf_ORIG)
    {
      long lz=lg(y),i;
      GEN p1,p2;

      z=cgetg(lz,t_VEC);
      for(i=1; i<lz; i++)
      {
	p1=cgetg(3,t_VEC); z[i]=(long)p1; p2=(GEN)y[i];
	p1[1]=lcopy((GEN)p2[1]); p1[2]=lsubst(al,vx,(GEN)p2[2]);
      }
    }
    else z=gcopy(y);
  }
  else
  {
    if (flun & nf_ORIG)
    {
      z=cgetg(3,t_VEC); z[1]=lcopy((GEN)y[1]);
      z[2]=lsubst(al,vx,(GEN)y[2]);
    }
    else z=gcopy(y);
  }
  return gerepile(av,tetpil,z);
}
  
GEN
polredabs0(GEN x, long flag, long prec)
{
  if (flag<8) return polredabs00(x,flag,prec);
  return polredabsfast(x,prec);
}

GEN
polredabsall(GEN x, long flun, long prec)
{
  return polredabs00(x, flun | nf_ALL, prec);
}
    
GEN
polredabs(GEN x, long prec)
{
  return polredabs00(x,nf_REGULAR,prec);
}

GEN
polredabs2(GEN x, long prec)
{
  return polredabs00(x,nf_ORIG,prec);
}

GEN
polredabsnored(GEN x, long prec)
{
  return polredabs00(x,nf_NORED,prec);
}

GEN
polred(GEN x, long prec)
{
  return allpolred(x,(GEN*)0,0,prec);
}

GEN
smallpolred(GEN x, long prec)
{
  return allpolred(x,(GEN*)0,1,prec);
}

GEN
factoredpolred(GEN x, GEN p, long prec)
{
  return allpolred(x,(GEN*)0,(long)p,prec);
}

GEN
polred2(GEN x, long prec)
{
  GEN y=cgetg(3,t_MAT);

  y[2]= (long) allpolred(x,(GEN*)(y+1),0,prec);
  return y;
}

GEN
smallpolred2(GEN x, long prec)
{
  GEN y=cgetg(3,t_MAT);

  y[2]= (long) allpolred(x,(GEN*)(y+1),1,prec);
  return y;
}

GEN
factoredpolred2(GEN x, GEN p, long prec)
{
  GEN y=cgetg(3,t_MAT);

  y[2]= (long) allpolred(x,(GEN*)(y+1),(long)p,prec);
  return y;
}

/********************************************************************/
/**                                                                **/
/**                              MINIM                             **/
/**                                                                **/
/********************************************************************/
long addcolumntomatrix(long *V,long n,long r,GEN *INVP,long *L);
GEN gmul_mat_smallvec(GEN x, GEN y, long hx, long ly);

/* Minimal vectors for the integral definite quadratic form: a.
 * Result u:
 *   u[1]= Number of vectors of square norm <= BORNE
 *   u[2]= maximum norm found
 *   u[3]= list of vectors found (at most STOCKMAX)
 *
 *  If BORNE = gzero: Minimal non-zero vectors.
 *  flag = min_ALL,   as above
 *  flag = min_FIRST, exits when first suitable vector is found.
 *  flag = min_PERF,  only compute rank of the family of v.v~ (v min.)
 */
static GEN
minim00(GEN a, GEN BORNE, GEN STOCKMAX, long flag)
{
  GEN res,p1,u,r,liste,gnorme,gnorme_max,invp,V, *gptr[2];
  long n = lg(a), av0 = avma, av1,av,tetpil,lim, i,j,k,s,maxrank,*x;
  double p,borne,*v,*y,*z,**q, eps = 0.000001;

  switch(flag)
  {
    case min_FIRST: res = cgetg(3,t_VEC); break;
    case min_ALL: res = cgetg(4,t_VEC);
  }
  av=avma;

  x = (long*)    cgeti(n);
  q = (double**) cgeti(n);

  /* correct alignment for the following */
  s = avma % sizeof(double); avma -= s;
  if (avma<bot) err(errpile);

  s = (n * sizeof(double))/sizeof(long);
  y = (double*) cgeti(s);
  z = (double*) cgeti(s);
  v = (double*) cgeti(s);
  for (j=1; j<n; j++) q[j] = (double*) cgeti(s);
  av1=avma; n--;

  u = lllgramint(a); a = qf_base_change(a,u);
  p1=cgetr(DEFAULTPREC); affsr(1,p1); a=gmul(a,p1); r=sqred1(a);
  if (DEBUGLEVEL>4) { fprintferr("minim: r = "); outerr(r); flusherr(); }
  for (j=1; j<=n; j++)
  {
    v[j] = rtodbl(gcoeff(r,j,j));
    for (i=1; i<j; i++) q[i][j] = rtodbl(gcoeff(r,i,j));
  }

  if (flag==min_PERF || gcmp0(BORNE))
  {
    double c, b = rtodbl(gcoeff(a,1,1));

    for (i=2; i<=n; i++)
      { c=rtodbl(gcoeff(a,i,i)); if (c<b) b=c; }
    borne = b+eps;
    BORNE = ground(dbltor(borne));
    gnorme_max = NULL;
  }
  else
  {
    BORNE = gfloor(BORNE);
    borne = gtodouble(BORNE)+eps;
    gnorme_max = gzero;
  }
  
  switch(flag)
  { 
    case min_ALL:
      maxrank=itos(STOCKMAX);
      liste = cgeti(1+maxrank);
      break;
    case min_PERF:
      BORNE = gerepileupto(av1,BORNE);
      maxrank = (n*(n+1))>>1;
      liste = cgeti(1+maxrank); V = cgeti(1+maxrank);
      for (i=1; i<=maxrank; i++) liste[i]=0;
  }

  s=0; av1=avma; lim = (av1+bot)>>1;
  k = n; y[n] = z[n] = 0;
  x[n] = (long) sqrt(borne/v[n]+eps);
  if (flag == min_PERF) invp = idmat(maxrank);
  for(;;)
  {
    do
    {
      if (k>1)
      {
	k--; z[k]=0;
	for (j=k+1; j<=n; j++) z[k] += q[k][j]*x[j];
	p = x[k+1]+z[k+1];
	y[k] = y[k+1] + p*p*v[k+1];
	x[k] = (long) floor(sqrt((borne-y[k]+eps)/v[k])-z[k]);
      }
      for(;;)
      {
	p=x[k]+z[k];
	if (y[k] + p*p*v[k] <= borne+eps) break;
	k++; x[k]--;
      }
    }
    while (k>1);
    if (! x[1] && y[1]<=eps) break;
    p = x[1]+z[1]; gnorme = ground( dbltor(y[1]+ p*p*v[1]) );
    if (gnorme_max)
      { if (gcmp(gnorme,gnorme_max) > 0) gnorme_max=gnorme; }
    else
    {
      if (gcmp(gnorme,BORNE) < 0)
      {
	borne=gtodouble(gnorme); s=0;
        affii(gnorme,BORNE); avma=av1;
	if (flag == min_PERF) invp = idmat(maxrank);
      }
    }

    switch(flag)
    {
      case min_ALL:
        s++;
        if (s<=maxrank)
        {
          p1 = cgeti(n+1); liste[s] = (long) p1;
          for (i=1; i<=n; i++) p1[i] = x[i];
        }
        break;

      case min_FIRST:
        if (! gnorme_max || gcmp(gnorme,BORNE)>0) break;

        tetpil=avma; gnorme = icopy(gnorme); r = gmul_mat_smallvec(r,x,n,n);
        gptr[0]=&gnorme; gptr[1]=&r; gerepilemanysp(av,tetpil,gptr,2);
        res[1]=(long)gnorme;
        res[2]=(long)r; return res;

      case min_PERF:
      {
        long av2=avma, I=1, newran;

        for (i=1; i<=n; i++)
          for (j=i; j<=n; j++,I++) V[I] = x[i]*x[j];
        newran = addcolumntomatrix(V,maxrank,s,&invp,liste);
        if (newran == s)
        { 
          avma=av2;
          if (DEBUGLEVEL>1) { fprintferr("."); flusherr(); }
        }
        else
        { 
          if (DEBUGLEVEL>1) { fprintferr("*"); flusherr(); }
          s = newran;
          if (s == maxrank)
          {
            if (DEBUGLEVEL>1) { fprintferr("\n"); flusherr(); }
            avma=av0; return stoi(s);
          }

          if (low_stack(lim, (av1+bot)>>1))
          {
            if(DEBUGMEM>1) err(warnmem,"minim00");
            if (DEBUGLEVEL>1)
            { 	
              fprintferr("\ngerepile in qfperfection. rank>=%ld\n",s);
              flusherr();
            }
            tetpil=avma; invp = gerepile(av1,tetpil,gcopy(invp));
          }
        }
      }
    }
    x[1]--;
  }
  switch(flag)
  {
    case min_FIRST:
      avma=av0; return cgetg(1,t_VEC);
    case min_PERF: 
      if (DEBUGLEVEL>1) { fprintferr("\n"); flusherr(); }
      avma=av0; return stoi(s);
  }
  k = min(s,maxrank); 

  tetpil = avma; p1=cgetg(k+1,t_MAT);
  for (j=1; j<=k; j++)
    p1[j] = (long) gmul_mat_smallvec(u,(GEN)liste[j],n,n);
  liste = p1;
  r = gnorme_max? gnorme_max: BORNE;

  r=icopy(r); gptr[0]=&r; gptr[1]=&liste;
  gerepilemanysp(av,tetpil,gptr,2);
  res[1]=lstoi(s<<1);
  res[2]=(long)r;
  res[3]=(long)liste; return res;
}

GEN
minim0(GEN a, GEN borne, GEN stockmax, long flag, long prec)
{
  switch(flag)
  {
    case 0: return minim00(a,borne,stockmax,min_ALL);
    case 1: return minim00(a,borne,gzero   ,min_FIRST);
    case 2: return fincke_pohst(a,borne,stockmax,0,prec);
    default: err(flagerr);
  }
  return NULL; /* not reached */
}

GEN
minim(GEN a, GEN borne, GEN stockmax)
{
  return minim00(a,borne,stockmax,min_ALL);
}

GEN
minim2(GEN a, GEN borne, GEN stockmax)
{
  return minim00(a,borne,stockmax,min_FIRST);
}

GEN
perf(GEN a)
{
  return minim00(a,gzero,gzero,min_PERF);
}

/* programme general pour les formes quadratiques definies positives
 * quelconques (a coeffs reels). On doit avoir BORNE != 0; on n'entre dans
 * cette fonction qu'a partir de fincke_pohst (la reduction LLL n'est donc
 * pas faite ici)
 */
static GEN
smallvectors(GEN a, GEN BORNE, GEN STOCKMAX, long flag, long prec)
{
  long av,tetpil,av2,lim,n1,n,i,j,k,s,stockmax,fl,epsbit;
  GEN u,r,S,x,y,z,v,q,norme1,normax1,p,borne1,eps,p1;

  if (gcmp0(BORNE)) err(talker,"bound equal 0 in smallvectors");
  n1=lg(a); n=n1-1; stockmax=itos(STOCKMAX);

  av=avma; lim=(bot+av)>>1; r=sqred1intern(a,flag);
  if (r == NULL) { avma=av; return NULL; }
  if (DEBUGLEVEL>5) { fprintferr("r = "); outerr(r); }
  epsbit = (bit_accuracy(prec)) >> 1;
  eps=cgetr(prec); affsr(1,eps); eps=gshift(eps,-epsbit);

  v=cgetg(n1,t_VEC);
  q=cgetg(n1,t_MAT);
  for (j=1; j<=n; j++)
  { 
    v[j]=coeff(r,j,j);
    q[j]=lgetg(n1,t_COL);
    for (i=1; i<j; i++)  coeff(q,i,j)=coeff(r,i,j);
    for (   ; i<=n; i++) coeff(q,i,j)=zero;
  }
  borne1=gadd(BORNE,eps); normax1=gzero;

  av2=avma;
  x=cgetg(n1,t_VEC);
  y=cgetg(n1,t_VEC);
  z=cgetg(n1,t_VEC);
  S=cgetg(stockmax+1,t_MAT);
  for (i=1; i<=stockmax; i++) S[i]=zero;
  for (i=1; i<=n; i++) y[i]=z[i]=zero;
  for (i=1; i<n; i++) x[i]=zero;
  x[n]=lfloor(gadd(eps,gsqrt(gdiv(BORNE,(GEN)v[n]),prec)));
  if (DEBUGLEVEL>3) { fprintferr("\nx[%ld] = %Z\n",n,x[n]); flusherr(); }

  s=0; k=n;
  for(;;)
  {
    do
    {
      fl=0;
      if (k>1)
      {
	k--; z[k]=zero;
	for (j=k+1; j<=n; j++)
	  z[k] = ladd((GEN)z[k], gmul(gcoeff(q,k,j),(GEN)x[j]));
	p = gadd((GEN)x[k+1],(GEN)z[k+1]);
	y[k] = ladd((GEN)y[k+1], gmul(gsqr(p),(GEN)v[k+1]));
	p1 = gsub(BORNE,(GEN)y[k]);
	if (gsigne(p1)<0)
	{
	  if (gexpo(p1)<-epsbit) p1=gzero; else fl=1;
	}
	if (!fl)
	  x[k]=lfloor(gadd(eps,
			   gsub(gsqrt(gdiv(p1,(GEN)v[k]),prec),
			        (GEN)z[k])));
      }
      for(;;)
      { 
	if (!fl)
	{
	  p1 = gmul((GEN)v[k], gsqr(gadd((GEN)x[k],(GEN)z[k])));
	  if (gcmp(gsub(p1,gadd(gsub(BORNE,(GEN)y[k]),eps)),
	           gmul(eps,gabs(p1,prec))) <= 0) break;
	}
	k++; x[k]=laddis((GEN)x[k],-1); fl=0;
      }
      if (DEBUGLEVEL>3)
      {
	if (DEBUGLEVEL>5) fprintferr("%ld ",k);
	if (k==n) fprintferr("\nx[%ld] = %Z",n,x[n]);
	flusherr();
      }
      if (low_stack(lim, (av+bot)>>1))
      {
	GEN *gptr[5];
	if(DEBUGMEM>1) err(warnmem,"smallvectors");
	gptr[0]=&x; gptr[1]=&y; gptr[2]=&z; gptr[3]=&normax1;
	if (stockmax) gptr[4]=&S;
	gerepilemany(av2,gptr,stockmax?5:4);
      }
    }
    while (k>1);
    if (gcmp0((GEN)x[1]) && gcmp((GEN)y[1],eps) <= 0) break;

    p1=gsqr(gadd((GEN)x[1],(GEN)z[1]));
    norme1=gadd((GEN)y[1],gmul((GEN)v[1],p1));
    if (gcmp(norme1,borne1)<=0) /* ce n'est pas bien, mais quoi faire ? */
    {
      if (gcmp(norme1,normax1)>0) normax1=norme1;
      s++;
      if (s<=stockmax)
      { 
	S[s]=lgetg(n+1,t_COL);
	for (i=1; i<=n; i++) coeff(S,i,s)=x[i];
      }
    }
    x[k]=laddis((GEN)x[k],-1);
  }
  tetpil=avma; u=cgetg(4,t_VEC);
  u[1]=lstoi(s<<1);
  u[2]=lcopy(normax1);
  if (s>stockmax) s=stockmax;
  setlg(S,s+1); S=gcopy(S);
  u[3]=(long)S; return gerepile(av,tetpil,u);
}

/* resolution de x~.a.x <= borne, a definie positive */
/* si flag = 1, on retourne NULL s'il y a un probleme de precision
   dans sqred1 ou lllgram, sinon erreur. */
GEN
fincke_pohst(GEN a,GEN borne,GEN stockmax,long flag, long prec)
{
  long pr,av=avma,tetpil,i,j,n,m;
  GEN r,rinv,rinvtrans,v,vtrans,u,s,sinvtrans,a1,res,x,y,matx,maty,z;
  GEN unr,vnorm,sperm,perm;

  if (DEBUGLEVEL>3)
    { fprintferr("\nEntree dans fincke_pohst\n"); flusherr(); }
  pr=gprecision(a);
  if (!pr) { unr=cgetr(prec); affsr(1,unr); a=gmul(a,unr); }
  else prec=pr;
  r=sqred1intern(a,flag);
  if (r == NULL) { avma=av; return NULL; }
  n=lg(a)-1;
  for (i=1; i<=n; i++)
  {
    coeff(r,i,i)=lsqrt(gcoeff(r,i,i),prec);
    for (j=i+1; j<=n; j++)
      coeff(r,i,j)=lmul(gcoeff(r,i,i),gcoeff(r,i,j));
  }
  rinv=invmat(r); rinvtrans=gtrans(rinv);
  if (DEBUGLEVEL>8)
  {
    fprintferr("prec = %ld, precision de rinvtrans = %ld\n",
                prec,gprecision(rinvtrans));
    fprintferr("rinvtrans = "); outerr(rinvtrans);
  }
  if (DEBUGLEVEL>3) { fprintferr("\nEntree dans LLL\n"); flusherr(); }
  v=lllintern(rinvtrans,flag,2*prec-2);
  if (v == NULL) { avma=av; return NULL; }
  if (DEBUGLEVEL>8) { fprintferr("v = "); outerr(v); }

  vtrans=gtrans(v); u=invmat(vtrans);
  s=gmul(r,u); sinvtrans=gmul(rinvtrans,v);
  vnorm=cgetg(n+1,t_VEC);
  for (j=1; j<=n; j++)
    vnorm[j]=lnorml2((GEN)sinvtrans[j]);
  perm=sindexsort(vnorm); sperm=cgetg(n+1,t_MAT);
  for (j=1; j<=n; j++)
    sperm[n+1-j]=s[perm[j]];
  a1=gram_matrix(sperm);
  if (DEBUGLEVEL>3)
    { fprintferr("\nEntree dans smallvectors\n"); flusherr(); }
  res=smallvectors(a1,borne,stockmax,flag,prec);
  if (!res) { avma=av; return NULL; }
  maty=(GEN)res[3]; m=lg(maty)-1; matx=cgetg(m+1,t_MAT);
  for (j=1; j<=m; j++)
  {
    y=(GEN)maty[j]; x=cgetg(n+1,t_COL);
    for (i=1; i<=n; i++)
      x[perm[i]] = y[n+1-i];
    matx[j]=lmul(u,x);
  }
  if (DEBUGLEVEL>3){ fprintferr("\nSortie de fincke_pohst\n"); flusherr(); }
  tetpil=avma; z=cgetg(4,t_VEC);
  z[1]=lcopy((GEN)res[1]);
  z[2]=pr ? lcopy((GEN)res[2]) : lround((GEN)res[2]);
  z[3]=lcopy(matx); return gerepile(av,tetpil,z);
}
