1       SUBROUTINE DSTEDC( COMPZ, N, D, E, Z, LDZ, WORK, LWORK, IWORK,
  2      $                   LIWORK, INFO )
  3 *
  4 *  -- LAPACK driver routine (version 3.2) --
  5 *  -- LAPACK is a software package provided by Univ. of Tennessee,    --
  6 *  -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--
  7 *     November 2006
  8 *
  9 *     .. Scalar Arguments ..
 10       CHARACTER          COMPZ
 11       INTEGER            INFO, LDZ, LIWORK, LWORK, N
 12 *     ..
 13 *     .. Array Arguments ..
 14       INTEGER            IWORK( * )
 15       DOUBLE PRECISION   D( * ), E( * ), WORK( * ), Z( LDZ, * )
 16 *     ..
 17 *
 18 *  Purpose
 19 *  =======
 20 *
 21 *  DSTEDC computes all eigenvalues and, optionally, eigenvectors of a
 22 *  symmetric tridiagonal matrix using the divide and conquer method.
 23 *  The eigenvectors of a full or band real symmetric matrix can also be
 24 *  found if DSYTRD or DSPTRD or DSBTRD has been used to reduce this
 25 *  matrix to tridiagonal form.
 26 *
 27 *  This code makes very mild assumptions about floating point
 28 *  arithmetic. It will work on machines with a guard digit in
 29 *  add/subtract, or on those binary machines without guard digits
 30 *  which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or Cray-2.
 31 *  It could conceivably fail on hexadecimal or decimal machines
 32 *  without guard digits, but we know of none.  See DLAED3 for details.
 33 *
 34 *  Arguments
 35 *  =========
 36 *
 37 *  COMPZ   (input) CHARACTER*1
 38 *          = 'N':  Compute eigenvalues only.
 39 *          = 'I':  Compute eigenvectors of tridiagonal matrix also.
 40 *          = 'V':  Compute eigenvectors of original dense symmetric
 41 *                  matrix also.  On entry, Z contains the orthogonal
 42 *                  matrix used to reduce the original matrix to
 43 *                  tridiagonal form.
 44 *
 45 *  N       (input) INTEGER
 46 *          The dimension of the symmetric tridiagonal matrix.  N >= 0.
 47 *
 48 *  D       (input/output) DOUBLE PRECISION array, dimension (N)
 49 *          On entry, the diagonal elements of the tridiagonal matrix.
 50 *          On exit, if INFO = 0, the eigenvalues in ascending order.
 51 *
 52 *  E       (input/output) DOUBLE PRECISION array, dimension (N-1)
 53 *          On entry, the subdiagonal elements of the tridiagonal matrix.
 54 *          On exit, E has been destroyed.
 55 *
 56 *  Z       (input/output) DOUBLE PRECISION array, dimension (LDZ,N)
 57 *          On entry, if COMPZ = 'V', then Z contains the orthogonal
 58 *          matrix used in the reduction to tridiagonal form.
 59 *          On exit, if INFO = 0, then if COMPZ = 'V', Z contains the
 60 *          orthonormal eigenvectors of the original symmetric matrix,
 61 *          and if COMPZ = 'I', Z contains the orthonormal eigenvectors
 62 *          of the symmetric tridiagonal matrix.
 63 *          If  COMPZ = 'N', then Z is not referenced.
 64 *
 65 *  LDZ     (input) INTEGER
 66 *          The leading dimension of the array Z.  LDZ >= 1.
 67 *          If eigenvectors are desired, then LDZ >= max(1,N).
 68 *
 69 *  WORK    (workspace/output) DOUBLE PRECISION array,
 70 *                                         dimension (LWORK)
 71 *          On exit, if INFO = 0, WORK(1) returns the optimal LWORK.
 72 *
 73 *  LWORK   (input) INTEGER
 74 *          The dimension of the array WORK.
 75 *          If COMPZ = 'N' or N <= 1 then LWORK must be at least 1.
 76 *          If COMPZ = 'V' and N > 1 then LWORK must be at least
 77 *                         ( 1 + 3*N + 2*N*lg N + 3*N**2 ),
 78 *                         where lg( N ) = smallest integer k such
 79 *                         that 2**k >= N.
 80 *          If COMPZ = 'I' and N > 1 then LWORK must be at least
 81 *                         ( 1 + 4*N + N**2 ).
 82 *          Note that for COMPZ = 'I' or 'V', then if N is less than or
 83 *          equal to the minimum divide size, usually 25, then LWORK need
 84 *          only be max(1,2*(N-1)).
 85 *
 86 *          If LWORK = -1, then a workspace query is assumed; the routine
 87 *          only calculates the optimal size of the WORK array, returns
 88 *          this value as the first entry of the WORK array, and no error
 89 *          message related to LWORK is issued by XERBLA.
 90 *
 91 *  IWORK   (workspace/output) INTEGER array, dimension (MAX(1,LIWORK))
 92 *          On exit, if INFO = 0, IWORK(1) returns the optimal LIWORK.
 93 *
 94 *  LIWORK  (input) INTEGER
 95 *          The dimension of the array IWORK.
 96 *          If COMPZ = 'N' or N <= 1 then LIWORK must be at least 1.
 97 *          If COMPZ = 'V' and N > 1 then LIWORK must be at least
 98 *                         ( 6 + 6*N + 5*N*lg N ).
 99 *          If COMPZ = 'I' and N > 1 then LIWORK must be at least
