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
1.2.18