File: [local] / OpenXM_contrib / pari / src / basemath / Attic / bibli1.c (download)
Revision 1.1.1.1 (vendor branch), Sun Jan 9 17:35:30 2000 UTC (24 years, 8 months ago) by maekawa
Branch: PARI_GP
CVS Tags: maekawa-ipv6, VERSION_2_0_17_BETA, RELEASE_20000124, RELEASE_1_2_3, RELEASE_1_2_2_KNOPPIX_b, RELEASE_1_2_2_KNOPPIX, RELEASE_1_2_2, RELEASE_1_2_1, RELEASE_1_1_3, RELEASE_1_1_2 Changes since 1.1: +0 -0
lines
Import PARI/GP 2.0.17 beta.
|
/********************************************************************/
/** **/
/** LLL Algorithm and close friends **/
/** **/
/********************************************************************/
/* $Id: bibli1.c,v 1.4 1999/09/24 10:51:24 karim Exp $ */
#include "pari.h"
#include "parinf.h"
GEN lincomb_integral(GEN u, GEN v, GEN X, GEN Y);
/* scalar product of x with himself */
static GEN
sqscal(GEN x)
{
long i,av=avma,lx=lg(x);
GEN z=gzero;
for (i=1; i<lx; i++)
z = gadd(z, gsqr((GEN)x[i]));
return gerepileupto(av,z);
}
/* scalar product x . y */
static GEN
gscal(GEN x,GEN y)
{
long i,av=avma,lx=lg(x);
GEN z=gzero;
for (i=1; i<lx; i++)
z = gadd(z, gmul((GEN)x[i],(GEN)y[i]));
return gerepileupto(av,z);
}
static GEN
sqscali(GEN x)
{
GEN z = gzero;
long i,lx=lg(x);
for (i=1; i<lx; i++)
z = addii(z,sqri((GEN)x[i]));
return z;
}
static GEN
gscali(GEN x,GEN y)
{
GEN z = gzero;
long i,lx=lg(x);
for (i=1; i<lx; i++)
z = addii(z, mulii((GEN)x[i],(GEN)y[i]));
return z;
}
static GEN
lllall_trivial(GEN x, long n, long flag)
{
GEN y;
if (!n)
{
if (flag != lll_ALL) return cgetg(1,t_MAT);
y=cgetg(3,t_VEC);
y[1]=lgetg(1,t_MAT);
y[2]=lgetg(1,t_MAT); return y;
}
/* here n = 1 */
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;
}
}
if (flag & lll_GRAM) flag ^= lll_GRAM; else x = NULL;
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]=x? lcopy(x): (long)idmat(1); return y;
}
}
static GEN
lllgramall_finish(GEN h,GEN fl,long flag,long n)
{
long k;
GEN y;
k=1; while (k<=n && !fl[k]) k++;
switch(flag)
{
case lll_KER: setlg(h,k);
y = gcopy(h); break;
case lll_IM: h += k-1; h[0] = evaltyp(t_MAT)| evallg(n-k+2);
y = gcopy(h); break;
default: setlg(h,k); y=cgetg(3,t_VEC);
y[1] = lcopy(h);
h += k-1; h[0] = evaltyp(t_MAT)| evallg(n-k+2);
y[2] = lcopy(h);
break;
}
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 av0=avma,av,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 lllall_trivial(x,n,flag);
if (lg((GEN)x[1])!=lx) err(mattype1,"lllgramintwithcontent");
fl = new_chunk(lx);
av=avma; lim=stack_lim(av,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, stack_lim(av,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, stack_lim(av,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, stack_lim(av,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, stack_lim(av,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, stack_lim(av,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, stack_lim(av,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(av0,tetpil,lllgramall_finish(h,fl,flag,n));
}
}
if (low_stack(lim, stack_lim(av,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 **/
/** **/
/********************************************************************/
#define swap(x,y) { long _t=x; x=y; y=_t; }
#define gswap(x,y) { GEN _t=x; x=y; y=_t; }
static void
lllupdate_int(GEN x, GEN h, GEN L, GEN B, long K, long k, long l)
{
long i,lx;
GEN r = truedvmdii(addii(B,shifti(gcoeff(L,k,l),1)), shifti(B,1), NULL);
GEN *hk,*hl,*xk,*xl;
if (!signe(r)) return;
r = negi(r); lx = lg(x);
hk = (GEN*)h[k]; hl = (GEN*)h[l];
xk = (GEN*)x[k]; xl = (GEN*)x[l];
if (is_pm1(r))
{
if (signe(r) > 0)
{
for (i=1;i<=K;i++) hk[i]=addii(hk[i],hl[i]);
for (i=1;i<lx;i++) xk[i]=addii(xk[i],xl[i]);
for (i=1;i<lx;i++) coeff(x,k,i)=laddii(gcoeff(x,k,i),gcoeff(x,l,i));
for (i=1;i<l; i++) coeff(L,k,i)=laddii(gcoeff(L,k,i),gcoeff(L,l,i));
} else {
for (i=1;i<=K;i++) hk[i]=subii(hk[i],hl[i]);
for (i=1;i<lx;i++) xk[i]=subii(xk[i],xl[i]);
for (i=1;i<lx;i++) coeff(x,k,i)=lsubii(gcoeff(x,k,i),gcoeff(x,l,i));
for (i=1;i<l; i++) coeff(L,k,i)=lsubii(gcoeff(L,k,i),gcoeff(L,l,i));
}
} else {
for(i=1;i<=K;i++) hk[i]=addii(hk[i],mulii(r,hl[i]));
for(i=1;i<lx;i++) xk[i]=addii(xk[i],mulii(r,xl[i]));
for(i=1;i<lx;i++) coeff(x,k,i)=laddii(gcoeff(x,k,i),mulii(r,gcoeff(x,l,i)));
for(i=1;i<l;i++) coeff(L,k,i)=laddii(gcoeff(L,k,i),mulii(r,gcoeff(L,l,i)));
}
coeff(L,k,l)=laddii(gcoeff(L,k,l),mulii(r,B));
}
static void
lllupdate(GEN x, GEN h, GEN L, long K, long k, long l)
{
long e,i,lx;
GEN r = grndtoi(gcoeff(L,k,l),&e);
GEN *hk,*hl,*xk,*xl;
if (DEBUGLEVEL>8)
fprintferr("error bits when rounding in lllgram: %ld\n",e);
if (!signe(r)) return;
r = negi(r); lx = lg(x);
hk = (GEN*)h[k]; hl = (GEN*)h[l];
xk = (GEN*)x[k]; xl = (GEN*)x[l];
if (is_pm1(r))
{
if (signe(r) > 0)
{
for (i=1;i<=K;i++) hk[i]=addii(hk[i],hl[i]);
for (i=1;i<lx;i++) xk[i]=gadd(xk[i],xl[i]);
for (i=1;i<lx;i++) coeff(x,k,i)=ladd(gcoeff(x,k,i),gcoeff(x,l,i));
for (i=1;i<l; i++) coeff(L,k,i)=ladd(gcoeff(L,k,i),gcoeff(L,l,i));
} else {
for (i=1;i<=K;i++) hk[i]=subii(hk[i],hl[i]);
for (i=1;i<lx;i++) xk[i]=gsub(xk[i],xl[i]);
for (i=1;i<lx;i++) coeff(x,k,i)=lsub(gcoeff(x,k,i),gcoeff(x,l,i));
for (i=1;i<l; i++) coeff(L,k,i)=lsub(gcoeff(L,k,i),gcoeff(L,l,i));
}
} else {
for (i=1;i<=K;i++) hk[i]=addii(hk[i],mulii(r,hl[i]));
for (i=1;i<lx;i++) xk[i]=gadd(xk[i],gmul(r,xl[i]));
for (i=1;i<lx;i++) coeff(x,k,i)=ladd(gcoeff(x,k,i),gmul(r,gcoeff(x,l,i)));
for (i=1;i<l; i++) coeff(L,k,i)=ladd(gcoeff(L,k,i),gmul(r,gcoeff(L,l,i)));
}
coeff(L,k,l)=ladd(gcoeff(L,k,l),r);
}
/* x integer matrix */
GEN
lllgramall(GEN x, long alpha, long flag)
{
long av0=avma,av,tetpil,lim,lx=lg(x),i,j,k,l,n,kmax;
GEN u,B,L,h,la,p1,p2,p3,p4,fl, *gptr[6];
if (typ(x) != t_MAT) err(typeer,"lllgramall");
n=lx-1; if (n<=1) return lllall_trivial(x,n,flag);
if (lg((GEN)x[1])!=lx) err(mattype1,"lllgramall");
fl = new_chunk(lx);
av=avma; lim=stack_lim(av,1); x=dummycopy(x);
B=gscalcol(gun, lx);
L=cgetg(lx,t_MAT);
for (j=1; j<lx; j++)
{
for (i=1; i<lx; i++)
if (typ(gcoeff(x,i,j))!=t_INT) err(lllger4);
fl[j] = 0; L[j] = (long)zerocol(n);
}
k=2; h=idmat(n); kmax=1;
u=gcoeff(x,1,1);
if (signe(u)) { B[2]=(long)u; coeff(L,1,1)=un; fl[1]=1; } else B[2]=un;
if (DEBUGLEVEL>5) fprintferr("k =");
for(;;)
{
if (k > kmax)
{
if (DEBUGLEVEL>3) {fprintferr(" K%ld",k);flusherr();}
kmax = k;
for (j=1; j<=k; j++)
if (j==k || fl[j])
{
long av1 = avma;
u = gcoeff(x,k,j);
for (i=1; i<j; i++) if (fl[i])
u = divii(subii(mulii((GEN)B[i+1],u),
mulii(gcoeff(L,k,i),gcoeff(L,j,i))),
(GEN)B[i]);
u = gerepileuptoint(av1, u);
if (j<k) coeff(L,k,j)=(long)u;
else
{
if (signe(u)) { B[k+1]=(long)u; coeff(L,k,k)=un; fl[k]=1; }
else { B[k+1]=B[k]; fl[k]=0; }
}
}
} else if (DEBUGLEVEL>5) {fprintferr(" %ld",k); flusherr();}
lllupdate_int(x,h,L,(GEN)B[k],kmax,k,k-1);
if (fl[k-1] &&
(cmpii(mulsi(alpha-1,sqri((GEN)B[k])),
mulsi(alpha,p3=addii(mulii((GEN)B[k-1],(GEN)B[k+1]),
p4=sqri(la=gcoeff(L,k,k-1))))) > 0
|| !fl[k]))
{
if (DEBUGLEVEL>3 && k==n)
{
fprintferr(" (%ld)", expi(mulsi(alpha-1,sqri((GEN)B[k])))
- expi(mulsi(alpha,p3)));
flusherr();
}
swap(h[k-1], h[k]);
swap(x[k-1], x[k]);
for (j=1; j<=n; j++) swap(coeff(x,k-1,j), coeff(x,k,j));
for (j=1; j<k-1; j++) swap(coeff(L,k-1,j), coeff(L,k,j))
if (fl[k])
{
GEN Bk = (GEN)B[k];
long av1 = avma;
for (i=k+1; i<=kmax; i++)
{
GEN bb=gcoeff(L,i,k);
p1 = divii(subii(mulii((GEN)B[k+1],gcoeff(L,i,k-1)),
mulii(la,bb)), Bk);
av1=avma=coeff(L,i,k) = (long)icopy_av(p1,(GEN)av1);
p1 = divii(addii(mulii(la,gcoeff(L,i,k-1)),
mulii((GEN)B[k-1],bb)), Bk);
av1=avma=coeff(L,i,k-1) = (long)icopy_av(p1,(GEN)av1);
}
B[k] = ldivii(p3,Bk);
}
else
{
if (signe(la))
{
p2=(GEN)B[k]; p1=divii(p4,p2);
B[k+1]=B[k]=(long)p1;
for (i=k+2; i<=lx; i++)
B[i]=ldivii(mulii(p1,(GEN)B[i]),p2);
for (i=k+1; i<=kmax; i++)
coeff(L,i,k-1)=ldivii(mulii(la,gcoeff(L,i,k-1)),p2);
for (j=k+1; j<kmax; j++)
{
for (i=j+1; i<=kmax; i++)
coeff(L,i,j)=ldivii(mulii(p1,gcoeff(L,i,j)),p2);
if (low_stack(lim, stack_lim(av,1)))
{
if(DEBUGMEM>1) err(warnmem,"lllgramall[1]");
gptr[0]=&B; gptr[1]=&L; gptr[2]=&h;
gptr[3]=&x; gptr[4]=&p2;
gerepilemany(av,gptr,5); p1=(GEN)B[k];
}
}
}
else
{
for (i=k+1; i<=kmax; i++)
{ coeff(L,i,k)=coeff(L,i,k-1); coeff(L,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; l--)
{
lllupdate_int(x,h,L,(GEN)B[l+1],kmax,k,l);
if (low_stack(lim, stack_lim(av,1)))
{
if(DEBUGMEM>1) err(warnmem,"lllgramall[2]");
gptr[0]=&B; gptr[1]=&L; gptr[2]=&h;
gptr[3]=&x; gerepilemany(av,gptr,4);
}
}
if (++k > n) break;
}
if (low_stack(lim, stack_lim(av,1)))
{
if(DEBUGMEM>1) err(warnmem,"lllgramall[3]");
gptr[0]=&B; gptr[1]=&L; gptr[2]=&h;
gptr[3]=&x; gerepilemany(av,gptr,4);
}
}
if (DEBUGLEVEL>3) fprintferr("\n");
tetpil=avma; return gerepile(av0,tetpil,lllgramall_finish(h,fl,flag,n));
}
static GEN
lllgramall0(GEN x, long flag) { return lllgramall(x,100,flag); }
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 av0=avma,av,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 lllall_trivial(x,n,flag);
if (lg((GEN)x[1])!=lx) err(mattype1,"lllgramallgen");
fl = new_chunk(lx);
av=avma; lim=stack_lim(av,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]))
{
flc = (ps1!=ps2);
swap(h[k-1],h[k]);
for (j=1; j<=k-2; j++) swap(coeff(lam,k-1,j), coeff(lam,k,j));
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)));
}
}
if (++k > n) break;
}
if (low_stack(lim, stack_lim(av,1)))
{
GEN *gptr[4];
if(DEBUGMEM>1) err(warnmem,"lllgramallgen");
gptr[0]=&B; gptr[1]=&lam; gptr[2]=&h;
gerepilemany(av,gptr,3);
}
}
tetpil=avma;
return gerepile(av0,tetpil,lllgramall_finish(h,fl,flag,n));
}
/* return x[k,j] - (mu.A)[j] */
#ifdef INLINE
INLINE
#endif
GEN
get_Aj(GEN x, GEN mu, GEN A, long j, long k)
{
long av,i;
GEN s;
if (j==1) return gcopy(gcoeff(x,k,1));
av = avma; s = gmul(gcoeff(mu,j,1),(GEN)A[1]);
for (i=2; i<j; i++) s=gadd(s,gmul(gcoeff(mu,j,i),(GEN)A[i]));
s=gneg(s); return gerepileupto(av, gadd(gcoeff(x,k,j),s));
}
/* x = Gram(b_i). If precision problems return NULL if flag=1, error otherwise.
* Quality ratio = (alpha-1)/alpha. Suggested value: alpha = 100
*/
GEN
lllgramintern(GEN x, long alpha, long flag, long prec)
{
GEN xinit,L,h,A,B,L1,L2,q,cst;
long retry = 2, av = avma,tetpil,lim,l,i,j,k,k1,lx=lg(x),n,kmax;
if (typ(x) != t_MAT) err(typeer,"lllgram");
n=lx-1; if (n && lg((GEN)x[1])!=lx) err(mattype1,"lllgram");
if (n<=1) return idmat(n);
lim = stack_lim(av,1); xinit=x;
for (k=2,j=1; j<lx; j++)
{
GEN p1=(GEN)x[j];
for (i=1; i<lx; i++) /* FIXME: lg <-> expo */
if (typ(p1[i]) == t_REAL) { l = lg((GEN)p1[i]); if (l>k) k=l; }
}
if (k == 2)
{
if (!prec) return lllgramint(x);
x = gmul(x, realun(prec+1));
}
else if (prec < k) prec = k;
h = idmat(n);
x = gprec_w(x, prec+1);
LABLLLGRAM:
switch(retry--)
{
case 2: /* entry */ break;
case 1: /* failed already */
tetpil = avma; h = gcopy(h);
prec = (prec<<1)-2;
if (DEBUGLEVEL > 3) fprintferr("\n");
if (DEBUGLEVEL) err(warnprec,"lllgramintern",prec);
x = qf_base_change(gprec_w(xinit,prec),h,1);
{
GEN *gsav[2]; gsav[0]=&h; gsav[1]=&x;
gerepilemanysp(av, tetpil, gsav, 2);
}
if (DEBUGLEVEL) err(warner,"lllgramintern starting over");
break;
case 0: /* give up */
if (DEBUGLEVEL > 3) fprintferr("\n");
if (DEBUGLEVEL) err(warner,"lllgramintern giving up");
if (flag) { avma=av; return NULL; }
if (DEBUGLEVEL) outerr(xinit);
err(lllger3);
}
cst = cgetr(prec+1); affsr(alpha-1,cst);
cst = divrs(cst,alpha);
L=cgetg(lx,t_MAT);
B=cgetg(lx,t_COL);
A=cgetg(lx,t_VEC);
for (j=1; j<lx; j++)
{
L[j] = (long)zerocol(n);
A[j] = B[j] = zero;
}
k=2; kmax=1; B[1]=coeff(x,1,1);
if (gcmp0((GEN)B[1]))
{
if (flag) return NULL;
err(lllger3);
}
if (DEBUGLEVEL>5) fprintferr("k =");
for(;;)
{
if (k>kmax)
{
if (DEBUGLEVEL>3) {fprintferr(" K%ld",k);flusherr();}
kmax=k;
for (j=1; j<k; j++)
{
A[j] = (long)get_Aj(x,L,A,j,k);
coeff(L,k,j) = ldiv((GEN)A[j],(GEN)B[j]);
}
B[k] = (long)get_Aj(x,L,A,k,k);
if (gsigne((GEN)B[k]) <= 0)
{
if (kmax == 2) retry = 0;
goto LABLLLGRAM;
}
}
else if (DEBUGLEVEL>5) fprintferr(" %ld",k);
L1=gcoeff(L,k,k-1);
if (DEBUGLEVEL>9)
{
fprintferr(" %ld", gexpo(L1) - bit_accuracy(lg(L1)));
for (i=1; i<lx; i++)
fprintferr("%ld: %Z\n",i,qfeval(x,(GEN)h[i]));
flusherr();
}
if (2*gexpo(L1) > bit_accuracy(lg(L1)))
{
if (DEBUGLEVEL>3)
{
fprintferr("\nRecomputing Gram-Schmidt, kmax = %ld\n",kmax);
if (DEBUGLEVEL>9) fprintferr("Old B = %Z\n",B);
}
for (k1=1; k1<=kmax; k1++)
{
for (j=1; j<k1; j++)
{
A[j] = (long)get_Aj(x,L,A,j,k1);
coeff(L,k1,j) = ldiv((GEN)A[j],(GEN)B[j]);
}
B[k1] = (long)get_Aj(x,L,A,k1,k1);
if (gsigne((GEN)B[k1]) <= 0) goto LABLLLGRAM;
}
if (DEBUGLEVEL>9) fprintferr("New B = %Z\n",B);
}
lllupdate(x,h,L,kmax,k,k-1);
L1 = gcoeff(L,k,k-1);
L2 = gsqr(L1);
q = gmul((GEN)B[k-1], gsub(cst,L2));
if (gcmp(q,(GEN)B[k]) > 0)
{
GEN BK,BB;
if (DEBUGLEVEL>3 && k==kmax)
{ fprintferr(" (%ld)",gexpo(q)-gexpo((GEN)B[k])); flusherr(); }
BB = gadd((GEN)B[k], gmul((GEN)B[k-1],L2));
if (gcmp0(BB)) goto LABLLLGRAM;
coeff(L,k,k-1) = ldiv(gmul(L1,(GEN)B[k-1]), BB);
BK = gdiv((GEN)B[k],BB);
B[k] = lmul((GEN)B[k-1], BK);
B[k-1] = (long)BB;
swap(h[k-1],h[k]);
swap(x[k-1],x[k]);
for (j=1; j<=n; j++) swap(coeff(x,k-1,j), coeff(x,k,j));
for (j=1; j<k-1; j++) swap(coeff(L,k-1,j), coeff(L,k,j))
for (i=k+1; i<=kmax; i++)
{
GEN p=gcoeff(L,i,k);
coeff(L,i,k) = lsub(gcoeff(L,i,k-1),gmul(L1,p));
coeff(L,i,k-1)=ladd(gmul(BK,p), gmul(gcoeff(L,k,k-1),gcoeff(L,i,k-1)));
}
if (k>2) k--;
}
else
{
for (l=k-2; l; l--) lllupdate(x,h,L,kmax,k,l);
if (++k > n) break;
}
if (low_stack(lim, stack_lim(av,1)))
{
GEN *gptr[6];
if(DEBUGMEM>1)
{
if (DEBUGLEVEL > 3) fprintferr("\n");
err(warnmem,"lllgram");
}
gptr[0]=&B; gptr[1]=&L; gptr[2]=&h; gptr[3]=&A;
gptr[4]=&x; gptr[5]=&cst; gerepilemany(av,gptr,6);
}
}
if (DEBUGLEVEL>3) fprintferr("\n");
tetpil=avma; return gerepile(av,tetpil,gcopy(h));
}
static GEN
lllgram_noerr(GEN x,long prec) { return lllgramintern(x,100,1,prec); }
GEN
lllgram(GEN x,long prec) { return lllgramintern(x,100,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,"qflll");
}
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,"qflllgram");
}
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,lllgramall0,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,lllgramall0); }
GEN
lllkerimgen(GEN x) { return lllkerim_proto(x,lllgramallgen); }
/* 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,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)
{
unreel = realun(prec+1);
x = gmul(x,unreel);
cst = gmul(cst,unreel);
}
av=avma; lim=stack_lim(av,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;
swap(u[k-1],u[k]);
for (j=1; j<=k-2; j++) swap(coeff(mu,k-1,j), coeff(mu,k,j));
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, stack_lim(av,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));
}
GEN
lllgramint(GEN x)
{
return lllgramall0(x,lll_IM);
}
GEN
lllgramkerim(GEN x)
{
return lllgramall0(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)
*
* If flag = 1 complete the reduction using lllint, otherwise return
* partially reduced basis.
*/
GEN
lllintpartialall(GEN m, long flag)
{
const long ncol = lg(m)-1;
const long ltop1 = avma;
long ncolnz;
GEN tm1, tm2, mid, *gptr[4];
if (typ(m) != t_MAT) err(typeer,"lllintpartialall");
if (ncol <= 1) return idmat(ncol);
{
GEN dot11 = sqscali((GEN)m[1]);
GEN dot22 = sqscali((GEN)m[2]);
GEN dot12 = gscali((GEN)m[1], (GEN)m[2]);
GEN tm = idmat(2); /* For first two columns only */
int progress = 0;
long npass2 = 0;
/* Try to row reduce the first two columns of m.
* Our best result so far is (first two columns of m)*tm.
*
* Initially tm = 2 x 2 identity matrix.
* The inner products of the reduced matrix are in
* dot11, dot12, dot22.
*/
while (npass2 < 2 || progress)
{
GEN dot12new,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 tm 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.
*/
q = negi(q);
dot12new = addii(dot12, mulii(q, dot22));
dot11 = addii(dot11, mulii(q, addii(dot12, dot12new)));
dot12 = dot12new;
tm[1] = (long)lincomb_integral(gun,q, (GEN)tm[1],(GEN)tm[2]);
}
/* Interchange the output vectors v1 and v2. */
gswap(dot11,dot22); swap(tm[1],tm[2]);
/* Occasionally (including final pass) do garbage collection. */
if (npass2 % 8 == 0 || !progress)
{
gptr[0] = &dot11; gptr[1] = &dot12;
gptr[2] = &dot22; gptr[3] = &tm;
gerepilemany(ltop1, gptr, 4);
}
} /* while npass2 < 2 || progress */
{
long icol;
GEN det12 = subii(mulii(dot11, dot22), mulii(dot12, dot12));
tm1 = idmat(ncol);
mid = cgetg(ncol+1, t_MAT);
for (icol = 1; icol <= 2; icol++)
{
coeff(tm1,1,icol) = coeff(tm,1,icol);
coeff(tm1,2,icol) = coeff(tm,2,icol);
mid[icol] = (long)lincomb_integral(
gcoeff(tm,1,icol),gcoeff(tm,2,icol), (GEN)m[1],(GEN)m[2]);
}
for (icol = 3; icol <= ncol; icol++)
{
GEN curcol = (GEN)m[icol];
GEN dot1i = gscali((GEN)mid[1], curcol);
GEN dot2i = gscali((GEN)mid[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*mid[1] - q2*mid[2].
* This will be approximately orthogonal to the
* first two vectors in the new basis.
*/
GEN q1neg = subii(mulii(dot12, dot2i), mulii(dot22, dot1i));
GEN q2neg = subii(mulii(dot12, dot1i), mulii(dot11, dot2i));
q1neg = gdivround(q1neg, det12);
q2neg = gdivround(q2neg, det12);
coeff(tm1, 1, icol) = ladd(gmul(q1neg, gcoeff(tm,1,1)),
gmul(q2neg, gcoeff(tm,1,2)));
coeff(tm1, 2, icol) = ladd(gmul(q1neg, gcoeff(tm,2,1)),
gmul(q2neg, gcoeff(tm,2,2)));
mid[icol] = ladd(curcol,
lincomb_integral(q1neg,q2neg, (GEN)mid[1],(GEN)mid[2]));
} /* for icol */
} /* local block */
}
if (DEBUGLEVEL>4)
{
fprintferr("tm1 = "); outbeauterr(tm1);
fprintferr("mid = "); outbeauterr(mid);
}
gptr[0] = &tm1; gptr[1] = ∣
gerepilemany(ltop1, gptr, 2);
{
/* For each pair of column vectors v and w in mid * tm2,
* 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 tm1 and mid */
long icol, lim, reductions, npass = 0;
GEN dotprd = cgetg(ncol+1, t_MAT);
tm2 = 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,jcol,icol) = coeff(dotprd,icol,jcol) =
(long)gscali((GEN)mid[icol], (GEN)mid[jcol]);
} /* for icol */
lim = stack_lim(ltop3,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 = (cmpii(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++; q = negi(q);
tm2[k1]=(long)
lincomb_integral(gun,q, (GEN)tm2[k1], (GEN)tm2[k2]);
dotprd[k1]=(long)
lincomb_integral(gun,q, (GEN)dotprd[k1], (GEN)dotprd[k2]);
coeff(dotprd, k1, k1) = laddii(gcoeff(dotprd,k1,k1),
mulii(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, stack_lim(ltop3,1)))
{
if(DEBUGMEM>1) err(warnmem,"lllintpartialall");
gptr[0] = &dotprd; gptr[1] = &tm2;
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, diag_prod);
}
} /* for(;;)*/
/* Sort columns so smallest comes first in m * tm1 * tm2.
* Use insertion sort.
*/
for (icol = 1; icol < ncol; icol++)
{
long jcol, s = icol;
for (jcol = icol+1; jcol <= ncol; jcol++)
if (cmpii(gcoeff(dotprd,s,s),gcoeff(dotprd,jcol,jcol)) > 0) s = jcol;
if (icol != s)
{ /* Exchange with proper column */
/* Only diagonal of dotprd is updated */
swap(tm2[icol], tm2[s]);
swap(coeff(dotprd,icol,icol), coeff(dotprd,s,s));
}
} /* for icol */
icol=1;
while (icol <= ncol && !signe(gcoeff(dotprd,icol,icol))) icol++;
ncolnz = ncol - icol + 1;
} /* local block */
if (flag)
{
if (ncolnz == lg((GEN)m[1])-1)
{
tm2 += (ncol-ncolnz);
tm2[0]=evaltyp(t_MAT)|evallg(ncolnz+1);
}
else
{
tm1 = gmul(tm1, tm2);
tm2 = lllint(gmul(m, tm1));
}
}
if (DEBUGLEVEL>4)
{ fprintferr("lllintpartial output = "); outbeauterr(gmul(tm1, tm2)); }
return gerepileupto(ltop1, gmul(tm1, tm2));
}
GEN
lllintpartial(GEN mat)
{
return lllintpartialall(mat,1);
}
/********************************************************************/
/** **/
/** 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);
if (lx == 3)
{ /* independant over R ? */
if (gexpo(gsub(gmul((GEN)re[1],(GEN)im[2]),
gmul((GEN)re[2],(GEN)im[1]))) > - bit)
{
avma = av; return cgetg(1, t_VEC);
}
}
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))
GEN
lindep(GEN x, long prec)
{
GEN *b,*be,*bn,**m,qzer;
GEN c1,c2,c3,px,py,pxy,re,im,p3,p4,r,f,em;
long i,j,fl,i1, lx = lg(x), tx = typ(x), n = lx-1;
long av = avma, lim = stack_lim(av,1), av0,av1,tetpil;
const long EXP = - bit_accuracy(prec) + 2*n;
if (! is_vec_t(tx)) err(typeer,"lindep");
if (lx<=2) return cgetg(1,t_VEC);
x = gmul(x, realun(prec));
re=greal(x); im=gimag(x);
if (lx == 3)
{ /* independant over R ? */
if (gexpo(gsub(gmul((GEN)re[1],(GEN)im[2]),
gmul((GEN)re[2],(GEN)im[1]))) > - bit_accuracy(prec))
{
avma = av; return cgetg(1, t_VEC);
}
}
qzer = new_chunk(lx);
b = (GEN*)idmat(n);
be= (GEN*)new_chunk(lx);
bn= (GEN*)new_chunk(lx);
m = (GEN**)new_chunk(lx);
for (i=1; i<=n; i++)
{
bn[i]=cgetr(prec+1);
be[i]=cgetg(lx,t_COL);
m[i] = (GEN*)new_chunk(lx);
for (j=1; j<i ; j++) m[i][j]=cgetr(prec+1);
for (j=1; j<=n; j++) be[i][j]=lgetr(prec+1);
}
px=sqscal(re);
py=sqscal(im); pxy=gscal(re,im);
p3=mpsub(mpmul(px,py),gsqr(pxy));
if (quazero(re)) { re=im; px=py; fl=1; } else fl=quazero(p3);
av0 = av1 = avma;
for (i=1; i<=n; i++)
{
p4 = gscal(b[i],re);
if (fl) p4=gmul(gdiv(p4,px),re);
else
{
GEN p5,p6,p7;
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])
{
long e;
if (DEBUGLEVEL>9)
{
fprintferr("qzer[%ld]=%ld\n",n,qzer[n]);
for (i1=1; i1<=n; i1++)
for (i=1; i<i1; i++) output(m[i1][i]);
}
em=bn[1]; j=1;
for (i=2; i<n; i++)
{
p3=shiftr(bn[i],i);
if (cmprr(p3,em)>0) { em=p3; j=i; }
}
i=j; i1=i+1;
avma = av1; r = grndtoi(m[i1][i], &e);
if (e >= 0) err(talker,"precision too low in lindep");
r = negi(r);
p3 = lincomb_integral(gun,r, b[i1],b[i]);
av1 = avma;
b[i1]=b[i]; b[i]=p3; f=addir(r,m[i1][i]);
for (j=1; j<i; j++)
if (!qzer[j])
{
p3=mpadd(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(gsqr(f),bn[i]));
if (!quazero(c1))
{
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]; qzer[i]=1;
affrr(bn[i],bn[i1]); affrr(c1,bn[i]);
for (j=i+2; j<=n; j++) affrr(m[j][i],m[j][i1]);
}
if (low_stack(lim, stack_lim(av,1)))
{
if(DEBUGMEM>1) err(warnmem,"lindep");
b = (GEN*)gerepileupto(av0, gcopy((GEN)b));
av1 = avma;
}
}
p3=cgetg(lx,t_COL); p3[n]=un; for (i=1; i<n; i++) p3[i]=zero;
p4 = (GEN)b; p4[0] = evaltyp(t_MAT) | evallg(lx);
p4=gauss(gtrans(p4),p3); tetpil=avma;
return gerepile(av,tetpil,gtrans(p4));
}
GEN
algdep0(GEN x, long n, long bit, long prec)
{
long tx=typ(x),av,i,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);
if (lg(p1) < 2)
err(talker,"higher degree than expected in algdep");
y=cgetg(n+3,t_POL);
y[1] = evalsigne(1) | evalvarn(0);
k=1; while (gcmp0((GEN)p1[k])) k++;
for (i=0; i<=n+1-k; i++) y[i+2] = p1[k+i];
normalizepol_i(y, n+4-k);
y = (gsigne(leading_term(y)) > 0)? gcopy(y): gneg(y);
return gerepileupto(av,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,"matkerint");
}
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=lllgramall0(g,lll_KER); p1=lllint(g);
av1=avma; return gerepile(av,av1,gmul(g,p1));
}
static GEN
lllall0(GEN x, long flag)
{
long av0=avma,av,tetpil,lx=lg(x),i,j,k,l,n,lim,kmax;
GEN u,B,L,q,r,h,la,p1,p2,p4,fl;
if (typ(x) != t_MAT) err(typeer,"lllall0");
n=lx-1; if (n<=1) return lllall_trivial(x,n, flag | lll_GRAM);
fl = new_chunk(lx);
av=avma; lim=stack_lim(av,1); x=dummycopy(x);
B=gscalcol(gun, lx);
L=cgetg(lx,t_MAT);
for (k=lg(x[1]),j=1; j<lx; j++)
{
for (i=1; i<k; i++)
if (typ(gcoeff(x,i,j))!=t_INT) err(lllger4);
fl[j] = 0; L[j] = (long)zerocol(n);
}
k=2; h=idmat(n); kmax=1;
u=sqscali((GEN)x[1]);
if (signe(u)) { B[2]=(long)u; coeff(L,1,1)=un; fl[1]=1; } else B[2]=un;
for(;;)
{
if (k > kmax)
{
kmax = k;
for (j=1; j<=k; j++)
{
if (j==k || fl[j])
{
long av1 = avma;
u=gscali((GEN)x[k],(GEN)x[j]);
for (i=1; i<j; i++)
if (fl[i])
u = divii(subii(mulii((GEN)B[i+1],u),
mulii(gcoeff(L,k,i),gcoeff(L,j,i))),
(GEN)B[i]);
u = gerepileuptoint(av1, u);
if (j<k) coeff(L,k,j)=(long)u;
else
{
if (signe(u)) { B[k+1]=(long)u; coeff(L,k,k)=un; fl[k]=1; }
else { B[k+1]=B[k]; fl[k]=0; }
}
}
}
}
if (fl[k-1] && !fl[k])
{
u = shifti(gcoeff(L,k,k-1),1);
if (absi_cmp(u, (GEN)B[k]) > 0)
{
q = truedvmdii(addii(u,(GEN)B[k]),shifti((GEN)B[k],1), NULL);
r = negi(q);
h[k] = (long)lincomb_integral(gun,r, (GEN)h[k],(GEN)h[k-1]);
x[k] = (long)lincomb_integral(gun,r, (GEN)x[k],(GEN)x[k-1]);
coeff(L,k,k-1)=laddii(gcoeff(L,k,k-1),mulii(r,(GEN)B[k]));
for (i=1; i<k-1; i++)
coeff(L,k,i)=laddii(gcoeff(L,k,i),mulii(r,gcoeff(L,k-1,i)));
}
la=gcoeff(L,k,k-1); p4=sqri(la);
swap(h[k-1], h[k]);
swap(x[k-1], x[k]);
for (j=1; j<k-1; j++) swap(coeff(L,k-1,j), coeff(L,k,j));
if (signe(la))
{
p2=(GEN)B[k]; p1=divii(p4,p2);
B[k+1]=B[k]=(long)p1;
for (i=k+1; i<=kmax; i++)
coeff(L,i,k-1)=ldivii(mulii(la,gcoeff(L,i,k-1)),p2);
for (j=k+1; j<kmax; j++)
for (i=j+1; i<=kmax; i++)
coeff(L,i,j)=ldivii(mulii((GEN)p1,gcoeff(L,i,j)),p2);
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(L,i,k)=coeff(L,i,k-1); coeff(L,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--)
{
u = shifti(gcoeff(L,k,l),1);
if (absi_cmp(u,(GEN)B[l+1]) > 0)
{
q = truedvmdii(addii(u,(GEN)B[l+1]),shifti((GEN)B[l+1],1), NULL);
r = negi(q);
h[k] = (long)lincomb_integral(gun,r,(GEN)h[k],(GEN)h[l]);
x[k] = (long)lincomb_integral(gun,r,(GEN)x[k],(GEN)x[l]);
coeff(L,k,l)=laddii(gcoeff(L,k,l),mulii(r,(GEN)B[l+1]));
for (i=1; i<l; i++)
coeff(L,k,i)=laddii(gcoeff(L,k,i),mulii(r,gcoeff(L,l,i)));
}
}
if (++k > n) break;
}
if (low_stack(lim, stack_lim(av,1)))
{
GEN *gptr[4];
if(DEBUGMEM>1) err(warnmem,"lllall0");
gptr[0]=&B; gptr[1]=&L; gptr[2]=&h;
gptr[3]=&x; gerepilemany(av,gptr,4);
}
}
tetpil=avma;
return gerepile(av0,tetpil,lllgramall_finish(h,fl,flag,n));
}
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. **/
/** **/
/********************************************************************/
/* remove duplicate polynomials in y, updating a (same indexes), in place */
static long
remove_duplicates(GEN y, GEN a)
{
long k,i, nv = lg(y), av = avma;
GEN z;
if (nv < 2) return nv;
z = new_chunk(3);
z[1] = (long)y;
z[2] = (long)a; (void)sort_factor(z, gcmp);
for (k=1, i=2; i<nv; i++)
if (!gegal((GEN)y[i], (GEN)y[k]))
{
k++;
a[k] = a[i];
y[k] = y[i];
}
nv = k+1; setlg(a,nv); setlg(y,nv);
avma = av; return nv;
}
/* in place; make sure second non-zero coeff is negative (choose x or -x) */
int
canon_pol(GEN z)
{
long i,s;
for (i=lgef(z)-2; i>=2; i-=2)
{
s = signe(z[i]);
if (s > 0)
{
for (; i>=2; i-=2) z[i]=lnegi((GEN)z[i]);
return -1;
}
if (s) return 1;
}
return 0;
}
static GEN
pols_for_polred(GEN x, GEN base, GEN LLLbase, GEN *pta)
{
long i,j, v = varn(x), n = lg(base);
GEN p1,p2,p3,y, a = cgetg(n,t_VEC);
for (i=1; i<n; i++) a[i] = lmul(base,(GEN)LLLbase[i]);
y=cgetg(n,t_VEC);
for (i=1; i<n; i++)
{
if (DEBUGLEVEL>2) { fprintferr("i = %ld\n",i); flusherr(); }
p1=(GEN)a[i]; p3=content(p1);
if (gcmp1(p3)) p3 = NULL; else p1 = gdiv(p1,p3);
p1 = caract2(x,p1,v);
if (p3)
for (p2=gun, j=lgef(p1)-2; j>=2; j--)
{
p2 = gmul(p2,p3); p1[j] = lmul((GEN)p1[j], p2);
}
p2=modulargcd(derivpol(p1),p1); p3=leading_term(p2);
if (!gcmp1(p3)) p2=gdiv(p2,p3);
p1 = gdiv(p1,p2);
if (canon_pol(p1) < 0 && pta)
a[i] = (long) gneg_i((GEN)a[i]);
y[i] = (long)p1; if (DEBUGLEVEL>=4) outerr(p1);
}
(void)remove_duplicates(y,a);
if (pta) *pta = a;
return y;
}
GEN
nf_get_T2(GEN base, GEN polr)
{
long i,j, n = lg(base);
GEN p1,p2=cgetg(n,t_MAT);
for (i=1; i<n; i++)
{
p1=cgetg(n,t_COL); p2[i]=(long)p1;
for (j=1; j<n; j++)
p1[j] = (long) poleval((GEN)base[i],(GEN)polr[j]);
}
return mulmat_real(gconj(gtrans(p2)),p2);
}
/* Return the base change matrix giving the an LLL-reduced basis for the
* maximal order of the nf given by x. Expressed in terms of the standard
* HNF basis (as polynomials) given in base (ignored if x is an nf)
*/
GEN
LLL_nfbasis(GEN *ptx, GEN polr, GEN base, long prec)
{
GEN T2,p1, x = *ptx;
int totally_real,n,i,j;
if (typ(x) != t_POL)
{
p1=checknf(x); *ptx=x=(GEN)p1[1];
base=(GEN)p1[7]; n=lgef(x)-3;
totally_real = !signe(gmael(p1,2,2));
T2=gmael(p1,5,3); if (totally_real) T2 = ground(T2);
}
else
{
n=lgef(x)-3; totally_real = (!prec || sturm(x)==n);
if (!totally_real)
T2 = nf_get_T2(base,polr? polr: roots(x,prec));
else
{ /* totally real */
GEN ptrace=cgetg(n+2,t_VEC);
long k;
ptrace[2]=lstoi(n);
for (k=2; k<=n; k++)
{ /* cf polsym */
GEN y = x + (n-k+1);
p1 = gmulsg(k-1,(GEN)y[2]);
for (i=3; i<=k; i++)
p1 = gadd(p1,gmul((GEN)y[i],(GEN)ptrace[i]));
ptrace[i] = lneg(p1);
}
T2=cgetg(n+1,t_MAT);
for (i=1; i<=n; i++)
{
p1=cgetg(n+1,t_COL); T2[i]=(long)p1;
for (j=1; j<i ; j++) p1[j] = coeff(T2,i,j);
for ( ; j<=n; j++)
{ /* cf quicktrace */
GEN p2 = gres(gmul((GEN)base[i],(GEN)base[j]),x);
GEN p3 = gzero;
for (k=lgef(p2)-1; k>1; k--)
p3 = gadd(p3, gmul((GEN)p2[k],(GEN)ptrace[k]));
p1[j]=(long)p3;
}
}
}
}
if (totally_real) return lllgramint(T2);
for (i=1; ; i++)
{
if ((p1 = lllgramintern(T2,100,1,prec))) return p1;
if (i == MAXITERPOL) err(accurer,"allpolred");
prec=(prec<<1)-2;
if (DEBUGLEVEL) err(warnprec,"allpolred",prec);
T2=nf_get_T2(base,roots(x,prec));
}
}
/* 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, base = NULL, polr = NULL;
long av = avma;
if (typ(x) == t_POL)
{
if (!signe(x)) return gcopy(x);
check_pol_int(x);
if (!gcmp1(leading_term(x)))
err(impl,"allpolred for nonmonic polynomials");
base = allbase4(x,code,&p1,NULL); /* p1 is junk */
}
else
{
long i = lg(x);
if (typ(x) == t_VEC && i<=4 && i>=3 && typ(x[1])==t_POL)
{ /* polynomial + integer basis */
base=(GEN)x[2]; x=(GEN)x[1];
}
}
p1 = LLL_nfbasis(&x,polr,base,prec);
y = pols_for_polred(x,base,p1,pta);
if (pta)
{
GEN *gptr[2]; gptr[0]=&y; gptr[1]=pta;
gerepilemany(av,gptr,2); return y;
}
return gerepileupto(av,y);
}
GEN
polred0(GEN x,long flag, GEN p, long prec)
{
GEN y;
long smll = (flag & 1);
if (p && !gcmp0(p)) smll=(long) p; /* factored polred */
if (flag & 2) /* polred2 */
{
y=cgetg(3,t_MAT);
y[2]=(long)allpolred(x,(GEN*)(y+1),smll,prec);
return y;
}
return allpolred(x,NULL,smll,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); /* power basis */
for (i=1; i<=n; i++)
{
base[i]=lpowgs(polx[v],i-1);
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 = mulmat_real(gconj(gtrans(p3)),p3);
p1 = pols_for_polred(x,base,lllgram(p2,prec), NULL);
tetpil=avma; return gerepile(av,tetpil, gcopy(p1));
}
GEN roots_to_pol_r1r2(GEN a, long r1, long v);
static GEN chk_basis_embed;
long chk_r1, chk_v;
static GEN
init_chk(GEN nf, GEN mat, GEN bound)
{
GEN M = gmael(nf,5,1);
long n = lg(nf[7])-1, prec,prec2;
if (!bound)
{
chk_v = varn(nf[1]);
chk_r1 = itos(gmael(nf,2,1));
chk_basis_embed = gmul(M, mat);
return gmul((GEN)nf[7],mat);
}
/* should be [max_k C^n_k (B/k) ^ k] ^ (1/2) */
bound = gsqrt(gpowgs(bound, n), 3);
prec2 = (1 + (gexpo(bound) >> TWOPOTBITS_IN_LONG));
if (prec2 < 0) prec2 = 0;
prec = 3 + prec2;
prec2= (long)nfnewprec(nf,-1);
if (DEBUGLEVEL)
fprintferr("init_chk: estimated prec = %ld (initially %ld)\n",
prec, prec2);
if (prec > prec2) return NULL;
if (prec < prec2) chk_basis_embed = gprec_w(chk_basis_embed, prec);
return (GEN)prec;
}
static GEN
checkgenerator(GEN x)
{
long l,i,av = avma;
GEN g = gmul(chk_basis_embed,x);
GEN r = gneg((GEN)g[1]);
long epsbit = 5 - bit_accuracy(gprecision(r));
l = lg(g)-1;
for (i=2; i<=l; i++)
if (gexpo(gadd((GEN)g[i], r)) < epsbit) { avma=av; return NULL; }
g = roots_to_pol_r1r2(g, chk_r1, chk_v);
g = ground(g);
if (lgef(modulargcd(g,derivpol(g))) > 3) { avma=av; return NULL; }
if (DEBUGLEVEL>3) fprintferr(" generator: %Z\n",g);
return g;
}
/* no garbage collecting, done in polredabs0 */
static GEN
findmindisc(GEN nf, GEN y, GEN a, GEN phimax, long flun)
{
long i,k, c = lg(y);
GEN v,dmin,z,beta,discs = cgetg(c,t_VEC);
for (i=1; i<c; i++) discs[i] = labsi(discsr((GEN)y[i]));
v = sindexsort(discs);
k = v[1]; dmin = (GEN)discs[k]; z = (GEN)y[k]; beta = (GEN)a[k];
for (i=2; i<c; i++)
{
k = v[i];
if (!egalii((GEN)discs[k],dmin)) break;
if (gpolcomp((GEN)y[k],z) < 0) { z = (GEN)y[k]; beta = (GEN)a[k]; }
}
if (flun & nf_RAW)
{
y=cgetg(3,t_VEC);
y[1]=lcopy(z);
y[2]=lcopy(beta);
}
else if (phimax)
{
y=cgetg(3,t_VEC);
y[1]=lcopy(z);
beta=polymodrecip(gmodulcp(beta,(GEN)nf[1]));
y[2]=(long)poleval(phimax,beta);
}
else y = gcopy(z);
return y;
}
/* no garbage collecting, done in polredabs0 */
static GEN
storeallpols(GEN nf, GEN z, GEN a, GEN phimax, long flun)
{
GEN p1,y,beta;
if (flun & nf_RAW)
{
long i, c = lg(z);
y=cgetg(c,t_VEC);
for (i=1; i<c; i++)
{
p1=cgetg(3,t_VEC); y[i]=(long)p1;
p1[1]=lcopy((GEN)z[i]);
p1[2]=lcopy((GEN)a[i]);
}
}
else if (phimax)
{
long i, c = lg(z);
beta = new_chunk(c);
for (i=1; i<c; i++)
beta[i] = (long)polymodrecip(gmodulcp((GEN)a[i],(GEN)nf[1]));
y=cgetg(c,t_VEC);
for (i=1; i<c; i++)
{
p1=cgetg(3,t_VEC); y[i]=(long)p1;
p1[1]=lcopy((GEN)z[i]);
p1[2]=(long)poleval(phimax,(GEN)beta[i]);
}
}
else y = gcopy(z);
return y;
}
GEN
polredabs0(GEN x, long flun, long prec)
{
long i,nv, av = avma;
GEN nf,v,y,a,phimax;
GEN (*storepols)(ANYARG);
if ((ulong)flun >= 16) err(flagerr,"polredabs");
nf = initalgall0(x,nf_SMALL|nf_REGULAR,prec);
if (lg(nf) == 3)
{
phimax = lift_to_pol((GEN)nf[2]);
nf = (GEN)nf[1];
}
else
phimax = (flun & nf_ORIG)? polx[0]: (GEN)NULL;
prec = (long)nfnewprec(nf,0);
nv = lgef(nf[1])==4? 1: 2;
for (i=1; ; i++)
{
v = fincke_pohst(nf,NULL,stoi(5000),3,prec, &checkgenerator);
if (v) break;
if (i==MAXITERPOL) err(accurer,"polredabs0");
prec = (prec<<1)-2; nf = nfnewprec(nf,prec);
if (DEBUGLEVEL) err(warnprec,"polredabs0",prec);
}
a = (GEN)v[2];
y = (GEN)v[1];
nv = lg(a);
for (i=1; i<nv; i++)
if (canon_pol((GEN)y[i]) < 0 && phimax)
a[i] = (long) gneg_i((GEN)a[i]);
nv = remove_duplicates(y,a);
if (DEBUGLEVEL)
{ fprintferr("%ld minimal vectors found.\n",nv-1); flusherr(); }
if (nv >= 10000) flun &= (~nf_ALL); /* should not happen */
storepols = (flun & nf_ALL)? storeallpols: findmindisc;
if (DEBUGLEVEL) fprintferr("\n");
if (nv==1)
{
x=(GEN)nf[1];
y = cgetg(2,t_VEC); y[1]=(long)x;
a = cgetg(2,t_VEC); a[1]=(long)polx[varn(x)];
}
return gerepileupto(av, storepols(nf,y,a,phimax,flun));
}
GEN
polredabsall(GEN x, long flun, long prec)
{
return polredabs0(x, flun | nf_ALL, prec);
}
GEN
polredabs(GEN x, long prec)
{
return polredabs0(x,nf_REGULAR,prec);
}
GEN
polredabs2(GEN x, long prec)
{
return polredabs0(x,nf_ORIG,prec);
}
GEN
polredabsnored(GEN x, long prec)
{
return polredabs0(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;
}
GEN makebasis(GEN nf,GEN pol);
/* relative polredabs. Returns
* flag = 0: relative polynomial
* flag = 1: relative polynomial + element
* flag = 2: absolute polynomial */
GEN
rnfpolredabs(GEN nf, GEN relpol, long flag, long prec)
{
GEN p1,bpol,rnf,elt,pol;
long va, av = avma;
if (typ(relpol)!=t_POL) err(typeer,"rnfpolredabs");
nf=checknf(nf); va = varn(relpol);
if (DEBUGLEVEL>1) timer2();
p1 = makebasis(nf, unifpol(nf,relpol,1));
rnf = (GEN)p1[3];
if (DEBUGLEVEL>1)
{
msgtimer("absolute basis");
fprintferr("original absolute generator: %Z\n",p1[1]);
}
p1 = polredabs0(p1, nf_RAW | nf_NORED, prec);
bpol = (GEN)p1[1];
if (DEBUGLEVEL>1) fprintferr("reduced absolute generator: %Z\n",bpol);
if (flag==2) return gerepileupto(av,bpol);
elt = rnfelementabstorel(rnf,(GEN)p1[2]);
p1=cgetg(3,t_VEC);
#if 1
pol = rnfcharpoly(nf,relpol,elt,va);
#else
{
long i;
p1=(GEN)nffactor(nf,bpol)[1];
for (i=lg(p1)-1; i; i--)
if(gcmp0(gsubst((GEN)p1[i],va,elt))) { pol=(GEN)p1[i]; break; }
if (!i) err(bugparier,"rnfpolredabs (pol not found)");
}
#endif
if (!flag) p1 = pol;
else
{
p1[1]=(long)pol;
p1[2]=(long)polymodrecip(elt);
}
return gerepileupto(av,p1);
}
/********************************************************************/
/** **/
/** 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*) new_chunk(n);
q = (double**) new_chunk(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*) new_chunk(s);
z = (double*) new_chunk(s);
v = (double*) new_chunk(s);
for (j=1; j<n; j++) q[j] = (double*) new_chunk(s);
av1=avma;
u = lllgramint(a); a = qf_base_change(a,u,1);
if (lg(a) != n)
err(talker,"not a definite form in minim00");
n--;
a = gmul(a, realun(DEFAULTPREC)); r = sqred1(a);
if (DEBUGLEVEL>4) { fprintferr("minim: r = "); outerr(r); }
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 = new_chunk(1+maxrank);
break;
case min_PERF:
BORNE = gerepileupto(av1,BORNE);
maxrank = (n*(n+1))>>1;
liste = new_chunk(1+maxrank); V = new_chunk(1+maxrank);
for (i=1; i<=maxrank; i++) liste[i]=0;
}
s=0; av1=avma; lim = stack_lim(av1,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 = new_chunk(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, stack_lim(av1,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,NULL);
default: err(flagerr,"qfminim");
}
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). Si flag >= 2, on s'arrete des que stockmax est atteint.
* Si flag&1 == 1, pas d'erreur dans sqred1intern. */
static GEN
smallvectors(GEN a, GEN BORNE, GEN STOCKMAX, long flag, long prec,
GEN (*check)(GEN))
{
long av = avma,av1,av2,lim,N,n,i,j,k,s,stockmax,epsbit,checkcnt = 0;
GEN u,S,x,y,z,v,q,norme1,normax1,borne1,borne2,eps,p1,alpha,norms;
N=lg(a); n=N-1; stockmax=itos(STOCKMAX);
if (DEBUGLEVEL)
fprintferr("smallvectors looking for norm <= %Z\n",gprec_w(BORNE,3));
lim=stack_lim(av,1); q=sqred1intern(a,flag&1);
if (q == NULL) { avma=av; return NULL; }
if (DEBUGLEVEL>5) fprintferr("q = %Z",q);
epsbit = bit_accuracy(prec) >> 1;
eps=realun(prec); setexpo(eps,-epsbit);
alpha = dbltor(0.95);
normax1=gzero;
borne1=gadd(BORNE,eps);
borne2=mpmul(borne1,alpha);
v=cgetg(N,t_VEC);
av2=avma;
S = cgetg(stockmax+1,t_MAT);
norms = cgetg(stockmax+1,t_VEC);
x=cgetg(N,t_COL);
y=cgetg(N,t_COL);
z=cgetg(N,t_COL);
for (i=1; i<N; i++) { v[i] = coeff(q,i,i); x[i]=y[i]=z[i] = zero; }
x[n] = lmpent(mpsqrt(gdiv(borne1,(GEN)v[n])));
if (DEBUGLEVEL>3) { fprintferr("\nx[%ld] = %Z\n",n,x[n]); flusherr(); }
s=0; k=n;
for(;;)
{
do
{
int fl=0;
if (k>1)
{
av1=avma; k--;
p1 = mpmul(gcoeff(q,k,k+1),(GEN)x[k+1]);
for (j=k+2; j<N; j++)
p1 = mpadd(p1, mpmul(gcoeff(q,k,j),(GEN)x[j]));
z[k] = lpileupto(av1,p1);
av1=avma;
p1 = gsqr(mpadd((GEN)x[k+1],(GEN)z[k+1]));
y[k] = lpileupto(av1, mpadd((GEN)y[k+1], mpmul(p1,(GEN)v[k+1])));
av1=avma;
p1 = mpsub(borne1, (GEN)y[k]);
if (signe(p1) < 0) { avma=av1; fl = 1; }
else
{
p1 = mpadd(eps,mpsub(mpsqrt(gdiv(p1,(GEN)v[k])), (GEN)z[k]));
avma=av1; x[k] = lmpent(p1); /* safe */
}
}
else if (check)
{ /* don't waste time on the [x,0,...0] */
for (i=k+1; i<N; i++)
if (signe(x[i])) break;
if (i == N && signe(x[1])) x[1] = un;
}
for(;;)
{
av1=avma;
if (!fl)
{
p1 = mpmul((GEN)v[k], gsqr(mpadd((GEN)x[k],(GEN)z[k])));
if (mpcmp(mpsub(mpadd(p1,(GEN)y[k]), borne1),
gmul2n(mpabs(p1),-epsbit)) <= 0) { avma=av1; break; }
}
avma=av1; k++; fl=0;
x[k]=laddis((GEN)x[k],-1);
}
if (low_stack(lim, stack_lim(av,1)))
{
GEN *gptr[8];
int a = 4;
if(DEBUGMEM>1) err(warnmem,"smallvectors");
gptr[0]=&x; gptr[1]=&y; gptr[2]=&z; gptr[3]=&normax1;
if (stockmax)
{
for (i=s+1; i<=stockmax; i++) S[i]=zero;
gptr[4]=&S; a++;
}
if (check)
{
gptr[5]=&borne1; gptr[6]=&borne2; gptr[7]=&norms;
for (i=s+1; i<=stockmax; i++) norms[i]=zero;
a+=3;
}
gerepilemany(av2,gptr,a);
}
if (DEBUGLEVEL>3)
{
if (DEBUGLEVEL>5) fprintferr("%ld ",k);
if (k==n) fprintferr("\nx[%ld] = %Z\n",n,x[n]);
flusherr();
}
}
while (k>1);
if (!signe(x[1]) && gexpo((GEN)y[1]) <= -epsbit) break;
av1=avma; p1 = gsqr(mpadd((GEN)x[1],(GEN)z[1]));
norme1 = mpadd((GEN)y[1], mpmul(p1, (GEN)v[1]));
if (mpcmp(norme1,borne1) > 0) avma=av1;
else
{
norme1 = gerepileupto(av1,norme1);
if (check)
{
if (checkcnt < 5 && mpcmp(norme1, borne2) < 0)
{
if (check(x))
{
borne1 = mpadd(norme1,eps);
borne2 = mpmul(borne1,alpha);
s = 0; checkcnt = 0;
}
else { checkcnt++ ; goto CONTINUE; }
}
}
else if (mpcmp(norme1,normax1) > 0) normax1=norme1;
if (++s <= stockmax)
{
norms[s] = (long)norme1;
p1 = cgetg(N,t_COL); S[s] = (long)p1;
for (i=1; i<N; i++) p1[i]=x[i];
if (s == stockmax && (flag&2) && check)
{
long av1 = avma;
GEN per = sindexsort(norms);
if (DEBUGLEVEL) fprintferr("sorting...\n");
for (i=1; i<=s; i++)
{
long k = per[i];
if (check((GEN)S[k]))
{
S[1] = S[k]; avma = av1;
borne1 = mpadd(norme1,eps);
borne2 = mpmul(borne1,alpha);
s = 1; checkcnt = 0; break;
}
}
if (checkcnt) s = 0;
}
}
}
CONTINUE:
x[k] = laddis((GEN)x[k],-1);
}
if (s<stockmax) stockmax = s;
if (check)
{
GEN per, alph,pols,p;
if (DEBUGLEVEL) fprintferr("final sort & check...\n");
setlg(norms,s+1); per = sindexsort(norms);
alph = cgetg(s+1,t_VEC);
pols = cgetg(s+1,t_VEC);
for (j=0,i=1; i<=s; i++)
{
long k = per[i];
if (j && mpcmp((GEN)norms[k], borne1) > 0) break;
if ((p = check((GEN)S[k])))
{
if (!j) borne1 = gadd((GEN)norms[k],eps);
j++; pols[j]=(long)p; alph[j]=S[k];
}
}
u = cgetg(3,t_VEC);
setlg(pols,j+1); u[1] = (long)pols;
setlg(alph,j+1); u[2] = (long)alph; return u;
}
u=cgetg(4,t_VEC);
u[1]=lstoi(s<<1);
u[2]=(long)normax1; setlg(S,stockmax+1);
u[3]=(long)S; return u;
}
/* return T2 norm of the polynomial defining nf */
static GEN
get_Bnf(GEN nf)
{
GEN p = gzero, r = (GEN)nf[6];
long i, r1 = itos(gmael(nf,2,1)), ru = lg(r)-1;
for (i=ru; i>0; i--)
{
if (i == r1) p = gmul2n(p, 1);
p = gadd(p, gnorm((GEN)r[i]));
}
if (i == r1) p = gmul2n(p, 1);
return p;
}
/* solve x~.a.x <= borne, a > 0. If check is non-NULL keep x only if check(x).
* flag = 1, return NULL in case of precision problems (sqred1 or lllgram)
* raise an error otherwse.
* flag = 2, return as soon as stockmax vectors found.
* flag = 3, corresponds to 1+2 */
GEN
fincke_pohst(GEN a,GEN bound,GEN stockmax,long flag, long prec,
GEN (*check)(GEN))
{
long pr,av=avma,i,j,n;
GEN B,nf,r,rinvtrans,v,v1,u,s,res,z,vnorm,sperm,perm,uperm,basis,gram;
if (DEBUGLEVEL>2) { fprintferr("entering fincke_pohst\n"); flusherr(); }
if (typ(a) == t_VEC) { nf = a; a = gmael(nf,5,3); } else nf = NULL;
pr = gprecision(a);
if (pr) prec = pr; else a = gmul(a,realun(prec));
if (DEBUGLEVEL>2) fprintferr("first LLL: prec = %ld\n", prec);
v1 = lllgramintern(a,4,flag&1, (prec<<1)-2);
if (v1 == NULL) goto PRECPB;
r = qf_base_change(a,v1,1);
r = sqred1intern(r,flag&1);
if (r == NULL) goto PRECPB;
n = lg(a);
for (i=1; i<n; i++)
{
GEN p1 = gsqrt(gcoeff(r,i,i), prec);
coeff(r,i,i)=(long)p1;
for (j=i+1; j<n; j++)
coeff(r,i,j) = lmpmul(p1, gcoeff(r,i,j));
}
/* now r~ * r = a in LLL basis */
rinvtrans = gtrans(invmat(r));
if (DEBUGLEVEL>2)
fprintferr("final LLL: prec = %ld, precision(rinvtrans) = %ld\n",
prec,gprecision(rinvtrans));
v = lllintern(rinvtrans,flag&1, (gprecision(rinvtrans)<<1)-2);
if (v == NULL) goto PRECPB;
rinvtrans = gmul(rinvtrans,v);
u = invmat(gtrans(v)); s = gmul(r,u);
u = gmul(v1, u);
vnorm=cgetg(n,t_VEC);
for (j=1; j<n; j++) vnorm[j] = lnorml2((GEN)rinvtrans[j]);
perm = sindexsort(vnorm);
sperm = cgetg(n,t_MAT);
uperm = cgetg(n,t_MAT);
for (i=1; i<n; i++) { uperm[n-i] = u[perm[i]]; sperm[n-i] = s[perm[i]]; }
gram = gram_matrix(sperm);
B = gcoeff(gram,n-1,n-1);
if (gexpo(B) >= bit_accuracy(lg(B)-2)) goto PRECPB;
if (check && nf) basis = init_chk(nf,uperm,NULL);
if (!bound)
{ /* polred */
GEN x = cgetg(n,t_COL);
if (nf) bound = get_Bnf(nf);
for (j=1; j<n; j++) x[j]=zero;
for (j=2; j<n; j++)
{
x[j]=un; B = gcoeff(gram,j,j);
if (!bound || mpcmp(B,bound) < 0)
if (!check || check(x)) bound = B;
x[j]=zero;
}
}
if (DEBUGLEVEL>2) {fprintferr("entering smallvectors\n"); flusherr();}
if (check && nf)
if (! (prec = (long)init_chk(nf,uperm,bound))) goto PRECPB;
i = check? 2: 1; if (i == n) i--;
for ( ; i<n; i++)
{
res = smallvectors(gram,bound? bound: gceil(gcoeff(gram,i,i)),
stockmax,flag,prec,check);
if (!res) goto PRECPB;
if (!check || lg(res[2]) > 1) break;
if (DEBUGLEVEL>2) fprintferr(" i = %ld failed\n",i);
}
if (check)
{
GEN p1 = (GEN)res[2];
for (i=1; i<lg(p1); i++) p1[i] = lmul(basis, (GEN)p1[i]);
return res;
}
if (DEBUGLEVEL>2) {fprintferr("leaving fincke_pohst\n"); flusherr();}
z=cgetg(4,t_VEC);
z[1]=lcopy((GEN)res[1]);
z[2]=pr? lcopy((GEN)res[2]) : lround((GEN)res[2]);
z[3]=lmul(uperm, (GEN)res[3]); return gerepileupto(av,z);
PRECPB:
if (!(flag & 1))
err(talker,"not a positive definite form in fincke_pohst");
avma = av; return NULL;
}