Segmentation fault using SCALAPACK in Fortran? No backtrace? - fortran

I'm trying to find the eigenvalues and eigenvectors of a Hermitian matrix using SCALAPACK and MPI in Fortran. For bug-squashing, I made this program as simple as possible, but am still getting a segmentation fault. Per the answers given to people with similar questions, I've tried changing all of my integers to integer*8, and all of my reals to real*8 or real*16, but I still get this issue. Most interestingly, I don't even get a backtrace for the segmentation fault: the program hangs up when trying to give me a backtrace and has to be aborted manually.
Also, please forgive my lack of knowledge -- I'm not familiar with most program-y things but I've done my best. Here is my code:
PROGRAM easydiag
IMPLICIT NONE
INCLUDE 'mpif.h'
EXTERNAL BLACS_EXIT, BLACS_GET, BLACS_GRIDEXIT, BLACS_GRIDINFO
EXTERNAL BLACS_GRIDINIT, BLACS_PINFO,BLACS_SETUP, DESCINIT
INTEGER,EXTERNAL::NUMROC,ICEIL
REAL*8,EXTERNAL::PDLAMCH
INTEGER,PARAMETER::XNDIM=4 ! MATRIX WILL BE XNDIM BY XNDIM
INTEGER,PARAMETER::EXPND=XNDIM
INTEGER,PARAMETER::NPROCS=1
INTEGER COMM,MYID,ROOT,NUMPROCS,IERR,STATUS(MPI_STATUS_SIZE)
INTEGER NUM_DIM
INTEGER NPROW,NPCOL
INTEGER CONTEXT, MYROW, MYCOL
COMPLEX*16,ALLOCATABLE::HH(:,:),ZZ(:,:),MATTODIAG(:,:)
REAL*8:: EIG(2*XNDIM) ! EIGENVALUES
CALL MPI_INIT(ierr)
CALL MPI_COMM_RANK(MPI_COMM_WORLD,myid,ierr)
CALL MPI_COMM_SIZE(MPI_COMM_WORLD,numprocs,ierr)
ROOT=0
NPROW=INT(SQRT(REAL(NPROCS)))
NPCOL=NPROCS/NPROW
NUM_DIM=2*EXPND/NPROW
CALL SL_init(CONTEXT,NPROW,NPCOL)
CALL BLACS_GRIDINFO( CONTEXT, NPROW, NPCOL, MYROW, MYCOL )
ALLOCATE(MATTODIAG(XNDIM,XNDIM),HH(NUM_DIM,NUM_DIM),ZZ(NUM_DIM,NUM_DIM))
MATTODIAG=0.D0
CALL MAKEHERMMAT(XNDIM,MATTODIAG)
CALL MPIDIAGH(EXPND,MATTODIAG,ZZ,MYROW,MYCOL,NPROW,NPCOL,NUM_DIM,CONTEXT,EIG)
DEALLOCATE(MATTODIAG,HH,ZZ)
CALL MPI_FINALIZE(IERR)
END
!****************************************************
SUBROUTINE MAKEHERMMAT(XNDIM,MATTODIAG)
IMPLICIT NONE
INTEGER:: XNDIM, I, J, COUNTER
COMPLEX*16:: MATTODIAG(XNDIM,XNDIM)
REAL*8:: RAND
COUNTER = 1
DO J=1,XNDIM
DO I=J,XNDIM
MATTODIAG(I,J)=COUNTER
COUNTER=COUNTER+1
END DO
END DO
END
!****************************************************
SUBROUTINE MPIDIAGH(EXPND,A,Z,MYROW,MYCOL,NPROW,NPCOL,NUM_DIM,CONTEXT,W)
IMPLICIT NONE
EXTERNAL DESCINIT
REAL*8,EXTERNAL::PDLAMCH
INTEGER EXPND,NUM_DIM
INTEGER CONTEXT
INTEGER MYCOL,MYROW,NPROW,NPCOL
COMPLEX*16 A(NUM_DIM,NUM_DIM), Z(NUM_DIM,NUM_DIM)
REAL*8 W(2*EXPND)
INTEGER N
CHARACTER JOBZ, RANGE, UPLO
INTEGER IL,IU,IA,JA,IZ,JZ
INTEGER LIWORK,LRWORK,LWORK
INTEGER M, NZ, INFO
REAL*8 ABSTOL, ORFAC, VL, VU
INTEGER DESCA(50), DESCZ(50)
INTEGER IFAIL(2*EXPND), ICLUSTR(2*NPROW*NPCOL)
REAL*8 GAP(NPROW*NPCOL)
INTEGER,ALLOCATABLE:: IWORK(:)
REAL*8,ALLOCATABLE :: RWORK(:)
COMPLEX*16,ALLOCATABLE::WORK(:)
N=2*EXPND
JOBZ='V'
RANGE='I'
UPLO='U' ! This should be U rather than L
VL=0.d0
VU=0.d0
IL=1 ! EXPND/2+1
IU=2*EXPND ! EXPND+(EXPND/2) ! HERE IS FOR THE CUTTING OFF OF THE STATE
M=IU-IL+1
ORFAC=-1.D0
IA=1
JA=1
IZ=1
JZ=1
ABSTOL=PDLAMCH( CONTEXT, 'U')
CALL DESCINIT( DESCA, N, N, NUM_DIM, NUM_DIM, 0, 0, CONTEXT, NUM_DIM, INFO )
CALL DESCINIT( DESCZ, N, N, NUM_DIM, NUM_DIM, 0, 0, CONTEXT, NUM_DIM, INFO )
LWORK = -1
LRWORK = -1
LIWORK = -1
ALLOCATE(WORK(LWORK))
ALLOCATE(RWORK(LRWORK))
ALLOCATE(IWORK(LIWORK))
CALL PZHEEVX( JOBZ, RANGE, UPLO, N, A, IA, JA, DESCA, VL, &
VU, IL, IU, ABSTOL, M, NZ, W, ORFAC, Z, IZ, &
JZ, DESCZ, WORK, LWORK, RWORK, LRWORK, IWORK, &
LIWORK, IFAIL, ICLUSTR, GAP, INFO )
LWORK = INT(ABS(WORK(1)))
LRWORK = INT(ABS(RWORK(1)))
LIWORK =INT (ABS(IWORK(1)))
DEALLOCATE(WORK)
DEALLOCATE(RWORK)
DEALLOCATE(IWORK)
ALLOCATE(WORK(LWORK))
ALLOCATE(RWORK(LRWORK))
ALLOCATE(IWORK(LIWORK))
PRINT*, LWORK, LRWORK, LIWORK
CALL PZHEEVX( JOBZ, RANGE, UPLO, N, A, IA, JA, DESCA, VL, &
VU, IL, IU, ABSTOL, M, NZ, W, ORFAC, Z, IZ, &
JZ, DESCZ, WORK, LWORK, RWORK, LRWORK, IWORK, &
LIWORK, IFAIL, ICLUSTR, GAP, INFO )
RETURN
END
The problem is with the second PZHEEVX function. I'm fairly certain that I'm using it correctly since this code is a simpler version of another more complicated code that works fine. For this purpose, I'm only using one processor.
Help!

