224
  225
  226
  227
  228
  229
  230      CHARACTER          JOBZ, RANGE, UPLO
  231      INTEGER            IL, INFO, IU, LDZ, N, NS
  232      DOUBLE PRECISION   VL, VU
  233
  234
  235      INTEGER            IWORK( * )
  236      DOUBLE PRECISION   D( * ), E( * ), S( * ), WORK( * ),
  237     $                   Z( LDZ, * )
  238
  239
  240
  241
  242
  243      DOUBLE PRECISION   ZERO, ONE, TEN, HNDRD, MEIGTH
  244      parameter( zero = 0.0d0, one = 1.0d0, ten = 10.0d0,
  245     $                     hndrd = 100.0d0, meigth = -0.1250d0 )
  246      DOUBLE PRECISION   FUDGE
  247      parameter( fudge = 2.0d0 )
  248
  249
  250      CHARACTER          RNGVX
  251      LOGICAL            ALLSV, INDSV, LOWER, SPLIT, SVEQ0, VALSV, WANTZ
  252      INTEGER            I, ICOLZ, IDBEG, IDEND, IDTGK, IDPTR, IEPTR,
  253     $                   IETGK, IIFAIL, IIWORK, ILTGK, IROWU, IROWV,
  254     $                   IROWZ, ISBEG, ISPLT, ITEMP, IUTGK, J, K,
  255     $                   NTGK, NRU, NRV, NSL
  256      DOUBLE PRECISION   ABSTOL, EPS, EMIN, MU, NRMU, NRMV, ORTOL, SMAX,
  257     $                   SMIN, SQRT2, THRESH, TOL, ULP,
  258     $                   VLTGK, VUTGK, ZJTJI
  259
  260
  261      LOGICAL            LSAME
  262      INTEGER            IDAMAX
  263      DOUBLE PRECISION   DDOT, DLAMCH, DNRM2
  266
  267
  270
  271
  272      INTRINSIC          abs, dble, sign, sqrt
  273
  274
  275
  276
  277
  278      allsv = 
lsame( range, 
'A' )
 
  279      valsv = 
lsame( range, 
'V' )
 
  280      indsv = 
lsame( range, 
'I' )
 
  281      wantz = 
lsame( jobz, 
'V' )
 
  282      lower = 
lsame( uplo, 
'L' )
 
  283
  284      info = 0
  285      IF( .NOT.
lsame( uplo, 
'U' ) .AND. .NOT.lower ) 
THEN 
  286         info = -1
  287      ELSE IF( .NOT.( wantz .OR. 
lsame( jobz, 
'N' ) ) ) 
THEN 
  288         info = -2
  289      ELSE IF( .NOT.( allsv .OR. valsv .OR. indsv ) ) THEN
  290         info = -3
  291      ELSE IF( n.LT.0 ) THEN
  292         info = -4
  293      ELSE IF( n.GT.0 ) THEN
  294         IF( valsv ) THEN
  295            IF( vl.LT.zero ) THEN
  296               info = -7
  297            ELSE IF( vu.LE.vl ) THEN
  298               info = -8
  299            END IF
  300         ELSE IF( indsv ) THEN
  301            IF( il.LT.1 .OR. il.GT.max( 1, n ) ) THEN
  302               info = -9
  303            ELSE IF( iu.LT.min( n, il ) .OR. iu.GT.n ) THEN
  304               info = -10
  305            END IF
  306         END IF
  307      END IF
  308      IF( info.EQ.0 ) THEN
  309         IF( ldz.LT.1 .OR. ( wantz .AND. ldz.LT.n*2 ) ) info = -14
  310      END IF
  311
  312      IF( info.NE.0 ) THEN
  313         CALL xerbla( 
'DBDSVDX', -info )
 
  314         RETURN
  315      END IF
  316
  317
  318
  319      ns = 0
  320      IF( n.EQ.0 ) RETURN
  321
  322      IF( n.EQ.1 ) THEN
  323         IF( allsv .OR. indsv ) THEN
  324            ns = 1
  325            s( 1 ) = abs( d( 1 ) )
  326         ELSE
  327            IF( vl.LT.abs( d( 1 ) ) .AND. vu.GE.abs( d( 1 ) ) ) THEN
  328               ns = 1
  329               s( 1 ) = abs( d( 1 ) )
  330            END IF
  331         END IF
  332         IF( wantz ) THEN
  333            z( 1, 1 ) = sign( one, d( 1 ) )
  334            z( 2, 1 ) = one
  335         END IF
  336         RETURN
  337      END IF
  338
  339      abstol = 2*
