1       SUBROUTINE DLAED0( ICOMPQ, QSIZ, N, D, E, Q, LDQ, QSTORE, LDQS,
  2      $                   WORK, IWORK, INFO )
  3 *
  4 *  -- LAPACK 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       INTEGER            ICOMPQ, INFO, LDQ, LDQS, N, QSIZ
 11 *     ..
 12 *     .. Array Arguments ..
 13       INTEGER            IWORK( * )
 14       DOUBLE PRECISION   D( * ), E( * ), Q( LDQ, * ), QSTORE( LDQS, * ),
 15      $                   WORK( * )
 16 *     ..
 17 *
 18 *  Purpose
 19 *  =======
 20 *
 21 *  DLAED0 computes all eigenvalues and corresponding eigenvectors of a
 22 *  symmetric tridiagonal matrix using the divide and conquer method.
 23 *
 24 *  Arguments
 25 *  =========
 26 *
 27 *  ICOMPQ  (input) INTEGER
 28 *          = 0:  Compute eigenvalues only.
 29 *          = 1:  Compute eigenvectors of original dense symmetric matrix
 30 *                also.  On entry, Q contains the orthogonal matrix used
 31 *                to reduce the original matrix to tridiagonal form.
 32 *          = 2:  Compute eigenvalues and eigenvectors of tridiagonal
 33 *                matrix.
 34 *
 35 *  QSIZ   (input) INTEGER
 36 *         The dimension of the orthogonal matrix used to reduce
 37 *         the full matrix to tridiagonal form.  QSIZ >= N if ICOMPQ = 1.
 38 *
 39 *  N      (input) INTEGER
 40 *         The dimension of the symmetric tridiagonal matrix.  N >= 0.
 41 *
 42 *  D      (input/output) DOUBLE PRECISION array, dimension (N)
 43 *         On entry, the main diagonal of the tridiagonal matrix.
 44 *         On exit, its eigenvalues.
 45 *
 46 *  E      (input) DOUBLE PRECISION array, dimension (N-1)
 47 *         The off-diagonal elements of the tridiagonal matrix.
 48 *         On exit, E has been destroyed.
 49 *
 50 *  Q      (input/output) DOUBLE PRECISION array, dimension (LDQ, N)
 51 *         On entry, Q must contain an N-by-N orthogonal matrix.
 52 *         If ICOMPQ = 0    Q is not referenced.
 53 *         If ICOMPQ = 1    On entry, Q is a subset of the columns of the
 54 *                          orthogonal matrix used to reduce the full
 55 *                          matrix to tridiagonal form corresponding to
 56 *                          the subset of the full matrix which is being
 57 *                          decomposed at this time.
 58 *         If ICOMPQ = 2    On entry, Q will be the identity matrix.
 59 *                          On exit, Q contains the eigenvectors of the
 60 *                          tridiagonal matrix.
 61 *
 62 *  LDQ    (input) INTEGER
 63 *         The leading dimension of the array Q.  If eigenvectors are
 64 *         desired, then  LDQ >= max(1,N).  In any case,  LDQ >= 1.
 65 *
 66 *  QSTORE (workspace) DOUBLE PRECISION array, dimension (LDQS, N)
 67 *         Referenced only when ICOMPQ = 1.  Used to store parts of
 68 *         the eigenvector matrix when the updating matrix multiplies
 69 *         take place.
 70 *
 71 *  LDQS   (input) INTEGER
 72 *         The leading dimension of the array QSTORE.  If ICOMPQ = 1,
 73 *         then  LDQS >= max(1,N).  In any case,  LDQS >= 1.
 74 *
 75 *  WORK   (workspace) DOUBLE PRECISION array,
 76 *         If ICOMPQ = 0 or 1, the dimension of WORK must be at least
 77 *                     1 + 3*N + 2*N*lg N + 2*N**2
 78 *                     ( lg( N ) = smallest integer k
 79 *                                 such that 2^k >= N )
 80 *         If ICOMPQ = 2, the dimension of WORK must be at least
 81 *                     4*N + N**2.
 82 *
 83 *  IWORK  (workspace) INTEGER array,
 84 *         If ICOMPQ = 0 or 1, the dimension of IWORK must be at least
 85 *                        6 + 6*N + 5*N*lg N.
 86 *                        ( lg( N ) = smallest integer k
 87 *                                    such that 2^k >= N )
 88 *         If ICOMPQ = 2, the dimension of IWORK must be at least
 89 *                        3 + 5*N.
 90 *
 91 *  INFO   (output) INTEGER
 92 *          = 0:  successful exit.
 93 *          < 0:  if INFO = -i, the i-th argument had an illegal value.
 94 *          > 0:  The algorithm failed to compute an eigenvalue while
 95 *                working on the submatrix lying in rows and columns
 96 *                INFO/(N+1) through mod(INFO,N+1).
 97 *
 98 *  Further Details
 99 *  ===============
