File:  [local] / rpl / lapack / lapack / zhetf2_rk.f
Revision 1.5: download - view: text, annotated - select for diffs - revision graph
Mon Aug 7 08:39:24 2023 UTC (8 months, 3 weeks ago) by bertrand
Branches: MAIN
CVS tags: rpl-4_1_35, rpl-4_1_34, HEAD
Première mise à jour de lapack et blas.

    1: *> \brief \b ZHETF2_RK computes the factorization of a complex Hermitian indefinite matrix using the bounded Bunch-Kaufman (rook) diagonal pivoting method (BLAS2 unblocked algorithm).
    2: *
    3: *  =========== DOCUMENTATION ===========
    4: *
    5: * Online html documentation available at
    6: *            http://www.netlib.org/lapack/explore-html/
    7: *
    8: *> \htmlonly
    9: *> Download ZHETF2_RK + dependencies
   10: *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/zhetf2_rk.f">
   11: *> [TGZ]</a>
   12: *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/zhetf2_rk.f">
   13: *> [ZIP]</a>
   14: *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/zhetf2_rk.f">
   15: *> [TXT]</a>
   16: *> \endhtmlonly
   17: *
   18: *  Definition:
   19: *  ===========
   20: *
   21: *       SUBROUTINE ZHETF2_RK( UPLO, N, A, LDA, E, IPIV, INFO )
   22: *
   23: *       .. Scalar Arguments ..
   24: *       CHARACTER          UPLO
   25: *       INTEGER            INFO, LDA, N
   26: *       ..
   27: *       .. Array Arguments ..
   28: *       INTEGER            IPIV( * )
   29: *       COMPLEX*16         A( LDA, * ), E ( * )
   30: *       ..
   31: *
   32: *
   33: *> \par Purpose:
   34: *  =============
   35: *>
   36: *> \verbatim
   37: *> ZHETF2_RK computes the factorization of a complex Hermitian matrix A
   38: *> using the bounded Bunch-Kaufman (rook) diagonal pivoting method:
   39: *>
   40: *>    A = P*U*D*(U**H)*(P**T) or A = P*L*D*(L**H)*(P**T),
   41: *>
   42: *> where U (or L) is unit upper (or lower) triangular matrix,
   43: *> U**H (or L**H) is the conjugate of U (or L), P is a permutation
   44: *> matrix, P**T is the transpose of P, and D is Hermitian and block
   45: *> diagonal with 1-by-1 and 2-by-2 diagonal blocks.
   46: *>
   47: *> This is the unblocked version of the algorithm, calling Level 2 BLAS.
   48: *> For more information see Further Details section.
   49: *> \endverbatim
   50: *
   51: *  Arguments:
   52: *  ==========
   53: *
   54: *> \param[in] UPLO
   55: *> \verbatim
   56: *>          UPLO is CHARACTER*1
   57: *>          Specifies whether the upper or lower triangular part of the
   58: *>          Hermitian matrix A is stored:
   59: *>          = 'U':  Upper triangular
   60: *>          = 'L':  Lower triangular
   61: *> \endverbatim
   62: *>
   63: *> \param[in] N
   64: *> \verbatim
   65: *>          N is INTEGER
   66: *>          The order of the matrix A.  N >= 0.
   67: *> \endverbatim
   68: *>
   69: *> \param[in,out] A
   70: *> \verbatim
   71: *>          A is COMPLEX*16 array, dimension (LDA,N)
   72: *>          On entry, the Hermitian matrix A.
   73: *>            If UPLO = 'U': the leading N-by-N upper triangular part
   74: *>            of A contains the upper triangular part of the matrix A,
   75: *>            and the strictly lower triangular part of A is not
   76: *>            referenced.
   77: *>
   78: *>            If UPLO = 'L': the leading N-by-N lower triangular part
   79: *>            of A contains the lower triangular part of the matrix A,
   80: *>            and the strictly upper triangular part of A is not
   81: *>            referenced.
   82: *>
   83: *>          On exit, contains:
   84: *>            a) ONLY diagonal elements of the Hermitian block diagonal
   85: *>               matrix D on the diagonal of A, i.e. D(k,k) = A(k,k);
   86: *>               (superdiagonal (or subdiagonal) elements of D
   87: *>                are stored on exit in array E), and
   88: *>            b) If UPLO = 'U': factor U in the superdiagonal part of A.
   89: *>               If UPLO = 'L': factor L in the subdiagonal part of A.
   90: *> \endverbatim
   91: *>
   92: *> \param[in] LDA
   93: *> \verbatim
   94: *>          LDA is INTEGER
   95: *>          The leading dimension of the array A.  LDA >= max(1,N).
   96: *> \endverbatim
   97: *>
   98: *> \param[out] E
   99: *> \verbatim
  100: *>          E is COMPLEX*16 array, dimension (N)
  101: *>          On exit, contains the superdiagonal (or subdiagonal)
  102: *>          elements of the Hermitian block diagonal matrix D
  103: *>          with 1-by-1 or 2-by-2 diagonal blocks, where
  104: *>          If UPLO = 'U': E(i) = D(i-1,i), i=2:N, E(1) is set to 0;
  105: *>          If UPLO = 'L': E(i) = D(i+1,i), i=1:N-1, E(N) is set to 0.
  106: *>
  107: *>          NOTE: For 1-by-1 diagonal block D(k), where
  108: *>          1 <= k <= N, the element E(k) is set to 0 in both
  109: *>          UPLO = 'U' or UPLO = 'L' cases.
  110: *> \endverbatim
  111: *>
  112: *> \param[out] IPIV
  113: *> \verbatim
  114: *>          IPIV is INTEGER array, dimension (N)
  115: *>          IPIV describes the permutation matrix P in the factorization
  116: *>          of matrix A as follows. The absolute value of IPIV(k)
  117: *>          represents the index of row and column that were
  118: *>          interchanged with the k-th row and column. The value of UPLO
  119: *>          describes the order in which the interchanges were applied.
  120: *>          Also, the sign of IPIV represents the block structure of
  121: *>          the Hermitian block diagonal matrix D with 1-by-1 or 2-by-2
  122: *>          diagonal blocks which correspond to 1 or 2 interchanges
  123: *>          at each factorization step. For more info see Further
  124: *>          Details section.
  125: *>
  126: *>          If UPLO = 'U',
  127: *>          ( in factorization order, k decreases from N to 1 ):
  128: *>            a) A single positive entry IPIV(k) > 0 means:
  129: *>               D(k,k) is a 1-by-1 diagonal block.
  130: *>               If IPIV(k) != k, rows and columns k and IPIV(k) were
  131: *>               interchanged in the matrix A(1:N,1:N);
  132: *>               If IPIV(k) = k, no interchange occurred.
  133: *>
  134: *>            b) A pair of consecutive negative entries
  135: *>               IPIV(k) < 0 and IPIV(k-1) < 0 means:
  136: *>               D(k-1:k,k-1:k) is a 2-by-2 diagonal block.
  137: *>               (NOTE: negative entries in IPIV appear ONLY in pairs).
  138: *>               1) If -IPIV(k) != k, rows and columns
  139: *>                  k and -IPIV(k) were interchanged
  140: *>                  in the matrix A(1:N,1:N).
  141: *>                  If -IPIV(k) = k, no interchange occurred.
  142: *>               2) If -IPIV(k-1) != k-1, rows and columns
  143: *>                  k-1 and -IPIV(k-1) were interchanged
  144: *>                  in the matrix A(1:N,1:N).
  145: *>                  If -IPIV(k-1) = k-1, no interchange occurred.
  146: *>
  147: *>            c) In both cases a) and b), always ABS( IPIV(k) ) <= k.
  148: *>
  149: *>            d) NOTE: Any entry IPIV(k) is always NONZERO on output.
  150: *>
  151: *>          If UPLO = 'L',
  152: *>          ( in factorization order, k increases from 1 to N ):
  153: *>            a) A single positive entry IPIV(k) > 0 means:
  154: *>               D(k,k) is a 1-by-1 diagonal block.
  155: *>               If IPIV(k) != k, rows and columns k and IPIV(k) were
  156: *>               interchanged in the matrix A(1:N,1:N).
  157: *>               If IPIV(k) = k, no interchange occurred.
  158: *>
  159: *>            b) A pair of consecutive negative entries
  160: *>               IPIV(k) < 0 and IPIV(k+1) < 0 means:
  161: *>               D(k:k+1,k:k+1) is a 2-by-2 diagonal block.
  162: *>               (NOTE: negative entries in IPIV appear ONLY in pairs).
  163: *>               1) If -IPIV(k) != k, rows and columns
  164: *>                  k and -IPIV(k) were interchanged
  165: *>                  in the matrix A(1:N,1:N).
  166: *>                  If -IPIV(k) = k, no interchange occurred.
  167: *>               2) If -IPIV(k+1) != k+1, rows and columns
  168: *>                  k-1 and -IPIV(k-1) were interchanged
  169: *>                  in the matrix A(1:N,1:N).
  170: *>                  If -IPIV(k+1) = k+1, no interchange occurred.
  171: *>
  172: *>            c) In both cases a) and b), always ABS( IPIV(k) ) >= k.
  173: *>
  174: *>            d) NOTE: Any entry IPIV(k) is always NONZERO on output.
  175: *> \endverbatim
  176: *>
  177: *> \param[out] INFO
  178: *> \verbatim
  179: *>          INFO is INTEGER
  180: *>          = 0: successful exit
  181: *>
  182: *>          < 0: If INFO = -k, the k-th argument had an illegal value
  183: *>
  184: *>          > 0: If INFO = k, the matrix A is singular, because:
  185: *>                 If UPLO = 'U': column k in the upper
  186: *>                 triangular part of A contains all zeros.
  187: *>                 If UPLO = 'L': column k in the lower
  188: *>                 triangular part of A contains all zeros.
  189: *>
  190: *>               Therefore D(k,k) is exactly zero, and superdiagonal
  191: *>               elements of column k of U (or subdiagonal elements of
  192: *>               column k of L ) are all zeros. The factorization has
  193: *>               been completed, but the block diagonal matrix D is
  194: *>               exactly singular, and division by zero will occur if
  195: *>               it is used to solve a system of equations.
  196: *>
  197: *>               NOTE: INFO only stores the first occurrence of
  198: *>               a singularity, any subsequent occurrence of singularity
  199: *>               is not stored in INFO even though the factorization
  200: *>               always completes.
  201: *> \endverbatim
  202: *
  203: *  Authors:
  204: *  ========
  205: *
  206: *> \author Univ. of Tennessee
  207: *> \author Univ. of California Berkeley
  208: *> \author Univ. of Colorado Denver
  209: *> \author NAG Ltd.
  210: *
  211: *> \ingroup complex16HEcomputational
  212: *
  213: *> \par Further Details:
  214: *  =====================
  215: *>
  216: *> \verbatim
  217: *> TODO: put further details
  218: *> \endverbatim
  219: *
  220: *> \par Contributors:
  221: *  ==================
  222: *>
  223: *> \verbatim
  224: *>
  225: *>  December 2016,  Igor Kozachenko,
  226: *>                  Computer Science Division,
  227: *>                  University of California, Berkeley
  228: *>
  229: *>  September 2007, Sven Hammarling, Nicholas J. Higham, Craig Lucas,
  230: *>                  School of Mathematics,
  231: *>                  University of Manchester
  232: *>
  233: *>  01-01-96 - Based on modifications by
  234: *>    J. Lewis, Boeing Computer Services Company
  235: *>    A. Petitet, Computer Science Dept.,
  236: *>                Univ. of Tenn., Knoxville abd , USA
  237: *> \endverbatim
  238: *
  239: *  =====================================================================
  240:       SUBROUTINE ZHETF2_RK( UPLO, N, A, LDA, E, IPIV, INFO )
  241: *
  242: *  -- LAPACK computational routine --
  243: *  -- LAPACK is a software package provided by Univ. of Tennessee,    --
  244: *  -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--
  245: *
  246: *     .. Scalar Arguments ..
  247:       CHARACTER          UPLO
  248:       INTEGER            INFO, LDA, N
  249: *     ..
  250: *     .. Array Arguments ..
  251:       INTEGER            IPIV( * )
  252:       COMPLEX*16         A( LDA, * ), E( * )
  253: *     ..
  254: *
  255: *  ======================================================================
  256: *
  257: *     .. Parameters ..
  258:       DOUBLE PRECISION   ZERO, ONE
  259:       PARAMETER          ( ZERO = 0.0D+0, ONE = 1.0D+0 )
  260:       DOUBLE PRECISION   EIGHT, SEVTEN
  261:       PARAMETER          ( EIGHT = 8.0D+0, SEVTEN = 17.0D+0 )
  262:       COMPLEX*16         CZERO
  263:       PARAMETER          ( CZERO = ( 0.0D+0, 0.0D+0 ) )
  264: *     ..
  265: *     .. Local Scalars ..
  266:       LOGICAL            DONE, UPPER
  267:       INTEGER            I, II, IMAX, ITEMP, J, JMAX, K, KK, KP, KSTEP,
  268:      $                   P
  269:       DOUBLE PRECISION   ABSAKK, ALPHA, COLMAX, D, D11, D22, R1, DTEMP,
  270:      $                   ROWMAX, TT, SFMIN
  271:       COMPLEX*16         D12, D21, T, WK, WKM1, WKP1, Z
  272: *     ..
  273: *     .. External Functions ..
  274: *
  275:       LOGICAL            LSAME
  276:       INTEGER            IZAMAX
  277:       DOUBLE PRECISION   DLAMCH, DLAPY2
  278:       EXTERNAL           LSAME, IZAMAX, DLAMCH, DLAPY2
  279: *     ..
  280: *     .. External Subroutines ..
  281:       EXTERNAL           XERBLA, ZDSCAL, ZHER, ZSWAP
  282: *     ..
  283: *     .. Intrinsic Functions ..
  284:       INTRINSIC          ABS, DBLE, DCMPLX, DCONJG, DIMAG, MAX, SQRT
  285: *     ..
  286: *     .. Statement Functions ..
  287:       DOUBLE PRECISION   CABS1
  288: *     ..
  289: *     .. Statement Function definitions ..
  290:       CABS1( Z ) = ABS( DBLE( Z ) ) + ABS( DIMAG( Z ) )
  291: *     ..
  292: *     .. Executable Statements ..
  293: *
  294: *     Test the input parameters.
  295: *
  296:       INFO = 0
  297:       UPPER = LSAME( UPLO, 'U' )
  298:       IF( .NOT.UPPER .AND. .NOT.LSAME( UPLO, 'L' ) ) THEN
  299:          INFO = -1
  300:       ELSE IF( N.LT.0 ) THEN
  301:          INFO = -2
  302:       ELSE IF( LDA.LT.MAX( 1, N ) ) THEN
  303:          INFO = -4
  304:       END IF
  305:       IF( INFO.NE.0 ) THEN
  306:          CALL XERBLA( 'ZHETF2_RK', -INFO )
  307:          RETURN
  308:       END IF
  309: *
  310: *     Initialize ALPHA for use in choosing pivot block size.
  311: *
  312:       ALPHA = ( ONE+SQRT( SEVTEN ) ) / EIGHT
  313: *
  314: *     Compute machine safe minimum
  315: *
  316:       SFMIN = DLAMCH( 'S' )
  317: *
  318:       IF( UPPER ) THEN
  319: *
  320: *        Factorize A as U*D*U**H using the upper triangle of A
  321: *
  322: *        Initialize the first entry of array E, where superdiagonal
  323: *        elements of D are stored
  324: *
  325:          E( 1 ) = CZERO
  326: *
  327: *        K is the main loop index, decreasing from N to 1 in steps of
  328: *        1 or 2
  329: *
  330:          K = N
  331:    10    CONTINUE
  332: *
  333: *        If K < 1, exit from loop
  334: *
  335:          IF( K.LT.1 )
  336:      $      GO TO 34
  337:          KSTEP = 1
  338:          P = K
  339: *
  340: *        Determine rows and columns to be interchanged and whether
  341: *        a 1-by-1 or 2-by-2 pivot block will be used
  342: *
  343:          ABSAKK = ABS( DBLE( A( K, K ) ) )
  344: *
  345: *        IMAX is the row-index of the largest off-diagonal element in
  346: *        column K, and COLMAX is its absolute value.
  347: *        Determine both COLMAX and IMAX.
  348: *
  349:          IF( K.GT.1 ) THEN
  350:             IMAX = IZAMAX( K-1, A( 1, K ), 1 )
  351:             COLMAX = CABS1( A( IMAX, K ) )
  352:          ELSE
  353:             COLMAX = ZERO
  354:          END IF
  355: *
  356:          IF( ( MAX( ABSAKK, COLMAX ).EQ.ZERO ) ) THEN
  357: *
  358: *           Column K is zero or underflow: set INFO and continue
  359: *
  360:             IF( INFO.EQ.0 )
  361:      $         INFO = K
  362:             KP = K
  363:             A( K, K ) = DBLE( A( K, K ) )
  364: *
  365: *           Set E( K ) to zero
  366: *
  367:             IF( K.GT.1 )
  368:      $         E( K ) = CZERO
  369: *
  370:          ELSE
  371: *
  372: *           ============================================================
  373: *
  374: *           BEGIN pivot search
  375: *
  376: *           Case(1)
  377: *           Equivalent to testing for ABSAKK.GE.ALPHA*COLMAX
  378: *           (used to handle NaN and Inf)
  379: *
  380:             IF( .NOT.( ABSAKK.LT.ALPHA*COLMAX ) ) THEN
  381: *
  382: *              no interchange, use 1-by-1 pivot block
  383: *
  384:                KP = K
  385: *
  386:             ELSE
  387: *
  388:                DONE = .FALSE.
  389: *
  390: *              Loop until pivot found
  391: *
  392:    12          CONTINUE
  393: *
  394: *                 BEGIN pivot search loop body
  395: *
  396: *
  397: *                 JMAX is the column-index of the largest off-diagonal
  398: *                 element in row IMAX, and ROWMAX is its absolute value.
  399: *                 Determine both ROWMAX and JMAX.
  400: *
  401:                   IF( IMAX.NE.K ) THEN
  402:                      JMAX = IMAX + IZAMAX( K-IMAX, A( IMAX, IMAX+1 ),
  403:      $                                     LDA )
  404:                      ROWMAX = CABS1( A( IMAX, JMAX ) )
  405:                   ELSE
  406:                      ROWMAX = ZERO
  407:                   END IF
  408: *
  409:                   IF( IMAX.GT.1 ) THEN
  410:                      ITEMP = IZAMAX( IMAX-1, A( 1, IMAX ), 1 )
  411:                      DTEMP = CABS1( A( ITEMP, IMAX ) )
  412:                      IF( DTEMP.GT.ROWMAX ) THEN
  413:                         ROWMAX = DTEMP
  414:                         JMAX = ITEMP
  415:                      END IF
  416:                   END IF
  417: *
  418: *                 Case(2)
  419: *                 Equivalent to testing for
  420: *                 ABS( DBLE( W( IMAX,KW-1 ) ) ).GE.ALPHA*ROWMAX
  421: *                 (used to handle NaN and Inf)
  422: *
  423:                   IF( .NOT.( ABS( DBLE( A( IMAX, IMAX ) ) )
  424:      $                       .LT.ALPHA*ROWMAX ) ) THEN
  425: *
  426: *                    interchange rows and columns K and IMAX,
  427: *                    use 1-by-1 pivot block
  428: *
  429:                      KP = IMAX
  430:                      DONE = .TRUE.
  431: *
  432: *                 Case(3)
  433: *                 Equivalent to testing for ROWMAX.EQ.COLMAX,
  434: *                 (used to handle NaN and Inf)
  435: *
  436:                   ELSE IF( ( P.EQ.JMAX ) .OR. ( ROWMAX.LE.COLMAX ) )
  437:      $            THEN
  438: *
  439: *                    interchange rows and columns K-1 and IMAX,
  440: *                    use 2-by-2 pivot block
  441: *
  442:                      KP = IMAX
  443:                      KSTEP = 2
  444:                      DONE = .TRUE.
  445: *
  446: *                 Case(4)
  447:                   ELSE
  448: *
  449: *                    Pivot not found: set params and repeat
  450: *
  451:                      P = IMAX
  452:                      COLMAX = ROWMAX
  453:                      IMAX = JMAX
  454:                   END IF
  455: *
  456: *                 END pivot search loop body
  457: *
  458:                IF( .NOT.DONE ) GOTO 12
  459: *
  460:             END IF
  461: *
  462: *           END pivot search
  463: *
  464: *           ============================================================
  465: *
  466: *           KK is the column of A where pivoting step stopped
  467: *
  468:             KK = K - KSTEP + 1
  469: *
  470: *           For only a 2x2 pivot, interchange rows and columns K and P
  471: *           in the leading submatrix A(1:k,1:k)
  472: *
  473:             IF( ( KSTEP.EQ.2 ) .AND. ( P.NE.K ) ) THEN
  474: *              (1) Swap columnar parts
  475:                IF( P.GT.1 )
  476:      $            CALL ZSWAP( P-1, A( 1, K ), 1, A( 1, P ), 1 )
  477: *              (2) Swap and conjugate middle parts
  478:                DO 14 J = P + 1, K - 1
  479:                   T = DCONJG( A( J, K ) )
  480:                   A( J, K ) = DCONJG( A( P, J ) )
  481:                   A( P, J ) = T
  482:    14          CONTINUE
  483: *              (3) Swap and conjugate corner elements at row-col interserction
  484:                A( P, K ) = DCONJG( A( P, K ) )
  485: *              (4) Swap diagonal elements at row-col intersection
  486:                R1 = DBLE( A( K, K ) )
  487:                A( K, K ) = DBLE( A( P, P ) )
  488:                A( P, P ) = R1
  489: *
  490: *              Convert upper triangle of A into U form by applying
  491: *              the interchanges in columns k+1:N.
  492: *
  493:                IF( K.LT.N )
  494:      $            CALL ZSWAP( N-K, A( K, K+1 ), LDA, A( P, K+1 ), LDA )
  495: *
  496:             END IF
  497: *
  498: *           For both 1x1 and 2x2 pivots, interchange rows and
  499: *           columns KK and KP in the leading submatrix A(1:k,1:k)
  500: *
  501:             IF( KP.NE.KK ) THEN
  502: *              (1) Swap columnar parts
  503:                IF( KP.GT.1 )
  504:      $            CALL ZSWAP( KP-1, A( 1, KK ), 1, A( 1, KP ), 1 )
  505: *              (2) Swap and conjugate middle parts
  506:                DO 15 J = KP + 1, KK - 1
  507:                   T = DCONJG( A( J, KK ) )
  508:                   A( J, KK ) = DCONJG( A( KP, J ) )
  509:                   A( KP, J ) = T
  510:    15          CONTINUE
  511: *              (3) Swap and conjugate corner elements at row-col interserction
  512:                A( KP, KK ) = DCONJG( A( KP, KK ) )
  513: *              (4) Swap diagonal elements at row-col intersection
  514:                R1 = DBLE( A( KK, KK ) )
  515:                A( KK, KK ) = DBLE( A( KP, KP ) )
  516:                A( KP, KP ) = R1
  517: *
  518:                IF( KSTEP.EQ.2 ) THEN
  519: *                 (*) Make sure that diagonal element of pivot is real
  520:                   A( K, K ) = DBLE( A( K, K ) )
  521: *                 (5) Swap row elements
  522:                   T = A( K-1, K )
  523:                   A( K-1, K ) = A( KP, K )
  524:                   A( KP, K ) = T
  525:                END IF
  526: *
  527: *              Convert upper triangle of A into U form by applying
  528: *              the interchanges in columns k+1:N.
  529: *
  530:                IF( K.LT.N )
  531:      $            CALL ZSWAP( N-K, A( KK, K+1 ), LDA, A( KP, K+1 ),
  532:      $                        LDA )
  533: *
  534:             ELSE
  535: *              (*) Make sure that diagonal element of pivot is real
  536:                A( K, K ) = DBLE( A( K, K ) )
  537:                IF( KSTEP.EQ.2 )
  538:      $            A( K-1, K-1 ) = DBLE( A( K-1, K-1 ) )
  539:             END IF
  540: *
  541: *           Update the leading submatrix
  542: *
  543:             IF( KSTEP.EQ.1 ) THEN
  544: *
  545: *              1-by-1 pivot block D(k): column k now holds
  546: *
  547: *              W(k) = U(k)*D(k)
  548: *
  549: *              where U(k) is the k-th column of U
  550: *
  551:                IF( K.GT.1 ) THEN
  552: *
  553: *                 Perform a rank-1 update of A(1:k-1,1:k-1) and
  554: *                 store U(k) in column k
  555: *
  556:                   IF( ABS( DBLE( A( K, K ) ) ).GE.SFMIN ) THEN
  557: *
  558: *                    Perform a rank-1 update of A(1:k-1,1:k-1) as
  559: *                    A := A - U(k)*D(k)*U(k)**T
  560: *                       = A - W(k)*1/D(k)*W(k)**T
  561: *
  562:                      D11 = ONE / DBLE( A( K, K ) )
  563:                      CALL ZHER( UPLO, K-1, -D11, A( 1, K ), 1, A, LDA )
  564: *
  565: *                    Store U(k) in column k
  566: *
  567:                      CALL ZDSCAL( K-1, D11, A( 1, K ), 1 )
  568:                   ELSE
  569: *
  570: *                    Store L(k) in column K
  571: *
  572:                      D11 = DBLE( A( K, K ) )
  573:                      DO 16 II = 1, K - 1
  574:                         A( II, K ) = A( II, K ) / D11
  575:    16                CONTINUE
  576: *
  577: *                    Perform a rank-1 update of A(k+1:n,k+1:n) as
  578: *                    A := A - U(k)*D(k)*U(k)**T
  579: *                       = A - W(k)*(1/D(k))*W(k)**T
  580: *                       = A - (W(k)/D(k))*(D(k))*(W(k)/D(K))**T
  581: *
  582:                      CALL ZHER( UPLO, K-1, -D11, A( 1, K ), 1, A, LDA )
  583:                   END IF
  584: *
  585: *                 Store the superdiagonal element of D in array E
  586: *
  587:                   E( K ) = CZERO
  588: *
  589:                END IF
  590: *
  591:             ELSE
  592: *
  593: *              2-by-2 pivot block D(k): columns k and k-1 now hold
  594: *
  595: *              ( W(k-1) W(k) ) = ( U(k-1) U(k) )*D(k)
  596: *
  597: *              where U(k) and U(k-1) are the k-th and (k-1)-th columns
  598: *              of U
  599: *
  600: *              Perform a rank-2 update of A(1:k-2,1:k-2) as
  601: *
  602: *              A := A - ( U(k-1) U(k) )*D(k)*( U(k-1) U(k) )**T
  603: *                 = A - ( ( A(k-1)A(k) )*inv(D(k)) ) * ( A(k-1)A(k) )**T
  604: *
  605: *              and store L(k) and L(k+1) in columns k and k+1
  606: *
  607:                IF( K.GT.2 ) THEN
  608: *                 D = |A12|
  609:                   D = DLAPY2( DBLE( A( K-1, K ) ),
  610:      $                DIMAG( A( K-1, K ) ) )
  611:                   D11 = DBLE( A( K, K ) / D )
  612:                   D22 = DBLE( A( K-1, K-1 ) / D )
  613:                   D12 = A( K-1, K ) / D
  614:                   TT = ONE / ( D11*D22-ONE )
  615: *
  616:                   DO 30 J = K - 2, 1, -1
  617: *
  618: *                    Compute  D21 * ( W(k)W(k+1) ) * inv(D(k)) for row J
  619: *
  620:                      WKM1 = TT*( D11*A( J, K-1 )-DCONJG( D12 )*
  621:      $                      A( J, K ) )
  622:                      WK = TT*( D22*A( J, K )-D12*A( J, K-1 ) )
  623: *
  624: *                    Perform a rank-2 update of A(1:k-2,1:k-2)
  625: *
  626:                      DO 20 I = J, 1, -1
  627:                         A( I, J ) = A( I, J ) -
  628:      $                              ( A( I, K ) / D )*DCONJG( WK ) -
  629:      $                              ( A( I, K-1 ) / D )*DCONJG( WKM1 )
  630:    20                CONTINUE
  631: *
  632: *                    Store U(k) and U(k-1) in cols k and k-1 for row J
  633: *
  634:                      A( J, K ) = WK / D
  635:                      A( J, K-1 ) = WKM1 / D
  636: *                    (*) Make sure that diagonal element of pivot is real
  637:                      A( J, J ) = DCMPLX( DBLE( A( J, J ) ), ZERO )
  638: *
  639:    30             CONTINUE
  640: *
  641:                END IF
  642: *
  643: *              Copy superdiagonal elements of D(K) to E(K) and
  644: *              ZERO out superdiagonal entry of A
  645: *
  646:                E( K ) = A( K-1, K )
  647:                E( K-1 ) = CZERO
  648:                A( K-1, K ) = CZERO
  649: *
  650:             END IF
  651: *
  652: *           End column K is nonsingular
  653: *
  654:          END IF
  655: *
  656: *        Store details of the interchanges in IPIV
  657: *
  658:          IF( KSTEP.EQ.1 ) THEN
  659:             IPIV( K ) = KP
  660:          ELSE
  661:             IPIV( K ) = -P
  662:             IPIV( K-1 ) = -KP
  663:          END IF
  664: *
  665: *        Decrease K and return to the start of the main loop
  666: *
  667:          K = K - KSTEP
  668:          GO TO 10
  669: *
  670:    34    CONTINUE
  671: *
  672:       ELSE
  673: *
  674: *        Factorize A as L*D*L**H using the lower triangle of A
  675: *
  676: *        Initialize the unused last entry of the subdiagonal array E.
  677: *
  678:          E( N ) = CZERO
  679: *
  680: *        K is the main loop index, increasing from 1 to N in steps of
  681: *        1 or 2
  682: *
  683:          K = 1
  684:    40    CONTINUE
  685: *
  686: *        If K > N, exit from loop
  687: *
  688:          IF( K.GT.N )
  689:      $      GO TO 64
  690:          KSTEP = 1
  691:          P = K
  692: *
  693: *        Determine rows and columns to be interchanged and whether
  694: *        a 1-by-1 or 2-by-2 pivot block will be used
  695: *
  696:          ABSAKK = ABS( DBLE( A( K, K ) ) )
  697: *
  698: *        IMAX is the row-index of the largest off-diagonal element in
  699: *        column K, and COLMAX is its absolute value.
  700: *        Determine both COLMAX and IMAX.
  701: *
  702:          IF( K.LT.N ) THEN
  703:             IMAX = K + IZAMAX( N-K, A( K+1, K ), 1 )
  704:             COLMAX = CABS1( A( IMAX, K ) )
  705:          ELSE
  706:             COLMAX = ZERO
  707:          END IF
  708: *
  709:          IF( MAX( ABSAKK, COLMAX ).EQ.ZERO ) THEN
  710: *
  711: *           Column K is zero or underflow: set INFO and continue
  712: *
  713:             IF( INFO.EQ.0 )
  714:      $         INFO = K
  715:             KP = K
  716:             A( K, K ) = DBLE( A( K, K ) )
  717: *
  718: *           Set E( K ) to zero
  719: *
  720:             IF( K.LT.N )
  721:      $         E( K ) = CZERO
  722: *
  723:          ELSE
  724: *
  725: *           ============================================================
  726: *
  727: *           BEGIN pivot search
  728: *
  729: *           Case(1)
  730: *           Equivalent to testing for ABSAKK.GE.ALPHA*COLMAX
  731: *           (used to handle NaN and Inf)
  732: *
  733:             IF( .NOT.( ABSAKK.LT.ALPHA*COLMAX ) ) THEN
  734: *
  735: *              no interchange, use 1-by-1 pivot block
  736: *
  737:                KP = K
  738: *
  739:             ELSE
  740: *
  741:                DONE = .FALSE.
  742: *
  743: *              Loop until pivot found
  744: *
  745:    42          CONTINUE
  746: *
  747: *                 BEGIN pivot search loop body
  748: *
  749: *
  750: *                 JMAX is the column-index of the largest off-diagonal
  751: *                 element in row IMAX, and ROWMAX is its absolute value.
  752: *                 Determine both ROWMAX and JMAX.
  753: *
  754:                   IF( IMAX.NE.K ) THEN
  755:                      JMAX = K - 1 + IZAMAX( IMAX-K, A( IMAX, K ), LDA )
  756:                      ROWMAX = CABS1( A( IMAX, JMAX ) )
  757:                   ELSE
  758:                      ROWMAX = ZERO
  759:                   END IF
  760: *
  761:                   IF( IMAX.LT.N ) THEN
  762:                      ITEMP = IMAX + IZAMAX( N-IMAX, A( IMAX+1, IMAX ),
  763:      $                                     1 )
  764:                      DTEMP = CABS1( A( ITEMP, IMAX ) )
  765:                      IF( DTEMP.GT.ROWMAX ) THEN
  766:                         ROWMAX = DTEMP
  767:                         JMAX = ITEMP
  768:                      END IF
  769:                   END IF
  770: *
  771: *                 Case(2)
  772: *                 Equivalent to testing for
  773: *                 ABS( DBLE( W( IMAX,KW-1 ) ) ).GE.ALPHA*ROWMAX
  774: *                 (used to handle NaN and Inf)
  775: *
  776:                   IF( .NOT.( ABS( DBLE( A( IMAX, IMAX ) ) )
  777:      $                       .LT.ALPHA*ROWMAX ) ) THEN
  778: *
  779: *                    interchange rows and columns K and IMAX,
  780: *                    use 1-by-1 pivot block
  781: *
  782:                      KP = IMAX
  783:                      DONE = .TRUE.
  784: *
  785: *                 Case(3)
  786: *                 Equivalent to testing for ROWMAX.EQ.COLMAX,
  787: *                 (used to handle NaN and Inf)
  788: *
  789:                   ELSE IF( ( P.EQ.JMAX ) .OR. ( ROWMAX.LE.COLMAX ) )
  790:      $            THEN
  791: *
  792: *                    interchange rows and columns K+1 and IMAX,
  793: *                    use 2-by-2 pivot block
  794: *
  795:                      KP = IMAX
  796:                      KSTEP = 2
  797:                      DONE = .TRUE.
  798: *
  799: *                 Case(4)
  800:                   ELSE
  801: *
  802: *                    Pivot not found: set params and repeat
  803: *
  804:                      P = IMAX
  805:                      COLMAX = ROWMAX
  806:                      IMAX = JMAX
  807:                   END IF
  808: *
  809: *
  810: *                 END pivot search loop body
  811: *
  812:                IF( .NOT.DONE ) GOTO 42
  813: *
  814:             END IF
  815: *
  816: *           END pivot search
  817: *
  818: *           ============================================================
  819: *
  820: *           KK is the column of A where pivoting step stopped
  821: *
  822:             KK = K + KSTEP - 1
  823: *
  824: *           For only a 2x2 pivot, interchange rows and columns K and P
  825: *           in the trailing submatrix A(k:n,k:n)
  826: *
  827:             IF( ( KSTEP.EQ.2 ) .AND. ( P.NE.K ) ) THEN
  828: *              (1) Swap columnar parts
  829:                IF( P.LT.N )
  830:      $            CALL ZSWAP( N-P, A( P+1, K ), 1, A( P+1, P ), 1 )
  831: *              (2) Swap and conjugate middle parts
  832:                DO 44 J = K + 1, P - 1
  833:                   T = DCONJG( A( J, K ) )
  834:                   A( J, K ) = DCONJG( A( P, J ) )
  835:                   A( P, J ) = T
  836:    44          CONTINUE
  837: *              (3) Swap and conjugate corner elements at row-col interserction
  838:                A( P, K ) = DCONJG( A( P, K ) )
  839: *              (4) Swap diagonal elements at row-col intersection
  840:                R1 = DBLE( A( K, K ) )
  841:                A( K, K ) = DBLE( A( P, P ) )
  842:                A( P, P ) = R1
  843: *
  844: *              Convert lower triangle of A into L form by applying
  845: *              the interchanges in columns 1:k-1.
  846: *
  847:                IF ( K.GT.1 )
  848:      $            CALL ZSWAP( K-1, A( K, 1 ), LDA, A( P, 1 ), LDA )
  849: *
  850:             END IF
  851: *
  852: *           For both 1x1 and 2x2 pivots, interchange rows and
  853: *           columns KK and KP in the trailing submatrix A(k:n,k:n)
  854: *
  855:             IF( KP.NE.KK ) THEN
  856: *              (1) Swap columnar parts
  857:                IF( KP.LT.N )
  858:      $            CALL ZSWAP( N-KP, A( KP+1, KK ), 1, A( KP+1, KP ), 1 )
  859: *              (2) Swap and conjugate middle parts
  860:                DO 45 J = KK + 1, KP - 1
  861:                   T = DCONJG( A( J, KK ) )
  862:                   A( J, KK ) = DCONJG( A( KP, J ) )
  863:                   A( KP, J ) = T
  864:    45          CONTINUE
  865: *              (3) Swap and conjugate corner elements at row-col interserction
  866:                A( KP, KK ) = DCONJG( A( KP, KK ) )
  867: *              (4) Swap diagonal elements at row-col intersection
  868:                R1 = DBLE( A( KK, KK ) )
  869:                A( KK, KK ) = DBLE( A( KP, KP ) )
  870:                A( KP, KP ) = R1
  871: *
  872:                IF( KSTEP.EQ.2 ) THEN
  873: *                 (*) Make sure that diagonal element of pivot is real
  874:                   A( K, K ) = DBLE( A( K, K ) )
  875: *                 (5) Swap row elements
  876:                   T = A( K+1, K )
  877:                   A( K+1, K ) = A( KP, K )
  878:                   A( KP, K ) = T
  879:                END IF
  880: *
  881: *              Convert lower triangle of A into L form by applying
  882: *              the interchanges in columns 1:k-1.
  883: *
  884:                IF ( K.GT.1 )
  885:      $            CALL ZSWAP( K-1, A( KK, 1 ), LDA, A( KP, 1 ), LDA )
  886: *
  887:             ELSE
  888: *              (*) Make sure that diagonal element of pivot is real
  889:                A( K, K ) = DBLE( A( K, K ) )
  890:                IF( KSTEP.EQ.2 )
  891:      $            A( K+1, K+1 ) = DBLE( A( K+1, K+1 ) )
  892:             END IF
  893: *
  894: *           Update the trailing submatrix
  895: *
  896:             IF( KSTEP.EQ.1 ) THEN
  897: *
  898: *              1-by-1 pivot block D(k): column k of A now holds
  899: *
  900: *              W(k) = L(k)*D(k),
  901: *
  902: *              where L(k) is the k-th column of L
  903: *
  904:                IF( K.LT.N ) THEN
  905: *
  906: *                 Perform a rank-1 update of A(k+1:n,k+1:n) and
  907: *                 store L(k) in column k
  908: *
  909: *                 Handle division by a small number
  910: *
  911:                   IF( ABS( DBLE( A( K, K ) ) ).GE.SFMIN ) THEN
  912: *
  913: *                    Perform a rank-1 update of A(k+1:n,k+1:n) as
  914: *                    A := A - L(k)*D(k)*L(k)**T
  915: *                       = A - W(k)*(1/D(k))*W(k)**T
  916: *
  917:                      D11 = ONE / DBLE( A( K, K ) )
  918:                      CALL ZHER( UPLO, N-K, -D11, A( K+1, K ), 1,
  919:      $                          A( K+1, K+1 ), LDA )
  920: *
  921: *                    Store L(k) in column k
  922: *
  923:                      CALL ZDSCAL( N-K, D11, A( K+1, K ), 1 )
  924:                   ELSE
  925: *
  926: *                    Store L(k) in column k
  927: *
  928:                      D11 = DBLE( A( K, K ) )
  929:                      DO 46 II = K + 1, N
  930:                         A( II, K ) = A( II, K ) / D11
  931:    46                CONTINUE
  932: *
  933: *                    Perform a rank-1 update of A(k+1:n,k+1:n) as
  934: *                    A := A - L(k)*D(k)*L(k)**T
  935: *                       = A - W(k)*(1/D(k))*W(k)**T
  936: *                       = A - (W(k)/D(k))*(D(k))*(W(k)/D(K))**T
  937: *
  938:                      CALL ZHER( UPLO, N-K, -D11, A( K+1, K ), 1,
  939:      $                          A( K+1, K+1 ), LDA )
  940:                   END IF
  941: *
  942: *                 Store the subdiagonal element of D in array E
  943: *
  944:                   E( K ) = CZERO
  945: *
  946:                END IF
  947: *
  948:             ELSE
  949: *
  950: *              2-by-2 pivot block D(k): columns k and k+1 now hold
  951: *
  952: *              ( W(k) W(k+1) ) = ( L(k) L(k+1) )*D(k)
  953: *
  954: *              where L(k) and L(k+1) are the k-th and (k+1)-th columns
  955: *              of L
  956: *
  957: *
  958: *              Perform a rank-2 update of A(k+2:n,k+2:n) as
  959: *
  960: *              A := A - ( L(k) L(k+1) ) * D(k) * ( L(k) L(k+1) )**T
  961: *                 = A - ( ( A(k)A(k+1) )*inv(D(k) ) * ( A(k)A(k+1) )**T
  962: *
  963: *              and store L(k) and L(k+1) in columns k and k+1
  964: *
  965:                IF( K.LT.N-1 ) THEN
  966: *                 D = |A21|
  967:                   D = DLAPY2( DBLE( A( K+1, K ) ),
  968:      $                DIMAG( A( K+1, K ) ) )
  969:                   D11 = DBLE( A( K+1, K+1 ) ) / D
  970:                   D22 = DBLE( A( K, K ) ) / D
  971:                   D21 = A( K+1, K ) / D
  972:                   TT = ONE / ( D11*D22-ONE )
  973: *
  974:                   DO 60 J = K + 2, N
  975: *
  976: *                    Compute  D21 * ( W(k)W(k+1) ) * inv(D(k)) for row J
  977: *
  978:                      WK = TT*( D11*A( J, K )-D21*A( J, K+1 ) )
  979:                      WKP1 = TT*( D22*A( J, K+1 )-DCONJG( D21 )*
  980:      $                      A( J, K ) )
  981: *
  982: *                    Perform a rank-2 update of A(k+2:n,k+2:n)
  983: *
  984:                      DO 50 I = J, N
  985:                         A( I, J ) = A( I, J ) -
  986:      $                              ( A( I, K ) / D )*DCONJG( WK ) -
  987:      $                              ( A( I, K+1 ) / D )*DCONJG( WKP1 )
  988:    50                CONTINUE
  989: *
  990: *                    Store L(k) and L(k+1) in cols k and k+1 for row J
  991: *
  992:                      A( J, K ) = WK / D
  993:                      A( J, K+1 ) = WKP1 / D
  994: *                    (*) Make sure that diagonal element of pivot is real
  995:                      A( J, J ) = DCMPLX( DBLE( A( J, J ) ), ZERO )
  996: *
  997:    60             CONTINUE
  998: *
  999:                END IF
 1000: *
 1001: *              Copy subdiagonal elements of D(K) to E(K) and
 1002: *              ZERO out subdiagonal entry of A
 1003: *
 1004:                E( K ) = A( K+1, K )
 1005:                E( K+1 ) = CZERO
 1006:                A( K+1, K ) = CZERO
 1007: *
 1008:             END IF
 1009: *
 1010: *           End column K is nonsingular
 1011: *
 1012:          END IF
 1013: *
 1014: *        Store details of the interchanges in IPIV
 1015: *
 1016:          IF( KSTEP.EQ.1 ) THEN
 1017:             IPIV( K ) = KP
 1018:          ELSE
 1019:             IPIV( K ) = -P
 1020:             IPIV( K+1 ) = -KP
 1021:          END IF
 1022: *
 1023: *        Increase K and return to the start of the main loop
 1024: *
 1025:          K = K + KSTEP
 1026:          GO TO 40
 1027: *
 1028:    64    CONTINUE
 1029: *
 1030:       END IF
 1031: *
 1032:       RETURN
 1033: *
 1034: *     End of ZHETF2_RK
 1035: *
 1036:       END

CVSweb interface <joel.bertrand@systella.fr>