/********************************************************************* ********************************************************************* ********************************************************************* * * xperm.c * * (C) Jose M. Martin-Garcia 2003-2008. * jmm@iem.cfmac.csic.es, IEM, CSIC, Madrid, Spain. * * 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. * 2015. Eliminate nested functions. Kasper Peeters. * * 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 * ********************************************************************* ********************************************************************* *********************************************************************/ /* KP */ #include #include #include #include #include "xperm_new.h" #include /********************************************************************* * 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); /********************************************************************* * 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; 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=0, 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; i& ALPHA, int *L, int Ll, int *s1, int *d1, int n) { int i; int l=0; /* Search ALPHA for the l corresponding to L */ // std::cout << ALPHA.size() << ", " << Ll << std::endl; for (i=0; i& ALPHA, int *L, int Ll, int *g, int *list, int *listl, int n, int Deltabl, int *Deltab, int *DeltaD) { int c, c1, c2; int *sgd= (int*)malloc(n*sizeof(int)); int *TAB1= (int*)malloc(n*sizeof(int)); int *TAB2= (int*)malloc(n*sizeof(int)); int *tmp= (int*)malloc(n*sizeof(int)); TAB(ALPHA, L, Ll, TAB1, TAB2, n); /* Compute s.g.d */ F2(TAB1, g, TAB2, sgd, n); #ifdef VERBOSE_DOUBLE /*PPC*/ printf("With L="); print_list(L, Ll, 0); /*PPC*/ printf(" we get sgd: "); print_perm(sgd, n, 1); /*PPC*/ #endif /*PPC*/ /* Images of Deltab under sgd. Note that tmp has length Deltabl */ for (c=0; c ALPHA(1); // alphastruct *ALPHA= new alphastruct[1]; //(struct alphastruct*)malloc(sizeof(struct alphastruct)); ALPHA[0].init(n); ALPHA[0].Ll=0; Ll=0; // ? range(ALPHA[0].s, n); range(ALPHA[0].d, n); ALPHAstep[0]=0; ALPHAstep[1]=1; /************************************************************** * CONSTRUCTION OF BASES **************************************************************/ /* Join all drummies */ copy_list(dummies, drummies, dl); copy_list(repes, drummies+dl, rl); dril = dl + rl; /* Slots of all those drummies */ inverse(g, ig, n); 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