6
    7
    8
    9
   10
   11
   12      CHARACTER          RANGE
   13      INTEGER            DOL, DOU, IL, INFO, IU, M, N, NSPLIT      
   14      DOUBLE PRECISION  PIVMIN, RTOL1, RTOL2, SPLTOL, VL, VU
   15
   16
   17      INTEGER            IBLOCK( * ), ISPLIT( * ), IWORK( * ),
   18     $                   INDEXW( * )
   19      DOUBLE PRECISION   D( * ), E( * ), E2( * ), GERS( * ), 
   20     $                   W( * ),WERR( * ), WGAP( * ), WORK( * )
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192      DOUBLE PRECISION   FAC, FOUR, FOURTH, FUDGE, HALF, HNDRD,
  193     $                   MAXGROWTH, ONE, PERT, TWO, ZERO
  194      parameter( zero = 0.0d0, one = 1.0d0, 
  195     $                     two = 2.0d0, four=4.0d0,
  196     $                     hndrd = 100.0d0,
  197     $                     pert = 8.0d0,
  198     $                     half = one/two, fourth = one/four, fac= half,
  199     $                     maxgrowth = 64.0d0, fudge = 2.0d0 )
  200      INTEGER            MAXTRY
  201      parameter( maxtry = 6 )
  202
  203
  204      LOGICAL            FORCEB, NOREP, RNDPRT, USEDQD
  205      INTEGER            CNT, CNT1, CNT2, I, IBEGIN, IDUM, IEND, IINFO,
  206     $                   IN, INDL, INDU, IRANGE, J, JBLK, MB, MM,
  207     $                   WBEGIN, WEND
  208      DOUBLE PRECISION   AVGAP, BSRTOL, CLWDTH, DMAX, DPIVOT, EABS,
  209     $                   EMAX, EOLD, EPS, GL, GU, ISLEFT, ISRGHT, RTL,
  210     $                   RTOL, S1, S2, SAFMIN, SGNDEF, SIGMA, SPDIAM,
  211     $                   TAU, TMP, TMP1
  212 
  213 
  214
  215
  216      INTEGER            ISEED( 4 )
  217
  218
  219      LOGICAL            LSAME
  220      DOUBLE PRECISION            DLAMCH
  222 
  223
  224
  225      EXTERNAL           dcopy, dlarnv, dlarra, dlarrb, dlarrc,
  226     $                   dlarrd, dlasq2
  227
  228
  230 
  231
  232
  233
  234 
  235      info = 0
  236 
  237
  238      rndprt = .true.
  239
  240
  241
  242      IF( 
lsame( range, 
'A' ) ) 
THEN 
  243         irange = 1
  244      ELSE IF( 
lsame( range, 
'V' ) ) 
THEN 
  245         irange = 2
  246      ELSE IF( 
lsame( range, 
'I' ) ) 
THEN 
  247         irange = 3
  248      END IF
  249 
  250      m = 0
  251 
  252
  255 
  256
  257      rtl = sqrt(eps)
  258      bsrtol = 1.0d-1
  259 
  260
  261      IF( n.EQ.1 ) THEN
  262         IF( (irange.EQ.1).OR.
  263     $       ((irange.EQ.2).AND.(d(1).GT.vl).AND.(d(1).LE.vu)).OR.
  264     $       ((irange.EQ.3).AND.(il.EQ.1).AND.(iu.EQ.1)) ) THEN
  265            m = 1
  266            w(1) = d(1)
  267
  268            werr(1) = zero
  269            wgap(1) = zero
  270            iblock( 1 ) = 1
  271            indexw( 1 ) = 1
  272            gers(1) = d( 1 ) 
  273            gers(2) = d( 1 ) 
  274         ENDIF       
  275
  276         e(1) = zero
  277         RETURN
  278      END IF
  279 
  280
  281
  282
  283
  284      gl = d(1)
  285      gu = d(1)
  286      eold = zero
  287      emax = zero
  288      e(n) = zero
  289      DO 5 i = 1,n
  290         werr(i) = zero
  291         wgap(i) = zero
  292         eabs = abs( e(i) )
  293         IF( eabs .GE. emax ) THEN
  294            emax = eabs
  295         END IF
  296         tmp1 = eabs + eold
  297         gers( 2*i-1) = d(i) - tmp1
  298         gl =  
