Main Page   Modules   Data Structures   File List   Data Fields   Globals   Related Pages  

gnn_line_search.c

Go to the documentation of this file.
00001 /***************************************************************************
00002  *  @file gnn_line_search.c
00003  *  @brief Line Search Procedures Implementation.
00004  *
00005  *  @date   : 15-09-03 21:55, 01-10-03 09:50
00006  *  @author : Pedro Ortega C. <peortega@dcc.uchile.cl>
00007  *  Copyright  2003  Pedro Ortega C.
00008  ****************************************************************************/
00009 /*
00010  *  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version.
00014  *
00015  *  This program is distributed in the hope that it will be useful,
00016  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  *  GNU Library General Public License for more details.
00019  *
00020  *  You should have received a copy of the GNU General Public License
00021  *  along with this program; if not, write to the Free Software
00022  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00023  */
00024 
00025 
00026 
00027 /**
00028  * @brief Line Search Procedures.
00029  * @defgroup gnn_line_search_doc Line Search Procedures for Nodes.
00030  * @ingroup  libgnn_node
00031  *
00032  * This module contains a set of line search procedures for a \ref gnn_node.
00033  * A line search procedure is a one-dimensional minimization algorithm, with
00034  * tries to find a minimum in a given direction.
00035  *
00036  * This module tries to factorize the common features available in trainers
00037  * that need line search procedures during training. It isn't implemented yet.
00038  *
00039  *
00040  */
00041 
00042 
00043 
00044 /******************************************/
00045 /* Include Files                          */
00046 /******************************************/
00047 
00048 #include <math.h>
00049 #include "gnn_utilities.h"
00050 #include "gnn_line_search.h"
00051 
00052 
00053 
00054 /******************************************/
00055 /* Static Declaration                     */
00056 /******************************************/
00057 
00058 
00059 
00060 
00061 /******************************************/
00062 /* Public Interface                       */
00063 /******************************************/
00064 
00065 /**
00066  * @brief Bracketing procedure.
00067  * @ingroup gnn_line_search
00068  *
00069  * Given a \ref gnn_line buffer, and given distinct initial points \a ax and
00070  * \a bx, this routine searches in the downhill direction (defined by the
00071  * function associated to \a line as evaluated at the initial points) and
00072  * returns new points \a ax, \a bx, \a cx that bracket a minimum of the
00073  * function. Also returned are the function values at the three points,
00074  * \a fa, \a fb, and \a fc.
00075  *
00076  * [Adapted from Numerical Recipes in C.]
00077  *
00078  * @param line A pointer to a \ref gnn_line buffer.
00079  * @param s    The index of the first pattern in the minibatch to be evaluated.
00080  * @param n    The size of the minibatch to be evaluated.
00081  * @param ax   A pointer to an initial point.
00082  * @param bx   A pointer to the second initial point.
00083  * @param cx   A pointer where the middle point should be placed in.
00084  * @param fa   A pointer where the value \f$<E(a)>\f$ should be placed in.
00085  * @param fb   A pointer where the value \f$<E(b)>\f$ should be placed in.
00086  * @param fc   A pointer where the value \f$<E(c)>\f$ should be placed in.
00087  * @return Returns 0 if succeeded.
00088  */
00089 int
00090 gnn_line_search_bracket (gnn_line *line, size_t s, size_t n,
00091                          double *ax, double *bx, double *cx,
00092                          double *fa, double *fb, double *fc)
00093 {
00094     double ulim;
00095     double u;
00096     double r;
00097     double q;
00098     double fu;
00099     double dum;
00100 
00101     /* evaluate function */
00102     gnn_line_pats (line, *ax, gnnLineE, s, n);
00103     *fa = GNN_LINE_E (line);
00104     gnn_line_pats (line, *bx, gnnLineE, s, n);
00105     *fb = GNN_LINE_E (line);
00106 
00107     /* swith roles of a and b, so that we can   */
00108     /* go downhill in the direction from a to b */
00109     if (*fb > *fa)
00110     {
00111         GNN_SHIFT3 (dum, *ax, *bx, dum);
00112         GNN_SHIFT3 (dum, *fb, *fa, dum);
00113     }
00114 
00115     /* First guess for c */
00116     *cx = *bx + GNN_GOLDEN_OLD * (*bx - *ax);
00117     gnn_line_pats (line, *cx, gnnLineE, s, n);
00118     *fc = GNN_LINE_E (line);
00119 
00120     /* Keep returning here until we bracket */
00121     while (*fb > *fc)
00122     {
00123         /* Compute u by parabolic extrapolation from  */
00124         /* a, b, c. GNN_GOLDEN_TINY is use to prevent */
00125         /* any posible division by zero.              */
00126         r = (*bx - *ax) * (*fb - *fc);
00127         q = (*bx - *cx) * (*fb - *fa);
00128         u = *bx
00129             - ((*bx - *cx) * q - (*bx - *ax) * r) /
00130               ( 2.0 * GNN_USE_SIGN ( GNN_MAX (fabs (q - r), GNN_GOLDEN_TINY),
00131                                      q - r ) );
00132         ulim = *bx + GNN_GOLDEN_LIMIT * (*cx - *bx);
00133 
00134         /* We won't go farther than this. */
00135         /* Test various possibilities:    */
00136         if ((*bx - u) * (u - *cx) > 0.0)
00137         {
00138             /* Parabolic u is between b and c: try it. */
00139             gnn_line_pats (line, u, gnnLineE, s, n);
00140             fu = GNN_LINE_E (line);
00141 
00142             if (fu < *fc)
00143             {
00144                 /* Got a minimum between b and c. */
00145                 *ax = *bx;
00146                 *bx =  u;
00147                 *fa = *fb;
00148                 *fb =  fu;
00149                 return 0;
00150             }
00151             else if (fu > *fb)
00152             {
00153                 /* Got a minimum between a und u. */
00154                 *cx = u;
00155                 *fc = fu;
00156                 return 0;
00157             }
00158 
00159             /* Parabolic fit was no use. Use default magnification. */
00160             u  = *cx + GNN_GOLDEN_OLD * (*cx - *bx);
00161             gnn_line_pats (line, u, gnnLineE, s, n);
00162             fu = GNN_LINE_E (line);
00163         }
00164         else if ((*cx - u) * (u - ulim) > 0.0)
00165         {
00166             /* Parabolic fit is between c and its allowed limit. */
00167             gnn_line_pats (line, u, gnnLineE, s, n);
00168             fu = GNN_LINE_E (line);
00169             
00170             if (fu < *fc)
00171             {
00172                 GNN_SHIFT3 (*bx, *cx, u, *cx + GNN_GOLDEN_OLD * (*cx - *bx));
00173                 GNN_SHIFT2 (*fb, *fc, fu);
00174                 gnn_line_pats (line, u, gnnLineE, s, n);
00175                 fu = GNN_LINE_E (line);
00176             }
00177         }
00178         else if ((u - ulim) * (ulim - *cx) >= 0.0)
00179         {
00180             /* Limit parabolic u to maximum allowed value. */
00181             u  = ulim;
00182             gnn_line_pats (line, u, gnnLineE, s, n);
00183             fu = GNN_LINE_E (line);
00184         }
00185         else
00186         {
00187             /* Reject parabolic u, use default magnification. */
00188             u  = *cx + GNN_GOLDEN_OLD * (*cx - *bx);
00189             gnn_line_pats (line, u, gnnLineE, s, n);
00190             fu = GNN_LINE_E (line);
00191         }
00192             
00193         /* Eliminate oldest point and continue. */
00194         GNN_SHIFT3 (*ax, *bx, *cx, u);
00195         GNN_SHIFT3 (*fa, *fb, *fc, fu);
00196     }
00197 
00198     return 0;
00199 }
00200 
00201 /**
00202  * @brief Bracketing procedure.
00203  * @ingroup gnn_line_search
00204  *
00205  * Given a \ref gnn_line buffer \a line, and given a bracketing triplet
00206  * of abscissas \a ax, \a bx, \a cx (such that \a bx is between \a ax
00207  * and \a cx, and \a f(bx) is less than both \a f(ax) and \a f(cx)),
00208  * this routine performs a golden section search for the minimum error,
00209  * isolating it to a fractional precision of about \a tol. The abscissa
00210  * of the minimum is returned as \a xmin, and the minimum function value
00211  * is returned as \em golden, the returned function value.
00212  *
00213  * [Adapted from Numerical Recipes in C.]
00214  *
00215  * @param line A pointer to a \ref gnn_line buffer.
00216  * @param s    The index of the first pattern in the minibatch to be evaluated.
00217  * @param n    The size of the minibatch to be evaluated.
00218  * @param ax   Initial point of the bracketing triplet.
00219  * @param bx   Middle point of the bracketing triplet.
00220  * @param cx   Last point of the bracketing triplet.
00221  * @param xmin The location of the minimum.
00222  * @param tol  Fractional precision tolerance.
00223  * @return Returns the minimum function value.
00224  */
00225 double
00226 gnn_line_search_golden (gnn_line *line, size_t s, size_t n,
00227                         double ax, double bx, double cx,
00228                         double *xmin, double tol)
00229 {
00230     double f1;
00231     double f2;
00232     double x0;
00233     double x1;
00234     double x2;
00235     double x3;
00236 
00237     x0 = ax;
00238     
00239     /* At any given time we will keep track */
00240     /* of four points, x0, x1, x2, x3.      */
00241     x3 = cx;
00242 
00243     /* Make x0 to x1 the smaller segment,     */
00244     /* and fill in the new point to be tried. */
00245     if (fabs (cx - bx) > fabs (bx - ax))
00246     {
00247         x1 = bx;
00248         x2 = bx + GNN_GOLDEN_C * (cx - bx);
00249     }
00250     else
00251     {
00252         x2 = bx;
00253         x1 = bx - GNN_GOLDEN_C * (bx - ax);
00254     }
00255 
00256     /* The initial function evaluations. Note that we never    */
00257     /* need to evaluate the function at the original endpoints. */
00258     gnn_line_pats (line, x1, gnnLineE, s, n);
00259     f1 = GNN_LINE_E (line);
00260     gnn_line_pats (line, x2, gnnLineE, s, n);
00261     f2 = GNN_LINE_E (line);
00262 
00263     while (fabs (x3 - x0) > tol * (fabs (x1) + fabs (x2)))
00264     {
00265         if (f2 < f1)
00266         {   /* One possible outcome, its housekeeping, */
00267             /* and a new function evaluation.          */
00268             GNN_SHIFT3 (x0, x1, x2, GNN_GOLDEN_R * x1 + GNN_GOLDEN_C * x3);
00269             f1 = f2;
00270             gnn_line_pats (line, x2, gnnLineE, s, n);
00271             f2 = GNN_LINE_E (line);
00272         }
00273         else
00274         {
00275             /* The other outcome, and its new function evaluation. */
00276             GNN_SHIFT3 (x3, x2, x1, GNN_GOLDEN_R * x2 + GNN_GOLDEN_C * x0);
00277             f2 = f1;
00278             gnn_line_pats (line, x1, gnnLineE, s, n);
00279             f1 = GNN_LINE_E (line);
00280         }
00281         
00282         /* Back to see if we are done. */
00283     }
00284 
00285     /* We are done. Output the best of the two current values. */
00286     if (f1 < f2)
00287     {
00288         *xmin = x1;
00289         return f1;
00290     }
00291     else
00292     {
00293         *xmin = x2;
00294         return f2;
00295     }
00296     
00297     return 0;
00298 }
00299 
00300 /**
00301  * @brief Bracketing procedure.
00302  * @ingroup gnn_line_search
00303  *
00304  * Given a \ref gnn_line buffer \a line, and given a bracketing triplet
00305  * of abscissas \a ax, \a bx, \a cx (such that \a bx is between \a ax and
00306  * \a cx, and \c f(bx) is less than both \c f(ax) and \c f(cx)), this
00307  * routine isolates the minimum to a fractional precision of about \a tol
00308  * using Brent’s method. The abscissa of the minimum is returned as \a xmin,
00309  * and the minimum function value is returned as \c brent, the
00310  * returned function value.
00311  *
00312  * @param line A pointer to a \ref gnn_line buffer.
00313  * @param s    The index of the first pattern in the minibatch to be evaluated.
00314  * @param n    The size of the minibatch to be evaluated.
00315  * @param ax   Initial point of the bracketing triplet.
00316  * @param bx   Middle point of the bracketing triplet.
00317  * @param cx   Last point of the bracketing triplet.
00318  * @param xmin The location of the minimum.
00319  * @param tol  Fractional precision tolerance.
00320  * @return Returns the minimum function value.
00321  */
00322 double
00323 gnn_line_search_brent (gnn_line *line, size_t s, size_t n,
00324                        double ax, double bx, double cx,
00325                        double *xmin, double tol)
00326 {
00327     size_t iter;
00328     double a, b, d;
00329     double e, etemp;
00330     
00331     double u,  v,  w,  x,  xm;
00332     double fu, fv, fw, fx;
00333     
00334     double p, q, r;
00335     double tol1, tol2;
00336     
00337     /* This will be the distance moved on the step before last.*/
00338     e = 0.0;
00339     
00340     /* a and b must be in ascending order, */
00341     /* but input abscissas need not be.    */
00342     a = (ax < cx ? ax : cx);
00343     b = (ax > cx ? ax : cx);
00344     x = w = v = bx;
00345     
00346     /* Initializations... */
00347     gnn_line_pats (line, x, gnnLineE, s, n);
00348     fw = fv = fx = GNN_LINE_E (line);
00349     
00350     /* Main program loop. */
00351     for (iter=1; iter<=GNN_BRENT_ITMAX; iter++)
00352     {
00353         xm   = 0.5 * (a + b);
00354         tol2 = 2.0 * (tol1 = tol * fabs (x) + GNN_BRENT_ZEPS);
00355         
00356         /*  Test for done here. */
00357         if (fabs (x - xm) <= (tol2 - 0.5 * (b - a)))
00358         {
00359             *xmin = x;
00360             return fx;
00361         }
00362         
00363         /* Construct a trial parabolic fit. */
00364         if (fabs(e) > tol1)
00365         {
00366             r = (x - w) * (fx - fv);
00367             q = (x - v) * (fx - fw);
00368             p = (x - v) * q - (x - w) * r;
00369             q = 2.0 * (q - r);
00370 
00371             if (q > 0.0)
00372                 p = -p;
00373                 
00374             q     = fabs (q);
00375             etemp = e;
00376             e     = d;
00377 
00378             if (    fabs (p) >= fabs (0.5 * q * etemp)
00379                  || p <= q * (a - x)
00380                  || p >= q * (b - x) )
00381             {
00382                 d = GNN_BRENT_CGOLD * (e = (x >= xm ? a - x : b - x));
00383             }
00384             /* The above conditions determine the acceptability  */
00385             /* of the parabolic fit. Here we take the golden     */
00386             /* section step into the larger of the two segments. */
00387             else
00388             {
00389                 /* Take the parabolic step. */
00390                 d = p / q;
00391                 u = x + d;
00392                 if (u - a < tol2 || b - u < tol2)
00393                     d = GNN_USE_SIGN(tol1, xm-x);
00394             }
00395         }
00396         else
00397         {
00398             d = GNN_BRENT_CGOLD * (e = (x >= xm ? a - x : b - x));
00399         }
00400         u = (fabs (d) >= tol1 ? x + d : x + GNN_USE_SIGN(tol1, d));
00401 
00402         /* This is the one function evaluation per iteration. */
00403         gnn_line_pats (line, u, gnnLineE, s, n);
00404         fu = GNN_LINE_E (line);
00405 
00406         /*  Now decide what to do with our function evaluation. */
00407         if (fu <= fx)
00408         {
00409             if (u >= x)
00410                 a = x;
00411             else
00412                 b = x;
00413 
00414             /*  Housekeeping follows: */
00415             GNN_SHIFT3 (v, w, x, u);
00416             GNN_SHIFT3 (fv, fw, fx, fu);
00417         }
00418         else
00419         {
00420             if (u < x)
00421                 a = u;
00422             else
00423                 b = u;
00424 
00425             if (fu <= fw || w == x)
00426             {
00427                 v = w;
00428                 w = u;
00429                 fv = fw;
00430                 fw = fu;
00431             }
00432             else if (fu <= fv || v == x || v == w)
00433             {
00434                 v  = u;
00435                 fv = fu;
00436             }
00437         }
00438         /* Done with housekeeping. Back for another iteration. */
00439     }
00440     GSL_ERROR ("too many iterations in brent", GSL_EFAILED);
00441     
00442     /* Never get here. */
00443     *xmin = x;
00444     return fx;
00445 }
00446 
00447 /**
00448  * @brief Simple line search procedure.
00449  * @ingroup gnn_line_search_doc
00450  * @todo Not implemented yet.
00451  *
00452  * @param line A pointer to a \ref gnn_line buffer.
00453  * @param s    The index of the first pattern in the minibatch to be evaluated.
00454  * @param n    The size of the minibatch to be evaluated.
00455  * @param ax   Initial point of the bracketing triplet.
00456  * @param bx   Middle point of the bracketing triplet.
00457  * @param cx   Last point of the bracketing triplet.
00458  * @param xmin The location of the minimum.
00459  * @param tol  Fractional precision tolerance.
00460  * @return Returns the minimum function value.
00461  */
00462 double
00463 gnn_line_search_charalambous (gnn_line *line, size_t s, size_t n,
00464                               double ax, double bx, double cx,
00465                               double *xmin, double tol)
00466 {
00467     return 0.0;
00468 }
00469 
00470 
00471 /**
00472  * @brief Simple line search procedure.
00473  * @ingroup gnn_line_search_doc
00474  *
00475  * This function implements a simple but robust line search routine. It returns
00476  * the \f$\alpha\f$, where
00477  *
00478  * \f[ F(x,w +\alpha d) \f]
00479  *
00480  * is minimized.
00481  *
00482  * The strategy is the following:
00483  * - Start with a fixed \f$\delta\f$
00484  * - Compute \f$F(x, w)\f$, \f$F(x, w+\delta d)\f$, \f$F(x, w+2\delta d)\f$
00485  * - If \f$F(x, w) \geq F(x, w+\delta d) \leq F(x, w+2\delta d)\f$, then
00486  *   proceed to interpolate.
00487  * - If \f$F(x, w) \geq F(x, w+\delta) > F(x, w+2\delta)\f$, then
00488  *   \f$d \leftarrow 2d\f$ and retry.
00489  * - If \f$F(x, w) < F(x, w+\delta)\f$, then \f$d \leftarrow d/2\f$ and retry.
00490  *
00491  * The interpolation is performed by a quadratic polynom:
00492  * \f[ P(\alpha) = a_0 + a_1 \alpha + a_2 \alpha^2 \f]
00493  * where the coefficients are
00494  *
00495  * \f[ \left [ \begin{array}{c}
00496  *               a_0 \\ a_1 \\ a_2 \\
00497  *             \end{array}
00498  *     \right ] =
00499  *     \left [ \begin{array}{ccc}
00500  *               1 & 0 & 0 \\
00501  *               -3/(2\delta)  & 2/\delta    & - 1/(2\delta) \\
00502  *               1/(2\delta^2) & -1/\delta^2 & 1/(2\delta^2) \\
00503  *             \end{array}
00504  *     \right ]
00505  *     \left [ \begin{array}{c}
00506  *                F(x, w) \\ F(x, w+\delta d) \\ F(x,w+2\delta d) \\
00507  *             \end{array}
00508  *     \right ]
00509  * \f]
00510  * which gives the solution for \f$\alpha\f$:
00511  * \f[ \alpha = -\frac{a_1}{2 a_2} \f]
00512  *
00513  * @param line A pointer to a \ref gnn_line buffer.
00514  * @param s    The index of the first pattern in the minibatch to be evaluated.
00515  * @param n    The size of the minibatch to be evaluated.
00516  * @param ax   Initial point of the bracketing triplet.
00517  * @param bx   Middle point of the bracketing triplet.
00518  * @param cx   Last point of the bracketing triplet.
00519  * @param xmin The location of the minimum.
00520  * @param tol  Fractional precision tolerance.
00521  * @return Returns the minimum function value.
00522  */
00523 double
00524 gnn_line_search_simple (gnn_line *line, size_t s, size_t n,
00525                         double ax, double bx, double cx,
00526                         double *xmin, double tol)
00527 {
00528     return 0.0;
00529 }
00530 
00531 
00532 
00533 
00534 

Generated on Sun Jun 13 20:50:11 2004 for libgnn Gradient Retropropagation Machine Library by doxygen1.2.18