According to this page
setting LWORK = -1 seems to request the PZHEEVX routine to return the necessary size of all the work arrays, for example,
If LWORK = -1, then LWORK is global input and a workspace query
is assumed; the routine only calculates the optimal size for
all work arrays. Each of these values is returned in the first
entry of the corresponding work array, and no error message is
issued by PXERBLA.
Similar explanations can be found for LRWORK = -1. As for IWORK,
IWORK (local workspace) INTEGER array
On return, IWORK(1) contains the amount of integer workspace
required.
but in your program the work arrays are allocated as
LWORK = -1
LRWORK = -1
LIWORK = -1
ALLOCATE(WORK(LWORK))
ALLOCATE(RWORK(LRWORK))
ALLOCATE(IWORK(LIWORK))
and after the first call of PZHEEVX, the sizes of the work arrays are obtained as
LWORK = INT(ABS(WORK(1)))
LRWORK = INT(ABS(RWORK(1)))
LIWORK =INT (ABS(IWORK(1)))
which looks inconsistent (-1 vs 1). So it will be better to modify the allocation as (*)
allocate( WORK(1), RWORK(1), IWORK(1) )
An example in this page also seems to allocate the work arrays this way. Another point of concern is that INT() is used in several places (for example, NPROW=INT(SQRT(REAL(NPROCS))), but I guess it might be better to use NINT() to avoid the effect of round-off errors.
(*) More precisely, allocation of an array with -1 is not valid because the size of an allocated array becomes 0 (thanks to #francescalus). You can verify this by printing size(a) or a(:). To prevent this kind of error, it is very useful to attach compiler options like -fcheck=all (for gfortran) or -check (for ifort).

There's a fishy piece of dimensioning in your code which can easily be responsible for the segfault. In your main program you set
EXPND=XNDIM=4
NUM_DIM=2*EXPND !NPROW==1 for a single-process test
ALLOCATE(MATTODIAG(XNDIM,XNDIM)) ! MATTODIAG(4,4)
Then you pass your MATTODIAG, the Hermitian matrix, to
CALL MPIDIAGH(EXPND,MATTODIAG,ZZ,MYROW,...)
which is in turn defined as
SUBROUTINE MPIDIAGH(EXPND,A,Z,MYROW,...)
COMPLEX*16 A(NUM_DIM,NUM_DIM) ! A(8,8)
This is already an inconsistency, which can mess up the computations in that subroutine (even without having a segfault). Furthermore, the subroutine along with scalapack thinks that A is of size (8,8), instead of (4,4) which you allocated in the main program, allowing the subroutine to overrun available memory.

Related

Trouble with Intel MKL libraries: segfault / unresolved external symbol

I am compiling some code trying to use the Intel MKL library eigensolvers. I am already using the VSL RNG's and the DFT libraries without issue. I am compiling and running everything in Visual Studio with Intel Parallel Studio XE installed. I have ensured that the mkl flag is enabled in project properties.
include 'lapack.f90'
program heev_test
use lapack95
implicit none
integer , parameter :: dp = kind(0.0d0)
complex(dp) :: matrix(4,4)
real(dp) :: eigs(4)
matrix = (1.0_dp,0.0_dp)
call zheev(matrix, eigs)
print*, eigs
read(*,*)
stop
end program
Running this code yields a segfault on two machines I have tested it on so far. I believe the issue is that the F77 routines are being called which require more arguments (documentation here). I would like to use the far simpler F95 routines. According to the documentation, I should replace zheev with heev. So I tried that, but then I get the error
fatal error LNK1120: 1 unresolved externals
error LNK2019: unresolved external symbol _ZHEEV_F95 referenced in function _MAIN__
ZHEEV_F95 has an interface defined in the lapack.f90 file.
The only other thing I have right now is that the documentation says I should also include mkl.fi, but doing so I get the following compilation errors
Error error #6218: This statement is positioned incorrectly and/or has syntax errors. C:\Program Files (x86)\IntelSWTools\compilers_and_libraries_2018\windows\\mkl\include\lapack.f90 21
Error error #6790: This is an invalid statement; an END [PROGRAM] statement is required. C:\Program Files (x86)\IntelSWTools\compilers_and_libraries_2018\windows\\mkl\include\lapack.f90 24
Error error #6785: This name does not match the unit name. [F95_PRECISION] C:\Program Files (x86)\IntelSWTools\compilers_and_libraries_2018\windows\\mkl\include\lapack.f90 24
Error Compilation Aborted (code 1)
Warning warning #5427: Program may contain only one main entry routine
referring to these lines from the lapack.f90 file:
21 MODULE F95_PRECISION
22 INTEGER, PARAMETER :: SP = KIND(1.0E0)
23 INTEGER, PARAMETER :: DP = KIND(1.0D0)
24 END MODULE F95_PRECISION
The solution was to link the Lapack95 library explicitly, which is not linked with simply the -mkl flag. For example, on Windows 64-bit with 4 byte integers compiled with the Intel Fortran compiler, use
ifort /Qmkl heev_test.f90 mkl_lapack95_lp64.lib
As for the seg fault, I was improperly calling the F77 routines. Since I did not provide an interface for these routines, the compiler did not complain, and when I did call them, it caused a segmentation fault since the arguments were not properly input.
Here is a code which properly calls both routines, and can be verified to produce the same results.
include 'lapack.f90'
program heev_test
use lapack95
implicit none
integer , parameter :: dp = kind(0.0d0)
complex(dp) :: matrix(4,4)
real(dp) :: eigs(4)
matrix = (1.0_dp,0.0_dp)
print*, "checking eigenvalues using zheevr"
call eigenvalues(matrix,eigs)
print*, eigs
matrix = (1.0_dp,0.0_dp)
print*, "checking eigenvalues using heevr"
call heevr(matrix,eigs)
print*, eigs
read(*,*)
stop
contains
subroutine eigenvalues(a,w)
complex(dp) :: a(:,:)
real(dp) :: w(:)
character*1 :: jobz, range, uplo
integer :: n, m, lda, il, iu, ldz
real(dp) :: vl, vu, abstol
integer :: info
integer :: lwork, liwork, lrwork
complex(dp) , allocatable :: z(:,:)
complex(dp) , allocatable :: work(:)
real(dp) , allocatable :: rwork(:)
integer , allocatable :: iwork(:)
integer , allocatable :: isuppz(:)
jobz = 'N'
range = 'A'
uplo = 'U'
n = size(a,dim=1)
lda = max(1,n)
vl = -huge(vl)
vu = +huge(vl)
il = 1
iu = n
abstol = 0.0_dp
ldz = max(1,n)
lwork = max(1,2*n)
lrwork = max(1,24*n)
liwork = max(1,10*n)
allocate(work(lwork))
allocate(rwork(lrwork))
allocate(iwork(liwork))
allocate(z(ldz,max(1,n)))
allocate(isuppz(2*max(1,n)))
lwork = -1
liwork = -1
lrwork = -1
call zheevr(jobz, range, uplo, n, a, lda, vl, vu, il, iu, abstol, m, w, &
& z, ldz, isuppz, work, lwork, rwork, lrwork, iwork, liwork, info)
lwork = work(1)
liwork = iwork(1)
lrwork = rwork(1)
deallocate(work,iwork,rwork)
allocate(work(lwork))
allocate(iwork(liwork))
allocate(rwork(lrwork))
call zheevr(jobz, range, uplo, n, a, lda, vl, vu, il, iu, abstol, m, w, &
& z, ldz, isuppz, work, lwork, rwork, lrwork, iwork, liwork, info)
deallocate(work,iwork,rwork)
if (info /= 0) then
print*, "diagonalization failed, info = ", info
read(*,*)
stop
end if
end subroutine
end program
In my case, the f95 libraries were not installed on the target machine (a remote cluster), so I had to fall back on the f77 library, for which the above subroutine is essentially equivalent to the f95 interface for a square matrix and can be easily modified. See the documentation for definitions of variables.
Note that according to the documentation, heevr/zheevr is a more efficient routine than heev/zheev, so I switched them.

How to find optimal block size and LWORK in LAPACK

I am trying to find inverse and eigenfunctions of nxn Hermitian matrices using Fortran with lapack.
How do I choose the optimal values for parameters like lda, lwork, liwork and lrwork. I browse through some example and find these choices
integer,parameter::lda=nh
integer,parameter::lwork=2*nh+nh*nh
integer,parameter::liwork=3+5*nh
integer,parameter::lrwork=1 + 5*nh + 2*nh*nh
where nh is the dimension of the matrix. I also find another example with lwork=16*nh. How can I determine the best choice? At this point, I am dealing with 500x500 Hermitian matrices (maximum).
I found this documentation which suggests
WORK
(workspace) REAL array, dimension (LWORK)
On exit, if INFO = 0, then WORK(1) returns the optimal LWORK.
LWORK
(input) INTEGER
The dimension of the array WORK. LWORK  max(1,N).
For optimal performance LWORK  N*NB, where NB is the optimal block size returned by ILAENV.
Is it possible to find out the optimal block size using WORK or ILAENV for a given matrix dimension?
I am using both gfortran and ifort with mkl.
EDIT
Based on the comment by #percusse and #kvantour's answer here is a sample code
character,parameter::jobz="v",uplo="u"
integer, parameter::nh=15
complex*16::m(nh,nh),m1(nh,nh)
integer,parameter::lda=nh
integer::ipiv(nh),info
complex*16::work(1)
real*8::rwork(1), w(nh)
integer::iwork(1)
real*8::x1(nh,nh),x2(nh,nh)
call random_seed()
call random_number(x1)
call random_number(x2)
m=cmplx(x1,x2)
m1=conjg(m)
m1=transpose(m1)
m=(m+m1)/2.0
call zheevd(jobz,uplo,nh,m,lda,w,work,-1,rwork,-1,iwork, -1,info)
print*,"info : ", info
print*,"lwork: ", int(work(1)) , 2*nh+nh*nh
print*,"lrwork:", int(rwork(1)) , 1 + 5*nh + 2*nh*nh
print*,"liwork:", int(iwork(1)) , 3+5*nh
end
info : 0
lwork: 255 255
lrwork: 526 526
liwork: 78 78
I'm not sure what you are implying with "Is it possible to find out the optimal block size using WORK or ILAENV for a particular machine architecture?". You can however find the optimal values for a particular problem.
Eg. If you want to find the eigenvalues of a complex Hermitian matrix, using cheev, you can ask the routine to return you the value :
subroutine CHEEV( JOBZ, UPLO, N, A, LDA, W, WORK, LWORK, RWORK, INFO )
character , intent(in) :: JOBZ
character , intent(in) :: UPLO
integer , intent(in) :: N
complex, dimension(lda,*), intent(inout) :: A
integer , intent(in) :: LDA
real , dimension(*) , intent(out) :: W
complex, dimension(*) , intent(out) :: WORK
integer , intent(in) :: LWORK
real , dimension(*) , intent(out) :: RWORK
integer , intent(out) :: INFO
Then the documentation clearly states (be advised, in the past this was easier to read):
WORK is COMPLEX array, dimension (MAX(1,LWORK))
On exit, if INFO = 0, WORK(1) returns the optimal LWORK.
LWORK is INTEGER
The length of the array WORK. LWORK >= max(1,2*N-1).
For optimal efficiency, LWORK >= (NB+1)*N,
where NB is the blocksize for CHETRD returned by ILAENV. If LWORK = -1, then a workspace query is assumed; the routine
only calculates the optimal size of the WORK array, returns
this value as the first entry of the WORK array, and no error
message related to LWORK is issued by XERBLA.
So all you need to do is
call cheev(jobz, uplo, n, a, lda, w, work, -1, rwork, info)
lwork=int(work(1))
dallocate(work)
allocate(work(lwork))
call cheev(jobz, uplo, n, a, lda, w, work, lwork, rwork, info)

Fortran subroutine delivers wrong result when called in C++ program

I have to write a Fortran routine returning the inverse matrix. If I run the code below in a Fortran program the inverse matrix is correct, but when I run the subroutine from C++ code my first value is a wrong value. It seems like a problem with the data types or the memory.
What am I doing wrong?
Here is the subroutine:
subroutine get_inverse_matrix( matrix, rows_matrix, cols_matrix, tmpMatrix, rows_tmpMatrix, cols_tmpMatrix) bind(c)
use iso_c_binding
integer :: m, n, lda, lwork, info, size_m
integer(c_int) :: rows_matrix, cols_matrix, rows_tmpMatrix, cols_tmpMatrix
real(c_double) :: matrix(rows_matrix, cols_matrix), tmpMatrix(rows_tmpMatrix, cols_tmpMatrix)
integer, dimension( rows_matrix ) :: ipiv
real, dimension( rows_matrix ) :: work
size_m = rows_matrix
m = size_m
n = size_m
lda = size_m
lwork = size_m
write(*,*) "Matrix: ", matrix
!tmpMatrix = matrix
write(*,*) "Temp matrix: ", tmpMatrix
! LU-Faktorisierung (Dreieckszerlegung) der Matrix
call sgetrf( m, n, tmpMatrix, lda, ipiv, info )
write(*,*) info
! Inverse der LU-faktorisierten Matrix
call sgetri( n, tmpMatrix, lda, ipiv, work, lwork, info )
write(*,*) info
select case(info)
case(0)
write(*,*) "SUCCESS"
case(:-1)
write(*,*) "ILLEGAL VALUE"
case(1:)
write(*,*) "SINGULAR MATRIX"
end select
end subroutine get_inverse_matrix
Here is the declaration in the C++ code:
extern "C"
{
void get_inverse_matrix( double *matrix, int *rows_matrix, int *cols_matrix, double *tmpMatrix, int *rows_tmpMatrix, int *cols_tmpMatrix);}
Here is the call from my C++ program:
get_inverse_matrix(&lhs[0], &sz, &sz, &res[0], &sz, &sz);
My program only uses a 3x3 matrix. If I pass the identity matrix the result looks like:
5.29981e-315 0 0
0 1 0
0 0 1
You are declaring your arrays as type real with kind c_double but you are using lapack routines that are expecting single precision inputs (e.g. c_float). To fix this you should replace the calls to sgetrf and sgetri with dgetrf and dgetri.
As noted by Vladimir F in the comments these issues can be more easily caught if you provide interfaces.

lapack zheevd gives wrong results

I am trying to use lapack's zheevd in order to diagonalize a complex Hermitian matrix. I' ve written a small example which doesn't produce any compile or run time error but gives wrong results for the eigenvalues... Here's the code:
program test
implicit none
INTEGER, PARAMETER :: N=4
INTEGER, PARAMETER :: LDA = N
INTEGER, PARAMETER :: LWMAX = 1000
INTEGER :: INFO, LWORK, LIWORK, LRWORK,i,j
INTEGER :: IWORK( LWMAX )
REAL(8) :: W(N), RWORK( LWMAX )
COMPLEX(16) :: A(LDA, N), WORK(LWMAX), zero
character(len=1) :: job,uplo
! the matrix I want to diagonalize is:
! ( 3.40, 0.00) ( -2.36, -1.93) ( -4.68, 9.55) ( 5.37, -1.23)
! A= ( -2.36, 1.93) ( 6.94, 0.00) ( 8.13, -1.47) ( 2.07, -5.78)
! ( -4.68, -9.55) ( 8.13, 1.47) ( -2.14, 0.00) ( 4.68, 7.44)
! ( 5.37, 1.23) ( 2.07, 5.78) ( 4.68, -7.44) ( -7.42, 0.00)
zero=dcmplx(0.0d0,0.0d0)
A=zero
A(1,1)= dcmplx( 3.40d0, 0.0d0); A(1,2)=dcmplx(-2.36d0, -1.93d0); A(1,3)= dcmplx(-4.68d0,9.55d0)
A(1,4)= dcmplx( 5.37d0, -1.23d0)
A(2,2)= dcmplx( 6.94d0, 0.0d0); A(2,3)=dcmplx( 8.13d0, -1.47d0); A(2,4)= dcmplx( 2.07d0, -5.78d0)
A(3,3)= dcmplx(-2.14d0, 0.0d0); A(3,4)=dcmplx( 4.68d0, 7.44d0); A(4,4)= dcmplx(-7.42d0, 0.0d0)
job='V'; uplo='U'
LWORK= N**2 + 2*N; LRWORK= 2*N**2 + 5*N + 1; LIWORK= 5*N+3
CALL ZHEEVD( job, uplo, N, A, LDA, W, WORK, LWORK, RWORK,LRWORK,IWORK,LIWORK, INFO )
IF( INFO > 0 ) THEN
WRITE(*,*)'The algorithm failed to compute eigenvalues.'
STOP
END IF
print*, 'eigenvalues found'
do i=1,N
print*, W(i)
end do
open(1, file='eigenvectors.dat')
write(1,10) ((A(i,j),j=1,N),i=1,N)
10 format(4(F10.5,2X,F10.5))
end program test
when I run the code the results I get for the eigenvalues are:
-2.8413, 0, 0, 2.8413
while the actual eigenvalues are: -21.968, 16.3387, 6.45946, -0.0501069
I keep seeing the routine's reference guide and it seems I have everything correct so it should work properly expect it doesn't... Has anyone an idea about what is wrong with my code?
Thanks
There are three main problems here that I can see:
The most serious issue is that you have translated the COMPLEX*16 types in the MKL example you have based your code on as COMPLEX(16). That is incorrect. You should use COMPLEX(8). I don't know whether your toolchain actually has an extended precision complex type, but there could be a size mismatch between your code and the LAPACK call
There is a typo in the code that means that the values of the matrix you pass to LAPACK are not the same as in your comments (and presumably also not the same as the matrix you computed the eigenvalues for)
Lastly, and just as importantly, you have not defined an interface for ZHEEVD (or declared it as external). This will lead to an implicit interface being guessed by the compiler, and it is quite probable that there are inconsistencies between the argument passing within your code and what LAPACK expects. Especially given the type mismatch in the complex arguments.
I would expect that some combination of all three should fix the results.

FORTRAN ZGEEV, all 0 eigenvalues

I am trying to get the ZGEEV routine in Lapack to work for a test problem and having some difficulties. I just started coding in FORTRAN a week ago, so I think it is probably something very trivial that I am missing.
I have to diagonalize rather large complex symmetric matrices. To get started, using Matlab I created a 200 by 200 matrix, which I have verified is diagonalizable. When I run the code, it brings up no errors and the INFO = 0, suggesting a success. However, all the eigenvalues are (0,0) which I know is wrong.
Attached is my code.
PROGRAM speed_zgeev
IMPLICIT NONE
INTEGER(8) :: N
COMPLEX*16, DIMENSION(:,:), ALLOCATABLE :: MAT
INTEGER(8) :: INFO, I, J
COMPLEX*16, DIMENSION(:), ALLOCATABLE :: RWORK
COMPLEX*16, DIMENSION(:), ALLOCATABLE :: D
COMPLEX*16, DIMENSION(1,1) :: VR, VL
INTEGER(8) :: LWORK = -1
COMPLEX*16, DIMENSION(:), ALLOCATABLE :: WORK
DOUBLE PRECISION :: RPART, IPART
EXTERNAL ZGEEV
N = 200
ALLOCATE(D(N))
ALLOCATE(RWORK(2*N))
ALLOCATE(WORK(N))
ALLOCATE(MAT(N,N))
OPEN(UNIT = 31, FILE = "newmat.txt")
OPEN(UNIT = 32, FILE = "newmati.txt")
DO J = 1,N
DO I = 1,N
READ(31,*) RPART
READ(32,*) IPART
MAT(I,J) = CMPLX(RPART, IPART)
END DO
END DO
CLOSE(31)
CLOSE(32)
CALL ZGEEV('N','N', N, MAT, N, D, VL, 1, VR, 1, WORK, LWORK, RWORK, INFO)
INFO = WORK(1)
DEALLOCATE(WORK)
ALLOCATE(WORK(INFO))
CALL ZGEEV('N','N', N, MAT, N, D, VL, 1, VR, 1, WORK, LWORK, RWORK, INFO)
IF (INFO .EQ. 0) THEN
PRINT*, D(1:10)
ELSE
PRINT*, INFO
END IF
DEALLOCATE(MAT)
DEALLOCATE(D)
DEALLOCATE(RWORK)
DEALLOCATE(WORK)
END PROGRAM speed_zgeev
I have tried the same code on smaller matrices, of size 30 by 30 and they work fine. Any help would be appreciated! Thanks.
I forgot to mention that I am loading the matrices from a test file which I have verified to be working right.
Maybe LWORK = WORK (1) instead of INFO = WORK(1)? Also change ALLOCATE(WORK(INFO)).