vnl_bracket_minimum.cxx
Go to the documentation of this file.
1 // This is core/vnl/algo/vnl_bracket_minimum.cxx
2 //:
3 // \file
4 // \brief Function to bracket a minimum
5 // \author Tim Cootes
6 // \date Feb 2007
7 
8 #include <cmath>
9 #include <algorithm>
12 
13 static const double GOLDEN_RATIO = 1.618033988749894848; // = 0.5*(std::sqrt(5)-1);
14 static const double EPS = 1e-7; // Loose tolerance
15 static const double EPSqr = 1e-14;
16 inline void swap(double& a, double& b)
17 {
18  double x=a;
19  a=b;
20  b=x;
21 }
22 
24 {
27  public:
29  double operator()(double x) { v[0]=x; return f->f(v); }
30 };
31 
32 //: Given initial values a and b, find bracket a<b<c s.t. f(a)>f(b)<f(c)
33 // Final function values at a,b,c stored in fa,fb,fc
35  double& a, double& b, double& c,
36  double& fa, double& fb, double& fc)
37 {
38  // Set up object to evaluate function
39  // Note that fn takes a vector input - f converts a scalar to a vector
40  vnl_bm_func f(fn);
41 
42  if (b==a) b=a+1.0;
43  fa = f(a);
44  fb = f(b);
45 
46  // Arrange that fb<=fa
47  if (fb>fa)
48  {
49  swap(a,b); swap(fa,fb);
50  }
51 
52  // Initial guess at c
53  c = b+ GOLDEN_RATIO*(b-a);
54  fc = f(c);
55 
56  while (fc<fb) // Keep stepping until we go uphill again
57  {
58  // Use parabolic interpolation to estimate position of centre
59  double p,q;
60  vnl_fit_parabola(a,b,c,fa,fb,fc,p,q);
61 
62  // Ensure q not within EPSqr of zero
63  if (q>=0 && q<EPSqr) q=EPSqr;
64  else if (q<0 && q+EPSqr>0) q=-1.0*EPSqr;
65 
66  // Estimate of centre of parabolic fit - ie minimum
67  // For true quadratic function, minima is at b+p/q
68  double du = p/q;
69 
70  double tol = EPS*(1.0+std::max(std::fabs(b),std::fabs(c)));
71 
72  // Don't evaluate too close to b
73  if (du>=0 && du<tol) du=tol;
74  else if (du<0 && du+tol>0) du=-1.0*tol;
75 
76  double u = b + du;
77 
78  // Don't evaluate too close to c
79  if ((u-c)<tol && (u-c)>=0) u+=tol; // u>c by small amount
80  else if ((c-u)<tol && (c-u)>=0) u-=tol; // u<c by small amount
81 
82  double u_limit = b + 100*(c-b); // Some way along the line
83  double fu=0.0;
84 
85  if ((u-b)*(c-u)>0.0) // u in range (b,c), allowing for c<b
86  {
87  fu = f(u);
88  if (fu<fc)
89  {
90  // Bracket is (b,u,c)
91  a=b; fa=fb; b=u; fb=fu;
92  // Ensure a<b<c
93  if (a>c) { swap(a,c); swap(fa,fc); }
94  return;
95  }
96  else if (fu>fb)
97  {
98  // Bracket is (a,b,u)
99  c=u; fc=fu;
100  // Ensure a<b<c
101  if (a>c) { swap(a,c); swap(fa,fc); }
102  return;
103  }
104  // The predicted point is unhelpful, so try a default step
105  u = c+GOLDEN_RATIO*(c-b);
106  fu = f(u);
107  }
108  else if ((u-c)*(u_limit-u)>0.0) // u in range (c,u_limit)
109  {
110  fu = f(u);
111  if (fu>fc)
112  {
113  // Bracket is (b,c,u)
114  a=b; fa=fb; b=c; fb=fc; c=u; fc=fu;
115  // Ensure a<b<c
116  if (a>c) { swap(a,c); swap(fa,fc); }
117  return;
118  }
119  }
120  else if ((u_limit-c)*(u-u_limit)>=0) // u is beyond u_limit
121  {
122  u=u_limit;
123  fu=f(u);
124  }
125  else // u is somewhere else
126  {
127  // Next guess is at u
128  u = c+GOLDEN_RATIO*(c-b);
129  fu = f(u);
130  }
131 
132  // Move bracket
133  a=b; b=c; c=u;
134  fa=fb; fb=fc; fc=fu;
135  }
136 
137  // Ensure a<b<c
138  if (a>c)
139  {
140  swap(a,c); swap(fa,fc);
141  }
142 }
An object that represents a function from R^n -> R.
bool set_size(size_t n)
Resize to n elements.
Definition: vnl_vector.hxx:250
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).
Function to bracket a minimum.
vnl_decnum max(vnl_decnum const &x, vnl_decnum const &y)
Definition: vnl_decnum.h:412
void swap(vnl_matrix< T > &A, vnl_matrix< T > &B)
Swap two matrices.
Definition: vnl_matrix.h:733
vnl_bm_func(vnl_cost_function &fn)
double operator()(double x)
Function to fit a parabola to three point to predict the centre line.
void vnl_fit_parabola(double xa, double xb, double xc, double fa, double fb, double fc, double &p, double &q)
Fit a parabola so as to estimate the position of the centre line.
vnl_cost_function * f
vnl_vector< double > v