厄米特矩阵对角化中的特征向量不连续

时间:2017-03-15 18:57:02

标签: fortran gfortran fortran77 intel-fortran

我需要对2x2 Hermitian矩阵进行对角化,该矩阵取决于参数x,该参数x连续变化。对于对角化我使用EISPACK。当我绘制特征向量的实部和虚部作为x的函数时,我注意到它们具有不连续性。特征值计算是可以的。当我在Maxima中绘制特征向量时,解决方案看起来是连续的。我需要连续的特征向量,因为在下一步中我将需要计算它们的导数。

在f77代码下面,我用作测试(在mingw上用gfortran编译)。

program Eigenvalue

  implicit none

  integer n, m 
  parameter (n=2)
  integer  ierr, matz, i, j 
  double precision x, dx, xf, amp, xin 
  double precision w(n)
  double precision Ar(n,n), Ai(n,n)
  double precision xr(n,n), xi(n,n)
  double precision fm1(2,n)   ! f77
  double precision fv1(n)     ! f77 
  double precision fv2(n)     ! f77       
  double complex psi1a, psi1b, psi2a, psi2b 

  m = 51              

  xf  = 10.d0  
  xin = 0.0d0     

  amp = 2.d0 
  dx = (xf - xin)/(m-1)

  do i = 1, m     
  x = dx*(i-m) + xf   

  Ar(1,1) = dsin(x)**2
  Ar(1,2) = amp*dcos(x)
  Ar(2,1) = amp*dcos(x)
  Ar(2,2) = dcos(x)**2

  Ai(1,1) = 0.0d0
  Ai(1,2) = amp*dsin(x)  
  Ai(2,1) = -amp*dsin(x) 
  Ai(2,2) = 0.0d0

  matz = 1

  call ch ( n, n, ar, ai, w, matz, xr, xi, fv1, fv2, fm1, ierr ) !f77

  write(20,*) x, w(1), w(2)

  write(21,*) x, xr(1,1), xi(1,1)
  write(22,*) x, xr(2,1), xi(2,1)

  write(23,*) x, xr(1,2), xi(1,2)
  write(24,*) x, xr(2,2), xi(2,2)       

!     autovetor 1

  psi1a = cmplx(xr(1,1),xi(1,1)) 
  psi1b = cmplx(xr(1,2),xi(1,2)) 

!     autovetor 2 

  psi2a = cmplx(xr(2,1),xi(2,1)) 
  psi2b = cmplx(xr(2,2),xi(2,2))         

  end do
  end

1 个答案:

答案 0 :(得分:1)

虽然不是真正的答案,但接下来是我与LAPACK一起使用的代码。 我使用了最新版本的LAPACK和BLAS,以及以下编译器选项:

gfortran -Og -std = f2008 -Wall -Wextra {location_of_lapack} /liblapack.a {location_of_blas} /blas_LINUX.a main.f90 -o main

我在Mac OS X上使用家乡的gfortran 6.3.0进行编译。

正如上面提到的那样,像cos这样的东西被cos替换了,我使用了KIND =配方来确保相同的精度。

伊恩上面也提到过任意阶段。 回答here;我已将此解决方案翻译成下面的代码。 "魔术"在打电话给ZHEEV之后发生。

通过此修复,我看到没有不连续性。

program Eigenvalue
  !> This can be used with the f2008 call
  use, intrinsic :: iso_fortran_env
  implicit none

  !> dp contains the kind value for double precision.
  !> Use below if compiling to f2008
  integer, parameter :: dp = REAL64
  !> Use below if compiling with f95 up and comment out iso_fortran_env
  !>integer, parameter :: dp = SELECTED_REAL_KIND(15, 300)
  !> Set wp to the desired precision.
  integer, parameter :: wp = dp

  integer, parameter :: n = 2
  integer :: i, j, k, m
  real(kind=wp) x, dx, xf, amp, xin 
  real(kind=wp), dimension(n) ::  w
  real(kind=wp), dimension(n, n) ::  Ar, Ai
  complex(kind=wp), dimension(n, n) :: A
  complex(kind=wp), dimension(max(1,2*n-1)) :: WORK
  integer, parameter :: lwork = max(1,2*n-1)
  real(kind=wp), dimension(max(1, 3*n-2)) :: RWORK
  integer :: info
  complex(kind=wp) ::  psi1a, psi1b, psi2a, psi2b 
  real(kind=wp) :: mag
  m = 51              

  xf  = 10.0_wp
  xin = 0.0_wp   

  amp = 2.0_wp

  if (m .eq. 1) then
     dx = 0.0_wp
  else
     dx = (xf - xin)/(m-1)
  end if

  do i = 1, m
     x = dx*(i-m) + xf   

     Ar(1,1) = sin(x)**2
     Ar(1,2) = amp*cos(x)
     Ar(2,1) = amp*cos(x)
     Ar(2,2) = cos(x)**2

     Ai(1,1) = 0.0_wp
     Ai(1,2) = amp*sin(x)  
     Ai(2,1) = -amp*sin(x) 
     Ai(2,2) = 0.0_wp

     do j = 1, n
        do k = 1, n
           A(j, k) = cmplx(Ar(j, k), Ai(j, k), kind=wp)
        end do
     end do
     call ZHEEV('V', 'U', N, A, N, W, WORK, LWORK, RWORK, INFO)
     do j = 1, n
        A(:, j) = A(:, j) / A(1, j)
        mag = sqrt(real(A(1, j)*conjg(A(1, j)))+ real(A(2, j)*conjg(A(2, j))))
        A(:, j) = A(:, j)/mag
     end do

     psi1a = A(1, 1)
     psi1b = A(1, 2)
     psi2a = A(2, 1)
     psi2b = A(2, 2)

  end do
end program Eigenvalue