Fortran- Inverse Matrix result not same if Decimal

2019-08-26 16:27发布

问题:

My real data is first input but inverse of result is so big. They are same data when you compare with first and second input. There is only difference decimal size. Why is there different result? Because they are same data. How can they have different result? You can see result and input. It is so strange.

program test

Implicit none

double precision,allocatable,dimension(:,:)         :: A       
double precision,allocatable,dimension(:)           :: WORK
integer ,allocatable,dimension(:)       :: ipiv
integer                                 :: n,info,M
 external     DGETRF,DGETRI
M=8
allocate(A(M,M),WORK(M),IPIV(M))
!!! First Input !!!!
A(1,:)=(/3.740486048842566D-4, 0.0D0, 0.0D0, 4.987315029057229D-5, 0.0D0, 0.0D0, 0.0D0, 0.0D0/)
A(2,:)=(/0.0D0 , 3.740486048842566D-4, 0.0D0, 0.0D0, 4.987315029057229D-5 ,0.0D0 ,0.0D0 ,0.0D0 /)
A(3,:)=(/0.0D0 , 0.0D0 ,3.740486048842566D-4, 0.0D0 ,0.0D0, 4.987315029057229D-5, 0.0D0 ,0.0D0/)
A(4,:)=(/4.987315029057229D-5 ,0.0D0 ,0.0D0 ,6.649753768432517D-6, 0.0D0 ,0.0D0, 0.0D0, 0.0D0 /)
A(5,:)=(/0.0D0 , 4.987315029057229D-5, 0.0D0, 0.0D0 ,6.649753768432517D-6 ,0.0D0 ,0.0D0 ,0.0D0 /)
A(6,:)=(/0.0D0, 0.0D0, 4.987315029057229D-5, 0.0D0 ,0.0D0, 6.649753768432517D-6, 0.0D0 ,0.0D0 /)
A(7,:)=(/0.0D0, 0.0D0 ,0.0D0, 0.0D0 ,0.0D0 ,0.0D0 ,1.499999910593033D-11, 0.0D0 /)
A(8,:)=(/0.0D0 ,0.0D0 ,0.0D0 ,0.0D0 ,0.0D0 ,0.0D0, 0.0D0 ,1.499999910593033D-11 /)
 !!!! Second Input !!!! 
!A(1,:)=(/3.74D-4, 0.0D0, 0.0D0, 4.98D-5, 0.0D0, 0.0D0, 0.0D0, 0.0D0/)
!A(2,:)=(/0.0D0 , 3.74D-4, 0.0D0, 0.0D0, 4.98D-5 ,0.0D0 ,0.0D0 ,0.0D0 /)
!A(3,:)=(/0.0D0 , 0.0D0 ,3.74D-4, 0.0D0 ,0.0D0, 4.98D-5, 0.0D0 ,0.0D0/)
!A(4,:)=(/4.98D-5 ,0.0D0 ,0.0D0 ,6.64D-6, 0.0D0 ,0.0D0, 0.0D0, 0.0D0 /)
!A(5,:)=(/0.0D0 , 4.98D-5, 0.0D0, 0.0D0 ,6.64D-6 ,0.0D0 ,0.0D0 ,0.0D0 /)
!A(6,:)=(/0.0D0, 0.0D0, 4.98D-5, 0.0D0 ,0.0D0, 6.64D-6, 0.0D0 ,0.0D0 /)
!A(7,:)=(/0.0D0, 0.0D0 ,0.0D0, 0.0D0 ,0.0D0 ,0.0D0 ,1.49D-11, 0.0D0 /)
!A(8,:)=(/0.0D0 ,0.0D0 ,0.0D0 ,0.0D0 ,0.0D0 ,0.0D0, 0.0D0 ,1.49D-11 /)


call DGETRF(M,M,A,M,IPIV,info)
if(info .eq. 0) then
Print *,'succeded'
else
Print *,'failed'
end if

call DGETRI(M,A,M,IPIV,WORK,M,info)
if(info .eq. 0) then
 Print *,'succeded'
else
Print *,'failed'
end if
Print *,A

deallocate(A,IPIV,WORK)

end 
!!!!! Second Input Result
!1.0e+10 *
! 0.0002     0       0   -0.0015       0      0        0   0
!     0      0.0002  0       0       -0.0015  0        0   0
!     0      0    0.0002     0         0     -0.0015   0   0
! -0.0015    0       0     0.0113      0      0        0   0
!     0     -0.0015  0       0       0.0113   0        0   0
!     0      0   -0.0015     0         0    0.0113     0   0
!     0      0       0       0         0      0     6.7114 0
!     0      0       0       0         0      0        0   6.7114

!!! First Input Result
!   1.0e+21 *

!-0.0238         0         0    0.1783         0         0         0         0
!     0   -0.0238         0         0    0.1783         0         0         0
!     0         0    0.0000         0         0   -0.0000         0         0
! 0.1783         0         0   -1.3375         0         0         0         0
!     0    0.1783         0         0   -1.3375         0         0         0
!     0         0   -0.0000         0         0    0.0000         0         0
!     0         0         0         0         0         0    0.0000         0
!     0         0         0         0         0         0         0    0.0000

回答1:

Creating a matrix inverse is not a difficult problem. I converted your earlier example to using a simple approach, based on Gaussian elimination with a shadowed identity matrix, which works well for most cases. The attached program inverts your earlier symmetric matrix, without resorting to pivoting of the rows. It does not need a "black-box".

That you get different results with different coefficients is hardly surprising. With the significant change in results for apparently small changes of input values, shows the sensitivity and possibly poor conditioning of the equation relationship you are using.

https://www.dropbox.com/s/ssotjx45yrz5sf9/dgetri.f90?dl=0

Additional response re "First Input"

https://www.dropbox.com/s/hximfoin977rmov/dgetri_piv4.f90?dl=0

This latest link (16-6) has both data sets included. In "First Input", your equations basically are rows 4:6 are rows 1:3 / 7.5 + small_noise.

This latest code example has accuracy checks both during the matrix inversion and also after. The during test checks the row changes are correct, while the after checks are "A.A^-1 - I" and "A - (A^-1)^-1", which better indicate poor accuracy.

It is interesting that "Second Input" (with more noise) reports a reasonably accurate outcome. Failing to get an inverse with 8-byte reals needs a fairly contrived matrix ! Similarly, the random number derived coefficients examples shows good accuracy.

These examples show that the accuracy tests I have presented don't always identify poorly defined equation relationships. Your inspection of the inverse to identify large variation in values is also useful.

Given the way the equations appear to have been defined, I am not sure what is the outcome you are wanting.