min( gl, gers( 2*i - 1))
 
  299         gers( 2*i ) = d(i) + tmp1
  300         gu = 
max( gu, gers(2*i) )
 
  301         eold  = eabs
  302 5    CONTINUE
  303
  304      pivmin = safmin * 
max( one, emax**2 )      
 
  305
  306
  307      spdiam = gu - gl
  308 
  309
  310      CALL dlarra( n, d, e, e2, spltol, spdiam, 
  311     $                    nsplit, isplit, iinfo )
  312 
  313
  314      forceb = .false.
  315 
  316      IF( (irange.EQ.1) .AND. (.NOT. forceb) ) THEN
  317
  318         vl = gl
  319         vu = gu
  320      ELSE
  321
  322
  323
  324
  325
  326
  327         CALL dlarrd( range, 'B', n, vl, vu, il, iu, gers, 
  328     $                    bsrtol, d, e, e2, pivmin, nsplit, isplit, 
  329     $                    mm, w, werr, vl, vu, iblock, indexw, 
  330     $                    work, iwork, iinfo )
  331         IF( iinfo.NE.0 ) THEN
  332            info = -1
  333            RETURN
  334         ENDIF       
  335
  336         DO 14 i = mm+1,n
  337            w( i ) = zero
  338            werr( i ) = zero
  339            iblock( i ) = 0
  340            indexw( i ) = 0
  341 14      CONTINUE
  342      END IF
  343 
  344 
  345
  346
  347      ibegin = 1
  348      wbegin = 1
  349      DO 170 jblk = 1, nsplit
  350         iend = isplit( jblk )
  351         in = iend - ibegin + 1
  352 
  353
  354         IF( in.EQ.1 ) THEN
  355            IF( (irange.EQ.1).OR.( (irange.EQ.2).AND.
  356     $         ( d( ibegin ).GT.vl ).AND.( d( ibegin ).LE.vu ) )
  357     $        .OR. ( (irange.EQ.3).AND.(iblock(wbegin).EQ.jblk))
  358     $        ) THEN
  359               m = m + 1
  360               w( m ) = d( ibegin )
  361               werr(m) = zero
  362
  363
  364               wgap(m) = zero
  365               iblock( m ) = jblk
  366               indexw( m ) = 1
  367               wbegin = wbegin + 1
  368            ENDIF
  369
  370            e( iend ) = zero
  371            ibegin = iend + 1
  372            GO TO 170
  373         END IF
  374
  375
  376
  377
  378         e( iend ) = zero
  379
  380
  381         gl = d(ibegin)
  382         gu = d(ibegin)
  383         DO 15 i = ibegin , iend
  384            gl = 
min( gers( 2*i-1 ), gl )
 
  385            gu = 
max( gers( 2*i ), gu )
 
  386 15      CONTINUE
  387         spdiam = gu - gl
  388 
  389         IF(.NOT. ((irange.EQ.1).AND.(.NOT.forceb)) ) THEN
  390
  391            mb = 0
  392            DO 20 i = wbegin,mm
  393               IF( iblock(i).EQ.jblk ) THEN
  394                  mb = mb+1
  395               ELSE
  396                  GOTO 21
  397               ENDIF 
  398 20         CONTINUE
  399 21         CONTINUE
  400 
  401            IF( mb.EQ.0) THEN
  402
  403
  404               e( iend ) = zero
  405               ibegin = iend + 1
  406               GO TO 170
  407            ELSE
  408 
  409
  410               usedqd = ( (mb .GT. fac*in) .AND. (.NOT.forceb) )
  411               wend = wbegin + mb - 1
  412
  413
  414
  415               sigma = zero
  416               DO 30 i = wbegin, wend - 1
  417                  wgap( i ) = 
