File:  [local] / rpl / lapack / lapack / dsteqr.f
Revision 1.18: download - view: text, annotated - select for diffs - revision graph
Mon Aug 7 08:39:07 2023 UTC (9 months 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 DSTEQR
    2: *
    3: *  =========== DOCUMENTATION ===========
    4: *
    5: * Online html documentation available at
    6: *            http://www.netlib.org/lapack/explore-html/
    7: *
    8: *> \htmlonly
    9: *> Download DSTEQR + dependencies
   10: *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dsteqr.f">
   11: *> [TGZ]</a>
   12: *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dsteqr.f">
   13: *> [ZIP]</a>
   14: *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dsteqr.f">
   15: *> [TXT]</a>
   16: *> \endhtmlonly
   17: *
   18: *  Definition:
   19: *  ===========
   20: *
   21: *       SUBROUTINE DSTEQR( COMPZ, N, D, E, Z, LDZ, WORK, INFO )
   22: *
   23: *       .. Scalar Arguments ..
   24: *       CHARACTER          COMPZ
   25: *       INTEGER            INFO, LDZ, N
   26: *       ..
   27: *       .. Array Arguments ..
   28: *       DOUBLE PRECISION   D( * ), E( * ), WORK( * ), Z( LDZ, * )
   29: *       ..
   30: *
   31: *
   32: *> \par Purpose:
   33: *  =============
   34: *>
   35: *> \verbatim
   36: *>
   37: *> DSTEQR computes all eigenvalues and, optionally, eigenvectors of a
   38: *> symmetric tridiagonal matrix using the implicit QL or QR method.
   39: *> The eigenvectors of a full or band symmetric matrix can also be found
   40: *> if DSYTRD or DSPTRD or DSBTRD has been used to reduce this matrix to
   41: *> tridiagonal form.
   42: *> \endverbatim
   43: *
   44: *  Arguments:
   45: *  ==========
   46: *
   47: *> \param[in] COMPZ
   48: *> \verbatim
   49: *>          COMPZ is CHARACTER*1
   50: *>          = 'N':  Compute eigenvalues only.
   51: *>          = 'V':  Compute eigenvalues and eigenvectors of the original
   52: *>                  symmetric matrix.  On entry, Z must contain the
   53: *>                  orthogonal matrix used to reduce the original matrix
   54: *>                  to tridiagonal form.
   55: *>          = 'I':  Compute eigenvalues and eigenvectors of the
   56: *>                  tridiagonal matrix.  Z is initialized to the identity
   57: *>                  matrix.
   58: *> \endverbatim
   59: *>
   60: *> \param[in] N
   61: *> \verbatim
   62: *>          N is INTEGER
   63: *>          The order of the matrix.  N >= 0.
   64: *> \endverbatim
   65: *>
   66: *> \param[in,out] D
   67: *> \verbatim
   68: *>          D is DOUBLE PRECISION array, dimension (N)
   69: *>          On entry, the diagonal elements of the tridiagonal matrix.
   70: *>          On exit, if INFO = 0, the eigenvalues in ascending order.
   71: *> \endverbatim
   72: *>
   73: *> \param[in,out] E
   74: *> \verbatim
   75: *>          E is DOUBLE PRECISION array, dimension (N-1)
   76: *>          On entry, the (n-1) subdiagonal elements of the tridiagonal
   77: *>          matrix.
   78: *>          On exit, E has been destroyed.
   79: *> \endverbatim
   80: *>
   81: *> \param[in,out] Z
   82: *> \verbatim
   83: *>          Z is DOUBLE PRECISION array, dimension (LDZ, N)
   84: *>          On entry, if  COMPZ = 'V', then Z contains the orthogonal
   85: *>          matrix used in the reduction to tridiagonal form.
   86: *>          On exit, if INFO = 0, then if  COMPZ = 'V', Z contains the
   87: *>          orthonormal eigenvectors of the original symmetric matrix,
   88: *>          and if COMPZ = 'I', Z contains the orthonormal eigenvectors
   89: *>          of the symmetric tridiagonal matrix.
   90: *>          If COMPZ = 'N', then Z is not referenced.
   91: *> \endverbatim
   92: *>
   93: *> \param[in] LDZ
   94: *> \verbatim
   95: *>          LDZ is INTEGER
   96: *>          The leading dimension of the array Z.  LDZ >= 1, and if
   97: *>          eigenvectors are desired, then  LDZ >= max(1,N).
   98: *> \endverbatim
   99: *>
  100: *> \param[out] WORK
  101: *> \verbatim
  102: *>          WORK is DOUBLE PRECISION array, dimension (max(1,2*N-2))
  103: *>          If COMPZ = 'N', then WORK is not referenced.
  104: *> \endverbatim
  105: *>
  106: *> \param[out] INFO
  107: *> \verbatim
  108: *>          INFO is INTEGER
  109: *>          = 0:  successful exit
  110: *>          < 0:  if INFO = -i, the i-th argument had an illegal value
  111: *>          > 0:  the algorithm has failed to find all the eigenvalues in
  112: *>                a total of 30*N iterations; if INFO = i, then i
  113: *>                elements of E have not converged to zero; on exit, D
  114: *>                and E contain the elements of a symmetric tridiagonal
  115: *>                matrix which is orthogonally similar to the original
  116: *>                matrix.
  117: *> \endverbatim
  118: *
  119: *  Authors:
  120: *  ========
  121: *
  122: *> \author Univ. of Tennessee
  123: *> \author Univ. of California Berkeley
  124: *> \author Univ. of Colorado Denver
  125: *> \author NAG Ltd.
  126: *
  127: *> \ingroup auxOTHERcomputational
  128: *
  129: *  =====================================================================
  130:       SUBROUTINE DSTEQR( COMPZ, N, D, E, Z, LDZ, WORK, INFO )
  131: *
  132: *  -- LAPACK computational routine --
  133: *  -- LAPACK is a software package provided by Univ. of Tennessee,    --
  134: *  -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--
  135: *
  136: *     .. Scalar Arguments ..
  137:       CHARACTER          COMPZ
  138:       INTEGER            INFO, LDZ, N
  139: *     ..
  140: *     .. Array Arguments ..
  141:       DOUBLE PRECISION   D( * ), E( * ), WORK( * ), Z( LDZ, * )
  142: *     ..
  143: *
  144: *  =====================================================================
  145: *
  146: *     .. Parameters ..
  147:       DOUBLE PRECISION   ZERO, ONE, TWO, THREE
  148:       PARAMETER          ( ZERO = 0.0D0, ONE = 1.0D0, TWO = 2.0D0,
  149:      $                   THREE = 3.0D0 )
  150:       INTEGER            MAXIT
  151:       PARAMETER          ( MAXIT = 30 )
  152: *     ..
  153: *     .. Local Scalars ..
  154:       INTEGER            I, ICOMPZ, II, ISCALE, J, JTOT, K, L, L1, LEND,
  155:      $                   LENDM1, LENDP1, LENDSV, LM1, LSV, M, MM, MM1,
  156:      $                   NM1, NMAXIT
  157:       DOUBLE PRECISION   ANORM, B, C, EPS, EPS2, F, G, P, R, RT1, RT2,
  158:      $                   S, SAFMAX, SAFMIN, SSFMAX, SSFMIN, TST
  159: *     ..
  160: *     .. External Functions ..
  161:       LOGICAL            LSAME
  162:       DOUBLE PRECISION   DLAMCH, DLANST, DLAPY2
  163:       EXTERNAL           LSAME, DLAMCH, DLANST, DLAPY2
  164: *     ..
  165: *     .. External Subroutines ..
  166:       EXTERNAL           DLAE2, DLAEV2, DLARTG, DLASCL, DLASET, DLASR,
  167:      $                   DLASRT, DSWAP, XERBLA
  168: *     ..
  169: *     .. Intrinsic Functions ..
  170:       INTRINSIC          ABS, MAX, SIGN, SQRT
  171: *     ..
  172: *     .. Executable Statements ..
  173: *
  174: *     Test the input parameters.
  175: *
  176:       INFO = 0
  177: *
  178:       IF( LSAME( COMPZ, 'N' ) ) THEN
  179:          ICOMPZ = 0
  180:       ELSE IF( LSAME( COMPZ, 'V' ) ) THEN
  181:          ICOMPZ = 1
  182:       ELSE IF( LSAME( COMPZ, 'I' ) ) THEN
  183:          ICOMPZ = 2
  184:       ELSE
  185:          ICOMPZ = -1
  186:       END IF
  187:       IF( ICOMPZ.LT.0 ) THEN
  188:          INFO = -1
  189:       ELSE IF( N.LT.0 ) THEN
  190:          INFO = -2
  191:       ELSE IF( ( LDZ.LT.1 ) .OR. ( ICOMPZ.GT.0 .AND. LDZ.LT.MAX( 1,
  192:      $         N ) ) ) THEN
  193:          INFO = -6
  194:       END IF
  195:       IF( INFO.NE.0 ) THEN
  196:          CALL XERBLA( 'DSTEQR', -INFO )
  197:          RETURN
  198:       END IF
  199: *
  200: *     Quick return if possible
  201: *
  202:       IF( N.EQ.0 )
  203:      $   RETURN
  204: *
  205:       IF( N.EQ.1 ) THEN
  206:          IF( ICOMPZ.EQ.2 )
  207:      $      Z( 1, 1 ) = ONE
  208:          RETURN
  209:       END IF
  210: *
  211: *     Determine the unit roundoff and over/underflow thresholds.
  212: *
  213:       EPS = DLAMCH( 'E' )
  214:       EPS2 = EPS**2
  215:       SAFMIN = DLAMCH( 'S' )
  216:       SAFMAX = ONE / SAFMIN
  217:       SSFMAX = SQRT( SAFMAX ) / THREE
  218:       SSFMIN = SQRT( SAFMIN ) / EPS2
  219: *
  220: *     Compute the eigenvalues and eigenvectors of the tridiagonal
  221: *     matrix.
  222: *
  223:       IF( ICOMPZ.EQ.2 )
  224:      $   CALL DLASET( 'Full', N, N, ZERO, ONE, Z, LDZ )
  225: *
  226:       NMAXIT = N*MAXIT
  227:       JTOT = 0
  228: *
  229: *     Determine where the matrix splits and choose QL or QR iteration
  230: *     for each block, according to whether top or bottom diagonal
  231: *     element is smaller.
  232: *
  233:       L1 = 1
  234:       NM1 = N - 1
  235: *
  236:    10 CONTINUE
  237:       IF( L1.GT.N )
  238:      $   GO TO 160
  239:       IF( L1.GT.1 )
  240:      $   E( L1-1 ) = ZERO
  241:       IF( L1.LE.NM1 ) THEN
  242:          DO 20 M = L1, NM1
  243:             TST = ABS( E( M ) )
  244:             IF( TST.EQ.ZERO )
  245:      $         GO TO 30
  246:             IF( TST.LE.( SQRT( ABS( D( M ) ) )*SQRT( ABS( D( M+
  247:      $          1 ) ) ) )*EPS ) THEN
  248:                E( M ) = ZERO
  249:                GO TO 30
  250:             END IF
  251:    20    CONTINUE
  252:       END IF
  253:       M = N
  254: *
  255:    30 CONTINUE
  256:       L = L1
  257:       LSV = L
  258:       LEND = M
  259:       LENDSV = LEND
  260:       L1 = M + 1
  261:       IF( LEND.EQ.L )
  262:      $   GO TO 10
  263: *
  264: *     Scale submatrix in rows and columns L to LEND
  265: *
  266:       ANORM = DLANST( 'M', LEND-L+1, D( L ), E( L ) )
  267:       ISCALE = 0
  268:       IF( ANORM.EQ.ZERO )
  269:      $   GO TO 10
  270:       IF( ANORM.GT.SSFMAX ) THEN
  271:          ISCALE = 1
  272:          CALL DLASCL( 'G', 0, 0, ANORM, SSFMAX, LEND-L+1, 1, D( L ), N,
  273:      $                INFO )
  274:          CALL DLASCL( 'G', 0, 0, ANORM, SSFMAX, LEND-L, 1, E( L ), N,
  275:      $                INFO )
  276:       ELSE IF( ANORM.LT.SSFMIN ) THEN
  277:          ISCALE = 2
  278:          CALL DLASCL( 'G', 0, 0, ANORM, SSFMIN, LEND-L+1, 1, D( L ), N,
  279:      $                INFO )
  280:          CALL DLASCL( 'G', 0, 0, ANORM, SSFMIN, LEND-L, 1, E( L ), N,
  281:      $                INFO )
  282:       END IF
  283: *
  284: *     Choose between QL and QR iteration
  285: *
  286:       IF( ABS( D( LEND ) ).LT.ABS( D( L ) ) ) THEN
  287:          LEND = LSV
  288:          L = LENDSV
  289:       END IF
  290: *
  291:       IF( LEND.GT.L ) THEN
  292: *
  293: *        QL Iteration
  294: *
  295: *        Look for small subdiagonal element.
  296: *
  297:    40    CONTINUE
  298:          IF( L.NE.LEND ) THEN
  299:             LENDM1 = LEND - 1
  300:             DO 50 M = L, LENDM1
  301:                TST = ABS( E( M ) )**2
  302:                IF( TST.LE.( EPS2*ABS( D( M ) ) )*ABS( D( M+1 ) )+
  303:      $             SAFMIN )GO TO 60
  304:    50       CONTINUE
  305:          END IF
  306: *
  307:          M = LEND
  308: *
  309:    60    CONTINUE
  310:          IF( M.LT.LEND )
  311:      $      E( M ) = ZERO
  312:          P = D( L )
  313:          IF( M.EQ.L )
  314:      $      GO TO 80
  315: *
  316: *        If remaining matrix is 2-by-2, use DLAE2 or SLAEV2
  317: *        to compute its eigensystem.
  318: *
  319:          IF( M.EQ.L+1 ) THEN
  320:             IF( ICOMPZ.GT.0 ) THEN
  321:                CALL DLAEV2( D( L ), E( L ), D( L+1 ), RT1, RT2, C, S )
  322:                WORK( L ) = C
  323:                WORK( N-1+L ) = S
  324:                CALL DLASR( 'R', 'V', 'B', N, 2, WORK( L ),
  325:      $                     WORK( N-1+L ), Z( 1, L ), LDZ )
  326:             ELSE
  327:                CALL DLAE2( D( L ), E( L ), D( L+1 ), RT1, RT2 )
  328:             END IF
  329:             D( L ) = RT1
  330:             D( L+1 ) = RT2
  331:             E( L ) = ZERO
  332:             L = L + 2
  333:             IF( L.LE.LEND )
  334:      $         GO TO 40
  335:             GO TO 140
  336:          END IF
  337: *
  338:          IF( JTOT.EQ.NMAXIT )
  339:      $      GO TO 140
  340:          JTOT = JTOT + 1
  341: *
  342: *        Form shift.
  343: *
  344:          G = ( D( L+1 )-P ) / ( TWO*E( L ) )
  345:          R = DLAPY2( G, ONE )
  346:          G = D( M ) - P + ( E( L ) / ( G+SIGN( R, G ) ) )
  347: *
  348:          S = ONE
  349:          C = ONE
  350:          P = ZERO
  351: *
  352: *        Inner loop
  353: *
  354:          MM1 = M - 1
  355:          DO 70 I = MM1, L, -1
  356:             F = S*E( I )
  357:             B = C*E( I )
  358:             CALL DLARTG( G, F, C, S, R )
  359:             IF( I.NE.M-1 )
  360:      $         E( I+1 ) = R
  361:             G = D( I+1 ) - P
  362:             R = ( D( I )-G )*S + TWO*C*B
  363:             P = S*R
  364:             D( I+1 ) = G + P
  365:             G = C*R - B
  366: *
  367: *           If eigenvectors are desired, then save rotations.
  368: *
  369:             IF( ICOMPZ.GT.0 ) THEN
  370:                WORK( I ) = C
  371:                WORK( N-1+I ) = -S
  372:             END IF
  373: *
  374:    70    CONTINUE
  375: *
  376: *        If eigenvectors are desired, then apply saved rotations.
  377: *
  378:          IF( ICOMPZ.GT.0 ) THEN
  379:             MM = M - L + 1
  380:             CALL DLASR( 'R', 'V', 'B', N, MM, WORK( L ), WORK( N-1+L ),
  381:      $                  Z( 1, L ), LDZ )
  382:          END IF
  383: *
  384:          D( L ) = D( L ) - P
  385:          E( L ) = G
  386:          GO TO 40
  387: *
  388: *        Eigenvalue found.
  389: *
  390:    80    CONTINUE
  391:          D( L ) = P
  392: *
  393:          L = L + 1
  394:          IF( L.LE.LEND )
  395:      $      GO TO 40
  396:          GO TO 140
  397: *
  398:       ELSE
  399: *
  400: *        QR Iteration
  401: *
  402: *        Look for small superdiagonal element.
  403: *
  404:    90    CONTINUE
  405:          IF( L.NE.LEND ) THEN
  406:             LENDP1 = LEND + 1
  407:             DO 100 M = L, LENDP1, -1
  408:                TST = ABS( E( M-1 ) )**2
  409:                IF( TST.LE.( EPS2*ABS( D( M ) ) )*ABS( D( M-1 ) )+
  410:      $             SAFMIN )GO TO 110
  411:   100       CONTINUE
  412:          END IF
  413: *
  414:          M = LEND
  415: *
  416:   110    CONTINUE
  417:          IF( M.GT.LEND )
  418:      $      E( M-1 ) = ZERO
  419:          P = D( L )
  420:          IF( M.EQ.L )
  421:      $      GO TO 130
  422: *
  423: *        If remaining matrix is 2-by-2, use DLAE2 or SLAEV2
  424: *        to compute its eigensystem.
  425: *
  426:          IF( M.EQ.L-1 ) THEN
  427:             IF( ICOMPZ.GT.0 ) THEN
  428:                CALL DLAEV2( D( L-1 ), E( L-1 ), D( L ), RT1, RT2, C, S )
  429:                WORK( M ) = C
  430:                WORK( N-1+M ) = S
  431:                CALL DLASR( 'R', 'V', 'F', N, 2, WORK( M ),
  432:      $                     WORK( N-1+M ), Z( 1, L-1 ), LDZ )
  433:             ELSE
  434:                CALL DLAE2( D( L-1 ), E( L-1 ), D( L ), RT1, RT2 )
  435:             END IF
  436:             D( L-1 ) = RT1
  437:             D( L ) = RT2
  438:             E( L-1 ) = ZERO
  439:             L = L - 2
  440:             IF( L.GE.LEND )
  441:      $         GO TO 90
  442:             GO TO 140
  443:          END IF
  444: *
  445:          IF( JTOT.EQ.NMAXIT )
  446:      $      GO TO 140
  447:          JTOT = JTOT + 1
  448: *
  449: *        Form shift.
  450: *
  451:          G = ( D( L-1 )-P ) / ( TWO*E( L-1 ) )
  452:          R = DLAPY2( G, ONE )
  453:          G = D( M ) - P + ( E( L-1 ) / ( G+SIGN( R, G ) ) )
  454: *
  455:          S = ONE
  456:          C = ONE
  457:          P = ZERO
  458: *
  459: *        Inner loop
  460: *
  461:          LM1 = L - 1
  462:          DO 120 I = M, LM1
  463:             F = S*E( I )
  464:             B = C*E( I )
  465:             CALL DLARTG( G, F, C, S, R )
  466:             IF( I.NE.M )
  467:      $         E( I-1 ) = R
  468:             G = D( I ) - P
  469:             R = ( D( I+1 )-G )*S + TWO*C*B
  470:             P = S*R
  471:             D( I ) = G + P
  472:             G = C*R - B
  473: *
  474: *           If eigenvectors are desired, then save rotations.
  475: *
  476:             IF( ICOMPZ.GT.0 ) THEN
  477:                WORK( I ) = C
  478:                WORK( N-1+I ) = S
  479:             END IF
  480: *
  481:   120    CONTINUE
  482: *
  483: *        If eigenvectors are desired, then apply saved rotations.
  484: *
  485:          IF( ICOMPZ.GT.0 ) THEN
  486:             MM = L - M + 1
  487:             CALL DLASR( 'R', 'V', 'F', N, MM, WORK( M ), WORK( N-1+M ),
  488:      $                  Z( 1, M ), LDZ )
  489:          END IF
  490: *
  491:          D( L ) = D( L ) - P
  492:          E( LM1 ) = G
  493:          GO TO 90
  494: *
  495: *        Eigenvalue found.
  496: *
  497:   130    CONTINUE
  498:          D( L ) = P
  499: *
  500:          L = L - 1
  501:          IF( L.GE.LEND )
  502:      $      GO TO 90
  503:          GO TO 140
  504: *
  505:       END IF
  506: *
  507: *     Undo scaling if necessary
  508: *
  509:   140 CONTINUE
  510:       IF( ISCALE.EQ.1 ) THEN
  511:          CALL DLASCL( 'G', 0, 0, SSFMAX, ANORM, LENDSV-LSV+1, 1,
  512:      $                D( LSV ), N, INFO )
  513:          CALL DLASCL( 'G', 0, 0, SSFMAX, ANORM, LENDSV-LSV, 1, E( LSV ),
  514:      $                N, INFO )
  515:       ELSE IF( ISCALE.EQ.2 ) THEN
  516:          CALL DLASCL( 'G', 0, 0, SSFMIN, ANORM, LENDSV-LSV+1, 1,
  517:      $                D( LSV ), N, INFO )
  518:          CALL DLASCL( 'G', 0, 0, SSFMIN, ANORM, LENDSV-LSV, 1, E( LSV ),
  519:      $                N, INFO )
  520:       END IF
  521: *
  522: *     Check for no convergence to an eigenvalue after a total
  523: *     of N*MAXIT iterations.
  524: *
  525:       IF( JTOT.LT.NMAXIT )
  526:      $   GO TO 10
  527:       DO 150 I = 1, N - 1
  528:          IF( E( I ).NE.ZERO )
  529:      $      INFO = INFO + 1
  530:   150 CONTINUE
  531:       GO TO 190
  532: *
  533: *     Order eigenvalues and eigenvectors.
  534: *
  535:   160 CONTINUE
  536:       IF( ICOMPZ.EQ.0 ) THEN
  537: *
  538: *        Use Quick Sort
  539: *
  540:          CALL DLASRT( 'I', N, D, INFO )
  541: *
  542:       ELSE
  543: *
  544: *        Use Selection Sort to minimize swaps of eigenvectors
  545: *
  546:          DO 180 II = 2, N
  547:             I = II - 1
  548:             K = I
  549:             P = D( I )
  550:             DO 170 J = II, N
  551:                IF( D( J ).LT.P ) THEN
  552:                   K = J
  553:                   P = D( J )
  554:                END IF
  555:   170       CONTINUE
  556:             IF( K.NE.I ) THEN
  557:                D( K ) = D( I )
  558:                D( I ) = P
  559:                CALL DSWAP( N, Z( 1, I ), 1, Z( 1, K ), 1 )
  560:             END IF
  561:   180    CONTINUE
  562:       END IF
  563: *
  564:   190 CONTINUE
  565:       RETURN
  566: *
  567: *     End of DSTEQR
  568: *
  569:       END

CVSweb interface <joel.bertrand@systella.fr>