GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it
#include"typedef.h"1/***** This file contains some routines to compute automorphisms of a lattice2and to determine candidates for the image of a base vector *****/345/***************************************************************\6| tests, whether x[0],...,x[I-1] is a partial7| automorphism, using scalar product combinations8| and Bacher-polynomials depending on the chosen9| options, puts the candidates for x[I] (i.e. the10| vectors vec such that the scalar products of11| x[0],...,x[I-1],vec are correct) on CI,12| returns their number (should be fp[I])13\***************************************************************/14static int cand(CI, I, x, V, F, fp, comb, bach, flags)15veclist V;16invar F;17fpstruct fp;18scpcomb *comb;19bachpol *bach;20flagstruct flags;21int *CI, I, *x;22{23int i, j, k, dim, okp, okm, sign, nr, fail, num;24int *vec, *scpvec, **xvec, **xbase, **Fxbase, DEP, len, rank, n;25int *Vvj, *FAiI, **Fvi, *xnum, xk, *comtri, *comcoi, xbij, vj;26scpcomb com;27int test;2829dim = F.dim;30DEP = flags.DEPTH;31len = F.n * DEP;3233if(normal_option == TRUE && I >0)34{35test = normal_aut_test(x, I-1, V);36if(test == FALSE)37return(0);38}39if (I-1 >= 0 && I-1 < flags.BACHDEP)40{41if (flags.BACH[2] == 0)42flags.BACHSCP = V.v[abs(x[I-1])][dim] / 2;43if (bachcomp(bach[I-1], x[I-1], flags.BACHSCP, V, F.v[0]) == 0)44return(0);45}46if ((vec = (int*)malloc(dim * sizeof(int))) == 0)47exit (2);48if ((scpvec = (int*)malloc(len * sizeof(int))) == 0)49exit (2);50if (I-1 >= 0 && DEP > 0)51{52com = comb[I-1];53rank = com.rank;54n = com.list.n;55/* xvec is the list of vector sums which are computed with respect to the56partial basis in x */57if ((xvec = (int**)malloc((n+1) * sizeof(int*))) == 0)58exit (2);59for (i = 0; i <= n; ++i)60{61if ((xvec[i] = (int*)malloc(dim * sizeof(int))) == 0)62exit (2);63for (j = 0; j < dim; ++j)64xvec[i][j] = 0;65}66/* xbase should be a basis for the lattice generated by the vectors in xvec,67it is obtained via the transformation matrix comb[I-1].trans */68if ((xbase = (int**)malloc(rank * sizeof(int*))) == 0)69exit (2);70for (i = 0; i < rank; ++i)71{72if ((xbase[i] = (int*)malloc(dim * sizeof(int))) == 0)73exit (2);74}75/* Fxbase is the product of a form F with the base xbase */76if ((Fxbase = (int**)malloc(rank * sizeof(int*))) == 0)77exit (2);78for (i = 0; i < rank; ++i)79{80if ((Fxbase[i] = (int*)malloc(dim * sizeof(int))) == 0)81exit (2);82}83}84/* CI is the list for the candidates */85for (i = 0; i < fp.diag[I]; ++i)86CI[i] = 0;87nr = 0;88fail = 0;89for (j = 1; j <= V.n && fail == 0; ++j)90{91Vvj = V.v[j];92okp = 0;93okm = 0;94for (k = 0; k < len; ++k)95scpvec[k] = 0;96for (i = 0; i < F.n; ++i)97{98FAiI = F.A[i][fp.per[I]];99Fvi = F.v[i];100/* vec is the vector of scalar products of V.v[j] with the first I base vectors101x[0]...x[I-1] */102for (k = 0; k < I; ++k)103{104if ((xk = x[k]) > 0)105vec[k] = sscp(Vvj, Fvi[xk], dim);106else107vec[k] = -sscp(Vvj, Fvi[-xk], dim);108}109for (k = 0; k < I && vec[k] == FAiI[fp.per[k]]; ++k);110if (k == I && Vvj[dim+i] == FAiI[fp.per[I]])111/* V.v[j] is a candidate for x[I] with respect to the form F.A[i] */112++okp;113for (k = 0; k < I && vec[k] == -FAiI[fp.per[k]]; ++k);114if (k == I && Vvj[dim+i] == FAiI[fp.per[I]])115/* -V.v[j] is a candidate for x[I] with respect to the form F.A[i] */116++okm;117if (I-1 >= 0 && DEP > 0)118{119for (k = I-1; k >= 0 && k > I-1-DEP; --k)120scpvec[i*DEP+I-1-k] = vec[k];121}122}123if (I-1 >= 0 && DEP > 0)124/* check, whether the scalar product combination scpvec is contained in the125list comb[I-1].list */126{127for (i = 0; i < len && scpvec[i] == 0; ++i);128if (i == len)129num = 0;130else131{132num = numberof(scpvec, com.list);133sign = num > 0 ? 1 : -1;134num *= sign;135}136if (num > n)137/* scpvec is not found, hence x[0]...x[I-1] is not a partial automorphism */138fail = 1;139else if (num > 0)140/* scpvec is found and the vector is added to the corresponding vector sum */141{142xnum = xvec[num];143for (k = 0; k < dim; ++k)144xnum[k] += sign * Vvj[k];145}146}147if (okp == F.n)148/* V.v[j] is a candidate for x[I] */149{150if (nr < fp.diag[I])151{152CI[nr] = j;153++nr;154}155else156/* there are too many candidates */157fail = 1;158}159if (okm == F.n)160/* -V.v[j] is a candidate for x[I] */161{162if (nr < fp.diag[I])163{164CI[nr] = -j;165++nr;166}167else168/* there are too many candidates */169fail = 1;170}171}172if (fail == 1)173nr = 0;174if (nr == fp.diag[I] && I-1 >= 0 && DEP > 0)175/* compute the basis of the lattice generated by the vectors in xvec via the176transformation matrix comb[I-1].trans */177{178for (i = 0; i < rank; ++i)179{180comtri = com.trans[i];181for (j = 0; j < dim; ++j)182{183xbij = 0;184for (k = 0; k <= n; ++k)185xbij += comtri[k] * xvec[k][j];186xbase[i][j] = xbij;187}188}189}190if (nr == fp.diag[I] && I-1 >= 0 && DEP > 0)191/* check, whether the base xbase has the right scalar products */192{193for (i = 0; i < F.n && nr > 0; ++i)194{195for (j = 0; j < rank; ++j)196{197for (k = 0; k < dim; ++k)198Fxbase[j][k] = sscp(F.A[i][k], xbase[j], dim);199}200for (j = 0; j < rank && nr > 0; ++j)201{202for (k = 0; k <= j && nr > 0; ++k)203{204if (sscp(xbase[j], Fxbase[k], dim) != com.F[i][j][k])205/* a scalar product is wrong */206nr = 0;207}208}209}210}211if (nr == fp.diag[I] && I-1 >= 0 && DEP > 0)212/* check, whether comb[I-1].coef * xbase = xvec */213{214for (i = 0; i <= n && nr > 0; ++i)215{216comcoi = com.coef[i];217for (j = 0; j < dim; ++j)218{219vj = 0;220for (k = 0; k < rank; ++k)221vj += comcoi[k] * xbase[k][j];222if (vj != xvec[i][j])223/* an entry is wrong */224nr = 0;225}226}227}228if (I-1 >= 0 && DEP > 0)229{230for (i = 0; i <= n; ++i)231free(xvec[i]);232free(xvec);233for (i = 0; i < rank; ++i)234{235free(xbase[i]);236free(Fxbase[i]);237}238free(xbase);239free(Fxbase);240}241free(scpvec);242free(vec);243return(nr);244}245246/**************************************************\247| search new automorphisms until on all248| levels representatives for all orbits249| have been tested250\**************************************************/251static void autom(G, V, F, fp, comb, bach, flags)252group *G;253veclist V;254invar F;255fpstruct fp;256scpcomb *comb;257bachpol *bach;258flagstruct flags;259{260FILE *outfile;261int i, j, dim, step, im, **C, nC, ***H, nH, **Ggng, found, try;262int *x, *orb, *oc, noc, *bad, nbad;263264dim = F.dim;265if ((C = (int**)malloc(dim * sizeof(int*))) == 0)266exit (2);267/* C[i] is the list of candidates for the image of the i-th base-vector */268for (i = 0; i < dim; ++i)269{270if ((C[i] = (int*)malloc(fp.diag[i] * sizeof(int))) == 0)271exit (2);272}273/* x is the new base, i.e. x[i] is the index in V.v of the i-th base-vector */274if ((x = (int*)malloc(dim * sizeof(int))) == 0)275exit (2);276if ((bad = (int*)malloc(2*V.n * sizeof(int))) == 0)277exit (2);278for (step = flags.STAB; step < dim; ++step)279{280nH = 0;281for (i = step; i < dim; ++i)282nH += G->ng[i];283if ((H = (int***)malloc(nH * sizeof(int**))) == 0)284exit (2);285nH = 0;286for (i = step; i < dim; ++i)287{288for (j = 0; j < G->ng[i]; ++j)289{290H[nH] = G->g[i][j];291++nH;292}293}294for (i = 0; i < 2*V.n; ++i)295bad[i] = 0;296nbad = 0;297/* the first step base-vectors are fixed */298for (i = 0; i < step; ++i)299x[i] = fp.e[i];300/* compute the candidates for x[step] */301if (fp.diag[step] > 1)302/* if fp.diag[step] compute the candidates for x[step] */303nC = cand(C[step], step, x, V, F, fp, comb, bach, flags);304else305/* if fp.diag[step] == 1, fp.e[step] is the only candidate */306{307C[step][0] = fp.e[step];308nC = 1;309}310G->ord[step] = orbit(&(fp.e[step]), 1, H, nH, V, &orb);311/* delete the orbit of the step-th base-vector from the candidates */312nC = delete(C[step], nC, orb, G->ord[step]);313free(orb);314while (nC > 0 && (im = C[step][0]) != 0)315{316found = 0;317/* try vector V.v[im] as image of the step-th base-vector */318x[step] = im;319if (step < dim-1)320{321/* check, whether x[0]...x[step] is a partial basis and compute the candidates322for x[step+1] */323if (cand(C[step+1], step+1, x, V, F, fp, comb, bach, flags) == fp.diag[step+1])324/* go into the recursion */325found = aut(step+1, x, C, G, V, F, fp, comb, bach, flags);326else327found = 0;328}329else330{331found = 1;332if(normal_option == TRUE)333{334found = 0;335for(i=0;i<fp.diag[step] && C[step][0] != 0 && found == 0; i++)336{337x[step] = C[step][0];338found = normal_aut_test(x, step, V);339if(found == 0)340{341for(j=0;j<fp.diag[step]-1;j++)342C[step][j] = C[step][j+1];343C[step][fp.diag[step]-1] = 0;344}345}346}347}348if (found == 0)349/* x[0]...x[step] can not be continued to an automorphism */350{351noc = orbit(&im, 1, H, nH, V, &oc);352/* delete the orbit of im from the candidates for x[step] */353nC = delete(C[step], nC, oc, noc);354free(oc);355bad[nbad] = im;356++nbad;357}358else359/* a new generator has been found */360{361++G->ng[step];362if ((G->g[step] = (int***)realloc(G->g[step], G->ng[step] * sizeof(int**))) == 0)363exit (2);364if ((G->g[step][G->ng[step]-1] = (int**)malloc(dim * sizeof(int*))) == 0)365exit (2);366for (i = 0; i < dim; ++i)367{368if ((G->g[step][G->ng[step]-1][i] = (int*)malloc(dim * sizeof(int))) == 0)369exit (2);370}371Ggng = G->g[step][G->ng[step]-1];372/* append the new generator to G->g[step] */373matgen(x, Ggng, dim, fp.per, V.v);374++nH;375if ((H = (int***)realloc(H, nH * sizeof(int**))) == 0)376exit (2);377nH = 0;378for (i = step; i < dim; ++i)379{380for (j = 0; j < G->ng[i]; ++j)381{382H[nH] = G->g[i][j];383++nH;384}385}386if (flags.PRINT == 1)387/* if the -P option is given, print the new generator on AUTO.tmp */388{389outfile = fopen("AUTO.tmp", "a");390fprintf(outfile, "%d\n", dim);391for (i = 0; i < dim; ++i)392{393for (j = 0; j < dim; ++j)394fprintf(outfile, " %2d", Ggng[i][j]);395fprintf(outfile, "\n");396}397fclose(outfile);398}399/* compute the new orbit of fp.e[step] */400G->ord[step] = orbit(&(fp.e[step]), 1, H, nH, V, &orb);401/* delete the orbit from the candidates for x[step] */402nC = delete(C[step], nC, orb, G->ord[step]);403free(orb);404/* compute the new orbit of the vectors, which could not be continued to an405automorphism */406noc = orbit(bad, nbad, H, nH, V, &oc);407/* delete the orbit from the candidates */408nC = delete(C[step], nC, oc, noc);409free(oc);410}411}412/* test, whether on step flags.STAB some generators may be omitted */413if (step == flags.STAB)414{415for (try = G->nsg[step]; try < G->ng[step]; ++try)416{417nH = 0;418for (j = 0; j < try; ++j)419{420H[nH] = G->g[step][j];421++nH;422}423for (j = try+1; j < G->ng[step]; ++j)424{425H[nH] = G->g[step][j];426++nH;427}428for (i = step+1; i < dim; ++i)429{430for (j = 0; j < G->ng[i]; ++j)431{432H[nH] = G->g[i][j];433++nH;434}435}436if (orbitlen(fp.e[step], G->ord[step], H, nH, V) == G->ord[step])437/* the generator g[step][try] can be omitted */438{439for (i = 0; i < dim; ++i)440free(G->g[step][try][i]);441free(G->g[step][try]);442for (i = try; i < G->ng[step]-1; ++i)443G->g[step][i] = G->g[step][i+1];444--G->ng[step];445--try;446}447}448}449free(H);450if (step < dim-1 && G->ord[step] > 1)451/* calculate stabilizer elements fixing the basis-vectors452fp.e[0]...fp.e[step] */453stab(step, G, fp, V);454if (flags.PRINT == 1)455/* if the -P option is given, print G.ord[step] AUTO.tmp */456{457outfile = fopen("AUTO.tmp", "a");458fprintf(outfile, "G.ord[%d] = %d\n", step, G->ord[step]);459fclose(outfile);460}461}462for (i = 0; i < dim; ++i)463free(C[i]);464free(C);465free(x);466free(bad);467}468469/***************************************************************\470| the heart of the program: the recursion471\***************************************************************/472static int aut(step, x, C, G, V, F, fp, comb, bach, flags)473group *G;474veclist V;475invar F;476fpstruct fp;477scpcomb *comb;478bachpol *bach;479flagstruct flags;480int step, *x, **C;481{482int i, j, dim, orb[1], found;483484dim = F.dim;485found = 0;486while (C[step][0] != 0 && found == 0)487{488if (step < dim-1)489{490/* choose the image of the base-vector nr. step */491x[step] = C[step][0];492/* check, whether x[0]...x[step] is a partial automorphism and compute the493candidates for x[step+1] */494if (cand(C[step+1], step+1, x, V, F, fp, comb, bach, flags) == fp.diag[step+1])495/* go deeper into the recursion */496found = aut(step+1, x, C, G, V, F, fp, comb, bach, flags);497if (found == 1)498return(found);499/* delete the chosen vector from the list of candidates */500orb[0] = x[step];501delete(C[step], fp.diag[step], orb, 1);502}503else504{505if(normal_option == TRUE)506{507found = 0;508for(i=0;i<fp.diag[step] && C[step][0] != 0 && found == 0;i++)509{510x[step] = C[step][0];511found = normal_aut_test(x, step, V);512if(found == 0)513{514for(j=0;j<fp.diag[step]-1;j++)515C[step][j] = C[step][j+1];516C[step][fp.diag[step]-1] = 0;517}518}519}520else521{522/* a new automorphism is found */523x[dim-1] = C[dim-1][0];524found = 1;525}526}527}528return(found);529}530531532