Неправильная обратная матрица с использованием ZGETRI в Фортране

Я пытаюсь вычислить обратную сложную матрицу с помощью ZGETRI, но даже если она выполняется без ошибок (info = 0), она не дает мне правильную обратную матрицу, и я совершенно не понимаю, откуда берется ошибка.

PROGRAM solvelinear
implicit none
INTEGER                        :: i,j,info,lwork
INTEGER,dimension(3)        :: ipiv
COMPLEX(16), dimension(3,3) :: C,Cinv,M,LU
COMPLEX(16),allocatable :: work(:)

info=0
lwork=100
allocate(work(lwork))
ipiv=0
work=(0.d0,0.d0)

C(1,1)=(0.d0,-1.d0)
C(1,2)=(1.d0,5.d0)
C(1,3)=(2.d0,-2.d0)
C(2,1)=(4.d0,-1.d0)
C(2,2)=(2.d0,-3.d0)
C(2,3)=(-1.d0,2.d0)
C(3,1)=(1.d0,0.d0)
C(3,2)=(3.d0,-2.d0)
C(3,3)=(0.d0,1.d0)

write(*,*)"C = "
do i=1,3
   write(*,10)(C(i,j),j=1,3)
end do

!-- LU factorisation
LU=C
CALL ZGETRF(3,3,LU,3,ipiv,info)
write(*,*)'info = ',info
write(*,*)"LU = "
do i=1,3
   write(*,10)(LU(i,j),j=1,3)
end do

!-- Inversion of matrix C using the LU

Cinv=LU
CALL ZGETRI(3,Cinv,3,ipiv,work,lwork,info)
write(*,*)'info = ',info
write(*,*)"Cinv = "
do i=1,3
   write(*,10)(Cinv(i,j),j=1,3)
end do

!-- computation of C^-1 * C to check the inverse
M = matmul(Cinv,C)
write(*,*)"M = "
do i=1,3
   write(*,10)(M(i,j),j=1,3)
end do
          10 FORMAT(3('(',F20.10,',',F20.10,') '))

END PROGRAM solvelinear

Я компилирую с помощью ifort (и мои библиотеки LAPACK версии 3.7.1 тоже компилируются с помощью ifort). Makefile:

#$Id: Makefile $
.SUFFIXES: .f90 .f .c .o
FC = ifort
FFLAGS = -g -check all -zmuldefs -i8
LIBS = -L/path/to/lapack-3.7.1 -llapack -ltmglib -lrefblas
MAIN = prog.o
EXEC = xx
all:  ${MAIN} Makefile
    ${FC} ${FFLAGS} -o ${EXEC} ${MAIN} ${LIBS}
.f.o: ${MODS} Makefile
    ${FC} ${FFLAGS} -c $<
.f90.o: ${MODS} Makefile
    ${FC} ${FFLAGS} -c $<

У меня нет ошибок при компиляции. Вот мой результат:

 C = 
(       0.00000,      -1.00000) (       1.00000,       5.00000) (       2.00000,      -2.00000) 
(       4.00000,      -1.00000) (       2.00000,      -3.00000) (      -1.00000,       2.00000) 
(       1.00000,       0.00000) (       3.00000,      -2.00000) (       0.00000,       1.00000) 
 info =                      0
 LU = 
(       4.00000,       0.00000) (       2.00000,  120470.58824) (       2.00000,      -2.00000) 
(       0.00000,       0.00000) (28003147.29412,      -3.00000) (      -1.00000,       2.00000) 
(       1.00000,       0.00000) (       3.00000,      -2.00000) (       0.00000,       1.00000) 
 info =                      0
 Cinv = 
(       0.00000,       0.00000) (      -0.00000,      -0.00000) (       2.00000,      -2.00000) 
(      -0.00000,       0.00000) (      -0.00000,      -3.00000) (      -1.00000,       2.00000) 
(      -0.00000,      -0.00000) (       3.00000,      -2.00000) (       0.00000,       1.00000) 
 M = 