max( zero, 
 
  418     $                        w(i+1)-werr(i+1) - (w(i)+werr(i)) )
  419 30            CONTINUE
  420               wgap( wend ) = 
max( zero, 
 
  421     $                     vu - sigma - (w( wend )+werr( wend )))
  422
  423               indl = indexw(wbegin)
  424               indu = indexw( wend )
  425            ENDIF
  426         ELSE
  427
  428            mb = in
  429            wend = wbegin + mb - 1
  430            indl = 1
  431            indu = in
  432         ENDIF
  433 
  434         IF( (wend.LT.dol).OR.(wbegin.GT.dou) ) THEN
  435
  436
  437            ibegin = iend + 1
  438            wbegin = wend + 1
  439            m = m + indu - indl + 1
  440            GO TO 170
  441         END IF
  442 
  443
  444         CALL dlarrk( in, 1, gl, gu, d(ibegin),
  445     $               e2(ibegin), pivmin, rtl, tmp, tmp1, iinfo )
  446         IF( iinfo.NE.0 ) THEN
  447            info = -1
  448            RETURN
  449         ENDIF       
  450         isleft = 
max(gl, tmp - tmp1
 
  451     $            - hndrd * eps* abs(tmp - tmp1))
  452         CALL dlarrk( in, in, gl, gu, d(ibegin),
  453     $               e2(ibegin), pivmin, rtl, tmp, tmp1, iinfo )
  454         IF( iinfo.NE.0 ) THEN
  455            info = -1
  456            RETURN
  457         ENDIF       
  458         isrght = 
min(gu, tmp + tmp1
 
  459     $                 + hndrd * eps * abs(tmp + tmp1))
  460         IF(( (irange.EQ.1) .AND. (.NOT. forceb) ).OR.usedqd) THEN
  461
  462
  463            spdiam = isrght - isleft
  464         ELSE
  465
  466
  467            isleft = 
max(gl, w(wbegin) - werr(wbegin) 
 
  468     $                  - hndrd * eps*abs(w(wbegin)- werr(wbegin) ))
  469            isrght = 
min(gu,w(wend) + werr(wend)
 
  470     $                  + hndrd * eps * abs(w(wend)+ werr(wend)))
  471         ENDIF
  472 
  473 
  474
  475
  476
  477
  478
  479
  480
  481
  482         IF( ( irange.EQ.1 ) .AND. (.NOT.forceb) ) THEN
  483
  484            usedqd = .true.
  485
  486            indl = 1
  487            indu = in
  488
  489            mb = in
  490            wend = wbegin + mb - 1
  491
  492            s1 = isleft + fourth * spdiam
  493            s2 = isrght - fourth * spdiam
  494         ELSE        
  495
  496
  497
  498            IF( usedqd ) THEN
  499               s1 = isleft + fourth * spdiam
  500               s2 = isrght - fourth * spdiam
  501            ELSE
  502               tmp = 
min(isrght,vu) -  
max(isleft,vl)
 
  503               s1 =  
max(isleft,vl) + fourth * tmp
 
  504               s2 =  
min(isrght,vu) - fourth * tmp
 
  505            ENDIF
  506         ENDIF       
  507 
  508
  509         IF(mb.GT.1) THEN
  510            CALL dlarrc( 'T', in, s1, s2, d(ibegin), 
  511     $                    e(ibegin), pivmin, cnt, cnt1, cnt2, iinfo)
  512         ENDIF
  513 
  514         IF(mb.EQ.1) THEN
  515            sigma = gl   
  516            sgndef = one
  517         ELSEIF( cnt1 - indl .GE. indu - cnt2 ) THEN
  518            IF( ( irange.EQ.1 ) .AND. (.NOT.forceb) ) THEN
  519               sigma = 
