1*> \brief \b DLARRB provides limited bisection to locate eigenvalues for more accuracy. 2* 3* =========== DOCUMENTATION =========== 4* 5* Online html documentation available at 6* http://www.netlib.org/lapack/explore-html/ 7* 8*> \htmlonly 9*> Download DLARRB + dependencies 10*> <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlarrb.f"> 11*> [TGZ]</a> 12*> <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlarrb.f"> 13*> [ZIP]</a> 14*> <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlarrb.f"> 15*> [TXT]</a> 16*> \endhtmlonly 17* 18* Definition: 19* =========== 20* 21* SUBROUTINE DLARRB( N, D, LLD, IFIRST, ILAST, RTOL1, 22* RTOL2, OFFSET, W, WGAP, WERR, WORK, IWORK, 23* PIVMIN, SPDIAM, TWIST, INFO ) 24* 25* .. Scalar Arguments .. 26* INTEGER IFIRST, ILAST, INFO, N, OFFSET, TWIST 27* DOUBLE PRECISION PIVMIN, RTOL1, RTOL2, SPDIAM 28* .. 29* .. Array Arguments .. 30* INTEGER IWORK( * ) 31* DOUBLE PRECISION D( * ), LLD( * ), W( * ), 32* $ WERR( * ), WGAP( * ), WORK( * ) 33* .. 34* 35* 36*> \par Purpose: 37* ============= 38*> 39*> \verbatim 40*> 41*> Given the relatively robust representation(RRR) L D L^T, DLARRB 42*> does "limited" bisection to refine the eigenvalues of L D L^T, 43*> W( IFIRST-OFFSET ) through W( ILAST-OFFSET ), to more accuracy. Initial 44*> guesses for these eigenvalues are input in W, the corresponding estimate 45*> of the error in these guesses and their gaps are input in WERR 46*> and WGAP, respectively. During bisection, intervals 47*> [left, right] are maintained by storing their mid-points and 48*> semi-widths in the arrays W and WERR respectively. 49*> \endverbatim 50* 51* Arguments: 52* ========== 53* 54*> \param[in] N 55*> \verbatim 56*> N is INTEGER 57*> The order of the matrix. 58*> \endverbatim 59*> 60*> \param[in] D 61*> \verbatim 62*> D is DOUBLE PRECISION array, dimension (N) 63*> The N diagonal elements of the diagonal matrix D. 64*> \endverbatim 65*> 66*> \param[in] LLD 67*> \verbatim 68*> LLD is DOUBLE PRECISION array, dimension (N-1) 69*> The (N-1) elements L(i)*L(i)*D(i). 70*> \endverbatim 71*> 72*> \param[in] IFIRST 73*> \verbatim 74*> IFIRST is INTEGER 75*> The index of the first eigenvalue to be computed. 76*> \endverbatim 77*> 78*> \param[in] ILAST 79*> \verbatim 80*> ILAST is INTEGER 81*> The index of the last eigenvalue to be computed. 82*> \endverbatim 83*> 84*> \param[in] RTOL1 85*> \verbatim 86*> RTOL1 is DOUBLE PRECISION 87*> \endverbatim 88*> 89*> \param[in] RTOL2 90*> \verbatim 91*> RTOL2 is DOUBLE PRECISION 92*> Tolerance for the convergence of the bisection intervals. 93*> An interval [LEFT,RIGHT] has converged if 94*> RIGHT-LEFT < MAX( RTOL1*GAP, RTOL2*MAX(|LEFT|,|RIGHT|) ) 95*> where GAP is the (estimated) distance to the nearest 96*> eigenvalue. 97*> \endverbatim 98*> 99*> \param[in] OFFSET 100*> \verbatim 101*> OFFSET is INTEGER 102*> Offset for the arrays W, WGAP and WERR, i.e., the IFIRST-OFFSET 103*> through ILAST-OFFSET elements of these arrays are to be used. 104*> \endverbatim 105*> 106*> \param[in,out] W 107*> \verbatim 108*> W is DOUBLE PRECISION array, dimension (N) 109*> On input, W( IFIRST-OFFSET ) through W( ILAST-OFFSET ) are 110*> estimates of the eigenvalues of L D L^T indexed IFIRST through 111*> ILAST. 112*> On output, these estimates are refined. 113*> \endverbatim 114*> 115*> \param[in,out] WGAP 116*> \verbatim 117*> WGAP is DOUBLE PRECISION array, dimension (N-1) 118*> On input, the (estimated) gaps between consecutive 119*> eigenvalues of L D L^T, i.e., WGAP(I-OFFSET) is the gap between 120*> eigenvalues I and I+1. Note that if IFIRST = ILAST 121*> then WGAP(IFIRST-OFFSET) must be set to ZERO. 122*> On output, these gaps are refined. 123*> \endverbatim 124*> 125*> \param[in,out] WERR 126*> \verbatim 127*> WERR is DOUBLE PRECISION array, dimension (N) 128*> On input, WERR( IFIRST-OFFSET ) through WERR( ILAST-OFFSET ) are 129*> the errors in the estimates of the corresponding elements in W. 130*> On output, these errors are refined. 131*> \endverbatim 132*> 133*> \param[out] WORK 134*> \verbatim 135*> WORK is DOUBLE PRECISION array, dimension (2*N) 136*> Workspace. 137*> \endverbatim 138*> 139*> \param[out] IWORK 140*> \verbatim 141*> IWORK is INTEGER array, dimension (2*N) 142*> Workspace. 143*> \endverbatim 144*> 145*> \param[in] PIVMIN 146*> \verbatim 147*> PIVMIN is DOUBLE PRECISION 148*> The minimum pivot in the Sturm sequence. 149*> \endverbatim 150*> 151*> \param[in] SPDIAM 152*> \verbatim 153*> SPDIAM is DOUBLE PRECISION 154*> The spectral diameter of the matrix. 155*> \endverbatim 156*> 157*> \param[in] TWIST 158*> \verbatim 159*> TWIST is INTEGER 160*> The twist index for the twisted factorization that is used 161*> for the negcount. 162*> TWIST = N: Compute negcount from L D L^T - LAMBDA I = L+ D+ L+^T 163*> TWIST = 1: Compute negcount from L D L^T - LAMBDA I = U- D- U-^T 164*> TWIST = R: Compute negcount from L D L^T - LAMBDA I = N(r) D(r) N(r) 165*> \endverbatim 166*> 167*> \param[out] INFO 168*> \verbatim 169*> INFO is INTEGER 170*> Error flag. 171*> \endverbatim 172* 173* Authors: 174* ======== 175* 176*> \author Univ. of Tennessee 177*> \author Univ. of California Berkeley 178*> \author Univ. of Colorado Denver 179*> \author NAG Ltd. 180* 181*> \ingroup OTHERauxiliary 182* 183*> \par Contributors: 184* ================== 185*> 186*> Beresford Parlett, University of California, Berkeley, USA \n 187*> Jim Demmel, University of California, Berkeley, USA \n 188*> Inderjit Dhillon, University of Texas, Austin, USA \n 189*> Osni Marques, LBNL/NERSC, USA \n 190*> Christof Voemel, University of California, Berkeley, USA 191* 192* ===================================================================== 193 SUBROUTINE DLARRB( N, D, LLD, IFIRST, ILAST, RTOL1, 194 $ RTOL2, OFFSET, W, WGAP, WERR, WORK, IWORK, 195 $ PIVMIN, SPDIAM, TWIST, INFO ) 196* 197* -- LAPACK auxiliary routine -- 198* -- LAPACK is a software package provided by Univ. of Tennessee, -- 199* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- 200* 201* .. Scalar Arguments .. 202 INTEGER IFIRST, ILAST, INFO, N, OFFSET, TWIST 203 DOUBLE PRECISION PIVMIN, RTOL1, RTOL2, SPDIAM 204* .. 205* .. Array Arguments .. 206 INTEGER IWORK( * ) 207 DOUBLE PRECISION D( * ), LLD( * ), W( * ), 208 $ WERR( * ), WGAP( * ), WORK( * ) 209* .. 210* 211* ===================================================================== 212* 213* .. Parameters .. 214 DOUBLE PRECISION ZERO, TWO, HALF 215 PARAMETER ( ZERO = 0.0D0, TWO = 2.0D0, 216 $ HALF = 0.5D0 ) 217 INTEGER MAXITR 218* .. 219* .. Local Scalars .. 220 INTEGER I, I1, II, IP, ITER, K, NEGCNT, NEXT, NINT, 221 $ OLNINT, PREV, R 222 DOUBLE PRECISION BACK, CVRGD, GAP, LEFT, LGAP, MID, MNWDTH, 223 $ RGAP, RIGHT, TMP, WIDTH 224* .. 225* .. External Functions .. 226 INTEGER DLANEG 227 EXTERNAL DLANEG 228* 229* .. 230* .. Intrinsic Functions .. 231 INTRINSIC ABS, MAX, MIN 232* .. 233* .. Executable Statements .. 234* 235 INFO = 0 236* 237* Quick return if possible 238* 239 IF( N.LE.0 ) THEN 240 RETURN 241 END IF 242* 243 MAXITR = INT( ( LOG( SPDIAM+PIVMIN )-LOG( PIVMIN ) ) / 244 $ LOG( TWO ) ) + 2 245 MNWDTH = TWO * PIVMIN 246* 247 R = TWIST 248 IF((R.LT.1).OR.(R.GT.N)) R = N 249* 250* Initialize unconverged intervals in [ WORK(2*I-1), WORK(2*I) ]. 251* The Sturm Count, Count( WORK(2*I-1) ) is arranged to be I-1, while 252* Count( WORK(2*I) ) is stored in IWORK( 2*I ). The integer IWORK( 2*I-1 ) 253* for an unconverged interval is set to the index of the next unconverged 254* interval, and is -1 or 0 for a converged interval. Thus a linked 255* list of unconverged intervals is set up. 256* 257 I1 = IFIRST 258* The number of unconverged intervals 259 NINT = 0 260* The last unconverged interval found 261 PREV = 0 262 263 RGAP = WGAP( I1-OFFSET ) 264 DO 75 I = I1, ILAST 265 K = 2*I 266 II = I - OFFSET 267 LEFT = W( II ) - WERR( II ) 268 RIGHT = W( II ) + WERR( II ) 269 LGAP = RGAP 270 RGAP = WGAP( II ) 271 GAP = MIN( LGAP, RGAP ) 272 273* Make sure that [LEFT,RIGHT] contains the desired eigenvalue 274* Compute negcount from dstqds facto L+D+L+^T = L D L^T - LEFT 275* 276* Do while( NEGCNT(LEFT).GT.I-1 ) 277* 278 BACK = WERR( II ) 279 20 CONTINUE 280 NEGCNT = DLANEG( N, D, LLD, LEFT, PIVMIN, R ) 281 IF( NEGCNT.GT.I-1 ) THEN 282 LEFT = LEFT - BACK 283 BACK = TWO*BACK 284 GO TO 20 285 END IF 286* 287* Do while( NEGCNT(RIGHT).LT.I ) 288* Compute negcount from dstqds facto L+D+L+^T = L D L^T - RIGHT 289* 290 BACK = WERR( II ) 291 50 CONTINUE 292 293 NEGCNT = DLANEG( N, D, LLD, RIGHT, PIVMIN, R ) 294 IF( NEGCNT.LT.I ) THEN 295 RIGHT = RIGHT + BACK 296 BACK = TWO*BACK 297 GO TO 50 298 END IF 299 WIDTH = HALF*ABS( LEFT - RIGHT ) 300 TMP = MAX( ABS( LEFT ), ABS( RIGHT ) ) 301 CVRGD = MAX(RTOL1*GAP,RTOL2*TMP) 302 IF( WIDTH.LE.CVRGD .OR. WIDTH.LE.MNWDTH ) THEN 303* This interval has already converged and does not need refinement. 304* (Note that the gaps might change through refining the 305* eigenvalues, however, they can only get bigger.) 306* Remove it from the list. 307 IWORK( K-1 ) = -1 308* Make sure that I1 always points to the first unconverged interval 309 IF((I.EQ.I1).AND.(I.LT.ILAST)) I1 = I + 1 310 IF((PREV.GE.I1).AND.(I.LE.ILAST)) IWORK( 2*PREV-1 ) = I + 1 311 ELSE 312* unconverged interval found 313 PREV = I 314 NINT = NINT + 1 315 IWORK( K-1 ) = I + 1 316 IWORK( K ) = NEGCNT 317 END IF 318 WORK( K-1 ) = LEFT 319 WORK( K ) = RIGHT 320 75 CONTINUE 321 322* 323* Do while( NINT.GT.0 ), i.e. there are still unconverged intervals 324* and while (ITER.LT.MAXITR) 325* 326 ITER = 0 327 80 CONTINUE 328 PREV = I1 - 1 329 I = I1 330 OLNINT = NINT 331 332 DO 100 IP = 1, OLNINT 333 K = 2*I 334 II = I - OFFSET 335 RGAP = WGAP( II ) 336 LGAP = RGAP 337 IF(II.GT.1) LGAP = WGAP( II-1 ) 338 GAP = MIN( LGAP, RGAP ) 339 NEXT = IWORK( K-1 ) 340 LEFT = WORK( K-1 ) 341 RIGHT = WORK( K ) 342 MID = HALF*( LEFT + RIGHT ) 343 344* semiwidth of interval 345 WIDTH = RIGHT - MID 346 TMP = MAX( ABS( LEFT ), ABS( RIGHT ) ) 347 CVRGD = MAX(RTOL1*GAP,RTOL2*TMP) 348 IF( ( WIDTH.LE.CVRGD ) .OR. ( WIDTH.LE.MNWDTH ).OR. 349 $ ( ITER.EQ.MAXITR ) )THEN 350* reduce number of unconverged intervals 351 NINT = NINT - 1 352* Mark interval as converged. 353 IWORK( K-1 ) = 0 354 IF( I1.EQ.I ) THEN 355 I1 = NEXT 356 ELSE 357* Prev holds the last unconverged interval previously examined 358 IF(PREV.GE.I1) IWORK( 2*PREV-1 ) = NEXT 359 END IF 360 I = NEXT 361 GO TO 100 362 END IF 363 PREV = I 364* 365* Perform one bisection step 366* 367 NEGCNT = DLANEG( N, D, LLD, MID, PIVMIN, R ) 368 IF( NEGCNT.LE.I-1 ) THEN 369 WORK( K-1 ) = MID 370 ELSE 371 WORK( K ) = MID 372 END IF 373 I = NEXT 374 100 CONTINUE 375 ITER = ITER + 1 376* do another loop if there are still unconverged intervals 377* However, in the last iteration, all intervals are accepted 378* since this is the best we can do. 379 IF( ( NINT.GT.0 ).AND.(ITER.LE.MAXITR) ) GO TO 80 380* 381* 382* At this point, all the intervals have converged 383 DO 110 I = IFIRST, ILAST 384 K = 2*I 385 II = I - OFFSET 386* All intervals marked by '0' have been refined. 387 IF( IWORK( K-1 ).EQ.0 ) THEN 388 W( II ) = HALF*( WORK( K-1 )+WORK( K ) ) 389 WERR( II ) = WORK( K ) - W( II ) 390 END IF 391 110 CONTINUE 392* 393 DO 111 I = IFIRST+1, ILAST 394 K = 2*I 395 II = I - OFFSET 396 WGAP( II-1 ) = MAX( ZERO, 397 $ W(II) - WERR (II) - W( II-1 ) - WERR( II-1 )) 398 111 CONTINUE 399 400 RETURN 401* 402* End of DLARRB 403* 404 END 405