Fortran Lapack 사용하기+ DSYEV 사용법

netlib.org/lapack참조. Lapack(라팍)은 선형 시스템, 선형 시스템의 최소제곱법, 고유값문제, singular value문제 등을 해결하는 routine들을 제공한다.

Numpy, Matlab, Maple, R등에서도 이미 쓰이고, mac os x에도 쓰이고 fortran77로 쓰여있다.

lapack 사이트에서 보면 내가 원하는 subroutine을 찾을수 있다. 참고로 난 이 documentation이 매우 마음에 들지 않는다.

All driver/ computational routine들은 XYYZZZ라는 모양의 이름을 가지고있다. 6번째가 blank이기도 하다.

첫번째 X는 data type을 알려준다:

S : Real

D : Double Precision

C : Complex

Z : Complex*16 or Double Complex

그다음의 YY는 type of matrix를 알려준다. 참고로 여긴 몇가지만 적겠지만 총 28가지의 matrix종류가 있다.

BD : Bidiagonal

DI : Diagonal

GB : General Band

GE : General (i.e. unsymmetric, in some cases rectangular)

GG : General matrices, generalized problem(i.e. a pair of general matrices)

GT : General Tridiagonal

HB : (complex) Hermitian band

HE : (complex) Hermitian

그래서 예를들어, DGESV이면 , Double Precision routine for SolVing(SV) systems with general matrices라는 뜻.

내가 이번 과제에서 사용했던 DSYEV 는 Double precision routine for computing Eigenvalues and optionally eigenvectors of a real symmetric matrix A. 이다.

그냥, 실대칭행렬의 고유값과 고유벡터를 계산해주는 routine.

근데 너무 힘들었던게 ㅋㅋㅋㅋㅋ

matlab에선 그냥 eig(M) 이러면 고유값 나오지않나여..?

얘는 documentation이 너무 복잡해서 힘들었음.

http://www.netlib.org/lapack/explore-html/d2/d8a/group__double_s_yeigen_ga442c43fca5493590f8f26cf42fed4044.html#ga442c43fca5493590f8f26cf42fed4044

일단 보면 알겠지만 매우 복잡함. (나만 그런가? 처음써봐서?) 설명도 별로 친절하지가않음.

subroutine dsyev를 사용하려면 (JOBZ, UPLO, N, A, LDA, W, WORK, LWORK, INFO) 를 적어줘야 한다.

작명최악…–;

하나씩 풀어서 설명하고 예제를 보여줄 것이다.

JOBZ : 는 인풋이다. character*1이다. ‘N’또는 ‘V’를 적어주면 된다. 각각 고윳값만 구할것인지, 고윳값과 고유벡터 둘다 구할것인지 먼저 셋팅해주는 것이다.

UPLO : 는 인풋이다. character*1이다. ‘U’ 를 적어주면 A의 상삼각행렬이 저장되고, ‘L’을 적어주면 A의 하삼각행렬이 저장된다.

N : 는 integer 인풋이다. A의 order를 적어주면 되고, 0보다 같거나 커야 한다.

A : 인풋이자 아웃풋이다. 우리가 구하고자하는 행렬, double precision array로 인풋을 주면 된다. dimension은 (LDA,N)이다. 고유벡터 아웃풋을 이 행렬에 다시 담아서 돌려주는 것 같다.

LDA : 인풋이고 integer이다. Leading dimension of A이다.

W : double precision array이고 아웃풋이다. dimension (N)이다. Info값이 0이면 고윳값이 ascending order로 여기에 담겨서 리턴된다.

WORK : double precision array이고 아웃풋이다. dimension은 (Max(1,LWORK))이다. subroutine이 끝날 때, INFO 값이 0이면, WORK(1)은 optimal LWORK를 리턴해준다.

LWORK : Integer이고 input이다. WORK어레이의 length이다. LWORK는 >= max(1,3*N-1)이라는 조건을 만족시켜주어야한다.

Optimal efficiency를 위해서는 LWORK >= (NB + 2)*N 이면 된다. NB는 blocksize for DSYTRD by ILAENV라는데 모르겠다 뭔말인지….

하지만 중요한건! LWORK = -1이면 workspace query를 가정하고 돌린다. 그러면 routine은 optimal size of WORK array만 계산해준다. 그리고 WORK(1)값에 그 값이 담긴다. 에러메세지도 생기지 않는다. 이게 무슨말인지 잠시후 예제에서 다룰 것이다.

INFO : Integer 이고 아웃풋인데, 쉽게말해선 이게 제대로 돌았는지 아닌지를 보여준다. 0이나오면 제대로된것이고, 음수가 나오면 , -i가 나오면 ith argument가 illegal value를 가졌다는 뜻이다. 양수로 i가 나오면, algorithm이 수렴하지 못했다는 것이다. I off-diagonal elements of an intermediate tridiagonal form 이 0으로 수렴하지 않았다는 뜻이다.

일단나는 이 documentation보다더 도움이됬던건 인텔 문서였다.

https://software.intel.com/en-us/node/469176

여기에 보면 dsyev에대해 다시 한번 설명을 해준다.

그리고 인텔에서 제공하는 예제코드가 있는데 난 이게 되게 많이 도움이 됐다.

https://software.intel.com/sites/products/documentation/doclib/mkl_sa/11/mkl_lapack_examples/dsyev_ex.f.htm

예제 코드를 보면 dsyev를 두번 call하는걸 볼 수 있다.

처음에 lwork의 optimal값을 모르기때문에 -1로 놓고 돌리고,

거기서 리턴된 work(1)값을 lwork에 다시 담아주고, work를 deallocate해준 후에 새로운 lwork값으로 dsyev를 돌려주면 우리가 원하는 고유값을 W에서 구할수 있다 !