sbdsdc.c
Go to the documentation of this file.
00001 /* sbdsdc.f -- translated by f2c (version 20061008).
00002    You must link the resulting object file with libf2c:
00003         on Microsoft Windows system, link with libf2c.lib;
00004         on Linux or Unix systems, link with .../path/to/libf2c.a -lm
00005         or, if you install libf2c.a in a standard place, with -lf2c -lm
00006         -- in that order, at the end of the command line, as in
00007                 cc *.o -lf2c -lm
00008         Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
00009 
00010                 http://www.netlib.org/f2c/libf2c.zip
00011 */
00012 
00013 #include "f2c.h"
00014 #include "blaswrap.h"
00015 
00016 /* Table of constant values */
00017 
00018 static integer c__9 = 9;
00019 static integer c__0 = 0;
00020 static real c_b15 = 1.f;
00021 static integer c__1 = 1;
00022 static real c_b29 = 0.f;
00023 
00024 /* Subroutine */ int sbdsdc_(char *uplo, char *compq, integer *n, real *d__, 
00025         real *e, real *u, integer *ldu, real *vt, integer *ldvt, real *q, 
00026         integer *iq, real *work, integer *iwork, integer *info)
00027 {
00028     /* System generated locals */
00029     integer u_dim1, u_offset, vt_dim1, vt_offset, i__1, i__2;
00030     real r__1;
00031 
00032     /* Builtin functions */
00033     double r_sign(real *, real *), log(doublereal);
00034 
00035     /* Local variables */
00036     integer i__, j, k;
00037     real p, r__;
00038     integer z__, ic, ii, kk;
00039     real cs;
00040     integer is, iu;
00041     real sn;
00042     integer nm1;
00043     real eps;
00044     integer ivt, difl, difr, ierr, perm, mlvl, sqre;
00045     extern logical lsame_(char *, char *);
00046     integer poles;
00047     extern /* Subroutine */ int slasr_(char *, char *, char *, integer *, 
00048             integer *, real *, real *, real *, integer *);
00049     integer iuplo, nsize, start;
00050     extern /* Subroutine */ int scopy_(integer *, real *, integer *, real *, 
00051             integer *), sswap_(integer *, real *, integer *, real *, integer *
00052 ), slasd0_(integer *, integer *, real *, real *, real *, integer *
00053 , real *, integer *, integer *, integer *, real *, integer *);
00054     extern doublereal slamch_(char *);
00055     extern /* Subroutine */ int slasda_(integer *, integer *, integer *, 
00056             integer *, real *, real *, real *, integer *, real *, integer *, 
00057             real *, real *, real *, real *, integer *, integer *, integer *, 
00058             integer *, real *, real *, real *, real *, integer *, integer *), 
00059             xerbla_(char *, integer *);
00060     extern integer ilaenv_(integer *, char *, char *, integer *, integer *, 
00061             integer *, integer *);
00062     extern /* Subroutine */ int slascl_(char *, integer *, integer *, real *, 
00063             real *, integer *, integer *, real *, integer *, integer *);
00064     integer givcol;
00065     extern /* Subroutine */ int slasdq_(char *, integer *, integer *, integer 
00066             *, integer *, integer *, real *, real *, real *, integer *, real *
00067 , integer *, real *, integer *, real *, integer *);
00068     integer icompq;
00069     extern /* Subroutine */ int slaset_(char *, integer *, integer *, real *, 
00070             real *, real *, integer *), slartg_(real *, real *, real *
00071 , real *, real *);
00072     real orgnrm;
00073     integer givnum;
00074     extern doublereal slanst_(char *, integer *, real *, real *);
00075     integer givptr, qstart, smlsiz, wstart, smlszp;
00076 
00077 
00078 /*  -- LAPACK routine (version 3.2) -- */
00079 /*     Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. */
00080 /*     November 2006 */
00081 
00082 /*     .. Scalar Arguments .. */
00083 /*     .. */
00084 /*     .. Array Arguments .. */
00085 /*     .. */
00086 
00087 /*  Purpose */
00088 /*  ======= */
00089 
00090 /*  SBDSDC computes the singular value decomposition (SVD) of a real */
00091 /*  N-by-N (upper or lower) bidiagonal matrix B:  B = U * S * VT, */
00092 /*  using a divide and conquer method, where S is a diagonal matrix */
00093 /*  with non-negative diagonal elements (the singular values of B), and */
00094 /*  U and VT are orthogonal matrices of left and right singular vectors, */
00095 /*  respectively. SBDSDC can be used to compute all singular values, */
00096 /*  and optionally, singular vectors or singular vectors in compact form. */
00097 
00098 /*  This code makes very mild assumptions about floating point */
00099 /*  arithmetic. It will work on machines with a guard digit in */
00100 /*  add/subtract, or on those binary machines without guard digits */
00101 /*  which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or Cray-2. */
00102 /*  It could conceivably fail on hexadecimal or decimal machines */
00103 /*  without guard digits, but we know of none.  See SLASD3 for details. */
00104 
00105 /*  The code currently calls SLASDQ if singular values only are desired. */
00106 /*  However, it can be slightly modified to compute singular values */
00107 /*  using the divide and conquer method. */
00108 
00109 /*  Arguments */
00110 /*  ========= */
00111 
00112 /*  UPLO    (input) CHARACTER*1 */
00113 /*          = 'U':  B is upper bidiagonal. */
00114 /*          = 'L':  B is lower bidiagonal. */
00115 
00116 /*  COMPQ   (input) CHARACTER*1 */
00117 /*          Specifies whether singular vectors are to be computed */
00118 /*          as follows: */
00119 /*          = 'N':  Compute singular values only; */
00120 /*          = 'P':  Compute singular values and compute singular */
00121 /*                  vectors in compact form; */
00122 /*          = 'I':  Compute singular values and singular vectors. */
00123 
00124 /*  N       (input) INTEGER */
00125 /*          The order of the matrix B.  N >= 0. */
00126 
00127 /*  D       (input/output) REAL array, dimension (N) */
00128 /*          On entry, the n diagonal elements of the bidiagonal matrix B. */
00129 /*          On exit, if INFO=0, the singular values of B. */
00130 
00131 /*  E       (input/output) REAL array, dimension (N-1) */
00132 /*          On entry, the elements of E contain the offdiagonal */
00133 /*          elements of the bidiagonal matrix whose SVD is desired. */
00134 /*          On exit, E has been destroyed. */
00135 
00136 /*  U       (output) REAL array, dimension (LDU,N) */
00137 /*          If  COMPQ = 'I', then: */
00138 /*             On exit, if INFO = 0, U contains the left singular vectors */
00139 /*             of the bidiagonal matrix. */
00140 /*          For other values of COMPQ, U is not referenced. */
00141 
00142 /*  LDU     (input) INTEGER */
00143 /*          The leading dimension of the array U.  LDU >= 1. */
00144 /*          If singular vectors are desired, then LDU >= max( 1, N ). */
00145 
00146 /*  VT      (output) REAL array, dimension (LDVT,N) */
00147 /*          If  COMPQ = 'I', then: */
00148 /*             On exit, if INFO = 0, VT' contains the right singular */
00149 /*             vectors of the bidiagonal matrix. */
00150 /*          For other values of COMPQ, VT is not referenced. */
00151 
00152 /*  LDVT    (input) INTEGER */
00153 /*          The leading dimension of the array VT.  LDVT >= 1. */
00154 /*          If singular vectors are desired, then LDVT >= max( 1, N ). */
00155 
00156 /*  Q       (output) REAL array, dimension (LDQ) */
00157 /*          If  COMPQ = 'P', then: */
00158 /*             On exit, if INFO = 0, Q and IQ contain the left */
00159 /*             and right singular vectors in a compact form, */
00160 /*             requiring O(N log N) space instead of 2*N**2. */
00161 /*             In particular, Q contains all the REAL data in */
00162 /*             LDQ >= N*(11 + 2*SMLSIZ + 8*INT(LOG_2(N/(SMLSIZ+1)))) */
00163 /*             words of memory, where SMLSIZ is returned by ILAENV and */
00164 /*             is equal to the maximum size of the subproblems at the */
00165 /*             bottom of the computation tree (usually about 25). */
00166 /*          For other values of COMPQ, Q is not referenced. */
00167 
00168 /*  IQ      (output) INTEGER array, dimension (LDIQ) */
00169 /*          If  COMPQ = 'P', then: */
00170 /*             On exit, if INFO = 0, Q and IQ contain the left */
00171 /*             and right singular vectors in a compact form, */
00172 /*             requiring O(N log N) space instead of 2*N**2. */
00173 /*             In particular, IQ contains all INTEGER data in */
00174 /*             LDIQ >= N*(3 + 3*INT(LOG_2(N/(SMLSIZ+1)))) */
00175 /*             words of memory, where SMLSIZ is returned by ILAENV and */
00176 /*             is equal to the maximum size of the subproblems at the */
00177 /*             bottom of the computation tree (usually about 25). */
00178 /*          For other values of COMPQ, IQ is not referenced. */
00179 
00180 /*  WORK    (workspace) REAL array, dimension (MAX(1,LWORK)) */
00181 /*          If COMPQ = 'N' then LWORK >= (4 * N). */
00182 /*          If COMPQ = 'P' then LWORK >= (6 * N). */
00183 /*          If COMPQ = 'I' then LWORK >= (3 * N**2 + 4 * N). */
00184 
00185 /*  IWORK   (workspace) INTEGER array, dimension (8*N) */
00186 
00187 /*  INFO    (output) INTEGER */
00188 /*          = 0:  successful exit. */
00189 /*          < 0:  if INFO = -i, the i-th argument had an illegal value. */
00190 /*          > 0:  The algorithm failed to compute an singular value. */
00191 /*                The update process of divide and conquer failed. */
00192 
00193 /*  Further Details */
00194 /*  =============== */
00195 
00196 /*  Based on contributions by */
00197 /*     Ming Gu and Huan Ren, Computer Science Division, University of */
00198 /*     California at Berkeley, USA */
00199 /*  ===================================================================== */
00200 /*  Changed dimension statement in comment describing E from (N) to */
00201 /*  (N-1).  Sven, 17 Feb 05. */
00202 /*  ===================================================================== */
00203 
00204 /*     .. Parameters .. */
00205 /*     .. */
00206 /*     .. Local Scalars .. */
00207 /*     .. */
00208 /*     .. External Functions .. */
00209 /*     .. */
00210 /*     .. External Subroutines .. */
00211 /*     .. */
00212 /*     .. Intrinsic Functions .. */
00213 /*     .. */
00214 /*     .. Executable Statements .. */
00215 
00216 /*     Test the input parameters. */
00217 
00218     /* Parameter adjustments */
00219     --d__;
00220     --e;
00221     u_dim1 = *ldu;
00222     u_offset = 1 + u_dim1;
00223     u -= u_offset;
00224     vt_dim1 = *ldvt;
00225     vt_offset = 1 + vt_dim1;
00226     vt -= vt_offset;
00227     --q;
00228     --iq;
00229     --work;
00230     --iwork;
00231 
00232     /* Function Body */
00233     *info = 0;
00234 
00235     iuplo = 0;
00236     if (lsame_(uplo, "U")) {
00237         iuplo = 1;
00238     }
00239     if (lsame_(uplo, "L")) {
00240         iuplo = 2;
00241     }
00242     if (lsame_(compq, "N")) {
00243         icompq = 0;
00244     } else if (lsame_(compq, "P")) {
00245         icompq = 1;
00246     } else if (lsame_(compq, "I")) {
00247         icompq = 2;
00248     } else {
00249         icompq = -1;
00250     }
00251     if (iuplo == 0) {
00252         *info = -1;
00253     } else if (icompq < 0) {
00254         *info = -2;
00255     } else if (*n < 0) {
00256         *info = -3;
00257     } else if (*ldu < 1 || icompq == 2 && *ldu < *n) {
00258         *info = -7;
00259     } else if (*ldvt < 1 || icompq == 2 && *ldvt < *n) {
00260         *info = -9;
00261     }
00262     if (*info != 0) {
00263         i__1 = -(*info);
00264         xerbla_("SBDSDC", &i__1);
00265         return 0;
00266     }
00267 
00268 /*     Quick return if possible */
00269 
00270     if (*n == 0) {
00271         return 0;
00272     }
00273     smlsiz = ilaenv_(&c__9, "SBDSDC", " ", &c__0, &c__0, &c__0, &c__0);
00274     if (*n == 1) {
00275         if (icompq == 1) {
00276             q[1] = r_sign(&c_b15, &d__[1]);
00277             q[smlsiz * *n + 1] = 1.f;
00278         } else if (icompq == 2) {
00279             u[u_dim1 + 1] = r_sign(&c_b15, &d__[1]);
00280             vt[vt_dim1 + 1] = 1.f;
00281         }
00282         d__[1] = dabs(d__[1]);
00283         return 0;
00284     }
00285     nm1 = *n - 1;
00286 
00287 /*     If matrix lower bidiagonal, rotate to be upper bidiagonal */
00288 /*     by applying Givens rotations on the left */
00289 
00290     wstart = 1;
00291     qstart = 3;
00292     if (icompq == 1) {
00293         scopy_(n, &d__[1], &c__1, &q[1], &c__1);
00294         i__1 = *n - 1;
00295         scopy_(&i__1, &e[1], &c__1, &q[*n + 1], &c__1);
00296     }
00297     if (iuplo == 2) {
00298         qstart = 5;
00299         wstart = (*n << 1) - 1;
00300         i__1 = *n - 1;
00301         for (i__ = 1; i__ <= i__1; ++i__) {
00302             slartg_(&d__[i__], &e[i__], &cs, &sn, &r__);
00303             d__[i__] = r__;
00304             e[i__] = sn * d__[i__ + 1];
00305             d__[i__ + 1] = cs * d__[i__ + 1];
00306             if (icompq == 1) {
00307                 q[i__ + (*n << 1)] = cs;
00308                 q[i__ + *n * 3] = sn;
00309             } else if (icompq == 2) {
00310                 work[i__] = cs;
00311                 work[nm1 + i__] = -sn;
00312             }
00313 /* L10: */
00314         }
00315     }
00316 
00317 /*     If ICOMPQ = 0, use SLASDQ to compute the singular values. */
00318 
00319     if (icompq == 0) {
00320         slasdq_("U", &c__0, n, &c__0, &c__0, &c__0, &d__[1], &e[1], &vt[
00321                 vt_offset], ldvt, &u[u_offset], ldu, &u[u_offset], ldu, &work[
00322                 wstart], info);
00323         goto L40;
00324     }
00325 
00326 /*     If N is smaller than the minimum divide size SMLSIZ, then solve */
00327 /*     the problem with another solver. */
00328 
00329     if (*n <= smlsiz) {
00330         if (icompq == 2) {
00331             slaset_("A", n, n, &c_b29, &c_b15, &u[u_offset], ldu);
00332             slaset_("A", n, n, &c_b29, &c_b15, &vt[vt_offset], ldvt);
00333             slasdq_("U", &c__0, n, n, n, &c__0, &d__[1], &e[1], &vt[vt_offset]
00334 , ldvt, &u[u_offset], ldu, &u[u_offset], ldu, &work[
00335                     wstart], info);
00336         } else if (icompq == 1) {
00337             iu = 1;
00338             ivt = iu + *n;
00339             slaset_("A", n, n, &c_b29, &c_b15, &q[iu + (qstart - 1) * *n], n);
00340             slaset_("A", n, n, &c_b29, &c_b15, &q[ivt + (qstart - 1) * *n], n);
00341             slasdq_("U", &c__0, n, n, n, &c__0, &d__[1], &e[1], &q[ivt + (
00342                     qstart - 1) * *n], n, &q[iu + (qstart - 1) * *n], n, &q[
00343                     iu + (qstart - 1) * *n], n, &work[wstart], info);
00344         }
00345         goto L40;
00346     }
00347 
00348     if (icompq == 2) {
00349         slaset_("A", n, n, &c_b29, &c_b15, &u[u_offset], ldu);
00350         slaset_("A", n, n, &c_b29, &c_b15, &vt[vt_offset], ldvt);
00351     }
00352 
00353 /*     Scale. */
00354 
00355     orgnrm = slanst_("M", n, &d__[1], &e[1]);
00356     if (orgnrm == 0.f) {
00357         return 0;
00358     }
00359     slascl_("G", &c__0, &c__0, &orgnrm, &c_b15, n, &c__1, &d__[1], n, &ierr);
00360     slascl_("G", &c__0, &c__0, &orgnrm, &c_b15, &nm1, &c__1, &e[1], &nm1, &
00361             ierr);
00362 
00363     eps = slamch_("Epsilon");
00364 
00365     mlvl = (integer) (log((real) (*n) / (real) (smlsiz + 1)) / log(2.f)) + 1;
00366     smlszp = smlsiz + 1;
00367 
00368     if (icompq == 1) {
00369         iu = 1;
00370         ivt = smlsiz + 1;
00371         difl = ivt + smlszp;
00372         difr = difl + mlvl;
00373         z__ = difr + (mlvl << 1);
00374         ic = z__ + mlvl;
00375         is = ic + 1;
00376         poles = is + 1;
00377         givnum = poles + (mlvl << 1);
00378 
00379         k = 1;
00380         givptr = 2;
00381         perm = 3;
00382         givcol = perm + mlvl;
00383     }
00384 
00385     i__1 = *n;
00386     for (i__ = 1; i__ <= i__1; ++i__) {
00387         if ((r__1 = d__[i__], dabs(r__1)) < eps) {
00388             d__[i__] = r_sign(&eps, &d__[i__]);
00389         }
00390 /* L20: */
00391     }
00392 
00393     start = 1;
00394     sqre = 0;
00395 
00396     i__1 = nm1;
00397     for (i__ = 1; i__ <= i__1; ++i__) {
00398         if ((r__1 = e[i__], dabs(r__1)) < eps || i__ == nm1) {
00399 
00400 /*        Subproblem found. First determine its size and then */
00401 /*        apply divide and conquer on it. */
00402 
00403             if (i__ < nm1) {
00404 
00405 /*        A subproblem with E(I) small for I < NM1. */
00406 
00407                 nsize = i__ - start + 1;
00408             } else if ((r__1 = e[i__], dabs(r__1)) >= eps) {
00409 
00410 /*        A subproblem with E(NM1) not too small but I = NM1. */
00411 
00412                 nsize = *n - start + 1;
00413             } else {
00414 
00415 /*        A subproblem with E(NM1) small. This implies an */
00416 /*        1-by-1 subproblem at D(N). Solve this 1-by-1 problem */
00417 /*        first. */
00418 
00419                 nsize = i__ - start + 1;
00420                 if (icompq == 2) {
00421                     u[*n + *n * u_dim1] = r_sign(&c_b15, &d__[*n]);
00422                     vt[*n + *n * vt_dim1] = 1.f;
00423                 } else if (icompq == 1) {
00424                     q[*n + (qstart - 1) * *n] = r_sign(&c_b15, &d__[*n]);
00425                     q[*n + (smlsiz + qstart - 1) * *n] = 1.f;
00426                 }
00427                 d__[*n] = (r__1 = d__[*n], dabs(r__1));
00428             }
00429             if (icompq == 2) {
00430                 slasd0_(&nsize, &sqre, &d__[start], &e[start], &u[start + 
00431                         start * u_dim1], ldu, &vt[start + start * vt_dim1], 
00432                         ldvt, &smlsiz, &iwork[1], &work[wstart], info);
00433             } else {
00434                 slasda_(&icompq, &smlsiz, &nsize, &sqre, &d__[start], &e[
00435                         start], &q[start + (iu + qstart - 2) * *n], n, &q[
00436                         start + (ivt + qstart - 2) * *n], &iq[start + k * *n], 
00437                          &q[start + (difl + qstart - 2) * *n], &q[start + (
00438                         difr + qstart - 2) * *n], &q[start + (z__ + qstart - 
00439                         2) * *n], &q[start + (poles + qstart - 2) * *n], &iq[
00440                         start + givptr * *n], &iq[start + givcol * *n], n, &
00441                         iq[start + perm * *n], &q[start + (givnum + qstart - 
00442                         2) * *n], &q[start + (ic + qstart - 2) * *n], &q[
00443                         start + (is + qstart - 2) * *n], &work[wstart], &
00444                         iwork[1], info);
00445                 if (*info != 0) {
00446                     return 0;
00447                 }
00448             }
00449             start = i__ + 1;
00450         }
00451 /* L30: */
00452     }
00453 
00454 /*     Unscale */
00455 
00456     slascl_("G", &c__0, &c__0, &c_b15, &orgnrm, n, &c__1, &d__[1], n, &ierr);
00457 L40:
00458 
00459 /*     Use Selection Sort to minimize swaps of singular vectors */
00460 
00461     i__1 = *n;
00462     for (ii = 2; ii <= i__1; ++ii) {
00463         i__ = ii - 1;
00464         kk = i__;
00465         p = d__[i__];
00466         i__2 = *n;
00467         for (j = ii; j <= i__2; ++j) {
00468             if (d__[j] > p) {
00469                 kk = j;
00470                 p = d__[j];
00471             }
00472 /* L50: */
00473         }
00474         if (kk != i__) {
00475             d__[kk] = d__[i__];
00476             d__[i__] = p;
00477             if (icompq == 1) {
00478                 iq[i__] = kk;
00479             } else if (icompq == 2) {
00480                 sswap_(n, &u[i__ * u_dim1 + 1], &c__1, &u[kk * u_dim1 + 1], &
00481                         c__1);
00482                 sswap_(n, &vt[i__ + vt_dim1], ldvt, &vt[kk + vt_dim1], ldvt);
00483             }
00484         } else if (icompq == 1) {
00485             iq[i__] = i__;
00486         }
00487 /* L60: */
00488     }
00489 
00490 /*     If ICOMPQ = 1, use IQ(N,1) as the indicator for UPLO */
00491 
00492     if (icompq == 1) {
00493         if (iuplo == 1) {
00494             iq[*n] = 1;
00495         } else {
00496             iq[*n] = 0;
00497         }
00498     }
00499 
00500 /*     If B is lower bidiagonal, update U by those Givens rotations */
00501 /*     which rotated B to be upper bidiagonal */
00502 
00503     if (iuplo == 2 && icompq == 2) {
00504         slasr_("L", "V", "B", n, n, &work[1], &work[*n], &u[u_offset], ldu);
00505     }
00506 
00507     return 0;
00508 
00509 /*     End of SBDSDC */
00510 
00511 } /* sbdsdc_ */


swiftnav
Author(s):
autogenerated on Sat Jun 8 2019 18:55:56