255
256
257
258
259
260
261 CHARACTER JOBU1, JOBU2, JOBV1T
262 INTEGER INFO, LDU1, LDU2, LDV1T, LWORK, LDX11, LDX21,
263 $ M, P, Q
264 INTEGER LRWORK, LRWORKMIN, LRWORKOPT
265
266
267 DOUBLE PRECISION RWORK(*)
268 DOUBLE PRECISION THETA(*)
269 COMPLEX*16 U1(LDU1,*), U2(LDU2,*), V1T(LDV1T,*), WORK(*),
270 $ X11(LDX11,*), X21(LDX21,*)
271 INTEGER IWORK(*)
272
273
274
275
276
277 COMPLEX*16 ONE, ZERO
278 parameter( one = (1.0d0,0.0d0), zero = (0.0d0,0.0d0) )
279
280
281 INTEGER CHILDINFO, I, IB11D, IB11E, IB12D, IB12E,
282 $ IB21D, IB21E, IB22D, IB22E, IBBCSD, IORBDB,
283 $ IORGLQ, IORGQR, IPHI, ITAUP1, ITAUP2, ITAUQ1,
284 $ J, LBBCSD, LORBDB, LORGLQ, LORGLQMIN,
285 $ LORGLQOPT, LORGQR, LORGQRMIN, LORGQROPT,
286 $ LWORKMIN, LWORKOPT, R
287 LOGICAL LQUERY, WANTU1, WANTU2, WANTV1T
288
289
290 DOUBLE PRECISION DUM( 1 )
291 COMPLEX*16 CDUM( 1, 1 )
292
293
298
299
300 LOGICAL LSAME
302
303
304 INTRINSIC int, max, min
305
306
307
308
309
310 info = 0
311 wantu1 =
lsame( jobu1,
'Y' )
312 wantu2 =
lsame( jobu2,
'Y' )
313 wantv1t =
lsame( jobv1t,
'Y' )
314 lquery = ( lwork.EQ.-1 ) .OR. ( lrwork.EQ.-1 )
315
316 IF( m .LT. 0 ) THEN
317 info = -4
318 ELSE IF( p .LT. 0 .OR. p .GT. m ) THEN
319 info = -5
320 ELSE IF( q .LT. 0 .OR. q .GT. m ) THEN
321 info = -6
322 ELSE IF( ldx11 .LT. max( 1, p ) ) THEN
323 info = -8
324 ELSE IF( ldx21 .LT. max( 1, m-p ) ) THEN
325 info = -10
326 ELSE IF( wantu1 .AND. ldu1 .LT. max( 1, p ) ) THEN
327 info = -13
328 ELSE IF( wantu2 .AND. ldu2 .LT. max( 1, m - p ) ) THEN
329 info = -15
330 ELSE IF( wantv1t .AND. ldv1t .LT. max( 1, q ) ) THEN
331 info = -17
332 END IF
333
334 r = min( p, m-p, q, m-q )
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369 IF( info .EQ. 0 ) THEN
370 iphi = 2
371 ib11d = iphi + max( 1, r-1 )
372 ib11e = ib11d + max( 1, r )
373 ib12d = ib11e + max( 1, r - 1 )
374 ib12e = ib12d + max( 1, r )
375 ib21d = ib12e + max( 1, r - 1 )
376 ib21e = ib21d + max( 1, r )
377 ib22d = ib21e + max( 1, r - 1 )
378 ib22e = ib22d + max( 1, r )
379 ibbcsd = ib22e + max( 1, r - 1 )
380 itaup1 = 2
381 itaup2 = itaup1 + max( 1, p )
382 itauq1 = itaup2 + max( 1, m-p )
383 iorbdb = itauq1 + max( 1, q )
384 iorgqr = itauq1 + max( 1, q )
385 iorglq = itauq1 + max( 1, q )
386 lorgqrmin = 1
387 lorgqropt = 1
388 lorglqmin = 1
389 lorglqopt = 1
390 IF( r .EQ. q ) THEN
391 CALL zunbdb1( m, p, q, x11, ldx11, x21, ldx21, theta,
392 $ dum,
393 $ cdum, cdum, cdum, work, -1, childinfo )
394 lorbdb = int( work(1) )
395 IF( wantu1 .AND. p .GT. 0 ) THEN
396 CALL zungqr( p, p, q, u1, ldu1, cdum, work(1), -1,
397 $ childinfo )
398 lorgqrmin = max( lorgqrmin, p )
399 lorgqropt = max( lorgqropt, int( work(1) ) )
400 ENDIF
401 IF( wantu2 .AND. m-p .GT. 0 ) THEN
402 CALL zungqr( m-p, m-p, q, u2, ldu2, cdum, work(1), -1,
403 $ childinfo )
404 lorgqrmin = max( lorgqrmin, m-p )
405 lorgqropt = max( lorgqropt, int( work(1) ) )
406 END IF
407 IF( wantv1t .AND. q .GT. 0 ) THEN
408 CALL zunglq( q-1, q-1, q-1, v1t, ldv1t,
409 $ cdum, work(1), -1, childinfo )
410 lorglqmin = max( lorglqmin, q-1 )
411 lorglqopt = max( lorglqopt, int( work(1) ) )
412 END IF
413 CALL zbbcsd( jobu1, jobu2, jobv1t,
'N',
'N', m, p, q,
414 $ theta,
415 $ dum, u1, ldu1, u2, ldu2, v1t, ldv1t, cdum, 1,
416 $ dum, dum, dum, dum, dum, dum, dum, dum,
417 $ rwork(1), -1, childinfo )
418 lbbcsd = int( rwork(1) )
419 ELSE IF( r .EQ. p ) THEN
420 CALL zunbdb2( m, p, q, x11, ldx11, x21, ldx21, theta,
421 $ dum,
422 $ cdum, cdum, cdum, work(1), -1, childinfo )
423 lorbdb = int( work(1) )
424 IF( wantu1 .AND. p .GT. 0 ) THEN
425 CALL zungqr( p-1, p-1, p-1, u1(2,2), ldu1, cdum,
426 $ work(1),
427 $ -1, childinfo )
428 lorgqrmin = max( lorgqrmin, p-1 )
429 lorgqropt = max( lorgqropt, int( work(1) ) )
430 END IF
431 IF( wantu2 .AND. m-p .GT. 0 ) THEN
432 CALL zungqr( m-p, m-p, q, u2, ldu2, cdum, work(1), -1,
433 $ childinfo )
434 lorgqrmin = max( lorgqrmin, m-p )
435 lorgqropt = max( lorgqropt, int( work(1) ) )
436 END IF
437 IF( wantv1t .AND. q .GT. 0 ) THEN
438 CALL zunglq( q, q, r, v1t, ldv1t, cdum, work(1), -1,
439 $ childinfo )
440 lorglqmin = max( lorglqmin, q )
441 lorglqopt = max( lorglqopt, int( work(1) ) )
442 END IF
443 CALL zbbcsd( jobv1t,
'N', jobu1, jobu2,
'T', m, q, p,
444 $ theta,
445 $ dum, v1t, ldv1t, cdum, 1, u1, ldu1, u2, ldu2,
446 $ dum, dum, dum, dum, dum, dum, dum, dum,
447 $ rwork(1), -1, childinfo )
448 lbbcsd = int( rwork(1) )
449 ELSE IF( r .EQ. m-p ) THEN
450 CALL zunbdb3( m, p, q, x11, ldx11, x21, ldx21, theta,
451 $ dum,
452 $ cdum, cdum, cdum, work(1), -1, childinfo )
453 lorbdb = int( work(1) )
454 IF( wantu1 .AND. p .GT. 0 ) THEN
455 CALL zungqr( p, p, q, u1, ldu1, cdum, work(1), -1,
456 $ childinfo )
457 lorgqrmin = max( lorgqrmin, p )
458 lorgqropt = max( lorgqropt, int( work(1) ) )
459 END IF
460 IF( wantu2 .AND. m-p .GT. 0 ) THEN
461 CALL zungqr( m-p-1, m-p-1, m-p-1, u2(2,2), ldu2, cdum,
462 $ work(1), -1, childinfo )
463 lorgqrmin = max( lorgqrmin, m-p-1 )
464 lorgqropt = max( lorgqropt, int( work(1) ) )
465 END IF
466 IF( wantv1t .AND. q .GT. 0 ) THEN
467 CALL zunglq( q, q, r, v1t, ldv1t, cdum, work(1), -1,
468 $ childinfo )
469 lorglqmin = max( lorglqmin, q )
470 lorglqopt = max( lorglqopt, int( work(1) ) )
471 END IF
472 CALL zbbcsd(
'N', jobv1t, jobu2, jobu1,
'T', m, m-q, m-p,
473 $ theta, dum, cdum, 1, v1t, ldv1t, u2, ldu2, u1,
474 $ ldu1, dum, dum, dum, dum, dum, dum, dum, dum,
475 $ rwork(1), -1, childinfo )
476 lbbcsd = int( rwork(1) )
477 ELSE
478 CALL zunbdb4( m, p, q, x11, ldx11, x21, ldx21, theta,
479 $ dum,
480 $ cdum, cdum, cdum, cdum, work(1), -1, childinfo
481 $ )
482 lorbdb = m + int( work(1) )
483 IF( wantu1 .AND. p .GT. 0 ) THEN
484 CALL zungqr( p, p, m-q, u1, ldu1, cdum, work(1), -1,
485 $ childinfo )
486 lorgqrmin = max( lorgqrmin, p )
487 lorgqropt = max( lorgqropt, int( work(1) ) )
488 END IF
489 IF( wantu2 .AND. m-p .GT. 0 ) THEN
490 CALL zungqr( m-p, m-p, m-q, u2, ldu2, cdum, work(1),
491 $ -1,
492 $ childinfo )
493 lorgqrmin = max( lorgqrmin, m-p )
494 lorgqropt = max( lorgqropt, int( work(1) ) )
495 END IF
496 IF( wantv1t .AND. q .GT. 0 ) THEN
497 CALL zunglq( q, q, q, v1t, ldv1t, cdum, work(1), -1,
498 $ childinfo )
499 lorglqmin = max( lorglqmin, q )
500 lorglqopt = max( lorglqopt, int( work(1) ) )
501 END IF
502 CALL zbbcsd( jobu2, jobu1,
'N', jobv1t,
'N', m, m-p, m-q,
503 $ theta, dum, u2, ldu2, u1, ldu1, cdum, 1, v1t,
504 $ ldv1t, dum, dum, dum, dum, dum, dum, dum, dum,
505 $ rwork(1), -1, childinfo )
506 lbbcsd = int( rwork(1) )
507 END IF
508 lrworkmin = ibbcsd+lbbcsd-1
509 lrworkopt = lrworkmin
510 rwork(1) = lrworkopt
511 lworkmin = max( iorbdb+lorbdb-1,
512 $ iorgqr+lorgqrmin-1,
513 $ iorglq+lorglqmin-1 )
514 lworkopt = max( iorbdb+lorbdb-1,
515 $ iorgqr+lorgqropt-1,
516 $ iorglq+lorglqopt-1 )
517 work(1) = lworkopt
518 IF( lwork .LT. lworkmin .AND. .NOT.lquery ) THEN
519 info = -19
520 END IF
521 IF( lrwork .LT. lrworkmin .AND. .NOT.lquery ) THEN
522 info = -21
523 END IF
524 END IF
525 IF( info .NE. 0 ) THEN
526 CALL xerbla(
'ZUNCSD2BY1', -info )
527 RETURN
528 ELSE IF( lquery ) THEN
529 RETURN
530 END IF
531 lorgqr = lwork-iorgqr+1
532 lorglq = lwork-iorglq+1
533
534
535
536
537 IF( r .EQ. q ) THEN
538
539
540
541
542
543 CALL zunbdb1( m, p, q, x11, ldx11, x21, ldx21, theta,
544 $ rwork(iphi), work(itaup1), work(itaup2),
545 $ work(itauq1), work(iorbdb), lorbdb, childinfo )
546
547
548
549 IF( wantu1 .AND. p .GT. 0 ) THEN
550 CALL zlacpy(
'L', p, q, x11, ldx11, u1, ldu1 )
551 CALL zungqr( p, p, q, u1, ldu1, work(itaup1),
552 $ work(iorgqr),
553 $ lorgqr, childinfo )
554 END IF
555 IF( wantu2 .AND. m-p .GT. 0 ) THEN
556 CALL zlacpy(
'L', m-p, q, x21, ldx21, u2, ldu2 )
557 CALL zungqr( m-p, m-p, q, u2, ldu2, work(itaup2),
558 $ work(iorgqr), lorgqr, childinfo )
559 END IF
560 IF( wantv1t .AND. q .GT. 0 ) THEN
561 v1t(1,1) = one
562 DO j = 2, q
563 v1t(1,j) = zero
564 v1t(j,1) = zero
565 END DO
566 CALL zlacpy(
'U', q-1, q-1, x21(1,2), ldx21, v1t(2,2),
567 $ ldv1t )
568 CALL zunglq( q-1, q-1, q-1, v1t(2,2), ldv1t,
569 $ work(itauq1),
570 $ work(iorglq), lorglq, childinfo )
571 END IF
572
573
574
575 CALL zbbcsd( jobu1, jobu2, jobv1t,
'N',
'N', m, p, q, theta,
576 $ rwork(iphi), u1, ldu1, u2, ldu2, v1t, ldv1t, cdum,
577 $ 1, rwork(ib11d), rwork(ib11e), rwork(ib12d),
578 $ rwork(ib12e), rwork(ib21d), rwork(ib21e),
579 $ rwork(ib22d), rwork(ib22e), rwork(ibbcsd),
580 $ lrwork-ibbcsd+1, childinfo )
581
582
583
584
585 IF( q .GT. 0 .AND. wantu2 ) THEN
586 DO i = 1, q
587 iwork(i) = m - p - q + i
588 END DO
589 DO i = q + 1, m - p
590 iwork(i) = i - q
591 END DO
592 CALL zlapmt( .false., m-p, m-p, u2, ldu2, iwork )
593 END IF
594 ELSE IF( r .EQ. p ) THEN
595
596
597
598
599
600 CALL zunbdb2( m, p, q, x11, ldx11, x21, ldx21, theta,
601 $ rwork(iphi), work(itaup1), work(itaup2),
602 $ work(itauq1), work(iorbdb), lorbdb, childinfo )
603
604
605
606 IF( wantu1 .AND. p .GT. 0 ) THEN
607 u1(1,1) = one
608 DO j = 2, p
609 u1(1,j) = zero
610 u1(j,1) = zero
611 END DO
612 CALL zlacpy(
'L', p-1, p-1, x11(2,1), ldx11, u1(2,2),
613 $ ldu1 )
614 CALL zungqr( p-1, p-1, p-1, u1(2,2), ldu1, work(itaup1),
615 $ work(iorgqr), lorgqr, childinfo )
616 END IF
617 IF( wantu2 .AND. m-p .GT. 0 ) THEN
618 CALL zlacpy(
'L', m-p, q, x21, ldx21, u2, ldu2 )
619 CALL zungqr( m-p, m-p, q, u2, ldu2, work(itaup2),
620 $ work(iorgqr), lorgqr, childinfo )
621 END IF
622 IF( wantv1t .AND. q .GT. 0 ) THEN
623 CALL zlacpy(
'U', p, q, x11, ldx11, v1t, ldv1t )
624 CALL zunglq( q, q, r, v1t, ldv1t, work(itauq1),
625 $ work(iorglq), lorglq, childinfo )
626 END IF
627
628
629
630 CALL zbbcsd( jobv1t,
'N', jobu1, jobu2,
'T', m, q, p, theta,
631 $ rwork(iphi), v1t, ldv1t, cdum, 1, u1, ldu1, u2,
632 $ ldu2, rwork(ib11d), rwork(ib11e), rwork(ib12d),
633 $ rwork(ib12e), rwork(ib21d), rwork(ib21e),
634 $ rwork(ib22d), rwork(ib22e), rwork(ibbcsd), lbbcsd,
635 $ childinfo )
636
637
638
639
640 IF( q .GT. 0 .AND. wantu2 ) THEN
641 DO i = 1, q
642 iwork(i) = m - p - q + i
643 END DO
644 DO i = q + 1, m - p
645 iwork(i) = i - q
646 END DO
647 CALL zlapmt( .false., m-p, m-p, u2, ldu2, iwork )
648 END IF
649 ELSE IF( r .EQ. m-p ) THEN
650
651
652
653
654
655 CALL zunbdb3( m, p, q, x11, ldx11, x21, ldx21, theta,
656 $ rwork(iphi), work(itaup1), work(itaup2),
657 $ work(itauq1), work(iorbdb), lorbdb, childinfo )
658
659
660
661 IF( wantu1 .AND. p .GT. 0 ) THEN
662 CALL zlacpy(
'L', p, q, x11, ldx11, u1, ldu1 )
663 CALL zungqr( p, p, q, u1, ldu1, work(itaup1),
664 $ work(iorgqr),
665 $ lorgqr, childinfo )
666 END IF
667 IF( wantu2 .AND. m-p .GT. 0 ) THEN
668 u2(1,1) = one
669 DO j = 2, m-p
670 u2(1,j) = zero
671 u2(j,1) = zero
672 END DO
673 CALL zlacpy(
'L', m-p-1, m-p-1, x21(2,1), ldx21, u2(2,2),
674 $ ldu2 )
675 CALL zungqr( m-p-1, m-p-1, m-p-1, u2(2,2), ldu2,
676 $ work(itaup2), work(iorgqr), lorgqr, childinfo )
677 END IF
678 IF( wantv1t .AND. q .GT. 0 ) THEN
679 CALL zlacpy(
'U', m-p, q, x21, ldx21, v1t, ldv1t )
680 CALL zunglq( q, q, r, v1t, ldv1t, work(itauq1),
681 $ work(iorglq), lorglq, childinfo )
682 END IF
683
684
685
686 CALL zbbcsd(
'N', jobv1t, jobu2, jobu1,
'T', m, m-q, m-p,
687 $ theta, rwork(iphi), cdum, 1, v1t, ldv1t, u2, ldu2,
688 $ u1, ldu1, rwork(ib11d), rwork(ib11e),
689 $ rwork(ib12d), rwork(ib12e), rwork(ib21d),
690 $ rwork(ib21e), rwork(ib22d), rwork(ib22e),
691 $ rwork(ibbcsd), lbbcsd, childinfo )
692
693
694
695
696 IF( q .GT. r ) THEN
697 DO i = 1, r
698 iwork(i) = q - r + i
699 END DO
700 DO i = r + 1, q
701 iwork(i) = i - r
702 END DO
703 IF( wantu1 ) THEN
704 CALL zlapmt( .false., p, q, u1, ldu1, iwork )
705 END IF
706 IF( wantv1t ) THEN
707 CALL zlapmr( .false., q, q, v1t, ldv1t, iwork )
708 END IF
709 END IF
710 ELSE
711
712
713
714
715
716 CALL zunbdb4( m, p, q, x11, ldx11, x21, ldx21, theta,
717 $ rwork(iphi), work(itaup1), work(itaup2),
718 $ work(itauq1), work(iorbdb), work(iorbdb+m),
719 $ lorbdb-m, childinfo )
720
721
722
723 IF( wantu2 .AND. m-p .GT. 0 ) THEN
724 CALL zcopy( m-p, work(iorbdb+p), 1, u2, 1 )
725 END IF
726 IF( wantu1 .AND. p .GT. 0 ) THEN
727 CALL zcopy( p, work(iorbdb), 1, u1, 1 )
728 DO j = 2, p
729 u1(1,j) = zero
730 END DO
731 CALL zlacpy(
'L', p-1, m-q-1, x11(2,1), ldx11, u1(2,2),
732 $ ldu1 )
733 CALL zungqr( p, p, m-q, u1, ldu1, work(itaup1),
734 $ work(iorgqr), lorgqr, childinfo )
735 END IF
736 IF( wantu2 .AND. m-p .GT. 0 ) THEN
737 DO j = 2, m-p
738 u2(1,j) = zero
739 END DO
740 CALL zlacpy(
'L', m-p-1, m-q-1, x21(2,1), ldx21, u2(2,2),
741 $ ldu2 )
742 CALL zungqr( m-p, m-p, m-q, u2, ldu2, work(itaup2),
743 $ work(iorgqr), lorgqr, childinfo )
744 END IF
745 IF( wantv1t .AND. q .GT. 0 ) THEN
746 CALL zlacpy(
'U', m-q, q, x21, ldx21, v1t, ldv1t )
747 CALL zlacpy(
'U', p-(m-q), q-(m-q), x11(m-q+1,m-q+1),
748 $ ldx11,
749 $ v1t(m-q+1,m-q+1), ldv1t )
750 CALL zlacpy(
'U', -p+q, q-p, x21(m-q+1,p+1), ldx21,
751 $ v1t(p+1,p+1), ldv1t )
752 CALL zunglq( q, q, q, v1t, ldv1t, work(itauq1),
753 $ work(iorglq), lorglq, childinfo )
754 END IF
755
756
757
758 CALL zbbcsd( jobu2, jobu1,
'N', jobv1t,
'N', m, m-p, m-q,
759 $ theta, rwork(iphi), u2, ldu2, u1, ldu1, cdum, 1,
760 $ v1t, ldv1t, rwork(ib11d), rwork(ib11e),
761 $ rwork(ib12d), rwork(ib12e), rwork(ib21d),
762 $ rwork(ib21e), rwork(ib22d), rwork(ib22e),
763 $ rwork(ibbcsd), lbbcsd, childinfo )
764
765
766
767
768 IF( p .GT. r ) THEN
769 DO i = 1, r
770 iwork(i) = p - r + i
771 END DO
772 DO i = r + 1, p
773 iwork(i) = i - r
774 END DO
775 IF( wantu1 ) THEN
776 CALL zlapmt( .false., p, p, u1, ldu1, iwork )
777 END IF
778 IF( wantv1t ) THEN
779 CALL zlapmr( .false., p, q, v1t, ldv1t, iwork )
780 END IF
781 END IF
782 END IF
783
784 RETURN
785
786
787
subroutine xerbla(srname, info)
subroutine zbbcsd(jobu1, jobu2, jobv1t, jobv2t, trans, m, p, q, theta, phi, u1, ldu1, u2, ldu2, v1t, ldv1t, v2t, ldv2t, b11d, b11e, b12d, b12e, b21d, b21e, b22d, b22e, rwork, lrwork, info)
ZBBCSD
subroutine zcopy(n, zx, incx, zy, incy)
ZCOPY
subroutine zlacpy(uplo, m, n, a, lda, b, ldb)
ZLACPY copies all or part of one two-dimensional array to another.
subroutine zlapmr(forwrd, m, n, x, ldx, k)
ZLAPMR rearranges rows of a matrix as specified by a permutation vector.
subroutine zlapmt(forwrd, m, n, x, ldx, k)
ZLAPMT performs a forward or backward permutation of the columns of a matrix.
logical function lsame(ca, cb)
LSAME
subroutine zunbdb1(m, p, q, x11, ldx11, x21, ldx21, theta, phi, taup1, taup2, tauq1, work, lwork, info)
ZUNBDB1
subroutine zunbdb2(m, p, q, x11, ldx11, x21, ldx21, theta, phi, taup1, taup2, tauq1, work, lwork, info)
ZUNBDB2
subroutine zunbdb3(m, p, q, x11, ldx11, x21, ldx21, theta, phi, taup1, taup2, tauq1, work, lwork, info)
ZUNBDB3
subroutine zunbdb4(m, p, q, x11, ldx11, x21, ldx21, theta, phi, taup1, taup2, tauq1, phantom, work, lwork, info)
ZUNBDB4
subroutine zunglq(m, n, k, a, lda, tau, work, lwork, info)
ZUNGLQ
subroutine zungqr(m, n, k, a, lda, tau, work, lwork, info)
ZUNGQR