max(isleft,gl)
 
  520            ELSEIF( usedqd ) THEN
  521
  522
  523               sigma = isleft
  524            ELSE
  525
  526
  527               sigma = 
max(isleft,vl)
 
  528            ENDIF
  529            sgndef = one
  530         ELSE
  531            IF( ( irange.EQ.1 ) .AND. (.NOT.forceb) ) THEN
  532               sigma = 
min(isrght,gu)
 
  533            ELSEIF( usedqd ) THEN
  534
  535
  536               sigma = isrght
  537            ELSE
  538
  539
  540               sigma = 
min(isrght,vu)
 
  541            ENDIF
  542            sgndef = -one
  543         ENDIF
  544 
  545 
  546
  547
  548
  549
  550
  551         IF( usedqd ) THEN
  552            tau = spdiam*eps*n + two*pivmin
  553            tau = 
max(tau,eps*abs(sigma))
 
  554         ELSE
  555            IF(mb.GT.1) THEN        
  556               clwdth = w(wend) + werr(wend) - w(wbegin) - werr(wbegin)
  557               avgap = abs(clwdth / dble(wend-wbegin))
  558               IF( sgndef.EQ.one ) THEN
  559                  tau = half*
max(wgap(wbegin),avgap)
 
  560                  tau = 
max(tau,werr(wbegin))
 
  561               ELSE
  562                  tau = half*
max(wgap(wend-1),avgap)
 
  563                  tau = 
max(tau,werr(wend))
 
  564               ENDIF
  565            ELSE
  566               tau = werr(wbegin)
  567            ENDIF
  568         ENDIF
  569
  570         DO 80 idum = 1, maxtry
  571
  572
  573
  574            dpivot = d( ibegin ) - sigma
  575            work( 1 ) = dpivot
  576            dmax = abs( work(1) )
  577            j = ibegin
  578            DO 70 i = 1, in - 1
  579               work( 2*in+i ) = one / work( i )
  580               tmp = e( j )*work( 2*in+i )
  581               work( in+i ) = tmp
  582               dpivot = ( d( j+1 )-sigma ) - tmp*e( j )
  583               work( i+1 ) = dpivot
  584               dmax = 
max( dmax, abs(dpivot) )
 
  585               j = j + 1
  586 70         CONTINUE
  587
  588            IF( dmax .GT. maxgrowth*spdiam ) THEN
  589               norep = .true.
  590            ELSE
  591               norep = .false.
  592            ENDIF
  593            IF(norep) THEN
  594
  595
  596
  597               IF( idum.EQ.maxtry-1 ) THEN
  598                  IF( sgndef.EQ.one ) THEN 
  599
  600                     sigma = 
  601     $                    gl - fudge*spdiam*eps*n - fudge*two*pivmin
  602                  ELSE
  603                     sigma = 
  604     $                    gu + fudge*spdiam*eps*n + fudge*two*pivmin
  605                  END IF
  606               ELSE
  607                  sigma = sigma - sgndef * tau 
  608                  tau = two * tau
  609               END IF
  610            ELSE    
  611
  612               GO TO 83 
  613            END IF
  614 80      CONTINUE
  615
  616
  617         info = 2
  618         RETURN
  619 
  620 83      CONTINUE
  621
  622
  623
  624         e( iend ) = sigma
  625
  626         CALL dcopy( in, work, 1, d( ibegin ), 1 )
  627         CALL dcopy( in-1, work( in+1 ), 1, e( ibegin ), 1 )
  628 
  629        
  630         IF(rndprt .AND. mb.GT.1 ) THEN
  631
  632
  633
  634
  635
  636            DO 122 i = 1, 4
  637               iseed( i ) = 1
  638 122        CONTINUE
  639 
  640            CALL dlarnv(2, iseed, 2*in-1, work(1))
  641            DO 125 i = 1,in-1
  642               d(ibegin+i-1) = d(ibegin+i-1)*(one+eps*pert*work(i))
  643               e(ibegin+i-1) = e(ibegin+i-1)*(one+eps*pert*work(in+i))
  644 125        CONTINUE
  645            d(iend) = d(iend)*(one+eps*four*work(in))
  646
  647         ENDIF
  648
  649
  650
  651
  652
  653 
  654
  655         IF ( .NOT.usedqd ) THEN
  656
  657
  658
  659
  660
  661            DO 134 j=wbegin,wend
  662               w(j) = w(j) - sigma
  663               werr(j) = werr(j) + abs(w(j)) * eps
  664 134        CONTINUE
  665
  666
  667            DO 135 i = ibegin, iend-1
  668               work( i ) = d( i ) * e( i )**2
  669 135        CONTINUE
  670
  671            CALL dlarrb(in, d(ibegin), work(ibegin),
  672     $                  indl, indu, rtol1, rtol2, indl-1,
  673     $                  w(wbegin), wgap(wbegin), werr(wbegin),
  674     $                  work( 2*n+1 ), iwork, pivmin, spdiam,
  675     $                  in, iinfo )
  676            IF( iinfo .NE. 0 ) THEN
  677               info = -4
  678               RETURN
  679            END IF
  680
  681
  682            wgap( wend ) = 
