vnl_brent_minimizer.cxx
Go to the documentation of this file.
1 // This is core/vnl/algo/vnl_brent_minimizer.cxx
2 //:
3 // \file
4 #include <cmath>
5 #include <cassert>
6 #include <iostream>
7 #include <algorithm>
10 
11 //static const double GOLDEN_RATIO = 1.618033988749894848; // = 0.5*(std::sqrt(5)-1);
12 static const double COMPL_GOLD = 0.381966011250105152; // = 0.5*(3-std::sqrt(5));
13 static const double EPS = 1e-8;
14 
15 // Wrapper to make it easy to evaluate the cost function
17 {
20  public:
22  { f=&fn; v.set_size(1); }
23 
24  double operator()(double x) { v[0]=x; return f->f(v); }
25 };
26 
28 {
29  f_=&functor;
30  set_x_tolerance(1e-6);
31 }
32 
34 
35 //: Find the minimum value of f(x) within a<= x <= c.
36 // The minimum x is the return value.
37 // You need to provide a bracket for the minimum (a<b<c s.t. f(a)>f(b)<f(c).
38 // The tolerance can be set using prior call to set_x_tolerance(tol).
39 // Use f_at_last_minimum() to get function evaluation at the returned minima.
40 double vnl_brent_minimizer::minimize_given_bounds(double ax, double bx, double cx)
41 {
43  double fb = f(bx);
44 
45  return minimize_given_bounds_and_one_f(ax,bx,cx,fb);
46 }
47 
48 //: Find the minimum value of f(x) within a<= x <= c.
49 // The minimum x is the return value.
50 // You need to provide a bracket for the minimum (a<b<c s.t. f(a)>f(b)<f(c),
51 // and the known value at b (fb=f(b)).
52 // The tolerance can be set using prior call to set_x_tolerance(tol).
53 // Use f_at_last_minimum() to get function evaluation at the returned minima.
54 double vnl_brent_minimizer::minimize_given_bounds_and_one_f(double ax, double bx, double cx,
55  double fb)
56 {
57  // Check that the bracket is valid
58  assert(ax<bx);
59  assert(bx<cx);
60 
61  // Set up object to evaluate function as f(x)
62  // Note that *f_ takes a vector input - f converts a scalar to a vector
64 
65  double x=bx; // Current best estimate of minimum
66  double w=x; // Next best point
67  double v=w; // Third best point
68  double u; // Most recently evaluated point
69 
70  // Function evaluations at these points
71  double fx = fb;
72  double fw = fx;
73  double fv = fw;
74  double fu;
75 
76  double m = 0.5*(ax+cx); // Midpoint of (a,c)
77  double tol = EPS*std::fabs(x)+xtol; // Tolerance to use
78  double tol2 = 2*tol; // Twice the tolerance
79 
80  double d=0.0; // Record of last p/q
81  double e=0.0; // Value of p/q in 2nd-to-last cycle of parabolic interp.
82 
83  // Loop until bracket sufficiently small
84  while (std::fabs(x-m)>(tol2-0.5*(cx-ax)))
85  {
86  // Variables for parabolic interpolation
87  double p=0.0,q=0.0,r=0.0;
88  if (std::fabs(e)>tol)
89  {
90  // Fit a parabola
91  r = (x-w)*(fx-fv);
92  q = (x-v)*(fx-fw);
93  p = (x-v)*q - (x-w)*r;
94  q = 2*(q-r);
95  if (q>0) p*=-1.0; else q*=-1.0; // q always positive
96  r = e; e = d;
97  }
98 
99  if (std::fabs(p)<std::fabs(0.5*q*r) &&
100  p>(q*(ax-x)) && p<(q*(cx-x)) ) // So that ax<x+p/q<cx
101  {
102  // Parabolic interpolation - set u to estimate of minimum
103  d = p/q;
104  u = x + d;
105 
106  // u must not be too close to ax or cx
107  if (u-ax<tol2 || cx-u<tol2) d = (x<m?tol:-tol);
108  }
109  else
110  {
111  // Golden section step
112  e = (x<m?cx:ax) - x;
113  d = COMPL_GOLD * e;
114  }
115 
116  // Do not evaluate too close to current x
117  if (std::fabs(d)>=tol)
118  u = x+d;
119  else
120  {
121  if (d>0) u=x+tol;
122  else u=x-tol;
123  }
124 
125  // Perform the function evaluation
126  fu = f(u);
127 
128  // Update our current bounds
129  if (fu<=fx)
130  {
131  if (u<x) cx=x; else ax=x;
132  v=w; fv=fw;
133  w=x; fw=fx;
134  x=u; fx=fu;
135  }
136  else
137  {
138  if (u<x) ax=u; else cx=u;
139  if (fu<=fw || w==x)
140  {
141  v=w; fv=fw;
142  w=u; fw=fu;
143  }
144  else if (fu<=fv || v==x || v==w) { v=u; fv=fu; }
145  }
146 
147  // Recompute mid-point and suitable tolerances
148  m = 0.5*(ax+cx); // Midpoint of (a,c)
149  tol = EPS*std::fabs(x)+xtol; // Tolerance to use
150  tol2 = 2*tol; // Twice the tolerance
151  }
152 
153  f_at_last_minimum_ = fx;
154  return x;
155 }
156 
157 //: Find the minimum value of f(x) within a<= x <= c.
158 // The minimum x is the return value.
159 // You need to provide a bracket for the minimum (a<b<c s.t. f(a)>f(b)<f(c)),
160 // and the values fa=f(a), fb=f(b), fc=f(c). This avoids recalculating
161 // them if you have them already.
162 // The tolerance can be set using prior call to set_x_tolerance(tol).
163 // Use f_at_last_minimum() to get function evaluation at the returned minima.
164 double vnl_brent_minimizer::minimize_given_bounds_and_all_f(double ax, double bx, double cx,
165  double fa, double fb, double fc)
166 {
167  // Check that the bracket is valid
168  assert(ax<bx);
169  assert(bx<cx);
170  assert(fb<fa);
171  assert(fb<fc);
172 
173  // Set up object to evaluate function as f(x)
174  // Note that *f_ takes a vector input - f converts a scalar to a vector
176 
177  double x=bx; // Current best estimate of minimum
178  double fx = fb;
179  double w, fw; // Next best point
180  double v, fv; // Third best point
181 
182  if (fa<fc) { w=ax; fw=fa; v=cx; fv=fc; }
183  else { w=cx; fw=fc; v=ax; fv=fa; }
184 
185  double u, fu; // Most recently evaluated point and its value
186 
187  double m = 0.5*(ax+cx); // Midpoint of (a,c)
188  double tol = EPS*std::fabs(x)+xtol; // Tolerance to use
189  double tol2 = 2*tol; // Twice the tolerance
190 
191  double d=std::min(bx-ax,cx-bx); // Record of last p/q
192  double e=std::max(bx-ax,cx-bx); // Value of p/q in 2nd-to-last cycle of parabolic interp.
193 
194  // Loop until bracket sufficiently small
195  while (std::fabs(x-m)>(tol2-0.5*(cx-ax)))
196  {
197  // Variables for parabolic interpolation
198  double p=0.0,q=0.0,r=0.0;
199  if (std::fabs(e)>tol)
200  {
201  // Fit a parabola
202  r = (x-w)*(fx-fv);
203  q = (x-v)*(fx-fw);
204  p = (x-v)*q - (x-w)*r;
205  q = 2*(q-r);
206  if (q>0) p*=-1.0; else q*=-1.0; // q always positive
207  r = e; e = d;
208  }
209 
210  if (std::fabs(p)<std::fabs(0.5*q*r) &&
211  p>(q*(ax-x)) && p<(q*(cx-x)) ) // So that ax<x+p/q<cx
212  {
213  // Parabolic interpolation - set u to estimate of minimum
214  d = p/q;
215  u = x + d;
216 
217  // u must not be too close to ax or cx
218  if (u-ax<tol2 || cx-u<tol2) d = (x<m?tol:-tol);
219  }
220  else
221  {
222  // Golden section step
223  e = (x<m?cx:ax) - x;
224  d = COMPL_GOLD * e;
225  }
226 
227  // Do not evaluate too close to current x
228  if (std::fabs(d)>=tol)
229  u = x+d;
230  else
231  {
232  if (d>0) u=x+tol;
233  else u=x-tol;
234  }
235 
236  // Perform the function evaluation
237  fu = f(u);
238 
239  // Update our current bounds
240  if (fu<=fx)
241  {
242  if (u<x) cx=x; else ax=x;
243  v=w; fv=fw;
244  w=x; fw=fx;
245  x=u; fx=fu;
246  }
247  else
248  {
249  if (u<x) ax=u; else cx=u;
250  if (fu<=fw || w==x)
251  {
252  v=w; fv=fw;
253  w=u; fw=fu;
254  }
255  else if (fu<=fv || v==x || v==w) { v=u; fv=fu; }
256  }
257 
258  // Recompute mid-point and suitable tolerances
259  m = 0.5*(ax+cx); // Midpoint of (a,c)
260  tol = EPS*std::fabs(x)+xtol; // Tolerance to use
261  tol2 = 2*tol; // Twice the tolerance
262  }
263 
264  f_at_last_minimum_ = fx;
265  return x;
266 }
267 
269 {
270  double ax=x-1.0;
271  double cx=x+1.0;
272  double fa,fx,fc;
273  vnl_bracket_minimum(*f_, ax,x,cx, fa,fx,fc);
274 
275  return minimize_given_bounds_and_all_f(ax,x,cx, fa,fx,fc);
276 }
An object that represents a function from R^n -> R.
double f_at_last_minimum_
Function evaluation at value returned by minimize(x).
double minimize_given_bounds_and_one_f(double ax, double bx, double cx, double fb)
Find the minimum value of f(x) within a<= x <= c.
bool set_size(size_t n)
Resize to n elements.
Definition: vnl_vector.hxx:250
double minimize_given_bounds_and_all_f(double ax, double bx, double cx, double fa, double fb, double fc)
Find the minimum value of f(x) within a<= x <= c.
#define m
Definition: vnl_vector.h:43
double minimize_given_bounds(double ax, double bx, double cx)
Find the minimum value of f(x) within a<= x <= c.
double f(vnl_vector< double > const &x) override
The main function. Given the parameter vector x, compute the value of f(x).
void vnl_bracket_minimum(vnl_cost_function &fn, double &a, double &b, double &c, double &fa, double &fb, double &fc)
Given initial values a and b, find bracket a<b<c s.t. f(a)>f(b)<f(c).
vnl_cost_function * f_
#define v
Definition: vnl_vector.h:42
double minimize(double ax)
Find a minimum of f(x) near to ax.
~vnl_brent_minimizer() override
Function to bracket a minimum.
vnl_decnum max(vnl_decnum const &x, vnl_decnum const &y)
Definition: vnl_decnum.h:412
double xtol
Termination tolerance on X (solution vector)
vnl_brent_minimizer(vnl_cost_function &functor)
vnl_decnum min(vnl_decnum const &x, vnl_decnum const &y)
Definition: vnl_decnum.h:413
vnl_brent_minimizer_func(vnl_cost_function &fn)
void set_x_tolerance(double v)
Set the convergence tolerance on X.