lsqr.c

来自「InsightToolkit-1.4.0(有大量的优化算法程序)」· C语言 代码 · 共 602 行 · 第 1/2 页

C
602
字号
/*          pp. 43-71. */

/*     C.C. Paige and M.A. Saunders,  Algorithm 583, LSQR: Sparse */
/*          linear equations and least-squares problems, */
/*          ACM Transactions on Mathematical Software 8, 2 (June 1982), */
/*          pp. 195-209. */

/*     C.L. Lawson, R.J. Hanson, D.R. Kincaid and F.T. Krogh, */
/*          Basic linear algebra subprograms for Fortran usage, */
/*          ACM Transactions on Mathematical Software 5, 3 (Sept 1979), */
/*          pp. 308-323 and 324-325. */
/* ----------------------------------------------------------------------- */


/*     LSQR development: */
/*     22 Feb 1982: LSQR sent to ACM TOMS to become Algorithm 583. */
/*     15 Sep 1985: Final F66 version.  LSQR sent to "misc" in netlib. */
/*     13 Oct 1987: Bug (Robert Davies, DSIR).  Have to delete */
/*                     IF ( (ONE + DABS(T)) .LE. ONE ) GO TO 200 */
/*                  from loop 200.  The test was an attempt to reduce */
/*                  underflows, but caused W(I) not to be updated. */
/*     17 Mar 1989: First F77 version. */
/*     04 May 1989: Bug (David Gay, AT&T).  When the second BETA is zero, */
/*                  RNORM = 0 and */
/*                  TEST2 = ARNORM / (ANORM * RNORM) overflows. */
/*                  Fixed by testing for RNORM = 0. */
/*     05 May 1989: Sent to "misc" in netlib. */

/*     Michael A. Saunders            (na.saunders @ NA-net.stanford.edu) */
/*     Department of Operations Research */
/*     Stanford University */
/*     Stanford, CA 94305-4022. */
/* ----------------------------------------------------------------------- */
/*     Initialize. */
/*      IF (NOUT .GT. 0) */
/*     $   WRITE(NOUT, 1000) ENTER, M, N, DAMP, ATOL, CONLIM, BTOL, ITNLIM */
    *itn = 0;
    *istop = 0;
    nstop = 0;
    ctol = 0.;
    if (*conlim > 0.) {
        ctol = 1. / *conlim;
    }
    *anorm = 0.;
    *acond = 0.;
    bbnorm = 0.;
    dampsq = *damp * *damp;
    ddnorm = 0.;
    res2 = 0.;
    *xnorm = 0.;
    xxnorm = 0.;
    cs2 = -1.;
    sn2 = 0.;
    z = 0.;
    for (i = 0; i < *n; ++i) {
        v[i] = 0.;
        x[i] = 0.;
        se[i] = 0.;
    }
/*     Set up the first vectors U and V for the bidiagonalization. */
/*     These satisfy  BETA*U = b,  ALFA*V = A(transpose)*U. */
    alfa = 0.;
    beta = dnrm2_(m, u, &c__1);
    if (beta > 0.) {
        d__1 = 1. / beta;
        dscal_(m, &d__1, u, &c__1);
        (*aprod)(&c__2, m, n, v, u, leniw, lenrw, iw, rw);
        alfa = dnrm2_(n, v, &c__1);
    }
    if (alfa > 0.) {
        d__1 = 1. / alfa;
        dscal_(n, &d__1, v, &c__1);
        dcopy_(n, v, &c__1, w, &c__1);
    }
    *arnorm = alfa * beta;
    if (*arnorm == 0.) {
        goto L800;
    }
    rhobar = alfa;
    phibar = beta;
    bnorm = beta;
    *rnorm = beta;