(       2.00000,      -2.00000) (       2.00000,     -10.00000) (       2.00000,       2.00000) 
(      -4.00000,     -10.00000) (      -8.00000,       2.00000) (       4.00000,       2.00000) 
(      10.00000,     -10.00000) (       2.00000,     -10.00000) (      -0.00000,       8.00000) 

И М должно быть тож, если я не ошибаюсь.


person B_runo    schedule 23.10.2017    source источник
comment
Пожалуйста, не ставьте теги в заголовке в круглых скобках, как вы это делали. StackOverflow имеет богатую систему тегов, размещайте теги под вопросом, где они должны быть. Если они являются неотъемлемой частью заголовка, они могут остаться там (например, в Фортране, в функции Фортрана или подобном), но не помещайте туда просто список, список тегов находится под вопросом.   -  person Vladimir F    schedule 23.10.2017


Ответы (1)


Я предлагаю вам НЕ использовать добрую нотацию с литеральными числами, такими как REAL(4) или COMPLEX(16).

Во-первых, это некрасиво и не портативно.

Во-вторых, сложные переменные могут сбивать с толку.

Здесь вы определяете свои переменные как COMPLEX(16), но ZGETRI и все другие подпрограммы LAPACK Z ожидают COMPLEX*16. Это НЕ одно и то же.

COMPLEX*16 — это нестандартное обозначение комплексных чисел с REAL*8 компонентами. REAL*8 — это нестандартная запись для 8-байтовых действительных чисел, которые обычно эквивалентны DOUBLE PRECISION.

COMPLEX(16) — это комплексное число с двумя компонентами REAL(16) при условии, что такой вид существует. В компиляторах, которые обеспечивают REAL(16), это действительно четверная точность, а не двойная точность.

Таким образом, вы фактически передаете 32-байтовые сложные переменные вместо 16-байтовых сложных переменных.

Существует достаточно ресурсов, где можно научиться правильно использовать виды Fortran. Вы можете начать с

integer, parameter :: dp = kind(1.d0)

а также

real(dp) :: x
complex(dp) :: c
person Vladimir F    schedule 23.10.2017
comment
Мне интересно, может ли быть лучшим подходом использовать комплекс * 16, а не комплекс (вид (1.0d0)) для соответствия типу, используемому в исходном источнике netlib.org/lapack/explore-3.1.1-html/zgetrf.f.html , но я не уверен, как это определяется в справочных (или последних, или mkl, или...) библиотеках на практике. - person roygvib; 23.10.2017
comment
Я упоминаю об этом в ответе, но не буду рекомендовать этот способ, потому что это не (стандартный) Фортран. - person Vladimir F; 23.10.2017
comment
@roygvib Основная причина для COMPLEX * 16 заключается в том, что не было стандартного DOUBLE COMPLEX, но DGETRF использует DOUBLE PRECISION, поэтому я бы рекомендовал использовать kind(1.d0). - person Vladimir F; 23.10.2017
comment
Спасибо за информацию, да, я согласен, что вид (1.d0) практически лучший (и я его использую). Меня беспокоит то, что если для реального значения по умолчанию установлено 64-битное значение (параметрами компилятора или чем-то еще), в будущем могут возникнуть проблемы... (В этом смысле комплекс (real64) из iso_fortran_env может быть безопаснее). Но до этого сам Лапак использует 1.0D0 и комплекс*16 (или реальный*8) вперемешку, так что хаотично... лол (Но это лишь крайне незначительная проблема, так что я тоже думаю, что комплекс(вид(0 .d0)) будет наиболее практичным.) - person roygvib; 23.10.2017
comment
Спасибо за ваш ответ и комментарии, это решило мою проблему. Итак, если я правильно понял, комплекс (16) был здесь неправильным, потому что используемый мной компилятор не имел квадрупольной точности для реального (16)? В любом случае, я воспользуюсь вашей рекомендацией в будущем :) - person B_runo; 24.10.2017
comment
@B_runo Не совсем так. У компилятора была четверная точность, но четверная точность не совместима с подпрограммами Z, такими как ZGETRF. Они требуют двойной точности. - person Vladimir F; 24.10.2017
comment
Хорошо, я понял! Спасибо за эти точности. - person B_runo; 25.10.2017