100 *
101 *  Based on contributions by
102 *     Jeff Rutter, Computer Science Division, University of California
103 *     at Berkeley, USA
104 *
105 *  =====================================================================
106 *
107 *     .. Parameters ..
108       DOUBLE PRECISION   ZERO, ONE, TWO
109       PARAMETER          ( ZERO = 0.D0, ONE = 1.D0, TWO = 2.D0 )
110 *     ..
111 *     .. Local Scalars ..
112       INTEGER            CURLVL, CURPRB, CURR, I, IGIVCL, IGIVNM,
113      $                   IGIVPT, INDXQ, IPERM, IPRMPT, IQ, IQPTR, IWREM,
114      $                   J, K, LGN, MATSIZ, MSD2, SMLSIZ, SMM1, SPM1,
115      $                   SPM2, SUBMAT, SUBPBS, TLVLS
116       DOUBLE PRECISION   TEMP
117 *     ..
118 *     .. External Subroutines ..
119       EXTERNAL           DCOPY, DGEMM, DLACPY, DLAED1, DLAED7, DSTEQR,
120      $                   XERBLA
121 *     ..
122 *     .. External Functions ..
123       INTEGER            ILAENV
124       EXTERNAL           ILAENV
125 *     ..
126 *     .. Intrinsic Functions ..
127       INTRINSIC          ABSDBLEINTLOGMAX
128 *     ..
129 *     .. Executable Statements ..
130 *
131 *     Test the input parameters.
132 *
133       INFO = 0
134 *
135       IF( ICOMPQ.LT.0 .OR. ICOMPQ.GT.2 ) THEN
136          INFO = -1
137       ELSE IF( ( ICOMPQ.EQ.1 ) .AND. ( QSIZ.LT.MAX0, N ) ) ) THEN
138          INFO = -2
139       ELSE IF( N.LT.0 ) THEN
140          INFO = -3
141       ELSE IF( LDQ.LT.MAX1, N ) ) THEN
142          INFO = -7
143       ELSE IF( LDQS.LT.MAX1, N ) ) THEN
144          INFO = -9
145       END IF
146       IF( INFO.NE.0 ) THEN
147          CALL XERBLA( 'DLAED0'-INFO )
148          RETURN
149       END IF
150 *
151 *     Quick return if possible
152 *
153       IF( N.EQ.0 )
154      $   RETURN
155 *
156       SMLSIZ = ILAENV( 9'DLAED0'' '0000 )
157 *
158 *     Determine the size and placement of the submatrices, and save in
159 *     the leading elements of IWORK.
160 *
161       IWORK( 1 ) = N
162       SUBPBS = 1
163       TLVLS = 0
164    10 CONTINUE
165       IF( IWORK( SUBPBS ).GT.SMLSIZ ) THEN
166          DO 20 J = SUBPBS, 1-1
167             IWORK( 2*J ) = ( IWORK( J )+1 ) / 2
168             IWORK( 2*J-1 ) = IWORK( J ) / 2
169    20    CONTINUE
170          TLVLS = TLVLS + 1
171          SUBPBS = 2*SUBPBS
172          GO TO 10
173       END IF
174       DO 30 J = 2, SUBPBS
175          IWORK( J ) = IWORK( J ) + IWORK( J-1 )
176    30 CONTINUE
177 *
178 *     Divide the matrix into SUBPBS submatrices of size at most SMLSIZ+1
179 *     using rank-1 modifications (cuts).
180 *
181       SPM1 = SUBPBS - 1
182       DO 40 I = 1, SPM1
183          SUBMAT = IWORK( I ) + 1
184          SMM1 = SUBMAT - 1
185          D( SMM1 ) = D( SMM1 ) - ABS( E( SMM1 ) )
186          D( SUBMAT ) = D( SUBMAT ) - ABS( E( SMM1 ) )
187    40 CONTINUE
188 *
189       INDXQ = 4*+ 3
190       IF( ICOMPQ.NE.2 ) THEN
191 *
192 *        Set up workspaces for eigenvalues only/accumulate new vectors
193 *        routine
194 *
195          TEMP = LOGDBLE( N ) ) / LOG( TWO )
196          LGN = INT( TEMP )
197          IF2**LGN.LT.N )
198      $      LGN = LGN + 1
199          IF2**LGN.LT.N )
200      $      LGN = LGN + 1
201          IPRMPT = INDXQ + N + 1
202          IPERM = IPRMPT + N*LGN
203          IQPTR = IPERM + N*LGN
204          IGIVPT = IQPTR + N + 2
205          IGIVCL = IGIVPT + N*LGN
206 *
207          IGIVNM = 1
208          IQ = IGIVNM + 2*N*LGN
209          IWREM = IQ + N**2 + 1
210 *
211 *        Initialize pointers
212 *
213          DO 50 I = 0, SUBPBS
214             IWORK( IPRMPT+I ) = 1
215             IWORK( IGIVPT+I ) = 1
216    50    CONTINUE
217          IWORK( IQPTR ) = 1
218       END IF
219 *
220 *     Solve each submatrix eigenproblem at the bottom of the divide and
221 *     conquer tree.
222 *
223       CURR = 0
224       DO 70 I = 0, SPM1
225          IF( I.EQ.0 ) THEN
226             SUBMAT = 1
227             MATSIZ = IWORK( 1 )
228          ELSE
229             SUBMAT = IWORK( I ) + 1
230             MATSIZ = IWORK( I+1 ) - IWORK( I )
231          END IF
232          IF( ICOMPQ.EQ.2 ) THEN
233             CALL DSTEQR( 'I', MATSIZ, D( SUBMAT ), E( SUBMAT ),
234      $                   Q( SUBMAT, SUBMAT ), LDQ, WORK, INFO )
235             IF( INFO.NE.0 )
236      $         GO TO 130
237          ELSE
238             CALL DSTEQR( 'I', MATSIZ, D( SUBMAT ), E( SUBMAT ),
239      $                   WORK( IQ-1+IWORK( IQPTR+CURR ) ), MATSIZ, WORK,
240      $                   INFO )
241             IF( INFO.NE.0 )
242      $         GO TO 130
243             IF( ICOMPQ.EQ.1 ) THEN
244                CALL DGEMM( 'N''N', QSIZ, MATSIZ, MATSIZ, ONE,
245      $                     Q( 1, SUBMAT ), LDQ, WORK( IQ-1+IWORK( IQPTR+
246      $                     CURR ) ), MATSIZ, ZERO, QSTORE( 1, SUBMAT ),
247      $                     LDQS )
248             END IF
249             IWORK( IQPTR+CURR+1 ) = IWORK( IQPTR+CURR ) + MATSIZ**2
250             CURR = CURR + 1
251          END IF
252          K = 1
253          DO 60 J = SUBMAT, IWORK( I+1 )
254             IWORK( INDXQ+J ) = K
255             K = K + 1
256    60    CONTINUE
257    70 CONTINUE
258 *
259 *     Successively merge eigensystems of adjacent submatrices
260 *     into eigensystem for the corresponding larger matrix.
261 *
262 *     while ( SUBPBS > 1 )
263 *
264       CURLVL = 1
265    80 CONTINUE
266       IF( SUBPBS.GT.1 ) THEN
267          SPM2 = SUBPBS - 2
268          DO 90 I = 0, SPM2, 2
269             IF( I.EQ.0 ) THEN
270                SUBMAT = 1
271                MATSIZ = IWORK( 2 )
272                MSD2 = IWORK( 1 )
273                CURPRB = 0
274             ELSE
275                SUBMAT = IWORK( I ) + 1
276                MATSIZ = IWORK( I+2 ) - IWORK( I )
277                MSD2 = MATSIZ / 2
278                CURPRB = CURPRB + 1
279             END IF
280 *
281 *     Merge lower order eigensystems (of size MSD2 and MATSIZ - MSD2)
282 *     into an eigensystem of size MATSIZ.
283 *     DLAED1 is used only for the full eigensystem of a tridiagonal
284 *     matrix.
285 *     DLAED7 handles the cases in which eigenvalues only or eigenvalues
286 *     and eigenvectors of a full symmetric matrix (which was reduced to
287 *     tridiagonal form) are desired.
288 *
289             IF( ICOMPQ.EQ.2 ) THEN
290                CALL DLAED1( MATSIZ, D( SUBMAT ), Q( SUBMAT, SUBMAT ),
291      $                      LDQ, IWORK( INDXQ+SUBMAT ),
292      $                      E( SUBMAT+MSD2-1 ), MSD2, WORK,
293      $                      IWORK( SUBPBS+1 ), INFO )
294             ELSE
295                CALL DLAED7( ICOMPQ, MATSIZ, QSIZ, TLVLS, CURLVL, CURPRB,
296      $                      D( SUBMAT ), QSTORE( 1, SUBMAT ), LDQS,
297      $                      IWORK( INDXQ+SUBMAT ), E( SUBMAT+MSD2-1 ),
298      $                      MSD2, WORK( IQ ), IWORK( IQPTR ),
299      $                      IWORK( IPRMPT ), IWORK( IPERM ),
300      $                      IWORK( IGIVPT ), IWORK( IGIVCL ),
301      $                      WORK( IGIVNM ), WORK( IWREM ),
302      $                      IWORK( SUBPBS+1 ), INFO )
303             END IF
304             IF( INFO.NE.0 )
305      $         GO TO 130
306             IWORK( I / 2+1 ) = IWORK( I+2 )
307    90    CONTINUE
308          SUBPBS = SUBPBS / 2
309          CURLVL = CURLVL + 1
310          GO TO 80
311       END IF
312 *
313 *     end while
314 *
315 *     Re-merge the eigenvalues/vectors which were deflated at the final
316 *     merge step.
317 *
318       IF( ICOMPQ.EQ.1 ) THEN
319          DO 100 I = 1, N
320             J = IWORK( INDXQ+I )
321             WORK( I ) = D( J )
322             CALL DCOPY( QSIZ, QSTORE( 1, J ), 1, Q( 1, I ), 1 )
323   100    CONTINUE
324          CALL DCOPY( N, WORK, 1, D, 1 )
325       ELSE IF( ICOMPQ.EQ.2 ) THEN
326          DO 110 I = 1, N
327             J = IWORK( INDXQ+I )
328             WORK( I ) = D( J )
329             CALL DCOPY( N, Q( 1, J ), 1, WORK( N*I+1 ), 1 )
330   110    CONTINUE
331          CALL DCOPY( N, WORK, 1, D, 1 )
332          CALL DLACPY( 'A', N, N, WORK( N+1 ), N, Q, LDQ )
333       ELSE
334          DO 120 I = 1, N
335             J = IWORK( INDXQ+I )
336             WORK( I ) = D( J )
337   120    CONTINUE
338          CALL DCOPY( N, WORK, 1, D, 1 )
339       END IF
340       GO TO 140
341 *
342   130 CONTINUE
343       INFO = SUBMAT*( N+1 ) + SUBMAT + MATSIZ - 1
344 *
345   140 CONTINUE
346       RETURN
347 *
348 *     End of DLAED0
349 *
350       END