英文:
Why is this simple Fortran matrix inversion code not returning the expected value with LAPACK?
问题
我理解了你的请求,以下是你提供的代码的翻译部分:
program test
implicit none
real, dimension(4,4) :: R,R_inv
integer :: info, ipiv
real, dimension(4) :: lol
R = reshape([real :: 1,0,0,0, &
0,1.0/34.0,0,0, &
0,0,1,2, &
0,0,2,1] &
,shape(R), order = [2,1] )
R_inv = R
call sgetrf(4,4,R_inv,4,ipiv,info)
print *,info
print *, "_"
do pp = 1,4
print *, R_inv(pp,:)
end do
print *, "_"
call sgetri(2,R_inv,4,ipiv,lol,4,info)
print *,info
print *, "_"
print *, lol
print *, "_"
do pp = 1,4
print *, R_inv(pp,:)
end do
R_inv = matmul(R_inv,R)
print *, "_"
do pp = 1,4
print *, R_inv(pp,:)
end do
print *, "_"
end program
英文:
I'm trying to use the LAPACK package to compute the inverse of a matrix. For this end, I've employed the routines sgetrf and sgetri. However, when testing the code, it doesn't return the expected values for the inverse or (from what I can understand would be the expected value of) the LU decomposition. The base matrix I used for inversion was an arbitrary 4x4 matrix. It's written in Fortran 90 on Code::blocks, and uses the most recent GNU compilers and LAPACK libraries available. If it's at all relevant, I'm using Windows 10. The code is simple enough I believe it's adequate to post it here directly:
program test
implicit none
real, dimension(4,4) :: R,R_inv
integer :: info, ipiv
real, dimension(4) :: lol
R = reshape([real :: 1,0,0,0, &
0,1.0/34.0,0,0, &
0,0,1,2, &
0,0,2,1] &
,shape(R), order = [2,1] )
R_inv = R
call sgetrf(4,4,R_inv,4,ipiv,info)
print *,info
print *, "_"
do pp = 1,4
print *, R_inv(pp,:)
end do
print *, "_"
call sgetri(2,R_inv,4,ipiv,lol,4,info)
print *,info
print *, "_"
print *, lol
print *, "_"
do pp = 1,4
print *, R_inv(pp,:)
end do
R_inv = matmul(R_inv,R)
print *, "_"
do pp = 1,4
print *, R_inv(pp,:)
end do
print *, "_"
end program
So far, here's what I noted:
-
The first info output returns 2. According to the documentation for the function sgetrf, this means that the factor U(2,2) is exactly singular. However, using a different LU factorization calculator such Matlab, I get a valid (and different) result for the factorization. Furthermore, I get a different result using an online calculator as well. This result agrees with the one obtained through Matlab.
-
The function sgetri seems to work fine.
-
This code works fine if the matrix is diagonal.
-
The LU factorized matrix seems fine for the first half of the diagonal, but becomes weird after that.
-
Using both online calculators and Matlab, the inverse of the matrix R exists and has no apparent problems. Perhaps negative values mess with the problem somehow? But I have no idea why that would be the case.
-
Switching the values from real to doubleprecision and using the respective dgetrf and dgetri routines had no effect on the result
Overall, can anyone tell what's wrong with this code? Are the assumptions about the routines called wrong? Am I misunderstanding what my results are supposed to be? If so, how would one go about calculating the inverse with the LAPACK package on Fortran?
Given I'm a bit inexperienced with Fortran, there might be issues on the way I handle the packages installation and usage. If this works on your machine, please let me know, as I might have messed up on that part.
答案1
得分: 0
你在使用 LAPACK 时有两个错误:
ipiv
必须是一个维度为 4 的整数数组,而不是一个标量。- 在你调用
sgetri
时,第一个参数(矩阵的阶数)应该是 4,而不是 2。
通过这些更改,你的矩阵求逆操作将正常工作。
但请注意,你的计算是在单精度(32位浮点数)下进行的,而Matlab(以及你链接的在线LU计算器)默认使用64位实数进行计算。因此,你的代码更容易出现精度问题,尤其是对于病态问题。
英文:
You have two errors in your usage of LAPACK:
ipiv
must be an integer array ofdimension(4)
, not a scalar.- In your call to
sgetri
, the first argument (the matrix order) should be 4, not 2.
With these changes your matrix inversion works correctly.
Note however that your calculation is done in single precision (32-bit floating point), whereas matlab (and presumably that online LU calculator you linked to as well) by default calculates using 64-bit reals. So your code is more prone to precision issues, particularly for ill-conditioned problems.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论