I encountered the following matrix
mat = {{2,
2.161209223472559` + 1.682941969615793` I}, {2.161209223472559` -
1.682941969615793` I, 2}}
and Inverse[mat]
will give
{{-0.57092 - 1.06364*10^-16 I,
0.616939 + 0.480412 I}, {0.616939 - 0.480412 I, -0.57092 -
1.11022*10^-16 I}}
Notice there is small imaginary part and they ought to be zero. as you can see from general symbolic calculation.
In[494]:= Inverse[{{a, b + I c}, {b - I c, a}}]
Out[494]= {{1/(1 - b^2 - c^2), (-b - I c)/(
1 - b^2 - c^2)}, {(-b + I c)/(1 - b^2 - c^2), 1/(1 - b^2 - c^2)}}
Normally, those small part won't bother. But I am doing iteration calculation right now, in each iteration step, there is inversion process and I found those small part in every step will greatly affect the result after only 30 iteration.
According to this link and this link, inverse matrix should never be performed and they recommend linear equation solving. So for example
mat1={{I, -1}, {-1, -I}}
mat2={{-I, -1}, {-1, I}}
and we want to calculate
mat1.Inverse[mat].mat2
we could do it without inverse like this
mat1.LinearSolve[mat,mat2]
But I found this give exactly the same result as directly calculating Inverse
The way I can think of is to Chop matrix at every step, but I don't know whether it will accumulate other kind of error in the iteration process.
So what is the correct way to deal with inverse matrix in this case?
PS: I also found Python's numpy gives more accurate inverse than Mathematica. for example, numpy.linalg.inv(mat)
gives imaginary part 6x10^-17, and np.dot(np.dot(mat1,mat),mat2)
will not present imaginary part.
Update
first
As Karsten 7. has pointed out, Method -> "CofactorExpansion"
will give correct result. And I think this method is actually using direct formula like the following for 2x2 matrix
$$\mathbf A^{-1}=\frac1{\det \mathbf A}\begin{bmatrix}d&-b\\-c&a\end{bmatrix}=\frac1{ad-bc}\begin{bmatrix}d&-b\\-c&a\end{bmatrix}$$
Though CofactorExpansion
is slower than direct Inverse
, but for 2x2 matrix, it is acceptable efficient. But I have no idea about the numerical stability.
Second
The thing I don't understand right now is that even using Mathematica's LinearAlgebra``Lapack
(see here) still can't get the correct answer, but simple fortran coding using lapack do give the correct answer !!!!
According to Lapack
,
"getrf" Computes the LU factorization of a general m-by-n matrix.
"getri" Computes the inverse of an LU-factored general matrix.
so we have the following code
tmp = mat;
ipiv = ConstantArray[1, Length@tmp];
LinearAlgebra`LAPACK`GETRF[tmp, ipiv, info];
LinearAlgebra`LAPACK`GETRI[tmp, ipiv, info];
tmp
But this gives result
{{-0.57092 - 1.06364*10^-16 I,
0.616939 + 0.480412 I}, {0.616939 - 0.480412 I, -0.57092 -
1.11022*10^-16 I}}
exactly the same wrong result as direct Inverse
!!
But I have tried fortran coding below
program testinversion
use lapack95
use f95_precision
implicit none
complex*16,dimension(2,2)::a
integer,dimension(2)::ipiv
integer::info
a=reshape((/(2.,0.),(2.161209223472559,-1.682941969615793),(2.161209223472559,1.682941969615793),(2.,0.)/),(/2,2/))
call zgetrf(2, 2, a, 2, ipiv, info)
if(info==0) then
call getri(a,ipiv,info)
print*,a
else
print*,"error"
endif
end program testinversion
Compile it with
ifort testinversion.f90 -mkl=sequential -lmkl_blas95_lp64 -lmkl_lapack95_lp64
it gives the correct result!
What is wrong with Mathematica's LAPACK?
update2
Solving inverse of 2x2 mat is actually equivalent to solving $$mat \cdot x = \left( {\begin{array}{*{20}{c}} 1&0\\ 0&1 \end{array}} \right)$$
But LinearSolve[mat,{1,0}]
gives
{-0.57092 - 5.91873*10^-17 I, 0.616939 - 0.480412 I}
looking at the document of LinearSolve
, I found more things:
"CofactorExpansion","DivisionFreeRowReduction","OneStepRowReduction" are actually designed for symbolic solving. For numerical solving, There are "Banded"
"Cholesky","Krylov","Multifrontal".
For this paticular simple problm, mathematica choosed a wrong method??!!
As I tested, both "Krylov" and "Multifrontal" can give correct answer.
So now, I don't know whether Inverse
is using LinearSolve
, but apparently, automatic method in LinearSolve
is also bugged.
In[59]:= mat1.LinearSolve[mat, mat2] Out[59]= {{-0.181014708395 + 0. I, 0. + 0.181014708395 I}, {0. - 0.181014708395 I, -0.181014708395 + 0. I}} In[60]:= mat1.Inverse[mat].mat2 Out[60]= {{-0.181014708395 + 0. I, 0. + 0.181014708395 I}, {0. - 0.181014708395 I, -0.181014708395 + 0. I}}
. For the inverse itself, I getIn[37]:= Inverse[mat] Out[37]= {{-0.570919803469 + 6.01693250938*10^-17 I, 0.61693857256 + 0.480412449271 I}, {0.61693857256 - 0.480412449271 I, -0.570919803469 + 5.55111512313*10^-17 I}}
. $\endgroup$Inverse
in order to solve a linear system, are you? $\endgroup$LinearSolve[]
is acting like this for a manifestly Hermitian system, I don't yet have any ideas. $\endgroup$