Gauss-Jordan matrix inversion: Difference between revisions
Content added Content deleted
m (→version 2: changed whitespace, added a comment.) |
(Add Fortran example. Original code.) |
||
Line 720: | Line 720: | ||
-16/23 25/69 11/138 9/46 |
-16/23 25/69 11/138 9/46 |
||
-13/23 16/69 -2/69 13/23 |
-13/23 16/69 -2/69 13/23 |
||
</pre> |
|||
=={{header|Fortran}}== |
|||
Note that the Crout algorithm is a more efficient way to invert a matrix. |
|||
<lang Fortran>!----------------------------------------------------------------------- |
|||
! gjinv - Invert a matrix, Gauss-Jordan algorithm |
|||
! A is destroyed. |
|||
! |
|||
!___Name_______Type_______________In/Out____Description_________________ |
|||
! A(LDA,N) Real In An N by N matrix |
|||
! LDA Integer In Row bound of A |
|||
! N Integer In Order of matrix |
|||
! B(LDB,N) Real Out Inverse of A |
|||
! LDB Integer In Row bound of B |
|||
! IERR Integer Out 0 = no errors |
|||
! 1 = singular matrix |
|||
!----------------------------------------------------------------------- |
|||
SUBROUTINE GJINV (A, LDA, N, B, LDB, IERR) |
|||
IMPLICIT NONE |
|||
INTEGER LDA, N, LDB, IERR |
|||
REAL A(LDA,N), B(LDB,N) |
|||
REAL EPS ! machine constant |
|||
PARAMETER (EPS = 1.1920929E-07) |
|||
INTEGER I, J, K, P ! local variables |
|||
REAL F, TOL |
|||
!----------------------------------------------------------------------- |
|||
! Begin. |
|||
!----------------------------------------------------------------------- |
|||
IF (N < 1) THEN ! Validate. |
|||
IERR = -1 |
|||
RETURN |
|||
ELSE IF (N > LDA .OR. N > LDB) THEN |
|||
IERR = -2 |
|||
RETURN |
|||
END IF |
|||
IERR = 0 |
|||
F = 0. ! Frobenius norm of A |
|||
DO J = 1, N |
|||
DO I = 1, N |
|||
F = F + A(I,J)**2 |
|||
END DO |
|||
END DO |
|||
F = SQRT(F) |
|||
TOL = F * EPS |
|||
DO J = 1, N ! Set B to identity matrix. |
|||
DO I = 1, N |
|||
IF (I .EQ. J) THEN |
|||
B(I,J) = 1. |
|||
ELSE |
|||
B(I,J) = 0. |
|||
END IF |
|||
END DO |
|||
END DO |
|||
! Main loop |
|||
DO K = 1, N |
|||
F = ABS(A(K,K)) ! Find pivot. |
|||
P = K |
|||
DO I = K+1, N |
|||
IF (ABS(A(I,K)) > F) THEN |
|||
F = ABS(A(I,K)) |
|||
P = I |
|||
END IF |
|||
END DO |
|||
IF (F < TOL) THEN ! Matrix is singular. |
|||
IERR = 1 |
|||
RETURN |
|||
END IF |
|||
IF (P .NE. K) THEN ! Swap rows. |
|||
DO J = K, N |
|||
F = A(K,J) |
|||
A(K,J) = A(P,J) |
|||
A(P,J) = F |
|||
END DO |
|||
DO J = 1, N |
|||
F = B(K,J) |
|||
B(K,J) = B(P,J) |
|||
B(P,J) = F |
|||
END DO |
|||
END IF |
|||
F = 1. / A(K,K) ! Scale row so pivot is 1. |
|||
DO J = K, N |
|||
A(K,J) = A(K,J) * F |
|||
END DO |
|||
DO J = 1, N |
|||
B(K,J) = B(K,J) * F |
|||
END DO |
|||
DO 10 I = 1, N ! Subtract to get zeros. |
|||
IF (I .EQ. K) GO TO 10 |
|||
F = A(I,K) |
|||
DO J = K, N |
|||
A(I,J) = A(I,J) - A(K,J) * F |
|||
END DO |
|||
DO J = 1, N |
|||
B(I,J) = B(I,J) - B(K,J) * F |
|||
END DO |
|||
10 CONTINUE |
|||
END DO |
|||
RETURN |
|||
END ! of gjinv</lang> |
|||
Test program: |
|||
{{works with|gfortran|8.3.0}} |
|||
<lang Fortran>! Test matrix inversion |
|||
PROGRAM TINV |
|||
IMPLICIT NONE |
|||
INTEGER I, J, K, N, IERR |
|||
PARAMETER (N = 4) |
|||
REAL AORIG(N,N), A(N,N), B(N,N), C(N,N) |
|||
DATA AORIG / -1., -4., 7., 1., |
|||
$ -2., -1., -8., -2., |
|||
$ 3., 6., 9., 1., |
|||
$ 2., 2., 1., 3. / |
|||
20 FORMAT (F8.3, $) |
|||
30 FORMAT () |
|||
DO J = 1, N |
|||
DO I = 1, N |
|||
A(I,J) = AORIG(I,J) |
|||
END DO |
|||
END DO |
|||
CALL GJINV (A, N, N, B, N, IERR) |
|||
PRINT *, 'gjinv returns #', IERR |
|||
PRINT 30 |
|||
PRINT *, 'matrix:' |
|||
DO I = 1, N |
|||
DO J = 1, N |
|||
PRINT 20, AORIG(I,J) |
|||
END DO |
|||
PRINT 30 |
|||
END DO |
|||
PRINT 30 |
|||
PRINT *, 'inverse:' |
|||
DO I = 1, N |
|||
DO J = 1, N |
|||
PRINT 20, B(I,J) |
|||
END DO |
|||
PRINT 30 |
|||
END DO |
|||
PRINT 30 |
|||
DO K = 1, N |
|||
DO J = 1, N |
|||
C(J,K) = 0. |
|||
DO I = 1, N |
|||
C(J,K) = C(J,K) + AORIG(J,I) * B(I,K) |
|||
END DO |
|||
END DO |
|||
END DO |
|||
PRINT *, 'matrix @ inverse:' |
|||
DO I = 1, N |
|||
DO J = 1, N |
|||
PRINT 20, C(I,J) |
|||
END DO |
|||
PRINT 30 |
|||
END DO |
|||
PRINT 30 |
|||
CALL GJINV (B, N, N, A, N, IERR) |
|||
PRINT *, 'gjinv returns #', IERR |
|||
PRINT 30 |
|||
PRINT *, 'inverse of inverse:' |
|||
DO I = 1, N |
|||
DO J = 1, N |
|||
PRINT 20, A(I,J) |
|||
END DO |
|||
PRINT 30 |
|||
END DO |
|||
END ! of test program</lang> |
|||
{{out}} |
|||
<pre> |
|||
gjinv returns # 0 |
|||
matrix: |
|||
-1.000 -2.000 3.000 2.000 |
|||
-4.000 -1.000 6.000 2.000 |
|||
7.000 -8.000 9.000 1.000 |
|||
1.000 -2.000 1.000 3.000 |
|||
inverse: |
|||
-0.913 0.246 0.094 0.413 |
|||
-1.652 0.652 0.043 0.652 |
|||
-0.696 0.362 0.080 0.196 |
|||
-0.565 0.232 -0.029 0.565 |
|||
matrix @ inverse: |
|||
1.000 0.000 -0.000 0.000 |
|||
0.000 1.000 -0.000 0.000 |
|||
-0.000 -0.000 1.000 0.000 |
|||
-0.000 -0.000 0.000 1.000 |
|||
gjinv returns # 0 |
|||
inverse of inverse: |
|||
-1.000 -2.000 3.000 2.000 |
|||
-4.000 -1.000 6.000 2.000 |
|||
7.000 -8.000 9.000 1.000 |
|||
1.000 -2.000 1.000 3.000 |
|||
</pre> |
</pre> |
||