dlamch( 
'Safe Minimum' )
 
  340      ulp = 
dlamch( 
'Precision' )
 
  342      sqrt2 = sqrt( 2.0d0 )
  343      ortol = sqrt( ulp )
  344
  345
  346
  347
  348
  349
  350      tol = max( ten, min( hndrd, eps**meigth ) )*eps
  351
  352
  353
  355      smax = abs( d( i ) )
  357      smax = max( smax, abs( e( i ) ) )
  358
  359
  360
  361      smin = abs( d( 1 ) )
  362      IF( smin.NE.zero ) THEN
  363         mu = smin
  364         DO i = 2, n
  365            mu = abs( d( i ) )*( mu / ( mu+abs( e( i-1 ) ) ) )
  366            smin = min( smin, mu )
  367            IF( smin.EQ.zero ) EXIT
  368         END DO
  369      END IF
  370      smin = smin / sqrt( dble( n ) )
  371      thresh = tol*smin
  372
  373
  374
  375      DO i = 1, n-1
  376         IF( abs( d( i ) ).LE.thresh ) d( i ) = zero
  377         IF( abs( e( i ) ).LE.thresh ) e( i ) = zero
  378      END DO
  379      IF( abs( d( n ) ).LE.thresh ) d( n ) = zero
  380
  381
  382
  383      idtgk = 1
  384      ietgk = idtgk + n*2
  385      itemp = ietgk + n*2
  386      iifail = 1
  387      iiwork = iifail + n*2
  388
  389
  390
  391
  392
  393      iltgk = 0
  394      iutgk = 0
  395      vltgk = zero
  396      vutgk = zero
  397
  398      IF( allsv ) THEN
  399
  400
  401
  402
  403
  404
  405         rngvx = 'I'
  406         IF( wantz ) 
CALL dlaset( 
'F', n*2, n+1, zero, zero, z, ldz )
 
  407      ELSE IF( valsv ) THEN
  408
  409
  410
  411
  412
  413         rngvx = 'V'
  414         vltgk = -vu
  415         vutgk = -vl
  416         work( idtgk:idtgk+2*n-1 ) = zero
  417         CALL dcopy( n, d, 1, work( ietgk ), 2 )
 
  418         CALL dcopy( n-1, e, 1, work( ietgk+1 ), 2 )
 
  419         CALL dstevx( 
'N', 
'V', n*2, work( idtgk ), work( ietgk ),
 
  420     $                vltgk, vutgk, iltgk, iltgk, abstol, ns, s,
  421     $                z, ldz, work( itemp ), iwork( iiwork ),
  422     $                iwork( iifail ), info )
  423         IF( ns.EQ.0 ) THEN
  424            RETURN
  425         ELSE
  426            IF( wantz ) 
CALL dlaset( 
'F', n*2, ns, zero, zero, z,
 
  427     $          ldz )
  428         END IF
  429      ELSE IF( indsv ) THEN
  430
  431
  432
  433
  434
  435
  436
  437
  438         iltgk = il
  439         iutgk = iu
  440         rngvx = 'V'
  441         work( idtgk:idtgk+2*n-1 ) = zero
  442         CALL dcopy( n, d, 1, work( ietgk ), 2 )
 
  443         CALL dcopy( n-1, e, 1, work( ietgk+1 ), 2 )
 
  444         CALL dstevx( 
'N', 
'I', n*2, work( idtgk ), work( ietgk ),
 
  445     $                vltgk, vltgk, iltgk, iltgk, abstol, ns, s,
  446     $                z, ldz, work( itemp ), iwork( iiwork ),
  447     $                iwork( iifail ), info )
  448         vltgk = s( 1 ) - fudge*smax*ulp*n
  449         work( idtgk:idtgk+2*n-1 ) = zero
  450         CALL dcopy( n, d, 1, work( ietgk ), 2 )
 
  451         CALL dcopy( n-1, e, 1, work( ietgk+1 ), 2 )
 
  452         CALL dstevx( 
'N', 
'I', n*2, work( idtgk ), work( ietgk ),
 
  453     $                vutgk, vutgk, iutgk, iutgk, abstol, ns, s,
  454     $                z, ldz, work( itemp ), iwork( iiwork ),
  455     $                iwork( iifail ), info )
  456         vutgk = s( 1 ) + fudge*smax*ulp*n
  457         vutgk = min( vutgk, zero )
  458
  459
  460
  461
  462         IF( vltgk.EQ.vutgk ) vltgk = vltgk - tol
  463
  464         IF( wantz ) 
