GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it
/***** This file contains some routines for orbit calculations *****/1#include"typedef.h"23/**********************************************************************\4| V.v is a sorted list of length V.n of vectors5| of dimension V.dim, the number of V.v[nr]*A in6| the list is returned, where a negative number7| indicates the negative of a vector8\**********************************************************************/9static int operate(nr, A, V)10veclist V;11int nr, **A;12{13int i, im, *w;1415if ((w = (int*)malloc(V.dim * sizeof(int))) == 0)16exit (2);17vecmatmul(V.v[abs(nr)], A, V.dim, w);18if (nr < 0)19{20for (i = 0; i < V.dim; ++i)21w[i] *= -1;22}23im = numberof(w, V);24if (abs(im) > V.n)25/* the vector is not in the list */26{27fprintf(stderr, "Error: image of vector %d not found\n", nr);28exit (3);29}30free(w);31return(im);32}3334/**********************************************************************\35| computes the orbit of npt points in pt36| under the nG matrices in G and puts the37| orbit in orb, allocates the memory for38| orb, returns the length of the orbit,39| the points are the indices in the list V.v40\**********************************************************************/41static int orbit(pt, npt, G, nG, V, orb)42veclist V;43int *pt, npt, ***G, nG, **orb;44{45int i, norb, cnd, im, *flag;4647if ((*orb = (int*)malloc(npt * sizeof(int))) == 0)48exit (2);49/* if flag[i + V.n] = 1, then the point i is already in the orbit */50if ((flag = (int*)malloc((2*V.n + 1) * sizeof(int))) == 0)51exit (2);52for (i = 0; i <= 2*V.n; ++i)53flag[i] = 0;54for (i = 0; i < npt; ++i)55{56(*orb)[i] = pt[i];57flag[pt[i]+V.n] = 1;58}59norb = npt;60cnd = 0;61while (cnd < norb)62{63for (i = 0; i < nG; ++i)64{65im = operate((*orb)[cnd], G[i], V);66if (flag[im+V.n] == 0)67/* the image is a new point in the orbit */68{69++norb;70if ((*orb = (int*)realloc(*orb, norb * sizeof(int))) == 0)71exit (2);72(*orb)[norb-1] = im;73flag[im+V.n] = 1;74}75}76++cnd;77}78free(flag);79return(norb);80}8182/**********************************************************************\83| checks, whether the orbit of pt under84| the nG matrices in G has at least length orblen85\**********************************************************************/86static int orbitlen(pt, orblen, G, nG, V)87veclist V;88int pt, orblen, ***G, nG;89{90int i, len, cnd, im, *orb, *flag;9192if ((orb = (int*)malloc(orblen * sizeof(int))) == 0)93exit(2);94/* if flag[i + V.n] = 1, then the point i is already in the orbit */95if ((flag = (int*)malloc((2*V.n + 1) * sizeof(int))) == 0)96exit(2);97for (i = 0; i <= 2*V.n; ++i)98flag[i] = 0;99orb[0] = pt;100flag[pt+V.n] = 1;101for (i = 1; i < orblen; ++i)102orb[i] = 0;103len = 1;104cnd = 0;105while (cnd < len && len < orblen)106{107for (i = 0; i < nG && len < orblen; ++i)108{109im = operate(orb[cnd], G[i], V);110if (flag[im+V.n] == 0)111/* the image is a new point in the orbit */112{113orb[len] = im;114++len;115flag[im+V.n] = 1;116}117}118++cnd;119}120free(orb);121free(flag);122return(len);123}124125/**********************************************************************\126| deletes the elements in orb2 from orb1,127| an entry 0 marks the end of the list, returns the length of orb1128\**********************************************************************/129static int delete(orb1, l1, orb2, l2)130int *orb1, l1, *orb2, l2;131{132int i, j, len, o2i;133134/* the true length of orb1 is len, hence orb1[len-1] != 0 */135for (i = 0; i < l1 && orb1[i] != 0; ++i);136len = i;137for (i = 0; i < l2 && orb2[i] != 0; ++i)138{139o2i = orb2[i];140for (j = 0; j < len && orb1[j] != o2i; ++j);141/* orb1[j] = orb2[i], hence delete orb1[j] from orb1 */142if (j < len)143{144orb1[j] = orb1[len-1];145orb1[len-1] = 0;146--len;147}148}149return(len);150}151152/**********************************************************************\153| computes the orbit of fp.e[I] under the154| generators in G->g[I]...G->g[n-1] and elements155| stabilizing fp.e[I],156| has some heuristic break conditions,157| the generators in G->g[i] stabilize158| fp.e[0]...fp.e[i-1] but not fp.e[i],159| G->ng[i] is the number of generators in G->g[i],160| the first G->nsg[i] of which are elements which161| are obtained as stabilizer elements in162| <G->g[0],...,G->g[i-1]>, G->ord[i] is the orbit163| length of fp.e[i] under <G->g[i],...,G->g[n-1]>164\**********************************************************************/165static void stab(I, G, fp, V)166group *G;167fpstruct fp;168veclist V;169{170int *orb, len, cnd, tmplen;171int **w, *flag, ***H, ***Hj, **S, **tmp, ***Ggj;172int i, j, k, l, dim, im, nH, nHj, fail;173int Maxfail, Rest;174175/* some heuristic break conditions for the computation of stabilizer elements:176it would be too expensive to calculate all the stabilizer generators, which177are obtained from the orbit, since this is highly redundant,178on the other hand every new generator which enlarges the group is much179cheaper than one obtained from the backtrack,180after Maxfail subsequent stabilizer elements, that do not enlarge the group,181Rest more elements are calculated even if they leave the group unchanged,182since it turned out that this is often useful in the following steps,183increasing the parameters will possibly decrease the number of generators184for the group, but will increase the running time,185there is no magic behind this heuristic, tuning might be appropriate */186dim = V.dim;187Rest = 0;188for (i = I; i < dim; ++i)189{190if (fp.diag[i] > 1 && G->ord[i] < fp.diag[i])191++Rest;192}193Maxfail = Rest;194for (i = 0; i < dim; ++i)195{196if (fp.diag[i] > 1)197++Maxfail;198}199nH = 0;200for (i = I; i < dim; ++i)201nH += G->ng[i];202/* H are the generators of the group in which the stabilizer is computed */203if ((H = (int***)malloc(nH * sizeof(int**))) == 0)204exit (2);205if ((Hj = (int***)malloc((nH+1) * sizeof(int**))) == 0)206exit (2);207k = 0;208for (i = I; i < dim; ++i)209{210for (j = 0; j < G->ng[i]; ++j)211{212H[k] = G->g[i][j];213++k;214}215}216/* in w[V.n+i] an element is stored that maps fp.e[I] on v[i] */217if ((w = (int**)malloc((2*V.n+1) * sizeof(int*))) == 0)218exit (2);219/* orb contains the orbit of fp.e[I] */220if ((orb = (int*)malloc(2*V.n * sizeof(int))) == 0)221exit (2);222for (i = 0; i < 2*V.n; ++i)223orb[i] = 0;224/* if flag[i + V.n] = 1, then the point i is already in the orbit */225if ((flag = (int*)malloc((2*V.n+1) * sizeof(int))) == 0)226exit (2);227for (i = 0; i <= 2*V.n; ++i)228flag[i] = 0;229/* S is a matrix to hold a stabilizer element temporarily */230if ((S = (int**)malloc(dim * sizeof(int*))) == 0)231exit (2);232for (i = 0; i < dim; ++i)233{234if ((S[i] = (int*)malloc(dim * sizeof(int))) == 0)235exit (2);236}237orb[0] = fp.e[I];238flag[orb[0]+V.n] = 1;239if ((w[orb[0]+V.n] = (int*)malloc(dim * sizeof(int))) == 0)240exit (2);241for (i = 0; i < dim; ++i)242w[orb[0]+V.n][i] = fp.e[i];243cnd = 0;244len = 1;245/* fail is the number of successive failures */246fail = 0;247while (len > cnd && fail < Maxfail+Rest)248{249for (i = 0; i < nH && fail < Maxfail+Rest; ++i)250{251if (fail >= Maxfail)252/* there have already been Maxfail successive failures, now a random generator253is applied to a random point of the orbit to get Rest more stabilizer254elements */255{256cnd = rand() % len;257if (cnd < 0)258cnd += len;259i = rand() % nH;260if (i < 0)261i += nH;262}263im = operate(orb[cnd], H[i], V);264if (flag[im+V.n] == 0)265/* a new element is found, appended to the orbit and an element mapping266fp.e[I] to im is stored in w[im+V.n] */267{268orb[len] = im;269flag[im+V.n] = 1;270if ((w[im+V.n] = (int*)malloc(dim * sizeof(int))) == 0)271exit (2);272for (j = 0; j < dim; ++j)273w[im+V.n][j] = operate(w[orb[cnd]+V.n][j], H[i], V);274++len;275}276else277/* the image was already in the orbit */278{279/* j is the first index where the images of the old and the new element280mapping e[I] on im differ */281for (j = I; j < dim && operate(w[orb[cnd]+V.n][j], H[i], V) == w[im+V.n][j]; ++j);282if (j < dim &&283(G->ord[j] < fp.diag[j] || fail >= Maxfail))284{285/* new stabilizer element S = w[orb[cnd]+V.n] * H[i] * (w[im+V.n])^-1 */286stabil(S, w[orb[cnd]+V.n], w[im+V.n], fp.per, H[i], V);287Hj[0] = S;288nHj = 1;289for (k = j; k < dim; ++k)290{291for (l = 0; l < G->ng[k]; ++l)292{293Hj[nHj] = G->g[k][l];294++nHj;295}296}297tmplen = orbitlen(fp.e[j], fp.diag[j], Hj, nHj, V);298if (tmplen > G->ord[j] || fail >= Maxfail)299/* the new stabilizer element S enlarges the orbit of e[j] */300{301++G->ng[j];302++G->nsg[j];303/* allocate memory for the new generator */304if ((G->g[j] = (int***)realloc(G->g[j], G->ng[j] * sizeof(int**))) == 0)305exit (2);306if ((G->g[j][G->ng[j]-1] = (int**)malloc(dim * sizeof(int*))) == 0)307exit (2);308for (k = 0; k < dim; ++k)309{310if ((G->g[j][G->ng[j]-1][k] = (int*)malloc(dim * sizeof(int))) == 0)311exit (2);312}313Ggj = G->g[j];314/* the new generator is inserted as stabilizer element nr. nsg[j]-1 */315for (k = G->ng[j]-1; k >= G->nsg[j]; --k)316{317tmp = Ggj[k];318Ggj[k] = Ggj[k-1];319Ggj[k-1] = tmp;320}321for (k = 0; k < dim; ++k)322{323for (l = 0; l < dim; ++l)324Ggj[G->nsg[j]-1][k][l] = S[k][l];325}326G->ord[j] = tmplen;327++nH;328if ((H = (int***)realloc(H, nH * sizeof(int**))) == 0)329exit (2);330if ((Hj = (int***)realloc(Hj, (nH+1) * sizeof(int**))) == 0)331exit (2);332/* the new generator is appended to H */333H[nH-1] = Ggj[G->nsg[j]-1];334/* the number of failures is reset to 0 */335if (fail < Maxfail)336fail = 0;337else338++fail;339}340else341/* the new stabilizer element S does not enlarge the orbit of e[j] */342++fail;343}344else if (j < dim && fail < Maxfail ||345j == dim && fail >= Maxfail)346++fail;347/* if S is the identity and fail < Maxfail, nothing is done */348}349}350if (fail < Maxfail)351++cnd;352}353for (i = 0; i <= 2*V.n; ++i)354{355if (flag[i] == 1)356free(w[i]);357}358free(w);359for (i = 0; i < dim; ++i)360free(S[i]);361free(S);362free(orb);363free(flag);364free(H);365free(Hj);366}367368/**********************************************************************\369| generates the matrix X which has as row370| per[i] the vector nr. x[i] from the list v371\**********************************************************************/372static void matgen(x, X, dim, per, v)373int *x, **X, dim, *per, **v;374{375int i, j, xi, *Xperi;376377for (i = 0; i < dim; ++i)378{379Xperi = X[per[i]];380if ((xi = x[i]) > 0)381{382for (j = 0; j < dim; ++j)383Xperi[j] = v[xi][j];384}385else386{387for (j = 0; j < dim; ++j)388Xperi[j] = -v[-xi][j];389}390}391}392393/**********************************************************************\394| x1 corresponds to an element X1 mapping some vector e on p1,395| x2 to an element X2 mapping e on p2 and G is a generator mapping396| p1 on p2, then S = X1*G*X2^-1 stabilizes e397\**********************************************************************/398static void stabil(S, x1, x2, per, G, V)399veclist V;400int **S, *x1, *x2, *per, **G;401{402int i, dim, *x, **XG, **X2;403404dim = V.dim;405if ((XG = (int**)malloc(dim * sizeof(int*))) == 0)406exit (2);407if ((X2 = (int**)malloc(dim * sizeof(int*))) == 0)408exit (2);409for (i = 0; i < dim; ++i)410{411if ((XG[i] = (int*)malloc(dim * sizeof(int))) == 0)412exit (2);413if ((X2[i] = (int*)malloc(dim * sizeof(int))) == 0)414exit (2);415}416if ((x = (int*)malloc(dim * sizeof(int))) == 0)417exit (2);418for (i = 0; i < dim; ++i)419x[i] = operate(x1[i], G, V);420/* XG is the composite mapping of the matrix corresponding to x1 and G */421matgen(x, XG, dim, per, V.v);422matgen(x2, X2, dim, per, V.v);423/* S = XG * X2^-1 */424psolve(S, X2, XG, dim, V.prime);425free(x);426for (i = 0; i < dim; ++i)427{428free(XG[i]);429free(X2[i]);430}431free(XG);432free(X2);433}434435436