GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it
/***************************************************************************1@2@ --------------------------------------------------------------------------3@4@ FILE: base2.c5@6@ some algorithms connected with the schreier-sims algorithm are collected.7@ in contrast to the functions in base.c these functions operate mod 2,8@ so these functions are able to calculate the kernel of the minkowski9@ homomorphism as well.10@11@ --------------------------------------------------------------------------12@13****************************************************************************/1415#include <typedef.h>16#include <longtools.h>17#include <orbit.h>18#include <getput.h>19#include <matrix.h>20#include <sort.h>21#include <base.h>2223extern int INFO_LEVEL;2425/***************************************************************************26@27@ --------------------------------------------------------------------------28@29@ int einordnen_2(bahn** erg,matrix_TYP *h, matrix_TYP *new_vec,int l,30@ int flag, matrix_TYP ***K,int *anz)31@32@ bahn **erg : the set of base/strong generators (mod 2) for a33@ (possibly infinite) group G. this variable will34@ be changed!35@ matrix_TYP *h :36@ matrix_TYP *new_vec : this value is not asked for in the case37@ described here, so any variable with the right38@ type will do.39@ int l : -1 ALLWAYS40@ int flag : TRUE ALLWAYS!!!!!41@ matrix_TYP ***K : this list of matrices might already contain42@ generators for the kernel of the minkowski43@ homomorphism. All newly found generators44@ will be stucked in K[0][anz[0]],K[0][anz[0]+1]..45@ and anz[0] will be changed accordingly.46@ int *anz[0] : see above47@48@ Inserts a new generator h into the list of strong generators (mod 2) for49@ any (possible infinite) group G.50@ The function calls itself recursively, and therefore the convention to51@ use it is somewhat cryptical. In all cases for the 'end user' l has to52@ be -1, and flag has to be TRUE (no garanties otherwise).53@ THE FUNCTION DOES NOT COPY THE VARIABLE h INTO erg[0]->generators,54@ (IT JUST STORES THE POINTER THERE), THEREFORE THE USER IS ASKED TO55@ ASSURE THAT h STAY'S IN THE SAME PLACE WHILE USING erg !!!!!!!!!!56@ The function does not check whether the new generator h is really needed,57@ so better check is out before calling this function by a call of is_element!58@ --------------------------------------------------------------------------59@60***************************************************************************/61int einordnen_2(bahn** erg,matrix_TYP *h, matrix_TYP *new_vec,int l,62int flag,matrix_TYP ***K,int *anz)63{64int tmp = erg[0]->representatives[0]->cols,65tmp2,66i,67finite_flag = TRUE;6869matrix_TYP *hinv,70*nv,71*nh;7273if (INFO_LEVEL & 2){74fprintf(stderr,"entering einordnen_2 with l = %d\n",l);75}7677if (l>=tmp){78/* this is the stage to memorize the kernel of79the minkowski homomorphism */80for (l=0;l<anz[0] && mat_comp(K[0][l],h) != 0;l++);8182if (anz[0] == 0 || l == anz[0]){83/* get more memory if needed */84if (anz[0]>0 && (anz[0] % MIN_SPEICHER) == 0){85K[0] = (matrix_TYP **) realloc(K[0],86(anz[0]+MIN_SPEICHER)*sizeof(matrix_TYP *));87}88K[0][anz[0]] = h;89anz[0]++;9091/* check if the group stay's finite */92/* the new generator should be of order 1 or 2 */93nh = mat_mul(K[0][anz[0]-1],K[0][anz[0]-1]);94Check_mat(nh);95if (!nh->flags.Symmetric ||96!nh->flags.Diagonal ||97nh->array.SZ[0][0] != 1){98finite_flag = FALSE;99}100free_mat(nh);101102/* the new generator should commute with all the other generators.103(it suffices to check only those which have smaller index)104(bare in mind that all of these have order at most 2) */105for (i=0;i<anz[0]-1 && finite_flag;i++){106nh = mat_kon(K[0][anz[0]-1],K[0][i],K[0][anz[0]-1]);107if (mat_comp(nh,K[0][i]) != 0){108finite_flag = FALSE;109}110free_mat(nh);111}112113if (finite_flag == FALSE){114return -1;115}116117}118else{119free_mat(h);120}121122return FALSE;123}124else{125126if (l!=(-1)){127tmp2 = hash_mat(erg[l]->hash,erg[l]->orbit,new_vec,erg[l]->length);128}129else{130tmp2 = (-1);131}132133if (tmp2!= (-1)){134/* we got an element of the stabilizer, */135/* calculate it then! */136free_mat(new_vec);137138if (mat_comp(h,erg[l]->representatives[tmp2])!=0){139/* hinv = mat_inv(h);140mat_muleq(hinv,erg[l]->representatives[tmp2]);141free_mat(h);142h = hinv; */143hinv = mat_mul(erg[l]->rep_invs[tmp2],h);144free_mat(h);145h = hinv;146if (l+1 < tmp){147new_vec = mat_mul(h,erg[l+1]->orbit[0]);148modp_mat(new_vec,2);149}150}151else{152/* only clean up memory */153free_mat(h);154return FALSE;155}156157/* enter the next stage */158flag = einordnen_2(erg,h,new_vec,++l,TRUE,K,anz);159}160else{161if (l != (-1)){162if (erg[l]->speicher<=erg[l]->length){163extend_bahn(erg+l);164}165erg[l]->orbit[erg[l]->length]=new_vec;166erg[l]->representatives[erg[l]->length]=h;167/* inserted to reduce the number of mat_inv's */168erg[l]->rep_invs[erg[l]->length] = mat_inv(h);169erg[l]->length++;170171if (INFO_LEVEL & 1){172fprintf(stderr,"l = %d, lenght in this stage %d\n"173,l,erg[l]->length);174}175}176177if (flag){178179if (l == (-1)) l =0;180181/* firstly put this element on the generator list */182erg[l]->generators[erg[l]->gen_no] = h;183erg[l]->gen_no++;184185}186187}188}189190if (flag == (-1)){191return (-1);192}193194if (flag){195/* do a new orbit-calculation */196/* apply all generators to the previous orbit elements */197for(tmp=0;tmp<erg[l]->length;tmp++){198for (tmp2=l;tmp2<erg[0]->representatives[0]->cols;tmp2++){199for (i=erg[tmp2]->gen_no-1;i>=0;i--){200h = erg[tmp2]->generators[i];201nv = mat_mul(h,erg[l]->orbit[tmp]);202modp_mat(nv,2);203nh = mat_mul(h,erg[l]->representatives[tmp]);204if (einordnen_2(erg,nh,nv,l,FALSE,K,anz) == -1){205return -1;206}207}208}209}210}211212return flag;213} /* einordnen_2(..........) */214215/***********************************************************************216@217@-----------------------------------------------------------------------218@219@ int strong_generators_2(matrix_TYP **base,bravais_TYP *U,220@ matrix_TYP ***K,int *anz,MP_INT *mp)221@222@ This function decides whether or not the integral group generated223@ by the matrices in U->gen[i], 0<= i< U->gen_no, is finite.224@ If so, it will return TRUE and the order of the group via the multiple225@ precision integer mp. Otherwise the function will return FALSE immediately226@ if infiniteness can be proven.227@ In the case the given group is finite it will return a generating set228@ for the kernel of the Minkowski homomorphim (g -> g mod 2) via K,229@ and the number of matrices via anz[0].230@ In case the function proves the group to be infinite, it will return231@ at least one element in K, which proves the group to ge infinite.232@233@ matrix_TYP **base: a set of U->dim integral column vectors. there are234@ two conditions to these vectors, which are not checked:235@ 1. the vectors entries 0,1 only,236@ 2. the vectors form a basis of Z^U->dim/(2Z)^U->dim.237@ bravais_TYP *U : the group in question. It is in no way changed.238@ matrix_TYP ***K : the function returns elements of the minkowski kernel239@ via this pointer.240@ int *anz : anz[0] is the number of returned elements in K241@ MP_INT *mp : a multiple precesion integer. Call the function with242@ strong_generators_2(....,&x) for an MP_INT x, which243@ has been initialized via mpz_init(&x) before.244@245@ SIDEEFECT: none are known.246@-----------------------------------------------------------------------247@248************************************************************************/249int strong_generators_2(matrix_TYP **base,bravais_TYP *U,250matrix_TYP ***K,int *anz,MP_INT *mp)251{252bahn **erg;253254int i,255j,256k,257m,258old_anz,259dim = U->dim,260finite_flag, /* indicates whether the kernel K stays finite */261opt[6]; /* options for orbit_alg */262263bravais_TYP G;264265matrix_TYP **gen=U->gen,266**con,267*new_vec,268*g,269*h,270*tmp;271272273/* geting the memory for the result */274erg = (bahn **) calloc(dim,sizeof(bahn *));275for (i=0;i<dim;i++){276erg[i] = (bahn *) calloc(1,sizeof(bahn));277init_bahn(erg[i]);278}279280/* initialise the minkowski kernel: to avoid trouble 1 is allways281a generator */282K[0] = (matrix_TYP **) malloc(MIN_SPEICHER*sizeof(matrix_TYP *));283anz[0] = 0;284finite_flag = TRUE;285286for (i=0;i<dim;i++){287erg[i]->representatives[0] = init_mat(U->dim,U->dim,"1");288erg[i]->rep_invs[0] = init_mat(U->dim,U->dim,"1");289erg[i]->orbit[0] = copy_mat(base[i]);290erg[i]->length = 1;291erg[i]->hash->no = 0;292}293294/* doing the orbit-calculation */295for (j=0;j<erg[0]->length && finite_flag;j++){296for (k=0;k<U->gen_no && finite_flag;k++){297298if (INFO_LEVEL & 4){299/* printing all results for debugging */300for (i=0;i<dim;i++){301for (m=0;m<erg[i]->length;m++){302printf("i=%d m=%d\n",i,m);303if (erg[i]->representatives[m]->rows != dim ||304erg[i]->orbit[m]->rows != dim){305printf("fehler in strong_generators_2\n");306exit(3);307}308put_mat(erg[i]->representatives[m],NULL,"represe",2);309put_mat(erg[i]->orbit[m],NULL,"orbit",2);310}311}312}313314/* decide which group element will act */315g=gen[k];316317if (INFO_LEVEL & 4 ){318put_mat(g,NULL,"angewandter erzeuger",2);319}320321h = mat_mul(g,erg[0]->representatives[j]);322new_vec = mat_mul(g,erg[0]->orbit[j]);323modp_mat(new_vec,2);324325old_anz = anz[0];326if (einordnen_2(erg,h,new_vec,0,FALSE,K,anz) == -1){327finite_flag = FALSE;328}329330/* we got new generators for the kernel, so see331whether we can prove the group to be infinite332for (i=old_anz;i<anz[0] && finite_flag;i++){ */333334/* the new generator should be of order 1 or 2335tmp = mat_mul(K[0][i],K[0][i]);336Check_mat(tmp);337if (!tmp->flags.Symmetric ||338!tmp->flags.Diagonal ||339tmp->array.SZ[0][0] != 1){340finite_flag = FALSE;341}342free_mat(tmp); */343344/* the new generator should commute with all the other generators.345(it suffices to check only those which have smaller index)346(bare in mind that all of these have order at most 2)347for (m=0;m<i && finite_flag;m++){348tmp = mat_kon(K[0][i],K[0][m],K[0][i]);349if (mat_comp(tmp,K[0][m]) != 0){350finite_flag = FALSE;351}352free_mat(tmp);353}354} */355}356}357358/* if the kernel K is trivial, we won't have generators at all,359which causes trouble afterwards */360if (anz[0] == 0){361anz[0] = 1;362K[0][0] = init_mat(U->dim,U->dim,"1");363}364365/* this is the time to calculate the order of the group modulo366the minkowski kernel */367mpz_set_si(mp,1);368for (i=0;i<dim;i++){369mpz_mul_ui(mp,mp,(unsigned long) erg[i]->length);370}371372/* bare in mind to free erg, which sounds crazy but is this373way because the function was used in a different way before */374for (i=0;i<dim;i++){375free_bahn(erg[i]);376free(erg[i]);377}378free(erg);379380/* we now decided whether nor not the group is finite,381because if we still got the finite_flag, the kernel K382is finitely generated, abelian, of exponent 2.383bare in mind that we only got an generating system for384K which generates K as normal subgroup of U */385opt[0] = 4; opt[2] = 1; opt[1] = opt[3] = opt[4] = opt[5] = 0;386for (i=0;i<dim;i++) opt[2] *= 2;387if (finite_flag){388/* make the normal closure */389old_anz = anz[0];390for (i=0;i<old_anz && finite_flag;i++){391con = orbit_alg(K[0][i],U,NULL,opt,&k);392for (j=0;j<k;j++){393for (m=0;m<anz[0] && mat_comp(K[0][m],con[j]) != 0;m++);394if (m==anz[0]){395if ((anz[0] % MIN_SPEICHER == 0) && anz[0] != 0)396K[0] = (matrix_TYP **) realloc(K[0],397(anz[0]+MIN_SPEICHER) * sizeof(matrix_TYP *));398K[0][anz[0]] = con[j];399Check_mat(K[0][anz[0]]);400/* look whether it stays finite */401if (finite_flag){402/* the new generator is of order 1 or 2 because it's403a conjugate of such an element, and the new generator404should commute with all the other generators. */405for (m=0;m<anz[0] && finite_flag;m++){406tmp = mat_kon(K[0][anz[0]],K[0][m],K[0][anz[0]]);407if (mat_comp(tmp,K[0][m]) != 0){408finite_flag = FALSE;409}410free_mat(tmp);411}412}413anz[0]++;414}415else{416free_mat(con[j]);417}418419}420free(con);421}422}423424/* the finite_flag might be changed since we last checked it */425if (finite_flag){426erg = NULL;427G.gen = K[0];428G.gen_no = anz[0];429G.dim = dim;430i = red_gen(&G,base,&erg,0);431anz[0] = G.gen_no;432K[0] = G.gen;433mpz_mul_ui(mp,mp,(unsigned long) i);434for (i=0;i<dim;i++){435free_bahn(erg[i]);436free(erg[i]);437}438free(erg);439}440441return finite_flag;442} /* strong_generators_2 */443444445