Jpp test-rotations-new
the software that should make you happy
Loading...
Searching...
No Matches
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#include <type_traits>
10
11#include "Jeep/JMessage.hh"
12#include "JMath/JVectorND.hh"
13#include "JMath/JMatrixNS.hh"
14#include "JMath/JZero.hh"
15#include "JLang/JManip.hh"
16#include "JLang/JException.hh"
17
18#include "Jeep/JMessage.hh"
19
20/**
21 * \author mdejong
22 */
23
24namespace JFIT {}
25namespace JPP { using namespace JFIT; }
26
27namespace JFIT {
28
29 using JEEP::JMessage;
31
32 namespace JFIT_LOCAL {
33
34 template<class T>
35 class JTypedef {
36 template<class U> static auto parameter_type(U*) -> decltype(std::declval<typename U::parameter_type>());
37 template<typename> static auto parameter_type(...) -> std::false_type;
38
39 public:
40 static const bool has_parameter_type = !std::is_same<std::false_type, decltype(parameter_type<T> (0))>::value;
41 };
42
43 template<class T, bool has_parameter_type = JTypedef<T>::has_parameter_type>
44 struct JTypedef_t;
45
46 template<class T> struct JTypedef_t<T, true> { typedef typename T::parameter_type parameter_type; };
47 template<class T> struct JTypedef_t<T, false> { typedef double T::*parameter_type; };
48 }
49
50
51 /**
52 * Auxiliary function to constrain model during fit.
53 *
54 * \param value model (I/O)
55 */
56 template<class JModel_t>
57 inline void model(JModel_t& value)
58 {}
59
60
61 /**
62 * Fit method based on the Levenberg-Marquardt method.
63 *
64 * The template argument refers to the model that should be fitted to the data.\n
65 * This data structure should have arithmetic capabilities.
66 *
67 * The data member JGandalf::value corresponds to the start c.q.\ final value of
68 * the model of the fit procedure and JGandalf::error to the uncertainties.\n
69 * The co-variance matrix is stored in data member JGandalf::V.\n
70 *
71 * The data member JGandalf::parameters constitutes a list of those parameters of the model that should actually be fitted.\n
72 * For this, the model should contain the type definition for <tt>parameter_type</tt>.\n
73 * Normally, this type definition corresponds to a pointer to a data member of the model.\n
74 * If not defined, the parameters are assumed to be data members of type <tt>double</tt>.\n
75 * Alternatively, the type definition can be <tt>size_t</tt> or <tt>int</tt>.\n
76 * In that case, the model should provide for the element access <tt>operator[]</tt>.\n
77 *
78 * The first template parameter in the function operator should provide for an implementation of the actual fit function.\n
79 * This function should return the data type JGandalf::result_type.\n
80 * This data structure comprises the values of the chi2 and the gradient for a given data point.\n
81 * The function operator returns the minimal chi2 and summed gradient of all data points.
82 */
83
84 template<class JModel_t>
85 class JGandalf :
86 public JMessage< JGandalf<JModel_t> >
87 {
88 public:
89
91
92
93 /**
94 * Data type of fit parameter.
95 */
97
98
99 /**
100 * Data structure for return value of fit function.
101 */
102 struct result_type {
103 /**
104 * Default constructor.
105 */
107 chi2 (0.0),
108 gradient()
109 {}
110
111
112 /**
113 * Constructor.
114 *
115 * \param chi2 chi2
116 * \param model gradient
117 */
118 result_type(const double chi2,
119 const JModel_t& model) :
120 chi2 (chi2),
122 {}
123
124
125 /**
126 * Type conversion operator.
127 *
128 * \return chi2
129 */
130 operator double() const
131 {
132 return chi2;
133 }
134
135
136 double chi2; //!< chi2
137 JModel_t gradient; //!< partial derivatives of chi2
138 };
139
140
141 /**
142 * Default constructor.
143 */
145 {}
146
147
148 /**
149 * Multi-dimensional fit of multiple data sets.
150 *
151 * The fit function should return the chi2 as well as the partial derivatives
152 * for the current value of the model and a given data point.
153 *
154 * \param fit fit function
155 * \param __begin begin of data
156 * \param __end end of data
157 * \param args optional data
158 * \return chi2 and gradient
159 */
160 template<class JFunction_t, class T, class ...Args>
161 result_type operator()(const JFunction_t& fit, T __begin, T __end, Args ...args)
162 {
163 using namespace std;
164 using namespace JPP;
165
166 // note that all model values should be assigned to the start value of the model before use
167 // because the actual list of model parameters can vary from fit to fit
168 // (e.g. if model consists of a container).
169
170 const size_t N = parameters.size();
171
172 V.resize(N);
173 h.resize(N);
174 x.resize(N);
175
176 previous.result.chi2 = numeric_limits<double>::max();
177
178 current.result.chi2 = numeric_limits<double>::max();
179 current.result.gradient = value;
180 current.result.gradient = zero;
181
182 error = value;
183 error = zero;
184
186
188
189 DEBUG("step: " << numberOfIterations << endl);
190
191 reset();
192
193 update(fit, __begin, __end, args...);
194
195 DEBUG("lambda: " << FIXED(12,5) << lambda << endl);
196 DEBUG("chi2: " << FIXED(12,5) << current.result.chi2 << endl);
197
198 if (current.result.chi2 < previous.result.chi2) {
199
200 if (numberOfIterations != 0) {
201
202 const double tolerance = EPSILON * (EPSILON_ABSOLUTE ? 1.0 : fabs(previous.result.chi2));
203
204 if (fabs(previous.result.chi2 - current.result.chi2) <= tolerance) {
205
206 // normal end
207
208 const result_type result = current.result;
209
210 reset();
211
212 update(fit, __begin, __end, args...);
213
214 try {
215 V.invert();
216 }
217 catch (const exception& error) {}
218
219 for (size_t i = 0; i != N; ++i) {
220 get(error, parameters[i]) = sqrt(V(i,i));
221 }
222
223 return result;
224 }
225
226 if (lambda > LAMBDA_MIN) {
228 }
229 }
230
231 // store current values
232
233 previous.value = value;
234 previous.result = current.result;
235
236 } else {
237
238 value = previous.value; // restore value
239
240 lambda *= LAMBDA_UP;
241
242 if (lambda > LAMBDA_MAX) {
243 break;
244 }
245
246 reset();
247
248 update(fit, __begin, __end, args...);
249 }
250
251 DEBUG("Hesse matrix:" << endl << V << endl);
252
253 // force definite positiveness
254
255 for (size_t i = 0; i != N; ++i) {
256
257 if (V(i,i) < PIVOT) {
258 V(i,i) = PIVOT;
259 }
260
261 h[i] = 1.0 / sqrt(V(i,i));
262 }
263
264 // normalisation
265
266 for (size_t row = 0; row != N; ++row) {
267 for (size_t col = 0; col != row; ++col) {
268 V(row,col) *= h[row] * h[col];
269 V(col,row) = V(row,col);
270 }
271 }
272
273 for (size_t i = 0; i != N; ++i) {
274 V(i,i) = 1.0 + lambda;
275 }
276
277 // solve A x = b
278
279 for (size_t col = 0; col != N; ++col) {
280 x[col] = h[col] * get(current.result.gradient, parameters[col]);
281 }
282
283 try {
284 V.solve(x);
285 }
286 catch (const exception& error) {
287
288 ERROR("JGandalf: " << error.what() << endl << V << endl);
289
290 break;
291 }
292
293 // update value
294
295 for (size_t row = 0; row != N; ++row) {
296
297 DEBUG("u[" << noshowpos << setw(3) << row << "] = " << showpos << FIXED(15,5) << get(value, parameters[row]));
298
299 get(value, parameters[row]) -= h[row] * x[row];
300
301 DEBUG(" -> " << FIXED(15,5) << get(value, parameters[row]) << noshowpos << endl);
302 }
303
304 model(value);
305 }
306
307 // abnormal end
308
309 const result_type result = previous.result;
310
311 value = previous.value; // restore value
312
313 reset();
314
315 update(fit, __begin, __end, args...);
316
317 try {
318 V.invert();
319 }
320 catch (const exception& error) {}
321
322 for (size_t i = 0; i != N; ++i) {
323 get(error, parameters[i]) = sqrt(V(i,i));
324 }
325
326 return result;
327 }
328
329
330 static int MAXIMUM_ITERATIONS; //!< maximal number of iterations
331 static double EPSILON; //!< maximal distance to minimum
332 static bool EPSILON_ABSOLUTE; //!< set epsilon to absolute difference instead of relative
333 static double LAMBDA_MIN; //!< minimal value control parameter
334 static double LAMBDA_MAX; //!< maximal value control parameter
335 static double LAMBDA_UP; //!< multiplication factor control parameter
336 static double LAMBDA_DOWN; //!< multiplication factor control parameter
337 static double PIVOT; //!< minimal value diagonal element of Hesse matrix
338
340 int numberOfIterations; //!< number of iterations
341 double lambda; //!< control parameter
342 JModel_t value; //!< value
343 JModel_t error; //!< error
344 JMATH::JMatrixNS V; //!< Hesse matrix
345
346 private:
347 /**
348 * Reset current parameters.
349 */
350 void reset()
351 {
352 using namespace JPP;
353
354 current.result.chi2 = 0.0;
355 current.result.gradient = zero;
356
357 V.reset();
358 }
359
360
361 /**
362 * Recursive method to update current parameters.
363 *
364 * \param fit fit function
365 * \param __begin begin of data
366 * \param __end end of data
367 * \param args optional data
368 */
369 template<class JFunction_t, class T, class ...Args>
370 inline void update(const JFunction_t& fit, T __begin, T __end, Args ...args)
371 {
372 for (T i = __begin; i != __end; ++i) {
373
374 const result_type& result = fit(value, *i);
375
376 current.result.chi2 += result.chi2;
377 current.result.gradient += result.gradient;
378
379 for (size_t row = 0; row != parameters.size(); ++row) {
380 for (size_t col = row; col != parameters.size(); ++col) {
381 V(row,col) += get(result.gradient, parameters[row]) * get(result.gradient, parameters[col]);
382 }
383 }
384 }
385
386 update(fit, args...);
387 }
388
389
390 /**
391 * Termination method to update current parameters.
392 *
393 * \param fit fit function
394 */
395 template<class JFunction_t>
396 inline void update(const JFunction_t& fit)
397 {
398 for (size_t row = 0; row != parameters.size(); ++row) {
399 for (size_t col = 0; col != row; ++col) {
400 V(row,col) = V(col,row);
401 }
402 }
403 }
404
405
406 /**
407 * Read/write access to parameter value by data member.
408 *
409 * \param model model
410 * \param parameter parameter
411 * \return value
412 */
413 static inline double get(const JModel_t& model, double JModel_t::*parameter)
414 {
415 return model.*parameter;
416 }
417
418
419 /**
420 * Read/write access to parameter value by data member.
421 *
422 * \param model model
423 * \param parameter parameter
424 * \return value
425 */
426 static inline double& get(JModel_t& model, double JModel_t::*parameter)
427 {
428 return model.*parameter;
429 }
430
431
432 /**
433 * Read/write access to parameter value by index.
434 *
435 * \param model model
436 * \param index index
437 * \return value
438 */
439 static inline double get(const JModel_t& model, const size_t index)
440 {
441 return model[index];
442 }
443
444
445 /**
446 * Read/write access to parameter value by index.
447 *
448 * \param model model
449 * \param index index
450 * \return value
451 */
452 static inline double& get(JModel_t& model, const size_t index)
453 {
454 return model[index];
455 }
456
457
458 /**
459 * Read/write access to parameter value by index.
460 *
461 * \param model model
462 * \param index index
463 * \return value
464 */
465 static inline double get(const JModel_t& model, const int index)
466 {
467 return model[index];
468 }
469
470
471 /**
472 * Read/write access to parameter value by index.
473 *
474 * \param model model
475 * \param index index
476 * \return value
477 */
478 static inline double& get(JModel_t& model, const int index)
479 {
480 return model[index];
481 }
482
483 std::vector<double> h; // normalisation vector
485
486 struct {
489
490 struct {
491 JModel_t value; // value
492 result_type result; // result
494 };
495
496
497 /**
498 * maximal number of iterations.
499 */
500 template<class JModel_t>
502
503
504 /**
505 * maximal distance to minimum.
506 */
507 template<class JModel_t>
508 double JGandalf<JModel_t>::EPSILON = 1.0e-3;
509
510 /**
511 * set epsilon to absolute difference instead of relative.
512 */
513 template<class JModel_t>
515
516 /**
517 * minimal value control parameter
518 */
519 template<class JModel_t>
520 double JGandalf<JModel_t>::LAMBDA_MIN = 0.01;
521
522
523 /**
524 * maximal value control parameter
525 */
526 template<class JModel_t>
527 double JGandalf<JModel_t>::LAMBDA_MAX = 100.0;
528
529
530 /**
531 * multiplication factor control parameter
532 */
533 template<class JModel_t>
534 double JGandalf<JModel_t>::LAMBDA_UP = 10.0;
535
536
537 /**
538 * multiplication factor control parameter
539 */
540 template<class JModel_t>
542
543
544 /**
545 * minimal value diagonal element of matrix
546 */
547 template<class JModel_t>
548 double JGandalf<JModel_t>::PIVOT = std::numeric_limits<double>::epsilon();
549}
550
551#endif
552
Exceptions.
I/O manipulators.
General purpose messaging.
#define DEBUG(A)
Message macros.
Definition JMessage.hh:62
#define ERROR(A)
Definition JMessage.hh:66
Definition of zero value for any class.
static auto parameter_type(...) -> std::false_type
static auto parameter_type(U *) -> decltype(std::declval< typename U::parameter_type >())
static const bool has_parameter_type
Definition JGandalf.hh:40
Fit method based on the Levenberg-Marquardt method.
Definition JGandalf.hh:87
void update(const JFunction_t &fit)
Termination method to update current parameters.
Definition JGandalf.hh:396
double lambda
control parameter
Definition JGandalf.hh:341
static double LAMBDA_MIN
minimal value control parameter
Definition JGandalf.hh:333
JMATH::JVectorND x
Definition JGandalf.hh:484
static double & get(JModel_t &model, const int index)
Read/write access to parameter value by index.
Definition JGandalf.hh:478
struct JFIT::JGandalf::@12 current
void reset()
Reset current parameters.
Definition JGandalf.hh:350
static double LAMBDA_DOWN
multiplication factor control parameter
Definition JGandalf.hh:336
std::vector< parameter_type > parameters
fit parameters
Definition JGandalf.hh:339
static double get(const JModel_t &model, const size_t index)
Read/write access to parameter value by index.
Definition JGandalf.hh:439
static double LAMBDA_UP
multiplication factor control parameter
Definition JGandalf.hh:335
int numberOfIterations
number of iterations
Definition JGandalf.hh:340
static bool EPSILON_ABSOLUTE
set epsilon to absolute difference instead of relative
Definition JGandalf.hh:332
std::vector< double > h
Definition JGandalf.hh:483
static double get(const JModel_t &model, double JModel_t::*parameter)
Read/write access to parameter value by data member.
Definition JGandalf.hh:413
static int MAXIMUM_ITERATIONS
maximal number of iterations
Definition JGandalf.hh:330
static double PIVOT
minimal value diagonal element of Hesse matrix
Definition JGandalf.hh:337
result_type operator()(const JFunction_t &fit, T __begin, T __end, Args ...args)
Multi-dimensional fit of multiple data sets.
Definition JGandalf.hh:161
void update(const JFunction_t &fit, T __begin, T __end, Args ...args)
Recursive method to update current parameters.
Definition JGandalf.hh:370
JGandalf()
Default constructor.
Definition JGandalf.hh:144
result_type result
Definition JGandalf.hh:487
static double EPSILON
maximal distance to minimum
Definition JGandalf.hh:331
JModel_t value
value
Definition JGandalf.hh:342
static double & get(JModel_t &model, double JModel_t::*parameter)
Read/write access to parameter value by data member.
Definition JGandalf.hh:426
JFIT_LOCAL::JTypedef_t< JModel_t >::parameter_type parameter_type
Data type of fit parameter.
Definition JGandalf.hh:96
JMATH::JMatrixNS V
Hesse matrix.
Definition JGandalf.hh:344
static double LAMBDA_MAX
maximal value control parameter
Definition JGandalf.hh:334
static double get(const JModel_t &model, const int index)
Read/write access to parameter value by index.
Definition JGandalf.hh:465
JModel_t error
error
Definition JGandalf.hh:343
struct JFIT::JGandalf::@13 previous
static double & get(JModel_t &model, const size_t index)
Read/write access to parameter value by index.
Definition JGandalf.hh:452
General exception.
Definition JException.hh:24
Auxiliary classes and methods for linear and iterative data regression.
Definition JEnergy.hh:15
void model(JModel_t &value)
Auxiliary function to constrain model during fit.
Definition JGandalf.hh:57
This name space includes all other name spaces (except KM3NETDAQ, KM3NET and ANTARES).
Auxiliary data structure for floating point format specification.
Definition JManip.hh:448
Auxiliary class for handling debug parameter within a class.
Definition JMessage.hh:44
static int debug
debug level (default is off).
Definition JMessage.hh:45
Data structure for return value of fit function.
Definition JGandalf.hh:102
result_type()
Default constructor.
Definition JGandalf.hh:106
result_type(const double chi2, const JModel_t &model)
Constructor.
Definition JGandalf.hh:118
JModel_t gradient
partial derivatives of chi2
Definition JGandalf.hh:137
void resize(const size_t size)
Resize matrix.
Definition JMatrixND.hh:446
JMatrixND & reset()
Set matrix to the null matrix.
Definition JMatrixND.hh:459
N x N symmetric matrix.
Definition JMatrixNS.hh:30
void solve(JVectorND_t &u)
Get solution of equation A x = b.
Definition JMatrixNS.hh:308
void invert()
Invert matrix according LDU decomposition.
Definition JMatrixNS.hh:75
Nx1 matrix.
Definition JVectorND.hh:23