/*      IF (NOUT   .GT.  0  ) THEN */
/*         IF (DAMPSQ .EQ. ZERO) THEN */
/*             WRITE(NOUT, 1200) */
/*         ELSE */
/*             WRITE(NOUT, 1300) */
/*         END IF */
/*         TEST1  = ONE */
/*         TEST2  = ALFA / BETA */
/*         WRITE(NOUT, 1500) ITN, X(1), RNORM, TEST1, TEST2 */
/*         WRITE(NOUT, 1600) */
/*      END IF */
/*     ------------------------------------------------------------------ */
/*     Main iteration loop. */
/*     ------------------------------------------------------------------ */
L100:
    ++(*itn);
/*     Perform the next step of the bidiagonalization to obtain the */
/*     next  BETA, U, ALFA, V.  These satisfy the relations */
/*                BETA*U  =  A*V  -  ALFA*U, */
/*                ALFA*V  =  A(transpose)*U  -  BETA*V. */
    d__1 = -alfa;
    dscal_(m, &d__1, u, &c__1);
    (*aprod)(&c__1, m, n, v, u, leniw, lenrw, iw, rw);
    beta = dnrm2_(m, u, &c__1);
    bbnorm = bbnorm + alfa * alfa + beta * beta + dampsq;
    if (beta > 0.) {
        d__1 = 1. / beta;
        dscal_(m, &d__1, u, &c__1);
        d__1 = -beta;
        dscal_(n, &d__1, v, &c__1);
        (*aprod)(&c__2, m, n, v, u, leniw, lenrw, iw, rw);
        alfa = dnrm2_(n, v, &c__1);
        if (alfa > 0.) {
            d__1 = 1. / alfa;
            dscal_(n, &d__1, v, &c__1);
        }
    }
/*     Use a plane rotation to eliminate the damping parameter. */
/*     This alters the diagonal (RHOBAR) of the lower-bidiagonal matrix.  */
    rhbar2 = rhobar * rhobar + dampsq;
    rhbar1 = sqrt(rhbar2);
    cs1 = rhobar / rhbar1;
    sn1 = *damp / rhbar1;
    psi = sn1 * phibar;
    phibar *= cs1;
/*     Use a plane rotation to eliminate the subdiagonal element (BETA) */
/*     of the lower-bidiagonal matrix, giving an upper-bidiagonal matrix.  */
    rho = sqrt(rhbar2 + beta * beta);
    cs = rhbar1 / rho;
    sn = beta / rho;
    theta = sn * alfa;
    rhobar = -cs * alfa;
    phi = cs * phibar;
    phibar *= sn;
    tau = sn * phi;
/*     Update  X, W  and the standard error estimates. */
    t1 = phi / rho;
    t2 = -theta / rho;
    t3 = 1. / rho;
    for (i = 0; i < *n; ++i) {
        t = w[i];
        x[i] += t1 * t;
        w[i] = t2 * t + v[i];
        t *= t3; t *= t;
        se[i] += t;
        ddnorm += t;
    }
/*     Use a plane rotation on the right to eliminate the */
/*     super-diagonal element (THETA) of the upper-bidiagonal matrix. */
/*     Then use the result to estimate  norm(X). */
    delta = sn2 * rho;
    gambar = -cs2 * rho;
    rhs = phi - delta * z;
    zbar = rhs / gambar;
    *xnorm = sqrt(xxnorm + zbar * zbar);
    gamma = sqrt(gambar * gambar + theta * theta);
    cs2 = gambar / gamma;
    sn2 = theta / gamma;
    z = rhs / gamma;
    xxnorm += z * z;
/*     Test for convergence. */
/*     First, estimate the norm and condition of the matrix  Abar, */
/*     and the norms of  rbar  and  Abar(transpose)*rbar. */
    *anorm = sqrt(bbnorm);
    *acond = *anorm * sqrt(ddnorm);
    res1 = phibar * phibar;
    res2 += psi * psi;
    *rnorm = sqrt(res1 + res2);
    *arnorm = alfa * abs(tau);