100 *                         ( 3 + 5*N ).
101 *          Note that for COMPZ = 'I' or 'V', then if N is less than or
102 *          equal to the minimum divide size, usually 25, then LIWORK
103 *          need only be 1.
104 *
105 *          If LIWORK = -1, then a workspace query is assumed; the
106 *          routine only calculates the optimal size of the IWORK array,
107 *          returns this value as the first entry of the IWORK array, and
108 *          no error message related to LIWORK is issued by XERBLA.
109 *
110 *  INFO    (output) INTEGER
111 *          = 0:  successful exit.
112 *          < 0:  if INFO = -i, the i-th argument had an illegal value.
113 *          > 0:  The algorithm failed to compute an eigenvalue while
114 *                working on the submatrix lying in rows and columns
115 *                INFO/(N+1) through mod(INFO,N+1).
116 *
117 *  Further Details
118 *  ===============
119 *
120 *  Based on contributions by
121 *     Jeff Rutter, Computer Science Division, University of California
122 *     at Berkeley, USA
123 *  Modified by Francoise Tisseur, University of Tennessee.
124 *
125 *  =====================================================================
126 *
127 *     .. Parameters ..
128       DOUBLE PRECISION   ZERO, ONE, TWO
129       PARAMETER          ( ZERO = 0.0D0, ONE = 1.0D0, TWO = 2.0D0 )
130 *     ..
131 *     .. Local Scalars ..
132       LOGICAL            LQUERY
133       INTEGER            FINISH, I, ICOMPZ, II, J, K, LGN, LIWMIN,
134      $                   LWMIN, M, SMLSIZ, START, STOREZ, STRTRW
135       DOUBLE PRECISION   EPS, ORGNRM, P, TINY
136 *     ..
137 *     .. External Functions ..
138       LOGICAL            LSAME
139       INTEGER            ILAENV
140       DOUBLE PRECISION   DLAMCH, DLANST
141       EXTERNAL           LSAME, ILAENV, DLAMCH, DLANST
142 *     ..
143 *     .. External Subroutines ..
144       EXTERNAL           DGEMM, DLACPY, DLAED0, DLASCL, DLASET, DLASRT,
145      $                   DSTEQR, DSTERF, DSWAP, XERBLA
146 *     ..
147 *     .. Intrinsic Functions ..
148       INTRINSIC          ABSDBLEINTLOGMAXMODSQRT
149 *     ..
150 *     .. Executable Statements ..
151 *
152 *     Test the input parameters.
153 *
154       INFO = 0
155       LQUERY = ( LWORK.EQ.-1 .OR. LIWORK.EQ.-1 )
156 *
157       IF( LSAME( COMPZ, 'N' ) ) THEN
158          ICOMPZ = 0
159       ELSE IF( LSAME( COMPZ, 'V' ) ) THEN
160          ICOMPZ = 1
161       ELSE IF( LSAME( COMPZ, 'I' ) ) THEN
162          ICOMPZ = 2
163       ELSE
164          ICOMPZ = -1
165       END IF
166       IF( ICOMPZ.LT.0 ) THEN
167          INFO = -1
168       ELSE IF( N.LT.0 ) THEN
169          INFO = -2
170       ELSE IF( ( LDZ.LT.1 ) .OR.
171      $         ( ICOMPZ.GT.0 .AND. LDZ.LT.MAX1, N ) ) ) THEN
172          INFO = -6
173       END IF
174 *
175       IF( INFO.EQ.0 ) THEN
176 *
177 *        Compute the workspace requirements
178 *
179          SMLSIZ = ILAENV( 9'DSTEDC'' '0000 )
180          IF( N.LE.1 .OR. ICOMPZ.EQ.0 ) THEN
181             LIWMIN = 1
182             LWMIN = 1
183          ELSE IF( N.LE.SMLSIZ ) THEN
184             LIWMIN = 1
185             LWMIN = 2*( N - 1 )
186          ELSE
187             LGN = INTLOGDBLE( N ) )/LOG( TWO ) )
188             IF2**LGN.LT.N )
189      $         LGN = LGN + 1
190             IF2**LGN.LT.N )
191      $         LGN = LGN + 1
192             IF( ICOMPZ.EQ.1 ) THEN
193                LWMIN = 1 + 3*+ 2*N*LGN + 3*N**2
194                LIWMIN = 6 + 6*+ 5*N*LGN
195             ELSE IF( ICOMPZ.EQ.2 ) THEN
196                LWMIN = 1 + 4*+ N**2
197                LIWMIN = 3 + 5*N
198             END IF
199          END IF
200          WORK( 1 ) = LWMIN
201          IWORK( 1 ) = LIWMIN
202 *
203          IF( LWORK.LT.LWMIN .AND. .NOT. LQUERY ) THEN
204             INFO = -8
205          ELSE IF( LIWORK.LT.LIWMIN .AND. .NOT. LQUERY ) THEN
206             INFO = -10
207          END IF
208       END IF
209 *
210       IF( INFO.NE.0 ) THEN
211          CALL XERBLA( 'DSTEDC'-INFO )
212          RETURN
213       ELSE IF (LQUERY) THEN
214          RETURN
215       END IF
216 *
217 *     Quick return if possible
218 *
219       IF( N.EQ.0 )
220      $   RETURN
221       IF( N.EQ.1 ) THEN
222          IF( ICOMPZ.NE.0 )
223      $      Z( 11 ) = ONE
224          RETURN
225       END IF
226 *
227 *     If the following conditional clause is removed, then the routine
228 *     will use the Divide and Conquer routine to compute only the
229 *     eigenvalues, which requires (3N + 3N**2) real workspace and
230 *     (2 + 5N + 2N lg(N)) integer workspace.
231 *     Since on many architectures DSTERF is much faster than any other
232 *     algorithm for finding eigenvalues only, it is used here
233 *     as the default. If the conditional clause is removed, then
234 *     information on the size of workspace needs to be changed.
235 *
236 *     If COMPZ = 'N', use DSTERF to compute the eigenvalues.
237 *
238       IF( ICOMPZ.EQ.0 ) THEN
239          CALL DSTERF( N, D, E, INFO )
240          GO TO 50
241       END IF
242 *
243 *     If N is smaller than the minimum divide size (SMLSIZ+1), then
244 *     solve the problem with another solver.
245 *
246       IF( N.LE.SMLSIZ ) THEN
247 *
248          CALL DSTEQR( COMPZ, N, D, E, Z, LDZ, WORK, INFO )
249 *
250       ELSE
251 *
252 *        If COMPZ = 'V', the Z matrix must be stored elsewhere for later
253 *        use.
254 *
255          IF( ICOMPZ.EQ.1 ) THEN
256             STOREZ = 1 + N*N
257          ELSE
258             STOREZ = 1
259          END IF
260 *
261          IF( ICOMPZ.EQ.2 ) THEN
262             CALL DLASET( 'Full', N, N, ZERO, ONE, Z, LDZ )
263          END IF
264 *
265 *        Scale.
266 *
267          ORGNRM = DLANST( 'M', N, D, E )
268          IF( ORGNRM.EQ.ZERO )
269      $      GO TO 50
270 *
271          EPS = DLAMCH( 'Epsilon' )
272 *
273          START = 1
274 *
275 *        while ( START <= N )
276 *
277    10    CONTINUE
278          IF( START.LE.N ) THEN
279 *
280 *           Let FINISH be the position of the next subdiagonal entry
281 *           such that E( FINISH ) <= TINY or FINISH = N if no such
282 *           subdiagonal exists.  The matrix identified by the elements
283 *           between START and FINISH constitutes an independent
284 *           sub-problem.
285 *
286             FINISH = START
287    20       CONTINUE
288             IF( FINISH.LT.N ) THEN
289                TINY = EPS*SQRTABS( D( FINISH ) ) )*
290      $                    SQRTABS( D( FINISH+1 ) ) )
291                IFABS( E( FINISH ) ).GT.TINY ) THEN
292                   FINISH = FINISH + 1
293                   GO TO 20
294                END IF
295             END IF
296 *
297 *           (Sub) Problem determined.  Compute its size and solve it.
298 *
299             M = FINISH - START + 1
300             IF( M.EQ.1 ) THEN
301                START = FINISH + 1
302                GO TO 10
303             END IF
304             IF( M.GT.SMLSIZ ) THEN
305 *
306 *              Scale.
307 *
308                ORGNRM = DLANST( 'M', M, D( START ), E( START ) )
309                CALL DLASCL( 'G'00, ORGNRM, ONE, M, 1, D( START ), M,
310      $                      INFO )
311                CALL DLASCL( 'G'00, ORGNRM, ONE, M-11, E( START ),
312      $                      M-1, INFO )
313 *
314                IF( ICOMPZ.EQ.1 ) THEN
315                   STRTRW = 1
316                ELSE
317                   STRTRW = START
318                END IF
319                CALL DLAED0( ICOMPZ, N, M, D( START ), E( START ),
320      $                      Z( STRTRW, START ), LDZ, WORK( 1 ), N,
321      $                      WORK( STOREZ ), IWORK, INFO )
322                IF( INFO.NE.0 ) THEN
323                   INFO = ( INFO / ( M+1 )+START-1 )*( N+1 ) +
324      $                   MOD( INFO, ( M+1 ) ) + START - 1
325                   GO TO 50
326                END IF
327 *
328 *              Scale back.
329 *
330                CALL DLASCL( 'G'00, ONE, ORGNRM, M, 1, D( START ), M,
331      $                      INFO )
332 *
333             ELSE
334                IF( ICOMPZ.EQ.1 ) THEN
335 *
336 *                 Since QR won't update a Z matrix which is larger than
337 *                 the length of D, we must solve the sub-problem in a
338 *                 workspace and then multiply back into Z.
339 *
340                   CALL DSTEQR( 'I', M, D( START ), E( START ), WORK, M,
341      $                         WORK( M*M+1 ), INFO )
342                   CALL DLACPY( 'A', N, M, Z( 1, START ), LDZ,
343      $                         WORK( STOREZ ), N )
344                   CALL DGEMM( 'N''N', N, M, M, ONE,
345      $                        WORK( STOREZ ), N, WORK, M, ZERO,
346      $                        Z( 1, START ), LDZ )
347                ELSE IF( ICOMPZ.EQ.2 ) THEN
348                   CALL DSTEQR( 'I', M, D( START ), E( START ),
349      $                         Z( START, START ), LDZ, WORK, INFO )
350                ELSE
351                   CALL DSTERF( M, D( START ), E( START ), INFO )
352                END IF
353                IF( INFO.NE.0 ) THEN
354                   INFO = START*( N+1 ) + FINISH
355                   GO TO 50
356                END IF
357             END IF
358 *
359             START = FINISH + 1
360             GO TO 10
361          END IF
362 *
363 *        endwhile
364 *
365 *        If the problem split any number of times, then the eigenvalues
366 *        will not be properly ordered.  Here we permute the eigenvalues
367 *        (and the associated eigenvectors) into ascending order.
368 *
369          IF( M.NE.N ) THEN
370             IF( ICOMPZ.EQ.0 ) THEN
371 *
372 *              Use Quick Sort
373 *
374                CALL DLASRT( 'I', N, D, INFO )
375 *
376             ELSE
377 *
378 *              Use Selection Sort to minimize swaps of eigenvectors
379 *
380                DO 40 II = 2, N
381                   I = II - 1
382                   K = I
383                   P = D( I )
384                   DO 30 J = II, N
385                      IF( D( J ).LT.P ) THEN
386                         K = J
387                         P = D( J )
388                      END IF
389    30             CONTINUE
390                   IF( K.NE.I ) THEN
391                      D( K ) = D( I )
392                      D( I ) = P
393                      CALL DSWAP( N, Z( 1, I ), 1, Z( 1, K ), 1 )
394                   END IF
395    40          CONTINUE
396             END IF
397          END IF
398       END IF
399 *
400    50 CONTINUE
401       WORK( 1 ) = LWMIN
402       IWORK( 1 ) = LIWMIN
403 *
404       RETURN
405 *
406 *     End of DSTEDC
407 *
408       END