CALL dlaset( 
'F', n*2, iu-il+1, zero, zero, z,
 
  465     $       ldz)
  466      END IF
  467
  468
  469
  470
  471
  472
  473
  474
  475      ns = 0
  476      nru = 0
  477      nrv = 0
  478      idbeg = 1
  479      isbeg = 1
  480      irowz = 1
  481      icolz = 1
  482      irowu = 2
  483      irowv = 1
  484      split = .false.
  485      sveq0 = .false.
  486
  487
  488
  489      s( 1:n ) = zero
  490      work( ietgk+2*n-1 ) = zero
  491      work( idtgk:idtgk+2*n-1 ) = zero
  492      CALL dcopy( n, d, 1, work( ietgk ), 2 )
 
  493      CALL dcopy( n-1, e, 1, work( ietgk+1 ), 2 )
 
  494
  495
  496
  497
  498
  499      DO ieptr = 2, n*2, 2
  500         IF( work( ietgk+ieptr-1 ).EQ.zero ) THEN
  501
  502
  503
  504
  505            isplt = idbeg
  506            idend = ieptr - 1
  507            DO idptr = idbeg, idend, 2
  508               IF( work( ietgk+idptr-1 ).EQ.zero ) THEN
  509
  510
  511
  512
  513                  IF( idptr.EQ.idbeg ) THEN
  514
  515
  516
  517                     sveq0 = .true.
  518                     IF( idbeg.EQ.idend) THEN
  519                        nru = 1
  520                        nrv = 1
  521                     END IF
  522                  ELSE IF( idptr.EQ.idend ) THEN
  523
  524
  525
  526                     sveq0 = .true.
  527                     nru = (idend-isplt)/2 + 1
  528                     nrv = nru
  529                     IF( isplt.NE.idbeg ) THEN
  530                        nru = nru + 1
  531                     END IF
  532                  ELSE
  533                     IF( isplt.EQ.idbeg ) THEN
  534
  535
  536
  537                        nru = (idptr-idbeg)/2
  538                        nrv = nru + 1
  539                     ELSE
  540
  541
  542
  543                        nru = (idptr-isplt)/2 + 1
  544                        nrv = nru
  545                     END IF
  546                  END IF
  547               ELSE IF( idptr.EQ.idend ) THEN
  548
  549
  550
  551                  IF( isplt.EQ.idbeg ) THEN
  552
  553
  554
  555                     nru = (idend-idbeg)/2 + 1
  556                     nrv = nru
  557                  ELSE
  558
  559
  560
  561                     nrv = (idend-isplt)/2 + 1
  562                     nru = nrv + 1
  563                  END IF
  564               END IF
  565
  566               ntgk = nru + nrv
  567
  568               IF( ntgk.GT.0 ) THEN
  569
  570
  571
  572
  573
  574
  575
  576                  iltgk = 1
  577                  iutgk = ntgk / 2
  578                  IF( allsv .OR. vutgk.EQ.zero ) THEN
  579                     IF( sveq0 .OR.
  580     $                   smin.LT.eps .OR.
  581     $                   mod(ntgk,2).GT.0 ) THEN
  582
  583
  584                         iutgk = iutgk + 1
  585                     END IF
  586                  END IF
  587
  588
  589
  590
  591
  592                  CALL dstevx( jobz, rngvx, ntgk,
 
  593     $                         work( idtgk+isplt-1 ),
  594     $                         work( ietgk+isplt-1 ), vltgk, vutgk,
  595     $                         iltgk, iutgk, abstol, nsl, s( isbeg ),
  596     $                         z( irowz,icolz ), ldz, work( itemp ),
  597     $                         iwork( iiwork ), iwork( iifail ),
  598     $                         info )
  599                  IF( info.NE.0 ) THEN
  600
  601                     RETURN
  602                  END IF
  603                  emin = abs( maxval( s( isbeg:isbeg+nsl-1 ) ) )
  604
  605                  IF( nsl.GT.0 .AND. wantz ) THEN
  606
  607
  608
  609
  610
  611
  612
  613
  614
  615                     IF( nsl.GT.1 .AND.
  616     $                   vutgk.EQ.zero .AND.
  617     $                   mod(ntgk,2).EQ.0 .AND.
  618     $                   emin.EQ.0 .AND. .NOT.split ) THEN
  619
  620
  621
  622
  623
  624
  625                        z( irowz:irowz+ntgk-1,icolz+nsl-2 ) =
  626     $                  z( irowz:irowz+ntgk-1,icolz+nsl-2 ) +
  627     $                  z( irowz:irowz+ntgk-1,icolz+nsl-1 )
  628                        z( irowz:irowz+ntgk-1,icolz+nsl-1 ) =
  629     $                  zero
  630
  631
  632
  633
  634                     END IF
  635
  636                     DO i = 0, min( nsl-1, nru-1 )
  637                        nrmu = 
