Jpp
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
JGandalf.hh
Go to the documentation of this file.
1 #ifndef __JFIT__JGANDALF__
2 #define __JFIT__JGANDALF__
3 
4 #include <limits>
5 #include <vector>
6 #include <cmath>
7 #include <ostream>
8 #include <iomanip>
9 
10 #include "Jeep/JPrint.hh"
11 #include "Jeep/JMessage.hh"
12 #include "JMath/JMatrixNS.hh"
13 #include "JMath/JZero.hh"
14 #include "JLang/JException.hh"
15 
16 
17 /**
18  * \author mdejong
19  */
20 
21 namespace JFIT {}
22 namespace JPP { using namespace JFIT; }
23 
24 namespace JFIT {
25 
26  using JEEP::JMessage;
27  using JLANG::JException;
28 
29 
30  /**
31  * Fit method based on the Levenberg-Marquardt method.
32  *
33  * The template argument refers to the model that should be fitted to the data.\n
34  * This data structure should have arithmetic capabilities.
35  *
36  * The data member JGandalf::value corresponds to the start c.q.\ final value of
37  * the model of the fit procedure and JGandalf::error to the uncertainties.\n
38  * The co-variance matrix is stored in data member JGandalf::H.\n
39  *
40  * The data member JGandalf::parameters constitutes a list of those parameters of the model that should actually be fitted.\n
41  * For this, the model should contain the type definition for <tt>parameter_type</tt>.\n
42  * Normally, this type definition corresponds to a pointer to a data member of the model.\n
43  * Alternatively, the type definition can be <tt>size_t</tt> or <tt>int</tt>.\n
44  * In that case, the model class should provide for the element access <tt>operator[]</tt>.\n
45  *
46  * The template fit function in JGandalf::operator() should provide for an implementation of the function.\n
47  * This operator should return the data type JGandalf::result_type which is composed of
48  * the value of the chi2 and the gradient of a data point, respectively.\n
49  * The function operator returns the chi2 of the overall fit.
50  */
51  template<class JModel_t>
52  class JGandalf :
53  public JMessage< JGandalf<JModel_t> >
54  {
55  public:
56 
58 
59 
60  /**
61  * Data type of fit parameter.
62  */
64 
65 
66  /**
67  * Data structure for return value of fit function.
68  */
69  struct result_type {
70  /**
71  * Default constructor.
72  */
74  chi2 (0.0),
75  gradient()
76  {}
77 
78 
79  /**
80  * Constructor.
81  *
82  * \param chi2 chi2
83  * \param model gradient
84  */
85  result_type(const double chi2,
86  const JModel_t& model) :
87  chi2 (chi2),
88  gradient(model)
89  {}
90 
91 
92  /**
93  * Type conversion operator.
94  *
95  * \return chi2
96  */
97  operator double() const
98  {
99  return chi2;
100  }
101 
102 
103  double chi2; //!< chi2
104  JModel_t gradient; //!< d(chi2)/d(...)
105  };
106 
107 
108  /**
109  * Default constructor.
110  */
112  {}
113 
114 
115  /**
116  * Multi-dimensional fit of two data sets.
117  *
118  * The fit function should return the equivalent of chi2 for the current value
119  * of the model and the given data point as well as the partial derivatives.
120  *
121  * \param fit fit function
122  * \param __begin begin of data
123  * \param __end end of data
124  * \return chi2
125  */
126  template<class JFunction_t, class T, class ...Args>
127  result_type operator()(const JFunction_t& fit, T __begin, T __end, Args ...args)
128  {
129  using namespace std;
130  using namespace JPP;
131 
132  const int N = parameters.size();
133 
134  H.resize(N);
135  h.resize(N);
136 
137  previous = value;
138 
141 
142  error = value;
143  error = zero;
144 
145  lambda = LAMBDA_MIN;
146 
147  result_type precessor = result_type(numeric_limits<double>::max(), value);
148 
150 
151  DEBUG("step: " << numberOfIterations << endl);
152 
153  reset();
154 
155  __evaluate__(fit, __begin, __end, args...);
156 
157  DEBUG("lambda: " << SCIENTIFIC(12,5) << lambda << endl);
158  DEBUG("chi2: " << FIXED (12,5) << successor.chi2 << endl);
159 
160  if (successor.chi2 < precessor.chi2) {
161 
162  if (numberOfIterations != 0) {
163 
164  if (fabs(precessor.chi2 - successor.chi2) < EPSILON*fabs(precessor.chi2)) {
165  return successor;
166  }
167 
168  if (lambda > LAMBDA_MIN) {
169  lambda /= LAMBDA_DOWN;
170  }
171  }
172 
173  precessor = successor;
174  previous = value;
175 
176  } else {
177 
178  value = previous;
179  lambda *= LAMBDA_UP;
180 
181  if (lambda > LAMBDA_MAX) {
182  return precessor; // no improvement found
183  }
184 
185  reset();
186 
187  __evaluate__(fit, __begin, __end, args...);
188  }
189 
190  DEBUG("Hesse matrix:" << endl);
191  DEBUG(H << endl);
192 
193 
194  // force definite positiveness
195 
196  for (int i = 0; i != N; ++i) {
197 
198  if (H(i,i) < PIVOT) {
199  H(i,i) = PIVOT;
200  }
201 
202  h[i] = 1.0 / sqrt(H(i,i));
203  }
204 
205 
206  // normalisation
207 
208  for (int i = 0; i != N; ++i) {
209  for (int j = 0; j != i; ++j) {
210  H(j,i) *= h[i] * h[j];
211  H(i,j) = H(j,i);
212  }
213  }
214 
215  for (int i = 0; i != N; ++i) {
216  H(i,i) = 1.0 + lambda;
217  }
218 
219 
220  try {
221  H.invert();
222  }
223  catch (const JException& error) {
224  ERROR("JGandalf: " << error.what() << endl);
225  return precessor;
226  }
227 
228 
229  for (int i = 0; i != N; ++i) {
230 
231  DEBUG("u[" << noshowpos << i << "] = " << showpos << FIXED(15,5) << alias(value, parameters[i]));
232 
233  for (int j = 0; j != N; ++j) {
234  alias(value, parameters[i]) -= H(i,j) * alias(successor.gradient, parameters[j]) * h[i] * h[j];
235  }
236 
237  DEBUG(' ' << FIXED(15,5) << alias(value, parameters[i]) << noshowpos << endl);
238 
239  alias(error, parameters[i]) = h[i];
240  }
241  }
242 
243  return precessor;
244  }
245 
246 
247  static int MAXIMUM_ITERATIONS; //!< maximal number of iterations
248  static double EPSILON; //!< maximal distance to minimum
249  static double LAMBDA_MIN; //!< minimal value control parameter
250  static double LAMBDA_MAX; //!< maximal value control parameter
251  static double LAMBDA_UP; //!< multiplication factor control parameter
252  static double LAMBDA_DOWN; //!< multiplication factor control parameter
253  static double PIVOT; //!< minimal value diagonal element of matrix
254 
255  double lambda;
256  JModel_t value;
257  JModel_t error;
261 
262  private:
263  /**
264  * Reset.
265  */
266  void reset()
267  {
268  using namespace std;
269  using namespace JPP;
270 
271  successor.chi2 = 0.0;
273 
274  H.reset();
275  }
276 
277 
278  /**
279  * Recursive method for evaluation of fit.
280  *
281  * \param fit fit function
282  * \param __begin begin of data
283  * \param __end end of data
284  */
285  template<class JFunction_t, class T, class ...Args>
286  inline void __evaluate__(const JFunction_t& fit, T __begin, T __end, Args ...args)
287  {
288  using namespace std;
289 
290  for (T hit = __begin; hit != __end; ++hit) {
291 
292  const result_type& result = fit(value, *hit);
293 
294  successor.chi2 += result.chi2;
295  successor.gradient += result.gradient;
296 
297  for (unsigned int i = 0; i != parameters.size(); ++i) {
298  for (unsigned int j = i; j != parameters.size(); ++j) {
299  H(i,j) += alias(result.gradient, parameters[i]) * alias(result.gradient, parameters[j]);
300  }
301  }
302  }
303 
304  __evaluate__(fit, args...);
305  }
306 
307 
308  /**
309  * Termination method for evaluation of fit.
310  *
311  * \param fit fit function
312  */
313  template<class JFunction_t>
314  inline void __evaluate__(const JFunction_t& fit)
315  {}
316 
317 
318  /**
319  * Read/write access to parameter value by data member.
320  *
321  * \param model model
322  * \param parameter parameter
323  * \return value
324  */
325  template<class T>
326  static inline double alias(const T& model, const typename T::parameter_type parameter)
327  {
328  return model.*parameter;
329  }
330 
331 
332  /**
333  * Read/write access to parameter value by data member.
334  *
335  * \param model model
336  * \param parameter parameter
337  * \return value
338  */
339  template<class T>
340  static inline double& alias(T& model, const typename T::parameter_type parameter)
341  {
342  return model.*parameter;
343  }
344 
345 
346  /**
347  * Read/write access to parameter value by index.
348  *
349  * \param model model
350  * \param index index
351  * \return value
352  */
353  template<class T>
354  static inline double alias(const T& model, const size_t index)
355  {
356  return model[index];
357  }
358 
359 
360  /**
361  * Read/write access to parameter value by index.
362  *
363  * \param model model
364  * \param index index
365  * \return value
366  */
367  template<class T>
368  static inline double& alias(T& model, const size_t index)
369  {
370  return model[index];
371  }
372 
373 
374  /**
375  * Read/write access to parameter value by index.
376  *
377  * \param model model
378  * \param index index
379  * \return value
380  */
381  template<class T>
382  static inline double alias(const T& model, const int index)
383  {
384  return model[index];
385  }
386 
387 
388  /**
389  * Read/write access to parameter value by index.
390  *
391  * \param model model
392  * \param index index
393  * \return value
394  */
395  template<class T>
396  static inline double& alias(T& model, const int index)
397  {
398  return model[index];
399  }
400 
401 
402  result_type successor;
403  JModel_t previous;
404  std::vector<double> h; // normalisation vector
405  };
406 
407 
408  /**
409  * maximal number of iterations.
410  */
411  template<class JModel_t>
413 
414 
415  /**
416  * maximal distance to minimum.
417  */
418  template<class JModel_t>
419  double JGandalf<JModel_t>::EPSILON = 1.0e-3;
420 
421 
422  /**
423  * minimal value control parameter
424  */
425  template<class JModel_t>
426  double JGandalf<JModel_t>::LAMBDA_MIN = 0.01;
427 
428 
429  /**
430  * maximal value control parameter
431  */
432  template<class JModel_t>
433  double JGandalf<JModel_t>::LAMBDA_MAX = 100.0;
434 
435 
436  /**
437  * multiplication factor control parameter
438  */
439  template<class JModel_t>
440  double JGandalf<JModel_t>::LAMBDA_UP = 9.0;
441 
442 
443  /**
444  * multiplication factor control parameter
445  */
446  template<class JModel_t>
447  double JGandalf<JModel_t>::LAMBDA_DOWN = 11.0;
448 
449 
450  /**
451  * minimal value diagonal element of matrix
452  */
453  template<class JModel_t>
454  double JGandalf<JModel_t>::PIVOT = 1.0e-3;
455 }
456 
457 #endif
458 
static int debug
debug level (default is off).
Definition: JMessage.hh:45
double lambda
Definition: JGandalf.hh:255
General exception.
Definition: JException.hh:23
Exceptions.
static double EPSILON
maximal distance to minimum
Definition: JGandalf.hh:248
JModel_t value
Definition: JGandalf.hh:256
static double PIVOT
minimal value diagonal element of matrix
Definition: JGandalf.hh:253
static const JZero zero
Function object to assign zero value.
Definition: JZero.hh:105
JMatrixND & reset()
Set matrix to the null matrix.
Definition: JMatrixND.hh:372
Auxiliary data structure for floating point format specification.
Definition: JPrint.hh:481
std::vector< parameter_type > parameters
Definition: JGandalf.hh:258
void resize(const size_t size)
Resize matrix.
Definition: JMatrixND.hh:359
static double LAMBDA_MIN
minimal value control parameter
Definition: JGandalf.hh:249
static double LAMBDA_DOWN
multiplication factor control parameter
Definition: JGandalf.hh:252
Definition of zero value for any class.
static double alias(const T &model, const size_t index)
Read/write access to parameter value by index.
Definition: JGandalf.hh:354
JModel_t previous
Definition: JGandalf.hh:403
void reset()
Reset.
Definition: JGandalf.hh:266
result_type successor
Definition: JGandalf.hh:402
I/O formatting auxiliaries.
static double & alias(T &model, const size_t index)
Read/write access to parameter value by index.
Definition: JGandalf.hh:368
return result
Definition: JPolint.hh:695
do set_variable OUTPUT_DIRECTORY $WORKDIR T
JModel_t gradient
d(chi2)/d(...)
Definition: JGandalf.hh:104
#define ERROR(A)
Definition: JMessage.hh:66
result_type operator()(const JFunction_t &fit, T __begin, T __end, Args...args)
Multi-dimensional fit of two data sets.
Definition: JGandalf.hh:127
JMATH::JMatrixNS H
Definition: JGandalf.hh:260
N x N symmetric matrix.
Definition: JMatrixNS.hh:27
static double alias(const T &model, const int index)
Read/write access to parameter value by index.
Definition: JGandalf.hh:382
General purpose messaging.
static double alias(const T &model, const typename T::parameter_type parameter)
Read/write access to parameter value by data member.
Definition: JGandalf.hh:326
static double LAMBDA_UP
multiplication factor control parameter
Definition: JGandalf.hh:251
void invert()
Invert matrix according LDU decomposition.
Definition: JMatrixNS.hh:80
Fit method based on the Levenberg-Marquardt method.
Definition: JGandalf.hh:52
void __evaluate__(const JFunction_t &fit, T __begin, T __end, Args...args)
Recursive method for evaluation of fit.
Definition: JGandalf.hh:286
void __evaluate__(const JFunction_t &fit)
Termination method for evaluation of fit.
Definition: JGandalf.hh:314
Data structure for return value of fit function.
Definition: JGandalf.hh:69
result_type(const double chi2, const JModel_t &model)
Constructor.
Definition: JGandalf.hh:85
static double & alias(T &model, const int index)
Read/write access to parameter value by index.
Definition: JGandalf.hh:396
static int MAXIMUM_ITERATIONS
maximal number of iterations
Definition: JGandalf.hh:247
int j
Definition: JPolint.hh:634
int numberOfIterations
Definition: JGandalf.hh:259
static double LAMBDA_MAX
maximal value control parameter
Definition: JGandalf.hh:250
JModel_t error
Definition: JGandalf.hh:257
virtual const char * what() const
Get error message.
Definition: JException.hh:48
size_t parameter_type
Definition: JMath/JModel.hh:35
result_type()
Default constructor.
Definition: JGandalf.hh:73
Auxiliary data structure for floating point format specification.
Definition: JPrint.hh:518
then usage $script[input file[working directory[option]]] nWhere option can be N
Definition: JMuonPostfit.sh:37
static double & alias(T &model, const typename T::parameter_type parameter)
Read/write access to parameter value by data member.
Definition: JGandalf.hh:340
JModel_t::parameter_type parameter_type
Data type of fit parameter.
Definition: JGandalf.hh:63
#define DEBUG(A)
Message macros.
Definition: JMessage.hh:62
Auxiliary class for handling debug parameter within a class.
Definition: JMessage.hh:44
JGandalf()
Default constructor.
Definition: JGandalf.hh:111
std::vector< double > h
Definition: JGandalf.hh:404