GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it
#include "typedef.h"1#include "voronoi.h"2#include "reduction.h"3#include "autgrp.h"4#include "bravais.h"5#include "symm.h"6#include "getput.h"7#include "matrix.h"8#include "longtools.h"9#include "polyeder.h"10#include "tools.h"11#include "sort.h"12#include "longtools.h"1314extern int INFO_LEVEL;1516int max_diagonal_entry(matrix_TYP *A)17/* returns the entry |A[i][i]| such that |A[i][i]| >= |A[j][j]| for all j */18{19int max=0,20i;2122if (A->cols != A->rows){23printf("error in max_diagonal_entry\n");24exit(3);25}2627for (i=0;i<A->cols;i++){28if ((max==0) || (max < abs(A->array.SZ[i][i]))){29max = abs(A->array.SZ[i][i]);30}31}3233return max;34}3536matrix_TYP *extends_to_isometry(37matrix_TYP **hforms,matrix_TYP *HSV,int anz_hneighbours,38matrix_TYP **gforms,matrix_TYP *GSV,int anz_gneighbours,39int fdim,int offset)40/* the situation is as follows:41the matrices hform and gform are isometric, now looks whther42we can find an isometry which transforms the set hneighbours43do the set gneighbours */44{45matrix_TYP *erg=NULL,46*tmp;4748int i=offset;4950if (INFO_LEVEL & 12){51fprintf(stderr,"entering extends_to_isometry\n");52}53if (anz_hneighbours != anz_gneighbours){54fprintf(stderr,"WARNING IN extends_to_isometry: different number\n");55fprintf(stderr," of forms.\n");56}5758while ((erg==NULL) && (i<anz_hneighbours)){59/* swap the i-th entry of gneighbours to the offset-th entry */60tmp = gforms[offset];61gforms[offset] = gforms[i];62gforms[i] = tmp;6364/* test whether this setting is possible at all */65tmp = isometry(hforms,gforms,offset+1,HSV,GSV,NULL,0,NULL);6667if (tmp!=NULL){68/* changed 16.10.01 tilman: the first condition is wrong, because69it uses properties of the direction (i.e. to be a base of the70space of invariant form) which they do not fullfill */71/* if ((offset<(fdim-1)) && (offset < (anz_hneighbours - 2))){*/72if (offset < (anz_hneighbours - 2)){73/* do the recursion */74free_mat(tmp);75erg = extends_to_isometry(hforms,HSV,anz_hneighbours,76gforms,GSV,anz_gneighbours,fdim,offset+1);77}78else{79erg = tmp;80}81}8283/* swap back */84tmp = gforms[i];85gforms[i] = gforms[offset];86gforms[offset] = tmp;87i++;88}8990return erg;91}929394int neighbours(matrix_TYP ***perf,bravais_TYP *G,matrix_TYP **Ftr,95matrix_TYP *tr_bifo,matrix_TYP *SV,int min)96{97int i,j,k,l, Fdim, Gdim;98int lc, rc, g,99min_x;100int Pmin, Vanz, Wanz;101102matrix_TYP **V,103*N,104*P, /* the G-perfect form */105*X;106polyeder_TYP *pol;107wall_TYP **W;108int *ww, *pw;109110/* initial settings */111P = perf[0][0];112113Fdim = G->form_no;114Gdim = G->form[0]->cols;115/**********************************************************************\116| calculate the vertices of the Voronoidomain in F(G^{tr})117| and the forms in F(G) corresponding to the walls of the Voronoidomain.118| The coordinates of these forms with respect to the basis given in G->form119| are obtained as the coordinates of the vetrices of the polyeder_TYP *pol.120\**********************************************************************/121V = voronoi_vertices(P, G, &Vanz, &Pmin, &i);122Wanz = Vanz;123if( (W = (wall_TYP **)malloc(Wanz *sizeof(wall_TYP *))) == NULL)124{125printf("malloc of W failed in neighbours\n");126exit(2);127}128if( (ww = (int *)malloc(Fdim *sizeof(int))) == NULL)129{130printf("malloc of ww failed in neighbours\n");131exit(2);132}133if( (pw = (int *)malloc(Fdim *sizeof(int))) == NULL)134{135printf("malloc of pw failed in neighbours\n");136exit(2);137}138for(i=0;i<Vanz;i++)139{140W[i] = init_wall(Fdim);141form_to_vec(ww, V[i], Ftr, Fdim, &k);142for(j=0;j<Fdim; j++)143for(k=0;k<Fdim; k++)144W[i]->gl[j] += ww[k] * tr_bifo->array.SZ[j][k];145normal_wall(W[i]);146free_mat(V[i]);147}148free(V);149pol = first_polyeder(W, Wanz);150if(pol == NULL)151{152printf("Error in neighbours: P not G-perfekt\n");153exit(3);154}155for(i=0;i<Wanz;i++)156{157refine_polyeder(pol, W[i]);158free_wall(&W[i]);159}160free(W);161162/*163put_polyeder(pol);164*/165166/******************************************************************\167| Each G-perfect form A, that is a neighbour of P, is (up to168| multiplication with a positive scalar) given by169| N = lc *P + rc * X,170| where X is a form defined by a vertex of the polyeder pol.171| The coefficients are calculated with the function 'voronoi_neighbour'.172\******************************************************************/173form_to_vec(pw, P, G->form, Fdim, &k);174175/* getting memory for the result */176perf[0] = (matrix_TYP **) realloc(perf[0],(pol->vert_no + 1)177* sizeof(matrix_TYP *));178179X = init_mat(Gdim, Gdim, "");180X->flags.Integral = X->flags.Symmetric = TRUE;181X->flags.Diagonal = FALSE;182183for(i=0;i<pol->vert_no;i++)184{185/******************************************************\186| Calculate X187\******************************************************/188for(j=0;j<Gdim;j++)189for(k=0;k<=j;k++)190{191X->array.SZ[j][k] = 0;192for(l=0;l<Fdim;l++)193X->array.SZ[j][k] +=pol->vert[i]->v[l] * G->form[l]->array.SZ[j][k];194X->array.SZ[k][j] = X->array.SZ[j][k];195}196N = voronoi_neighbour(P, X, Pmin, &lc, &rc);197198if(N != NULL){199perf[0][i+1] = N;200}201else{202/* we got a blind direction here */203/* so the neighbour in this sense is the intersection of the204boundary of the cone with the line through P with slope205X */206N = scal_pr(SV,X,TRUE);207min_x = N->array.SZ[0][0];208for (j=0;j<N->rows;j++){209if (N->array.SZ[j][j] < min_x) min_x = N->array.SZ[j][j];210}211perf[0][i+1] = imat_add(P,X,min_x,min);212free_mat(N);213}214215/* divide this result by the gcd of all entries */216g = perf[0][i+1]->array.SZ[0][0];217for (j=0;j<perf[0][i+1]->rows;j++){218for (k=0;k<perf[0][i+1]->cols;k++){219g = GGT(perf[0][i+1]->array.SZ[j][k],g);220}221}222for (j=0;j<perf[0][i+1]->rows;j++){223for (k=0;k<perf[0][i+1]->cols;k++){224perf[0][i+1]->array.SZ[j][k] = perf[0][i+1]->array.SZ[j][k]/g;225}226}227}228229free_mat(X);230free(pw);231free(ww);232/*********************************233put_polyeder(pol);234***********************************/235236/* changed 14.04.99 to save this variable from being freed, it237causes trouble on some machines */238i = pol->vert_no;239free_polyeder(pol);240241/* return the number of neighbours */242return i;243244}245246void transform_pair(bravais_TYP *H,bravais_TYP *Htr,matrix_TYP *x)247{248int i;249250matrix_TYP *xi,251*xitr,252*xtr,253*tmp;254255Check_mat(x);256xi=long_mat_inv(x);257xitr=tr_pose(xi);258xtr=tr_pose(x);259260if (INFO_LEVEL & 4){261put_mat(x,NULL,"x",2);262put_mat(xtr,NULL,"xtr",2);263put_mat(xi,NULL,"xi",2);264put_mat(xitr,NULL,"xitr",2);265}266267/* firstly transform H->gen */268for (i=0;i<H->gen_no;i++){269tmp = mat_mul(xitr,H->gen[i]);270free_mat(H->gen[i]);271H->gen[i] = mat_mul(tmp,xtr);272free_mat(tmp);273}274275/* now transform Htr->gen */276for (i=0;i<Htr->gen_no;i++){277tmp = mat_mul(x,Htr->gen[i]);278free_mat(Htr->gen[i]);279Htr->gen[i] = mat_mul(tmp,xi);280free_mat(tmp);281}282283/* now transform H->form */284for (i=0;i<H->form_no;i++){285tmp = mat_mul(x,H->form[i]);286free_mat(H->form[i]);287H->form[i] = mat_mul(tmp,xtr);288free_mat(tmp);289}290291/* now transform Htr->form */292for (i=0;i<Htr->form_no;i++){293tmp = mat_mul(xitr,Htr->form[i]);294free_mat(Htr->form[i]);295Htr->form[i] = mat_mul(tmp,xi);296free_mat(tmp);297}298299/* old version300tmp = konj_bravais(Htr,x);301tmp = konj_bravais(H,xitr); */302303/* inserted: tilman 26.08.98 to get a better304basis for the formspace of H,Htr */305long_rein_formspace(H->form,H->form_no,1);306long_rein_formspace(Htr->form,Htr->form_no,1);307308free_mat(xtr);309free_mat(xi);310free_mat(xitr);311312return;313314}315316matrix_TYP *is_z_equivalent(bravais_TYP *G,bravais_TYP *G_tr,317bravais_TYP *H,bravais_TYP *H_tr)318/* IMPORTANT: G,H HAVE TO BE BRAVAIS-GROUPS!!!!,319AND G_tr, H_tr HAVE TO BE THE TRANSPOSED GROUPS OF G,H RESP.320This function returns an integral matrix A such that G^A = H, if321such a matrix exists. Otherwise NULL is returned */322{323int i,324j,325dim,326epsilon = 101,327ming,328minh,329prime = 1949,330anz_gperfect,331anz_hneighbours,332anz_gneighbours,333max; /* will hold the maximal diagonal entry of a form */334335voronoi_TYP **gp; /* normalizer returns a list of all336perfect forms via a voronoi_TYP */337338bravais_TYP *GB; /* the bravais group of G, for temporary purposes */339340matrix_TYP *gtrbifo, /* the tracebifo of G,G_tr */341*htrbifo, /* the tracebifo of H,H_tr */342*tmp,343*tmp2,344*id,345*gperfect, /* will hold ONE G-perfect form modulo the346operation of the normalizer */347*hperfect, /* will hold ONE H-perfect form */348*HSV, /* will hold the short vectors of hperfect */349*GSV,350**hneighbours, /* holds all neighbours of hperfect */351**gneighbours,352*h_pair=NULL, /* h will be transformed in a way such that353we get a "nice" basis of the formspace */354*conj; /* the matrix that conjugates these both groups,355if this exists */356357if (INFO_LEVEL & 4){358fprintf(stderr,"Entered is_z_equivalent\n");359}360361dim = G->dim;362363/* checking all the trivialities */364if (G->dim != H->dim){365conj = NULL;366if (INFO_LEVEL & 4){367fprintf(stderr,"the groups don't even live in the same universe\n");368}369}370else if(G->form_no != H->form_no){371conj = NULL;372if (INFO_LEVEL & 4){373fprintf(stderr,"the groups are not conjugated\n");374fprintf(stderr,"Dimension of the Formspace of G: %d\n",G->form_no);375fprintf(stderr,"Dimension of the Formspace of H: %d\n",H->form_no);376}377}378/* the order is an criterion if it's known */379else if((G->order != H->order) && (G->order !=0) && (H->order !=0)){380conj = NULL;381if (INFO_LEVEL & 4){382fprintf(stderr,"the groups are not conjugated\n");383fprintf(stderr,"Order of G: %d\n",G->order);384fprintf(stderr,"Order of H: %d\n",H->order);385}386}387else{388/* now start the real bussiness */389390/* firstly calculate the trace_bifo for G,H */391gtrbifo = trace_bifo(G->form,G_tr->form,G->form_no);392htrbifo = trace_bifo(H->form,H_tr->form,H->form_no);393394/* inserted tilman 30.5.97 */395for (i=0;i<G->form_no;i++){396Check_mat(G->form[i]);397Check_mat(H->form[i]);398}399400/* output for debugging401put_mat(gtrbifo,NULL,"gtrbifo",2);402put_mat(htrbifo,NULL,"htrbifo",2); */403404/* the two trace bifos should have the same elementary devisors */405tmp = long_elt_mat(NULL,gtrbifo,NULL);406tmp2 = long_elt_mat(NULL,htrbifo,NULL);407408if (mat_comp(tmp,tmp2) == 0){409free_mat(tmp);410free_mat(tmp2);411412id = init_mat(dim,dim,"1");413414if (INFO_LEVEL & 4){415fprintf(stderr,"\n");416}417418/* now calculate one G-perfect form */419tmp = rform(G->gen,G->gen_no,id,epsilon);420gperfect = first_perfect(tmp,G,G_tr->form,gtrbifo,&ming);421free_mat(tmp);422423/* now calculate one H-perfect form, and the short vectors424of it */425tmp = rform(H->gen,H->gen_no,id,epsilon);426hperfect = first_perfect(tmp,H,H_tr->form,htrbifo,&minh);427free_mat(tmp);428429/* reduce H by pair_reduction, and transform H_tr accordingly */430h_pair = init_mat(H->dim,H->dim,"1");431tmp = pair_red(hperfect,h_pair);432free_mat(hperfect);433434transform_pair(H,H_tr,h_pair);435436free_mat(htrbifo);437htrbifo = trace_bifo(H->form,H_tr->form,H->form_no);438hperfect = first_perfect(tmp,H,H_tr->form,htrbifo,&minh);439free_mat(tmp);440441max = max_diagonal_entry(hperfect);442HSV = short_vectors(hperfect,max,0,0,0,&i);443444if (INFO_LEVEL & 4){445fprintf(stderr,"Got perfect forms for G and H.\n");446}447448/* output for debugging */449if (INFO_LEVEL & 4){450put_mat(hperfect,NULL,"hperfect",2);451put_mat(htrbifo,NULL,"htrbifo",2);452printf("maximaler diagonaleintrag von hperfect %d\n",max);453}454455/* now calculate all perfect neigbours of hperfect */456hneighbours = (matrix_TYP **) malloc(sizeof(matrix_TYP *));457hneighbours[0] = hperfect;458anz_hneighbours = neighbours(&hneighbours,H,H_tr->form,htrbifo,459HSV,minh);460461if (INFO_LEVEL & 4){462fprintf(stderr,"Calculated the neighbours of hperfect.\n");463}464465GB = bravais_group(G,TRUE);466/* and calculate all G-perfect forms which represent the orbit467of the normalizer on them, i.e. the quotient graph */468gp = normalizer(gperfect,GB,G_tr,prime,&anz_gperfect);469G->normal = GB->normal; G->normal_no = GB->normal_no;470GB->normal = NULL; GB->normal_no = 0;471free_bravais(GB);472473if (INFO_LEVEL & 4){474fprintf(stderr,"Calculated the normalizer of G.\n");475}476477/* now search for a G-perfect form which is isometric to the478H-perfect form and all of its neighbours are also */479conj = NULL;480i = 0;481while ((i<anz_gperfect) && (conj == NULL)){482483/* calculate the short vectors of the G-perfect form in question */484GSV = short_vectors(gp[i]->gram,max,0,0,0,&j);485486/* let's see whether there is an isometry between this form487and hperfect */488conj = isometry(&hperfect,&gp[i]->gram,1,HSV,GSV,NULL,0,NULL);489490if (INFO_LEVEL & 4){491fprintf(stderr,"calculating isometries\n");492fprintf(stderr,"%d-th of %d\n",i+1,anz_gperfect);493if (conj!=NULL){494fprintf(stderr,"found a new isometry.\n");495put_mat(conj,NULL,"conj",2);496put_mat(hperfect,NULL,"hperfect",2);497put_mat(gp[i]->gram,NULL,"gp[i]->gram",2);498}499}500501/* output for debugging502put_mat(hperfect,NULL,"hperfect",2);503put_mat(gp[i]->gram,NULL,"gp[i]->gram",2);504put_mat(conj,NULL,"conj",2);505put_mat(HSV,NULL,"HSV",2);506put_mat(GSV,NULL,"GSV",2); */507508if (conj != NULL){509/* there is an isometry, let's see whether it respects the510neighbours also */511/* now calculate all perfect neigbours of hperfect */512gneighbours = (matrix_TYP **) malloc(sizeof(matrix_TYP));513gneighbours[0] = gp[i]->gram;514anz_gneighbours = neighbours(&gneighbours,G,G_tr->form,gtrbifo,515GSV,ming);516517free_mat(conj);518conj = NULL;519520if (anz_hneighbours == anz_gneighbours){521522if (INFO_LEVEL & 4){523printf("anz_hneighbours %d\n",anz_hneighbours);524for (j=0;j<=anz_hneighbours;j++){525put_mat(hneighbours[j],NULL,"hneighbours[j]",2);526put_mat(gneighbours[j],NULL,"gneighbours[j]",2);527}528}529530conj = extends_to_isometry(hneighbours,HSV,531anz_hneighbours+1,gneighbours,GSV,532anz_gneighbours+1,H->form_no,1);533534535}536/* cleaning up memory */537for (j=0;j<anz_gneighbours;j++){538free_mat(gneighbours[j+1]);539}540free(gneighbours);541542}543544free_mat(GSV);545i++;546}547548/* clean up memory used only here */549free_mat(id);550free_mat(hperfect);551free_mat(gperfect);552free_mat(HSV);553for (i=0;i<anz_gperfect;i++){554clear_voronoi(gp[i]);555free(gp[i]);556}557free(gp);558for (i=0;i<anz_hneighbours;i++){559free_mat(hneighbours[i+1]);560}561free(hneighbours);562563}564else{565/* the groups are not conjugated, so clean up the memory used566so far and return NULL */567if (INFO_LEVEL & 4){568put_mat(tmp,NULL,"tmp",2);569put_mat(tmp2,NULL,"tmp2",2);570fprintf(stderr,571"The groups are not conjugated: elementary divisors\n");572}573free_mat(tmp);574free_mat(tmp2);575conj = NULL;576}577578/* clean up memory used only in this stage */579free_mat(gtrbifo);580free_mat(htrbifo);581}582583/* retransform H, H_tr to the original value, and fiddle around with584conj a bit */585if (h_pair != NULL){586tmp = long_mat_inv(h_pair);587transform_pair(H,H_tr,tmp);588if (conj != NULL){589mat_muleq(conj,h_pair);590}591free_mat(tmp);592free_mat(h_pair);593}594595/* we will return the transposed matrix if there was one at all */596if (conj != NULL){597tmp = tr_pose(conj);598free_mat(conj);599conj = tmp;600}601602return conj;603}604605606