dnrm2( nru, z( irowu, icolz+i ), 2 )
 
  638                        IF( nrmu.EQ.zero ) THEN
  639                           info = n*2 + 1
  640                           RETURN
  641                        END IF
  642                        CALL dscal( nru, one/nrmu,
 
  643     $                              z( irowu,icolz+i ), 2 )
  644                        IF( nrmu.NE.one .AND.
  645     $                      abs( nrmu-ortol )*sqrt2.GT.one )
  646     $                      THEN
  647                           DO j = 0, i-1
  648                              zjtji = -
ddot( nru, z( irowu,
 
  649     $                                       icolz+j ),
  650     $                                       2, z( irowu, icolz+i ), 2 )
  651                              CALL daxpy( nru, zjtji,
 
  652     $                                    z( irowu, icolz+j ), 2,
  653     $                                    z( irowu, icolz+i ), 2 )
  654                           END DO
  655                           nrmu = 
dnrm2( nru, z( irowu, icolz+i ),
 
  656     $                                   2 )
  657                           CALL dscal( nru, one/nrmu,
 
  658     $                                 z( irowu,icolz+i ), 2 )
  659                        END IF
  660                     END DO
  661                     DO i = 0, min( nsl-1, nrv-1 )
  662                        nrmv = 
dnrm2( nrv, z( irowv, icolz+i ), 2 )
 
  663                        IF( nrmv.EQ.zero ) THEN
  664                           info = n*2 + 1
  665                           RETURN
  666                        END IF
  667                        CALL dscal( nrv, -one/nrmv,
 
  668     $                              z( irowv,icolz+i ), 2 )
  669                        IF( nrmv.NE.one .AND.
  670     $                      abs( nrmv-ortol )*sqrt2.GT.one )
  671     $                      THEN
  672                           DO j = 0, i-1
  673                              zjtji = -
ddot( nrv, z( irowv,
 
  674     $                                       icolz+j ),
  675     $                                       2, z( irowv, icolz+i ), 2 )
  676                              CALL daxpy( nru, zjtji,
 
  677     $                                    z( irowv, icolz+j ), 2,
  678     $                                    z( irowv, icolz+i ), 2 )
  679                           END DO
  680                           nrmv = 
