Annotation of OpenXM_contrib/pari-2.2/src/basemath/subgroup.c, Revision 1.1
1.1 ! noro 1: /* $Id: subgroup.c,v 1.9 2001/06/20 15:26:57 karim Exp $
! 2:
! 3: Copyright (C) 2000 The PARI group.
! 4:
! 5: This file is part of the PARI/GP package.
! 6:
! 7: PARI/GP is free software; you can redistribute it and/or modify it under the
! 8: terms of the GNU General Public License as published by the Free Software
! 9: Foundation. It is distributed in the hope that it will be useful, but WITHOUT
! 10: ANY WARRANTY WHATSOEVER.
! 11:
! 12: Check the License for details. You should have received a copy of it, along
! 13: with the package; see the file 'COPYING'. If not, write to the Free Software
! 14: Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
! 15:
! 16: #include "pari.h"
! 17: extern GEN hnf0(GEN x, long r);
! 18: void push_val(entree *ep, GEN a);
! 19: void pop_val(entree *ep);
! 20:
! 21: /* SUBGROUPS
! 22: * Assume: G = Gp x I, with Gp a p-group and (|I|,p)=1, and I small.
! 23: * Compute subgroups of I by recursive calls
! 24: * Loop through subgroups Hp of Gp using Birkhoff's algorithm.
! 25: * If (I is non trivial)
! 26: * lift Hp to G (mul by exponent of I)
! 27: * for each subgp of I, lift it to G (mult by exponent of Gp)
! 28: * consider the group generated by the two subgroups (concat)
! 29: */
! 30: static long *powerlist, *mmu, *lam, *c, *maxc, *a, *maxa, **g, **maxg;
! 31: static GEN **H, subq, subqpart, hnfgroup;
! 32: static GEN BINMAT;
! 33: static long countsub, expoI;
! 34: static long *available, indexbound, lsubq, lsubqpart;
! 35: static char *gpch;
! 36: static entree *ep;
! 37: static void(*treatsub_fun)(GEN);
! 38: typedef struct slist {
! 39: struct slist *next;
! 40: long *data;
! 41: } slist;
! 42:
! 43: static slist *sublist;
! 44:
! 45: void
! 46: printtyp(long *typ)
! 47: {
! 48: long i;
! 49: for (i=1; i<=typ[0]; i++) fprintferr(" %ld ",typ[i]);
! 50: fprintferr("\n");
! 51: }
! 52:
! 53: /* compute conjugate partition of typ */
! 54: static long*
! 55: conjugate(long *typ)
! 56: {
! 57: long *t, i, k = typ[0], l, last;
! 58:
! 59: if (!k) { t = new_chunk(1); t[0]=0; return t; }
! 60: l = typ[1]; t = new_chunk(l+2);
! 61: t[1] = k; last = k;
! 62: for (i=2; i<=l; i++)
! 63: {
! 64: while (typ[last] < i) last--;
! 65: t[i] = last;
! 66: }
! 67: t[i] = 0; t[0] = l;
! 68: return t;
! 69: }
! 70:
! 71: static void
! 72: std_fun(GEN x)
! 73: {
! 74: ep->value = (void*)x;
! 75: lisseq(gpch); countsub++;
! 76: }
! 77:
! 78: void
! 79: addcell(GEN H)
! 80: {
! 81: long *pt,i,j, k = 0, n = lg(H)-1;
! 82: slist *cell = (slist*) gpmalloc(sizeof(slist) + n*(n+1)/2 * sizeof(long));
! 83:
! 84: sublist->next = cell; cell->data = pt = (long*) (cell + 1);
! 85: for (j=1; j<=n; j++)
! 86: for(i=1; i<=j; i++) pt[k++] = itos(gcoeff(H,i,j));
! 87: sublist = cell;
! 88: }
! 89:
! 90: static void
! 91: list_fun(GEN x)
! 92: {
! 93: addcell(hnf(concatsp(hnfgroup,x))); countsub++;
! 94: }
! 95:
! 96: /* treat subgroup Hp (not in HNF, treatsub_fun should do it if desired) */
! 97: static void
! 98: treatsub(GEN Hp)
! 99: {
! 100: long i;
! 101: if (!subq) treatsub_fun(Hp);
! 102: else
! 103: { /* not a p group, add the trivial part */
! 104: Hp = gmulsg(expoI,Hp); /* lift Hp to G */
! 105: for (i=1; i<lsubqpart; i++)
! 106: treatsub_fun(concatsp(Hp, (GEN)subqpart[i]));
! 107: }
! 108: }
! 109:
! 110: /* assume t>0 and l>1 */
! 111: static void
! 112: dogroup(void)
! 113: {
! 114: long av = avma,av1, e,i,j,k,r,n,t2,ind, t = mmu[0], l = lam[0];
! 115:
! 116: t2 = (l==t)? t-1: t;
! 117: n = t2 * l - (t2*(t2+1))/2; /* number of gamma_ij */
! 118: for (i=1, r=t+1; ; i++)
! 119: {
! 120: if (available[i]) c[r++] = i;
! 121: if (r > l) break;
! 122: }
! 123: if (DEBUGLEVEL>2) { fprintferr(" column selection:"); printtyp(c); }
! 124: /* a/g and maxa/maxg access the same data indexed differently */
! 125: for (ind=0,i=1; i<=t; ind+=(l-i),i++)
! 126: {
! 127: maxg[i] = maxa + (ind - (i+1)); /* only access maxg[i][i+1..l] */
! 128: g[i] = a + (ind - (i+1));
! 129: for (r=i+1; r<=l; r++)
! 130: if (c[r] < c[i]) maxg[i][r] = powerlist[mmu[i]-mmu[r]-1];
! 131: else if (lam[c[r]] < mmu[i]) maxg[i][r] = powerlist[lam[c[r]]-mmu[r]];
! 132: else maxg[i][r] = powerlist[mmu[i]-mmu[r]];
! 133: }
! 134: av1=avma; a[n-1]=0; for (i=0; i<n-1; i++) a[i]=1;
! 135: for(;;)
! 136: {
! 137: a[n-1]++;
! 138: if (a[n-1] > maxa[n-1])
! 139: {
! 140: j=n-2; while (j>=0 && a[j]==maxa[j]) j--;
! 141: if (j<0) { avma=av; return; }
! 142: a[j]++; for (k=j+1; k<n; k++) a[k]=1;
! 143: }
! 144: for (i=1; i<=t; i++)
! 145: {
! 146: for (r=1; r<i; r++) affsi(0, H[i][c[r]]);
! 147: affsi(powerlist[lam[c[r]]-mmu[r]], H[r][c[r]]);
! 148: for (r=i+1; r<=l; r++)
! 149: {
! 150: if (c[r] < c[i])
! 151: e = g[i][r]*powerlist[lam[c[r]]-mmu[i]+1];
! 152: else
! 153: if (lam[c[r]] < mmu[i]) e = g[i][r];
! 154: else e = g[i][r]*powerlist[lam[c[r]]-mmu[i]];
! 155: affsi(e, H[i][c[r]]);
! 156: }
! 157: }
! 158: treatsub((GEN)H); avma=av1;
! 159: }
! 160: }
! 161:
! 162: /* c[1],...,c[r-1] filled */
! 163: static void
! 164: loop(long r)
! 165: {
! 166: long j;
! 167:
! 168: if (r > mmu[0]) { dogroup(); return; }
! 169:
! 170: if (r!=1 && (mmu[r-1] == mmu[r])) j = c[r-1]+1; else j = 1;
! 171: for ( ; j<=maxc[r]; j++)
! 172: if (available[j])
! 173: {
! 174: c[r] = j; available[j] = 0;
! 175: loop(r+1); available[j] = 1;
! 176: }
! 177: }
! 178:
! 179: static void
! 180: dopsubtyp(void)
! 181: {
! 182: long av = avma, i,r, l = lam[0], t = mmu[0];
! 183:
! 184: if (!t)
! 185: {
! 186: GEN p1 = cgetg(2,t_MAT);
! 187: p1[1] = (long)zerocol(l);
! 188: treatsub(p1); avma=av; return;
! 189: }
! 190: if (l==1) /* imply t = 1 */
! 191: {
! 192: GEN p1 = gtomat(stoi(powerlist[lam[1]-mmu[1]]));
! 193: treatsub(p1); avma=av; return;
! 194: }
! 195: c = new_chunk(l+1); c[0] = l;
! 196: maxc = new_chunk(l+1);
! 197: available = new_chunk(l+1);
! 198: a = new_chunk(l*(t+1));
! 199: maxa=new_chunk(l*(t+1));
! 200: g = (long**)new_chunk(t+1);
! 201: maxg = (long**)new_chunk(t+1);
! 202:
! 203: if (DEBUGLEVEL) { fprintferr(" subgroup:"); printtyp(mmu); }
! 204: for (i=1; i<=t; i++)
! 205: {
! 206: for (r=1; r<=l; r++)
! 207: if (mmu[i] > lam[r]) break;
! 208: maxc[i] = r-1;
! 209: }
! 210: H = (GEN**)cgetg(t+1, t_MAT);
! 211: for (i=1; i<=t; i++)
! 212: {
! 213: H[i] = (GEN*)cgetg(l+1, t_COL);
! 214: for (r=1; r<=l; r++) H[i][r] = cgeti(3);
! 215: }
! 216: for (i=1; i<=l; i++) available[i]=1;
! 217: for (i=1; i<=t; i++) c[i]=0;
! 218: /* go through all column selections */
! 219: loop(1); avma=av; return;
! 220: }
! 221:
! 222: static long
! 223: weight(long *typ)
! 224: {
! 225: long i,w = 0;
! 226: for (i=1; i<=typ[0]; i++) w += typ[i];
! 227: return w;
! 228: }
! 229:
! 230: static long
! 231: dopsub(long p, long *gtyp, long *indexsubq)
! 232: {
! 233: long w,i,j,k,n, wg = 0, wmin = 0, count = 0;
! 234:
! 235: if (DEBUGLEVEL) { fprintferr("\ngroup:"); printtyp(gtyp); }
! 236: if (indexbound)
! 237: {
! 238: wg = weight(gtyp);
! 239: wmin = (long) (wg - (log((double)indexbound) / log((double)p)));
! 240: if (cmpis(gpuigs(stoi(p), wg - wmin), indexbound) > 0) wmin++;
! 241: }
! 242: lam = gtyp; n = lam[0]; mmu = new_chunk(n+1);
! 243: mmu[1] = -1; for (i=2; i<=n; i++) mmu[i]=0;
! 244: for(;;) /* go through all vectors mu_{i+1} <= mu_i <= lam_i */
! 245: {
! 246: mmu[1]++;
! 247: if (mmu[1] > lam[1])
! 248: {
! 249: for (j=2; j<=n; j++)
! 250: if (mmu[j] < lam[j] && mmu[j] < mmu[j-1]) break;
! 251: if (j>n) return count;
! 252: mmu[j]++; for (k=1; k<j; k++) mmu[k]=mmu[j];
! 253: }
! 254: for (j=1; j<=n; j++)
! 255: if (!mmu[j]) break;
! 256: mmu[0] = j-1; w = weight(mmu);
! 257: if (w >= wmin)
! 258: {
! 259: GEN p1 = gun;
! 260:
! 261: if (subq) /* G not a p-group */
! 262: {
! 263: if (indexbound)
! 264: {
! 265: long indexH = itos(gpuigs(stoi(p), wg - w));
! 266: long bound = indexbound / indexH;
! 267: subqpart = cgetg(lsubq, t_VEC);
! 268: lsubqpart = 1;
! 269: for (i=1; i<lsubq; i++)
! 270: if (indexsubq[i] <= bound) subqpart[lsubqpart++] = subq[i];
! 271: }
! 272: else { subqpart = subq; lsubqpart = lsubq; }
! 273: }
! 274: if (DEBUGLEVEL)
! 275: {
! 276: long *lp = conjugate(lam);
! 277: long *mp = conjugate(mmu);
! 278:
! 279: if (DEBUGLEVEL > 3)
! 280: {
! 281: fprintferr(" lambda = "); printtyp(lam);
! 282: fprintferr(" lambda'= "); printtyp(lp);
! 283: fprintferr(" mu = "); printtyp(mmu);
! 284: fprintferr(" mu'= "); printtyp(mp);
! 285: }
! 286: for (j=1; j<=mp[0]; j++)
! 287: {
! 288: p1 = mulii(p1, gpuigs(stoi(p), mp[j+1]*(lp[j]-mp[j])));
! 289: p1 = mulii(p1, gcoeff(BINMAT, lp[j]-mp[j+1]+1, mp[j]-mp[j+1]+1));
! 290: }
! 291: fprintferr(" alpha_lambda(mu,p) = %Z\n",p1);
! 292: }
! 293: countsub = 0;
! 294: dopsubtyp();
! 295: count += countsub;
! 296: if (DEBUGLEVEL)
! 297: {
! 298: fprintferr(" countsub = %ld\n", countsub);
! 299: msgtimer("for this type");
! 300: if (subq) p1 = mulis(p1,lsubqpart-1);
! 301: if (cmpis(p1,countsub))
! 302: {
! 303: fprintferr(" alpha = %Z\n",p1);
! 304: err(bugparier,"forsubgroup (alpha != countsub)");
! 305: }
! 306: }
! 307: }
! 308: }
! 309: }
! 310:
! 311: static GEN
! 312: expand_sub(GEN x, long n)
! 313: {
! 314: long i,j, m = lg(x);
! 315: GEN p = idmat(n-1), q,c;
! 316:
! 317: for (i=1; i<m; i++)
! 318: {
! 319: q = (GEN)p[i]; c = (GEN)x[i];
! 320: for (j=1; j<m; j++) q[j] = c[j];
! 321: for ( ; j<n; j++) q[j] = zero;
! 322: }
! 323: return p;
! 324: }
! 325:
! 326: extern GEN matqpascal(long n, GEN q);
! 327:
! 328: static long
! 329: subgroup_engine(GEN cyc, long bound)
! 330: {
! 331: long av=avma,i,j,k,imax,nbprim,count, n = lg(cyc);
! 332: GEN gtyp,fa,junk,primlist,p,listgtyp,indexsubq = NULL;
! 333: long oindexbound = indexbound;
! 334: long oexpoI = expoI;
! 335: long *opowerlist = powerlist;
! 336: GEN osubq = subq;
! 337: GEN oBINMAT = BINMAT;
! 338: long olsubq = lsubq;
! 339:
! 340: long *ommu=mmu, *olam=lam, *oc=c, *omaxc=maxc, *oa=a, *omaxa=maxa, **og=g, **omaxg=maxg;
! 341: GEN **oH=H, osubqpart=subqpart;
! 342: long ocountsub=countsub;
! 343: long *oavailable=available, olsubqpart=lsubqpart;
! 344:
! 345: if (typ(cyc) != t_VEC)
! 346: {
! 347: if (typ(cyc) != t_MAT) err(typeer,"forsubgroup");
! 348: cyc = mattodiagonal(cyc);
! 349: }
! 350: for (i=1; i<n-1; i++)
! 351: if (!divise((GEN)cyc[i], (GEN)cyc[i+1]))
! 352: err(talker,"not a group in forsubgroup");
! 353: if (n == 1 || gcmp1((GEN)cyc[1])) { treatsub(cyc); return 1; }
! 354: if (!signe(cyc[1]))
! 355: err(talker,"infinite group in forsubgroup");
! 356: if (DEBUGLEVEL) timer2();
! 357: indexbound = bound;
! 358: fa = factor((GEN)cyc[1]); primlist = (GEN)fa[1];
! 359: nbprim = lg(primlist);
! 360: listgtyp = new_chunk(n); imax = k = 0;
! 361: for (i=1; i<nbprim; i++)
! 362: {
! 363: gtyp = new_chunk(n); p = (GEN)primlist[i];
! 364: for (j=1; j<n; j++)
! 365: {
! 366: gtyp[j] = pvaluation((GEN)cyc[j], p, &junk);
! 367: if (!gtyp[j]) break;
! 368: }
! 369: j--; gtyp[0] = j;
! 370: if (j > k) { k = j; imax = i; }
! 371: listgtyp[i] = (long)gtyp;
! 372: }
! 373: gtyp = (GEN)listgtyp[imax]; p = (GEN)primlist[imax];
! 374: k = gtyp[1];
! 375: powerlist = new_chunk(k+1); powerlist[0] = 1;
! 376: powerlist[1] = itos(p);
! 377: for (j=1; j<=k; j++) powerlist[j] = powerlist[1] * powerlist[j-1];
! 378:
! 379: if (DEBUGLEVEL) BINMAT = matqpascal(gtyp[0]+1, p);
! 380: if (nbprim == 2) subq = NULL;
! 381: else
! 382: { /* not a p-group */
! 383: GEN cyc2 = dummycopy(cyc);
! 384: GEN ohnfgroup = hnfgroup;
! 385: for (i=1; i<n; i++)
! 386: {
! 387: cyc2[i] = ldivis((GEN)cyc2[i], powerlist[gtyp[i]]);
! 388: if (gcmp1((GEN)cyc2[i])) break;
! 389: }
! 390: setlg(cyc2, i);
! 391: if (is_bigint(cyc[1]))
! 392: err(impl,"subgrouplist for large cyclic factors");
! 393: expoI = itos((GEN)cyc2[1]);
! 394: hnfgroup = diagonal(cyc2);
! 395: subq = subgrouplist(cyc2, bound);
! 396: hnfgroup = ohnfgroup;
! 397: lsubq = lg(subq);
! 398: for (i=1; i<lsubq; i++)
! 399: subq[i] = (long)expand_sub((GEN)subq[i], n);
! 400: if (indexbound)
! 401: {
! 402: indexsubq = new_chunk(lsubq);
! 403: for (i=1; i<lsubq; i++)
! 404: indexsubq[i] = itos(dethnf((GEN)subq[i]));
! 405: }
! 406: /* lift subgroups of I to G */
! 407: for (i=1; i<lsubq; i++)
! 408: subq[i] = lmulsg(powerlist[k],(GEN)subq[i]);
! 409: if (DEBUGLEVEL>2)
! 410: {
! 411: fprintferr("(lifted) subgp of prime to %Z part:\n",p);
! 412: outbeaut(subq);
! 413: }
! 414: }
! 415: count = dopsub(powerlist[1],gtyp,indexsubq);
! 416: if (DEBUGLEVEL) fprintferr("nb subgroup = %ld\n",count);
! 417:
! 418: mmu=ommu; lam=olam; c=oc; maxc=omaxc; a=oa; maxa=omaxa; g=og; maxg=omaxg;
! 419: H=oH; subqpart=osubqpart,
! 420: countsub=ocountsub;
! 421: available=oavailable; lsubqpart=olsubqpart;
! 422:
! 423: indexbound = oindexbound;
! 424: expoI = oexpoI;
! 425: powerlist = opowerlist;
! 426: subq = osubq;
! 427: BINMAT = oBINMAT;
! 428: lsubq = olsubq;
! 429: avma=av; return count;
! 430: }
! 431:
! 432: static GEN
! 433: get_snf(GEN x)
! 434: {
! 435: GEN cyc;
! 436: long n;
! 437: switch(typ(x))
! 438: {
! 439: case t_MAT:
! 440: if (!isdiagonal(x)) return NULL;
! 441: cyc = mattodiagonal_i(x); break;
! 442: case t_VEC:
! 443: case t_COL: cyc = dummycopy(x); break;
! 444: default: return NULL;
! 445: }
! 446: for (n = lg(cyc)-1; n > 1; n--) /* take care of trailing 1s */
! 447: {
! 448: GEN c = (GEN)cyc[n];
! 449: if (typ(c) != t_INT) return NULL;
! 450: if (!gcmp1(c)) break;
! 451: }
! 452: setlg(cyc, n+1);
! 453: for ( ; n > 0; n--)
! 454: {
! 455: GEN c = (GEN)cyc[n];
! 456: if (typ(c) != t_INT) return NULL;
! 457: }
! 458: return cyc;
! 459: }
! 460:
! 461: void
! 462: forsubgroup(entree *oep, GEN cyc, long bound, char *och)
! 463: {
! 464: entree *saveep = ep;
! 465: char *savech = gpch;
! 466: void(*savefun)(GEN) = treatsub_fun;
! 467:
! 468: treatsub_fun = std_fun;
! 469: cyc = get_snf(cyc);
! 470: if (!cyc) err(typeer,"forsubgroup");
! 471: gpch = och;
! 472: ep = oep;
! 473: push_val(ep, gzero);
! 474: (void)subgroup_engine(cyc,bound);
! 475: pop_val(ep);
! 476: treatsub_fun = savefun;
! 477: gpch = savech;
! 478: ep = saveep;
! 479: }
! 480:
! 481: GEN
! 482: subgrouplist(GEN cyc, long bound)
! 483: {
! 484: void(*savefun)(GEN) = treatsub_fun;
! 485: slist *olist = sublist, *list;
! 486: long ii,i,j,k,nbsub,n, N = lg(cyc)-1, av = avma;
! 487: GEN z,H;
! 488: GEN ohnfgroup = hnfgroup;
! 489:
! 490: sublist = list = (slist*) gpmalloc(sizeof(slist));
! 491: treatsub_fun = list_fun;
! 492: cyc = get_snf(cyc);
! 493: if (!cyc) err(typeer,"subgrouplist");
! 494: n = lg(cyc)-1;
! 495: hnfgroup = diagonal(cyc);
! 496: nbsub = subgroup_engine(cyc,bound);
! 497: hnfgroup = ohnfgroup; avma = av;
! 498: z = cgetg(nbsub+1,t_VEC); sublist = list;
! 499: for (ii=1; ii<=nbsub; ii++)
! 500: {
! 501: list = sublist; sublist = list->next; free(list);
! 502: H = cgetg(N+1,t_MAT); z[ii]=(long)H; k=0;
! 503: for (j=1; j<=n; j++)
! 504: {
! 505: H[j] = lgetg(N+1, t_COL);
! 506: for (i=1; i<=j; i++) coeff(H,i,j) = lstoi(sublist->data[k++]);
! 507: for ( ; i<=N; i++) coeff(H,i,j) = zero;
! 508: }
! 509: for ( ; j<=N; j++)
! 510: {
! 511: H[j] = lgetg(N+1, t_COL);
! 512: for (i=1; i<=N; i++) coeff(H,i,j) = (i==j)? un: zero;
! 513: }
! 514: }
! 515: free(sublist); sublist = olist;
! 516: treatsub_fun = savefun; return z;
! 517: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>