[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.2

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

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