Intel® oneAPI Math Kernel Library
Ask questions and share information with other developers who use Intel® Math Kernel Library.

Cannot use MKL F95 eigensolver routines

chung__kristian
Beginner
1,383 Views

I am using Intel Parallel Studio XE with Visual Studio. I would like to use the heev()/heevr() routines. I have written a simple code to test it, and I have enabled the "Use MKL libraries" option 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)
    integer :: i
    matrix = (1.0_dp,0.0_dp)
    call heevr(matrix, eigs, info=i)
    print*, i
    print*, eigs
    read(*,*)
    stop  
end program

This code produces the error:

error LNK2019: unresolved external symbol _ZHEEVR_F95 referenced in function _MAIN__		
fatal error LNK1120: 1 unresolved externals		

So the linker is not finding the ZHEEVR_F95 subroutine whose interface is provided in the lapack.f90 file. Replacing HEEVR with HEEV produces the same results. I should say that I am also using the VSL and DFT libraries without any issue. 

I noticed in the documentation for ?heev it says to include the mkl.fi file (which I don't normally include for the VSL or DFT libraries), but doing so produces the following 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

The line numbers are 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

which doesn't really tell me much.

I need to figure out why the linker can't find the f95 subroutines, any help appreciated. 

EDIT:

I tried using the F77 interface with the following code:

 

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)
    integer :: i
    matrix = (1.0_dp,0.0_dp)
    call eigenvalues(matrix,eigs)
    print*, eigs
    read(*,*)
    stop  
    
contains
    
    subroutine eigenvalues(H,eigs)
        complex(dp) :: H(:,:)
        real(dp)    :: eigs(:)
        integer   :: d
        integer   :: info
        integer   :: lwork, liwork
        real(dp), allocatable  :: work(:)
        integer , allocatable  :: iwork(:)
        
        d = size(eigs)
        
        lwork = 4*d
        liwork = 10
        allocate(work(lwork))
        allocate(iwork(liwork))
        
        call zheevr('N','U',d,H,d,eigs,work,-1,iwork,-1,info)
        
        lwork = work(1)
        liwork = iwork(1)
        deallocate(work,iwork)        
        allocate(work(lwork))
        allocate(iwork(liwork))
        
        call zheevr('N','U',d,H,d,eigs,work,lwork,iwork,liwork,info)
        
        deallocate(work,iwork)
        
        if (info /= 0) then
            print*, "diagonalization failed, info = ", info
            read(*,*)
            stop
        end if
                
    end subroutine
end program

but this causes a seg fault as soon as zheevr is called, and now I have absolutely no idea what is going on. 

 

0 Kudos
6 Replies
mecej4
Honored Contributor III
1,383 Views

Take your first (shortest) code. The missing external routine is to be found in the Lapack95 library for the architecture that you are targeting. If, for example, you are targeting X64 and using 4-byte integer arguments to MKL routines, the command to compile and link is:

ifort /Qmkl xheevr.f90 mkl_lapack95_lp64.lib

For other combinations, etc., a good tool to use is the MKL Link Line Advisor, see https://software.intel.com/en-us/articles/intel-mkl-link-line-advisor .

0 Kudos
chung__kristian
Beginner
1,383 Views

mecej4 wrote:

Take your first (shortest) code. The missing external routine is to be found in the Lapack95 library for the architecture that you are targeting. If, for example, you are targeting X64 and using 4-byte integer arguments to MKL routines, the command to compile and link is:

ifort /Qmkl xheevr.f90 mkl_lapack95_lp64.lib

For other combinations, etc., a good tool to use is the MKL Link Line Advisor, see https://software.intel.com/en-us/articles/intel-mkl-link-line-advisor .



Thanks for your reply, I was able to compile and run the program by adding mkl_lapack_lp64.lib to the additional depedencies in Project Properties, but I still don't understand why it is that explicitly linking to external libraries is required for the lapack routines and not for the VSL or DFT routines.