/*     Now use these norms to estimate certain other quantities, */
/*     some of which will be small near a solution. */
    test1 = *rnorm / bnorm;
    test2 = 0.;
    if (*rnorm > 0.) {
        test2 = *arnorm / (*anorm * *rnorm);
    }
    test3 = 1. / *acond;
    t1 = test1 / (*anorm * *xnorm / bnorm + 1.);
    rtol = *btol + *atol * *anorm * *xnorm / bnorm;
/*     The following tests guard against extremely small values of */
/*     ATOL, BTOL  or  CTOL.  (The user may have set any or all of */
/*     the parameters  ATOL, BTOL, CONLIM  to zero.) */
/*     The effect is equivalent to the normal tests using */
/*     ATOL = RELPR,  BTOL = RELPR,  CONLIM = 1/RELPR. */
    t3 = test3 + 1.;
    t2 = test2 + 1.;
    t1 += 1.;
    if (*itn >= *itnlim) {
        *istop = 7;
    }
    if (t3 <= 1.) {
        *istop = 6;
    }
    if (t2 <= 1.) {
        *istop = 5;
    }
    if (t1 <= 1.) {
        *istop = 4;
    }
/*     Allow for tolerances set by the user. */
    if (test3 <= ctol) {
        *istop = 3;
    }
    if (test2 <= *atol) {
        *istop = 2;
    }
    if (test1 <= rtol) {
        *istop = 1;
    }
/*     ================================================================== */
/*     See if it is time to print something. */
    if (*nout <= 0) {
        goto L600;
    }
    if (*n <= 40) {
        goto L400;
    }
    if (*itn <= 10) {
        goto L400;
    }
    if (*itn >= *itnlim - 10) {
        goto L400;
    }
    if (*itn % 10 == 0) {
        goto L400;
    }
    if (test3 <= ctol * 2.f) {
        goto L400;
    }
    if (test2 <= *atol * 10.f) {
        goto L400;
    }
    if (test1 <= rtol * 10.f) {
        goto L400;
    }
    if (*istop != 0) {
        goto L400;
    }
    goto L600;
/*     Print a line for this iteration. */
L400:
    if (TRUE_) {
        goto L600;
    }
/*  400 WRITE(NOUT, 1500) ITN, X(1), RNORM, TEST1, TEST2, ANORM, ACOND */
/*  IF (MOD(ITN,10) .EQ. 0) WRITE(NOUT, 1600) */
/*     ================================================================== */
/*     Stop if appropriate. */
/*     The convergence criteria are required to be met on  NCONV */
/*     consecutive iterations, where  NCONV  is set below. */
/*     Suggested value:  NCONV = 1, 2  or  3. */
L600:
    if (*istop == 0) {
        nstop = 0;
    }
    if (*istop == 0) {
        goto L100;
    }
    nconv = 1;
    ++nstop;
    if (nstop < nconv && *itn < *itnlim) {
        *istop = 0;
    }
    if (*istop == 0) {
        goto L100;
    }
/*     ------------------------------------------------------------------ */
/*     End of iteration loop. */
/*     ------------------------------------------------------------------ */
/*     Finish off the standard error estimates. */
    t = 1.;
    if (*m > *n) {
        t = (doublereal) (*m - *n);
    }
    if (dampsq > 0.) {
        t = (doublereal) (*m);
    }
    t = *rnorm / sqrt(t);
    for (i = 0; i < *n; ++i) {
        se[i] = t * sqrt(se[i]);
    }
/*     Print the stopping condition. */
L800:
    if (TRUE_) {
        goto L900;
    }
/*  800 IF (NOUT .GT. 0) THEN */
/*         WRITE(NOUT, 2000) EXIT, ISTOP, ITN, */
/*     $                     EXIT, ANORM, ACOND, */
/*     $                     EXIT, RNORM, ARNORM, */
/*     $                     EXIT, BNORM, XNORM */
/*         WRITE(NOUT, 3000) EXIT, MSG(ISTOP) */
/*      END IF */
L900:
    return;
/*     ------------------------------------------------------------------ */
/*     ------------------------------------------------------------------ */
} /* lsqr_ */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?