Você está na página 1de 3

57834899.

doc 12/09/21 1
CALL RSEED(57,89)
DO 10 I=1,3
Gauss Elimination DO 10 J=1,3
When there is no need to pivot, the code is 10 A(I,J)=RNDMF(1.)*10.
for\tgaussj\gauselim.wpj for\tgaussj\cgauelim.for, DO 20 J=1,3
for\tgaussj\Tcgaussj.for. This is a very simple implementation 20 A(J,J)=1
of the notion that one simply eliminaties the 1,1 element, then WRITE(*,108)A
the 2,2 element and so on. Since the array is being reduced to 108 FORMAT(' A ='/(3E15.6))
a diagonal form, the earlier elements can then be used for DO 30 I=1,3
backsustitution. This method assumes that you know which DO 30 J=1,3
elements are dominant and have set your array up to utilize 30 AS(J,I)=A(J,I)
this. CALL GAUSSJ(A,3,3,B,0,1)
DO 40 I=1,3
Gauss Jordan Matrix Inversion with DO 40 J=1,3
AT(J,I)=0
pivoting DO 40 K=1,3
The old reliable workhorse matrix inverter simultaneous 40 AT(J,I)=AS(J,K)*A(K,I)+AT(J,I)
equation solver GAUSSJ is given in Press Section 2.1. The WRITE(*,109)AT
method is very straightforward 109 FORMAT(' AI*A='/(3E15.6))
eqn # col1 col2 col3 rhs STOP
1 a11c1 +a12c2 +a13c3 = b1 END
2 a21c2 +a22c2 +a23c3 = b2 In C this becomes GAUSSJ.CPP
3 a31c3 +a32c2 +a33c3 = b3 #include <stdio.h>
#include <math.h>
Start with a set of simultaneous equations. Find the largest #define mp 3
array element, e.g. a32 and keep track of the fact that this was struct {int ix,iy,itab[128];} ran;
int rseed(int ix,int iy);
row 3 and Col 2 in a pair of storage vectors. Rearrange the
double rndmf();
equations so that this term is in the upper left hand corner
double gaussj(double a[][mp], int n,double
Eqn # col1 col2 col3 rhs
b[]);
3 +a32c2 a31c3 +a33c3 = b3 void main(void)
1 +a12c2 a11c1 +a13c3 = b1 {int i,j,k,n=3,ix=57,iy=89;
2 +a22c2 a21c2 +a23c3 = b2 double a[3][3],at[3][3],as[3][3],b[3];
rseed(ix,iy);
divide the first equation by a32 or rather the term in the upper for (i=0;i<3;++i){
left hand corner and subtract this multiplied by the correct for (j=0;j<3;++j){
value form the succeeding equations. a[i][j]=rndmf()*10;}}
eqn col1 col2 col3 rhs for (j=0;j<3;++j){
# a[j][j]=1;}
3 +a32c2 a31c3 +a33c3 = b3 for (i=0;i<3;++i){
1 (a12-a12)c2 (a11- (a13- = (b1-a12b3/a32) for (j=0;j<3;++j){
a12a31/a32) a12a33/a32) as[i][j]=a[i][j];}}
c1 c3 for (j=0;j<3;j++){
2 (a22-a22)c2 (a21- (a23- = (b2-a22b3/a32) printf(" col %d %6f %6f %6f
a22a31/a32) a22a33/a32) \n",j,
c2 c3 as[0][j],as[1][j],as[2][j]);}
gaussj(a,n,b);
reducing the set of equations down to a 22 set in which all for(i=0;i<3;i++){
divisions are by the largest element in the array. This is much for (j=0;j<3;j++){
easier to code than to explain as here. The important part at[j][i]=0;
being that there are two vectors used to keep track of all the for(k=0;k<3;k++){
term swapping and that it is necessary to undo this at the end. at[j][i]+=as[i][k]*a[k][j];}}}
One of the common problems is keeping track of where the
matrix elements actually are in the 2-d array. Note that the printf(" unit matrix? \n");
inputs to GAUSSJ are A the array, N the number of equations for (i=0;i<3;i++)
being solved, NP the dimensions of the array in the calling {for (j=0;j<3;j++)printf(" %d %d %6f
code, B the right hand side vector which is positive here, but ",j,i,a[j][i]);
-PC in the case that we want to solve, M the number of right printf("\n");}
hand side vectors, and MP the actual second dimension of B. for (i=0;i<3;i++)
My version complete with test main is GAUSSJ.FOR {for (j=0;j<3;j++)printf(" %d %d %6f
DIMENSION A(3,3),AT(3,3),AS(3,3),B(3) ",j,i,at[j][i]);
printf("\n");}
57834899.doc 12/09/21 2
} b[ll]-=b[icol]*temp;
double gaussj(double a[][mp], int n,double } /* ENDIF */
b[]) } /* 21 CONTINUE */
{int } /* 22 CONTINUE end of main loop
i,j,k,l,ll,irow,icol,ipiv[mp],indxr[mp],in over cols to be replaced */
dxc[mp]; printf(" indxr ");
double big,temp,pivinv; for(l=0;l<n;l++)printf(" %d
for(i=0;i<n;i++)ipiv[i]=0; ",indxr[l]);
for(i=0;i<n;i++) /* DO 22 main loop printf("/n indxc ");
over cols to be replaced */ for(l=0;l<n;l++)printf(" %d
{big=0; ",indxc[l]);
for(j=0;j<n;j++) /* DO 13 */ for (j=0;j<n;j++) /* DO 24 MAKES A AN
{if(ipiv[j]!=1) INVERSE MATRIX*/
{for(k=0;k<n;k++) /* DO 12 */ {l=n-1-j; /* a bit diff from l=n+1-j
{if(ipiv[k]==0) in fortran */
{if(fabs(a[j][k]) >= big) if(indxr[l]!=indxc[l])
{big=fabs(a[j][k]); {for (k=0;k<n;k++)
irow=j; {temp=a[k][indxr[l]];
icol=k; a[k][indxr[l]]=a[k][indxc[l]];
} a[k][indxc[l]]=temp;
else }
{if(ipiv[k]>1) }
{printf(" error 1 /n"); }
scanf(" %lf",temp); return 0;}
return 1; with rseed and rndmf the same as in for\random.for - The two
} routines produce
} In fortran
} /* ENDIF OF IF THEN ELSE */ A =
} /* 12 CONTINUE */ 0.100000E+01 0.932207E+01
} /* ENDIF OF IPIV(J).NE.1 */ 0.926890E+01
} /* 13 CONTINUE */ 0.881985E+01 0.100000E+01
ipiv[icol]+=1;/* DO 13 ABOVE */ 0.224496E+01
if(irow!=icol) 0.848141E+01 0.227670E+01
{for (l=0;l<n;l++) 0.100000E+01
{temp=a[irow][l]; Original matrix in C
a[irow][l]=a[icol][l]; col 0 1.000000 9.322065 9.268897
a[icol][l]=temp; col 1 8.819853 1.000000 2.244955
} /* 14 CONTINUE */ col 2 8.481414 2.276695 1.000000
temp=b[irow]; in fortran
b[irow]=b[icol]; INDXR 2 2 3
b[icol]=temp; INDXC 1 2 3
} /* ENDIF */ in c
indxr[i]=irow; 1 1 2
indxc[i]=icol; 0 1 2
if(a[icol][icol]==0) The inverse matrix in fortran
{printf(" singular matrix %d -0.206927E-01 0.592955E-01
/n",icol); 0.586831E-01
scanf(" %lf",temp); 0.514441E-01 -0.390659E+00
return 1; 0.400183E+00
} /* ENDIF ON SINGULAR MATRIX */ 0.583810E-01 0.386503E+00
pivinv=1/a[icol][icol]; -0.408809E+00
a[icol][icol]=1; The inverse matrix in C
for (l=0;l<n;l++)a[icol][l]*=pivinv; 0 0 -0.020693 1 0 0.059295 2 0 0.058683
/* DO 16 LOOP */ 0 1 0.051444 1 1 -0.390659 2 1 0.400183
b[icol]*=pivinv; 0 2 0.058381 1 2 0.386503 2 2 -0.408809
for (ll=0;ll<n;ll++) /* DO 21 LOOP in fortran
*/ AI*A=
{if(ll!=icol) 0.100000E+01 0.117426E-07
{temp=a[ll][icol]; 0.111759E-07
a[ll][icol]=0; 0.273850E-07 0.100000E+01
for(l=0;l<n;l++)a[ll][l]- -0.298023E-07
=a[icol][l]*temp; /* DO 18 LOOP */
57834899.doc 12/09/21 3
-0.553685E-07 0.585674E-07 Note that until the ( ) becomes zero, that each new M-1 can be
0.100000E+01 taken equal to Ma-1. The matrix multiplication is such that
A times the inverse in C n
0 0 1.000000 1 0 0.000000 2 0 0.000000 each iteration requires n3 operations. -- M i , j   Ai ,k Bk , j
0 1 0.000000 1 1 1.000000 2 1 0.000000 k 1
0 2 0.000000 1 2 0.000000 2 2 1.000000 n operations for each of n2 elements. This should be compared
to the n3 operations required to invert the matrix originally.
Iterative improvement of the inverse mpcholesky\Cholesky.for
matrix1
Begin with the basic set of equations
 
Mc  b .
Unfortunately the best inverse that we can find is only
approximate
  
c A  M A1b
Substitute these into the original equations
b g
   
M cA    b

d i
  
M  b  Mc A

d i
  
d  b  Mc A
  
  M A1d
Writing this out in a bit more detail
   
c  c A    M a1b  M a1d
  
d 
 M a1b  M a1 b  MM a1b i
o
 
d 
 M a1  M a1 I  MM a1 b it
which shows that to this approximation
M M M d I  MM i
 1
 1
 1
 1
a a a

C forming I-MMa-1
DO I=1,NMAT
DO J=1,NMAT
ATEMP(I,J)=0
DO K=1,NMAT
ATEMP(I,J)=ATEMP(I,J)-AS(I,K)*A(K,J)
ENDDO
ENDDO
ATEMP(I,I)=1+ATEMP(I,I)
ENDDO

C multiplying by Ma-1
DO I=1,NMAT
DO J=1,NMAT
ATEMP2(I,J)=0
DO K=1,NMAT
ATEMP2(I,J)=ATEMP2(I,J)
+A(I,K)*ATEMP(K,J)
ENDDO
ENDDO
ENDDO
C adding Ma-1
DO I=1,NMAT
DO J=1,NMAT
A(I,J)=A(I,J)+ATEMP2(I,J)
AI(I,J)=A(I,J)
ENDDO
ENDDO

1
V.N. Fadeeva, translated by C.D. Benster, Computational
Methods of Linear Algebra, Dover (1959) pp 117-127

Você também pode gostar