1      SUBROUTINE ZHEEVR( JOBZ, RANGE, UPLO, N, A, LDA, VL, VU, IL, IU,
2     $                   ABSTOL, M, W, Z, LDZ, ISUPPZ, WORK, LWORK,
3     $                   RWORK, LRWORK, IWORK, LIWORK, INFO )
4*
5*  -- LAPACK driver routine (version 3.0) --
6*     Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
7*     Courant Institute, Argonne National Lab, and Rice University
8*     March 20, 2000
9*
10*     .. Scalar Arguments ..
11      CHARACTER          JOBZ, RANGE, UPLO
12      INTEGER            IL, INFO, IU, LDA, LDZ, LIWORK, LRWORK, LWORK,
13     $                   M, N
14      DOUBLE PRECISION   ABSTOL, VL, VU
15*     ..
16*     .. Array Arguments ..
17      INTEGER            ISUPPZ( * ), IWORK( * )
18      DOUBLE PRECISION   RWORK( * ), W( * )
19      COMPLEX*16         A( LDA, * ), WORK( * ), Z( LDZ, * )
20*     ..
21*
22*  Purpose
23*  =======
24*
25*  ZHEEVR computes selected eigenvalues and, optionally, eigenvectors
26*  of a complex Hermitian matrix T.  Eigenvalues and eigenvectors can
27*  be selected by specifying either a range of values or a range of
28*  indices for the desired eigenvalues.
29*
30*  Whenever possible, ZHEEVR calls ZSTEGR to compute the
31*  eigenspectrum using Relatively Robust Representations.  ZSTEGR
32*  computes eigenvalues by the dqds algorithm, while orthogonal
33*  eigenvectors are computed from various "good" L D L^T representations
34*  (also known as Relatively Robust Representations). Gram-Schmidt
35*  orthogonalization is avoided as far as possible. More specifically,
36*  the various steps of the algorithm are as follows. For the i-th
37*  unreduced block of T,
38*     (a) Compute T - sigma_i = L_i D_i L_i^T, such that L_i D_i L_i^T
39*          is a relatively robust representation,
40*     (b) Compute the eigenvalues, lambda_j, of L_i D_i L_i^T to high
41*         relative accuracy by the dqds algorithm,
42*     (c) If there is a cluster of close eigenvalues, "choose" sigma_i
43*         close to the cluster, and go to step (a),
44*     (d) Given the approximate eigenvalue lambda_j of L_i D_i L_i^T,
45*         compute the corresponding eigenvector by forming a
46*         rank-revealing twisted factorization.
47*  The desired accuracy of the output can be specified by the input
48*  parameter ABSTOL.
49*
50*  For more details, see "A new O(n^2) algorithm for the symmetric
51*  tridiagonal eigenvalue/eigenvector problem", by Inderjit Dhillon,
52*  Computer Science Division Technical Report No. UCB//CSD-97-971,
53*  UC Berkeley, May 1997.
54*
55*
56*  Note 1 : ZHEEVR calls ZSTEGR when the full spectrum is requested
57*  on machines which conform to the ieee-754 floating point standard.
58*  ZHEEVR calls DSTEBZ and ZSTEIN on non-ieee machines and
59*  when partial spectrum requests are made.
60*
61*  Normal execution of ZSTEGR may create NaNs and infinities and
62*  hence may abort due to a floating point exception in environments
63*  which do not handle NaNs and infinities in the ieee standard default
64*  manner.
65*
66*  Arguments
67*  =========
68*
69*  JOBZ    (input) CHARACTER*1
70*          = 'N':  Compute eigenvalues only;
71*          = 'V':  Compute eigenvalues and eigenvectors.
72*
73*  RANGE   (input) CHARACTER*1
74*          = 'A': all eigenvalues will be found.
75*          = 'V': all eigenvalues in the half-open interval (VL,VU]
76*                 will be found.
77*          = 'I': the IL-th through IU-th eigenvalues will be found.
78********** For RANGE = 'V' or 'I' and IU - IL < N - 1, DSTEBZ and
79********** ZSTEIN are called
80*
81*  UPLO    (input) CHARACTER*1
82*          = 'U':  Upper triangle of A is stored;
83*          = 'L':  Lower triangle of A is stored.
84*
85*  N       (input) INTEGER
86*          The order of the matrix A.  N >= 0.
87*
88*  A       (input/output) COMPLEX*16 array, dimension (LDA, N)
89*          On entry, the Hermitian matrix A.  If UPLO = 'U', the
90*          leading N-by-N upper triangular part of A contains the
91*          upper triangular part of the matrix A.  If UPLO = 'L',
92*          the leading N-by-N lower triangular part of A contains
93*          the lower triangular part of the matrix A.
94*          On exit, the lower triangle (if UPLO='L') or the upper
95*          triangle (if UPLO='U') of A, including the diagonal, is
96*          destroyed.
97*
98*  LDA     (input) INTEGER
99*          The leading dimension of the array A.  LDA >= max(1,N).
100*
101*  VL      (input) DOUBLE PRECISION
102*  VU      (input) DOUBLE PRECISION
103*          If RANGE='V', the lower and upper bounds of the interval to
104*          be searched for eigenvalues. VL < VU.
105*          Not referenced if RANGE = 'A' or 'I'.
106*
107*  IL      (input) INTEGER
108*  IU      (input) INTEGER
109*          If RANGE='I', the indices (in ascending order) of the
110*          smallest and largest eigenvalues to be returned.
111*          1 <= IL <= IU <= N, if N > 0; IL = 1 and IU = 0 if N = 0.
112*          Not referenced if RANGE = 'A' or 'V'.
113*
114*  ABSTOL  (input) DOUBLE PRECISION
115*          The absolute error tolerance for the eigenvalues.
116*          An approximate eigenvalue is accepted as converged
117*          when it is determined to lie in an interval [a,b]
118*          of width less than or equal to
119*
120*                  ABSTOL + EPS *   max( |a|,|b| ) ,
121*
122*          where EPS is the machine precision.  If ABSTOL is less than
123*          or equal to zero, then  EPS*|T|  will be used in its place,
124*          where |T| is the 1-norm of the tridiagonal matrix obtained
125*          by reducing A to tridiagonal form.
126*
127*          See "Computing Small Singular Values of Bidiagonal Matrices
128*          with Guaranteed High Relative Accuracy," by Demmel and
129*          Kahan, LAPACK Working Note #3.
130*
131*          If high relative accuracy is important, set ABSTOL to
132*          DLAMCH( 'Safe minimum' ).  Doing so will guarantee that
133*          eigenvalues are computed to high relative accuracy when
134*          possible in future releases.  The current code does not
135*          make any guarantees about high relative accuracy, but
136*          furutre releases will. See J. Barlow and J. Demmel,
137*          "Computing Accurate Eigensystems of Scaled Diagonally
138*          Dominant Matrices", LAPACK Working Note #7, for a discussion
139*          of which matrices define their eigenvalues to high relative
140*          accuracy.
141*
142*  M       (output) INTEGER
143*          The total number of eigenvalues found.  0 <= M <= N.
144*          If RANGE = 'A', M = N, and if RANGE = 'I', M = IU-IL+1.
145*
146*  W       (output) DOUBLE PRECISION array, dimension (N)
147*          The first M elements contain the selected eigenvalues in
148*          ascending order.
149*
150*  Z       (output) COMPLEX*16 array, dimension (LDZ, max(1,M))
151*          If JOBZ = 'V', then if INFO = 0, the first M columns of Z
152*          contain the orthonormal eigenvectors of the matrix A
153*          corresponding to the selected eigenvalues, with the i-th
154*          column of Z holding the eigenvector associated with W(i).
155*          If JOBZ = 'N', then Z is not referenced.
156*          Note: the user must ensure that at least max(1,M) columns are
157*          supplied in the array Z; if RANGE = 'V', the exact value of M
158*          is not known in advance and an upper bound must be used.
159*
160*  LDZ     (input) INTEGER
161*          The leading dimension of the array Z.  LDZ >= 1, and if
162*          JOBZ = 'V', LDZ >= max(1,N).
163*
164*  ISUPPZ  (output) INTEGER ARRAY, dimension ( 2*max(1,M) )
165*          The support of the eigenvectors in Z, i.e., the indices
166*          indicating the nonzero elements in Z. The i-th eigenvector
167*          is nonzero only in elements ISUPPZ( 2*i-1 ) through
168*          ISUPPZ( 2*i ).
169********** Implemented only for RANGE = 'A' or 'I' and IU - IL = N - 1
170*
171*  WORK    (workspace/output) COMPLEX*16 array, dimension (LWORK)
172*          On exit, if INFO = 0, WORK(1) returns the optimal LWORK.
173*
174*  LWORK   (input) INTEGER
175*          The length of the array WORK.  LWORK >= max(1,2*N).
176*          For optimal efficiency, LWORK >= (NB+1)*N,
177*          where NB is the max of the blocksize for ZHETRD and for
178*          ZUNMTR as returned by ILAENV.
179*
180*          If LWORK = -1, then a workspace query is assumed; the routine
181*          only calculates the optimal size of the WORK array, returns
182*          this value as the first entry of the WORK array, and no error
183*          message related to LWORK is issued by XERBLA.
184*
185*  RWORK   (workspace/output) DOUBLE PRECISION array, dimension (LRWORK)
186*          On exit, if INFO = 0, RWORK(1) returns the optimal
187*          (and minimal) LRWORK.
188*
189* LRWORK  (input) INTEGER
190*         The length of the array RWORK.  LRWORK >= max(1,24*N).
191*
192*         If LRWORK = -1, then a workspace query is assumed; the routine
193*         only calculates the optimal size of the RWORK array, returns
194*         this value as the first entry of the RWORK array, and no error
195*         message related to LRWORK is issued by XERBLA.
196*
197*  IWORK   (workspace/output) INTEGER array, dimension (LIWORK)
198*          On exit, if INFO = 0, IWORK(1) returns the optimal
199*          (and minimal) LIWORK.
200*
201* LIWORK  (input) INTEGER
202*         The dimension of the array IWORK.  LIWORK >= max(1,10*N).
203*
204*         If LIWORK = -1, then a workspace query is assumed; the
205*         routine only calculates the optimal size of the IWORK array,
206*         returns this value as the first entry of the IWORK array, and
207*         no error message related to LIWORK is issued by XERBLA.
208*
209*  INFO    (output) INTEGER
210*          = 0:  successful exit
211*          < 0:  if INFO = -i, the i-th argument had an illegal value
212*          > 0:  Internal error
213*
214*  Further Details
215*  ===============
216*
217*  Based on contributions by
218*     Inderjit Dhillon, IBM Almaden, USA
219*     Osni Marques, LBNL/NERSC, USA
220*     Ken Stanley, Computer Science Division, University of
221*       California at Berkeley, USA
222*
223* =====================================================================
224*
225*     .. Parameters ..
226      DOUBLE PRECISION   ZERO, ONE
227      PARAMETER          ( ZERO = 0.0D+0, ONE = 1.0D+0 )
228*     ..
229*     .. Local Scalars ..
230      LOGICAL            ALLEIG, INDEIG, LOWER, LQUERY, VALEIG, WANTZ
231      CHARACTER          ORDER
232      INTEGER            I, IEEEOK, IINFO, IMAX, INDIBL, INDIFL, INDISP,
233     $                   INDIWO, INDRD, INDRDD, INDRE, INDREE, INDRWK,
234     $                   INDTAU, INDWK, INDWKN, ISCALE, ITMP1, J, JJ,
235     $                   LIWMIN, LLWORK, LLWRKN, LRWMIN, LWKOPT, LWMIN,
236     $                   NB, NSPLIT
237      DOUBLE PRECISION   ABSTLL, ANRM, BIGNUM, EPS, RMAX, RMIN, SAFMIN,
238     $                   SIGMA, SMLNUM, TMP1, VLL, VUU
239*     ..
240*     .. External Functions ..
241      LOGICAL            LSAME
242      INTEGER            ILAENV
243      DOUBLE PRECISION   DLAMCH, ZLANSY
244      EXTERNAL           LSAME, ILAENV, DLAMCH, ZLANSY
245*     ..
246*     .. External Subroutines ..
247      EXTERNAL           DCOPY, DSCAL, DSTEBZ, DSTERF, XERBLA, ZDSCAL,
248     $                   ZHETRD, ZSTEGR, ZSTEIN, ZSWAP, ZUNMTR
249*     ..
250*     .. Intrinsic Functions ..
251      INTRINSIC          DBLE, MAX, MIN, SQRT
252*     ..
253*     .. Executable Statements ..
254*
255*     Test the input parameters.
256*
257      IEEEOK = ILAENV( 10, 'ZHEEVR', 'N', 1, 2, 3, 4 )
258*
259      LOWER = LSAME( UPLO, 'L' )
260      WANTZ = LSAME( JOBZ, 'V' )
261      ALLEIG = LSAME( RANGE, 'A' )
262      VALEIG = LSAME( RANGE, 'V' )
263      INDEIG = LSAME( RANGE, 'I' )
264*
265      LQUERY = ( ( LWORK.EQ.-1 ) .OR. ( LRWORK.EQ.-1 ) .OR.
266     $         ( LIWORK.EQ.-1 ) )
267*
268      LRWMIN = MAX( 1, 24*N )
269      LIWMIN = MAX( 1, 10*N )
270      LWMIN = MAX( 1, 2*N )
271*
272      INFO = 0
273      IF( .NOT.( WANTZ .OR. LSAME( JOBZ, 'N' ) ) ) THEN
274         INFO = -1
275      ELSE IF( .NOT.( ALLEIG .OR. VALEIG .OR. INDEIG ) ) THEN
276         INFO = -2
277      ELSE IF( .NOT.( LOWER .OR. LSAME( UPLO, 'U' ) ) ) THEN
278         INFO = -3
279      ELSE IF( N.LT.0 ) THEN
280         INFO = -4
281      ELSE IF( LDA.LT.MAX( 1, N ) ) THEN
282         INFO = -6
283      ELSE
284         IF( VALEIG ) THEN
285            IF( N.GT.0 .AND. VU.LE.VL )
286     $         INFO = -8
287         ELSE IF( INDEIG ) THEN
288            IF( IL.LT.1 .OR. IL.GT.MAX( 1, N ) ) THEN
289               INFO = -9
290            ELSE IF( IU.LT.MIN( N, IL ) .OR. IU.GT.N ) THEN
291               INFO = -10
292            END IF
293         END IF
294      END IF
295      IF( INFO.EQ.0 ) THEN
296         IF( LDZ.LT.1 .OR. ( WANTZ .AND. LDZ.LT.N ) ) THEN
297            INFO = -15
298         ELSE IF( LWORK.LT.LWMIN .AND. .NOT.LQUERY ) THEN
299            INFO = -18
300         ELSE IF( LRWORK.LT.LRWMIN .AND. .NOT.LQUERY ) THEN
301            INFO = -20
302         ELSE IF( LIWORK.LT.LIWMIN .AND. .NOT.LQUERY ) THEN
303            INFO = -22
304         END IF
305      END IF
306*
307      IF( INFO.EQ.0 ) THEN
308         NB = ILAENV( 1, 'ZHETRD', UPLO, N, -1, -1, -1 )
309         NB = MAX( NB, ILAENV( 1, 'ZUNMTR', UPLO, N, -1, -1, -1 ) )
310         LWKOPT = MAX( ( NB+1 )*N, LWMIN )
311         WORK( 1 ) = LWKOPT
312         RWORK( 1 ) = LRWMIN
313         IWORK( 1 ) = LIWMIN
314      END IF
315*
316      IF( INFO.NE.0 ) THEN
317         CALL XERBLA( 'ZHEEVR', -INFO )
318         RETURN
319      ELSE IF( LQUERY ) THEN
320         RETURN
321      END IF
322*
323*     Quick return if possible
324*
325      M = 0
326      IF( N.EQ.0 ) THEN
327         WORK( 1 ) = 1
328         RETURN
329      END IF
330*
331      IF( N.EQ.1 ) THEN
332         WORK( 1 ) = 7
333         IF( ALLEIG .OR. INDEIG ) THEN
334            M = 1
335            W( 1 ) = DBLE( A( 1, 1 ) )
336         ELSE
337            IF( VL.LT.DBLE( A( 1, 1 ) ) .AND. VU.GE.DBLE( A( 1, 1 ) ) )
338     $           THEN
339               M = 1
340               W( 1 ) = DBLE( A( 1, 1 ) )
341            END IF
342         END IF
343         IF( WANTZ )
344     $      Z( 1, 1 ) = ONE
345         RETURN
346      END IF
347*
348*     Get machine constants.
349*
350      SAFMIN = DLAMCH( 'Safe minimum' )
351      EPS = DLAMCH( 'Precision' )
352      SMLNUM = SAFMIN / EPS
353      BIGNUM = ONE / SMLNUM
354      RMIN = SQRT( SMLNUM )
355      RMAX = MIN( SQRT( BIGNUM ), ONE / SQRT( SQRT( SAFMIN ) ) )
356*
357*     Scale matrix to allowable range, if necessary.
358*
359      ISCALE = 0
360      ABSTLL = ABSTOL
361      VLL = VL
362      VUU = VU
363      ANRM = ZLANSY( 'M', UPLO, N, A, LDA, RWORK )
364      IF( ANRM.GT.ZERO .AND. ANRM.LT.RMIN ) THEN
365         ISCALE = 1
366         SIGMA = RMIN / ANRM
367      ELSE IF( ANRM.GT.RMAX ) THEN
368         ISCALE = 1
369         SIGMA = RMAX / ANRM
370      END IF
371      IF( ISCALE.EQ.1 ) THEN
372         IF( LOWER ) THEN
373            DO 10 J = 1, N
374               CALL ZDSCAL( N-J+1, SIGMA, A( J, J ), 1 )
375   10       CONTINUE
376         ELSE
377            DO 20 J = 1, N
378               CALL ZDSCAL( J, SIGMA, A( 1, J ), 1 )
379   20       CONTINUE
380         END IF
381         IF( ABSTOL.GT.0 )
382     $      ABSTLL = ABSTOL*SIGMA
383         IF( VALEIG ) THEN
384            VLL = VL*SIGMA
385            VUU = VU*SIGMA
386         END IF
387      END IF
388*
389*     Call ZHETRD to reduce Hermitian matrix to tridiagonal form.
390*
391      INDTAU = 1
392      INDWK = INDTAU + N
393*
394      INDRE = 1
395      INDRD = INDRE + N
396      INDREE = INDRD + N
397      INDRDD = INDREE + N
398      INDRWK = INDRDD + N
399      LLWORK = LWORK - INDWK + 1
400      CALL ZHETRD( UPLO, N, A, LDA, RWORK( INDRD ), RWORK( INDRE ),
401     $             WORK( INDTAU ), WORK( INDWK ), LLWORK, IINFO )
402*
403*     If all eigenvalues are desired
404*     then call DSTERF or ZSTEGR and ZUNMTR.
405*
406      IF( ( ALLEIG .OR. ( INDEIG .AND. IL.EQ.1 .AND. IU.EQ.N ) ) .AND.
407     $    IEEEOK.EQ.1 ) THEN
408         IF( .NOT.WANTZ ) THEN
409            CALL DCOPY( N, RWORK( INDRD ), 1, W, 1 )
410            CALL DCOPY( N-1, RWORK( INDRE ), 1, RWORK( INDREE ), 1 )
411            CALL DSTERF( N, W, RWORK( INDREE ), INFO )
412         ELSE
413            CALL DCOPY( N-1, RWORK( INDRE ), 1, RWORK( INDREE ), 1 )
414            CALL DCOPY( N, RWORK( INDRD ), 1, RWORK( INDRDD ), 1 )
415*
416            CALL ZSTEGR( JOBZ, 'A', N, RWORK( INDRDD ),
417     $                   RWORK( INDREE ), VL, VU, IL, IU, ABSTOL, M, W,
418     $                   Z, LDZ, ISUPPZ, RWORK( INDRWK ), LWORK, IWORK,
419     $                   LIWORK, INFO )
420*
421*
422*
423*        Apply unitary matrix used in reduction to tridiagonal
424*        form to eigenvectors returned by ZSTEIN.
425*
426            IF( WANTZ .AND. INFO.EQ.0 ) THEN
427               INDWKN = INDWK
428               LLWRKN = LWORK - INDWKN + 1
429               CALL ZUNMTR( 'L', UPLO, 'N', N, M, A, LDA,
430     $                      WORK( INDTAU ), Z, LDZ, WORK( INDWKN ),
431     $                      LLWRKN, IINFO )
432            END IF
433         END IF
434*
435*
436         IF( INFO.EQ.0 ) THEN
437            M = N
438            GO TO 30
439         END IF
440         INFO = 0
441      END IF
442*
443*     Otherwise, call DSTEBZ and, if eigenvectors are desired, ZSTEIN.
444*     Also call DSTEBZ and ZSTEIN if CSTEGR fails.
445*
446      IF( WANTZ ) THEN
447         ORDER = 'B'
448      ELSE
449         ORDER = 'E'
450      END IF
451      INDIFL = 1
452      INDIBL = INDIFL + N
453      INDISP = INDIBL + N
454      INDIWO = INDISP + N
455      CALL DSTEBZ( RANGE, ORDER, N, VLL, VUU, IL, IU, ABSTLL,
456     $             RWORK( INDRD ), RWORK( INDRE ), M, NSPLIT, W,
457     $             IWORK( INDIBL ), IWORK( INDISP ), RWORK( INDRWK ),
458     $             IWORK( INDIWO ), INFO )
459*
460      IF( WANTZ ) THEN
461         CALL ZSTEIN( N, RWORK( INDRD ), RWORK( INDRE ), M, W,
462     $                IWORK( INDIBL ), IWORK( INDISP ), Z, LDZ,
463     $                RWORK( INDRWK ), IWORK( INDIWO ), IWORK( INDIFL ),
464     $                INFO )
465*
466*        Apply unitary matrix used in reduction to tridiagonal
467*        form to eigenvectors returned by ZSTEIN.
468*
469         INDWKN = INDWK
470         LLWRKN = LWORK - INDWKN + 1
471         CALL ZUNMTR( 'L', UPLO, 'N', N, M, A, LDA, WORK( INDTAU ), Z,
472     $                LDZ, WORK( INDWKN ), LLWRKN, IINFO )
473      END IF
474*
475*     If matrix was scaled, then rescale eigenvalues appropriately.
476*
477   30 CONTINUE
478      IF( ISCALE.EQ.1 ) THEN
479         IF( INFO.EQ.0 ) THEN
480            IMAX = M
481         ELSE
482            IMAX = INFO - 1
483         END IF
484         CALL DSCAL( IMAX, ONE / SIGMA, W, 1 )
485      END IF
486*
487*     If eigenvalues are not in order, then sort them, along with
488*     eigenvectors.
489*
490      IF( WANTZ ) THEN
491         DO 50 J = 1, M - 1
492            I = 0
493            TMP1 = W( J )
494            DO 40 JJ = J + 1, M
495               IF( W( JJ ).LT.TMP1 ) THEN
496                  I = JJ
497                  TMP1 = W( JJ )
498               END IF
499   40       CONTINUE
500*
501            IF( I.NE.0 ) THEN
502               ITMP1 = IWORK( INDIBL+I-1 )
503               W( I ) = W( J )
504               IWORK( INDIBL+I-1 ) = IWORK( INDIBL+J-1 )
505               W( J ) = TMP1
506               IWORK( INDIBL+J-1 ) = ITMP1
507               CALL ZSWAP( N, Z( 1, I ), 1, Z( 1, J ), 1 )
508            END IF
509   50    CONTINUE
510      END IF
511*
512*     Set WORK(1) to optimal workspace size.
513*
514      WORK( 1 ) = LWKOPT
515      RWORK( 1 ) = LRWMIN
516      IWORK( 1 ) = LIWMIN
517*
518      RETURN
519*
520*     End of ZHEEVR
521*
522      END
523