GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it
#include "typedef.h"1#include "tools.h"2#include "matrix.h"3#include "longtools.h"456/**************************************************************************\7@---------------------------------------------------------------------------8@---------------------------------------------------------------------------9@ FILE: inv_mat.c10@---------------------------------------------------------------------------11@---------------------------------------------------------------------------12@13\**************************************************************************/14/*{{{}}}*/15/*{{{ rmat_inv */16/*17* result = rmat_inv( mat );18*19* berechnet Inverse zu eine Nennermatrix. Das "r" steht fuer rational20*21* matrix_TYP *result: Inverse zu mat, wird erzeugt22* matrix_TYP *mat: wird nicht veraendert23*/24static matrix_TYP *rmat_inv ( mat )25matrix_TYP *mat;26{27rational **M, **II, *v, f ;28int n, i, j, k ,l , flag;29int *nuin_M, *nuin_I;30int kgv, h;31matrix_TYP *inv;3233flag =34kgv =35h = 0;36f = Zero;37n = mat->cols;38nuin_M = (int *)calloc((n+1),sizeof(int));39nuin_I = (int *)calloc((n+1),sizeof(int));4041/*42* create rational version II of identity matrix43*/44/*{{{ */45II = ( rational ** )malloc2dim( n, n, sizeof(rational) );46memset2dim( (char ** )II, n, n, sizeof(rational), (char *)&Zero );47for(i = 0; i < n; i++) {48II[i][i] = One;49}50/*}}} */51/*52* create rational version M of matrix mat53*/54/*{{{ */55M = (rational **)malloc2dim( n, n, sizeof(rational) );56for ( i = 0; i < n; i ++) {57for ( j = 0; j < n; j ++) {58M[i][j].z = mat->array.SZ[i][j];59M[i][j].n = mat->array.N[i][j];60}61}62/*}}} */63/*64* Invert M by paralell transformation of M and II s.t M is unit65*/6667/*68* first create triangular matrix69*/70/*{{{ */71for (i = 0; i < n; i++) {72if ( M[i][i].z == 0 ) {73/*74* Swap a non-zero element into [i][i]-position75*/76/*{{{ */77for (j = i+1; j < n && M[j][i].z == 0; j++ );78if ( j == n ) {79fprintf (stderr, "matrix is singular. Can't invert\n");80exit (3);81}82v = M[i]; M[i] = M[j]; M[j] = v;83v = II[i]; II[i] = II[j]; II[j] = v;84/*}}} */85}86/*87* Find the non-zero entries in i-th row in M and II88* 17.02.92, stored in var "f"89*/90/*{{{ */91nuin_M[0] =92nuin_I[0] = 1;93for(k = 0; k < n; k++) {94if ( M[i][k].z != 0) nuin_M[nuin_M[0]++] = k;95if (II[i][k].z != 0) nuin_I[nuin_I[0]++] = k;96}97f.z= M[i][i].z;98f.n= M[i][i].n;99/*}}} */100if ( (f.z != 1) || (f.n != 1) ) {101/*102* Normalize i-th row s.t. [i][i]-element is 1103*/104/*{{{ */105for (k = nuin_M[1], l = 1; l < nuin_M[0]; k=nuin_M[++l]) {106M[i][k].z *= f.n;107M[i][k].n *= f.z;108Normal (&M[i][k]);109}110for (k = nuin_I[1], l = 1; l < nuin_I[0]; k=nuin_I[++l]) {111II[i][k].z *= f.n;112II[i][k].n *= f.z;113Normal (&II[i][k]);114}115/*}}} */116}117/*118* Clear i-th column downwards119*/120/*{{{ */121for ( j = i+1; j < n; j++) {122if ( M[j][i].z != 0 ) {123f.z = M[j][i].z;124f.n = M[j][i].n;125for (k = nuin_M[1], l = 1; l < nuin_M[0]; k = nuin_M[++l]) {126if(M[j][k].z != 0) {127h= f.n * M[i][k].n;128M[j][k].z *= h;129M[j][k].z -= M[j][k].n * M[i][k].z * f.z;130M[j][k].n *= h;131} else {132M[j][k].z= - M[i][k].z * f.z;133M[j][k].n = M[i][k].n * f.n;134}135Normal (&M[j][k]);136}137for (k = nuin_I[1], l = 1; l < nuin_I[0]; k = nuin_I[++l]) {138if(II[j][k].z != 0) {139h= f.n * II[i][k].n;140II[j][k].z *= h;141II[j][k].z -= II[j][k].n * II[i][k].z * f.z;142II[j][k].n *= h;143} else {144II[j][k].z = - II[i][k].z*f.z;145II[j][k].n = II[i][k].n * f.n;146}147Normal (&II[j][k]);148}149}150}151/*}}} */152} /* M is now triangular */153/*}}} */154/*155* Clear columns upwards156*/157/*{{{ */158for (i = n-1; i >= 0; i --) {159nuin_I[0] = 1;160for ( k = 0; k < n; k++) {161if (II[i][k].z != 0) nuin_I[nuin_I[0]++] = k;162}163for ( j = i-1; j >= 0; j--) {164if ( M[j][i].z != 0 ) {165for (k = nuin_I[1], l = 1; l < nuin_I[0]; k = nuin_I[++l]) {166h= M[j][i].n* II[i][k].n;167II[j][k].z *= h;168II[j][k].z -= M[j][i].z * II[j][k].n * II[i][k].z;169II[j][k].n *= h;170Normal (&II[j][k]);171}172}173}174}175/*}}} */176/*177* copy M to result matrix "inv"178*179*/180inv = init_mat(n,n,"r");181for ( i = 0; i < n ; i++) {182for ( j = 0; j < n; j++) {183inv->array.SZ[i][j] = II[i][j].z;184inv->array.N [i][j] = II[i][j].n;185}186}187free2dim( (char **)M, n );188free2dim( (char **)II, n );189free(nuin_M);190free(nuin_I);191192Check_mat( inv );193194return ( inv );195}196197/*}}} */198#ifdef __OLD__199/*{{{ imat_inv */200static matrix_TYP *imat_inv (mat)201matrix_TYP *mat;202{203rational **M, **II, *v, f ;204int n, i, j, k ,l , flag;205int *nuin_M, *nuin_I;206int kgv, h, waste ;207matrix_TYP *inv;208209flag =210kgv =211h =212waste = 0;213f = Zero;214n = mat->cols;215nuin_M = (int *)calloc((n+1),sizeof(int),"imat_inv:nuin_M");216nuin_I = (int *)calloc((n+1),sizeof(int),"imat_inv:nuin_I");217218/*219* create rational version II of identity matrix220*/221/*{{{ */222II = (rational **)malloc(n*sizeof(rational *),"imat_inv:II");223II[0] = (rational *)malloc(n*sizeof(rational),"imat_inv:II[0]");224for (i = 0; i < n; i++) {225II[0][i] = Zero;226}227for(i = 1; i < n; i++) {228II[i] = (rational *)malloc(n*sizeof(rational),"imat_inv:II[i]");229memcpy(II[i],II[0],n*sizeof(rational));230II[i][i] = One;231}232II[0][0] = One;233234/*}}} */235/*236* create rational version M of matrix mat237*/238/*{{{ */239M = (rational **)malloc(n*sizeof(rational *),"imat_inv:M");240if(mat->flags.Integral) {241for ( i = 0; i < n; i ++) {242M[i] = (rational *)malloc(n*sizeof(rational),"imat_inv:M[i]");243for ( j = 0; j < n; j ++) {244M[i][j].z = mat->array.SZ[i][j];245M[i][j].n = 1;246}247}248} else {249for ( i = 0; i < n; i ++) {250M[i] = (rational *)malloc(n*sizeof(rational),"imat_inv:M[i]");251for ( j = 0; j < n; j ++) {252M[i][j].z = mat->array.SZ[i][j];253if ( M[i][j].z == 0 ) {254M[i][j].n = 1;255} else {256M[i][j].n = mat->kgv;257if ( abs(M[i][j].z) > 1) {258Normal(&M[i][j]);259}260}261}262}263}264/*}}} */265/*266* Invert M by paralell transformation of M and II s.t M is unit267*/268269/*270* first create triangular matrix271*/272/*{{{ */273for (i = 0; i < n; i++) {274if ( M[i][i].z == 0 ) {275/*276* Swap a non-zero element into [i][i]-position277*/278/*{{{ */279for (j = i+1; j < n && M[j][i].z != 0; j++ );280if ( j == n ) {281fprintf (stderr, "matrix is singular. Can't invert\n");282exit (3);283}284v = M[i]; M[i] = M[j]; M[j] = v;285v = II[i]; II[i] = II[j]; II[j] = v;286/*}}} */287}288/*289* Find the non-zero entries in i-th row in M and II290* 17.02.92, stored in var "f"291*/292/*{{{ */293nuin_M[0] =294nuin_I[0] = 1;295for(k = 0; k < n; k++) {296if ( M[i][k].z != 0) nuin_M[nuin_M[0]++] = k;297if (II[i][k].z != 0) nuin_I[nuin_I[0]++] = k;298}299f.z= M[i][i].z;300f.n= M[i][i].n;301/*}}} */302if ( (f.z != 1) || (f.n != 1) ) {303/*304* Normalize i-th row s.t. [i][i]-element is 1305*/306/*{{{ */307for (k = nuin_M[1], l = 1; l < nuin_M[0]; k=nuin_M[++l]) {308M[i][k].z *= f.n;309M[i][k].n *= f.z;310Normal (&M[i][k]);311}312for (k = nuin_I[1], l = 1; l < nuin_I[0]; k=nuin_I[++l]) {313II[i][k].z *= f.n;314II[i][k].n *= f.z;315Normal (&II[i][k]);316}317/*}}} */318}319/*320* Clear i-th column downwards321*/322/*{{{ */323for ( j = i+1; j < n; j++) {324if ( M[j][i].z != 0 ) {325f.z = M[j][i].z;326f.n = M[j][i].n;327for (k = nuin_M[1], l = 1; l < nuin_M[0]; k = nuin_M[++l]) {328if(M[j][k].z != 0) {329h= f.n * M[i][k].n;330M[j][k].z *= h;331M[j][k].z -= M[j][k].n * M[i][k].z * f.z;332M[j][k].n *= h;333} else {334M[j][k].z= - M[i][k].z * f.z;335M[j][k].n = M[i][k].n * f.n;336}337Normal (&M[j][k]);338}339for (k = nuin_I[1], l = 1; l < nuin_I[0]; k = nuin_I[++l]) {340if(II[j][k].z != 0) {341h= f.n * II[i][k].n;342II[j][k].z *= h;343II[j][k].z -= II[j][k].n * II[i][k].z * f.z;344II[j][k].n *= h;345} else {346II[j][k].z = - II[i][k].z*f.z;347II[j][k].n = II[i][k].n * f.n;348}349Normal (&II[j][k]);350}351}352}353/*}}} */354} /* end of inversion loop */355/*}}} */356/*357* Clear columns upwards and calculate lcm of denominators358*/359kgv= II[n-1][0].n;360for (i = n-1; i >= 0; i --) {361nuin_I[0] = 1;362for ( k = 0; k < n; k++) {363kgv = kgv / GGT(kgv, II[i][k].n) * II[i][k].n;364if (II[i][k].z != 0) nuin_I[nuin_I[0]++] = k;365}366for ( j = i-1; j >= 0; j--) {367if ( M[j][i].z != 0 ) {368for (k = nuin_I[1], l = 1; l < nuin_I[0]; k = nuin_I[++l]) {369h= M[j][i].n* II[i][k].n;370II[j][k].z *= h;371II[j][k].z -= M[j][i].z * II[j][k].n * II[i][k].z;372II[j][k].n *= h;373Normal (&II[j][k]);374}375}376}377}378379inv = init_mat(n,n,"ik");380/*------------------------------------------------------------*\381| Normalize all entries to the form II[i][j].z / kgv |382| and copy into inv->array.SZ |383\*------------------------------------------------------------*/384for ( i = 0; i < n ; i++) {385for ( j = 0; j < n; j++) {386II[i][j].z = II[i][j].z * kgv /II[i][j].n;387inv->array.SZ[i][j] = II[i][j].z;388}389free(M[i]);390free(II[i]);391}392free(M);393free(II);394free(nuin_M);395free(nuin_I);396397inv->kgv = kgv;398inv->flags.Integral = (kgv == 1);399inv->prime = mat->prime;400inv->Type = inv->Type & ~(I_Typ | P_Typ);401Check_mat( inv );402return ( inv );403}404405/*}}} */406#else407/*{{{ imat_inv*/408static matrix_TYP *imat_inv (mat)409matrix_TYP *mat;410{411matrix_TYP *inv, *help;412413/* don't relie on kgv2rat() and rat2kgv() being the inverse of each other414* there might be integer overflows and we don't want to demolish the415* original matrix416*/417help = copy_mat( mat );418/*419* Allocate a real rational denominator matrix420*/421kgv2rat( help );422/*423* compute the invers of it424*/425inv = rmat_inv( help );426/*427* free workspace428*/429free_mat( help );430/*431* transform the result to lcm-representation. This might be stupid.432* There could be integer overflow and in that case we'd better stay to the433* denominator matrix434*/435rat2kgv( inv );436/*437* eigentlich sollte ein Check_mat() noetig sein. rat2kgv() berechnet438* schon eine maximal gekuerzte Darstellung439*/440#if 0441Check_mat( inv );442#endif443return ( inv );444}445446#endif447448#ifdef __OLD__449450/* replaced the above function to use mp integres., tilman 02/05/97 */451static matrix_TYP *imat_inv (mat)452matrix_TYP *mat;453{454matrix_TYP *ID,455**X,456*res;457458ID = init_mat(mat->cols,mat->cols,"1");459460X = long_solve_mat(mat,ID);461462free_mat(ID);463464if (X == NULL){465fprintf(stderr,"matrix is not invertible\n");466exit(3);467}468469res = X[0];470471free(X);472473return res;474}475476/*}}} */477#endif478/*{{{ pmat_inv, unchanged*/479480481/**************************************************************************\482@---------------------------------------------------------------------------483@ matrix_TYP *pmat_inv (mat)484@ matrix_TYP *mat;485@486@ calculates the inverse of mat modulo mat->prime487@---------------------------------------------------------------------------488@489\**************************************************************************/490matrix_TYP *pmat_inv (mat)491matrix_TYP *mat;492{493int n, f, *v;494int i, j, k, **M, **II;495matrix_TYP *inv;496497n = mat->cols;498init_prime(mat->prime);499500M = (int **)malloc2dim( n, n, sizeof(int) );501memcpy2dim( (char **)M, (char **)mat->array.SZ, n, n, sizeof(int) );502II = (int **)calloc2dim( n, n, sizeof(int) );503for ( i= 0; i< n; i ++) {504II[i][i] = 1;505}506/*507* Invert M by paralell transformation of M and II s.t M is unit508*/509for ( i= 0; i< n; i ++ ) {510if ( M[j=i][j] == 0 ) {511/*512* Swap a non-zero element into [i][i]-position513*/514for ( j= i+1; j< n && M[j][i] == 0; j++ );515if ( j == n ) {516fprintf (stderr, "matrix is singular. Can't invert\n");517exit (3);518}519v= M[i]; M[i] = M[j]; M[j] = v;520v= II[i]; II[i] = II[j]; II[j] = v;521}522f = M[i][i];523if (f != 1) {524/*525* Normalize i-th row s.t. [i][i]-element is 1526*/527for ( k= 0; k< n; k ++ ) {528if ( k >= i ) {529M[i][k] = P(M[i][k], - f);530}531II[i][k] = P(II[i][k], - f);532}533}534/*535* Clear i-th column536*/537for ( j= 0; j< n; j ++ ) {538if ((j != i) && (f = M[j][i]) ) {539for ( k= 0; k< n; k ++ ) {540if (k > i) {541M[j][k] = S(M[j][k], - P(f,M[i][k]));542}543II[j][k] = S(II[j][k], - P(f,II[i][k]));544}545}546}547}548inv = init_mat(n,n,"p");549free2dim( (char **)M, n );550free2dim( (char **)inv->array.SZ, n );551inv->array.SZ = II;552553inv->prime = mat->prime;554555inv->flags.Symmetric = mat->flags.Symmetric;556inv->flags.Diagonal = mat->flags.Diagonal ;557inv->flags.Scalar = mat->flags.Scalar ;558559return (inv);560}561562/*}}} */563/*{{{ mat_inv*/564/**************************************************************************\565@---------------------------------------------------------------------------566@ matrix_TYP *mat_inv (mat)567@ matrix_TYP *mat;568@569@ calculates the inverse of mat570@---------------------------------------------------------------------------571@572\**************************************************************************/573matrix_TYP *mat_inv(mat)574matrix_TYP *mat;575{576matrix_TYP *inv;577578if ( mat->rows != mat->cols ) {579fprintf (stderr, "Can't invert non-square matrix\n");580exit (3);581}582if ( mat->prime > 0 ) {583inv = pmat_inv( mat );584} else if ( mat->array.N != NULL ) {585inv = rmat_inv( mat );586} else {587inv = imat_inv( mat );588}589return(inv);590}591/*}}} */592593594