Next, I am trying to get this running on a remote cluster now (let's ignore parallelization), but when I try to compile it there is tells me that the .lib file is not found (I normally run on this cluster compiling with the -mkl flag for the VSL and DFT libraries without issue). I tried copying the library over and linking it explicitly, but I still get the error "undefined reference to `zheev_f95_'". Any ideas why? I will also contact the admins and see if they can help with that. 

Lastly, I still want to understand why my code seg faults when calling the F77 zheev algorithm as in my second example. It does this both on my computer and on the cluster. The code compiles without any warnings or errors and runs fine, but as soon as it calls the zheevr subroutine it seg faults. Any idea why this is?
 

0 Kudos
chung__kristian
Beginner
1,383 Views

Okay, after further testing, I have a somewhat different problem. I understand why the code was seg faulting, I wasn't using an explicit interface for the f77 routine and I was using it incorrectly. I now have the F77 routines running on both my own computer and the cluster. I still don't have the f95 routine running on the cluster, but I wrote a subroutine for the F77 routine which makes it equivalent. However, I noticed that the F95 routine running on my computer produces an incorrect output. Consider the following code

 

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
    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        
        
        print*, "test 2"
        
        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)        
        
        print*, "test 3"
        
        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

which produces the following output

 checking eigenvalues using zheevr
 -6.330005540529565E-016  0.000000000000000E+000  7.788904174037827E-017
   4.00000000000000
 checking eigenvalues using heevr
 -0.612842417299582      -1.525922570253684E-002  0.612055954590501
   4.01604568841162



The heevr (F95) result is incorrect, the correct eigenvalues are {0,0,0,4} as returned by the zheevr routine. Any idea why this is? For now I can move forward using my own subroutine as it seems to work properly.

 

0 Kudos
mecej4
Honored Contributor III
1,383 Views

chung, kristian wrote:
 ... but I still don't understand why it is that explicitly linking to external libraries is required for the lapack routines and not for the VSL or DFT routines.

Explicit linking is not required for Lapack routines called using the F77 interface. Explicit linking is required for Lapack routines called using the Fortran 95 interface (calls to generic routine names with abbreviated arguments lists and optional arguments) because the corresponding specific names are not present in the Lapack library; they are present in the Lapack95 library.

chung, kristian wrote:
Next, I am trying to get this running on a remote cluster now (let's ignore parallelization), but when I try to compile it there is tells me that the .lib file is not found (I normally run on this cluster compiling with the -mkl flag for the VSL and DFT libraries without issue). I tried copying the library over and linking it explicitly, but I still get the error "undefined reference to `zheev_f95_'". Any ideas why? 

Does your cluster have MKL and Lapack95 installed on it? Which versions?

chung, kristian wrote:
 However, I noticed that the F95 routine running on my computer produces an incorrect output. Consider the following code...

When your call to zheevr in Subroutine Eigenvalues returns, the matrix will have been overwritten. Please consult the documentation. You have to set the array matrix back to the desired set of values before calling heevr.

0 Kudos
chung__kristian
Beginner
1,383 Views

mecej4 wrote:

When your call to zheevr in Subroutine Eigenvalues returns, the matrix will have been overwritten. Please consult the documentation. You have to set the array matrix back to the desired set of values before calling heevr.

Thanks! My mistake, I should have realized this. After resetting the matrix both routines produce the same result

mecej4 wrote:

Does your cluster have MKL and Lapack95 installed on it? Which versions?



Certainly MKL, but perhaps not Lapack95, is there a simple way I could check? 

0 Kudos
mecej4
Honored Contributor III
1,383 Views

The directory structure is shown at https://software.intel.com/en-us/mkl-linux-developer-guide-high-level-directory-structure .Check the ../lib/<arch> directories for library file names containing "95" and the ../include/<arch> directory for the Lapack95 module files.

0 Kudos
Reply