KTH framework for Nek5000 toolboxes; testing version  0.0.1
dgelss.f
Go to the documentation of this file.
1  SUBROUTINE dgelss( M, N, NRHS, A, LDA, B, LDB, S, RCOND, RANK,
2  $ WORK, LWORK, INFO )
3 *
4 * -- LAPACK driver routine (version 3.0) --
5 * Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
6 * Courant Institute, Argonne National Lab, and Rice University
7 * October 31, 1999
8 *
9 * .. Scalar Arguments ..
10  INTEGER INFO, LDA, LDB, LWORK, M, N, NRHS, RANK
11  DOUBLE PRECISION RCOND
12 * ..
13 * .. Array Arguments ..
14  DOUBLE PRECISION A( LDA, * ), B( LDB, * ), S( * ), WORK( * )
15 * ..
16 *
17 * Purpose
18 * =======
19 *
20 * DGELSS computes the minimum norm solution to a real linear least
21 * squares problem:
22 *
23 * Minimize 2-norm(| b - A*x |).
24 *
25 * using the singular value decomposition (SVD) of A. A is an M-by-N
26 * matrix which may be rank-deficient.
27 *
28 * Several right hand side vectors b and solution vectors x can be
29 * handled in a single call; they are stored as the columns of the
30 * M-by-NRHS right hand side matrix B and the N-by-NRHS solution matrix
31 * X.
32 *
33 * The effective rank of A is determined by treating as zero those
34 * singular values which are less than RCOND times the largest singular
35 * value.
36 *
37 * Arguments
38 * =========
39 *
40 * M (input) INTEGER
41 * The number of rows of the matrix A. M >= 0.
42 *
43 * N (input) INTEGER
44 * The number of columns of the matrix A. N >= 0.
45 *
46 * NRHS (input) INTEGER
47 * The number of right hand sides, i.e., the number of columns
48 * of the matrices B and X. NRHS >= 0.
49 *
50 * A (input/output) DOUBLE PRECISION array, dimension (LDA,N)
51 * On entry, the M-by-N matrix A.
52 * On exit, the first min(m,n) rows of A are overwritten with
53 * its right singular vectors, stored rowwise.
54 *
55 * LDA (input) INTEGER
56 * The leading dimension of the array A. LDA >= max(1,M).
57 *
58 * B (input/output) DOUBLE PRECISION array, dimension (LDB,NRHS)
59 * On entry, the M-by-NRHS right hand side matrix B.
60 * On exit, B is overwritten by the N-by-NRHS solution
61 * matrix X. If m >= n and RANK = n, the residual
62 * sum-of-squares for the solution in the i-th column is given
63 * by the sum of squares of elements n+1:m in that column.
64 *
65 * LDB (input) INTEGER
66 * The leading dimension of the array B. LDB >= max(1,max(M,N)).
67 *
68 * S (output) DOUBLE PRECISION array, dimension (min(M,N))
69 * The singular values of A in decreasing order.
70 * The condition number of A in the 2-norm = S(1)/S(min(m,n)).
71 *
72 * RCOND (input) DOUBLE PRECISION
73 * RCOND is used to determine the effective rank of A.
74 * Singular values S(i) <= RCOND*S(1) are treated as zero.
75 * If RCOND < 0, machine precision is used instead.
76 *
77 * RANK (output) INTEGER
78 * The effective rank of A, i.e., the number of singular values
79 * which are greater than RCOND*S(1).
80 *
81 * WORK (workspace/output) DOUBLE PRECISION array, dimension (LWORK)
82 * On exit, if INFO = 0, WORK(1) returns the optimal LWORK.
83 *
84 * LWORK (input) INTEGER
85 * The dimension of the array WORK. LWORK >= 1, and also:
86 * LWORK >= 3*min(M,N) + max( 2*min(M,N), max(M,N), NRHS )
87 * For good performance, LWORK should generally be larger.
88 *
89 * If LWORK = -1, then a workspace query is assumed; the routine
90 * only calculates the optimal size of the WORK array, returns
91 * this value as the first entry of the WORK array, and no error
92 * message related to LWORK is issued by XERBLA.
93 *
94 * INFO (output) INTEGER
95 * = 0: successful exit
96 * < 0: if INFO = -i, the i-th argument had an illegal value.
97 * > 0: the algorithm for computing the SVD failed to converge;
98 * if INFO = i, i off-diagonal elements of an intermediate
99 * bidiagonal form did not converge to zero.
100 *
101 * =====================================================================
102 *
103 * .. Parameters ..
104  DOUBLE PRECISION ZERO, ONE
105  parameter( zero = 0.0d+0, one = 1.0d+0 )
106 * ..
107 * .. Local Scalars ..
108  LOGICAL LQUERY
109  INTEGER BDSPAC, BL, CHUNK, I, IASCL, IBSCL, IE, IL,
110  $ itau, itaup, itauq, iwork, ldwork, maxmn,
111  $ maxwrk, minmn, minwrk, mm, mnthr
112  DOUBLE PRECISION ANRM, BIGNUM, BNRM, EPS, SFMIN, SMLNUM, THR
113 * ..
114 * .. Local Arrays ..
115  DOUBLE PRECISION VDUM( 1 )
116 * ..
117 * .. External Subroutines ..
118  EXTERNAL dbdsqr, dcopy, dgebrd, dgelqf, dgemm, dgemv,
121 * ..
122 * .. External Functions ..
123  INTEGER ILAENV
124  DOUBLE PRECISION DLAMCH, DLANGE
125  EXTERNAL ilaenv, dlamch, dlange
126 * ..
127 * .. Intrinsic Functions ..
128  INTRINSIC max, min
129 * ..
130 * .. Executable Statements ..
131 *
132 * Test the input arguments
133 *
134  info = 0
135  minmn = min( m, n )
136  maxmn = max( m, n )
137  mnthr = ilaenv( 6, 'DGELSS', ' ', m, n, nrhs, -1 )
138  lquery = ( lwork.EQ.-1 )
139  IF( m.LT.0 ) THEN
140  info = -1
141  ELSE IF( n.LT.0 ) THEN
142  info = -2
143  ELSE IF( nrhs.LT.0 ) THEN
144  info = -3
145  ELSE IF( lda.LT.max( 1, m ) ) THEN
146  info = -5
147  ELSE IF( ldb.LT.max( 1, maxmn ) ) THEN
148  info = -7
149  END IF
150 *
151 * Compute workspace
152 * (Note: Comments in the code beginning "Workspace:" describe the
153 * minimal amount of workspace needed at that point in the code,
154 * as well as the preferred amount for good performance.
155 * NB refers to the optimal block size for the immediately
156 * following subroutine, as returned by ILAENV.)
157 *
158  minwrk = 1
159  IF( info.EQ.0 .AND. ( lwork.GE.1 .OR. lquery ) ) THEN
160  maxwrk = 0
161  mm = m
162  IF( m.GE.n .AND. m.GE.mnthr ) THEN
163 *
164 * Path 1a - overdetermined, with many more rows than columns
165 *
166  mm = n
167  maxwrk = max( maxwrk, n+n*ilaenv( 1, 'DGEQRF', ' ', m, n,
168  $ -1, -1 ) )
169  maxwrk = max( maxwrk, n+nrhs*
170  $ ilaenv( 1, 'DORMQR', 'LT', m, nrhs, n, -1 ) )
171  END IF
172  IF( m.GE.n ) THEN
173 *
174 * Path 1 - overdetermined or exactly determined
175 *
176 * Compute workspace needed for DBDSQR
177 *
178  bdspac = max( 1, 5*n )
179  maxwrk = max( maxwrk, 3*n+( mm+n )*
180  $ ilaenv( 1, 'DGEBRD', ' ', mm, n, -1, -1 ) )
181  maxwrk = max( maxwrk, 3*n+nrhs*
182  $ ilaenv( 1, 'DORMBR', 'QLT', mm, nrhs, n, -1 ) )
183  maxwrk = max( maxwrk, 3*n+( n-1 )*
184  $ ilaenv( 1, 'DORGBR', 'P', n, n, n, -1 ) )
185  maxwrk = max( maxwrk, bdspac )
186  maxwrk = max( maxwrk, n*nrhs )
187  minwrk = max( 3*n+mm, 3*n+nrhs, bdspac )
188  maxwrk = max( minwrk, maxwrk )
189  END IF
190  IF( n.GT.m ) THEN
191 *
192 * Compute workspace needed for DBDSQR
193 *
194  bdspac = max( 1, 5*m )
195  minwrk = max( 3*m+nrhs, 3*m+n, bdspac )
196  IF( n.GE.mnthr ) THEN
197 *
198 * Path 2a - underdetermined, with many more columns
199 * than rows
200 *
201  maxwrk = m + m*ilaenv( 1, 'DGELQF', ' ', m, n, -1, -1 )
202  maxwrk = max( maxwrk, m*m+4*m+2*m*
203  $ ilaenv( 1, 'DGEBRD', ' ', m, m, -1, -1 ) )
204  maxwrk = max( maxwrk, m*m+4*m+nrhs*
205  $ ilaenv( 1, 'DORMBR', 'QLT', m, nrhs, m, -1 ) )
206  maxwrk = max( maxwrk, m*m+4*m+( m-1 )*
207  $ ilaenv( 1, 'DORGBR', 'P', m, m, m, -1 ) )
208  maxwrk = max( maxwrk, m*m+m+bdspac )
209  IF( nrhs.GT.1 ) THEN
210  maxwrk = max( maxwrk, m*m+m+m*nrhs )
211  ELSE
212  maxwrk = max( maxwrk, m*m+2*m )
213  END IF
214  maxwrk = max( maxwrk, m+nrhs*
215  $ ilaenv( 1, 'DORMLQ', 'LT', n, nrhs, m, -1 ) )
216  ELSE
217 *
218 * Path 2 - underdetermined
219 *
220  maxwrk = 3*m + ( n+m )*ilaenv( 1, 'DGEBRD', ' ', m, n,
221  $ -1, -1 )
222  maxwrk = max( maxwrk, 3*m+nrhs*
223  $ ilaenv( 1, 'DORMBR', 'QLT', m, nrhs, m, -1 ) )
224  maxwrk = max( maxwrk, 3*m+m*
225  $ ilaenv( 1, 'DORGBR', 'P', m, n, m, -1 ) )
226  maxwrk = max( maxwrk, bdspac )
227  maxwrk = max( maxwrk, n*nrhs )
228  END IF
229  END IF
230  maxwrk = max( minwrk, maxwrk )
231  work( 1 ) = maxwrk
232  END IF
233 *
234  minwrk = max( minwrk, 1 )
235  IF( lwork.LT.minwrk .AND. .NOT.lquery )
236  $ info = -12
237  IF( info.NE.0 ) THEN
238  CALL xerbla( 'DGELSS', -info )
239  RETURN
240  ELSE IF( lquery ) THEN
241  RETURN
242  END IF
243 *
244 * Quick return if possible
245 *
246  IF( m.EQ.0 .OR. n.EQ.0 ) THEN
247  rank = 0
248  RETURN
249  END IF
250 *
251 * Get machine parameters
252 *
253  eps = dlamch( 'P' )
254  sfmin = dlamch( 'S' )
255  smlnum = sfmin / eps
256  bignum = one / smlnum
257  CALL dlabad( smlnum, bignum )
258 *
259 * Scale A if max element outside range [SMLNUM,BIGNUM]
260 *
261  anrm = dlange( 'M', m, n, a, lda, work )
262  iascl = 0
263  IF( anrm.GT.zero .AND. anrm.LT.smlnum ) THEN
264 *
265 * Scale matrix norm up to SMLNUM
266 *
267  CALL dlascl( 'G', 0, 0, anrm, smlnum, m, n, a, lda, info )
268  iascl = 1
269  ELSE IF( anrm.GT.bignum ) THEN
270 *
271 * Scale matrix norm down to BIGNUM
272 *
273  CALL dlascl( 'G', 0, 0, anrm, bignum, m, n, a, lda, info )
274  iascl = 2
275  ELSE IF( anrm.EQ.zero ) THEN
276 *
277 * Matrix all zero. Return zero solution.
278 *
279  CALL dlaset( 'F', max( m, n ), nrhs, zero, zero, b, ldb )
280  CALL dlaset( 'F', minmn, 1, zero, zero, s, 1 )
281  rank = 0
282  GO TO 70
283  END IF
284 *
285 * Scale B if max element outside range [SMLNUM,BIGNUM]
286 *
287  bnrm = dlange( 'M', m, nrhs, b, ldb, work )
288  ibscl = 0
289  IF( bnrm.GT.zero .AND. bnrm.LT.smlnum ) THEN
290 *
291 * Scale matrix norm up to SMLNUM
292 *
293  CALL dlascl( 'G', 0, 0, bnrm, smlnum, m, nrhs, b, ldb, info )
294  ibscl = 1
295  ELSE IF( bnrm.GT.bignum ) THEN
296 *
297 * Scale matrix norm down to BIGNUM
298 *
299  CALL dlascl( 'G', 0, 0, bnrm, bignum, m, nrhs, b, ldb, info )
300  ibscl = 2
301  END IF
302 *
303 * Overdetermined case
304 *
305  IF( m.GE.n ) THEN
306 *
307 * Path 1 - overdetermined or exactly determined
308 *
309  mm = m
310  IF( m.GE.mnthr ) THEN
311 *
312 * Path 1a - overdetermined, with many more rows than columns
313 *
314  mm = n
315  itau = 1
316  iwork = itau + n
317 *
318 * Compute A=Q*R
319 * (Workspace: need 2*N, prefer N+N*NB)
320 *
321  CALL dgeqrf( m, n, a, lda, work( itau ), work( iwork ),
322  $ lwork-iwork+1, info )
323 *
324 * Multiply B by transpose(Q)
325 * (Workspace: need N+NRHS, prefer N+NRHS*NB)
326 *
327  CALL dormqr( 'L', 'T', m, nrhs, n, a, lda, work( itau ), b,
328  $ ldb, work( iwork ), lwork-iwork+1, info )
329 *
330 * Zero out below R
331 *
332  IF( n.GT.1 )
333  $ CALL dlaset( 'L', n-1, n-1, zero, zero, a( 2, 1 ), lda )
334  END IF
335 *
336  ie = 1
337  itauq = ie + n
338  itaup = itauq + n
339  iwork = itaup + n
340 *
341 * Bidiagonalize R in A
342 * (Workspace: need 3*N+MM, prefer 3*N+(MM+N)*NB)
343 *
344  CALL dgebrd( mm, n, a, lda, s, work( ie ), work( itauq ),
345  $ work( itaup ), work( iwork ), lwork-iwork+1,
346  $ info )
347 *
348 * Multiply B by transpose of left bidiagonalizing vectors of R
349 * (Workspace: need 3*N+NRHS, prefer 3*N+NRHS*NB)
350 *
351  CALL dormbr( 'Q', 'L', 'T', mm, nrhs, n, a, lda, work( itauq ),
352  $ b, ldb, work( iwork ), lwork-iwork+1, info )
353 *
354 * Generate right bidiagonalizing vectors of R in A
355 * (Workspace: need 4*N-1, prefer 3*N+(N-1)*NB)
356 *
357  CALL dorgbr( 'P', n, n, n, a, lda, work( itaup ),
358  $ work( iwork ), lwork-iwork+1, info )
359  iwork = ie + n
360 *
361 * Perform bidiagonal QR iteration
362 * multiply B by transpose of left singular vectors
363 * compute right singular vectors in A
364 * (Workspace: need BDSPAC)
365 *
366  CALL dbdsqr( 'U', n, n, 0, nrhs, s, work( ie ), a, lda, vdum,
367  $ 1, b, ldb, work( iwork ), info )
368  IF( info.NE.0 )
369  $ GO TO 70
370 *
371 * Multiply B by reciprocals of singular values
372 *
373  thr = max( rcond*s( 1 ), sfmin )
374  IF( rcond.LT.zero )
375  $ thr = max( eps*s( 1 ), sfmin )
376  rank = 0
377  DO 10 i = 1, n
378  IF( s( i ).GT.thr ) THEN
379  CALL drscl( nrhs, s( i ), b( i, 1 ), ldb )
380  rank = rank + 1
381  ELSE
382  CALL dlaset( 'F', 1, nrhs, zero, zero, b( i, 1 ), ldb )
383  END IF
384  10 CONTINUE
385 *
386 * Multiply B by right singular vectors
387 * (Workspace: need N, prefer N*NRHS)
388 *
389  IF( lwork.GE.ldb*nrhs .AND. nrhs.GT.1 ) THEN
390  CALL dgemm( 'T', 'N', n, nrhs, n, one, a, lda, b, ldb, zero,
391  $ work, ldb )
392  CALL dlacpy( 'G', n, nrhs, work, ldb, b, ldb )
393  ELSE IF( nrhs.GT.1 ) THEN
394  chunk = lwork / n
395  DO 20 i = 1, nrhs, chunk
396  bl = min( nrhs-i+1, chunk )
397  CALL dgemm( 'T', 'N', n, bl, n, one, a, lda, b( 1, i ),
398  $ ldb, zero, work, n )
399  CALL dlacpy( 'G', n, bl, work, n, b( 1, i ), ldb )
400  20 CONTINUE
401  ELSE
402  CALL dgemv( 'T', n, n, one, a, lda, b, 1, zero, work, 1 )
403  CALL dcopy( n, work, 1, b, 1 )
404  END IF
405 *
406  ELSE IF( n.GE.mnthr .AND. lwork.GE.4*m+m*m+
407  $ max( m, 2*m-4, nrhs, n-3*m ) ) THEN
408 *
409 * Path 2a - underdetermined, with many more columns than rows
410 * and sufficient workspace for an efficient algorithm
411 *
412  ldwork = m
413  IF( lwork.GE.max( 4*m+m*lda+max( m, 2*m-4, nrhs, n-3*m ),
414  $ m*lda+m+m*nrhs ) )ldwork = lda
415  itau = 1
416  iwork = m + 1
417 *
418 * Compute A=L*Q
419 * (Workspace: need 2*M, prefer M+M*NB)
420 *
421  CALL dgelqf( m, n, a, lda, work( itau ), work( iwork ),
422  $ lwork-iwork+1, info )
423  il = iwork
424 *
425 * Copy L to WORK(IL), zeroing out above it
426 *
427  CALL dlacpy( 'L', m, m, a, lda, work( il ), ldwork )
428  CALL dlaset( 'U', m-1, m-1, zero, zero, work( il+ldwork ),
429  $ ldwork )
430  ie = il + ldwork*m
431  itauq = ie + m
432  itaup = itauq + m
433  iwork = itaup + m
434 *
435 * Bidiagonalize L in WORK(IL)
436 * (Workspace: need M*M+5*M, prefer M*M+4*M+2*M*NB)
437 *
438  CALL dgebrd( m, m, work( il ), ldwork, s, work( ie ),
439  $ work( itauq ), work( itaup ), work( iwork ),
440  $ lwork-iwork+1, info )
441 *
442 * Multiply B by transpose of left bidiagonalizing vectors of L
443 * (Workspace: need M*M+4*M+NRHS, prefer M*M+4*M+NRHS*NB)
444 *
445  CALL dormbr( 'Q', 'L', 'T', m, nrhs, m, work( il ), ldwork,
446  $ work( itauq ), b, ldb, work( iwork ),
447  $ lwork-iwork+1, info )
448 *
449 * Generate right bidiagonalizing vectors of R in WORK(IL)
450 * (Workspace: need M*M+5*M-1, prefer M*M+4*M+(M-1)*NB)
451 *
452  CALL dorgbr( 'P', m, m, m, work( il ), ldwork, work( itaup ),
453  $ work( iwork ), lwork-iwork+1, info )
454  iwork = ie + m
455 *
456 * Perform bidiagonal QR iteration,
457 * computing right singular vectors of L in WORK(IL) and
458 * multiplying B by transpose of left singular vectors
459 * (Workspace: need M*M+M+BDSPAC)
460 *
461  CALL dbdsqr( 'U', m, m, 0, nrhs, s, work( ie ), work( il ),
462  $ ldwork, a, lda, b, ldb, work( iwork ), info )
463  IF( info.NE.0 )
464  $ GO TO 70
465 *
466 * Multiply B by reciprocals of singular values
467 *
468  thr = max( rcond*s( 1 ), sfmin )
469  IF( rcond.LT.zero )
470  $ thr = max( eps*s( 1 ), sfmin )
471  rank = 0
472  DO 30 i = 1, m
473  IF( s( i ).GT.thr ) THEN
474  CALL drscl( nrhs, s( i ), b( i, 1 ), ldb )
475  rank = rank + 1
476  ELSE
477  CALL dlaset( 'F', 1, nrhs, zero, zero, b( i, 1 ), ldb )
478  END IF
479  30 CONTINUE
480  iwork = ie
481 *
482 * Multiply B by right singular vectors of L in WORK(IL)
483 * (Workspace: need M*M+2*M, prefer M*M+M+M*NRHS)
484 *
485  IF( lwork.GE.ldb*nrhs+iwork-1 .AND. nrhs.GT.1 ) THEN
486  CALL dgemm( 'T', 'N', m, nrhs, m, one, work( il ), ldwork,
487  $ b, ldb, zero, work( iwork ), ldb )
488  CALL dlacpy( 'G', m, nrhs, work( iwork ), ldb, b, ldb )
489  ELSE IF( nrhs.GT.1 ) THEN
490  chunk = ( lwork-iwork+1 ) / m
491  DO 40 i = 1, nrhs, chunk
492  bl = min( nrhs-i+1, chunk )
493  CALL dgemm( 'T', 'N', m, bl, m, one, work( il ), ldwork,
494  $ b( 1, i ), ldb, zero, work( iwork ), n )
495  CALL dlacpy( 'G', m, bl, work( iwork ), n, b( 1, i ),
496  $ ldb )
497  40 CONTINUE
498  ELSE
499  CALL dgemv( 'T', m, m, one, work( il ), ldwork, b( 1, 1 ),
500  $ 1, zero, work( iwork ), 1 )
501  CALL dcopy( m, work( iwork ), 1, b( 1, 1 ), 1 )
502  END IF
503 *
504 * Zero out below first M rows of B
505 *
506  CALL dlaset( 'F', n-m, nrhs, zero, zero, b( m+1, 1 ), ldb )
507  iwork = itau + m
508 *
509 * Multiply transpose(Q) by B
510 * (Workspace: need M+NRHS, prefer M+NRHS*NB)
511 *
512  CALL dormlq( 'L', 'T', n, nrhs, m, a, lda, work( itau ), b,
513  $ ldb, work( iwork ), lwork-iwork+1, info )
514 *
515  ELSE
516 *
517 * Path 2 - remaining underdetermined cases
518 *
519  ie = 1
520  itauq = ie + m
521  itaup = itauq + m
522  iwork = itaup + m
523 *
524 * Bidiagonalize A
525 * (Workspace: need 3*M+N, prefer 3*M+(M+N)*NB)
526 *
527  CALL dgebrd( m, n, a, lda, s, work( ie ), work( itauq ),
528  $ work( itaup ), work( iwork ), lwork-iwork+1,
529  $ info )
530 *
531 * Multiply B by transpose of left bidiagonalizing vectors
532 * (Workspace: need 3*M+NRHS, prefer 3*M+NRHS*NB)
533 *
534  CALL dormbr( 'Q', 'L', 'T', m, nrhs, n, a, lda, work( itauq ),
535  $ b, ldb, work( iwork ), lwork-iwork+1, info )
536 *
537 * Generate right bidiagonalizing vectors in A
538 * (Workspace: need 4*M, prefer 3*M+M*NB)
539 *
540  CALL dorgbr( 'P', m, n, m, a, lda, work( itaup ),
541  $ work( iwork ), lwork-iwork+1, info )
542  iwork = ie + m
543 *
544 * Perform bidiagonal QR iteration,
545 * computing right singular vectors of A in A and
546 * multiplying B by transpose of left singular vectors
547 * (Workspace: need BDSPAC)
548 *
549  CALL dbdsqr( 'L', m, n, 0, nrhs, s, work( ie ), a, lda, vdum,
550  $ 1, b, ldb, work( iwork ), info )
551  IF( info.NE.0 )
552  $ GO TO 70
553 *
554 * Multiply B by reciprocals of singular values
555 *
556  thr = max( rcond*s( 1 ), sfmin )
557  IF( rcond.LT.zero )
558  $ thr = max( eps*s( 1 ), sfmin )
559  rank = 0
560  DO 50 i = 1, m
561  IF( s( i ).GT.thr ) THEN
562  CALL drscl( nrhs, s( i ), b( i, 1 ), ldb )
563  rank = rank + 1
564  ELSE
565  CALL dlaset( 'F', 1, nrhs, zero, zero, b( i, 1 ), ldb )
566  END IF
567  50 CONTINUE
568 *
569 * Multiply B by right singular vectors of A
570 * (Workspace: need N, prefer N*NRHS)
571 *
572  IF( lwork.GE.ldb*nrhs .AND. nrhs.GT.1 ) THEN
573  CALL dgemm( 'T', 'N', n, nrhs, m, one, a, lda, b, ldb, zero,
574  $ work, ldb )
575  CALL dlacpy( 'F', n, nrhs, work, ldb, b, ldb )
576  ELSE IF( nrhs.GT.1 ) THEN
577  chunk = lwork / n
578  DO 60 i = 1, nrhs, chunk
579  bl = min( nrhs-i+1, chunk )
580  CALL dgemm( 'T', 'N', n, bl, m, one, a, lda, b( 1, i ),
581  $ ldb, zero, work, n )
582  CALL dlacpy( 'F', n, bl, work, n, b( 1, i ), ldb )
583  60 CONTINUE
584  ELSE
585  CALL dgemv( 'T', m, n, one, a, lda, b, 1, zero, work, 1 )
586  CALL dcopy( n, work, 1, b, 1 )
587  END IF
588  END IF
589 *
590 * Undo scaling
591 *
592  IF( iascl.EQ.1 ) THEN
593  CALL dlascl( 'G', 0, 0, anrm, smlnum, n, nrhs, b, ldb, info )
594  CALL dlascl( 'G', 0, 0, smlnum, anrm, minmn, 1, s, minmn,
595  $ info )
596  ELSE IF( iascl.EQ.2 ) THEN
597  CALL dlascl( 'G', 0, 0, anrm, bignum, n, nrhs, b, ldb, info )
598  CALL dlascl( 'G', 0, 0, bignum, anrm, minmn, 1, s, minmn,
599  $ info )
600  END IF
601  IF( ibscl.EQ.1 ) THEN
602  CALL dlascl( 'G', 0, 0, smlnum, bnrm, n, nrhs, b, ldb, info )
603  ELSE IF( ibscl.EQ.2 ) THEN
604  CALL dlascl( 'G', 0, 0, bignum, bnrm, n, nrhs, b, ldb, info )
605  END IF
606 *
607  70 CONTINUE
608  work( 1 ) = maxwrk
609  RETURN
610 *
611 * End of DGELSS
612 *
613  END
subroutine dbdsqr(UPLO, N, NCVT, NRU, NCC, D, E, VT, LDVT, U, LDU, C, LDC, WORK, INFO)
Definition: dbdsqr.f:3
subroutine dcopy(n, dx, incx, dy, incy)
Definition: dcopy.f:2
subroutine dgebrd(M, N, A, LDA, D, E, TAUQ, TAUP, WORK, LWORK, INFO)
Definition: dgebrd.f:3
subroutine dgelqf(M, N, A, LDA, TAU, WORK, LWORK, INFO)
Definition: dgelqf.f:2
subroutine dgelss(M, N, NRHS, A, LDA, B, LDB, S, RCOND, RANK, WORK, LWORK, INFO)
Definition: dgelss.f:3
subroutine dgemm(TRANSA, TRANSB, M, N, K, ALPHA, A, LDA, B, LDB, BETA, C, LDC)
Definition: dgemm.f:3
subroutine dgemv(TRANS, M, N, ALPHA, A, LDA, X, INCX, BETA, Y, INCY)
Definition: dgemv.f:3
subroutine dgeqrf(M, N, A, LDA, TAU, WORK, LWORK, INFO)
Definition: dgeqrf.f:2
subroutine dlabad(SMALL, LARGE)
Definition: dlabad.f:2
subroutine dlacpy(UPLO, M, N, A, LDA, B, LDB)
Definition: dlacpy.f:2
subroutine dlascl(TYPE, KL, KU, CFROM, CTO, M, N, A, LDA, INFO)
Definition: dlascl.f:2
subroutine dlaset(UPLO, M, N, ALPHA, BETA, A, LDA)
Definition: dlaset.f:2
subroutine dorgbr(VECT, M, N, K, A, LDA, TAU, WORK, LWORK, INFO)
Definition: dorgbr.f:2
subroutine dormbr(VECT, SIDE, TRANS, M, N, K, A, LDA, TAU, C, LDC, WORK, LWORK, INFO)
Definition: dormbr.f:3
subroutine dormlq(SIDE, TRANS, M, N, K, A, LDA, TAU, C, LDC, WORK, LWORK, INFO)
Definition: dormlq.f:3
subroutine dormqr(SIDE, TRANS, M, N, K, A, LDA, TAU, C, LDC, WORK, LWORK, INFO)
Definition: dormqr.f:3
subroutine drscl(N, SA, SX, INCX)
Definition: drscl.f:2
subroutine xerbla(SRNAME, INFO)
Definition: xerbla.f:2