GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it
/***** Main program for the automorphism program AUTO *****/12#include "typedef.h"3#include "types.h"4#include "sort.h"56/**************************************************************************\7@---------------------------------------------------------------------------8@---------------------------------------------------------------------------9@ FILE: autgrp.c10@---------------------------------------------------------------------------11@---------------------------------------------------------------------------12@13\**************************************************************************/1415static int normal_option;16static int perp_no;17static int ***perp;18static int perpdim;19static int ***perpbase;20static int ***perpprod;21static int *perpvec;2223#include "auttools.c"24#include "bachtools.c"25#include "iotools.c"26#include "lattools.c"27#include "mattools.c"28#include "orbtools.c"29#include "preproc.c"30#include "sorttools.c"31#include "perfecttools.c"3233/*************************************************************************\34@-------------------------------------------------------------------------35@ bravais_TYP *autgrp(Fo, Foanz, SV, Erz, Erzanz, options)36@ matrix_TYP **Fo, **Erz, *SV;37@ int Foanz, Erzanz, *options;38@39@ The functions 'autgrp' calculates generators and the order of the group40@ G := {g in GL_n(Z) | g^{tr} * Fo[i] * g = Fo[i], 1<= i<= Foanz}41@ returned via a pointer to 'bravais_TYP'.42@43@ The arguments of autgrp are:44@ matrix_TYP **Fo: a set of n times n matrices,45@ the first must be positiv definite46@ int Foanz: the number of the matrices given in 'Fo'.47@ matrix_TYP **Erz: if already element of G are known,48@ they can be used for calculating generators49@ for the whole group.50@ The matrices of known elements can be given51@ to the function by the pointer 'Erz'.52@ int Erzanz: The number of matrices given in 'Erz"53@ matrix_TYP *SV: The rows of the matrix 'SV' must be the vectors54@ x in Z^n with x * F[0] * x^{tr} <= m, where55@ m is the maximal diagonal entry of the Matrix56@ F[0]57@ int *options: see below.58@59@ options is a pointer to integer (of length 6)60@ The possible options are encoded in the following way:61@ options[0]: The depth, up to wich scalar product combinations62@ shall be calculated. The value should be small.63@ options[0] > 0 should be used only, if the automorphismn64@ group is expected to be small (with respect to the number65@ of shortest vectors).66@ options[1]: The n-point stabiliser with respect to different basis67@ will be calculated.68@ options[2]: If options[2] = 1, additional output is written to the69@ file AUTO.tmp70@ options[3]: If options[3] = 1, Bacher polynomials are used.71@ If options[3] = 2, Bacher polynomial are used up to a deepth72@ specified in options[4].73@ If options[3] = 3, Bacher polynomials are used, using74@ combinations of vectors having the scalar75@ product specified in options[5]76@ options[3] = 4 is the combination of options[3] = 2 and77@ options[3] = 3.78@ options[4]: A natural number number or zero (if options[3] = 2 or 4)79@ options[5]: An integral number (if options[3] = 3 or 4)80@81@ It is possible to use NULL for options,82@ in this case option is assumed to be [0,0,0,0,0,0]83@-------------------------------------------------------------------------84\*************************************************************************/858687bravais_TYP *autgrp(Fo, Foanz, SV, Erz, Erzanz, options)88matrix_TYP **Fo, **Erz, *SV;89int Foanz, Erzanz, *options;90{91FILE *outfile;92bachpol *bach;93flagstruct flags;94scpcomb *comb;95group G;96invar F;97veclist V, norm;98fpstruct fp;99int dim, max, fail, *vec;100int ***H, nH, ngen, **sumveclist, **sumvecbase;101int i, j, k, l, n, *Vvi, *Vvj, **Fvi, *Fvij, **FAi;102bravais_TYP *B;103104normal_option = FALSE;105/* get the flags from the command line */106getflags(&flags, options);107if(Erzanz > 0)108flags.GEN = 1;109else110flags.GEN = 0;111/* F.n is the number of invariant forms */112F.n = Foanz;113if ((F.A = (int***)malloc(F.n * sizeof(int**))) == 0)114exit (2);115/* read the invariant forms */116F.dim = Fo[0]->cols;117dim = F.dim;118for(i=0;i<F.n;i++)119{120if(Fo[i]->cols != F.dim || Fo[i]->rows != F.dim)121{122printf("forms in autgrp have different dimension\n");123exit(3);124}125}126for(i=0;i<F.n;i++)127{128if ((F.A[i] = (int**)malloc(dim * sizeof(int*))) == 0)129exit (2);130for(j=0;j<F.dim;j++)131{132if ((F.A[i][j] = (int*)malloc(dim * sizeof(int))) == 0)133exit (2);134for(k=0;k<F.dim;k++)135F.A[i][j][k] = Fo[i]->array.SZ[j][k];136}137}138if (flags.GEN == 1)139/* some automorphisms are already known */140{141ngen = Erzanz;142if ((H = (int***)malloc(ngen * sizeof(int**))) == 0)143exit (2);144nH = 0;145fail = 0;146for(i=0;i<ngen;i++)147{148if(Erz[i]->cols != dim || Erz[i]->rows != dim)149{150printf("Elements 'Erz' have wrong dimension\n");151exit(3);152}153}154i = 0;155while (nH+fail < ngen)156{157if ((H[nH] = (int**)malloc(dim * sizeof(int*))) == 0)158exit (2);159for(j=0;j<dim;j++)160{161if ((H[nH][j] = (int*)malloc(dim * sizeof(int))) == 0)162exit (2);163for(k=0;k<dim;k++)164H[nH][j][k] = Erz[i]->array.SZ[k][j];165}166/* check whether the matrix is really an automorphism, i.e. fixes the forms */167if (checkgen(H[nH], F) == 0)168/* the matrix is not an automorphism */169{170++fail;171for (j = 0; j < dim; ++j)172free(H[nH][j]);173free(H[nH]);174}175else176/* the matrix fixes all forms in F */177++nH;178i++;179}180}181else182nH = 0;183184185186V.dim = dim;187V.len = dim + F.n;188/* get the short vectors */189V.n = SV->rows;190if ((V.v = (int**)malloc((V.n+1) * sizeof(int*))) == 0)191exit (2);192for(i=0;i<=V.n;i++)193{194if ((V.v[i] = (int*)malloc(V.len * sizeof(int))) == 0)195exit (2);196}197for(i=1;i<= V.n;i++)198{199for(j=0;j<=dim;j++)200V.v[i][j] = SV->array.SZ[i-1][j];201}202/* the first nonzero entry of each vector is made positive and the maximal203entry of the vectors is determined */204max = 1;205for (i = 1; i <= V.n; ++i)206{207Vvi = V.v[i];208for (j = 0; j < dim && Vvi[j] == 0; ++j);209if (j < dim && Vvi[j] < 0)210{211for (k = j; k < dim; ++k)212Vvi[k] *= -1;213}214for (k = j; k < dim; ++k)215{216if (abs(Vvi[k]) > max)217max = abs(Vvi[k]);218}219}220if (max > MAXENTRY)221/* there is an entry, which is bigger than MAXENTRY, which might cause overflow,222since the program doesn't use long integer arithmetic */223{224fprintf(stderr, "Error: Found entry %d in short vectors.\nTo avoid overflow, the entries should not exceed %d.\n", max, MAXENTRY);225exit (3);226}227/* V.prime is a prime p, such that every entry x in the short vectors remains228unchanged under reduction mod p in symmetric form, i.e. -p/2 < x <= p/2 */229for (V.prime = 2*max + 1; isprime(V.prime) == 0; ++V.prime);230/* sort the vectors and delete doublets */231sortvecs(&V);232/* the norm-vector (i.e. the vector of the norms with respect to the different233invariant forms) of each vector must be equal to the norm-vector of one234of the vectors from the standard-base */235if ((norm.v = (int**)malloc((dim+1) * sizeof(int*))) == 0)236exit (2);237norm.n = dim;238norm.dim = F.n;239norm.len = F.n;240for (i = 1; i <= norm.n; ++i)241{242/* norm.v[i] is the norm combination of the (i-1)-th base-vector */243if ((norm.v[i] = (int*)malloc(norm.dim * sizeof(int))) == 0)244exit (2);245for (k = 0; k < norm.dim; ++k)246norm.v[i][k] = F.A[k][i-1][i-1];247}248sortvecs(&norm);249/* delete those vectors, which can not be the image of any of the standard-base250vectors */251checkvecs(&V, F, norm);252for (i = 1; i <= norm.n; ++i)253free(norm.v[i]);254free(norm.v);255/* print the invariant forms, if output is in ASCII-format */256/*********************************************257printf("#%d\n", F.n);258for (i = 0; i < F.n; ++i)259putform(F.A[i], dim);260**********************************************/261/* F.v[i][j] is the transposed of the product of the Gram-matrix F.A[i] with the262transposed of the vector v[j], hence the scalar product of v[j] and v[k] with263respect to the Gram-matrix F.A[i] can be computed as standard scalar product264of v[j] and F.v[i][k] */265if ((F.v = (int***)malloc(F.n * sizeof(int**))) == 0)266exit (2);267/* the product of the maximal entry in the short vectors with the maximal entry268in F.v[i] should not exceed MAXNORM to avoid overflow */269max = MAXNORM / max;270for (i = 0; i < F.n; ++i)271{272FAi = F.A[i];273if ((F.v[i] = (int**)malloc((V.n+1) * sizeof(int*))) == 0)274exit (2);275Fvi = F.v[i];276for (j = 1; j <= V.n; ++j)277{278Vvj = V.v[j];279if ((Fvi[j] = (int*)malloc(dim * sizeof(int))) == 0)280exit (2);281Fvij = Fvi[j];282for (k = 0; k < dim; ++k)283{284Fvij[k] = sscp(FAi[k], Vvj, dim);285if (abs(Fvij[k]) > max)286/* some entry in F.v[i] is too large */287{288fprintf(stderr, "Error: Found entry %d in F.v.\nTo avoid overflow, the entries should not exceed %d.\n", Fvij[k], max);289exit (3);290}291}292}293}294/* fp.per is the order in which the images of the base-vectors are set */295if ((fp.per = (int*)malloc(dim * sizeof(int))) == 0)296exit (2);297/* fp.e[i] is the index in V.v of the i-th vector of the standard-base in the298new order */299if ((fp.e = (int*)malloc(dim * sizeof(int))) == 0)300exit (2);301/* fp.diag is the diagonal of the fingerprint in the new order, fp.diag[i] is302an upper bound for the length of the orbit of the i-th base-vector under303the stabilizer of the preceding ones */304if ((fp.diag = (int*)malloc(dim * sizeof(int))) == 0)305exit (2);306/* compute the fingerprint */307fingerprint(&fp, F, V);308if (flags.PRINT == 1)309/* if the -P option is given, print the diagonal fp.diag and the number of short310vectors on AUTO.tmp */311{312outfile = fopen("AUTO.tmp", "a");313fprintf(outfile, "%d short vectors\n", 2*V.n);314fprintf(outfile, "fingerprint diagonal:\n");315for (i = 0; i < dim; ++i)316fprintf(outfile, " %2d", fp.diag[i]);317fprintf(outfile, "\n");318fclose(outfile);319}320/* get the standard basis in the new order */321if ((vec = (int*)malloc(dim * sizeof(int))) == 0)322exit (2);323for (i = 0; i < dim; ++i)324{325for (j = 0; j < dim; ++j)326vec[j] = 0;327vec[fp.per[i]] = 1;328fp.e[i] = numberof(vec, V);329if (abs(fp.e[i]) > V.n)330/* the standard-base must occur in the set of short vectors, since Id is331certainly an automorphism */332{333fprintf(stderr, "Error: standard basis vector nr. %d not found\n", i);334exit (2);335}336}337free(vec);338/* if the -D option is given, the scalar product combinations and the339corresponding vector sums are computed for the standard-basis */340if (flags.DEPTH > 0)341{342if ((comb = (scpcomb*)malloc(dim * sizeof(scpcomb))) == 0)343exit (2);344for (i = 0; i < dim; ++i)345{346/* compute the list of scalar product combinations and the corresponding347vector sums */348scpvecs(&comb[i].list, &sumveclist, i, fp.e, flags.DEPTH, V, F);349/* compute a basis for the lattice that is generated by the vector sums and350a transformation matrix that expresses the basis in terms of the351vector sums */352base(&comb[i], &sumvecbase, sumveclist, F.A[0], dim);353if (flags.PRINT == 1)354/* if the -P option is given, print the rank of the lattice generated by the355vector sums on level i on AUTO.tmp */356{357outfile = fopen("AUTO.tmp", "a");358fprintf(outfile, "comb[%d].rank = %d\n", i, comb[i].rank);359fclose(outfile);360}361/* compute the coefficients of the vector sums in terms of the basis */362coef(&comb[i], sumvecbase, sumveclist, F.A[0], dim);363for (j = 0; j <= comb[i].list.n; ++j)364free(sumveclist[j]);365free(sumveclist);366/* compute the scalar products of the base-vectors */367scpforms(&comb[i], sumvecbase, F);368for (j = 0; j < comb[i].rank; ++j)369free(sumvecbase[j]);370free(sumvecbase);371}372}373/* the Bacher-polynomials for the first BACHDEP base-vectors are computed,374if no scalar product was given as an argument, the scalar product is set375to 1/2 the norm of the base-vector (with respect to the first form) */376if (flags.BACH[0] == 1)377{378if ((bach = (bachpol*)malloc(flags.BACHDEP * sizeof(bachpol))) == 0)379exit (2);380for (i = 0; i < flags.BACHDEP; ++i)381{382if (flags.BACH[2] == 0)383/* no scalar product was given as an option */384flags.BACHSCP = V.v[fp.e[i]][dim] / 2;385/* compute the Bacher-polynomial */386bacher(&bach[i], fp.e[i], flags.BACHSCP, V, F.v[0]);387if (flags.PRINT == 1)388/* if the -P option is given, print the Bacher-polynomial on AUTO.tmp */389{390outfile = fopen("AUTO.tmp", "a");391fprintf(outfile, "Bacher-polynomial of base vector fp.e[%d]:\n", i);392fputbach(outfile, bach[i]);393fclose(outfile);394}395}396}397/* set up the group: the generators in G.g[i] are matrices that fix the398first i base-vectors but do not fix fp.e[i] */399if ((G.g = (int****)malloc(dim * sizeof(int***))) == 0)400exit (2);401/* G.ng is the number of generators in G.g[i] */402if ((G.ng = (int*)malloc(dim * sizeof(int))) == 0)403exit (2);404/* the first G.nsg[i] generators in G.g[i] are obtained as stabilizer elements405and are not necessary to generate the group */406if ((G.nsg = (int*)malloc(dim * sizeof(int))) == 0)407exit (2);408/* G.ord[i] is the orbit length of fp.e[i] under the generators in409G.g[i] ... G.g[dim-1] */410if ((G.ord = (int*)malloc(dim * sizeof(int))) == 0)411exit (2);412for (i = 0; i < dim; ++i)413{414if ((G.g[i] = (int***)malloc(1 * sizeof(int**))) == 0)415exit (2);416G.ng[i] = 0;417G.nsg[i] = 0;418}419G.dim = dim;420if ((G.g[0][0] = (int**)malloc(dim * sizeof(int*))) == 0)421exit (2);422/* -Id is always an automorphism */423for (i = 0; i < dim; ++i)424{425if ((G.g[0][0][i] = (int*)malloc(dim * sizeof(int))) == 0)426exit (2);427for (j = 0; j < dim; ++j)428G.g[0][0][i][j] = 0;429G.g[0][0][i][i] = -1;430G.ng[0] = 1;431}432/* fill in the generators which were given as input */433for (i = 0; i < nH; ++i)434{435for (j = 0; j < dim && operate(fp.e[j], H[i], V) == fp.e[j]; ++j);436if (j < dim)437/* the generator is not Id and fixes fp.e[0],...,fp.e[j-1] but not fp.e[j] */438{439++G.ng[j];440if ((G.g[j] = (int***)realloc(G.g[j], G.ng[j] * sizeof(int**))) == 0)441exit (2);442if ((G.g[j][G.ng[j]-1] = (int**)malloc(dim * sizeof(int*))) == 0)443exit (2);444for (k = 0; k < dim; ++k)445{446if ((G.g[j][G.ng[j]-1][k] = (int*)malloc(dim * sizeof(int))) == 0)447exit (2);448for (l = 0; l < dim; ++l)449G.g[j][G.ng[j]-1][k][l] = H[i][k][l];450}451}452for (k = 0; k < dim; ++k)453free(H[i][k]);454free(H[i]);455}456if (nH > 0)457free(H);458nH = 0;459for (i = 0; i < dim; ++i)460nH += G.ng[i];461if ((H = (int***)malloc(nH * sizeof(int**))) == 0)462exit (2);463/* calculate the orbit lengths under the automorphisms known so far */464for (i = 0; i < dim; ++i)465{466if (G.ng[i] > 0)467{468nH = 0;469for (j = i; j < dim; ++j)470{471for (k = 0; k < G.ng[j]; ++k)472{473H[nH] = G.g[j][k];474++nH;475}476}477G.ord[i] = orbitlen(fp.e[i], fp.diag[i], H, nH, V);478}479else480G.ord[i] = 1;481}482free(H);483/* compute the full automorphism group */484autom(&G, V, F, fp, comb, bach, flags);485/* print the generators of the group, which are necessary for generating */486B = putgens(G, flags);487n = 0;488for (i = flags.STAB; i < dim; ++i)489{490if (G.ord[i] > 1)491++n;492}493/* print a base to AUTO.tmp if the print-flag is set */494if (flags.PRINT == 1)495{496outfile = fopen("AUTO.tmp", "a");497fprintf(outfile, "%dx%d\n", n, dim);498for (i = flags.STAB; i < dim; ++i)499{500if (G.ord[i] > 1)501{502for (j = 0; j < dim; ++j)503fprintf(outfile, " %d", V.v[fp.e[i]][j]);504fprintf(outfile, "\n");505}506}507fclose(outfile);508}509/* print the order of the group */510putord(G, flags, B);511512513if (flags.BACH[0] == 1)514{515for (i = 0; i < flags.BACHDEP; ++i)516free(bach[i].coef);517free(bach);518}519if (flags.DEPTH > 0)520{521for(i=0;i<dim;i++)522{523for(j=0;j<=comb[i].list.n;j++)524free(comb[i].coef[j]);525free(comb[i].coef);526for(j=0;j<=comb[i].list.n;j++)527free(comb[i].list.v[j]);528free(comb[i].list.v);529for(j=0;j<comb[i].rank;j++)530free(comb[i].trans[j]);531free(comb[i].trans);532for(j=0;j<F.n;j++)533{534for(k=0;k<comb[i].rank;k++)535free(comb[i].F[j][k]);536free(comb[i].F[j]);537}538free(comb[i].F);539}540free(comb);541}542for(i=0;i<F.n;i++)543{544for(j=1;j<=V.n;j++)545free(F.v[i][j]);546free(F.v[i]);547for(j=0;j<dim;j++)548free(F.A[i][j]);549free(F.A[i]);550}551free(F.A); free(F.v);552for(i=0;i<=V.n;i++)553free(V.v[i]);554free(V.v);555free(fp.diag); free(fp.per); free(fp.e);556for(i=0;i<dim;i++)557{558for(j=0;j<G.ng[i];j++)559{560for(k=0;k<dim;k++)561free(G.g[i][j][k]);562free(G.g[i][j]);563}564free(G.g[i]);565}566free(G.g); free(G.ord); free(G.ng); free(G.nsg);567568return(B);569}570571572/**************************************************************************\573@---------------------------------------------------------------------------574@ bravais_TYP *perfect_normal_autgrp(Fo, SV, Erz, Erzanz, options,575@ P, Panz, Pbase, Pdim)576@ matrix_TYP *Fo, **Erz, *SV, **P, **Pbase;577@ int Erzanz, *options, Panz, Pdim;578@579@ The function 'perfect_normal_autgrp' calculates generators for580@ G = {g in GL_n(Z)| g^{tr} * Fo * g = Fo and581@ g^{tr} Pbase[i] g is a matrix in P for 0<=i<Pdim}582@583@ The arguments are:584@ Fo: a symmetric positive definite n by n-matrix.585@ SV: the vectors x in GL_n(Z) (up to sign) with x Fo x^{tr} < k,586@ where k is the maximal diagonal entry of 'Fo'.587@ Erz: matrices of elements of G (if known).588@ Erzanz: the number of matrices in 'Erz'.589@ options: the same as for the function 'autgrp'.590@ P: a set of matrices591@ Panz: the number of matrices given in 'P'.592@ Pbase: a set of matrices593@ Pdim: the number of matrices given in 'Pbase'.594@595@ This function is designed to calculate the stabilizer of a perfect596@ form 'Fo' in the normalizer of the group generated by the matrices597@ given in 'Erz'.598@ Then 'P' is the set of matrices given by the Voronoi-directions of 'Fo'599@ and 'Pbase' a maximal linearly independent subset of 'P'.600@601@---------------------------------------------------------------------------602@603\**************************************************************************/604605606bravais_TYP *perfect_normal_autgrp(Fo, SV, Erz, Erzanz, options, P, Panz, Pbase, Pdim)607matrix_TYP *Fo, **Erz, *SV, **P, **Pbase;608int Erzanz, *options, Panz, Pdim;609{610FILE *outfile;611bachpol *bach;612flagstruct flags;613scpcomb *comb;614group G;615invar F;616veclist V, norm;617fpstruct fp;618int dim, max, fail, *vec;619int ***H, nH, ngen, **sumveclist, **sumvecbase;620int i, j, k, l, n, *Vvi, *Vvj, **Fvi, *Fvij, **FAi;621bravais_TYP *B;622623extern matrix_TYP *init_mat();624extern int pointer_lower_triangular_mat_comp();625626normal_option = TRUE;627perp_no = Panz;628perpdim = Pdim;629/* get the flags from the command line */630getflags(&flags, options);631if(Erzanz > 0)632flags.GEN = 1;633else634flags.GEN = 0;635/* F.n is the number of invariant forms */636F.n = 1;637if ((F.A = (int***)malloc(1 *sizeof(int**))) == 0)638exit (2);639/* read the invariant forms */640F.dim = Fo->cols;641dim = F.dim;642if(Fo->cols != F.dim || Fo->rows != F.dim)643{644printf("error form 'Fo' in autgrp must be a square matrix\n");645exit(3);646}647if ((F.A[0] = (int**)malloc(dim * sizeof(int*))) == 0)648exit (2);649for(j=0;j<F.dim;j++)650{651if ((F.A[0][j] = (int*)malloc(dim * sizeof(int))) == 0)652exit (2);653for(k=0;k<F.dim;k++)654F.A[0][j][k] = Fo->array.SZ[j][k];655}656if (flags.GEN == 1)657/* some automorphisms are already known */658{659ngen = Erzanz;660if ((H = (int***)malloc(ngen * sizeof(int**))) == 0)661exit (2);662nH = 0;663fail = 0;664for(i=0;i<ngen;i++)665{666if(Erz[i]->cols != dim || Erz[i]->rows != dim)667{668printf("Elements 'Erz' have wrong dimension\n");669exit(2);670}671}672i = 0;673while (nH+fail < ngen)674{675if ((H[nH] = (int**)malloc(dim * sizeof(int*))) == 0)676exit (2);677for(j=0;j<dim;j++)678{679if ((H[nH][j] = (int*)malloc(dim * sizeof(int))) == 0)680exit (2);681for(k=0;k<dim;k++)682H[nH][j][k] = Erz[i]->array.SZ[k][j];683}684/* check whether the matrix is really an automorphism, i.e. fixes the forms */685if (checkgen(H[nH], F) == 0)686/* the matrix is not an automorphism */687{688++fail;689for (j = 0; j < dim; ++j)690free(H[nH][j]);691free(H[nH]);692}693else694/* the matrix fixes all forms in F */695++nH;696i++;697}698}699else700nH = 0;701702703704V.dim = dim;705V.len = dim + F.n;706/* get the short vectors */707V.n = SV->rows;708if ((V.v = (int**)malloc((V.n+1) * sizeof(int*))) == 0)709exit (2);710if ((V.v[0] = (int*)malloc(V.len * sizeof(int))) == 0)711exit (2);712/* tilman 9/1/97 changed these lines713for(i=1;i<= V.n;i++)714{715V.v[i] = SV->array.SZ[i-1];716} to (next 5 lines): */717for(i=1;i<= V.n;i++)718{719V.v[i] = (int *) malloc((SV->rows+1) * sizeof(int));720for (j=0;j<SV->cols;j++){721V.v[i][j] = SV->array.SZ[i-1][j];722}723}724725/* the first nonzero entry of each vector is made positive and the maximal726entry of the vectors is determined */727max = 1;728for (i = 1; i <= V.n; ++i)729{730Vvi = V.v[i];731for (j = 0; j < dim && Vvi[j] == 0; ++j);732if (j < dim && Vvi[j] < 0)733{734for (k = j; k < dim; ++k)735Vvi[k] *= -1;736}737for (k = j; k < dim; ++k)738{739if (abs(Vvi[k]) > max)740max = abs(Vvi[k]);741}742}743if (max > MAXENTRY)744/* there is an entry, which is bigger than MAXENTRY, which might cause overflow,745since the program doesn't use long integer arithmetic */746{747fprintf(stderr, "Error: Found entry %d in short vectors.\nTo avoid overflow, the entries should not exceed %d.\n", max, MAXENTRY);748exit (3);749}750/* V.prime is a prime p, such that every entry x in the short vectors remains751unchanged under reduction mod p in symmetric form, i.e. -p/2 < x <= p/2 */752for (V.prime = 2*max + 1; isprime(V.prime) == 0; ++V.prime);753/* sort the vectors and delete doublets */754sortvecs(&V);755/* the norm-vector (i.e. the vector of the norms with respect to the different756invariant forms) of each vector must be equal to the norm-vector of one757of the vectors from the standard-base */758if ((norm.v = (int**)malloc((dim+1) * sizeof(int*))) == 0)759exit (2);760norm.n = dim;761norm.dim = F.n;762norm.len = F.n;763for (i = 1; i <= norm.n; ++i)764{765/* norm.v[i] is the norm combination of the (i-1)-th base-vector */766if ((norm.v[i] = (int*)malloc(norm.dim * sizeof(int))) == 0)767exit (2);768for (k = 0; k < norm.dim; ++k)769norm.v[i][k] = F.A[k][i-1][i-1];770}771sortvecs(&norm);772/* delete those vectors, which can not be the image of any of the standard-base773vectors */774checkvecs(&V, F, norm);775for (i = 1; i <= norm.n; ++i)776free(norm.v[i]);777free(norm.v);778/* print the invariant forms, if output is in ASCII-format */779/*********************************************780printf("#%d\n", F.n);781for (i = 0; i < F.n; ++i)782putform(F.A[i], dim);783**********************************************/784/* F.v[i][j] is the transposed of the product of the Gram-matrix F.A[i] with the785transposed of the vector v[j], hence the scalar product of v[j] and v[k] with786respect to the Gram-matrix F.A[i] can be computed as standard scalar product787of v[j] and F.v[i][k] */788if ((F.v = (int***)malloc(F.n * sizeof(int**))) == 0)789exit (2);790/* the product of the maximal entry in the short vectors with the maximal entry791in F.v[i] should not exceed MAXNORM to avoid overflow */792max = MAXNORM / max;793for (i = 0; i < F.n; ++i)794{795FAi = F.A[i];796if ((F.v[i] = (int**)malloc((V.n+1) * sizeof(int*))) == 0)797exit (2);798Fvi = F.v[i];799for (j = 1; j <= V.n; ++j)800{801Vvj = V.v[j];802if ((Fvi[j] = (int*)malloc(dim * sizeof(int))) == 0)803exit (2);804Fvij = Fvi[j];805for (k = 0; k < dim; ++k)806{807Fvij[k] = sscp(FAi[k], Vvj, dim);808if (abs(Fvij[k]) > max)809/* some entry in F.v[i] is too large */810{811fprintf(stderr, "Error: Found entry %d in F.v.\nTo avoid overflow, the entries should not exceed %d.\n", Fvij[k], max);812exit (3);813}814}815}816}817/* fp.per is the order in which the images of the base-vectors are set */818if ((fp.per = (int*)malloc(dim * sizeof(int))) == 0)819exit (2);820/* fp.e[i] is the index in V.v of the i-th vector of the standard-base in the821new order */822if ((fp.e = (int*)malloc(dim * sizeof(int))) == 0)823exit (2);824/* fp.diag is the diagonal of the fingerprint in the new order, fp.diag[i] is825an upper bound for the length of the orbit of the i-th base-vector under826the stabilizer of the preceding ones */827if ((fp.diag = (int*)malloc(dim * sizeof(int))) == 0)828exit (2);829/* compute the fingerprint */830fingerprint(&fp, F, V);831mach_perp_matrices(fp, P, Pbase, dim);832pointer_mat_quicksort(perp, 0, perp_no-1, dim, dim, pointer_lower_triangular_mat_comp);833if (flags.PRINT == 1)834/* if the -P option is given, print the diagonal fp.diag and the number of short835vectors on AUTO.tmp */836{837outfile = fopen("AUTO.tmp", "a");838fprintf(outfile, "%d short vectors\n", 2*V.n);839fprintf(outfile, "fingerprint diagonal:\n");840for (i = 0; i < dim; ++i)841fprintf(outfile, " %2d", fp.diag[i]);842fprintf(outfile, "\n");843fclose(outfile);844}845/* get the standard basis in the new order */846if ((vec = (int*)malloc(dim * sizeof(int))) == 0)847exit (2);848for (i = 0; i < dim; ++i)849{850for (j = 0; j < dim; ++j)851vec[j] = 0;852vec[fp.per[i]] = 1;853fp.e[i] = numberof(vec, V);854if (abs(fp.e[i]) > V.n)855/* the standard-base must occur in the set of short vectors, since Id is856certainly an automorphism */857{858fprintf(stderr, "Error: standard basis vector nr. %d not found\n", i);859exit (3);860}861}862free(vec);863/* if the -D option is given, the scalar product combinations and the864corresponding vector sums are computed for the standard-basis */865if (flags.DEPTH > 0)866{867if ((comb = (scpcomb*)malloc(dim * sizeof(scpcomb))) == 0)868exit (3);869for (i = 0; i < dim; ++i)870{871/* compute the list of scalar product combinations and the corresponding872vector sums */873scpvecs(&comb[i].list, &sumveclist, i, fp.e, flags.DEPTH, V, F);874/* compute a basis for the lattice that is generated by the vector sums and875a transformation matrix that expresses the basis in terms of the876vector sums */877base(&comb[i], &sumvecbase, sumveclist, F.A[0], dim);878if (flags.PRINT == 1)879/* if the -P option is given, print the rank of the lattice generated by the880vector sums on level i on AUTO.tmp */881{882outfile = fopen("AUTO.tmp", "a");883fprintf(outfile, "comb[%d].rank = %d\n", i, comb[i].rank);884fclose(outfile);885}886/* compute the coefficients of the vector sums in terms of the basis */887coef(&comb[i], sumvecbase, sumveclist, F.A[0], dim);888for (j = 0; j <= comb[i].list.n; ++j)889free(sumveclist[j]);890free(sumveclist);891/* compute the scalar products of the base-vectors */892scpforms(&comb[i], sumvecbase, F);893for (j = 0; j < comb[i].rank; ++j)894free(sumvecbase[j]);895free(sumvecbase);896}897}898/* the Bacher-polynomials for the first BACHDEP base-vectors are computed,899if no scalar product was given as an argument, the scalar product is set900to 1/2 the norm of the base-vector (with respect to the first form) */901if (flags.BACH[0] == 1)902{903if ((bach = (bachpol*)malloc(flags.BACHDEP * sizeof(bachpol))) == 0)904exit (2);905for (i = 0; i < flags.BACHDEP; ++i)906{907if (flags.BACH[2] == 0)908/* no scalar product was given as an option */909flags.BACHSCP = V.v[fp.e[i]][dim] / 2;910/* compute the Bacher-polynomial */911bacher(&bach[i], fp.e[i], flags.BACHSCP, V, F.v[0]);912if (flags.PRINT == 1)913/* if the -P option is given, print the Bacher-polynomial on AUTO.tmp */914{915outfile = fopen("AUTO.tmp", "a");916fprintf(outfile, "Bacher-polynomial of base vector fp.e[%d]:\n", i);917fputbach(outfile, bach[i]);918fclose(outfile);919}920}921}922/* set up the group: the generators in G.g[i] are matrices that fix the923first i base-vectors but do not fix fp.e[i] */924if ((G.g = (int****)malloc(dim * sizeof(int***))) == 0)925exit (2);926/* G.ng is the number of generators in G.g[i] */927if ((G.ng = (int*)malloc(dim * sizeof(int))) == 0)928exit (2);929/* the first G.nsg[i] generators in G.g[i] are obtained as stabilizer elements930and are not necessary to generate the group */931if ((G.nsg = (int*)malloc(dim * sizeof(int))) == 0)932exit (2);933/* G.ord[i] is the orbit length of fp.e[i] under the generators in934G.g[i] ... G.g[dim-1] */935if ((G.ord = (int*)malloc(dim * sizeof(int))) == 0)936exit (2);937for (i = 0; i < dim; ++i)938{939if ((G.g[i] = (int***)malloc(1 * sizeof(int**))) == 0)940exit (2);941G.ng[i] = 0;942G.nsg[i] = 0;943}944G.dim = dim;945if ((G.g[0][0] = (int**)malloc(dim * sizeof(int*))) == 0)946exit (2);947/* -Id is always an automorphism */948for (i = 0; i < dim; ++i)949{950if ((G.g[0][0][i] = (int*)malloc(dim * sizeof(int))) == 0)951exit (2);952for (j = 0; j < dim; ++j)953G.g[0][0][i][j] = 0;954G.g[0][0][i][i] = -1;955G.ng[0] = 1;956}957/* fill in the generators which were given as input */958for (i = 0; i < nH; ++i)959{960for (j = 0; j < dim && operate(fp.e[j], H[i], V) == fp.e[j]; ++j);961if (j < dim)962/* the generator is not Id and fixes fp.e[0],...,fp.e[j-1] but not fp.e[j] */963{964++G.ng[j];965if ((G.g[j] = (int***)realloc(G.g[j], G.ng[j] * sizeof(int**))) == 0)966exit (2);967if ((G.g[j][G.ng[j]-1] = (int**)malloc(dim * sizeof(int*))) == 0)968exit (2);969for (k = 0; k < dim; ++k)970{971if ((G.g[j][G.ng[j]-1][k] = (int*)malloc(dim * sizeof(int))) == 0)972exit (2);973for (l = 0; l < dim; ++l)974G.g[j][G.ng[j]-1][k][l] = H[i][k][l];975}976}977for (k = 0; k < dim; ++k)978free(H[i][k]);979free(H[i]);980}981if (nH > 0)982free(H);983nH = 0;984for (i = 0; i < dim; ++i)985nH += G.ng[i];986if ((H = (int***)malloc(nH * sizeof(int**))) == 0)987exit (2);988/* calculate the orbit lengths under the automorphisms known so far */989for (i = 0; i < dim; ++i)990{991if (G.ng[i] > 0)992{993nH = 0;994for (j = i; j < dim; ++j)995{996for (k = 0; k < G.ng[j]; ++k)997{998H[nH] = G.g[j][k];999++nH;1000}1001}1002G.ord[i] = orbitlen(fp.e[i], fp.diag[i], H, nH, V);1003}1004else1005G.ord[i] = 1;1006}1007free(H);1008/* compute the full automorphism group */1009autom(&G, V, F, fp, comb, bach, flags);1010/* print the generators of the group, which are necessary for generating */1011B = putgens(G, flags);1012n = 0;1013for (i = flags.STAB; i < dim; ++i)1014{1015if (G.ord[i] > 1)1016++n;1017}1018/* print a base to AUTO.tmp if the print-flag is set */1019if (flags.PRINT == 1)1020{1021outfile = fopen("AUTO.tmp", "a");1022fprintf(outfile, "%dx%d\n", n, dim);1023for (i = flags.STAB; i < dim; ++i)1024{1025if (G.ord[i] > 1)1026{1027for (j = 0; j < dim; ++j)1028fprintf(outfile, " %d", V.v[fp.e[i]][j]);1029fprintf(outfile, "\n");1030}1031}1032fclose(outfile);1033}1034/* print the order of the group */1035putord(G, flags, B);103610371038if (flags.BACH[0] == 1)1039{1040for (i = 0; i < flags.BACHDEP; ++i)1041free(bach[i].coef);1042free(bach);1043}1044if (flags.DEPTH > 0)1045{1046for(i=0;i<dim;i++)1047{1048for(j=0;j<=comb[i].list.n;j++)1049free(comb[i].coef[j]);1050free(comb[i].coef);1051for(j=0;j<=comb[i].list.n;j++)1052free(comb[i].list.v[j]);1053free(comb[i].list.v);1054for(j=0;j<comb[i].rank;j++)1055free(comb[i].trans[j]);1056free(comb[i].trans);1057for(j=0;j<F.n;j++)1058{1059for(k=0;k<comb[i].rank;k++)1060free(comb[i].F[j][k]);1061free(comb[i].F[j]);1062}1063free(comb[i].F);1064}1065free(comb);1066}1067for(i=0;i<F.n;i++)1068{1069for(j=1;j<=V.n;j++)1070free(F.v[i][j]);1071free(F.v[i]);1072for(j=0;j<dim;j++)1073free(F.A[i][j]);1074free(F.A[i]);1075}1076free(F.A); free(F.v);10771078/* inserted the next 3 lines 9/1/97 tilman */1079for (j=0;j<=V.n;j++){1080free(V.v[j]);1081}10821083free(V.v);1084free_perp_matrices(dim);1085free(fp.diag); free(fp.per); free(fp.e);1086for(i=0;i<dim;i++)1087{1088for(j=0;j<G.ng[i];j++)1089{1090for(k=0;k<dim;k++)1091free(G.g[i][j][k]);1092free(G.g[i][j]);1093}1094free(G.g[i]);1095}1096free(G.g); free(G.ord); free(G.ng); free(G.nsg);10971098return(B);1099}110011011102