Jpp
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
JSimplex.hh
Go to the documentation of this file.
1 #ifndef __JFIT__JSIMPLEX__
2 #define __JFIT__JSIMPLEX__
3 
4 #include <cmath>
5 #include <vector>
6 #include <ostream>
7 #include <iomanip>
8 
9 #include "Jeep/JPrint.hh"
10 #include "Jeep/JMessage.hh"
11 
12 
13 /**
14  * \author mdejong
15  */
16 
17 namespace JFIT {}
18 namespace JPP { using namespace JFIT; }
19 
20 namespace JFIT {
21 
22  using JEEP::JMessage;
23 
24 
25  /**
26  * Simple fit method based on Powell's algorithm, see reference:
27  * Numerical Recipes in C++, W.H. Press, S.A. Teukolsky, W.T. Vetterling and B.P. Flannery,
28  * Cambridge University Press.
29  *
30  * The template argument refers to the model that should be fitted to the data.
31  * This data structure should have arithmetic capabalities.
32  *
33  * The data member JSimplex::value corresponds to the start, current or final value
34  * of the model of the fit procedure.
35  * The data member JSimplex::step corresponds to the step directions.
36  * Note that the step directions may change during the fit.
37  * The template fit function should return the data type JGandalf::result_type
38  * which is composed of the values of the chi2 and gradient of a hit.
39  * The function operator returns the chi2 of the fit.
40  */
41  template<class JModel_t>
42  class JSimplex :
43  public JMessage< JSimplex<JModel_t> >
44  {
45  public:
46 
48 
49 
50  /**
51  * Default constructor.
52  */
54  {}
55 
56 
57  /**
58  * Multi-dimensional fit.
59  *
60  * The given fit function should return the equivalent of chi2 for
61  * the current value of the given model and a given data point.
62  *
63  * \param fit fit function
64  * \param __begin begin of data
65  * \param __end end of data
66  * \return chi2
67  */
68  template<class JFunction_t, class T>
69  double operator()(const JFunction_t& fit, T __begin, T __end)
70  {
71  using namespace std;
72  using namespace JPP;
73 
74  double chi2_old = evaluate(fit, __begin, __end);
75 
76  const int N = step.size();
77 
78  if (N != 0) {
79 
80  double chi2[N];
81 
83 
85 
86  DEBUG("old: " << FIXED(12,5) << chi2_old << endl);
87 
88  const JModel_t p0(value);
89 
90  for (int i = 0; i != N; ++i) {
91 
92  DEBUG("step: " << i << ' ' << setw(5) << numberOfIterations << endl);
93 
94  chi2[i] = (*this)(fit, __begin, __end, step[i]);
95  }
96 
97  // overall step direction of last iteration
98 
99  JModel_t wall = value - p0;
100 
101  const double chi2_new = (*this)(fit, __begin, __end, wall);
102 
103  DEBUG("new: " << FIXED(12,5) << chi2_new << endl);
104 
105 
106  if (fabs(chi2_old - chi2_new) < EPSILON*fabs(chi2_old)) {
107  return chi2_new;
108  }
109 
110  // double overall step
111 
112  wall = value - p0;
113 
114  value += wall;
115 
116  const double fe = evaluate(fit, __begin, __end);
117 
118  value -= wall;
119 
120 
121  for (int i = N-1; i != 0; --i) {
122  chi2[i] = chi2[i-1] - chi2[i];
123  }
124 
125  chi2[0] = chi2_old - chi2[0];
126 
127 
128  double df = 0.0;
129 
130  for (int i = 0; i != N; ++i) {
131  if (chi2[i] > df) {
132  df = chi2[i];
133  }
134  }
135 
136  const double fn = chi2_new;
137  const double f0 = chi2_old;
138  const double ff = f0 - fn - df;
139 
140  // shift step directions
141 
142  if (fe < f0 && 2.0*(f0 - 2.0*fn + fe)*ff*ff < (f0-fe)*(f0-fe)*df) {
143 
144  for (int i = 0; i != N - 1; ++i) {
145  step[i] = step[i+1];
146  }
147 
148  step[N-1] = wall;
149  }
150 
151  chi2_old = chi2_new;
152  }
153  }
154 
155  return chi2_old;
156  }
157 
158 
159  /**
160  * 1D fit.
161  *
162  * The given fit function should return the equivalent of chi2 for
163  * the current value of the given model and a given data point.
164  *
165  * \param fit fit function
166  * \param __begin begin of data
167  * \param __end end of data
168  * \param step step direction
169  */
170  template<class JFunction_t, class T>
171  double operator()(const JFunction_t& fit, T __begin, T __end, const JModel_t& step)
172  {
173  using namespace std;
174  using namespace JPP;
175 
176  double lambda = 0.5; // control parameter
177  double factor = 1.0; // multiplication factor
178 
179  double chi2_old = evaluate(fit, __begin, __end);
180 
181  for (int i = 0; numberOfIterations != MAXIMUM_ITERATIONS; ++numberOfIterations, ++i) {
182 
183  value += lambda * step;
184 
185  const double chi2_new = evaluate(fit, __begin, __end);
186 
187  DEBUG("step: " << setw(3) << i << ' ' << FIXED(12,5) << chi2_old << ' ' << FIXED(12,5) << chi2_new << ' ' << FIXED(5,2) << lambda << endl);
188 
189  if (fabs(chi2_old - chi2_new) < EPSILON*fabs(chi2_old)) {
190 
191  if (chi2_new > chi2_old) {
192 
193  value -= lambda * step; // undo last step
194 
195  return chi2_old;
196 
197  } else {
198 
199  return chi2_new;
200  }
201  }
202 
203  if (chi2_new < chi2_old) {
204 
205  chi2_old = chi2_new;
206 
207  } else {
208 
209  value -= lambda * step; // step back
210  lambda = -lambda; // change direction
211 
212  if (i != 0) {
213  factor = 0.5; // reduce step size
214  }
215  }
216 
217  lambda = factor * lambda;
218  }
219 
220  return chi2_old;
221  }
222 
223 
224  static int MAXIMUM_ITERATIONS; //!< maximal number of iterations
225  static double EPSILON; //!< maximal distance to minimum
226 
227  JModel_t value;
230 
231  private:
232  /**
233  * Evaluate chi2 for given data set.
234  *
235  * \param fit fit function
236  * \param __begin begin of data
237  * \param __end end of data
238  */
239  template<class JFunction_t, class T>
240  inline double evaluate(const JFunction_t& fit, T __begin, T __end) const
241  {
242  double chi2 = 0.0;
243 
244  for (T hit = __begin; hit != __end; ++hit) {
245  chi2 += fit(value, *hit);
246  }
247 
248  return chi2;
249  }
250  };
251 
252 
253  /**
254  * maximal number of iterations.
255  */
256  template<class JModel_t>
258 
259 
260  /**
261  * maximal distance to minimum.
262  */
263  template<class JModel_t>
264  double JSimplex<JModel_t>::EPSILON = 1.0e-4;
265 }
266 
267 #endif
static int debug
debug level (default is off).
Definition: JMessage.hh:43
double operator()(const JFunction_t &fit, T __begin, T __end, const JModel_t &step)
1D fit.
Definition: JSimplex.hh:171
Auxiliary data structure for floating point format specification.
Definition: JPrint.hh:461
I/O formatting auxiliaries.
int numberOfIterations
Definition: JSimplex.hh:229
JModel_t value
Definition: JSimplex.hh:227
General purpose messaging.
double operator()(const JFunction_t &fit, T __begin, T __end)
Multi-dimensional fit.
Definition: JSimplex.hh:69
Simple fit method based on Powell&#39;s algorithm, see reference: Numerical Recipes in C++...
Definition: JSimplex.hh:42
JSimplex()
Default constructor.
Definition: JSimplex.hh:53
double evaluate(const JFunction_t &fit, T __begin, T __end) const
Evaluate chi2 for given data set.
Definition: JSimplex.hh:240
static int MAXIMUM_ITERATIONS
maximal number of iterations
Definition: JSimplex.hh:224
static double EPSILON
maximal distance to minimum
Definition: JSimplex.hh:225
#define DEBUG(A)
Message macros.
Definition: JMessage.hh:60
Auxiliary class for handling debug parameter within a class.
Definition: JMessage.hh:42
std::vector< JModel_t > step
Definition: JSimplex.hh:228