GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it
/***** Main program for the isometry program ISOM *****/1/**************************************************************************\2@---------------------------------------------------------------------------3@---------------------------------------------------------------------------4@ FILE: isometry.c5@---------------------------------------------------------------------------6@---------------------------------------------------------------------------7@8\**************************************************************************/910#include"typedef.h"11#include "types.h"1213static int normal_option;14static int perp_no;15static int ***perp;16static int perpdim;17static int ***perpbase;18static int ***perpprod;19static int *perpvec;2021#include "isotools.c"22#include "bachtools.c"23#include "iotools.c"24#include "lattools.c"25#include "mattools.c"26#include "orbtools.c"27#include "preproc.c"28#include "sorttools.c"29#include "perfecttools.c"3031/*32@-------------------------------------------------------------------------33@ matrix_TYP *isometry(F1, F2, Fanz, SV1, SV2, Erz, Erzanz, options)34@ matrix_TYP **F1, **F2, *SV1, *SV2, **Erz;35@ int Fanz, Erzanz, *options;36@37@ The function 'isometry' calculates a matrix X such that38@ X * F1[i] *X^{tr} = F2[i] for 1<= i<= Foanz39@ returned via a pointer to 'matrix_TYP'.40@ If no such matrix exists the functions returns NULL41@42@ The arguments of isometry are:43@ matrix_TYP **F1: a set of n times n matrices,44@ the first must be positiv definite45@ matrix_TYP **F2: a set of n times n matrices,46@ the first must be positiv definite47@ int Fanz: the number of the matrices given in 'F1'.48@ matrix_TYP *SV1: The rows of the matrix 'SV1' must be the vectors49@ x in Z^n with x * F1[0] * x^{tr} <= m, where50@ m is the maximal diagonal entry of the Matrix51@ F1[0]52@ matrix_TYP *SV2: The rows of the matrix 'SV2' must be the vectors53@ x in Z^n with x * F2[0] * x^{tr} <= m, where54@ m is the maximal diagonal entry of the Matrix55@ F.[0]56@ int *options: see below.57@ matrix_TYP **Erz: if already elements with g^{tr}F1[i]g = F2[i]58@ are known, the can be used for calculating59@ the isometry.60@ The matrices of known elements can be given61@ to the function by the pointer 'Erz'.62@ int Erzanz: The number of matrices given in 'Erz"63@ int *options: see below.64@65@ options is a pointer to integer (of length 6)66@ The possible options are encoded in the following way:67@ options[0]: The depth, up to wich scalar product combinations68@ shall be calculated. The value should be small.69@ options[0] > 0 should be used only, if the automorphismn70@ group is expected to be small (with respect to the number71@ of shortest vectors).72@ options[1]: The n-point stabiliser with respect to different basis73@ will be calculated.74@ options[2]: If options[2] = 1, additional output is written to the75@ file AUTO.tmp76@ options[3]: If options[3] = 1, Bacher polynomials are used.77@ If options[3] = 2, Bacher polynomial are used up to a deepth78@ specified in options[4].79@ If options[3] = 3, Bacher polynomials are used, using80@ combinations of vectors having the scalar81@ product specified in options[5]82@ options[3] = 4 is the combination of options[3] = 2 and83@ options[3] = 3.84@ options[4]: A natural number number or zero (if options[3] = 2 or 4)85@ options[5]: An integral number (if options[3] = 3 or 4)86@87@ It is possible to use NULL for options,88@ in this case option is assumed to be [0,0,0,0,0,0]89@-------------------------------------------------------------------------90*/9192matrix_TYP *isometry(F1, F2, Fanz, SV1, SV2, Erz, Erzanz, options)93matrix_TYP **F1, **F2, *SV1, *SV2, **Erz;94int Fanz, Erzanz, *options;95{96FILE *outfile;97bachpol *bach;98flagstruct flags;99scpcomb *comb;100invar F, FF;101veclist V, norm;102fpstruct fp;103int dim, max, fail, *vec;104int ***G, nG, ngen, **sumveclist, **sumvecbase;105int i, j, k, n, *Vvi, *Vvj, **Fvi, *Fvij, **FAi, nV1;106matrix_TYP *erg, *erg1;107108extern matrix_TYP *mat_inv();109110normal_option = FALSE;111if(SV1->rows != SV2->rows)112return(NULL);113/* FF.v[i][j] is the transposed of the product of the Gram-matrix FF.A[i]114get the flags from the command line */115getflags(&flags, options);116if(Erzanz > 0)117flags.GEN = 1;118else flags.GEN = 0;119/* F.n is the number of invariant forms */120F.n = Fanz;121if ((F.A = (int***)malloc(F.n * sizeof(int**))) == 0)122exit (2);123/* read the invariant forms of the first lattice */124F.dim = F1[0]->cols;125dim = F.dim;126if(F1[0]->cols != F1[0]->rows)127{128printf("Non-square matrix as input for isometry\n");129exit(3);130}131for(i=1;i<F.n;i++)132{133if(F1[i]->rows != F.dim || F1[i]->cols != F.dim)134{135printf("Different dimensions of the forms in isometry\n");136exit(3);137}138}139for(i=0;i<F.n;i++)140{141if((F.A[i] = (int **)malloc(dim *sizeof(int *))) == 0)142{143printf("realloc of F.A[%d] failed in isometry\n", i);144exit(2);145}146for(j=0;j<dim;j++)147{148if((F.A[i][j] = (int *)malloc(dim *sizeof(int))) == 0)149{150printf("realloc of F.A[%d][%d] failed in isometry\n", i, j);151exit(2);152}153for(k=0;k<dim;k++)154F.A[i][j][k] = F1[i]->array.SZ[j][k];155}156}157/* get the short vectors of the first lattice */158V.dim = dim;159V.len = dim + F.n;160V.n = SV1->rows;161if((V.v = (int **)malloc((V.n+1) *sizeof(int *))) == 0)162{163printf("realloc of V.v failed in isometry\n");164exit(2);165}166if((V.v[0] = (int *)malloc(V.len *sizeof(int))) == 0)167{168printf("realloc of V.v[0] failed in isometry\n");169exit(2);170}171for(j=0;j<V.len;j++)172V.v[0][j] = 0;173for(i=1;i<=V.n;i++)174{175if((V.v[i] = (int *)malloc(V.len *sizeof(int))) == 0)176{177printf("realloc of V.v[%d] failed in isometry\n", i);178exit(2);179}180for(j=0;j<=V.dim;j++)181V.v[i][j] = SV1->array.SZ[i-1][j];182}183/* the first nonzero entry of each vector is made positive and the maximal184entry in the vectors is determined */185max = 1;186for (i = 1; i <= V.n; ++i)187{188Vvi = V.v[i];189for (j = 0; j < dim && Vvi[j] == 0; ++j);190if (j < dim && Vvi[j] < 0)191{192for (k = j; k < dim; ++k)193Vvi[k] *= -1;194}195for (k = j; k < dim; ++k)196{197if (abs(Vvi[k]) > max)198max = abs(Vvi[k]);199}200}201if (max > MAXENTRY)202/* there is an entry, which is bigger than MAXENTRY, which might cause overflow,203since the program doesn't use long integer arithmetic */204{205fprintf(stderr, "Error: Found entry %d in short vectors of the first lattice.\nTo avoid overflow, the entries should not exceed %d.\n", max, MAXENTRY);206exit (3);207}208/* sort the vectors and delete doublets */209sortvecs(&V);210/* the norm-vector (i.e. the vector of the norms with respect to the different211invariant forms) of each vector must be equal to the norm-vector of one212of the vectors from the standard-base */213if ((norm.v = (int**)malloc((dim+1) * sizeof(int*))) == 0)214exit (2);215norm.n = dim;216norm.dim = F.n;217norm.len = F.n;218for (i = 1; i <= norm.n; ++i)219{220/* norm.v[i] is the norm combination of the (i-1)-th base-vector */221if ((norm.v[i] = (int*)malloc(norm.dim * sizeof(int))) == 0)222exit (2);223for (k = 0; k < norm.dim; ++k)224norm.v[i][k] = F.A[k][i-1][i-1];225}226sortvecs(&norm);227/* delete those vectors, which can not be the image of any vector of the228standard-base */229checkvecs(&V, F, norm);230/* F.v[i][j] is the transposed of the product of the Gram-matrix F.A[i] with the231transposed of the vector v[j], hence the scalar product of v[j] and v[k] with232respect to the Gram-matrix F.A[i] can be computed as standard scalar product233of v[j] and F.v[i][k] */234if ((F.v = (int***)malloc(F.n * sizeof(int**))) == 0)235exit (2);236/* the product of the maximal entry in the short vectors with the maximal entry237in F.v[i] should not exceed MAXNORM to avoid overflow */238max = MAXNORM / max;239for (i = 0; i < F.n; ++i)240{241FAi = F.A[i];242if ((F.v[i] = (int**)malloc((V.n+1) * sizeof(int*))) == 0)243exit (2);244Fvi = F.v[i];245for (j = 1; j <= V.n; ++j)246{247Vvj = V.v[j];248if ((Fvi[j] = (int*)malloc(dim * sizeof(int))) == 0)249exit (2);250Fvij = Fvi[j];251for (k = 0; k < dim; ++k)252{253Fvij[k] = sscp(FAi[k], Vvj, dim);254if (abs(Fvij[k]) > max)255/* some entry in F.v[i] is too large */256{257fprintf(stderr, "Error: Found entry %d in F.v.\nTo avoid overflow, the entries should not exceed %d.\n", Fvij[k], max);258exit (3);259}260}261}262}263/* fp.per is the order in which the images of the base vectors are chosen */264if ((fp.per = (int*)malloc(dim * sizeof(int))) == 0)265exit (2);266/* fp.e[i] is the index in V.v of the i-th vector of the standard-base in the267new order */268if ((fp.e = (int*)malloc(dim * sizeof(int))) == 0)269exit (2);270/* fp.diag is the diagonal of the fingerprint in the new order */271if ((fp.diag = (int*)malloc(dim * sizeof(int))) == 0)272exit (2);273/* compute the fingerprint */274fingerprint(&fp, F, V);275if (flags.PRINT == 1)276/* if the -P option is given, print the diagonal fp.diag and the number of277short vectors on ISOM.tmp */278{279outfile = fopen("ISOM.tmp", "a");280fprintf(outfile, "%d short vectors\n", 2*V.n);281fprintf(outfile, "fingerprint diagonal:\n");282for (i = 0; i < dim; ++i)283fprintf(outfile, " %2d", fp.diag[i]);284fprintf(outfile, "\n");285fclose(outfile);286}287/* get the standard basis in the new order */288if ((vec = (int*)malloc(dim * sizeof(int))) == 0)289exit (2);290for (i = 0; i < dim; ++i)291{292for (j = 0; j < dim; ++j)293vec[j] = 0;294vec[fp.per[i]] = 1;295fp.e[i] = numberof(vec, V);296if (abs(fp.e[i]) > V.n)297{298fprintf(stderr, "Error: standard basis vector nr. %d not found\n", i);299exit (3);300}301}302free(vec);303/* if the -D option is given, the scalar product combinations and the304corresponding vector sums are computed for the basis of the first lattice */305if (flags.DEPTH > 0)306{307if ((comb = (scpcomb*)malloc(dim * sizeof(scpcomb))) == 0)308exit (2);309for (i = 0; i < dim; ++i)310{311/* compute the list of scalar product combinations and the corresponding312vector sums */313scpvecs(&comb[i].list, &sumveclist, i, fp.e, flags.DEPTH, V, F);314/* compute a basis for the lattice that is generated by the vector sums and315a transformation matrix that expresses the basis in terms of the316vector sums */317base(&comb[i], &sumvecbase, sumveclist, F.A[0], dim);318if (flags.PRINT == 1)319/* if the -P option is given, print the rank of the lattice generated by the320vector sums on level i on ISOM.tmp */321{322outfile = fopen("ISOM.tmp", "a");323fprintf(outfile, "comb[%d].rank = %d\n", i, comb[i].rank);324fclose(outfile);325}326/* compute the coefficients of the vector sums in terms of the basis */327coef(&comb[i], sumvecbase, sumveclist, F.A[0], dim);328for (j = 0; j <= comb[i].list.n; ++j)329free(sumveclist[j]);330free(sumveclist);331/* compute the scalar products of the base-vectors */332scpforms(&comb[i], sumvecbase, F);333for (j = 0; j < comb[i].rank; ++j)334free(sumvecbase[j]);335free(sumvecbase);336}337}338/* the Bacher-polynomials for the first BACHDEP base vectors are computed,339if no scalar product was given as an argument, the scalar product is set340to 1/2 the norm of the base-vector (with respect to the first form) */341if (flags.BACH[0] == 1)342{343if ((bach = (bachpol*)malloc(flags.BACHDEP * sizeof(bachpol))) == 0)344exit (2);345for (i = 0; i < flags.BACHDEP; ++i)346{347if (flags.BACH[2] == 0)348/* no scalar product was given as an option */349flags.BACHSCP = V.v[fp.e[i]][dim] / 2;350/* compute the Bacher-polynomial */351bacher(&bach[i], fp.e[i], flags.BACHSCP, V, F.v[0]);352if (flags.PRINT == 1)353/* if the -P option is given, print the Bacher-polynomial on ISOM.tmp */354{355outfile = fopen("ISOM.tmp", "a");356fprintf(outfile, "Bacher-polynomial of base vector fp.e[%d]:\n", i);357fputbach(outfile, bach[i]);358fclose(outfile);359}360}361}362/* the vectors of the first lattice are no longer required, only their number */363nV1 = V.n;364for(i=0;i<=V.n;i++)365free(V.v[i]);366free(V.v);367for (i = 0; i < F.n; ++i)368{369for (j = 1; j <= V.n; ++j)370free(F.v[i][j]);371free(F.v[i]);372}373free(F.v);374/* FF are the invariant forms of the second lattice */375if ((FF.A = (int***)malloc(F.n * sizeof(int**))) == 0)376exit (2);377FF.n = F.n;378FF.dim = dim;379/* read the invariant forms of the second lattice */380for(i=1;i<F.n;i++)381{382if(F2[i]->rows != F.dim || F2[i]->cols != F.dim)383{384printf("Different dimensions of the forms in isometry\n");385exit(2);386}387}388for(i=0;i<F.n;i++)389{390if((FF.A[i] = (int **)malloc(dim *sizeof(int *))) == 0)391{392printf("realloc of FF.A[%d] failed in isometry\n", i);393exit(2);394}395for(j=0;j<dim;j++)396{397if((FF.A[i][j] = (int *)malloc(dim *sizeof(int))) == 0)398{399printf("realloc of FF.A[%d][%d] failed in isometry\n", i, j);400exit(2);401}402for(k=0;k<dim;k++)403FF.A[i][j][k] = F2[i]->array.SZ[j][k];404}405}406/* get the short vectors of the second lattice */407V.dim = dim;408V.len = dim + F.n;409V.n = SV2->rows;410if((V.v = (int **)malloc((V.n+1) *sizeof(int *))) == 0)411{412printf("realloc of V.v failed in isometry\n");413exit(2);414}415if((V.v[0] = (int *)malloc(V.len *sizeof(int))) == 0)416{417printf("realloc of V.v[0] failed in isometry\n");418exit(2);419}420for(j=0;j<V.len;j++)421V.v[0][j] = 0;422for(i=1;i<=V.n;i++)423{424if((V.v[i] = (int *)malloc(V.len *sizeof(int))) == 0)425{426printf("realloc of V.v[%d] failed in isometry\n", i);427exit(2);428}429for(j=0;j<=V.dim;j++)430V.v[i][j] = SV2->array.SZ[i-1][j];431}432/* the first nonzero entry of each vector is made positive and the maximal433entry of the vectors is determined */434max = 1;435for (i = 1; i <= V.n; ++i)436{437Vvi = V.v[i];438for (j = 0; j < dim && Vvi[j] == 0; ++j);439if (j < dim && Vvi[j] < 0)440{441for (k = j; k < dim; ++k)442Vvi[k] *= -1;443}444for (k = j; k < dim; ++k)445{446if (abs(Vvi[k]) > max)447max = abs(Vvi[k]);448}449}450if (max > MAXENTRY)451/* there is an entry, which is bigger than MAXENTRY, which might cause overflow,452since the program doesn't use long integer arithmetic */453{454fprintf(stderr, "Error: Found entry %d in short vectors of the second lattice.\nTo avoid overflow, the entries should not exceed %d.\n", max, MAXENTRY);455exit (3);456}457/* V.prime is a prime p, such that the entries of the short vectors remain458unchanged under reduction mod p in symmetric form, i.e. -p/2 < x <= p/2 */459for (V.prime = 2*max + 1; isprime(V.prime) == 0; ++V.prime);460j = F.A[0][0][0];461for(k=1;k<dim;k++)462{463if(F.A[0][k][k] > j)464j = F.A[0][k][k];465}466for(k=0;k<dim;k++)467{468if(FF.A[0][k][k] > j)469V.prime = DEF_PRIME;470}471/* sort the vectors and delete doublets */472sortvecs(&V);473/* the norm-vector (i.e. the vector of the norms with respect to the different474invariant forms) of each vector must be equal to the norm-vector of one475of the vectors from the standard-base of the first lattice */476checkvecs(&V, FF, norm);477for (i = 1; i <= norm.n; ++i)478free(norm.v[i]);479free(norm.v);480/* FF.v[i][j] is the transposed of the product of the Gram-matrix FF.A[i]481with the transposed of the vector V.v[j], which now is a short vector of482the second lattice */483if ((FF.v = (int***)malloc(FF.n * sizeof(int**))) == 0)484exit (2);485/* the product of the maximal entry in the short vectors with the maximal entry486in FF.v[i] should not exceed MAXNORM to avoid overflow */487max = MAXNORM / max;488for (i = 0; i < FF.n; ++i)489{490FAi = FF.A[i];491if ((FF.v[i] = (int**)malloc((V.n+1) * sizeof(int*))) == 0)492exit (2);493Fvi = FF.v[i];494for (j = 1; j <= V.n; ++j)495{496Vvj = V.v[j];497if ((Fvi[j] = (int*)malloc(dim * sizeof(int))) == 0)498exit (2);499Fvij = Fvi[j];500for (k = 0; k < dim; ++k)501{502Fvij[k] = sscp(FAi[k], Vvj, dim);503if (abs(Fvij[k]) > max)504/* some entry in FF.v[i] is too large */505{506fprintf(stderr, "Error: Found entry %d in FF.v.\nTo avoid overflow, the entries should not exceed %d.\n", Fvij[k], max);507exit (3);508}509}510}511}512/* G are the automorphisms of the second lattice */513if ((G = (int***)malloc(1 * sizeof(int**))) == 0)514exit (2);515/* nG is the number of automorphisms of the second lattice */516nG = 0;517if (flags.GEN == 1)518/* get the automorphisms, which are already known */519{520ngen = Erzanz;521if ((G = (int***)realloc(G, ngen * sizeof(int**))) == 0)522exit (2);523fail = 0;524i=0;525while (nG+fail < ngen)526{527if (Erz[i]->cols != dim || Erz[i]->rows != dim)528{529fprintf(stderr, "Error: dimension %d should be %d\n", n, dim);530exit (3);531}532if((G[nG] = (int **)malloc(dim *sizeof(int *))) == 0)533{534printf("realloc of G[%d] in isometry failed\n", nG);535exit(2);536}537for(j=0;j<dim;j++)538{539if((G[nG][j] = (int *)malloc(dim *sizeof(int))) == 0)540{541printf("realloc of G[%d][%d] in isometry failed\n", nG, j);542exit(2);543}544for(k=0;k<dim;k++)545G[nG][j][k] = Erz[i]->array.SZ[k][j];546}547/* check whether the matrix is really an automorphism, i.e. fixes the forms */548if (checkgen(G[nG], FF) == 0)549/* the matrix is not an automorphism */550{551++fail;552for (j = 0; j < dim; ++j)553free(G[nG][j]);554free(G[nG]);555}556else557/* the matrix fixes the forms in FF */558++nG;559i++;560}561}562if (nG == 0)563/* if no automorphisms are known at least take -Id */564{565if ((G[0] = (int**)malloc(dim * sizeof(int*))) == 0)566exit (2);567for (i = 0; i < dim; ++i)568{569if ((G[0][i] = (int*)malloc(dim * sizeof(int))) == 0)570exit (2);571for (j = 0; j < dim; ++j)572G[0][i][j] = 0;573G[0][i][i] = -1;574}575nG = 1;576}577/* now search for an isometry */578erg = bs_isometry(V, F, FF, fp, G, nG, comb, bach, flags);579/**********************580for(i=0;i<nG;i++)581{582for(j=0;j<dim;j++)583free(G[i][j]);584free(G[i]);585}586*************************/587free(G);588for(i=0;i<F.n;i++)589{590for(j=0;j<dim;j++)591free(F.A[i][j]);592free(F.A[i]);593}594free(F.A);595for(i=0;i<FF.n;i++)596{597for(j=1;j<=V.n;j++)598free(FF.v[i][j]);599free(FF.v[i]);600for(j=0;j<dim;j++)601free(FF.A[i][j]);602free(FF.A[i]);603}604free(FF.A); free(FF.v);605for(i=0;i<=V.n;i++)606free(V.v[i]);607free(V.v);608if (flags.BACH[0] == 1)609{610for(i=0;i<flags.BACHDEP;i++)611free(bach[i].coef);612free(bach);613}614if (flags.DEPTH > 0)615{616for(i=0;i<dim;i++)617{618for(j=0;j<=comb[i].list.n;j++)619free(comb[i].coef[j]);620free(comb[i].coef);621for(j=0;j<=comb[i].list.n;j++)622free(comb[i].list.v[j]);623free(comb[i].list.v);624for(j=0;j<comb[i].rank;j++)625free(comb[i].trans[j]);626free(comb[i].trans);627for(j=0;j<F.n;j++)628{629for(k=0;k<comb[i].rank;k++)630free(comb[i].F[j][k]);631free(comb[i].F[j]);632}633free(comb[i].F);634}635free(comb);636}637free(fp.diag); free(fp.per); free(fp.e);638if(erg == NULL)639return(NULL);640erg1 = mat_inv(erg);641free_mat(erg);642return(erg1);643}644645/*646@-------------------------------------------------------------------------647@ matrix_TYP *perfect_normal_isometry(F1, F2, SV1, SV2, Erz, Erzanz,648@ options, P, Panz, Pbase, Pdim)649@ matrix_TYP *F1, *F2, *SV1, *SV2, **Erz, **P, **Pbase;650@ int Erzanz, *options, Panz, Pdim;651@652@ The function 'perfect_normal_isometry' calculates a matrix X with653@ X * F1 * X^{tr} = F2 and654@ X^{-1} * Pbase[i] * X^{-tr} is a matrix in P for 0<= i< Pdim655@656@657@ The arguments are:658@ F1: a symmetric positive definite n by n-matrix.659@ F2: a symmetric positive definite n by n-matrix.660@ SV1: the vectors x in GL_n(Z) (up to sign) with xF1x^{tr} < k,661@ where k is the maximal diagonal entry of 'F1'.662@ SV2: the vectors x in GL_n(Z) (up to sign) with xF2x^{tr} < k,663@ where k is the maximal diagonal entry of 'F1'.664@ Erz: matrices of elements of Aut(F2) (if known).665@ Erzanz: the number of matrices in 'Erz'.666@ options: the same as for the function 'isometry'.667@ P: a set of matrices668@ Panz: the number of matrices given in 'P'.669@ Pbase: a set of matrices670@ Pdim: the number of matrices given in 'Pbase'.671@672@ This function is designed to calculate an isometry of two673@ G-perfect forms that is in the normalizer of a group G (the674@ generators of G are the matrices 'Erz').675@ Then 'P' is the set of matrices given by the Voronoi-directions of 'F1'676@ and 'Pbase' a maximal linearly independent subset of the677@ Voronoi-directions of 'F2'.678@679@---------------------------------------------------------------------------680@681*/682683684matrix_TYP *perfect_normal_isometry(F1, F2, SV1, SV2, Erz, Erzanz, options, P, Panz, Pbase, Pdim)685matrix_TYP *F1, *F2, *SV1, *SV2, **Erz, **P, **Pbase;686int Erzanz, *options, Panz, Pdim;687{688FILE *outfile;689bachpol *bach;690flagstruct flags;691scpcomb *comb;692invar F, FF;693veclist V, norm;694fpstruct fp;695int dim, max, fail, *vec;696int ***G, nG, ngen, **sumveclist, **sumvecbase;697int i, j, k, n, *Vvi, *Vvj, **Fvi, *Fvij, **FAi, nV1;698matrix_TYP *erg, *erg1;699700extern int pointer_lower_triangular_mat_comp();701extern matrix_TYP *mat_inv();702703if(SV1->rows != SV2->rows)704return(NULL);705normal_option = TRUE;706perpdim = Pdim;707perp_no = Panz;708/* FF.v[i][j] is the transposed of the product of the Gram-matrix FF.A[i]709get the flags from the command line */710getflags(&flags, options);711if(Erzanz > 0)712flags.GEN = 1;713else flags.GEN = 0;714/* F.n is the number of invariant forms */715F.n = 1;716if ((F.A = (int***)malloc(F.n * sizeof(int**))) == 0)717exit (2);718/* read the invariant forms of the first lattice */719F.dim = F1->cols;720dim = F.dim;721if(F1->cols != F1->rows)722{723printf("Non-square matrix as input for isometry\n");724exit(2);725}726if((F.A[0] = (int **)malloc(dim *sizeof(int *))) == 0)727{728printf("realloc of F.A[0] failed in isometry\n");729exit(2);730}731for(j=0;j<dim;j++)732{733if((F.A[0][j] = (int *)malloc(dim *sizeof(int))) == 0)734{735printf("realloc of F.A[0][%d] failed in isometry\n", j);736exit(2);737}738for(k=0;k<dim;k++)739F.A[0][j][k] = F1->array.SZ[j][k];740}741/* get the short vectors of the first lattice */742V.dim = dim;743V.len = dim + F.n;744V.n = SV1->rows;745if((V.v = (int **)malloc((V.n+1) *sizeof(int *))) == 0)746{747printf("realloc of V.v failed in isometry\n");748exit(2);749}750if((V.v[0] = (int *)malloc(V.len *sizeof(int))) == 0)751{752printf("realloc of V.v[0] failed in isometry\n");753exit(2);754}755for(j=0;j<V.len;j++)756V.v[0][j] = 0;757for(i=1;i<=V.n;i++)758{759if((V.v[i] = (int *)malloc(V.len *sizeof(int))) == 0)760{761printf("realloc of V.v[%d] failed in isometry\n", i);762exit(2);763}764for(j=0;j<=V.dim;j++)765V.v[i][j] = SV1->array.SZ[i-1][j];766}767/* the first nonzero entry of each vector is made positive and the maximal768entry in the vectors is determined */769max = 1;770for (i = 1; i <= V.n; ++i)771{772Vvi = V.v[i];773for (j = 0; j < dim && Vvi[j] == 0; ++j);774if (j < dim && Vvi[j] < 0)775{776for (k = j; k < dim; ++k)777Vvi[k] *= -1;778}779for (k = j; k < dim; ++k)780{781if (abs(Vvi[k]) > max)782max = abs(Vvi[k]);783}784}785if (max > MAXENTRY)786/* there is an entry, which is bigger than MAXENTRY, which might cause overflow,787since the program doesn't use long integer arithmetic */788{789fprintf(stderr, "Error: Found entry %d in short vectors of the first lattice.\nTo avoid overflow, the entries should not exceed %d.\n", max, MAXENTRY);790exit (3);791}792/* sort the vectors and delete doublets */793sortvecs(&V);794/* the norm-vector (i.e. the vector of the norms with respect to the different795invariant forms) of each vector must be equal to the norm-vector of one796of the vectors from the standard-base */797if ((norm.v = (int**)malloc((dim+1) * sizeof(int*))) == 0)798exit (2);799norm.n = dim;800norm.dim = F.n;801norm.len = F.n;802for (i = 1; i <= norm.n; ++i)803{804/* norm.v[i] is the norm combination of the (i-1)-th base-vector */805if ((norm.v[i] = (int*)malloc(norm.dim * sizeof(int))) == 0)806exit (2);807for (k = 0; k < norm.dim; ++k)808norm.v[i][k] = F.A[k][i-1][i-1];809}810sortvecs(&norm);811/* delete those vectors, which can not be the image of any vector of the812standard-base */813checkvecs(&V, F, norm);814/* F.v[i][j] is the transposed of the product of the Gram-matrix F.A[i] with the815transposed of the vector v[j], hence the scalar product of v[j] and v[k] with816respect to the Gram-matrix F.A[i] can be computed as standard scalar product817of v[j] and F.v[i][k] */818if ((F.v = (int***)malloc(F.n * sizeof(int**))) == 0)819exit (2);820/* the product of the maximal entry in the short vectors with the maximal entry821in F.v[i] should not exceed MAXNORM to avoid overflow */822max = MAXNORM / max;823for (i = 0; i < F.n; ++i)824{825FAi = F.A[i];826if ((F.v[i] = (int**)malloc((V.n+1) * sizeof(int*))) == 0)827exit (2);828Fvi = F.v[i];829for (j = 1; j <= V.n; ++j)830{831Vvj = V.v[j];832if ((Fvi[j] = (int*)malloc(dim * sizeof(int))) == 0)833exit (2);834Fvij = Fvi[j];835for (k = 0; k < dim; ++k)836{837Fvij[k] = sscp(FAi[k], Vvj, dim);838if (abs(Fvij[k]) > max)839/* some entry in F.v[i] is too large */840{841fprintf(stderr, "Error: Found entry %d in F.v.\nTo avoid overflow, the entries should not exceed %d.\n", Fvij[k], max);842exit (3);843}844}845}846}847/* fp.per is the order in which the images of the base vectors are chosen */848if ((fp.per = (int*)malloc(dim * sizeof(int))) == 0)849exit (2);850/* fp.e[i] is the index in V.v of the i-th vector of the standard-base in the851new order */852if ((fp.e = (int*)malloc(dim * sizeof(int))) == 0)853exit (2);854/* fp.diag is the diagonal of the fingerprint in the new order */855if ((fp.diag = (int*)malloc(dim * sizeof(int))) == 0)856exit (2);857/* compute the fingerprint */858fingerprint(&fp, F, V);859mach_perp_matrices(fp, P, Pbase, dim);860pointer_mat_quicksort(perp, 0, perp_no-1, dim, dim, pointer_lower_triangular_mat_comp);861if (flags.PRINT == 1)862/* if the -P option is given, print the diagonal fp.diag and the number of863short vectors on ISOM.tmp */864{865outfile = fopen("ISOM.tmp", "a");866fprintf(outfile, "%d short vectors\n", 2*V.n);867fprintf(outfile, "fingerprint diagonal:\n");868for (i = 0; i < dim; ++i)869fprintf(outfile, " %2d", fp.diag[i]);870fprintf(outfile, "\n");871fclose(outfile);872}873/* get the standard basis in the new order */874if ((vec = (int*)malloc(dim * sizeof(int))) == 0)875exit (2);876for (i = 0; i < dim; ++i)877{878for (j = 0; j < dim; ++j)879vec[j] = 0;880vec[fp.per[i]] = 1;881fp.e[i] = numberof(vec, V);882if (abs(fp.e[i]) > V.n)883{884fprintf(stderr, "Error: standard basis vector nr. %d not found\n", i);885exit (3);886}887}888free(vec);889/* if the -D option is given, the scalar product combinations and the890corresponding vector sums are computed for the basis of the first lattice */891if (flags.DEPTH > 0)892{893if ((comb = (scpcomb*)malloc(dim * sizeof(scpcomb))) == 0)894exit (2);895for (i = 0; i < dim; ++i)896{897/* compute the list of scalar product combinations and the corresponding898vector sums */899scpvecs(&comb[i].list, &sumveclist, i, fp.e, flags.DEPTH, V, F);900/* compute a basis for the lattice that is generated by the vector sums and901a transformation matrix that expresses the basis in terms of the902vector sums */903base(&comb[i], &sumvecbase, sumveclist, F.A[0], dim);904if (flags.PRINT == 1)905/* if the -P option is given, print the rank of the lattice generated by the906vector sums on level i on ISOM.tmp */907{908outfile = fopen("ISOM.tmp", "a");909fprintf(outfile, "comb[%d].rank = %d\n", i, comb[i].rank);910fclose(outfile);911}912/* compute the coefficients of the vector sums in terms of the basis */913coef(&comb[i], sumvecbase, sumveclist, F.A[0], dim);914for (j = 0; j <= comb[i].list.n; ++j)915free(sumveclist[j]);916free(sumveclist);917/* compute the scalar products of the base-vectors */918scpforms(&comb[i], sumvecbase, F);919for (j = 0; j < comb[i].rank; ++j)920free(sumvecbase[j]);921free(sumvecbase);922}923}924/* the Bacher-polynomials for the first BACHDEP base vectors are computed,925if no scalar product was given as an argument, the scalar product is set926to 1/2 the norm of the base-vector (with respect to the first form) */927if (flags.BACH[0] == 1)928{929if ((bach = (bachpol*)malloc(flags.BACHDEP * sizeof(bachpol))) == 0)930exit (2);931for (i = 0; i < flags.BACHDEP; ++i)932{933if (flags.BACH[2] == 0)934/* no scalar product was given as an option */935flags.BACHSCP = V.v[fp.e[i]][dim] / 2;936/* compute the Bacher-polynomial */937bacher(&bach[i], fp.e[i], flags.BACHSCP, V, F.v[0]);938if (flags.PRINT == 1)939/* if the -P option is given, print the Bacher-polynomial on ISOM.tmp */940{941outfile = fopen("ISOM.tmp", "a");942fprintf(outfile, "Bacher-polynomial of base vector fp.e[%d]:\n", i);943fputbach(outfile, bach[i]);944fclose(outfile);945}946}947}948/* the vectors of the first lattice are no longer required, only their number */949nV1 = V.n;950for(i=0;i<=V.n;i++)951free(V.v[i]);952free(V.v);953for (i = 0; i < F.n; ++i)954{955for (j = 1; j <= V.n; ++j)956free(F.v[i][j]);957free(F.v[i]);958}959free(F.v);960/* FF are the invariant forms of the second lattice */961if ((FF.A = (int***)malloc(F.n * sizeof(int**))) == 0)962exit (2);963FF.n = F.n;964FF.dim = dim;965/* read the invariant forms of the second lattice */966if((FF.A[0] = (int **)malloc(dim *sizeof(int *))) == 0)967{968printf("realloc of FF.A[0] failed in isometry\n");969exit(2);970}971for(j=0;j<dim;j++)972{973if((FF.A[0][j] = (int *)malloc(dim *sizeof(int))) == 0)974{975printf("realloc of FF.A[0][%d] failed in isometry\n", j);976exit(2);977}978for(k=0;k<dim;k++)979FF.A[0][j][k] = F2->array.SZ[j][k];980}981/* get the short vectors of the second lattice */982V.dim = dim;983V.len = dim + F.n;984V.n = SV2->rows;985if((V.v = (int **)malloc((V.n+1) *sizeof(int *))) == 0)986{987printf("realloc of V.v failed in isometry\n");988exit(2);989}990if((V.v[0] = (int *)malloc(V.len *sizeof(int))) == 0)991{992printf("realloc of V.v[0] failed in isometry\n");993exit(2);994}995for(j=0;j<V.len;j++)996V.v[0][j] = 0;997for(i=1;i<=V.n;i++)998{999if((V.v[i] = (int *)malloc(V.len *sizeof(int))) == 0)1000{1001printf("realloc of V.v[%d] failed in isometry\n", i);1002exit(2);1003}1004for(j=0;j<=V.dim;j++)1005V.v[i][j] = SV2->array.SZ[i-1][j];1006}1007/* the first nonzero entry of each vector is made positive and the maximal1008entry of the vectors is determined */1009max = 1;1010for (i = 1; i <= V.n; ++i)1011{1012Vvi = V.v[i];1013for (j = 0; j < dim && Vvi[j] == 0; ++j);1014if (j < dim && Vvi[j] < 0)1015{1016for (k = j; k < dim; ++k)1017Vvi[k] *= -1;1018}1019for (k = j; k < dim; ++k)1020{1021if (abs(Vvi[k]) > max)1022max = abs(Vvi[k]);1023}1024}1025if (max > MAXENTRY)1026/* there is an entry, which is bigger than MAXENTRY, which might cause overflow,1027since the program doesn't use long integer arithmetic */1028{1029fprintf(stderr, "Error: Found entry %d in short vectors of the second lattice.\nTo avoid overflow, the entries should not exceed %d.\n", max, MAXENTRY);1030exit (3);1031}1032/* V.prime is a prime p, such that the entries of the short vectors remain1033unchanged under reduction mod p in symmetric form, i.e. -p/2 < x <= p/2 */1034for (V.prime = 2*max + 1; isprime(V.prime) == 0; ++V.prime);1035/* sort the vectors and delete doublets */1036sortvecs(&V);1037/* the norm-vector (i.e. the vector of the norms with respect to the different1038invariant forms) of each vector must be equal to the norm-vector of one1039of the vectors from the standard-base of the first lattice */1040checkvecs(&V, FF, norm);1041for (i = 1; i <= norm.n; ++i)1042free(norm.v[i]);1043free(norm.v);1044/* FF.v[i][j] is the transposed of the product of the Gram-matrix FF.A[i]1045with the transposed of the vector V.v[j], which now is a short vector of1046the second lattice */1047if ((FF.v = (int***)malloc(FF.n * sizeof(int**))) == 0)1048exit (2);1049/* the product of the maximal entry in the short vectors with the maximal entry1050in FF.v[i] should not exceed MAXNORM to avoid overflow */1051max = MAXNORM / max;1052for (i = 0; i < FF.n; ++i)1053{1054FAi = FF.A[i];1055if ((FF.v[i] = (int**)malloc((V.n+1) * sizeof(int*))) == 0)1056exit (2);1057Fvi = FF.v[i];1058for (j = 1; j <= V.n; ++j)1059{1060Vvj = V.v[j];1061if ((Fvi[j] = (int*)malloc(dim * sizeof(int))) == 0)1062exit (2);1063Fvij = Fvi[j];1064for (k = 0; k < dim; ++k)1065{1066Fvij[k] = sscp(FAi[k], Vvj, dim);1067if (abs(Fvij[k]) > max)1068/* some entry in FF.v[i] is too large */1069{1070fprintf(stderr, "Error: Found entry %d in FF.v.\nTo avoid overflow, the entries should not exceed %d.\n", Fvij[k], max);1071exit (3);1072}1073}1074}1075}1076/* G are the automorphisms of the second lattice */1077if ((G = (int***)malloc(1 * sizeof(int**))) == 0)1078exit (2);1079/* nG is the number of automorphisms of the second lattice */1080nG = 0;1081if (flags.GEN == 1)1082/* get the automorphisms, which are already known */1083{1084ngen = Erzanz;1085if ((G = (int***)realloc(G, ngen * sizeof(int**))) == 0)1086exit (2);1087fail = 0;1088i=0;1089while (nG+fail < ngen)1090{1091if (Erz[i]->cols != dim || Erz[i]->rows != dim)1092{1093fprintf(stderr, "Error: dimension %d should be %d\n", n, dim);1094exit (3);1095}1096if((G[nG] = (int **)malloc(dim *sizeof(int *))) == 0)1097{1098printf("realloc of G[%d] in isometry failed\n", nG);1099exit(2);1100}1101for(j=0;j<dim;j++)1102{1103if((G[nG][j] = (int *)malloc(dim *sizeof(int))) == 0)1104{1105printf("realloc of G[%d][%d] in isometry failed\n", nG, j);1106exit(2);1107}1108for(k=0;k<dim;k++)1109G[nG][j][k] = Erz[i]->array.SZ[k][j];1110}1111/* check whether the matrix is really an automorphism, i.e. fixes the forms */1112if (checkgen(G[nG], FF) == 0)1113/* the matrix is not an automorphism */1114{1115++fail;1116for (j = 0; j < dim; ++j)1117free(G[nG][j]);1118free(G[nG]);1119}1120else1121/* the matrix fixes the forms in FF */1122++nG;1123i++;1124}1125}1126if (nG == 0)1127/* if no automorphisms are known at least take -Id */1128{1129if ((G[0] = (int**)malloc(dim * sizeof(int*))) == 0)1130exit (2);1131for (i = 0; i < dim; ++i)1132{1133if ((G[0][i] = (int*)malloc(dim * sizeof(int))) == 0)1134exit (2);1135for (j = 0; j < dim; ++j)1136G[0][i][j] = 0;1137G[0][i][i] = -1;1138}1139nG = 1;1140}1141/* now search for an isometry */1142erg = bs_isometry(V, F, FF, fp, G, nG, comb, bach, flags);1143for(i=0;i<F.n;i++)1144{1145for(j=0;j<dim;j++)1146free(F.A[i][j]);1147free(F.A[i]);1148}1149free(F.A);1150for(i=0;i<FF.n;i++)1151{1152for(j=1;j<=V.n;j++)1153free(FF.v[i][j]);1154free(FF.v[i]);1155for(j=0;j<dim;j++)1156free(FF.A[i][j]);1157free(FF.A[i]);1158}1159free(FF.A); free(FF.v);1160for(i=0;i<=V.n;i++)1161free(V.v[i]);1162free(V.v);1163if (flags.BACH[0] == 1)1164{1165for(i=0;i<flags.BACHDEP;i++)1166free(bach[i].coef);1167free(bach);1168}1169if (flags.DEPTH > 0)1170{1171for(i=0;i<dim;i++)1172{1173for(j=0;j<=comb[i].list.n;j++)1174free(comb[i].coef[j]);1175free(comb[i].coef);1176for(j=0;j<=comb[i].list.n;j++)1177free(comb[i].list.v[j]);1178free(comb[i].list.v);1179for(j=0;j<comb[i].rank;j++)1180free(comb[i].trans[j]);1181free(comb[i].trans);1182for(j=0;j<F.n;j++)1183{1184for(k=0;k<comb[i].rank;k++)1185free(comb[i].F[j][k]);1186free(comb[i].F[j]);1187}1188free(comb[i].F);1189}1190free(comb);1191}1192free(fp.diag); free(fp.per); free(fp.e);1193/****************************1194for(i=0;i<nG;i++)1195{1196for(j=0;j<dim;j++)1197free(G[i][j]);1198free(G[i]);1199}1200*********************/1201free(G);1202free_perp_matrices(dim);1203if(erg == NULL)1204return(NULL);1205erg1 = mat_inv(erg);1206free_mat(erg);1207return(erg1);1208}120912101211