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 "JLang/JException.hh"
14 
15 
16 /**
17  * \author mdejong
18  */
19 
20 namespace JFIT {}
21 namespace JPP { using namespace JFIT; }
22 
23 namespace JFIT {
24 
25  using JEEP::JMessage;
26  using JLANG::JException;
27 
28 
29  /**
30  * Fit method based on the Levenberg-Marquardt method.
31  *
32  * The template argument refers to the model that should be fitted to the data.
33  * This data structure should have arithmetic capabalities.
34  *
35  * The data member JGandalf::value corresponds to the start or final value of
36  * the model of the fit procedure and JGandalf::error to the uncertainties.
37  * The co-variance matrix is stored in data member JGandalf::H.
38  * The data member JGandalf::parameters is a list of pointers to those
39  * data members of the model that should be fitted.
40  * The template fit function should return the data type JGandalf::result_type
41  * which is composed of the values of the chi2 and gradient of a data point, respectively.
42  * The function operator returns the chi2 of the fit.
43  */
44  template<class JModel_t>
45  class JGandalf :
46  public JMessage< JGandalf<JModel_t> >
47  {
48  public:
49 
51 
52 
53  /**
54  * Data type of fit parameter.
55  */
56  typedef typename JModel_t::parameter_type parameter_type;
57 
58 
59  /**
60  * Data structure for return value of fit function.
61  */
62  struct result_type {
63  /**
64  * Default constructor.
65  */
67  chi2(0.0),
68  gradient()
69  {}
70 
71 
72  /**
73  * Constructor.
74  *
75  * \param __chi2 chi2
76  * \param __model gradient
77  */
78  result_type(const double __chi2,
79  const JModel_t __model) :
80  chi2(__chi2),
81  gradient(__model)
82  {}
83 
84 
85  /**
86  * Type conversion operator.
87  *
88  * \return chi2
89  */
90  operator double() const
91  {
92  return chi2;
93  }
94 
95 
96  double chi2; //!< chi2 of data point
97  JModel_t gradient; //!< d(chi2)/d(...)
98  };
99 
100 
101  /**
102  * Default constructor.
103  */
105  {}
106 
107 
108  /**
109  * Multi-dimensional fit of two data sets.
110  *
111  * The fit function should return the equivalent of chi2 for the current value
112  * of the model and the given data point as well as the partial derivatives.
113  *
114  * \param fit fit function
115  * \param __begin1 begin of first data set
116  * \param __end1 end of first data set
117  * \param __begin2 begin of second data set
118  * \param __end2 end of second data set
119  * \return chi2
120  */
121  template<class JFunction_t, class T1, class T2>
122  double operator()(const JFunction_t& fit,
123  T1 __begin1, T1 __end1,
124  T2 __begin2, T2 __end2)
125  {
126  using namespace std;
127 
128  const int N = parameters.size();
129 
130  H.resize(N);
131  h.resize(N);
132 
133  previous = value;
134  error = JModel_t();
135  lambda = LAMBDA_MIN;
136 
137  double chi2_old = numeric_limits<double>::max();
138 
140 
141  DEBUG("step: " << numberOfIterations << endl);
142 
143  reset();
144 
145  evaluate(fit, __begin1, __end1);
146  evaluate(fit, __begin2, __end2);
147 
148  DEBUG("lambda: " << SCIENTIFIC(12,5) << lambda << endl);
149  DEBUG("chi2: " << FIXED (12,5) << chi2 << endl);
150 
151  if (chi2 < chi2_old) {
152 
153  if (numberOfIterations != 0) {
154 
155  if (fabs(chi2_old - chi2) < EPSILON*fabs(chi2_old)) {
156  return chi2;
157  }
158 
159  lambda /= LAMBDA_DOWN;
160  }
161 
162  chi2_old = chi2;
163  previous = value;
164 
165  } else {
166 
167  value = previous;
168  lambda *= LAMBDA_UP;
169 
170  if (lambda > LAMBDA_MAX) {
171  return chi2_old; // no improvement found
172  }
173 
174  reset();
175 
176  evaluate(fit, __begin1, __end1);
177  evaluate(fit, __begin2, __end2);
178  }
179 
180  DEBUG("Hesse matrix:" << endl);
181  DEBUG(H << endl);
182 
183 
184  // force definite positiveness
185 
186  for (int i = 0; i != N; ++i) {
187 
188  if (H(i,i) < PIVOT) {
189  H(i,i) = PIVOT;
190  }
191 
192  h[i] = 1.0 / sqrt(H(i,i));
193  }
194 
195 
196  // normalisation
197 
198  for (int i = 0; i != N; ++i) {
199  for (int j = 0; j != i; ++j) {
200  H(j,i) *= h[i] * h[j];
201  H(i,j) = H(j,i);
202  }
203  }
204 
205  for (int i = 0; i != N; ++i) {
206  H(i,i) = 1.0 + lambda;
207  }
208 
209 
210  try {
211  H.invert();
212  }
213  catch (const JException& error) {
214  ERROR("JGandalf: " << error.what() << endl);
215  return chi2_old;
216  }
217 
218 
219  for (int i = 0; i != N; ++i) {
220 
221  DEBUG("u[" << noshowpos << i << "] = " << showpos << FIXED(15,5) << value.*parameters[i]);
222 
223  for (int j = 0; j != N; ++j) {
224  value.*parameters[i] -= H(i,j) * gradient.*parameters[j] * h[i] * h[j];
225  }
226 
227  DEBUG(' ' << FIXED(15,5) << value.*parameters[i] << noshowpos << endl);
228 
229  error.*parameters[i] = h[i];
230  }
231  }
232 
233  return chi2_old;
234  }
235 
236 
237  /**
238  * Multi-dimensional fit of one data set.
239  *
240  * The fit function should return the equivalent of chi2 for the current value
241  * of the model and the given data point as well as the partial derivatives.
242  *
243  * \param fit fit function
244  * \param __begin begin of data
245  * \param __end end of data
246  * \return chi2
247  */
248  template<class JFunction_t, class T>
249  double operator()(const JFunction_t& fit, T __begin, T __end)
250  {
251  return (*this)(fit, __begin, __end, __end, __end);
252  }
253 
254 
255  static int MAXIMUM_ITERATIONS; //!< maximal number of iterations
256  static double EPSILON; //!< maximal distance to minimum
257  static double LAMBDA_MIN; //!< minimal value control parameter
258  static double LAMBDA_MAX; //!< maximal value control parameter
259  static double LAMBDA_UP; //!< multiplication factor control parameter
260  static double LAMBDA_DOWN; //!< multiplication factor control parameter
261  static double PIVOT; //!< minimal value diagonal element of matrix
262 
263 
264  double lambda;
265  JModel_t value;
266  JModel_t error;
270 
271  private:
272  /**
273  * Reset.
274  */
275  void reset()
276  {
277  chi2 = 0.0;
278  gradient = JModel_t();
279 
280  H.reset();
281  }
282 
283 
284  /**
285  * Evaluate fit for given data set.
286  *
287  * \param fit fit function
288  * \param __begin begin of data
289  * \param __end end of data
290  */
291  template<class JFunction_t, class T>
292  inline void evaluate(const JFunction_t& fit, T __begin, T __end)
293  {
294  for (T hit = __begin; hit != __end; ++hit) {
295 
296  const result_type& result = fit(value, *hit);
297 
298  chi2 += result.chi2;
299  gradient += result.gradient;
300 
301  for (unsigned int i = 0; i != parameters.size(); ++i) {
302  for (unsigned int j = i; j != parameters.size(); ++j) {
303  H(i,j) += result.gradient.*parameters[i] * result.gradient.*parameters[j];
304  }
305  }
306  }
307  }
308 
309  double chi2;
310  JModel_t gradient;
311  JModel_t previous;
312  std::vector<double> h; // normalisation vector
313  };
314 
315 
316  /**
317  * maximal number of iterations.
318  */
319  template<class JModel_t>
321 
322 
323  /**
324  * maximal distance to minimum.
325  */
326  template<class JModel_t>
327  double JGandalf<JModel_t>::EPSILON = 1.0e-4;
328 
329 
330  /**
331  * minimal value control parameter
332  */
333  template<class JModel_t>
334  double JGandalf<JModel_t>::LAMBDA_MIN = 0.01;
335 
336 
337  /**
338  * maximal value control parameter
339  */
340  template<class JModel_t>
341  double JGandalf<JModel_t>::LAMBDA_MAX = 100.0;
342 
343 
344  /**
345  * multiplication factor control parameter
346  */
347  template<class JModel_t>
348  double JGandalf<JModel_t>::LAMBDA_UP = 9.0;
349 
350 
351  /**
352  * multiplication factor control parameter
353  */
354  template<class JModel_t>
355  double JGandalf<JModel_t>::LAMBDA_DOWN = 11.0;
356 
357 
358  /**
359  * minimal value diagonal element of matrix
360  */
361  template<class JModel_t>
362  double JGandalf<JModel_t>::PIVOT = 1.0e-3;
363 }
364 
365 #endif
366 
static int debug
debug level (default is off).
Definition: JMessage.hh:43
double lambda
Definition: JGandalf.hh:264
General exception.
Definition: JException.hh:40
Exceptions.
static double EPSILON
maximal distance to minimum
Definition: JGandalf.hh:256
JModel_t value
Definition: JGandalf.hh:265
static double PIVOT
minimal value diagonal element of matrix
Definition: JGandalf.hh:261
N x N symmetric matrix.
Definition: JMatrixNS.hh:26
Auxiliary data structure for floating point format specification.
Definition: JPrint.hh:461
std::vector< parameter_type > parameters
Definition: JGandalf.hh:267
static double LAMBDA_MIN
minimal value control parameter
Definition: JGandalf.hh:257
static double LAMBDA_DOWN
multiplication factor control parameter
Definition: JGandalf.hh:260
JModel_t previous
Definition: JGandalf.hh:311
void resize(const size_t size)
Resize matrix.
Definition: JMatrixND.hh:98
void reset()
Reset.
Definition: JGandalf.hh:275
double operator()(const JFunction_t &fit, T __begin, T __end)
Multi-dimensional fit of one data set.
Definition: JGandalf.hh:249
I/O formatting auxiliaries.
JMatrixND & reset()
Set matrix to the null matrix.
Definition: JMatrixND.hh:170
void evaluate(const JFunction_t &fit, T __begin, T __end)
Evaluate fit for given data set.
Definition: JGandalf.hh:292
JModel_t gradient
d(chi2)/d(...)
Definition: JGandalf.hh:97
#define ERROR(A)
Definition: JMessage.hh:64
double chi2
chi2 of data point
Definition: JGandalf.hh:96
JMATH::JMatrixNS H
Definition: JGandalf.hh:269
General purpose messaging.
static double LAMBDA_UP
multiplication factor control parameter
Definition: JGandalf.hh:259
Fit method based on the Levenberg-Marquardt method.
Definition: JGandalf.hh:45
JModel_t gradient
Definition: JGandalf.hh:310
Data structure for return value of fit function.
Definition: JGandalf.hh:62
double operator()(const JFunction_t &fit, T1 __begin1, T1 __end1, T2 __begin2, T2 __end2)
Multi-dimensional fit of two data sets.
Definition: JGandalf.hh:122
result_type(const double __chi2, const JModel_t __model)
Constructor.
Definition: JGandalf.hh:78
static int MAXIMUM_ITERATIONS
maximal number of iterations
Definition: JGandalf.hh:255
int numberOfIterations
Definition: JGandalf.hh:268
static double LAMBDA_MAX
maximal value control parameter
Definition: JGandalf.hh:258
JModel_t error
Definition: JGandalf.hh:266
virtual const char * what() const
Get error message.
Definition: JException.hh:65
result_type()
Default constructor.
Definition: JGandalf.hh:66
Auxiliary data structure for floating point format specification.
Definition: JPrint.hh:498
void invert()
Invert matrix.
Definition: JMatrixNS.hh:61
JModel_t::parameter_type parameter_type
Data type of fit parameter.
Definition: JGandalf.hh:56
#define DEBUG(A)
Message macros.
Definition: JMessage.hh:60
Auxiliary class for handling debug parameter within a class.
Definition: JMessage.hh:42
JGandalf()
Default constructor.
Definition: JGandalf.hh:104
std::vector< double > h
Definition: JGandalf.hh:312