我正在尝试使用dgesvd
计算SVD,但遇到以下错误:
Program received signal SIGSEGV: Segmentation fault - invalid memory reference.
Backtrace for this error:
#0 0x10af44a69
#1 0x10af43e35
#2 0x7fff8ae4b529 Segmentation fault: 11
我的代码如下
program calc_pseud3
implicit none
character:: jobu*1, jobvt*1
integer:: N, M, i, j, lwork, info, LDg, LDU, LDVT
real*8:: t0,t1,t2,t3
real*8, allocatable, dimension(:) :: g_, work, S
real*8, allocatable, dimension(:,:) :: g,U,VT,S2,I_check,g_i
call cpu_time(t0)
N = 512*512
M = 2560
lwork = 280000
jobu = 'A'
jobvt = 'A'
LDg = N
LDU = N
LDVT = M
allocate(g_(N*M))
allocate(g(LDg,M))
allocate(g_i(M,N))
allocate(work(lwork))
allocate(S(M))
allocate(S2(N,M))
allocate(U(LDU,N))
allocate(VT(LDVT,M))
allocate(I_check(M,M))
open(1, file='projection.txt')
do i = 1,M
print *, i
do j = 1,N
read(1,*) g_(N*(i-1)+j)
end do
end do
call cpu_time(t1)
print *, t1-t0
g = reshape(g_, [N, M])
print *, 'Shape of matrix G is ', shape(g)
call cpu_time(t2)
print *, t2-t1
call dgesvd(jobu,jobvt,N,M,g,LDg,S,U,LDU,VT,LDVT,work,lwork,info)
print *, 'here'
S2 = 0.0*g
do j = 1,N
do i = 1,M
if (j == i .and. S(i) >= 10**(-4)*S(1)) then ! If M > N, replace S(i) with S(j)
S2(j,i) = 1/S(i)
end if
end do
end do
g_i = matmul( transpose(VT),matmul(transpose(S2),transpose(U)) )
I_check = matmul(g_i,g)
write (*,1) sum(sum(I_check,1))
1 format(1f10.5)
print *, 'info = ',info
open(4, file='Pseud_inverse.txt')
do i = 1,N*M
write(4,3) g_i
end do
close(4)
3 format(1f10.3)
call cpu_time(t3)
print *, t3-t2
deallocate(g_)
deallocate(g)
deallocate(g_i)
deallocate(work)
deallocate(S)
deallocate(S2)
deallocate(U)
deallocate(VT)
deallocate(I_check)
end
调用dgesvd
时会出现该错误消息,因此我认为它必须来自此子例程。我查阅了该例程的文档,似乎我没有违反任何要求。
我也使用相同的输入矩阵进行了与上面相同的计算,但是jobu=jobvt='N'
因此不计算U
和VT
,因此它们的内存分配并不重要,它有效。上述代码仍然没有成功。
答案 0 :(得分:1)
首先,确保你有足够的内存来分配这么大的矩阵,大约5GB,即使这不是错误的来源。无论如何,在这种情况下,我建议执行矩阵的截断SVD,因为您可以节省大量内存。
此外,lwork
的定义如下:
数组的维度WORK。
LWORK >= MAX(1,5*MIN(M,N)) for the paths (see comments inside code): - PATH 1 (M much larger than N, JOBU='N') - PATH 1t (N much larger than M, JOBVT='N') LWORK >= MAX(1,3*MIN(M,N) + MAX(M,N),5*MIN(M,N)) for the other paths For good performance, LWORK should generally be larger.
您将N
作为行传递,将M
作为列传递给子例程。请注意,在文档中,它使用N
作为列,M
作为行。也许这里有一个混乱。仔细检查以确定。因此,对于您的情况,lwork
将是269824,低于您指定的值。但是,我会尽力坚持文档。
最后,我前段时间编写了一个Fortran模块,它有助于使用Lapack库和其他有用的计算执行SVD(截断 - 保存内存)。你可以找到它here。如果有帮助,请随时查看并使用它。注意它是针对单精度Lapack子程序的,但是你不应该有任何问题来使它适应双精度子程序。