dnrm2( nrv, z( irowv, icolz+i ),
 
  681     $                                   2 )
  682                           CALL dscal( nrv, one/nrmv,
 
  683     $                                 z( irowv,icolz+i ), 2 )
  684                        END IF
  685                     END DO
  686                     IF( vutgk.EQ.zero .AND.
  687     $                   idptr.LT.idend .AND.
  688     $                   mod(ntgk,2).GT.0 ) THEN
  689
  690
  691
  692
  693
  694
  695                        split = .true.
  696                        z( irowz:irowz+ntgk-1,n+1 ) =
  697     $                     z( irowz:irowz+ntgk-1,ns+nsl )
  698                        z( irowz:irowz+ntgk-1,ns+nsl ) =
  699     $                     zero
  700                     END IF
  701                  END IF 
  702
  703                  nsl = min( nsl, nru )
  704                  sveq0 = .false.
  705
  706
  707
  708                  DO i = 0, nsl-1
  709                     s( isbeg+i ) = abs( s( isbeg+i ) )
  710                  END DO
  711
  712
  713
  714                  isbeg = isbeg + nsl
  715                  irowz = irowz + ntgk
  716                  icolz = icolz + nsl
  717                  irowu = irowz
  718                  irowv = irowz + 1
  719                  isplt = idptr + 1
  720                  ns = ns + nsl
  721                  nru = 0
  722                  nrv = 0
  723               END IF 
  724               IF( irowz.LT.n*2 .AND. wantz ) THEN
  725                  z( 1:irowz-1, icolz ) = zero
  726               END IF
  727            END DO 
  728            IF( split .AND. wantz ) THEN
  729
  730
  731
  732
  733               z( idbeg:idend-ntgk+1,isbeg-1 ) =
  734     $         z( idbeg:idend-ntgk+1,isbeg-1 ) +
  735     $         z( idbeg:idend-ntgk+1,n+1 )
  736               z( idbeg:idend-ntgk+1,n+1 ) = 0
  737            END IF
  738            irowv = irowv - 1
  739            irowu = irowu + 1
  740            idbeg = ieptr + 1
  741            sveq0 = .false.
  742            split = .false.
  743         END IF 
  744      END DO 
  745
  746
  747
  748
  749      DO i = 1, ns-1
  750         k = 1
  751         smin = s( 1 )
  752         DO j = 2, ns + 1 - i
  753            IF( s( j ).LE.smin ) THEN
  754               k = j
  755               smin = s( j )
  756            END IF
  757         END DO
  758         IF( k.NE.ns+1-i ) THEN
  759            s( k ) = s( ns+1-i )
  760            s( ns+1-i ) = smin
  761            IF( wantz ) 
CALL dswap( n*2, z( 1,k ), 1, z( 1,ns+1-i ),
 
  762     $          1 )
  763         END IF
  764      END DO
  765
  766
  767
  768      IF( indsv ) THEN
  769         k = iu - il + 1
  770         IF( k.LT.ns ) THEN
  771            s( k+1:ns ) = zero
  772            IF( wantz ) z( 1:n*2,k+1:ns ) = zero
  773            ns = k
  774         END IF
  775      END IF
  776
  777
  778
  779
  780      IF( wantz ) THEN
  781      DO i = 1, ns
  782         CALL dcopy( n*2, z( 1,i ), 1, work, 1 )
 
  783         IF( lower ) THEN
  784            CALL dcopy( n, work( 2 ), 2, z( n+1,i ), 1 )
 
  785            CALL dcopy( n, work( 1 ), 2, z( 1  ,i ), 1 )
 
  786         ELSE
  787            CALL dcopy( n, work( 2 ), 2, z( 1  ,i ), 1 )
 
  788            CALL dcopy( n, work( 1 ), 2, z( n+1,i ), 1 )
 
  789         END IF
  790      END DO
  791      END IF
  792
  793      RETURN
  794
  795
  796
subroutine xerbla(srname, info)
subroutine daxpy(n, da, dx, incx, dy, incy)
DAXPY
subroutine dcopy(n, dx, incx, dy, incy)
DCOPY
double precision function ddot(n, dx, incx, dy, incy)
DDOT
integer function idamax(n, dx, incx)
IDAMAX
double precision function dlamch(cmach)
DLAMCH
subroutine dlaset(uplo, m, n, alpha, beta, a, lda)
DLASET initializes the off-diagonal elements and the diagonal elements of a matrix to given values.
logical function lsame(ca, cb)
LSAME
real(wp) function dnrm2(n, x, incx)
DNRM2
subroutine dscal(n, da, dx, incx)
DSCAL
subroutine dstevx(jobz, range, n, d, e, vl, vu, il, iu, abstol, m, w, z, ldz, work, iwork, ifail, info)
DSTEVX computes the eigenvalues and, optionally, the left and/or right eigenvectors for OTHER matrice...
subroutine dswap(n, dx, incx, dy, incy)
DSWAP