/********************************************************************/ /** **/ /** LINEAR ALGEBRA **/ /** (second part) **/ /** **/ /********************************************************************/ /* $Id: alglin2.c,v 1.3 1999/09/23 17:50:55 karim Exp $ */ #include "pari.h" /*******************************************************************/ /* */ /* CHARACTERISTIC POLYNOMIAL */ /* */ /*******************************************************************/ GEN charpoly0(GEN x, int v, long flag) { if (v<0) v = 0; switch(flag) { case 0: return caradj(x,v,0); case 1: return caract(x,v); case 2: return carhess(x,v); } err(flagerr,"charpoly"); return NULL; /* not reached */ } static GEN caract2_i(GEN p, GEN x, int v, GEN (subres_f)(GEN,GEN,GEN*)) { long av = avma, d; GEN p1, p2 = leading_term(p); if (!signe(x)) return gpowgs(polx[v], lgef(p)-3); x = gneg_i(x); x[2] = ladd((GEN)x[2], polx[MAXVARN]); p1=subres_f(p, x, NULL); if (varn(p1)==MAXVARN) setvarn(p1,v); else p1=gsubst(p1,MAXVARN,polx[v]); if (!gcmp1(p2) && (d=lgef(x)-3) > 0) p1 = gdiv(p1, gpuigs(p2,d)); return gerepileupto(av,p1); } /* return caract(Mod(x,p)) in variable v */ GEN caract2(GEN p, GEN x, int v) { return caract2_i(p,x,v, subresall); } GEN caractducos(GEN p, GEN x, int v) { return caract2_i(p,x,v, (GEN (*)(GEN,GEN,GEN*))resultantducos); } /* characteristic pol. Easy cases. Return NULL in case it's not so easy. */ static GEN easychar(GEN x, int v, GEN *py) { long l,tetpil,lx; GEN p1,p2; switch(typ(x)) { case t_INT: case t_REAL: case t_INTMOD: case t_FRAC: case t_FRACN: case t_PADIC: p1=cgetg(4,t_POL); p1[1]=evalsigne(1) | evallgef(4) | evalvarn(v); p1[2]=lneg(x); p1[3]=un; if (py) { p2=cgetg(2,t_MAT); p2[1]=lgetg(2,t_COL); coeff(p2,1,1)=lcopy(x); *py=p2; } return p1; case t_COMPLEX: case t_QUAD: if (py) err(typeer,"easychar"); p1=cgetg(5,t_POL); p1[1]=evalsigne(1) | evallgef(5) | evalvarn(v); p1[2]=lnorm(x); l=avma; p2=gtrace(x); tetpil=avma; p1[3]=lpile(l,tetpil,gneg(p2)); p1[4]=un; return p1; case t_POLMOD: if (py) err(typeer,"easychar"); return caract2((GEN)x[1], (GEN)x[2], v); case t_MAT: lx=lg(x); if (lx==1) { if (py) *py = cgetg(1,t_MAT); return polun[v]; } if (lg(x[1]) != lx) break; return NULL; } err(mattype1,"easychar"); return NULL; /* not reached */ } GEN caract(GEN x, int v) { long n,k,l=avma,tetpil; GEN p1,p2,p3,p4,p5,p6; if ((p1 = easychar(x,v,NULL))) return p1; p1=gzero; p2=gun; n=lg(x)-1; if (n&1) p2=gneg_i(p2); p4=cgetg(3,t_RFRACN); p5=dummycopy(polx[v]); p4[2]=(long)p5; p6=cgeti(3); p6[1] = evalsigne(-1) | evallgefint(3); for (k=0; k<=n; k++) { p3=det(gsub(gscalmat(stoi(k),n), x)); p4[1]=lmul(p3,p2); p6[2]=k; p1=gadd(p4,p1); p5[2]=(long)p6; if (k!=n) p2=gdivgs(gmulsg(k-n,p2),k+1); } p2=mpfact(n); tetpil=avma; return gerepile(l,tetpil,gdiv((GEN) p1[1],p2)); } GEN caradj0(GEN x, long v) { return caradj(x,v,NULL); } /* Using traces: return the characteristic polynomial of x (in variable v). * If py != NULL, the adjoint matrix is put there. */ GEN caradj(GEN x, long v, GEN *py) { long i,j,k,l,av,tetpil; GEN p,y,t,*gptr[2]; if ((p = easychar(x,v,py))) return p; l=lg(x); if (l==1) { p=polun[v]; if (py) *py=gcopy(x); return p; } if (l==2) { p=gsub(polx[v],gtrace(x)); if (py) *py=idmat(1); return p; } p=cgetg(l+2,t_POL); p[1]=evalsigne(1) | evallgef(l+2) | evalvarn(v); av=avma; t=gtrace(x); tetpil=avma; t=gerepile(av,tetpil,gneg(t)); p[l]=(long)t; p[l+1]=un; av=avma; y=cgetg(l,t_MAT); for (j=1; j1) err(warnmem,"sqred1"); tetpil=avma; b=gerepile(av,tetpil,gcopy(b)); } } tetpil=avma; return gerepile(av,tetpil,gcopy(b)); } GEN sqred1(GEN a) { return sqred1intern(a,0); } GEN sqred3(GEN a) { long av=avma,tetpil,i,j,k,l, lim=stack_lim(av,1), n=lg(a); GEN p1,b; if (typ(a)!=t_MAT) err(typeer,"sqred3"); if (lg(a[1])!=n) err(mattype1,"sqred3"); av=avma; b=cgetg(n,t_MAT); for (j=1; j1) err(warnmem,"sqred3"); tetpil=avma; b=gerepile(av,tetpil,gcopy(b)); } } tetpil=avma; return gerepile(av,tetpil,gcopy(b)); } /* Gauss reduction (arbitrary symetric matrix, only the part above the * diagonal is considered). If no_signature is zero, return only the * signature */ static GEN sqred2(GEN a, long no_signature) { GEN r,p,mun; long av,tetpil,av1,lim,n,i,j,k,l,sp,sn,t; if (typ(a)!=t_MAT) err(typeer,"sqred2"); n=lg(a); if (lg(a[1]) != n) err(mattype1,"sqred2"); av=avma; mun=negi(gun); r=new_chunk(n); for (i=1; i0) sp++; else sn++; r[k]=0; t--; for (j=1; j<=n; j++) coeff(a,k,j)=r[j] ? ldiv(gcoeff(a,k,j),p) : zero; for (i=1; i<=n; i++) if (r[i]) for (j=1; j<=n; j++) coeff(a,i,j) = r[j] ? lsub(gcoeff(a,i,j), gmul(gmul(gcoeff(a,k,i),gcoeff(a,k,j)),p)) : zero; coeff(a,k,k)=(long)p; } else { for (k=1; k<=n; k++) if (r[k]) { l=k+1; while (l<=n && (gcmp0(gcoeff(a,k,l)) || !r[l])) l++; if (l<=n) { p=gcoeff(a,k,l); r[k]=r[l]=0; sp++; sn++; t-=2; for (i=1; i<=n; i++) if (r[i]) { for (j=1; j<=n; j++) coeff(a,i,j) = r[j]? lsub(gcoeff(a,i,j), gdiv(gadd(gmul(gcoeff(a,k,i),gcoeff(a,l,j)), gmul(gcoeff(a,k,j),gcoeff(a,l,i))), p)) : zero; coeff(a,k,i)=ldiv(gadd(gcoeff(a,k,i),gcoeff(a,l,i)),p); coeff(a,l,i)=ldiv(gsub(gcoeff(a,k,i),gcoeff(a,l,i)),p); } coeff(a,k,l)=un; coeff(a,l,k)=(long)mun; coeff(a,k,k)=lmul2n(p,-1); coeff(a,l,l)=lneg(gcoeff(a,k,k)); if (low_stack(lim, stack_lim(av1,1))) { if(DEBUGMEM>1) err(warnmem,"sqred2"); tetpil=avma; a=gerepile(av1,tetpil,gcopy(a)); } break; } } if (k>n) break; } } if (no_signature) { tetpil=avma; return gerepile(av,tetpil,gcopy(a)); } avma=av; a=cgetg(3,t_VEC); a[1]=lstoi(sp); a[2]=lstoi(sn); return a; } GEN sqred(GEN a) { return sqred2(a,1); } GEN signat(GEN a) { return sqred2(a,0); } /* Diagonalization of a REAL symetric matrix. Return a 2-component vector: * 1st comp = vector of eigenvalues * 2nd comp = matrix of eigenvectors */ GEN jacobi(GEN a, long prec) { long de,e,e1,e2,l,n,i,j,p,q,av1,av2; GEN c,s,t,u,ja,lambda,r,unr,x,y,x1,y1; if (typ(a)!=t_MAT) err(mattype1,"jacobi"); ja=cgetg(3,t_VEC); l=lg(a); n=l-1; e1=HIGHEXPOBIT-1; lambda=cgetg(l,t_COL); ja[1]=(long)lambda; for (j=1; j<=n; j++) { lambda[j]=lgetr(prec); gaffect(gcoeff(a,j,j), (GEN)lambda[j]); e=expo(lambda[j]); if (ee2) { e2=e; p=i; q=j; } } } a=c; unr = realun(prec); de=bit_accuracy(prec); /* e1 = min des expo des coeff diagonaux * e2 = max des expo des coeff extra-diagonaux * Test d'arret: e2 < e1-precision */ while (e1-e20)? divrr(unr,addrr(x,y)) : divrr(unr,subrr(x,y)); c=divrr(unr,mpsqrt(addrr(unr,mulrr(t,t)))); s=mulrr(t,c); u=divrr(s,addrr(unr,c)); /* Recalcul des transformees successives de a et de la matrice cumulee (r) des rotations : */ for (i=1; i e2) { e2=e; p=i; q=j; } for (i=j+1; i<=n; i++) if ((e=expo(gcoeff(a,j,i))) > e2) { e2=e; p=j; q=i; } } avma=av2; } avma=av1; return ja; } /*************************************************************************/ /** **/ /** MATRICE RATIONNELLE --> ENTIERE **/ /** **/ /*************************************************************************/ GEN matrixqz0(GEN x,GEN p) { if (typ(p)!=t_INT) err(typeer,"matrixqz0"); if (signe(p)>=0) return matrixqz(x,p); if (!cmpsi(-1,p)) return matrixqz2(x); if (!cmpsi(-2,p)) return matrixqz3(x); err(flagerr,"matrixqz"); return NULL; /* not reached */ } GEN matrixqz(GEN x, GEN p) { long av=avma,av1,tetpil,i,j,j1,m,n,t,lim,nfact; GEN p1,p2,p3,unmodp; if (typ(x)!=t_MAT) err(typeer,"matrixqz"); n=lg(x)-1; if (!n) return gcopy(x); m=lg(x[1])-1; if (n > m) err(talker,"more rows than columns in matrixqz"); if (n==m) { p1=det(x); if (gcmp0(p1)) err(talker,"matrix of non-maximal rank in matrixqz"); avma=av; return idmat(n); } p1=cgetg(n+1,t_MAT); for (j=1; j<=n; j++) { p2=gun; p3=(GEN)x[j]; for (i=1; i<=m; i++) { t=typ(p3[i]); if (t != t_INT && !is_frac_t(t)) err(talker,"not a rational or integral matrix in matrixqz"); p2=ggcd(p2,(GEN)p3[i]); } p1[j]=ldiv(p3,p2); } x=p1; unmodp=cgetg(3,t_INTMOD); unmodp[2]=un; if (gcmp0(p)) { p1=cgetg(n+1,t_MAT); p2=gtrans(x); for (j=1; j<=n; j++) p1[j]=p2[j]; p3=det(p1); p1[n]=p2[n+1]; p3=ggcd(p3,det(p1)); if (!signe(p3)) err(impl,"matrixqz when the first 2 dets are zero"); if (gcmp1(p3)) { tetpil=avma; return gerepile(av,tetpil,gcopy(x)); } p3=factor(p3); p1=(GEN)p3[1]; nfact=lg(p1)-1; } else { p1=cgetg(2,t_VEC); p1[1]=(long)p; nfact=1; } av1=avma; lim=stack_lim(av1,1); for (i=1; i<=nfact; i++) { p=(GEN)p1[i]; unmodp[1]=(long)p; for(;;) { p2=ker(gmul(unmodp,x)); if (lg(p2)==1) break; p2=centerlift(p2); p3=gdiv(gmul(x,p2),p); for (j=1; j1) err(warnmem,"matrixqz"); tetpil=avma; x=gerepile(av1,tetpil,gcopy(x)); } } } tetpil=avma; return gerepile(av,tetpil,gcopy(x)); } static GEN matrixqz_aux(GEN x, long m, long n) { long av = avma, lim = stack_lim(av,1), tetpil,i,j,k,in[2]; GEN p1; for (i=1; i<=m; i++) { for(;;) { long fl=0; for (j=1; j<=n; j++) if (!gcmp0(gcoeff(x,i,j))) { in[fl]=j; fl++; if (fl==2) break; } if (j>n) break; j=(gcmp(gabs(gcoeff(x,i,in[0]),DEFAULTPREC), gabs(gcoeff(x,i,in[1]),DEFAULTPREC)) > 0)? in[1]: in[0]; p1=gcoeff(x,i,j); for (k=1; k<=n; k++) if (k!=j) x[k]=lsub((GEN)x[k],gmul(ground(gdiv(gcoeff(x,i,k),p1)),(GEN)x[j])); } j=1; while (j<=n && gcmp0(gcoeff(x,i,j))) j++; if (j<=n) { p1=denom(gcoeff(x,i,j)); if (!gcmp1(p1)) x[j]=lmul(p1,(GEN)x[j]); } if (low_stack(lim, stack_lim(av,1))) { if(DEBUGMEM>1) err(warnmem,"matrixqz_aux"); tetpil=avma; x=gerepile(av,tetpil,gcopy(x)); } } return hnf(x); } GEN matrixqz2(GEN x) { long av = avma,m,n; if (typ(x)!=t_MAT) err(typeer,"matrixqz2"); n=lg(x)-1; if (!n) return gcopy(x); m=lg(x[1])-1; x=dummycopy(x); return gerepileupto(av, matrixqz_aux(x,m,n)); } GEN matrixqz3(GEN x) { long av=avma,av1,j,j1,k,m,n,lim; GEN c; if (typ(x)!=t_MAT) err(typeer,"matrixqz3"); n=lg(x)-1; if (!n) return gcopy(x); m=lg(x[1])-1; x=dummycopy(x); c=new_chunk(n+1); for (j=1; j<=n; j++) c[j]=0; av1=avma; lim=stack_lim(av1,1); for (k=1; k<=m; k++) { j=1; while (j<=n && (c[j] || gcmp0(gcoeff(x,k,j)))) j++; if (j<=n) { c[j]=k; x[j]=ldiv((GEN)x[j],gcoeff(x,k,j)); for (j1=1; j1<=n; j1++) if (j1!=j) x[j1]=lsub((GEN)x[j1],gmul(gcoeff(x,k,j1),(GEN)x[j])); if (low_stack(lim, stack_lim(av1,1))) { long tetpil = avma; if(DEBUGMEM>1) err(warnmem,"matrixqz3"); x=gerepile(av1,tetpil,gcopy(x)); } } } return gerepileupto(av, matrixqz_aux(x,m,n)); } GEN intersect(GEN x, GEN y) { long av,tetpil,j, lx = lg(x); GEN z; if (typ(x)!=t_MAT || typ(y)!=t_MAT) err(typeer,"intersect"); if (lx==1 || lg(y)==1) return cgetg(1,t_MAT); av=avma; z=ker(concatsp(x,y)); for (j=lg(z)-1; j; j--) setlg(z[j],lx); tetpil=avma; return gerepile(av,tetpil,gmul(x,z)); } /**************************************************************/ /** **/ /** HERMITE NORMAL FORM REDUCTION **/ /** **/ /**************************************************************/ GEN mathnf0(GEN x, long flag) { switch(flag) { case 0: return hnf(x); case 1: return hnfall(x); case 2: return hnfhavas(x); case 3: return hnfperm(x); case 4: return hnflll(x); default: err(flagerr,"mathnf"); } return NULL; /* not reached */ } static GEN init_hnf(GEN x, GEN *denx, long *co, long *li, long *av) { if (typ(x) != t_MAT) err(typeer,"mathnf"); *co=lg(x); if (*co==1) return NULL; /* empty matrix */ *li=lg(x[1]); *denx=denom(x); *av=avma; if (gcmp1(*denx)) /* no denominator */ { *denx = NULL; return dummycopy(x); } return gmul(x,*denx); } /* return c * X */ #ifdef INLINE INLINE #endif GEN int_col_mul(GEN c, GEN X) { long i,m = lg(X); GEN A = new_chunk(m); for (i=1; ico)? li-co: 0; if (lg(x2) != co) err(talker,"incompatible matrices in hnf_special"); x2 = dummycopy(x2); for (i=li-1; i>ldef; i--) { for (j=def-1; j; j--) { while (j && !signe(gcoeff(x,i,j))) j--; if (!j) break; k = (j==1)? def: j-1; a = gcoeff(x,i,j); b = gcoeff(x,i,k); d = bezout(a,b,&u,&v); if (!is_pm1(d)) { a = divii(a,d); b = divii(b,d); } if (DEBUGLEVEL>5) { outerr(u); outerr(v); } p1 = (GEN)x[j]; b = negi(b); x[j] = (long)lincomb_integral(a,b, (GEN)x[k], p1); x[k] = (long)lincomb_integral(u,v, p1, (GEN)x[k]); p1 = (GEN)x2[j]; x2[j]= ladd(gmul(a, (GEN)x2[k]), gmul(b,p1)); x2[k] = ladd(gmul(u,p1), gmul(v, (GEN)x2[k])); if (low_stack(lim, stack_lim(av,1))) { GEN *gptr[2]; gptr[0]=&x; gptr[1]=&x2; if (DEBUGMEM>1) err(warnmem,"hnf_special[1]. i=%ld",i); gerepilemany(av,gptr,2); } } p1 = gcoeff(x,i,def); s = signe(p1); if (s) { if (s < 0) { x[def] = lneg((GEN)x[def]); p1 = gcoeff(x,i,def); x2[def]= lneg((GEN)x2[def]); } for (j=def+1; j1) err(warnmem,"hnf_special[2]. i=%ld",i); gerepilemany(av,gptr,2); } } if (remove) { /* remove null columns */ for (i=1,j=1; jco)? li-co: 0; for (i=li-1; i>ldef; i--) { for (j=def-1; j; j--) { while (j && !signe(gcoeff(x,i,j))) j--; if (!j) break; k = (j==1)? def: j-1; a = gcoeff(x,i,j); b = gcoeff(x,i,k); d = bezout(a,b,&u,&v); if (!is_pm1(d)) { a = divii(a,d); b = divii(b,d); } if (DEBUGLEVEL>5) { outerr(u); outerr(v); } p1 = (GEN)x[j]; x[j] = (long)lincomb_integral(a,negi(b), (GEN)x[k],p1); x[k] = (long)lincomb_integral(u,v, p1,(GEN)x[k]); if (low_stack(lim, stack_lim(av,1))) { if (DEBUGMEM>1) err(warnmem,"hnf[1]. i=%ld",i); tetpil=avma; x=gerepile(av,tetpil,gcopy(x)); } } p1 = gcoeff(x,i,def); s = signe(p1); if (s) { if (s < 0) { x[def] = lneg((GEN)x[def]); p1 = gcoeff(x,i,def); } for (j=def+1; j1) err(warnmem,"hnf[2]. i=%ld",i); tetpil=avma; x=gerepile(av,tetpil,gcopy(x)); } } if (remove) { /* remove null columns */ for (i=1,j=1; j0) a=subii(a,u); x=(long)a;} /* dm = multiple of diag element (usually detint(x)) */ /* flag: don't/do append dm*matid. */ static GEN allhnfmod(GEN x,GEN dm,long flag) { long li,co,av0,av,tetpil,i,j,k,def,ldef,lim,ldm; GEN a,b,w,p1,p2,d,u,v,dms2; if (typ(dm)!=t_INT) err(typeer,"allhnfmod"); if (!signe(dm)) return hnf(x); if (typ(x)!=t_MAT) err(typeer,"allhnfmod"); if (DEBUGLEVEL>6) fprintferr("Enter hnfmod"); co=lg(x); if (co==1) return cgetg(1,t_MAT); av0=avma; lim=stack_lim(av0,1); dms2=shifti(dm,-1); li=lg(x[1]); av=avma; if (flag) { p1 = cgetg(co,t_MAT); for (i=1; i co) err(talker,"nb lines > nb columns in hnfmod"); x = p1; } else { /* concatenate dm * Id to x */ x = concatsp(x, idmat_intern(li-1,dm,gzero)); for (i=1; ildef; i--,def--) { if (DEBUGLEVEL>6) { fprintferr(" %ld",i); flusherr(); } for (j=def-1; j; j--) { while (j && !signe(gcoeff(x,i,j))) j--; if (!j) break; if (DEBUGLEVEL>8) { fprintferr(" %ld",j); flusherr(); } k = (j==1)? def: j-1; a = gcoeff(x,i,j); b = gcoeff(x,i,k); d = bezout(a,b,&u,&v); if (!is_pm1(d)) { a = divii(a,d); b = divii(b,d); } p1 = lincomb_integral(u,v, (GEN)x[j], (GEN)x[k]); p2 = lincomb_integral(a, negi(b), (GEN)x[k], (GEN)x[j]); x[k] = (long)p1; x[j] = (long)p2; for (k=1; k<=i; k++) { cmod(p1[k], dm, dms2); cmod(p2[k], dm, dms2); } if (low_stack(lim, stack_lim(av0,1))) { if (DEBUGMEM>1) err(warnmem,"allhnfmod[1]. i=%ld",i); tetpil=avma; x=gerepile(av,tetpil,gcopy(x)); } } } w=cgetg(li,t_MAT); b=dm; for (i=li-1; i>=1; i--) { d = bezout(gcoeff(x,i,i+def),b,&u,&v); w[i] = lmod(gmul(u,(GEN)x[i+def]), b); if (!signe(gcoeff(w,i,i))) coeff(w,i,i)=(long)d; if (i > 1 && flag) b=divii(b,d); } ldm = lgefint(dm); for (i=li-2; i>=1; i--) { GEN diag = gcoeff(w,i,i); for (j=i+1; j ldm) p1[k] = lmodii(p2, dm); } if (low_stack(lim, stack_lim(av0,1))) { if (DEBUGMEM>1) err(warnmem,"allhnfmod[2]. i=%ld", i); tetpil=avma; w=gerepile(av,tetpil,gcopy(w)); diag = gcoeff(w,i,i); } } } if (DEBUGLEVEL>6) { fprintferr("\nEnd hnfmod\n"); flusherr(); } tetpil=avma; return gerepile(av0,tetpil,gcopy(w)); } #undef cmod GEN hnfmod(GEN x, GEN detmat) { return allhnfmod(x,detmat,1); } GEN hnfmodid(GEN x, GEN p) { return allhnfmod(x,p,0); } /* Return [y,U,V] such that y=V.x.U, V permutation vector, U unimodular * matrix, and y in HNF form */ GEN hnfhavas(GEN x) { long av0=avma, av,av1,tetpil,li,co,i,j,k,def,ldef,lim,imin,jmin,vpk; long jpro,com,vi; GEN p1,p2,z,u,denx,vperm,mat1,col2,lil2,s,pmin,apro,bpro,cpro; if (DEBUGLEVEL>6) { fprintferr("Entering hnfhavas: AVMA = %ld\n",avma); flusherr(); } if (typ(x)!=t_MAT) err(typeer,"hnfhavas"); co=lg(x); if (co==1) { z=cgetg(4,t_VEC); z[1]=lgetg(1,t_MAT); z[2]=lgetg(1,t_MAT); z[3]=lgetg(1,t_VEC); return z; } li=lg(x[1]); denx=denom(x); vperm=new_chunk(li); for (i=1; ico)?li-co+1:1; for (i=li-1; i>=ldef; i--) { def--; av1=avma; mat1=cgetg(def+1,t_MAT); col2=cgetg(def+1,t_COL); for (j=1; j<=def; j++) { p1=cgetg(i+1,t_COL); mat1[j]=(long)p1; s=gzero; for (k=1; k<=i; k++) { p2=gsqr(gcoeff(x,vperm[k],j)); p1[k]=(long)p2; s=gadd(s,p2); } col2[j]=(long)s; } lil2=cgetg(i+1,t_COL); for (k=1; k<=i; k++) { s=gzero; for (j=1; j<=def; j++) s=gadd(s,gcoeff(mat1,k,j)); lil2[k]=(long)s; } pmin = NULL; for (k=i; k>=1; k--) { while (k>=1 && !signe(lil2[k])) k--; if (!k) goto comterm; vpk=vperm[k]; if (!pmin || cmpii((GEN)lil2[k],pmin) <= 0) { j=1; while (!signe(gcoeff(x,vpk,j))) j++; if (!pmin) { imin=k; jmin=j; pmin=mulii((GEN)lil2[k],(GEN)col2[j]); cpro=absi(gcoeff(x,vpk,j)); } jpro=j; apro=absi(gcoeff(x,vpk,j)); j++; for (; j<=def; j++) { com=cmpii((GEN)col2[j],(GEN)col2[jpro]); if (signe(gcoeff(x,vpk,j)) && com <=0) { if (com<0) { jpro=j; apro=absi(gcoeff(x,vpk,j)); } else { bpro=absi(gcoeff(x,vpk,j)); if (cmpii(bpro,apro)<0) { jpro=j; apro=bpro; } } } } p1=mulii((GEN)lil2[k],(GEN)col2[jpro]); com=cmpii(p1,pmin); if (com<0 || (com==0 && cmpii(apro,cpro)<0)) { imin=k; jmin=jpro; pmin=p1; cpro=apro; } } } avma=av1; if (jmin!=def) { p1=(GEN)x[def]; x[def]=x[jmin]; x[jmin]=(long)p1; p1=(GEN)u[def]; u[def]=u[jmin]; u[jmin]=(long)p1; } if (imin!=i) { vpk=vperm[i]; vperm[i]=vperm[imin]; vperm[imin]=vpk; } vi=vperm[i]; for(;;) { GEN p3,p12,p13; if (signe(gcoeff(x,vi,def))<0) { x[def]=lneg((GEN)x[def]); u[def]=lneg((GEN)u[def]); } p1=gcoeff(x,vi,def); p12=shifti(p1,-1); p13=negi(p12); for (j=1; j0) p2=addis(p2,1); } if (DEBUGLEVEL>5) outerr(p2); setsigne(p2,-signe(p2)); x[j]=ladd((GEN)x[j],gmul(p2,(GEN)x[def])); u[j]=ladd((GEN)u[j],gmul(p2,(GEN)u[def])); } j=1; while (!signe(gcoeff(x,vi,j))) j++; if (j5) outerr(p2); x[j]=ladd((GEN)x[j],gmul(p2,(GEN)x[def])); u[j]=ladd((GEN)u[j],gmul(p2,(GEN)u[def])); } if (low_stack(lim, stack_lim(av,1))) { GEN *gptr[2]; if (DEBUGMEM>1) err(warnmem,"hnfhavas"); gptr[0]=&x; gptr[1]=&u; gerepilemany(av,gptr,2); } } comterm: tetpil=avma; z=cgetg(4,t_VEC); p1=cgetg(co,t_MAT); if (gcmp1(denx)) { for (j=1; jkmax) { kmax=k; for (j=1; jabsi(gcoeff(x,k,c))) || (gegal(gcoeff(x,k-1,c),gcoeff(x,k,c)) && (gcmp((GEN) B[k], gmul(gsub(cst,gsqr(gcoeff(mu,k,k-1))), (GEN) B[k-1])) < 0) ); while (ok) { for (j=1; j<=p; j++) { t=gcoeff(x,k,j); coeff(x,k,j)=coeff(x,k-1,j); coeff(x,k-1,j)=(long)t; } for (j=1; j<=k-2; j++) { t=gcoeff(mu,k,j); coeff(mu,k,j)=coeff(mu,k-1,j); coeff(mu,k-1,j)=(long)t; } mmu=gcoeff(mu,k,k-1); BB=gadd((GEN)B[k],gmul(gmul(mmu,mmu),(GEN)B[k-1])); q=gdiv((GEN)B[k-1],BB); coeff(mu,k,k-1)=lmul(mmu,q); B[k]=lmul((GEN)B[k],q); B[k-1]=(long)BB; for (i=k+1; i<=kmax; i++) { t=gcoeff(mu,i,k); coeff(mu,i,k)=lsub(gcoeff(mu,i,k-1),gmul(mmu,t)); coeff(mu,i,k-1)=ladd(t,gmul(gcoeff(mu,k,k-1),gcoeff(mu,i,k))); } if (k>2) k--; redlll(x,mu,k-1,c,k); ok=(absi(gcoeff(x,k-1,c))>absi(gcoeff(x,k,c))) || (gegal(gcoeff(x,k-1,c),gcoeff(x,k,c)) && (gcmp((GEN) B[k], gmul(gsub(cst,gsqr(gcoeff(mu,k,k-1))), (GEN) B[k-1])) < 0)); } for (i=k-2; i; i--) redlll(x,mu,i,c,k); k++; } s++; c=n+1; for (i=1; i<=m-s; i++) c=min(c,depthvector(x,i)); } s=m-s+1; if (signe(gcoeff(x,s,depthvector(x,s)))<0) for (j=1; j<=p; j++) coeff(x,s,j)=lnegi(gcoeff(x,s,j)); for (i=s+1; i<=m; i++) { if (signe(gcoeff(x,i,depthvector(x,i)))<0) for (j=1; j<=p; j++) coeff(x,i,j)=lnegi(gcoeff(x,i,j)); for (j=i-1; j>=s; j--) { k=depthvector(x,j); qneg=negi(gdivent(gcoeff(x,i,k),gcoeff(x,j,k))); for (jj=1; jj<=p; jj++) coeff(x,i,jj)=laddii(gcoeff(x,i,jj),mulii(qneg,gcoeff(x,j,jj))); } } for (k=s; k<=m; k++) { for (j=1; j=1; ii--) p1[m-ii+1]=lcopy(gcoeff(x,ii,i+n)); } y[2]=(long)U; return gerepile(av,tetpil,y); } /* HNF with permutation */ GEN hnfperm(GEN A) { GEN U,c,l,perm,d,u,v,p,q,y,a,b,p1; long r,t,i,j,j1,k,m,n,av=avma,av1,tetpil,lim; if (typ(A)!=t_MAT) err(typeer,"hnfperm"); n=lg(A)-1; if (!n) { y=cgetg(4,t_VEC); y[1]=lgetg(1,t_MAT); y[2]=lgetg(1,t_MAT); y[3]=lgetg(1,t_VEC); return y; } m=lg(A[1])-1; c=new_chunk(m+1); for (i=1; i<=m; i++) c[i]=0; l=new_chunk(n+1); for (j=1; j<=n; j++) l[j]=0; perm=new_chunk(m+1); av1=avma; lim=stack_lim(av1,1); U=idmat(n); A=dummycopy(A); /* U base change matrix : A0*U=A all along */ for (r=0,k=1; k<=n; k++) { for (j=1; j 0) { p=q; t=i; } } perm[++r]=l[k]=t; c[t]=k; if (signe(p) < 0) { for (i=1; i<=m; i++) coeff(A,i,k)= lnegi(gcoeff(A,i,k)); for (i=1; i<=n; i++) coeff(U,i,k)= lnegi(gcoeff(U,i,k)); p=gcoeff(A,t,k); } for (j=1; j1) err(warnmem,"hnfperm"); gerepilemany(av1,gptr,2); } } if (r < m) { for (i=1,k=r; i<=m; i++) if (c[i]==0) perm[++k] = i; } /* We have A0*U=A, U in Gl(n,Z) * basis for Im(A): columns of A s.t l[j]>0 (r cols) * basis for Ker(A): columns of U s.t l[j]=0 (n-r cols) */ tetpil=avma; y=cgetg(4,t_VEC); p=cgetg(r+1,t_MAT); u=cgetg(n+1,t_MAT); for (t=1,k=r,j=1; j<=n; j++) if (l[j]) { q=cgetg(m+1,t_COL); p[k]=(long)q; for (i=1; i<=m; i++) q[i]=lcopy(gcoeff(A,perm[m-i+1],j)); u[k+n-r]=lcopy((GEN)U[j]); k--; } else u[t++]=lcopy((GEN)U[j]); y[1]=(long)p; y[2]=(long)u; q = cgetg(m+1,t_VEC); y[3]=(long)q; for (i=1; i<=m; i++) q[m-i+1]=lstoi(perm[i]); return gerepile(av,tetpil,y); } GEN colint_copy(GEN x) { long i, lx = lg(x); GEN y = cgetg(lx, t_COL); for (i=1; ili; i--) { b = gcoeff(A,i,j); if (signe(b)) { k=c[i]; a=gcoeff(A,i,k); /* annuler bij A l'aide de p=bik */ d=bezout(a,b,&u,&v); if (DEBUGLEVEL>5) { fprintferr("(u,v) = (%Z, %Z); ",u,v); flusherr(); } if (!is_pm1(d)) { a=divii(a,d); b =divii(b,d); } p1 = (GEN)A[k]; b = negi(b); A[k] = (long)lincomb_integral(u,v, p1,(GEN)A[j]); A[j] = (long)lincomb_integral(a,b, (GEN)A[j],p1); p1 = (GEN)U[k]; U[k] = (long)lincomb_integral(u,v, p1,(GEN)U[j]); U[j] = (long)lincomb_integral(a,b, (GEN)U[j],p1); for (j1=k+1; j1<=n; j1++) { q=truedvmdii(gcoeff(A,i,j1),d,NULL); if (signe(q)) { q = negi(q); A[j1]=(long)lincomb_integral(gun,q,(GEN)A[j1],(GEN)A[k]); U[j1]=(long)lincomb_integral(gun,q,(GEN)U[j1],(GEN)U[k]); } } if (low_stack(lim, stack_lim(av1,1))) { GEN *gptr[2]; tetpil = avma; A = matint_copy(A); gptr[0]=&A; U = matint_copy(U); gptr[1]=&U; if (DEBUGMEM>1) err(warnmem,"hnfall[1], li = %ld", li); gerepilemanysp(av1,tetpil,gptr,2); } } } x=gcoeff(A,li,j); if (signe(x)) { r--; if (j1) err(warnmem,"hnfall[2], li = %ld", li); gerepilemany(av1,gptr,2); } break; } h[j]=li-1; } } if (DEBUGLEVEL>5) fprintferr("\nhnfall, final phase: "); r--; /* first r cols are in the image the n-r (independent) last ones */ for (j=1; j<=r; j++) for (i=h[j]; i; i--) if (signe(b=gcoeff(A,i,j))) { k=c[i]; a=gcoeff(A,i,k); d=bezout(a,b,&u,&v); if (!is_pm1(d)) { a=divii(a,d); b=divii(b,d); } if (DEBUGLEVEL>5) { fprintferr("(u,v) = (%Z, %Z); ",u,v); flusherr(); } p1 = (GEN)A[k]; b = negi(b); A[k] = (long)lincomb_integral(u,v, p1,(GEN)A[j]); A[j] = (long)lincomb_integral(a,b, (GEN)A[j],p1); p1 = (GEN)U[k]; U[k] = (long)lincomb_integral(u,v, p1,(GEN)U[j]); U[j] = (long)lincomb_integral(a,b, (GEN)U[j],p1); for (j1=k+1; j1<=n; j1++) { q=truedvmdii(gcoeff(A,i,j1),d,NULL); if (signe(q)) { q = negi(q); A[j1] = (long)lincomb_integral(gun,q,(GEN)A[j1],(GEN)A[k]); U[j1] = (long)lincomb_integral(gun,q,(GEN)U[j1],(GEN)U[k]); } } if (low_stack(lim, stack_lim(av1,1))) { GEN *gptr[2]; tetpil = avma; A = matint_copy(A); gptr[0]=&A; U = matint_copy(U); gptr[1]=&U; if (DEBUGMEM>1) err(warnmem,"hnfall[3], j = %ld", j); gerepilemanysp(av1,tetpil,gptr,2); } } if (DEBUGLEVEL>5) fprintferr("\n"); tetpil=avma; y=cgetg(3,t_VEC); if (remove) { /* remove the first r columns */ A += r; A[0] = evaltyp(t_MAT) | evallg(n-r+1); } y[1]=lcopy(A); y[2]=lcopy(U); return gerepile(av,tetpil,y); } GEN hnfall(GEN x) {return hnfall0(x,1);} /***************************************************************/ /** **/ /** SMITH NORMAL FORM REDUCTION **/ /** **/ /***************************************************************/ static GEN col_mul(GEN x, GEN c) { long s = signe(x); GEN xc = NULL; if (s) { if (!is_pm1(x)) xc = gmul(x,c); else xc = (s>0)? c: gneg_i(c); } return xc; } static void do_zero(GEN x) { long i, lx = lg(x); for (i=1; i=9) outerr(x); n=lg(x)-1; if (!n) return trivsmith(all); if (lg(x[1]) != n+1) err(mattype1,"smithall"); for (i=1; i<=n; i++) for (j=1; j<=n; j++) if (typ(coeff(x,i,j)) != t_INT) err(talker,"non integral matrix in smithall"); av = avma; lim = stack_lim(av,1); x = dummycopy(x); mdet = detint(x); if (ishnfall(x)) { if (all) { ml=idmat(n); mr=idmat(n); } } else { if (signe(mdet)) { p1=hnfmod(x,mdet); if (all) { ml=idmat(n); mr=gauss(x,p1); } } else { if (all) { p1 = hnfall0(x,0); ml = idmat(n); mr = (GEN)p1[2]; p1 = (GEN)p1[1]; } else p1 = hnf0(x,0); } x = p1; } p1=cgetg(n+1,t_VEC); for (i=1; i<=n; i++) p1[i]=lnegi(gcoeff(x,i,i)); p2=sindexsort(p1); ys=cgetg(n+1,t_MAT); for (j=1; j<=n; j++) { p1=cgetg(n+1,t_COL); ys[j]=(long)p1; for (i=1; i<=n; i++) p1[i]=coeff(x,p2[i],p2[j]); } x = ys; if (all) { p3=cgetg(n+1,t_MAT); p4=cgetg(n+1,t_MAT); for (j=1; j<=n; j++) { p3[j]=ml[p2[j]]; p4[j]=mr[p2[j]]; } ml=p3; mr=p4; } if (signe(mdet)) { p1 = hnfmod(x,mdet); if (all) mr=gmul(mr,gauss(x,p1)); } else { if (all) { p1 = hnfall0(x,0); mr = gmul(mr,(GEN)p1[2]); p1 = (GEN)p1[1]; } else p1 = hnf0(x,0); } x=p1; mun = negi(gun); if (DEBUGLEVEL>7) {fprintferr("starting SNF loop");flusherr();} for (i=n; i>=2; i--) { if (DEBUGLEVEL>7) {fprintferr("\ni = %ld: ",i);flusherr();} for(;;) { c = 0; for (j=i-1; j>=1; j--) { p1=gcoeff(x,i,j); s1 = signe(p1); if (s1) { p2=gcoeff(x,i,i); if (!absi_cmp(p1,p2)) { s2=signe(p2); if (s1 == s2) { d=p1; u=gun; p4=gun; } else { if (s2>0) { u = gun; p4 = mun; } else { u = mun; p4 = gun; } d=(s1>0)? p1: absi(p1); } v = gzero; p3 = u; } else { d=bezout(p2,p1,&u,&v); p3=divii(p2,d); p4=divii(p1,d); } for (k=1; k<=i; k++) { b=addii(mulii(u,gcoeff(x,k,i)),mulii(v,gcoeff(x,k,j))); coeff(x,k,j)=lsubii(mulii(p3,gcoeff(x,k,j)), mulii(p4,gcoeff(x,k,i))); coeff(x,k,i)=(long)b; } if (all) update(u,v,p3,p4,(GEN*)(mr+i),(GEN*)(mr+j)); if (low_stack(lim, stack_lim(av,1))) { if (DEBUGMEM>1) err(warnmem,"[1]: smithall"); if (all) { GEN *gptr[3]; gptr[0]=&x; gptr[1]=&ml; gptr[2]=&mr; gerepilemany(av,gptr,3); } else x=gerepileupto(av,gcopy(x)); } } } if (DEBUGLEVEL>=8) {fprintferr("; ");flusherr();} for (j=i-1; j>=1; j--) { p1=gcoeff(x,j,i); s1 = signe(p1); if (s1) { p2=gcoeff(x,i,i); if (!absi_cmp(p1,p2)) { s2 = signe(p2); if (s1 == s2) { d=p1; u=gun; p4=gun; } else { if (s2>0) { u = gun; p4 = mun; } else { u = mun; p4 = gun; } d=(s1>0)? p1: absi(p1); } v = gzero; p3 = u; } else { d=bezout(p2,p1,&u,&v); p3=divii(p2,d); p4=divii(p1,d); } for (k=1; k<=i; k++) { b=addii(mulii(u,gcoeff(x,i,k)),mulii(v,gcoeff(x,j,k))); coeff(x,j,k)=lsubii(mulii(p3,gcoeff(x,j,k)), mulii(p4,gcoeff(x,i,k))); coeff(x,i,k)=(long)b; } if (all) update(u,v,p3,p4,(GEN*)(ml+i),(GEN*)(ml+j)); c = 1; } } if (!c) { b=gcoeff(x,i,i); fl=1; if (signe(b)) { for (k=1; k1) err(warnmem,"[2]: smithall"); if (all) { GEN *gptr[3]; gptr[0]=&x; gptr[1]=&ml; gptr[2]=&mr; gerepilemany(av,gptr,3); } else x=gerepileupto(av,gcopy(x)); } } } if (DEBUGLEVEL>7) {fprintferr("\n");flusherr();} if (all) { for (k=1; k<=n; k++) if (signe(gcoeff(x,k,k))<0) { mr[k]=lneg((GEN)mr[k]); coeff(x,k,k)=lnegi(gcoeff(x,k,k)); } tetpil=avma; z=cgetg(4,t_VEC); z[1]=ltrans(ml); z[2]=lcopy(mr); z[3]=lcopy(x); return gerepile(av,tetpil,z); } tetpil=avma; z=cgetg(n+1,t_VEC); j=n; for (k=n; k; k--) if (signe(gcoeff(x,k,k))) z[j--]=labsi(gcoeff(x,k,k)); for ( ; j; j--) z[j]=zero; return gerepile(av,tetpil,z); } GEN smith(GEN x) { return smithall(x,0); } GEN smith2(GEN x) { return smithall(x,1); } /* Assume z was computed by [g]smithall(). Remove the 1s on the diagonal */ GEN smithclean(GEN z) { long i,j,l,c; GEN u,v,y,d,p1; if (typ(z) != t_VEC) err(typeer,"smithclean"); l = lg(z); if (l == 1) return cgetg(1,t_VEC); u=(GEN)z[1]; if (l != 4 || typ(u) != t_MAT) { if (typ(u) != t_INT) err(typeer,"smithclean"); for (c=1; c=2; i--) { do { c=0; for (j=i-1; j>=1; j--) { p1=gcoeff(x,i,j); if (signe(p1)) { p2=gcoeff(x,i,i); v=gdiventres(p1,p2); if (gcmp0((GEN)v[2])) { d=p2; p4=(GEN)v[1]; v=gzero; p3=gun; u=gun; } else { d=gbezout(p2,p1,&u,&v); p3=gdiv(p2,d); p4=gdiv(p1,d); } for (k=1; k<=i; k++) { b=gadd(gmul(u,gcoeff(x,k,i)),gmul(v,gcoeff(x,k,j))); coeff(x,k,j)=lsub(gmul(p3,gcoeff(x,k,j)),gmul(p4,gcoeff(x,k,i))); coeff(x,k,i)=(long)b; } if (all) update(u,v,p3,p4,(GEN*)(mr+i),(GEN*)(mr+j)); } } for (j=i-1; j>=1; j--) { p1=gcoeff(x,j,i); if (signe(p1)) { p2=gcoeff(x,i,i); v=gdiventres(p1,p2); if (gcmp0((GEN)v[2])) { d=p2; p4=(GEN)v[1]; v=gzero; p3=gun; u=gun; } else { d=gbezout(p2,p1,&u,&v); p3=gdiv(p2,d); p4=gdiv(p1,d); } for (k=1; k<=i; k++) { b=gadd(gmul(u,gcoeff(x,i,k)),gmul(v,gcoeff(x,j,k))); coeff(x,j,k)=lsub(gmul(p3,gcoeff(x,j,k)),gmul(p4,gcoeff(x,i,k))); coeff(x,i,k)=(long)b; } if (all) update(u,v,p3,p4,(GEN*)(ml+i),(GEN*)(ml+j)); c = 1; } } if (!c) { b=gcoeff(x,i,i); fl=1; if (signe(b)) { for (k=1; (k1) err(warnmem,"[5]: smithall"); tetpil=avma; if (all) { GEN *gptr[3]; gptr[0]=&x; gptr[1]=&ml; gptr[2]=&mr; gerepilemany(av,gptr,3); } else x=gerepile(av,tetpil,gcopy(x)); } } while (c || !fl); } if (all) { for (k=1; k<=n; k++) if (signe(gcoeff(x,k,k))<0) { mr[k]=lneg((GEN)mr[k]); coeff(x,k,k)=lneg(gcoeff(x,k,k)); } tetpil=avma; z=cgetg(4,t_VEC); z[1]=ltrans(ml); z[2]=lcopy(mr); z[3]=lcopy(x); } else { tetpil=avma; z=cgetg(n+1,t_VEC); for (j=0,k=1; k<=n; k++) if (!signe(gcoeff(x,k,k))) z[++j]=zero; for (k=1; k<=n; k++) if (signe(p1=gcoeff(x,k,k))) z[++j]=(long)gabs(p1,0); } return gerepile(av,tetpil,z); } GEN matsnf0(GEN x,long flag) { long av = avma; if (flag > 7) err(flagerr,"matsnf"); if (typ(x) == t_VEC && flag & 4) return smithclean(x); if (flag & 2) x = gsmithall(x,flag & 1); else x = smithall(x, flag & 1); if (flag & 4) x = smithclean(x); return gerepileupto(av, x); } GEN gsmith(GEN x) { return gsmithall(x,0); } GEN gsmith2(GEN x) { return gsmithall(x,1); }