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