/********************************************************************* ********************************************************************* ********************************************************************* * * xperm.c * * (C) Jose M. Martin-Garcia 2003-2011. * jose@xAct.es * http://www.xAct.es/ * * This is free software, distributed under the GNU GPL license. * See http://metric.iem.csic.es/Martin-Garcia/xAct/ * * These are a collection of C-functions that find Strong Generating * Sets, Coset representatives and Double-coset representatives. * The algorithms are based on Butler and Portugal et al. * * xperm can be used standalone or from the Mathematica package xPerm. * * 20 June - 5 July 2003. Main development. * 3 September 2004. Eliminated MAX variables. * 9 November 2005. Corrected treatment of SGS of group D. * 6 May 2006. All arrays declared dynamically to avoid stack limits. * Thanks to Kasper Peeters for spotting and correcting this. * 25-28 June 2007. Large extension to included multiple dummysets and * repeatedsets. * * Main ideas: * - Permutations are represented using Images notation. * - Generating sets with m n-permutations are stored as lists of * length m*n. * - #define VERBOSE_* to turn on log output. *PPC* * * Comments: * - Permutations are assumed to have degree n>0. * - Lists can have length 0 or positive. * * This is ISO C99, not ANSI-C. There are some gcc extensions: * - ISO C forbids nested functions * - ISO C89 forbids mixed declarations and code * - ISO C90 does not support `long long' * - ISO C90 forbids variable-size arrays * ********************************************************************* ********************************************************************* *********************************************************************/ /********************************************************************* * PROTOTYPES * *********************************************************************/ /* Output */ void print_perm(int *p, int n, int nl); void print_array_perm(int *perms, int m, int n, int nl); void print_list(int *list, int n, int nl); void print_array(int *array, int m, int n, int nl); /* Lists */ int equal_list(int *list1, int *list2, int n); void copy_list(int *list1, int *list2, int n); int position(int i, int *list, int n); int position_list(int *matrix, int m, int *row, int n); void zeros(int *list, int n); void range(int *list, int n); void complement(int *all, int al, int *part, int pl, int n, int *com, int *cl); void sort(int *list, int *slist, int l); void sortB(int *list, int *slist, int l, int *B, int Bl); int minim(int *list, int n); int maxim(int *list, int n); void intersection(int *list1, int l1, int *list2, int l2, int *list, int *l); /* Permutations */ int isid(int *list, int n ); void product(int *p1, int *p2, int *p, int n); void inverse(int *p, int *ip, int n); int onpoints(int point, int *p, int n); void stable_points(int *p, int n, int *list, int *m); int first_nonstable_point(int *p, int n); void nonstable_points(int *list1, int l1, int *GS, int m, int n, int *list2, int *l2); void stabilizer(int *points, int k, int *GS, int m, int n, int *subGS, int *mm); void one_orbit(int point, int *GS, int m, int n, int *orbit, int *ol); void all_orbits(int *GS, int m, int n, int *orbits); void schreier_vector(int point, int *GS, int m, int n, int *nu, int *w); void trace_schreier(int point, int *nu, int *w, int *perm, int n); /* Algorithms */ long long int order_of_group(int *base, int bl, int *GS, int m, int n); int perm_member(int *p, int *base, int bl, int *GS, int m, int n); void schreier_sims_step(int *base, int bl, int *GS, int m, int n, int i, int *T, int mm, int *newbase, int *nbl, int **newGS, int *nm, int *num); void schreier_sims(int *base, int bl, int *GS, int m, int n, int *newbase, int *nbl, int **newGS, int *nm, int *num); void coset_rep(int *p, int n, int *base, int bl, int *GS, int *m, int *freeps, int fl, int *cr); void SGSD(int *vds, int vdsl, int *dummies, int dl, int *mQ, int *vrs, int vrsl, int *repes, int rl, int n, int firstd, int *KD, int *KDl, int *bD, int *bDl); void double_coset_rep(int *g, int n, int *base, int bl, int *GS, int m, int *vds, int vdsl, int *dummies, int dl, int *mQ, int *vrs, int vrsl, int *repes, int rl, int *dcr); void canonical_perm(int *perm, int SGSQ, int *base, int bl, int *GS, int m, int n, int *freeps, int fl, int *dummyps, int dl, int ob, int metricQ, int *cperm); void canonical_perm_ext(int *perm, int n, int SGSQ, int *base, int bl, int *GS, int m, int *frees, int fl, int *vds, int vdsl, int *dummies, int dl, int *mQ, int *vrs, int vrsl, int *repes, int rl, int *cperm); void stab_chain(int *base, int bl, int *GS, int m, int n, int **chain, int *cl); void one_orbit_chain(int point, int *GS, int *poslist, int poslistl, int n, int *orbit, int *ol); void one_schreier_orbit_chain(int point, int *GS, int *poslist, int poslistl, int n, int *orbit, int *ol, int *nu, int *w, int init); void conjugate_chain(int *base, int bl, int *GS, int m, int n, int *p); void basechange_chain(int **base, int *bl, int **GS, int *m, int n, int ***chain, int **cl, int *newbase, int newbl); void appendbasepoint_chain(int **base, int *bl, int ***chain, int **cl, int newbasepoint); void interchange_chain(int **base, int *bl, int **GS, int *m, int n, int ***chain, int **cl, int j); /********************************************************************* * PRINTING FUNCTIONS * *********************************************************************/ /**********************************************************************/ /* print_perm. JMM, 22 June 2003 * * This function prints a permutation p of degree n. If nl=1(0) adds * (does not) a newline. */ void print_perm(int *p, int n, int nl) { int i; if (isid(p,n)) printf("id"); else { printf("("); printf("%d", p[0]); /* No comma */ for (i=1; i0) printf("%d", list[0]); /* No comma */ for (i=1; i0) fprintf(file, "%d", list[0]); /* No comma */ for (i=1; im) m=list[n]; } return(m); } /**********************************************************************/ /* intersection. JMM, 3 July 2003 * * This function returns in list (length l) the intersection of the * elements of lists list1 (length l1) and list2 (length l2). Note that * we return unique (that is, non-repeated) elements. Returned elements * keep the original order in list1. * We assume that enough space (typical l1 or l2 integers) has been * already allocated for list. */ void intersection(int *list1, int l1, int *list2, int l2, int *list, int *l) { int i, j, a; *l = 0; for(i=0; i newbase -> base2 -> newbase -> ... */ /* Copy base into newbase, adding more points if needed */ nonstable_points(base, bl, GS, m, n, newbase, nbl); #ifdef VERBOSE_SCHREIER /*PPC*/ printf("Original base:"); print_list(base, bl, 1); /*PPC*/ printf("New base:"); print_list(newbase, *nbl, 1); /*PPC*/ #endif /*PPC*/ /* Initialize newGS=GS */ copy_list(GS, *newGS, m*n); *nm = m; if (*nbl==0) { /* Problem. Return input sets */ copy_list(base, newbase, bl); *nbl = bl; return; } /* Allocate memory for intermediate SGS and stabilizer */ int i; /* Base index */ int *base2= (int*)malloc( n*sizeof(int)), bl2;/* Interm base */ int *GS2= (int*)malloc(m*n*sizeof(int)), m2; /* Interm GS */ int *stab= (int*)malloc(m*n*sizeof(int)), mm; /* Stabilizer */ /* Main loop */ m2 = *nm; /* Initially GS2 will be just newGS */ for(i=(*nbl); i>0; i--) { #ifdef VERBOSE_SCHREIER /*PPC*/ printf("\nComputing SGS for H^(%d)\n", i-1); /*PPC*/ #endif /*PPC*/ if (*nm > m2) { /* Reallocate GS2 and stab */ GS2 = (int*)realloc(GS2, (*nm)*n*sizeof(int)); stab = (int*)realloc(stab, (*nm)*n*sizeof(int)); } /* Copy newbase into base2 */ copy_list(newbase, base2, *nbl); bl2=*nbl; copy_list(*newGS, GS2, (*nm)*n); m2=*nm; /* Compute newbase from base2 */ stabilizer(base2, i-1, GS2, m2, n, stab, &mm); schreier_sims_step(base2, bl2, GS2, m2, n, i, stab, mm, newbase, nbl, newGS, nm, num); } /* Free allocated memory */ free(base2); free(GS2); free(stab); #ifdef VERBOSE_SCHREIER /*PPC*/ printf("************ END OF ALGORITHM ***********\n"); /*PPC*/ #endif /*PPC*/ } /* Intermediate function for schreier_sims. * * Assuming that S^(i-1) is a GenSet for H^(i-1) and that [B, S^(i)] * are a StrongGenSet for H^(i), find a StrongGenSet for H^(i-1). * T is the set of additional generators in S^(i-1) since the previous * call to the procedure with the present value of i. Assume that a * StrongGenSet of < S^(i-1) - T > (the previous value of H^(i-1)) is * included in B and S. The present value of nu^(i-1) must be an * extension of the previous value. * * base (length bl): tentative base for the whole group * GS (m n-permutations): tentative StrongGenSet for the whole group * i: current order in the hierarchy of stabilizers * * Sizes on input: * i <= bl <= n Not changed * mm <= m Not changed * nbl = bl nbl will increase * nm = m nm will increase */ void schreier_sims_step(int *base, int bl, int *GS, int m, int n, int i, int *T, int mm, int *newbase, int *nbl, int **newGS, int *nm, int *num) { /* Declarations */ /* Counters */ int c, j, jj, level; /* Intermediate permutations */ int *p= (int*)malloc(n*sizeof(int)); int *ip= (int*)malloc(n*sizeof(int)); int *pp= (int*)malloc(n*sizeof(int)); int *ppp= (int*)malloc(n*sizeof(int)); /* Stabilizer of base[1...i-1] */ int *Si= (int*)malloc(m*n*sizeof(int)), Sil; /* Old stabilizer. Here we could use mm*n rather than m*n */ int *oldSi= (int *)malloc(m*n*sizeof(int)), oldSil; /* Orbit of base[i] */ int *Deltai= (int*)malloc( n*sizeof(int)), Deltail; int *w= (int*)malloc( n*sizeof(int)); int *nu= (int*)malloc(n*n*sizeof(int)); /* Old orbit */ int *oldDeltai= (int*)malloc( n*sizeof(int)), oldDeltail; int *oldw= (int*)malloc( n*sizeof(int)); int *oldnu= (int*)malloc(n*n*sizeof(int)); /* Generators to check */ int *genset= (int*)malloc(m*n*sizeof(int)), gensetl; /* Loops */ int gamma, gn, sn; int *s= (int*)malloc(n*sizeof(int)); int *g= (int*)malloc(n*sizeof(int)); /* Stabilizer */ int *stab = (int*)malloc(m*n*sizeof(int)), stabl; int *stabps= (int*)malloc( n*sizeof(int)), stabpsl; #ifdef VERBOSE_SCHREIER /*PPC*/ printf("******** schreier_sims_step ********\n"); /*PPC*/ printf("base:"); print_list(base, bl, 1); /*PPC*/ printf("GS (%d perms of degree %d):", m, n); /*PPC*/ print_array_perm(GS, m, n, 1); /*PPC*/ #endif /*PPC*/ /* Initialize newbase=base and newGS=GS (and their lengths) */ /* They are already equal on input. Always true? */ copy_list(base, newbase, bl); *nbl = bl; copy_list(GS, *newGS, m*n); *nm = m; /* Original generating sets. We get Sil<=m and oldSil<=mm */ stabilizer(base, i-1, GS, m, n, Si, &Sil); #ifdef VERBOSE_SCHREIER /*PPC*/ printf("Stabilizer of first %d points of base ", i-1); /*PPC*/ print_list(base, i-1, 0); printf(" :\n"); /*PPC*/ print_array_perm(Si, Sil, n, 1); /*PPC*/ #endif /*PPC*/ complement(Si, Sil, T, mm, n, oldSi, &oldSil); #ifdef VERBOSE_SCHREIER /*PPC*/ printf("Previous stabilizer of %d points:\n", i-1); /*PPC*/ print_array_perm(oldSi, oldSil, n, 1); /*PPC*/ #endif /*PPC*/ /* Basic orbits */ one_schreier_orbit(base[i-1], Si, Sil, n, Deltai, &Deltail, nu, w, 1); one_schreier_orbit(base[i-1], oldSi, oldSil, n, oldDeltai, &oldDeltail, oldnu, oldw, 1); /* Check that Deltai is an extension of oldDeltai */ for(c=0; ci; level--) { #ifdef VERBOSE_SCHREIER /*PPC*/ printf("\nEnsuring H^(%d) at level %d\n", i+1, level); /*PPC*/ #endif /*PPC*/ schreier_sims_step(newbase,*nbl,*newGS,*nm, n, level, g, 1, newbase,nbl,newGS,nm,num); } #ifdef VERBOSE_SCHREIER /*PPC*/ printf("***** Finished check of H(%d) ******\n\n", i+1);/*PPC*/ #endif /*PPC*/ } } } } /* Free allocated memory */ free(p); free(ip); free(pp); free(ppp); free(Si); free(oldSi); free(Deltai); free(w); free(nu); free(oldDeltai); free(oldw); free(oldnu); free(genset); free(s); free(g); free(stab); free(stabps); } /********************************************************************** * * Notations and comments: * - In xTensor, a permutation g corresponding to a given tensor * configuration is understood as acting on index-numbers giving * tensor-slot numbers. That is, p = i^g (which is p= onpoints(i, g)) * means that i is the index at slot p in the configuration g. * Equivalently, i = p^ig, where ig is the inverse of g. * - That convention is precisely the opposite to the one chosen by * Renato. Everything here and in xPerm follow Renato's convention. * There are two InversePerm actions in ToCanonicalOne in xTensor to * perform the change of notation. Here canonical_perm also has two * inverse actions for backwards compatibility. * - The base of a SGS for the group S represents an ordering of the * slots of the tensor. Changing the base can be understood as a * change of priorities for index canonicalization. */ /**********************************************************************/ /* coset_rep. JMM, 30 June 2003 * * This algorithm is encoded from Renato Portugal et al. * * This function gives a canonical representant of a n-permutation p * in the group described by a SGS (pair base,GS) and the result is * stored in cr. In other words, it gives the canonical representant * of the right coset S.p. The free slots are different at return time. */ void coset_rep(int *p, int n, int *base, int bl, int *GS, int *m, int *freeps, int fl, int *cr) { #ifdef VERBOSE_COSET /*PPC*/ printf("***** RIGHT-COSET-REP ALGORITHM ****\n"); /*PPC*/ printf("Permutation "); print_perm(p, n, 1); /*PPC*/ printf("Base: "); print_list(base, bl, 1); /*PPC*/ #endif /*PPC*/ /* Trivial case without symmetries */ if (*m==0) { copy_list(p, cr, n); return; } /* else */ int i, j, k, b, pp; int *deltap= (int*)malloc( n*sizeof(int)), deltapl; int *deltapsorted= (int*)malloc( n*sizeof(int)); int *om= (int*)malloc( n*sizeof(int)); int *PERM= (int*)malloc( n*sizeof(int)); int *perm2= (int*)malloc( n*sizeof(int)); int *orbit= (int*)malloc( n*sizeof(int)), ol; int *orbit1= (int*)malloc( n*sizeof(int)), o1l; int *w= (int*)malloc( n*sizeof(int)); int *nu= (int*)malloc(n*n*sizeof(int)); int *genset= (int*)malloc(*m*n*sizeof(int)), gensetl; int *stab= (int*)malloc(*m*n*sizeof(int)), mm; /* Copy p to PERM and GS to genset, to avoid side effects. */ copy_list(p, PERM, n); copy_list(GS, genset, *m*n); gensetl=*m; /* Loop over elements of base */ for(i=0; i0 || rl>0) { SGSD(vds, vdsl, dummies, dl, mQ, vrs, vrsl, repes, rl, n, p[i-1], KD, &KDl, bD, &bDl); } else { /* Do nothing */ #ifdef VERBOSE_DOUBLE /*PPC*/ printf("Rearrangement of base of D not required.\n"); /*PPC*/ #endif /*PPC*/ } /* Schreier vector of D */ schreier_vector(p[i-1], KD, KDl, n, nuD, wD); /* Orbit of p[i-1] under D */ one_orbit(p[i-1], KD, KDl, n, Deltap, &Deltapl); #ifdef VERBOSE_DOUBLE /*PPC*/ printf("The orbit of index %d is Deltap: ", p[i-1]); /*PPC*/ print_list(Deltap, Deltapl, 1); /*PPC*/ printf("Looking for digs moving index %d to slot %d\n", /*PPC*/ p[i-1], b); /*PPC*/ #endif /*PPC*/ /* Calculate ALPHA and TAB */ ALPHAstep[i+1]=ALPHAstep[i]; for(l=ALPHAstep[i-1]; l=m) { *GSK = realloc(*GSK, (*mK+1)*n*sizeof(int)); } copy_list(g,(*GSK)+(*mK)*n,n); (*mK)++; *mark=1; } } else { stabilizer(base,i-1,GS,m,n, stab, &sl); one_orbit(base[i-1],stab,sl,n, orbit, &ol); /* file = fopen("/home/jmm/setwise","a"); fprintf(file,"generating over points "); fprint_list(file, orbit, ol, 1); fclose(file); */ for (j=0; j0){ one_schreier_orbit((*base)[0], *GS, *m, n, orbit, &ol, nu, w, 1); more=position(newbase[0], orbit, ol); } else{ more=0; } if(more>0){ trace_schreier(newbase[0], nu, w, g, n); while(more>0 && i<*bl && i0){ trace_schreier(point, nu, w, g2, n); product(g2,g,g3,n); memmove(g, g3, n*sizeof(int)); } i=i+1; } conjugate_chain(*base, *bl, *GS, *m, n, g); } for(j=i-1; j < newbl; j++) { pos=position(newbase[j], *base, *bl); if(pos==0){ appendbasepoint_chain(base, bl, chain, cl, newbase[j]); pos=*bl; } /* file = fopen("xpermlog.txt","a"); fprintf(file,"i=%d, j=%d, pos=%d \n", i, j, pos); fprint_list(file, *base, *bl, 1); fclose(file);*/ while((pos!=(j+1))&&(pos>1)){ /* file = fopen("xpermlog.txt","a"); fprintf(file,"interchange_chain, pos=%d \n", pos); fclose(file);*/ interchange_chain(base, bl, GS, m, n, chain, cl, --pos); } } } /* appendbasepoint_chain. TB, 12 March 2014 * * Appends a point to the end of the base in the stabilizer chain structure. * */ void appendbasepoint_chain(int **base, int *bl, int ***chain, int **cl, int newbasepoint) { (*bl)++; *base=(int *)realloc(*base, (*bl)*sizeof(int)); *cl=(int *)realloc(*cl, (*bl)*sizeof(int)); *chain=(int* *)realloc(*chain, (*bl)*sizeof(int*)); (*base)[(*bl)-1]=newbasepoint; (*cl)[(*bl)-1]=0; (*chain)[(*bl)-1]=NULL; } /* interchange_chain. TB, 13 March 2014 * * Interchanges the point j and j+1 in the base using the stabilizer chain structure. * */ void interchange_chain(int **base, int *bl, int **GS, int *m, int n, int ***chain, int **cl, int j) { int basej, basejp1; int Deltaj[n], Deltajl; int nuj[n*n]; int wj[n]; int Deltajp1[n], Deltajp1l; int orbitjp1jm1l; int nujp1[n*n]; int wjp1[n]; int i,k; int GSK[(*m)*n]; int LDeltaBarjp1; int *T=NULL; int Tl=0; int *Gamma=NULL; int Gammal; int Delta[n]; int Deltal, gamma, p, pos; int g1[n]; int invg1[n]; int g2[n], g2g1[n]; int orbitgammaT[n], orbitgammaTl; int *newT=NULL; int newTl, oldm; int *gsp=NULL; /* FILE *file;*/ basej=(*base)[j-1]; basejp1=(*base)[j]; oldm=*m; /* file = fopen("xpermlog.txt","a"); fprintf(file,"Inside interchange_chain: m=%d, basej=%d, basejp1=%d \n",*m, basej, basejp1); fprintf(file,"base="); fprint_list(file, *base, *bl, 1); fclose(file); file = fopen("xpermlog.txt","a"); fprintf(file,"cl="); fprint_list(file, *cl, *bl, 1); fclose(file);*/ /* for(i=0; i < (*cl)[j]; i++) { memmove(&GSK[n*i], &(*GS)[n*((*chain)[j][i])], n*sizeof(int)); } one_schreier_orbit(basejp1, GSK, (*cl)[j], n, Deltajp1, &Deltajp1l, nujp1, wjp1, 1); */ one_schreier_orbit_chain(basejp1, *GS,(*chain)[j], (*cl)[j], n, Deltajp1, &Deltajp1l, nujp1, wjp1, 1); /* file = fopen("xpermlog.txt","a"); fprintf(file,"Deltajp1="); fprint_list(file, Deltajp1, Deltajp1l, 1); fclose(file);*/ /* for(i=0; i < (*cl)[j-1]; i++) { memmove(&GSK[n*i], &(*GS)[n*((*chain)[j-1][i])], n*sizeof(int)); } one_orbit(basejp1, GSK, (*cl)[j-1], n, Deltaj, &orbitjp1jm1l); one_schreier_orbit(basej, GSK, (*cl)[j-1], n, Deltaj, &Deltajl, nuj, wj, 1); */ one_orbit_chain(basejp1, *GS, (*chain)[j-1], (*cl)[j-1], n, Deltaj, &orbitjp1jm1l); one_schreier_orbit_chain(basej, *GS,(*chain)[j-1], (*cl)[j-1], n, Deltaj, &Deltajl, nuj, wj, 1); /* file = fopen("xpermlog.txt","a"); fprintf(file,"Deltaj="); fprint_list(file, Deltaj, Deltajl, 1); fclose(file);*/ LDeltaBarjp1=Deltajp1l*Deltajl/orbitjp1jm1l; if(j+1<*bl){ T=(int *)malloc(((*cl)[j+1])*n*sizeof(int)); Tl=(*cl)[j+1]; for(i=0; i < (*cl)[j+1]; i++) { memmove(&T[n*i], &(*GS)[n*((*chain)[j+1][i])], n*sizeof(int)); } } Gamma=(int *)malloc(Deltajl*sizeof(int)); Gammal=0; sort(Deltaj, Gamma, Deltajl); for(i=0; i