GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it
#include "typedef.h"1#include "gmp.h"2/* #include "gmp-impl.h" */3#include "longtools.h"4#include "matrix.h"5/**************************************************************************\6@---------------------------------------------------------------------------7@---------------------------------------------------------------------------8@ FILE: long_elt.c9@---------------------------------------------------------------------------10@---------------------------------------------------------------------------11@12\**************************************************************************/131415161718/**************************************************************************\19@---------------------------------------------------------------------------20@ matrix_TYP *long_elt_mat(left_trans, Mat, right_trans)21@ matrix_TYP *Mat, *left_trans, *right_trans;22@23@ calculates the elementary divisors of the matrix Mat, t.m.24@ calculates a 'diagonal' matrix D in Gl_n(Z) such that25@ L * Mat * R = D for some matrices L and R26@ 'left_trans' has to be a matrix of size Mat->rows x Mat->rows27@ it is changed to L * left_trans.28@ It is possible to start the function with left_trans = NULL.29@ 'right_trans' has to be a matrix of size Mat->cols x Mat->cols30@ it is changed to right_trans * R.31@ It is possible to start the function with right_trans = NULL.32@33@ The calculations are done using multiple precision integers.34@---------------------------------------------------------------------------35@36\**************************************************************************/37matrix_TYP *long_elt_mat(left_trans, Mat, right_trans)38matrix_TYP *left_trans, *Mat, *right_trans;39{4041int i,j,k,l, m, step, stepclear, flag;42int cols, rows, rang;43MP_INT **trf, **M, **Mt, *merkpointer, **rtrf, *help, **hilf;44matrix_TYP *erg;45int t_option, r_t_option;46MP_INT a1, a2, x1, x2, y1, y2, merk, g, f, o, pos1, pos2;4748cols = Mat->cols;49rows = Mat->rows;50if(left_trans != NULL)51{52t_option = TRUE;53if(left_trans->cols != rows)54{55printf("error in 'long_elt_mat':\n");56printf("the matrix 'left_trans' has to be a %dx%d-matrix, but has %d columns\n", rows, cols, left_trans->cols);57exit(3);58}59if(left_trans->cols != left_trans->rows)60{61printf("error: matrix 'left_trans' in 'long_elt_mat' has to be a square matrix\n");62exit(3);63}64}65else66t_option = FALSE;6768/* inserted the next 17 lines: oliver 2/3/1999 */69if(right_trans != NULL)70{71r_t_option = TRUE;72if(right_trans->rows != cols)73{74printf("error in 'long_elt_mat':\n");75printf("the matrix 'right_trans' has to be a %dx%d-matrix, but has %d rows\n", cols, cols, left_trans->rows);76exit(3);77}78if(left_trans->cols != left_trans->rows)79{80printf("error: matrix 'left_trans' in 'long_elt_mat' has to be a square matrix\n");81exit(3);82}83}84else85r_t_option = FALSE;8687mpz_init(&a1), mpz_init(&a2);88mpz_init(&x1), mpz_init(&x2);89mpz_init(&y1), mpz_init(&y2);90mpz_init(&f), mpz_init(&g); mpz_init(&o);91mpz_init(&merk); mpz_init(&pos1); mpz_init(&pos2);9293/***************************************************************\94| (inserted the next 33 lines: oliver 29/4/1999)95| Set hilf = right_trans^tr96\***************************************************************/97if(r_t_option == TRUE)98{99if((rtrf = (MP_INT **)malloc(cols *sizeof(MP_INT *))) == NULL)100{101printf("malloc of 'rtrf' in 'long_elt_mat' failed\n");102exit(2);103}104for(i=0;i<cols;i++)105{106if((rtrf[i] = (MP_INT *)malloc(cols *sizeof(MP_INT))) == NULL)107{108printf("malloc of 'rtrf[%d]' in 'long_elt_mat' failed\n", i);109exit(2);110}111}112if((hilf = (MP_INT **)malloc(cols *sizeof(MP_INT *))) == NULL)113{114printf("malloc of 'hilf' in 'long_elt_mat' failed\n");115exit(2);116}117for(i=0;i<cols;i++)118{119if((hilf[i] = (MP_INT *)malloc(cols *sizeof(MP_INT))) == NULL)120{121printf("malloc of 'hilf[%d]' in 'long_elt_mat' failed\n", i);122exit(2);123}124for(j=0;j<cols;j++)125{126mpz_init_set_si(&hilf[i][j], right_trans->array.SZ[j][i]);127}128}129}130131/***************************************************************\132| Set Mt= Mat^{tr} transform Mt to Hermite normal form.133\***************************************************************/134if((Mt = (MP_INT **)malloc(cols *sizeof(MP_INT *))) == NULL)135{136printf("malloc of 'Mt' in 'long_elt_mat' failed\n");137exit(2);138}139for(i=0;i<cols;i++)140{141if((Mt[i] = (MP_INT *)malloc(rows *sizeof(MP_INT))) == NULL)142{143printf("malloc of 'Mt[%d]' in 'long_elt_mat' failed\n", i);144exit(2);145}146for(j=0;j<rows;j++)147mpz_init_set_si(&Mt[i][j], Mat->array.SZ[j][i]);148}149150/* changed on 29/4/1999 oliver from151rang = MP_hnf(Mt, cols, rows);152to: */153if(r_t_option == TRUE)154{155rang = MP_hnf_simultaneous(Mt, cols, rows, hilf, cols);156}157else158rang = MP_hnf(Mt, cols, rows);159160/***************************************************************\161| Set trf = left_trans162\***************************************************************/163if(t_option == TRUE)164{165if((trf = (MP_INT **)malloc(rows *sizeof(MP_INT *))) == NULL)166{167printf("malloc of 'trf' in 'long_elt_mat' failed\n");168exit(2);169}170for(i=0;i<rows;i++)171{172if((trf[i] = (MP_INT *)malloc(rows *sizeof(MP_INT))) == NULL)173{174printf("malloc of 'trf[%d]' in 'long_elt_mat' failed\n", i);175exit(2);176}177for(j=0;j<rows;j++)178mpz_init_set_si(&trf[i][j], left_trans->array.SZ[i][j]);179}180}181182/***************************************************************\183| Set M= Mt^{tr} transform Mt to Hermite normal form.184\***************************************************************/185if((M = (MP_INT **)malloc(rows *sizeof(MP_INT *))) == NULL)186{187printf("malloc of 'M' in 'long_elt_mat' failed\n");188exit(2);189}190for(i=0;i<rows;i++)191{192if((M[i] = (MP_INT *)malloc(cols *sizeof(MP_INT))) == NULL)193{194printf("malloc of 'M[%d]' in 'long_elt_mat' failed\n", i);195exit(2);196}197for(j=0;j<cols;j++)198mpz_init_set(&M[i][j], &Mt[j][i]);199}200201/* the hnf produces big enties in the transformation matrix, there do202hnf only if the transformation matrix is not wanted203if(t_option == TRUE)204rang = MP_hnf_simultaneous(M, rows, cols, trf, rows);205else206rang = MP_hnf(M, rows, cols); */207if(t_option != TRUE)208rang = MP_hnf(M, rows, cols);209210/***************************************************************\211| Clear the space allocated for 'Mt'.212| Set rtrf = hilf^tr and free hilf.213\***************************************************************/214for(i=0;i<cols;i++)215{216for(j=0;j<rows;j++)217mpz_clear(&Mt[i][j]);218free(Mt[i]);219}220free(Mt);221222if (r_t_option){223for (i=0; i<cols; i++)224{225for(j=0; j<cols; j++)226{227mpz_init_set(&rtrf[j][i], &hilf[i][j]);228mpz_clear(&hilf[i][j]);229}230free(hilf[i]);231}232free(hilf);233}234/***************************************************************\235| Now the elementary divisor algorithm starts236\***************************************************************/237for(step = 0; step < rang; step++)238{239240do241{242/* output for debugging */243/* dump_MP_mat(M,rang,rang,"M"); */244245/*------------------------------------------------------*\246| Clear the 'step'^th row of M247\*------------------------------------------------------*/248for(i=step;i<cols && mpz_cmp_si(&M[step][i], 0) == 0; i++);249250if (i<cols){251if(i!=step)252{253for(j=step;j<rows;j++)254{255mpz_set(&merk, &M[j][step]);256mpz_set(&M[j][step], &M[j][i]);257mpz_set(&M[j][i], &merk);258}259260/* inserted the following 9 lines: oliver 29/4/99 */261if (r_t_option == TRUE)262{263for(j=0;j<cols;j++)264{265mpz_set(&merk, &rtrf[j][step]);266mpz_set(&rtrf[j][step], &rtrf[j][i]);267mpz_set(&rtrf[j][i], &merk);268}269}270}271272if(mpz_cmp_si(&M[step][step], 0) < 0)273{274for(i=step;i<rows;i++)275mpz_neg(&M[i][step], &M[i][step]);276/* inserted oliver 30/04/99 */277if (r_t_option == TRUE)278{279for(i=0;i<cols;i++)280mpz_neg(&rtrf[i][step], &rtrf[i][step]);281}282}283for(i=step+1;i<cols;i++)284{285if(mpz_cmp_si(&M[step][i], 0) != 0)286{287if(mpz_cmp_si(&M[step][step], 1) == 0)288{289mpz_set(&f, &M[step][i]);290for(j=step+1;j<rows;j++)291{292mpz_mul(&merk, &M[j][step], &f);293mpz_sub(&M[j][i], &M[j][i], &merk);294}295mpz_set_si(&M[step][i], 0);296297/* inserted the next 8 lines: oliver 2/3/99 */298if(r_t_option == TRUE)299{300for(j=0;j<cols;j++)301{302mpz_mul(&merk, &rtrf[j][step], &f);303mpz_sub(&rtrf[j][i], &rtrf[j][i], &merk);304}305}306}307else308{309/* changed 30/04/99 (tilman) from310mpz_gcdext(&g, &a1, &a2, &M[step][step], &M[step][i]); to */311mpz_abs( &g,&M[step][i]);312if (mpz_cmp(&M[step][step],&g) == 0){313mpz_set_si(&a1,1);314mpz_set_si(&a2,0);315}316else{317mpz_gcdext(&g, &a1, &a2, &M[step][step], &M[step][i]);318}319mpz_div(&x1, &M[step][i], &g);320mpz_div(&x2, &M[step][step], &g);321mpz_neg(&x2, &x2);322323for(j=step+1; j<rows;j++)324{325mpz_mul(&y1, &a1, &M[j][step]);326mpz_mul(&merk, &a2, &M[j][i]);327mpz_add(&y1, &y1, &merk);328329mpz_mul(&y2, &x1, &M[j][step]);330mpz_mul(&merk, &x2, &M[j][i]);331mpz_add(&y2, &y2, &merk);332333mpz_set(&M[j][step], &y1);334mpz_set(&M[j][i], &y2);335}336337/* inserted the next 16 lines: oliver 2/3/99 */338if(r_t_option == TRUE)339{340for(j=0; j<cols; j++)341{342mpz_mul(&y1, &a1, &rtrf[j][step]);343mpz_mul(&merk, &a2, &rtrf[j][i]);344mpz_add(&y1, &y1, &merk);345346mpz_mul(&y2, &x1, &rtrf[j][step]);347mpz_mul(&merk, &x2, &rtrf[j][i]);348mpz_add(&y2, &y2, &merk);349350mpz_set(&rtrf[j][step], &y1);351mpz_set(&rtrf[j][i], &y2);352}353}354355mpz_set(&M[step][step], &g);356mpz_set_si(&M[step][i], 0);357}358}359}360}361362/*------------------------------------------------------*\363| Clear the 'step'^th column of M364\*------------------------------------------------------*/365for(i=step;i<rows && mpz_cmp_si(&M[i][step], 0) == 0; i++);366if(i!=step)367{368merkpointer = M[step];369M[step] = M[i];370M[i] = merkpointer;371if(t_option == TRUE)372{373merkpointer = trf[step];374trf[step] = trf[i];375trf[i] = merkpointer;376}377}378if(mpz_cmp_si(&M[step][step], 0) < 0)379{380for(i=step;i<rows;i++)381mpz_neg(&M[i][step], &M[i][step]);382383/* inserted following 5 lines: 30/04/99 oliver */384if (r_t_option == TRUE)385{386for(i=0;i<cols;i++)387mpz_neg(&rtrf[i][step], &rtrf[i][step]);388}389}390for(i=step+1;i<rows;i++)391{392if(mpz_cmp_si(&M[i][step], 0) != 0)393{394if(mpz_cmp_si(&M[step][step], 1) == 0)395{396mpz_set(&f, &M[i][step]);397for(j=step+1;j<cols;j++)398{399mpz_mul(&merk, &M[step][j], &f);400mpz_sub(&M[i][j], &M[i][j], &merk);401}402mpz_set_si(&M[i][step], 0);403404/* inserted the next 7 lines: tilman 5/12/96 */405if (t_option){406for(j=0;j<rows;j++)407{408mpz_mul(&merk, &trf[step][j], &f);409mpz_sub(&trf[i][j], &trf[i][j], &merk);410}411}412413}414else415{416/* changed on 8/1/97 tilman from417mpz_gcdext(&g, &a1, &a2, &M[step][step], &M[i][step]);418to : */419mpz_abs( &g,&M[i][step]);420if (mpz_cmp(&M[step][step],&g) == 0){421mpz_set_si(&a1,1);422mpz_set_si(&a2,0);423}424else{425mpz_gcdext(&g, &a1, &a2, &M[step][step], &M[i][step]);426}427428mpz_div(&x1, &M[i][step], &g);429mpz_div(&x2, &M[step][step], &g);430mpz_neg(&x2, &x2);431432for(j=step+1; j<cols;j++)433{434mpz_mul(&y1, &a1, &M[step][j]);435mpz_mul(&merk, &a2, &M[i][j]);436mpz_add(&y1, &y1, &merk);437438mpz_mul(&y2, &x1, &M[step][j]);439mpz_mul(&merk, &x2, &M[i][j]);440mpz_add(&y2, &y2, &merk);441442mpz_set(&M[step][j], &y1);443mpz_set(&M[i][j], &y2);444}445446/* inserted the next 15 lines: tilman 5/12/96 */447if (t_option){448for(j=0; j<rows;j++)449{450mpz_mul(&y1, &a1, &trf[step][j]);451mpz_mul(&merk, &a2, &trf[i][j]);452mpz_add(&y1, &y1, &merk);453454mpz_mul(&y2, &x1, &trf[step][j]);455mpz_mul(&merk, &x2, &trf[i][j]);456mpz_add(&y2, &y2, &merk);457458mpz_set(&trf[step][j], &y1);459mpz_set(&trf[i][j], &y2);460}461}462463mpz_set(&M[step][step], &g);464mpz_set_si(&M[i][step], 0);465}466}467}468/*------------------------------------------------------*\469| Check whether the column and row are both clear470\*------------------------------------------------------*/471stepclear = TRUE;472for(i=step+1;i<cols && stepclear == TRUE;i++)473{474if(mpz_cmp_si(&M[step][i], 0) != 0)475stepclear = FALSE;476}477for(i=step+1;i<rows && stepclear == TRUE;i++)478{479if(mpz_cmp_si(&M[i][step], 0) != 0)480stepclear = FALSE;481}482}while(stepclear == FALSE);483if(mpz_cmp_si(&M[step][step], 0) < 0)484{485mpz_neg(&M[step][step], &M[step][step]);486487/* inserted next 6 lines: oliver 2/5/99 */488if (r_t_option == TRUE)489{490for(i=0;i<cols;i++)491mpz_neg(&rtrf[i][step], &rtrf[i][step]);492}493}494}495496/*******************************************************************\497| Now M is diagonal.498| Now one has transform M such that M[i][i] divides M[i+1][i+1]499\*******************************************************************/500for(step = 0;step < rang; step ++)501{502/*******************************************************************\503| Search for the minimal entry of M[step][step],...,M[rang][rang]504| and swap it to M[step][step]505\*******************************************************************/506j = step;507for(i=step+1; i<rang;i++)508{509if(mpz_cmp(&M[i][i], &M[j][j]) < 0)510j = i;511}512if(j != step)513{514mpz_set(&merk, &M[step][step]);515mpz_set(&M[step][step], &M[j][j]);516mpz_set(&M[j][j], &merk);517if(t_option != 0)518{519merkpointer = trf[step];520trf[step] = trf[j];521trf[j] = merkpointer;522}523524/* inserted following 6 lines: oliver 30/4/1999 */525if(r_t_option != 0)526{527for(m=0;m<cols;m++)528{529mpz_set(&merk, &rtrf[m][step]);530mpz_set(&rtrf[m][step], &rtrf[m][j]);531mpz_set(&rtrf[m][j], &merk);532}533}534}535for(i=step+1;i<rang;i++)536{537mpz_mod(&merk, &M[i][i], &M[step][step]);538539/*changed the following if else: 2/3/1999 oliver */540if(mpz_cmp_si(&merk, 0) != 0)541{542if(t_option == TRUE || r_t_option == TRUE)543{544mpz_gcdext(&g, &a1, &a2, &M[step][step], &M[i][i]);545if(t_option == TRUE)546{547for(j=0;j<rows;j++)548mpz_add(&trf[step][j], &trf[step][j], &trf[i][j]);549550mpz_div(&f, &M[i][i], &g);551mpz_mul(&f, &f, &a2);552for(j=0;j<rows;j++)553{554mpz_mul(&merk, &f, &trf[step][j]);555mpz_sub(&trf[i][j], &trf[i][j], &merk);556}557558}559if(r_t_option == TRUE)560{561if((help = (MP_INT *)malloc(cols *sizeof(MP_INT))) == NULL)562{563printf("malloc of 'help' in 'long_elt_mat' failed\n");564exit(2);565}566for(j=0;j<cols;j++)567{568mpz_init_set(&help[j], &rtrf[j][step]);569mpz_mul(&rtrf[j][step],&rtrf[j][step],&a1);570mpz_mul(&merk, &rtrf[j][i], &a2);571mpz_add(&rtrf[j][step], &rtrf[j][step], &merk);572}573mpz_div(&o, &M[step][step], &g );574mpz_div(&f, &M[i][i], &g);575for(j=0;j<cols;j++)576{577mpz_mul(&merk, &f, &help[j]);578mpz_clear(&help[j]);579mpz_mul(&rtrf[j][i], &rtrf[j][i], &o);580mpz_sub(&rtrf[j][i], &rtrf[j][i], &merk);581}582free(help);583}584mpz_div(&merk, &M[i][i], &g);585mpz_mul(&M[i][i], &merk, &M[step][step]);586587/* changed 28/2/97 tilman from588mpz_div(&M[step][step], &M[step][step], &g);589to: */590mpz_set(&M[step][step],&g);591}592else593{594mpz_gcd(&g, &M[step][step], &M[i][i]);595mpz_div(&merk, &M[i][i], &g);596mpz_mul(&M[i][i], &merk, &M[step][step]);597598/* changed 28/2/97 tilman from599mpz_div(&M[step][step], &M[step][step], &g);600to: */601mpz_set(&M[step][step],&g);602}603}604}605}606607if (0) dump_MP_mat(NULL,0,0,NULL);608609erg = MP_mat_to_matrix(M, rows, cols);610611if(t_option == TRUE)612{613for(i=0;i<rows;i++)614for(j=0;j<rows;j++)615{616if(abs(trf[i][j]._mp_size) > 1)617{618printf("Error: Integer overflow in 'long_mat_elt'\n");619exit(3);620}621left_trans->array.SZ[i][j] = mpz_get_si(&trf[i][j]);622}623}624/* inserted following "if": oliver 2/3/1999 */625if(r_t_option == TRUE)626{627for(i=0;i<cols;i++)628{629for(j=0;j<cols;j++)630{631if(abs(rtrf[i][j]._mp_size) > 1)632{633printf("Error: Integer overflow in 'long_mat_elt'\n");634exit(3);635}636right_trans->array.SZ[i][j] = mpz_get_si(&rtrf[i][j]);637mpz_clear(&rtrf[i][j]);638}639free(rtrf[i]);640}641}642643for(i=0;i<rows;i++)644{645if(t_option == TRUE)646{647for(j=0;j<rows;j++)648mpz_clear(&trf[i][j]);649free(trf[i]);650}651for(j=0;j<cols;j++)652mpz_clear(&M[i][j]);653free(M[i]);654}655free(M);656if(t_option == TRUE)657free(trf);658if(r_t_option == TRUE)659free(rtrf);660merkpointer = NULL;661mpz_clear(&a1), mpz_clear(&a2);662mpz_clear(&x1), mpz_clear(&x2);663mpz_clear(&y1), mpz_clear(&y2);664mpz_clear(&f), mpz_clear(&g); mpz_clear(&o);665mpz_clear(&merk); mpz_clear(&pos1); mpz_clear(&pos2);666Check_mat(erg);667if(t_option == TRUE)668Check_mat(left_trans);669if(r_t_option == TRUE)670Check_mat(right_trans);671672/*inserted next 2 lines: oliver 16/3/99 */673erg->kgv = Mat->kgv;674Check_mat(erg);675676677return(erg);678}679680681682