与MATMUL(Fortran)错误的矩阵乘法

时间:2016-08-24 18:40:17

标签: fortran matrix-multiplication gfortran

我在minimalexample.f90:

中保存了以下最小示例
        MODULE FUNCTION_CONTAINER
        IMPLICIT NONE
        SAVE

        INTEGER, PARAMETER :: DBL = SELECTED_REAL_KIND(P = 15,R = 200)

        INTEGER :: DIMSYS, DIMMAT

        COMPLEX(KIND = DBL), DIMENSION(4,1) :: INSTATE_BASISSTATES

        COMPLEX(KIND = DBL), DIMENSION(2,2) :: SIGMAX

        REAL(KIND = DBL), DIMENSION(2,2) :: BASISSTATES

        REAL(KIND = DBL), DIMENSION(2,2) :: ID

        COMPLEX(KIND = DBL),DIMENSION(2,2) :: PROJECTOR

        CONTAINS

        SUBROUTINE INDEXCONVERTER(N,K,L)
        IMPLICIT NONE
        INTEGER, INTENT(IN)::N
        INTEGER, INTENT(OUT)::K,L
        INTEGER::X, REMAINDER
        X = N/DIMSYS
        REMAINDER = N - (X * DIMSYS)
        IF (REMAINDER == 0) THEN
        K = X
        L = DIMSYS
        ELSE
        K = X + 1
        L = REMAINDER
        END IF
        END SUBROUTINE INDEXCONVERTER


        SUBROUTINE DENSITYMATRIX(X,RHO)
        IMPLICIT NONE
        COMPLEX(KIND = DBL), DIMENSION(DIMMAT,1), INTENT(IN) :: X
        COMPLEX(KIND = DBL), DIMENSION(2,2),INTENT(OUT)::RHO
        INTEGER :: J, K, L
        DO J = 1, DIMMAT
        CALL INDEXCONVERTER(J,K,L)
        RHO(K,L) = X(J,1)
        END DO
        END SUBROUTINE DENSITYMATRIX

        SUBROUTINE WRONGRESULT(X,RHONEW)
        IMPLICIT NONE
        COMPLEX(KIND = DBL), DIMENSION(DIMMAT,1), INTENT(IN) :: X
        COMPLEX(KIND = DBL),DIMENSION(DIMSYS,DIMSYS),INTENT(OUT)::RHONEW
        COMPLEX(KIND = DBL), DIMENSION(DIMSYS,DIMSYS) :: RHO
        REAL(KIND = DBL), DIMENSION(DIMSYS,DIMSYS) :: ID
        COMPLEX(KIND = DBL), DIMENSION(DIMSYS,DIMSYS) :: SIGMAZ
        COMPLEX(KIND = DBL), DIMENSION(DIMSYS,DIMSYS) :: SIGMAX
        CALL DENSITYMATRIX(X,RHO)
        RHONEW = matmul(SIGMAX,rho)
        END SUBROUTINE WRONGRESULT

        SUBROUTINE EXPECTATION(X,D,ANS)
        IMPLICIT NONE
        COMPLEX(KIND = DBL), DIMENSION(DIMMAT,1), INTENT(IN) :: X
        COMPLEX(KIND = DBL), DIMENSION(DIMSYS,DIMSYS) :: RHONEW
        COMPLEX(KIND = DBL), DIMENSION(DIMSYS,DIMSYS), INTENT(IN) :: D
        REAL(KIND = DBL),INTENT(OUT)::ANS
        COMPLEX(KIND = DBL),DIMENSION(DIMSYS, DIMSYS) :: TEMP
        INTEGER :: J
        REAL(KIND = DBL)::SUMM
        SUMM = 0.0D0
        CALL WRONGRESULT(X,RHONEW)
        TEMP = MATMUL(D,RHONEW)
        DO J = 1, DIMSYS
        SUMM = SUMM + DREAL(TEMP(J,J))
        END DO
        ANS = SUMM
        END SUBROUTINE EXPECTATION

        SUBROUTINE RK(ANSWER)
        IMPLICIT NONE
        REAL(KIND = DBL), INTENT(OUT) :: ANSWER
        COMPLEX(KIND = DBL), DIMENSION(DIMMAT,1)::X
        REAL(KIND = DBL) :: X_EXPECTATION
        REAL(KIND = DBL)::T
        T = 0.0D0
        X = INSTATE_BASISSTATES
        CALL EXPECTATION(X,SIGMAX,X_EXPECTATION)
        ANSWER = X_EXPECTATION
        END SUBROUTINE RK

        END MODULE FUNCTION_CONTAINER

        PROGRAM ONE
        USE FUNCTION_CONTAINER

        IMPLICIT NONE

        REAL(KIND = DBL) :: ANS

        SIGMAX(1,1) = (0.0D0,0.0D0)
        SIGMAX(1,2) = (1.0D0,0.0D0)
        SIGMAX(2,1) = (1.0D0,0.0D0)
        SIGMAX(2,2) = (0.0D0,0.0D0)

        ID(1,1) = 1.0D0
        ID(1,2) = 0.0D0
        ID(2,1) = 0.0D0
        ID(2,2) = 1.0D0

        DIMSYS = 2
        DIMMAT = 4

        BASISSTATES = ID

        INSTATE_BASISSTATES(1,1) = (0.5D0,0.0D0)
        INSTATE_BASISSTATES(2,1) = (0.5D0,0.0D0)
        INSTATE_BASISSTATES(3,1) = (0.5D0,0.0D0)
        INSTATE_BASISSTATES(4,1) = (0.5D0,0.0D0)

        CALL RK(ANS)

        WRITE (*,*) ANS



        END PROGRAM ONE

