Matrix 分配矩阵时Fortran Seg错误
[更新]代码和几句话已更改,以反映我在第二条评论中解释的实现。代码应该用下面的代码行编译,但是,我有一个较旧的gfortran,可能没有看到您可能看到的一些错误Matrix 分配矩阵时Fortran Seg错误,matrix,segmentation-fault,fortran,derived-types,Matrix,Segmentation Fault,Fortran,Derived Types,[更新]代码和几句话已更改,以反映我在第二条评论中解释的实现。代码应该用下面的代码行编译,但是,我有一个较旧的gfortran,可能没有看到您可能看到的一些错误 gfortran BLU_implementation_copy.f90 -o BLU_implementation_copy.x 我在Fortran 90运行时遇到了一个难以置信的不一致seg错误 我的代码的总体目标是将一个随机生成的、复杂的、对称的、对角占优的矩阵分解成易于并行化的块。最后可以找到精简版(相关功能除外) 在函数ma
gfortran BLU_implementation_copy.f90 -o BLU_implementation_copy.x
我在Fortran 90运行时遇到了一个难以置信的不一致seg错误
我的代码的总体目标是将一个随机生成的、复杂的、对称的、对角占优的矩阵分解成易于并行化的块。最后可以找到精简版(相关功能除外)
在函数mat2tiles中将原始矩阵分解为块(tile)时,我遇到了错误。具体而言,这一行代码不断失败:
o(i,j)=单元(x(a:min(i*Nblock,M),b:min(j*Nblock,N))
这是将输入矩阵X的一个块分配给索引i,j处的矩阵o。它实现了这一点,因为o的每个索引都是通过派生类型的矩阵NblockxNblock:
类型单元
复杂*16::块(Nblock,Nblock)
端型单元格
type(cell) :: o(M/Nblock+rem,N/Nblock+rem)
对于特定的矩阵大小和瓷砖大小,一切都可以完美地工作。对于较大的尺寸,错误开始出现在接近矩阵尺寸的瓷砖尺寸中,并最终达到矩阵尺寸的一半。例如,我发现发生这种情况的最小实例是一个20x20矩阵,其平铺大小为18。但这种情况并非始终如一。如果我尝试使用较小的矩阵,这些矩阵都正常运行,并且构建到该大小,它就会运行。如果我做一个更大尺寸的seg故障,然后运行20x20和18,它seg故障。我发现的最小一致参数是25x25,瓷砖大小为23。然而,即使使用这种大小,如果我打印出在o(I,j)赋值行之后失败的块:
print*,o(2,1)%block
它突然毫无问题地贯穿了整个过程。取出print语句使其再次出现seg错误。
最后,最恼人的一个问题[修复-请参阅我的第二条评论],如果我使用一个2000 x2000矩阵,其平铺大小为1000或更大,我在进入函数后会出现seg错误(这意味着它发生在变量分配期间)。这让我相信问题可能源于矩阵是如何分配的,特别是因为我使用的是派生类型。但当我试图诊断矩阵的大小和内容时,一切似乎都正常
program BLU_implementation
implicit none
integer :: rem
integer, parameter :: M=20, N=20, Nblock=19
real*8 :: start, finish
complex*16 :: A(M,N)
type cell
complex*16 :: block(Nblock,Nblock)
end type cell
!determines if cell matrix doesn't need to be bigger
rem=1
if (modulo(M,Nblock)==0) then
rem=0
endif
call cpu_time(start)
call functionCalling(A, M, N, Nblock, rem)
call cpu_time(finish)
print*, 'overall time:', finish-start, 'seconds'
contains
!==================================================================================================================
subroutine functionCalling(A, M, N, Nblock, rem)
implicit none
integer :: IPIV, INFO, M, N, Nblock, rem
real*8 :: start, finish
complex*16 :: A(M,N)
type(cell) :: C(M/Nblock+rem,N/Nblock+rem)
call cpu_time(start)
A= CSPDmatrixFill(A,M,N)
call cpu_time(finish)
print*, 'matrix fill time:', finish-start, 'seconds'
call cpu_time(start)
C= mat2tiles(A,M,N,Nblock,rem)
call cpu_time(finish)
print*, 'tiling time:', finish-start, 'seconds'
end subroutine
!===================================================================================================================
! generates a complex, symmetric, positive-definite matrix (based off of another's code)
function CSPDmatrixFill(A, M, N) result (Matrix)
! initialization
implicit none
integer :: i, j
integer :: M, N
real*8 :: x, xi
complex*16 :: A(M, N), Matrix(M, N), EYE(M, N), MT(N, M)
EYE=0
forall(j=1:M) EYE(j,j)=1
! execution
call random_seed
do i=1, M
do j=1, N
call random_number (x)
call random_number(xi)
Matrix(i,j) = cmplx(x,xi)
end do
end do
! construct a symmetric matrix ( O(n^2) )
call Mtranspose(Matrix, M, N)
Matrix = Matrix+MT
! make positive definite (diagonally dominant)
Matrix = Matrix + N*EYE
end function CSPDmatrixFill
!======================================================================================================
subroutine Mtranspose(A, i, j)
! takes a matrix and the two parameters used to make the matrix: A(i,j)
! returns a matrix with switched indices: A(j,i)
implicit none
integer :: i, j
complex*16 :: A(i,j), MT(j,i)
MT=A(j,i)
return
end subroutine Mtranspose
!=======================================================================================================
!MAT2TILES - breaks up an array into a cell array of adjacent sub-arrays of equal sizes
!
! O=mat2tiles(X,M,N,Nblock)
!
!will produce a cell array o containing adjacent chunks of the array X(M,N)
!with each chunk of dimensions NblockxNblock. If Nblock does
!not divide evenly into size(X,i), then the chunks at the upper boundary of
!X along dimension i will have bogus values that do not affect the factorization
!in the places where the matrix doesn't occupy. (according to older versions. Might have changed with some edits)
!
function mat2tiles(X,M,N,Nblock,rem) result(o)
! initialization
implicit none
integer :: a, b, i, j, M, N, Nblock, rem
complex*16 :: X(M,N)
type(cell) :: o(M/Nblock+rem,N/Nblock+rem)
! diagnostic print statements
print*,size(o(1,1)%block), size(o(1,2)%block), size(o(2,1)%block), size(o(2,2)%block)
print*, 'got to start'
! turn matrix x into cell matrix o
do j=1, N/Nblock+rem
if (j==1) then
b=j
else
b=b+Nblock
endif
do i=1, M/Nblock+rem
if (i==1) then
a=i
else
a=a+Nblock
endif
! diagnostic print statement
print*, 'writing to o: i:', i, 'j:', j, 'i*Nblock:', i*Nblock, 'j*Nblock:', j*Nblock, 'min of i:', min(i*Nblock, M), &
'min of j:', min(j*Nblock, N), 'a:', a, 'b:', b
o(i,j)=cell(x(a:min(i*Nblock,M), b:min(j*Nblock, N)))
enddo
enddo
! diagnostic print statement
print*, 'got to end'
return
end function mat2tiles
!==================================================================================================
end program
在将问题缩小到使用数字和相同数字的变量之后,人们发现Fortran不喜欢将矩阵分配给不同维度的矩阵,即使它适合内部。这很奇怪,因为较小的
M
、N
和Nblock
值完美地解决了这个问题
解决方案是简单地定义o(i,j)%block(1:Nblock,1:Nblock)=x(dim1:dim2等)
而不是o(i,j)=cell(x(dim1:dim2等)
来表示i=1
和j=1
的
正确的代码(适用于矩阵大小和磁贴大小的所有情况)如下所示:
if (i==M/Nblock+rem .AND. j==N/Nblock+rem .AND. rem==1) then
o(i,j)%block(1:M-(i-1)*Nblock,1:N-(j-1)*Nblock)=x(a:min(i*Nblock,M), b:min(j*Nblock, N))
else if (i==M/Nblock+rem .AND. j/=N/Nblock+rem .AND. rem==1) then
o(i,j)%block(1:M-(i-1)*Nblock,1:Nblock)=x(a:min(i*Nblock,M), b:min(j*Nblock, N))
else if (i/=M/Nblock+rem .AND. j==N/Nblock+rem .AND. rem==1) then
o(i,j)%block(1:Nblock,1:N-(j-1)*Nblock)=x(a:min(i*Nblock,M), b:min(j*Nblock, N))
else
o(i,j)%block(1:Nblock,1:Nblock)=x(a:min(i*Nblock,M), b:min(j*Nblock, N))
end if
通过此更正,我的代码在gfortran的新旧版本上运行。然而,值得注意的是,Mac OS X版本的gfortran从未遇到此错误,只有Linux版本。您提供的代码甚至没有编译!我收到大量错误消息。请先解决这些问题,也许您的问题会在这个过程。@AlexanderVogt嗨,它为我编译了以下代码行:gfortran BLU_implementation_copy.f90-o BLU_implementation_copy.x~/lapack/liblapack.a~/lapack/librefblas.aHey各位!更新:我发现了部分问题。我的编译器有点旧,没有发现错误。在另一台计算机上,编译器在f中发现了错误CSPDmatrix fill的函数行,其中我为函数定义了“complex”。这与正确的数据类型相冲突,去掉它,2000x2000和1000个磁贴大小的案例运行。但是,其他案例仍然存在seg故障。