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/JMessage.hh"
11 #include "JMath/JMatrixNS.hh"
12 #include "JMath/JZero.hh"
13 #include "JLang/JManip.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::V.\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  * \param args optional data
125  * \return chi2
126  */
127  template<class JFunction_t, class T, class ...Args>
128  result_type operator()(const JFunction_t& fit, T __begin, T __end, Args ...args)
129  {
130  using namespace std;
131  using namespace JPP;
132 
133  const int N = parameters.size();
134 
135  V.resize(N);
136  h.resize(N);
137 
138  previous = value;
139 
142 
143  error = value;
144  error = zero;
145 
146  lambda = LAMBDA_MIN;
147 
148  result_type precessor = result_type(numeric_limits<double>::max(), value);
149 
151 
152  DEBUG("step: " << numberOfIterations << endl);
153 
154  reset();
155 
156  __evaluate__(fit, __begin, __end, args...);
157 
158  DEBUG("lambda: " << FIXED(12,5) << lambda << endl);
159  DEBUG("chi2: " << FIXED(12,5) << successor.chi2 << endl);
160 
161  if (successor.chi2 < precessor.chi2) {
162 
163  if (numberOfIterations != 0) {
164 
165  if (fabs(precessor.chi2 - successor.chi2) < EPSILON*fabs(precessor.chi2)) {
166  return successor;
167  }
168 
169  if (lambda > LAMBDA_MIN) {
170  lambda /= LAMBDA_DOWN;
171  }
172  }
173 
174  precessor = successor;
175  previous = value;
176 
177  } else {
178 
179  value = previous;
180  lambda *= LAMBDA_UP;
181 
182  if (lambda > LAMBDA_MAX) {
183  return precessor; // no improvement found
184  }
185 
186  reset();
187 
188  __evaluate__(fit, __begin, __end, args...);
189  }
190 
191  DEBUG("Hesse matrix:" << endl);
192  DEBUG(V << endl);
193 
194 
195  // force definite positiveness
196 
197  for (int i = 0; i != N; ++i) {
198 
199  if (V(i,i) < PIVOT) {
200  V(i,i) = PIVOT;
201  }
202 
203  h[i] = 1.0 / sqrt(V(i,i));
204  }
205 
206 
207  // normalisation
208 
209  for (int i = 0; i != N; ++i) {
210  for (int j = 0; j != i; ++j) {
211  V(j,i) *= h[i] * h[j];
212  V(i,j) = V(j,i);
213  }
214  }
215 
216  for (int i = 0; i != N; ++i) {
217  V(i,i) = 1.0 + lambda;
218  }
219 
220 
221  try {
222  V.invert();
223  }
224  catch (const JException& error) {
225  ERROR("JGandalf: " << error.what() << endl);
226  return precessor;
227  }
228 
229 
230  for (int i = 0; i != N; ++i) {
231 
232  DEBUG("u[" << noshowpos << i << "] = " << showpos << FIXED(15,5) << alias(value, parameters[i]));
233 
234  for (int j = 0; j != N; ++j) {
235  alias(value, parameters[i]) -= V(i,j) * alias(successor.gradient, parameters[j]) * h[i] * h[j];
236  }
237 
238  DEBUG(' ' << FIXED(15,5) << alias(value, parameters[i]) << noshowpos << endl);
239 
240  alias(error, parameters[i]) = h[i];
241  }
242  }
243 
244  return precessor;
245  }
246 
247 
248  static int MAXIMUM_ITERATIONS; //!< maximal number of iterations
249  static double EPSILON; //!< maximal distance to minimum
250  static double LAMBDA_MIN; //!< minimal value control parameter
251  static double LAMBDA_MAX; //!< maximal value control parameter
252  static double LAMBDA_UP; //!< multiplication factor control parameter
253  static double LAMBDA_DOWN; //!< multiplication factor control parameter
254  static double PIVOT; //!< minimal value diagonal element of matrix
255 
256  double lambda;
257  JModel_t value;
258  JModel_t error;
262 
263  private:
264  /**
265  * Reset.
266  */
267  void reset()
268  {
269  using namespace std;
270  using namespace JPP;
271 
272  successor.chi2 = 0.0;
274 
275  V.reset();
276  }
277 
278 
279  /**
280  * Recursive method for evaluation of fit.
281  *
282  * \param fit fit function
283  * \param __begin begin of data
284  * \param __end end of data
285  * \param args optional data
286  */
287  template<class JFunction_t, class T, class ...Args>
288  inline void __evaluate__(const JFunction_t& fit, T __begin, T __end, Args ...args)
289  {
290  using namespace std;
291 
292  for (T hit = __begin; hit != __end; ++hit) {
293 
294  const result_type& result = fit(value, *hit);
295 
296  successor.chi2 += result.chi2;
297  successor.gradient += result.gradient;
298 
299  for (unsigned int i = 0; i != parameters.size(); ++i) {
300  for (unsigned int j = i; j != parameters.size(); ++j) {
301  V(i,j) += alias(result.gradient, parameters[i]) * alias(result.gradient, parameters[j]);
302  }
303  }
304  }
305 
306  __evaluate__(fit, args...);
307  }
308 
309 
310  /**
311  * Termination method for evaluation of fit.
312  *
313  * \param fit fit function
314  */
315  template<class JFunction_t>
316  inline void __evaluate__(const JFunction_t& fit)
317  {}
318 
319 
320  /**
321  * Read/write access to parameter value by data member.
322  *
323  * \param model model
324  * \param parameter parameter
325  * \return value
326  */
327  static inline double alias(const JModel_t& model, double JModel_t::*parameter)
328  {
329  return model.*parameter;
330  }
331 
332 
333  /**
334  * Read/write access to parameter value by data member.
335  *
336  * \param model model
337  * \param parameter parameter
338  * \return value
339  */
340  static inline double& alias(JModel_t& model, double JModel_t::*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  static inline double alias(const JModel_t& model, const size_t index)
354  {
355  return model[index];
356  }
357 
358 
359  /**
360  * Read/write access to parameter value by index.
361  *
362  * \param model model
363  * \param index index
364  * \return value
365  */
366  static inline double& alias(JModel_t& model, const size_t index)
367  {
368  return model[index];
369  }
370 
371 
372  /**
373  * Read/write access to parameter value by index.
374  *
375  * \param model model
376  * \param index index
377  * \return value
378  */
379  static inline double alias(const JModel_t& model, const int index)
380  {
381  return model[index];
382  }
383 
384 
385  /**
386  * Read/write access to parameter value by index.
387  *
388  * \param model model
389  * \param index index
390  * \return value
391  */
392  static inline double& alias(JModel_t& model, const int index)
393  {
394  return model[index];
395  }
396 
397 
398  result_type successor;
399  JModel_t previous;
400  std::vector<double> h; // normalisation vector
401  };
402 
403 
404  /**
405  * maximal number of iterations.
406  */
407  template<class JModel_t>
409 
410 
411  /**
412  * maximal distance to minimum.
413  */
414  template<class JModel_t>
415  double JGandalf<JModel_t>::EPSILON = 1.0e-3;
416 
417 
418  /**
419  * minimal value control parameter
420  */
421  template<class JModel_t>
422  double JGandalf<JModel_t>::LAMBDA_MIN = 0.01;
423 
424 
425  /**
426  * maximal value control parameter
427  */
428  template<class JModel_t>
429  double JGandalf<JModel_t>::LAMBDA_MAX = 100.0;
430 
431 
432  /**
433  * multiplication factor control parameter
434  */
435  template<class JModel_t>
436  double JGandalf<JModel_t>::LAMBDA_UP = 9.0;
437 
438 
439  /**
440  * multiplication factor control parameter
441  */
442  template<class JModel_t>
443  double JGandalf<JModel_t>::LAMBDA_DOWN = 11.0;
444 
445 
446  /**
447  * minimal value diagonal element of matrix
448  */
449  template<class JModel_t>
450  double JGandalf<JModel_t>::PIVOT = 1.0e-3;
451 }
452 
453 #endif
454 
static int debug
debug level (default is off).
Definition: JMessage.hh:45
double lambda
Definition: JGandalf.hh:256
General exception.
Definition: JException.hh:23
Exceptions.
static double EPSILON
maximal distance to minimum
Definition: JGandalf.hh:249
static double alias(const JModel_t &model, const size_t index)
Read/write access to parameter value by index.
Definition: JGandalf.hh:353
JModel_t value
Definition: JGandalf.hh:257
static double PIVOT
minimal value diagonal element of matrix
Definition: JGandalf.hh:254
static double alias(const JModel_t &model, double JModel_t::*parameter)
Read/write access to parameter value by data member.
Definition: JGandalf.hh:327
JMATH::JMatrixNS V
Definition: JGandalf.hh:261
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:375
Auxiliary data structure for floating point format specification.
Definition: JManip.hh:445
std::vector< parameter_type > parameters
Definition: JGandalf.hh:259
void resize(const size_t size)
Resize matrix.
Definition: JMatrixND.hh:362
static double LAMBDA_MIN
minimal value control parameter
Definition: JGandalf.hh:250
static double LAMBDA_DOWN
multiplication factor control parameter
Definition: JGandalf.hh:253
Definition of zero value for any class.
JModel_t previous
Definition: JGandalf.hh:399
void reset()
Reset.
Definition: JGandalf.hh:267
result_type successor
Definition: JGandalf.hh:398
return result
Definition: JPolint.hh:727
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:128
N x N symmetric matrix.
Definition: JMatrixNS.hh:27
static double alias(const JModel_t &model, const int index)
Read/write access to parameter value by index.
Definition: JGandalf.hh:379
General purpose messaging.
I/O manipulators.
static double LAMBDA_UP
multiplication factor control parameter
Definition: JGandalf.hh:252
void invert()
Invert matrix according LDU decomposition.
Definition: JMatrixNS.hh:80
Fit method based on the Levenberg-Marquardt method.
Definition: JGandalf.hh:52
virtual const char * what() const override
Get error message.
Definition: JException.hh:48
void __evaluate__(const JFunction_t &fit, T __begin, T __end, Args...args)
Recursive method for evaluation of fit.
Definition: JGandalf.hh:288
void __evaluate__(const JFunction_t &fit)
Termination method for evaluation of fit.
Definition: JGandalf.hh:316
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 int MAXIMUM_ITERATIONS
maximal number of iterations
Definition: JGandalf.hh:248
int j
Definition: JPolint.hh:666
int numberOfIterations
Definition: JGandalf.hh:260
static double LAMBDA_MAX
maximal value control parameter
Definition: JGandalf.hh:251
JModel_t error
Definition: JGandalf.hh:258
size_t parameter_type
Definition: JMath/JModel.hh:35
result_type()
Default constructor.
Definition: JGandalf.hh:73
then usage $script[input file[working directory[option]]] nWhere option can be N
Definition: JMuonPostfit.sh:37
static double & alias(JModel_t &model, double JModel_t::*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
static double & alias(JModel_t &model, const int index)
Read/write access to parameter value by index.
Definition: JGandalf.hh:392
JGandalf()
Default constructor.
Definition: JGandalf.hh:111
std::vector< double > h
Definition: JGandalf.hh:400
static double & alias(JModel_t &model, const size_t index)
Read/write access to parameter value by index.
Definition: JGandalf.hh:366