optimization/brent.h

00001 #ifndef TOON_BRENT_H
00002 #define TOON_BRENT_H
00003 #include <TooN/TooN.h>
00004 #include <TooN/helpers.h>
00005 #include <limits>
00006 #include <cmath>
00007 #include <cstdlib>
00008 #include <iomanip>
00009 
00010 
00011 namespace TooN
00012 {
00013     using std::numeric_limits;
00014 
00029     template<class Functor, class Precision> Vector<2, Precision> brent_line_search(Precision a, Precision x, Precision b, Precision fx, const Functor& func, int maxiterations, Precision tolerance = sqrt(numeric_limits<Precision>::epsilon()), Precision epsilon = numeric_limits<Precision>::epsilon())
00030     {
00031         using std::min;
00032         using std::max;
00033 
00034         using std::abs;
00035 
00036         //The golden ratio:
00037         const Precision g = (3.0 - sqrt(5))/2;
00038         
00039         //The following points are tracked by the algorithm:
00040         //a, b bracket the interval
00041         // x   is the best value so far
00042         // w   second best point so far
00043         // v   third best point so far
00044         // These may not be unique.
00045         
00046         //The following points are used during iteration
00047         // u   the point currently being evaluated
00048         // xm   (a+b)/2
00049         
00050         //The updates are tracked as:
00051         //e is the distance moved last step, or current if golden section is used
00052         //d is the point moved in the current step
00053         
00054         Precision w=x, v=x, fw=fx, fv=fx;
00055         
00056         Precision d=0, e=0;
00057         int i=0;
00058 
00059         while(abs(b-a) > (abs(a) + abs(b)) * tolerance + epsilon && i < maxiterations)
00060         {
00061             i++;
00062             //The midpoint of the bracket
00063             const Precision xm = (a+b)/2;
00064 
00065             //Per-iteration tolerance 
00066             const Precision tol1 = abs(x)*tolerance + epsilon;
00067 
00068             //If we recently had an unhelpful step, then do
00069             //not attempt a parabolic fit. This prevents bad parabolic
00070             //fits spoiling the convergence. Also, do not attempt to fit if
00071             //there is not yet enough unique information in x, w, v.
00072             if(abs(e) > tol1 && w != v)
00073             {
00074                 //Attempt a parabolic through the best 3 points. The pdata is shifted
00075                 //so that x = 0 and f(x) = 0. The remaining parameters are:
00076                 //
00077                 // xw  = w'    = w-x
00078                 // fxw = f'(w) = f(w) - f(x)
00079                 //
00080                 // etc:
00081                 const Precision fxw = fw - fx;
00082                 const Precision fxv = fv - fx;
00083                 const Precision xw = w-x;
00084                 const Precision xv = v-x;
00085 
00086                 //The parabolic fit has only second and first order coefficients:
00087                 //const Precision c1 = (fxv*xw - fxw*xv) / (xw*xv*(xv-xw));
00088                 //const Precision c2 = (fxw*xv*xv - fxv*xw*xw) / (xw*xv*(xv-xw));
00089                 
00090                 //The minimum is at -.5*c2 / c1;
00091                 //
00092                 //This can be written as p/q where:
00093                 const Precision p = fxv*xw*xw - fxw*xv*xv;
00094                 const Precision q = 2*(fxv*xw - fxw*xv);
00095 
00096                 //The minimum is at p/q. The minimum must lie within the bracket for it
00097                 //to be accepted. 
00098                 // Also, we want the step to be smaller than half the old one. So:
00099 
00100                 if(q == 0 || x + p/q < a || x+p/q > b || abs(p/q) > abs(e/2))
00101                 {
00102                     //Parabolic fit no good. Take a golden section step instead
00103                     //and reset d and e.
00104                     if(x > xm)
00105                         e = a-x;
00106                     else
00107                         e = b-x;
00108 
00109                     d = g*e;
00110                 }
00111                 else
00112                 {
00113                     //Parabolic fit was good. Shift d and e
00114                     e = d;
00115                     d = p/q;
00116                 }
00117             }
00118             else
00119             {
00120                 //Don't attempt a parabolic fit. Take a golden section step
00121                 //instead and reset d and e.
00122                 if(x > xm)
00123                     e = a-x;
00124                 else
00125                     e = b-x;
00126 
00127                 d = g*e;
00128             }
00129 
00130             const Precision u = x+d;
00131             //Our one function evaluation per iteration
00132             const Precision fu = func(u);
00133 
00134             if(fu < fx)
00135             {
00136                 //U is the best known point.
00137 
00138                 //Update the bracket
00139                 if(u > x)
00140                     a = x;
00141                 else
00142                     b = x;
00143 
00144                 //Shift v, w, x
00145                 v=w; fv = fw;
00146                 w=x; fw = fx;
00147                 x=u; fx = fu;
00148             }
00149             else
00150             {
00151                 //u is not the best known point. However, it is within the
00152                 //bracket.
00153                 if(u < x)
00154                     a = u;
00155                 else
00156                     b = u;
00157 
00158                 if(fu <= fw || w == x)
00159                 {
00160                     //Here, u is the new second-best point
00161                     v = w; fv = fw;
00162                     w = u; fw = fu;
00163                 }
00164                 else if(fu <= fv || v==x || v == w)
00165                 {
00166                     //Here, u is the new third-best point.
00167                     v = u; fv = fu;
00168                 }
00169             }
00170         }
00171 
00172         return makeVector(x, fx);
00173     }
00174 }
00175 #endif

Generated on Thu May 7 20:28:40 2009 for TooN by  doxygen 1.5.3