当我运行它时,编译器cygwin将答案打印为1.这没关系 - 正如预期的那样。现在在子例程中错了,我使用RHONEW.的不同表达式。例如,使用RHONEW = 2*RHO,我得到2作为答案。再次,如预期的那样。

现在,我写RHONEW = matmul(id,rho)。我应该得到1作为答案,因为在计算子例程RHO中定义的EXPECTATION的期望值之前,我(通常)乘以身份。相反,我得到1.2732139384274929E-313.完全无意义。

可能发生什么事?在我的实际代码中,我想做一个复杂的矩阵乘法形式:

 RHONEW = UCONJ*RHO*U,

其中UCONJU是矩阵的线性组合。

即使是一个微不足道的乘法,我也没有得到正确的结果。我可以纠正可能的错误以继续解决我的问题?

请注意,代码在所有CAPS中,因为我是从我的主管那里得到的,并且是以固定形式编写的。该代码使用.f.f90扩展名进行编译。

2 个答案:

答案 0 :(得分:1)

您再次在子例程SIGMAX中定义WRONGRESULT。因此,它在子程序中(再次)作用域并遮蔽模块中定义的那个。

    SUBROUTINE WRONGRESULT(X,RHONEW)
      ! ...
      COMPLEX(KIND = DBL), DIMENSION(DIMSYS,DIMSYS) :: SIGMAX
      CALL DENSITYMATRIX(X,RHO)
      RHONEW = matmul(SIGMAX,rho)
      ! ...

此子例程中的SIGMAX永远不会被初始化,因此matmul会返回垃圾。

答案 1 :(得分:0)

有时编译器开关如' -check uninit'。使用这些通常是值得的,以及 - 未使用过的'和' -check bounds'。然后,一旦整个工作正在工作和清洁,那么你可以删除那些支票并放入' -O2'。 一些缩进在美学上会令人愉悦。 对于更大的阵列,您可以初始化整个事物...... 我认为复杂的初始化值得称为CMPLX,但也许gfortran不需要那个??  例子:

    !... Indent
    DO J = 1, DIMMAT
      CALL INDEXCONVERTER(J,K,L)
      RHO(K,L) = X(J,1)
    END DO
    !... CMPLX ... array init
    SIGMAX(:,:) = CMPLX(1.0D0,0.0D0)
    SIGMAX(1,1) = CMPLX(0.0D0,0.0D0)
    SIGMAX(2,2) = CMPLX(0.0D0,0.0D0)
    !... Whole array init
    ID(:,:) = 0.0D0
    !... diag init
    DO I = 1, 2
      ID(I,I) = 1.0D0
    ENDDO
    !... Whole array init
    INSTATE_BASISSTATES(:,1) = CMPLX(0.5D0,0.0D0)

这一切都不好,但考虑使用假定的数组大小可能更容易......但是你需要分配和释放TEMP和RHONEW,所以这个2x2可能没什么好处。但是,如果您最终得到更大的数组,则会提供一个示例:

    SUBROUTINE EXPECTATION(X, D, ANS)
    IMPLICIT NONE
    COMPLEX(KIND = DBL), DIMENSION(:,1), INTENT(IN   ) :: X
    COMPLEX(KIND = DBL), DIMENSION(:,:), INTENT(IN   ) :: D
    REAL(KIND = DBL)                   , INTENT(  OUT) :: ANS
    !~~Local~~
    COMPLEX(KIND = DBL), DIMENSION(DIMSYS,DIMSYS)      :: RHONEW
    COMPLEX(KIND = DBL), DIMENSION(DIMSYS,DIMSYS)      :: TEMP
    INTEGER                                            :: J
    !REAL(KIND = DBL)                                   :: SUMM

    CALL WRONGRESULT(X,RHONEW)
    TEMP = MATMUL(D,RHONEW)
    !SUMM = 0.0D0
    DO J = LBOUND(TEMP,1), UBOUND(TEMP,1)  !DIMSYS
      !SUMM = SUMM + DREAL(TEMP(J,J))
      ANS = ANS + DREAL(TEMP(J,J))
    END DO
    !ANS = SUMM
    END SUBROUTINE EXPECTATION