File:  [local] / rpl / lapack / lapack / dlarre.f
Revision 1.24: download - view: text, annotated - select for diffs - revision graph
Mon Aug 7 08:38:57 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 DLARRE given the tridiagonal matrix T, sets small off-diagonal elements to zero and for each unreduced block Ti, finds base representations and eigenvalues.
    2: *
    3: *  =========== DOCUMENTATION ===========
    4: *
    5: * Online html documentation available at
    6: *            http://www.netlib.org/lapack/explore-html/
    7: *
    8: *> \htmlonly
    9: *> Download DLARRE + dependencies
   10: *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlarre.f">
   11: *> [TGZ]</a>
   12: *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlarre.f">
   13: *> [ZIP]</a>
   14: *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlarre.f">
   15: *> [TXT]</a>
   16: *> \endhtmlonly
   17: *
   18: *  Definition:
   19: *  ===========
   20: *
   21: *       SUBROUTINE DLARRE( RANGE, N, VL, VU, IL, IU, D, E, E2,
   22: *                           RTOL1, RTOL2, SPLTOL, NSPLIT, ISPLIT, M,
   23: *                           W, WERR, WGAP, IBLOCK, INDEXW, GERS, PIVMIN,
   24: *                           WORK, IWORK, INFO )
   25: *
   26: *       .. Scalar Arguments ..
   27: *       CHARACTER          RANGE
   28: *       INTEGER            IL, INFO, IU, M, N, NSPLIT
   29: *       DOUBLE PRECISION  PIVMIN, RTOL1, RTOL2, SPLTOL, VL, VU
   30: *       ..
   31: *       .. Array Arguments ..
   32: *       INTEGER            IBLOCK( * ), ISPLIT( * ), IWORK( * ),
   33: *      $                   INDEXW( * )
   34: *       DOUBLE PRECISION   D( * ), E( * ), E2( * ), GERS( * ),
   35: *      $                   W( * ),WERR( * ), WGAP( * ), WORK( * )
   36: *       ..
   37: *
   38: *
   39: *> \par Purpose:
   40: *  =============
   41: *>
   42: *> \verbatim
   43: *>
   44: *> To find the desired eigenvalues of a given real symmetric
   45: *> tridiagonal matrix T, DLARRE sets any "small" off-diagonal
   46: *> elements to zero, and for each unreduced block T_i, it finds
   47: *> (a) a suitable shift at one end of the block's spectrum,
   48: *> (b) the base representation, T_i - sigma_i I = L_i D_i L_i^T, and
   49: *> (c) eigenvalues of each L_i D_i L_i^T.
   50: *> The representations and eigenvalues found are then used by
   51: *> DSTEMR to compute the eigenvectors of T.
   52: *> The accuracy varies depending on whether bisection is used to
   53: *> find a few eigenvalues or the dqds algorithm (subroutine DLASQ2) to
   54: *> conpute all and then discard any unwanted one.
   55: *> As an added benefit, DLARRE also outputs the n
   56: *> Gerschgorin intervals for the matrices L_i D_i L_i^T.
   57: *> \endverbatim
   58: *
   59: *  Arguments:
   60: *  ==========
   61: *
   62: *> \param[in] RANGE
   63: *> \verbatim
   64: *>          RANGE is CHARACTER*1
   65: *>          = 'A': ("All")   all eigenvalues will be found.
   66: *>          = 'V': ("Value") all eigenvalues in the half-open interval
   67: *>                           (VL, VU] will be found.
   68: *>          = 'I': ("Index") the IL-th through IU-th eigenvalues (of the
   69: *>                           entire matrix) will be found.
   70: *> \endverbatim
   71: *>
   72: *> \param[in] N
   73: *> \verbatim
   74: *>          N is INTEGER
   75: *>          The order of the matrix. N > 0.
   76: *> \endverbatim
   77: *>
   78: *> \param[in,out] VL
   79: *> \verbatim
   80: *>          VL is DOUBLE PRECISION
   81: *>          If RANGE='V', the lower bound for the eigenvalues.
   82: *>          Eigenvalues less than or equal to VL, or greater than VU,
   83: *>          will not be returned.  VL < VU.
   84: *>          If RANGE='I' or ='A', DLARRE computes bounds on the desired
   85: *>          part of the spectrum.
   86: *> \endverbatim
   87: *>
   88: *> \param[in,out] VU
   89: *> \verbatim
   90: *>          VU is DOUBLE PRECISION
   91: *>          If RANGE='V', the upper bound for the eigenvalues.
   92: *>          Eigenvalues less than or equal to VL, or greater than VU,
   93: *>          will not be returned.  VL < VU.
   94: *>          If RANGE='I' or ='A', DLARRE computes bounds on the desired
   95: *>          part of the spectrum.
   96: *> \endverbatim
   97: *>
   98: *> \param[in] IL
   99: *> \verbatim
  100: *>          IL is INTEGER
  101: *>          If RANGE='I', the index of the
  102: *>          smallest eigenvalue to be returned.
  103: *>          1 <= IL <= IU <= N.
  104: *> \endverbatim
  105: *>
  106: *> \param[in] IU
  107: *> \verbatim
  108: *>          IU is INTEGER
  109: *>          If RANGE='I', the index of the
  110: *>          largest eigenvalue to be returned.
  111: *>          1 <= IL <= IU <= N.
  112: *> \endverbatim
  113: *>
  114: *> \param[in,out] D
  115: *> \verbatim
  116: *>          D is DOUBLE PRECISION array, dimension (N)
  117: *>          On entry, the N diagonal elements of the tridiagonal
  118: *>          matrix T.
  119: *>          On exit, the N diagonal elements of the diagonal
  120: *>          matrices D_i.
  121: *> \endverbatim
  122: *>
  123: *> \param[in,out] E
  124: *> \verbatim
  125: *>          E is DOUBLE PRECISION array, dimension (N)
  126: *>          On entry, the first (N-1) entries contain the subdiagonal
  127: *>          elements of the tridiagonal matrix T; E(N) need not be set.
  128: *>          On exit, E contains the subdiagonal elements of the unit
  129: *>          bidiagonal matrices L_i. The entries E( ISPLIT( I ) ),
  130: *>          1 <= I <= NSPLIT, contain the base points sigma_i on output.
  131: *> \endverbatim
  132: *>
  133: *> \param[in,out] E2
  134: *> \verbatim
  135: *>          E2 is DOUBLE PRECISION array, dimension (N)
  136: *>          On entry, the first (N-1) entries contain the SQUARES of the
  137: *>          subdiagonal elements of the tridiagonal matrix T;
  138: *>          E2(N) need not be set.
  139: *>          On exit, the entries E2( ISPLIT( I ) ),
  140: *>          1 <= I <= NSPLIT, have been set to zero
  141: *> \endverbatim
  142: *>
  143: *> \param[in] RTOL1
  144: *> \verbatim
  145: *>          RTOL1 is DOUBLE PRECISION
  146: *> \endverbatim
  147: *>
  148: *> \param[in] RTOL2
  149: *> \verbatim
  150: *>          RTOL2 is DOUBLE PRECISION
  151: *>           Parameters for bisection.
  152: *>           An interval [LEFT,RIGHT] has converged if
  153: *>           RIGHT-LEFT < MAX( RTOL1*GAP, RTOL2*MAX(|LEFT|,|RIGHT|) )
  154: *> \endverbatim
  155: *>
  156: *> \param[in] SPLTOL
  157: *> \verbatim
  158: *>          SPLTOL is DOUBLE PRECISION
  159: *>          The threshold for splitting.
  160: *> \endverbatim
  161: *>
  162: *> \param[out] NSPLIT
  163: *> \verbatim
  164: *>          NSPLIT is INTEGER
  165: *>          The number of blocks T splits into. 1 <= NSPLIT <= N.
  166: *> \endverbatim
  167: *>
  168: *> \param[out] ISPLIT
  169: *> \verbatim
  170: *>          ISPLIT is INTEGER array, dimension (N)
  171: *>          The splitting points, at which T breaks up into blocks.
  172: *>          The first block consists of rows/columns 1 to ISPLIT(1),
  173: *>          the second of rows/columns ISPLIT(1)+1 through ISPLIT(2),
  174: *>          etc., and the NSPLIT-th consists of rows/columns
  175: *>          ISPLIT(NSPLIT-1)+1 through ISPLIT(NSPLIT)=N.
  176: *> \endverbatim
  177: *>
  178: *> \param[out] M
  179: *> \verbatim
  180: *>          M is INTEGER
  181: *>          The total number of eigenvalues (of all L_i D_i L_i^T)
  182: *>          found.
  183: *> \endverbatim
  184: *>
  185: *> \param[out] W
  186: *> \verbatim
  187: *>          W is DOUBLE PRECISION array, dimension (N)
  188: *>          The first M elements contain the eigenvalues. The
  189: *>          eigenvalues of each of the blocks, L_i D_i L_i^T, are
  190: *>          sorted in ascending order ( DLARRE may use the
  191: *>          remaining N-M elements as workspace).
  192: *> \endverbatim
  193: *>
  194: *> \param[out] WERR
  195: *> \verbatim
  196: *>          WERR is DOUBLE PRECISION array, dimension (N)
  197: *>          The error bound on the corresponding eigenvalue in W.
  198: *> \endverbatim
  199: *>
  200: *> \param[out] WGAP
  201: *> \verbatim
  202: *>          WGAP is DOUBLE PRECISION array, dimension (N)
  203: *>          The separation from the right neighbor eigenvalue in W.
  204: *>          The gap is only with respect to the eigenvalues of the same block
  205: *>          as each block has its own representation tree.
  206: *>          Exception: at the right end of a block we store the left gap
  207: *> \endverbatim
  208: *>
  209: *> \param[out] IBLOCK
  210: *> \verbatim
  211: *>          IBLOCK is INTEGER array, dimension (N)
  212: *>          The indices of the blocks (submatrices) associated with the
  213: *>          corresponding eigenvalues in W; IBLOCK(i)=1 if eigenvalue
  214: *>          W(i) belongs to the first block from the top, =2 if W(i)
  215: *>          belongs to the second block, etc.
  216: *> \endverbatim
  217: *>
  218: *> \param[out] INDEXW
  219: *> \verbatim
  220: *>          INDEXW is INTEGER array, dimension (N)
  221: *>          The indices of the eigenvalues within each block (submatrix);
  222: *>          for example, INDEXW(i)= 10 and IBLOCK(i)=2 imply that the
  223: *>          i-th eigenvalue W(i) is the 10-th eigenvalue in block 2
  224: *> \endverbatim
  225: *>
  226: *> \param[out] GERS
  227: *> \verbatim
  228: *>          GERS is DOUBLE PRECISION array, dimension (2*N)
  229: *>          The N Gerschgorin intervals (the i-th Gerschgorin interval
  230: *>          is (GERS(2*i-1), GERS(2*i)).
  231: *> \endverbatim
  232: *>
  233: *> \param[out] PIVMIN
  234: *> \verbatim
  235: *>          PIVMIN is DOUBLE PRECISION
  236: *>          The minimum pivot in the Sturm sequence for T.
  237: *> \endverbatim
  238: *>
  239: *> \param[out] WORK
  240: *> \verbatim
  241: *>          WORK is DOUBLE PRECISION array, dimension (6*N)
  242: *>          Workspace.
  243: *> \endverbatim
  244: *>
  245: *> \param[out] IWORK
  246: *> \verbatim
  247: *>          IWORK is INTEGER array, dimension (5*N)
  248: *>          Workspace.
  249: *> \endverbatim
  250: *>
  251: *> \param[out] INFO
  252: *> \verbatim
  253: *>          INFO is INTEGER
  254: *>          = 0:  successful exit
  255: *>          > 0:  A problem occurred in DLARRE.
  256: *>          < 0:  One of the called subroutines signaled an internal problem.
  257: *>                Needs inspection of the corresponding parameter IINFO
  258: *>                for further information.
  259: *>
  260: *>          =-1:  Problem in DLARRD.
  261: *>          = 2:  No base representation could be found in MAXTRY iterations.
  262: *>                Increasing MAXTRY and recompilation might be a remedy.
  263: *>          =-3:  Problem in DLARRB when computing the refined root
  264: *>                representation for DLASQ2.
  265: *>          =-4:  Problem in DLARRB when preforming bisection on the
  266: *>                desired part of the spectrum.
  267: *>          =-5:  Problem in DLASQ2.
  268: *>          =-6:  Problem in DLASQ2.
  269: *> \endverbatim
  270: *
  271: *  Authors:
  272: *  ========
  273: *
  274: *> \author Univ. of Tennessee
  275: *> \author Univ. of California Berkeley
  276: *> \author Univ. of Colorado Denver
  277: *> \author NAG Ltd.
  278: *
  279: *> \ingroup OTHERauxiliary
  280: *
  281: *> \par Further Details:
  282: *  =====================
  283: *>
  284: *> \verbatim
  285: *>
  286: *>  The base representations are required to suffer very little
  287: *>  element growth and consequently define all their eigenvalues to
  288: *>  high relative accuracy.
  289: *> \endverbatim
  290: *
  291: *> \par Contributors:
  292: *  ==================
  293: *>
  294: *>     Beresford Parlett, University of California, Berkeley, USA \n
  295: *>     Jim Demmel, University of California, Berkeley, USA \n
  296: *>     Inderjit Dhillon, University of Texas, Austin, USA \n
  297: *>     Osni Marques, LBNL/NERSC, USA \n
  298: *>     Christof Voemel, University of California, Berkeley, USA \n
  299: *>
  300: *  =====================================================================
  301:       SUBROUTINE DLARRE( RANGE, N, VL, VU, IL, IU, D, E, E2,
  302:      $                    RTOL1, RTOL2, SPLTOL, NSPLIT, ISPLIT, M,
  303:      $                    W, WERR, WGAP, IBLOCK, INDEXW, GERS, PIVMIN,
  304:      $                    WORK, IWORK, INFO )
  305: *
  306: *  -- LAPACK auxiliary routine --
  307: *  -- LAPACK is a software package provided by Univ. of Tennessee,    --
  308: *  -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--
  309: *
  310: *     .. Scalar Arguments ..
  311:       CHARACTER          RANGE
  312:       INTEGER            IL, INFO, IU, M, N, NSPLIT
  313:       DOUBLE PRECISION  PIVMIN, RTOL1, RTOL2, SPLTOL, VL, VU
  314: *     ..
  315: *     .. Array Arguments ..
  316:       INTEGER            IBLOCK( * ), ISPLIT( * ), IWORK( * ),
  317:      $                   INDEXW( * )
  318:       DOUBLE PRECISION   D( * ), E( * ), E2( * ), GERS( * ),
  319:      $                   W( * ),WERR( * ), WGAP( * ), WORK( * )
  320: *     ..
  321: *
  322: *  =====================================================================
  323: *
  324: *     .. Parameters ..
  325:       DOUBLE PRECISION   FAC, FOUR, FOURTH, FUDGE, HALF, HNDRD,
  326:      $                   MAXGROWTH, ONE, PERT, TWO, ZERO
  327:       PARAMETER          ( ZERO = 0.0D0, ONE = 1.0D0,
  328:      $                     TWO = 2.0D0, FOUR=4.0D0,
  329:      $                     HNDRD = 100.0D0,
  330:      $                     PERT = 8.0D0,
  331:      $                     HALF = ONE/TWO, FOURTH = ONE/FOUR, FAC= HALF,
  332:      $                     MAXGROWTH = 64.0D0, FUDGE = 2.0D0 )
  333:       INTEGER            MAXTRY, ALLRNG, INDRNG, VALRNG
  334:       PARAMETER          ( MAXTRY = 6, ALLRNG = 1, INDRNG = 2,
  335:      $                     VALRNG = 3 )
  336: *     ..
  337: *     .. Local Scalars ..
  338:       LOGICAL            FORCEB, NOREP, USEDQD
  339:       INTEGER            CNT, CNT1, CNT2, I, IBEGIN, IDUM, IEND, IINFO,
  340:      $                   IN, INDL, INDU, IRANGE, J, JBLK, MB, MM,
  341:      $                   WBEGIN, WEND
  342:       DOUBLE PRECISION   AVGAP, BSRTOL, CLWDTH, DMAX, DPIVOT, EABS,
  343:      $                   EMAX, EOLD, EPS, GL, GU, ISLEFT, ISRGHT, RTL,
  344:      $                   RTOL, S1, S2, SAFMIN, SGNDEF, SIGMA, SPDIAM,
  345:      $                   TAU, TMP, TMP1
  346: 
  347: 
  348: *     ..
  349: *     .. Local Arrays ..
  350:       INTEGER            ISEED( 4 )
  351: *     ..
  352: *     .. External Functions ..
  353:       LOGICAL            LSAME
  354:       DOUBLE PRECISION            DLAMCH
  355:       EXTERNAL           DLAMCH, LSAME
  356: 
  357: *     ..
  358: *     .. External Subroutines ..
  359:       EXTERNAL           DCOPY, DLARNV, DLARRA, DLARRB, DLARRC, DLARRD,
  360:      $                   DLASQ2, DLARRK
  361: *     ..
  362: *     .. Intrinsic Functions ..
  363:       INTRINSIC          ABS, MAX, MIN
  364: 
  365: *     ..
  366: *     .. Executable Statements ..
  367: *
  368: 
  369:       INFO = 0
  370: *
  371: *     Quick return if possible
  372: *
  373:       IF( N.LE.0 ) THEN
  374:          RETURN
  375:       END IF
  376: *
  377: *     Decode RANGE
  378: *
  379:       IF( LSAME( RANGE, 'A' ) ) THEN
  380:          IRANGE = ALLRNG
  381:       ELSE IF( LSAME( RANGE, 'V' ) ) THEN
  382:          IRANGE = VALRNG
  383:       ELSE IF( LSAME( RANGE, 'I' ) ) THEN
  384:          IRANGE = INDRNG
  385:       END IF
  386: 
  387:       M = 0
  388: 
  389: *     Get machine constants
  390:       SAFMIN = DLAMCH( 'S' )
  391:       EPS = DLAMCH( 'P' )
  392: 
  393: *     Set parameters
  394:       RTL = SQRT(EPS)
  395:       BSRTOL = SQRT(EPS)
  396: 
  397: *     Treat case of 1x1 matrix for quick return
  398:       IF( N.EQ.1 ) THEN
  399:          IF( (IRANGE.EQ.ALLRNG).OR.
  400:      $       ((IRANGE.EQ.VALRNG).AND.(D(1).GT.VL).AND.(D(1).LE.VU)).OR.
  401:      $       ((IRANGE.EQ.INDRNG).AND.(IL.EQ.1).AND.(IU.EQ.1)) ) THEN
  402:             M = 1
  403:             W(1) = D(1)
  404: *           The computation error of the eigenvalue is zero
  405:             WERR(1) = ZERO
  406:             WGAP(1) = ZERO
  407:             IBLOCK( 1 ) = 1
  408:             INDEXW( 1 ) = 1
  409:             GERS(1) = D( 1 )
  410:             GERS(2) = D( 1 )
  411:          ENDIF
  412: *        store the shift for the initial RRR, which is zero in this case
  413:          E(1) = ZERO
  414:          RETURN
  415:       END IF
  416: 
  417: *     General case: tridiagonal matrix of order > 1
  418: *
  419: *     Init WERR, WGAP. Compute Gerschgorin intervals and spectral diameter.
  420: *     Compute maximum off-diagonal entry and pivmin.
  421:       GL = D(1)
  422:       GU = D(1)
  423:       EOLD = ZERO
  424:       EMAX = ZERO
  425:       E(N) = ZERO
  426:       DO 5 I = 1,N
  427:          WERR(I) = ZERO
  428:          WGAP(I) = ZERO
  429:          EABS = ABS( E(I) )
  430:          IF( EABS .GE. EMAX ) THEN
  431:             EMAX = EABS
  432:          END IF
  433:          TMP1 = EABS + EOLD
  434:          GERS( 2*I-1) = D(I) - TMP1
  435:          GL =  MIN( GL, GERS( 2*I - 1))
  436:          GERS( 2*I ) = D(I) + TMP1
  437:          GU = MAX( GU, GERS(2*I) )
  438:          EOLD  = EABS
  439:  5    CONTINUE
  440: *     The minimum pivot allowed in the Sturm sequence for T
  441:       PIVMIN = SAFMIN * MAX( ONE, EMAX**2 )
  442: *     Compute spectral diameter. The Gerschgorin bounds give an
  443: *     estimate that is wrong by at most a factor of SQRT(2)
  444:       SPDIAM = GU - GL
  445: 
  446: *     Compute splitting points
  447:       CALL DLARRA( N, D, E, E2, SPLTOL, SPDIAM,
  448:      $                    NSPLIT, ISPLIT, IINFO )
  449: 
  450: *     Can force use of bisection instead of faster DQDS.
  451: *     Option left in the code for future multisection work.
  452:       FORCEB = .FALSE.
  453: 
  454: *     Initialize USEDQD, DQDS should be used for ALLRNG unless someone
  455: *     explicitly wants bisection.
  456:       USEDQD = (( IRANGE.EQ.ALLRNG ) .AND. (.NOT.FORCEB))
  457: 
  458:       IF( (IRANGE.EQ.ALLRNG) .AND. (.NOT. FORCEB) ) THEN
  459: *        Set interval [VL,VU] that contains all eigenvalues
  460:          VL = GL
  461:          VU = GU
  462:       ELSE
  463: *        We call DLARRD to find crude approximations to the eigenvalues
  464: *        in the desired range. In case IRANGE = INDRNG, we also obtain the
  465: *        interval (VL,VU] that contains all the wanted eigenvalues.
  466: *        An interval [LEFT,RIGHT] has converged if
  467: *        RIGHT-LEFT.LT.RTOL*MAX(ABS(LEFT),ABS(RIGHT))
  468: *        DLARRD needs a WORK of size 4*N, IWORK of size 3*N
  469:          CALL DLARRD( RANGE, 'B', N, VL, VU, IL, IU, GERS,
  470:      $                    BSRTOL, D, E, E2, PIVMIN, NSPLIT, ISPLIT,
  471:      $                    MM, W, WERR, VL, VU, IBLOCK, INDEXW,
  472:      $                    WORK, IWORK, IINFO )
  473:          IF( IINFO.NE.0 ) THEN
  474:             INFO = -1
  475:             RETURN
  476:          ENDIF
  477: *        Make sure that the entries M+1 to N in W, WERR, IBLOCK, INDEXW are 0
  478:          DO 14 I = MM+1,N
  479:             W( I ) = ZERO
  480:             WERR( I ) = ZERO
  481:             IBLOCK( I ) = 0
  482:             INDEXW( I ) = 0
  483:  14      CONTINUE
  484:       END IF
  485: 
  486: 
  487: ***
  488: *     Loop over unreduced blocks
  489:       IBEGIN = 1
  490:       WBEGIN = 1
  491:       DO 170 JBLK = 1, NSPLIT
  492:          IEND = ISPLIT( JBLK )
  493:          IN = IEND - IBEGIN + 1
  494: 
  495: *        1 X 1 block
  496:          IF( IN.EQ.1 ) THEN
  497:             IF( (IRANGE.EQ.ALLRNG).OR.( (IRANGE.EQ.VALRNG).AND.
  498:      $         ( D( IBEGIN ).GT.VL ).AND.( D( IBEGIN ).LE.VU ) )
  499:      $        .OR. ( (IRANGE.EQ.INDRNG).AND.(IBLOCK(WBEGIN).EQ.JBLK))
  500:      $        ) THEN
  501:                M = M + 1
  502:                W( M ) = D( IBEGIN )
  503:                WERR(M) = ZERO
  504: *              The gap for a single block doesn't matter for the later
  505: *              algorithm and is assigned an arbitrary large value
  506:                WGAP(M) = ZERO
  507:                IBLOCK( M ) = JBLK
  508:                INDEXW( M ) = 1
  509:                WBEGIN = WBEGIN + 1
  510:             ENDIF
  511: *           E( IEND ) holds the shift for the initial RRR
  512:             E( IEND ) = ZERO
  513:             IBEGIN = IEND + 1
  514:             GO TO 170
  515:          END IF
  516: *
  517: *        Blocks of size larger than 1x1
  518: *
  519: *        E( IEND ) will hold the shift for the initial RRR, for now set it =0
  520:          E( IEND ) = ZERO
  521: *
  522: *        Find local outer bounds GL,GU for the block
  523:          GL = D(IBEGIN)
  524:          GU = D(IBEGIN)
  525:          DO 15 I = IBEGIN , IEND
  526:             GL = MIN( GERS( 2*I-1 ), GL )
  527:             GU = MAX( GERS( 2*I ), GU )
  528:  15      CONTINUE
  529:          SPDIAM = GU - GL
  530: 
  531:          IF(.NOT. ((IRANGE.EQ.ALLRNG).AND.(.NOT.FORCEB)) ) THEN
  532: *           Count the number of eigenvalues in the current block.
  533:             MB = 0
  534:             DO 20 I = WBEGIN,MM
  535:                IF( IBLOCK(I).EQ.JBLK ) THEN
  536:                   MB = MB+1
  537:                ELSE
  538:                   GOTO 21
  539:                ENDIF
  540:  20         CONTINUE
  541:  21         CONTINUE
  542: 
  543:             IF( MB.EQ.0) THEN
  544: *              No eigenvalue in the current block lies in the desired range
  545: *              E( IEND ) holds the shift for the initial RRR
  546:                E( IEND ) = ZERO
  547:                IBEGIN = IEND + 1
  548:                GO TO 170
  549:             ELSE
  550: 
  551: *              Decide whether dqds or bisection is more efficient
  552:                USEDQD = ( (MB .GT. FAC*IN) .AND. (.NOT.FORCEB) )
  553:                WEND = WBEGIN + MB - 1
  554: *              Calculate gaps for the current block
  555: *              In later stages, when representations for individual
  556: *              eigenvalues are different, we use SIGMA = E( IEND ).
  557:                SIGMA = ZERO
  558:                DO 30 I = WBEGIN, WEND - 1
  559:                   WGAP( I ) = MAX( ZERO,
  560:      $                        W(I+1)-WERR(I+1) - (W(I)+WERR(I)) )
  561:  30            CONTINUE
  562:                WGAP( WEND ) = MAX( ZERO,
  563:      $                     VU - SIGMA - (W( WEND )+WERR( WEND )))
  564: *              Find local index of the first and last desired evalue.
  565:                INDL = INDEXW(WBEGIN)
  566:                INDU = INDEXW( WEND )
  567:             ENDIF
  568:          ENDIF
  569:          IF(( (IRANGE.EQ.ALLRNG) .AND. (.NOT. FORCEB) ).OR.USEDQD) THEN
  570: *           Case of DQDS
  571: *           Find approximations to the extremal eigenvalues of the block
  572:             CALL DLARRK( IN, 1, GL, GU, D(IBEGIN),
  573:      $               E2(IBEGIN), PIVMIN, RTL, TMP, TMP1, IINFO )
  574:             IF( IINFO.NE.0 ) THEN
  575:                INFO = -1
  576:                RETURN
  577:             ENDIF
  578:             ISLEFT = MAX(GL, TMP - TMP1
  579:      $               - HNDRD * EPS* ABS(TMP - TMP1))
  580: 
  581:             CALL DLARRK( IN, IN, GL, GU, D(IBEGIN),
  582:      $               E2(IBEGIN), PIVMIN, RTL, TMP, TMP1, IINFO )
  583:             IF( IINFO.NE.0 ) THEN
  584:                INFO = -1
  585:                RETURN
  586:             ENDIF
  587:             ISRGHT = MIN(GU, TMP + TMP1
  588:      $                 + HNDRD * EPS * ABS(TMP + TMP1))
  589: *           Improve the estimate of the spectral diameter
  590:             SPDIAM = ISRGHT - ISLEFT
  591:          ELSE
  592: *           Case of bisection
  593: *           Find approximations to the wanted extremal eigenvalues
  594:             ISLEFT = MAX(GL, W(WBEGIN) - WERR(WBEGIN)
  595:      $                  - HNDRD * EPS*ABS(W(WBEGIN)- WERR(WBEGIN) ))
  596:             ISRGHT = MIN(GU,W(WEND) + WERR(WEND)
  597:      $                  + HNDRD * EPS * ABS(W(WEND)+ WERR(WEND)))
  598:          ENDIF
  599: 
  600: 
  601: *        Decide whether the base representation for the current block
  602: *        L_JBLK D_JBLK L_JBLK^T = T_JBLK - sigma_JBLK I
  603: *        should be on the left or the right end of the current block.
  604: *        The strategy is to shift to the end which is "more populated"
  605: *        Furthermore, decide whether to use DQDS for the computation of
  606: *        the eigenvalue approximations at the end of DLARRE or bisection.
  607: *        dqds is chosen if all eigenvalues are desired or the number of
  608: *        eigenvalues to be computed is large compared to the blocksize.
  609:          IF( ( IRANGE.EQ.ALLRNG ) .AND. (.NOT.FORCEB) ) THEN
  610: *           If all the eigenvalues have to be computed, we use dqd
  611:             USEDQD = .TRUE.
  612: *           INDL is the local index of the first eigenvalue to compute
  613:             INDL = 1
  614:             INDU = IN
  615: *           MB =  number of eigenvalues to compute
  616:             MB = IN
  617:             WEND = WBEGIN + MB - 1
  618: *           Define 1/4 and 3/4 points of the spectrum
  619:             S1 = ISLEFT + FOURTH * SPDIAM
  620:             S2 = ISRGHT - FOURTH * SPDIAM
  621:          ELSE
  622: *           DLARRD has computed IBLOCK and INDEXW for each eigenvalue
  623: *           approximation.
  624: *           choose sigma
  625:             IF( USEDQD ) THEN
  626:                S1 = ISLEFT + FOURTH * SPDIAM
  627:                S2 = ISRGHT - FOURTH * SPDIAM
  628:             ELSE
  629:                TMP = MIN(ISRGHT,VU) -  MAX(ISLEFT,VL)
  630:                S1 =  MAX(ISLEFT,VL) + FOURTH * TMP
  631:                S2 =  MIN(ISRGHT,VU) - FOURTH * TMP
  632:             ENDIF
  633:          ENDIF
  634: 
  635: *        Compute the negcount at the 1/4 and 3/4 points
  636:          IF(MB.GT.1) THEN
  637:             CALL DLARRC( 'T', IN, S1, S2, D(IBEGIN),
  638:      $                    E(IBEGIN), PIVMIN, CNT, CNT1, CNT2, IINFO)
  639:          ENDIF
  640: 
  641:          IF(MB.EQ.1) THEN
  642:             SIGMA = GL
  643:             SGNDEF = ONE
  644:          ELSEIF( CNT1 - INDL .GE. INDU - CNT2 ) THEN
  645:             IF( ( IRANGE.EQ.ALLRNG ) .AND. (.NOT.FORCEB) ) THEN
  646:                SIGMA = MAX(ISLEFT,GL)
  647:             ELSEIF( USEDQD ) THEN
  648: *              use Gerschgorin bound as shift to get pos def matrix
  649: *              for dqds
  650:                SIGMA = ISLEFT
  651:             ELSE
  652: *              use approximation of the first desired eigenvalue of the
  653: *              block as shift
  654:                SIGMA = MAX(ISLEFT,VL)
  655:             ENDIF
  656:             SGNDEF = ONE
  657:          ELSE
  658:             IF( ( IRANGE.EQ.ALLRNG ) .AND. (.NOT.FORCEB) ) THEN
  659:                SIGMA = MIN(ISRGHT,GU)
  660:             ELSEIF( USEDQD ) THEN
  661: *              use Gerschgorin bound as shift to get neg def matrix
  662: *              for dqds
  663:                SIGMA = ISRGHT
  664:             ELSE
  665: *              use approximation of the first desired eigenvalue of the
  666: *              block as shift
  667:                SIGMA = MIN(ISRGHT,VU)
  668:             ENDIF
  669:             SGNDEF = -ONE
  670:          ENDIF
  671: 
  672: 
  673: *        An initial SIGMA has been chosen that will be used for computing
  674: *        T - SIGMA I = L D L^T
  675: *        Define the increment TAU of the shift in case the initial shift
  676: *        needs to be refined to obtain a factorization with not too much
  677: *        element growth.
  678:          IF( USEDQD ) THEN
  679: *           The initial SIGMA was to the outer end of the spectrum
  680: *           the matrix is definite and we need not retreat.
  681:             TAU = SPDIAM*EPS*N + TWO*PIVMIN
  682:             TAU = MAX( TAU,TWO*EPS*ABS(SIGMA) )
  683:          ELSE
  684:             IF(MB.GT.1) THEN
  685:                CLWDTH = W(WEND) + WERR(WEND) - W(WBEGIN) - WERR(WBEGIN)
  686:                AVGAP = ABS(CLWDTH / DBLE(WEND-WBEGIN))
  687:                IF( SGNDEF.EQ.ONE ) THEN
  688:                   TAU = HALF*MAX(WGAP(WBEGIN),AVGAP)
  689:                   TAU = MAX(TAU,WERR(WBEGIN))
  690:                ELSE
  691:                   TAU = HALF*MAX(WGAP(WEND-1),AVGAP)
  692:                   TAU = MAX(TAU,WERR(WEND))
  693:                ENDIF
  694:             ELSE
  695:                TAU = WERR(WBEGIN)
  696:             ENDIF
  697:          ENDIF
  698: *
  699:          DO 80 IDUM = 1, MAXTRY
  700: *           Compute L D L^T factorization of tridiagonal matrix T - sigma I.
  701: *           Store D in WORK(1:IN), L in WORK(IN+1:2*IN), and reciprocals of
  702: *           pivots in WORK(2*IN+1:3*IN)
  703:             DPIVOT = D( IBEGIN ) - SIGMA
  704:             WORK( 1 ) = DPIVOT
  705:             DMAX = ABS( WORK(1) )
  706:             J = IBEGIN
  707:             DO 70 I = 1, IN - 1
  708:                WORK( 2*IN+I ) = ONE / WORK( I )
  709:                TMP = E( J )*WORK( 2*IN+I )
  710:                WORK( IN+I ) = TMP
  711:                DPIVOT = ( D( J+1 )-SIGMA ) - TMP*E( J )
  712:                WORK( I+1 ) = DPIVOT
  713:                DMAX = MAX( DMAX, ABS(DPIVOT) )
  714:                J = J + 1
  715:  70         CONTINUE
  716: *           check for element growth
  717:             IF( DMAX .GT. MAXGROWTH*SPDIAM ) THEN
  718:                NOREP = .TRUE.
  719:             ELSE
  720:                NOREP = .FALSE.
  721:             ENDIF
  722:             IF( USEDQD .AND. .NOT.NOREP ) THEN
  723: *              Ensure the definiteness of the representation
  724: *              All entries of D (of L D L^T) must have the same sign
  725:                DO 71 I = 1, IN
  726:                   TMP = SGNDEF*WORK( I )
  727:                   IF( TMP.LT.ZERO ) NOREP = .TRUE.
  728:  71            CONTINUE
  729:             ENDIF
  730:             IF(NOREP) THEN
  731: *              Note that in the case of IRANGE=ALLRNG, we use the Gerschgorin
  732: *              shift which makes the matrix definite. So we should end up
  733: *              here really only in the case of IRANGE = VALRNG or INDRNG.
  734:                IF( IDUM.EQ.MAXTRY-1 ) THEN
  735:                   IF( SGNDEF.EQ.ONE ) THEN
  736: *                    The fudged Gerschgorin shift should succeed
  737:                      SIGMA =
  738:      $                    GL - FUDGE*SPDIAM*EPS*N - FUDGE*TWO*PIVMIN
  739:                   ELSE
  740:                      SIGMA =
  741:      $                    GU + FUDGE*SPDIAM*EPS*N + FUDGE*TWO*PIVMIN
  742:                   END IF
  743:                ELSE
  744:                   SIGMA = SIGMA - SGNDEF * TAU
  745:                   TAU = TWO * TAU
  746:                END IF
  747:             ELSE
  748: *              an initial RRR is found
  749:                GO TO 83
  750:             END IF
  751:  80      CONTINUE
  752: *        if the program reaches this point, no base representation could be
  753: *        found in MAXTRY iterations.
  754:          INFO = 2
  755:          RETURN
  756: 
  757:  83      CONTINUE
  758: *        At this point, we have found an initial base representation
  759: *        T - SIGMA I = L D L^T with not too much element growth.
  760: *        Store the shift.
  761:          E( IEND ) = SIGMA
  762: *        Store D and L.
  763:          CALL DCOPY( IN, WORK, 1, D( IBEGIN ), 1 )
  764:          CALL DCOPY( IN-1, WORK( IN+1 ), 1, E( IBEGIN ), 1 )
  765: 
  766: 
  767:          IF(MB.GT.1 ) THEN
  768: *
  769: *           Perturb each entry of the base representation by a small
  770: *           (but random) relative amount to overcome difficulties with
  771: *           glued matrices.
  772: *
  773:             DO 122 I = 1, 4
  774:                ISEED( I ) = 1
  775:  122        CONTINUE
  776: 
  777:             CALL DLARNV(2, ISEED, 2*IN-1, WORK(1))
  778:             DO 125 I = 1,IN-1
  779:                D(IBEGIN+I-1) = D(IBEGIN+I-1)*(ONE+EPS*PERT*WORK(I))
  780:                E(IBEGIN+I-1) = E(IBEGIN+I-1)*(ONE+EPS*PERT*WORK(IN+I))
  781:  125        CONTINUE
  782:             D(IEND) = D(IEND)*(ONE+EPS*FOUR*WORK(IN))
  783: *
  784:          ENDIF
  785: *
  786: *        Don't update the Gerschgorin intervals because keeping track
  787: *        of the updates would be too much work in DLARRV.
  788: *        We update W instead and use it to locate the proper Gerschgorin
  789: *        intervals.
  790: 
  791: *        Compute the required eigenvalues of L D L' by bisection or dqds
  792:          IF ( .NOT.USEDQD ) THEN
  793: *           If DLARRD has been used, shift the eigenvalue approximations
  794: *           according to their representation. This is necessary for
  795: *           a uniform DLARRV since dqds computes eigenvalues of the
  796: *           shifted representation. In DLARRV, W will always hold the
  797: *           UNshifted eigenvalue approximation.
  798:             DO 134 J=WBEGIN,WEND
  799:                W(J) = W(J) - SIGMA
  800:                WERR(J) = WERR(J) + ABS(W(J)) * EPS
  801:  134        CONTINUE
  802: *           call DLARRB to reduce eigenvalue error of the approximations
  803: *           from DLARRD
  804:             DO 135 I = IBEGIN, IEND-1
  805:                WORK( I ) = D( I ) * E( I )**2
  806:  135        CONTINUE
  807: *           use bisection to find EV from INDL to INDU
  808:             CALL DLARRB(IN, D(IBEGIN), WORK(IBEGIN),
  809:      $                  INDL, INDU, RTOL1, RTOL2, INDL-1,
  810:      $                  W(WBEGIN), WGAP(WBEGIN), WERR(WBEGIN),
  811:      $                  WORK( 2*N+1 ), IWORK, PIVMIN, SPDIAM,
  812:      $                  IN, IINFO )
  813:             IF( IINFO .NE. 0 ) THEN
  814:                INFO = -4
  815:                RETURN
  816:             END IF
  817: *           DLARRB computes all gaps correctly except for the last one
  818: *           Record distance to VU/GU
  819:             WGAP( WEND ) = MAX( ZERO,
  820:      $           ( VU-SIGMA ) - ( W( WEND ) + WERR( WEND ) ) )
  821:             DO 138 I = INDL, INDU
  822:                M = M + 1
  823:                IBLOCK(M) = JBLK
  824:                INDEXW(M) = I
  825:  138        CONTINUE
  826:          ELSE
  827: *           Call dqds to get all eigs (and then possibly delete unwanted
  828: *           eigenvalues).
  829: *           Note that dqds finds the eigenvalues of the L D L^T representation
  830: *           of T to high relative accuracy. High relative accuracy
  831: *           might be lost when the shift of the RRR is subtracted to obtain
  832: *           the eigenvalues of T. However, T is not guaranteed to define its
  833: *           eigenvalues to high relative accuracy anyway.
  834: *           Set RTOL to the order of the tolerance used in DLASQ2
  835: *           This is an ESTIMATED error, the worst case bound is 4*N*EPS
  836: *           which is usually too large and requires unnecessary work to be
  837: *           done by bisection when computing the eigenvectors
  838:             RTOL = LOG(DBLE(IN)) * FOUR * EPS
  839:             J = IBEGIN
  840:             DO 140 I = 1, IN - 1
  841:                WORK( 2*I-1 ) = ABS( D( J ) )
  842:                WORK( 2*I ) = E( J )*E( J )*WORK( 2*I-1 )
  843:                J = J + 1
  844:   140       CONTINUE
  845:             WORK( 2*IN-1 ) = ABS( D( IEND ) )
  846:             WORK( 2*IN ) = ZERO
  847:             CALL DLASQ2( IN, WORK, IINFO )
  848:             IF( IINFO .NE. 0 ) THEN
  849: *              If IINFO = -5 then an index is part of a tight cluster
  850: *              and should be changed. The index is in IWORK(1) and the
  851: *              gap is in WORK(N+1)
  852:                INFO = -5
  853:                RETURN
  854:             ELSE
  855: *              Test that all eigenvalues are positive as expected
  856:                DO 149 I = 1, IN
  857:                   IF( WORK( I ).LT.ZERO ) THEN
  858:                      INFO = -6
  859:                      RETURN
  860:                   ENDIF
  861:  149           CONTINUE
  862:             END IF
  863:             IF( SGNDEF.GT.ZERO ) THEN
  864:                DO 150 I = INDL, INDU
  865:                   M = M + 1
  866:                   W( M ) = WORK( IN-I+1 )
  867:                   IBLOCK( M ) = JBLK
  868:                   INDEXW( M ) = I
  869:  150           CONTINUE
  870:             ELSE
  871:                DO 160 I = INDL, INDU
  872:                   M = M + 1
  873:                   W( M ) = -WORK( I )
  874:                   IBLOCK( M ) = JBLK
  875:                   INDEXW( M ) = I
  876:  160           CONTINUE
  877:             END IF
  878: 
  879:             DO 165 I = M - MB + 1, M
  880: *              the value of RTOL below should be the tolerance in DLASQ2
  881:                WERR( I ) = RTOL * ABS( W(I) )
  882:  165        CONTINUE
  883:             DO 166 I = M - MB + 1, M - 1
  884: *              compute the right gap between the intervals
  885:                WGAP( I ) = MAX( ZERO,
  886:      $                          W(I+1)-WERR(I+1) - (W(I)+WERR(I)) )
  887:  166        CONTINUE
  888:             WGAP( M ) = MAX( ZERO,
  889:      $           ( VU-SIGMA ) - ( W( M ) + WERR( M ) ) )
  890:          END IF
  891: *        proceed with next block
  892:          IBEGIN = IEND + 1
  893:          WBEGIN = WEND + 1
  894:  170  CONTINUE
  895: *
  896: 
  897:       RETURN
  898: *
  899: *     End of DLARRE
  900: *
  901:       END

CVSweb interface <joel.bertrand@systella.fr>