"In call to DSYEV, an array temporary was created for argument" infort 但相关维度只有 1

"In call to DSYEV, an array temporary was created for argument" in ifort but the related dimension is only 1

相关问题Temporary array creation and routine GEMM

对于以下 Fortran 代码(修改自 dsyev in fortran 90

program test_dsyev   
implicit none  
integer, parameter :: dp = selected_real_kind(15, 307)
real(dp), allocatable  :: A(:,:), A2(:,:,:), work (:), w(:)  
real(dp) :: c1
integer :: i, j  
integer :: lwork, info,  n, lda  
character :: jobz, UPLO 

n=5
allocate(A(n,n))  
allocate(A2(1,n,n))  

A = 0.0_dp
c1 = 1.0_dp
do i = 1, n  
   do j = 1, n
     A(i, j) = i * c1 + j * c1  
   end do  
end do  
A2(1,:,:) = A

lda = n  
lwork = 10 * n  

jobz = 'N'
UPLO = 'U'
allocate(work(lwork))  
allocate(w(n))  
call dsyev(jobz,uplo,n,A,lda,w,work,lwork,info)  
write (*,*) w

call dsyev(jobz,uplo,n,A2(1,:,:),lda,w,work,lwork,info)
write (*,*) w
end program test_dsyev

d.f90ifort -mkl -warn all -check all d.f90 给我

 -1.58312395177700      -1.465651932086313E-015  8.229374109843719E-018
  4.803282588162841E-016   31.5831239517770
forrtl: warning (406): fort: (1): In call to DSYEV, an array temporary was created for argument #4

Image              PC                Routine            Line        Source
a.out              0000000000408E86  Unknown               Unknown  Unknown
a.out              000000000040580B  Unknown               Unknown  Unknown
a.out              0000000000403812  Unknown               Unknown  Unknown
libc-2.17.so       00002B10A2A31555  __libc_start_main     Unknown  Unknown
a.out              0000000000403729  Unknown               Unknown  Unknown
  -1.58312395177700      -1.465651932086313E-015  8.229374109843719E-018

看来警告信息与A2(1,:,:)和内存不连续有关。是的,Fortran 是专栏专业的。但是,A2 的第一个维度是 1。A2 应该遵循 A2(1,1,1)A2(1,2,1)、...,我的意思是,A2 的第一个索引确实不参与内存分配。还是我完全错了?

让我们考虑一个更简单的程序来查看发生了什么:

  implicit none

  integer i(1,1)
  call s(i(1,:))

contains

  subroutine s(j)
    integer j(*)
  end subroutine s

end program

使用 -check 编译以启用临时复制检查,我们可以看到完全相同的警告:

forrtl: warning (406): fort: (1): In call to S, an array temporary was created for argument #1

像问题的例子一样,伪参数假定大小,实际参数是相同等级的数组部分,但比整个数组小一级。

数组部分 i(1,:) 实际参数是连续的,所以也许不需要为虚拟 j 临时复制?看看这个,当 i 不是 只是 连续时,ifort 会制作一个临时副本,即使它“显然”是连续的。1

但是,因为伪参数 j 是 assumed-size,我们不需要担心传递数组部分 i(1,:):我们可以传递整个数组 i,或简单连续的部分 i(:,:)。我们可以这样做,因为当虚拟参数为 assumed-size(或 explicit-size)时,实际参数和虚拟参数的等级不需要匹配。

请注意,如果假定虚拟对象为 -shape,则行列确实需要匹配,但编译器可能会通过传递数组 descriptor/dope 来处理参数关联而不是制作临时副本:与 assumed- 和 explicit-size 数组参数不同,assumed-shape 虚拟对象不必连续。 (编译器可能仍然会制作一个临时副本,并在它认为有益时警告制作临时副本,但这并不总是会发生。)

最后,我推测警告的触发器是简单的连续性(很高兴知道 confirm/dispute 的人),但有一些证据表明您可以通过简单的替代方法避免运行时检查警告像这里一样处理。 (如果不是简单地连续,那么制作副本是完全有意义的:简单连续性以一种易于检查的方式定义。)


1 i(1,:) 不是简单连续的,即使第一个范围是 1,因为简单连续的规则(F2018,9.5.4):

no subscript-triplet is preceded by a section-subscript that is a subscript.

第二位的:是下标三联体,而第一位的1是下标