[BACK]Return to alglin2.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib / pari-2.2 / src / basemath

Annotation of OpenXM_contrib/pari-2.2/src/basemath/alglin2.c, Revision 1.1

1.1     ! noro        1: /* $Id: alglin2.c,v 1.32 2001/10/01 12:11:28 karim Exp $
        !             2:
        !             3: Copyright (C) 2000  The PARI group.
        !             4:
        !             5: This file is part of the PARI/GP package.
        !             6:
        !             7: PARI/GP is free software; you can redistribute it and/or modify it under the
        !             8: terms of the GNU General Public License as published by the Free Software
        !             9: Foundation. It is distributed in the hope that it will be useful, but WITHOUT
        !            10: ANY WARRANTY WHATSOEVER.
        !            11:
        !            12: Check the License for details. You should have received a copy of it, along
        !            13: with the package; see the file 'COPYING'. If not, write to the Free Software
        !            14: Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
        !            15:
        !            16: /********************************************************************/
        !            17: /**                                                                **/
        !            18: /**                         LINEAR ALGEBRA                         **/
        !            19: /**                         (second part)                          **/
        !            20: /**                                                                **/
        !            21: /********************************************************************/
        !            22: #include "pari.h"
        !            23:
        !            24: /*******************************************************************/
        !            25: /*                                                                 */
        !            26: /*                   CHARACTERISTIC POLYNOMIAL                     */
        !            27: /*                                                                 */
        !            28: /*******************************************************************/
        !            29:
        !            30: GEN
        !            31: charpoly0(GEN x, int v, long flag)
        !            32: {
        !            33:   if (v<0) v = 0;
        !            34:   switch(flag)
        !            35:   {
        !            36:     case 0: return caradj(x,v,0);
        !            37:     case 1: return caract(x,v);
        !            38:     case 2: return carhess(x,v);
        !            39:   }
        !            40:   err(flagerr,"charpoly"); return NULL; /* not reached */
        !            41: }
        !            42:
        !            43: static GEN
        !            44: caract2_i(GEN p, GEN x, int v, GEN (subres_f)(GEN,GEN,GEN*))
        !            45: {
        !            46:   long av = avma, d;
        !            47:   GEN p1, p2 = leading_term(p);
        !            48:
        !            49:   if (!signe(x)) return gpowgs(polx[v], degpol(p));
        !            50:   if (typ(x) != t_POL) x = scalarpol(x,v);
        !            51:   x = gneg_i(x); x[2] = ladd((GEN)x[2], polx[MAXVARN]);
        !            52:   p1=subres_f(p, x, NULL);
        !            53:   if (typ(p1) == t_POL && varn(p1)==MAXVARN)
        !            54:     setvarn(p1,v);
        !            55:   else
        !            56:     p1 = gsubst(p1,MAXVARN,polx[v]);
        !            57:
        !            58:   if (!gcmp1(p2) && (d=degpol(x)) > 0) p1 = gdiv(p1, gpuigs(p2,d));
        !            59:   return gerepileupto(av,p1);
        !            60: }
        !            61:
        !            62: /* return caract(Mod(x,p)) in variable v */
        !            63: GEN
        !            64: caract2(GEN p, GEN x, int v)
        !            65: {
        !            66:   return caract2_i(p,x,v, subresall);
        !            67: }
        !            68: GEN
        !            69: caractducos(GEN p, GEN x, int v)
        !            70: {
        !            71:   return caract2_i(p,x,v, (GEN (*)(GEN,GEN,GEN*))resultantducos);
        !            72: }
        !            73:
        !            74: /* characteristic pol. Easy cases. Return NULL in case it's not so easy. */
        !            75: static GEN
        !            76: easychar(GEN x, int v, GEN *py)
        !            77: {
        !            78:   long l,tetpil,lx;
        !            79:   GEN p1,p2;
        !            80:
        !            81:   switch(typ(x))
        !            82:   {
        !            83:     case t_INT: case t_REAL: case t_INTMOD:
        !            84:     case t_FRAC: case t_FRACN: case t_PADIC:
        !            85:       p1=cgetg(4,t_POL);
        !            86:       p1[1]=evalsigne(1) | evallgef(4) | evalvarn(v);
        !            87:       p1[2]=lneg(x); p1[3]=un;
        !            88:       if (py)
        !            89:       {
        !            90:        p2=cgetg(2,t_MAT);
        !            91:        p2[1]=lgetg(2,t_COL);
        !            92:        coeff(p2,1,1)=lcopy(x);
        !            93:        *py=p2;
        !            94:       }
        !            95:       return p1;
        !            96:
        !            97:     case t_COMPLEX: case t_QUAD:
        !            98:       if (py) err(typeer,"easychar");
        !            99:       p1=cgetg(5,t_POL);
        !           100:       p1[1]=evalsigne(1) | evallgef(5) | evalvarn(v);
        !           101:       p1[2]=lnorm(x); l=avma; p2=gtrace(x); tetpil=avma;
        !           102:       p1[3]=lpile(l,tetpil,gneg(p2));
        !           103:       p1[4]=un; return p1;
        !           104:
        !           105:     case t_POLMOD:
        !           106:       if (py) err(typeer,"easychar");
        !           107:       return caract2((GEN)x[1], (GEN)x[2], v);
        !           108:
        !           109:     case t_MAT:
        !           110:       lx=lg(x);
        !           111:       if (lx==1)
        !           112:       {
        !           113:        if (py) *py = cgetg(1,t_MAT);
        !           114:        return polun[v];
        !           115:       }
        !           116:       if (lg(x[1]) != lx) break;
        !           117:       return NULL;
        !           118:   }
        !           119:   err(mattype1,"easychar");
        !           120:   return NULL; /* not reached */
        !           121: }
        !           122:
        !           123: GEN
        !           124: caract(GEN x, int v)
        !           125: {
        !           126:   long n,k,l=avma,tetpil;
        !           127:   GEN  p1,p2,p3,p4,p5,p6;
        !           128:
        !           129:   if ((p1 = easychar(x,v,NULL))) return p1;
        !           130:
        !           131:   p1=gzero; p2=gun;
        !           132:   n=lg(x)-1; if (n&1) p2=gneg_i(p2);
        !           133:   p4=cgetg(3,t_RFRACN); p5=dummycopy(polx[v]); p4[2]=(long)p5;
        !           134:   p6=cgeti(3); p6[1] = evalsigne(-1) | evallgefint(3);
        !           135:   for (k=0; k<=n; k++)
        !           136:   {
        !           137:     p3=det(gsub(gscalmat(stoi(k),n), x));
        !           138:     p4[1]=lmul(p3,p2); p6[2]=k;
        !           139:     p1=gadd(p4,p1); p5[2]=(long)p6;
        !           140:     if (k!=n) p2=gdivgs(gmulsg(k-n,p2),k+1);
        !           141:   }
        !           142:   p2=mpfact(n); tetpil=avma;
        !           143:   return gerepile(l,tetpil,gdiv((GEN) p1[1],p2));
        !           144: }
        !           145:
        !           146: GEN
        !           147: caradj0(GEN x, long v)
        !           148: {
        !           149:   return caradj(x,v,NULL);
        !           150: }
        !           151:
        !           152: /* Using traces: return the characteristic polynomial of x (in variable v).
        !           153:  * If py != NULL, the adjoint matrix is put there.
        !           154:  */
        !           155: GEN
        !           156: caradj(GEN x, long v, GEN *py)
        !           157: {
        !           158:   long i,j,k,l,av,tetpil;
        !           159:   GEN p,y,t,*gptr[2];
        !           160:
        !           161:   if ((p = easychar(x,v,py))) return p;
        !           162:
        !           163:   l=lg(x);
        !           164:   if (l==1) { p=polun[v]; if (py) *py=gcopy(x); return p; }
        !           165:   if (l==2) { p=gsub(polx[v],gtrace(x)); if (py) *py=idmat(1); return p; }
        !           166:
        !           167:   p=cgetg(l+2,t_POL); p[1]=evalsigne(1) | evallgef(l+2) | evalvarn(v);
        !           168:   av=avma; t=gtrace(x); tetpil=avma;
        !           169:   t=gerepile(av,tetpil,gneg(t));
        !           170:   p[l]=(long)t; p[l+1]=un;
        !           171:
        !           172:   av=avma; y=cgetg(l,t_MAT);
        !           173:   for (j=1; j<l; j++)
        !           174:   {
        !           175:     y[j]=lgetg(l,t_COL);
        !           176:     for (i=1; i<l; i++)
        !           177:       coeff(y,i,j) = (i==j) ? ladd(gcoeff(x,i,j),t) : coeff(x,i,j);
        !           178:   }
        !           179:
        !           180:   for (k=2; k<l-1; k++)
        !           181:   {
        !           182:     GEN z=gmul(x,y);
        !           183:
        !           184:     t=gtrace(z); tetpil=avma;
        !           185:     t=gdivgs(t,-k); y=cgetg(l,t_MAT);
        !           186:     for (j=1; j<l; j++)
        !           187:     {
        !           188:       y[j]=lgetg(l,t_COL);
        !           189:       for (i=1;i<l;i++)
        !           190:        coeff(y,i,j) = (i==j)? ladd(gcoeff(z,i,i),t): lcopy(gcoeff(z,i,j));
        !           191:     }
        !           192:     gptr[0]=&y; gptr[1]=&t;
        !           193:     gerepilemanysp(av,tetpil,gptr,2);
        !           194:     p[l-k+1]=(long)t; av=avma;
        !           195:   }
        !           196:
        !           197:   t=gzero;
        !           198:   for (i=1; i<l; i++)
        !           199:     t=gadd(t,gmul(gcoeff(x,1,i),gcoeff(y,i,1)));
        !           200:   tetpil=avma; t=gneg(t);
        !           201:
        !           202:   if (py)
        !           203:   {
        !           204:     *py = (l&1) ? gneg(y) : gcopy(y);
        !           205:     gptr[0] = &t; gptr[1] = py;
        !           206:     gerepilemanysp(av,tetpil,gptr,2);
        !           207:     p[2]=(long)t;
        !           208:   }
        !           209:   else p[2]=lpile(av,tetpil,t);
        !           210:   i = gvar2(p);
        !           211:   if (i == v) err(talker,"incorrect variable in caradj");
        !           212:   if (i < v) p = poleval(p, polx[v]);
        !           213:   return p;
        !           214: }
        !           215:
        !           216: GEN
        !           217: adj(GEN x)
        !           218: {
        !           219:   GEN y;
        !           220:   caradj(x,MAXVARN,&y); return y;
        !           221: }
        !           222:
        !           223: /*******************************************************************/
        !           224: /*                                                                 */
        !           225: /*                       HESSENBERG FORM                           */
        !           226: /*                                                                 */
        !           227: /*******************************************************************/
        !           228: #define swap(x,y) { long _t=x; x=y; y=_t; }
        !           229: #define gswap(x,y) { GEN _t=x; x=y; y=_t; }
        !           230:
        !           231: GEN
        !           232: hess(GEN x)
        !           233: {
        !           234:   ulong av = avma;
        !           235:   long lx=lg(x),m,i,j;
        !           236:   GEN p,p1,p2;
        !           237:
        !           238:   if (typ(x) != t_MAT) err(mattype1,"hess");
        !           239:   if (lx==1) return cgetg(1,t_MAT);
        !           240:   if (lg(x[1])!=lx) err(mattype1,"hess");
        !           241:   x = dummycopy(x);
        !           242:
        !           243:   for (m=2; m<lx-1; m++)
        !           244:     for (i=m+1; i<lx; i++)
        !           245:     {
        !           246:       p = gcoeff(x,i,m-1);
        !           247:       if (gcmp0(p)) continue;
        !           248:
        !           249:       for (j=m-1; j<lx; j++) swap(coeff(x,i,j), coeff(x,m,j));
        !           250:       swap(x[i], x[m]); p = ginv(p);
        !           251:       for (i=m+1; i<lx; i++)
        !           252:       {
        !           253:         p1 = gcoeff(x,i,m-1);
        !           254:         if (gcmp0(p1)) continue;
        !           255:
        !           256:         p1 = gmul(p1,p); p2 = gneg_i(p1);
        !           257:         coeff(x,i,m-1) = zero;
        !           258:         for (j=m; j<lx; j++)
        !           259:           coeff(x,i,j) = ladd(gcoeff(x,i,j), gmul(p2,gcoeff(x,m,j)));
        !           260:         for (j=1; j<lx; j++)
        !           261:           coeff(x,j,m) = ladd(gcoeff(x,j,m), gmul(p1,gcoeff(x,j,i)));
        !           262:       }
        !           263:       break;
        !           264:     }
        !           265:   return gerepilecopy(av,x);
        !           266: }
        !           267:
        !           268: GEN
        !           269: carhess(GEN x, long v)
        !           270: {
        !           271:   long av,tetpil,lx,r,i;
        !           272:   GEN *y,p1,p2,p3,p4;
        !           273:
        !           274:   if ((p1 = easychar(x,v,NULL))) return p1;
        !           275:
        !           276:   lx=lg(x); av=avma; y = (GEN*) new_chunk(lx);
        !           277:   y[0]=polun[v]; p1=hess(x); p2=polx[v];
        !           278:   tetpil=avma;
        !           279:   for (r=1; r<lx; r++)
        !           280:   {
        !           281:     y[r]=gmul(y[r-1], gsub(p2,gcoeff(p1,r,r)));
        !           282:     p3=gun; p4=gzero;
        !           283:     for (i=r-1; i; i--)
        !           284:     {
        !           285:       p3=gmul(p3,gcoeff(p1,i+1,i));
        !           286:       p4=gadd(p4,gmul(gmul(p3,gcoeff(p1,i,r)),y[i-1]));
        !           287:     }
        !           288:     tetpil=avma; y[r]=gsub(y[r],p4);
        !           289:   }
        !           290:   return gerepile(av,tetpil,y[lx-1]);
        !           291: }
        !           292:
        !           293: /*******************************************************************/
        !           294: /*                                                                 */
        !           295: /*                            NORM                                 */
        !           296: /*                                                                 */
        !           297: /*******************************************************************/
        !           298:
        !           299: GEN
        !           300: gnorm(GEN x)
        !           301: {
        !           302:   long l,lx,i,tetpil, tx=typ(x);
        !           303:   GEN p1,p2,y;
        !           304:
        !           305:   switch(tx)
        !           306:   {
        !           307:     case t_INT:
        !           308:       return sqri(x);
        !           309:
        !           310:     case t_REAL:
        !           311:       return mulrr(x,x);
        !           312:
        !           313:     case t_FRAC: case t_FRACN:
        !           314:       return gsqr(x);
        !           315:
        !           316:     case t_COMPLEX:
        !           317:       l=avma; p1=gsqr((GEN) x[1]); p2=gsqr((GEN) x[2]);
        !           318:       tetpil=avma; return gerepile(l,tetpil,gadd(p1,p2));
        !           319:
        !           320:     case t_QUAD:
        !           321:       l=avma; p1=(GEN)x[1];
        !           322:       p2=gmul((GEN) p1[2], gsqr((GEN) x[3]));
        !           323:       p1 = gcmp0((GEN) p1[3])? gsqr((GEN) x[2])
        !           324:                              : gmul((GEN) x[2], gadd((GEN) x[2],(GEN) x[3]));
        !           325:       tetpil=avma; return gerepile(l,tetpil,gadd(p1,p2));
        !           326:
        !           327:     case t_POL: case t_SER: case t_RFRAC: case t_RFRACN:
        !           328:       l=avma; p1=gmul(gconj(x),x); tetpil=avma;
        !           329:       return gerepile(l,tetpil,greal(p1));
        !           330:
        !           331:     case t_POLMOD:
        !           332:       p1=(GEN)x[1]; p2=leading_term(p1);
        !           333:       if (gcmp1(p2) || gcmp0((GEN) x[2])) return subres(p1,(GEN) x[2]);
        !           334:       l=avma; y=subres(p1,(GEN)x[2]); p1=gpuigs(p2,degpol(x[2]));
        !           335:       tetpil=avma; return gerepile(l,tetpil,gdiv(y,p1));
        !           336:
        !           337:     case t_VEC: case t_COL: case t_MAT:
        !           338:       lx=lg(x); y=cgetg(lx,tx);
        !           339:       for (i=1; i<lx; i++) y[i]=lnorm((GEN) x[i]);
        !           340:       return y;
        !           341:   }
        !           342:   err(typeer,"gnorm");
        !           343:   return NULL; /* not reached */
        !           344: }
        !           345:
        !           346: GEN
        !           347: gnorml2(GEN x)
        !           348: {
        !           349:   GEN y;
        !           350:   long i,tx=typ(x),lx,av,lim;
        !           351:
        !           352:   if (! is_matvec_t(tx)) return gnorm(x);
        !           353:   lx=lg(x); if (lx==1) return gzero;
        !           354:
        !           355:   av=avma; lim = stack_lim(av,1); y = gnorml2((GEN) x[1]);
        !           356:   for (i=2; i<lx; i++)
        !           357:   {
        !           358:     y = gadd(y, gnorml2((GEN) x[i]));
        !           359:     if (low_stack(lim, stack_lim(av,1)))
        !           360:     {
        !           361:       if (DEBUGMEM>1) err(warnmem,"gnorml2");
        !           362:       y = gerepileupto(av, y);
        !           363:     }
        !           364:   }
        !           365:   return gerepileupto(av,y);
        !           366: }
        !           367:
        !           368: GEN
        !           369: QuickNormL2(GEN x, long prec)
        !           370: {
        !           371:   long av = avma;
        !           372:   GEN y = gmul(x, realun(prec));
        !           373:   if (typ(x) == t_POL)
        !           374:     *++y = evaltyp(t_VEC) | evallg(lgef(x)-1);
        !           375:   return gerepileupto(av, gnorml2(y));
        !           376: }
        !           377:
        !           378: GEN
        !           379: gnorml1(GEN x,long prec)
        !           380: {
        !           381:   ulong av = avma;
        !           382:   long lx,i;
        !           383:   GEN s;
        !           384:   switch(typ(x))
        !           385:   {
        !           386:     case t_INT: case t_REAL: case t_COMPLEX: case t_FRAC:
        !           387:     case t_FRACN: case t_QUAD:
        !           388:       return gabs(x,prec);
        !           389:
        !           390:     case t_POL:
        !           391:       lx = lgef(x); s = gzero;
        !           392:       for (i=2; i<lx; i++) s = gadd(s, gabs((GEN)x[i],prec));
        !           393:       break;
        !           394:
        !           395:     case t_VEC: case t_COL: case t_MAT:
        !           396:       lx = lg(x); s = gzero;
        !           397:       for (i=1; i<lx; i++) s = gadd(s, gabs((GEN)x[i],prec));
        !           398:       break;
        !           399:
        !           400:     default: err(typeer,"gnorml1");
        !           401:       return NULL; /* not reached */
        !           402:   }
        !           403:   return gerepileupto(av, s);
        !           404: }
        !           405:
        !           406: GEN
        !           407: QuickNormL1(GEN x,long prec)
        !           408: {
        !           409:   ulong av = avma;
        !           410:   long lx,i;
        !           411:   GEN p1,p2,s;
        !           412:   switch(typ(x))
        !           413:   {
        !           414:     case t_INT: case t_REAL: case t_FRAC: case t_FRACN:
        !           415:       return gabs(x,prec);
        !           416:
        !           417:     case t_INTMOD: case t_PADIC: case t_POLMOD:
        !           418:     case t_SER: case t_RFRAC: case t_RFRACN:
        !           419:       return gcopy(x);
        !           420:
        !           421:     case t_COMPLEX:
        !           422:       p1=gabs((GEN)x[1],prec); p2=gabs((GEN)x[2],prec);
        !           423:       return gerepileupto(av, gadd(p1,p2));
        !           424:
        !           425:     case t_QUAD:
        !           426:       p1=gabs((GEN)x[2],prec); p2=gabs((GEN)x[3],prec);
        !           427:       return gerepileupto(av, gadd(p1,p2));
        !           428:
        !           429:     case t_POL:
        !           430:       lx=lg(x); s=gzero;
        !           431:       for (i=2; i<lx; i++) s=gadd(s,QuickNormL1((GEN)x[i],prec));
        !           432:       return gerepileupto(av, s);
        !           433:
        !           434:     case t_VEC: case t_COL: case t_MAT:
        !           435:       lx=lg(x); s=gzero;
        !           436:       for (i=1; i<lx; i++) s=gadd(s,QuickNormL1((GEN)x[i],prec));
        !           437:       return gerepileupto(av, s);
        !           438:   }
        !           439:   err(typeer,"QuickNormL1");
        !           440:   return NULL; /* not reached */
        !           441: }
        !           442:
        !           443: /*******************************************************************/
        !           444: /*                                                                 */
        !           445: /*                          CONJUGATION                            */
        !           446: /*                                                                 */
        !           447: /*******************************************************************/
        !           448:
        !           449: GEN
        !           450: gconj(GEN x)
        !           451: {
        !           452:   long lx,i,tx=typ(x);
        !           453:   GEN z;
        !           454:
        !           455:   switch(tx)
        !           456:   {
        !           457:     case t_INT: case t_REAL: case t_INTMOD:
        !           458:     case t_FRAC: case t_FRACN: case t_PADIC:
        !           459:       return gcopy(x);
        !           460:
        !           461:     case t_COMPLEX:
        !           462:       z=cgetg(3,t_COMPLEX);
        !           463:       z[1]=lcopy((GEN) x[1]);
        !           464:       z[2]=lneg((GEN) x[2]);
        !           465:       break;
        !           466:
        !           467:     case t_QUAD:
        !           468:       z=cgetg(4,t_QUAD);
        !           469:       copyifstack(x[1],z[1]);
        !           470:       z[2]=gcmp0(gmael(x,1,3))? lcopy((GEN) x[2])
        !           471:                               : ladd((GEN) x[2],(GEN) x[3]);
        !           472:       z[3]=lneg((GEN) x[3]);
        !           473:       break;
        !           474:
        !           475:     case t_POL:
        !           476:       lx=lgef(x); z=cgetg(lx,tx); z[1]=x[1];
        !           477:       for (i=2; i<lx; i++) z[i]=lconj((GEN) x[i]);
        !           478:       break;
        !           479:
        !           480:     case t_SER:
        !           481:       lx=lg(x); z=cgetg(lx,tx); z[1]=x[1];
        !           482:       for (i=2; i<lx; i++) z[i]=lconj((GEN) x[i]);
        !           483:       break;
        !           484:
        !           485:     case t_RFRAC: case t_RFRACN: case t_VEC: case t_COL: case t_MAT:
        !           486:       lx=lg(x); z=cgetg(lx,tx);
        !           487:       for (i=1; i<lx; i++) z[i]=lconj((GEN) x[i]);
        !           488:       break;
        !           489:
        !           490:     default:
        !           491:       err(typeer,"gconj");
        !           492:       return NULL; /* not reached */
        !           493:   }
        !           494:   return z;
        !           495: }
        !           496:
        !           497: GEN
        !           498: conjvec(GEN x,long prec)
        !           499: {
        !           500:   long lx,s,av,tetpil,i,tx=typ(x);
        !           501:   GEN z,y,p1,p2,p;
        !           502:
        !           503:   switch(tx)
        !           504:   {
        !           505:     case t_INT: case t_INTMOD: case t_FRAC: case t_FRACN:
        !           506:       z=cgetg(2,t_COL); z[1]=lcopy(x); break;
        !           507:
        !           508:     case t_COMPLEX: case t_QUAD:
        !           509:       z=cgetg(3,t_COL); z[1]=lcopy(x); z[2]=lconj(x); break;
        !           510:
        !           511:     case t_VEC: case t_COL:
        !           512:       lx=lg(x); z=cgetg(lx,t_MAT);
        !           513:       for (i=1; i<lx; i++) z[i]=(long)conjvec((GEN)x[i],prec);
        !           514:       s=lg(z[1]);
        !           515:       for (i=2; i<lx; i++)
        !           516:        if (lg(z[i])!=s) err(talker,"incompatible field degrees in conjvec");
        !           517:       break;
        !           518:
        !           519:     case t_POLMOD:
        !           520:       y=(GEN)x[1]; lx=lgef(y);
        !           521:       if (lx<=3) return cgetg(1,t_COL);
        !           522:       av=avma; p=NULL;
        !           523:       for (i=2; i<lx; i++)
        !           524:       {
        !           525:        tx=typ(y[i]);
        !           526:        if (tx==t_INTMOD) p=gmael(y,i,1);
        !           527:        else
        !           528:          if (tx != t_INT && ! is_frac_t(tx))
        !           529:            err(polrationer,"conjvec");
        !           530:       }
        !           531:       if (!p)
        !           532:       {
        !           533:        p1=roots(y,prec); x = (GEN)x[2]; tetpil=avma;
        !           534:        z=cgetg(lx-2,t_COL);
        !           535:        for (i=1; i<=lx-3; i++)
        !           536:        {
        !           537:          p2=(GEN)p1[i]; if (gcmp0((GEN)p2[2])) p2 = (GEN)p2[1];
        !           538:          z[i] = (long)poleval(x, p2);
        !           539:         }
        !           540:        return gerepile(av,tetpil,z);
        !           541:       }
        !           542:       z=cgetg(lx-2,t_COL); z[1]=lcopy(x);
        !           543:       for (i=2; i<=lx-3; i++) z[i] = lpui((GEN) z[i-1],p,prec);
        !           544:       break;
        !           545:
        !           546:     default:
        !           547:       err(typeer,"conjvec");
        !           548:       return NULL; /* not reached */
        !           549:   }
        !           550:   return z;
        !           551: }
        !           552:
        !           553: /*******************************************************************/
        !           554: /*                                                                 */
        !           555: /*                            TRACES                               */
        !           556: /*                                                                 */
        !           557: /*******************************************************************/
        !           558:
        !           559: GEN
        !           560: assmat(GEN x)
        !           561: {
        !           562:   long lx,i,j;
        !           563:   GEN y,p1,p2;
        !           564:
        !           565:   if (typ(x)!=t_POL) err(notpoler,"assmat");
        !           566:   if (gcmp0(x)) err(zeropoler,"assmat");
        !           567:
        !           568:   lx=lgef(x)-2; y=cgetg(lx,t_MAT);
        !           569:   for (i=1; i<lx-1; i++)
        !           570:   {
        !           571:     p1=cgetg(lx,t_COL); y[i]=(long)p1;
        !           572:     for (j=1; j<lx; j++)
        !           573:       p1[j] = (j==(i+1))? un: zero;
        !           574:   }
        !           575:   p1=cgetg(lx,t_COL); y[i]=(long)p1;
        !           576:   if (gcmp1((GEN) x[lx+1]))
        !           577:     for (j=1; j<lx; j++)
        !           578:       p1[j] = lneg((GEN)x[j+1]);
        !           579:   else
        !           580:   {
        !           581:     p2 = (GEN)x[lx+1]; gnegz(p2,p2);
        !           582:     for (j=1; j<lx; j++)
        !           583:       p1[j] = ldiv((GEN)x[j+1],p2);
        !           584:     gnegz(p2,p2);
        !           585:   }
        !           586:   return y;
        !           587: }
        !           588:
        !           589: GEN
        !           590: gtrace(GEN x)
        !           591: {
        !           592:   long i,l,n,tx=typ(x),lx,tetpil;
        !           593:   GEN y,p1,p2;
        !           594:
        !           595:   switch(tx)
        !           596:   {
        !           597:     case t_INT: case t_REAL: case t_FRAC: case t_FRACN:
        !           598:       return gmul2n(x,1);
        !           599:
        !           600:     case t_COMPLEX:
        !           601:       return gmul2n((GEN)x[1],1);
        !           602:
        !           603:     case t_QUAD:
        !           604:       p1=(GEN)x[1];
        !           605:       if (!gcmp0((GEN) p1[3]))
        !           606:       {
        !           607:        l=avma; p2=gmul2n((GEN)x[2],1);
        !           608:        tetpil=avma; return gerepile(l,tetpil,gadd((GEN)x[3],p2));
        !           609:       }
        !           610:       return gmul2n((GEN)x[2],1);
        !           611:
        !           612:     case t_POL:
        !           613:       lx=lgef(x); y=cgetg(lx,tx); y[1]=x[1];
        !           614:       for (i=2; i<lx; i++) y[i]=ltrace((GEN)x[i]);
        !           615:       return y;
        !           616:
        !           617:     case t_SER:
        !           618:       lx=lg(x); y=cgetg(lx,tx); y[1]=x[1];
        !           619:       for (i=2; i<lx; i++) y[i]=ltrace((GEN)x[i]);
        !           620:       return y;
        !           621:
        !           622:     case t_POLMOD:
        !           623:       l=avma; n=(lgef(x[1])-4);
        !           624:       p1=polsym((GEN)x[1],n); p2=gzero;
        !           625:       for (i=0; i<=n; i++)
        !           626:         p2=gadd(p2,gmul(truecoeff((GEN)x[2],i),(GEN)p1[i+1]));
        !           627:       return gerepileupto(l,p2);
        !           628:
        !           629:     case t_RFRAC: case t_RFRACN:
        !           630:       return gadd(x,gconj(x));
        !           631:
        !           632:     case t_VEC: case t_COL:
        !           633:       lx=lg(x); y=cgetg(lx,tx);
        !           634:       for (i=1; i<lx; i++) y[i]=ltrace((GEN)x[i]);
        !           635:       return y;
        !           636:
        !           637:     case t_MAT:
        !           638:       lx=lg(x); if (lx==1) return gzero;/*now lx>=2*/
        !           639:       if (lx!=lg(x[1])) err(mattype1,"gtrace");
        !           640:       l=avma; p1=gcoeff(x,1,1); if (lx==2) return gcopy(p1);
        !           641:       for (i=2; i<lx-1; i++)
        !           642:        p1=gadd(p1,gcoeff(x,i,i));
        !           643:       tetpil=avma; return gerepile(l,tetpil,gadd(p1,gcoeff(x,i,i)));
        !           644:
        !           645:   }
        !           646:   err(typeer,"gtrace");
        !           647:   return NULL; /* not reached */
        !           648: }
        !           649:
        !           650: /* Gauss reduction for positive definite matrix a
        !           651:  * If a is not positive definite:
        !           652:  *   if flag is zero: raise an error
        !           653:  *   else: return NULL.
        !           654:  */
        !           655: GEN
        !           656: sqred1intern(GEN a,long flag)
        !           657: {
        !           658:   GEN b,p;
        !           659:   long i,j,k, n = lg(a);
        !           660:   ulong av = avma, lim=stack_lim(av,1);
        !           661:
        !           662:   if (typ(a)!=t_MAT) err(typeer,"sqred1");
        !           663:   if (n == 1) return cgetg(1, t_MAT);
        !           664:   if (lg(a[1])!=n) err(mattype1,"sqred1");
        !           665:   b=cgetg(n,t_MAT);
        !           666:   for (j=1; j<n; j++)
        !           667:   {
        !           668:     GEN p1=cgetg(n,t_COL), p2=(GEN)a[j];
        !           669:
        !           670:     b[j]=(long)p1;
        !           671:     for (i=1; i<=j; i++) p1[i] = p2[i];
        !           672:     for (   ; i<n ; i++) p1[i] = zero;
        !           673:   }
        !           674:   for (k=1; k<n; k++)
        !           675:   {
        !           676:     p = gcoeff(b,k,k);
        !           677:     if (gsigne(p)<=0) /* not positive definite */
        !           678:     {
        !           679:       if (flag) { avma=av; return NULL; }
        !           680:       err(talker,"not a positive definite matrix in sqred1");
        !           681:     }
        !           682:     p = ginv(p);
        !           683:     for (i=k+1; i<n; i++)
        !           684:       for (j=i; j<n; j++)
        !           685:        coeff(b,i,j)=lsub(gcoeff(b,i,j),
        !           686:                          gmul(gmul(gcoeff(b,k,i),gcoeff(b,k,j)), p));
        !           687:     for (j=k+1; j<n; j++)
        !           688:       coeff(b,k,j)=lmul(gcoeff(b,k,j), p);
        !           689:     if (low_stack(lim, stack_lim(av,1)))
        !           690:     {
        !           691:       if (DEBUGMEM>1) err(warnmem,"sqred1");
        !           692:       b=gerepilecopy(av,b);
        !           693:     }
        !           694:   }
        !           695:   return gerepilecopy(av,b);
        !           696: }
        !           697:
        !           698: GEN
        !           699: sqred1(GEN a)
        !           700: {
        !           701:   return sqred1intern(a,0);
        !           702: }
        !           703:
        !           704: GEN
        !           705: sqred3(GEN a)
        !           706: {
        !           707:   ulong av = avma, lim = stack_lim(av,1);
        !           708:   long i,j,k,l, n = lg(a);
        !           709:   GEN p1,b;
        !           710:
        !           711:   if (typ(a)!=t_MAT) err(typeer,"sqred3");
        !           712:   if (lg(a[1])!=n) err(mattype1,"sqred3");
        !           713:   av=avma; b=cgetg(n,t_MAT);
        !           714:   for (j=1; j<n; j++)
        !           715:   {
        !           716:     p1=cgetg(n,t_COL); b[j]=(long)p1;
        !           717:     for (i=1; i<n; i++) p1[i]=zero;
        !           718:   }
        !           719:   for (i=1; i<n; i++)
        !           720:   {
        !           721:     for (k=1; k<i; k++)
        !           722:     {
        !           723:       p1=gzero;
        !           724:       for (l=1; l<k; l++)
        !           725:        p1=gadd(p1, gmul(gmul(gcoeff(b,l,l),gcoeff(b,k,l)), gcoeff(b,i,l)));
        !           726:       coeff(b,i,k)=ldiv(gsub(gcoeff(a,i,k),p1),gcoeff(b,k,k));
        !           727:     }
        !           728:     p1=gzero;
        !           729:     for (l=1; l<i; l++)
        !           730:       p1=gadd(p1, gmul(gcoeff(b,l,l), gsqr(gcoeff(b,i,l))));
        !           731:     coeff(b,i,k)=lsub(gcoeff(a,i,i),p1);
        !           732:     if (low_stack(lim, stack_lim(av,1)))
        !           733:     {
        !           734:       if (DEBUGMEM>1) err(warnmem,"sqred3");
        !           735:       b=gerepilecopy(av,b);
        !           736:     }
        !           737:   }
        !           738:   return gerepilecopy(av,b);
        !           739: }
        !           740:
        !           741: /* Gauss reduction (arbitrary symetric matrix, only the part above the
        !           742:  * diagonal is considered). If no_signature is zero, return only the
        !           743:  * signature
        !           744:  */
        !           745: static GEN
        !           746: sqred2(GEN a, long no_signature)
        !           747: {
        !           748:   GEN r,p,mun;
        !           749:   ulong av,av1,lim;
        !           750:   long n,i,j,k,l,sp,sn,t;
        !           751:
        !           752:   if (typ(a)!=t_MAT) err(typeer,"sqred2");
        !           753:   n=lg(a); if (lg(a[1]) != n) err(mattype1,"sqred2");
        !           754:
        !           755:   av=avma; mun=negi(gun); r=new_chunk(n);
        !           756:   for (i=1; i<n; i++) r[i]=1;
        !           757:   av1=avma; lim=stack_lim(av1,1); a=dummycopy(a);
        !           758:   n--; t=n; sp=sn=0;
        !           759:   while (t)
        !           760:   {
        !           761:     k=1; while (k<=n && (gcmp0(gcoeff(a,k,k)) || !r[k])) k++;
        !           762:     if (k<=n)
        !           763:     {
        !           764:       p=gcoeff(a,k,k); if (gsigne(p)>0) sp++; else sn++;
        !           765:       r[k]=0; t--;
        !           766:       for (j=1; j<=n; j++)
        !           767:        coeff(a,k,j)=r[j] ? ldiv(gcoeff(a,k,j),p) : zero;
        !           768:
        !           769:       for (i=1; i<=n; i++) if (r[i])
        !           770:        for (j=1; j<=n; j++)
        !           771:          coeff(a,i,j) = r[j] ? lsub(gcoeff(a,i,j),
        !           772:                                     gmul(gmul(gcoeff(a,k,i),gcoeff(a,k,j)),p))
        !           773:                              : zero;
        !           774:       coeff(a,k,k)=(long)p;
        !           775:     }
        !           776:     else
        !           777:     {
        !           778:       for (k=1; k<=n; k++) if (r[k])
        !           779:       {
        !           780:        l=k+1; while (l<=n && (gcmp0(gcoeff(a,k,l)) || !r[l])) l++;
        !           781:        if (l<=n)
        !           782:        {
        !           783:          p=gcoeff(a,k,l); r[k]=r[l]=0; sp++; sn++; t-=2;
        !           784:          for (i=1; i<=n; i++) if (r[i])
        !           785:          {
        !           786:            for (j=1; j<=n; j++)
        !           787:              coeff(a,i,j) =
        !           788:                r[j]? lsub(gcoeff(a,i,j),
        !           789:                           gdiv(gadd(gmul(gcoeff(a,k,i),gcoeff(a,l,j)),
        !           790:                                     gmul(gcoeff(a,k,j),gcoeff(a,l,i))),
        !           791:                                p))
        !           792:                    : zero;
        !           793:            coeff(a,k,i)=ldiv(gadd(gcoeff(a,k,i),gcoeff(a,l,i)),p);
        !           794:            coeff(a,l,i)=ldiv(gsub(gcoeff(a,k,i),gcoeff(a,l,i)),p);
        !           795:          }
        !           796:          coeff(a,k,l)=un; coeff(a,l,k)=(long)mun;
        !           797:          coeff(a,k,k)=lmul2n(p,-1); coeff(a,l,l)=lneg(gcoeff(a,k,k));
        !           798:          if (low_stack(lim, stack_lim(av1,1)))
        !           799:          {
        !           800:            if(DEBUGMEM>1) err(warnmem,"sqred2");
        !           801:            a=gerepilecopy(av1,a);
        !           802:          }
        !           803:          break;
        !           804:        }
        !           805:       }
        !           806:       if (k>n) break;
        !           807:     }
        !           808:   }
        !           809:   if (no_signature) return gerepilecopy(av,a);
        !           810:   avma=av;
        !           811:   a=cgetg(3,t_VEC); a[1]=lstoi(sp); a[2]=lstoi(sn); return a;
        !           812: }
        !           813:
        !           814: GEN
        !           815: sqred(GEN a) { return sqred2(a,1); }
        !           816:
        !           817: GEN
        !           818: signat(GEN a) { return sqred2(a,0); }
        !           819:
        !           820: /* Diagonalization of a REAL symetric matrix. Return a 2-component vector:
        !           821:  * 1st comp = vector of eigenvalues
        !           822:  * 2nd comp = matrix of eigenvectors
        !           823:  */
        !           824: GEN
        !           825: jacobi(GEN a, long prec)
        !           826: {
        !           827:   long de,e,e1,e2,l,n,i,j,p,q,av1,av2;
        !           828:   GEN c,s,t,u,ja,lambda,r,unr,x,y,x1,y1;
        !           829:
        !           830:   if (typ(a)!=t_MAT) err(mattype1,"jacobi");
        !           831:   ja=cgetg(3,t_VEC); l=lg(a); n=l-1;
        !           832:   e1=HIGHEXPOBIT-1;
        !           833:   lambda=cgetg(l,t_COL); ja[1]=(long)lambda;
        !           834:   for (j=1; j<=n; j++)
        !           835:   {
        !           836:     lambda[j]=lgetr(prec);
        !           837:     gaffect(gcoeff(a,j,j), (GEN)lambda[j]);
        !           838:     e=expo(lambda[j]); if (e<e1) e1=e;
        !           839:   }
        !           840:   r=cgetg(l,t_MAT); ja[2]=(long)r;
        !           841:   for (j=1; j<=n; j++)
        !           842:   {
        !           843:     r[j]=lgetg(l,t_COL);
        !           844:     for (i=1; i<=n; i++)
        !           845:       affsr(i==j, (GEN)(coeff(r,i,j)=lgetr(prec)));
        !           846:   }
        !           847:   av1=avma;
        !           848:
        !           849:   e2=-HIGHEXPOBIT;p=q=1;
        !           850:   c=cgetg(l,t_MAT);
        !           851:   for (j=1; j<=n; j++)
        !           852:   {
        !           853:     c[j]=lgetg(j,t_COL);
        !           854:     for (i=1; i<j; i++)
        !           855:     {
        !           856:       gaffect(gcoeff(a,i,j), (GEN)(coeff(c,i,j)=lgetr(prec)));
        !           857:       e=expo(gcoeff(c,i,j)); if (e>e2) { e2=e; p=i; q=j; }
        !           858:     }
        !           859:   }
        !           860:   a=c; unr = realun(prec);
        !           861:   de=bit_accuracy(prec);
        !           862:
        !           863:  /* e1 = min des expo des coeff diagonaux
        !           864:   * e2 = max des expo des coeff extra-diagonaux
        !           865:   * Test d'arret: e2 < e1-precision
        !           866:   */
        !           867:   while (e1-e2<de)
        !           868:   {
        !           869:     /*calcul de la rotation associee dans le plan
        !           870:          des p et q-iemes vecteurs de base   */
        !           871:     av2=avma;
        !           872:     x=divrr(subrr((GEN)lambda[q],(GEN)lambda[p]),shiftr(gcoeff(a,p,q),1));
        !           873:     y=mpsqrt(addrr(unr,mulrr(x,x)));
        !           874:     t=(gsigne(x)>0)? divrr(unr,addrr(x,y)) : divrr(unr,subrr(x,y));
        !           875:     c=divrr(unr,mpsqrt(addrr(unr,mulrr(t,t))));
        !           876:     s=mulrr(t,c); u=divrr(s,addrr(unr,c));
        !           877:
        !           878:     /* Recalcul des transformees successives de a et de la matrice
        !           879:           cumulee (r) des rotations :  */
        !           880:
        !           881:     for (i=1; i<p; i++)
        !           882:     {
        !           883:       x=gcoeff(a,i,p); y=gcoeff(a,i,q);
        !           884:       x1=subrr(x,mulrr(s,addrr(y,mulrr(u,x))));
        !           885:       y1=addrr(y,mulrr(s,subrr(x,mulrr(u,y))));
        !           886:       affrr(x1,gcoeff(a,i,p)); affrr(y1,gcoeff(a,i,q));
        !           887:     }
        !           888:     for (i=p+1; i<q; i++)
        !           889:     {
        !           890:       x=gcoeff(a,p,i); y=gcoeff(a,i,q);
        !           891:       x1=subrr(x,mulrr(s,addrr(y,mulrr(u,x))));
        !           892:       y1=addrr(y,mulrr(s,subrr(x,mulrr(u,y))));
        !           893:       affrr(x1,gcoeff(a,p,i)); affrr(y1,gcoeff(a,i,q));
        !           894:     }
        !           895:     for (i=q+1; i<=n; i++)
        !           896:     {
        !           897:       x=gcoeff(a,p,i); y=gcoeff(a,q,i);
        !           898:       x1=subrr(x,mulrr(s,addrr(y,mulrr(u,x))));
        !           899:       y1=addrr(y,mulrr(s,subrr(x,mulrr(u,y))));
        !           900:       affrr(x1,gcoeff(a,p,i)); affrr(y1,gcoeff(a,q,i));
        !           901:     }
        !           902:     x=(GEN)lambda[p]; y=gcoeff(a,p,q); subrrz(x,mulrr(t,y),(GEN)lambda[p]);
        !           903:     x=y; y=(GEN)lambda[q]; addrrz(y,mulrr(t,x),y);
        !           904:     setexpo(x,expo(x)-de-1);
        !           905:
        !           906:     for (i=1; i<=n; i++)
        !           907:     {
        !           908:       x=gcoeff(r,i,p); y=gcoeff(r,i,q);
        !           909:       x1=subrr(x,mulrr(s,addrr(y,mulrr(u,x))));
        !           910:       y1=addrr(y,mulrr(s,subrr(x,mulrr(u,y))));
        !           911:       affrr(x1,gcoeff(r,i,p)); affrr(y1,gcoeff(r,i,q));
        !           912:     }
        !           913:
        !           914:     e2=expo(gcoeff(a,1,2)); p=1; q=2;
        !           915:     for (j=1; j<=n; j++)
        !           916:     {
        !           917:       for (i=1; i<j; i++)
        !           918:        if ((e=expo(gcoeff(a,i,j))) > e2) { e2=e; p=i; q=j; }
        !           919:       for (i=j+1; i<=n; i++)
        !           920:        if ((e=expo(gcoeff(a,j,i))) > e2) { e2=e; p=j; q=i; }
        !           921:     }
        !           922:     avma=av2;
        !           923:   }
        !           924:   avma=av1; return ja;
        !           925: }
        !           926:
        !           927: /*************************************************************************/
        !           928: /**                                                                    **/
        !           929: /**                MATRICE RATIONNELLE --> ENTIERE                     **/
        !           930: /**                                                                    **/
        !           931: /*************************************************************************/
        !           932:
        !           933: GEN
        !           934: matrixqz0(GEN x,GEN p)
        !           935: {
        !           936:   if (typ(p)!=t_INT) err(typeer,"matrixqz0");
        !           937:   if (signe(p)>=0)  return matrixqz(x,p);
        !           938:   if (!cmpsi(-1,p)) return matrixqz2(x);
        !           939:   if (!cmpsi(-2,p)) return matrixqz3(x);
        !           940:   err(flagerr,"matrixqz"); return NULL; /* not reached */
        !           941: }
        !           942:
        !           943: GEN
        !           944: matrixqz(GEN x, GEN p)
        !           945: {
        !           946:   ulong av = avma, av1, lim;
        !           947:   long i,j,j1,m,n,t,nfact;
        !           948:   GEN p1,p2,p3,unmodp;
        !           949:
        !           950:   if (typ(x)!=t_MAT) err(typeer,"matrixqz");
        !           951:   n=lg(x)-1; if (!n) return gcopy(x);
        !           952:   m=lg(x[1])-1;
        !           953:   if (n > m) err(talker,"more rows than columns in matrixqz");
        !           954:   if (n==m)
        !           955:   {
        !           956:     p1=det(x);
        !           957:     if (gcmp0(p1)) err(talker,"matrix of non-maximal rank in matrixqz");
        !           958:     avma=av; return idmat(n);
        !           959:   }
        !           960:   p1=cgetg(n+1,t_MAT);
        !           961:   for (j=1; j<=n; j++)
        !           962:   {
        !           963:     p2=gun; p3=(GEN)x[j];
        !           964:     for (i=1; i<=m; i++)
        !           965:     {
        !           966:       t=typ(p3[i]);
        !           967:       if (t != t_INT && !is_frac_t(t))
        !           968:         err(talker,"not a rational or integral matrix in matrixqz");
        !           969:       p2=ggcd(p2,(GEN)p3[i]);
        !           970:     }
        !           971:     p1[j]=ldiv(p3,p2);
        !           972:   }
        !           973:   x=p1; unmodp=cgetg(3,t_INTMOD); unmodp[2]=un;
        !           974:
        !           975:   if (gcmp0(p))
        !           976:   {
        !           977:     p1=cgetg(n+1,t_MAT); p2=gtrans(x);
        !           978:     for (j=1; j<=n; j++) p1[j]=p2[j];
        !           979:     p3=det(p1); p1[n]=p2[n+1]; p3=ggcd(p3,det(p1));
        !           980:     if (!signe(p3))
        !           981:       err(impl,"matrixqz when the first 2 dets are zero");
        !           982:     if (gcmp1(p3)) return gerepilecopy(av,x);
        !           983:
        !           984:     p3=factor(p3); p1=(GEN)p3[1]; nfact=lg(p1)-1;
        !           985:   }
        !           986:   else
        !           987:   {
        !           988:     p1=cgetg(2,t_VEC); p1[1]=(long)p; nfact=1;
        !           989:   }
        !           990:   av1=avma; lim=stack_lim(av1,1);
        !           991:   for (i=1; i<=nfact; i++)
        !           992:   {
        !           993:     p=(GEN)p1[i]; unmodp[1]=(long)p;
        !           994:     for(;;)
        !           995:     {
        !           996:       p2=ker(gmul(unmodp,x));
        !           997:       if (lg(p2)==1) break;
        !           998:
        !           999:       p2=centerlift(p2); p3=gdiv(gmul(x,p2),p);
        !          1000:       for (j=1; j<lg(p2); j++)
        !          1001:       {
        !          1002:        j1=n; while (gcmp0(gcoeff(p2,j1,j))) j1--;
        !          1003:        x[j1] = p3[j];
        !          1004:       }
        !          1005:       if (low_stack(lim, stack_lim(av1,1)))
        !          1006:       {
        !          1007:        if (DEBUGMEM>1) err(warnmem,"matrixqz");
        !          1008:        x=gerepilecopy(av1,x);
        !          1009:       }
        !          1010:     }
        !          1011:   }
        !          1012:   return gerepilecopy(av,x);
        !          1013: }
        !          1014:
        !          1015: static GEN
        !          1016: matrixqz_aux(GEN x, long m, long n)
        !          1017: {
        !          1018:   ulong av = avma, lim = stack_lim(av,1);
        !          1019:   long i,j,k,in[2];
        !          1020:   GEN p1;
        !          1021:
        !          1022:   for (i=1; i<=m; i++)
        !          1023:   {
        !          1024:     for(;;)
        !          1025:     {
        !          1026:       long fl=0;
        !          1027:
        !          1028:       for (j=1; j<=n; j++)
        !          1029:        if (!gcmp0(gcoeff(x,i,j)))
        !          1030:          { in[fl]=j; fl++; if (fl==2) break; }
        !          1031:       if (j>n) break;
        !          1032:
        !          1033:       j=(gcmp(gabs(gcoeff(x,i,in[0]),DEFAULTPREC),
        !          1034:              gabs(gcoeff(x,i,in[1]),DEFAULTPREC)) > 0)? in[1]: in[0];
        !          1035:       p1=gcoeff(x,i,j);
        !          1036:       for (k=1; k<=n; k++)
        !          1037:        if (k!=j)
        !          1038:          x[k]=lsub((GEN)x[k],gmul(ground(gdiv(gcoeff(x,i,k),p1)),(GEN)x[j]));
        !          1039:     }
        !          1040:
        !          1041:     j=1; while (j<=n && gcmp0(gcoeff(x,i,j))) j++;
        !          1042:     if (j<=n)
        !          1043:     {
        !          1044:       p1=denom(gcoeff(x,i,j));
        !          1045:       if (!gcmp1(p1)) x[j]=lmul(p1,(GEN)x[j]);
        !          1046:     }
        !          1047:     if (low_stack(lim, stack_lim(av,1)))
        !          1048:     {
        !          1049:       if(DEBUGMEM>1) err(warnmem,"matrixqz_aux");
        !          1050:       x=gerepilecopy(av,x);
        !          1051:     }
        !          1052:   }
        !          1053:   return hnf(x);
        !          1054: }
        !          1055:
        !          1056: GEN
        !          1057: matrixqz2(GEN x)
        !          1058: {
        !          1059:   long av = avma,m,n;
        !          1060:
        !          1061:   if (typ(x)!=t_MAT) err(typeer,"matrixqz2");
        !          1062:   n=lg(x)-1; if (!n) return gcopy(x);
        !          1063:   m=lg(x[1])-1; x=dummycopy(x);
        !          1064:   return gerepileupto(av, matrixqz_aux(x,m,n));
        !          1065: }
        !          1066:
        !          1067: GEN
        !          1068: matrixqz3(GEN x)
        !          1069: {
        !          1070:   long av=avma,av1,j,j1,k,m,n,lim;
        !          1071:   GEN c;
        !          1072:
        !          1073:   if (typ(x)!=t_MAT) err(typeer,"matrixqz3");
        !          1074:   n=lg(x)-1; if (!n) return gcopy(x);
        !          1075:   m=lg(x[1])-1; x=dummycopy(x); c=new_chunk(n+1);
        !          1076:   for (j=1; j<=n; j++) c[j]=0;
        !          1077:   av1=avma; lim=stack_lim(av1,1);
        !          1078:   for (k=1; k<=m; k++)
        !          1079:   {
        !          1080:     j=1; while (j<=n && (c[j] || gcmp0(gcoeff(x,k,j)))) j++;
        !          1081:     if (j<=n)
        !          1082:     {
        !          1083:       c[j]=k; x[j]=ldiv((GEN)x[j],gcoeff(x,k,j));
        !          1084:       for (j1=1; j1<=n; j1++)
        !          1085:        if (j1!=j) x[j1]=lsub((GEN)x[j1],gmul(gcoeff(x,k,j1),(GEN)x[j]));
        !          1086:       if (low_stack(lim, stack_lim(av1,1)))
        !          1087:       {
        !          1088:        if(DEBUGMEM>1) err(warnmem,"matrixqz3");
        !          1089:        x=gerepilecopy(av1,x);
        !          1090:       }
        !          1091:     }
        !          1092:   }
        !          1093:   return gerepileupto(av, matrixqz_aux(x,m,n));
        !          1094: }
        !          1095:
        !          1096: GEN
        !          1097: intersect(GEN x, GEN y)
        !          1098: {
        !          1099:   long av,tetpil,j, lx = lg(x);
        !          1100:   GEN z;
        !          1101:
        !          1102:   if (typ(x)!=t_MAT || typ(y)!=t_MAT) err(typeer,"intersect");
        !          1103:   if (lx==1 || lg(y)==1) return cgetg(1,t_MAT);
        !          1104:
        !          1105:   av=avma; z=ker(concatsp(x,y));
        !          1106:   for (j=lg(z)-1; j; j--) setlg(z[j],lx);
        !          1107:   tetpil=avma; return gerepile(av,tetpil,gmul(x,z));
        !          1108: }
        !          1109:
        !          1110: /**************************************************************/
        !          1111: /**                                                          **/
        !          1112: /**               HERMITE NORMAL FORM REDUCTION             **/
        !          1113: /**                                                         **/
        !          1114: /**************************************************************/
        !          1115:
        !          1116: GEN
        !          1117: mathnf0(GEN x, long flag)
        !          1118: {
        !          1119:   switch(flag)
        !          1120:   {
        !          1121:     case 0: return hnf(x);
        !          1122:     case 1: return hnfall(x);
        !          1123:     case 3: return hnfperm(x);
        !          1124:     case 4: return hnflll(x);
        !          1125:     default: err(flagerr,"mathnf");
        !          1126:   }
        !          1127:   return NULL; /* not reached */
        !          1128: }
        !          1129:
        !          1130: static GEN
        !          1131: init_hnf(GEN x, GEN *denx, long *co, long *li, long *av)
        !          1132: {
        !          1133:   if (typ(x) != t_MAT) err(typeer,"mathnf");
        !          1134:   *co=lg(x); if (*co==1) return NULL; /* empty matrix */
        !          1135:   *li=lg(x[1]); *denx=denom(x); *av=avma;
        !          1136:
        !          1137:   if (gcmp1(*denx)) /* no denominator */
        !          1138:     { *denx = NULL; return dummycopy(x); }
        !          1139:   return gmul(x,*denx);
        !          1140: }
        !          1141:
        !          1142: GEN
        !          1143: ZV_copy(GEN x)
        !          1144: {
        !          1145:   long i, lx = lg(x);
        !          1146:   GEN y = cgetg(lx, t_COL);
        !          1147:   for (i=1; i<lx; i++) y[i] = signe(x[i])? licopy((GEN)x[i]): zero;
        !          1148:   return y;
        !          1149: }
        !          1150:
        !          1151: GEN
        !          1152: ZM_copy(GEN x)
        !          1153: {
        !          1154:   long i, lx = lg(x);
        !          1155:   GEN y = cgetg(lx, t_MAT);
        !          1156:
        !          1157:   for (i=1; i<lx; i++)
        !          1158:     y[i] = (long)ZV_copy((GEN)x[i]);
        !          1159:   return y;
        !          1160: }
        !          1161:
        !          1162: /* return c * X. Not memory clean if c = 1 */
        !          1163: GEN
        !          1164: ZV_Z_mul(GEN c, GEN X)
        !          1165: {
        !          1166:   long i,m = lg(X);
        !          1167:   GEN A = new_chunk(m);
        !          1168:   if (is_pm1(c))
        !          1169:   {
        !          1170:     if (signe(c) > 0)
        !          1171:       { for (i=1; i<m; i++) A[i] = X[i]; }
        !          1172:     else
        !          1173:       { for (i=1; i<m; i++) A[i] = lnegi((GEN)X[i]); }
        !          1174:   }
        !          1175:   else /* c = 0 should be exceedingly rare */
        !          1176:     { for (i=1; i<m; i++) A[i] = lmulii(c,(GEN)X[i]); }
        !          1177:   A[0] = X[0]; return A;
        !          1178: }
        !          1179:
        !          1180: /* X,Y columns; u,v scalars; everybody is integral. return A = u*X + v*Y
        !          1181:  * Not memory clean if (u,v) = (1,0) or (0,1) */
        !          1182: GEN
        !          1183: ZV_lincomb(GEN u, GEN v, GEN X, GEN Y)
        !          1184: {
        !          1185:   long av,i,lx,m;
        !          1186:   GEN p1,p2,A;
        !          1187:
        !          1188:   if (!signe(u)) return ZV_Z_mul(v,Y);
        !          1189:   if (!signe(v)) return ZV_Z_mul(u,X);
        !          1190:   lx = lg(X); A = cgetg(lx,t_COL); m = lgefint(u)+lgefint(v)+4;
        !          1191:   if (is_pm1(v)) { gswap(u,v); gswap(X,Y); }
        !          1192:   if (is_pm1(u))
        !          1193:   {
        !          1194:     if (signe(u) > 0)
        !          1195:     {
        !          1196:       for (i=1; i<lx; i++)
        !          1197:       {
        !          1198:         p1=(GEN)X[i]; p2=(GEN)Y[i];
        !          1199:         if      (!signe(p1)) A[i] = lmulii(v,p2);
        !          1200:         else if (!signe(p2)) A[i] = licopy(p1);
        !          1201:         else
        !          1202:         {
        !          1203:           av = avma; (void)new_chunk(m+lgefint(p1)+lgefint(p2)); /* HACK */
        !          1204:           p2 = mulii(v,p2);
        !          1205:           avma = av; A[i] = laddii(p1,p2);
        !          1206:         }
        !          1207:       }
        !          1208:     }
        !          1209:     else
        !          1210:     {
        !          1211:       for (i=1; i<lx; i++)
        !          1212:       {
        !          1213:         p1=(GEN)X[i]; p2=(GEN)Y[i];
        !          1214:         if      (!signe(p1)) A[i] = lmulii(v,p2);
        !          1215:         else if (!signe(p2)) A[i] = lnegi(p1);
        !          1216:         else
        !          1217:         {
        !          1218:           av = avma; (void)new_chunk(m+lgefint(p1)+lgefint(p2)); /* HACK */
        !          1219:           p2 = mulii(v,p2);
        !          1220:           avma = av; A[i] = lsubii(p2,p1);
        !          1221:         }
        !          1222:       }
        !          1223:     }
        !          1224:   }
        !          1225:   else
        !          1226:     for (i=1; i<lx; i++)
        !          1227:     {
        !          1228:       p1=(GEN)X[i]; p2=(GEN)Y[i];
        !          1229:       if      (!signe(p1)) A[i] = lmulii(v,p2);
        !          1230:       else if (!signe(p2)) A[i] = lmulii(u,p1);
        !          1231:       else
        !          1232:       {
        !          1233:         av = avma; (void)new_chunk(m+lgefint(p1)+lgefint(p2)); /* HACK */
        !          1234:         p1 = mulii(u,p1);
        !          1235:         p2 = mulii(v,p2);
        !          1236:         avma = av; A[i] = laddii(p1,p2);
        !          1237:       }
        !          1238:     }
        !          1239:   return A;
        !          1240: }
        !          1241:
        !          1242: /* x = [A,U], nbcol(A) = nbcol(U), A integral. Return [AV, UV], with AV HNF */
        !          1243: GEN
        !          1244: hnf_special(GEN x, long remove)
        !          1245: {
        !          1246:   long av0, s,li,co,av,tetpil,i,j,k,def,ldef,lim;
        !          1247:   GEN p1,u,v,d,denx,a,b, x2,res;
        !          1248:
        !          1249:   if (typ(x) != t_VEC || lg(x) !=3) err(typeer,"hnf_special");
        !          1250:   res = cgetg(3,t_VEC);
        !          1251:   av0 = avma;
        !          1252:   x2 = (GEN)x[2];
        !          1253:   x  = (GEN)x[1];
        !          1254:   x = init_hnf(x,&denx,&co,&li,&av);
        !          1255:   if (!x) return cgetg(1,t_MAT);
        !          1256:
        !          1257:   lim = stack_lim(av,1);
        !          1258:   def=co-1; ldef=(li>co)? li-co: 0;
        !          1259:   if (lg(x2) != co) err(talker,"incompatible matrices in hnf_special");
        !          1260:   x2 = dummycopy(x2);
        !          1261:   for (i=li-1; i>ldef; i--)
        !          1262:   {
        !          1263:     for (j=def-1; j; j--)
        !          1264:     {
        !          1265:       a = gcoeff(x,i,j);
        !          1266:       if (!signe(a)) continue;
        !          1267:
        !          1268:       k = (j==1)? def: j-1;
        !          1269:       b = gcoeff(x,i,k); d = bezout(a,b,&u,&v);
        !          1270:       if (!is_pm1(d)) { a = divii(a,d); b = divii(b,d); }
        !          1271:       p1 = (GEN)x[j]; b = negi(b);
        !          1272:       x[j] = (long)ZV_lincomb(a,b, (GEN)x[k], p1);
        !          1273:       x[k] = (long)ZV_lincomb(u,v, p1, (GEN)x[k]);
        !          1274:       p1 = (GEN)x2[j];
        !          1275:       x2[j]=  ladd(gmul(a, (GEN)x2[k]), gmul(b,p1));
        !          1276:       x2[k] = ladd(gmul(u,p1), gmul(v, (GEN)x2[k]));
        !          1277:       if (low_stack(lim, stack_lim(av,1)))
        !          1278:       {
        !          1279:         GEN *gptr[2]; gptr[0]=&x; gptr[1]=&x2;
        !          1280:         if (DEBUGMEM>1) err(warnmem,"hnf_special[1]. i=%ld",i);
        !          1281:         gerepilemany(av,gptr,2);
        !          1282:       }
        !          1283:     }
        !          1284:     p1 = gcoeff(x,i,def); s = signe(p1);
        !          1285:     if (s)
        !          1286:     {
        !          1287:       if (s < 0)
        !          1288:       {
        !          1289:         x[def] = lneg((GEN)x[def]); p1 = gcoeff(x,i,def);
        !          1290:         x2[def]= lneg((GEN)x2[def]);
        !          1291:       }
        !          1292:       for (j=def+1; j<co; j++)
        !          1293:       {
        !          1294:        b = negi(gdivent(gcoeff(x,i,j),p1));
        !          1295:        x[j] = (long)ZV_lincomb(gun,b, (GEN)x[j], (GEN)x[def]);
        !          1296:         x2[j]= ladd((GEN)x2[j], gmul(b, (GEN)x2[def]));
        !          1297:       }
        !          1298:       def--;
        !          1299:     }
        !          1300:     else
        !          1301:       if (ldef && i==ldef+1) ldef--;
        !          1302:     if (low_stack(lim, stack_lim(av,1)))
        !          1303:     {
        !          1304:       GEN *gptr[2]; gptr[0]=&x; gptr[1]=&x2;
        !          1305:       if (DEBUGMEM>1) err(warnmem,"hnf_special[2]. i=%ld",i);
        !          1306:       gerepilemany(av,gptr,2);
        !          1307:     }
        !          1308:   }
        !          1309:   if (remove)
        !          1310:   {                            /* remove null columns */
        !          1311:     for (i=1,j=1; j<co; j++)
        !          1312:       if (!gcmp0((GEN)x[j]))
        !          1313:       {
        !          1314:         x[i] = x[j];
        !          1315:         x2[i] = x2[j]; i++;
        !          1316:       }
        !          1317:     setlg(x,i);
        !          1318:     setlg(x2,i);
        !          1319:   }
        !          1320:   tetpil=avma;
        !          1321:   x = denx? gdiv(x,denx): ZM_copy(x);
        !          1322:   x2 = gcopy(x2);
        !          1323:   {
        !          1324:     GEN *gptr[2]; gptr[0]=&x; gptr[1]=&x2;
        !          1325:     gerepilemanysp(av0,tetpil,gptr,2);
        !          1326:   }
        !          1327:   res[1] = (long)x;
        !          1328:   res[2] = (long)x2;
        !          1329:   return res;
        !          1330: }
        !          1331:
        !          1332: /*******************************************************************/
        !          1333: /*                                                                 */
        !          1334: /*                SPECIAL HNF (FOR INTERNAL USE !!!)               */
        !          1335: /*                                                                 */
        !          1336: /*******************************************************************/
        !          1337: extern GEN imagecomplspec(GEN x, long *nlze);
        !          1338:
        !          1339: static int
        !          1340: count(long **mat, long row, long len, long *firstnonzero)
        !          1341: {
        !          1342:   int j, n=0;
        !          1343:
        !          1344:   for (j=1; j<=len; j++)
        !          1345:   {
        !          1346:     long p = mat[j][row];
        !          1347:     if (p)
        !          1348:     {
        !          1349:       if (labs(p)!=1) return -1;
        !          1350:       n++; *firstnonzero=j;
        !          1351:     }
        !          1352:   }
        !          1353:   return n;
        !          1354: }
        !          1355:
        !          1356: static int
        !          1357: count2(long **mat, long row, long len)
        !          1358: {
        !          1359:   int j;
        !          1360:   for (j=len; j; j--)
        !          1361:     if (labs(mat[j][row]) == 1) return j;
        !          1362:   return 0;
        !          1363: }
        !          1364:
        !          1365: static GEN
        !          1366: hnffinal(GEN matgen,GEN perm,GEN* ptdep,GEN* ptB,GEN* ptC)
        !          1367: {
        !          1368:   GEN p1,p2,U,H,Hnew,Bnew,Cnew,diagH1;
        !          1369:   GEN B = *ptB, C = *ptC, dep = *ptdep, depnew;
        !          1370:   long av,i,j,k,s,i1,j1,lim,zc;
        !          1371:   long co = lg(C);
        !          1372:   long col = lg(matgen)-1;
        !          1373:   long lnz, nlze, lig;
        !          1374:
        !          1375:   if (col == 0) return matgen;
        !          1376:   lnz = lg(matgen[1])-1; /* was called lnz-1 - nr in hnfspec */
        !          1377:   nlze = lg(dep[1])-1;
        !          1378:   lig = nlze + lnz;
        !          1379:   if (DEBUGLEVEL>5)
        !          1380:   {
        !          1381:     fprintferr("Entering hnffinal:\n");
        !          1382:     if (DEBUGLEVEL>6)
        !          1383:     {
        !          1384:       if (nlze) fprintferr("dep = %Z\n",dep);
        !          1385:       fprintferr("mit = %Z\n",matgen);
        !          1386:       fprintferr("B = %Z\n",B);
        !          1387:     }
        !          1388:   }
        !          1389:   p1 = hnflll(matgen);
        !          1390:   H = (GEN)p1[1]; /* lnz x lnz */
        !          1391:   U = (GEN)p1[2]; /* col x col */
        !          1392:   /* Only keep the part above the H (above the 0s is 0 since the dep rows
        !          1393:    * are dependant from the ones in matgen) */
        !          1394:   zc = col - lnz; /* # of 0 columns, correspond to units */
        !          1395:   if (nlze) { dep = gmul(dep,U); dep += zc; }
        !          1396:
        !          1397:   diagH1 = new_chunk(lnz+1); /* diagH1[i] = 0 iff H[i,i] != 1 (set later) */
        !          1398:
        !          1399:   av = avma; lim = stack_lim(av,1);
        !          1400:   Cnew = cgetg(co,t_MAT);
        !          1401:   setlg(C, col+1); p1 = gmul(C,U);
        !          1402:   for (j=1; j<=col; j++) Cnew[j] = p1[j];
        !          1403:   for (   ; j<co ; j++)  Cnew[j] = C[j];
        !          1404:   if (DEBUGLEVEL>5) fprintferr("    hnflll done\n");
        !          1405:
        !          1406:   /* Clean up B using new H */
        !          1407:   for (s=0,i=lnz; i; i--)
        !          1408:   {
        !          1409:     GEN h = gcoeff(H,i,i);
        !          1410:     if ( (diagH1[i] = gcmp1(h)) ) { h = NULL; s++; }
        !          1411:     for (j=col+1; j<co; j++)
        !          1412:     {
        !          1413:       GEN z = (GEN)B[j-col];
        !          1414:       p1 = (GEN)z[i+nlze]; if (h) p1 = gdivent(p1,h);
        !          1415:       for (k=1; k<=nlze; k++)
        !          1416:        z[k] = lsubii((GEN)z[k], mulii(p1, gcoeff(dep,k,i)));
        !          1417:       for (   ; k<=lig; k++)
        !          1418:        z[k] = lsubii((GEN)z[k], mulii(p1, gcoeff(H,k-nlze,i)));
        !          1419:       Cnew[j] = lsub((GEN)Cnew[j], gmul(p1, (GEN)Cnew[i+zc]));
        !          1420:     }
        !          1421:     if (low_stack(lim, stack_lim(av,1)))
        !          1422:     {
        !          1423:       GEN *gptr[2]; gptr[0]=&Cnew; gptr[1]=&B;
        !          1424:       if(DEBUGMEM>1) err(warnmem,"hnffinal, i = %ld",i);
        !          1425:       gerepilemany(av,gptr,2);
        !          1426:     }
        !          1427:   }
        !          1428:   p1 = cgetg(lnz+1,t_VEC); p2 = perm + nlze;
        !          1429:   for (i1=0, j1=lnz-s, i=1; i<=lnz; i++) /* push the 1 rows down */
        !          1430:     if (diagH1[i])
        !          1431:       p1[++j1] = p2[i];
        !          1432:     else
        !          1433:       p2[++i1] = p2[i];
        !          1434:   for (i=i1+1; i<=lnz; i++) p2[i] = p1[i];
        !          1435:   if (DEBUGLEVEL>5) fprintferr("    first pass in hnffinal done\n");
        !          1436:
        !          1437:   /* s = # extra redundant generators taken from H
        !          1438:    *          zc  col-s  co   zc = col ­ lnz
        !          1439:    *       [ 0 |dep |     ]    i = lnze + lnz - s = lig - s
        !          1440:    *  nlze [--------|  B' ]
        !          1441:    *       [ 0 | H' |     ]    H' = H minus the s rows with a 1 on diagonal
        !          1442:    *     i [--------|-----] lig-s           (= "1-rows")
        !          1443:    *       [   0    | Id  ]
        !          1444:    *       [        |     ] li */
        !          1445:   lig -= s; col -= s; lnz -= s;
        !          1446:   Hnew = cgetg(lnz+1,t_MAT);
        !          1447:   depnew = cgetg(lnz+1,t_MAT); /* only used if nlze > 0 */
        !          1448:   Bnew = cgetg(co-col,t_MAT);
        !          1449:   C = dummycopy(Cnew);
        !          1450:   for (j=1,i1=j1=0; j<=lnz+s; j++)
        !          1451:   {
        !          1452:     GEN z = (GEN)H[j];
        !          1453:     if (diagH1[j])
        !          1454:     { /* hit exactly s times */
        !          1455:       i1++; p1 = cgetg(lig+1,t_COL); Bnew[i1] = (long)p1;
        !          1456:       C[i1+col] = Cnew[j+zc];
        !          1457:       for (i=1; i<=nlze; i++) p1[i] = coeff(dep,i,j);
        !          1458:       p1 += nlze;
        !          1459:     }
        !          1460:     else
        !          1461:     {
        !          1462:       j1++; p1 = cgetg(lnz+1,t_COL); Hnew[j1] = (long)p1;
        !          1463:       C[j1+zc] = Cnew[j+zc];
        !          1464:       if (nlze) depnew[j1] = dep[j];
        !          1465:     }
        !          1466:     for (i=k=1; k<=lnz; i++)
        !          1467:       if (!diagH1[i]) p1[k++] = z[i];
        !          1468:   }
        !          1469:   for (j=s+1; j<co-col; j++)
        !          1470:   {
        !          1471:     GEN z = (GEN)B[j-s];
        !          1472:     p1 = cgetg(lig+1,t_COL); Bnew[j] = (long)p1;
        !          1473:     for (i=1; i<=nlze; i++) p1[i] = z[i];
        !          1474:     z += nlze; p1 += nlze;
        !          1475:     for (i=k=1; k<=lnz; i++)
        !          1476:       if (!diagH1[i]) p1[k++] = z[i];
        !          1477:   }
        !          1478:   if (DEBUGLEVEL>5)
        !          1479:   {
        !          1480:     fprintferr("Leaving hnffinal\n");
        !          1481:     if (DEBUGLEVEL>6)
        !          1482:     {
        !          1483:       if (nlze) fprintferr("dep = %Z\n",depnew);
        !          1484:       fprintferr("mit = %Z\nB = %Z\nC = %Z\n", Hnew, Bnew, C);
        !          1485:     }
        !          1486:   }
        !          1487:   if (nlze) *ptdep = depnew;
        !          1488:   *ptC = C;
        !          1489:   *ptB = Bnew; return Hnew;
        !          1490: }
        !          1491:
        !          1492: /* for debugging */
        !          1493: static void
        !          1494: p_mat(long **mat, long *perm, long k0)
        !          1495: {
        !          1496:   long av=avma, i,j;
        !          1497:   GEN p1, matj, matgen;
        !          1498:   long co = lg(mat);
        !          1499:   long li = lg(perm);
        !          1500:
        !          1501:   fprintferr("Permutation: %Z\n",perm);
        !          1502:   matgen = cgetg(co,t_MAT);
        !          1503:   for (j=1; j<co; j++)
        !          1504:   {
        !          1505:     p1 = cgetg(li-k0,t_COL); matgen[j]=(long)p1;
        !          1506:     p1 -= k0; matj = mat[j];
        !          1507:     for (i=k0+1; i<li; i++) p1[i] = lstoi(matj[perm[i]]);
        !          1508:   }
        !          1509:   if (DEBUGLEVEL > 6) fprintferr("matgen = %Z\n",matgen);
        !          1510:   avma=av;
        !          1511: }
        !          1512:
        !          1513: static GEN
        !          1514: col_dup(long n, GEN col)
        !          1515: {
        !          1516:    GEN c = new_chunk(n+1);
        !          1517:    memcpy(c,col,(n+1)*sizeof(long));
        !          1518:    return c;
        !          1519: }
        !          1520:
        !          1521: /* HNF reduce a relation matrix (column operations + row permutation)
        !          1522: ** Input:
        !          1523: **   mat = (li-1) x (co-1) matrix of long
        !          1524: **   C   = r x (co-1) matrix of GEN
        !          1525: **   perm= permutation vector (length li-1), indexing the rows of mat: easier
        !          1526: **     to maintain perm than to copy rows. For columns we can do it directly
        !          1527: **     using e.g. swap(mat[i], mat[j])
        !          1528: **   k0 = integer. The k0 first lines of mat are dense, the others are sparse.
        !          1529: **     Also if k0=0, mat is modified in place [from mathnfspec], otherwise
        !          1530: **     it is left alone [from buchall]
        !          1531: ** Output: cf ASCII art in the function body
        !          1532: **
        !          1533: ** row permutations applied to perm
        !          1534: ** column operations applied to C.
        !          1535: **/
        !          1536: GEN
        !          1537: hnfspec(long** mat0, GEN perm, GEN* ptdep, GEN* ptB, GEN* ptC, long k0)
        !          1538: {
        !          1539:   long av=avma,av2,*p,i,j,k,lk0,col,lig,*matj, **mat;
        !          1540:   long n,s,t,lim,nlze,lnz,nr;
        !          1541:   GEN p1,p2,matb,matbnew,vmax,matt,T,extramat;
        !          1542:   GEN B,H,dep,permpro;
        !          1543:   GEN *gptr[4];
        !          1544:   long co = lg(mat0);
        !          1545:   long li = lg(perm); /* = lg(mat0[1]) */
        !          1546:   int updateT = 1;
        !          1547:
        !          1548:   if (!k0) mat = mat0; /* in place */
        !          1549:   else
        !          1550:   { /* keep original mat0 safe, modify a copy */
        !          1551:     mat = (long**)new_chunk(co); mat[0] = mat0[0];
        !          1552:     for (j=1; j<co; j++) mat[j] = col_dup(li,mat0[j]);
        !          1553:   }
        !          1554:
        !          1555:   if (DEBUGLEVEL>5)
        !          1556:   {
        !          1557:     fprintferr("Entering hnfspec\n");
        !          1558:     p_mat(mat,perm,0);
        !          1559:   }
        !          1560:   matt = cgetg(co,t_MAT); /* dense part of mat (top) */
        !          1561:   for (j=1; j<co; j++)
        !          1562:   {
        !          1563:     p1=cgetg(k0+1,t_COL); matt[j]=(long)p1; matj = mat[j];
        !          1564:     for (i=1; i<=k0; i++) p1[i] = lstoi(matj[perm[i]]);
        !          1565:   }
        !          1566:   vmax = cgetg(co,t_VECSMALL);
        !          1567:   av2 = avma; lim = stack_lim(av2,1);
        !          1568:
        !          1569:   i=lig=li-1; col=co-1; lk0=k0;
        !          1570:   if (k0 || (lg(*ptC) > 1 && lg((*ptC)[1]) > 1)) T = idmat(col);
        !          1571:   else
        !          1572:   { /* dummy ! */
        !          1573:     GEN z = cgetg(1,t_COL);
        !          1574:     T = cgetg(co, t_MAT); updateT = 0;
        !          1575:     for (j=1; j<co; j++) T[j] = (long)z;
        !          1576:   }
        !          1577:   /* Look for lines with a single non­0 entry, equal to ±1 */
        !          1578:   while (i > lk0)
        !          1579:     switch( count(mat,perm[i],col,&n) )
        !          1580:     {
        !          1581:       case 0: /* move zero lines between k0+1 and lk0 */
        !          1582:        lk0++; swap(perm[i], perm[lk0]);
        !          1583:         i=lig; continue;
        !          1584:
        !          1585:       case 1: /* move trivial generator between lig+1 and li */
        !          1586:        swap(perm[i], perm[lig]);
        !          1587:         swap(T[n], T[col]);
        !          1588:        gswap(mat[n], mat[col]); p = mat[col];
        !          1589:        if (p[perm[lig]] < 0) /* = -1 */
        !          1590:        { /* convert relation -g = 0 to g = 0 */
        !          1591:          for (i=lk0+1; i<lig; i++) p[perm[i]] = -p[perm[i]];
        !          1592:           if (updateT)
        !          1593:           {
        !          1594:             p1 = (GEN)T[col];
        !          1595:             for (i=1; ; i++)
        !          1596:               if (signe((GEN)p1[i])) { p1[i] = lnegi((GEN)p1[i]); break; }
        !          1597:           }
        !          1598:        }
        !          1599:        lig--; col--; i=lig; continue;
        !          1600:
        !          1601:       default: i--;
        !          1602:     }
        !          1603:   if (DEBUGLEVEL>5)
        !          1604:   {
        !          1605:     fprintferr("    after phase1:\n");
        !          1606:     p_mat(mat,perm,0);
        !          1607:   }
        !          1608:
        !          1609: #define absmax(s,z) {long _z; _z = labs(z); if (_z > s) s = _z;}
        !          1610:
        !          1611: #if 0 /* TODO: check, and put back in */
        !          1612:   /* Get rid of all lines containing only 0 and ± 1, keeping track of column
        !          1613:    * operations in T. Leave the rows 1..lk0 alone [up to k0, coeff
        !          1614:    * explosion, between k0+1 and lk0, row is 0]
        !          1615:    */
        !          1616:   s = 0;
        !          1617:   while (lig > lk0 && s < (HIGHBIT>>1))
        !          1618:   {
        !          1619:     for (i=lig; i>lk0; i--)
        !          1620:       if (count(mat,perm[i],col,&n) >= 0) break;
        !          1621:     if (i == lk0) break;
        !          1622:
        !          1623:     /* only 0, ±1 entries, at least 2 of them non-zero */
        !          1624:     swap(perm[i], perm[lig]);
        !          1625:     swap(T[n], T[col]); p1 = (GEN)T[col];
        !          1626:     gswap(mat[n], mat[col]); p = mat[col];
        !          1627:     if (p[perm[lig]] < 0)
        !          1628:     {
        !          1629:       for (i=lk0+1; i<=lig; i++) p[perm[i]] = -p[perm[i]];
        !          1630:       T[col] = lneg(p1);
        !          1631:     }
        !          1632:     for (j=1; j<n; j++)
        !          1633:     {
        !          1634:       matj = mat[j];
        !          1635:       if (! (t = matj[perm[lig]]) ) continue;
        !          1636:       if (t == 1)
        !          1637:       { /* t = 1 */
        !          1638:         for (i=lk0+1; i<=lig; i++)
        !          1639:           absmax(s, matj[perm[i]] -= p[perm[i]]);
        !          1640:         T[j] = lsub((GEN)T[j], p1);
        !          1641:       }
        !          1642:       else
        !          1643:       { /* t = -1 */
        !          1644:         for (i=lk0+1; i<=lig; i++)
        !          1645:           absmax(s, matj[perm[i]] += p[perm[i]]);
        !          1646:         T[j] = ladd((GEN)T[j], p1);
        !          1647:       }
        !          1648:     }
        !          1649:     lig--; col--;
        !          1650:     if (low_stack(lim, stack_lim(av2,1)))
        !          1651:     {
        !          1652:       if(DEBUGMEM>1) err(warnmem,"hnfspec[1]");
        !          1653:       T = gerepilecopy(av2, T);
        !          1654:     }
        !          1655:   }
        !          1656: #endif
        !          1657:   /* As above with lines containing a ±1 (no other assumption).
        !          1658:    * Stop when single precision becomes dangerous */
        !          1659:   for (j=1; j<=col; j++)
        !          1660:   {
        !          1661:     matj = mat[j];
        !          1662:     for (s=0, i=lk0+1; i<=lig; i++) absmax(s, matj[i]);
        !          1663:     vmax[j] = s;
        !          1664:   }
        !          1665:   while (lig > lk0)
        !          1666:   {
        !          1667:     for (i=lig; i>lk0; i--)
        !          1668:       if ( (n = count2(mat,perm[i],col)) ) break;
        !          1669:     if (i == lk0) break;
        !          1670:
        !          1671:     swap(perm[i], perm[lig]);
        !          1672:     swap(vmax[n], vmax[col]);
        !          1673:     gswap(mat[n], mat[col]); p = mat[col];
        !          1674:     swap(T[n], T[col]); p1 = (GEN)T[col];
        !          1675:     if (p[perm[lig]] < 0)
        !          1676:     {
        !          1677:       for (i=lk0+1; i<=lig; i++) p[perm[i]] = -p[perm[i]];
        !          1678:       p1 = gneg(p1); T[col] = (long)p1;
        !          1679:     }
        !          1680:     for (j=1; j<col; j++)
        !          1681:     {
        !          1682:       matj = mat[j];
        !          1683:       if (! (t = matj[perm[lig]]) ) continue;
        !          1684:       if (vmax[col] && (ulong)labs(t) >= (HIGHBIT-vmax[j]) / vmax[col])
        !          1685:         goto END2;
        !          1686:
        !          1687:       for (s=0, i=lk0+1; i<=lig; i++)
        !          1688:         absmax(s, matj[perm[i]] -= t*p[perm[i]]);
        !          1689:       vmax[j] = s;
        !          1690:       T[j] = (long)ZV_lincomb(gun,stoi(-t), (GEN)T[j],p1);
        !          1691:     }
        !          1692:     lig--; col--;
        !          1693:     if (low_stack(lim, stack_lim(av2,1)))
        !          1694:     {
        !          1695:       if(DEBUGMEM>1) err(warnmem,"hnfspec[2]");
        !          1696:       T = gerepilecopy(av2,T);
        !          1697:     }
        !          1698:   }
        !          1699:
        !          1700: END2: /* clean up mat: remove everything to the right of the 1s on diagonal */
        !          1701:   /* go multiprecision first */
        !          1702:   matb = cgetg(co,t_MAT); /* bottom part (complement of matt) */
        !          1703:   for (j=1; j<co; j++)
        !          1704:   {
        !          1705:     p1 = cgetg(li-k0,t_COL); matb[j] = (long)p1;
        !          1706:     p1 -= k0; matj = mat[j];
        !          1707:     for (i=k0+1; i<li; i++) p1[i] = lstoi(matj[perm[i]]);
        !          1708:   }
        !          1709:   if (DEBUGLEVEL>5)
        !          1710:   {
        !          1711:     fprintferr("    after phase2:\n");
        !          1712:     p_mat(mat,perm,k0);
        !          1713:   }
        !          1714:   for (i=li-2; i>lig; i--)
        !          1715:   {
        !          1716:     long i1, i0 = i - k0, k = i + co-li;
        !          1717:     GEN Bk = (GEN)matb[k];
        !          1718:     GEN Tk = (GEN)T[k];
        !          1719:     for (j=k+1; j<co; j++)
        !          1720:     {
        !          1721:       p1=(GEN)matb[j]; p2=(GEN)p1[i0];
        !          1722:       if (! (s=signe(p2)) ) continue;
        !          1723:
        !          1724:       p1[i0] = zero;
        !          1725:       if (is_pm1(p2))
        !          1726:       {
        !          1727:         if (s > 0)
        !          1728:         { /* p2 = 1 */
        !          1729:           for (i1=1; i1<i0; i1++)
        !          1730:             p1[i1] = lsubii((GEN)p1[i1], (GEN)Bk[i1]);
        !          1731:           T[j] = lsub((GEN)T[j], Tk);
        !          1732:         }
        !          1733:         else
        !          1734:         { /* p2 = -1 */
        !          1735:           for (i1=1; i1<i0; i1++)
        !          1736:             p1[i1] = laddii((GEN)p1[i1], (GEN)Bk[i1]);
        !          1737:           T[j] = ladd((GEN)T[j], Tk);
        !          1738:         }
        !          1739:       }
        !          1740:       else
        !          1741:       {
        !          1742:         for (i1=1; i1<i0; i1++)
        !          1743:           p1[i1] = lsubii((GEN)p1[i1], mulii(p2,(GEN) Bk[i1]));
        !          1744:         T[j] = (long)ZV_lincomb(gun,negi(p2), (GEN)T[j],Tk);
        !          1745:       }
        !          1746:     }
        !          1747:     if (low_stack(lim, stack_lim(av2,1)))
        !          1748:     {
        !          1749:       if(DEBUGMEM>1) err(warnmem,"hnfspec[3], i = %ld", i);
        !          1750:       for (j=1; j<co; j++) setlg(matb[j], i0+1); /* bottom can be forgotten */
        !          1751:       gptr[0]=&T; gptr[1]=&matb; gerepilemany(av2,gptr,2);
        !          1752:     }
        !          1753:   }
        !          1754:   gptr[0]=&T; gptr[1]=&matb; gerepilemany(av2,gptr,2);
        !          1755:   if (DEBUGLEVEL>5)
        !          1756:   {
        !          1757:     fprintferr("    matb cleaned up (using Id block)\n");
        !          1758:     if (DEBUGLEVEL>6) outerr(matb);
        !          1759:   }
        !          1760:
        !          1761:   nlze = lk0 - k0;  /* # of 0 rows */
        !          1762:   lnz = lig-nlze+1; /* 1 + # of non-0 rows (!= 0...0 1 0 ... 0) */
        !          1763:   if (updateT) matt = gmul(matt,T); /* update top rows */
        !          1764:   extramat = cgetg(col+1,t_MAT); /* = new C minus the 0 rows */
        !          1765:   for (j=1; j<=col; j++)
        !          1766:   {
        !          1767:     GEN z = (GEN)matt[j];
        !          1768:     GEN t = ((GEN)matb[j]) + nlze - k0;
        !          1769:     p2=cgetg(lnz,t_COL); extramat[j]=(long)p2;
        !          1770:     for (i=1; i<=k0; i++) p2[i] = z[i]; /* top k0 rows */
        !          1771:     for (   ; i<lnz; i++) p2[i] = t[i]; /* other non-0 rows */
        !          1772:   }
        !          1773:   permpro = imagecomplspec(extramat, &nr); /* lnz = lg(permpro) */
        !          1774:
        !          1775:   if (nlze)
        !          1776:   { /* put the nlze 0 rows (trivial generators) at the top */
        !          1777:     p1 = new_chunk(lk0+1);
        !          1778:     for (i=1; i<=nlze; i++) p1[i] = perm[i + k0];
        !          1779:     for (   ; i<=lk0; i++)  p1[i] = perm[i - nlze];
        !          1780:     for (i=1; i<=lk0; i++)  perm[i] = p1[i];
        !          1781:   }
        !          1782:   /* sort other rows according to permpro (nr redundant generators first) */
        !          1783:   p1 = new_chunk(lnz); p2 = perm + nlze;
        !          1784:   for (i=1; i<lnz; i++) p1[i] = p2[permpro[i]];
        !          1785:   for (i=1; i<lnz; i++) p2[i] = p1[i];
        !          1786:   /* perm indexes the rows of mat
        !          1787:    *   |_0__|__redund__|__dense__|__too big__|_____done______|
        !          1788:    *   0  nlze                              lig             li
        !          1789:    *         \___nr___/ \___k0__/
        !          1790:    *         \____________lnz ______________/
        !          1791:    *
        !          1792:    *               col   co
        !          1793:    *       [dep     |     ]
        !          1794:    *    i0 [--------|  B  ] (i0 = nlze + nr)
        !          1795:    *       [matbnew |     ] matbnew has maximal rank = lnz-1 - nr
        !          1796:    * mat = [--------|-----] lig
        !          1797:    *       [   0    | Id  ]
        !          1798:    *       [        |     ] li */
        !          1799:
        !          1800:   matbnew = cgetg(col+1,t_MAT); /* dense+toobig, maximal rank. For hnffinal */
        !          1801:   dep    = cgetg(col+1,t_MAT); /* rows dependant from the ones in matbnew */
        !          1802:   for (j=1; j<=col; j++)
        !          1803:   {
        !          1804:     GEN z = (GEN)extramat[j];
        !          1805:     p1 = cgetg(nlze+nr+1,t_COL); dep[j]=(long)p1;
        !          1806:     p2 = cgetg(lnz-nr,t_COL); matbnew[j]=(long)p2;
        !          1807:     for (i=1; i<=nlze; i++) p1[i]=zero;
        !          1808:     p1 += nlze; for (i=1; i<=nr; i++) p1[i] = z[permpro[i]];
        !          1809:     p2 -= nr;   for (   ; i<lnz; i++) p2[i] = z[permpro[i]];
        !          1810:   }
        !          1811:
        !          1812:   /* redundant generators in terms of the genuine generators
        !          1813:    * (x_i) = - (g_i) B */
        !          1814:   B = cgetg(co-col,t_MAT);
        !          1815:   for (j=col+1; j<co; j++)
        !          1816:   {
        !          1817:     GEN y = (GEN)matt[j];
        !          1818:     GEN z = (GEN)matb[j];
        !          1819:     p1=cgetg(lig+1,t_COL); B[j-col]=(long)p1;
        !          1820:     for (i=1; i<=nlze; i++) p1[i] = z[i];
        !          1821:     p1 += nlze; z += nlze-k0;
        !          1822:     for (k=1; k<lnz; k++)
        !          1823:     {
        !          1824:       i = permpro[k];
        !          1825:       p1[k] = (i <= k0)? y[i]: z[i];
        !          1826:     }
        !          1827:   }
        !          1828:   if (updateT) *ptC = gmul(*ptC,T);
        !          1829:   *ptdep = dep;
        !          1830:   *ptB = B;
        !          1831:   H = hnffinal(matbnew,perm,ptdep,ptB,ptC);
        !          1832:   gptr[0]=ptC;
        !          1833:   gptr[1]=ptdep;
        !          1834:   gptr[2]=ptB;
        !          1835:   gptr[3]=&H; gerepilemany(av,gptr,4);
        !          1836:   if (DEBUGLEVEL)
        !          1837:     msgtimer("hnfspec [%ld x %ld] --> [%ld x %ld]",li-1,co-1, lig-1,col-1);
        !          1838:   return H;
        !          1839: }
        !          1840:
        !          1841: /* HNF reduce x, apply same transforms to C */
        !          1842: GEN
        !          1843: mathnfspec(GEN x, GEN *ptperm, GEN *ptdep, GEN *ptB, GEN *ptC)
        !          1844: {
        !          1845:   long i,j,k,ly,lx = lg(x);
        !          1846:   GEN p1,p2,z,perm;
        !          1847:   if (lx == 1) return gcopy(x);
        !          1848:   ly = lg(x[1]);
        !          1849:   z = cgetg(lx,t_MAT);
        !          1850:   perm = cgetg(ly,t_VECSMALL); *ptperm = perm;
        !          1851:   for (i=1; i<ly; i++) perm[i] = i;
        !          1852:   for (i=1; i<lx; i++)
        !          1853:   {
        !          1854:     p1 = cgetg(ly,t_COL); z[i] = (long)p1;
        !          1855:     p2 = (GEN)x[i];
        !          1856:     for (j=1; j<ly; j++)
        !          1857:     {
        !          1858:       if (is_bigint(p2[j])) goto TOOLARGE;
        !          1859:       p1[j] = itos((GEN)p2[j]);
        !          1860:     }
        !          1861:   }
        !          1862:   /*  [ dep |     ]
        !          1863:    *  [-----|  B  ]
        !          1864:    *  [  H  |     ]
        !          1865:    *  [-----|-----]
        !          1866:    *  [  0  | Id  ] */
        !          1867:   return hnfspec((long**)z,perm, ptdep, ptB, ptC, 0);
        !          1868:
        !          1869: TOOLARGE:
        !          1870:   if (lg(*ptC) > 1 && lg((*ptC)[1]) > 1)
        !          1871:     err(impl,"mathnfspec with large entries");
        !          1872:   x = hnf(x); lx = lg(x); j = ly; k = 0;
        !          1873:   for (i=1; i<ly; i++)
        !          1874:   {
        !          1875:     if (gcmp1(gcoeff(x,i,i + lx-ly)))
        !          1876:       perm[--j] = i;
        !          1877:     else
        !          1878:       perm[++k] = i;
        !          1879:   }
        !          1880:   setlg(perm,k+1);
        !          1881:   x = rowextract_p(x, perm); /* upper part */
        !          1882:   setlg(perm,ly);
        !          1883:   *ptB = vecextract_i(x, j+lx-ly, lx-1);
        !          1884:   setlg(x, j);
        !          1885:   *ptdep = rowextract_i(x, 1, lx-ly);
        !          1886:   return rowextract_i(x, lx-ly+1, k); /* H */
        !          1887: }
        !          1888:
        !          1889: /* add new relations to a matrix treated by hnfspec (extramat / extraC) */
        !          1890: GEN
        !          1891: hnfadd(GEN H, GEN perm, GEN* ptdep, GEN* ptB, GEN* ptC, /* cf hnfspec */
        !          1892:        GEN extramat,GEN extraC)
        !          1893: {
        !          1894:   GEN p1,p2,p3,matb,extratop,Cnew,permpro;
        !          1895:   GEN B=*ptB, C=*ptC, dep=*ptdep, *gptr[4];
        !          1896:   long av = avma, i,j,lextra,colnew;
        !          1897:   long li = lg(perm);
        !          1898:   long co = lg(C);
        !          1899:   long lB = lg(B);
        !          1900:   long lig = li - lB;
        !          1901:   long col = co - lB;
        !          1902:   long lH = lg(H)-1;
        !          1903:   long nlze = lH? lg(dep[1])-1: lg(B[1])-1;
        !          1904:
        !          1905:   if (DEBUGLEVEL>5)
        !          1906:   {
        !          1907:     fprintferr("Entering hnfadd:\n");
        !          1908:     if (DEBUGLEVEL>6) fprintferr("extramat = %Z\n",extramat);
        !          1909:   }
        !          1910:  /*               col    co
        !          1911:   *       [ 0 |dep |     ]
        !          1912:   *  nlze [--------|  B  ]
        !          1913:   *       [ 0 | H  |     ]
        !          1914:   *       [--------|-----] lig
        !          1915:   *       [   0    | Id  ]
        !          1916:   *       [        |     ] li */
        !          1917:   lextra = lg(extramat)-1;
        !          1918:   extratop = cgetg(lextra+1,t_MAT); /* [1..lig] part (top) */
        !          1919:   p2 = cgetg(lextra+1,t_MAT); /* bottom */
        !          1920:   for (j=1; j<=lextra; j++)
        !          1921:   {
        !          1922:     GEN z = (GEN)extramat[j];
        !          1923:     p1=cgetg(lig+1,t_COL); extratop[j] = (long)p1;
        !          1924:     for (i=1; i<=lig; i++) p1[i] = z[i];
        !          1925:     p1=cgetg(lB,t_COL); p2[j] = (long)p1;
        !          1926:     p1 -= lig;
        !          1927:     for (   ; i<li; i++) p1[i] = z[i];
        !          1928:   }
        !          1929:   if (li-1 != lig)
        !          1930:   { /* zero out bottom part, using the Id block */
        !          1931:     GEN A = cgetg(lB,t_MAT);
        !          1932:     for (j=1; j<lB; j++) A[j] = C[j+col];
        !          1933:     extraC   = gsub(extraC,  gmul(A,p2));
        !          1934:     extratop = gsub(extratop,gmul(B,p2));
        !          1935:   }
        !          1936:
        !          1937:   colnew = lH + lextra;
        !          1938:   extramat = cgetg(colnew+1,t_MAT);
        !          1939:   Cnew = cgetg(lB+colnew,t_MAT);
        !          1940:   for (j=1; j<=lextra; j++)
        !          1941:   {
        !          1942:     extramat[j] = extratop[j];
        !          1943:     Cnew[j] = extraC[j];
        !          1944:   }
        !          1945:   for (   ; j<=colnew; j++)
        !          1946:   {
        !          1947:     p1 = cgetg(lig+1,t_COL); extramat[j] = (long)p1;
        !          1948:     p2 = (GEN)dep[j-lextra]; for (i=1; i<=nlze; i++) p1[i] = p2[i];
        !          1949:     p2 = (GEN)  H[j-lextra]; for (   ; i<=lig ; i++) p1[i] = p2[i-nlze];
        !          1950:   }
        !          1951:   for (j=lextra+1; j<lB+colnew; j++)
        !          1952:     Cnew[j] = C[j-lextra+col-lH];
        !          1953:   if (DEBUGLEVEL>5)
        !          1954:   {
        !          1955:     fprintferr("    1st phase done\n");
        !          1956:     if (DEBUGLEVEL>6) fprintferr("extramat = %Z\n",extramat);
        !          1957:   }
        !          1958:   permpro = imagecomplspec(extramat, &nlze);
        !          1959:   p1 = new_chunk(lig+1);
        !          1960:   for (i=1; i<=lig; i++) p1[i] = perm[permpro[i]];
        !          1961:   for (i=1; i<=lig; i++) perm[i] = p1[i];
        !          1962:
        !          1963:   matb = cgetg(colnew+1,t_MAT);
        !          1964:   dep = cgetg(colnew+1,t_MAT);
        !          1965:   for (j=1; j<=colnew; j++)
        !          1966:   {
        !          1967:     GEN z = (GEN)extramat[j];
        !          1968:     p1=cgetg(nlze+1,t_COL); dep[j]=(long)p1;
        !          1969:     p2=cgetg(lig+1-nlze,t_COL); matb[j]=(long)p2;
        !          1970:     p2 -= nlze;
        !          1971:     for (i=1; i<=nlze; i++) p1[i] = z[permpro[i]];
        !          1972:     for (   ; i<= lig; i++) p2[i] = z[permpro[i]];
        !          1973:   }
        !          1974:   p3 = cgetg(lB,t_MAT);
        !          1975:   for (j=1; j<lB; j++)
        !          1976:   {
        !          1977:     p2 = (GEN)B[j];
        !          1978:     p1 = cgetg(lig+1,t_COL); p3[j] = (long)p1;
        !          1979:     for (i=1; i<=lig; i++) p1[i] = p2[permpro[i]];
        !          1980:   }
        !          1981:   B = p3;
        !          1982:   if (DEBUGLEVEL>5) fprintferr("    2nd phase done\n");
        !          1983:   *ptdep = dep;
        !          1984:   *ptB = B;
        !          1985:   H = hnffinal(matb,perm,ptdep,ptB,&Cnew);
        !          1986:   p1 = cgetg(co+lextra,t_MAT);
        !          1987:   for (j=1; j <= col-lH; j++)   p1[j] = C[j];
        !          1988:   C = Cnew - (col-lH);
        !          1989:   for (   ; j < co+lextra; j++) p1[j] = C[j];
        !          1990:
        !          1991:   gptr[0]=ptC; *ptC=p1;
        !          1992:   gptr[1]=ptdep;
        !          1993:   gptr[2]=ptB;
        !          1994:   gptr[3]=&H; gerepilemany(av,gptr,4);
        !          1995:   if (DEBUGLEVEL)
        !          1996:   {
        !          1997:     if (DEBUGLEVEL>7) fprintferr("mit = %Z\nC = %Z\n",H,*ptC);
        !          1998:     msgtimer("hnfadd (%ld)",lextra);
        !          1999:   }
        !          2000:   return H;
        !          2001: }
        !          2002:
        !          2003: static void
        !          2004: ZV_neg(GEN x)
        !          2005: {
        !          2006:   long i, lx = lg(x);
        !          2007:   for (i=1; i<lx ; i++) x[i]=lnegi((GEN)x[i]);
        !          2008: }
        !          2009:
        !          2010: /* zero aj = Aij (!= 0)  using  ak = Aik (maybe 0), via linear combination of
        !          2011:  * A[j] and A[k] of determinant 1. If U != NULL, likewise update its columns */
        !          2012: static void
        !          2013: ZV_elem(GEN aj, GEN ak, GEN A, GEN U, long j, long k)
        !          2014: {
        !          2015:   GEN p1,u,v,d;
        !          2016:
        !          2017:   if (!signe(ak)) { swap(A[j],A[k]); if (U) swap(U[j],U[k]); return; }
        !          2018:   d = bezout(aj,ak,&u,&v);
        !          2019:   /* frequent special case (u,v) = (1,0) or (0,1) */
        !          2020:   if (!signe(u))
        !          2021:   { /* ak | aj */
        !          2022:     p1 = negi(divii(aj,ak));
        !          2023:     A[j]   = (long)ZV_lincomb(gun, p1, (GEN)A[j], (GEN)A[k]);
        !          2024:     if (U)
        !          2025:       U[j] = (long)ZV_lincomb(gun, p1, (GEN)U[j], (GEN)U[k]);
        !          2026:     return;
        !          2027:   }
        !          2028:   if (!signe(v))
        !          2029:   { /* aj | ak */
        !          2030:     p1 = negi(divii(ak,aj));
        !          2031:     A[k]   = (long)ZV_lincomb(gun, p1, (GEN)A[k], (GEN)A[j]);
        !          2032:     swap(A[j], A[k]);
        !          2033:     if (U) {
        !          2034:       U[k] = (long)ZV_lincomb(gun, p1, (GEN)U[k], (GEN)U[j]);
        !          2035:       swap(U[j], U[k]);
        !          2036:     }
        !          2037:     return;
        !          2038:   }
        !          2039:
        !          2040:   if (!is_pm1(d)) { aj = divii(aj,d); ak = divii(ak,d); }
        !          2041:   p1 = (GEN)A[k]; aj = negi(aj);
        !          2042:   A[k] = (long)ZV_lincomb(u,v, (GEN)A[j],p1);
        !          2043:   A[j] = (long)ZV_lincomb(aj,ak, p1,(GEN)A[j]);
        !          2044:   if (U)
        !          2045:   {
        !          2046:     p1 = (GEN)U[k];
        !          2047:     U[k] = (long)ZV_lincomb(u,v, (GEN)U[j],p1);
        !          2048:     U[j] = (long)ZV_lincomb(aj,ak, p1,(GEN)U[j]);
        !          2049:   }
        !          2050: }
        !          2051:
        !          2052: /* reduce A[i,j] mod A[i,j0] for j=j0+1... via column operations */
        !          2053: static void
        !          2054: ZM_reduce(GEN A, GEN U, long i, long j0)
        !          2055: {
        !          2056:   long j, lA = lg(A);
        !          2057:   GEN d = gcoeff(A,i,j0);
        !          2058:   if (signe(d) < 0)
        !          2059:   {
        !          2060:     ZV_neg((GEN)A[j0]);
        !          2061:     if (U) ZV_neg((GEN)U[j0]);
        !          2062:     d = gcoeff(A,i,j0);
        !          2063:   }
        !          2064:   for (j=j0+1; j<lA; j++)
        !          2065:   {
        !          2066:     GEN q = truedvmdii(gcoeff(A,i,j), d, NULL);
        !          2067:     if (!signe(q)) continue;
        !          2068:
        !          2069:     q = negi(q);
        !          2070:     A[j] = (long)ZV_lincomb(gun,q, (GEN)A[j], (GEN)A[j0]);
        !          2071:     if (U)
        !          2072:       U[j] = (long)ZV_lincomb(gun,q,(GEN)U[j],(GEN)U[j0]);
        !          2073:   }
        !          2074: }
        !          2075:
        !          2076: /* remove: throw away lin.dep.columns */
        !          2077: GEN
        !          2078: hnf0(GEN A, int remove)
        !          2079: {
        !          2080:   long av0 = avma, s,li,co,av,tetpil,i,j,k,def,ldef,lim;
        !          2081:   GEN denx,a,p1;
        !          2082:
        !          2083:   if (typ(A) == t_VEC) return hnf_special(A,remove);
        !          2084:   A = init_hnf(A,&denx,&co,&li,&av);
        !          2085:   if (!A) return cgetg(1,t_MAT);
        !          2086:
        !          2087:   lim = stack_lim(av,1);
        !          2088:   def=co-1; ldef=(li>co)? li-co: 0;
        !          2089:   for (i=li-1; i>ldef; i--)
        !          2090:   {
        !          2091:     for (j=def-1; j; j--)
        !          2092:     {
        !          2093:       a = gcoeff(A,i,j);
        !          2094:       if (!signe(a)) continue;
        !          2095:
        !          2096:       /* zero a = Aij  using  b = Aik */
        !          2097:       k = (j==1)? def: j-1;
        !          2098:       ZV_elem(a,gcoeff(A,i,k), A,NULL, j,k);
        !          2099:
        !          2100:       if (low_stack(lim, stack_lim(av,1)))
        !          2101:       {
        !          2102:         if (DEBUGMEM>1) err(warnmem,"hnf[1]. i=%ld",i);
        !          2103:         tetpil=avma; A=gerepile(av,tetpil,ZM_copy(A));
        !          2104:       }
        !          2105:     }
        !          2106:     p1 = gcoeff(A,i,def); s = signe(p1);
        !          2107:     if (s)
        !          2108:     {
        !          2109:       if (s < 0) ZV_neg((GEN)A[def]);
        !          2110:       ZM_reduce(A, NULL, i,def);
        !          2111:       def--;
        !          2112:     }
        !          2113:     else
        !          2114:       if (ldef) ldef--;
        !          2115:     if (low_stack(lim, stack_lim(av,1)))
        !          2116:     {
        !          2117:       if (DEBUGMEM>1) err(warnmem,"hnf[2]. i=%ld",i);
        !          2118:       tetpil=avma; A=gerepile(av,tetpil,ZM_copy(A));
        !          2119:     }
        !          2120:   }
        !          2121:   if (remove)
        !          2122:   {                            /* remove null columns */
        !          2123:     for (i=1,j=1; j<co; j++)
        !          2124:       if (!gcmp0((GEN)A[j])) A[i++] = A[j];
        !          2125:     setlg(A,i);
        !          2126:   }
        !          2127:   tetpil=avma;
        !          2128:   A = denx? gdiv(A,denx): ZM_copy(A);
        !          2129:   return gerepile(av0,tetpil,A);
        !          2130: }
        !          2131:
        !          2132: GEN
        !          2133: hnf(GEN x) { return hnf0(x,1); }
        !          2134:
        !          2135: /* dm = multiple of diag element (usually detint(x)) */
        !          2136: /* flag: don't/do append dm*matid. */
        !          2137: static GEN
        !          2138: allhnfmod(GEN x,GEN dm,int flag)
        !          2139: {
        !          2140:   ulong av,tetpil,lim;
        !          2141:   long li,co,i,j,k,def,ldef,ldm;
        !          2142:   GEN a,b,w,p1,p2,d,u,v;
        !          2143:
        !          2144:   if (typ(dm)!=t_INT) err(typeer,"allhnfmod");
        !          2145:   if (!signe(dm)) return hnf(x);
        !          2146:   if (typ(x)!=t_MAT) err(typeer,"allhnfmod");
        !          2147:
        !          2148:   co=lg(x); if (co==1) return cgetg(1,t_MAT);
        !          2149:   li=lg(x[1]);
        !          2150:   av = avma; lim = stack_lim(av,1);
        !          2151:   x = dummycopy(x);
        !          2152:
        !          2153:   if (flag)
        !          2154:   {
        !          2155:     if (li > co) err(talker,"nb lines > nb columns in hnfmod");
        !          2156:   }
        !          2157:   else
        !          2158:   { /* concatenate dm * Id to x */
        !          2159:     x = concatsp(x, idmat_intern(li-1,dm,gzero));
        !          2160:     co += li-1;
        !          2161:   }
        !          2162:   /* Avoid wasteful divisions. we only want to prevent coeff explosion, so
        !          2163:    * only reduce mod dm when lg(coeff) > ldm */
        !          2164:   ldm = lgefint(dm);
        !          2165:   def = co-1; ldef = 0;
        !          2166:   for (i=li-1; i>ldef; i--,def--)
        !          2167:     for (j=def-1; j; j--)
        !          2168:     {
        !          2169:       coeff(x,i,j) = lresii(gcoeff(x,i,j), dm);
        !          2170:       a = gcoeff(x,i,j);
        !          2171:       if (!signe(a)) continue;
        !          2172:
        !          2173:       k = (j==1)? def: j-1;
        !          2174:       /* do not reduce the appended dm [hnfmodid] */
        !          2175:       if (flag || j != 1) coeff(x,i,k) = lresii(gcoeff(x,i,k), dm);
        !          2176:       ZV_elem(a,gcoeff(x,i,k), x,NULL, j,k);
        !          2177:       p1 = (GEN)x[j];
        !          2178:       p2 = (GEN)x[k];
        !          2179:       for (k=1; k<i; k++)
        !          2180:       {
        !          2181:         if (lgefint(p1[k]) > ldm) p1[k] = lresii((GEN)p1[k], dm);
        !          2182:         if (lgefint(p2[k]) > ldm) p2[k] = lresii((GEN)p2[k], dm);
        !          2183:       }
        !          2184:       if (low_stack(lim, stack_lim(av,1)))
        !          2185:       {
        !          2186:         if (DEBUGMEM>1) err(warnmem,"allhnfmod[1]. i=%ld",i);
        !          2187:        tetpil=avma; x=gerepile(av,tetpil,ZM_copy(x));
        !          2188:       }
        !          2189:     }
        !          2190:   w = cgetg(li,t_MAT); b = dm;
        !          2191:   for (i=li-1; i>=1; i--)
        !          2192:   {
        !          2193:     d = bezout(gcoeff(x,i,i+def),b,&u,&v);
        !          2194:     w[i] = lmod(gmul(u,(GEN)x[i+def]), b);
        !          2195:     if (!signe(gcoeff(w,i,i))) coeff(w,i,i) = (long)d;
        !          2196:     if (flag && i > 1) b = diviiexact(b,d);
        !          2197:   }
        !          2198:   if (flag)
        !          2199:   { /* compute optimal value for dm */
        !          2200:     dm = gcoeff(w,1,1);
        !          2201:     for (i=2; i<li; i++) dm = mpppcm(dm, gcoeff(w,i,i));
        !          2202:     ldm = lgefint(dm);
        !          2203:   }
        !          2204:   for (i=li-2; i>=1; i--)
        !          2205:   {
        !          2206:     GEN diag = gcoeff(w,i,i);
        !          2207:     for (j=i+1; j<li; j++)
        !          2208:     {
        !          2209:       b = negi(truedvmdii(gcoeff(w,i,j), diag, NULL));
        !          2210:       p1 = ZV_lincomb(gun,b, (GEN)w[j], (GEN)w[i]);
        !          2211:       w[j] = (long)p1;
        !          2212:       for (k=1; k<i; k++)
        !          2213:         if (lgefint(p1[k]) > ldm) p1[k] = lresii((GEN)p1[k], dm);
        !          2214:       if (low_stack(lim, stack_lim(av,1)))
        !          2215:       {
        !          2216:         if (DEBUGMEM>1) err(warnmem,"allhnfmod[2]. i=%ld", i);
        !          2217:         tetpil=avma; w=gerepile(av,tetpil,ZM_copy(w));
        !          2218:         diag = gcoeff(w,i,i);
        !          2219:       }
        !          2220:     }
        !          2221:   }
        !          2222:   tetpil=avma; return gerepile(av,tetpil,ZM_copy(w));
        !          2223: }
        !          2224:
        !          2225: GEN
        !          2226: hnfmod(GEN x, GEN detmat) { return allhnfmod(x,detmat,1); }
        !          2227:
        !          2228: GEN
        !          2229: hnfmodid(GEN x, GEN p) { return allhnfmod(x,p,0); }
        !          2230:
        !          2231: /***********************************************************************/
        !          2232: /*                                                                     */
        !          2233: /*                 HNFLLL (Havas, Majewski, Mathews)                   */
        !          2234: /*                                                                     */
        !          2235: /***********************************************************************/
        !          2236:
        !          2237: /* negate in place, except universal constants */
        !          2238: static GEN
        !          2239: mynegi(GEN x)
        !          2240: {
        !          2241:   static long mun[]={evaltyp(t_INT)|m_evallg(3),evalsigne(-1)|evallgefint(3),1};
        !          2242:   long s = signe(x);
        !          2243:
        !          2244:   if (!s) return gzero;
        !          2245:   if (is_pm1(x))
        !          2246:     return (s>0)? mun: gun;
        !          2247:   setsigne(x,-s); return x;
        !          2248: }
        !          2249:
        !          2250: /* We assume y > 0 */
        !          2251: static GEN
        !          2252: divnearest(GEN x, GEN y)
        !          2253: {
        !          2254:   GEN r, q = dvmdii(x,y,&r);
        !          2255:   long av = avma, s=signe(r), t;
        !          2256:
        !          2257:   if (!s) { cgiv(r); return q; }
        !          2258:   if (s<0) r = mynegi(r);
        !          2259:
        !          2260:   y = shifti(y,-1); t = cmpii(r,y);
        !          2261:   avma=av; cgiv(r);
        !          2262:   if (t < 0 || (t == 0 && s > 0)) return q;
        !          2263:   return addsi(s,q);
        !          2264: }
        !          2265:
        !          2266: static void
        !          2267: Minus(long j, GEN **lambda)
        !          2268: {
        !          2269:   long k, n = lg(lambda);
        !          2270:
        !          2271:   for (k=1  ; k<j; k++) lambda[j][k] = mynegi(lambda[j][k]);
        !          2272:   for (k=j+1; k<n; k++) lambda[k][j] = mynegi(lambda[k][j]);
        !          2273: }
        !          2274:
        !          2275: static void
        !          2276: neg_col(GEN M)
        !          2277: {
        !          2278:   long i;
        !          2279:   for (i = lg(M)-1; i; i--)
        !          2280:     M[i] = (long)mynegi((GEN)M[i]);
        !          2281: }
        !          2282:
        !          2283: /* M_k = M_k + q M_i  (col operations) */
        !          2284: static void
        !          2285: elt_col(GEN Mk, GEN Mi, GEN q)
        !          2286: {
        !          2287:   long j;
        !          2288:   if (is_pm1(q))
        !          2289:   {
        !          2290:     if (signe(q) > 0)
        !          2291:     {
        !          2292:       for (j = lg(Mk)-1; j; j--)
        !          2293:         if (signe(Mi[j])) Mk[j] = laddii((GEN)Mk[j], (GEN)Mi[j]);
        !          2294:     }
        !          2295:     else
        !          2296:     {
        !          2297:       for (j = lg(Mk)-1; j; j--)
        !          2298:         if (signe(Mi[j])) Mk[j] = lsubii((GEN)Mk[j], (GEN)Mi[j]);
        !          2299:     }
        !          2300:   }
        !          2301:   else
        !          2302:     for (j = lg(Mk)-1; j; j--)
        !          2303:       if (signe(Mi[j])) Mk[j] = laddii((GEN)Mk[j], mulii(q, (GEN)Mi[j]));
        !          2304: }
        !          2305:
        !          2306: /* index of first non-zero entry */
        !          2307: static long
        !          2308: findi(GEN M)
        !          2309: {
        !          2310:   long i, n = lg(M);
        !          2311:   for (i=1; i<n; i++)
        !          2312:     if (signe(M[i])) return i;
        !          2313:   return 0;
        !          2314: }
        !          2315:
        !          2316: static void
        !          2317: reduce2(GEN A, GEN B, long k, long j, long *row, GEN **lambda, GEN *D)
        !          2318: {
        !          2319:   GEN q;
        !          2320:   long i, row0, row1;
        !          2321:
        !          2322:   row0 = findi((GEN)A[j]);
        !          2323:   if (row0 && signe(gcoeff(A,row0,j)) < 0)
        !          2324:   {
        !          2325:     neg_col((GEN)A[j]);
        !          2326:     if (B) neg_col((GEN)B[j]);
        !          2327:     Minus(j,lambda);
        !          2328:   }
        !          2329:
        !          2330:   row1 = findi((GEN)A[k]);
        !          2331:   if (row1 && signe(gcoeff(A,row1,k)) < 0)
        !          2332:   {
        !          2333:     neg_col((GEN)A[k]);
        !          2334:     if (B) neg_col((GEN)B[k]);
        !          2335:     Minus(k,lambda);
        !          2336:   }
        !          2337:
        !          2338:   row[0]=row0; row[1]=row1;
        !          2339:   if (row0)
        !          2340:     q = truedvmdii(gcoeff(A,row0,k), gcoeff(A,row0,j), NULL);
        !          2341:   else if (absi_cmp(shifti(lambda[k][j], 1), D[j]) > 0)
        !          2342:     q = divnearest(lambda[k][j], D[j]);
        !          2343:   else
        !          2344:     return;
        !          2345:
        !          2346:   if (signe(q))
        !          2347:   {
        !          2348:     GEN *Lk = lambda[k], *Lj = lambda[j];
        !          2349:     q = mynegi(q);
        !          2350:     if (row0) elt_col((GEN)A[k],(GEN)A[j],q);
        !          2351:     if (B) elt_col((GEN)B[k],(GEN)B[j],q);
        !          2352:     Lk[j] = addii(Lk[j], mulii(q,D[j]));
        !          2353:     if (is_pm1(q))
        !          2354:     {
        !          2355:       if (signe(q) > 0)
        !          2356:       {
        !          2357:         for (i=1; i<j; i++)
        !          2358:           if (signe(Lj[i])) Lk[i] = addii(Lk[i], Lj[i]);
        !          2359:       }
        !          2360:       else
        !          2361:       {
        !          2362:         for (i=1; i<j; i++)
        !          2363:           if (signe(Lj[i])) Lk[i] = subii(Lk[i], Lj[i]);
        !          2364:       }
        !          2365:     }
        !          2366:     else
        !          2367:     {
        !          2368:       for (i=1; i<j; i++)
        !          2369:         if (signe(Lj[i])) Lk[i] = addii(Lk[i], mulii(q,Lj[i]));
        !          2370:     }
        !          2371:   }
        !          2372: }
        !          2373:
        !          2374: #define SWAP(x,y) {GEN _t=y; y=x; x=_t;}
        !          2375:
        !          2376: static void
        !          2377: hnfswap(GEN A, GEN B, long k, GEN **lambda, GEN *D)
        !          2378: {
        !          2379:   GEN t,p1,p2;
        !          2380:   long i,j,n = lg(A);
        !          2381:
        !          2382:   swap(A[k],A[k-1]);
        !          2383:   if (B) swap(B[k],B[k-1]);
        !          2384:   for (j=k-2; j; j--) SWAP(lambda[k-1][j], lambda[k][j]);
        !          2385:   for (i=k+1; i<n; i++)
        !          2386:   {
        !          2387:     p1 = mulii(lambda[i][k-1], D[k]);
        !          2388:     p2 = mulii(lambda[i][k], lambda[k][k-1]);
        !          2389:     t = subii(p1,p2);
        !          2390:
        !          2391:     p1 = mulii(lambda[i][k], D[k-2]);
        !          2392:     p2 = mulii(lambda[i][k-1], lambda[k][k-1]);
        !          2393:     lambda[i][k-1] = divii(addii(p1,p2), D[k-1]);
        !          2394:
        !          2395:     lambda[i][k] = divii(t, D[k-1]);
        !          2396:   }
        !          2397:   p1 = mulii(D[k-2],D[k]);
        !          2398:   p2 = sqri(lambda[k][k-1]);
        !          2399:   D[k-1] = divii(addii(p1,p2), D[k-1]);
        !          2400: }
        !          2401:
        !          2402: /* A[k] = 0,  A[nz] != 0,  k > nz,  A[j] = 0 for all j < nz.
        !          2403:  * "Deep insert" A[k] at nz */
        !          2404: static void
        !          2405: trivswap(GEN *A, long nz, long k, GEN **lambda, GEN *D)
        !          2406: {
        !          2407:   GEN p1;
        !          2408:   long i,j,n = lg(A);
        !          2409:
        !          2410:   p1 = A[nz]; /* cycle A */
        !          2411:   for (j = nz; j < k; j++) SWAP(A[j+1], p1);
        !          2412:   A[nz] = p1; /* = [0...0] */
        !          2413:
        !          2414:   p1 = D[nz]; /* cycle D */
        !          2415:   for (j = nz; j < k; j++) SWAP(D[j+1], p1);
        !          2416:   D[nz] = gun;
        !          2417:
        !          2418:   for (j=k-1; j>=nz; j--) /* cycle lambda */
        !          2419:     for (i=k-1; i>=nz; i--) lambda[i+1][j+1] = lambda[i][j];
        !          2420:   for (j=n-1; j>k; j--)
        !          2421:     for (i=k-1; i>=nz; i--)
        !          2422:     {
        !          2423:       lambda[i+1][j] = lambda[i][j];
        !          2424:       lambda[j][i+1] = lambda[j][i];
        !          2425:     }
        !          2426:   for (i=1; i<n; i++) lambda[nz][i] = lambda[i][nz] = gzero;
        !          2427: }
        !          2428:
        !          2429: static GEN
        !          2430: fix_rows(GEN A)
        !          2431: {
        !          2432:   long i,j, h,n = lg(A);
        !          2433:   GEN cB,cA,B = cgetg(n,t_MAT);
        !          2434:   if (n == 1) return B;
        !          2435:   h = lg(A[1]);
        !          2436:   for (j=1; j<n; j++)
        !          2437:   {
        !          2438:     cB = cgetg(h, t_COL);
        !          2439:     cA = (GEN)A[j]; B[j] = (long)cB;
        !          2440:     for (i=h>>1; i; i--) { cB[h-i] = cA[i]; cB[i] = cA[h-i]; }
        !          2441:   }
        !          2442:   return B;
        !          2443: }
        !          2444:
        !          2445: GEN
        !          2446: hnflll_i(GEN A, GEN *ptB)
        !          2447: {
        !          2448:   ulong av = avma, lim = stack_lim(av,3);
        !          2449:   long m1 = 1, n1 = 1; /* alpha = m1/n1. Maybe 3/4 here ? */
        !          2450:   long row[2], do_swap,i,n,k;
        !          2451:   long nzcol = 1; /* index of 1st (maybe) non-0 col [only updated when !B] */
        !          2452:   GEN z,B, **lambda, *D;
        !          2453:   GEN *gptr[4];
        !          2454:
        !          2455:   if (typ(A) != t_MAT) err(typeer,"hnflll");
        !          2456:   n = lg(A);
        !          2457:   A = ZM_copy(fix_rows(A));
        !          2458:   B = ptB? idmat(n-1): NULL;
        !          2459:   D = (GEN*) cgetg(n+1, t_VEC); D++; /* hack: need a "sentinel" D[0] */
        !          2460:   if (n == 2) /* handle trivial case: return negative diag coeff otherwise */
        !          2461:   {
        !          2462:     i = findi((GEN)A[1]);
        !          2463:     if (i && signe(gcoeff(A,i,1)) < 0)
        !          2464:     {
        !          2465:       neg_col((GEN)A[1]);
        !          2466:       if (B) neg_col((GEN)B[1]);
        !          2467:     }
        !          2468:   }
        !          2469:   lambda = (GEN**) cgetg(n,t_MAT);
        !          2470:   for (i=1; i<n; i++) { D[i] = gun; lambda[i] = (GEN*)zerocol(n-1); }
        !          2471:   D[0] = gun; k = 2;
        !          2472:   while (k < n)
        !          2473:   {
        !          2474:     reduce2(A,B,k,k-1,row,lambda,D);
        !          2475:     if (!B)
        !          2476:     { /* not interested in B. Eliminate 0 cols */
        !          2477:       if (!row[0] || !row[1])
        !          2478:       {
        !          2479:         while (!findi((GEN)A[nzcol]) && nzcol < n) nzcol++;
        !          2480:         /* A[nzcol] != 0,  A[i] = 0 for i < nzcol */
        !          2481:         if (!row[0] && k-1 > nzcol)
        !          2482:           {trivswap((GEN*)A,nzcol,k-1, lambda,D); nzcol++;}
        !          2483:         if (!row[1] && k   > nzcol)
        !          2484:           {trivswap((GEN*)A,nzcol,k  , lambda,D); nzcol++;}
        !          2485:         if (k <= nzcol) k = nzcol+1;
        !          2486:         continue;
        !          2487:       }
        !          2488:       do_swap = (row[0] && row[0] <= row[1]);
        !          2489:     }
        !          2490:     else
        !          2491:     {
        !          2492:       if (row[0])
        !          2493:         do_swap = (!row[1] || row[0] <= row[1]);
        !          2494:       else if (row[1])
        !          2495:         do_swap = 0;
        !          2496:       else
        !          2497:       { /* row[0] == row[1] == 0 */
        !          2498:         ulong av1 = avma;
        !          2499:         z = addii(mulii(D[k-2],D[k]), sqri(lambda[k][k-1]));
        !          2500:         do_swap = (cmpii(mulsi(n1,z), mulsi(m1,sqri(D[k-1]))) < 0);
        !          2501:         avma = av1;
        !          2502:       }
        !          2503:     }
        !          2504:     if (do_swap)
        !          2505:     {
        !          2506:       hnfswap(A,B,k,lambda,D);
        !          2507:       if (k > nzcol+1) k--;
        !          2508:     }
        !          2509:     else
        !          2510:     {
        !          2511:       for (i=k-2; i>=nzcol; i--) reduce2(A,B,k,i,row,lambda,D);
        !          2512:       k++;
        !          2513:     }
        !          2514:     if (low_stack(lim, stack_lim(av,3)))
        !          2515:     {
        !          2516:       GEN a = (GEN)lambda, b = (GEN)(D-1); /* gcc -Wall */
        !          2517:       gptr[0]=&A; gptr[1]=&a; gptr[2]=&b; gptr[3]=&B;
        !          2518:       if (DEBUGMEM) err(warnmem,"hnflll, k = %ld / %ld",k,n);
        !          2519:       gerepilemany(av,gptr,B? 4: 3); lambda = (GEN**)a; D = (GEN*)(b+1);
        !          2520:     }
        !          2521:   }
        !          2522:   for (i=nzcol; i<n; i++)
        !          2523:     if (findi((GEN)A[i])) break;
        !          2524:   i--; A += i; A[0] = evaltyp(t_MAT)|evallg(n-i);
        !          2525:   A = fix_rows(A);
        !          2526:   gptr[0] = &A; gptr[1] = &B;
        !          2527:   gerepilemany(av, gptr, B? 2: 1);
        !          2528:   if (B) *ptB = B;
        !          2529:   return A;
        !          2530: }
        !          2531:
        !          2532: GEN
        !          2533: hnflll(GEN A)
        !          2534: {
        !          2535:   GEN B, z = cgetg(3, t_VEC);
        !          2536:   z[1] = (long)hnflll_i(A, &B);
        !          2537:   z[2] = (long)B; return z;
        !          2538: }
        !          2539:
        !          2540: /* Variation on HNFLLL: Extended GCD */
        !          2541:
        !          2542: static void
        !          2543: reduce1(GEN A, GEN B, long k, long j, GEN **lambda, GEN *D)
        !          2544: {
        !          2545:   GEN q;
        !          2546:   long i;
        !          2547:
        !          2548:   if (signe(A[j]))
        !          2549:     q = divnearest((GEN)A[k],(GEN)A[j]);
        !          2550:   else if (absi_cmp(shifti(lambda[k][j], 1), D[j]) > 0)
        !          2551:     q = divnearest(lambda[k][j], D[j]);
        !          2552:   else
        !          2553:     return;
        !          2554:
        !          2555:   if (! gcmp0(q))
        !          2556:   {
        !          2557:     q = mynegi(q);
        !          2558:     A[k] = laddii((GEN)A[k], mulii(q,(GEN)A[j]));
        !          2559:     elt_col((GEN)B[k],(GEN)B[j],q);
        !          2560:     lambda[k][j] = addii(lambda[k][j], mulii(q,D[j]));
        !          2561:     for (i=1; i<j; i++)
        !          2562:       if (signe(lambda[j][i]))
        !          2563:         lambda[k][i] = addii(lambda[k][i], mulii(q,lambda[j][i]));
        !          2564:   }
        !          2565: }
        !          2566:
        !          2567: GEN
        !          2568: extendedgcd(GEN A)
        !          2569: {
        !          2570:   long m1 = 1, n1 = 1; /* alpha = m1/n1. Maybe 3/4 here ? */
        !          2571:   long av = avma, tetpil, do_swap,i,j,n,k;
        !          2572:   GEN p1,p2,B, **lambda, *D;
        !          2573:
        !          2574:   n = lg(A); B = idmat(n-1); A = ZM_copy(A);
        !          2575:   D = (GEN*) cgeti(n); lambda = (GEN**) cgetg(n,t_MAT);
        !          2576:   for (i=0; i<n; i++) D[i] = gun;
        !          2577:   for (i=1; i<n; i++)
        !          2578:   {
        !          2579:     lambda[i] = (GEN*) cgetg(n,t_COL);
        !          2580:     for(j=1;j<n;j++) lambda[i][j] = gzero;
        !          2581:   }
        !          2582:   k = 2;
        !          2583:   while (k < n)
        !          2584:   {
        !          2585:     reduce1(A,B,k,k-1,lambda,D);
        !          2586:     if (signe(A[k-1])) do_swap = 1;
        !          2587:     else if (!signe(A[k]))
        !          2588:     {
        !          2589:       long av1=avma;
        !          2590:       p1 = addii(mulii(D[k-2],D[k]), sqri(lambda[k][k-1]));
        !          2591:       p1 = mulsi(n1,p1);
        !          2592:       p2 = mulsi(m1,sqri(D[k-1]));
        !          2593:       do_swap = (cmpii(p1,p2) < 0);
        !          2594:       avma=av1;
        !          2595:     }
        !          2596:     else do_swap = 0;
        !          2597:
        !          2598:     if (do_swap)
        !          2599:     {
        !          2600:       hnfswap(A,B,k,lambda,D);
        !          2601:       if (k>2) k--;
        !          2602:     }
        !          2603:     else
        !          2604:     {
        !          2605:       for (i=k-2; i; i--) reduce1(A,B,k,i,lambda,D);
        !          2606:       k++;
        !          2607:     }
        !          2608:   }
        !          2609:   if (signe(A[n-1])<0)
        !          2610:   {
        !          2611:     A[n-1] = (long)mynegi((GEN)A[n-1]);
        !          2612:     neg_col((GEN)B[n-1]);
        !          2613:   }
        !          2614:   tetpil = avma;
        !          2615:   p1 = cgetg(3,t_VEC);
        !          2616:   p1[1]=lcopy((GEN)A[n-1]);
        !          2617:   p1[2]=lcopy(B);
        !          2618:   return gerepile(av,tetpil,p1);
        !          2619: }
        !          2620:
        !          2621: /* HNF with permutation. TODO: obsolete, replace with hnflll. */
        !          2622: GEN
        !          2623: hnfperm(GEN A)
        !          2624: {
        !          2625:   GEN U,c,l,perm,d,u,p,q,y,b;
        !          2626:   long r,t,i,j,j1,k,m,n,av=avma,av1,tetpil,lim;
        !          2627:
        !          2628:   if (typ(A) != t_MAT) err(typeer,"hnfperm");
        !          2629:   n = lg(A)-1;
        !          2630:   if (!n)
        !          2631:   {
        !          2632:     y = cgetg(4,t_VEC);
        !          2633:     y[1] = lgetg(1,t_MAT);
        !          2634:     y[2] = lgetg(1,t_MAT);
        !          2635:     y[3] = lgetg(1,t_VEC); return y;
        !          2636:   }
        !          2637:   m = lg(A[1])-1;
        !          2638:   c = cgetg(m+1,t_VECSMALL); for (i=1; i<=m; i++) c[i]=0;
        !          2639:   l = cgetg(n+1,t_VECSMALL); for (j=1; j<=n; j++) l[j]=0;
        !          2640:   perm = cgetg(m+1, t_VECSMALL);
        !          2641:   av1 = avma; lim = stack_lim(av1,1);
        !          2642:   U = idmat(n); A = dummycopy(A); /* U base change matrix : A0*U=A all along */
        !          2643:   for (r=0,k=1; k<=n; k++)
        !          2644:   {
        !          2645:     for (j=1; j<k; j++)
        !          2646:     {
        !          2647:       if (!l[j]) continue;
        !          2648:       t=l[j]; b=gcoeff(A,t,k);
        !          2649:       if (!signe(b)) continue;
        !          2650:
        !          2651:       ZV_elem(b,gcoeff(A,t,j), A,U,k,j);
        !          2652:       d = gcoeff(A,t,j);
        !          2653:       if (signe(d) < 0)
        !          2654:       {
        !          2655:         ZV_neg((GEN)A[j]);
        !          2656:         ZV_neg((GEN)U[j]);
        !          2657:         d = gcoeff(A,t,j);
        !          2658:       }
        !          2659:       for (j1=1; j1<j; j1++)
        !          2660:       {
        !          2661:         if (!l[j1]) continue;
        !          2662:         q = truedvmdii(gcoeff(A,t,j1),d,NULL);
        !          2663:         if (!signe(q)) continue;
        !          2664:
        !          2665:         q = negi(q);
        !          2666:         A[j1] = (long)ZV_lincomb(gun,q,(GEN)A[j1],(GEN)A[j]);
        !          2667:         U[j1] = (long)ZV_lincomb(gun,q,(GEN)U[j1],(GEN)U[j]);
        !          2668:       }
        !          2669:     }
        !          2670:     t=m; while (t && (c[t] || !signe(gcoeff(A,t,k)))) t--;
        !          2671:     if (t)
        !          2672:     {
        !          2673:       p = gcoeff(A,t,k);
        !          2674:       for (i=t-1; i; i--)
        !          2675:       {
        !          2676:         q = gcoeff(A,i,k);
        !          2677:        if (signe(q) && absi_cmp(p,q) > 0) { p=q; t=i; }
        !          2678:       }
        !          2679:       perm[++r]=l[k]=t; c[t]=k;
        !          2680:       if (signe(p) < 0)
        !          2681:       {
        !          2682:         ZV_neg((GEN)A[k]);
        !          2683:         ZV_neg((GEN)U[k]);
        !          2684:        p = gcoeff(A,t,k);
        !          2685:       }
        !          2686:       for (j=1; j<k; j++)
        !          2687:       {
        !          2688:         if (!l[j]) continue;
        !          2689:        q = truedvmdii(gcoeff(A,t,j),p,NULL);
        !          2690:        if (!signe(q)) continue;
        !          2691:
        !          2692:         q = negi(q);
        !          2693:         A[j] = (long)ZV_lincomb(gun,q,(GEN)A[j],(GEN)A[k]);
        !          2694:         U[j] = (long)ZV_lincomb(gun,q,(GEN)U[j],(GEN)U[k]);
        !          2695:       }
        !          2696:     }
        !          2697:     if (low_stack(lim, stack_lim(av1,1)))
        !          2698:     {
        !          2699:       GEN *gptr[2]; gptr[0]=&A; gptr[1]=&U;
        !          2700:       if (DEBUGMEM>1) err(warnmem,"hnfperm");
        !          2701:       gerepilemany(av1,gptr,2);
        !          2702:     }
        !          2703:   }
        !          2704:   if (r < m)
        !          2705:   {
        !          2706:     for (i=1,k=r; i<=m; i++)
        !          2707:       if (c[i]==0) perm[++k] = i;
        !          2708:   }
        !          2709:
        !          2710: /* We have A0*U=A, U in Gl(n,Z)
        !          2711:  * basis for Im(A):  columns of A s.t l[j]>0 (r   cols)
        !          2712:  * basis for Ker(A): columns of U s.t l[j]=0 (n-r cols)
        !          2713:  */
        !          2714:   tetpil=avma; y=cgetg(4,t_VEC);
        !          2715:   p=cgetg(r+1,t_MAT); u=cgetg(n+1,t_MAT);
        !          2716:   for (t=1,k=r,j=1; j<=n; j++)
        !          2717:     if (l[j])
        !          2718:     {
        !          2719:       q=cgetg(m+1,t_COL); p[k]=(long)q;
        !          2720:       for (i=1; i<=m; i++) q[i]=lcopy(gcoeff(A,perm[m-i+1],j));
        !          2721:       u[k+n-r]=lcopy((GEN)U[j]);
        !          2722:       k--;
        !          2723:     }
        !          2724:     else u[t++]=lcopy((GEN)U[j]);
        !          2725:   y[1]=(long)p; y[2]=(long)u;
        !          2726:   q = cgetg(m+1,t_VEC); y[3]=(long)q;
        !          2727:   for (i=1; i<=m; i++) q[m-i+1]=lstoi(perm[i]);
        !          2728:   return gerepile(av,tetpil,y);
        !          2729: }
        !          2730:
        !          2731: /*====================================================================
        !          2732:  *         Forme Normale d'Hermite (Version par colonnes 31/01/94)
        !          2733:  *====================================================================*/
        !          2734: GEN
        !          2735: hnfall_i(GEN A, GEN *ptB, long remove)
        !          2736: {
        !          2737:   GEN B,c,h,x,p,a;
        !          2738:   long m,n,r,i,j,k,li,av=avma,av1,tetpil,lim;
        !          2739:   GEN *gptr[2];
        !          2740:
        !          2741:   if (typ(A)!=t_MAT) err(typeer,"hnfall");
        !          2742:   n=lg(A)-1;
        !          2743:   if (!n)
        !          2744:   {
        !          2745:     if (ptB) *ptB = cgetg(1,t_MAT);
        !          2746:     return cgetg(1,t_MAT);
        !          2747:   }
        !          2748:   m = lg(A[1])-1;
        !          2749:   c = cgetg(m+1,t_VECSMALL); for (i=1; i<=m; i++) c[i]=0;
        !          2750:   h = cgetg(n+1,t_VECSMALL); for (j=1; j<=n; j++) h[j]=m;
        !          2751:   av1 = avma; lim = stack_lim(av1,1);
        !          2752:   A = dummycopy(A);
        !          2753:   B = ptB? idmat(n): NULL;
        !          2754:   r = n+1;
        !          2755:   for (li=m; li; li--)
        !          2756:   {
        !          2757:     for (j=1; j<r; j++)
        !          2758:     {
        !          2759:       for (i=h[j]; i>li; i--)
        !          2760:       {
        !          2761:         a = gcoeff(A,i,j);
        !          2762:        if (!signe(a)) continue;
        !          2763:
        !          2764:         k = c[i]; /* zero a = Aij  using  Aik */
        !          2765:         ZV_elem(a,gcoeff(A,i,k), A,B,j,k);
        !          2766:         ZM_reduce(A,B, i,k);
        !          2767:         if (low_stack(lim, stack_lim(av1,1)))
        !          2768:         {
        !          2769:           tetpil = avma;
        !          2770:           A = ZM_copy(A); gptr[0]=&A;
        !          2771:           if (B) { B = ZM_copy(B); gptr[1]=&B; }
        !          2772:           if (DEBUGMEM>1) err(warnmem,"hnfall[1], li = %ld", li);
        !          2773:           gerepilemanysp(av1,tetpil,gptr,B? 2: 1);
        !          2774:         }
        !          2775:       }
        !          2776:       x = gcoeff(A,li,j); if (signe(x)) break;
        !          2777:       h[j] = li-1;
        !          2778:     }
        !          2779:     if (j == r) continue;
        !          2780:     r--;
        !          2781:     if (j < r) /* A[j] != 0 */
        !          2782:     {
        !          2783:       swap(A[j], A[r]);
        !          2784:       if (B) swap(B[j], B[r]);
        !          2785:       h[j]=h[r]; h[r]=li; c[li]=r;
        !          2786:     }
        !          2787:     p = gcoeff(A,li,r);
        !          2788:     if (signe(p) < 0)
        !          2789:     {
        !          2790:       ZV_neg((GEN)A[r]);
        !          2791:       if (B) ZV_neg((GEN)B[r]);
        !          2792:       p = gcoeff(A,li,r);
        !          2793:     }
        !          2794:     ZM_reduce(A,B, li,r);
        !          2795:     if (low_stack(lim, stack_lim(av1,1)))
        !          2796:     {
        !          2797:       GEN *gptr[2]; gptr[0]=&A; gptr[1]=&B;
        !          2798:       if (DEBUGMEM>1) err(warnmem,"hnfall[2], li = %ld", li);
        !          2799:       gerepilemany(av1,gptr,B? 2: 1);
        !          2800:     }
        !          2801:   }
        !          2802:   if (DEBUGLEVEL>5) fprintferr("\nhnfall, final phase: ");
        !          2803:   r--; /* first r cols are in the image the n-r (independent) last ones */
        !          2804:   for (j=1; j<=r; j++)
        !          2805:     for (i=h[j]; i; i--)
        !          2806:     {
        !          2807:       a = gcoeff(A,i,j);
        !          2808:       if (!signe(a)) continue;
        !          2809:
        !          2810:       k = c[i];
        !          2811:       ZV_elem(a,gcoeff(A,i,k), A,B, j,k);
        !          2812:       ZM_reduce(A,B, i,k);
        !          2813:       if (low_stack(lim, stack_lim(av1,1)))
        !          2814:       {
        !          2815:         tetpil = avma;
        !          2816:         A = ZM_copy(A); gptr[0]=&A;
        !          2817:         if (B) { B = ZM_copy(B); gptr[1]=&B; }
        !          2818:         if (DEBUGMEM>1) err(warnmem,"hnfall[3], j = %ld", j);
        !          2819:         gerepilemanysp(av1,tetpil,gptr, B? 2: 1);
        !          2820:       }
        !          2821:     }
        !          2822:   if (DEBUGLEVEL>5) fprintferr("\n");
        !          2823:   /* remove the first r columns */
        !          2824:   if (remove) { A += r; A[0] = evaltyp(t_MAT) | evallg(n-r+1); }
        !          2825:   gptr[0] = &A; gptr[1] = &B;
        !          2826:   gerepilemany(av, gptr, B? 2: 1);
        !          2827:   if (B) *ptB = B;
        !          2828:   return A;
        !          2829: }
        !          2830:
        !          2831: GEN
        !          2832: hnfall0(GEN A, long remove)
        !          2833: {
        !          2834:   GEN B, z = cgetg(3, t_VEC);
        !          2835:   z[1] = (long)hnfall_i(A, &B, remove);
        !          2836:   z[2] = (long)B; return z;
        !          2837: }
        !          2838:
        !          2839: GEN
        !          2840: hnfall(GEN x) {return hnfall0(x,1);}
        !          2841:
        !          2842: /***************************************************************/
        !          2843: /**                                                          **/
        !          2844: /**                SMITH NORMAL FORM REDUCTION               **/
        !          2845: /**                                                          **/
        !          2846: /***************************************************************/
        !          2847:
        !          2848: static GEN
        !          2849: col_mul(GEN x, GEN c)
        !          2850: {
        !          2851:   long s = signe(x);
        !          2852:   GEN xc = NULL;
        !          2853:   if (s)
        !          2854:   {
        !          2855:     if (!is_pm1(x)) xc = gmul(x,c);
        !          2856:     else xc = (s>0)? c: gneg_i(c);
        !          2857:   }
        !          2858:   return xc;
        !          2859: }
        !          2860:
        !          2861: static void
        !          2862: do_zero(GEN x)
        !          2863: {
        !          2864:   long i, lx = lg(x);
        !          2865:   for (i=1; i<lx; i++) x[i] = zero;
        !          2866: }
        !          2867:
        !          2868: /* c1 <-- u.c1 + v.c2; c2 <-- a.c2 - b.c1 */
        !          2869: static void
        !          2870: update(GEN u, GEN v, GEN a, GEN b, GEN *c1, GEN *c2)
        !          2871: {
        !          2872:   GEN p1,p2;
        !          2873:
        !          2874:   u = col_mul(u,*c1);
        !          2875:   v = col_mul(v,*c2);
        !          2876:   if (u) p1 = v? gadd(u,v): u;
        !          2877:   else   p1 = v? v: (GEN)NULL;
        !          2878:
        !          2879:   a = col_mul(a,*c2);
        !          2880:   b = col_mul(gneg_i(b),*c1);
        !          2881:   if (a) p2 = b? gadd(a,b): a;
        !          2882:   else   p2 = b? b: (GEN)NULL;
        !          2883:
        !          2884:   if (!p1) do_zero(*c1); else *c1 = p1;
        !          2885:   if (!p2) do_zero(*c2); else *c2 = p2;
        !          2886: }
        !          2887:
        !          2888: static GEN
        !          2889: trivsmith(long all)
        !          2890: {
        !          2891:   GEN z;
        !          2892:   if (!all) return cgetg(1,t_VEC);
        !          2893:   z=cgetg(4,t_VEC);
        !          2894:   z[1]=lgetg(1,t_MAT);
        !          2895:   z[2]=lgetg(1,t_MAT);
        !          2896:   z[3]=lgetg(1,t_MAT); return z;
        !          2897: }
        !          2898:
        !          2899: /* Return the smith normal form d of matrix x. If all != 0 return [d,u,v],
        !          2900:  * where d = u.x.v
        !          2901:  */
        !          2902: static GEN
        !          2903: smithall(GEN x, long all)
        !          2904: {
        !          2905:   long av,tetpil,i,j,k,l,c,fl,n,s1,s2,lim;
        !          2906:   GEN p1,p2,p3,p4,z,b,u,v,d,ml,mr,mun,mdet,ys;
        !          2907:
        !          2908:   if (typ(x)!=t_MAT) err(typeer,"smithall");
        !          2909:   if (DEBUGLEVEL>=9) outerr(x);
        !          2910:   n=lg(x)-1;
        !          2911:   if (!n) return trivsmith(all);
        !          2912:   if (lg(x[1]) != n+1) err(mattype1,"smithall");
        !          2913:   for (i=1; i<=n; i++)
        !          2914:     for (j=1; j<=n; j++)
        !          2915:       if (typ(coeff(x,i,j)) != t_INT)
        !          2916:         err(talker,"non integral matrix in smithall");
        !          2917:
        !          2918:   av = avma; lim = stack_lim(av,1);
        !          2919:   x = dummycopy(x); mdet = detint(x);
        !          2920:   if (ishnfall(x)) { if (all) { ml=idmat(n); mr=idmat(n); } }
        !          2921:   else
        !          2922:   {
        !          2923:     if (signe(mdet))
        !          2924:     {
        !          2925:       p1=hnfmod(x,mdet);
        !          2926:       if (all) { ml=idmat(n); mr=gauss(x,p1); }
        !          2927:     }
        !          2928:     else
        !          2929:     {
        !          2930:       if (all)
        !          2931:       {
        !          2932:         p1 = hnfall0(x,0);
        !          2933:         ml = idmat(n); mr = (GEN)p1[2]; p1 = (GEN)p1[1];
        !          2934:       }
        !          2935:       else
        !          2936:         p1 = hnf0(x,0);
        !          2937:     }
        !          2938:     x = p1;
        !          2939:   }
        !          2940:   p1=cgetg(n+1,t_VEC); for (i=1; i<=n; i++) p1[i]=lnegi(gcoeff(x,i,i));
        !          2941:   p2=sindexsort(p1); ys=cgetg(n+1,t_MAT);
        !          2942:   for (j=1; j<=n; j++)
        !          2943:   {
        !          2944:     p1=cgetg(n+1,t_COL); ys[j]=(long)p1;
        !          2945:     for (i=1; i<=n; i++) p1[i]=coeff(x,p2[i],p2[j]);
        !          2946:   }
        !          2947:   x = ys;
        !          2948:   if (all)
        !          2949:   {
        !          2950:     p3=cgetg(n+1,t_MAT); p4=cgetg(n+1,t_MAT);
        !          2951:     for (j=1; j<=n; j++) { p3[j]=ml[p2[j]]; p4[j]=mr[p2[j]]; }
        !          2952:     ml=p3; mr=p4;
        !          2953:   }
        !          2954:   if (signe(mdet))
        !          2955:   {
        !          2956:     p1 = hnfmod(x,mdet);
        !          2957:     if (all) mr=gmul(mr,gauss(x,p1));
        !          2958:   }
        !          2959:   else
        !          2960:   {
        !          2961:     if (all)
        !          2962:     {
        !          2963:       p1 = hnfall0(x,0);
        !          2964:       mr = gmul(mr,(GEN)p1[2]); p1 = (GEN)p1[1];
        !          2965:     }
        !          2966:     else
        !          2967:       p1 = hnf0(x,0);
        !          2968:   }
        !          2969:   x=p1; mun = negi(gun);
        !          2970:
        !          2971:   if (DEBUGLEVEL>7) {fprintferr("starting SNF loop");flusherr();}
        !          2972:   for (i=n; i>=2; i--)
        !          2973:   {
        !          2974:     if (DEBUGLEVEL>7) {fprintferr("\ni = %ld: ",i);flusherr();}
        !          2975:     for(;;)
        !          2976:     {
        !          2977:       c = 0;
        !          2978:       for (j=i-1; j>=1; j--)
        !          2979:       {
        !          2980:        p1=gcoeff(x,i,j); s1 = signe(p1);
        !          2981:        if (s1)
        !          2982:        {
        !          2983:          p2=gcoeff(x,i,i);
        !          2984:           if (!absi_cmp(p1,p2))
        !          2985:           {
        !          2986:             s2=signe(p2);
        !          2987:             if (s1 == s2) { d=p1; u=gun; p4=gun; }
        !          2988:             else
        !          2989:            {
        !          2990:               if (s2>0) { u = gun; p4 = mun; }
        !          2991:               else      { u = mun; p4 = gun; }
        !          2992:              d=(s1>0)? p1: absi(p1);
        !          2993:            }
        !          2994:             v = gzero; p3 = u;
        !          2995:           }
        !          2996:           else { d=bezout(p2,p1,&u,&v); p3=divii(p2,d); p4=divii(p1,d); }
        !          2997:          for (k=1; k<=i; k++)
        !          2998:          {
        !          2999:            b=addii(mulii(u,gcoeff(x,k,i)),mulii(v,gcoeff(x,k,j)));
        !          3000:            coeff(x,k,j)=lsubii(mulii(p3,gcoeff(x,k,j)),
        !          3001:                                mulii(p4,gcoeff(x,k,i)));
        !          3002:            coeff(x,k,i)=(long)b;
        !          3003:          }
        !          3004:          if (all) update(u,v,p3,p4,(GEN*)(mr+i),(GEN*)(mr+j));
        !          3005:           if (low_stack(lim, stack_lim(av,1)))
        !          3006:          {
        !          3007:            if (DEBUGMEM>1) err(warnmem,"[1]: smithall");
        !          3008:            if (all)
        !          3009:            {
        !          3010:              GEN *gptr[3]; gptr[0]=&x; gptr[1]=&ml; gptr[2]=&mr;
        !          3011:              gerepilemany(av,gptr,3);
        !          3012:            }
        !          3013:            else x=gerepileupto(av, ZM_copy(x));
        !          3014:          }
        !          3015:        }
        !          3016:       }
        !          3017:       if (DEBUGLEVEL>=8) {fprintferr("; ");flusherr();}
        !          3018:       for (j=i-1; j>=1; j--)
        !          3019:       {
        !          3020:        p1=gcoeff(x,j,i); s1 = signe(p1);
        !          3021:        if (s1)
        !          3022:        {
        !          3023:          p2=gcoeff(x,i,i);
        !          3024:          if (!absi_cmp(p1,p2))
        !          3025:           {
        !          3026:             s2 = signe(p2);
        !          3027:             if (s1 == s2) { d=p1; u=gun; p4=gun; }
        !          3028:             else
        !          3029:            {
        !          3030:               if (s2>0) { u = gun; p4 = mun; }
        !          3031:               else      { u = mun; p4 = gun; }
        !          3032:              d=(s1>0)? p1: absi(p1);
        !          3033:            }
        !          3034:             v = gzero; p3 = u;
        !          3035:           }
        !          3036:           else { d=bezout(p2,p1,&u,&v); p3=divii(p2,d); p4=divii(p1,d); }
        !          3037:          for (k=1; k<=i; k++)
        !          3038:          {
        !          3039:            b=addii(mulii(u,gcoeff(x,i,k)),mulii(v,gcoeff(x,j,k)));
        !          3040:            coeff(x,j,k)=lsubii(mulii(p3,gcoeff(x,j,k)),
        !          3041:                                mulii(p4,gcoeff(x,i,k)));
        !          3042:            coeff(x,i,k)=(long)b;
        !          3043:          }
        !          3044:          if (all) update(u,v,p3,p4,(GEN*)(ml+i),(GEN*)(ml+j));
        !          3045:          c = 1;
        !          3046:        }
        !          3047:       }
        !          3048:       if (!c)
        !          3049:       {
        !          3050:        b=gcoeff(x,i,i); fl=1;
        !          3051:        if (signe(b))
        !          3052:        {
        !          3053:          for (k=1; k<i && fl; k++)
        !          3054:            for (l=1; l<i && fl; l++)
        !          3055:              fl = (int)!signe(resii(gcoeff(x,k,l),b));
        !          3056:           /* cast to (int) necessary for gcc-2.95 on sparcv9-64 (IS) */
        !          3057:          if (!fl)
        !          3058:          {
        !          3059:            k--;
        !          3060:            for (l=1; l<=i; l++)
        !          3061:              coeff(x,i,l)=laddii(gcoeff(x,i,l),gcoeff(x,k,l));
        !          3062:            if (all) ml[i]=ladd((GEN)ml[i],(GEN)ml[k]);
        !          3063:          }
        !          3064:        }
        !          3065:         if (fl) break;
        !          3066:       }
        !          3067:       if (low_stack(lim, stack_lim(av,1)))
        !          3068:       {
        !          3069:        if (DEBUGMEM>1) err(warnmem,"[2]: smithall");
        !          3070:        if (all)
        !          3071:        {
        !          3072:          GEN *gptr[3]; gptr[0]=&x; gptr[1]=&ml; gptr[2]=&mr;
        !          3073:          gerepilemany(av,gptr,3);
        !          3074:        }
        !          3075:        else x=gerepileupto(av,ZM_copy(x));
        !          3076:       }
        !          3077:     }
        !          3078:   }
        !          3079:   if (DEBUGLEVEL>7) {fprintferr("\n");flusherr();}
        !          3080:   if (all)
        !          3081:   {
        !          3082:     for (k=1; k<=n; k++)
        !          3083:       if (signe(gcoeff(x,k,k))<0)
        !          3084:         { mr[k]=lneg((GEN)mr[k]); coeff(x,k,k)=lnegi(gcoeff(x,k,k)); }
        !          3085:     tetpil=avma; z=cgetg(4,t_VEC);
        !          3086:     z[1]=ltrans(ml); z[2]=lcopy(mr); z[3]=lcopy(x);
        !          3087:     return gerepile(av,tetpil,z);
        !          3088:   }
        !          3089:   tetpil=avma; z=cgetg(n+1,t_VEC); j=n;
        !          3090:   for (k=n; k; k--)
        !          3091:     if (signe(gcoeff(x,k,k))) z[j--]=labsi(gcoeff(x,k,k));
        !          3092:   for (   ; j; j--) z[j]=zero;
        !          3093:   return gerepile(av,tetpil,z);
        !          3094: }
        !          3095:
        !          3096: GEN
        !          3097: smith(GEN x) { return smithall(x,0); }
        !          3098:
        !          3099: GEN
        !          3100: smith2(GEN x) { return smithall(x,1); }
        !          3101:
        !          3102: /* Assume z was computed by [g]smithall(). Remove the 1s on the diagonal */
        !          3103: GEN
        !          3104: smithclean(GEN z)
        !          3105: {
        !          3106:   long i,j,l,c;
        !          3107:   GEN u,v,y,d,p1;
        !          3108:
        !          3109:   if (typ(z) != t_VEC) err(typeer,"smithclean");
        !          3110:   l = lg(z); if (l == 1) return cgetg(1,t_VEC);
        !          3111:   u=(GEN)z[1];
        !          3112:   if (l != 4 || typ(u) != t_MAT)
        !          3113:   {
        !          3114:     if (typ(u) != t_INT) err(typeer,"smithclean");
        !          3115:     for (c=1; c<l; c++)
        !          3116:       if (gcmp1((GEN)z[c])) break;
        !          3117:     return gcopy_i(z, c);
        !          3118:   }
        !          3119:   v=(GEN)z[2]; d=(GEN)z[3]; l = lg(d);
        !          3120:   for (c=1; c<l; c++)
        !          3121:     if (gcmp1(gcoeff(d,c,c))) break;
        !          3122:
        !          3123:   y=cgetg(4,t_VEC);
        !          3124:   y[1]=(long)(p1 = cgetg(l,t_MAT));
        !          3125:   for (i=1; i<l; i++) p1[i] = (long)gcopy_i((GEN)u[i], c);
        !          3126:   y[2]=(long)gcopy_i(v, c);
        !          3127:   y[3]=(long)(p1 = cgetg(c,t_MAT));
        !          3128:   for (i=1; i<c; i++)
        !          3129:   {
        !          3130:     GEN p2 = cgetg(c,t_COL); p1[i] = (long)p2;
        !          3131:     for (j=1; j<c; j++) p2[j] = i==j? lcopy(gcoeff(d,i,i)): zero;
        !          3132:   }
        !          3133:   return y;
        !          3134: }
        !          3135:
        !          3136: static GEN
        !          3137: gsmithall(GEN x,long all)
        !          3138: {
        !          3139:   long av,tetpil,i,j,k,l,c,n, lim;
        !          3140:   GEN p1,p2,p3,p4,z,b,u,v,d,ml,mr;
        !          3141:
        !          3142:   if (typ(x)!=t_MAT) err(typeer,"gsmithall");
        !          3143:   n=lg(x)-1;
        !          3144:   if (!n) return trivsmith(all);
        !          3145:   if (lg(x[1]) != n+1) err(mattype1,"gsmithall");
        !          3146:   av = avma; lim = stack_lim(av,1);
        !          3147:   x = dummycopy(x);
        !          3148:   if (all) { ml=idmat(n); mr=idmat(n); }
        !          3149:   for (i=n; i>=2; i--)
        !          3150:   {
        !          3151:     do
        !          3152:     {
        !          3153:       c=0;
        !          3154:       for (j=i-1; j>=1; j--)
        !          3155:       {
        !          3156:        p1=gcoeff(x,i,j);
        !          3157:        if (signe(p1))
        !          3158:        {
        !          3159:          p2=gcoeff(x,i,i);
        !          3160:           if (!signe(p2))
        !          3161:           {
        !          3162:             p3 = gzero; p4 = gun; u = gzero; v = gun;
        !          3163:           }
        !          3164:           else
        !          3165:           {
        !          3166:             v = gdiventres(p1,p2);
        !          3167:             if (gcmp0((GEN)v[2]))
        !          3168:               { d=p2; p4=(GEN)v[1]; v=gzero; p3=gun; u=gun; }
        !          3169:             else
        !          3170:               { d=gbezout(p2,p1,&u,&v); p3=gdiv(p2,d); p4=gdiv(p1,d); }
        !          3171:           }
        !          3172:          for (k=1; k<=i; k++)
        !          3173:          {
        !          3174:            b=gadd(gmul(u,gcoeff(x,k,i)),gmul(v,gcoeff(x,k,j)));
        !          3175:            coeff(x,k,j)=lsub(gmul(p3,gcoeff(x,k,j)),gmul(p4,gcoeff(x,k,i)));
        !          3176:            coeff(x,k,i)=(long)b;
        !          3177:          }
        !          3178:          if (all) update(u,v,p3,p4,(GEN*)(mr+i),(GEN*)(mr+j));
        !          3179:        }
        !          3180:       }
        !          3181:       for (j=i-1; j>=1; j--)
        !          3182:       {
        !          3183:        p1=gcoeff(x,j,i);
        !          3184:        if (signe(p1))
        !          3185:        {
        !          3186:          p2 = gcoeff(x,i,i);
        !          3187:           if (!signe(p2))
        !          3188:           {
        !          3189:             p3 = gzero; p4 = gun; u = gzero; v = gun;
        !          3190:           }
        !          3191:           else
        !          3192:           {
        !          3193:             v = gdiventres(p1,p2);
        !          3194:             if (gcmp0((GEN)v[2]))
        !          3195:               { d=p2; p4=(GEN)v[1]; v=gzero; p3=gun; u=gun; }
        !          3196:             else
        !          3197:               { d=gbezout(p2,p1,&u,&v); p3=gdiv(p2,d); p4=gdiv(p1,d); }
        !          3198:           }
        !          3199:          for (k=1; k<=i; k++)
        !          3200:          {
        !          3201:            b=gadd(gmul(u,gcoeff(x,i,k)),gmul(v,gcoeff(x,j,k)));
        !          3202:            coeff(x,j,k)=lsub(gmul(p3,gcoeff(x,j,k)),gmul(p4,gcoeff(x,i,k)));
        !          3203:            coeff(x,i,k)=(long)b;
        !          3204:          }
        !          3205:          if (all) update(u,v,p3,p4,(GEN*)(ml+i),(GEN*)(ml+j));
        !          3206:           c = 1;
        !          3207:        }
        !          3208:       }
        !          3209:       if (!c)
        !          3210:       {
        !          3211:        b = gcoeff(x,i,i);
        !          3212:        if (signe(b))
        !          3213:          for (k=1; k<i; k++)
        !          3214:            for (l=1; l<i; l++)
        !          3215:              if (signe(gmod(gcoeff(x,k,l),b)))
        !          3216:               {
        !          3217:                 for (l=1; l<=i; l++)
        !          3218:                   coeff(x,i,l) = ladd(gcoeff(x,i,l),gcoeff(x,k,l));
        !          3219:                 if (all) ml[i] = ladd((GEN)ml[i],(GEN)ml[k]);
        !          3220:                 k = l = i; c = 1;
        !          3221:               }
        !          3222:       }
        !          3223:       if (low_stack(lim, stack_lim(av,1)))
        !          3224:       {
        !          3225:        if (DEBUGMEM>1) err(warnmem,"[5]: smithall");
        !          3226:        if (all)
        !          3227:        {
        !          3228:          GEN *gptr[3]; gptr[0]=&x; gptr[1]=&ml; gptr[2]=&mr;
        !          3229:          gerepilemany(av,gptr,3);
        !          3230:        }
        !          3231:        else x=gerepilecopy(av,x);
        !          3232:       }
        !          3233:     }
        !          3234:     while (c);
        !          3235:   }
        !          3236:   if (all)
        !          3237:   {
        !          3238:     for (k=1; k<=n; k++)
        !          3239:       if (signe(gcoeff(x,k,k)) < 0)
        !          3240:       { mr[k]=lneg((GEN)mr[k]); coeff(x,k,k)=lneg(gcoeff(x,k,k)); }
        !          3241:     tetpil=avma; z=cgetg(4,t_VEC);
        !          3242:     z[1]=ltrans(ml); z[2]=lcopy(mr); z[3]=lcopy(x);
        !          3243:   }
        !          3244:   else
        !          3245:   {
        !          3246:     tetpil=avma; z=cgetg(n+1,t_VEC);
        !          3247:     for (j=0,k=1; k<=n; k++) if (!signe(gcoeff(x,k,k))) z[++j]=zero;
        !          3248:     for (k=1; k<=n; k++)
        !          3249:       if (signe(p1=gcoeff(x,k,k))) z[++j]=(long)gabs(p1,0);
        !          3250:   }
        !          3251:   return gerepile(av,tetpil,z);
        !          3252: }
        !          3253:
        !          3254: GEN
        !          3255: matsnf0(GEN x,long flag)
        !          3256: {
        !          3257:   long av = avma;
        !          3258:   if (flag > 7) err(flagerr,"matsnf");
        !          3259:   if (typ(x) == t_VEC && flag & 4) return smithclean(x);
        !          3260:   if (flag & 2) x = gsmithall(x,flag & 1);
        !          3261:   else          x = smithall(x, flag & 1);
        !          3262:   if (flag & 4) x = smithclean(x);
        !          3263:   return gerepileupto(av, x);
        !          3264: }
        !          3265:
        !          3266: GEN
        !          3267: gsmith(GEN x) { return gsmithall(x,0); }
        !          3268:
        !          3269: GEN
        !          3270: gsmith2(GEN x) { return gsmithall(x,1); }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>