GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it
#include "typedef.h"1/***** This file includes those routines for the isometry program which2differ from the routines for the automorphism program *****/345/*****************************************************************\6| tests, whether x[0],...,x[I-1] is a partial7| isometry, 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 number13| (should be fp.diag[I])14\*****************************************************************/15static int isocand(CI, I, x, V, F, FF, fp, comb, bach, flags)16veclist V;17invar F, FF;18fpstruct fp;19scpcomb *comb;20bachpol *bach;21flagstruct flags;22int *CI, I, *x;23{24int i, j, k, dim, okp, okm, sign, nr, fail, num;25int *vec, *scpvec, **xvec, **xbase, **Fxbase, DEP, len, rank, n;26int *Vvj, *FAiI, **Fvi, *xnum, xk, *comtri, *comcoi, xbij, vj;27scpcomb com;28int test;2930dim = F.dim;31DEP = flags.DEPTH;32len = F.n * DEP;3334if(normal_option == TRUE && I >0)35{36test = normal_aut_test(x, I-1, V);37if(test == FALSE)38return(0);39}40if (I-1 >= 0 && I-1 < flags.BACHDEP)41{42if (flags.BACH[2] == 0)43flags.BACHSCP = V.v[abs(x[I-1])][dim] / 2;44if (bachcomp(bach[I-1], x[I-1], flags.BACHSCP, V, FF.v[0]) == 0)45return(0);46}47if ((vec = (int*)malloc(dim * sizeof(int))) == 0)48exit (2);49if ((scpvec = (int*)malloc(len * sizeof(int))) == 0)50exit (2);51if (I-1 >= 0 && DEP > 0)52{53com = comb[I-1];54rank = com.rank;55n = com.list.n;56/* xvec is the list of vector sums which are computed with respect to the57partial basis in x */58if ((xvec = (int**)malloc((n+1) * sizeof(int*))) == 0)59exit (2);60for (i = 0; i <= n; ++i)61{62if ((xvec[i] = (int*)malloc(dim * sizeof(int))) == 0)63exit (2);64for (j = 0; j < dim; ++j)65xvec[i][j] = 0;66}67/* xbase should be a basis for the lattice generated by the vectors in xvec,68it is obtained via the transformation matrix comb[I-1].trans */69if ((xbase = (int**)malloc(rank * sizeof(int*))) == 0)70exit (2);71for (i = 0; i < rank; ++i)72{73if ((xbase[i] = (int*)malloc(dim * sizeof(int))) == 0)74exit (2);75}76/* Fxbase is the product of a form F with the base xbase */77if ((Fxbase = (int**)malloc(rank * sizeof(int*))) == 0)78exit (2);79for (i = 0; i < rank; ++i)80{81if ((Fxbase[i] = (int*)malloc(dim * sizeof(int))) == 0)82exit (2);83}84}85/* CI is the list for the candidates */86for (i = 0; i < fp.diag[I]; ++i)87CI[i] = 0;88nr = 0;89fail = 0;90for (j = 1; j <= V.n && fail == 0; ++j)91{92Vvj = V.v[j];93okp = 0;94okm = 0;95for (k = 0; k < len; ++k)96scpvec[k] = 0;97for (i = 0; i < F.n; ++i)98{99FAiI = F.A[i][fp.per[I]];100Fvi = FF.v[i];101/* vec is the vector of scalar products of V.v[j] with the first I base vectors102x[0]...x[I-1] with respect to the forms in FF */103for (k = 0; k < I; ++k)104{105if ((xk = x[k]) > 0)106vec[k] = sscp(Vvj, Fvi[xk], dim);107else108vec[k] = -sscp(Vvj, Fvi[-xk], dim);109}110for (k = 0; k < I && vec[k] == FAiI[fp.per[k]]; ++k);111if (k == I && Vvj[dim+i] == FAiI[fp.per[I]])112/* V.v[j] is a candidate for x[I] with respect to the form F.A[i] */113++okp;114for (k = 0; k < I && vec[k] == -FAiI[fp.per[k]]; ++k);115if (k == I && Vvj[dim+i] == FAiI[fp.per[I]])116/* -V.v[j] is a candidate for x[I] with respect to the form F.A[i] */117++okm;118if (I-1 >= 0 && DEP > 0)119{120for (k = I-1; k >= 0 && k > I-1-DEP; --k)121scpvec[i*DEP+I-1-k] = vec[k];122}123}124if (I-1 >= 0 && DEP > 0)125/* check, whether the scalar product combination scpvec is contained in the126list comb[I-1].list */127{128for (i = 0; i < len && scpvec[i] == 0; ++i);129if (i == len)130num = 0;131else132{133num = numberof(scpvec, com.list);134sign = num > 0 ? 1 : -1;135num *= sign;136}137if (num > n)138/* scpvec is not found, hence x[0]...x[I-1] is not a partial isometry */139fail = 1;140else if (num > 0)141/* scpvec is found and the vector is added to the corresponding vector sum */142{143xnum = xvec[num];144for (k = 0; k < dim; ++k)145xnum[k] += sign * Vvj[k];146}147}148if (okp == F.n)149/* V.v[j] is a candidate for x[I] */150{151if (nr < fp.diag[I])152{153CI[nr] = j;154++nr;155}156else157/* there are too many candidates */158fail = 1;159}160if (okm == F.n)161/* -V.v[j] is a candidate for x[I] */162{163if (nr < fp.diag[I])164{165CI[nr] = -j;166++nr;167}168else169/* there are too many candidates */170fail = 1;171}172}173if (fail == 1)174nr = 0;175if (nr == fp.diag[I] && I-1 >= 0 && DEP > 0)176/* compute the basis of the lattice generated by the vectors in xvec via the177transformation matrix comb[I-1].trans */178{179for (i = 0; i < rank; ++i)180{181comtri = com.trans[i];182for (j = 0; j < dim; ++j)183{184xbij = 0;185for (k = 0; k <= n; ++k)186xbij += comtri[k] * xvec[k][j];187xbase[i][j] = xbij;188}189}190}191if (nr == fp.diag[I] && I-1 >= 0 && DEP > 0)192/* check, whether the base xbase has the right scalar products */193{194for (i = 0; i < F.n && nr > 0; ++i)195{196for (j = 0; j < rank; ++j)197{198for (k = 0; k < dim; ++k)199Fxbase[j][k] = sscp(FF.A[i][k], xbase[j], dim);200}201for (j = 0; j < rank && nr > 0; ++j)202{203for (k = 0; k <= j && nr > 0; ++k)204{205if (sscp(xbase[j], Fxbase[k], dim) != com.F[i][j][k])206/* a scalar product is wrong */207nr = 0;208}209}210}211}212if (nr == fp.diag[I] && I-1 >= 0 && DEP > 0)213/* check, whether comb[I-1].coef * xbase = xvec */214{215for (i = 0; i <= n && nr > 0; ++i)216{217comcoi = com.coef[i];218for (j = 0; j < dim; ++j)219{220vj = 0;221for (k = 0; k < rank; ++k)222vj += comcoi[k] * xbase[k][j];223if (vj != xvec[i][j])224/* an entry is wrong */225nr = 0;226}227}228}229if (I-1 >= 0 && DEP > 0)230{231for (i = 0; i <= n; ++i)232free(xvec[i]);233free(xvec);234for (i = 0; i < rank; ++i)235{236free(xbase[i]);237free(Fxbase[i]);238}239free(xbase);240free(Fxbase);241}242free(scpvec);243free(vec);244return(nr);245}246247/*****************************************************\248| search for an isometry249\*****************************************************/250static matrix_TYP *bs_isometry(V, F, FF, fp, G, nG, comb, bach, flags)251veclist V;252invar F, FF;253fpstruct fp;254int ***G, nG;255scpcomb *comb;256bachpol *bach;257flagstruct flags;258{259int i,j, dim, *x, **C, **X, found;260matrix_TYP *erg;261262dim = F.dim;263if ((C = (int**)malloc(dim * sizeof(int*))) == 0)264exit (2);265/* C[i] is the list of candidates for the image of the i-th base-vector */266for (i = 0; i < dim; ++i)267{268if ((C[i] = (int*)malloc(fp.diag[i] * sizeof(int))) == 0)269exit (2);270}271/* x is the new base, i.e. x[i] is the index in V.v of the i-th base-vector */272if ((x = (int*)malloc(dim * sizeof(int))) == 0)273exit (2);274/* compute the candidates for x[0] */275isocand(C[0], 0, x, V, F, FF, fp, comb, bach, flags);276found = 0;277/* go into the recursion */278found = iso(0, x, C, V, F, FF, fp, G, nG, comb, bach, flags);279/***********************************280for(i=0;i<nG;i++)281{282for(j=0;j<dim;j++)283free(G[i][j]);284free(G[i]);285}286*****************************/287if (found == 1)288{289if ((X = (int**)malloc(dim * sizeof(int*))) == 0)290exit (2);291for (i = 0; i < dim; ++i)292{293if ((X[i] = (int*)malloc(dim * sizeof(int))) == 0)294exit (2);295}296matgen(x, X, dim, fp.per, V.v);297/* print the isometry */298erg = putiso(X, flags, dim);299for (i = 0; i < dim; ++i)300free(X[i]);301free(X);302}303else304erg = NULL;305for (i = 0; i < dim; ++i)306free(C[i]);307free(C);308free(x);309return(erg);310}311312/**********************************************************\313| the heart of the program: the recursion314\**********************************************************/315static int iso(step, x, C, V, F, FF, fp, G, nG, comb, bach, flags)316veclist V;317invar F, FF;318fpstruct fp;319scpcomb *comb;320bachpol *bach;321flagstruct flags;322int step, *x, **C, ***G, nG;323{324FILE *outfile;325int i, j, dim, ***H, nH, *orb, orblen, found, Maxfail;326327dim = F.dim;328found = 0;329while (C[step][0] != 0 && found == 0)330{331if (step < dim-1)332{333/* choose the image of the base-vector nr. step */334x[step] = C[step][0];335/* check, whether x[0]...x[step] is a partial automorphism and compute the336candidates for x[step+1] */337if (isocand(C[step+1], step+1, x, V, F, FF, fp, comb, bach, flags) == fp.diag[step+1])338{339/* go deeper into the recursion */340Maxfail = 0;341/* determine the heuristic value of Maxfail for the break condition in342isostab */343for (i = 0; i <= step; ++i)344{345if (fp.diag[i] > 1)346Maxfail += 1;347}348for (i = step+1; i < dim; ++i)349{350if (fp.diag[i] > 1)351Maxfail += 2;352}353/* compute the stabilizer H of x[step] in G */354nH = isostab(&H, x[step], G, nG, V, Maxfail);355found = iso(step+1, x, C, V, F, FF, fp, H, nH, comb, bach, flags);356/* inserted 16/1/97 tilman */357free(H);358359}360if (found == 1)361{362for (i = 0; i < nG; ++i)363{364for (j = 0; j < dim; ++j)365free(G[i][j]);366free(G[i]);367}368return(found);369}370orblen = orbit(&(x[step]), 1, G, nG, V, &orb);371/* delete the orbit of the chosen vector from the list of candidates */372delete(C[step], fp.diag[step], orb, orblen);373free(orb);374if (step == 0 && flags.PRINT == 1)375/* if the -P option is given, print on top level the number of excluded376candidates on ISOM.tmp */377{378outfile = fopen("ISOM.tmp", "a");379fprintf(outfile, "excluded %d vectors on top level\n", orblen);380fclose(outfile);381}382}383else384{385/* an isomorphism is found */386if(normal_option == TRUE)387{388found = 0;389for(i=0;i<fp.diag[step] && C[step][0] != 0 && found == 0;i++)390{391x[step] = C[step][0];392found = normal_aut_test(x, step, V);393if(found == 0)394{395for(j=0;j<fp.diag[step]-1;j++)396C[step][j] = C[step][j+1];397C[step][fp.diag[step]-1] = 0;398}399}400}401else402{403x[dim-1] = C[dim-1][0];404found = 1;405}406}407}408for (i = 0; i < nG; ++i)409{410for (j = 0; j < dim; ++j)411free(G[i][j]);412free(G[i]);413}414415return(found);416}417418/*********************************************************************\419| computes the orbit of V.v[pt] under the generators420| G[0],...,G[nG-1] and elements stabilizing V.v[pt], which are421| stored in H, returns the number of generators in H422\*********************************************************************/423static int isostab(H, pt, G, nG, V, Maxfail)424int ****H, pt, ***G, nG, Maxfail;425veclist V;426{427int *orb, len, cnd, orblen, tmplen, rpt;428int ***w, *flag, **A, **B;429int i, j, k, dim, im, nH, fail;430431/* a heuristic break condition for the computation of stabilizer elements:432it would be too expensive to calculate all the stabilizer generators, which433are obtained from the orbit, since this is highly redundant,434on the other hand every new generator which enlarges the group reduces the435number of orbits and hence the number of candidates to be tested,436after Maxfail subsequent stabilizer elements, that do not enlarge the group,437the procedure stops,438increasing Maxfail will possibly decrease the number of tests,439but will increase the running time of the stabilizer computation440there is no magic behind the heuristic, tuning might be appropriate */441dim = V.dim;442/* H are the generators of the stabilizer of V.v[pt] */443if ((*H = (int***)malloc(1 * sizeof(int**))) == 0)444exit (2);445if (((*H)[0] = (int**)malloc(dim * sizeof(int*))) == 0)446exit (2);447for (i = 0; i < dim; ++i)448{449if (((*H)[0][i] = (int*)malloc(dim * sizeof(int))) == 0)450exit (2);451}452nH = 0;453/* w[i+V.n] is a matrix that maps V.v[pt] on V.v[i] */454if ((w = (int***)malloc((2*V.n+1) * sizeof(int**))) == 0)455exit (2);456/* orb contains the orbit of V.v[pt] */457if ((orb = (int*)malloc(2*V.n * sizeof(int))) == 0)458exit (2);459/* orblen is the length of the orbit of a random vector in V.v */460orblen = 1;461for (i = 0; i < 2*V.n; ++i)462orb[i] = 0;463/* if flag[i+V.n] = 1, then the point i is already in the orbit */464if ((flag = (int*)malloc((2*V.n+1) * sizeof(int))) == 0)465exit (2);466for (i = 0; i <= 2*V.n; ++i)467flag[i] = 0;468orb[0] = pt;469flag[orb[0]+V.n] = 1;470/* w[pt+V.n] is the Identity */471if ((w[orb[0]+V.n] = (int**)malloc(dim * sizeof(int*))) == 0)472exit (2);473for (i = 0; i < dim; ++i)474{475if ((w[orb[0]+V.n][i] = (int*)malloc(dim * sizeof(int))) == 0)476exit (2);477for (j = 0; j < dim; ++j)478w[orb[0]+V.n][i][j] = 0;479w[orb[0]+V.n][i][i] = 1;480}481/* A and B are matrices for temporary use */482if ((A = (int**)malloc(dim * sizeof(int*))) == 0)483exit (2);484for (i = 0; i < dim; ++i)485{486if ((A[i] = (int*)malloc(dim * sizeof(int))) == 0)487exit (2);488}489if ((B = (int**)malloc(dim * sizeof(int*))) == 0)490exit (2);491for (i = 0; i < dim; ++i)492{493if ((B[i] = (int*)malloc(dim * sizeof(int))) == 0)494exit (2);495}496cnd = 0;497len = 1;498/* fail is the number of successive failures */499fail = 0;500while (len > cnd && fail < Maxfail)501{502for (i = 0; i < nG && fail < Maxfail; ++i)503{504im = operate(orb[cnd], G[i], V);505if (flag[im+V.n] == 0)506/* a new element is found, appended to the orbit and an element mapping507V.v[pt] to im is stored in w[im+V.n] */508{509orb[len] = im;510flag[im+V.n] = 1;511if ((w[im+V.n] = (int**)malloc(dim * sizeof(int*))) == 0)512exit (2);513for (j = 0; j < dim; ++j)514{515if ((w[im+V.n][j] = (int*)malloc(dim * sizeof(int))) == 0)516exit (2);517}518matmul(w[orb[cnd]+V.n], G[i], dim, w[im+V.n]);519++len;520}521else522/* the image was already in the orbit */523{524matmul(w[orb[cnd]+V.n], G[i], dim, B);525/* check, whether the old and the new element mapping pt on im differ */526for (j = 0; j < dim && comp(B[j], w[im+V.n][j], dim) == 0; ++j);527if (j < dim)528{529/* w[im+V.n] is copied to A, since psolve changes the matrices */530for (j = 0; j < dim; ++j)531{532for (k = 0; k < dim; ++k)533A[j][k] = w[im+V.n][j][k];534}535/* new stabilizer element H[nH] = w[orb[cnd]+V.n] * G[i] * (w[im+V.n])^-1 */536psolve((*H)[nH], A, B, dim, V.prime);537rpt = rand() % V.n + 1;538tmplen = orbitlen(rpt, 2*V.n, *H, nH+1, V);539while (tmplen < orblen)540/* the orbit of this vector is shorter than a previous one, hence choose a new541random vector */542{543rpt = rand() % V.n + 1;544tmplen = orbitlen(rpt, 2*V.n, *H, nH+1, V);545}546if (tmplen > orblen)547/* the new stabilizer element H[nH] enlarges the group generated by H */548{549orblen = tmplen;550++nH;551/* allocate memory for the new generator */552if ((*H = (int***)realloc(*H, (nH+1) * sizeof(int**))) == 0)553exit (2);554if (((*H)[nH] = (int**)malloc(dim * sizeof(int*))) == 0)555exit (2);556for (k = 0; k < dim; ++k)557{558if (((*H)[nH][k] = (int*)malloc(dim * sizeof(int))) == 0)559exit (2);560}561fail = 0;562}563else564/* the new stabilizer element does not enlarge the orbit of a random vector */565++fail;566}567/* if H[nH] is the identity, nothing is done */568}569}570++cnd;571}572for (i = 0; i <= 2*V.n; ++i)573{574if (flag[i] == 1)575{576for (j = 0; j < dim; ++j)577free(w[i][j]);578free(w[i]);579}580}581free(w);582for (i = 0; i < dim; ++i)583{584free(A[i]);585free(B[i]);586free((*H)[nH][i]);587}588free(A);589free(B);590free((*H)[nH]);591free(orb);592free(flag);593594return(nH);595}596597598