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

Annotation of OpenXM_contrib/pari-2.2/src/basemath/alglin1.c, Revision 1.1.1.1

1.1       noro        1: /* $Id: alglin1.c,v 1.57 2001/10/01 12:11:27 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: /**                          (first part)                          **/
                     20: /**                                                                **/
                     21: /********************************************************************/
                     22: #include "pari.h"
                     23:
                     24: /* for linear algebra mod p */
                     25: #ifdef LONG_IS_64BIT
                     26: #  define MASK (0x7fffffff00000000UL)
                     27: #else
                     28: #  define MASK (0x7fff0000UL)
                     29: #endif
                     30:
                     31: /* 2p^2 < 2^BITS_IN_LONG */
                     32: #ifdef LONG_IS_64BIT
                     33: #  define u_OK_ULONG(p) ((ulong)p <= 3037000493UL)
                     34: #else
                     35: #  define u_OK_ULONG(p) ((ulong)p <= 46337UL)
                     36: #endif
                     37: #define OK_ULONG(p) (lgefint(p) == 3 && u_OK_ULONG(p[2]))
                     38: extern GEN ZM_init_CRT(GEN Hp, ulong p);
                     39: extern ulong u_invmod(ulong x, ulong p);
                     40:
                     41: /*******************************************************************/
                     42: /*                                                                 */
                     43: /*                         TRANSPOSE                               */
                     44: /*                                                                 */
                     45: /*******************************************************************/
                     46:
                     47: /* No copy*/
                     48: GEN
                     49: gtrans_i(GEN x)
                     50: {
                     51:   long i,j,lx,dx, tx=typ(x);
                     52:   GEN y,p1;
                     53:
                     54:   if (! is_matvec_t(tx)) err(typeer,"gtrans_i");
                     55:   switch(tx)
                     56:   {
                     57:     case t_VEC:
                     58:       y=dummycopy(x); settyp(y,t_COL); break;
                     59:
                     60:     case t_COL:
                     61:       y=dummycopy(x); settyp(y,t_VEC); break;
                     62:
                     63:     case t_MAT:
                     64:       lx=lg(x); if (lx==1) return cgetg(1,t_MAT);
                     65:       dx=lg(x[1]); y=cgetg(dx,tx);
                     66:       for (i=1; i<dx; i++)
                     67:       {
                     68:        p1=cgetg(lx,t_COL); y[i]=(long)p1;
                     69:        for (j=1; j<lx; j++) p1[j]=coeff(x,i,j);
                     70:       }
                     71:       break;
                     72:
                     73:     default: y=x; break;
                     74:   }
                     75:   return y;
                     76: }
                     77:
                     78:
                     79: GEN
                     80: gtrans(GEN x)
                     81: {
                     82:   long i,j,lx,dx, tx=typ(x);
                     83:   GEN y,p1;
                     84:
                     85:   if (! is_matvec_t(tx)) err(typeer,"gtrans");
                     86:   switch(tx)
                     87:   {
                     88:     case t_VEC:
                     89:       y=gcopy(x); settyp(y,t_COL); break;
                     90:
                     91:     case t_COL:
                     92:       y=gcopy(x); settyp(y,t_VEC); break;
                     93:
                     94:     case t_MAT:
                     95:       lx=lg(x); if (lx==1) return cgetg(1,t_MAT);
                     96:       dx=lg(x[1]); y=cgetg(dx,tx);
                     97:       for (i=1; i<dx; i++)
                     98:       {
                     99:        p1=cgetg(lx,t_COL); y[i]=(long)p1;
                    100:        for (j=1; j<lx; j++) p1[j]=lcopy(gcoeff(x,i,j));
                    101:       }
                    102:       break;
                    103:
                    104:     default: y=gcopy(x); break;
                    105:   }
                    106:   return y;
                    107: }
                    108:
                    109: /*******************************************************************/
                    110: /*                                                                 */
                    111: /*                    CONCATENATION & EXTRACTION                   */
                    112: /*                                                                 */
                    113: /*******************************************************************/
                    114:
                    115: static GEN
                    116: strconcat(GEN x, GEN y)
                    117: {
                    118:   long flx=0,fly=0,l;
                    119:   char *sx,*sy,*str;
                    120:
                    121:   if (typ(x)==t_STR) sx = GSTR(x); else { flx=1; sx = GENtostr(x); }
                    122:   if (typ(y)==t_STR) sy = GSTR(y); else { fly=1; sy = GENtostr(y); }
                    123:   l = strlen(sx) + strlen(sy) + 1;
                    124:   l = (l+BYTES_IN_LONG) >> TWOPOTBYTES_IN_LONG;
                    125:   x = cgetg(l+1, t_STR); str = GSTR(x);
                    126:   strcpy(str,sx);
                    127:   strcat(str,sy);
                    128:   if (flx) free(sx);
                    129:   if (fly) free(sy);
                    130:   return x;
                    131: }
                    132:
                    133: /* concat 3 matrices. Internal */
                    134: GEN
                    135: concatsp3(GEN x, GEN y, GEN z)
                    136: {
                    137:   long i, lx = lg(x), ly = lg(y), lz = lg(z);
                    138:   GEN r = cgetg(lx+ly+lz-2, t_MAT), t = r;
                    139:   for (i=1; i<lx; i++) *++t = *++x;
                    140:   for (i=1; i<ly; i++) *++t = *++y;
                    141:   for (i=1; i<lz; i++) *++t = *++z;
                    142:   return r;
                    143: }
                    144:
                    145: /* concat A and B vertically. Internal */
                    146: GEN
                    147: vconcat(GEN A, GEN B)
                    148: {
                    149:   long la,ha,hb,hc,i,j;
                    150:   GEN M,a,b,c;
                    151:
                    152:   la = lg(A); if (la==1) return A;
                    153:   ha = lg(A[1]); M = cgetg(la,t_MAT);
                    154:   hb = lg(B[1]); hc = ha+hb-1;
                    155:   for (j=1; j<la; j++)
                    156:   {
                    157:     c = cgetg(hc,t_COL); M[j] = (long)c; a = (GEN)A[j]; b = (GEN)B[j];
                    158:     for (i=1; i<ha; i++) *++c = *++a;
                    159:     for (i=1; i<hb; i++) *++c = *++b;
                    160:   }
                    161:   return M;
                    162: }
                    163:
                    164: GEN
                    165: _vec(GEN x) { GEN v = cgetg(2, t_VEC); v[1] = (long)x; return v; }
                    166: GEN
                    167: _col(GEN x) { GEN v = cgetg(2, t_COL); v[1] = (long)x; return v; }
                    168:
                    169: GEN
                    170: concatsp(GEN x, GEN y)
                    171: {
                    172:   long tx=typ(x),ty=typ(y),lx=lg(x),ly=lg(y),i;
                    173:   GEN z,p1;
                    174:
                    175:   if (tx==t_LIST || ty==t_LIST) return listconcat(x,y);
                    176:   if (tx==t_STR  || ty==t_STR)  return strconcat(x,y);
                    177:
                    178:   if (tx==t_MAT && lx==1)
                    179:   {
                    180:     if (ty!=t_VEC || ly==1) return gtomat(y);
                    181:     err(concater);
                    182:   }
                    183:   if (ty==t_MAT && ly==1)
                    184:   {
                    185:     if (tx!=t_VEC || lx==1) return gtomat(x);
                    186:     err(concater);
                    187:   }
                    188:
                    189:   if (! is_matvec_t(tx))
                    190:   {
                    191:     if (! is_matvec_t(ty))
                    192:     {
                    193:       z=cgetg(3,t_VEC); z[1]=(long)x; z[2]=(long)y;
                    194:       return z;
                    195:     }
                    196:     z=cgetg(ly+1,ty);
                    197:     if (ty != t_MAT) p1 = x;
                    198:     else
                    199:     {
                    200:       if (lg(y[1])!=2) err(concater);
                    201:       p1=cgetg(2,t_COL); p1[1]=(long)x;
                    202:     }
                    203:     for (i=2; i<=ly; i++) z[i]=y[i-1];
                    204:     z[1]=(long)p1; return z;
                    205:   }
                    206:   if (! is_matvec_t(ty))
                    207:   {
                    208:     z=cgetg(lx+1,tx);
                    209:     if (tx != t_MAT) p1 = y;
                    210:     else
                    211:     {
                    212:       if (lg(x[1])!=2) err(concater);
                    213:       p1=cgetg(2,t_COL); p1[1]=(long)y;
                    214:     }
                    215:     for (i=1; i<lx; i++) z[i]=x[i];
                    216:     z[lx]=(long)p1; return z;
                    217:   }
                    218:
                    219:   if (tx == ty)
                    220:   {
                    221:     if (tx == t_MAT && lg(x[1]) != lg(y[1])) err(concater);
                    222:     z=cgetg(lx+ly-1,tx);
                    223:     for (i=1; i<lx; i++) z[i]=x[i];
                    224:     for (i=1; i<ly; i++) z[lx+i-1]=y[i];
                    225:     return z;
                    226:   }
                    227:
                    228:   switch(tx)
                    229:   {
                    230:     case t_VEC:
                    231:       switch(ty)
                    232:       {
                    233:        case t_COL:
                    234:          if (lx<=2) return (lx==1)? y: concatsp((GEN) x[1],y);
                    235:           if (ly>=3) break;
                    236:           return (ly==1)? x: concatsp(x,(GEN) y[1]);
                    237:        case t_MAT:
                    238:          z=cgetg(ly,ty); if (lx != ly) break;
                    239:          for (i=1; i<ly; i++) z[i]=(long)concatsp((GEN) x[i],(GEN) y[i]);
                    240:           return z;
                    241:       }
                    242:       break;
                    243:
                    244:     case t_COL:
                    245:       switch(ty)
                    246:       {
                    247:        case t_VEC:
                    248:          if (lx<=2) return (lx==1)? y: concatsp((GEN) x[1],y);
                    249:          if (ly>=3) break;
                    250:          return (ly==1)? x: concatsp(x,(GEN) y[1]);
                    251:        case t_MAT:
                    252:          if (lx != lg(y[1])) break;
                    253:          z=cgetg(ly+1,ty); z[1]=(long)x;
                    254:          for (i=2; i<=ly; i++) z[i]=y[i-1];
                    255:           return z;
                    256:       }
                    257:       break;
                    258:
                    259:     case t_MAT:
                    260:       switch(ty)
                    261:       {
                    262:        case t_VEC:
                    263:          z=cgetg(lx,tx); if (ly != lx) break;
                    264:          for (i=1; i<lx; i++) z[i]=(long)concatsp((GEN) x[i],(GEN) y[i]);
                    265:           return z;
                    266:        case t_COL:
                    267:          if (ly != lg(x[1])) break;
                    268:          z=cgetg(lx+1,tx); z[lx]=(long)y;
                    269:          for (i=1; i<lx; i++) z[i]=x[i];
                    270:           return z;
                    271:       }
                    272:       break;
                    273:   }
                    274:   err(concater);
                    275:   return NULL; /* not reached */
                    276: }
                    277:
                    278: GEN
                    279: concat(GEN x, GEN y)
                    280: {
                    281:   long tx = typ(x), lx,ty,ly,i;
                    282:   GEN z,p1;
                    283:
                    284:   if (!y)
                    285:   {
                    286:     ulong av = avma;
                    287:     if (tx == t_LIST)
                    288:       { lx = lgef(x); i = 2; }
                    289:     else if (tx == t_VEC)
                    290:       { lx = lg(x); i = 1; }
                    291:     else
                    292:     {
                    293:       err(concater);
                    294:       return NULL; /* not reached */
                    295:     }
                    296:     if (i>=lx) err(talker,"trying to concat elements of an empty vector");
                    297:     y = (GEN)x[i++];
                    298:     for (; i<lx; i++) y = concatsp(y, (GEN)x[i]);
                    299:     return gerepilecopy(av,y);
                    300:   }
                    301:   ty = typ(y);
                    302:   if (tx==t_LIST || ty==t_LIST) return listconcat(x,y);
                    303:   if (tx==t_STR  || ty==t_STR)  return strconcat(x,y);
                    304:   lx=lg(x); ly=lg(y);
                    305:
                    306:   if (tx==t_MAT && lx==1)
                    307:   {
                    308:     if (ty!=t_VEC || ly==1) return gtomat(y);
                    309:     err(concater);
                    310:   }
                    311:   if (ty==t_MAT && ly==1)
                    312:   {
                    313:     if (tx!=t_VEC || lx==1) return gtomat(x);
                    314:     err(concater);
                    315:   }
                    316:
                    317:   if (! is_matvec_t(tx))
                    318:   {
                    319:     if (! is_matvec_t(ty))
                    320:     {
                    321:       z=cgetg(3,t_VEC); z[1]=lcopy(x); z[2]=lcopy(y);
                    322:       return z;
                    323:     }
                    324:     z=cgetg(ly+1,ty);
                    325:     if (ty != t_MAT) p1 = gcopy(x);
                    326:     else
                    327:     {
                    328:       if (lg(y[1])!=2) err(concater);
                    329:       p1=cgetg(2,t_COL); p1[1]=lcopy(x);
                    330:     }
                    331:     for (i=2; i<=ly; i++) z[i]=lcopy((GEN) y[i-1]);
                    332:     z[1]=(long)p1; return z;
                    333:   }
                    334:   if (! is_matvec_t(ty))
                    335:   {
                    336:     z=cgetg(lx+1,tx);
                    337:     if (tx != t_MAT) p1 = gcopy(y);
                    338:     else
                    339:     {
                    340:       if (lg(x[1])!=2) err(concater);
                    341:       p1=cgetg(2,t_COL); p1[1]=lcopy(y);
                    342:     }
                    343:     for (i=1; i<lx; i++) z[i]=lcopy((GEN) x[i]);
                    344:     z[lx]=(long)p1; return z;
                    345:   }
                    346:
                    347:   if (tx == ty)
                    348:   {
                    349:     if (tx == t_MAT && lg(x[1]) != lg(y[1])) err(concater);
                    350:     z=cgetg(lx+ly-1,tx);
                    351:     for (i=1; i<lx; i++) z[i]=lcopy((GEN) x[i]);
                    352:     for (i=1; i<ly; i++) z[lx+i-1]=lcopy((GEN) y[i]);
                    353:     return z;
                    354:   }
                    355:
                    356:   switch(tx)
                    357:   {
                    358:     case t_VEC:
                    359:       switch(ty)
                    360:       {
                    361:        case t_COL:
                    362:          if (lx<=2) return (lx==1)? gcopy(y): concat((GEN) x[1],y);
                    363:           if (ly>=3) break;
                    364:           return (ly==1)? gcopy(x): concat(x,(GEN) y[1]);
                    365:        case t_MAT:
                    366:          z=cgetg(ly,ty); if (lx != ly) break;
                    367:          for (i=1; i<ly; i++) z[i]=lconcat((GEN) x[i],(GEN) y[i]);
                    368:           return z;
                    369:       }
                    370:       break;
                    371:
                    372:     case t_COL:
                    373:       switch(ty)
                    374:       {
                    375:        case t_VEC:
                    376:          if (lx<=2) return (lx==1)? gcopy(y): concat((GEN) x[1],y);
                    377:          if (ly>=3) break;
                    378:          return (ly==1)? gcopy(x): concat(x,(GEN) y[1]);
                    379:        case t_MAT:
                    380:          if (lx != lg(y[1])) break;
                    381:          z=cgetg(ly+1,ty); z[1]=lcopy(x);
                    382:          for (i=2; i<=ly; i++) z[i]=lcopy((GEN) y[i-1]);
                    383:           return z;
                    384:       }
                    385:       break;
                    386:
                    387:     case t_MAT:
                    388:       switch(ty)
                    389:       {
                    390:        case t_VEC:
                    391:          z=cgetg(lx,tx); if (ly != lx) break;
                    392:          for (i=1; i<lx; i++) z[i]=lconcat((GEN) x[i],(GEN) y[i]);
                    393:           return z;
                    394:        case t_COL:
                    395:          if (ly != lg(x[1])) break;
                    396:          z=cgetg(lx+1,tx); z[lx]=lcopy(y);
                    397:          for (i=1; i<lx; i++) z[i]=lcopy((GEN) x[i]);
                    398:           return z;
                    399:       }
                    400:       break;
                    401:   }
                    402:   err(concater);
                    403:   return NULL; /* not reached */
                    404: }
                    405:
                    406: static long
                    407: str_to_long(char *s, char **pt)
                    408: {
                    409:   long a = atol(s);
                    410:   while (isspace((int)*s)) s++;
                    411:   if (*s == '-' || *s == '+') s++;
                    412:   while (isdigit((int)*s) || isspace((int)*s)) s++;
                    413:   *pt = s; return a;
                    414: }
                    415:
                    416: static int
                    417: get_range(char *s, long *a, long *b, long *cmpl, long lx)
                    418: {
                    419:   long max = lx - 1;
                    420:
                    421:   *a = 1; *b = max;
                    422:   if (*s == '^') { *cmpl = 1; s++; } else *cmpl = 0;
                    423:   if (*s == 0) return 0;
                    424:   if (*s != '.')
                    425:   {
                    426:     *a = str_to_long(s, &s);
                    427:     if (*a < 0) *a += lx;
                    428:     if (*a<1 || *a>max) return 0;
                    429:   }
                    430:   if (*s == '.')
                    431:   {
                    432:     s++; if (*s != '.') return 0;
                    433:     do s++; while (isspace((int)*s));
                    434:     if (*s)
                    435:     {
                    436:       *b = str_to_long(s, &s);
                    437:       if (*b < 0) *b += lx;
                    438:       if (*b<1 || *b>max || *s) return 0;
                    439:     }
                    440:     return 1;
                    441:   }
                    442:   if (*s) return 0;
                    443:   *b = *a; return 1;
                    444: }
                    445:
                    446: GEN
                    447: vecextract_i(GEN A, long y1, long y2)
                    448: {
                    449:   long i,lB = y2 - y1 + 2;
                    450:   GEN B = cgetg(lB, typ(A));
                    451:   for (i=1; i<lB; i++) B[i] = A[y1-1+i];
                    452:   return B;
                    453: }
                    454:
                    455: GEN
                    456: rowextract_i(GEN A, long x1, long x2)
                    457: {
                    458:   long i, lB = lg(A);
                    459:   GEN B = cgetg(lB, typ(A));
                    460:   for (i=1; i<lB; i++) B[i] = (long)vecextract_i((GEN)A[i],x1,x2);
                    461:   return B;
                    462: }
                    463:
                    464: GEN
                    465: vecextract_p(GEN A, GEN p)
                    466: {
                    467:   long i,lB = lg(p);
                    468:   GEN B = cgetg(lB, typ(A));
                    469:   for (i=1; i<lB; i++) B[i] = A[p[i]];
                    470:   return B;
                    471: }
                    472:
                    473: GEN
                    474: rowextract_p(GEN A, GEN p)
                    475: {
                    476:   long i, lB = lg(A);
                    477:   GEN B = cgetg(lB, typ(A));
                    478:   for (i=1; i<lB; i++) B[i] = (long)vecextract_p((GEN)A[i],p);
                    479:   return B;
                    480: }
                    481:
                    482: void
                    483: vecselect_p(GEN A, GEN B, GEN p, long init, long lB)
                    484: {
                    485:   long i; setlg(B, lB);
                    486:   for (i=init; i<lB; i++) B[i] = A[p[i]];
                    487: }
                    488:
                    489: /* B := p . A = row selection according to permutation p. Treat only lower
                    490:  * right corner init x init */
                    491: void
                    492: rowselect_p(GEN A, GEN B, GEN p, long init)
                    493: {
                    494:   long i, lB = lg(A), lp = lg(p);
                    495:   for (i=1; i<init; i++) setlg(B[i],lp);
                    496:   for (   ; i<lB;   i++) vecselect_p((GEN)A[i],(GEN)B[i],p,init,lp);
                    497: }
                    498:
                    499: GEN
                    500: extract(GEN x, GEN l)
                    501: {
                    502:   long av,i,j, tl = typ(l), tx = typ(x), lx = lg(x);
                    503:   GEN y;
                    504:
                    505:   if (! is_matvec_t(tx)) err(typeer,"extract");
                    506:   if (tl==t_INT)
                    507:   {
                    508:     /* extract components of x as per the bits of mask l */
                    509:     if (!signe(l)) return cgetg(1,tx);
                    510:     av=avma; y = (GEN) gpmalloc(lx*sizeof(long));
                    511:     i = j = 1; while (!mpodd(l)) { l=shifti(l,-1); i++; }
                    512:     while (signe(l) && i<lx)
                    513:     {
                    514:       if (mod2(l)) y[j++] = x[i];
                    515:       i++; l=shifti(l,-1);
                    516:     }
                    517:     if (signe(l)) err(talker,"mask too large in vecextract");
                    518:     y[0] = evaltyp(tx) | evallg(j);
                    519:     avma=av; x = gcopy(y); free(y); return x;
                    520:   }
                    521:   if (tl==t_STR)
                    522:   {
                    523:     char *s = GSTR(l);
                    524:     long first, last, cmpl;
                    525:     if (! get_range(s, &first, &last, &cmpl, lx))
                    526:       err(talker, "incorrect range in extract");
                    527:     if (lx == 1) return gcopy(x);
                    528:     if (cmpl)
                    529:     {
                    530:       if (first <= last)
                    531:       {
                    532:         y = cgetg(lx - (last - first + 1),tx);
                    533:         for (j=1; j<first; j++) y[j] = lcopy((GEN)x[j]);
                    534:         for (i=last+1; i<lx; i++,j++) y[j] = lcopy((GEN)x[i]);
                    535:       }
                    536:       else
                    537:       {
                    538:         y = cgetg(lx - (first - last + 1),tx);
                    539:         for (j=1,i=lx-1; i>first; i--,j++) y[j] = lcopy((GEN)x[i]);
                    540:         for (i=last-1; i>0; i--,j++) y[j] = lcopy((GEN)x[i]);
                    541:       }
                    542:     }
                    543:     else
                    544:     {
                    545:       if (first <= last)
                    546:       {
                    547:         y = cgetg(last-first+2,tx);
                    548:         for (i=first,j=1; i<=last; i++,j++) y[j] = lcopy((GEN)x[i]);
                    549:       }
                    550:       else
                    551:       {
                    552:         y = cgetg(first-last+2,tx);
                    553:         for (i=first,j=1; i>=last; i--,j++) y[j] = lcopy((GEN)x[i]);
                    554:       }
                    555:     }
                    556:     return y;
                    557:   }
                    558:
                    559:   if (is_vec_t(tl))
                    560:   {
                    561:     long ll=lg(l); y=cgetg(ll,tx);
                    562:     for (i=1; i<ll; i++)
                    563:     {
                    564:       j = itos((GEN) l[i]);
                    565:       if (j>=lx || j<=0) err(talker,"no such component in vecextract");
                    566:       y[i] = lcopy((GEN) x[j]);
                    567:     }
                    568:     return y;
                    569:   }
                    570:   if (tl == t_VECSMALL)
                    571:   {
                    572:     long ll=lg(l); y=cgetg(ll,tx);
                    573:     for (i=1; i<ll; i++)
                    574:     {
                    575:       j = l[i];
                    576:       if (j>=lx || j<=0) err(talker,"no such component in vecextract");
                    577:       y[i] = lcopy((GEN) x[j]);
                    578:     }
                    579:     return y;
                    580:   }
                    581:   err(talker,"incorrect mask in vecextract");
                    582:   return NULL; /* not reached */
                    583: }
                    584:
                    585: GEN
                    586: matextract(GEN x, GEN l1, GEN l2)
                    587: {
                    588:   long av = avma, tetpil;
                    589:
                    590:   if (typ(x)!=t_MAT) err(typeer,"matextract");
                    591:   x = extract(gtrans(extract(x,l2)),l1); tetpil=avma;
                    592:   return gerepile(av,tetpil, gtrans(x));
                    593: }
                    594:
                    595: GEN
                    596: extract0(GEN x, GEN l1, GEN l2)
                    597: {
                    598:   if (! l2) return extract(x,l1);
                    599:   return matextract(x,l1,l2);
                    600: }
                    601:
                    602: /*******************************************************************/
                    603: /*                                                                 */
                    604: /*                     SCALAR-MATRIX OPERATIONS                    */
                    605: /*                                                                 */
                    606: /*******************************************************************/
                    607:
                    608: /* create the square nxn matrix equal to z*Id */
                    609: static GEN
                    610: gscalmat_proto(GEN z, GEN myzero, long n, int flag)
                    611: {
                    612:   long i,j;
                    613:   GEN y = cgetg(n+1,t_MAT);
                    614:   if (n < 0) err(talker,"negative size in scalmat");
                    615:   if (flag) z = (flag==1)? stoi((long)z): gcopy(z);
                    616:   for (i=1; i<=n; i++)
                    617:   {
                    618:     y[i]=lgetg(n+1,t_COL);
                    619:     for (j=1; j<=n; j++)
                    620:       coeff(y,j,i) = (i==j)? (long)z: (long)myzero;
                    621:   }
                    622:   return y;
                    623: }
                    624:
                    625: GEN
                    626: gscalmat(GEN x, long n) { return gscalmat_proto(x,gzero,n,2); }
                    627:
                    628: GEN
                    629: gscalsmat(long x, long n) { return gscalmat_proto((GEN)x,gzero,n,1); }
                    630:
                    631: GEN
                    632: idmat(long n) { return gscalmat_proto(gun,gzero,n,0); }
                    633:
                    634: GEN
                    635: idmat_intern(long n,GEN myun,GEN z) { return gscalmat_proto(myun,z,n,0); }
                    636:
                    637: GEN
                    638: gscalcol_proto(GEN z, GEN myzero, long n)
                    639: {
                    640:   GEN y = cgetg(n+1,t_COL);
                    641:   long i;
                    642:
                    643:   if (n)
                    644:   {
                    645:     y[1]=(long)z;
                    646:     for (i=2; i<=n; i++) y[i]=(long)myzero;
                    647:   }
                    648:   return y;
                    649: }
                    650:
                    651: GEN
                    652: zerocol(long n)
                    653: {
                    654:   GEN y = cgetg(n+1,t_COL);
                    655:   long i; for (i=1; i<=n; i++) y[i]=zero;
                    656:   return y;
                    657: }
                    658:
                    659: GEN
                    660: zerovec(long n)
                    661: {
                    662:   GEN y = cgetg(n+1,t_VEC);
                    663:   long i; for (i=1; i<=n; i++) y[i]=zero;
                    664:   return y;
                    665: }
                    666:
                    667: GEN
                    668: zeromat(long m, long n)
                    669: {
                    670:   GEN y = cgetg(n+1,t_MAT);
                    671:   long i; for (i=1; i<=n; i++) y[i]=(long)zerocol(m);
                    672:   return y;
                    673: }
                    674:
                    675: GEN
                    676: gscalcol(GEN x, long n)
                    677: {
                    678:   GEN y=gscalcol_proto(gzero,gzero,n);
                    679:   if (n) y[1]=lcopy(x);
                    680:   return y;
                    681: }
                    682:
                    683: GEN
                    684: gscalcol_i(GEN x, long n) { return gscalcol_proto(x,gzero,n); }
                    685:
                    686: GEN
                    687: gtomat(GEN x)
                    688: {
                    689:   long tx,lx,i;
                    690:   GEN y,p1;
                    691:
                    692:   if (!x) return cgetg(1, t_MAT);
                    693:   tx = typ(x);
                    694:   if (! is_matvec_t(tx))
                    695:   {
                    696:     y=cgetg(2,t_MAT); p1=cgetg(2,t_COL); y[1]=(long)p1;
                    697:     p1[1]=lcopy(x); return y;
                    698:   }
                    699:   switch(tx)
                    700:   {
                    701:     case t_VEC:
                    702:       lx=lg(x); y=cgetg(lx,t_MAT);
                    703:       for (i=1; i<lx; i++)
                    704:       {
                    705:        p1=cgetg(2,t_COL); y[i]=(long)p1;
                    706:        p1[1]=lcopy((GEN) x[i]);
                    707:       }
                    708:       break;
                    709:     case t_COL:
                    710:       y=cgetg(2,t_MAT); y[1]=lcopy(x); break;
                    711:     default: /* case t_MAT: */
                    712:       y=gcopy(x); break;
                    713:   }
                    714:   return y;
                    715: }
                    716:
                    717: long
                    718: isscalarmat(GEN x, GEN s)
                    719: {
                    720:   long nco,i,j;
                    721:
                    722:   if (typ(x)!=t_MAT) err(typeer,"isdiagonal");
                    723:   nco=lg(x)-1; if (!nco) return 1;
                    724:   if (nco != lg(x[1])-1) return 0;
                    725:
                    726:   for (j=1; j<=nco; j++)
                    727:   {
                    728:     GEN *col = (GEN*) x[j];
                    729:     for (i=1; i<=nco; i++)
                    730:       if (i == j)
                    731:       {
                    732:         if (!gegal(col[i],s)) return 0;
                    733:       }
                    734:       else if (!gcmp0(col[i])) return 0;
                    735:   }
                    736:   return 1;
                    737: }
                    738:
                    739: long
                    740: isdiagonal(GEN x)
                    741: {
                    742:   long nco,i,j;
                    743:
                    744:   if (typ(x)!=t_MAT) err(typeer,"isdiagonal");
                    745:   nco=lg(x)-1; if (!nco) return 1;
                    746:   if (nco != lg(x[1])-1) return 0;
                    747:
                    748:   for (j=1; j<=nco; j++)
                    749:   {
                    750:     GEN *col = (GEN*) x[j];
                    751:     for (i=1; i<=nco; i++)
                    752:       if (i!=j && !gcmp0(col[i])) return 0;
                    753:   }
                    754:   return 1;
                    755: }
                    756:
                    757: /* create the diagonal matrix, whose diagonal is given by x */
                    758: GEN
                    759: diagonal(GEN x)
                    760: {
                    761:   long i,j,lx,tx=typ(x);
                    762:   GEN y,p1;
                    763:
                    764:   if (! is_matvec_t(tx)) return gscalmat(x,1);
                    765:   if (tx==t_MAT)
                    766:   {
                    767:     if (isdiagonal(x)) return gcopy(x);
                    768:     err(talker,"incorrect object in diagonal");
                    769:   }
                    770:   lx=lg(x); y=cgetg(lx,t_MAT);
                    771:   for (j=1; j<lx; j++)
                    772:   {
                    773:     p1=cgetg(lx,t_COL); y[j]=(long)p1;
                    774:     for (i=1; i<lx; i++)
                    775:       p1[i] = (i==j)? lcopy((GEN) x[i]): zero;
                    776:   }
                    777:   return y;
                    778: }
                    779:
                    780: /* compute m*diagonal(d) */
                    781: GEN
                    782: matmuldiagonal(GEN m, GEN d)
                    783: {
                    784:   long j=typ(d),lx=lg(m);
                    785:   GEN y;
                    786:
                    787:   if (typ(m)!=t_MAT) err(typeer,"matmuldiagonal");
                    788:   if (! is_vec_t(j) || lg(d)!=lx)
                    789:     err(talker,"incorrect vector in matmuldiagonal");
                    790:   y=cgetg(lx,t_MAT);
                    791:   for (j=1; j<lx; j++) y[j] = lmul((GEN) d[j],(GEN) m[j]);
                    792:   return y;
                    793: }
                    794:
                    795: /* compute m*n assuming the result is a diagonal matrix */
                    796: GEN
                    797: matmultodiagonal(GEN m, GEN n)
                    798: {
                    799:   long lx,i,j;
                    800:   GEN s,y;
                    801:
                    802:   if (typ(m)!=t_MAT || typ(n)!=t_MAT) err(typeer,"matmultodiagonal");
                    803:   lx=lg(n); y=idmat(lx-1);
                    804:   if (lx == 1)
                    805:     { if (lg(m) != 1) err(consister,"matmultodiagonal"); }
                    806:   else
                    807:     { if (lg(m) != lg(n[1])) err(consister,"matmultodiagonal"); }
                    808:   for (i=1; i<lx; i++)
                    809:   {
                    810:     s = gzero;
                    811:     for (j=1; j<lx; j++)
                    812:       s = gadd(s,gmul(gcoeff(m,i,j),gcoeff(n,j,i)));
                    813:     coeff(y,i,i) = (long)s;
                    814:   }
                    815:   return y;
                    816: }
                    817:
                    818: /* [m[1,1], ..., m[l,l]], internal */
                    819: GEN
                    820: mattodiagonal_i(GEN m)
                    821: {
                    822:   long i, lx = lg(m);
                    823:   GEN y = cgetg(lx,t_VEC);
                    824:   for (i=1; i<lx; i++) y[i] = coeff(m,i,i);
                    825:   return y;
                    826: }
                    827:
                    828: /* same, public function */
                    829: GEN
                    830: mattodiagonal(GEN m)
                    831: {
                    832:   long i, lx = lg(m);
                    833:   GEN y = cgetg(lx,t_VEC);
                    834:
                    835:   if (typ(m)!=t_MAT) err(typeer,"mattodiagonal");
                    836:   for (i=1; i<lx; i++) y[i] = lcopy(gcoeff(m,i,i));
                    837:   return y;
                    838: }
                    839:
                    840: /*******************************************************************/
                    841: /*                                                                 */
                    842: /*                    ADDITION SCALAR + MATRIX                     */
                    843: /*                                                                 */
                    844: /*******************************************************************/
                    845:
                    846: /* create the square matrix x*Id + y */
                    847: GEN
                    848: gaddmat(GEN x, GEN y)
                    849: {
                    850:   long ly,dy,i,j;
                    851:   GEN z;
                    852:
                    853:   ly=lg(y); if (ly==1) return cgetg(1,t_MAT);
                    854:   dy=lg(y[1]);
                    855:   if (typ(y)!=t_MAT || ly!=dy) err(mattype1,"gaddmat");
                    856:   z=cgetg(ly,t_MAT);
                    857:   for (i=1; i<ly; i++)
                    858:   {
                    859:     z[i]=lgetg(dy,t_COL);
                    860:     for (j=1; j<dy; j++)
                    861:       coeff(z,j,i) = i==j? ladd(x,gcoeff(y,j,i)): lcopy(gcoeff(y,j,i));
                    862:   }
                    863:   return z;
                    864: }
                    865:
                    866: /*******************************************************************/
                    867: /*                                                                 */
                    868: /*                       Solve A*X=B (Gauss pivot)                 */
                    869: /*                                                                 */
                    870: /*******************************************************************/
                    871: #define swap(x,y) { long _t=x; x=y; y=_t; }
                    872:
                    873: /* Assume x is a non-empty matrix. Return 0 if maximal pivot should not be
                    874:  * used, and the matrix precision (min real precision of coeffs) otherwise.
                    875:  */
                    876: static long
                    877: matprec(GEN x)
                    878: {
                    879:   long tx,i,j,l, k = VERYBIGINT, lx = lg(x), ly = lg(x[1]);
                    880:   GEN p1;
                    881:   for (i=1; i<lx; i++)
                    882:     for (j=1; j<ly; j++)
                    883:     {
                    884:       p1 = gmael(x,i,j); tx = typ(p1);
                    885:       if (!is_scalar_t(tx)) return 0;
                    886:       l = precision(p1); if (l && l<k) k = l;
                    887:     }
                    888:   return (k==VERYBIGINT)? 0: k;
                    889: }
                    890:
                    891: /* As above, returning 1 if the precision would be non-zero, 0 otherwise */
                    892: static long
                    893: use_maximal_pivot(GEN x)
                    894: {
                    895:   long tx,i,j, lx = lg(x), ly = lg(x[1]);
                    896:   GEN p1;
                    897:   for (i=1; i<lx; i++)
                    898:     for (j=1; j<ly; j++)
                    899:     {
                    900:       p1 = gmael(x,i,j); tx = typ(p1);
                    901:       if (!is_scalar_t(tx)) return 0;
                    902:       if (precision(p1)) return 1;
                    903:     }
                    904:   return 0;
                    905: }
                    906:
                    907: static GEN
                    908: check_b(GEN b, long nbli)
                    909: {
                    910:   GEN col;
                    911:   if (!b) return idmat(nbli);
                    912:   col = (typ(b) == t_MAT)? (GEN)b[1]: b;
                    913:   if (nbli != lg(col)-1) err(talker,"incompatible matrix dimensions in gauss");
                    914:   return dummycopy(b);
                    915: }
                    916:
                    917: /* C = A^(-1)(tB) where A, B, C are integral, A is upper triangular, t t_INT */
                    918: GEN
                    919: gauss_triangle_i(GEN A, GEN B, GEN t)
                    920: {
                    921:   long n = lg(A)-1, i,j,k;
                    922:   GEN m, c = cgetg(n+1,t_MAT);
                    923:
                    924:   if (!n) return c;
                    925:   for (k=1; k<=n; k++)
                    926:   {
                    927:     GEN u = cgetg(n+1, t_COL), b = (GEN)B[k];
                    928:     ulong av = avma;
                    929:     c[k] = (long)u; m = mulii((GEN)b[n],t);
                    930:     u[n] = (long)gerepileuptoint(av, divii(m, gcoeff(A,n,n)));
                    931:     for (i=n-1; i>0; i--)
                    932:     {
                    933:       av = avma; m = mulii(negi((GEN)b[i]),t);
                    934:       for (j=i+1; j<=n; j++)
                    935:         m = addii(m, mulii(gcoeff(A,i,j),(GEN) u[j]));
                    936:       u[i] = (long)gerepileuptoint(av, divii(negi(m), gcoeff(A,i,i)));
                    937:     }
                    938:   }
                    939:   return c;
                    940: }
                    941:
                    942: GEN
                    943: gauss_get_col(GEN a, GEN b, GEN p, long li)
                    944: {
                    945:   GEN m, u=cgetg(li+1,t_COL);
                    946:   long i,j;
                    947:
                    948:   u[li] = ldiv((GEN)b[li], p);
                    949:   for (i=li-1; i>0; i--)
                    950:   {
                    951:     m = gneg_i((GEN)b[i]);
                    952:     for (j=i+1; j<=li; j++)
                    953:       m = gadd(m, gmul(gcoeff(a,i,j), (GEN)u[j]));
                    954:     u[i] = ldiv(gneg_i(m), gcoeff(a,i,i));
                    955:   }
                    956:   return u;
                    957: }
                    958:
                    959: GEN
                    960: Fp_gauss_get_col(GEN a, GEN b, GEN piv, long li, GEN p)
                    961: {
                    962:   GEN m, u=cgetg(li+1,t_COL);
                    963:   long i,j;
                    964:
                    965:   u[li] = lresii(mulii((GEN)b[li], mpinvmod(piv,p)), p);
                    966:   for (i=li-1; i>0; i--)
                    967:   {
                    968:     m = (GEN)b[i];
                    969:     for (j=i+1; j<=li; j++)
                    970:       m = subii(m, mulii(gcoeff(a,i,j), (GEN)u[j]));
                    971:     m = resii(m, p);
                    972:     u[i] = lresii(mulii(m, mpinvmod(gcoeff(a,i,i), p)), p);
                    973:   }
                    974:   return u;
                    975: }
                    976:
                    977: /* assume -p < a < p, return 1/a mod p */
                    978: static long
                    979: u_Fp_inv(long a, long p)
                    980: {
                    981:   if (a < 0) a = p + a; /* pb with ulongs < 0 */
                    982:   return u_invmod(a,p);
                    983: }
                    984:
                    985: GEN
                    986: u_Fp_gauss_get_col(GEN a, GEN b, long piv, long li, long p)
                    987: {
                    988:   GEN u=cgetg(li+1,t_VECSMALL);
                    989:   long i,j, m;
                    990:
                    991:   u[li] = (b[li] *  u_Fp_inv(piv,p)) % p;
                    992:   if (u[li] < 0) u[li] += p;
                    993:   for (i=li-1; i>0; i--)
                    994:   {
                    995:     m = b[i];
                    996:     for (j=i+1; j<=li; j++) { m -= coeff(a,i,j) * u[j]; if (m & MASK) m %= p; }
                    997:     u[i] = ((m%p) * u_Fp_inv(coeff(a,i,i), p)) % p;
                    998:     if (u[i] < 0) u[i] += p;
                    999:   }
                   1000:   return u;
                   1001: }
                   1002:
                   1003: /* bk += m * bi */
                   1004: static void
                   1005: _addmul(GEN b, long k, long i, GEN m)
                   1006: {
                   1007:   b[k] = ladd((GEN)b[k], gmul(m, (GEN)b[i]));
                   1008: }
                   1009:
                   1010: /* same, reduce mod p */
                   1011: static void
                   1012: _Fp_addmul(GEN b, long k, long i, GEN m, GEN p)
                   1013: {
                   1014:   if (lgefint(b[i]) > lgefint(p)) b[i] = lresii((GEN)b[i], p);
                   1015:   b[k] = laddii((GEN)b[k], mulii(m, (GEN)b[i]));
                   1016: }
                   1017:
                   1018: static void
                   1019: _u_Fp_addmul(GEN b, long k, long i, long m, long p)
                   1020: {
                   1021:   long a;
                   1022:   if (b[i] & MASK) b[i] %= p;
                   1023:   a = b[k] + m * b[i];
                   1024:   if (a & MASK) a %= p;
                   1025:   b[k] = a;
                   1026: }
                   1027:
                   1028: /* Gaussan Elimination. Compute a^(-1)*b
                   1029:  * b is a matrix or column vector, NULL meaning: take the identity matrix
                   1030:  * If a and b are empty, the result is the empty matrix.
                   1031:  *
                   1032:  * li: nb lines of a and b
                   1033:  * aco: nb columns of a
                   1034:  * bco: nb columns of b (if matrix)
                   1035:  *
                   1036:  * li > aco is allowed if b = NULL, in which case return c such that c a = Id */
                   1037: GEN
                   1038: gauss_intern(GEN a, GEN b)
                   1039: {
                   1040:   long inexact,iscol,i,j,k,av,lim,li,bco, aco = lg(a)-1;
                   1041:   GEN p,m,u;
                   1042:
                   1043:   if (typ(a)!=t_MAT) err(mattype1,"gauss");
                   1044:   if (b && typ(b)!=t_COL && typ(b)!=t_MAT) err(typeer,"gauss");
                   1045:   if (!aco)
                   1046:   {
                   1047:     if (b && lg(b)!=1) err(consister,"gauss");
                   1048:     if (DEBUGLEVEL) err(warner,"in Gauss lg(a)=1 lg(b)=%ld", b?1:-1);
                   1049:     return cgetg(1,t_MAT);
                   1050:   }
                   1051:   av=avma; lim=stack_lim(av,1);
                   1052:   li = lg(a[1])-1;
                   1053:   if (li != aco && (li < aco || b)) err(mattype1,"gauss");
                   1054:   a = dummycopy(a);
                   1055:   b = check_b(b,li); bco = lg(b)-1;
                   1056:   inexact = use_maximal_pivot(a);
                   1057:   iscol   = (typ(b)==t_COL);
                   1058:   if(DEBUGLEVEL>4)
                   1059:     fprintferr("Entering gauss with inexact=%ld iscol=%ld\n",inexact,iscol);
                   1060:
                   1061:   p = NULL; /* gcc -Wall */
                   1062:   for (i=1; i<=aco; i++)
                   1063:   {
                   1064:     /* k is the line where we find the pivot */
                   1065:     p = gcoeff(a,i,i); k = i;
                   1066:     if (inexact) /* maximal pivot */
                   1067:     {
                   1068:       long e, ex = gexpo(p);
                   1069:       for (j=i+1; j<=li; j++)
                   1070:       {
                   1071:         e = gexpo(gcoeff(a,j,i));
                   1072:         if (e > ex) { ex=e; k=j; }
                   1073:       }
                   1074:       if (gcmp0(gcoeff(a,k,i))) return NULL;
                   1075:     }
                   1076:     else if (gcmp0(p)) /* first non-zero pivot */
                   1077:     {
                   1078:       do k++; while (k<=li && gcmp0(gcoeff(a,k,i)));
                   1079:       if (k>li) return NULL;
                   1080:     }
                   1081:
                   1082:     /* if (k!=i), exchange the lines s.t. k = i */
                   1083:     if (k != i)
                   1084:     {
                   1085:       for (j=i; j<=aco; j++) swap(coeff(a,i,j), coeff(a,k,j));
                   1086:       if (iscol) { swap(b[i],b[k]); }
                   1087:       else
                   1088:         for (j=1; j<=bco; j++) swap(coeff(b,i,j), coeff(b,k,j));
                   1089:       p = gcoeff(a,i,i);
                   1090:     }
                   1091:     if (i == aco) break;
                   1092:
                   1093:     for (k=i+1; k<=li; k++)
                   1094:     {
                   1095:       m=gcoeff(a,k,i);
                   1096:       if (!gcmp0(m))
                   1097:       {
                   1098:        m = gneg_i(gdiv(m,p));
                   1099:        for (j=i+1; j<=aco; j++) _addmul((GEN)a[j],k,i,m);
                   1100:        if (iscol) _addmul(b,k,i,m);
                   1101:         else
                   1102:           for (j=1; j<=bco; j++) _addmul((GEN)b[j],k,i,m);
                   1103:       }
                   1104:     }
                   1105:     if (low_stack(lim, stack_lim(av,1)))
                   1106:     {
                   1107:       GEN *gptr[2]; gptr[0]=&a; gptr[1]=&b;
                   1108:       if(DEBUGMEM>1) err(warnmem,"gauss. i=%ld",i);
                   1109:       gerepilemany(av,gptr,2);
                   1110:     }
                   1111:   }
                   1112:
                   1113:   if(DEBUGLEVEL>4) fprintferr("Solving the triangular system\n");
                   1114:   if (iscol) u = gauss_get_col(a,b,p,aco);
                   1115:   else
                   1116:   {
                   1117:     long av1 = avma;
                   1118:     lim = stack_lim(av1,1); u=cgetg(bco+1,t_MAT);
                   1119:     for (j=2; j<=bco; j++) u[j] = zero; /* dummy */
                   1120:     for (j=1; j<=bco; j++)
                   1121:     {
                   1122:       u[j] = (long)gauss_get_col(a,(GEN)b[j],p,aco);
                   1123:       if (low_stack(lim, stack_lim(av1,1)))
                   1124:       {
                   1125:         if(DEBUGMEM>1) err(warnmem,"gauss[2]. j=%ld", j);
                   1126:         u = gerepilecopy(av1, u);
                   1127:       }
                   1128:     }
                   1129:   }
                   1130:   return gerepilecopy(av, u);
                   1131: }
                   1132:
                   1133: GEN
                   1134: gauss(GEN a, GEN b)
                   1135: {
                   1136:   GEN z = gauss_intern(a,b);
                   1137:   if (!z) err(matinv1);
                   1138:   return z;
                   1139: }
                   1140:
                   1141: GEN
                   1142: u_FpM_gauss(GEN a, GEN b, long p)
                   1143: {
                   1144:   long piv,m,iscol,i,j,k,li,bco, aco = lg(a)-1;
                   1145:   GEN u;
                   1146:
                   1147:   if (!aco) return cgetg(1,t_MAT);
                   1148:   li = lg(a[1])-1;
                   1149:   bco = lg(b)-1;
                   1150:   iscol = (typ(b)==t_COL);
                   1151:   piv = 0; /* gcc -Wall */
                   1152:   for (i=1; i<=aco; i++)
                   1153:   {
                   1154:     /* k is the line where we find the pivot */
                   1155:     coeff(a,i,i) = coeff(a,i,i) % p;
                   1156:     piv = coeff(a,i,i); k = i;
                   1157:     if (!piv)
                   1158:     {
                   1159:       for (k++; k <= li; k++)
                   1160:       {
                   1161:         coeff(a,k,i) %= p;
                   1162:         if (coeff(a,k,i)) break;
                   1163:       }
                   1164:       if (k>li) return NULL;
                   1165:     }
                   1166:
                   1167:     /* if (k!=i), exchange the lines s.t. k = i */
                   1168:     if (k != i)
                   1169:     {
                   1170:       for (j=i; j<=aco; j++) swap(coeff(a,i,j), coeff(a,k,j));
                   1171:       if (iscol) { swap(b[i],b[k]); }
                   1172:       else
                   1173:         for (j=1; j<=bco; j++) swap(coeff(b,i,j), coeff(b,k,j));
                   1174:       piv = coeff(a,i,i);
                   1175:     }
                   1176:     if (i == aco) break;
                   1177:
                   1178:     for (k=i+1; k<=li; k++)
                   1179:     {
                   1180:       coeff(a,k,i) %= p;
                   1181:       m = coeff(a,k,i); coeff(a,k,i) = 0;
                   1182:       if (m)
                   1183:       {
                   1184:        m = - (m * u_Fp_inv(piv,p)) % p;
                   1185:        for (j=i+1; j<=aco; j++) _u_Fp_addmul((GEN)a[j],k,i,m, p);
                   1186:        if (iscol) _u_Fp_addmul(b,k,i,m, p);
                   1187:         else
                   1188:           for (j=1; j<=bco; j++) _u_Fp_addmul((GEN)b[j],k,i,m, p);
                   1189:       }
                   1190:     }
                   1191:   }
                   1192:   if (iscol) u = u_Fp_gauss_get_col(a,b,piv,aco,p);
                   1193:   else
                   1194:   {
                   1195:     u=cgetg(bco+1,t_MAT);
                   1196:     for (j=1; j<=bco; j++)
                   1197:       u[j] = (long)u_Fp_gauss_get_col(a,(GEN)b[j],piv,aco,p);
                   1198:   }
                   1199:   return u;
                   1200: }
                   1201:
                   1202: GEN
                   1203: FpM_gauss(GEN a, GEN b, GEN p)
                   1204: {
                   1205:   long iscol,i,j,k,av,lim,li,bco, aco = lg(a)-1;
                   1206:   GEN piv,m,u;
                   1207:
                   1208:   if (typ(a)!=t_MAT) err(mattype1,"gauss");
                   1209:   if (b && typ(b)!=t_COL && typ(b)!=t_MAT) err(typeer,"gauss");
                   1210:   if (!aco)
                   1211:   {
                   1212:     if (b && lg(b)!=1) err(consister,"gauss");
                   1213:     if (DEBUGLEVEL) err(warner,"in Gauss lg(a)=1 lg(b)=%ld", b?1:-1);
                   1214:     return cgetg(1,t_MAT);
                   1215:   }
                   1216:   li = lg(a[1])-1;
                   1217:   if (li != aco && (li < aco || b)) err(mattype1,"gauss");
                   1218:   b = check_b(b,li); av = avma;
                   1219:   if (OK_ULONG(p))
                   1220:   {
                   1221:     ulong pp=p[2];
                   1222:     a = u_Fp_FpM(a, pp);
                   1223:     b = u_Fp_FpM(b, pp);
                   1224:     u = u_FpM_gauss(a,b, pp);
                   1225:     return gerepileupto(av, small_to_mat(u));
                   1226:   }
                   1227:   lim = stack_lim(av,1);
                   1228:   a = dummycopy(a);
                   1229:   bco = lg(b)-1;
                   1230:   iscol = (typ(b)==t_COL);
                   1231:   piv = NULL; /* gcc -Wall */
                   1232:   for (i=1; i<=aco; i++)
                   1233:   {
                   1234:     /* k is the line where we find the pivot */
                   1235:     coeff(a,i,i) = lresii(gcoeff(a,i,i), p);
                   1236:     piv = gcoeff(a,i,i); k = i;
                   1237:     if (!signe(piv))
                   1238:     {
                   1239:       for (k++; k <= li; k++)
                   1240:       {
                   1241:         coeff(a,k,i) = lresii(gcoeff(a,k,i), p);
                   1242:         if (signe(coeff(a,k,i))) break;
                   1243:       }
                   1244:       if (k>li) return NULL;
                   1245:     }
                   1246:
                   1247:     /* if (k!=i), exchange the lines s.t. k = i */
                   1248:     if (k != i)
                   1249:     {
                   1250:       for (j=i; j<=aco; j++) swap(coeff(a,i,j), coeff(a,k,j));
                   1251:       if (iscol) { swap(b[i],b[k]); }
                   1252:       else
                   1253:         for (j=1; j<=bco; j++) swap(coeff(b,i,j), coeff(b,k,j));
                   1254:       piv = gcoeff(a,i,i);
                   1255:     }
                   1256:     if (i == aco) break;
                   1257:
                   1258:     for (k=i+1; k<=li; k++)
                   1259:     {
                   1260:       coeff(a,k,i) = lresii(gcoeff(a,k,i), p);
                   1261:       m = gcoeff(a,k,i); coeff(a,k,i) = zero;
                   1262:       if (signe(m))
                   1263:       {
                   1264:        m = mulii(m, mpinvmod(piv,p));
                   1265:         m = resii(negi(m), p);
                   1266:        for (j=i+1; j<=aco; j++) _Fp_addmul((GEN)a[j],k,i,m, p);
                   1267:        if (iscol) _Fp_addmul(b,k,i,m, p);
                   1268:         else
                   1269:           for (j=1; j<=bco; j++) _Fp_addmul((GEN)b[j],k,i,m, p);
                   1270:       }
                   1271:     }
                   1272:     if (low_stack(lim, stack_lim(av,1)))
                   1273:     {
                   1274:       GEN *gptr[2]; gptr[0]=&a; gptr[1]=&b;
                   1275:       if(DEBUGMEM>1) err(warnmem,"FpM_gauss. i=%ld",i);
                   1276:       gerepilemany(av,gptr,2);
                   1277:     }
                   1278:   }
                   1279:
                   1280:   if(DEBUGLEVEL>4) fprintferr("Solving the triangular system\n");
                   1281:   if (iscol) u = Fp_gauss_get_col(a,b,piv,aco,p);
                   1282:   else
                   1283:   {
                   1284:     long av1 = avma;
                   1285:     lim = stack_lim(av1,1); u=cgetg(bco+1,t_MAT);
                   1286:     for (j=2; j<=bco; j++) u[j] = zero; /* dummy */
                   1287:     for (j=1; j<=bco; j++)
                   1288:     {
                   1289:       u[j] = (long)Fp_gauss_get_col(a,(GEN)b[j],piv,aco,p);
                   1290:       if (low_stack(lim, stack_lim(av1,1)))
                   1291:       {
                   1292:         if(DEBUGMEM>1) err(warnmem,"gauss[2]. j=%ld", j);
                   1293:         u = gerepilecopy(av1, u);
                   1294:       }
                   1295:     }
                   1296:   }
                   1297:   return gerepilecopy(av, u);
                   1298: }
                   1299:
                   1300: GEN
                   1301: FpM_inv(GEN x, GEN p) { return FpM_gauss(x, NULL, p); }
                   1302:
                   1303: static GEN
                   1304: u_idmat(long n)
                   1305: {
                   1306:   GEN y = cgetg(n+1,t_MAT);
                   1307:   long i,j;
                   1308:   if (n < 0) err(talker,"negative size in u_idmat");
                   1309:   for (i=1; i<=n; i++)
                   1310:   {
                   1311:     y[i]=lgetg(n+1,t_VECSMALL);
                   1312:     for (j=1; j<=n; j++) coeff(y,j,i) = (i==j)? 1: 0;
                   1313:   }
                   1314:   return y;
                   1315: }
                   1316:
                   1317: /* set y = x * y */
                   1318: #define HIGHWORD(a) ((a) >> BITS_IN_HALFULONG)
                   1319: static GEN
                   1320: u_FpM_Fp_mul_ip(GEN y, long x, long p)
                   1321: {
                   1322:   int i,j, m = lg(y[1]), l = lg(y);
                   1323:   if (HIGHWORD(x | p))
                   1324:     for(j=1; j<l; j++)
                   1325:       for(i=1; i<m; i++)
                   1326:         coeff(y,i,j) = (long)mulssmod(coeff(y,i,j), x, p);
                   1327:   else
                   1328:     for(j=1; j<l; j++)
                   1329:       for(i=1; i<m; i++)
                   1330:         coeff(y,i,j) = (coeff(y,i,j) * x) % p;
                   1331:   return y;
                   1332: }
                   1333:
                   1334: /* M integral, dM such that M' = dM M^-1 is integral [e.g det(M)]. Return M' */
                   1335: GEN
                   1336: ZM_inv(GEN M, GEN dM)
                   1337: {
                   1338:   GEN  ID,Hp,q,H;
                   1339:   ulong p,dMp, av2, av = avma, lim = stack_lim(av,1);
                   1340:   byteptr d = diffptr;
                   1341:   long lM = lg(M), stable = 0;
                   1342:
                   1343:   if (lM == 1) return cgetg(1,t_MAT);
                   1344:   if (!dM) dM = det(M);
                   1345:
                   1346:   av2 = avma;
                   1347:   H = NULL;
                   1348:   d += 3000; /* 27449 = prime(3000) */
                   1349:   for(p = 27449; ; p+= *d++)
                   1350:   {
                   1351:     if (!*d) err(primer1);
                   1352:     dMp = umodiu(dM,p);
                   1353:     if (!dMp) continue;
                   1354:     ID = u_idmat(lM-1);
                   1355:     Hp = u_FpM_gauss(u_Fp_FpM(M,p), ID, p);
                   1356:     if (dMp != 1) Hp = u_FpM_Fp_mul_ip(Hp, dMp, p);
                   1357:
                   1358:     if (!H)
                   1359:     {
                   1360:       H = ZM_init_CRT(Hp, p);
                   1361:       q = utoi(p);
                   1362:     }
                   1363:     else
                   1364:     {
                   1365:       GEN qp = muliu(q,p);
                   1366:       stable = ZM_incremental_CRT(H, Hp, q,qp, p);
                   1367:       q = qp;
                   1368:     }
                   1369:     if (DEBUGLEVEL>5) msgtimer("inverse mod %ld (stable=%ld)", p,stable);
                   1370:     if (stable && isscalarmat(gmul(M, H), dM)) break; /* DONE */
                   1371:
                   1372:     if (low_stack(lim, stack_lim(av,2)))
                   1373:     {
                   1374:       GEN *gptr[2]; gptr[0] = &H; gptr[1] = &q;
                   1375:       if (DEBUGMEM>1) err(warnmem,"ZM_inv");
                   1376:       gerepilemany(av2,gptr, 2);
                   1377:     }
                   1378:
                   1379:   }
                   1380:   if (DEBUGLEVEL>5) msgtimer("ZM_inv done");
                   1381:   return gerepilecopy(av, H);
                   1382: }
                   1383:
                   1384: /* same as above, M rational */
                   1385: GEN
                   1386: QM_inv(GEN M, GEN dM)
                   1387: {
                   1388:   ulong av = avma;
                   1389:   GEN cM = content(M);
                   1390:   if (is_pm1(cM)) { avma = av; return ZM_inv(M,dM); }
                   1391:   return gerepileupto(av, ZM_inv(gdiv(M,cM), gdiv(dM,cM)));
                   1392: }
                   1393:
                   1394: /* x a matrix with integer coefficients. Return a multiple of the determinant
                   1395:  * of the lattice generated by the columns of x (to be used with hnfmod)
                   1396:  */
                   1397: GEN
                   1398: detint(GEN x)
                   1399: {
                   1400:   GEN pass,c,v,det1,piv,pivprec,vi,p1;
                   1401:   long i,j,k,rg,n,m,m1,av=avma,av1,lim;
                   1402:
                   1403:   if (typ(x)!=t_MAT) err(typeer,"detint");
                   1404:   n=lg(x)-1; if (!n) return gun;
                   1405:   m1=lg(x[1]); m=m1-1; lim=stack_lim(av,1);
                   1406:   c=new_chunk(m1); for (k=1; k<=m; k++) c[k]=0;
                   1407:   av1=avma; pass=cgetg(m1,t_MAT);
                   1408:   for (j=1; j<=m; j++)
                   1409:   {
                   1410:     p1=cgetg(m1,t_COL); pass[j]=(long)p1;
                   1411:     for (i=1; i<=m; i++) p1[i]=zero;
                   1412:   }
                   1413:   for (k=1; k<=n; k++)
                   1414:     for (j=1; j<=m; j++)
                   1415:       if (typ(gcoeff(x,j,k)) != t_INT)
                   1416:         err(talker,"not an integer matrix in detint");
                   1417:   v=cgetg(m1,t_COL);
                   1418:   det1=gzero; piv=pivprec=gun;
                   1419:   for (rg=0,k=1; k<=n; k++)
                   1420:   {
                   1421:     long t = 0;
                   1422:     for (i=1; i<=m; i++)
                   1423:       if (!c[i])
                   1424:       {
                   1425:        vi=mulii(piv,gcoeff(x,i,k));
                   1426:        for (j=1; j<=m; j++)
                   1427:          if (c[j]) vi=addii(vi,mulii(gcoeff(pass,i,j),gcoeff(x,j,k)));
                   1428:        v[i]=(long)vi; if (!t && signe(vi)) t=i;
                   1429:       }
                   1430:     if (t)
                   1431:     {
                   1432:       if (rg == m-1)
                   1433:         { det1=mppgcd((GEN)v[t],det1); c[t]=0; }
                   1434:       else
                   1435:       {
                   1436:         rg++; pivprec = piv; piv=(GEN)v[t]; c[t]=k;
                   1437:        for (i=1; i<=m; i++)
                   1438:          if (!c[i])
                   1439:          {
                   1440:             GEN p2 = negi((GEN)v[i]);
                   1441:            for (j=1; j<=m; j++)
                   1442:              if (c[j] && j!=t)
                   1443:              {
                   1444:                p1 = addii(mulii(gcoeff(pass,i,j), piv),
                   1445:                           mulii(gcoeff(pass,t,j), p2));
                   1446:                 if (rg>1) p1 = divii(p1,pivprec);
                   1447:                coeff(pass,i,j) = (long)p1;
                   1448:              }
                   1449:            coeff(pass,i,t) = (long)p2;
                   1450:          }
                   1451:       }
                   1452:     }
                   1453:     if (low_stack(lim, stack_lim(av,1)))
                   1454:     {
                   1455:       GEN *gptr[5];
                   1456:       if(DEBUGMEM>1) err(warnmem,"detint. k=%ld",k);
                   1457:       gptr[0]=&det1; gptr[1]=&piv; gptr[2]=&pivprec;
                   1458:       gptr[3]=&pass; gptr[4]=&v; gerepilemany(av1,gptr,5);
                   1459:     }
                   1460:   }
                   1461:   return gerepileupto(av, absi(det1));
                   1462: }
                   1463:
                   1464: static void
                   1465: gerepile_gauss_ker(GEN x, long m, long n, long k, long t, ulong av)
                   1466: {
                   1467:   ulong tetpil = avma,A;
                   1468:   long dec,u,i;
                   1469:
                   1470:   if (DEBUGMEM > 1) err(warnmem,"gauss_pivot_ker. k=%ld, n=%ld",k,n);
                   1471:   for (u=t+1; u<=m; u++) copyifstack(coeff(x,u,k), coeff(x,u,k));
                   1472:   for (i=k+1; i<=n; i++)
                   1473:     for (u=1; u<=m; u++) copyifstack(coeff(x,u,i), coeff(x,u,i));
                   1474:
                   1475:   (void)gerepile(av,tetpil,NULL); dec = av-tetpil;
                   1476:   for (u=t+1; u<=m; u++)
                   1477:   {
                   1478:     A=coeff(x,u,k);
                   1479:     if (A<av && A>=bot) coeff(x,u,k)+=dec;
                   1480:   }
                   1481:   for (i=k+1; i<=n; i++)
                   1482:     for (u=1; u<=m; u++)
                   1483:     {
                   1484:       A=coeff(x,u,i);
                   1485:       if (A<av && A>=bot) coeff(x,u,i)+=dec;
                   1486:     }
                   1487: }
                   1488:
                   1489: static void
                   1490: gerepile_gauss_FpM_ker(GEN x, GEN p, long m, long n, long k, long t, ulong av)
                   1491: {
                   1492:   ulong tetpil = avma,A;
                   1493:   long dec,u,i;
                   1494:
                   1495:   if (DEBUGMEM > 1) err(warnmem,"gauss_pivot_ker. k=%ld, n=%ld",k,n);
                   1496:   for (u=t+1; u<=m; u++)
                   1497:     if (isonstack(coeff(x,u,k))) coeff(x,u,k) = lmodii(gcoeff(x,u,k),p);
                   1498:   for (i=k+1; i<=n; i++)
                   1499:     for (u=1; u<=m; u++)
                   1500:       if (isonstack(coeff(x,u,i))) coeff(x,u,i) = lmodii(gcoeff(x,u,i),p);
                   1501:
                   1502:   (void)gerepile(av,tetpil,NULL); dec = av-tetpil;
                   1503:   for (u=t+1; u<=m; u++)
                   1504:   {
                   1505:     A=coeff(x,u,k);
                   1506:     if (A<av && A>=bot) coeff(x,u,k)+=dec;
                   1507:   }
                   1508:   for (i=k+1; i<=n; i++)
                   1509:     for (u=1; u<=m; u++)
                   1510:     {
                   1511:       A=coeff(x,u,i);
                   1512:       if (A<av && A>=bot) coeff(x,u,i)+=dec;
                   1513:     }
                   1514: }
                   1515:
                   1516: /* special gerepile for huge matrices */
                   1517:
                   1518: static void
                   1519: gerepile_gauss(GEN x,long m,long n,long k,long t,ulong av, long j, GEN c)
                   1520: {
                   1521:   ulong tetpil = avma,A;
                   1522:   long dec,u,i;
                   1523:
                   1524:   if (DEBUGMEM > 1) err(warnmem,"gauss_pivot. k=%ld, n=%ld",k,n);
                   1525:   for (u=t+1; u<=m; u++)
                   1526:     if (u==j || !c[u]) copyifstack(coeff(x,u,k), coeff(x,u,k));
                   1527:   for (u=1; u<=m; u++)
                   1528:     if (u==j || !c[u])
                   1529:       for (i=k+1; i<=n; i++) copyifstack(coeff(x,u,i), coeff(x,u,i));
                   1530:
                   1531:   (void)gerepile(av,tetpil,NULL); dec = av-tetpil;
                   1532:   for (u=t+1; u<=m; u++)
                   1533:     if (u==j || !c[u])
                   1534:     {
                   1535:       A=coeff(x,u,k);
                   1536:       if (A<av && A>=bot) coeff(x,u,k)+=dec;
                   1537:     }
                   1538:   for (u=1; u<=m; u++)
                   1539:     if (u==j || !c[u])
                   1540:       for (i=k+1; i<=n; i++)
                   1541:       {
                   1542:         A=coeff(x,u,i);
                   1543:         if (A<av && A>=bot) coeff(x,u,i)+=dec;
                   1544:       }
                   1545: }
                   1546:
                   1547: /*******************************************************************/
                   1548: /*                                                                 */
                   1549: /*                    KERNEL of an m x n matrix                    */
                   1550: /*          return n - rk(x) linearly independant vectors          */
                   1551: /*                                                                 */
                   1552: /*******************************************************************/
                   1553:
                   1554: /* x has INTEGER coefficients */
                   1555: GEN
                   1556: keri(GEN x)
                   1557: {
                   1558:   GEN c,d,y,p,pp;
                   1559:   long i,j,k,r,t,n,m,av,av0,tetpil,lim;
                   1560:
                   1561:   if (typ(x)!=t_MAT) err(typeer,"keri");
                   1562:   n=lg(x)-1; if (!n) return cgetg(1,t_MAT);
                   1563:
                   1564:   av0=avma; m=lg(x[1])-1; r=0;
                   1565:   pp=cgetg(n+1,t_COL);
                   1566:   x=dummycopy(x); p=gun;
                   1567:   c=new_chunk(m+1); for (k=1; k<=m; k++) c[k]=0;
                   1568:   d=new_chunk(n+1); av=avma; lim=stack_lim(av,1);
                   1569:   for (k=1; k<=n; k++)
                   1570:   {
                   1571:     j=1;
                   1572:     while (j<=m && (c[j] || !signe(gcoeff(x,j,k))) ) j++;
                   1573:     if (j>m)
                   1574:     {
                   1575:       r++; d[k]=0;
                   1576:       for(j=1; j<k; j++)
                   1577:        if (d[j]) coeff(x,d[j],k) = lclone(gcoeff(x,d[j],k));
                   1578:       pp[k]=lclone(p);
                   1579:     }
                   1580:     else
                   1581:     {
                   1582:       GEN p0 = p;
                   1583:       long av1;
                   1584:
                   1585:       c[j]=k; d[k]=j; p = gcoeff(x,j,k);
                   1586:
                   1587:       for (t=1; t<=m; t++)
                   1588:        if (t!=j)
                   1589:        {
                   1590:          GEN q=gcoeff(x,t,k), p1,p2;
                   1591:          for (i=k+1; i<=n; i++)
                   1592:          {
                   1593:            av1=avma; (void)new_chunk(lgefint(p0));
                   1594:            p1=mulii(q,gcoeff(x,j,i));
                   1595:            p2=mulii(p,gcoeff(x,t,i));
                   1596:            p1=subii(p2,p1); avma=av1;
                   1597:            coeff(x,t,i) = ldivii(p1,p0);
                   1598:          }
                   1599:          if (low_stack(lim, stack_lim(av,1)))
                   1600:           {
                   1601:             p1 = gclone(p);
                   1602:             gerepile_gauss_ker(x,m,n,k,t,av);
                   1603:             p = gcopy(p1); gunclone(p1);
                   1604:           }
                   1605:        }
                   1606:     }
                   1607:   }
                   1608:   if (!r) { avma=av0; y=cgetg(1,t_MAT); return y; }
                   1609:
                   1610:   /* non trivial kernel */
                   1611:   tetpil=avma; y=cgetg(r+1,t_MAT);
                   1612:   for (j=k=1; j<=r; j++,k++)
                   1613:   {
                   1614:     p = cgetg(n+1, t_COL);
                   1615:     y[j]=(long)p; while (d[k]) k++;
                   1616:     for (i=1; i<k; i++)
                   1617:       if (d[i])
                   1618:       {
                   1619:        c=gcoeff(x,d[i],k);
                   1620:        p[i] = (long) forcecopy(c); gunclone(c);
                   1621:       }
                   1622:       else
                   1623:        p[i] = zero;
                   1624:     p[k]=lnegi((GEN)pp[k]); gunclone((GEN)pp[k]);
                   1625:     for (i=k+1; i<=n; i++) p[i]=zero;
                   1626:   }
                   1627:   return gerepile(av0,tetpil,y);
                   1628: }
                   1629:
                   1630: GEN
                   1631: deplin(GEN x)
                   1632: {
                   1633:   long i,j,k,t,nc,nl, av=avma;
                   1634:   GEN y,q,c,l,d;
                   1635:
                   1636:   if (typ(x) != t_MAT) err(typeer,"deplin");
                   1637:   nc=lg(x)-1; if (!nc) err(talker,"empty matrix in deplin");
                   1638:   nl=lg(x[1])-1;
                   1639:   c=new_chunk(nl+1);
                   1640:   l=new_chunk(nc+1);
                   1641:   d=cgetg(nl+1,t_VEC);
                   1642:   for (i=1; i<=nl; i++) { d[i]=un; c[i]=0; }
                   1643:   k=1; t=1;
                   1644:   while (t<=nl && k<=nc)
                   1645:   {
                   1646:     for (j=1; j<k; j++)
                   1647:      for (i=1; i<=nl; i++)
                   1648:       if (i!=l[j])
                   1649:        coeff(x,i,k)=lsub(gmul((GEN) d[j],gcoeff(x,i,k)),
                   1650:                          gmul(gcoeff(x,i,j),gcoeff(x,l[j],k)));
                   1651:     t=1;
                   1652:     while ( t<=nl && (c[t] || gcmp0(gcoeff(x,t,k))) ) t++;
                   1653:     if (t<=nl)
                   1654:     {
                   1655:       d[k]=coeff(x,t,k);
                   1656:       c[t]=k; l[k++]=t;
                   1657:     }
                   1658:   }
                   1659:   if (k>nc)
                   1660:   {
                   1661:     avma=av; y=cgetg(nc+1,t_COL);
                   1662:     for (j=1; j<=nc; j++) y[j]=zero;
                   1663:     return y;
                   1664:   }
                   1665:   y=cgetg(nc+1,t_COL);
                   1666:   y[1]=(k>1)? coeff(x,l[1],k): un;
                   1667:   for (q=gun,j=2; j<k; j++)
                   1668:   {
                   1669:     q=gmul(q,(GEN) d[j-1]);
                   1670:     y[j]=lmul(gcoeff(x,l[j],k),q);
                   1671:   }
                   1672:   if (k>1) y[k]=lneg(gmul(q,(GEN) d[k-1]));
                   1673:   for (j=k+1; j<=nc; j++) y[j]=zero;
                   1674:   d=content(y); t=avma;
                   1675:   return gerepile(av,t,gdiv(y,d));
                   1676: }
                   1677:
                   1678: /*******************************************************************/
                   1679: /*                                                                 */
                   1680: /*         GAUSS REDUCTION OF MATRICES  (m lines x n cols)         */
                   1681: /*           (kernel, image, complementary image, rank)            */
                   1682: /*                                                                 */
                   1683: /*******************************************************************/
                   1684: static long gauss_ex;
                   1685: static int (*gauss_is_zero)(GEN);
                   1686:
                   1687: static int
                   1688: real0(GEN x)
                   1689: {
                   1690:   return gcmp0(x) || (gexpo(x) < gauss_ex);
                   1691: }
                   1692:
                   1693: static void
                   1694: gauss_get_prec(GEN x, long prec)
                   1695: {
                   1696:   long pr = matprec(x);
                   1697:
                   1698:   if (!pr) { gauss_is_zero = &gcmp0; return; }
                   1699:   if (pr > prec) prec = pr;
                   1700:
                   1701:   gauss_ex = - (long)(0.85 * bit_accuracy(prec));
                   1702:   gauss_is_zero = &real0;
                   1703: }
                   1704:
                   1705: static long
                   1706: gauss_get_pivot_NZ(GEN x, GEN x0/* unused */, GEN c, long i0)
                   1707: {
                   1708:   long i,lx = lg(x);
                   1709:   if (c)
                   1710:     for (i=i0; i<lx; i++)
                   1711:     {
                   1712:       if (c[i]) continue;
                   1713:       if (!gcmp0((GEN)x[i])) break;
                   1714:     }
                   1715:   else
                   1716:     for (i=i0; i<lx; i++)
                   1717:       if (!gcmp0((GEN)x[i])) break;
                   1718:   return i;
                   1719:
                   1720: }
                   1721:
                   1722: /* ~ 0 compared to reference y */
                   1723: static int
                   1724: approx_0(GEN x, GEN y)
                   1725: {
                   1726:   long tx = typ(x);
                   1727:   if (tx == t_COMPLEX)
                   1728:     return approx_0((GEN)x[1], y) && approx_0((GEN)x[2], y);
                   1729:   return gcmp0(x) ||
                   1730:          (tx == t_REAL && gexpo(y) - gexpo(x) > bit_accuracy(lg(x)));
                   1731: }
                   1732:
                   1733: static long
                   1734: gauss_get_pivot_max(GEN x, GEN x0, GEN c, long i0)
                   1735: {
                   1736:   long i,e, k = i0, ex = -HIGHEXPOBIT, lx = lg(x);
                   1737:   GEN p,r;
                   1738:   if (c)
                   1739:     for (i=i0; i<lx; i++)
                   1740:     {
                   1741:       if (c[i]) continue;
                   1742:       e = gexpo((GEN)x[i]);
                   1743:       if (e > ex) { ex=e; k=i; }
                   1744:     }
                   1745:   else
                   1746:     for (i=i0; i<lx; i++)
                   1747:     {
                   1748:       e = gexpo((GEN)x[i]);
                   1749:       if (e > ex) { ex=e; k=i; }
                   1750:     }
                   1751:   p = (GEN)x[k];
                   1752:   r = (GEN)x0[k]; if (isexactzero(r)) r = x0;
                   1753:   return approx_0(p, r)? i: k;
                   1754: }
                   1755:
                   1756: /* return the transform of x under a standard Gauss pivot. r = dim ker(x).
                   1757:  * d[k] contains the index of the first non-zero pivot in column k
                   1758:  * If a != NULL, use x - a Id instead (for eigen)
                   1759:  */
                   1760: static GEN
                   1761: gauss_pivot_ker(GEN x0, GEN a, GEN *dd, long *rr)
                   1762: {
                   1763:   GEN x,c,d,p,mun;
                   1764:   long i,j,k,r,t,n,m,av,lim;
                   1765:   long (*get_pivot)(GEN,GEN,GEN,long);
                   1766:
                   1767:   if (typ(x0)!=t_MAT) err(typeer,"gauss_pivot");
                   1768:   n=lg(x0)-1; if (!n) { *dd=NULL; *rr=0; return cgetg(1,t_MAT); }
                   1769:   m=lg(x0[1])-1; r=0;
                   1770:
                   1771:   x = dummycopy(x0); mun = negi(gun);
                   1772:   if (a)
                   1773:   {
                   1774:     if (n != m) err(consister,"gauss_pivot_ker");
                   1775:     for (k=1; k<=n; k++) coeff(x,k,k) = lsub(gcoeff(x,k,k), a);
                   1776:   }
                   1777:   get_pivot = use_maximal_pivot(x)? gauss_get_pivot_max: gauss_get_pivot_NZ;
                   1778:   c=cgetg(m+1,t_VECSMALL); for (k=1; k<=m; k++) c[k]=0;
                   1779:   d=cgetg(n+1,t_VECSMALL);
                   1780:   av=avma; lim=stack_lim(av,1);
                   1781:   for (k=1; k<=n; k++)
                   1782:   {
                   1783:     j = get_pivot((GEN)x[k], (GEN)x0[k], c, 1);
                   1784:     if (j > m)
                   1785:     {
                   1786:       r++; d[k]=0;
                   1787:       for(j=1; j<k; j++)
                   1788:         if (d[j]) coeff(x,d[j],k) = lclone(gcoeff(x,d[j],k));
                   1789:     }
                   1790:     else
                   1791:     { /* pivot for column k on row j */
                   1792:       c[j]=k; d[k]=j; p = gdiv(mun,gcoeff(x,j,k));
                   1793:       coeff(x,j,k) = (long)mun;
                   1794:       /* x[j,] /= - x[j,k] */
                   1795:       for (i=k+1; i<=n; i++)
                   1796:        coeff(x,j,i) = lmul(p,gcoeff(x,j,i));
                   1797:       for (t=1; t<=m; t++)
                   1798:        if (t!=j)
                   1799:        { /* x[t,] -= 1 / x[j,k] x[j,] */
                   1800:          p=gcoeff(x,t,k); coeff(x,t,k)=zero;
                   1801:          for (i=k+1; i<=n; i++)
                   1802:            coeff(x,t,i) = ladd(gcoeff(x,t,i),gmul(p,gcoeff(x,j,i)));
                   1803:           if (low_stack(lim, stack_lim(av,1)))
                   1804:             gerepile_gauss_ker(x,m,n,k,t,av);
                   1805:        }
                   1806:     }
                   1807:   }
                   1808:   *dd=d; *rr=r; return x;
                   1809: }
                   1810:
                   1811: /* r = dim ker(x).
                   1812:  * d[k] contains the index of the first non-zero pivot in column k
                   1813:  */
                   1814: static void
                   1815: gauss_pivot(GEN x0, GEN *dd, long *rr)
                   1816: {
                   1817:   GEN x,c,d,d0,mun,p;
                   1818:   long i,j,k,r,t,n,m,av,lim;
                   1819:   long (*get_pivot)(GEN,GEN,GEN,long);
                   1820:
                   1821:   if (typ(x0)!=t_MAT) err(typeer,"gauss_pivot");
                   1822:   n=lg(x0)-1; if (!n) { *dd=NULL; *rr=0; return; }
                   1823:
                   1824:   d0 = cgetg(n+1, t_VECSMALL);
                   1825:   if (use_maximal_pivot(x0))
                   1826:   { /* put exact columns first, then largest inexact ones */
                   1827:     get_pivot = gauss_get_pivot_max;
                   1828:     for (k=1; k<=n; k++)
                   1829:       d0[k] = isinexactreal((GEN)x0[k])? -gexpo((GEN)x0[k]): -VERYBIGINT;
                   1830:     d0 = gen_sort(d0, cmp_C|cmp_IND, NULL);
                   1831:     x0 = vecextract_p(x0, d0);
                   1832:   }
                   1833:   else
                   1834:   {
                   1835:     get_pivot = gauss_get_pivot_NZ;
                   1836:     for (k=1; k<=n; k++) d0[k] = k;
                   1837:   }
                   1838:   x = dummycopy(x0); mun = negi(gun);
                   1839:   m=lg(x[1])-1; r=0;
                   1840:   c=cgetg(m+1, t_VECSMALL); for (k=1; k<=m; k++) c[k]=0;
                   1841:   d=(GEN)gpmalloc((n+1)*sizeof(long)); av=avma; lim=stack_lim(av,1);
                   1842:   for (k=1; k<=n; k++)
                   1843:   {
                   1844:     j = get_pivot((GEN)x[k], (GEN)x0[k], c, 1);
                   1845:     if (j>m) { r++; d[d0[k]]=0; }
                   1846:     else
                   1847:     {
                   1848:       c[j]=k; d[d0[k]]=j; p = gdiv(mun,gcoeff(x,j,k));
                   1849:       for (i=k+1; i<=n; i++)
                   1850:        coeff(x,j,i) = lmul(p,gcoeff(x,j,i));
                   1851:
                   1852:       for (t=1; t<=m; t++)
                   1853:         if (!c[t]) /* no pivot on that line yet */
                   1854:         {
                   1855:           p=gcoeff(x,t,k); coeff(x,t,k)=zero;
                   1856:           for (i=k+1; i<=n; i++)
                   1857:             coeff(x,t,i) = ladd(gcoeff(x,t,i), gmul(p,gcoeff(x,j,i)));
                   1858:           if (low_stack(lim, stack_lim(av,1)))
                   1859:             gerepile_gauss(x,m,n,k,t,av,j,c);
                   1860:         }
                   1861:       for (i=k; i<=n; i++) coeff(x,j,i) = zero; /* dummy */
                   1862:     }
                   1863:   }
                   1864:   *dd=d; *rr=r;
                   1865: }
                   1866:
                   1867: /* compute ker(x - aI) */
                   1868: static GEN
                   1869: ker0(GEN x, GEN a)
                   1870: {
                   1871:   GEN d,y;
                   1872:   long i,j,k,r,n, av = avma, tetpil;
                   1873:
                   1874:   x = gauss_pivot_ker(x,a,&d,&r);
                   1875:   if (!r) { avma=av; return cgetg(1,t_MAT); }
                   1876:   n = lg(x)-1; tetpil=avma; y=cgetg(r+1,t_MAT);
                   1877:   for (j=k=1; j<=r; j++,k++)
                   1878:   {
                   1879:     GEN p = cgetg(n+1,t_COL);
                   1880:
                   1881:     y[j]=(long)p; while (d[k]) k++;
                   1882:     for (i=1; i<k; i++)
                   1883:       if (d[i])
                   1884:       {
                   1885:        GEN p1=gcoeff(x,d[i],k);
                   1886:        p[i] = (long)forcecopy(p1); gunclone(p1);
                   1887:       }
                   1888:       else
                   1889:        p[i] = zero;
                   1890:     p[k]=un; for (i=k+1; i<=n; i++) p[i]=zero;
                   1891:   }
                   1892:   return gerepile(av,tetpil,y);
                   1893: }
                   1894:
                   1895: GEN
                   1896: ker(GEN x) /* Programme pour types exacts */
                   1897: {
                   1898:   return ker0(x,NULL);
                   1899: }
                   1900:
                   1901: GEN
                   1902: matker0(GEN x,long flag)
                   1903: {
                   1904:   return flag? keri(x): ker(x);
                   1905: }
                   1906:
                   1907: GEN
                   1908: image(GEN x)
                   1909: {
                   1910:   GEN d,y;
                   1911:   long j,k,r, av = avma;
                   1912:
                   1913:   gauss_pivot(x,&d,&r);
                   1914:
                   1915:   /* r = dim ker(x) */
                   1916:   if (!r) { avma=av; if (d) free(d); return gcopy(x); }
                   1917:
                   1918:   /* r = dim Im(x) */
                   1919:   r = lg(x)-1 - r; avma=av;
                   1920:   y=cgetg(r+1,t_MAT);
                   1921:   for (j=k=1; j<=r; k++)
                   1922:     if (d[k]) y[j++] = lcopy((GEN)x[k]);
                   1923:   free(d); return y;
                   1924: }
                   1925:
                   1926: GEN
                   1927: imagecompl(GEN x)
                   1928: {
                   1929:   GEN d,y;
                   1930:   long j,i,r,av = avma;
                   1931:
                   1932:   gauss_pivot(x,&d,&r);
                   1933:   avma=av; y=cgetg(r+1,t_VEC);
                   1934:   for (i=j=1; j<=r; i++)
                   1935:     if (!d[i]) y[j++]=lstoi(i);
                   1936:   if (d) free(d); return y;
                   1937: }
                   1938:
                   1939: /* for hnfspec: imagecompl(trans(x)) + image(trans(x)) */
                   1940: GEN
                   1941: imagecomplspec(GEN x, long *nlze)
                   1942: {
                   1943:   GEN d,y;
                   1944:   long i,j,k,l,r,av = avma;
                   1945:
                   1946:   x = gtrans(x); l = lg(x);
                   1947:   gauss_pivot(x,&d,&r);
                   1948:   avma=av; y = cgetg(l,t_VECSMALL);
                   1949:   for (i=j=1, k=r+1; i<l; i++)
                   1950:     if (d[i]) y[k++]=i; else y[j++]=i;
                   1951:   *nlze = r;
                   1952:   if (d) free(d); return y;
                   1953: }
                   1954:
                   1955: static GEN
                   1956: sinverseimage(GEN mat, GEN y)
                   1957: {
                   1958:   long av=avma,tetpil,i, nbcol = lg(mat);
                   1959:   GEN col,p1 = cgetg(nbcol+1,t_MAT);
                   1960:
                   1961:   if (nbcol==1) return NULL;
                   1962:   if (lg(y) != lg(mat[1])) err(consister,"inverseimage");
                   1963:
                   1964:   p1[nbcol] = (long)y;
                   1965:   for (i=1; i<nbcol; i++) p1[i]=mat[i];
                   1966:   p1 = ker(p1); i=lg(p1)-1;
                   1967:   if (!i) return NULL;
                   1968:
                   1969:   col = (GEN)p1[i]; p1 = (GEN) col[nbcol];
                   1970:   if (gcmp0(p1)) return NULL;
                   1971:
                   1972:   p1 = gneg_i(p1); setlg(col,nbcol); tetpil=avma;
                   1973:   return gerepile(av,tetpil, gdiv(col, p1));
                   1974: }
                   1975:
                   1976: /* Calcule l'image reciproque de v par m */
                   1977: GEN
                   1978: inverseimage(GEN m,GEN v)
                   1979: {
                   1980:   long av=avma,j,lv,tv=typ(v);
                   1981:   GEN y,p1;
                   1982:
                   1983:   if (typ(m)!=t_MAT) err(typeer,"inverseimage");
                   1984:   if (tv==t_COL)
                   1985:   {
                   1986:     p1 = sinverseimage(m,v);
                   1987:     if (p1) return p1;
                   1988:     avma = av; return cgetg(1,t_MAT);
                   1989:   }
                   1990:   if (tv!=t_MAT) err(typeer,"inverseimage");
                   1991:
                   1992:   lv=lg(v)-1; y=cgetg(lv+1,t_MAT);
                   1993:   for (j=1; j<=lv; j++)
                   1994:   {
                   1995:     p1 = sinverseimage(m,(GEN)v[j]);
                   1996:     if (!p1) { avma = av; return cgetg(1,t_MAT); }
                   1997:     y[j] = (long)p1;
                   1998:   }
                   1999:   return y;
                   2000: }
                   2001:
                   2002: /* x is an n x k matrix, rank(x) = k <= n. Return an invertible n x n matrix
                   2003:  * whose first k columns are given by x. If rank(x)<k, the result may be wrong
                   2004:  */
                   2005: GEN
                   2006: suppl_intern(GEN x, GEN myid)
                   2007: {
                   2008:   long av = avma, lx = lg(x), n,i,j;
                   2009:   GEN y,p1;
                   2010:   stackzone *zone;
                   2011:
                   2012:   if (typ(x) != t_MAT) err(typeer,"suppl");
                   2013:   if (lx==1) err(talker,"empty matrix in suppl");
                   2014:   n=lg(x[1]); if (lx>n) err(suppler2);
                   2015:   if (lx == n) return gcopy(x);
                   2016:
                   2017:   zone  = switch_stack(NULL, n*n);
                   2018:   switch_stack(zone,1);
                   2019:   y = myid? dummycopy(myid): idmat(n-1);
                   2020:   switch_stack(zone,0);
                   2021:   gauss_get_prec(x,0);
                   2022:   for (i=1; i<lx; i++)
                   2023:   {
                   2024:     p1 = gauss(y,(GEN)x[i]); j=i;
                   2025:     while (j<n && gauss_is_zero((GEN)p1[j])) j++;
                   2026:     if (j>=n) err(suppler2);
                   2027:     p1=(GEN)y[i]; y[i]=x[i]; if (i!=j) y[j]=(long)p1;
                   2028:   }
                   2029:   avma = av; y = gcopy(y);
                   2030:   free(zone); return y;
                   2031: }
                   2032:
                   2033: GEN
                   2034: suppl(GEN x)
                   2035: {
                   2036:   return suppl_intern(x,NULL);
                   2037: }
                   2038:
                   2039: GEN
                   2040: image2(GEN x)
                   2041: {
                   2042:   long av=avma,tetpil,k,n,i;
                   2043:   GEN p1,p2;
                   2044:
                   2045:   if (typ(x)!=t_MAT) err(typeer,"image2");
                   2046:   k=lg(x)-1; if (!k) return gcopy(x);
                   2047:   n=lg(x[1])-1; p1=ker(x); k=lg(p1)-1;
                   2048:   if (k) { p1=suppl(p1); n=lg(p1)-1; }
                   2049:   else p1=idmat(n);
                   2050:
                   2051:   tetpil=avma; p2=cgetg(n-k+1,t_MAT);
                   2052:   for (i=k+1; i<=n; i++) p2[i-k]=lmul(x,(GEN) p1[i]);
                   2053:   return gerepile(av,tetpil,p2);
                   2054: }
                   2055:
                   2056: GEN
                   2057: matimage0(GEN x,long flag)
                   2058: {
                   2059:   switch(flag)
                   2060:   {
                   2061:     case 0: return image(x);
                   2062:     case 1: return image2(x);
                   2063:     default: err(flagerr,"matimage");
                   2064:   }
                   2065:   return NULL; /* not reached */
                   2066: }
                   2067:
                   2068: long
                   2069: rank(GEN x)
                   2070: {
                   2071:   long av = avma, r;
                   2072:   GEN d;
                   2073:
                   2074:   gauss_pivot(x,&d,&r);
                   2075:   /* yield r = dim ker(x) */
                   2076:
                   2077:   avma=av; if (d) free(d);
                   2078:   return lg(x)-1 - r;
                   2079: }
                   2080:
                   2081: static void FpM_gauss_pivot(GEN x, GEN p, GEN *dd, long *rr);
                   2082:
                   2083: /* if p != NULL, assume x integral and compute rank over Fp */
                   2084: static GEN
                   2085: indexrank0(GEN x, GEN p, int small)
                   2086: {
                   2087:   long av = avma, i,j,n,r;
                   2088:   GEN res,d,p1,p2;
                   2089:
                   2090:   /* yield r = dim ker(x) */
                   2091:   FpM_gauss_pivot(x,p,&d,&r);
                   2092:
                   2093:   /* now r = dim Im(x) */
                   2094:   n = lg(x)-1; r = n - r;
                   2095:
                   2096:   avma=av; res=cgetg(3,t_VEC);
                   2097:   p1=cgetg(r+1,small? t_VECSMALL: t_VEC); res[1]=(long)p1;
                   2098:   p2=cgetg(r+1,small? t_VECSMALL: t_VEC); res[2]=(long)p2;
                   2099:   if (d)
                   2100:   {
                   2101:     for (i=0,j=1; j<=n; j++)
                   2102:       if (d[j]) { i++; p1[i]=d[j]; p2[i]=j; }
                   2103:     free(d);
                   2104:     qsort(p1+1,r,sizeof(long),(QSCOMP)pari_compare_long);
                   2105:   }
                   2106:   if (!small)
                   2107:     for (i=1;i<=r;i++) { p1[i]=lstoi(p1[i]); p2[i]=lstoi(p2[i]); }
                   2108:   return res;
                   2109: }
                   2110:
                   2111: GEN
                   2112: indexrank(GEN x) { return indexrank0(x,NULL,0); }
                   2113:
                   2114: GEN
                   2115: sindexrank(GEN x) { return indexrank0(x,NULL,1); }
                   2116:
                   2117: GEN
                   2118: FpM_sindexrank(GEN x, GEN p) { return indexrank0(x,p,1); }
                   2119:
                   2120: /*******************************************************************/
                   2121: /*                                                                 */
                   2122: /*                    LINEAR ALGEBRA MODULO P                      */
                   2123: /*                                                                 */
                   2124: /*******************************************************************/
                   2125:
                   2126: /*If p is NULL no reduction is performed.*/
                   2127: GEN
                   2128: FpM_mul(GEN x, GEN y, GEN p)
                   2129: {
                   2130:   long i,j,l,lx=lg(x), ly=lg(y);
                   2131:   GEN z;
                   2132:   if (ly==1) return cgetg(ly,t_MAT);
                   2133:   if (lx != lg(y[1])) err(operi,"* [mod p]",t_MAT,t_MAT);
                   2134:   z=cgetg(ly,t_MAT);
                   2135:   if (lx==1)
                   2136:   {
                   2137:     for (i=1; i<ly; i++) z[i]=lgetg(1,t_COL);
                   2138:     return z;
                   2139:   }
                   2140:   l=lg(x[1]);
                   2141:   for (j=1; j<ly; j++)
                   2142:   {
                   2143:     z[j] = lgetg(l,t_COL);
                   2144:     for (i=1; i<l; i++)
                   2145:     {
                   2146:       ulong av;
                   2147:       GEN p1,p2;
                   2148:       int k;
                   2149:       p1=gzero; av=avma;
                   2150:       for (k=1; k<lx; k++)
                   2151:       {
                   2152:        p2=mulii(gcoeff(x,i,k),gcoeff(y,k,j));
                   2153:        p1=addii(p1,p2);
                   2154:       }
                   2155:       coeff(z,i,j)=lpileupto(av,p?modii(p1,p):p1);
                   2156:     }
                   2157:   }
                   2158:   return z;
                   2159: }
                   2160:
                   2161: /*If p is NULL no reduction is performed.*/
                   2162: GEN
                   2163: FpM_FpV_mul(GEN x, GEN y, GEN p)
                   2164: {
                   2165:   long i,l,lx=lg(x), ly=lg(y);
                   2166:   GEN z;
                   2167:   if (lx != ly) err(operi,"* [mod p]",t_MAT,t_COL);
                   2168:   z=cgetg(ly,t_COL);
                   2169:   if (lx==1) return cgetg(1,t_COL);
                   2170:   l=lg(x[1]);
                   2171:   for (i=1; i<l; i++)
                   2172:   {
                   2173:     ulong av;
                   2174:     GEN p1,p2;
                   2175:     int k;
                   2176:     p1=gzero; av=avma;
                   2177:     for (k=1; k<lx; k++)
                   2178:     {
                   2179:       p2=mulii(gcoeff(x,i,k),(GEN)y[k]);
                   2180:       p1=addii(p1,p2);
                   2181:     }
                   2182:     z[i]=lpileupto(av,p?modii(p1,p):p1);
                   2183:   }
                   2184:   return z;
                   2185: }
                   2186:
                   2187: static GEN
                   2188: u_FpM_ker(GEN x, GEN pp, long nontriv)
                   2189: {
                   2190:   GEN y,c,d;
                   2191:   long a,i,j,k,r,t,n,m,av0,tetpil, p = pp[2], piv;
                   2192:
                   2193:   n = lg(x)-1;
                   2194:   m=lg(x[1])-1; r=0; av0 = avma;
                   2195:   x = dummycopy(x);
                   2196:   for (i=1; i<=n; i++)
                   2197:   {
                   2198:     GEN p1 = (GEN)x[i];
                   2199:     for (j=1; j<=m; j++) p1[j] = itos((GEN)p1[j]);
                   2200:   }
                   2201:   c=new_chunk(m+1); for (k=1; k<=m; k++) c[k]=0;
                   2202:   d=new_chunk(n+1);
                   2203:   a=0; /* for gcc -Wall */
                   2204:   for (k=1; k<=n; k++)
                   2205:   {
                   2206:     for (j=1; j<=m; j++)
                   2207:       if (!c[j])
                   2208:       {
                   2209:         a = coeff(x,j,k) % p;
                   2210:         if (a) break;
                   2211:       }
                   2212:     if (j>m)
                   2213:     {
                   2214:       if (nontriv) { avma=av0; return NULL; }
                   2215:       r++; d[k]=0;
                   2216:     }
                   2217:     else
                   2218:     {
                   2219:       c[j]=k; d[k]=j;
                   2220:       piv = - u_Fp_inv(a, p);
                   2221:       coeff(x,j,k) = -1;
                   2222:       for (i=k+1; i<=n; i++)
                   2223:        coeff(x,j,i) = (piv * coeff(x,j,i)) % p;
                   2224:       for (t=1; t<=m; t++)
                   2225:        if (t!=j)
                   2226:        {
                   2227:          piv = coeff(x,t,k) % p;
                   2228:           if (piv)
                   2229:           {
                   2230:             coeff(x,t,k) = 0;
                   2231:             for (i=k+1; i<=n; i++) _u_Fp_addmul((GEN)x[i],t,j,piv,p);
                   2232:           }
                   2233:        }
                   2234:     }
                   2235:   }
                   2236:
                   2237:   tetpil=avma; y=cgetg(r+1,t_MAT);
                   2238:   for (j=k=1; j<=r; j++,k++)
                   2239:   {
                   2240:     GEN c = cgetg(n+1,t_COL);
                   2241:
                   2242:     y[j]=(long)c; while (d[k]) k++;
                   2243:     for (i=1; i<k; i++)
                   2244:       if (d[i])
                   2245:       {
                   2246:         long a = coeff(x,d[i],k) % p;
                   2247:         if (a < 0) a += p;
                   2248:        c[i] = lstoi(a);
                   2249:       }
                   2250:       else
                   2251:        c[i] = zero;
                   2252:     c[k]=un; for (i=k+1; i<=n; i++) c[i]=zero;
                   2253:   }
                   2254:   return gerepile(av0,tetpil,y);
                   2255: }
                   2256:
                   2257: static GEN
                   2258: FpM_ker_i(GEN x, GEN p, long nontriv)
                   2259: {
                   2260:   GEN y,c,d,piv,mun;
                   2261:   long i,j,k,r,t,n,m,av0,av,lim,tetpil;
                   2262:
                   2263:   if (typ(x)!=t_MAT) err(typeer,"FpM_ker");
                   2264:   n=lg(x)-1; if (!n) return cgetg(1,t_MAT);
                   2265:   if (OK_ULONG(p)) return u_FpM_ker(x, p, nontriv);
                   2266:
                   2267:   m=lg(x[1])-1; r=0; av0 = avma;
                   2268:   x=dummycopy(x); mun=negi(gun);
                   2269:   c=new_chunk(m+1); for (k=1; k<=m; k++) c[k]=0;
                   2270:   d=new_chunk(n+1);
                   2271:   av=avma; lim=stack_lim(av,1);
                   2272:   for (k=1; k<=n; k++)
                   2273:   {
                   2274:     for (j=1; j<=m; j++)
                   2275:       if (!c[j])
                   2276:       {
                   2277:         coeff(x,j,k) = lmodii(gcoeff(x,j,k), p);
                   2278:         if (signe(coeff(x,j,k))) break;
                   2279:       }
                   2280:     if (j>m)
                   2281:     {
                   2282:       if (nontriv) { avma = av0; return NULL; }
                   2283:       r++; d[k]=0;
                   2284:       for(j=1; j<k; j++)
                   2285:         if (d[j]) coeff(x,d[j],k) = lclone(gcoeff(x,d[j],k));
                   2286:     }
                   2287:     else
                   2288:     {
                   2289:       c[j]=k; d[k]=j; piv = negi(mpinvmod(gcoeff(x,j,k), p));
                   2290:       coeff(x,j,k) = (long)mun;
                   2291:       for (i=k+1; i<=n; i++)
                   2292:        coeff(x,j,i) = lmodii(mulii(piv,gcoeff(x,j,i)), p);
                   2293:       for (t=1; t<=m; t++)
                   2294:        if (t!=j)
                   2295:        {
                   2296:          piv = modii(gcoeff(x,t,k), p);
                   2297:           if (signe(piv))
                   2298:           {
                   2299:             coeff(x,t,k)=zero;
                   2300:             for (i=k+1; i<=n; i++)
                   2301:               coeff(x,t,i) = laddii(gcoeff(x,t,i),mulii(piv,gcoeff(x,j,i)));
                   2302:             if (low_stack(lim, stack_lim(av,1)))
                   2303:               gerepile_gauss_FpM_ker(x,p,m,n,k,t,av);
                   2304:           }
                   2305:        }
                   2306:     }
                   2307:   }
                   2308:
                   2309:   tetpil=avma; y=cgetg(r+1,t_MAT);
                   2310:   for (j=k=1; j<=r; j++,k++)
                   2311:   {
                   2312:     GEN c = cgetg(n+1,t_COL);
                   2313:
                   2314:     y[j]=(long)c; while (d[k]) k++;
                   2315:     for (i=1; i<k; i++)
                   2316:       if (d[i])
                   2317:       {
                   2318:        GEN p1=gcoeff(x,d[i],k);
                   2319:        c[i] = lmodii(p1, p); gunclone(p1);
                   2320:       }
                   2321:       else
                   2322:        c[i] = zero;
                   2323:     c[k]=un; for (i=k+1; i<=n; i++) c[i]=zero;
                   2324:   }
                   2325:   return gerepile(av0,tetpil,y);
                   2326: }
                   2327:
                   2328: static void
                   2329: FpM_gauss_pivot(GEN x, GEN p, GEN *dd, long *rr)
                   2330: {
                   2331:   GEN c,d,piv;
                   2332:   long i,j,k,r,t,n,m,av,lim;
                   2333:
                   2334:   if (!p) return gauss_pivot(x,dd,rr);
                   2335:   if (typ(x)!=t_MAT) err(typeer,"FpM_gauss_pivot");
                   2336:   n=lg(x)-1; if (!n) { *dd=NULL; *rr=0; return; }
                   2337:
                   2338:   m=lg(x[1])-1; r=0;
                   2339:   x=dummycopy(x);
                   2340:   c=new_chunk(m+1); for (k=1; k<=m; k++) c[k]=0;
                   2341:   d=(GEN)gpmalloc((n+1)*sizeof(long)); av=avma; lim=stack_lim(av,1);
                   2342:   for (k=1; k<=n; k++)
                   2343:   {
                   2344:     for (j=1; j<=m; j++)
                   2345:       if (!c[j])
                   2346:       {
                   2347:         coeff(x,j,k) = lmodii(gcoeff(x,j,k), p);
                   2348:         if (signe(coeff(x,j,k))) break;
                   2349:       }
                   2350:     if (j>m) { r++; d[k]=0; }
                   2351:     else
                   2352:     {
                   2353:       c[j]=k; d[k]=j; piv = negi(mpinvmod(gcoeff(x,j,k), p));
                   2354:       for (i=k+1; i<=n; i++)
                   2355:        coeff(x,j,i) = lmodii(mulii(piv,gcoeff(x,j,i)), p);
                   2356:       for (t=1; t<=m; t++)
                   2357:         if (!c[t]) /* no pivot on that line yet */
                   2358:         {
                   2359:           piv=gcoeff(x,t,k);
                   2360:           if (signe(piv))
                   2361:           {
                   2362:             coeff(x,t,k)=zero;
                   2363:             for (i=k+1; i<=n; i++)
                   2364:               coeff(x,t,i) = laddii(gcoeff(x,t,i), mulii(piv,gcoeff(x,j,i)));
                   2365:             if (low_stack(lim, stack_lim(av,1)))
                   2366:               gerepile_gauss(x,m,n,k,t,av,j,c);
                   2367:           }
                   2368:         }
                   2369:       for (i=k; i<=n; i++) coeff(x,j,i) = zero; /* dummy */
                   2370:     }
                   2371:   }
                   2372:   *dd=d; *rr=r;
                   2373: }
                   2374:
                   2375: GEN
                   2376: FpM_ker(GEN x, GEN p)
                   2377: {
                   2378:   return FpM_ker_i(x, p, 0);
                   2379: }
                   2380:
                   2381: int
                   2382: ker_trivial_mod_p(GEN x, GEN p)
                   2383: {
                   2384:   return FpM_ker_i(x, p, 1)==NULL;
                   2385: }
                   2386:
                   2387: GEN
                   2388: FpM_image(GEN x, GEN p)
                   2389: {
                   2390:   GEN d,y;
                   2391:   long j,k,r, av = avma;
                   2392:
                   2393:   FpM_gauss_pivot(x,p,&d,&r);
                   2394:
                   2395:   /* r = dim ker(x) */
                   2396:   if (!r) { avma=av; if (d) free(d); return gcopy(x); }
                   2397:
                   2398:   /* r = dim Im(x) */
                   2399:   r = lg(x)-1 - r; avma=av;
                   2400:   y=cgetg(r+1,t_MAT);
                   2401:   for (j=k=1; j<=r; k++)
                   2402:     if (d[k]) y[j++] = lcopy((GEN)x[k]);
                   2403:   free(d); return y;
                   2404: }
                   2405:
                   2406: static GEN
                   2407: sFpM_invimage(GEN mat, GEN y, GEN p)
                   2408: {
                   2409:   long av=avma,i, nbcol = lg(mat);
                   2410:   GEN col,p1 = cgetg(nbcol+1,t_MAT),res;
                   2411:
                   2412:   if (nbcol==1) return NULL;
                   2413:   if (lg(y) != lg(mat[1])) err(consister,"FpM_invimage");
                   2414:
                   2415:   p1[nbcol] = (long)y;
                   2416:   for (i=1; i<nbcol; i++) p1[i]=mat[i];
                   2417:   p1 = FpM_ker(p1,p); i=lg(p1)-1;
                   2418:   if (!i) return NULL;
                   2419:
                   2420:   col = (GEN)p1[i]; p1 = (GEN) col[nbcol];
                   2421:   if (gcmp0(p1)) return NULL;
                   2422:
                   2423:   p1 = mpinvmod(negi(p1),p);
                   2424:   setlg(col,nbcol);
                   2425:   for(i=1;i<nbcol;i++)
                   2426:     col[i]=lmulii((GEN)col[i],p1);
                   2427:   res=cgetg(nbcol,t_COL);
                   2428:   for(i=1;i<nbcol;i++)
                   2429:     res[i]=lmodii((GEN)col[i],p);
                   2430:   return gerepileupto(av,res);
                   2431: }
                   2432:
                   2433: /* Calcule l'image reciproque de v par m */
                   2434: GEN
                   2435: FpM_invimage(GEN m, GEN v, GEN p)
                   2436: {
                   2437:   long av=avma,j,lv,tv=typ(v);
                   2438:   GEN y,p1;
                   2439:
                   2440:   if (typ(m)!=t_MAT) err(typeer,"inverseimage");
                   2441:   if (tv==t_COL)
                   2442:   {
                   2443:     p1 = sFpM_invimage(m,v,p);
                   2444:     if (p1) return p1;
                   2445:     avma = av; return cgetg(1,t_MAT);
                   2446:   }
                   2447:   if (tv!=t_MAT) err(typeer,"inverseimage");
                   2448:
                   2449:   lv=lg(v)-1; y=cgetg(lv+1,t_MAT);
                   2450:   for (j=1; j<=lv; j++)
                   2451:   {
                   2452:     p1 = sFpM_invimage(m,(GEN)v[j],p);
                   2453:     if (!p1) { avma = av; return cgetg(1,t_MAT); }
                   2454:     y[j] = (long)p1;
                   2455:   }
                   2456:   return y;
                   2457: }
                   2458: /**************************************************************
                   2459:  Rather stupid implementation of linear algebra in finite fields
                   2460:  **************************************************************/
                   2461: static GEN
                   2462: Fq_add(GEN x, GEN y, GEN T/*unused*/, GEN p)
                   2463: {
                   2464:   switch((typ(x)==t_POL)|((typ(y)==t_POL)<<1))
                   2465:   {
                   2466:     case 0: return modii(addii(x,y),p);
                   2467:     case 1: return FpX_Fp_add(x,y,p);
                   2468:     case 2: return FpX_Fp_add(y,x,p);
                   2469:     case 3: return FpX_add(x,y,p);
                   2470:   }
                   2471:   return NULL;
                   2472: }
                   2473: #if 0
                   2474: /* this function is really for FpV_roots_to_pol in polarit1.c
                   2475:  * For consistency we write the code there.
                   2476:  * To avoid having to remove static status, we rewrite it in polarit1.c
                   2477:  */
                   2478: static GEN
                   2479: Fq_neg(GEN x, GEN T, GEN p)
                   2480: {
                   2481:   switch(typ(x)==t_POL)
                   2482:   {
                   2483:     case 0: return signe(x)?subii(p,x):gzero;
                   2484:     case 1: return FpX_neg(x,p);
                   2485:   }
                   2486:   return NULL;
                   2487: }
                   2488: #endif
                   2489:
                   2490: static GEN
                   2491: Fq_mul(GEN x, GEN y, GEN T, GEN p)
                   2492: {
                   2493:   switch((typ(x)==t_POL)|((typ(y)==t_POL)<<1))
                   2494:   {
                   2495:     case 0: return modii(mulii(x,y),p);
                   2496:     case 1: return FpX_Fp_mul(x,y,p);
                   2497:     case 2: return FpX_Fp_mul(y,x,p);
                   2498:     case 3: return FpXQ_mul(x,y,T,p);
                   2499:   }
                   2500:   return NULL;
                   2501: }
                   2502:
                   2503: static GEN
                   2504: Fq_neg_inv(GEN x, GEN T, GEN p)
                   2505: {
                   2506:   switch(typ(x)==t_POL)
                   2507:   {
                   2508:     case 0: return mpinvmod(negi(x),p);
                   2509:     case 1: return FpXQ_inv(FpX_neg(x,p),T,p);
                   2510:   }
                   2511:   return NULL;
                   2512: }
                   2513:
                   2514: static GEN
                   2515: Fq_res(GEN x, GEN T, GEN p)
                   2516: {
                   2517:   ulong ltop=avma;
                   2518:   switch(typ(x)==t_POL)
                   2519:   {
                   2520:     case 0: return modii(x,p);
                   2521:     case 1: return gerepileupto(ltop,FpX_res(FpX_red(x,p),T,p));
                   2522:   }
                   2523:   return NULL;
                   2524: }
                   2525:
                   2526: static void
                   2527: Fq_gerepile_gauss_ker(GEN x, GEN T, GEN p, long m, long n, long k, long t,
                   2528:                       ulong av)
                   2529: {
                   2530:   ulong tetpil = avma,A;
                   2531:   long dec,u,i;
                   2532:
                   2533:   if (DEBUGMEM > 1) err(warnmem,"gauss_pivot_ker. k=%ld, n=%ld",k,n);
                   2534:   for (u=t+1; u<=m; u++)
                   2535:     if (isonstack(coeff(x,u,k))) coeff(x,u,k) = (long) Fq_res(gcoeff(x,u,k),T,p);
                   2536:   for (i=k+1; i<=n; i++)
                   2537:     for (u=1; u<=m; u++)
                   2538:       if (isonstack(coeff(x,u,i))) coeff(x,u,i) = (long) Fq_res(gcoeff(x,u,i),T,p);
                   2539:
                   2540:   (void)gerepile(av,tetpil,NULL); dec = av-tetpil;
                   2541:   for (u=t+1; u<=m; u++)
                   2542:   {
                   2543:     A=coeff(x,u,k);
                   2544:     if (A<av && A>=bot) coeff(x,u,k)+=dec;
                   2545:   }
                   2546:   for (i=k+1; i<=n; i++)
                   2547:     for (u=1; u<=m; u++)
                   2548:     {
                   2549:       A=coeff(x,u,i);
                   2550:       if (A<av && A>=bot) coeff(x,u,i)+=dec;
                   2551:     }
                   2552: }
                   2553:
                   2554: static GEN
                   2555: FqM_ker_i(GEN x, GEN T, GEN p, long nontriv)
                   2556: {
                   2557:   GEN y,c,d,piv,mun;
                   2558:   long i,j,k,r,t,n,m,av0,av,lim,tetpil;
                   2559:
                   2560:   if (typ(x)!=t_MAT) err(typeer,"FpM_ker");
                   2561:   n=lg(x)-1; if (!n) return cgetg(1,t_MAT);
                   2562:
                   2563:   m=lg(x[1])-1; r=0; av0 = avma;
                   2564:   x=dummycopy(x); mun=negi(gun);
                   2565:   c=new_chunk(m+1); for (k=1; k<=m; k++) c[k]=0;
                   2566:   d=new_chunk(n+1);
                   2567:   av=avma; lim=stack_lim(av,1);
                   2568:   for (k=1; k<=n; k++)
                   2569:   {
                   2570:     for (j=1; j<=m; j++)
                   2571:       if (!c[j])
                   2572:       {
                   2573:         coeff(x,j,k) = (long) Fq_res(gcoeff(x,j,k), T, p);
                   2574:         if (signe(coeff(x,j,k))) break;
                   2575:       }
                   2576:     if (j>m)
                   2577:     {
                   2578:       if (nontriv) { avma = av0; return NULL; }
                   2579:       r++; d[k]=0;
                   2580:       for(j=1; j<k; j++)
                   2581:         if (d[j]) coeff(x,d[j],k) = lclone(gcoeff(x,d[j],k));
                   2582:     }
                   2583:     else
                   2584:     {
                   2585:       c[j]=k; d[k]=j; piv = Fq_neg_inv(gcoeff(x,j,k), T, p);
                   2586:       coeff(x,j,k) = (long)mun;
                   2587:       for (i=k+1; i<=n; i++)
                   2588:        coeff(x,j,i) = (long) Fq_mul(piv,gcoeff(x,j,i), T, p);
                   2589:       for (t=1; t<=m; t++)
                   2590:        if (t!=j)
                   2591:        {
                   2592:          piv = Fq_res(gcoeff(x,t,k), T, p);
                   2593:           if (signe(piv))
                   2594:           {
                   2595:             coeff(x,t,k)=zero;
                   2596:             for (i=k+1; i<=n; i++)
                   2597:               coeff(x,t,i) = (long)Fq_add(gcoeff(x,t,i),Fq_mul(piv,gcoeff(x,j,i), T, p), T, p);
                   2598:             if (low_stack(lim, stack_lim(av,1)))
                   2599:               Fq_gerepile_gauss_ker(x,T,p,m,n,k,t,av);
                   2600:           }
                   2601:        }
                   2602:     }
                   2603:   }
                   2604:
                   2605:   tetpil=avma; y=cgetg(r+1,t_MAT);
                   2606:   for (j=k=1; j<=r; j++,k++)
                   2607:   {
                   2608:     GEN c = cgetg(n+1,t_COL);
                   2609:
                   2610:     y[j]=(long)c; while (d[k]) k++;
                   2611:     for (i=1; i<k; i++)
                   2612:       if (d[i])
                   2613:       {
                   2614:        GEN p1=gcoeff(x,d[i],k);
                   2615:        c[i] = (long) Fq_res(p1, T, p); gunclone(p1);
                   2616:       }
                   2617:       else
                   2618:        c[i] = zero;
                   2619:     c[k]=un; for (i=k+1; i<=n; i++) c[i]=zero;
                   2620:   }
                   2621:   return gerepile(av0,tetpil,y);
                   2622: }
                   2623: GEN
                   2624: FqM_ker(GEN x, GEN T, GEN p)
                   2625: {
                   2626:   return FqM_ker_i(x, T, p, 0);
                   2627: }
                   2628:
                   2629: /*******************************************************************/
                   2630: /*                                                                 */
                   2631: /*                        EIGENVECTORS                             */
                   2632: /*   (independent eigenvectors, sorted by increasing eigenvalue)   */
                   2633: /*                                                                 */
                   2634: /*******************************************************************/
                   2635:
                   2636: GEN
                   2637: eigen(GEN x, long prec)
                   2638: {
                   2639:   GEN y,rr,p,ssesp,r1,r2,r3;
                   2640:   long e,i,k,l,ly,ex, n = lg(x);
                   2641:   ulong av = avma;
                   2642:
                   2643:   if (typ(x)!=t_MAT) err(typeer,"eigen");
                   2644:   if (n != 1 && n != lg(x[1])) err(mattype1,"eigen");
                   2645:   if (n<=2) return gcopy(x);
                   2646:
                   2647:   ex = 16 - bit_accuracy(prec);
                   2648:   y=cgetg(n,t_MAT);
                   2649:   p=caradj(x,0,NULL); rr=roots(p,prec);
                   2650:   for (i=1; i<n; i++)
                   2651:   {
                   2652:     GEN p1 = (GEN)rr[i];
                   2653:     if (!signe(p1[2]) || gexpo((GEN)p1[2]) - gexpo(p1) < ex) rr[i] = p1[1];
                   2654:   }
                   2655:   ly=1; k=2; r2=(GEN)rr[1];
                   2656:   for(;;)
                   2657:   {
                   2658:     r3 = grndtoi(r2, &e); if (e < ex) r2 = r3;
                   2659:     ssesp = ker0(x,r2); l = lg(ssesp);
                   2660:     if (l == 1 || ly + (l-1) > n)
                   2661:       err(talker2, "missing eigenspace. Compute the matrix to higher accuracy, then restart eigen at the current precision",NULL,NULL);
                   2662:     for (i=1; i<l; ) y[ly++]=ssesp[i++]; /* done with this eigenspace */
                   2663:
                   2664:     r1=r2; /* try to find a different eigenvalue */
                   2665:     do
                   2666:     {
                   2667:       if (k == n || ly == n)
                   2668:       {
                   2669:         setlg(y,ly); /* x may not be diagonalizable */
                   2670:         return gerepilecopy(av,y);
                   2671:       }
                   2672:       r2 = (GEN)rr[k++];
                   2673:       r3 = gsub(r1,r2);
                   2674:     }
                   2675:     while (gcmp0(r3) || gexpo(r3) < ex);
                   2676:   }
                   2677: }
                   2678:
                   2679: /*******************************************************************/
                   2680: /*                                                                 */
                   2681: /*                           DETERMINANT                           */
                   2682: /*                                                                 */
                   2683: /*******************************************************************/
                   2684:
                   2685: GEN
                   2686: det0(GEN a,long flag)
                   2687: {
                   2688:   switch(flag)
                   2689:   {
                   2690:     case 0: return det(a);
                   2691:     case 1: return det2(a);
                   2692:     default: err(flagerr,"matdet");
                   2693:   }
                   2694:   return NULL; /* not reached */
                   2695: }
                   2696:
                   2697: /* Exact types: choose the first non-zero pivot. Otherwise: maximal pivot */
                   2698: static GEN
                   2699: det_simple_gauss(GEN a, long inexact)
                   2700: {
                   2701:   long i,j,k,av,av1,s, nbco = lg(a)-1;
                   2702:   GEN x,p;
                   2703:
                   2704:   av=avma; s=1; x=gun; a=dummycopy(a);
                   2705:   for (i=1; i<nbco; i++)
                   2706:   {
                   2707:     p=gcoeff(a,i,i); k=i;
                   2708:     if (inexact)
                   2709:     {
                   2710:       long e, ex = gexpo(p);
                   2711:       GEN p1;
                   2712:
                   2713:       for (j=i+1; j<=nbco; j++)
                   2714:       {
                   2715:         e = gexpo(gcoeff(a,i,j));
                   2716:         if (e > ex) { ex=e; k=j; }
                   2717:       }
                   2718:       p1 = gcoeff(a,i,k);
                   2719:       if (gcmp0(p1)) return gerepilecopy(av, p1);
                   2720:     }
                   2721:     else if (gcmp0(p))
                   2722:     {
                   2723:       do k++; while(k<=nbco && gcmp0(gcoeff(a,i,k)));
                   2724:       if (k>nbco) return gerepilecopy(av, p);
                   2725:     }
                   2726:     if (k != i)
                   2727:     {
                   2728:       swap(a[i],a[k]); s = -s;
                   2729:       p = gcoeff(a,i,i);
                   2730:     }
                   2731:
                   2732:     x = gmul(x,p);
                   2733:     for (k=i+1; k<=nbco; k++)
                   2734:     {
                   2735:       GEN m = gcoeff(a,i,k);
                   2736:       if (!gcmp0(m))
                   2737:       {
                   2738:        m = gneg_i(gdiv(m,p));
                   2739:        for (j=i+1; j<=nbco; j++)
                   2740:          coeff(a,j,k) = ladd(gcoeff(a,j,k), gmul(m,gcoeff(a,j,i)));
                   2741:       }
                   2742:     }
                   2743:   }
                   2744:   if (s<0) x = gneg_i(x);
                   2745:   av1=avma; return gerepile(av,av1,gmul(x,gcoeff(a,nbco,nbco)));
                   2746: }
                   2747:
                   2748: /* a has integer entries, N = P^n */
                   2749: GEN
                   2750: det_mod_P_n(GEN a, GEN N, GEN P)
                   2751: {
                   2752:   long va,i,j,k,s, av = avma, nbco = lg(a)-1;
                   2753:   GEN x,p;
                   2754:
                   2755:   s=1; va=0; x=gun; a=dummycopy(a);
                   2756:   p = NULL; /* for gcc -Wall */
                   2757:   for (i=1; i<nbco; i++)
                   2758:   {
                   2759:     long fl = 0;
                   2760:     for(;;)
                   2761:     {
                   2762:       for (k=i; k<=nbco; k++)
                   2763:       {
                   2764:         p=gcoeff(a,i,k);
                   2765:         if (signe(p))
                   2766:         {
                   2767:           fl = 1;
                   2768:           if (resii(p,P) != gzero) break;
                   2769:         }
                   2770:       }
                   2771:       if (k <= nbco) break;
                   2772:       va++; N = divii(N, P);
                   2773:       if (!fl || is_pm1(N)) { avma=av; return gzero; }
                   2774:       for (k=i; k<=nbco; k++) coeff(a,i,k) = ldivii(gcoeff(a,i,k), P);
                   2775:     }
                   2776:     if (k != i) { swap(a[i],a[k]); s = -s; }
                   2777:
                   2778:     x = gmul(x,p); p = mpinvmod(p,N);
                   2779:     for (k=i+1; k<=nbco; k++)
                   2780:     {
                   2781:       GEN m = resii(gcoeff(a,i,k), N);
                   2782:       coeff(a,i,k) = zero;
                   2783:       if (signe(m))
                   2784:       {
                   2785:        m = negi(resii(mulii(m,p), N));
                   2786:        for (j=i+1; j<=nbco; j++)
                   2787:          coeff(a,j,k) = lresii(addii(gcoeff(a,j,k),
                   2788:                                 mulii(m,gcoeff(a,j,i))), N);
                   2789:       }
                   2790:     }
                   2791:   }
                   2792:   if (s<0) x = negi(x);
                   2793:   x = resii(mulii(x,gcoeff(a,nbco,nbco)), N);
                   2794:   return gerepileuptoint(av, mulii(x, gpowgs(P,va)));
                   2795: }
                   2796:
                   2797: GEN
                   2798: det2(GEN a)
                   2799: {
                   2800:   long nbco = lg(a)-1;
                   2801:   if (typ(a)!=t_MAT) err(mattype1,"det2");
                   2802:   if (!nbco) return gun;
                   2803:   if (nbco != lg(a[1])-1) err(mattype1,"det2");
                   2804:   return det_simple_gauss(a,use_maximal_pivot(a));
                   2805: }
                   2806:
                   2807: static GEN
                   2808: mydiv(GEN x, GEN y)
                   2809: {
                   2810:   long tx = typ(x), ty = typ(y);
                   2811:   if (tx == ty && tx == t_POL && varn(x) == varn(y))
                   2812:     return gdeuc(x,y);
                   2813:   return gdiv(x,y);
                   2814: }
                   2815:
                   2816: /* determinant in a ring A: all computations are done within A
                   2817:  * (Gauss-Bareiss algorithm) */
                   2818: GEN
                   2819: det(GEN a)
                   2820: {
                   2821:   ulong av, lim;
                   2822:   long nbco = lg(a)-1,i,j,k,s;
                   2823:   GEN p,pprec;
                   2824:
                   2825:   if (typ(a)!=t_MAT) err(mattype1,"det");
                   2826:   if (!nbco) return gun;
                   2827:   if (nbco != lg(a[1])-1) err(mattype1,"det");
                   2828:   if (use_maximal_pivot(a)) return det_simple_gauss(a,1);
                   2829:   if (DEBUGLEVEL > 7) timer2();
                   2830:
                   2831:   av = avma; lim = stack_lim(av,2);
                   2832:   a = dummycopy(a); s = 1;
                   2833:   for (pprec=gun,i=1; i<nbco; i++,pprec=p)
                   2834:   {
                   2835:     GEN *ci, *ck, m, p1;
                   2836:     int diveuc = (gcmp1(pprec)==0);
                   2837:
                   2838:     p = gcoeff(a,i,i);
                   2839:     if (gcmp0(p))
                   2840:     {
                   2841:       k=i+1; while (k<=nbco && gcmp0(gcoeff(a,i,k))) k++;
                   2842:       if (k>nbco) return gerepilecopy(av, p);
                   2843:       swap(a[k], a[i]); s = -s;
                   2844:       p = gcoeff(a,i,i);
                   2845:     }
                   2846:     ci = (GEN*)a[i];
                   2847:     for (k=i+1; k<=nbco; k++)
                   2848:     {
                   2849:       ck = (GEN*)a[k]; m = (GEN)ck[i];
                   2850:       if (gcmp0(m))
                   2851:       {
                   2852:         if (gcmp1(p))
                   2853:         {
                   2854:           if (diveuc)
                   2855:             a[k] = (long)mydiv((GEN)a[k], pprec);
                   2856:         }
                   2857:         else
                   2858:           for (j=i+1; j<=nbco; j++)
                   2859:           {
                   2860:             p1 = gmul(p,ck[j]);
                   2861:             if (diveuc) p1 = mydiv(p1,pprec);
                   2862:             ck[j] = p1;
                   2863:           }
                   2864:       }
                   2865:       else
                   2866:       {
                   2867:         m = gneg_i(m);
                   2868:         for (j=i+1; j<=nbco; j++)
                   2869:         {
                   2870:           p1 = gadd(gmul(p,ck[j]), gmul(m,ci[j]));
                   2871:           if (diveuc) p1 = mydiv(p1,pprec);
                   2872:           ck[j] = p1;
                   2873:         }
                   2874:       }
                   2875:       if (low_stack(lim,stack_lim(av,2)))
                   2876:       {
                   2877:         GEN *gptr[2]; gptr[0]=&a; gptr[1]=&pprec;
                   2878:         if(DEBUGMEM>1) err(warnmem,"det. col = %ld",i);
                   2879:         gerepilemany(av,gptr,2); p = gcoeff(a,i,i); ci = (GEN*)a[i];
                   2880:       }
                   2881:     }
                   2882:     if (DEBUGLEVEL > 7) msgtimer("det, col %ld / %ld",i,nbco-1);
                   2883:   }
                   2884:   p = gcoeff(a,nbco,nbco);
                   2885:   if (s < 0) p = gneg(p); else p = gcopy(p);
                   2886:   return gerepileupto(av, p);
                   2887: }
                   2888:
                   2889: /* return a solution of congruence system sum M_{ i,j } X_j = Y_i mod D_i
                   2890:  * If ptu1 != NULL, put in *ptu1 a Z-basis of the homogeneous system
                   2891:  */
                   2892: static GEN
                   2893: gaussmoduloall(GEN M, GEN D, GEN Y, GEN *ptu1)
                   2894: {
                   2895:   long n,m,i,j,lM,av=avma,tetpil;
                   2896:   GEN p1,delta,H,U,u1,u2,x;
                   2897:
                   2898:   if (typ(M)!=t_MAT) err(typeer,"gaussmodulo");
                   2899:   lM = lg(M); m = lM-1;
                   2900:   if (!m)
                   2901:   {
                   2902:     if ((typ(Y)!=t_INT && lg(Y)!=1)
                   2903:      || (typ(D)!=t_INT && lg(D)!=1)) err(consister,"gaussmodulo");
                   2904:     return gzero;
                   2905:   }
                   2906:   n = lg(M[1])-1;
                   2907:   switch(typ(D))
                   2908:   {
                   2909:     case t_VEC:
                   2910:     case t_COL: delta=diagonal(D); break;
                   2911:     case t_INT: delta=gscalmat(D,n); break;
                   2912:     default: err(typeer,"gaussmodulo");
                   2913:       return NULL; /* not reached */
                   2914:   }
                   2915:   if (typ(Y) == t_INT)
                   2916:   {
                   2917:     p1 = cgetg(n+1,t_COL);
                   2918:     for (i=1; i<=n; i++) p1[i]=(long)Y;
                   2919:     Y = p1;
                   2920:   }
                   2921:   p1 = hnfall(concatsp(M,delta));
                   2922:   H = (GEN)p1[1]; U = (GEN)p1[2];
                   2923:   Y = gauss(H,Y);
                   2924:   if (!gcmp1(denom(Y))) return gzero;
                   2925:   u1 = cgetg(m+1,t_MAT);
                   2926:   u2 = cgetg(n+1,t_MAT);
                   2927:   for (j=1; j<=m; j++)
                   2928:   {
                   2929:     p1 = (GEN)U[j]; setlg(p1,lM);
                   2930:     u1[j] = (long)p1;
                   2931:   }
                   2932:   U += m;
                   2933:   for (j=1; j<=n; j++)
                   2934:   {
                   2935:     p1 = (GEN)U[j]; setlg(p1,lM);
                   2936:     u2[j] = (long)p1;
                   2937:   }
                   2938:   x = gmul(u2,Y);
                   2939:   tetpil=avma; x=lllreducemodmatrix(x,u1);
                   2940:   if (!ptu1) x = gerepile(av,tetpil,x);
                   2941:   else
                   2942:   {
                   2943:     GEN *gptr[2];
                   2944:     *ptu1=gcopy(u1); gptr[0]=ptu1; gptr[1]=&x;
                   2945:     gerepilemanysp(av,tetpil,gptr,2);
                   2946:   }
                   2947:   return x;
                   2948: }
                   2949:
                   2950: GEN
                   2951: matsolvemod0(GEN M, GEN D, GEN Y, long flag)
                   2952: {
                   2953:   long av;
                   2954:   GEN p1,y;
                   2955:
                   2956:   if (!flag) return gaussmoduloall(M,D,Y,NULL);
                   2957:
                   2958:   av=avma; y = cgetg(3,t_VEC);
                   2959:   p1 = gaussmoduloall(M,D,Y, (GEN*)y+2);
                   2960:   if (p1==gzero) { avma=av; return gzero; }
                   2961:   y[1] = (long)p1; return y;
                   2962: }
                   2963:
                   2964: GEN
                   2965: gaussmodulo2(GEN M, GEN D, GEN Y)
                   2966: {
                   2967:   return matsolvemod0(M,D,Y,1);
                   2968: }
                   2969:
                   2970: GEN
                   2971: gaussmodulo(GEN M, GEN D, GEN Y)
                   2972: {
                   2973:   return matsolvemod0(M,D,Y,0);
                   2974: }

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