CC Localization
nelder_mead.hxx
Go to the documentation of this file.
1 
5 #pragma once
6 #include <functional>
7 #include <array>
8 
10 template<int N>
12 {
13 public:
14  typedef std::array<double,N> vec_t;
15  typedef std::function<double(vec_t const &)> fun_t;
16 private:
17  double const alpha = 1;
18  double const beta = 0.5;
19  double const gamma = 2;
20  double const delta = 0.5;
21  double mxrngy = 0.00001;
22  double mxrngx = 0.00001;
23  int mxiter = 1000;
24 public:
26  vec_t minimize(
27  fun_t fn,
28  vec_t const & x0,
29  vec_t const & step
30  ){
31  // initialize the simplex
32  std::array<vec_t,N+1> s;
33  for (int i = 0; i<N; i++) {
34  s[i] = x0;
35  s[i][i] += step[i];
36  }
37  s[N] = x0;
38 
39  std::array<double,N+1> y;
40  for (int i = 0; i<=N; i ++) y[i] = fn(s[i]);
41 
42  // workspace
43  vec_t xc; // reflection center
44  vec_t xn; // test point
45  vec_t x2; // next test point
46  int li; //lowest
47  int ni; //next-to-highest
48  int hi; //highest
49 
50  // iterate
51  int iter = 0;
52  do {
53  // find lowest, highest, and next-to-highest
54  li = 0;
55  ni = 0;
56  hi = 1;
57  if (y[1]<y[0]) {
58  li = 1;
59  ni = 1;
60  hi = 0;
61  }
62  for (int i = 2; i<=N; i++) {
63  if (y[i]<y[li]) li = i;
64  else if (y[i]>y[hi]) {
65  ni = hi;
66  hi = i;
67  }
68  else if (y[i]>y[ni]) ni = i;
69  }
70  if (ni==li) ni = 2;
71  // check for convergence
72  if (y[hi]-y[li]<mxrngy) { // y-range satisfied, check x
73  double mx = 0;
74  for (int i = 0; i<N; i++) {
75  double mnx = s[N][i];
76  double mxx = mnx;
77  for (int j = 0; j<N; j++) {
78  double xx = s[j][i];
79  if (xx<mnx) mnx = xx;
80  if (xx>mxx) mxx = xx;
81  }
82  double r = mxx-mnx;
83  if (r>mx) mx = r;
84  }
85  if (mx<mxrngx) break; // x-range small enough, done!
86  }
87  auto & sh = s[hi]; // highest position
88  // find reflection center and reflected position
89  for (int i = 0; i<N; i++) {
90  xc[i] = 0;
91  for (int j = 0; j<=N; j++) xc[i] += s[j][i];
92  xc[i] = (xc[i]-sh[i])/N;
93  xn[i] = xc[i]+(xc[i]-sh[i])*alpha;
94  }
95  double yn = fn(xn);
96  if (yn<y[ni]) { // reflection ok?
97  if (yn<y[li]) { // reflection best?
98  // expand
99  for (int i = 0; i<N; i++) x2[i] = xc[i]+(xc[i]-sh[i])*gamma;
100  double y2 = fn(x2);
101  if (y2<yn) { // expansion good?
102  y[hi] = y2;
103  sh = x2;
104  }
105  else { // scrap expansion
106  y[hi] = yn;
107  sh = xn;
108  }
109  }
110  else { // just use reflection
111  y[hi] = yn;
112  sh = xn;
113  }
114  }
115  else { // reflection bad
116  if (yn<y[hi]) { // not worst
117  // contract the reflection
118  for (int i = 0; i<N; i++) x2[i] = xc[i]+(xn[i]-xc[i])*beta;
119  double y2 = fn(x2);
120  if (y2<yn) { // contraction better?
121  y[hi] = y2;
122  sh = x2;
123  }
124  else { // use relection (this differs from Scholarpedia, which shrinks)
125  y[hi] = yn;
126  sh = xn;
127  }
128  }
129  else { // worst
130  // contract the original position
131  for (int i = 0; i<N; i++) xn[i] = xc[i]+(sh[i]-xc[i])*beta;
132  yn = fn(xn);
133  if (yn<y[hi]) { // improves a bit
134  y[hi] = yn;
135  sh = xn;
136  }
137  else { // not working, shink the simplex
138  auto & sl = s[li];
139  for (int i = 0; i<=N; i++) {
140  if (i==li) continue;
141  auto & d = s[i];
142  for (int j = 0; j<N; j++) d[j] = sl[j]+(d[j]-sl[j])*delta;
143  y[i] = fn(d);
144  }
145  }
146  }
147  }
148  iter ++;
149  } while (iter<mxiter);
150  return s[li];
151  }
152 };
153 
double fn(double const *p)
Function to be minimized.
Definition: localization.cc:39
vec_t minimize(fun_t fn, vec_t const &x0, vec_t const &step)
<perform minimization
Definition: nelder_mead.hxx:26
Optimizer with Nelder–Mead method for functions with N arguments.
Definition: nelder_mead.hxx:11
std::function< double(vec_t const &)> fun_t
minimized function
Definition: nelder_mead.hxx:15
std::array< double, N > vec_t
parameter space
Definition: nelder_mead.hxx:14