Annotation of rpl/lapack/lapack/dgesdd.f, revision 1.1.1.1
1.1 bertrand 1: SUBROUTINE DGESDD( JOBZ, M, N, A, LDA, S, U, LDU, VT, LDVT, WORK,
2: $ LWORK, IWORK, INFO )
3: *
4: * -- LAPACK driver routine (version 3.2.1) --
5: * -- LAPACK is a software package provided by Univ. of Tennessee, --
6: * -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--
7: * March 2009
8: *
9: * .. Scalar Arguments ..
10: CHARACTER JOBZ
11: INTEGER INFO, LDA, LDU, LDVT, LWORK, M, N
12: * ..
13: * .. Array Arguments ..
14: INTEGER IWORK( * )
15: DOUBLE PRECISION A( LDA, * ), S( * ), U( LDU, * ),
16: $ VT( LDVT, * ), WORK( * )
17: * ..
18: *
19: * Purpose
20: * =======
21: *
22: * DGESDD computes the singular value decomposition (SVD) of a real
23: * M-by-N matrix A, optionally computing the left and right singular
24: * vectors. If singular vectors are desired, it uses a
25: * divide-and-conquer algorithm.
26: *
27: * The SVD is written
28: *
29: * A = U * SIGMA * transpose(V)
30: *
31: * where SIGMA is an M-by-N matrix which is zero except for its
32: * min(m,n) diagonal elements, U is an M-by-M orthogonal matrix, and
33: * V is an N-by-N orthogonal matrix. The diagonal elements of SIGMA
34: * are the singular values of A; they are real and non-negative, and
35: * are returned in descending order. The first min(m,n) columns of
36: * U and V are the left and right singular vectors of A.
37: *
38: * Note that the routine returns VT = V**T, not V.
39: *
40: * The divide and conquer algorithm makes very mild assumptions about
41: * floating point arithmetic. It will work on machines with a guard
42: * digit in add/subtract, or on those binary machines without guard
43: * digits which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or
44: * Cray-2. It could conceivably fail on hexadecimal or decimal machines
45: * without guard digits, but we know of none.
46: *
47: * Arguments
48: * =========
49: *
50: * JOBZ (input) CHARACTER*1
51: * Specifies options for computing all or part of the matrix U:
52: * = 'A': all M columns of U and all N rows of V**T are
53: * returned in the arrays U and VT;
54: * = 'S': the first min(M,N) columns of U and the first
55: * min(M,N) rows of V**T are returned in the arrays U
56: * and VT;
57: * = 'O': If M >= N, the first N columns of U are overwritten
58: * on the array A and all rows of V**T are returned in
59: * the array VT;
60: * otherwise, all columns of U are returned in the
61: * array U and the first M rows of V**T are overwritten
62: * in the array A;
63: * = 'N': no columns of U or rows of V**T are computed.
64: *
65: * M (input) INTEGER
66: * The number of rows of the input matrix A. M >= 0.
67: *
68: * N (input) INTEGER
69: * The number of columns of the input matrix A. N >= 0.
70: *
71: * A (input/output) DOUBLE PRECISION array, dimension (LDA,N)
72: * On entry, the M-by-N matrix A.
73: * On exit,
74: * if JOBZ = 'O', A is overwritten with the first N columns
75: * of U (the left singular vectors, stored
76: * columnwise) if M >= N;
77: * A is overwritten with the first M rows
78: * of V**T (the right singular vectors, stored
79: * rowwise) otherwise.
80: * if JOBZ .ne. 'O', the contents of A are destroyed.
81: *
82: * LDA (input) INTEGER
83: * The leading dimension of the array A. LDA >= max(1,M).
84: *
85: * S (output) DOUBLE PRECISION array, dimension (min(M,N))
86: * The singular values of A, sorted so that S(i) >= S(i+1).
87: *
88: * U (output) DOUBLE PRECISION array, dimension (LDU,UCOL)
89: * UCOL = M if JOBZ = 'A' or JOBZ = 'O' and M < N;
90: * UCOL = min(M,N) if JOBZ = 'S'.
91: * If JOBZ = 'A' or JOBZ = 'O' and M < N, U contains the M-by-M
92: * orthogonal matrix U;
93: * if JOBZ = 'S', U contains the first min(M,N) columns of U
94: * (the left singular vectors, stored columnwise);
95: * if JOBZ = 'O' and M >= N, or JOBZ = 'N', U is not referenced.
96: *
97: * LDU (input) INTEGER
98: * The leading dimension of the array U. LDU >= 1; if
99: * JOBZ = 'S' or 'A' or JOBZ = 'O' and M < N, LDU >= M.
100: *
101: * VT (output) DOUBLE PRECISION array, dimension (LDVT,N)
102: * If JOBZ = 'A' or JOBZ = 'O' and M >= N, VT contains the
103: * N-by-N orthogonal matrix V**T;
104: * if JOBZ = 'S', VT contains the first min(M,N) rows of
105: * V**T (the right singular vectors, stored rowwise);
106: * if JOBZ = 'O' and M < N, or JOBZ = 'N', VT is not referenced.
107: *
108: * LDVT (input) INTEGER
109: * The leading dimension of the array VT. LDVT >= 1; if
110: * JOBZ = 'A' or JOBZ = 'O' and M >= N, LDVT >= N;
111: * if JOBZ = 'S', LDVT >= min(M,N).
112: *
113: * WORK (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK))
114: * On exit, if INFO = 0, WORK(1) returns the optimal LWORK;
115: *
116: * LWORK (input) INTEGER
117: * The dimension of the array WORK. LWORK >= 1.
118: * If JOBZ = 'N',
119: * LWORK >= 3*min(M,N) + max(max(M,N),7*min(M,N)).
120: * If JOBZ = 'O',
121: * LWORK >= 3*min(M,N) +
122: * max(max(M,N),5*min(M,N)*min(M,N)+4*min(M,N)).
123: * If JOBZ = 'S' or 'A'
124: * LWORK >= 3*min(M,N) +
125: * max(max(M,N),4*min(M,N)*min(M,N)+4*min(M,N)).
126: * For good performance, LWORK should generally be larger.
127: * If LWORK = -1 but other input arguments are legal, WORK(1)
128: * returns the optimal LWORK.
129: *
130: * IWORK (workspace) INTEGER array, dimension (8*min(M,N))
131: *
132: * INFO (output) INTEGER
133: * = 0: successful exit.
134: * < 0: if INFO = -i, the i-th argument had an illegal value.
135: * > 0: DBDSDC did not converge, updating process failed.
136: *
137: * Further Details
138: * ===============
139: *
140: * Based on contributions by
141: * Ming Gu and Huan Ren, Computer Science Division, University of
142: * California at Berkeley, USA
143: *
144: * =====================================================================
145: *
146: * .. Parameters ..
147: DOUBLE PRECISION ZERO, ONE
148: PARAMETER ( ZERO = 0.0D0, ONE = 1.0D0 )
149: * ..
150: * .. Local Scalars ..
151: LOGICAL LQUERY, WNTQA, WNTQAS, WNTQN, WNTQO, WNTQS
152: INTEGER BDSPAC, BLK, CHUNK, I, IE, IERR, IL,
153: $ IR, ISCL, ITAU, ITAUP, ITAUQ, IU, IVT, LDWKVT,
154: $ LDWRKL, LDWRKR, LDWRKU, MAXWRK, MINMN, MINWRK,
155: $ MNTHR, NWORK, WRKBL
156: DOUBLE PRECISION ANRM, BIGNUM, EPS, SMLNUM
157: * ..
158: * .. Local Arrays ..
159: INTEGER IDUM( 1 )
160: DOUBLE PRECISION DUM( 1 )
161: * ..
162: * .. External Subroutines ..
163: EXTERNAL DBDSDC, DGEBRD, DGELQF, DGEMM, DGEQRF, DLACPY,
164: $ DLASCL, DLASET, DORGBR, DORGLQ, DORGQR, DORMBR,
165: $ XERBLA
166: * ..
167: * .. External Functions ..
168: LOGICAL LSAME
169: INTEGER ILAENV
170: DOUBLE PRECISION DLAMCH, DLANGE
171: EXTERNAL DLAMCH, DLANGE, ILAENV, LSAME
172: * ..
173: * .. Intrinsic Functions ..
174: INTRINSIC INT, MAX, MIN, SQRT
175: * ..
176: * .. Executable Statements ..
177: *
178: * Test the input arguments
179: *
180: INFO = 0
181: MINMN = MIN( M, N )
182: WNTQA = LSAME( JOBZ, 'A' )
183: WNTQS = LSAME( JOBZ, 'S' )
184: WNTQAS = WNTQA .OR. WNTQS
185: WNTQO = LSAME( JOBZ, 'O' )
186: WNTQN = LSAME( JOBZ, 'N' )
187: LQUERY = ( LWORK.EQ.-1 )
188: *
189: IF( .NOT.( WNTQA .OR. WNTQS .OR. WNTQO .OR. WNTQN ) ) THEN
190: INFO = -1
191: ELSE IF( M.LT.0 ) THEN
192: INFO = -2
193: ELSE IF( N.LT.0 ) THEN
194: INFO = -3
195: ELSE IF( LDA.LT.MAX( 1, M ) ) THEN
196: INFO = -5
197: ELSE IF( LDU.LT.1 .OR. ( WNTQAS .AND. LDU.LT.M ) .OR.
198: $ ( WNTQO .AND. M.LT.N .AND. LDU.LT.M ) ) THEN
199: INFO = -8
200: ELSE IF( LDVT.LT.1 .OR. ( WNTQA .AND. LDVT.LT.N ) .OR.
201: $ ( WNTQS .AND. LDVT.LT.MINMN ) .OR.
202: $ ( WNTQO .AND. M.GE.N .AND. LDVT.LT.N ) ) THEN
203: INFO = -10
204: END IF
205: *
206: * Compute workspace
207: * (Note: Comments in the code beginning "Workspace:" describe the
208: * minimal amount of workspace needed at that point in the code,
209: * as well as the preferred amount for good performance.
210: * NB refers to the optimal block size for the immediately
211: * following subroutine, as returned by ILAENV.)
212: *
213: IF( INFO.EQ.0 ) THEN
214: MINWRK = 1
215: MAXWRK = 1
216: IF( M.GE.N .AND. MINMN.GT.0 ) THEN
217: *
218: * Compute space needed for DBDSDC
219: *
220: MNTHR = INT( MINMN*11.0D0 / 6.0D0 )
221: IF( WNTQN ) THEN
222: BDSPAC = 7*N
223: ELSE
224: BDSPAC = 3*N*N + 4*N
225: END IF
226: IF( M.GE.MNTHR ) THEN
227: IF( WNTQN ) THEN
228: *
229: * Path 1 (M much larger than N, JOBZ='N')
230: *
231: WRKBL = N + N*ILAENV( 1, 'DGEQRF', ' ', M, N, -1,
232: $ -1 )
233: WRKBL = MAX( WRKBL, 3*N+2*N*
234: $ ILAENV( 1, 'DGEBRD', ' ', N, N, -1, -1 ) )
235: MAXWRK = MAX( WRKBL, BDSPAC+N )
236: MINWRK = BDSPAC + N
237: ELSE IF( WNTQO ) THEN
238: *
239: * Path 2 (M much larger than N, JOBZ='O')
240: *
241: WRKBL = N + N*ILAENV( 1, 'DGEQRF', ' ', M, N, -1, -1 )
242: WRKBL = MAX( WRKBL, N+N*ILAENV( 1, 'DORGQR', ' ', M,
243: $ N, N, -1 ) )
244: WRKBL = MAX( WRKBL, 3*N+2*N*
245: $ ILAENV( 1, 'DGEBRD', ' ', N, N, -1, -1 ) )
246: WRKBL = MAX( WRKBL, 3*N+N*
247: $ ILAENV( 1, 'DORMBR', 'QLN', N, N, N, -1 ) )
248: WRKBL = MAX( WRKBL, 3*N+N*
249: $ ILAENV( 1, 'DORMBR', 'PRT', N, N, N, -1 ) )
250: WRKBL = MAX( WRKBL, BDSPAC+3*N )
251: MAXWRK = WRKBL + 2*N*N
252: MINWRK = BDSPAC + 2*N*N + 3*N
253: ELSE IF( WNTQS ) THEN
254: *
255: * Path 3 (M much larger than N, JOBZ='S')
256: *
257: WRKBL = N + N*ILAENV( 1, 'DGEQRF', ' ', M, N, -1, -1 )
258: WRKBL = MAX( WRKBL, N+N*ILAENV( 1, 'DORGQR', ' ', M,
259: $ N, N, -1 ) )
260: WRKBL = MAX( WRKBL, 3*N+2*N*
261: $ ILAENV( 1, 'DGEBRD', ' ', N, N, -1, -1 ) )
262: WRKBL = MAX( WRKBL, 3*N+N*
263: $ ILAENV( 1, 'DORMBR', 'QLN', N, N, N, -1 ) )
264: WRKBL = MAX( WRKBL, 3*N+N*
265: $ ILAENV( 1, 'DORMBR', 'PRT', N, N, N, -1 ) )
266: WRKBL = MAX( WRKBL, BDSPAC+3*N )
267: MAXWRK = WRKBL + N*N
268: MINWRK = BDSPAC + N*N + 3*N
269: ELSE IF( WNTQA ) THEN
270: *
271: * Path 4 (M much larger than N, JOBZ='A')
272: *
273: WRKBL = N + N*ILAENV( 1, 'DGEQRF', ' ', M, N, -1, -1 )
274: WRKBL = MAX( WRKBL, N+M*ILAENV( 1, 'DORGQR', ' ', M,
275: $ M, N, -1 ) )
276: WRKBL = MAX( WRKBL, 3*N+2*N*
277: $ ILAENV( 1, 'DGEBRD', ' ', N, N, -1, -1 ) )
278: WRKBL = MAX( WRKBL, 3*N+N*
279: $ ILAENV( 1, 'DORMBR', 'QLN', N, N, N, -1 ) )
280: WRKBL = MAX( WRKBL, 3*N+N*
281: $ ILAENV( 1, 'DORMBR', 'PRT', N, N, N, -1 ) )
282: WRKBL = MAX( WRKBL, BDSPAC+3*N )
283: MAXWRK = WRKBL + N*N
284: MINWRK = BDSPAC + N*N + 3*N
285: END IF
286: ELSE
287: *
288: * Path 5 (M at least N, but not much larger)
289: *
290: WRKBL = 3*N + ( M+N )*ILAENV( 1, 'DGEBRD', ' ', M, N, -1,
291: $ -1 )
292: IF( WNTQN ) THEN
293: MAXWRK = MAX( WRKBL, BDSPAC+3*N )
294: MINWRK = 3*N + MAX( M, BDSPAC )
295: ELSE IF( WNTQO ) THEN
296: WRKBL = MAX( WRKBL, 3*N+N*
297: $ ILAENV( 1, 'DORMBR', 'QLN', M, N, N, -1 ) )
298: WRKBL = MAX( WRKBL, 3*N+N*
299: $ ILAENV( 1, 'DORMBR', 'PRT', N, N, N, -1 ) )
300: WRKBL = MAX( WRKBL, BDSPAC+3*N )
301: MAXWRK = WRKBL + M*N
302: MINWRK = 3*N + MAX( M, N*N+BDSPAC )
303: ELSE IF( WNTQS ) THEN
304: WRKBL = MAX( WRKBL, 3*N+N*
305: $ ILAENV( 1, 'DORMBR', 'QLN', M, N, N, -1 ) )
306: WRKBL = MAX( WRKBL, 3*N+N*
307: $ ILAENV( 1, 'DORMBR', 'PRT', N, N, N, -1 ) )
308: MAXWRK = MAX( WRKBL, BDSPAC+3*N )
309: MINWRK = 3*N + MAX( M, BDSPAC )
310: ELSE IF( WNTQA ) THEN
311: WRKBL = MAX( WRKBL, 3*N+M*
312: $ ILAENV( 1, 'DORMBR', 'QLN', M, M, N, -1 ) )
313: WRKBL = MAX( WRKBL, 3*N+N*
314: $ ILAENV( 1, 'DORMBR', 'PRT', N, N, N, -1 ) )
315: MAXWRK = MAX( MAXWRK, BDSPAC+3*N )
316: MINWRK = 3*N + MAX( M, BDSPAC )
317: END IF
318: END IF
319: ELSE IF( MINMN.GT.0 ) THEN
320: *
321: * Compute space needed for DBDSDC
322: *
323: MNTHR = INT( MINMN*11.0D0 / 6.0D0 )
324: IF( WNTQN ) THEN
325: BDSPAC = 7*M
326: ELSE
327: BDSPAC = 3*M*M + 4*M
328: END IF
329: IF( N.GE.MNTHR ) THEN
330: IF( WNTQN ) THEN
331: *
332: * Path 1t (N much larger than M, JOBZ='N')
333: *
334: WRKBL = M + M*ILAENV( 1, 'DGELQF', ' ', M, N, -1,
335: $ -1 )
336: WRKBL = MAX( WRKBL, 3*M+2*M*
337: $ ILAENV( 1, 'DGEBRD', ' ', M, M, -1, -1 ) )
338: MAXWRK = MAX( WRKBL, BDSPAC+M )
339: MINWRK = BDSPAC + M
340: ELSE IF( WNTQO ) THEN
341: *
342: * Path 2t (N much larger than M, JOBZ='O')
343: *
344: WRKBL = M + M*ILAENV( 1, 'DGELQF', ' ', M, N, -1, -1 )
345: WRKBL = MAX( WRKBL, M+M*ILAENV( 1, 'DORGLQ', ' ', M,
346: $ N, M, -1 ) )
347: WRKBL = MAX( WRKBL, 3*M+2*M*
348: $ ILAENV( 1, 'DGEBRD', ' ', M, M, -1, -1 ) )
349: WRKBL = MAX( WRKBL, 3*M+M*
350: $ ILAENV( 1, 'DORMBR', 'QLN', M, M, M, -1 ) )
351: WRKBL = MAX( WRKBL, 3*M+M*
352: $ ILAENV( 1, 'DORMBR', 'PRT', M, M, M, -1 ) )
353: WRKBL = MAX( WRKBL, BDSPAC+3*M )
354: MAXWRK = WRKBL + 2*M*M
355: MINWRK = BDSPAC + 2*M*M + 3*M
356: ELSE IF( WNTQS ) THEN
357: *
358: * Path 3t (N much larger than M, JOBZ='S')
359: *
360: WRKBL = M + M*ILAENV( 1, 'DGELQF', ' ', M, N, -1, -1 )
361: WRKBL = MAX( WRKBL, M+M*ILAENV( 1, 'DORGLQ', ' ', M,
362: $ N, M, -1 ) )
363: WRKBL = MAX( WRKBL, 3*M+2*M*
364: $ ILAENV( 1, 'DGEBRD', ' ', M, M, -1, -1 ) )
365: WRKBL = MAX( WRKBL, 3*M+M*
366: $ ILAENV( 1, 'DORMBR', 'QLN', M, M, M, -1 ) )
367: WRKBL = MAX( WRKBL, 3*M+M*
368: $ ILAENV( 1, 'DORMBR', 'PRT', M, M, M, -1 ) )
369: WRKBL = MAX( WRKBL, BDSPAC+3*M )
370: MAXWRK = WRKBL + M*M
371: MINWRK = BDSPAC + M*M + 3*M
372: ELSE IF( WNTQA ) THEN
373: *
374: * Path 4t (N much larger than M, JOBZ='A')
375: *
376: WRKBL = M + M*ILAENV( 1, 'DGELQF', ' ', M, N, -1, -1 )
377: WRKBL = MAX( WRKBL, M+N*ILAENV( 1, 'DORGLQ', ' ', N,
378: $ N, M, -1 ) )
379: WRKBL = MAX( WRKBL, 3*M+2*M*
380: $ ILAENV( 1, 'DGEBRD', ' ', M, M, -1, -1 ) )
381: WRKBL = MAX( WRKBL, 3*M+M*
382: $ ILAENV( 1, 'DORMBR', 'QLN', M, M, M, -1 ) )
383: WRKBL = MAX( WRKBL, 3*M+M*
384: $ ILAENV( 1, 'DORMBR', 'PRT', M, M, M, -1 ) )
385: WRKBL = MAX( WRKBL, BDSPAC+3*M )
386: MAXWRK = WRKBL + M*M
387: MINWRK = BDSPAC + M*M + 3*M
388: END IF
389: ELSE
390: *
391: * Path 5t (N greater than M, but not much larger)
392: *
393: WRKBL = 3*M + ( M+N )*ILAENV( 1, 'DGEBRD', ' ', M, N, -1,
394: $ -1 )
395: IF( WNTQN ) THEN
396: MAXWRK = MAX( WRKBL, BDSPAC+3*M )
397: MINWRK = 3*M + MAX( N, BDSPAC )
398: ELSE IF( WNTQO ) THEN
399: WRKBL = MAX( WRKBL, 3*M+M*
400: $ ILAENV( 1, 'DORMBR', 'QLN', M, M, N, -1 ) )
401: WRKBL = MAX( WRKBL, 3*M+M*
402: $ ILAENV( 1, 'DORMBR', 'PRT', M, N, M, -1 ) )
403: WRKBL = MAX( WRKBL, BDSPAC+3*M )
404: MAXWRK = WRKBL + M*N
405: MINWRK = 3*M + MAX( N, M*M+BDSPAC )
406: ELSE IF( WNTQS ) THEN
407: WRKBL = MAX( WRKBL, 3*M+M*
408: $ ILAENV( 1, 'DORMBR', 'QLN', M, M, N, -1 ) )
409: WRKBL = MAX( WRKBL, 3*M+M*
410: $ ILAENV( 1, 'DORMBR', 'PRT', M, N, M, -1 ) )
411: MAXWRK = MAX( WRKBL, BDSPAC+3*M )
412: MINWRK = 3*M + MAX( N, BDSPAC )
413: ELSE IF( WNTQA ) THEN
414: WRKBL = MAX( WRKBL, 3*M+M*
415: $ ILAENV( 1, 'DORMBR', 'QLN', M, M, N, -1 ) )
416: WRKBL = MAX( WRKBL, 3*M+M*
417: $ ILAENV( 1, 'DORMBR', 'PRT', N, N, M, -1 ) )
418: MAXWRK = MAX( WRKBL, BDSPAC+3*M )
419: MINWRK = 3*M + MAX( N, BDSPAC )
420: END IF
421: END IF
422: END IF
423: MAXWRK = MAX( MAXWRK, MINWRK )
424: WORK( 1 ) = MAXWRK
425: *
426: IF( LWORK.LT.MINWRK .AND. .NOT.LQUERY ) THEN
427: INFO = -12
428: END IF
429: END IF
430: *
431: IF( INFO.NE.0 ) THEN
432: CALL XERBLA( 'DGESDD', -INFO )
433: RETURN
434: ELSE IF( LQUERY ) THEN
435: RETURN
436: END IF
437: *
438: * Quick return if possible
439: *
440: IF( M.EQ.0 .OR. N.EQ.0 ) THEN
441: RETURN
442: END IF
443: *
444: * Get machine constants
445: *
446: EPS = DLAMCH( 'P' )
447: SMLNUM = SQRT( DLAMCH( 'S' ) ) / EPS
448: BIGNUM = ONE / SMLNUM
449: *
450: * Scale A if max element outside range [SMLNUM,BIGNUM]
451: *
452: ANRM = DLANGE( 'M', M, N, A, LDA, DUM )
453: ISCL = 0
454: IF( ANRM.GT.ZERO .AND. ANRM.LT.SMLNUM ) THEN
455: ISCL = 1
456: CALL DLASCL( 'G', 0, 0, ANRM, SMLNUM, M, N, A, LDA, IERR )
457: ELSE IF( ANRM.GT.BIGNUM ) THEN
458: ISCL = 1
459: CALL DLASCL( 'G', 0, 0, ANRM, BIGNUM, M, N, A, LDA, IERR )
460: END IF
461: *
462: IF( M.GE.N ) THEN
463: *
464: * A has at least as many rows as columns. If A has sufficiently
465: * more rows than columns, first reduce using the QR
466: * decomposition (if sufficient workspace available)
467: *
468: IF( M.GE.MNTHR ) THEN
469: *
470: IF( WNTQN ) THEN
471: *
472: * Path 1 (M much larger than N, JOBZ='N')
473: * No singular vectors to be computed
474: *
475: ITAU = 1
476: NWORK = ITAU + N
477: *
478: * Compute A=Q*R
479: * (Workspace: need 2*N, prefer N+N*NB)
480: *
481: CALL DGEQRF( M, N, A, LDA, WORK( ITAU ), WORK( NWORK ),
482: $ LWORK-NWORK+1, IERR )
483: *
484: * Zero out below R
485: *
486: CALL DLASET( 'L', N-1, N-1, ZERO, ZERO, A( 2, 1 ), LDA )
487: IE = 1
488: ITAUQ = IE + N
489: ITAUP = ITAUQ + N
490: NWORK = ITAUP + N
491: *
492: * Bidiagonalize R in A
493: * (Workspace: need 4*N, prefer 3*N+2*N*NB)
494: *
495: CALL DGEBRD( N, N, A, LDA, S, WORK( IE ), WORK( ITAUQ ),
496: $ WORK( ITAUP ), WORK( NWORK ), LWORK-NWORK+1,
497: $ IERR )
498: NWORK = IE + N
499: *
500: * Perform bidiagonal SVD, computing singular values only
501: * (Workspace: need N+BDSPAC)
502: *
503: CALL DBDSDC( 'U', 'N', N, S, WORK( IE ), DUM, 1, DUM, 1,
504: $ DUM, IDUM, WORK( NWORK ), IWORK, INFO )
505: *
506: ELSE IF( WNTQO ) THEN
507: *
508: * Path 2 (M much larger than N, JOBZ = 'O')
509: * N left singular vectors to be overwritten on A and
510: * N right singular vectors to be computed in VT
511: *
512: IR = 1
513: *
514: * WORK(IR) is LDWRKR by N
515: *
516: IF( LWORK.GE.LDA*N+N*N+3*N+BDSPAC ) THEN
517: LDWRKR = LDA
518: ELSE
519: LDWRKR = ( LWORK-N*N-3*N-BDSPAC ) / N
520: END IF
521: ITAU = IR + LDWRKR*N
522: NWORK = ITAU + N
523: *
524: * Compute A=Q*R
525: * (Workspace: need N*N+2*N, prefer N*N+N+N*NB)
526: *
527: CALL DGEQRF( M, N, A, LDA, WORK( ITAU ), WORK( NWORK ),
528: $ LWORK-NWORK+1, IERR )
529: *
530: * Copy R to WORK(IR), zeroing out below it
531: *
532: CALL DLACPY( 'U', N, N, A, LDA, WORK( IR ), LDWRKR )
533: CALL DLASET( 'L', N-1, N-1, ZERO, ZERO, WORK( IR+1 ),
534: $ LDWRKR )
535: *
536: * Generate Q in A
537: * (Workspace: need N*N+2*N, prefer N*N+N+N*NB)
538: *
539: CALL DORGQR( M, N, N, A, LDA, WORK( ITAU ),
540: $ WORK( NWORK ), LWORK-NWORK+1, IERR )
541: IE = ITAU
542: ITAUQ = IE + N
543: ITAUP = ITAUQ + N
544: NWORK = ITAUP + N
545: *
546: * Bidiagonalize R in VT, copying result to WORK(IR)
547: * (Workspace: need N*N+4*N, prefer N*N+3*N+2*N*NB)
548: *
549: CALL DGEBRD( N, N, WORK( IR ), LDWRKR, S, WORK( IE ),
550: $ WORK( ITAUQ ), WORK( ITAUP ), WORK( NWORK ),
551: $ LWORK-NWORK+1, IERR )
552: *
553: * WORK(IU) is N by N
554: *
555: IU = NWORK
556: NWORK = IU + N*N
557: *
558: * Perform bidiagonal SVD, computing left singular vectors
559: * of bidiagonal matrix in WORK(IU) and computing right
560: * singular vectors of bidiagonal matrix in VT
561: * (Workspace: need N+N*N+BDSPAC)
562: *
563: CALL DBDSDC( 'U', 'I', N, S, WORK( IE ), WORK( IU ), N,
564: $ VT, LDVT, DUM, IDUM, WORK( NWORK ), IWORK,
565: $ INFO )
566: *
567: * Overwrite WORK(IU) by left singular vectors of R
568: * and VT by right singular vectors of R
569: * (Workspace: need 2*N*N+3*N, prefer 2*N*N+2*N+N*NB)
570: *
571: CALL DORMBR( 'Q', 'L', 'N', N, N, N, WORK( IR ), LDWRKR,
572: $ WORK( ITAUQ ), WORK( IU ), N, WORK( NWORK ),
573: $ LWORK-NWORK+1, IERR )
574: CALL DORMBR( 'P', 'R', 'T', N, N, N, WORK( IR ), LDWRKR,
575: $ WORK( ITAUP ), VT, LDVT, WORK( NWORK ),
576: $ LWORK-NWORK+1, IERR )
577: *
578: * Multiply Q in A by left singular vectors of R in
579: * WORK(IU), storing result in WORK(IR) and copying to A
580: * (Workspace: need 2*N*N, prefer N*N+M*N)
581: *
582: DO 10 I = 1, M, LDWRKR
583: CHUNK = MIN( M-I+1, LDWRKR )
584: CALL DGEMM( 'N', 'N', CHUNK, N, N, ONE, A( I, 1 ),
585: $ LDA, WORK( IU ), N, ZERO, WORK( IR ),
586: $ LDWRKR )
587: CALL DLACPY( 'F', CHUNK, N, WORK( IR ), LDWRKR,
588: $ A( I, 1 ), LDA )
589: 10 CONTINUE
590: *
591: ELSE IF( WNTQS ) THEN
592: *
593: * Path 3 (M much larger than N, JOBZ='S')
594: * N left singular vectors to be computed in U and
595: * N right singular vectors to be computed in VT
596: *
597: IR = 1
598: *
599: * WORK(IR) is N by N
600: *
601: LDWRKR = N
602: ITAU = IR + LDWRKR*N
603: NWORK = ITAU + N
604: *
605: * Compute A=Q*R
606: * (Workspace: need N*N+2*N, prefer N*N+N+N*NB)
607: *
608: CALL DGEQRF( M, N, A, LDA, WORK( ITAU ), WORK( NWORK ),
609: $ LWORK-NWORK+1, IERR )
610: *
611: * Copy R to WORK(IR), zeroing out below it
612: *
613: CALL DLACPY( 'U', N, N, A, LDA, WORK( IR ), LDWRKR )
614: CALL DLASET( 'L', N-1, N-1, ZERO, ZERO, WORK( IR+1 ),
615: $ LDWRKR )
616: *
617: * Generate Q in A
618: * (Workspace: need N*N+2*N, prefer N*N+N+N*NB)
619: *
620: CALL DORGQR( M, N, N, A, LDA, WORK( ITAU ),
621: $ WORK( NWORK ), LWORK-NWORK+1, IERR )
622: IE = ITAU
623: ITAUQ = IE + N
624: ITAUP = ITAUQ + N
625: NWORK = ITAUP + N
626: *
627: * Bidiagonalize R in WORK(IR)
628: * (Workspace: need N*N+4*N, prefer N*N+3*N+2*N*NB)
629: *
630: CALL DGEBRD( N, N, WORK( IR ), LDWRKR, S, WORK( IE ),
631: $ WORK( ITAUQ ), WORK( ITAUP ), WORK( NWORK ),
632: $ LWORK-NWORK+1, IERR )
633: *
634: * Perform bidiagonal SVD, computing left singular vectors
635: * of bidiagoal matrix in U and computing right singular
636: * vectors of bidiagonal matrix in VT
637: * (Workspace: need N+BDSPAC)
638: *
639: CALL DBDSDC( 'U', 'I', N, S, WORK( IE ), U, LDU, VT,
640: $ LDVT, DUM, IDUM, WORK( NWORK ), IWORK,
641: $ INFO )
642: *
643: * Overwrite U by left singular vectors of R and VT
644: * by right singular vectors of R
645: * (Workspace: need N*N+3*N, prefer N*N+2*N+N*NB)
646: *
647: CALL DORMBR( 'Q', 'L', 'N', N, N, N, WORK( IR ), LDWRKR,
648: $ WORK( ITAUQ ), U, LDU, WORK( NWORK ),
649: $ LWORK-NWORK+1, IERR )
650: *
651: CALL DORMBR( 'P', 'R', 'T', N, N, N, WORK( IR ), LDWRKR,
652: $ WORK( ITAUP ), VT, LDVT, WORK( NWORK ),
653: $ LWORK-NWORK+1, IERR )
654: *
655: * Multiply Q in A by left singular vectors of R in
656: * WORK(IR), storing result in U
657: * (Workspace: need N*N)
658: *
659: CALL DLACPY( 'F', N, N, U, LDU, WORK( IR ), LDWRKR )
660: CALL DGEMM( 'N', 'N', M, N, N, ONE, A, LDA, WORK( IR ),
661: $ LDWRKR, ZERO, U, LDU )
662: *
663: ELSE IF( WNTQA ) THEN
664: *
665: * Path 4 (M much larger than N, JOBZ='A')
666: * M left singular vectors to be computed in U and
667: * N right singular vectors to be computed in VT
668: *
669: IU = 1
670: *
671: * WORK(IU) is N by N
672: *
673: LDWRKU = N
674: ITAU = IU + LDWRKU*N
675: NWORK = ITAU + N
676: *
677: * Compute A=Q*R, copying result to U
678: * (Workspace: need N*N+2*N, prefer N*N+N+N*NB)
679: *
680: CALL DGEQRF( M, N, A, LDA, WORK( ITAU ), WORK( NWORK ),
681: $ LWORK-NWORK+1, IERR )
682: CALL DLACPY( 'L', M, N, A, LDA, U, LDU )
683: *
684: * Generate Q in U
685: * (Workspace: need N*N+2*N, prefer N*N+N+N*NB)
686: CALL DORGQR( M, M, N, U, LDU, WORK( ITAU ),
687: $ WORK( NWORK ), LWORK-NWORK+1, IERR )
688: *
689: * Produce R in A, zeroing out other entries
690: *
691: CALL DLASET( 'L', N-1, N-1, ZERO, ZERO, A( 2, 1 ), LDA )
692: IE = ITAU
693: ITAUQ = IE + N
694: ITAUP = ITAUQ + N
695: NWORK = ITAUP + N
696: *
697: * Bidiagonalize R in A
698: * (Workspace: need N*N+4*N, prefer N*N+3*N+2*N*NB)
699: *
700: CALL DGEBRD( N, N, A, LDA, S, WORK( IE ), WORK( ITAUQ ),
701: $ WORK( ITAUP ), WORK( NWORK ), LWORK-NWORK+1,
702: $ IERR )
703: *
704: * Perform bidiagonal SVD, computing left singular vectors
705: * of bidiagonal matrix in WORK(IU) and computing right
706: * singular vectors of bidiagonal matrix in VT
707: * (Workspace: need N+N*N+BDSPAC)
708: *
709: CALL DBDSDC( 'U', 'I', N, S, WORK( IE ), WORK( IU ), N,
710: $ VT, LDVT, DUM, IDUM, WORK( NWORK ), IWORK,
711: $ INFO )
712: *
713: * Overwrite WORK(IU) by left singular vectors of R and VT
714: * by right singular vectors of R
715: * (Workspace: need N*N+3*N, prefer N*N+2*N+N*NB)
716: *
717: CALL DORMBR( 'Q', 'L', 'N', N, N, N, A, LDA,
718: $ WORK( ITAUQ ), WORK( IU ), LDWRKU,
719: $ WORK( NWORK ), LWORK-NWORK+1, IERR )
720: CALL DORMBR( 'P', 'R', 'T', N, N, N, A, LDA,
721: $ WORK( ITAUP ), VT, LDVT, WORK( NWORK ),
722: $ LWORK-NWORK+1, IERR )
723: *
724: * Multiply Q in U by left singular vectors of R in
725: * WORK(IU), storing result in A
726: * (Workspace: need N*N)
727: *
728: CALL DGEMM( 'N', 'N', M, N, N, ONE, U, LDU, WORK( IU ),
729: $ LDWRKU, ZERO, A, LDA )
730: *
731: * Copy left singular vectors of A from A to U
732: *
733: CALL DLACPY( 'F', M, N, A, LDA, U, LDU )
734: *
735: END IF
736: *
737: ELSE
738: *
739: * M .LT. MNTHR
740: *
741: * Path 5 (M at least N, but not much larger)
742: * Reduce to bidiagonal form without QR decomposition
743: *
744: IE = 1
745: ITAUQ = IE + N
746: ITAUP = ITAUQ + N
747: NWORK = ITAUP + N
748: *
749: * Bidiagonalize A
750: * (Workspace: need 3*N+M, prefer 3*N+(M+N)*NB)
751: *
752: CALL DGEBRD( M, N, A, LDA, S, WORK( IE ), WORK( ITAUQ ),
753: $ WORK( ITAUP ), WORK( NWORK ), LWORK-NWORK+1,
754: $ IERR )
755: IF( WNTQN ) THEN
756: *
757: * Perform bidiagonal SVD, only computing singular values
758: * (Workspace: need N+BDSPAC)
759: *
760: CALL DBDSDC( 'U', 'N', N, S, WORK( IE ), DUM, 1, DUM, 1,
761: $ DUM, IDUM, WORK( NWORK ), IWORK, INFO )
762: ELSE IF( WNTQO ) THEN
763: IU = NWORK
764: IF( LWORK.GE.M*N+3*N+BDSPAC ) THEN
765: *
766: * WORK( IU ) is M by N
767: *
768: LDWRKU = M
769: NWORK = IU + LDWRKU*N
770: CALL DLASET( 'F', M, N, ZERO, ZERO, WORK( IU ),
771: $ LDWRKU )
772: ELSE
773: *
774: * WORK( IU ) is N by N
775: *
776: LDWRKU = N
777: NWORK = IU + LDWRKU*N
778: *
779: * WORK(IR) is LDWRKR by N
780: *
781: IR = NWORK
782: LDWRKR = ( LWORK-N*N-3*N ) / N
783: END IF
784: NWORK = IU + LDWRKU*N
785: *
786: * Perform bidiagonal SVD, computing left singular vectors
787: * of bidiagonal matrix in WORK(IU) and computing right
788: * singular vectors of bidiagonal matrix in VT
789: * (Workspace: need N+N*N+BDSPAC)
790: *
791: CALL DBDSDC( 'U', 'I', N, S, WORK( IE ), WORK( IU ),
792: $ LDWRKU, VT, LDVT, DUM, IDUM, WORK( NWORK ),
793: $ IWORK, INFO )
794: *
795: * Overwrite VT by right singular vectors of A
796: * (Workspace: need N*N+2*N, prefer N*N+N+N*NB)
797: *
798: CALL DORMBR( 'P', 'R', 'T', N, N, N, A, LDA,
799: $ WORK( ITAUP ), VT, LDVT, WORK( NWORK ),
800: $ LWORK-NWORK+1, IERR )
801: *
802: IF( LWORK.GE.M*N+3*N+BDSPAC ) THEN
803: *
804: * Overwrite WORK(IU) by left singular vectors of A
805: * (Workspace: need N*N+2*N, prefer N*N+N+N*NB)
806: *
807: CALL DORMBR( 'Q', 'L', 'N', M, N, N, A, LDA,
808: $ WORK( ITAUQ ), WORK( IU ), LDWRKU,
809: $ WORK( NWORK ), LWORK-NWORK+1, IERR )
810: *
811: * Copy left singular vectors of A from WORK(IU) to A
812: *
813: CALL DLACPY( 'F', M, N, WORK( IU ), LDWRKU, A, LDA )
814: ELSE
815: *
816: * Generate Q in A
817: * (Workspace: need N*N+2*N, prefer N*N+N+N*NB)
818: *
819: CALL DORGBR( 'Q', M, N, N, A, LDA, WORK( ITAUQ ),
820: $ WORK( NWORK ), LWORK-NWORK+1, IERR )
821: *
822: * Multiply Q in A by left singular vectors of
823: * bidiagonal matrix in WORK(IU), storing result in
824: * WORK(IR) and copying to A
825: * (Workspace: need 2*N*N, prefer N*N+M*N)
826: *
827: DO 20 I = 1, M, LDWRKR
828: CHUNK = MIN( M-I+1, LDWRKR )
829: CALL DGEMM( 'N', 'N', CHUNK, N, N, ONE, A( I, 1 ),
830: $ LDA, WORK( IU ), LDWRKU, ZERO,
831: $ WORK( IR ), LDWRKR )
832: CALL DLACPY( 'F', CHUNK, N, WORK( IR ), LDWRKR,
833: $ A( I, 1 ), LDA )
834: 20 CONTINUE
835: END IF
836: *
837: ELSE IF( WNTQS ) THEN
838: *
839: * Perform bidiagonal SVD, computing left singular vectors
840: * of bidiagonal matrix in U and computing right singular
841: * vectors of bidiagonal matrix in VT
842: * (Workspace: need N+BDSPAC)
843: *
844: CALL DLASET( 'F', M, N, ZERO, ZERO, U, LDU )
845: CALL DBDSDC( 'U', 'I', N, S, WORK( IE ), U, LDU, VT,
846: $ LDVT, DUM, IDUM, WORK( NWORK ), IWORK,
847: $ INFO )
848: *
849: * Overwrite U by left singular vectors of A and VT
850: * by right singular vectors of A
851: * (Workspace: need 3*N, prefer 2*N+N*NB)
852: *
853: CALL DORMBR( 'Q', 'L', 'N', M, N, N, A, LDA,
854: $ WORK( ITAUQ ), U, LDU, WORK( NWORK ),
855: $ LWORK-NWORK+1, IERR )
856: CALL DORMBR( 'P', 'R', 'T', N, N, N, A, LDA,
857: $ WORK( ITAUP ), VT, LDVT, WORK( NWORK ),
858: $ LWORK-NWORK+1, IERR )
859: ELSE IF( WNTQA ) THEN
860: *
861: * Perform bidiagonal SVD, computing left singular vectors
862: * of bidiagonal matrix in U and computing right singular
863: * vectors of bidiagonal matrix in VT
864: * (Workspace: need N+BDSPAC)
865: *
866: CALL DLASET( 'F', M, M, ZERO, ZERO, U, LDU )
867: CALL DBDSDC( 'U', 'I', N, S, WORK( IE ), U, LDU, VT,
868: $ LDVT, DUM, IDUM, WORK( NWORK ), IWORK,
869: $ INFO )
870: *
871: * Set the right corner of U to identity matrix
872: *
873: IF( M.GT.N ) THEN
874: CALL DLASET( 'F', M-N, M-N, ZERO, ONE, U( N+1, N+1 ),
875: $ LDU )
876: END IF
877: *
878: * Overwrite U by left singular vectors of A and VT
879: * by right singular vectors of A
880: * (Workspace: need N*N+2*N+M, prefer N*N+2*N+M*NB)
881: *
882: CALL DORMBR( 'Q', 'L', 'N', M, M, N, A, LDA,
883: $ WORK( ITAUQ ), U, LDU, WORK( NWORK ),
884: $ LWORK-NWORK+1, IERR )
885: CALL DORMBR( 'P', 'R', 'T', N, N, M, A, LDA,
886: $ WORK( ITAUP ), VT, LDVT, WORK( NWORK ),
887: $ LWORK-NWORK+1, IERR )
888: END IF
889: *
890: END IF
891: *
892: ELSE
893: *
894: * A has more columns than rows. If A has sufficiently more
895: * columns than rows, first reduce using the LQ decomposition (if
896: * sufficient workspace available)
897: *
898: IF( N.GE.MNTHR ) THEN
899: *
900: IF( WNTQN ) THEN
901: *
902: * Path 1t (N much larger than M, JOBZ='N')
903: * No singular vectors to be computed
904: *
905: ITAU = 1
906: NWORK = ITAU + M
907: *
908: * Compute A=L*Q
909: * (Workspace: need 2*M, prefer M+M*NB)
910: *
911: CALL DGELQF( M, N, A, LDA, WORK( ITAU ), WORK( NWORK ),
912: $ LWORK-NWORK+1, IERR )
913: *
914: * Zero out above L
915: *
916: CALL DLASET( 'U', M-1, M-1, ZERO, ZERO, A( 1, 2 ), LDA )
917: IE = 1
918: ITAUQ = IE + M
919: ITAUP = ITAUQ + M
920: NWORK = ITAUP + M
921: *
922: * Bidiagonalize L in A
923: * (Workspace: need 4*M, prefer 3*M+2*M*NB)
924: *
925: CALL DGEBRD( M, M, A, LDA, S, WORK( IE ), WORK( ITAUQ ),
926: $ WORK( ITAUP ), WORK( NWORK ), LWORK-NWORK+1,
927: $ IERR )
928: NWORK = IE + M
929: *
930: * Perform bidiagonal SVD, computing singular values only
931: * (Workspace: need M+BDSPAC)
932: *
933: CALL DBDSDC( 'U', 'N', M, S, WORK( IE ), DUM, 1, DUM, 1,
934: $ DUM, IDUM, WORK( NWORK ), IWORK, INFO )
935: *
936: ELSE IF( WNTQO ) THEN
937: *
938: * Path 2t (N much larger than M, JOBZ='O')
939: * M right singular vectors to be overwritten on A and
940: * M left singular vectors to be computed in U
941: *
942: IVT = 1
943: *
944: * IVT is M by M
945: *
946: IL = IVT + M*M
947: IF( LWORK.GE.M*N+M*M+3*M+BDSPAC ) THEN
948: *
949: * WORK(IL) is M by N
950: *
951: LDWRKL = M
952: CHUNK = N
953: ELSE
954: LDWRKL = M
955: CHUNK = ( LWORK-M*M ) / M
956: END IF
957: ITAU = IL + LDWRKL*M
958: NWORK = ITAU + M
959: *
960: * Compute A=L*Q
961: * (Workspace: need M*M+2*M, prefer M*M+M+M*NB)
962: *
963: CALL DGELQF( M, N, A, LDA, WORK( ITAU ), WORK( NWORK ),
964: $ LWORK-NWORK+1, IERR )
965: *
966: * Copy L to WORK(IL), zeroing about above it
967: *
968: CALL DLACPY( 'L', M, M, A, LDA, WORK( IL ), LDWRKL )
969: CALL DLASET( 'U', M-1, M-1, ZERO, ZERO,
970: $ WORK( IL+LDWRKL ), LDWRKL )
971: *
972: * Generate Q in A
973: * (Workspace: need M*M+2*M, prefer M*M+M+M*NB)
974: *
975: CALL DORGLQ( M, N, M, A, LDA, WORK( ITAU ),
976: $ WORK( NWORK ), LWORK-NWORK+1, IERR )
977: IE = ITAU
978: ITAUQ = IE + M
979: ITAUP = ITAUQ + M
980: NWORK = ITAUP + M
981: *
982: * Bidiagonalize L in WORK(IL)
983: * (Workspace: need M*M+4*M, prefer M*M+3*M+2*M*NB)
984: *
985: CALL DGEBRD( M, M, WORK( IL ), LDWRKL, S, WORK( IE ),
986: $ WORK( ITAUQ ), WORK( ITAUP ), WORK( NWORK ),
987: $ LWORK-NWORK+1, IERR )
988: *
989: * Perform bidiagonal SVD, computing left singular vectors
990: * of bidiagonal matrix in U, and computing right singular
991: * vectors of bidiagonal matrix in WORK(IVT)
992: * (Workspace: need M+M*M+BDSPAC)
993: *
994: CALL DBDSDC( 'U', 'I', M, S, WORK( IE ), U, LDU,
995: $ WORK( IVT ), M, DUM, IDUM, WORK( NWORK ),
996: $ IWORK, INFO )
997: *
998: * Overwrite U by left singular vectors of L and WORK(IVT)
999: * by right singular vectors of L
1000: * (Workspace: need 2*M*M+3*M, prefer 2*M*M+2*M+M*NB)
1001: *
1002: CALL DORMBR( 'Q', 'L', 'N', M, M, M, WORK( IL ), LDWRKL,
1003: $ WORK( ITAUQ ), U, LDU, WORK( NWORK ),
1004: $ LWORK-NWORK+1, IERR )
1005: CALL DORMBR( 'P', 'R', 'T', M, M, M, WORK( IL ), LDWRKL,
1006: $ WORK( ITAUP ), WORK( IVT ), M,
1007: $ WORK( NWORK ), LWORK-NWORK+1, IERR )
1008: *
1009: * Multiply right singular vectors of L in WORK(IVT) by Q
1010: * in A, storing result in WORK(IL) and copying to A
1011: * (Workspace: need 2*M*M, prefer M*M+M*N)
1012: *
1013: DO 30 I = 1, N, CHUNK
1014: BLK = MIN( N-I+1, CHUNK )
1015: CALL DGEMM( 'N', 'N', M, BLK, M, ONE, WORK( IVT ), M,
1016: $ A( 1, I ), LDA, ZERO, WORK( IL ), LDWRKL )
1017: CALL DLACPY( 'F', M, BLK, WORK( IL ), LDWRKL,
1018: $ A( 1, I ), LDA )
1019: 30 CONTINUE
1020: *
1021: ELSE IF( WNTQS ) THEN
1022: *
1023: * Path 3t (N much larger than M, JOBZ='S')
1024: * M right singular vectors to be computed in VT and
1025: * M left singular vectors to be computed in U
1026: *
1027: IL = 1
1028: *
1029: * WORK(IL) is M by M
1030: *
1031: LDWRKL = M
1032: ITAU = IL + LDWRKL*M
1033: NWORK = ITAU + M
1034: *
1035: * Compute A=L*Q
1036: * (Workspace: need M*M+2*M, prefer M*M+M+M*NB)
1037: *
1038: CALL DGELQF( M, N, A, LDA, WORK( ITAU ), WORK( NWORK ),
1039: $ LWORK-NWORK+1, IERR )
1040: *
1041: * Copy L to WORK(IL), zeroing out above it
1042: *
1043: CALL DLACPY( 'L', M, M, A, LDA, WORK( IL ), LDWRKL )
1044: CALL DLASET( 'U', M-1, M-1, ZERO, ZERO,
1045: $ WORK( IL+LDWRKL ), LDWRKL )
1046: *
1047: * Generate Q in A
1048: * (Workspace: need M*M+2*M, prefer M*M+M+M*NB)
1049: *
1050: CALL DORGLQ( M, N, M, A, LDA, WORK( ITAU ),
1051: $ WORK( NWORK ), LWORK-NWORK+1, IERR )
1052: IE = ITAU
1053: ITAUQ = IE + M
1054: ITAUP = ITAUQ + M
1055: NWORK = ITAUP + M
1056: *
1057: * Bidiagonalize L in WORK(IU), copying result to U
1058: * (Workspace: need M*M+4*M, prefer M*M+3*M+2*M*NB)
1059: *
1060: CALL DGEBRD( M, M, WORK( IL ), LDWRKL, S, WORK( IE ),
1061: $ WORK( ITAUQ ), WORK( ITAUP ), WORK( NWORK ),
1062: $ LWORK-NWORK+1, IERR )
1063: *
1064: * Perform bidiagonal SVD, computing left singular vectors
1065: * of bidiagonal matrix in U and computing right singular
1066: * vectors of bidiagonal matrix in VT
1067: * (Workspace: need M+BDSPAC)
1068: *
1069: CALL DBDSDC( 'U', 'I', M, S, WORK( IE ), U, LDU, VT,
1070: $ LDVT, DUM, IDUM, WORK( NWORK ), IWORK,
1071: $ INFO )
1072: *
1073: * Overwrite U by left singular vectors of L and VT
1074: * by right singular vectors of L
1075: * (Workspace: need M*M+3*M, prefer M*M+2*M+M*NB)
1076: *
1077: CALL DORMBR( 'Q', 'L', 'N', M, M, M, WORK( IL ), LDWRKL,
1078: $ WORK( ITAUQ ), U, LDU, WORK( NWORK ),
1079: $ LWORK-NWORK+1, IERR )
1080: CALL DORMBR( 'P', 'R', 'T', M, M, M, WORK( IL ), LDWRKL,
1081: $ WORK( ITAUP ), VT, LDVT, WORK( NWORK ),
1082: $ LWORK-NWORK+1, IERR )
1083: *
1084: * Multiply right singular vectors of L in WORK(IL) by
1085: * Q in A, storing result in VT
1086: * (Workspace: need M*M)
1087: *
1088: CALL DLACPY( 'F', M, M, VT, LDVT, WORK( IL ), LDWRKL )
1089: CALL DGEMM( 'N', 'N', M, N, M, ONE, WORK( IL ), LDWRKL,
1090: $ A, LDA, ZERO, VT, LDVT )
1091: *
1092: ELSE IF( WNTQA ) THEN
1093: *
1094: * Path 4t (N much larger than M, JOBZ='A')
1095: * N right singular vectors to be computed in VT and
1096: * M left singular vectors to be computed in U
1097: *
1098: IVT = 1
1099: *
1100: * WORK(IVT) is M by M
1101: *
1102: LDWKVT = M
1103: ITAU = IVT + LDWKVT*M
1104: NWORK = ITAU + M
1105: *
1106: * Compute A=L*Q, copying result to VT
1107: * (Workspace: need M*M+2*M, prefer M*M+M+M*NB)
1108: *
1109: CALL DGELQF( M, N, A, LDA, WORK( ITAU ), WORK( NWORK ),
1110: $ LWORK-NWORK+1, IERR )
1111: CALL DLACPY( 'U', M, N, A, LDA, VT, LDVT )
1112: *
1113: * Generate Q in VT
1114: * (Workspace: need M*M+2*M, prefer M*M+M+M*NB)
1115: *
1116: CALL DORGLQ( N, N, M, VT, LDVT, WORK( ITAU ),
1117: $ WORK( NWORK ), LWORK-NWORK+1, IERR )
1118: *
1119: * Produce L in A, zeroing out other entries
1120: *
1121: CALL DLASET( 'U', M-1, M-1, ZERO, ZERO, A( 1, 2 ), LDA )
1122: IE = ITAU
1123: ITAUQ = IE + M
1124: ITAUP = ITAUQ + M
1125: NWORK = ITAUP + M
1126: *
1127: * Bidiagonalize L in A
1128: * (Workspace: need M*M+4*M, prefer M*M+3*M+2*M*NB)
1129: *
1130: CALL DGEBRD( M, M, A, LDA, S, WORK( IE ), WORK( ITAUQ ),
1131: $ WORK( ITAUP ), WORK( NWORK ), LWORK-NWORK+1,
1132: $ IERR )
1133: *
1134: * Perform bidiagonal SVD, computing left singular vectors
1135: * of bidiagonal matrix in U and computing right singular
1136: * vectors of bidiagonal matrix in WORK(IVT)
1137: * (Workspace: need M+M*M+BDSPAC)
1138: *
1139: CALL DBDSDC( 'U', 'I', M, S, WORK( IE ), U, LDU,
1140: $ WORK( IVT ), LDWKVT, DUM, IDUM,
1141: $ WORK( NWORK ), IWORK, INFO )
1142: *
1143: * Overwrite U by left singular vectors of L and WORK(IVT)
1144: * by right singular vectors of L
1145: * (Workspace: need M*M+3*M, prefer M*M+2*M+M*NB)
1146: *
1147: CALL DORMBR( 'Q', 'L', 'N', M, M, M, A, LDA,
1148: $ WORK( ITAUQ ), U, LDU, WORK( NWORK ),
1149: $ LWORK-NWORK+1, IERR )
1150: CALL DORMBR( 'P', 'R', 'T', M, M, M, A, LDA,
1151: $ WORK( ITAUP ), WORK( IVT ), LDWKVT,
1152: $ WORK( NWORK ), LWORK-NWORK+1, IERR )
1153: *
1154: * Multiply right singular vectors of L in WORK(IVT) by
1155: * Q in VT, storing result in A
1156: * (Workspace: need M*M)
1157: *
1158: CALL DGEMM( 'N', 'N', M, N, M, ONE, WORK( IVT ), LDWKVT,
1159: $ VT, LDVT, ZERO, A, LDA )
1160: *
1161: * Copy right singular vectors of A from A to VT
1162: *
1163: CALL DLACPY( 'F', M, N, A, LDA, VT, LDVT )
1164: *
1165: END IF
1166: *
1167: ELSE
1168: *
1169: * N .LT. MNTHR
1170: *
1171: * Path 5t (N greater than M, but not much larger)
1172: * Reduce to bidiagonal form without LQ decomposition
1173: *
1174: IE = 1
1175: ITAUQ = IE + M
1176: ITAUP = ITAUQ + M
1177: NWORK = ITAUP + M
1178: *
1179: * Bidiagonalize A
1180: * (Workspace: need 3*M+N, prefer 3*M+(M+N)*NB)
1181: *
1182: CALL DGEBRD( M, N, A, LDA, S, WORK( IE ), WORK( ITAUQ ),
1183: $ WORK( ITAUP ), WORK( NWORK ), LWORK-NWORK+1,
1184: $ IERR )
1185: IF( WNTQN ) THEN
1186: *
1187: * Perform bidiagonal SVD, only computing singular values
1188: * (Workspace: need M+BDSPAC)
1189: *
1190: CALL DBDSDC( 'L', 'N', M, S, WORK( IE ), DUM, 1, DUM, 1,
1191: $ DUM, IDUM, WORK( NWORK ), IWORK, INFO )
1192: ELSE IF( WNTQO ) THEN
1193: LDWKVT = M
1194: IVT = NWORK
1195: IF( LWORK.GE.M*N+3*M+BDSPAC ) THEN
1196: *
1197: * WORK( IVT ) is M by N
1198: *
1199: CALL DLASET( 'F', M, N, ZERO, ZERO, WORK( IVT ),
1200: $ LDWKVT )
1201: NWORK = IVT + LDWKVT*N
1202: ELSE
1203: *
1204: * WORK( IVT ) is M by M
1205: *
1206: NWORK = IVT + LDWKVT*M
1207: IL = NWORK
1208: *
1209: * WORK(IL) is M by CHUNK
1210: *
1211: CHUNK = ( LWORK-M*M-3*M ) / M
1212: END IF
1213: *
1214: * Perform bidiagonal SVD, computing left singular vectors
1215: * of bidiagonal matrix in U and computing right singular
1216: * vectors of bidiagonal matrix in WORK(IVT)
1217: * (Workspace: need M*M+BDSPAC)
1218: *
1219: CALL DBDSDC( 'L', 'I', M, S, WORK( IE ), U, LDU,
1220: $ WORK( IVT ), LDWKVT, DUM, IDUM,
1221: $ WORK( NWORK ), IWORK, INFO )
1222: *
1223: * Overwrite U by left singular vectors of A
1224: * (Workspace: need M*M+2*M, prefer M*M+M+M*NB)
1225: *
1226: CALL DORMBR( 'Q', 'L', 'N', M, M, N, A, LDA,
1227: $ WORK( ITAUQ ), U, LDU, WORK( NWORK ),
1228: $ LWORK-NWORK+1, IERR )
1229: *
1230: IF( LWORK.GE.M*N+3*M+BDSPAC ) THEN
1231: *
1232: * Overwrite WORK(IVT) by left singular vectors of A
1233: * (Workspace: need M*M+2*M, prefer M*M+M+M*NB)
1234: *
1235: CALL DORMBR( 'P', 'R', 'T', M, N, M, A, LDA,
1236: $ WORK( ITAUP ), WORK( IVT ), LDWKVT,
1237: $ WORK( NWORK ), LWORK-NWORK+1, IERR )
1238: *
1239: * Copy right singular vectors of A from WORK(IVT) to A
1240: *
1241: CALL DLACPY( 'F', M, N, WORK( IVT ), LDWKVT, A, LDA )
1242: ELSE
1243: *
1244: * Generate P**T in A
1245: * (Workspace: need M*M+2*M, prefer M*M+M+M*NB)
1246: *
1247: CALL DORGBR( 'P', M, N, M, A, LDA, WORK( ITAUP ),
1248: $ WORK( NWORK ), LWORK-NWORK+1, IERR )
1249: *
1250: * Multiply Q in A by right singular vectors of
1251: * bidiagonal matrix in WORK(IVT), storing result in
1252: * WORK(IL) and copying to A
1253: * (Workspace: need 2*M*M, prefer M*M+M*N)
1254: *
1255: DO 40 I = 1, N, CHUNK
1256: BLK = MIN( N-I+1, CHUNK )
1257: CALL DGEMM( 'N', 'N', M, BLK, M, ONE, WORK( IVT ),
1258: $ LDWKVT, A( 1, I ), LDA, ZERO,
1259: $ WORK( IL ), M )
1260: CALL DLACPY( 'F', M, BLK, WORK( IL ), M, A( 1, I ),
1261: $ LDA )
1262: 40 CONTINUE
1263: END IF
1264: ELSE IF( WNTQS ) THEN
1265: *
1266: * Perform bidiagonal SVD, computing left singular vectors
1267: * of bidiagonal matrix in U and computing right singular
1268: * vectors of bidiagonal matrix in VT
1269: * (Workspace: need M+BDSPAC)
1270: *
1271: CALL DLASET( 'F', M, N, ZERO, ZERO, VT, LDVT )
1272: CALL DBDSDC( 'L', 'I', M, S, WORK( IE ), U, LDU, VT,
1273: $ LDVT, DUM, IDUM, WORK( NWORK ), IWORK,
1274: $ INFO )
1275: *
1276: * Overwrite U by left singular vectors of A and VT
1277: * by right singular vectors of A
1278: * (Workspace: need 3*M, prefer 2*M+M*NB)
1279: *
1280: CALL DORMBR( 'Q', 'L', 'N', M, M, N, A, LDA,
1281: $ WORK( ITAUQ ), U, LDU, WORK( NWORK ),
1282: $ LWORK-NWORK+1, IERR )
1283: CALL DORMBR( 'P', 'R', 'T', M, N, M, A, LDA,
1284: $ WORK( ITAUP ), VT, LDVT, WORK( NWORK ),
1285: $ LWORK-NWORK+1, IERR )
1286: ELSE IF( WNTQA ) THEN
1287: *
1288: * Perform bidiagonal SVD, computing left singular vectors
1289: * of bidiagonal matrix in U and computing right singular
1290: * vectors of bidiagonal matrix in VT
1291: * (Workspace: need M+BDSPAC)
1292: *
1293: CALL DLASET( 'F', N, N, ZERO, ZERO, VT, LDVT )
1294: CALL DBDSDC( 'L', 'I', M, S, WORK( IE ), U, LDU, VT,
1295: $ LDVT, DUM, IDUM, WORK( NWORK ), IWORK,
1296: $ INFO )
1297: *
1298: * Set the right corner of VT to identity matrix
1299: *
1300: IF( N.GT.M ) THEN
1301: CALL DLASET( 'F', N-M, N-M, ZERO, ONE, VT( M+1, M+1 ),
1302: $ LDVT )
1303: END IF
1304: *
1305: * Overwrite U by left singular vectors of A and VT
1306: * by right singular vectors of A
1307: * (Workspace: need 2*M+N, prefer 2*M+N*NB)
1308: *
1309: CALL DORMBR( 'Q', 'L', 'N', M, M, N, A, LDA,
1310: $ WORK( ITAUQ ), U, LDU, WORK( NWORK ),
1311: $ LWORK-NWORK+1, IERR )
1312: CALL DORMBR( 'P', 'R', 'T', N, N, M, A, LDA,
1313: $ WORK( ITAUP ), VT, LDVT, WORK( NWORK ),
1314: $ LWORK-NWORK+1, IERR )
1315: END IF
1316: *
1317: END IF
1318: *
1319: END IF
1320: *
1321: * Undo scaling if necessary
1322: *
1323: IF( ISCL.EQ.1 ) THEN
1324: IF( ANRM.GT.BIGNUM )
1325: $ CALL DLASCL( 'G', 0, 0, BIGNUM, ANRM, MINMN, 1, S, MINMN,
1326: $ IERR )
1327: IF( ANRM.LT.SMLNUM )
1328: $ CALL DLASCL( 'G', 0, 0, SMLNUM, ANRM, MINMN, 1, S, MINMN,
1329: $ IERR )
1330: END IF
1331: *
1332: * Return optimal workspace in WORK(1)
1333: *
1334: WORK( 1 ) = MAXWRK
1335: *
1336: RETURN
1337: *
1338: * End of DGESDD
1339: *
1340: END
CVSweb interface <joel.bertrand@systella.fr>