jomiro87
Programmer
- Nov 21, 2012
- 3
I am trying to set a program in fortran 95 for calculating inverses of matrices by using the jacobi algorithm. I have compiled it successfully, but I execute it, it is only able to calculate correctly the first column of the new matrix. The code is:
Program algo
implicit none
real(8), dimension,, allocatable :: A, ID, AINVI, AS, D, DINV, PM, SM, AINVF
real(8) :: sub, e, tru, trd, FindDet
integer :: i, j, n, iter
print *, 'Dimensió matriu'
read *, n
allocate (A(n,n))
allocate (ID(n,n))
allocate (AINVI(n,n))
allocate (AS(n,n))
allocate (D(n,n))
allocate (DINV(n,n))
allocate (PM(n,n))
allocate (SM(n,n))
allocate (AINVF(n,n))
print *, 'matriu'
do i=1, n
print *, 'fila', i
read *, (A(i,j), j=1, n)
end do
ID=0.0d0
do i=1, n
ID(i,i)=1.0d0
end do
AINVI=0.0d0
do i=1, n
do j=1, n
if (i == j) then
AS(i,j)=0.0d0
else
AS(i,j)=A(i,j)
end if
end do
end do
do i=1, n
do j=1, n
if (i==j) then
D(i,j)=A(i,j)
else
D(i,j)=0.0d0
end if
end do
end do
do i=1, n
do j=1, n
if (i==j) then
DINV(i,j)=1/D(i,j)
else
DINV(i,j)=0.0d0
end if
end do
end do
do i=1, n
print *, (AS(i,j), j=1, n)
end do
do i=1, n
print *, (D(i,j), j=1, n)
end do
do i=1, n
print *, (DINV(i,j), j=1, n)
end do
PM=matmul(DINV, ID)
SM=matmul(DINV, AS)
print *, 'pm'
do i=1, n
print *, (PM(i,j), j=1, n)
end do
print *, 'sm'
do i=1, n
print *, (SM(i,j), j=1, n)
end do
iter=0
e=0.0001
sub=1.0d0
tru=0.0d0
trd=0.0d0
do while (sub>=e)
iter=iter+1
AINVF=PM-matmul(SM, AINVI)
do i=1, n
tru=tru+AINVI(i,i)
trd=trd+AINVF(i,i)
end do
print *, tru, trd, AINVI(1,1), AINVF(1,1), FindDet(AINVI,n), FindDet(AINVF,n)
sub=abs(tru-trd)
AINVI=AINVF
end do
print *, 'inversa'
do i=1, n
print *, (AINVF(i,j), j=1, n)
end do
print *, 'iteracions', iter
print *, sub
print *, e
end program
REAL(8) FUNCTION FindDet(matrix, n)
IMPLICIT NONE
REAL(8), DIMENSION(n,n) :: matrix
INTEGER, INTENT(IN) :: n
REAL(8) :: m, temp
INTEGER :: i, j, k, l
LOGICAL :: DetExists = .TRUE.
l = 1
!Convert to upper triangular form
DO k = 1, n-1
IF (matrix(k,k) == 0) THEN
DetExists = .FALSE.
DO i = k+1, n
IF (matrix(i,k) /= 0) THEN
DO j = 1, n
temp = matrix(i,j)
matrix(i,j)= matrix(k,j)
matrix(k,j) = temp
END DO
DetExists = .TRUE.
l=-l
EXIT
ENDIF
END DO
IF (DetExists .EQV. .FALSE.) THEN
FindDet = 0
return
END IF
ENDIF
DO j = k+1, n
m = matrix(j,k)/matrix(k,k)
DO i = k+1, n
matrix(j,i) = matrix(j,i) - m*matrix(k,i)
END DO
END DO
END DO
!Calculate determinant by finding product of diagonal elements
FindDet = l
DO i = 1, n
FindDet = FindDet * matrix(i,i)
END DO
END FUNCTION FindDet
For example, for matrix
2 1
3 2
it shows
1.9999999999 -Infinity
-2.9999999999 NaN
When actually, it should give the following:
2 -1
-3 2
I would be grateful if you could provide me any suggestion for improving my code.
Cheers,
Joan
Program algo
implicit none
real(8), dimension,, allocatable :: A, ID, AINVI, AS, D, DINV, PM, SM, AINVF
real(8) :: sub, e, tru, trd, FindDet
integer :: i, j, n, iter
print *, 'Dimensió matriu'
read *, n
allocate (A(n,n))
allocate (ID(n,n))
allocate (AINVI(n,n))
allocate (AS(n,n))
allocate (D(n,n))
allocate (DINV(n,n))
allocate (PM(n,n))
allocate (SM(n,n))
allocate (AINVF(n,n))
print *, 'matriu'
do i=1, n
print *, 'fila', i
read *, (A(i,j), j=1, n)
end do
ID=0.0d0
do i=1, n
ID(i,i)=1.0d0
end do
AINVI=0.0d0
do i=1, n
do j=1, n
if (i == j) then
AS(i,j)=0.0d0
else
AS(i,j)=A(i,j)
end if
end do
end do
do i=1, n
do j=1, n
if (i==j) then
D(i,j)=A(i,j)
else
D(i,j)=0.0d0
end if
end do
end do
do i=1, n
do j=1, n
if (i==j) then
DINV(i,j)=1/D(i,j)
else
DINV(i,j)=0.0d0
end if
end do
end do
do i=1, n
print *, (AS(i,j), j=1, n)
end do
do i=1, n
print *, (D(i,j), j=1, n)
end do
do i=1, n
print *, (DINV(i,j), j=1, n)
end do
PM=matmul(DINV, ID)
SM=matmul(DINV, AS)
print *, 'pm'
do i=1, n
print *, (PM(i,j), j=1, n)
end do
print *, 'sm'
do i=1, n
print *, (SM(i,j), j=1, n)
end do
iter=0
e=0.0001
sub=1.0d0
tru=0.0d0
trd=0.0d0
do while (sub>=e)
iter=iter+1
AINVF=PM-matmul(SM, AINVI)
do i=1, n
tru=tru+AINVI(i,i)
trd=trd+AINVF(i,i)
end do
print *, tru, trd, AINVI(1,1), AINVF(1,1), FindDet(AINVI,n), FindDet(AINVF,n)
sub=abs(tru-trd)
AINVI=AINVF
end do
print *, 'inversa'
do i=1, n
print *, (AINVF(i,j), j=1, n)
end do
print *, 'iteracions', iter
print *, sub
print *, e
end program
REAL(8) FUNCTION FindDet(matrix, n)
IMPLICIT NONE
REAL(8), DIMENSION(n,n) :: matrix
INTEGER, INTENT(IN) :: n
REAL(8) :: m, temp
INTEGER :: i, j, k, l
LOGICAL :: DetExists = .TRUE.
l = 1
!Convert to upper triangular form
DO k = 1, n-1
IF (matrix(k,k) == 0) THEN
DetExists = .FALSE.
DO i = k+1, n
IF (matrix(i,k) /= 0) THEN
DO j = 1, n
temp = matrix(i,j)
matrix(i,j)= matrix(k,j)
matrix(k,j) = temp
END DO
DetExists = .TRUE.
l=-l
EXIT
ENDIF
END DO
IF (DetExists .EQV. .FALSE.) THEN
FindDet = 0
return
END IF
ENDIF
DO j = k+1, n
m = matrix(j,k)/matrix(k,k)
DO i = k+1, n
matrix(j,i) = matrix(j,i) - m*matrix(k,i)
END DO
END DO
END DO
!Calculate determinant by finding product of diagonal elements
FindDet = l
DO i = 1, n
FindDet = FindDet * matrix(i,i)
END DO
END FUNCTION FindDet
For example, for matrix
2 1
3 2
it shows
1.9999999999 -Infinity
-2.9999999999 NaN
When actually, it should give the following:
2 -1
-3 2
I would be grateful if you could provide me any suggestion for improving my code.
Cheers,
Joan