max( zero, 
 
  683     $           ( vu-sigma ) - ( w( wend ) + werr( wend ) ) )
  684            DO 138 i = indl, indu
  685               m = m + 1
  686               iblock(m) = jblk
  687               indexw(m) = i 
  688 138        CONTINUE
  689         ELSE
  690
  691
  692
  693
  694
  695
  696
  697
  698
  699
  700
  701            rtol = log(dble(in)) * four * eps
  702            j = ibegin
  703            DO 140 i = 1, in - 1
  704               work( 2*i-1 ) = abs( d( j ) )
  705               work( 2*i ) = e( j )*e( j )*work( 2*i-1 )
  706               j = j + 1
  707  140       CONTINUE
  708            work( 2*in-1 ) = abs( d( iend ) )
  709            work( 2*in ) = zero
  710            CALL dlasq2( in, work, iinfo )
  711            IF( iinfo .NE. 0 ) THEN
  712
  713
  714
  715               info = -5
  716               RETURN
  717            ELSE
  718
  719               DO 149 i = 1, in
  720                  IF( work( i ).LT.zero ) THEN
  721                     info = -6
  722                     RETURN
  723                  ENDIF
  724 149           CONTINUE
  725            END IF
  726            IF( sgndef.GT.zero ) THEN
  727               DO 150 i = indl, indu
  728                  m = m + 1                                   
  729                  w( m ) = work( in-i+1 )
  730                  iblock( m ) = jblk
  731                  indexw( m ) = i
  732 150           CONTINUE
  733            ELSE
  734               DO 160 i = indl, indu
  735                  m = m + 1
  736                  w( m ) = -work( i )
  737                  iblock( m ) = jblk
  738                  indexw( m ) = i
  739 160           CONTINUE
  740            END IF
  741 
  742            DO 165 i = m - mb + 1, m
  743
  744               werr( i ) = rtol * abs( w(i) )
  745 165        CONTINUE
  746            DO 166 i = m - mb + 1, m - 1
  747
  748               wgap( i ) = 
max( zero,
 
  749     $                          w(i+1)-werr(i+1) - (w(i)+werr(i)) )
  750 166        CONTINUE
  751            wgap( m ) = 
max( zero, 
 
  752     $           ( vu-sigma ) - ( w( m ) + werr( m ) ) )
  753         END IF
  754
  755         ibegin = iend + 1
  756         wbegin = wend + 1
  757 170  CONTINUE
  758
  759 
  760      RETURN
  761
  762
  763