Jpp  test_elongated_shower_pde
the software that should make you happy
 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 first template parameter in the function operator should provide for an implementation of the actual fit function.\n
47  * This function should return the data type JGandalf::result_type.\n
48  * This data type comprises the values of the chi2 and the gradient for a given data point.\n
49  * The function operator returns the minimal chi2 and combined gradient of the data points.
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; //!< partial derivatives of chi2
105  };
106 
107 
108  /**
109  * Default constructor.
110  */
112  {}
113 
114 
115  /**
116  * Multi-dimensional fit of multiple data sets.
117  *
118  * The fit function should return the chi2 as well as the partial derivatives
119  * for the current value of the model and a given data point.
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  // note that all model values should be assigned to the start value of the model before use
134  // because the actual list of model parameters can vary from fit to fit
135  // (e.g. if model consists of a container).
136 
137  const size_t N = parameters.size();
138 
139  V.resize(N);
140  h.resize(N);
141 
142  previous.result.chi2 = numeric_limits<double>::max();
143 
144  previous.V.resize(N);
145 
146  current.result.chi2 = numeric_limits<double>::max();
147  current.result.gradient = value;
148  current.result.gradient = zero;
149 
150  current.V.resize(N);
151 
152  error = value;
153  error = zero;
154 
155  lambda = LAMBDA_MIN;
156 
157 
159 
160  DEBUG("step: " << numberOfIterations << endl);
161 
162  reset();
163 
164  update(fit, __begin, __end, args...);
165 
166  DEBUG("lambda: " << FIXED(12,5) << lambda << endl);
167  DEBUG("chi2: " << FIXED(12,5) << current.result.chi2 << endl);
168 
169  if (current.result.chi2 < previous.result.chi2) {
170 
171  if (numberOfIterations != 0) {
172 
173  if (fabs(previous.result.chi2 - current.result.chi2) < EPSILON*fabs(previous.result.chi2)) {
174  return current.result; // normal end
175  }
176 
177  if (lambda > LAMBDA_MIN) {
178  lambda /= LAMBDA_DOWN;
179  }
180 
181  // store current values
182 
183  previous.value = value;
184  previous.error = error;
185  previous.result = current.result;
186 
187  previous.V.swap(V);
188  }
189 
190  } else {
191 
192  value = previous.value; // restore value
193 
194  lambda *= LAMBDA_UP;
195 
196  if (lambda > LAMBDA_MAX) {
197  break;
198  }
199 
200  reset();
201 
202  update(fit, __begin, __end, args...);
203  }
204 
205 
206  V.swap(current.V);
207 
208  DEBUG("Hesse matrix:" << endl << V << endl);
209 
210 
211  // force definite positiveness
212 
213  for (size_t i = 0; i != N; ++i) {
214 
215  if (V(i,i) < PIVOT) {
216  V(i,i) = PIVOT;
217  }
218 
219  h[i] = 1.0 / sqrt(V(i,i));
220  }
221 
222 
223  // normalisation
224 
225  for (size_t row = 0; row != N; ++row) {
226  for (size_t col = 0; col != row; ++col) {
227  V(row,col) *= h[row] * h[col];
228  V(col,row) = V(row,col);
229  }
230  }
231 
232  for (size_t i = 0; i != N; ++i) {
233  V(i,i) = 1.0 + lambda;
234  }
235 
236 
237  // invert Hesse matrix
238 
239  try {
240  V.invert();
241  }
242  catch (const JException& error) {
243 
244  ERROR("JGandalf: " << error.what() << endl << V << endl);
245 
246  break;
247  }
248 
249 
250  // update value and error
251 
252  for (size_t row = 0; row != N; ++row) {
253 
254  DEBUG("u[" << noshowpos << row << "] = " << showpos << FIXED(15,5) << get(value, parameters[row]));
255 
256  for (size_t col = 0; col != N; ++col) {
257 
258  V(row,col) *= h[row] * h[col];
259 
260  get(value, parameters[row]) -= V(row,col) * get(current.result.gradient, parameters[col]);
261  }
262 
263  DEBUG(" -> " << FIXED(15,5) << get(value, parameters[row]) << noshowpos << endl);
264 
265  get(error, parameters[row]) = h[row];
266  }
267  }
268 
269  // abnormal end
270 
271  value = previous.value; // restore value
272  error = previous.error; // restore error
273 
274  V.swap(previous.V); // restore Hesse matrix
275 
276  return previous.result;
277  }
278 
279 
280  static int MAXIMUM_ITERATIONS; //!< maximal number of iterations
281  static double EPSILON; //!< maximal distance to minimum
282  static double LAMBDA_MIN; //!< minimal value control parameter
283  static double LAMBDA_MAX; //!< maximal value control parameter
284  static double LAMBDA_UP; //!< multiplication factor control parameter
285  static double LAMBDA_DOWN; //!< multiplication factor control parameter
286  static double PIVOT; //!< minimal value diagonal element of Hesse matrix
287 
289  int numberOfIterations; //!< number of iterations
290  double lambda; //!< control parameter
291  JModel_t value; //!< value
292  JModel_t error; //!< error
293  JMATH::JMatrixNS V; //!< Hesse matrix
294 
295  private:
296  /**
297  * Reset current parameters.
298  */
299  void reset()
300  {
301  using namespace JPP;
302 
303  current.result.chi2 = 0.0;
304  current.result.gradient = zero;
305 
306  current.V.reset();
307  }
308 
309 
310  /**
311  * Recursive method to update current parameters.
312  *
313  * \param fit fit function
314  * \param __begin begin of data
315  * \param __end end of data
316  * \param args optional data
317  */
318  template<class JFunction_t, class T, class ...Args>
319  inline void update(const JFunction_t& fit, T __begin, T __end, Args ...args)
320  {
321  for (T i = __begin; i != __end; ++i) {
322 
323  const result_type& result = fit(value, *i);
324 
325  current.result.chi2 += result.chi2;
326  current.result.gradient += result.gradient;
327 
328  for (size_t row = 0; row != parameters.size(); ++row) {
329  for (size_t col = row; col != parameters.size(); ++col) {
330  current.V(row,col) += get(result.gradient, parameters[row]) * get(result.gradient, parameters[col]);
331  }
332  }
333  }
334 
335  update(fit, args...);
336  }
337 
338 
339  /**
340  * Termination method to update current parameters.
341  *
342  * \param fit fit function
343  */
344  template<class JFunction_t>
345  inline void update(const JFunction_t& fit)
346  {
347  for (size_t row = 0; row != parameters.size(); ++row) {
348  for (size_t col = 0; col != row; ++col) {
349  current.V(row,col) = current.V(col,row);
350  }
351  }
352  }
353 
354 
355  /**
356  * Read/write access to parameter value by data member.
357  *
358  * \param model model
359  * \param parameter parameter
360  * \return value
361  */
362  static inline double get(const JModel_t& model, double JModel_t::*parameter)
363  {
364  return model.*parameter;
365  }
366 
367 
368  /**
369  * Read/write access to parameter value by data member.
370  *
371  * \param model model
372  * \param parameter parameter
373  * \return value
374  */
375  static inline double& get(JModel_t& model, double JModel_t::*parameter)
376  {
377  return model.*parameter;
378  }
379 
380 
381  /**
382  * Read/write access to parameter value by index.
383  *
384  * \param model model
385  * \param index index
386  * \return value
387  */
388  static inline double get(const JModel_t& model, const size_t index)
389  {
390  return model[index];
391  }
392 
393 
394  /**
395  * Read/write access to parameter value by index.
396  *
397  * \param model model
398  * \param index index
399  * \return value
400  */
401  static inline double& get(JModel_t& model, const size_t index)
402  {
403  return model[index];
404  }
405 
406 
407  /**
408  * Read/write access to parameter value by index.
409  *
410  * \param model model
411  * \param index index
412  * \return value
413  */
414  static inline double get(const JModel_t& model, const int index)
415  {
416  return model[index];
417  }
418 
419 
420  /**
421  * Read/write access to parameter value by index.
422  *
423  * \param model model
424  * \param index index
425  * \return value
426  */
427  static inline double& get(JModel_t& model, const int index)
428  {
429  return model[index];
430  }
431 
432  std::vector<double> h; // normalisation vector
433 
434  struct {
435  result_type result; // result
436  JMATH::JMatrixNS V; // Hesse matrix
437  } current;
438 
439  struct {
440  JModel_t value; // value
441  JModel_t error; // error
442  result_type result; // result
443  JMATH::JMatrixNS V; // Hesse matrix
444  } previous;
445  };
446 
447 
448  /**
449  * maximal number of iterations.
450  */
451  template<class JModel_t>
453 
454 
455  /**
456  * maximal distance to minimum.
457  */
458  template<class JModel_t>
459  double JGandalf<JModel_t>::EPSILON = 1.0e-3;
460 
461 
462  /**
463  * minimal value control parameter
464  */
465  template<class JModel_t>
466  double JGandalf<JModel_t>::LAMBDA_MIN = 0.01;
467 
468 
469  /**
470  * maximal value control parameter
471  */
472  template<class JModel_t>
473  double JGandalf<JModel_t>::LAMBDA_MAX = 100.0;
474 
475 
476  /**
477  * multiplication factor control parameter
478  */
479  template<class JModel_t>
480  double JGandalf<JModel_t>::LAMBDA_UP = 9.0;
481 
482 
483  /**
484  * multiplication factor control parameter
485  */
486  template<class JModel_t>
487  double JGandalf<JModel_t>::LAMBDA_DOWN = 11.0;
488 
489 
490  /**
491  * minimal value diagonal element of matrix
492  */
493  template<class JModel_t>
494  double JGandalf<JModel_t>::PIVOT = 1.0e-3;
495 }
496 
497 #endif
498 
static int debug
debug level (default is off).
Definition: JMessage.hh:45
double lambda
control parameter
Definition: JGandalf.hh:290
General exception.
Definition: JException.hh:23
Exceptions.
static double EPSILON
maximal distance to minimum
Definition: JGandalf.hh:281
JModel_t value
value
Definition: JGandalf.hh:291
static double PIVOT
minimal value diagonal element of Hesse matrix
Definition: JGandalf.hh:286
JMATH::JMatrixNS V
Hesse matrix.
Definition: JGandalf.hh:293
then JShowerPostfit f $INPUT_FILE o $OUTPUT_FILE N
static const JZero zero
Function object to assign zero value.
Definition: JZero.hh:105
Auxiliary data structure for floating point format specification.
Definition: JManip.hh:446
std::vector< parameter_type > parameters
fit parameters
Definition: JGandalf.hh:288
void resize(const size_t size)
Resize matrix.
Definition: JMatrixND.hh:410
static double LAMBDA_MIN
minimal value control parameter
Definition: JGandalf.hh:282
static double LAMBDA_DOWN
multiplication factor control parameter
Definition: JGandalf.hh:285
Definition of zero value for any class.
void reset()
Reset current parameters.
Definition: JGandalf.hh:299
struct JFIT::JGandalf::@13 previous
void update(const JFunction_t &fit)
Termination method to update current parameters.
Definition: JGandalf.hh:345
do set_variable OUTPUT_DIRECTORY $WORKDIR T
JModel_t gradient
partial derivatives of chi2
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 multiple data sets.
Definition: JGandalf.hh:128
void update(const JFunction_t &fit, T __begin, T __end, Args...args)
Recursive method to update current parameters.
Definition: JGandalf.hh:319
N x N symmetric matrix.
Definition: JMatrixNS.hh:27
result_type result
Definition: JGandalf.hh:435
General purpose messaging.
I/O manipulators.
static double LAMBDA_UP
multiplication factor control parameter
Definition: JGandalf.hh:284
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
Data structure for return value of fit function.
Definition: JGandalf.hh:69
then usage $script< input_file >< detector_file > fi set_variable OUTPUT_DIR set_variable SELECTOR JDAQTimesliceL1 set_variable DEBUG case set_variable DEBUG
result_type(const double chi2, const JModel_t &model)
Constructor.
Definition: JGandalf.hh:85
void swap(JMatrixND_t &A)
Swap matrices.
Definition: JMatrixND.hh:147
static int MAXIMUM_ITERATIONS
maximal number of iterations
Definition: JGandalf.hh:280
int numberOfIterations
number of iterations
Definition: JGandalf.hh:289
static double LAMBDA_MAX
maximal value control parameter
Definition: JGandalf.hh:283
JModel_t error
error
Definition: JGandalf.hh:292
struct JFIT::JGandalf::@12 current
size_t parameter_type
Definition: JMath/JModel.hh:35
result_type()
Default constructor.
Definition: JGandalf.hh:73
JModel_t::parameter_type parameter_type
Data type of fit parameter.
Definition: JGandalf.hh:63
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:432