Jpp
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
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  result_type 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  result_type precursor = result_type(numeric_limits<double>::max(), JModel_t());
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) << successor.chi2 << endl);
150 
151  if (successor.chi2 < precursor.chi2) {
152 
153  if (numberOfIterations != 0) {
154 
155  if (fabs(precursor.chi2 - successor.chi2) < EPSILON*fabs(precursor.chi2)) {
156  return successor;
157  }
158 
159  if (lambda > LAMBDA_MIN) {
160  lambda /= LAMBDA_DOWN;
161  }
162  }
163 
164  precursor = successor;
165  previous = value;
166 
167  } else {
168 
169  value = previous;
170  lambda *= LAMBDA_UP;
171 
172  if (lambda > LAMBDA_MAX) {
173  return precursor; // no improvement found
174  }
175 
176  reset();
177 
178  evaluate(fit, __begin1, __end1);
179  evaluate(fit, __begin2, __end2);
180  }
181 
182  DEBUG("Hesse matrix:" << endl);
183  DEBUG(H << endl);
184 
185 
186  // force definite positiveness
187 
188  for (int i = 0; i != N; ++i) {
189 
190  if (H(i,i) < PIVOT) {
191  H(i,i) = PIVOT;
192  }
193 
194  h[i] = 1.0 / sqrt(H(i,i));
195  }
196 
197 
198  // normalisation
199 
200  for (int i = 0; i != N; ++i) {
201  for (int j = 0; j != i; ++j) {
202  H(j,i) *= h[i] * h[j];
203  H(i,j) = H(j,i);
204  }
205  }
206 
207  for (int i = 0; i != N; ++i) {
208  H(i,i) = 1.0 + lambda;
209  }
210 
211 
212  try {
213  H.invert();
214  }
215  catch (const JException& error) {
216  ERROR("JGandalf: " << error.what() << endl);
217  return precursor;
218  }
219 
220 
221  for (int i = 0; i != N; ++i) {
222  DEBUG("u[" << noshowpos << i << "] = " << showpos << FIXED(15,5) << value.*parameters[i]);
223 
224  for (int j = 0; j != N; ++j) {
225  value.*parameters[i] -= H(i,j) * successor.gradient.*parameters[j] * h[i] * h[j];
226  }
227 
228  DEBUG(' ' << FIXED(15,5) << value.*parameters[i] << noshowpos << endl);
229 
230  error.*parameters[i] = h[i];
231  }
232 
233  }
234 
235  return precursor;
236  }
237 
238 
239  /**
240  * Multi-dimensional fit of one data set.
241  *
242  * The fit function should return the equivalent of chi2 for the current value
243  * of the model and the given data point as well as the partial derivatives.
244  *
245  * \param fit fit function
246  * \param __begin begin of data
247  * \param __end end of data
248  * \return chi2
249  */
250  template<class JFunction_t, class T>
251  result_type operator()(const JFunction_t& fit, T __begin, T __end)
252  {
253  return (*this)(fit, __begin, __end, __end, __end);
254  }
255 
256 
257  static int MAXIMUM_ITERATIONS; //!< maximal number of iterations
258  static double EPSILON; //!< maximal distance to minimum
259  static double LAMBDA_MIN; //!< minimal value control parameter
260  static double LAMBDA_MAX; //!< maximal value control parameter
261  static double LAMBDA_UP; //!< multiplication factor control parameter
262  static double LAMBDA_DOWN; //!< multiplication factor control parameter
263  static double PIVOT; //!< minimal value diagonal element of matrix
264 
265  double lambda;
266  JModel_t value;
267  JModel_t error;
271 
272  private:
273  /**
274  * Reset.
275  */
276  void reset()
277  {
278  successor = result_type();
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  successor.chi2 += result.chi2;
299  successor.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  result_type successor;
310  JModel_t previous;
311  std::vector<double> h; // normalisation vector
312 
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-3;
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 
JFIT::JGandalf::LAMBDA_MAX
static double LAMBDA_MAX
maximal value control parameter
Definition: JGandalf.hh:260
JException.hh
JFIT::JGandalf::operator()
result_type operator()(const JFunction_t &fit, T1 __begin1, T1 __end1, T2 __begin2, T2 __end2)
Multi-dimensional fit of two data sets.
Definition: JGandalf.hh:122
FIXED
Auxiliary data structure for floating point format specification.
Definition: JPrint.hh:481
JFIT
Auxiliary classes and methods for linear and iterative data regression.
Definition: JEnergy.hh:15
JFIT::JGandalf::numberOfIterations
int numberOfIterations
Definition: JGandalf.hh:269
JFIT::JGandalf::LAMBDA_DOWN
static double LAMBDA_DOWN
multiplication factor control parameter
Definition: JGandalf.hh:262
JFIT::JGandalf::reset
void reset()
Reset.
Definition: JGandalf.hh:276
JMessage.hh
JFIT::JGandalf::evaluate
void evaluate(const JFunction_t &fit, T __begin, T __end)
Evaluate fit for given data set.
Definition: JGandalf.hh:292
JPrint.hh
JFIT::JGandalf::MAXIMUM_ITERATIONS
static int MAXIMUM_ITERATIONS
maximal number of iterations
Definition: JGandalf.hh:257
JFIT::JGandalf::EPSILON
static double EPSILON
maximal distance to minimum
Definition: JGandalf.hh:258
JFIT::JGandalf::result_type::result_type
result_type()
Default constructor.
Definition: JGandalf.hh:66
JFIT::JGandalf
Fit method based on the Levenberg-Marquardt method.
Definition: JGandalf.hh:45
JFIT::JGandalf::h
std::vector< double > h
Definition: JGandalf.hh:311
std::vector< parameter_type >
JFIT::JGandalf::result_type::result_type
result_type(const double chi2, const JModel_t model)
Constructor.
Definition: JGandalf.hh:78
JTOOLS::j
int j
Definition: JPolint.hh:634
JFIT::JGandalf::error
JModel_t error
Definition: JGandalf.hh:267
JPP
This name space includes all other name spaces (except KM3NETDAQ, KM3NET and ANTARES).
Definition: JAAnetToolkit.hh:37
JFIT::JGandalf::lambda
double lambda
Definition: JGandalf.hh:265
ERROR
#define ERROR(A)
Definition: JMessage.hh:66
JFIT::JGandalf::PIVOT
static double PIVOT
minimal value diagonal element of matrix
Definition: JGandalf.hh:263
JFIT::JGandalf::LAMBDA_MIN
static double LAMBDA_MIN
minimal value control parameter
Definition: JGandalf.hh:259
JMatrixNS.hh
JTOOLS::result
return result
Definition: JPolint.hh:695
JFIT::JGandalf::parameters
std::vector< parameter_type > parameters
Definition: JGandalf.hh:268
SCIENTIFIC
Auxiliary data structure for floating point format specification.
Definition: JPrint.hh:518
JFIT::JGandalf::operator()
result_type operator()(const JFunction_t &fit, T __begin, T __end)
Multi-dimensional fit of one data set.
Definition: JGandalf.hh:251
JFIT::JGandalf::result_type
Data structure for return value of fit function.
Definition: JGandalf.hh:62
JFIT::JGandalf::value
JModel_t value
Definition: JGandalf.hh:266
JMATH::JMatrixND::reset
JMatrixND & reset()
Set matrix to the null matrix.
Definition: JMatrixND.hh:372
JFIT::JGandalf::result_type::gradient
JModel_t gradient
d(chi2)/d(...)
Definition: JGandalf.hh:97
JMATH::JMatrixNS
N x N symmetric matrix.
Definition: JMatrixNS.hh:27
JFIT::JGandalf::parameter_type
JModel_t::parameter_type parameter_type
Data type of fit parameter.
Definition: JGandalf.hh:56
JMATH::JMatrixNS::invert
void invert()
Invert matrix according LDU decomposition.
Definition: JMatrixNS.hh:80
DEBUG
#define DEBUG(A)
Message macros.
Definition: JMessage.hh:62
std
Definition: jaanetDictionary.h:36
JFIT::JGandalf::result_type::chi2
double chi2
chi2
Definition: JGandalf.hh:96
JFIT::JGandalf::previous
JModel_t previous
Definition: JGandalf.hh:310
JFIT::JGandalf::LAMBDA_UP
static double LAMBDA_UP
multiplication factor control parameter
Definition: JGandalf.hh:261
JFIT::JGandalf::successor
result_type successor
Definition: JGandalf.hh:309
JFIT::JGandalf::JGandalf
JGandalf()
Default constructor.
Definition: JGandalf.hh:104
JMATH::JMatrixND::resize
void resize(const size_t size)
Resize matrix.
Definition: JMatrixND.hh:359
JEEP::JMessage< JGandalf< JModel_t > >::debug
static int debug
debug level (default is off).
Definition: JMessage.hh:45
JFIT::JGandalf::H
JMATH::JMatrixNS H
Definition: JGandalf.hh:270
JLANG::JException
General exception.
Definition: JException.hh:23
JEEP::JMessage
Auxiliary class for handling debug parameter within a class.
Definition: JMessage.hh:44