slalsd.c
Go to the documentation of this file.
00001 /* slalsd.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__1 = 1;
00019 static real c_b6 = 0.f;
00020 static integer c__0 = 0;
00021 static real c_b11 = 1.f;
00022 
00023 /* Subroutine */ int slalsd_(char *uplo, integer *smlsiz, integer *n, integer 
00024         *nrhs, real *d__, real *e, real *b, integer *ldb, real *rcond, 
00025         integer *rank, real *work, integer *iwork, integer *info)
00026 {
00027     /* System generated locals */
00028     integer b_dim1, b_offset, i__1, i__2;
00029     real r__1;
00030 
00031     /* Builtin functions */
00032     double log(doublereal), r_sign(real *, real *);
00033 
00034     /* Local variables */
00035     integer c__, i__, j, k;
00036     real r__;
00037     integer s, u, z__;
00038     real cs;
00039     integer bx;
00040     real sn;
00041     integer st, vt, nm1, st1;
00042     real eps;
00043     integer iwk;
00044     real tol;
00045     integer difl, difr;
00046     real rcnd;
00047     integer perm, nsub, nlvl, sqre, bxst;
00048     extern /* Subroutine */ int srot_(integer *, real *, integer *, real *, 
00049             integer *, real *, real *), sgemm_(char *, char *, integer *, 
00050             integer *, integer *, real *, real *, integer *, real *, integer *
00051 , real *, real *, integer *);
00052     integer poles, sizei, nsize;
00053     extern /* Subroutine */ int scopy_(integer *, real *, integer *, real *, 
00054             integer *);
00055     integer nwork, icmpq1, icmpq2;
00056     extern doublereal slamch_(char *);
00057     extern /* Subroutine */ int slasda_(integer *, integer *, integer *, 
00058             integer *, real *, real *, real *, integer *, real *, integer *, 
00059             real *, real *, real *, real *, integer *, integer *, integer *, 
00060             integer *, real *, real *, real *, real *, integer *, integer *), 
00061             xerbla_(char *, integer *), slalsa_(integer *, integer *, 
00062             integer *, integer *, real *, integer *, real *, integer *, real *
00063 , integer *, real *, integer *, real *, real *, real *, real *, 
00064             integer *, integer *, integer *, integer *, real *, real *, real *
00065 , real *, integer *, integer *), slascl_(char *, integer *, 
00066             integer *, real *, real *, integer *, integer *, real *, integer *
00067 , integer *);
00068     integer givcol;
00069     extern integer isamax_(integer *, real *, integer *);
00070     extern /* Subroutine */ int slasdq_(char *, integer *, integer *, integer 
00071             *, integer *, integer *, real *, real *, real *, integer *, real *
00072 , integer *, real *, integer *, real *, integer *), 
00073             slacpy_(char *, integer *, integer *, real *, integer *, real *, 
00074             integer *), slartg_(real *, real *, real *, real *, real *
00075 ), slaset_(char *, integer *, integer *, real *, real *, real *, 
00076             integer *);
00077     real orgnrm;
00078     integer givnum;
00079     extern doublereal slanst_(char *, integer *, real *, real *);
00080     extern /* Subroutine */ int slasrt_(char *, integer *, real *, integer *);
00081     integer givptr, smlszp;
00082 
00083 
00084 /*  -- LAPACK routine (version 3.2) -- */
00085 /*     Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. */
00086 /*     November 2006 */
00087 
00088 /*     .. Scalar Arguments .. */
00089 /*     .. */
00090 /*     .. Array Arguments .. */
00091 /*     .. */
00092 
00093 /*  Purpose */
00094 /*  ======= */
00095 
00096 /*  SLALSD uses the singular value decomposition of A to solve the least */
00097 /*  squares problem of finding X to minimize the Euclidean norm of each */
00098 /*  column of A*X-B, where A is N-by-N upper bidiagonal, and X and B */
00099 /*  are N-by-NRHS. The solution X overwrites B. */
00100 
00101 /*  The singular values of A smaller than RCOND times the largest */
00102 /*  singular value are treated as zero in solving the least squares */
00103 /*  problem; in this case a minimum norm solution is returned. */
00104 /*  The actual singular values are returned in D in ascending order. */
00105 
00106 /*  This code makes very mild assumptions about floating point */
00107 /*  arithmetic. It will work on machines with a guard digit in */
00108 /*  add/subtract, or on those binary machines without guard digits */
00109 /*  which subtract like the Cray XMP, Cray YMP, Cray C 90, or Cray 2. */
00110 /*  It could conceivably fail on hexadecimal or decimal machines */
00111 /*  without guard digits, but we know of none. */
00112 
00113 /*  Arguments */
00114 /*  ========= */
00115 
00116 /*  UPLO   (input) CHARACTER*1 */
00117 /*         = 'U': D and E define an upper bidiagonal matrix. */
00118 /*         = 'L': D and E define a  lower bidiagonal matrix. */
00119 
00120 /*  SMLSIZ (input) INTEGER */
00121 /*         The maximum size of the subproblems at the bottom of the */
00122 /*         computation tree. */
00123 
00124 /*  N      (input) INTEGER */
00125 /*         The dimension of the  bidiagonal matrix.  N >= 0. */
00126 
00127 /*  NRHS   (input) INTEGER */
00128 /*         The number of columns of B. NRHS must be at least 1. */
00129 
00130 /*  D      (input/output) REAL array, dimension (N) */
00131 /*         On entry D contains the main diagonal of the bidiagonal */
00132 /*         matrix. On exit, if INFO = 0, D contains its singular values. */
00133 
00134 /*  E      (input/output) REAL array, dimension (N-1) */
00135 /*         Contains the super-diagonal entries of the bidiagonal matrix. */
00136 /*         On exit, E has been destroyed. */
00137 
00138 /*  B      (input/output) REAL array, dimension (LDB,NRHS) */
00139 /*         On input, B contains the right hand sides of the least */
00140 /*         squares problem. On output, B contains the solution X. */
00141 
00142 /*  LDB    (input) INTEGER */
00143 /*         The leading dimension of B in the calling subprogram. */
00144 /*         LDB must be at least max(1,N). */
00145 
00146 /*  RCOND  (input) REAL */
00147 /*         The singular values of A less than or equal to RCOND times */
00148 /*         the largest singular value are treated as zero in solving */
00149 /*         the least squares problem. If RCOND is negative, */
00150 /*         machine precision is used instead. */
00151 /*         For example, if diag(S)*X=B were the least squares problem, */
00152 /*         where diag(S) is a diagonal matrix of singular values, the */
00153 /*         solution would be X(i) = B(i) / S(i) if S(i) is greater than */
00154 /*         RCOND*max(S), and X(i) = 0 if S(i) is less than or equal to */
00155 /*         RCOND*max(S). */
00156 
00157 /*  RANK   (output) INTEGER */
00158 /*         The number of singular values of A greater than RCOND times */
00159 /*         the largest singular value. */
00160 
00161 /*  WORK   (workspace) REAL array, dimension at least */
00162 /*         (9*N + 2*N*SMLSIZ + 8*N*NLVL + N*NRHS + (SMLSIZ+1)**2), */
00163 /*         where NLVL = max(0, INT(log_2 (N/(SMLSIZ+1))) + 1). */
00164 
00165 /*  IWORK  (workspace) INTEGER array, dimension at least */
00166 /*         (3*N*NLVL + 11*N) */
00167 
00168 /*  INFO   (output) INTEGER */
00169 /*         = 0:  successful exit. */
00170 /*         < 0:  if INFO = -i, the i-th argument had an illegal value. */
00171 /*         > 0:  The algorithm failed to compute an singular value while */
00172 /*               working on the submatrix lying in rows and columns */
00173 /*               INFO/(N+1) through MOD(INFO,N+1). */
00174 
00175 /*  Further Details */
00176 /*  =============== */
00177 
00178 /*  Based on contributions by */
00179 /*     Ming Gu and Ren-Cang Li, Computer Science Division, University of */
00180 /*       California at Berkeley, USA */
00181 /*     Osni Marques, LBNL/NERSC, USA */
00182 
00183 /*  ===================================================================== */
00184 
00185 /*     .. Parameters .. */
00186 /*     .. */
00187 /*     .. Local Scalars .. */
00188 /*     .. */
00189 /*     .. External Functions .. */
00190 /*     .. */
00191 /*     .. External Subroutines .. */
00192 /*     .. */
00193 /*     .. Intrinsic Functions .. */
00194 /*     .. */
00195 /*     .. Executable Statements .. */
00196 
00197 /*     Test the input parameters. */
00198 
00199     /* Parameter adjustments */
00200     --d__;
00201     --e;
00202     b_dim1 = *ldb;
00203     b_offset = 1 + b_dim1;
00204     b -= b_offset;
00205     --work;
00206     --iwork;
00207 
00208     /* Function Body */
00209     *info = 0;
00210 
00211     if (*n < 0) {
00212         *info = -3;
00213     } else if (*nrhs < 1) {
00214         *info = -4;
00215     } else if (*ldb < 1 || *ldb < *n) {
00216         *info = -8;
00217     }
00218     if (*info != 0) {
00219         i__1 = -(*info);
00220         xerbla_("SLALSD", &i__1);
00221         return 0;
00222     }
00223 
00224     eps = slamch_("Epsilon");
00225 
00226 /*     Set up the tolerance. */
00227 
00228     if (*rcond <= 0.f || *rcond >= 1.f) {
00229         rcnd = eps;
00230     } else {
00231         rcnd = *rcond;
00232     }
00233 
00234     *rank = 0;
00235 
00236 /*     Quick return if possible. */
00237 
00238     if (*n == 0) {
00239         return 0;
00240     } else if (*n == 1) {
00241         if (d__[1] == 0.f) {
00242             slaset_("A", &c__1, nrhs, &c_b6, &c_b6, &b[b_offset], ldb);
00243         } else {
00244             *rank = 1;
00245             slascl_("G", &c__0, &c__0, &d__[1], &c_b11, &c__1, nrhs, &b[
00246                     b_offset], ldb, info);
00247             d__[1] = dabs(d__[1]);
00248         }
00249         return 0;
00250     }
00251 
00252 /*     Rotate the matrix if it is lower bidiagonal. */
00253 
00254     if (*(unsigned char *)uplo == 'L') {
00255         i__1 = *n - 1;
00256         for (i__ = 1; i__ <= i__1; ++i__) {
00257             slartg_(&d__[i__], &e[i__], &cs, &sn, &r__);
00258             d__[i__] = r__;
00259             e[i__] = sn * d__[i__ + 1];
00260             d__[i__ + 1] = cs * d__[i__ + 1];
00261             if (*nrhs == 1) {
00262                 srot_(&c__1, &b[i__ + b_dim1], &c__1, &b[i__ + 1 + b_dim1], &
00263                         c__1, &cs, &sn);
00264             } else {
00265                 work[(i__ << 1) - 1] = cs;
00266                 work[i__ * 2] = sn;
00267             }
00268 /* L10: */
00269         }
00270         if (*nrhs > 1) {
00271             i__1 = *nrhs;
00272             for (i__ = 1; i__ <= i__1; ++i__) {
00273                 i__2 = *n - 1;
00274                 for (j = 1; j <= i__2; ++j) {
00275                     cs = work[(j << 1) - 1];
00276                     sn = work[j * 2];
00277                     srot_(&c__1, &b[j + i__ * b_dim1], &c__1, &b[j + 1 + i__ *
00278                              b_dim1], &c__1, &cs, &sn);
00279 /* L20: */
00280                 }
00281 /* L30: */
00282             }
00283         }
00284     }
00285 
00286 /*     Scale. */
00287 
00288     nm1 = *n - 1;
00289     orgnrm = slanst_("M", n, &d__[1], &e[1]);
00290     if (orgnrm == 0.f) {
00291         slaset_("A", n, nrhs, &c_b6, &c_b6, &b[b_offset], ldb);
00292         return 0;
00293     }
00294 
00295     slascl_("G", &c__0, &c__0, &orgnrm, &c_b11, n, &c__1, &d__[1], n, info);
00296     slascl_("G", &c__0, &c__0, &orgnrm, &c_b11, &nm1, &c__1, &e[1], &nm1, 
00297             info);
00298 
00299 /*     If N is smaller than the minimum divide size SMLSIZ, then solve */
00300 /*     the problem with another solver. */
00301 
00302     if (*n <= *smlsiz) {
00303         nwork = *n * *n + 1;
00304         slaset_("A", n, n, &c_b6, &c_b11, &work[1], n);
00305         slasdq_("U", &c__0, n, n, &c__0, nrhs, &d__[1], &e[1], &work[1], n, &
00306                 work[1], n, &b[b_offset], ldb, &work[nwork], info);
00307         if (*info != 0) {
00308             return 0;
00309         }
00310         tol = rcnd * (r__1 = d__[isamax_(n, &d__[1], &c__1)], dabs(r__1));
00311         i__1 = *n;
00312         for (i__ = 1; i__ <= i__1; ++i__) {
00313             if (d__[i__] <= tol) {
00314                 slaset_("A", &c__1, nrhs, &c_b6, &c_b6, &b[i__ + b_dim1], ldb);
00315             } else {
00316                 slascl_("G", &c__0, &c__0, &d__[i__], &c_b11, &c__1, nrhs, &b[
00317                         i__ + b_dim1], ldb, info);
00318                 ++(*rank);
00319             }
00320 /* L40: */
00321         }
00322         sgemm_("T", "N", n, nrhs, n, &c_b11, &work[1], n, &b[b_offset], ldb, &
00323                 c_b6, &work[nwork], n);
00324         slacpy_("A", n, nrhs, &work[nwork], n, &b[b_offset], ldb);
00325 
00326 /*        Unscale. */
00327 
00328         slascl_("G", &c__0, &c__0, &c_b11, &orgnrm, n, &c__1, &d__[1], n, 
00329                 info);
00330         slasrt_("D", n, &d__[1], info);
00331         slascl_("G", &c__0, &c__0, &orgnrm, &c_b11, n, nrhs, &b[b_offset], 
00332                 ldb, info);
00333 
00334         return 0;
00335     }
00336 
00337 /*     Book-keeping and setting up some constants. */
00338 
00339     nlvl = (integer) (log((real) (*n) / (real) (*smlsiz + 1)) / log(2.f)) + 1;
00340 
00341     smlszp = *smlsiz + 1;
00342 
00343     u = 1;
00344     vt = *smlsiz * *n + 1;
00345     difl = vt + smlszp * *n;
00346     difr = difl + nlvl * *n;
00347     z__ = difr + (nlvl * *n << 1);
00348     c__ = z__ + nlvl * *n;
00349     s = c__ + *n;
00350     poles = s + *n;
00351     givnum = poles + (nlvl << 1) * *n;
00352     bx = givnum + (nlvl << 1) * *n;
00353     nwork = bx + *n * *nrhs;
00354 
00355     sizei = *n + 1;
00356     k = sizei + *n;
00357     givptr = k + *n;
00358     perm = givptr + *n;
00359     givcol = perm + nlvl * *n;
00360     iwk = givcol + (nlvl * *n << 1);
00361 
00362     st = 1;
00363     sqre = 0;
00364     icmpq1 = 1;
00365     icmpq2 = 0;
00366     nsub = 0;
00367 
00368     i__1 = *n;
00369     for (i__ = 1; i__ <= i__1; ++i__) {
00370         if ((r__1 = d__[i__], dabs(r__1)) < eps) {
00371             d__[i__] = r_sign(&eps, &d__[i__]);
00372         }
00373 /* L50: */
00374     }
00375 
00376     i__1 = nm1;
00377     for (i__ = 1; i__ <= i__1; ++i__) {
00378         if ((r__1 = e[i__], dabs(r__1)) < eps || i__ == nm1) {
00379             ++nsub;
00380             iwork[nsub] = st;
00381 
00382 /*           Subproblem found. First determine its size and then */
00383 /*           apply divide and conquer on it. */
00384 
00385             if (i__ < nm1) {
00386 
00387 /*              A subproblem with E(I) small for I < NM1. */
00388 
00389                 nsize = i__ - st + 1;
00390                 iwork[sizei + nsub - 1] = nsize;
00391             } else if ((r__1 = e[i__], dabs(r__1)) >= eps) {
00392 
00393 /*              A subproblem with E(NM1) not too small but I = NM1. */
00394 
00395                 nsize = *n - st + 1;
00396                 iwork[sizei + nsub - 1] = nsize;
00397             } else {
00398 
00399 /*              A subproblem with E(NM1) small. This implies an */
00400 /*              1-by-1 subproblem at D(N), which is not solved */
00401 /*              explicitly. */
00402 
00403                 nsize = i__ - st + 1;
00404                 iwork[sizei + nsub - 1] = nsize;
00405                 ++nsub;
00406                 iwork[nsub] = *n;
00407                 iwork[sizei + nsub - 1] = 1;
00408                 scopy_(nrhs, &b[*n + b_dim1], ldb, &work[bx + nm1], n);
00409             }
00410             st1 = st - 1;
00411             if (nsize == 1) {
00412 
00413 /*              This is a 1-by-1 subproblem and is not solved */
00414 /*              explicitly. */
00415 
00416                 scopy_(nrhs, &b[st + b_dim1], ldb, &work[bx + st1], n);
00417             } else if (nsize <= *smlsiz) {
00418 
00419 /*              This is a small subproblem and is solved by SLASDQ. */
00420 
00421                 slaset_("A", &nsize, &nsize, &c_b6, &c_b11, &work[vt + st1], 
00422                         n);
00423                 slasdq_("U", &c__0, &nsize, &nsize, &c__0, nrhs, &d__[st], &e[
00424                         st], &work[vt + st1], n, &work[nwork], n, &b[st + 
00425                         b_dim1], ldb, &work[nwork], info);
00426                 if (*info != 0) {
00427                     return 0;
00428                 }
00429                 slacpy_("A", &nsize, nrhs, &b[st + b_dim1], ldb, &work[bx + 
00430                         st1], n);
00431             } else {
00432 
00433 /*              A large problem. Solve it using divide and conquer. */
00434 
00435                 slasda_(&icmpq1, smlsiz, &nsize, &sqre, &d__[st], &e[st], &
00436                         work[u + st1], n, &work[vt + st1], &iwork[k + st1], &
00437                         work[difl + st1], &work[difr + st1], &work[z__ + st1], 
00438                          &work[poles + st1], &iwork[givptr + st1], &iwork[
00439                         givcol + st1], n, &iwork[perm + st1], &work[givnum + 
00440                         st1], &work[c__ + st1], &work[s + st1], &work[nwork], 
00441                         &iwork[iwk], info);
00442                 if (*info != 0) {
00443                     return 0;
00444                 }
00445                 bxst = bx + st1;
00446                 slalsa_(&icmpq2, smlsiz, &nsize, nrhs, &b[st + b_dim1], ldb, &
00447                         work[bxst], n, &work[u + st1], n, &work[vt + st1], &
00448                         iwork[k + st1], &work[difl + st1], &work[difr + st1], 
00449                         &work[z__ + st1], &work[poles + st1], &iwork[givptr + 
00450                         st1], &iwork[givcol + st1], n, &iwork[perm + st1], &
00451                         work[givnum + st1], &work[c__ + st1], &work[s + st1], 
00452                         &work[nwork], &iwork[iwk], info);
00453                 if (*info != 0) {
00454                     return 0;
00455                 }
00456             }
00457             st = i__ + 1;
00458         }
00459 /* L60: */
00460     }
00461 
00462 /*     Apply the singular values and treat the tiny ones as zero. */
00463 
00464     tol = rcnd * (r__1 = d__[isamax_(n, &d__[1], &c__1)], dabs(r__1));
00465 
00466     i__1 = *n;
00467     for (i__ = 1; i__ <= i__1; ++i__) {
00468 
00469 /*        Some of the elements in D can be negative because 1-by-1 */
00470 /*        subproblems were not solved explicitly. */
00471 
00472         if ((r__1 = d__[i__], dabs(r__1)) <= tol) {
00473             slaset_("A", &c__1, nrhs, &c_b6, &c_b6, &work[bx + i__ - 1], n);
00474         } else {
00475             ++(*rank);
00476             slascl_("G", &c__0, &c__0, &d__[i__], &c_b11, &c__1, nrhs, &work[
00477                     bx + i__ - 1], n, info);
00478         }
00479         d__[i__] = (r__1 = d__[i__], dabs(r__1));
00480 /* L70: */
00481     }
00482 
00483 /*     Now apply back the right singular vectors. */
00484 
00485     icmpq2 = 1;
00486     i__1 = nsub;
00487     for (i__ = 1; i__ <= i__1; ++i__) {
00488         st = iwork[i__];
00489         st1 = st - 1;
00490         nsize = iwork[sizei + i__ - 1];
00491         bxst = bx + st1;
00492         if (nsize == 1) {
00493             scopy_(nrhs, &work[bxst], n, &b[st + b_dim1], ldb);
00494         } else if (nsize <= *smlsiz) {
00495             sgemm_("T", "N", &nsize, nrhs, &nsize, &c_b11, &work[vt + st1], n, 
00496                      &work[bxst], n, &c_b6, &b[st + b_dim1], ldb);
00497         } else {
00498             slalsa_(&icmpq2, smlsiz, &nsize, nrhs, &work[bxst], n, &b[st + 
00499                     b_dim1], ldb, &work[u + st1], n, &work[vt + st1], &iwork[
00500                     k + st1], &work[difl + st1], &work[difr + st1], &work[z__ 
00501                     + st1], &work[poles + st1], &iwork[givptr + st1], &iwork[
00502                     givcol + st1], n, &iwork[perm + st1], &work[givnum + st1], 
00503                      &work[c__ + st1], &work[s + st1], &work[nwork], &iwork[
00504                     iwk], info);
00505             if (*info != 0) {
00506                 return 0;
00507             }
00508         }
00509 /* L80: */
00510     }
00511 
00512 /*     Unscale and sort the singular values. */
00513 
00514     slascl_("G", &c__0, &c__0, &c_b11, &orgnrm, n, &c__1, &d__[1], n, info);
00515     slasrt_("D", n, &d__[1], info);
00516     slascl_("G", &c__0, &c__0, &orgnrm, &c_b11, n, nrhs, &b[b_offset], ldb, 
00517             info);
00518 
00519     return 0;
00520 
00521 /*     End of SLALSD */
00522 
00523 } /* slalsd_ */


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