File:  [local] / rpl / lapack / lapack / dlarre.f
Revision 1.23: download - view: text, annotated - select for diffs - revision graph
Thu May 21 21:46:00 2020 UTC (4 years ago) by bertrand
Branches: MAIN
CVS tags: rpl-4_1_33, rpl-4_1_32, HEAD
Mise à jour de Lapack.

    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: *> \date June 2016
  280: *
  281: *> \ingroup OTHERauxiliary
  282: *
  283: *> \par Further Details:
  284: *  =====================
  285: *>
  286: *> \verbatim
  287: *>
  288: *>  The base representations are required to suffer very little
  289: *>  element growth and consequently define all their eigenvalues to
  290: *>  high relative accuracy.
  291: *> \endverbatim
  292: *
  293: *> \par Contributors:
  294: *  ==================
  295: *>
  296: *>     Beresford Parlett, University of California, Berkeley, USA \n
  297: *>     Jim Demmel, University of California, Berkeley, USA \n
  298: *>     Inderjit Dhillon, University of Texas, Austin, USA \n
  299: *>     Osni Marques, LBNL/NERSC, USA \n
  300: *>     Christof Voemel, University of California, Berkeley, USA \n
  301: *>
  302: *  =====================================================================
  303:       SUBROUTINE DLARRE( RANGE, N, VL, VU, IL, IU, D, E, E2,
  304:      $                    RTOL1, RTOL2, SPLTOL, NSPLIT, ISPLIT, M,
  305:      $                    W, WERR, WGAP, IBLOCK, INDEXW, GERS, PIVMIN,
  306:      $                    WORK, IWORK, INFO )
  307: *
  308: *  -- LAPACK auxiliary routine (version 3.8.0) --
  309: *  -- LAPACK is a software package provided by Univ. of Tennessee,    --
  310: *  -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--
  311: *     June 2016
  312: *
  313: *     .. Scalar Arguments ..
  314:       CHARACTER          RANGE
  315:       INTEGER            IL, INFO, IU, M, N, NSPLIT
  316:       DOUBLE PRECISION  PIVMIN, RTOL1, RTOL2, SPLTOL, VL, VU
  317: *     ..
  318: *     .. Array Arguments ..
  319:       INTEGER            IBLOCK( * ), ISPLIT( * ), IWORK( * ),
  320:      $                   INDEXW( * )
  321:       DOUBLE PRECISION   D( * ), E( * ), E2( * ), GERS( * ),
  322:      $                   W( * ),WERR( * ), WGAP( * ), WORK( * )
  323: *     ..
  324: *
  325: *  =====================================================================
  326: *
  327: *     .. Parameters ..
  328:       DOUBLE PRECISION   FAC, FOUR, FOURTH, FUDGE, HALF, HNDRD,
  329:      $                   MAXGROWTH, ONE, PERT, TWO, ZERO
  330:       PARAMETER          ( ZERO = 0.0D0, ONE = 1.0D0,
  331:      $                     TWO = 2.0D0, FOUR=4.0D0,
  332:      $                     HNDRD = 100.0D0,
  333:      $                     PERT = 8.0D0,
  334:      $                     HALF = ONE/TWO, FOURTH = ONE/FOUR, FAC= HALF,
  335:      $                     MAXGROWTH = 64.0D0, FUDGE = 2.0D0 )
  336:       INTEGER            MAXTRY, ALLRNG, INDRNG, VALRNG
  337:       PARAMETER          ( MAXTRY = 6, ALLRNG = 1, INDRNG = 2,
  338:      $                     VALRNG = 3 )
  339: *     ..
  340: *     .. Local Scalars ..
  341:       LOGICAL            FORCEB, NOREP, USEDQD
  342:       INTEGER            CNT, CNT1, CNT2, I, IBEGIN, IDUM, IEND, IINFO,
  343:      $                   IN, INDL, INDU, IRANGE, J, JBLK, MB, MM,
  344:      $                   WBEGIN, WEND
  345:       DOUBLE PRECISION   AVGAP, BSRTOL, CLWDTH, DMAX, DPIVOT, EABS,
  346:      $                   EMAX, EOLD, EPS, GL, GU, ISLEFT, ISRGHT, RTL,
  347:      $                   RTOL, S1, S2, SAFMIN, SGNDEF, SIGMA, SPDIAM,
  348:      $                   TAU, TMP, TMP1
  349: 
  350: 
  351: *     ..
  352: *     .. Local Arrays ..
  353:       INTEGER            ISEED( 4 )
  354: *     ..
  355: *     .. External Functions ..
  356:       LOGICAL            LSAME
  357:       DOUBLE PRECISION            DLAMCH
  358:       EXTERNAL           DLAMCH, LSAME
  359: 
  360: *     ..
  361: *     .. External Subroutines ..
  362:       EXTERNAL           DCOPY, DLARNV, DLARRA, DLARRB, DLARRC, DLARRD,
  363:      $                   DLASQ2, DLARRK
  364: *     ..
  365: *     .. Intrinsic Functions ..
  366:       INTRINSIC          ABS, MAX, MIN
  367: 
  368: *     ..
  369: *     .. Executable Statements ..
  370: *
  371: 
  372:       INFO = 0
  373: *
  374: *     Quick return if possible
  375: *
  376:       IF( N.LE.0 ) THEN
  377:          RETURN
  378:       END IF
  379: *
  380: *     Decode RANGE
  381: *
  382:       IF( LSAME( RANGE, 'A' ) ) THEN
  383:          IRANGE = ALLRNG
  384:       ELSE IF( LSAME( RANGE, 'V' ) ) THEN
  385:          IRANGE = VALRNG
  386:       ELSE IF( LSAME( RANGE, 'I' ) ) THEN
  387:          IRANGE = INDRNG
  388:       END IF
  389: 
  390:       M = 0
  391: 
  392: *     Get machine constants
  393:       SAFMIN = DLAMCH( 'S' )
  394:       EPS = DLAMCH( 'P' )
  395: 
  396: *     Set parameters
  397:       RTL = SQRT(EPS)
  398:       BSRTOL = SQRT(EPS)
  399: 
  400: *     Treat case of 1x1 matrix for quick return
  401:       IF( N.EQ.1 ) THEN
  402:          IF( (IRANGE.EQ.ALLRNG).OR.
  403:      $       ((IRANGE.EQ.VALRNG).AND.(D(1).GT.VL).AND.(D(1).LE.VU)).OR.
  404:      $       ((IRANGE.EQ.INDRNG).AND.(IL.EQ.1).AND.(IU.EQ.1)) ) THEN
  405:             M = 1
  406:             W(1) = D(1)
  407: *           The computation error of the eigenvalue is zero
  408:             WERR(1) = ZERO
  409:             WGAP(1) = ZERO
  410:             IBLOCK( 1 ) = 1
  411:             INDEXW( 1 ) = 1
  412:             GERS(1) = D( 1 )
  413:             GERS(2) = D( 1 )
  414:          ENDIF
  415: *        store the shift for the initial RRR, which is zero in this case
  416:          E(1) = ZERO
  417:          RETURN
  418:       END IF
  419: 
  420: *     General case: tridiagonal matrix of order > 1
  421: *
  422: *     Init WERR, WGAP. Compute Gerschgorin intervals and spectral diameter.
  423: *     Compute maximum off-diagonal entry and pivmin.
  424:       GL = D(1)
  425:       GU = D(1)
  426:       EOLD = ZERO
  427:       EMAX = ZERO
  428:       E(N) = ZERO
  429:       DO 5 I = 1,N
  430:          WERR(I) = ZERO
  431:          WGAP(I) = ZERO
  432:          EABS = ABS( E(I) )
  433:          IF( EABS .GE. EMAX ) THEN
  434:             EMAX = EABS
  435:          END IF
  436:          TMP1 = EABS + EOLD
  437:          GERS( 2*I-1) = D(I) - TMP1
  438:          GL =  MIN( GL, GERS( 2*I - 1))
  439:          GERS( 2*I ) = D(I) + TMP1
  440:          GU = MAX( GU, GERS(2*I) )
  441:          EOLD  = EABS
  442:  5    CONTINUE
  443: *     The minimum pivot allowed in the Sturm sequence for T
  444:       PIVMIN = SAFMIN * MAX( ONE, EMAX**2 )
  445: *     Compute spectral diameter. The Gerschgorin bounds give an
  446: *     estimate that is wrong by at most a factor of SQRT(2)
  447:       SPDIAM = GU - GL
  448: 
  449: *     Compute splitting points
  450:       CALL DLARRA( N, D, E, E2, SPLTOL, SPDIAM,
  451:      $                    NSPLIT, ISPLIT, IINFO )
  452: 
  453: *     Can force use of bisection instead of faster DQDS.
  454: *     Option left in the code for future multisection work.
  455:       FORCEB = .FALSE.
  456: 
  457: *     Initialize USEDQD, DQDS should be used for ALLRNG unless someone
  458: *     explicitly wants bisection.
  459:       USEDQD = (( IRANGE.EQ.ALLRNG ) .AND. (.NOT.FORCEB))
  460: 
  461:       IF( (IRANGE.EQ.ALLRNG) .AND. (.NOT. FORCEB) ) THEN
  462: *        Set interval [VL,VU] that contains all eigenvalues
  463:          VL = GL
  464:          VU = GU
  465:       ELSE
  466: *        We call DLARRD to find crude approximations to the eigenvalues
  467: *        in the desired range. In case IRANGE = INDRNG, we also obtain the
  468: *        interval (VL,VU] that contains all the wanted eigenvalues.
  469: *        An interval [LEFT,RIGHT] has converged if
  470: *        RIGHT-LEFT.LT.RTOL*MAX(ABS(LEFT),ABS(RIGHT))
  471: *        DLARRD needs a WORK of size 4*N, IWORK of size 3*N
  472:          CALL DLARRD( RANGE, 'B', N, VL, VU, IL, IU, GERS,
  473:      $                    BSRTOL, D, E, E2, PIVMIN, NSPLIT, ISPLIT,
  474:      $                    MM, W, WERR, VL, VU, IBLOCK, INDEXW,
  475:      $                    WORK, IWORK, IINFO )
  476:          IF( IINFO.NE.0 ) THEN
  477:             INFO = -1
  478:             RETURN
  479:          ENDIF
  480: *        Make sure that the entries M+1 to N in W, WERR, IBLOCK, INDEXW are 0
  481:          DO 14 I = MM+1,N
  482:             W( I ) = ZERO
  483:             WERR( I ) = ZERO
  484:             IBLOCK( I ) = 0
  485:             INDEXW( I ) = 0
  486:  14      CONTINUE
  487:       END IF
  488: 
  489: 
  490: ***
  491: *     Loop over unreduced blocks
  492:       IBEGIN = 1
  493:       WBEGIN = 1
  494:       DO 170 JBLK = 1, NSPLIT
  495:          IEND = ISPLIT( JBLK )
  496:          IN = IEND - IBEGIN + 1
  497: 
  498: *        1 X 1 block
  499:          IF( IN.EQ.1 ) THEN
  500:             IF( (IRANGE.EQ.ALLRNG).OR.( (IRANGE.EQ.VALRNG).AND.
  501:      $         ( D( IBEGIN ).GT.VL ).AND.( D( IBEGIN ).LE.VU ) )
  502:      $        .OR. ( (IRANGE.EQ.INDRNG).AND.(IBLOCK(WBEGIN).EQ.JBLK))
  503:      $        ) THEN
  504:                M = M + 1
  505:                W( M ) = D( IBEGIN )
  506:                WERR(M) = ZERO
  507: *              The gap for a single block doesn't matter for the later
  508: *              algorithm and is assigned an arbitrary large value
  509:                WGAP(M) = ZERO
  510:                IBLOCK( M ) = JBLK
  511:                INDEXW( M ) = 1
  512:                WBEGIN = WBEGIN + 1
  513:             ENDIF
  514: *           E( IEND ) holds the shift for the initial RRR
  515:             E( IEND ) = ZERO
  516:             IBEGIN = IEND + 1
  517:             GO TO 170
  518:          END IF
  519: *
  520: *        Blocks of size larger than 1x1
  521: *
  522: *        E( IEND ) will hold the shift for the initial RRR, for now set it =0
  523:          E( IEND ) = ZERO
  524: *
  525: *        Find local outer bounds GL,GU for the block
  526:          GL = D(IBEGIN)
  527:          GU = D(IBEGIN)
  528:          DO 15 I = IBEGIN , IEND
  529:             GL = MIN( GERS( 2*I-1 ), GL )
  530:             GU = MAX( GERS( 2*I ), GU )
  531:  15      CONTINUE
  532:          SPDIAM = GU - GL
  533: 
  534:          IF(.NOT. ((IRANGE.EQ.ALLRNG).AND.(.NOT.FORCEB)) ) THEN
  535: *           Count the number of eigenvalues in the current block.
  536:             MB = 0
  537:             DO 20 I = WBEGIN,MM
  538:                IF( IBLOCK(I).EQ.JBLK ) THEN
  539:                   MB = MB+1
  540:                ELSE
  541:                   GOTO 21
  542:                ENDIF
  543:  20         CONTINUE
  544:  21         CONTINUE
  545: 
  546:             IF( MB.EQ.0) THEN
  547: *              No eigenvalue in the current block lies in the desired range
  548: *              E( IEND ) holds the shift for the initial RRR
  549:                E( IEND ) = ZERO
  550:                IBEGIN = IEND + 1
  551:                GO TO 170
  552:             ELSE
  553: 
  554: *              Decide whether dqds or bisection is more efficient
  555:                USEDQD = ( (MB .GT. FAC*IN) .AND. (.NOT.FORCEB) )
  556:                WEND = WBEGIN + MB - 1
  557: *              Calculate gaps for the current block
  558: *              In later stages, when representations for individual
  559: *              eigenvalues are different, we use SIGMA = E( IEND ).
  560:                SIGMA = ZERO
  561:                DO 30 I = WBEGIN, WEND - 1
  562:                   WGAP( I ) = MAX( ZERO,
  563:      $                        W(I+1)-WERR(I+1) - (W(I)+WERR(I)) )
  564:  30            CONTINUE
  565:                WGAP( WEND ) = MAX( ZERO,
  566:      $                     VU - SIGMA - (W( WEND )+WERR( WEND )))
  567: *              Find local index of the first and last desired evalue.
  568:                INDL = INDEXW(WBEGIN)
  569:                INDU = INDEXW( WEND )
  570:             ENDIF
  571:          ENDIF
  572:          IF(( (IRANGE.EQ.ALLRNG) .AND. (.NOT. FORCEB) ).OR.USEDQD) THEN
  573: *           Case of DQDS
  574: *           Find approximations to the extremal eigenvalues of the block
  575:             CALL DLARRK( IN, 1, GL, GU, D(IBEGIN),
  576:      $               E2(IBEGIN), PIVMIN, RTL, TMP, TMP1, IINFO )
  577:             IF( IINFO.NE.0 ) THEN
  578:                INFO = -1
  579:                RETURN
  580:             ENDIF
  581:             ISLEFT = MAX(GL, TMP - TMP1
  582:      $               - HNDRD * EPS* ABS(TMP - TMP1))
  583: 
  584:             CALL DLARRK( IN, IN, GL, GU, D(IBEGIN),
  585:      $               E2(IBEGIN), PIVMIN, RTL, TMP, TMP1, IINFO )
  586:             IF( IINFO.NE.0 ) THEN
  587:                INFO = -1
  588:                RETURN
  589:             ENDIF
  590:             ISRGHT = MIN(GU, TMP + TMP1
  591:      $                 + HNDRD * EPS * ABS(TMP + TMP1))
  592: *           Improve the estimate of the spectral diameter
  593:             SPDIAM = ISRGHT - ISLEFT
  594:          ELSE
  595: *           Case of bisection
  596: *           Find approximations to the wanted extremal eigenvalues
  597:             ISLEFT = MAX(GL, W(WBEGIN) - WERR(WBEGIN)
  598:      $                  - HNDRD * EPS*ABS(W(WBEGIN)- WERR(WBEGIN) ))
  599:             ISRGHT = MIN(GU,W(WEND) + WERR(WEND)
  600:      $                  + HNDRD * EPS * ABS(W(WEND)+ WERR(WEND)))
  601:          ENDIF
  602: 
  603: 
  604: *        Decide whether the base representation for the current block
  605: *        L_JBLK D_JBLK L_JBLK^T = T_JBLK - sigma_JBLK I
  606: *        should be on the left or the right end of the current block.
  607: *        The strategy is to shift to the end which is "more populated"
  608: *        Furthermore, decide whether to use DQDS for the computation of
  609: *        the eigenvalue approximations at the end of DLARRE or bisection.
  610: *        dqds is chosen if all eigenvalues are desired or the number of
  611: *        eigenvalues to be computed is large compared to the blocksize.
  612:          IF( ( IRANGE.EQ.ALLRNG ) .AND. (.NOT.FORCEB) ) THEN
  613: *           If all the eigenvalues have to be computed, we use dqd
  614:             USEDQD = .TRUE.
  615: *           INDL is the local index of the first eigenvalue to compute
  616:             INDL = 1
  617:             INDU = IN
  618: *           MB =  number of eigenvalues to compute
  619:             MB = IN
  620:             WEND = WBEGIN + MB - 1
  621: *           Define 1/4 and 3/4 points of the spectrum
  622:             S1 = ISLEFT + FOURTH * SPDIAM
  623:             S2 = ISRGHT - FOURTH * SPDIAM
  624:          ELSE
  625: *           DLARRD has computed IBLOCK and INDEXW for each eigenvalue
  626: *           approximation.
  627: *           choose sigma
  628:             IF( USEDQD ) THEN
  629:                S1 = ISLEFT + FOURTH * SPDIAM
  630:                S2 = ISRGHT - FOURTH * SPDIAM
  631:             ELSE
  632:                TMP = MIN(ISRGHT,VU) -  MAX(ISLEFT,VL)
  633:                S1 =  MAX(ISLEFT,VL) + FOURTH * TMP
  634:                S2 =  MIN(ISRGHT,VU) - FOURTH * TMP
  635:             ENDIF
  636:          ENDIF
  637: 
  638: *        Compute the negcount at the 1/4 and 3/4 points
  639:          IF(MB.GT.1) THEN
  640:             CALL DLARRC( 'T', IN, S1, S2, D(IBEGIN),
  641:      $                    E(IBEGIN), PIVMIN, CNT, CNT1, CNT2, IINFO)
  642:          ENDIF
  643: 
  644:          IF(MB.EQ.1) THEN
  645:             SIGMA = GL
  646:             SGNDEF = ONE
  647:          ELSEIF( CNT1 - INDL .GE. INDU - CNT2 ) THEN
  648:             IF( ( IRANGE.EQ.ALLRNG ) .AND. (.NOT.FORCEB) ) THEN
  649:                SIGMA = MAX(ISLEFT,GL)
  650:             ELSEIF( USEDQD ) THEN
  651: *              use Gerschgorin bound as shift to get pos def matrix
  652: *              for dqds
  653:                SIGMA = ISLEFT
  654:             ELSE
  655: *              use approximation of the first desired eigenvalue of the
  656: *              block as shift
  657:                SIGMA = MAX(ISLEFT,VL)
  658:             ENDIF
  659:             SGNDEF = ONE
  660:          ELSE
  661:             IF( ( IRANGE.EQ.ALLRNG ) .AND. (.NOT.FORCEB) ) THEN
  662:                SIGMA = MIN(ISRGHT,GU)
  663:             ELSEIF( USEDQD ) THEN
  664: *              use Gerschgorin bound as shift to get neg def matrix
  665: *              for dqds
  666:                SIGMA = ISRGHT
  667:             ELSE
  668: *              use approximation of the first desired eigenvalue of the
  669: *              block as shift
  670:                SIGMA = MIN(ISRGHT,VU)
  671:             ENDIF
  672:             SGNDEF = -ONE
  673:          ENDIF
  674: 
  675: 
  676: *        An initial SIGMA has been chosen that will be used for computing
  677: *        T - SIGMA I = L D L^T
  678: *        Define the increment TAU of the shift in case the initial shift
  679: *        needs to be refined to obtain a factorization with not too much
  680: *        element growth.
  681:          IF( USEDQD ) THEN
  682: *           The initial SIGMA was to the outer end of the spectrum
  683: *           the matrix is definite and we need not retreat.
  684:             TAU = SPDIAM*EPS*N + TWO*PIVMIN
  685:             TAU = MAX( TAU,TWO*EPS*ABS(SIGMA) )
  686:          ELSE
  687:             IF(MB.GT.1) THEN
  688:                CLWDTH = W(WEND) + WERR(WEND) - W(WBEGIN) - WERR(WBEGIN)
  689:                AVGAP = ABS(CLWDTH / DBLE(WEND-WBEGIN))
  690:                IF( SGNDEF.EQ.ONE ) THEN
  691:                   TAU = HALF*MAX(WGAP(WBEGIN),AVGAP)
  692:                   TAU = MAX(TAU,WERR(WBEGIN))
  693:                ELSE
  694:                   TAU = HALF*MAX(WGAP(WEND-1),AVGAP)
  695:                   TAU = MAX(TAU,WERR(WEND))
  696:                ENDIF
  697:             ELSE
  698:                TAU = WERR(WBEGIN)
  699:             ENDIF
  700:          ENDIF
  701: *
  702:          DO 80 IDUM = 1, MAXTRY
  703: *           Compute L D L^T factorization of tridiagonal matrix T - sigma I.
  704: *           Store D in WORK(1:IN), L in WORK(IN+1:2*IN), and reciprocals of
  705: *           pivots in WORK(2*IN+1:3*IN)
  706:             DPIVOT = D( IBEGIN ) - SIGMA
  707:             WORK( 1 ) = DPIVOT
  708:             DMAX = ABS( WORK(1) )
  709:             J = IBEGIN
  710:             DO 70 I = 1, IN - 1
  711:                WORK( 2*IN+I ) = ONE / WORK( I )
  712:                TMP = E( J )*WORK( 2*IN+I )
  713:                WORK( IN+I ) = TMP
  714:                DPIVOT = ( D( J+1 )-SIGMA ) - TMP*E( J )
  715:                WORK( I+1 ) = DPIVOT
  716:                DMAX = MAX( DMAX, ABS(DPIVOT) )
  717:                J = J + 1
  718:  70         CONTINUE
  719: *           check for element growth
  720:             IF( DMAX .GT. MAXGROWTH*SPDIAM ) THEN
  721:                NOREP = .TRUE.
  722:             ELSE
  723:                NOREP = .FALSE.
  724:             ENDIF
  725:             IF( USEDQD .AND. .NOT.NOREP ) THEN
  726: *              Ensure the definiteness of the representation
  727: *              All entries of D (of L D L^T) must have the same sign
  728:                DO 71 I = 1, IN
  729:                   TMP = SGNDEF*WORK( I )
  730:                   IF( TMP.LT.ZERO ) NOREP = .TRUE.
  731:  71            CONTINUE
  732:             ENDIF
  733:             IF(NOREP) THEN
  734: *              Note that in the case of IRANGE=ALLRNG, we use the Gerschgorin
  735: *              shift which makes the matrix definite. So we should end up
  736: *              here really only in the case of IRANGE = VALRNG or INDRNG.
  737:                IF( IDUM.EQ.MAXTRY-1 ) THEN
  738:                   IF( SGNDEF.EQ.ONE ) THEN
  739: *                    The fudged Gerschgorin shift should succeed
  740:                      SIGMA =
  741:      $                    GL - FUDGE*SPDIAM*EPS*N - FUDGE*TWO*PIVMIN
  742:                   ELSE
  743:                      SIGMA =
  744:      $                    GU + FUDGE*SPDIAM*EPS*N + FUDGE*TWO*PIVMIN
  745:                   END IF
  746:                ELSE
  747:                   SIGMA = SIGMA - SGNDEF * TAU
  748:                   TAU = TWO * TAU
  749:                END IF
  750:             ELSE
  751: *              an initial RRR is found
  752:                GO TO 83
  753:             END IF
  754:  80      CONTINUE
  755: *        if the program reaches this point, no base representation could be
  756: *        found in MAXTRY iterations.
  757:          INFO = 2
  758:          RETURN
  759: 
  760:  83      CONTINUE
  761: *        At this point, we have found an initial base representation
  762: *        T - SIGMA I = L D L^T with not too much element growth.
  763: *        Store the shift.
  764:          E( IEND ) = SIGMA
  765: *        Store D and L.
  766:          CALL DCOPY( IN, WORK, 1, D( IBEGIN ), 1 )
  767:          CALL DCOPY( IN-1, WORK( IN+1 ), 1, E( IBEGIN ), 1 )
  768: 
  769: 
  770:          IF(MB.GT.1 ) THEN
  771: *
  772: *           Perturb each entry of the base representation by a small
  773: *           (but random) relative amount to overcome difficulties with
  774: *           glued matrices.
  775: *
  776:             DO 122 I = 1, 4
  777:                ISEED( I ) = 1
  778:  122        CONTINUE
  779: 
  780:             CALL DLARNV(2, ISEED, 2*IN-1, WORK(1))
  781:             DO 125 I = 1,IN-1
  782:                D(IBEGIN+I-1) = D(IBEGIN+I-1)*(ONE+EPS*PERT*WORK(I))
  783:                E(IBEGIN+I-1) = E(IBEGIN+I-1)*(ONE+EPS*PERT*WORK(IN+I))
  784:  125        CONTINUE
  785:             D(IEND) = D(IEND)*(ONE+EPS*FOUR*WORK(IN))
  786: *
  787:          ENDIF
  788: *
  789: *        Don't update the Gerschgorin intervals because keeping track
  790: *        of the updates would be too much work in DLARRV.
  791: *        We update W instead and use it to locate the proper Gerschgorin
  792: *        intervals.
  793: 
  794: *        Compute the required eigenvalues of L D L' by bisection or dqds
  795:          IF ( .NOT.USEDQD ) THEN
  796: *           If DLARRD has been used, shift the eigenvalue approximations
  797: *           according to their representation. This is necessary for
  798: *           a uniform DLARRV since dqds computes eigenvalues of the
  799: *           shifted representation. In DLARRV, W will always hold the
  800: *           UNshifted eigenvalue approximation.
  801:             DO 134 J=WBEGIN,WEND
  802:                W(J) = W(J) - SIGMA
  803:                WERR(J) = WERR(J) + ABS(W(J)) * EPS
  804:  134        CONTINUE
  805: *           call DLARRB to reduce eigenvalue error of the approximations
  806: *           from DLARRD
  807:             DO 135 I = IBEGIN, IEND-1
  808:                WORK( I ) = D( I ) * E( I )**2
  809:  135        CONTINUE
  810: *           use bisection to find EV from INDL to INDU
  811:             CALL DLARRB(IN, D(IBEGIN), WORK(IBEGIN),
  812:      $                  INDL, INDU, RTOL1, RTOL2, INDL-1,
  813:      $                  W(WBEGIN), WGAP(WBEGIN), WERR(WBEGIN),
  814:      $                  WORK( 2*N+1 ), IWORK, PIVMIN, SPDIAM,
  815:      $                  IN, IINFO )
  816:             IF( IINFO .NE. 0 ) THEN
  817:                INFO = -4
  818:                RETURN
  819:             END IF
  820: *           DLARRB computes all gaps correctly except for the last one
  821: *           Record distance to VU/GU
  822:             WGAP( WEND ) = MAX( ZERO,
  823:      $           ( VU-SIGMA ) - ( W( WEND ) + WERR( WEND ) ) )
  824:             DO 138 I = INDL, INDU
  825:                M = M + 1
  826:                IBLOCK(M) = JBLK
  827:                INDEXW(M) = I
  828:  138        CONTINUE
  829:          ELSE
  830: *           Call dqds to get all eigs (and then possibly delete unwanted
  831: *           eigenvalues).
  832: *           Note that dqds finds the eigenvalues of the L D L^T representation
  833: *           of T to high relative accuracy. High relative accuracy
  834: *           might be lost when the shift of the RRR is subtracted to obtain
  835: *           the eigenvalues of T. However, T is not guaranteed to define its
  836: *           eigenvalues to high relative accuracy anyway.
  837: *           Set RTOL to the order of the tolerance used in DLASQ2
  838: *           This is an ESTIMATED error, the worst case bound is 4*N*EPS
  839: *           which is usually too large and requires unnecessary work to be
  840: *           done by bisection when computing the eigenvectors
  841:             RTOL = LOG(DBLE(IN)) * FOUR * EPS
  842:             J = IBEGIN
  843:             DO 140 I = 1, IN - 1
  844:                WORK( 2*I-1 ) = ABS( D( J ) )
  845:                WORK( 2*I ) = E( J )*E( J )*WORK( 2*I-1 )
  846:                J = J + 1
  847:   140       CONTINUE
  848:             WORK( 2*IN-1 ) = ABS( D( IEND ) )
  849:             WORK( 2*IN ) = ZERO
  850:             CALL DLASQ2( IN, WORK, IINFO )
  851:             IF( IINFO .NE. 0 ) THEN
  852: *              If IINFO = -5 then an index is part of a tight cluster
  853: *              and should be changed. The index is in IWORK(1) and the
  854: *              gap is in WORK(N+1)
  855:                INFO = -5
  856:                RETURN
  857:             ELSE
  858: *              Test that all eigenvalues are positive as expected
  859:                DO 149 I = 1, IN
  860:                   IF( WORK( I ).LT.ZERO ) THEN
  861:                      INFO = -6
  862:                      RETURN
  863:                   ENDIF
  864:  149           CONTINUE
  865:             END IF
  866:             IF( SGNDEF.GT.ZERO ) THEN
  867:                DO 150 I = INDL, INDU
  868:                   M = M + 1
  869:                   W( M ) = WORK( IN-I+1 )
  870:                   IBLOCK( M ) = JBLK
  871:                   INDEXW( M ) = I
  872:  150           CONTINUE
  873:             ELSE
  874:                DO 160 I = INDL, INDU
  875:                   M = M + 1
  876:                   W( M ) = -WORK( I )
  877:                   IBLOCK( M ) = JBLK
  878:                   INDEXW( M ) = I
  879:  160           CONTINUE
  880:             END IF
  881: 
  882:             DO 165 I = M - MB + 1, M
  883: *              the value of RTOL below should be the tolerance in DLASQ2
  884:                WERR( I ) = RTOL * ABS( W(I) )
  885:  165        CONTINUE
  886:             DO 166 I = M - MB + 1, M - 1
  887: *              compute the right gap between the intervals
  888:                WGAP( I ) = MAX( ZERO,
  889:      $                          W(I+1)-WERR(I+1) - (W(I)+WERR(I)) )
  890:  166        CONTINUE
  891:             WGAP( M ) = MAX( ZERO,
  892:      $           ( VU-SIGMA ) - ( W( M ) + WERR( M ) ) )
  893:          END IF
  894: *        proceed with next block
  895:          IBEGIN = IEND + 1
  896:          WBEGIN = WEND + 1
  897:  170  CONTINUE
  898: *
  899: 
  900:       RETURN
  901: *
  902: *     end of DLARRE
  903: *
  904:       END

CVSweb interface <joel.bertrand@systella.fr>