/* $Id: perm.c,v 1.9 2002/05/29 17:58:23 bill Exp $ Copyright (C) 2000 The PARI group. This file is part of the PARI/GP package. PARI/GP is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY WHATSOEVER. Check the License for details. You should have received a copy of it, along with the package; see the file 'COPYING'. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "pari.h" /*************************************************************************/ /** **/ /** Routine for handling VECSMALL **/ /** **/ /*************************************************************************/ GEN vecsmall_const(long n, long c) { long i; GEN V=cgetg(n+1,t_VECSMALL); for(i=1;i<=n;i++) V[i]=c; return V; } GEN vecsmall_shorten(GEN v, long n) { long i; GEN V=cgetg(n+1,t_VECSMALL); for(i=1;i<=n;i++) V[i]=v[i]; return V; } /*in place sort.*/ void vecsmall_sort(GEN V) { long i,j,k,l,m; for(l=1;l>1)V[k]) { long z=V[k]; for (m=k;m>i;m--) V[m]=V[m-1]; V[i]=z; k++; } else i++; } GEN vecsmall_uniq(GEN V) { gpmem_t ltop=avma; GEN W; long i,j; if ( lg(V) == 1 ) return gcopy(V); W=cgetg(lg(V),t_VECSMALL); W[1]=V[1]; for(i=2,j=1;i>TWOPOTBITS_IN_LONG); return vecsmall_const(l,0); } GEN bitvec_shorten(GEN bitvec, long n) { long l=1+(n>>TWOPOTBITS_IN_LONG); return vecsmall_shorten(bitvec,l); } long bitvec_test(GEN bitvec, long b) { long q=b>>TWOPOTBITS_IN_LONG; long r=b&(BITS_IN_LONG-1); return (bitvec[1+q]>>r)&1L; } void bitvec_set(GEN bitvec, long b) { long q=b>>TWOPOTBITS_IN_LONG; long r=b&(BITS_IN_LONG-1); bitvec[1+q]|=1L<>TWOPOTBITS_IN_LONG; long r=b&(BITS_IN_LONG-1); bitvec[1+q]&=~(1L<perm[i] * cyc (VEC of VECSMALL): a product of disjoint cycles. */ /* indentity permutation */ /* Not a good name since l is not a perm...*/ GEN perm_identity(long l) { GEN perm; int i; perm = cgetg(l + 1, t_VECSMALL); for (i = 1; i <= l; i++) perm[i] = i; return perm; } GEN cyclicperm(long l, long d) { GEN perm; int i; perm = cgetg(l + 1, t_VECSMALL); for (i = 1; i <= l-d; i++) perm[i] = i+d; for (i = l-d+1; i <= l; i++) perm[i] = i-l+d; return perm; } /* * Multiply (compose) two permutations. * Can be used if s is a vector but with no copy */ GEN perm_mul(GEN s, GEN t) { GEN u; int i; if (lg(s) < lg(t)) err(talker, "First permutation shorter than second in perm_mul"); u = cgetg(lg(s), typ(s)); for (i = 1; i < lg(s); i++) u[i] = s[t[i]]; return u; } /* Compute the inverse (reciprocal) of a permutation. */ GEN perm_inv(GEN x) { long i,lx = lg(x); GEN y = cgetg(lx,t_VECSMALL); for (i=1; i G/H */ /*The ouput is [gen,hash]*/ /* gen (vecvecsmall): coset generators * hash (vecvecsmall): sorted vecsmall of concat(perm,coset number) */ GEN group_quotient(GEN G, GEN H) { gpmem_t ltop=avma; GEN p1,p2,p3; long i,j,k; long a=1; long n=lg(mael(G,1,1))-1; long o=group_order(H); GEN elt = vecvecsmall_sort(group_elts(G,n)); GEN used = bitvec_alloc(lg(elt)); long l = (lg(elt)-1)/o; p2 = cgetg(l+1, t_VEC); p3 = cgetg(lg(elt), t_VEC); for (i = 1, k = 1; i <= l; ++i) { GEN V; while(bitvec_test(used,a)) a++; V = group_leftcoset(H,(GEN)elt[a]); p2[i] = V[1]; for(j=1;j G/H * * Lift a subgroup S of G/H to a subgroup of G containing H */ GEN quotient_subgroup_lift(GEN C, GEN H, GEN S) { GEN p1,L; long l1=lg(H[1])-1; long l2=lg(S[1])-1; long j; p1 = cgetg(3, t_VEC); L = cgetg(l1+l2+1, t_VEC); for (j = 1; j <= l1; ++j) L[j] = mael(H,1,j); for (j = 1; j <= l2; ++j) L[l1+j] = (long) gmael(C,1,mael3(S,1,j,1)); p1[1] = (long) L; p1[2] = (long) vecsmall_concat((GEN)H[2],(GEN)S[2]); return p1; } /* Let G a group and H a quotient map G --> G/H * Assume H is normal, return the group G/H. */ GEN quotient_group(GEN C, GEN G) { gpmem_t ltop=avma; GEN Qgen,Qord,Qelt; GEN Q; long i,j; long n=lg(C[1])-1; long l=lg(G[1]); Qord = cgetg(l, t_VECSMALL); Qgen = cgetg(l, t_VEC); Qelt = cgetg(2, t_VEC); Qelt[1] = (long) perm_identity(n); for (i = 1, j = 1; i < l; ++i) { Qgen[j] = (long) quotient_perm(C, gmael(G,1,i)); Qord[j] = (long) perm_relorder((GEN) Qgen[j], vecvecsmall_sort(Qelt)); if (Qord[j]!=1) { Qelt=perm_generate((GEN) Qgen[j], Qelt, Qord[j]); j++; } } setlg(Qgen,j); setlg(Qord,j); Q=cgetg(3,t_VEC); Q[1]=(long)Qgen; Q[2]=(long)Qord; return gerepilecopy(ltop,Q); } /* Test if g normalize N*/ long group_perm_normalize(GEN N, GEN g) { gpmem_t ltop=avma; long l1 = gegal(vecvecsmall_sort(group_leftcoset(N, g)), vecvecsmall_sort(group_rightcoset(N, g))); avma=ltop; return l1; } /* L is a list of subgroups, C is a coset and r a rel. order.*/ static GEN liftlistsubgroups(GEN L, GEN C, long r) { gpmem_t ltop=avma; GEN p4; long i, k; long c=lg(C)-1; long l=lg(L)-1; long n=lg(C[1])-1; if ( !l ) return cgetg(1,t_VEC); p4 = cgetg(l*c+1, t_VEC); for (i = 1, k = 1; i <= l; ++i) { long j; GEN S = (GEN) L[i]; GEN Selt = vecvecsmall_sort(group_elts(S,n)); for (j = 1; j <= c; ++j) if ((perm_relorder((GEN) C[j], Selt) == r) && group_perm_normalize(S, (GEN) C[j])) { GEN p7 = cgetg(3, t_VEC); p7[1] = (long) vecsmall_append((GEN) S[1], C[j]); p7[2] = (long) vecsmall_append((GEN) S[2], r); p4[k++] = (long) p7; } } setlg(p4,k); return gerepilecopy(ltop,p4); } /* H is a normal subgroup, C is the quotient map G -->G/H, * S is a subgroup of G/H, and G is embedded in Sym(l) * Return all the subgroups K of G such that * S= K mod H and K inter H={1}. */ static GEN liftsubgroup(GEN C, GEN H, GEN S) { gpmem_t ltop=avma; GEN V = trivialsubgroups(); long n = lg(S[1]); long i; /*Loop over generators of S*/ for (i = 1; i < n; ++i) { GEN W = group_leftcoset(H, gmael(C, 1, mael3(S, 1, i, 1))); V = liftlistsubgroups(V, W, mael(S, 2, i)); } return gerepilecopy(ltop,V); } /* compute all the subgroups of a group G */ GEN group_subgroups(GEN G) { gpmem_t ltop=avma; GEN p1; GEN C,Q,M; long lM; GEN sg1,sg2,sg3; long i, j; GEN gen=(GEN)G[1], ord=(GEN)G[2]; GEN H; long l, n = lg(gen); if (n == 1) return trivialsubgroups(); l = lg(gen[1]);/*now lg(gen)>1*/ if ( ( n == 4 || n == 5) && ord[1]==2 && ord[2]==2 && ord[3]==3 && (n == 4 || ord[4]==2) ) { GEN u=perm_mul((GEN) gen[1],(GEN) gen[2]); H = dicyclicgroup((GEN) gen[1],(GEN) gen[2],2,2); /* sg3 is the list of subgroups intersecting only partially with H*/ sg3 = cgetg((n==4)?4:10, t_VEC); sg3[1] = (long) cyclicgroup((GEN) gen[1], 2); sg3[2] = (long) cyclicgroup((GEN) gen[2], 2); sg3[3] = (long) cyclicgroup(u, 2); if (n==5) { GEN s=(GEN) gen[1]; GEN t=(GEN) gen[2]; GEN u=(GEN) gen[3],u2=perm_mul(u,u); GEN v=(GEN) gen[4]; GEN st=perm_mul(s,t); GEN w=perm_mul(perm_mul(u2,perm_mul(s,v)),u2); sg3[4] = (long) dicyclicgroup(s,v,2,2); sg3[5] = (long) dicyclicgroup(t,perm_mul(u,perm_mul(v,u2)),2,2); sg3[6] = (long) dicyclicgroup(st,perm_mul(u2,perm_mul(v,u)),2,2); sg3[7] = (long) dicyclicgroup(s,w,2,2); sg3[8] = (long) dicyclicgroup(t,perm_mul(u,perm_mul(w,u2)),2,2); sg3[9] = (long) dicyclicgroup(st,perm_mul(u2,perm_mul(w,u)),2,2); } } else { long osig = itos((GEN) coeff(decomp(stoi(ord[1])), 1, 1)); GEN sig = perm_pow((GEN) gen[1], ord[1]/osig); H = cyclicgroup(sig,osig); sg3=NULL; } C = group_quotient(G,H); Q = quotient_group(C,G); M = group_subgroups(Q); lM = lg(M); /* sg1 is the list of subgroups containing H*/ sg1 = cgetg(lM, t_VEC); for (i = 1; i < lM; ++i) sg1[i] = (long) quotient_subgroup_lift(C,H,(GEN)M[i]); /*sg2 is a list of lists of subgroups not intersecting with H*/ sg2 = cgetg(lM, t_VEC); /* Loop over all subgroups of G/H */ for (j = 1; j < lM; ++j) sg2[j] = (long) liftsubgroup(C, H, (GEN) M[j]); p1 = concat(sg1, concat(sg2, NULL)); if (sg3) p1 = concat(p1, sg3); return gerepileupto(ltop,p1); } /*return 1 if G is abelian, else 0*/ long group_isabelian(GEN G) { gpmem_t ltop=avma; long i,j; for(i=2;i