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