202
203
204
205
206
207
208 INTEGER INFO, LDA, LDB, LWORK, M, N, NRHS, RANK
209 REAL RCOND
210
211
212 INTEGER IWORK( * )
213 REAL A( LDA, * ), B( LDB, * ), S( * ), WORK( * )
214
215
216
217
218
219 REAL ZERO, ONE, TWO
220 parameter( zero = 0.0e0, one = 1.0e0, two = 2.0e0 )
221
222
223 LOGICAL LQUERY
224 INTEGER IASCL, IBSCL, IE, IL, ITAU, ITAUP, ITAUQ,
225 $ LDWORK, LIWORK, MAXMN, MAXWRK, MINMN, MINWRK,
226 $ MM, MNTHR, NLVL, NWORK, SMLSIZ, WLALSD
227 REAL ANRM, BIGNUM, BNRM, EPS, SFMIN, SMLNUM
228
229
233
234
235 INTEGER ILAENV
236 REAL SLAMCH, SLANGE, SROUNDUP_LWORK
239
240
241 INTRINSIC int, log, max, min, real
242
243
244
245
246
247 info = 0
248 minmn = min( m, n )
249 maxmn = max( m, n )
250 lquery = ( lwork.EQ.-1 )
251 IF( m.LT.0 ) THEN
252 info = -1
253 ELSE IF( n.LT.0 ) THEN
254 info = -2
255 ELSE IF( nrhs.LT.0 ) THEN
256 info = -3
257 ELSE IF( lda.LT.max( 1, m ) ) THEN
258 info = -5
259 ELSE IF( ldb.LT.max( 1, maxmn ) ) THEN
260 info = -7
261 END IF
262
263
264
265
266
267
268
269
270 IF( info.EQ.0 ) THEN
271 minwrk = 1
272 maxwrk = 1
273 liwork = 1
274 IF( minmn.GT.0 ) THEN
275 smlsiz =
ilaenv( 9,
'SGELSD',
' ', 0, 0, 0, 0 )
276 mnthr =
ilaenv( 6,
'SGELSD',
' ', m, n, nrhs, -1 )
277 nlvl = max( int( log( real( minmn ) / real( smlsiz + 1 ) ) /
278 $ log( two ) ) + 1, 0 )
279 liwork = 3*minmn*nlvl + 11*minmn
280 mm = m
281 IF( m.GE.n .AND. m.GE.mnthr ) THEN
282
283
284
285
286 mm = n
287 maxwrk = max( maxwrk, n + n*
ilaenv( 1,
'SGEQRF',
' ',
288 $ m,
289 $ n, -1, -1 ) )
290 maxwrk = max( maxwrk, n + nrhs*
ilaenv( 1,
'SORMQR',
291 $ 'LT',
292 $ m, nrhs, n, -1 ) )
293 END IF
294 IF( m.GE.n ) THEN
295
296
297
298 maxwrk = max( maxwrk, 3*n + ( mm + n )*
ilaenv( 1,
299 $ 'SGEBRD', ' ', mm, n, -1, -1 ) )
300 maxwrk = max( maxwrk, 3*n + nrhs*
ilaenv( 1,
'SORMBR',
301 $ 'QLT', mm, nrhs, n, -1 ) )
302 maxwrk = max( maxwrk, 3*n + ( n - 1 )*
ilaenv( 1,
303 $ 'SORMBR', 'PLN', n, nrhs, n, -1 ) )
304 wlalsd = 9*n + 2*n*smlsiz + 8*n*nlvl + n*nrhs +
305 $ ( smlsiz + 1 )**2
306 maxwrk = max( maxwrk, 3*n + wlalsd )
307 minwrk = max( 3*n + mm, 3*n + nrhs, 3*n + wlalsd )
308 END IF
309 IF( n.GT.m ) THEN
310 wlalsd = 9*m + 2*m*smlsiz + 8*m*nlvl + m*nrhs +
311 $ ( smlsiz + 1 )**2
312 IF( n.GE.mnthr ) THEN
313
314
315
316
317 maxwrk = m + m*
ilaenv( 1,
'SGELQF',
' ', m, n, -1,
318 $ -1 )
319 maxwrk = max( maxwrk, m*m + 4*m + 2*m*
ilaenv( 1,
320 $ 'SGEBRD', ' ', m, m, -1, -1 ) )
321 maxwrk = max( maxwrk, m*m + 4*m + nrhs*
ilaenv( 1,
322 $ 'SORMBR', 'QLT', m, nrhs, m, -1 ) )
323 maxwrk = max( maxwrk,
324 $ m*m + 4*m + ( m - 1 )*
ilaenv( 1,
325 $ 'SORMBR', 'PLN', m, nrhs, m, -1 ) )
326 IF( nrhs.GT.1 ) THEN
327 maxwrk = max( maxwrk, m*m + m + m*nrhs )
328 ELSE
329 maxwrk = max( maxwrk, m*m + 2*m )
330 END IF
331 maxwrk = max( maxwrk, m + nrhs*
ilaenv( 1,
'SORMLQ',
332 $ 'LT', n, nrhs, m, -1 ) )
333 maxwrk = max( maxwrk, m*m + 4*m + wlalsd )
334
335
336 maxwrk = max( maxwrk,
337 $ 4*m+m*m+max( m, 2*m-4, nrhs, n-3*m ) )
338 ELSE
339
340
341
342 maxwrk = 3*m + ( n + m )*
ilaenv( 1,
'SGEBRD',
' ',
343 $ m,
344 $ n, -1, -1 )
345 maxwrk = max( maxwrk, 3*m + nrhs*
ilaenv( 1,
346 $ 'SORMBR',
347 $ 'QLT', m, nrhs, n, -1 ) )
348 maxwrk = max( maxwrk, 3*m + m*
ilaenv( 1,
'SORMBR',
349 $ 'PLN', n, nrhs, m, -1 ) )
350 maxwrk = max( maxwrk, 3*m + wlalsd )
351 END IF
352 minwrk = max( 3*m + nrhs, 3*m + m, 3*m + wlalsd )
353 END IF
354 END IF
355 minwrk = min( minwrk, maxwrk )
357 iwork( 1 ) = liwork
358
359 IF( lwork.LT.minwrk .AND. .NOT.lquery ) THEN
360 info = -12
361 END IF
362 END IF
363
364 IF( info.NE.0 ) THEN
365 CALL xerbla(
'SGELSD', -info )
366 RETURN
367 ELSE IF( lquery ) THEN
368 RETURN
369 END IF
370
371
372
373 IF( m.EQ.0 .OR. n.EQ.0 ) THEN
374 rank = 0
375 RETURN
376 END IF
377
378
379
382 smlnum = sfmin / eps
383 bignum = one / smlnum
384
385
386
387 anrm =
slange(
'M', m, n, a, lda, work )
388 iascl = 0
389 IF( anrm.GT.zero .AND. anrm.LT.smlnum ) THEN
390
391
392
393 CALL slascl(
'G', 0, 0, anrm, smlnum, m, n, a, lda, info )
394 iascl = 1
395 ELSE IF( anrm.GT.bignum ) THEN
396
397
398
399 CALL slascl(
'G', 0, 0, anrm, bignum, m, n, a, lda, info )
400 iascl = 2
401 ELSE IF( anrm.EQ.zero ) THEN
402
403
404
405 CALL slaset(
'F', max( m, n ), nrhs, zero, zero, b, ldb )
406 CALL slaset(
'F', minmn, 1, zero, zero, s, 1 )
407 rank = 0
408 GO TO 10
409 END IF
410
411
412
413 bnrm =
slange(
'M', m, nrhs, b, ldb, work )
414 ibscl = 0
415 IF( bnrm.GT.zero .AND. bnrm.LT.smlnum ) THEN
416
417
418
419 CALL slascl(
'G', 0, 0, bnrm, smlnum, m, nrhs, b, ldb,
420 $ info )
421 ibscl = 1
422 ELSE IF( bnrm.GT.bignum ) THEN
423
424
425
426 CALL slascl(
'G', 0, 0, bnrm, bignum, m, nrhs, b, ldb,
427 $ info )
428 ibscl = 2
429 END IF
430
431
432
433 IF( m.LT.n )
434 $
CALL slaset(
'F', n-m, nrhs, zero, zero, b( m+1, 1 ), ldb )
435
436
437
438 IF( m.GE.n ) THEN
439
440
441
442 mm = m
443 IF( m.GE.mnthr ) THEN
444
445
446
447 mm = n
448 itau = 1
449 nwork = itau + n
450
451
452
453
454 CALL sgeqrf( m, n, a, lda, work( itau ), work( nwork ),
455 $ lwork-nwork+1, info )
456
457
458
459
460 CALL sormqr(
'L',
'T', m, nrhs, n, a, lda, work( itau ),
461 $ b,
462 $ ldb, work( nwork ), lwork-nwork+1, info )
463
464
465
466 IF( n.GT.1 ) THEN
467 CALL slaset(
'L', n-1, n-1, zero, zero, a( 2, 1 ),
468 $ lda )
469 END IF
470 END IF
471
472 ie = 1
473 itauq = ie + n
474 itaup = itauq + n
475 nwork = itaup + n
476
477
478
479
480 CALL sgebrd( mm, n, a, lda, s, work( ie ), work( itauq ),
481 $ work( itaup ), work( nwork ), lwork-nwork+1,
482 $ info )
483
484
485
486
487 CALL sormbr(
'Q',
'L',
'T', mm, nrhs, n, a, lda,
488 $ work( itauq ),
489 $ b, ldb, work( nwork ), lwork-nwork+1, info )
490
491
492
493 CALL slalsd(
'U', smlsiz, n, nrhs, s, work( ie ), b, ldb,
494 $ rcond, rank, work( nwork ), iwork, info )
495 IF( info.NE.0 ) THEN
496 GO TO 10
497 END IF
498
499
500
501 CALL sormbr(
'P',
'L',
'N', n, nrhs, n, a, lda,
502 $ work( itaup ),
503 $ b, ldb, work( nwork ), lwork-nwork+1, info )
504
505 ELSE IF( n.GE.mnthr .AND. lwork.GE.4*m+m*m+
506 $ max( m, 2*m-4, nrhs, n-3*m, wlalsd ) ) THEN
507
508
509
510
511 ldwork = m
512 IF( lwork.GE.max( 4*m+m*lda+max( m, 2*m-4, nrhs, n-3*m ),
513 $ m*lda+m+m*nrhs, 4*m+m*lda+wlalsd ) )ldwork = lda
514 itau = 1
515 nwork = m + 1
516
517
518
519
520 CALL sgelqf( m, n, a, lda, work( itau ), work( nwork ),
521 $ lwork-nwork+1, info )
522 il = nwork
523
524
525
526 CALL slacpy(
'L', m, m, a, lda, work( il ), ldwork )
527 CALL slaset(
'U', m-1, m-1, zero, zero, work( il+ldwork ),
528 $ ldwork )
529 ie = il + ldwork*m
530 itauq = ie + m
531 itaup = itauq + m
532 nwork = itaup + m
533
534
535
536
537 CALL sgebrd( m, m, work( il ), ldwork, s, work( ie ),
538 $ work( itauq ), work( itaup ), work( nwork ),
539 $ lwork-nwork+1, info )
540
541
542
543
544 CALL sormbr(
'Q',
'L',
'T', m, nrhs, m, work( il ), ldwork,
545 $ work( itauq ), b, ldb, work( nwork ),
546 $ lwork-nwork+1, info )
547
548
549
550 CALL slalsd(
'U', smlsiz, m, nrhs, s, work( ie ), b, ldb,
551 $ rcond, rank, work( nwork ), iwork, info )
552 IF( info.NE.0 ) THEN
553 GO TO 10
554 END IF
555
556
557
558 CALL sormbr(
'P',
'L',
'N', m, nrhs, m, work( il ), ldwork,
559 $ work( itaup ), b, ldb, work( nwork ),
560 $ lwork-nwork+1, info )
561
562
563
564 CALL slaset(
'F', n-m, nrhs, zero, zero, b( m+1, 1 ), ldb )
565 nwork = itau + m
566
567
568
569
570 CALL sormlq(
'L',
'T', n, nrhs, m, a, lda, work( itau ), b,
571 $ ldb, work( nwork ), lwork-nwork+1, info )
572
573 ELSE
574
575
576
577 ie = 1
578 itauq = ie + m
579 itaup = itauq + m
580 nwork = itaup + m
581
582
583
584
585 CALL sgebrd( m, n, a, lda, s, work( ie ), work( itauq ),
586 $ work( itaup ), work( nwork ), lwork-nwork+1,
587 $ info )
588
589
590
591
592 CALL sormbr(
'Q',
'L',
'T', m, nrhs, n, a, lda,
593 $ work( itauq ),
594 $ b, ldb, work( nwork ), lwork-nwork+1, info )
595
596
597
598 CALL slalsd(
'L', smlsiz, m, nrhs, s, work( ie ), b, ldb,
599 $ rcond, rank, work( nwork ), iwork, info )
600 IF( info.NE.0 ) THEN
601 GO TO 10
602 END IF
603
604
605
606 CALL sormbr(
'P',
'L',
'N', n, nrhs, m, a, lda,
607 $ work( itaup ),
608 $ b, ldb, work( nwork ), lwork-nwork+1, info )
609
610 END IF
611
612
613
614 IF( iascl.EQ.1 ) THEN
615 CALL slascl(
'G', 0, 0, anrm, smlnum, n, nrhs, b, ldb,
616 $ info )
617 CALL slascl(
'G', 0, 0, smlnum, anrm, minmn, 1, s, minmn,
618 $ info )
619 ELSE IF( iascl.EQ.2 ) THEN
620 CALL slascl(
'G', 0, 0, anrm, bignum, n, nrhs, b, ldb,
621 $ info )
622 CALL slascl(
'G', 0, 0, bignum, anrm, minmn, 1, s, minmn,
623 $ info )
624 END IF
625 IF( ibscl.EQ.1 ) THEN
626 CALL slascl(
'G', 0, 0, smlnum, bnrm, n, nrhs, b, ldb,
627 $ info )
628 ELSE IF( ibscl.EQ.2 ) THEN
629 CALL slascl(
'G', 0, 0, bignum, bnrm, n, nrhs, b, ldb,
630 $ info )
631 END IF
632
633 10 CONTINUE
635 iwork( 1 ) = liwork
636 RETURN
637
638
639
subroutine xerbla(srname, info)
subroutine sgebrd(m, n, a, lda, d, e, tauq, taup, work, lwork, info)
SGEBRD
subroutine sgelqf(m, n, a, lda, tau, work, lwork, info)
SGELQF
subroutine sgeqrf(m, n, a, lda, tau, work, lwork, info)
SGEQRF
integer function ilaenv(ispec, name, opts, n1, n2, n3, n4)
ILAENV
subroutine slacpy(uplo, m, n, a, lda, b, ldb)
SLACPY copies all or part of one two-dimensional array to another.
subroutine slalsd(uplo, smlsiz, n, nrhs, d, e, b, ldb, rcond, rank, work, iwork, info)
SLALSD uses the singular value decomposition of A to solve the least squares problem.
real function slamch(cmach)
SLAMCH
real function slange(norm, m, n, a, lda, work)
SLANGE returns the value of the 1-norm, Frobenius norm, infinity-norm, or the largest absolute value ...
subroutine slascl(type, kl, ku, cfrom, cto, m, n, a, lda, info)
SLASCL multiplies a general rectangular matrix by a real scalar defined as cto/cfrom.
subroutine slaset(uplo, m, n, alpha, beta, a, lda)
SLASET initializes the off-diagonal elements and the diagonal elements of a matrix to given values.
real function sroundup_lwork(lwork)
SROUNDUP_LWORK
subroutine sormbr(vect, side, trans, m, n, k, a, lda, tau, c, ldc, work, lwork, info)
SORMBR
subroutine sormlq(side, trans, m, n, k, a, lda, tau, c, ldc, work, lwork, info)
SORMLQ
subroutine sormqr(side, trans, m, n, k, a, lda, tau, c, ldc, work, lwork, info)
SORMQR