Annotation of rpl/lapack/lapack/zgesvdq.f, revision 1.1
1.1 ! bertrand 1: *> \brief <b> ZGESVDQ computes the singular value decomposition (SVD) with a QR-Preconditioned QR SVD Method for GE matrices</b>
! 2: *
! 3: * =========== DOCUMENTATION ===========
! 4: *
! 5: * Online html documentation available at
! 6: * http://www.netlib.org/lapack/explore-html/
! 7: *
! 8: *> \htmlonly
! 9: *> Download ZGESVDQ + dependencies
! 10: *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/zgesvdq.f">
! 11: *> [TGZ]</a>
! 12: *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/zgesvdq.f">
! 13: *> [ZIP]</a>
! 14: *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/zgesvdq.f">
! 15: *> [TXT]</a>
! 16: *> \endhtmlonly
! 17: *
! 18: * Definition:
! 19: * ===========
! 20: *
! 21: * SUBROUTINE ZGESVDQ( JOBA, JOBP, JOBR, JOBU, JOBV, M, N, A, LDA,
! 22: * S, U, LDU, V, LDV, NUMRANK, IWORK, LIWORK,
! 23: * CWORK, LCWORK, RWORK, LRWORK, INFO )
! 24: *
! 25: * .. Scalar Arguments ..
! 26: * IMPLICIT NONE
! 27: * CHARACTER JOBA, JOBP, JOBR, JOBU, JOBV
! 28: * INTEGER M, N, LDA, LDU, LDV, NUMRANK, LIWORK, LCWORK, LRWORK,
! 29: * INFO
! 30: * ..
! 31: * .. Array Arguments ..
! 32: * COMPLEX*16 A( LDA, * ), U( LDU, * ), V( LDV, * ), CWORK( * )
! 33: * DOUBLE PRECISION S( * ), RWORK( * )
! 34: * INTEGER IWORK( * )
! 35: * ..
! 36: *
! 37: *
! 38: *> \par Purpose:
! 39: * =============
! 40: *>
! 41: *> \verbatim
! 42: *>
! 43: * ZCGESVDQ computes the singular value decomposition (SVD) of a complex
! 44: *> M-by-N matrix A, where M >= N. The SVD of A is written as
! 45: *> [++] [xx] [x0] [xx]
! 46: *> A = U * SIGMA * V^*, [++] = [xx] * [ox] * [xx]
! 47: *> [++] [xx]
! 48: *> where SIGMA is an N-by-N diagonal matrix, U is an M-by-N orthonormal
! 49: *> matrix, and V is an N-by-N unitary matrix. The diagonal elements
! 50: *> of SIGMA are the singular values of A. The columns of U and V are the
! 51: *> left and the right singular vectors of A, respectively.
! 52: *> \endverbatim
! 53: *
! 54: * Arguments
! 55: * =========
! 56: *
! 57: *> \param[in] JOBA
! 58: *> \verbatim
! 59: *> JOBA is CHARACTER*1
! 60: *> Specifies the level of accuracy in the computed SVD
! 61: *> = 'A' The requested accuracy corresponds to having the backward
! 62: *> error bounded by || delta A ||_F <= f(m,n) * EPS * || A ||_F,
! 63: *> where EPS = DLAMCH('Epsilon'). This authorises ZGESVDQ to
! 64: *> truncate the computed triangular factor in a rank revealing
! 65: *> QR factorization whenever the truncated part is below the
! 66: *> threshold of the order of EPS * ||A||_F. This is aggressive
! 67: *> truncation level.
! 68: *> = 'M' Similarly as with 'A', but the truncation is more gentle: it
! 69: *> is allowed only when there is a drop on the diagonal of the
! 70: *> triangular factor in the QR factorization. This is medium
! 71: *> truncation level.
! 72: *> = 'H' High accuracy requested. No numerical rank determination based
! 73: *> on the rank revealing QR factorization is attempted.
! 74: *> = 'E' Same as 'H', and in addition the condition number of column
! 75: *> scaled A is estimated and returned in RWORK(1).
! 76: *> N^(-1/4)*RWORK(1) <= ||pinv(A_scaled)||_2 <= N^(1/4)*RWORK(1)
! 77: *> \endverbatim
! 78: *>
! 79: *> \param[in] JOBP
! 80: *> \verbatim
! 81: *> JOBP is CHARACTER*1
! 82: *> = 'P' The rows of A are ordered in decreasing order with respect to
! 83: *> ||A(i,:)||_\infty. This enhances numerical accuracy at the cost
! 84: *> of extra data movement. Recommended for numerical robustness.
! 85: *> = 'N' No row pivoting.
! 86: *> \endverbatim
! 87: *>
! 88: *> \param[in] JOBR
! 89: *> \verbatim
! 90: *> JOBR is CHARACTER*1
! 91: *> = 'T' After the initial pivoted QR factorization, ZGESVD is applied to
! 92: *> the adjoint R**H of the computed triangular factor R. This involves
! 93: *> some extra data movement (matrix transpositions). Useful for
! 94: *> experiments, research and development.
! 95: *> = 'N' The triangular factor R is given as input to CGESVD. This may be
! 96: *> preferred as it involves less data movement.
! 97: *> \endverbatim
! 98: *>
! 99: *> \param[in] JOBU
! 100: *> \verbatim
! 101: *> JOBU is CHARACTER*1
! 102: *> = 'A' All M left singular vectors are computed and returned in the
! 103: *> matrix U. See the description of U.
! 104: *> = 'S' or 'U' N = min(M,N) left singular vectors are computed and returned
! 105: *> in the matrix U. See the description of U.
! 106: *> = 'R' Numerical rank NUMRANK is determined and only NUMRANK left singular
! 107: *> vectors are computed and returned in the matrix U.
! 108: *> = 'F' The N left singular vectors are returned in factored form as the
! 109: *> product of the Q factor from the initial QR factorization and the
! 110: *> N left singular vectors of (R**H , 0)**H. If row pivoting is used,
! 111: *> then the necessary information on the row pivoting is stored in
! 112: *> IWORK(N+1:N+M-1).
! 113: *> = 'N' The left singular vectors are not computed.
! 114: *> \endverbatim
! 115: *>
! 116: *> \param[in] JOBV
! 117: *> \verbatim
! 118: *> JOBV is CHARACTER*1
! 119: *> = 'A', 'V' All N right singular vectors are computed and returned in
! 120: *> the matrix V.
! 121: *> = 'R' Numerical rank NUMRANK is determined and only NUMRANK right singular
! 122: *> vectors are computed and returned in the matrix V. This option is
! 123: *> allowed only if JOBU = 'R' or JOBU = 'N'; otherwise it is illegal.
! 124: *> = 'N' The right singular vectors are not computed.
! 125: *> \endverbatim
! 126: *>
! 127: *> \param[in] M
! 128: *> \verbatim
! 129: *> M is INTEGER
! 130: *> The number of rows of the input matrix A. M >= 0.
! 131: *> \endverbatim
! 132: *>
! 133: *> \param[in] N
! 134: *> \verbatim
! 135: *> N is INTEGER
! 136: *> The number of columns of the input matrix A. M >= N >= 0.
! 137: *> \endverbatim
! 138: *>
! 139: *> \param[in,out] A
! 140: *> \verbatim
! 141: *> A is COMPLEX*16 array of dimensions LDA x N
! 142: *> On entry, the input matrix A.
! 143: *> On exit, if JOBU .NE. 'N' or JOBV .NE. 'N', the lower triangle of A contains
! 144: *> the Householder vectors as stored by ZGEQP3. If JOBU = 'F', these Householder
! 145: *> vectors together with CWORK(1:N) can be used to restore the Q factors from
! 146: *> the initial pivoted QR factorization of A. See the description of U.
! 147: *> \endverbatim
! 148: *>
! 149: *> \param[in] LDA
! 150: *> \verbatim
! 151: *> LDA is INTEGER.
! 152: *> The leading dimension of the array A. LDA >= max(1,M).
! 153: *> \endverbatim
! 154: *>
! 155: *> \param[out] S
! 156: *> \verbatim
! 157: *> S is DOUBLE PRECISION array of dimension N.
! 158: *> The singular values of A, ordered so that S(i) >= S(i+1).
! 159: *> \endverbatim
! 160: *>
! 161: *> \param[out] U
! 162: *> \verbatim
! 163: *> U is COMPLEX*16 array, dimension
! 164: *> LDU x M if JOBU = 'A'; see the description of LDU. In this case,
! 165: *> on exit, U contains the M left singular vectors.
! 166: *> LDU x N if JOBU = 'S', 'U', 'R' ; see the description of LDU. In this
! 167: *> case, U contains the leading N or the leading NUMRANK left singular vectors.
! 168: *> LDU x N if JOBU = 'F' ; see the description of LDU. In this case U
! 169: *> contains N x N unitary matrix that can be used to form the left
! 170: *> singular vectors.
! 171: *> If JOBU = 'N', U is not referenced.
! 172: *> \endverbatim
! 173: *>
! 174: *> \param[in] LDU
! 175: *> \verbatim
! 176: *> LDU is INTEGER.
! 177: *> The leading dimension of the array U.
! 178: *> If JOBU = 'A', 'S', 'U', 'R', LDU >= max(1,M).
! 179: *> If JOBU = 'F', LDU >= max(1,N).
! 180: *> Otherwise, LDU >= 1.
! 181: *> \endverbatim
! 182: *>
! 183: *> \param[out] V
! 184: *> \verbatim
! 185: *> V is COMPLEX*16 array, dimension
! 186: *> LDV x N if JOBV = 'A', 'V', 'R' or if JOBA = 'E' .
! 187: *> If JOBV = 'A', or 'V', V contains the N-by-N unitary matrix V**H;
! 188: *> If JOBV = 'R', V contains the first NUMRANK rows of V**H (the right
! 189: *> singular vectors, stored rowwise, of the NUMRANK largest singular values).
! 190: *> If JOBV = 'N' and JOBA = 'E', V is used as a workspace.
! 191: *> If JOBV = 'N', and JOBA.NE.'E', V is not referenced.
! 192: *> \endverbatim
! 193: *>
! 194: *> \param[in] LDV
! 195: *> \verbatim
! 196: *> LDV is INTEGER
! 197: *> The leading dimension of the array V.
! 198: *> If JOBV = 'A', 'V', 'R', or JOBA = 'E', LDV >= max(1,N).
! 199: *> Otherwise, LDV >= 1.
! 200: *> \endverbatim
! 201: *>
! 202: *> \param[out] NUMRANK
! 203: *> \verbatim
! 204: *> NUMRANK is INTEGER
! 205: *> NUMRANK is the numerical rank first determined after the rank
! 206: *> revealing QR factorization, following the strategy specified by the
! 207: *> value of JOBA. If JOBV = 'R' and JOBU = 'R', only NUMRANK
! 208: *> leading singular values and vectors are then requested in the call
! 209: *> of CGESVD. The final value of NUMRANK might be further reduced if
! 210: *> some singular values are computed as zeros.
! 211: *> \endverbatim
! 212: *>
! 213: *> \param[out] IWORK
! 214: *> \verbatim
! 215: *> IWORK is INTEGER array, dimension (max(1, LIWORK)).
! 216: *> On exit, IWORK(1:N) contains column pivoting permutation of the
! 217: *> rank revealing QR factorization.
! 218: *> If JOBP = 'P', IWORK(N+1:N+M-1) contains the indices of the sequence
! 219: *> of row swaps used in row pivoting. These can be used to restore the
! 220: *> left singular vectors in the case JOBU = 'F'.
! 221: *
! 222: *> If LIWORK, LCWORK, or LRWORK = -1, then on exit, if INFO = 0,
! 223: *> LIWORK(1) returns the minimal LIWORK.
! 224: *> \endverbatim
! 225: *>
! 226: *> \param[in] LIWORK
! 227: *> \verbatim
! 228: *> LIWORK is INTEGER
! 229: *> The dimension of the array IWORK.
! 230: *> LIWORK >= N + M - 1, if JOBP = 'P';
! 231: *> LIWORK >= N if JOBP = 'N'.
! 232: *>
! 233: *> If LIWORK = -1, then a workspace query is assumed; the routine
! 234: *> only calculates and returns the optimal and minimal sizes
! 235: *> for the CWORK, IWORK, and RWORK arrays, and no error
! 236: *> message related to LCWORK is issued by XERBLA.
! 237: *> \endverbatim
! 238: *>
! 239: *> \param[out] CWORK
! 240: *> \verbatim
! 241: *> CWORK is COMPLEX*12 array, dimension (max(2, LCWORK)), used as a workspace.
! 242: *> On exit, if, on entry, LCWORK.NE.-1, CWORK(1:N) contains parameters
! 243: *> needed to recover the Q factor from the QR factorization computed by
! 244: *> ZGEQP3.
! 245: *
! 246: *> If LIWORK, LCWORK, or LRWORK = -1, then on exit, if INFO = 0,
! 247: *> CWORK(1) returns the optimal LCWORK, and
! 248: *> CWORK(2) returns the minimal LCWORK.
! 249: *> \endverbatim
! 250: *>
! 251: *> \param[in,out] LCWORK
! 252: *> \verbatim
! 253: *> LCWORK is INTEGER
! 254: *> The dimension of the array CWORK. It is determined as follows:
! 255: *> Let LWQP3 = N+1, LWCON = 2*N, and let
! 256: *> LWUNQ = { MAX( N, 1 ), if JOBU = 'R', 'S', or 'U'
! 257: *> { MAX( M, 1 ), if JOBU = 'A'
! 258: *> LWSVD = MAX( 3*N, 1 )
! 259: *> LWLQF = MAX( N/2, 1 ), LWSVD2 = MAX( 3*(N/2), 1 ), LWUNLQ = MAX( N, 1 ),
! 260: *> LWQRF = MAX( N/2, 1 ), LWUNQ2 = MAX( N, 1 )
! 261: *> Then the minimal value of LCWORK is:
! 262: *> = MAX( N + LWQP3, LWSVD ) if only the singular values are needed;
! 263: *> = MAX( N + LWQP3, LWCON, LWSVD ) if only the singular values are needed,
! 264: *> and a scaled condition estimate requested;
! 265: *>
! 266: *> = N + MAX( LWQP3, LWSVD, LWUNQ ) if the singular values and the left
! 267: *> singular vectors are requested;
! 268: *> = N + MAX( LWQP3, LWCON, LWSVD, LWUNQ ) if the singular values and the left
! 269: *> singular vectors are requested, and also
! 270: *> a scaled condition estimate requested;
! 271: *>
! 272: *> = N + MAX( LWQP3, LWSVD ) if the singular values and the right
! 273: *> singular vectors are requested;
! 274: *> = N + MAX( LWQP3, LWCON, LWSVD ) if the singular values and the right
! 275: *> singular vectors are requested, and also
! 276: *> a scaled condition etimate requested;
! 277: *>
! 278: *> = N + MAX( LWQP3, LWSVD, LWUNQ ) if the full SVD is requested with JOBV = 'R';
! 279: *> independent of JOBR;
! 280: *> = N + MAX( LWQP3, LWCON, LWSVD, LWUNQ ) if the full SVD is requested,
! 281: *> JOBV = 'R' and, also a scaled condition
! 282: *> estimate requested; independent of JOBR;
! 283: *> = MAX( N + MAX( LWQP3, LWSVD, LWUNQ ),
! 284: *> N + MAX( LWQP3, N/2+LWLQF, N/2+LWSVD2, N/2+LWUNLQ, LWUNQ) ) if the
! 285: *> full SVD is requested with JOBV = 'A' or 'V', and
! 286: *> JOBR ='N'
! 287: *> = MAX( N + MAX( LWQP3, LWCON, LWSVD, LWUNQ ),
! 288: *> N + MAX( LWQP3, LWCON, N/2+LWLQF, N/2+LWSVD2, N/2+LWUNLQ, LWUNQ ) )
! 289: *> if the full SVD is requested with JOBV = 'A' or 'V', and
! 290: *> JOBR ='N', and also a scaled condition number estimate
! 291: *> requested.
! 292: *> = MAX( N + MAX( LWQP3, LWSVD, LWUNQ ),
! 293: *> N + MAX( LWQP3, N/2+LWQRF, N/2+LWSVD2, N/2+LWUNQ2, LWUNQ ) ) if the
! 294: *> full SVD is requested with JOBV = 'A', 'V', and JOBR ='T'
! 295: *> = MAX( N + MAX( LWQP3, LWCON, LWSVD, LWUNQ ),
! 296: *> N + MAX( LWQP3, LWCON, N/2+LWQRF, N/2+LWSVD2, N/2+LWUNQ2, LWUNQ ) )
! 297: *> if the full SVD is requested with JOBV = 'A', 'V' and
! 298: *> JOBR ='T', and also a scaled condition number estimate
! 299: *> requested.
! 300: *> Finally, LCWORK must be at least two: LCWORK = MAX( 2, LCWORK ).
! 301: *>
! 302: *> If LCWORK = -1, then a workspace query is assumed; the routine
! 303: *> only calculates and returns the optimal and minimal sizes
! 304: *> for the CWORK, IWORK, and RWORK arrays, and no error
! 305: *> message related to LCWORK is issued by XERBLA.
! 306: *> \endverbatim
! 307: *>
! 308: *> \param[out] RWORK
! 309: *> \verbatim
! 310: *> RWORK is DOUBLE PRECISION array, dimension (max(1, LRWORK)).
! 311: *> On exit,
! 312: *> 1. If JOBA = 'E', RWORK(1) contains an estimate of the condition
! 313: *> number of column scaled A. If A = C * D where D is diagonal and C
! 314: *> has unit columns in the Euclidean norm, then, assuming full column rank,
! 315: *> N^(-1/4) * RWORK(1) <= ||pinv(C)||_2 <= N^(1/4) * RWORK(1).
! 316: *> Otherwise, RWORK(1) = -1.
! 317: *> 2. RWORK(2) contains the number of singular values computed as
! 318: *> exact zeros in ZGESVD applied to the upper triangular or trapeziodal
! 319: *> R (from the initial QR factorization). In case of early exit (no call to
! 320: *> ZGESVD, such as in the case of zero matrix) RWORK(2) = -1.
! 321: *
! 322: *> If LIWORK, LCWORK, or LRWORK = -1, then on exit, if INFO = 0,
! 323: *> RWORK(1) returns the minimal LRWORK.
! 324: *> \endverbatim
! 325: *>
! 326: *> \param[in] LRWORK
! 327: *> \verbatim
! 328: *> LRWORK is INTEGER.
! 329: *> The dimension of the array RWORK.
! 330: *> If JOBP ='P', then LRWORK >= MAX(2, M, 5*N);
! 331: *> Otherwise, LRWORK >= MAX(2, 5*N).
! 332: *
! 333: *> If LRWORK = -1, then a workspace query is assumed; the routine
! 334: *> only calculates and returns the optimal and minimal sizes
! 335: *> for the CWORK, IWORK, and RWORK arrays, and no error
! 336: *> message related to LCWORK is issued by XERBLA.
! 337: *> \endverbatim
! 338: *>
! 339: *> \param[out] INFO
! 340: *> \verbatim
! 341: *> INFO is INTEGER
! 342: *> = 0: successful exit.
! 343: *> < 0: if INFO = -i, the i-th argument had an illegal value.
! 344: *> > 0: if ZBDSQR did not converge, INFO specifies how many superdiagonals
! 345: *> of an intermediate bidiagonal form B (computed in ZGESVD) did not
! 346: *> converge to zero.
! 347: *> \endverbatim
! 348: *
! 349: *> \par Further Details:
! 350: * ========================
! 351: *>
! 352: *> \verbatim
! 353: *>
! 354: *> 1. The data movement (matrix transpose) is coded using simple nested
! 355: *> DO-loops because BLAS and LAPACK do not provide corresponding subroutines.
! 356: *> Those DO-loops are easily identified in this source code - by the CONTINUE
! 357: *> statements labeled with 11**. In an optimized version of this code, the
! 358: *> nested DO loops should be replaced with calls to an optimized subroutine.
! 359: *> 2. This code scales A by 1/SQRT(M) if the largest ABS(A(i,j)) could cause
! 360: *> column norm overflow. This is the minial precaution and it is left to the
! 361: *> SVD routine (CGESVD) to do its own preemptive scaling if potential over-
! 362: *> or underflows are detected. To avoid repeated scanning of the array A,
! 363: *> an optimal implementation would do all necessary scaling before calling
! 364: *> CGESVD and the scaling in CGESVD can be switched off.
! 365: *> 3. Other comments related to code optimization are given in comments in the
! 366: *> code, enlosed in [[double brackets]].
! 367: *> \endverbatim
! 368: *
! 369: *> \par Bugs, examples and comments
! 370: * ===========================
! 371: *
! 372: *> \verbatim
! 373: *> Please report all bugs and send interesting examples and/or comments to
! 374: *> drmac@math.hr. Thank you.
! 375: *> \endverbatim
! 376: *
! 377: *> \par References
! 378: * ===============
! 379: *
! 380: *> \verbatim
! 381: *> [1] Zlatko Drmac, Algorithm 977: A QR-Preconditioned QR SVD Method for
! 382: *> Computing the SVD with High Accuracy. ACM Trans. Math. Softw.
! 383: *> 44(1): 11:1-11:30 (2017)
! 384: *>
! 385: *> SIGMA library, xGESVDQ section updated February 2016.
! 386: *> Developed and coded by Zlatko Drmac, Department of Mathematics
! 387: *> University of Zagreb, Croatia, drmac@math.hr
! 388: *> \endverbatim
! 389: *
! 390: *
! 391: *> \par Contributors:
! 392: * ==================
! 393: *>
! 394: *> \verbatim
! 395: *> Developed and coded by Zlatko Drmac, Department of Mathematics
! 396: *> University of Zagreb, Croatia, drmac@math.hr
! 397: *> \endverbatim
! 398: *
! 399: * Authors:
! 400: * ========
! 401: *
! 402: *> \author Univ. of Tennessee
! 403: *> \author Univ. of California Berkeley
! 404: *> \author Univ. of Colorado Denver
! 405: *> \author NAG Ltd.
! 406: *
! 407: *> \date November 2018
! 408: *
! 409: *> \ingroup complex16GEsing
! 410: *
! 411: * =====================================================================
! 412: SUBROUTINE ZGESVDQ( JOBA, JOBP, JOBR, JOBU, JOBV, M, N, A, LDA,
! 413: $ S, U, LDU, V, LDV, NUMRANK, IWORK, LIWORK,
! 414: $ CWORK, LCWORK, RWORK, LRWORK, INFO )
! 415: * .. Scalar Arguments ..
! 416: IMPLICIT NONE
! 417: CHARACTER JOBA, JOBP, JOBR, JOBU, JOBV
! 418: INTEGER M, N, LDA, LDU, LDV, NUMRANK, LIWORK, LCWORK, LRWORK,
! 419: $ INFO
! 420: * ..
! 421: * .. Array Arguments ..
! 422: COMPLEX*16 A( LDA, * ), U( LDU, * ), V( LDV, * ), CWORK( * )
! 423: DOUBLE PRECISION S( * ), RWORK( * )
! 424: INTEGER IWORK( * )
! 425: *
! 426: * =====================================================================
! 427: *
! 428: * .. Parameters ..
! 429: DOUBLE PRECISION ZERO, ONE
! 430: PARAMETER ( ZERO = 0.0D0, ONE = 1.0D0 )
! 431: COMPLEX*16 CZERO, CONE
! 432: PARAMETER ( CZERO = (0.0D0,0.0D0), CONE = (1.0D0,0.0D0) )
! 433: * ..
! 434: * .. Local Scalars ..
! 435: INTEGER IERR, NR, N1, OPTRATIO, p, q
! 436: INTEGER LWCON, LWQP3, LWRK_ZGELQF, LWRK_ZGESVD, LWRK_ZGESVD2,
! 437: $ LWRK_ZGEQP3, LWRK_ZGEQRF, LWRK_ZUNMLQ, LWRK_ZUNMQR,
! 438: $ LWRK_ZUNMQR2, LWLQF, LWQRF, LWSVD, LWSVD2, LWUNQ,
! 439: $ LWUNQ2, LWUNLQ, MINWRK, MINWRK2, OPTWRK, OPTWRK2,
! 440: $ IMINWRK, RMINWRK
! 441: LOGICAL ACCLA, ACCLM, ACCLH, ASCALED, CONDA, DNTWU, DNTWV,
! 442: $ LQUERY, LSVC0, LSVEC, ROWPRM, RSVEC, RTRANS, WNTUA,
! 443: $ WNTUF, WNTUR, WNTUS, WNTVA, WNTVR
! 444: DOUBLE PRECISION BIG, EPSLN, RTMP, SCONDA, SFMIN
! 445: COMPLEX*16 CTMP
! 446: * ..
! 447: * .. Local Arrays
! 448: COMPLEX*16 CDUMMY(1)
! 449: DOUBLE PRECISION RDUMMY(1)
! 450: * ..
! 451: * .. External Subroutines (BLAS, LAPACK)
! 452: EXTERNAL ZGELQF, ZGEQP3, ZGEQRF, ZGESVD, ZLACPY, ZLAPMT,
! 453: $ ZLASCL, ZLASET, ZLASWP, ZDSCAL, DLASET, DLASCL,
! 454: $ ZPOCON, ZUNMLQ, ZUNMQR, XERBLA
! 455: * ..
! 456: * .. External Functions (BLAS, LAPACK)
! 457: LOGICAL LSAME
! 458: INTEGER IDAMAX
! 459: DOUBLE PRECISION ZLANGE, DZNRM2, DLAMCH
! 460: EXTERNAL LSAME, ZLANGE, IDAMAX, DZNRM2, DLAMCH
! 461: * ..
! 462: * .. Intrinsic Functions ..
! 463: INTRINSIC ABS, CONJG, MAX, MIN, DBLE, SQRT
! 464: * ..
! 465: * .. Executable Statements ..
! 466: *
! 467: * Test the input arguments
! 468: *
! 469: WNTUS = LSAME( JOBU, 'S' ) .OR. LSAME( JOBU, 'U' )
! 470: WNTUR = LSAME( JOBU, 'R' )
! 471: WNTUA = LSAME( JOBU, 'A' )
! 472: WNTUF = LSAME( JOBU, 'F' )
! 473: LSVC0 = WNTUS .OR. WNTUR .OR. WNTUA
! 474: LSVEC = LSVC0 .OR. WNTUF
! 475: DNTWU = LSAME( JOBU, 'N' )
! 476: *
! 477: WNTVR = LSAME( JOBV, 'R' )
! 478: WNTVA = LSAME( JOBV, 'A' ) .OR. LSAME( JOBV, 'V' )
! 479: RSVEC = WNTVR .OR. WNTVA
! 480: DNTWV = LSAME( JOBV, 'N' )
! 481: *
! 482: ACCLA = LSAME( JOBA, 'A' )
! 483: ACCLM = LSAME( JOBA, 'M' )
! 484: CONDA = LSAME( JOBA, 'E' )
! 485: ACCLH = LSAME( JOBA, 'H' ) .OR. CONDA
! 486: *
! 487: ROWPRM = LSAME( JOBP, 'P' )
! 488: RTRANS = LSAME( JOBR, 'T' )
! 489: *
! 490: IF ( ROWPRM ) THEN
! 491: IMINWRK = MAX( 1, N + M - 1 )
! 492: RMINWRK = MAX( 2, M, 5*N )
! 493: ELSE
! 494: IMINWRK = MAX( 1, N )
! 495: RMINWRK = MAX( 2, 5*N )
! 496: END IF
! 497: LQUERY = (LIWORK .EQ. -1 .OR. LCWORK .EQ. -1 .OR. LRWORK .EQ. -1)
! 498: INFO = 0
! 499: IF ( .NOT. ( ACCLA .OR. ACCLM .OR. ACCLH ) ) THEN
! 500: INFO = -1
! 501: ELSE IF ( .NOT.( ROWPRM .OR. LSAME( JOBP, 'N' ) ) ) THEN
! 502: INFO = -2
! 503: ELSE IF ( .NOT.( RTRANS .OR. LSAME( JOBR, 'N' ) ) ) THEN
! 504: INFO = -3
! 505: ELSE IF ( .NOT.( LSVEC .OR. DNTWU ) ) THEN
! 506: INFO = -4
! 507: ELSE IF ( WNTUR .AND. WNTVA ) THEN
! 508: INFO = -5
! 509: ELSE IF ( .NOT.( RSVEC .OR. DNTWV )) THEN
! 510: INFO = -5
! 511: ELSE IF ( M.LT.0 ) THEN
! 512: INFO = -6
! 513: ELSE IF ( ( N.LT.0 ) .OR. ( N.GT.M ) ) THEN
! 514: INFO = -7
! 515: ELSE IF ( LDA.LT.MAX( 1, M ) ) THEN
! 516: INFO = -9
! 517: ELSE IF ( LDU.LT.1 .OR. ( LSVC0 .AND. LDU.LT.M ) .OR.
! 518: $ ( WNTUF .AND. LDU.LT.N ) ) THEN
! 519: INFO = -12
! 520: ELSE IF ( LDV.LT.1 .OR. ( RSVEC .AND. LDV.LT.N ) .OR.
! 521: $ ( CONDA .AND. LDV.LT.N ) ) THEN
! 522: INFO = -14
! 523: ELSE IF ( LIWORK .LT. IMINWRK .AND. .NOT. LQUERY ) THEN
! 524: INFO = -17
! 525: END IF
! 526: *
! 527: *
! 528: IF ( INFO .EQ. 0 ) THEN
! 529: * .. compute the minimal and the optimal workspace lengths
! 530: * [[The expressions for computing the minimal and the optimal
! 531: * values of LCWORK are written with a lot of redundancy and
! 532: * can be simplified. However, this detailed form is easier for
! 533: * maintenance and modifications of the code.]]
! 534: *
! 535: * .. minimal workspace length for ZGEQP3 of an M x N matrix
! 536: LWQP3 = N+1
! 537: * .. minimal workspace length for ZUNMQR to build left singular vectors
! 538: IF ( WNTUS .OR. WNTUR ) THEN
! 539: LWUNQ = MAX( N , 1 )
! 540: ELSE IF ( WNTUA ) THEN
! 541: LWUNQ = MAX( M , 1 )
! 542: END IF
! 543: * .. minimal workspace length for ZPOCON of an N x N matrix
! 544: LWCON = 2 * N
! 545: * .. ZGESVD of an N x N matrix
! 546: LWSVD = MAX( 3 * N, 1 )
! 547: IF ( LQUERY ) THEN
! 548: CALL ZGEQP3( M, N, A, LDA, IWORK, CDUMMY, CDUMMY, -1,
! 549: $ RDUMMY, IERR )
! 550: LWRK_ZGEQP3 = INT( CDUMMY(1) )
! 551: IF ( WNTUS .OR. WNTUR ) THEN
! 552: CALL ZUNMQR( 'L', 'N', M, N, N, A, LDA, CDUMMY, U,
! 553: $ LDU, CDUMMY, -1, IERR )
! 554: LWRK_ZUNMQR = INT( CDUMMY(1) )
! 555: ELSE IF ( WNTUA ) THEN
! 556: CALL ZUNMQR( 'L', 'N', M, M, N, A, LDA, CDUMMY, U,
! 557: $ LDU, CDUMMY, -1, IERR )
! 558: LWRK_ZUNMQR = INT( CDUMMY(1) )
! 559: ELSE
! 560: LWRK_ZUNMQR = 0
! 561: END IF
! 562: END IF
! 563: MINWRK = 2
! 564: OPTWRK = 2
! 565: IF ( .NOT. (LSVEC .OR. RSVEC ) ) THEN
! 566: * .. minimal and optimal sizes of the complex workspace if
! 567: * only the singular values are requested
! 568: IF ( CONDA ) THEN
! 569: MINWRK = MAX( N+LWQP3, LWCON, LWSVD )
! 570: ELSE
! 571: MINWRK = MAX( N+LWQP3, LWSVD )
! 572: END IF
! 573: IF ( LQUERY ) THEN
! 574: CALL ZGESVD( 'N', 'N', N, N, A, LDA, S, U, LDU,
! 575: $ V, LDV, CDUMMY, -1, RDUMMY, IERR )
! 576: LWRK_ZGESVD = INT( CDUMMY(1) )
! 577: IF ( CONDA ) THEN
! 578: OPTWRK = MAX( N+LWRK_ZGEQP3, N+LWCON, LWRK_ZGESVD )
! 579: ELSE
! 580: OPTWRK = MAX( N+LWRK_ZGEQP3, LWRK_ZGESVD )
! 581: END IF
! 582: END IF
! 583: ELSE IF ( LSVEC .AND. (.NOT.RSVEC) ) THEN
! 584: * .. minimal and optimal sizes of the complex workspace if the
! 585: * singular values and the left singular vectors are requested
! 586: IF ( CONDA ) THEN
! 587: MINWRK = N + MAX( LWQP3, LWCON, LWSVD, LWUNQ )
! 588: ELSE
! 589: MINWRK = N + MAX( LWQP3, LWSVD, LWUNQ )
! 590: END IF
! 591: IF ( LQUERY ) THEN
! 592: IF ( RTRANS ) THEN
! 593: CALL ZGESVD( 'N', 'O', N, N, A, LDA, S, U, LDU,
! 594: $ V, LDV, CDUMMY, -1, RDUMMY, IERR )
! 595: ELSE
! 596: CALL ZGESVD( 'O', 'N', N, N, A, LDA, S, U, LDU,
! 597: $ V, LDV, CDUMMY, -1, RDUMMY, IERR )
! 598: END IF
! 599: LWRK_ZGESVD = INT( CDUMMY(1) )
! 600: IF ( CONDA ) THEN
! 601: OPTWRK = N + MAX( LWRK_ZGEQP3, LWCON, LWRK_ZGESVD,
! 602: $ LWRK_ZUNMQR )
! 603: ELSE
! 604: OPTWRK = N + MAX( LWRK_ZGEQP3, LWRK_ZGESVD,
! 605: $ LWRK_ZUNMQR )
! 606: END IF
! 607: END IF
! 608: ELSE IF ( RSVEC .AND. (.NOT.LSVEC) ) THEN
! 609: * .. minimal and optimal sizes of the complex workspace if the
! 610: * singular values and the right singular vectors are requested
! 611: IF ( CONDA ) THEN
! 612: MINWRK = N + MAX( LWQP3, LWCON, LWSVD )
! 613: ELSE
! 614: MINWRK = N + MAX( LWQP3, LWSVD )
! 615: END IF
! 616: IF ( LQUERY ) THEN
! 617: IF ( RTRANS ) THEN
! 618: CALL ZGESVD( 'O', 'N', N, N, A, LDA, S, U, LDU,
! 619: $ V, LDV, CDUMMY, -1, RDUMMY, IERR )
! 620: ELSE
! 621: CALL ZGESVD( 'N', 'O', N, N, A, LDA, S, U, LDU,
! 622: $ V, LDV, CDUMMY, -1, RDUMMY, IERR )
! 623: END IF
! 624: LWRK_ZGESVD = INT( CDUMMY(1) )
! 625: IF ( CONDA ) THEN
! 626: OPTWRK = N + MAX( LWRK_ZGEQP3, LWCON, LWRK_ZGESVD )
! 627: ELSE
! 628: OPTWRK = N + MAX( LWRK_ZGEQP3, LWRK_ZGESVD )
! 629: END IF
! 630: END IF
! 631: ELSE
! 632: * .. minimal and optimal sizes of the complex workspace if the
! 633: * full SVD is requested
! 634: IF ( RTRANS ) THEN
! 635: MINWRK = MAX( LWQP3, LWSVD, LWUNQ )
! 636: IF ( CONDA ) MINWRK = MAX( MINWRK, LWCON )
! 637: MINWRK = MINWRK + N
! 638: IF ( WNTVA ) THEN
! 639: * .. minimal workspace length for N x N/2 ZGEQRF
! 640: LWQRF = MAX( N/2, 1 )
! 641: * .. minimal workspace lengt for N/2 x N/2 ZGESVD
! 642: LWSVD2 = MAX( 3 * (N/2), 1 )
! 643: LWUNQ2 = MAX( N, 1 )
! 644: MINWRK2 = MAX( LWQP3, N/2+LWQRF, N/2+LWSVD2,
! 645: $ N/2+LWUNQ2, LWUNQ )
! 646: IF ( CONDA ) MINWRK2 = MAX( MINWRK2, LWCON )
! 647: MINWRK2 = N + MINWRK2
! 648: MINWRK = MAX( MINWRK, MINWRK2 )
! 649: END IF
! 650: ELSE
! 651: MINWRK = MAX( LWQP3, LWSVD, LWUNQ )
! 652: IF ( CONDA ) MINWRK = MAX( MINWRK, LWCON )
! 653: MINWRK = MINWRK + N
! 654: IF ( WNTVA ) THEN
! 655: * .. minimal workspace length for N/2 x N ZGELQF
! 656: LWLQF = MAX( N/2, 1 )
! 657: LWSVD2 = MAX( 3 * (N/2), 1 )
! 658: LWUNLQ = MAX( N , 1 )
! 659: MINWRK2 = MAX( LWQP3, N/2+LWLQF, N/2+LWSVD2,
! 660: $ N/2+LWUNLQ, LWUNQ )
! 661: IF ( CONDA ) MINWRK2 = MAX( MINWRK2, LWCON )
! 662: MINWRK2 = N + MINWRK2
! 663: MINWRK = MAX( MINWRK, MINWRK2 )
! 664: END IF
! 665: END IF
! 666: IF ( LQUERY ) THEN
! 667: IF ( RTRANS ) THEN
! 668: CALL ZGESVD( 'O', 'A', N, N, A, LDA, S, U, LDU,
! 669: $ V, LDV, CDUMMY, -1, RDUMMY, IERR )
! 670: LWRK_ZGESVD = INT( CDUMMY(1) )
! 671: OPTWRK = MAX(LWRK_ZGEQP3,LWRK_ZGESVD,LWRK_ZUNMQR)
! 672: IF ( CONDA ) OPTWRK = MAX( OPTWRK, LWCON )
! 673: OPTWRK = N + OPTWRK
! 674: IF ( WNTVA ) THEN
! 675: CALL ZGEQRF(N,N/2,U,LDU,CDUMMY,CDUMMY,-1,IERR)
! 676: LWRK_ZGEQRF = INT( CDUMMY(1) )
! 677: CALL ZGESVD( 'S', 'O', N/2,N/2, V,LDV, S, U,LDU,
! 678: $ V, LDV, CDUMMY, -1, RDUMMY, IERR )
! 679: LWRK_ZGESVD2 = INT( CDUMMY(1) )
! 680: CALL ZUNMQR( 'R', 'C', N, N, N/2, U, LDU, CDUMMY,
! 681: $ V, LDV, CDUMMY, -1, IERR )
! 682: LWRK_ZUNMQR2 = INT( CDUMMY(1) )
! 683: OPTWRK2 = MAX( LWRK_ZGEQP3, N/2+LWRK_ZGEQRF,
! 684: $ N/2+LWRK_ZGESVD2, N/2+LWRK_ZUNMQR2 )
! 685: IF ( CONDA ) OPTWRK2 = MAX( OPTWRK2, LWCON )
! 686: OPTWRK2 = N + OPTWRK2
! 687: OPTWRK = MAX( OPTWRK, OPTWRK2 )
! 688: END IF
! 689: ELSE
! 690: CALL ZGESVD( 'S', 'O', N, N, A, LDA, S, U, LDU,
! 691: $ V, LDV, CDUMMY, -1, RDUMMY, IERR )
! 692: LWRK_ZGESVD = INT( CDUMMY(1) )
! 693: OPTWRK = MAX(LWRK_ZGEQP3,LWRK_ZGESVD,LWRK_ZUNMQR)
! 694: IF ( CONDA ) OPTWRK = MAX( OPTWRK, LWCON )
! 695: OPTWRK = N + OPTWRK
! 696: IF ( WNTVA ) THEN
! 697: CALL ZGELQF(N/2,N,U,LDU,CDUMMY,CDUMMY,-1,IERR)
! 698: LWRK_ZGELQF = INT( CDUMMY(1) )
! 699: CALL ZGESVD( 'S','O', N/2,N/2, V, LDV, S, U, LDU,
! 700: $ V, LDV, CDUMMY, -1, RDUMMY, IERR )
! 701: LWRK_ZGESVD2 = INT( CDUMMY(1) )
! 702: CALL ZUNMLQ( 'R', 'N', N, N, N/2, U, LDU, CDUMMY,
! 703: $ V, LDV, CDUMMY,-1,IERR )
! 704: LWRK_ZUNMLQ = INT( CDUMMY(1) )
! 705: OPTWRK2 = MAX( LWRK_ZGEQP3, N/2+LWRK_ZGELQF,
! 706: $ N/2+LWRK_ZGESVD2, N/2+LWRK_ZUNMLQ )
! 707: IF ( CONDA ) OPTWRK2 = MAX( OPTWRK2, LWCON )
! 708: OPTWRK2 = N + OPTWRK2
! 709: OPTWRK = MAX( OPTWRK, OPTWRK2 )
! 710: END IF
! 711: END IF
! 712: END IF
! 713: END IF
! 714: *
! 715: MINWRK = MAX( 2, MINWRK )
! 716: OPTWRK = MAX( 2, OPTWRK )
! 717: IF ( LCWORK .LT. MINWRK .AND. (.NOT.LQUERY) ) INFO = -19
! 718: *
! 719: END IF
! 720: *
! 721: IF (INFO .EQ. 0 .AND. LRWORK .LT. RMINWRK .AND. .NOT. LQUERY) THEN
! 722: INFO = -21
! 723: END IF
! 724: IF( INFO.NE.0 ) THEN
! 725: CALL XERBLA( 'ZGESVDQ', -INFO )
! 726: RETURN
! 727: ELSE IF ( LQUERY ) THEN
! 728: *
! 729: * Return optimal workspace
! 730: *
! 731: IWORK(1) = IMINWRK
! 732: CWORK(1) = OPTWRK
! 733: CWORK(2) = MINWRK
! 734: RWORK(1) = RMINWRK
! 735: RETURN
! 736: END IF
! 737: *
! 738: * Quick return if the matrix is void.
! 739: *
! 740: IF( ( M.EQ.0 ) .OR. ( N.EQ.0 ) ) THEN
! 741: * .. all output is void.
! 742: RETURN
! 743: END IF
! 744: *
! 745: BIG = DLAMCH('O')
! 746: ASCALED = .FALSE.
! 747: IF ( ROWPRM ) THEN
! 748: * .. reordering the rows in decreasing sequence in the
! 749: * ell-infinity norm - this enhances numerical robustness in
! 750: * the case of differently scaled rows.
! 751: DO 1904 p = 1, M
! 752: * RWORK(p) = ABS( A(p,IZAMAX(N,A(p,1),LDA)) )
! 753: * [[ZLANGE will return NaN if an entry of the p-th row is Nan]]
! 754: RWORK(p) = ZLANGE( 'M', 1, N, A(p,1), LDA, RDUMMY )
! 755: * .. check for NaN's and Inf's
! 756: IF ( ( RWORK(p) .NE. RWORK(p) ) .OR.
! 757: $ ( (RWORK(p)*ZERO) .NE. ZERO ) ) THEN
! 758: INFO = -8
! 759: CALL XERBLA( 'ZGESVDQ', -INFO )
! 760: RETURN
! 761: END IF
! 762: 1904 CONTINUE
! 763: DO 1952 p = 1, M - 1
! 764: q = IDAMAX( M-p+1, RWORK(p), 1 ) + p - 1
! 765: IWORK(N+p) = q
! 766: IF ( p .NE. q ) THEN
! 767: RTMP = RWORK(p)
! 768: RWORK(p) = RWORK(q)
! 769: RWORK(q) = RTMP
! 770: END IF
! 771: 1952 CONTINUE
! 772: *
! 773: IF ( RWORK(1) .EQ. ZERO ) THEN
! 774: * Quick return: A is the M x N zero matrix.
! 775: NUMRANK = 0
! 776: CALL DLASET( 'G', N, 1, ZERO, ZERO, S, N )
! 777: IF ( WNTUS ) CALL ZLASET('G', M, N, CZERO, CONE, U, LDU)
! 778: IF ( WNTUA ) CALL ZLASET('G', M, M, CZERO, CONE, U, LDU)
! 779: IF ( WNTVA ) CALL ZLASET('G', N, N, CZERO, CONE, V, LDV)
! 780: IF ( WNTUF ) THEN
! 781: CALL ZLASET( 'G', N, 1, CZERO, CZERO, CWORK, N )
! 782: CALL ZLASET( 'G', M, N, CZERO, CONE, U, LDU )
! 783: END IF
! 784: DO 5001 p = 1, N
! 785: IWORK(p) = p
! 786: 5001 CONTINUE
! 787: IF ( ROWPRM ) THEN
! 788: DO 5002 p = N + 1, N + M - 1
! 789: IWORK(p) = p - N
! 790: 5002 CONTINUE
! 791: END IF
! 792: IF ( CONDA ) RWORK(1) = -1
! 793: RWORK(2) = -1
! 794: RETURN
! 795: END IF
! 796: *
! 797: IF ( RWORK(1) .GT. BIG / SQRT(DBLE(M)) ) THEN
! 798: * .. to prevent overflow in the QR factorization, scale the
! 799: * matrix by 1/sqrt(M) if too large entry detected
! 800: CALL ZLASCL('G',0,0,SQRT(DBLE(M)),ONE, M,N, A,LDA, IERR)
! 801: ASCALED = .TRUE.
! 802: END IF
! 803: CALL ZLASWP( N, A, LDA, 1, M-1, IWORK(N+1), 1 )
! 804: END IF
! 805: *
! 806: * .. At this stage, preemptive scaling is done only to avoid column
! 807: * norms overflows during the QR factorization. The SVD procedure should
! 808: * have its own scaling to save the singular values from overflows and
! 809: * underflows. That depends on the SVD procedure.
! 810: *
! 811: IF ( .NOT.ROWPRM ) THEN
! 812: RTMP = ZLANGE( 'M', M, N, A, LDA, RWORK )
! 813: IF ( ( RTMP .NE. RTMP ) .OR.
! 814: $ ( (RTMP*ZERO) .NE. ZERO ) ) THEN
! 815: INFO = -8
! 816: CALL XERBLA( 'ZGESVDQ', -INFO )
! 817: RETURN
! 818: END IF
! 819: IF ( RTMP .GT. BIG / SQRT(DBLE(M)) ) THEN
! 820: * .. to prevent overflow in the QR factorization, scale the
! 821: * matrix by 1/sqrt(M) if too large entry detected
! 822: CALL ZLASCL('G',0,0, SQRT(DBLE(M)),ONE, M,N, A,LDA, IERR)
! 823: ASCALED = .TRUE.
! 824: END IF
! 825: END IF
! 826: *
! 827: * .. QR factorization with column pivoting
! 828: *
! 829: * A * P = Q * [ R ]
! 830: * [ 0 ]
! 831: *
! 832: DO 1963 p = 1, N
! 833: * .. all columns are free columns
! 834: IWORK(p) = 0
! 835: 1963 CONTINUE
! 836: CALL ZGEQP3( M, N, A, LDA, IWORK, CWORK, CWORK(N+1), LCWORK-N,
! 837: $ RWORK, IERR )
! 838: *
! 839: * If the user requested accuracy level allows truncation in the
! 840: * computed upper triangular factor, the matrix R is examined and,
! 841: * if possible, replaced with its leading upper trapezoidal part.
! 842: *
! 843: EPSLN = DLAMCH('E')
! 844: SFMIN = DLAMCH('S')
! 845: * SMALL = SFMIN / EPSLN
! 846: NR = N
! 847: *
! 848: IF ( ACCLA ) THEN
! 849: *
! 850: * Standard absolute error bound suffices. All sigma_i with
! 851: * sigma_i < N*EPS*||A||_F are flushed to zero. This is an
! 852: * aggressive enforcement of lower numerical rank by introducing a
! 853: * backward error of the order of N*EPS*||A||_F.
! 854: NR = 1
! 855: RTMP = SQRT(DBLE(N))*EPSLN
! 856: DO 3001 p = 2, N
! 857: IF ( ABS(A(p,p)) .LT. (RTMP*ABS(A(1,1))) ) GO TO 3002
! 858: NR = NR + 1
! 859: 3001 CONTINUE
! 860: 3002 CONTINUE
! 861: *
! 862: ELSEIF ( ACCLM ) THEN
! 863: * .. similarly as above, only slightly more gentle (less aggressive).
! 864: * Sudden drop on the diagonal of R is used as the criterion for being
! 865: * close-to-rank-deficient. The threshold is set to EPSLN=DLAMCH('E').
! 866: * [[This can be made more flexible by replacing this hard-coded value
! 867: * with a user specified threshold.]] Also, the values that underflow
! 868: * will be truncated.
! 869: NR = 1
! 870: DO 3401 p = 2, N
! 871: IF ( ( ABS(A(p,p)) .LT. (EPSLN*ABS(A(p-1,p-1))) ) .OR.
! 872: $ ( ABS(A(p,p)) .LT. SFMIN ) ) GO TO 3402
! 873: NR = NR + 1
! 874: 3401 CONTINUE
! 875: 3402 CONTINUE
! 876: *
! 877: ELSE
! 878: * .. RRQR not authorized to determine numerical rank except in the
! 879: * obvious case of zero pivots.
! 880: * .. inspect R for exact zeros on the diagonal;
! 881: * R(i,i)=0 => R(i:N,i:N)=0.
! 882: NR = 1
! 883: DO 3501 p = 2, N
! 884: IF ( ABS(A(p,p)) .EQ. ZERO ) GO TO 3502
! 885: NR = NR + 1
! 886: 3501 CONTINUE
! 887: 3502 CONTINUE
! 888: *
! 889: IF ( CONDA ) THEN
! 890: * Estimate the scaled condition number of A. Use the fact that it is
! 891: * the same as the scaled condition number of R.
! 892: * .. V is used as workspace
! 893: CALL ZLACPY( 'U', N, N, A, LDA, V, LDV )
! 894: * Only the leading NR x NR submatrix of the triangular factor
! 895: * is considered. Only if NR=N will this give a reliable error
! 896: * bound. However, even for NR < N, this can be used on an
! 897: * expert level and obtain useful information in the sense of
! 898: * perturbation theory.
! 899: DO 3053 p = 1, NR
! 900: RTMP = DZNRM2( p, V(1,p), 1 )
! 901: CALL ZDSCAL( p, ONE/RTMP, V(1,p), 1 )
! 902: 3053 CONTINUE
! 903: IF ( .NOT. ( LSVEC .OR. RSVEC ) ) THEN
! 904: CALL ZPOCON( 'U', NR, V, LDV, ONE, RTMP,
! 905: $ CWORK, RWORK, IERR )
! 906: ELSE
! 907: CALL ZPOCON( 'U', NR, V, LDV, ONE, RTMP,
! 908: $ CWORK(N+1), RWORK, IERR )
! 909: END IF
! 910: SCONDA = ONE / SQRT(RTMP)
! 911: * For NR=N, SCONDA is an estimate of SQRT(||(R^* * R)^(-1)||_1),
! 912: * N^(-1/4) * SCONDA <= ||R^(-1)||_2 <= N^(1/4) * SCONDA
! 913: * See the reference [1] for more details.
! 914: END IF
! 915: *
! 916: ENDIF
! 917: *
! 918: IF ( WNTUR ) THEN
! 919: N1 = NR
! 920: ELSE IF ( WNTUS .OR. WNTUF) THEN
! 921: N1 = N
! 922: ELSE IF ( WNTUA ) THEN
! 923: N1 = M
! 924: END IF
! 925: *
! 926: IF ( .NOT. ( RSVEC .OR. LSVEC ) ) THEN
! 927: *.......................................................................
! 928: * .. only the singular values are requested
! 929: *.......................................................................
! 930: IF ( RTRANS ) THEN
! 931: *
! 932: * .. compute the singular values of R**H = [A](1:NR,1:N)**H
! 933: * .. set the lower triangle of [A] to [A](1:NR,1:N)**H and
! 934: * the upper triangle of [A] to zero.
! 935: DO 1146 p = 1, MIN( N, NR )
! 936: A(p,p) = CONJG(A(p,p))
! 937: DO 1147 q = p + 1, N
! 938: A(q,p) = CONJG(A(p,q))
! 939: IF ( q .LE. NR ) A(p,q) = CZERO
! 940: 1147 CONTINUE
! 941: 1146 CONTINUE
! 942: *
! 943: CALL ZGESVD( 'N', 'N', N, NR, A, LDA, S, U, LDU,
! 944: $ V, LDV, CWORK, LCWORK, RWORK, INFO )
! 945: *
! 946: ELSE
! 947: *
! 948: * .. compute the singular values of R = [A](1:NR,1:N)
! 949: *
! 950: IF ( NR .GT. 1 )
! 951: $ CALL ZLASET( 'L', NR-1,NR-1, CZERO,CZERO, A(2,1), LDA )
! 952: CALL ZGESVD( 'N', 'N', NR, N, A, LDA, S, U, LDU,
! 953: $ V, LDV, CWORK, LCWORK, RWORK, INFO )
! 954: *
! 955: END IF
! 956: *
! 957: ELSE IF ( LSVEC .AND. ( .NOT. RSVEC) ) THEN
! 958: *.......................................................................
! 959: * .. the singular values and the left singular vectors requested
! 960: *.......................................................................""""""""
! 961: IF ( RTRANS ) THEN
! 962: * .. apply ZGESVD to R**H
! 963: * .. copy R**H into [U] and overwrite [U] with the right singular
! 964: * vectors of R
! 965: DO 1192 p = 1, NR
! 966: DO 1193 q = p, N
! 967: U(q,p) = CONJG(A(p,q))
! 968: 1193 CONTINUE
! 969: 1192 CONTINUE
! 970: IF ( NR .GT. 1 )
! 971: $ CALL ZLASET( 'U', NR-1,NR-1, CZERO,CZERO, U(1,2), LDU )
! 972: * .. the left singular vectors not computed, the NR right singular
! 973: * vectors overwrite [U](1:NR,1:NR) as conjugate transposed. These
! 974: * will be pre-multiplied by Q to build the left singular vectors of A.
! 975: CALL ZGESVD( 'N', 'O', N, NR, U, LDU, S, U, LDU,
! 976: $ U, LDU, CWORK(N+1), LCWORK-N, RWORK, INFO )
! 977: *
! 978: DO 1119 p = 1, NR
! 979: U(p,p) = CONJG(U(p,p))
! 980: DO 1120 q = p + 1, NR
! 981: CTMP = CONJG(U(q,p))
! 982: U(q,p) = CONJG(U(p,q))
! 983: U(p,q) = CTMP
! 984: 1120 CONTINUE
! 985: 1119 CONTINUE
! 986: *
! 987: ELSE
! 988: * .. apply ZGESVD to R
! 989: * .. copy R into [U] and overwrite [U] with the left singular vectors
! 990: CALL ZLACPY( 'U', NR, N, A, LDA, U, LDU )
! 991: IF ( NR .GT. 1 )
! 992: $ CALL ZLASET( 'L', NR-1, NR-1, CZERO, CZERO, U(2,1), LDU )
! 993: * .. the right singular vectors not computed, the NR left singular
! 994: * vectors overwrite [U](1:NR,1:NR)
! 995: CALL ZGESVD( 'O', 'N', NR, N, U, LDU, S, U, LDU,
! 996: $ V, LDV, CWORK(N+1), LCWORK-N, RWORK, INFO )
! 997: * .. now [U](1:NR,1:NR) contains the NR left singular vectors of
! 998: * R. These will be pre-multiplied by Q to build the left singular
! 999: * vectors of A.
! 1000: END IF
! 1001: *
! 1002: * .. assemble the left singular vector matrix U of dimensions
! 1003: * (M x NR) or (M x N) or (M x M).
! 1004: IF ( ( NR .LT. M ) .AND. ( .NOT.WNTUF ) ) THEN
! 1005: CALL ZLASET('A', M-NR, NR, CZERO, CZERO, U(NR+1,1), LDU)
! 1006: IF ( NR .LT. N1 ) THEN
! 1007: CALL ZLASET( 'A',NR,N1-NR,CZERO,CZERO,U(1,NR+1), LDU )
! 1008: CALL ZLASET( 'A',M-NR,N1-NR,CZERO,CONE,
! 1009: $ U(NR+1,NR+1), LDU )
! 1010: END IF
! 1011: END IF
! 1012: *
! 1013: * The Q matrix from the first QRF is built into the left singular
! 1014: * vectors matrix U.
! 1015: *
! 1016: IF ( .NOT.WNTUF )
! 1017: $ CALL ZUNMQR( 'L', 'N', M, N1, N, A, LDA, CWORK, U,
! 1018: $ LDU, CWORK(N+1), LCWORK-N, IERR )
! 1019: IF ( ROWPRM .AND. .NOT.WNTUF )
! 1020: $ CALL ZLASWP( N1, U, LDU, 1, M-1, IWORK(N+1), -1 )
! 1021: *
! 1022: ELSE IF ( RSVEC .AND. ( .NOT. LSVEC ) ) THEN
! 1023: *.......................................................................
! 1024: * .. the singular values and the right singular vectors requested
! 1025: *.......................................................................
! 1026: IF ( RTRANS ) THEN
! 1027: * .. apply ZGESVD to R**H
! 1028: * .. copy R**H into V and overwrite V with the left singular vectors
! 1029: DO 1165 p = 1, NR
! 1030: DO 1166 q = p, N
! 1031: V(q,p) = CONJG(A(p,q))
! 1032: 1166 CONTINUE
! 1033: 1165 CONTINUE
! 1034: IF ( NR .GT. 1 )
! 1035: $ CALL ZLASET( 'U', NR-1,NR-1, CZERO,CZERO, V(1,2), LDV )
! 1036: * .. the left singular vectors of R**H overwrite V, the right singular
! 1037: * vectors not computed
! 1038: IF ( WNTVR .OR. ( NR .EQ. N ) ) THEN
! 1039: CALL ZGESVD( 'O', 'N', N, NR, V, LDV, S, U, LDU,
! 1040: $ U, LDU, CWORK(N+1), LCWORK-N, RWORK, INFO )
! 1041: *
! 1042: DO 1121 p = 1, NR
! 1043: V(p,p) = CONJG(V(p,p))
! 1044: DO 1122 q = p + 1, NR
! 1045: CTMP = CONJG(V(q,p))
! 1046: V(q,p) = CONJG(V(p,q))
! 1047: V(p,q) = CTMP
! 1048: 1122 CONTINUE
! 1049: 1121 CONTINUE
! 1050: *
! 1051: IF ( NR .LT. N ) THEN
! 1052: DO 1103 p = 1, NR
! 1053: DO 1104 q = NR + 1, N
! 1054: V(p,q) = CONJG(V(q,p))
! 1055: 1104 CONTINUE
! 1056: 1103 CONTINUE
! 1057: END IF
! 1058: CALL ZLAPMT( .FALSE., NR, N, V, LDV, IWORK )
! 1059: ELSE
! 1060: * .. need all N right singular vectors and NR < N
! 1061: * [!] This is simple implementation that augments [V](1:N,1:NR)
! 1062: * by padding a zero block. In the case NR << N, a more efficient
! 1063: * way is to first use the QR factorization. For more details
! 1064: * how to implement this, see the " FULL SVD " branch.
! 1065: CALL ZLASET('G', N, N-NR, CZERO, CZERO, V(1,NR+1), LDV)
! 1066: CALL ZGESVD( 'O', 'N', N, N, V, LDV, S, U, LDU,
! 1067: $ U, LDU, CWORK(N+1), LCWORK-N, RWORK, INFO )
! 1068: *
! 1069: DO 1123 p = 1, N
! 1070: V(p,p) = CONJG(V(p,p))
! 1071: DO 1124 q = p + 1, N
! 1072: CTMP = CONJG(V(q,p))
! 1073: V(q,p) = CONJG(V(p,q))
! 1074: V(p,q) = CTMP
! 1075: 1124 CONTINUE
! 1076: 1123 CONTINUE
! 1077: CALL ZLAPMT( .FALSE., N, N, V, LDV, IWORK )
! 1078: END IF
! 1079: *
! 1080: ELSE
! 1081: * .. aply ZGESVD to R
! 1082: * .. copy R into V and overwrite V with the right singular vectors
! 1083: CALL ZLACPY( 'U', NR, N, A, LDA, V, LDV )
! 1084: IF ( NR .GT. 1 )
! 1085: $ CALL ZLASET( 'L', NR-1, NR-1, CZERO, CZERO, V(2,1), LDV )
! 1086: * .. the right singular vectors overwrite V, the NR left singular
! 1087: * vectors stored in U(1:NR,1:NR)
! 1088: IF ( WNTVR .OR. ( NR .EQ. N ) ) THEN
! 1089: CALL ZGESVD( 'N', 'O', NR, N, V, LDV, S, U, LDU,
! 1090: $ V, LDV, CWORK(N+1), LCWORK-N, RWORK, INFO )
! 1091: CALL ZLAPMT( .FALSE., NR, N, V, LDV, IWORK )
! 1092: * .. now [V](1:NR,1:N) contains V(1:N,1:NR)**H
! 1093: ELSE
! 1094: * .. need all N right singular vectors and NR < N
! 1095: * [!] This is simple implementation that augments [V](1:NR,1:N)
! 1096: * by padding a zero block. In the case NR << N, a more efficient
! 1097: * way is to first use the LQ factorization. For more details
! 1098: * how to implement this, see the " FULL SVD " branch.
! 1099: CALL ZLASET('G', N-NR, N, CZERO,CZERO, V(NR+1,1), LDV)
! 1100: CALL ZGESVD( 'N', 'O', N, N, V, LDV, S, U, LDU,
! 1101: $ V, LDV, CWORK(N+1), LCWORK-N, RWORK, INFO )
! 1102: CALL ZLAPMT( .FALSE., N, N, V, LDV, IWORK )
! 1103: END IF
! 1104: * .. now [V] contains the adjoint of the matrix of the right singular
! 1105: * vectors of A.
! 1106: END IF
! 1107: *
! 1108: ELSE
! 1109: *.......................................................................
! 1110: * .. FULL SVD requested
! 1111: *.......................................................................
! 1112: IF ( RTRANS ) THEN
! 1113: *
! 1114: * .. apply ZGESVD to R**H [[this option is left for R&D&T]]
! 1115: *
! 1116: IF ( WNTVR .OR. ( NR .EQ. N ) ) THEN
! 1117: * .. copy R**H into [V] and overwrite [V] with the left singular
! 1118: * vectors of R**H
! 1119: DO 1168 p = 1, NR
! 1120: DO 1169 q = p, N
! 1121: V(q,p) = CONJG(A(p,q))
! 1122: 1169 CONTINUE
! 1123: 1168 CONTINUE
! 1124: IF ( NR .GT. 1 )
! 1125: $ CALL ZLASET( 'U', NR-1,NR-1, CZERO,CZERO, V(1,2), LDV )
! 1126: *
! 1127: * .. the left singular vectors of R**H overwrite [V], the NR right
! 1128: * singular vectors of R**H stored in [U](1:NR,1:NR) as conjugate
! 1129: * transposed
! 1130: CALL ZGESVD( 'O', 'A', N, NR, V, LDV, S, V, LDV,
! 1131: $ U, LDU, CWORK(N+1), LCWORK-N, RWORK, INFO )
! 1132: * .. assemble V
! 1133: DO 1115 p = 1, NR
! 1134: V(p,p) = CONJG(V(p,p))
! 1135: DO 1116 q = p + 1, NR
! 1136: CTMP = CONJG(V(q,p))
! 1137: V(q,p) = CONJG(V(p,q))
! 1138: V(p,q) = CTMP
! 1139: 1116 CONTINUE
! 1140: 1115 CONTINUE
! 1141: IF ( NR .LT. N ) THEN
! 1142: DO 1101 p = 1, NR
! 1143: DO 1102 q = NR+1, N
! 1144: V(p,q) = CONJG(V(q,p))
! 1145: 1102 CONTINUE
! 1146: 1101 CONTINUE
! 1147: END IF
! 1148: CALL ZLAPMT( .FALSE., NR, N, V, LDV, IWORK )
! 1149: *
! 1150: DO 1117 p = 1, NR
! 1151: U(p,p) = CONJG(U(p,p))
! 1152: DO 1118 q = p + 1, NR
! 1153: CTMP = CONJG(U(q,p))
! 1154: U(q,p) = CONJG(U(p,q))
! 1155: U(p,q) = CTMP
! 1156: 1118 CONTINUE
! 1157: 1117 CONTINUE
! 1158: *
! 1159: IF ( ( NR .LT. M ) .AND. .NOT.(WNTUF)) THEN
! 1160: CALL ZLASET('A', M-NR,NR, CZERO,CZERO, U(NR+1,1), LDU)
! 1161: IF ( NR .LT. N1 ) THEN
! 1162: CALL ZLASET('A',NR,N1-NR,CZERO,CZERO,U(1,NR+1),LDU)
! 1163: CALL ZLASET( 'A',M-NR,N1-NR,CZERO,CONE,
! 1164: $ U(NR+1,NR+1), LDU )
! 1165: END IF
! 1166: END IF
! 1167: *
! 1168: ELSE
! 1169: * .. need all N right singular vectors and NR < N
! 1170: * .. copy R**H into [V] and overwrite [V] with the left singular
! 1171: * vectors of R**H
! 1172: * [[The optimal ratio N/NR for using QRF instead of padding
! 1173: * with zeros. Here hard coded to 2; it must be at least
! 1174: * two due to work space constraints.]]
! 1175: * OPTRATIO = ILAENV(6, 'ZGESVD', 'S' // 'O', NR,N,0,0)
! 1176: * OPTRATIO = MAX( OPTRATIO, 2 )
! 1177: OPTRATIO = 2
! 1178: IF ( OPTRATIO*NR .GT. N ) THEN
! 1179: DO 1198 p = 1, NR
! 1180: DO 1199 q = p, N
! 1181: V(q,p) = CONJG(A(p,q))
! 1182: 1199 CONTINUE
! 1183: 1198 CONTINUE
! 1184: IF ( NR .GT. 1 )
! 1185: $ CALL ZLASET('U',NR-1,NR-1, CZERO,CZERO, V(1,2),LDV)
! 1186: *
! 1187: CALL ZLASET('A',N,N-NR,CZERO,CZERO,V(1,NR+1),LDV)
! 1188: CALL ZGESVD( 'O', 'A', N, N, V, LDV, S, V, LDV,
! 1189: $ U, LDU, CWORK(N+1), LCWORK-N, RWORK, INFO )
! 1190: *
! 1191: DO 1113 p = 1, N
! 1192: V(p,p) = CONJG(V(p,p))
! 1193: DO 1114 q = p + 1, N
! 1194: CTMP = CONJG(V(q,p))
! 1195: V(q,p) = CONJG(V(p,q))
! 1196: V(p,q) = CTMP
! 1197: 1114 CONTINUE
! 1198: 1113 CONTINUE
! 1199: CALL ZLAPMT( .FALSE., N, N, V, LDV, IWORK )
! 1200: * .. assemble the left singular vector matrix U of dimensions
! 1201: * (M x N1), i.e. (M x N) or (M x M).
! 1202: *
! 1203: DO 1111 p = 1, N
! 1204: U(p,p) = CONJG(U(p,p))
! 1205: DO 1112 q = p + 1, N
! 1206: CTMP = CONJG(U(q,p))
! 1207: U(q,p) = CONJG(U(p,q))
! 1208: U(p,q) = CTMP
! 1209: 1112 CONTINUE
! 1210: 1111 CONTINUE
! 1211: *
! 1212: IF ( ( N .LT. M ) .AND. .NOT.(WNTUF)) THEN
! 1213: CALL ZLASET('A',M-N,N,CZERO,CZERO,U(N+1,1),LDU)
! 1214: IF ( N .LT. N1 ) THEN
! 1215: CALL ZLASET('A',N,N1-N,CZERO,CZERO,U(1,N+1),LDU)
! 1216: CALL ZLASET('A',M-N,N1-N,CZERO,CONE,
! 1217: $ U(N+1,N+1), LDU )
! 1218: END IF
! 1219: END IF
! 1220: ELSE
! 1221: * .. copy R**H into [U] and overwrite [U] with the right
! 1222: * singular vectors of R
! 1223: DO 1196 p = 1, NR
! 1224: DO 1197 q = p, N
! 1225: U(q,NR+p) = CONJG(A(p,q))
! 1226: 1197 CONTINUE
! 1227: 1196 CONTINUE
! 1228: IF ( NR .GT. 1 )
! 1229: $ CALL ZLASET('U',NR-1,NR-1,CZERO,CZERO,U(1,NR+2),LDU)
! 1230: CALL ZGEQRF( N, NR, U(1,NR+1), LDU, CWORK(N+1),
! 1231: $ CWORK(N+NR+1), LCWORK-N-NR, IERR )
! 1232: DO 1143 p = 1, NR
! 1233: DO 1144 q = 1, N
! 1234: V(q,p) = CONJG(U(p,NR+q))
! 1235: 1144 CONTINUE
! 1236: 1143 CONTINUE
! 1237: CALL ZLASET('U',NR-1,NR-1,CZERO,CZERO,V(1,2),LDV)
! 1238: CALL ZGESVD( 'S', 'O', NR, NR, V, LDV, S, U, LDU,
! 1239: $ V,LDV, CWORK(N+NR+1),LCWORK-N-NR,RWORK, INFO )
! 1240: CALL ZLASET('A',N-NR,NR,CZERO,CZERO,V(NR+1,1),LDV)
! 1241: CALL ZLASET('A',NR,N-NR,CZERO,CZERO,V(1,NR+1),LDV)
! 1242: CALL ZLASET('A',N-NR,N-NR,CZERO,CONE,V(NR+1,NR+1),LDV)
! 1243: CALL ZUNMQR('R','C', N, N, NR, U(1,NR+1), LDU,
! 1244: $ CWORK(N+1),V,LDV,CWORK(N+NR+1),LCWORK-N-NR,IERR)
! 1245: CALL ZLAPMT( .FALSE., N, N, V, LDV, IWORK )
! 1246: * .. assemble the left singular vector matrix U of dimensions
! 1247: * (M x NR) or (M x N) or (M x M).
! 1248: IF ( ( NR .LT. M ) .AND. .NOT.(WNTUF)) THEN
! 1249: CALL ZLASET('A',M-NR,NR,CZERO,CZERO,U(NR+1,1),LDU)
! 1250: IF ( NR .LT. N1 ) THEN
! 1251: CALL ZLASET('A',NR,N1-NR,CZERO,CZERO,U(1,NR+1),LDU)
! 1252: CALL ZLASET( 'A',M-NR,N1-NR,CZERO,CONE,
! 1253: $ U(NR+1,NR+1),LDU)
! 1254: END IF
! 1255: END IF
! 1256: END IF
! 1257: END IF
! 1258: *
! 1259: ELSE
! 1260: *
! 1261: * .. apply ZGESVD to R [[this is the recommended option]]
! 1262: *
! 1263: IF ( WNTVR .OR. ( NR .EQ. N ) ) THEN
! 1264: * .. copy R into [V] and overwrite V with the right singular vectors
! 1265: CALL ZLACPY( 'U', NR, N, A, LDA, V, LDV )
! 1266: IF ( NR .GT. 1 )
! 1267: $ CALL ZLASET( 'L', NR-1,NR-1, CZERO,CZERO, V(2,1), LDV )
! 1268: * .. the right singular vectors of R overwrite [V], the NR left
! 1269: * singular vectors of R stored in [U](1:NR,1:NR)
! 1270: CALL ZGESVD( 'S', 'O', NR, N, V, LDV, S, U, LDU,
! 1271: $ V, LDV, CWORK(N+1), LCWORK-N, RWORK, INFO )
! 1272: CALL ZLAPMT( .FALSE., NR, N, V, LDV, IWORK )
! 1273: * .. now [V](1:NR,1:N) contains V(1:N,1:NR)**H
! 1274: * .. assemble the left singular vector matrix U of dimensions
! 1275: * (M x NR) or (M x N) or (M x M).
! 1276: IF ( ( NR .LT. M ) .AND. .NOT.(WNTUF)) THEN
! 1277: CALL ZLASET('A', M-NR,NR, CZERO,CZERO, U(NR+1,1), LDU)
! 1278: IF ( NR .LT. N1 ) THEN
! 1279: CALL ZLASET('A',NR,N1-NR,CZERO,CZERO,U(1,NR+1),LDU)
! 1280: CALL ZLASET( 'A',M-NR,N1-NR,CZERO,CONE,
! 1281: $ U(NR+1,NR+1), LDU )
! 1282: END IF
! 1283: END IF
! 1284: *
! 1285: ELSE
! 1286: * .. need all N right singular vectors and NR < N
! 1287: * .. the requested number of the left singular vectors
! 1288: * is then N1 (N or M)
! 1289: * [[The optimal ratio N/NR for using LQ instead of padding
! 1290: * with zeros. Here hard coded to 2; it must be at least
! 1291: * two due to work space constraints.]]
! 1292: * OPTRATIO = ILAENV(6, 'ZGESVD', 'S' // 'O', NR,N,0,0)
! 1293: * OPTRATIO = MAX( OPTRATIO, 2 )
! 1294: OPTRATIO = 2
! 1295: IF ( OPTRATIO * NR .GT. N ) THEN
! 1296: CALL ZLACPY( 'U', NR, N, A, LDA, V, LDV )
! 1297: IF ( NR .GT. 1 )
! 1298: $ CALL ZLASET('L', NR-1,NR-1, CZERO,CZERO, V(2,1),LDV)
! 1299: * .. the right singular vectors of R overwrite [V], the NR left
! 1300: * singular vectors of R stored in [U](1:NR,1:NR)
! 1301: CALL ZLASET('A', N-NR,N, CZERO,CZERO, V(NR+1,1),LDV)
! 1302: CALL ZGESVD( 'S', 'O', N, N, V, LDV, S, U, LDU,
! 1303: $ V, LDV, CWORK(N+1), LCWORK-N, RWORK, INFO )
! 1304: CALL ZLAPMT( .FALSE., N, N, V, LDV, IWORK )
! 1305: * .. now [V] contains the adjoint of the matrix of the right
! 1306: * singular vectors of A. The leading N left singular vectors
! 1307: * are in [U](1:N,1:N)
! 1308: * .. assemble the left singular vector matrix U of dimensions
! 1309: * (M x N1), i.e. (M x N) or (M x M).
! 1310: IF ( ( N .LT. M ) .AND. .NOT.(WNTUF)) THEN
! 1311: CALL ZLASET('A',M-N,N,CZERO,CZERO,U(N+1,1),LDU)
! 1312: IF ( N .LT. N1 ) THEN
! 1313: CALL ZLASET('A',N,N1-N,CZERO,CZERO,U(1,N+1),LDU)
! 1314: CALL ZLASET( 'A',M-N,N1-N,CZERO,CONE,
! 1315: $ U(N+1,N+1), LDU )
! 1316: END IF
! 1317: END IF
! 1318: ELSE
! 1319: CALL ZLACPY( 'U', NR, N, A, LDA, U(NR+1,1), LDU )
! 1320: IF ( NR .GT. 1 )
! 1321: $ CALL ZLASET('L',NR-1,NR-1,CZERO,CZERO,U(NR+2,1),LDU)
! 1322: CALL ZGELQF( NR, N, U(NR+1,1), LDU, CWORK(N+1),
! 1323: $ CWORK(N+NR+1), LCWORK-N-NR, IERR )
! 1324: CALL ZLACPY('L',NR,NR,U(NR+1,1),LDU,V,LDV)
! 1325: IF ( NR .GT. 1 )
! 1326: $ CALL ZLASET('U',NR-1,NR-1,CZERO,CZERO,V(1,2),LDV)
! 1327: CALL ZGESVD( 'S', 'O', NR, NR, V, LDV, S, U, LDU,
! 1328: $ V, LDV, CWORK(N+NR+1), LCWORK-N-NR, RWORK, INFO )
! 1329: CALL ZLASET('A',N-NR,NR,CZERO,CZERO,V(NR+1,1),LDV)
! 1330: CALL ZLASET('A',NR,N-NR,CZERO,CZERO,V(1,NR+1),LDV)
! 1331: CALL ZLASET('A',N-NR,N-NR,CZERO,CONE,V(NR+1,NR+1),LDV)
! 1332: CALL ZUNMLQ('R','N',N,N,NR,U(NR+1,1),LDU,CWORK(N+1),
! 1333: $ V, LDV, CWORK(N+NR+1),LCWORK-N-NR,IERR)
! 1334: CALL ZLAPMT( .FALSE., N, N, V, LDV, IWORK )
! 1335: * .. assemble the left singular vector matrix U of dimensions
! 1336: * (M x NR) or (M x N) or (M x M).
! 1337: IF ( ( NR .LT. M ) .AND. .NOT.(WNTUF)) THEN
! 1338: CALL ZLASET('A',M-NR,NR,CZERO,CZERO,U(NR+1,1),LDU)
! 1339: IF ( NR .LT. N1 ) THEN
! 1340: CALL ZLASET('A',NR,N1-NR,CZERO,CZERO,U(1,NR+1),LDU)
! 1341: CALL ZLASET( 'A',M-NR,N1-NR,CZERO,CONE,
! 1342: $ U(NR+1,NR+1), LDU )
! 1343: END IF
! 1344: END IF
! 1345: END IF
! 1346: END IF
! 1347: * .. end of the "R**H or R" branch
! 1348: END IF
! 1349: *
! 1350: * The Q matrix from the first QRF is built into the left singular
! 1351: * vectors matrix U.
! 1352: *
! 1353: IF ( .NOT. WNTUF )
! 1354: $ CALL ZUNMQR( 'L', 'N', M, N1, N, A, LDA, CWORK, U,
! 1355: $ LDU, CWORK(N+1), LCWORK-N, IERR )
! 1356: IF ( ROWPRM .AND. .NOT.WNTUF )
! 1357: $ CALL ZLASWP( N1, U, LDU, 1, M-1, IWORK(N+1), -1 )
! 1358: *
! 1359: * ... end of the "full SVD" branch
! 1360: END IF
! 1361: *
! 1362: * Check whether some singular values are returned as zeros, e.g.
! 1363: * due to underflow, and update the numerical rank.
! 1364: p = NR
! 1365: DO 4001 q = p, 1, -1
! 1366: IF ( S(q) .GT. ZERO ) GO TO 4002
! 1367: NR = NR - 1
! 1368: 4001 CONTINUE
! 1369: 4002 CONTINUE
! 1370: *
! 1371: * .. if numerical rank deficiency is detected, the truncated
! 1372: * singular values are set to zero.
! 1373: IF ( NR .LT. N ) CALL DLASET( 'G', N-NR,1, ZERO,ZERO, S(NR+1), N )
! 1374: * .. undo scaling; this may cause overflow in the largest singular
! 1375: * values.
! 1376: IF ( ASCALED )
! 1377: $ CALL DLASCL( 'G',0,0, ONE,SQRT(DBLE(M)), NR,1, S, N, IERR )
! 1378: IF ( CONDA ) RWORK(1) = SCONDA
! 1379: RWORK(2) = p - NR
! 1380: * .. p-NR is the number of singular values that are computed as
! 1381: * exact zeros in ZGESVD() applied to the (possibly truncated)
! 1382: * full row rank triangular (trapezoidal) factor of A.
! 1383: NUMRANK = NR
! 1384: *
! 1385: RETURN
! 1386: *
! 1387: * End of ZGESVDQ
! 1388: *
! 1389: END
CVSweb interface <joel.bertrand@systella.fr>