运行dgesvd时内存引用无效

时间:2016-12-09 12:27:41

标签: segmentation-fault fortran

我正在尝试使用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'因此不计算UVT,因此它们的内存分配并不重要,它有效。上述代码仍然没有成功。

1 个答案:

答案 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子程序的,但是你不应该有任何问题来使它适应双精度子程序。