Public feed #380018

Miscellany

public text v1 · immutable
Raw Edit
·published 2007-03-03 18:21 UTC
rendered paste body
static int cauchy_(
integer *n, doublereal *x, doublereal *l, doublereal *u, integer *nbd,
doublereal *g, integer *iorder, integer *iwhere, doublereal *t,
doublereal *d__, doublereal *xcp, integer *m, doublereal *wy, doublereal *ws,
doublereal *sy, doublereal *wt, doublereal *theta, integer *col, integer *head,
doublereal *p, doublereal *c__, doublereal *wbp, doublereal *v, integer *nint,
doublereal *sg, doublereal *yg, integer *iprint, doublereal *sbgnrm,
integer *info, doublereal *epsmch)
{
    /* Format strings */
/*
    static char fmt_3010[] = "(/,\002---------------- CAUCHY entered--------\
-----------\002)";
    static char fmt_1010[] = "(\002Cauchy X =  \002,/,(4x,1p,6(1x,d11.4)))";
    static char fmt_4011[] = "(/,\002Piece    \002,i3,\002 --f1, f2 at start\
 point \002,1p,2(1x,d11.4))";
    static char fmt_5010[] = "(\002Distance to the next break point =  \002,\
1p,d11.4)";
    static char fmt_6010[] = "(\002Distance to the stationary point =  \002,\
1p,d11.4)";
    static char fmt_4010[] = "(\002Piece    \002,i3,\002 --f1, f2 at start p\
oint \002,1p,2(1x,d11.4))";
    static char fmt_2010[] = "(/,\002---------------- exit CAUCHY-----------\
-----------\002,/)";
*/

    /* System generated locals */
    integer wy_dim1, wy_offset, ws_dim1, ws_offset, sy_dim1, sy_offset,
        wt_dim1, wt_offset, i__1, i__2;
    doublereal d__1;

    /* Local variables */
    static doublereal dibp;
    static integer iter;
    static doublereal zibp, tsum, dibp2;
    static integer i__, j;
    static logical bnded;
    static doublereal neggi;
    static integer nfree;
    static doublereal bkmin;
    static integer nleft;
    static doublereal f1, f2, f2_org__, dt, tj, tl;
    static integer nbreak, ibkmin;
    static doublereal tu;
    static integer pointr;
    static doublereal tj0;
    static logical xlower, xupper;
    static integer ibp;
    static doublereal dtm;
    static doublereal wmc, wmp, wmw;
    static integer col2;

    /* Fortran I/O blocks */
/*
    static cilist io___88 = { 0, 6, 0, 0, 0 };
    static cilist io___96 = { 0, 6, 0, fmt_3010, 0 };
    static cilist io___105 = { 0, 6, 0, fmt_1010, 0 };
    static cilist io___110 = { 0, 6, 0, 0, 0 };
    static cilist io___117 = { 0, 6, 0, fmt_4011, 0 };
    static cilist io___118 = { 0, 6, 0, fmt_5010, 0 };
    static cilist io___119 = { 0, 6, 0, fmt_6010, 0 };
    static cilist io___122 = { 0, 6, 0, 0, 0 };
    static cilist io___127 = { 0, 6, 0, 0, 0 };
    static cilist io___128 = { 0, 6, 0, 0, 0 };
    static cilist io___129 = { 0, 6, 0, fmt_4010, 0 };
    static cilist io___130 = { 0, 6, 0, fmt_6010, 0 };
    static cilist io___131 = { 0, 6, 0, fmt_1010, 0 };
    static cilist io___132 = { 0, 6, 0, fmt_2010, 0 };
*/


/*     ************ */

/*     Subroutine cauchy */

/*     For given x, l, u, g (with sbgnrm > 0), and a limited memory */
/*       BFGS matrix B defined in terms of matrices WY, WS, WT, and */
/*       scalars head, col, and theta, this subroutine computes the */
/*       generalized Cauchy point (GCP), defined as the first local */
/*       minimizer of the quadratic */

/*                  Q(x + s) = g's + 1/2 s'Bs */

/*       along the projected gradient direction P(x-tg,l,u). */
/*       The routine returns the GCP in xcp. */

/*     n is an integer variable. */
/*       On entry n is the dimension of the problem. */
/*       On exit n is unchanged. */

/*     x is a double precision array of dimension n. */
/*       On entry x is the starting point for the GCP computation. */
/*       On exit x is unchanged. */

/*     l is a double precision array of dimension n. */
/*       On entry l is the lower bound of x. */
/*       On exit l is unchanged. */

/*     u is a double precision array of dimension n. */
/*       On entry u is the upper bound of x. */
/*       On exit u is unchanged. */

/*     nbd is an integer array of dimension n. */
/*       On entry nbd represents the type of bounds imposed on the */
/*         variables, and must be specified as follows: */
/*         nbd(i)=0 if x(i) is unbounded, */
/*                1 if x(i) has only a lower bound, */
/*                2 if x(i) has both lower and upper bounds, and */
/*                3 if x(i) has only an upper bound. */
/*       On exit nbd is unchanged. */

/*     g is a double precision array of dimension n. */
/*       On entry g is the gradient of f(x).  g must be a nonzero vector. */
/*       On exit g is unchanged. */

/*     iorder is an integer working array of dimension n. */
/*       iorder will be used to store the breakpoints in the piecewise */
/*       linear path and free variables encountered. On exit, */
/*         iorder(1),...,iorder(nleft) are indices of breakpoints */
/*                                which have not been encountered; */
/*         iorder(nleft+1),...,iorder(nbreak) are indices of */
/*                                     encountered breakpoints; and */
/*         iorder(nfree),...,iorder(n) are indices of variables which */
/*                 have no bound constraits along the search direction. */

/*     iwhere is an integer array of dimension n. */
/*       On entry iwhere indicates only the permanently fixed (iwhere=3) */
/*       or free (iwhere= -1) components of x. */
/*       On exit iwhere records the status of the current x variables. */
/*       iwhere(i)=-3  if x(i) is free and has bounds, but is not moved */
/*                 0   if x(i) is free and has bounds, and is moved */
/*                 1   if x(i) is fixed at l(i), and l(i) .ne. u(i) */
/*                 2   if x(i) is fixed at u(i), and u(i) .ne. l(i) */
/*                 3   if x(i) is always fixed, i.e.,  u(i)=x(i)=l(i) */
/*                 -1  if x(i) is always free, i.e., it has no bounds. */

/*     t is a double precision working array of dimension n. */
/*       t will be used to store the break points. */

/*     d is a double precision array of dimension n used to store */
/*       the Cauchy direction P(x-tg)-x. */

/*     xcp is a double precision array of dimension n used to return the */
/*       GCP on exit. */

/*     m is an integer variable. */
/*       On entry m is the maximum number of variable metric corrections */
/*         used to define the limited memory matrix. */
/*       On exit m is unchanged. */

/*     ws, wy, sy, and wt are double precision arrays. */
/*       On entry they store information that defines the */
/*                             limited memory BFGS matrix: */
/*         ws(n,m) stores S, a set of s-vectors; */
/*         wy(n,m) stores Y, a set of y-vectors; */
/*         sy(m,m) stores S'Y; */
/*         wt(m,m) stores the */
/*                 Cholesky factorization of (theta*S'S+LD^(-1)L'). */
/*       On exit these arrays are unchanged. */

/*     theta is a double precision variable. */
/*       On entry theta is the scaling factor specifying B_0 = theta I. */
/*       On exit theta is unchanged. */

/*     col is an integer variable. */
/*       On entry col is the actual number of variable metric */
/*         corrections stored so far. */
/*       On exit col is unchanged. */

/*     head is an integer variable. */
/*       On entry head is the location of the first s-vector (or y-vector) */
/*         in S (or Y). */
/*       On exit col is unchanged. */

/*     p is a double precision working array of dimension 2m. */
/*       p will be used to store the vector p = W^(T)d. */

/*     c is a double precision working array of dimension 2m. */
/*       c will be used to store the vector c = W^(T)(xcp-x). */

/*     wbp is a double precision working array of dimension 2m. */
/*       wbp will be used to store the row of W corresponding */
/*         to a breakpoint. */

/*     v is a double precision working array of dimension 2m. */

/*     nint is an integer variable. */
/*       On exit nint records the number of quadratic segments explored */
/*         in searching for the GCP. */

/*     sg and yg are double precision arrays of dimension m. */
/*       On entry sg  and yg store S'g and Y'g correspondingly. */
/*       On exit they are unchanged. */

/*     iprint is an INTEGER variable that must be set by the user. */
/*       It controls the frequency and type of output generated: */
/*        iprint<0    no output is generated; */
/*        iprint=0    print only one line at the last iteration; */
/*        0<iprint<99 print also f and |proj g| every iprint iterations; */
/*        iprint=99   print details of every iteration except n-vectors; */
/*        iprint=100  print also the changes of active set and final x; */
/*        iprint>100  print details of every iteration including x and g; */
/*       When iprint > 0, the file iterate.dat will be created to */
/*                        summarize the iteration. */

/*     sbgnrm is a double precision variable. */
/*       On entry sbgnrm is the norm of the projected gradient at x. */
/*       On exit sbgnrm is unchanged. */

/*     info is an integer variable. */
/*       On entry info is 0. */
/*       On exit info = 0       for normal return, */
/*                    = nonzero for abnormal return when the the system */
/*                              used in routine bmv is singular. */

/*     Subprograms called: */

/*       L-BFGS-B Library ... hpsolb, bmv. */

/*       Linpack ... dscal dcopy, daxpy. */


/*     References: */

/*       [1] R. H. Byrd, P. Lu, J. Nocedal and C. Zhu, ``A limited */
/*       memory algorithm for bound constrained optimization'', */
/*       SIAM J. Scientific Computing 16 (1995), no. 5, pp. 1190--1208. */

/*       [2] C. Zhu, R.H. Byrd, P. Lu, J. Nocedal, ``L-BFGS-B: FORTRAN */
/*       Subroutines for Large Scale Bound Constrained Optimization'' */
/*       Tech. Report, NAM-11, EECS Department, Northwestern University, */
/*       1994. */

/*       (Postscript files of these papers are available via anonymous */
/*        ftp to eecs.nwu.edu in the directory pub/lbfgs/lbfgs_bcm.) */

/*                           *  *  * */

/*     NEOS, November 1994. (Latest revision June 1996.) */
/*     Optimization Technology Center. */
/*     Argonne National Laboratory and Northwestern University. */
/*     Written by */
/*                        Ciyou Zhu */
/*     in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal. */


/*     ************ */
/*     Check the status of the variables, reset iwhere(i) if necessary; */
/*       compute the Cauchy direction d and the breakpoints t; initialize */
/*       the derivative f1 and the vector p = W'd (for theta = 1). */
    /* Parameter adjustments */
    --xcp;
    --d__;
    --t;
    --iwhere;
    --iorder;
    --g;
    --nbd;
    --u;
    --l;
    --x;
    --yg;
    --sg;
    --v;
    --wbp;
    --c__;
    --p;
    wt_dim1 = *m;
    wt_offset = 1 + wt_dim1 * 1;
    wt -= wt_offset;
    sy_dim1 = *m;
    sy_offset = 1 + sy_dim1 * 1;
    sy -= sy_offset;
    ws_dim1 = *n;
    ws_offset = 1 + ws_dim1 * 1;
    ws -= ws_offset;
    wy_dim1 = *n;
    wy_offset = 1 + wy_dim1 * 1;
    wy -= wy_offset;

    /* Function Body */
    if (*sbgnrm <= 0.) {
    if (*iprint >= 0) {
/*
        s_wsle(&io___88);
        do_lio(&c__9, &c__1, "Subgnorm = 0.  GCP = X.", (ftnlen)23);
        e_wsle();
*/
    }
    dcopy_(n, &x[1], &c__1, &xcp[1], &c__1);
    return 0;
    }
    bnded = TRUE_;
    nfree = *n + 1;
    nbreak = 0;
    ibkmin = 0;
    bkmin = 0.;
    col2 = *col << 1;
    f1 = 0.;
    if (*iprint >= 99) {
/*
    s_wsfe(&io___96);
    e_wsfe();
*/
    }
/*     We set p to zero and build it up as we determine d. */
    i__1 = col2;
    for (i__ = 1; i__ <= i__1; ++i__) {
    p[i__] = 0.;
/* L20: */
    }
/*     In the following loop we determine for each variable its bound */
/*        status and its breakpoint, and update p accordingly. */
/*        Smallest breakpoint is identified. */
    i__1 = *n;
    for (i__ = 1; i__ <= i__1; ++i__) {
    neggi = -g[i__];
    if (iwhere[i__] != 3 && iwhere[i__] != -1) {
/*             if x(i) is not a constant and has bounds, */
/*             compute the difference between x(i) and its bounds. */
        if (nbd[i__] <= 2) {
        tl = x[i__] - l[i__];
        }
        if (nbd[i__] >= 2) {
        tu = u[i__] - x[i__];
        }
/*           If a variable is close enough to a bound */
/*             we treat it as at bound. */
        xlower = nbd[i__] <= 2 && tl <= 0.;
        xupper = nbd[i__] >= 2 && tu <= 0.;
/*              reset iwhere(i). */
        iwhere[i__] = 0;
        if (xlower) {
        if (neggi <= 0.) {
            iwhere[i__] = 1;
        }
        } else if (xupper) {
        if (neggi >= 0.) {
            iwhere[i__] = 2;
        }
        } else {
        if (abs(neggi) <= 0.) {
            iwhere[i__] = -3;
        }
        }
    }
    pointr = *head;
    if (iwhere[i__] != 0 && iwhere[i__] != -1) {
        d__[i__] = 0.;
    } else {
        d__[i__] = neggi;
        f1 -= neggi * neggi;
/*             calculate p := p - W'e_i* (g_i). */
        i__2 = *col;
        for (j = 1; j <= i__2; ++j) {
        p[j] += wy[i__ + pointr * wy_dim1] * neggi;
        p[*col + j] += ws[i__ + pointr * ws_dim1] * neggi;
        pointr = pointr % *m + 1;
/* L40: */
        }
        if (nbd[i__] <= 2 && nbd[i__] != 0 && neggi < 0.) {
/*                                 x(i) + d(i) is bounded; compute t(i). */
        ++nbreak;
        iorder[nbreak] = i__;
        t[nbreak] = tl / (-neggi);
        if (nbreak == 1 || t[nbreak] < bkmin) {
            bkmin = t[nbreak];
            ibkmin = nbreak;
        }
        } else if (nbd[i__] >= 2 && neggi > 0.) {
/*                                 x(i) + d(i) is bounded; compute t(i). */
        ++nbreak;
        iorder[nbreak] = i__;
        t[nbreak] = tu / neggi;
        if (nbreak == 1 || t[nbreak] < bkmin) {
            bkmin = t[nbreak];
            ibkmin = nbreak;
        }
        } else {
/*                x(i) + d(i) is not bounded. */
        --nfree;
        iorder[nfree] = i__;
        if (abs(neggi) > 0.) {
            bnded = FALSE_;
        }
        }
    }
/* L50: */
    }
/*     The indices of the nonzero components of d are now stored */
/*       in iorder(1),...,iorder(nbreak) and iorder(nfree),...,iorder(n). */
/*       The smallest of the nbreak breakpoints is in t(ibkmin)=bkmin. */
    if (*theta != 1.) {
/*                   complete the initialization of p for theta not= one. */
    dscal_(col, theta, &p[*col + 1], &c__1);
    }
/*     Initialize GCP xcp = x. */
    dcopy_(n, &x[1], &c__1, &xcp[1], &c__1);
    if (nbreak == 0 && nfree == *n + 1) {
/*                  is a zero vector, return with the initial xcp as GCP. */
    if (*iprint > 100) {
/*
        s_wsfe(&io___105);
        i__1 = *n;
        for (i__ = 1; i__ <= i__1; ++i__) {
        do_fio(&c__1, (char *)&xcp[i__], (ftnlen)sizeof(doublereal));
        }
        e_wsfe();
*/
    }
    return 0;
    }
/*     Initialize c = W'(xcp - x) = 0. */
    i__1 = col2;
    for (j = 1; j <= i__1; ++j) {
    c__[j] = 0.;
/* L60: */
    }
/*     Initialize derivative f2. */
    f2 = -(*theta) * f1;
    f2_org__ = f2;
    if (*col > 0) {
    bmv_(m, &sy[sy_offset], &wt[wt_offset], col, &p[1], &v[1], info);
    if (*info != 0) {
        return 0;
    }
    f2 -= ddot_(&col2, &v[1], &c__1, &p[1], &c__1);
    }
    dtm = -f1 / f2;
    tsum = 0.;
    *nint = 1;
    if (*iprint >= 99) {
/*
    s_wsle(&io___110);
    do_lio(&c__9, &c__1, "There are ", (ftnlen)10);
    do_lio(&c__3, &c__1, (char *)&nbreak, (ftnlen)sizeof(integer));
    do_lio(&c__9, &c__1, "  breakpoints ", (ftnlen)14);
    e_wsle();
*/
    }
/*     If there are no breakpoints, locate the GCP and return. */
    if (nbreak == 0) {
    goto L888;
    }
    nleft = nbreak;
    iter = 1;
    tj = 0.;
/* ------------------- the beginning of the loop ------------------------- */
L777:
/*     Find the next smallest breakpoint; */
/*       compute dt = t(nleft) - t(nleft + 1). */
    tj0 = tj;
    if (iter == 1) {
/*         Since we already have the smallest breakpoint we need not do */
/*         heapsort yet. Often only one breakpoint is used and the */
/*         cost of heapsort is avoided. */
    tj = bkmin;
    ibp = iorder[ibkmin];
    } else {
    if (iter == 2) {
/*             Replace the already used smallest breakpoint with the */
/*             breakpoint numbered nbreak > nlast, before heapsort call. */
        if (ibkmin != nbreak) {
        t[ibkmin] = t[nbreak];
        iorder[ibkmin] = iorder[nbreak];
        }
/*        Update heap structure of breakpoints */
/*           (if iter=2, initialize heap). */
    }
    i__1 = iter - 2;
    hpsolb_(&nleft, &t[1], &iorder[1], &i__1);
    tj = t[nleft];
    ibp = iorder[nleft];
    }
    dt = tj - tj0;
    if (dt != 0. && *iprint >= 100) {
/*
    s_wsfe(&io___117);
    do_fio(&c__1, (char *)&(*nint), (ftnlen)sizeof(integer));
    do_fio(&c__1, (char *)&f1, (ftnlen)sizeof(doublereal));
    do_fio(&c__1, (char *)&f2, (ftnlen)sizeof(doublereal));
    e_wsfe();
    s_wsfe(&io___118);
    do_fio(&c__1, (char *)&dt, (ftnlen)sizeof(doublereal));
    e_wsfe();
    s_wsfe(&io___119);
    do_fio(&c__1, (char *)&dtm, (ftnlen)sizeof(doublereal));
    e_wsfe();
*/
    }
/*     If a minimizer is within this interval, locate the GCP and return. */
    if (dtm < dt) {
    goto L888;
    }
/*     Otherwise fix one variable and */
/*       reset the corresponding component of d to zero. */
    tsum += dt;
    --nleft;
    ++iter;
    dibp = d__[ibp];
    d__[ibp] = 0.;
    if (dibp > 0.) {
    zibp = u[ibp] - x[ibp];
    xcp[ibp] = u[ibp];
    iwhere[ibp] = 2;
    } else {
    zibp = l[ibp] - x[ibp];
    xcp[ibp] = l[ibp];
    iwhere[ibp] = 1;
    }
    if (*iprint >= 100) {
/*
    s_wsle(&io___122);
    do_lio(&c__9, &c__1, "Variable  ", (ftnlen)10);
    do_lio(&c__3, &c__1, (char *)&ibp, (ftnlen)sizeof(integer));
    do_lio(&c__9, &c__1, "  is fixed.", (ftnlen)11);
    e_wsle();
*/
    }
    if (nleft == 0 && nbreak == *n) {
/*                                             all n variables are fixed, */
/*                                                return with xcp as GCP. */
    dtm = dt;
    goto L999;
    }
/*     Update the derivative information. */
    ++(*nint);
/* Computing 2nd power */
    d__1 = dibp;
    dibp2 = d__1 * d__1;
/*     Update f1 and f2. */
/*        temporarily set f1 and f2 for col=0. */
    f1 = f1 + dt * f2 + dibp2 - *theta * dibp * zibp;
    f2 -= *theta * dibp2;
    if (*col > 0) {
/*                          update c = c + dt*p. */
    daxpy_(&col2, &dt, &p[1], &c__1, &c__[1], &c__1);
/*           choose wbp, */
/*           the row of W corresponding to the breakpoint encountered. */
    pointr = *head;
    i__1 = *col;
    for (j = 1; j <= i__1; ++j) {
        wbp[j] = wy[ibp + pointr * wy_dim1];
        wbp[*col + j] = *theta * ws[ibp + pointr * ws_dim1];
        pointr = pointr % *m + 1;
/* L70: */
    }
/*           compute (wbp)Mc, (wbp)Mp, and (wbp)M(wbp)'. */
    bmv_(m, &sy[sy_offset], &wt[wt_offset], col, &wbp[1], &v[1], info);
    if (*info != 0) {
        return 0;
    }
    wmc = ddot_(&col2, &c__[1], &c__1, &v[1], &c__1);
    wmp = ddot_(&col2, &p[1], &c__1, &v[1], &c__1);
    wmw = ddot_(&col2, &wbp[1], &c__1, &v[1], &c__1);
/*           update p = p - dibp*wbp. */
    d__1 = -dibp;
    daxpy_(&col2, &d__1, &wbp[1], &c__1, &p[1], &c__1);
/*           complete updating f1 and f2 while col > 0. */
    f1 += dibp * wmc;
    f2 = f2 + dibp * 2. * wmp - dibp2 * wmw;
    }
/* Computing MAX */
    d__1 = *epsmch * f2_org__;
    f2 = max(d__1,f2);
    if (nleft > 0) {
    dtm = -f1 / f2;
    goto L777;
/*                 to repeat the loop for unsearched intervals. */
    } else if (bnded) {
    f1 = 0.;
    f2 = 0.;
    dtm = 0.;
    } else {
    dtm = -f1 / f2;
    }
/* ------------------- the end of the loop ------------------------------- */
L888:
    if (*iprint >= 99) {
/*
    s_wsle(&io___127);
    e_wsle();
    s_wsle(&io___128);
    do_lio(&c__9, &c__1, "GCP found in this segment", (ftnlen)25);
    e_wsle();
    s_wsfe(&io___129);
    do_fio(&c__1, (char *)&(*nint), (ftnlen)sizeof(integer));
    do_fio(&c__1, (char *)&f1, (ftnlen)sizeof(doublereal));
    do_fio(&c__1, (char *)&f2, (ftnlen)sizeof(doublereal));
    e_wsfe();
    s_wsfe(&io___130);
    do_fio(&c__1, (char *)&dtm, (ftnlen)sizeof(doublereal));
    e_wsfe();
*/
    }
    if (dtm <= 0.) {
    dtm = 0.;
    }
    tsum += dtm;
/*     Move free variables (i.e., the ones w/o breakpoints) and */
/*       the variables whose breakpoints haven't been reached. */
    daxpy_(n, &tsum, &d__[1], &c__1, &xcp[1], &c__1);
L999:
/*     Update c = c + dtm*p = W'(x^c - x) */
/*       which will be used in computing r = Z'(B(x^c - x) + g). */
    if (*col > 0) {
    daxpy_(&col2, &dtm, &p[1], &c__1, &c__[1], &c__1);
    }
    if (*iprint > 100) {
/*
    s_wsfe(&io___131);
    i__1 = *n;
    for (i__ = 1; i__ <= i__1; ++i__) {
        do_fio(&c__1, (char *)&xcp[i__], (ftnlen)sizeof(doublereal));
    }
    e_wsfe();
*/
    }
    if (*iprint >= 99) {
/*
    s_wsfe(&io___132);
    e_wsfe();
*/
    }
    return 0;
} /* cauchy_ */