GammaLib 2.0.0
Loading...
Searching...
No Matches
GDerivative.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * GDerivative.cpp - Derivative class *
3 * ----------------------------------------------------------------------- *
4 * copyright (C) 2011-2020 by Juergen Knoedlseder *
5 * ----------------------------------------------------------------------- *
6 * *
7 * This program is free software: you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation, either version 3 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
19 * *
20 ***************************************************************************/
21/**
22 * @file GDerivative.cpp
23 * @brief GDerivative class implementation.
24 * @author Juergen Knoedlseder
25 */
26
27/* __ Includes ___________________________________________________________ */
28#include <cstdlib> // Definition of NULL
29#include <cmath> // for abs()
30#include <cfloat> // for DBL_MAX
31#include "GDerivative.hpp"
32#include "GMatrix.hpp"
33#include "GTools.hpp"
34
35/* __ Method name definitions ____________________________________________ */
36#define G_VALUE "GDerivative::value(double&, double&)"
37#define G_RIDDER "GDerivative::ridder(double&, double&, double*)"
38#define G_MINUIT2 "GDerivative::minuit2(double&, double*)"
39#define G_SMOOTH_ROBUST "GDerivative::smooth_robust(double&, double&, int&,"\
40 " int&)"
41
42/* __ Macros _____________________________________________________________ */
43
44/* __ Coding definitions _________________________________________________ */
45
46/* __ Debug definitions __________________________________________________ */
47#define G_VALUE_DEBUG 0 //!< Debug value method
48#define G_MINUIT_DEBUG 0 //!< Debug minuit method
49
50
51/*==========================================================================
52 = =
53 = Constructors/destructors =
54 = =
55 ==========================================================================*/
56
57/***********************************************************************//**
58 * @brief Void constructor
59 ***************************************************************************/
61{
62 // Initialise private members
64
65 // Return
66 return;
67}
68
69
70/***********************************************************************//**
71 * @brief Function constructor
72 *
73 * @param[in] func Function pointer.
74 *
75 * Construct class instance from single parameter function. Note that the
76 * function is not copied but just a pointer to it is stored. The function
77 * should thus not be destroyed before computation of derivatives is
78 * finished.
79 ***************************************************************************/
81{
82 // Initialise private members
84
85 // Set function
86 this->function(func);
87
88 // Return
89 return;
90}
91
92
93/***********************************************************************//**
94 * @brief Copy constructor
95 *
96 * @param[in] dx Derivative.
97 ***************************************************************************/
99{
100 // Initialise members
101 init_members();
102
103 // Copy members
104 copy_members(dx);
105
106 // Return
107 return;
108}
109
110
111/***********************************************************************//**
112 * @brief Destructor
113 ***************************************************************************/
115{
116 // Free members
117 free_members();
118
119 // Return
120 return;
121}
122
123
124/*==========================================================================
125 = =
126 = Operators =
127 = =
128 ==========================================================================*/
129
130/***********************************************************************//**
131 * @brief Assignment operator
132 *
133 * @param[in] dx Derivative.
134 * @return Derivative.
135 ***************************************************************************/
137{
138 // Execute only if object is not identical
139 if (this != &dx) {
140
141 // Free members
142 free_members();
143
144 // Initialise members
145 init_members();
146
147 // Copy members
148 copy_members(dx);
149
150 } // endif: object was not identical
151
152 // Return
153 return *this;
154}
155
156
157/*==========================================================================
158 = =
159 = Public methods =
160 = =
161 ==========================================================================*/
162
163/***********************************************************************//**
164 * @brief Clear derivative
165 ***************************************************************************/
167{
168 // Free members
169 free_members();
170
171 // Initialise private members
172 init_members();
173
174 // Return
175 return;
176}
177
178
179/***********************************************************************//**
180 * @brief Clone derivative
181 *
182 * @return Pointer to deep copy of derivative.
183 ***************************************************************************/
185{
186 return new GDerivative(*this);
187}
188
189
190/***********************************************************************//**
191 * @brief Returns derivative
192 *
193 * @param[in] x Function value.
194 * @param[in] step Initial step size (default: automatic)
195 *
196 * Computes derivative using the Ridders' method. If the specified initial
197 * step size is non-zero, the method starts with this step size and
198 * iteratively decreases the step size until the error becomes less than
199 * a threshold defined with the eps() method (by default the threshold is
200 * set to 1e-6). If the initial step size is zero, the method takes
201 * \f$h={\tt m\_step\_frac} |x|\f$ as initial step size.
202 * The maximum number of iterations is controlled by the max_iter()
203 * method (by default, the maximum is set to 5).
204 ***************************************************************************/
205double GDerivative::value(const double& x, const double& step)
206{
207 // Set constants
208 const double min_h = 1.0e-6;
209
210 // Initialise result
211 double result = 0.0;
212
213 // Set initial step size. Use either the specified initial step size,
214 // or if the initial step size is 0, use a fixed fraction of the function
215 // value
216 double h = step;
217 if (h == 0.0) {
218 h = m_step_frac * std::abs(x);
219 if (h < min_h) {
220 h = min_h;
221 }
222 }
223
224 // Initialise tolerance
225 double err = DBL_MAX;
226
227 // Loop over Ridder's method until we have an acceptable tolerance
228 m_iter = 0;
229 for (; m_iter < m_max_iter; ++m_iter) {
230
231 // Compute derivative using Ridder's method
232 result = ridder(x, h, &err);
233
234 // Debug option: Show actual results
235 #if G_VALUE_DEBUG
236 std::cout << "GDerivative::value(";
237 std::cout << "iter=" << m_iter;
238 std::cout << ", x=" << x;
239 std::cout << ", dy/dx=" << result;
240 std::cout << ", h=" << h;
241 std::cout << ", err=" << err;
242 std::cout << ")" << std::endl;
243 #endif
244
245 // If uncertainty is below tolerance then exit now
246 if (err < m_eps) {
247 break;
248 }
249
250 // Reduce the step size
251 h /= 5.0;
252
253 } // endfor: tolerance matching loop
254
255 // Compile option: signal if we exceed the tolerance
256 if (!silent()) {
257 if (err >= m_eps) {
258 std::string msg = "Derivative uncertainty "+gammalib::str(err)+
259 " exceeds tolerance of "+gammalib::str(m_eps)+
260 " at function value "+gammalib::str(x)+
261 " (df/dx="+gammalib::str(result)+
262 ", iter="+gammalib::str(m_iter)+
263 ", h="+gammalib::str(h)+").";
265 }
266 }
267
268 // Return derivative
269 return result;
270}
271
272/***********************************************************************//**
273 * @brief Returns derivative by Ridders' method
274 *
275 * @param[in] x Function value.
276 * @param[in] h Estimated initial step size.
277 * @param[out] err Estimated error in the derivative.
278 *
279 * @exception GException::invalid_argument
280 * Step size of 0 has been specified.
281 *
282 * Returns the derivative of a function at point x by Ridders's method of
283 * polynomial extrapolation. The value h is input as an estimated initial
284 * stepsize; it needs not to be small, but rather should be an increment
285 * in x over which the function changes substantially.
286 *
287 * This method has been adopted from Numerical Recipes, 3rd edition, page
288 * 321f.
289 ***************************************************************************/
290double GDerivative::ridder(const double& x, const double& h, double* err)
291{
292 // Set constants
293 const int ntab = 10; // Maximum table size
294 const double con = 1.4; // Stepsize decreases by con at each iteration
295 const double con2 = con * con;
296 const double big = DBL_MAX;
297 const double safe = 2.0; // Return when error is safe worse than best so far
298
299 // Initialise result
300 double dx = 0.0;
301 *err = big;
302
303 // Continue only if we have a valid function
304 if (m_func != NULL) {
305
306 // Allocate Neville table
307 GMatrix a(ntab, ntab);
308
309 // Throw exception if step size is zero
310 if (h <= 0) {
311 throw GException::invalid_argument(G_RIDDER, "Step size must be positive.");
312 }
313
314 // Initialise adaptive step size
315 double hh = h;
316
317 // Perform initial function evaluation
318 a(0,0) = (m_func->eval(x+hh) - m_func->eval(x-hh))/(2.0*hh);
319
320 // Perform successive computations
321 for (int i = 1; i < ntab; ++i) {
322
323 // Reduce step size
324 hh /= con;
325
326 // Try new smaller step size
327 a(0,i) = (m_func->eval(x+hh) - m_func->eval(x-hh))/(2.0*hh);
328
329 // Compute extrapolations of various orders, requiring no new
330 // function evaluations
331 double fac = con2;
332 for (int j = 1; j <= i; ++j) {
333
334 // Compute extrapolation
335 a(j,i) = ( a(j-1,i) * fac - a(j-1,i-1) ) / (fac - 1.0);
336 fac *= con2;
337
338 // If the error is reduced then save the improved answer
339 double err1 = std::abs(a(j,i) - a(j-1,i));
340 double err2 = std::abs(a(j,i) - a(j-1,i-1));
341 double errt = (err1 > err2) ? err1 : err2;
342 if (errt <= *err) {
343 *err = errt;
344 dx = a(j,i);
345 }
346
347 } // endfor: looped over tableau
348
349 // If higher order is worse by a significant factor, then quit early
350 if (std::abs( a(i,i) - a(i-1,i-1) ) >= safe*(*err)) {
351 break;
352 }
353
354 } // endfor: looped over computations
355
356 } // endif: we had a valid function
357
358 // Return derivative
359 return dx;
360}
361
362
363/***********************************************************************//**
364 * @brief Returns derivative using Minuit2 algorithm
365 *
366 * @param[in] x Function value.
367 * @param[out] err Estimated error in the derivative.
368 *
369 * This method has been inspired by corresponding code in the Minuit2
370 * package. Please check the following files in Minuit2 for more information:
371 *
372 * Numerical2PGradientCalculator.cxx for the main code
373 * MnStrategy.cxx for the definition of algorithm parameters
374 * MnMachinePrecision.h for the definition of eps and eps2
375 * InitialGradientCalculator.cxx for the Minuit2 way of estimating initial
376 * gradients.
377 *
378 * The exact value of fcnup has little impact on the results.
379 ***************************************************************************/
380double GDerivative::minuit2(const double& x, double* err)
381{
382 // Evaluate function at x
383 double fcnmin = m_func->eval(x);
384
385 // Set precision
386// double eps = m_eps; // Minuit2: smallest number that gives 1.+eps>1
387// double eps = m_tiny; // Bad
388// double eps = 1.0e-30; // Bad
389// double eps = 1.0e-10; // Poor
390// double eps = 1.0e-6; // Quite good
391// double eps = 1.0e-8; // Worse than 1.0e-6
392 double eps = 1.0e-4; // Pretty good !
393// double eps = 1.0e-2; // Wrong
394 double eps2 = 2.0 * std::sqrt(eps);
395
396 // Set ...
397 //double fcnup = 1.0; // Minuit2: Fcn().Up() - function delta for 1 sigma errors
398 double fcnup = 0.01 * fcnmin;
399 double dfmin = 8.0 * eps2 * (std::abs(fcnmin) + fcnup);
400 double vrysml = 8.0 * eps * eps;
401
402 // Set high strategy (see MnStrategy)
403 int ncycles = 5;
404 double step_tol = 0.1;
405 double grad_tol = 0.02;
406
407 // Initial gradient estimation. Note that this is brute force method
408 // that does not correspond to the Minuit2 approach. For the Minuit2
409 // approach, check InitialGradientCalculator.cxx
410 double gstep = 0.001; // Initial gradient step
411 double fs1 = m_func->eval(x + gstep);
412 double fs2 = m_func->eval(x - gstep);
413 double grd = 0.5 * (fs1 - fs2) / gstep;
414 double g2 = (fs1 + fs2 - 2.0*fcnmin) / gstep / gstep;
415
416 // Debug option: Show actual results
417 #if G_MINUIT_DEBUG
418 std::cout << "GDerivative::minuit(";
419 std::cout << "iter=0";
420 std::cout << ", x=" << x;
421 std::cout << ", grd=" << grd;
422 std::cout << ", step=" << gstep;
423 std::cout << ")" << std::endl;
424 #endif
425
426 // Initialise values
427 double epspri = eps2 + std::abs(grd*eps2);
428 double step = 0.0;
429 double stepb4 = 0.0;
430 double step_change = 0.0;
431 *err = 0.0;
432
433 // Loop over cycles
434 for (m_iter = 1; m_iter <= ncycles; ++m_iter) {
435
436 // Compute optimum step size
437 double optstp = std::sqrt(dfmin/(std::abs(g2)+epspri));
438
439 // Compute step size
440 step = std::max(optstp, std::abs(0.1*gstep));
441 double stpmax = 10.0 * std::abs(gstep);
442 double stpmin = std::max(vrysml, 8.0 * std::abs(eps2*x));
443 if (step > stpmax) step = stpmax;
444 if (step < stpmin) step = stpmin;
445
446 // Break is we are below the step tolerance
447 step_change = std::abs((step-stepb4)/step);
448 if (step_change < step_tol) {
449 break;
450 }
451
452 // Store step size information
453 gstep = step;
454 stepb4 = step;
455
456 // Bookkeeping of last gradient
457 double grdb4 = grd;
458
459 // Evaluate gradient
460 double fs1 = m_func->eval(x + step);
461 double fs2 = m_func->eval(x - step);
462 grd = 0.5 * (fs1 - fs2) / step;
463 g2 = (fs1 + fs2 - 2.0*fcnmin) / step / step;
464
465 // Compute error
466 *err = std::abs(grdb4-grd) / (std::abs(grd)+dfmin/step);
467
468 // Debug option: Show actual results
469 #if G_MINUIT_DEBUG
470 std::cout << "GDerivative::minuit(";
471 std::cout << "iter=" << m_iter;
472 std::cout << ", x=" << x;
473 std::cout << ", grd=" << grd;
474 std::cout << ", step=" << step;
475 std::cout << ", err=" << *err;
476 std::cout << ")" << std::endl;
477 #endif
478
479 // Break if gradient is accurate enough
480 if (*err < grad_tol) {
481 break;
482 }
483
484 } // endfor: looped over cycles
485
486 // Compile option: signal if we exceed the tolerance
487 if (!silent()) {
488 if (*err >= grad_tol) {
489 std::string msg = "Derivative uncertainty "+gammalib::str(*err)+
490 " exceeds tolerance of "+gammalib::str(grad_tol)+
491 " at function value "+gammalib::str(x)+
492 " (df/dx="+gammalib::str(grd)+
493 ", step="+gammalib::str(step)+
494 ", step_change="+gammalib::str(step_change)+").";
496 }
497 }
498
499 // Return gradient
500 return grd;
501}
502
503
504/***********************************************************************//**
505 * @brief Returns gradient computed from symmetric function difference
506 *
507 * @param[in] x Function value.
508 * @param[in] h Step size.
509 *
510 * This is the most simple and dumb gradient computation method we can think
511 * of. It does a reasonable good job if the problem is well controlled, and
512 * in particular, if the step size is known in advance.
513 ***************************************************************************/
514double GDerivative::difference(const double& x, const double& h)
515{
516 // Compute derivative
517 double fs1 = m_func->eval(x + h);
518 double fs2 = m_func->eval(x - h);
519 double derivative = 0.5 * (fs1 - fs2) / h;
520
521 // Return derivative
522 return derivative;
523}
524
525
526/***********************************************************************//**
527 * @brief Returns gradient computed from left-sided function difference
528 *
529 * @param[in] x Function value.
530 * @param[in] h Step size.
531 *
532 * This is the most simple and dumb gradient computation method we can think
533 * of. It does a reasonable good job if the problem is well controlled, and
534 * in particular, if the step size is known in advance.
535 ***************************************************************************/
536double GDerivative::left_difference(const double& x, const double& h)
537{
538 // Compute derivative
539 double fs1 = m_func->eval(x);
540 double fs2 = m_func->eval(x - h);
541 double derivative = (fs1 - fs2) / h;
542
543 // Return derivative
544 return derivative;
545}
546
547
548/***********************************************************************//**
549 * @brief Returns gradient computed from right-sided function difference
550 *
551 * @param[in] x Function value.
552 * @param[in] h Step size.
553 *
554 * This is the most simple and dumb gradient computation method we can think
555 * of. It does a reasonable good job if the problem is well controlled, and
556 * in particular, if the step size is known in advance.
557 ***************************************************************************/
558double GDerivative::right_difference(const double& x, const double& h)
559{
560 // Compute derivative
561 double fs1 = m_func->eval(x + h);
562 double fs2 = m_func->eval(x);
563 double derivative = (fs1 - fs2) / h;
564
565 // Return derivative
566 return derivative;
567}
568
569
570/***********************************************************************//**
571 * @brief Returns smooth noise-robust derivative
572 *
573 * @param[in] x Function value.
574 * @param[in] h Step size.
575 * @param[in] degree Differentiator degree (default: 2).
576 * @param[in] length Filter length (default: 5).
577 *
578 * Compute a smooth noise-robust numerical derivative using the method
579 * proposed by Pavel Holoborodko
580 * (http://www.holoborodko.com/pavel/numerical-methods/)
581 * Formulae for the following filter lengths and degrees have been
582 * implemented:
583 *
584 * degree=2 length=5,7,9,11
585 * degree=4 length=7,9,11
586 ***************************************************************************/
587double GDerivative::smooth_robust(const double& x, const double& h,
588 const int& degree, const int& length)
589{
590 // Initialise derivative
591 double derivative = 0.0;
592
593 // Use method dependent on length and degree
594 switch (degree) {
595
596 // Degree 2
597 case 2:
598 switch (length) {
599 case 5:
600 {
601 double h2 = 2.0 * h;
602 double fp1 = m_func->eval(x + h);
603 double fm1 = m_func->eval(x - h);
604 double fp2 = m_func->eval(x + h2);
605 double fm2 = m_func->eval(x - h2);
606 derivative = (2.0*(fp1-fm1) + (fp2-fm2))/(8.0*h);
607 } // block needed against cross-initialization
608 break;
609 case 7:
610 {
611 double h2 = 2.0 * h;
612 double h3 = 3.0 * h;
613 double fp1 = m_func->eval(x + h);
614 double fm1 = m_func->eval(x - h);
615 double fp2 = m_func->eval(x + h2);
616 double fm2 = m_func->eval(x - h2);
617 double fp3 = m_func->eval(x + h3);
618 double fm3 = m_func->eval(x - h3);
619 derivative = (5.0*(fp1-fm1) + 4.0*(fp2-fm2) + (fp3-fm3))/(32.0*h);
620 } // block needed against cross-initialization
621 break;
622 case 9:
623 {
624 double h2 = 2.0 * h;
625 double h3 = 3.0 * h;
626 double h4 = 4.0 * h;
627 double fp1 = m_func->eval(x + h);
628 double fm1 = m_func->eval(x - h);
629 double fp2 = m_func->eval(x + h2);
630 double fm2 = m_func->eval(x - h2);
631 double fp3 = m_func->eval(x + h3);
632 double fm3 = m_func->eval(x - h3);
633 double fp4 = m_func->eval(x + h4);
634 double fm4 = m_func->eval(x - h4);
635 derivative = (14.0*(fp1-fm1) + 14.0*(fp2-fm2) + 6.0*(fp3-fm3) +
636 (fp4-fm4))/(128.0*h);
637 } // block needed against cross-initialization
638 break;
639 case 11:
640 {
641 double h2 = 2.0 * h;
642 double h3 = 3.0 * h;
643 double h4 = 4.0 * h;
644 double h5 = 5.0 * h;
645 double fp1 = m_func->eval(x + h);
646 double fm1 = m_func->eval(x - h);
647 double fp2 = m_func->eval(x + h2);
648 double fm2 = m_func->eval(x - h2);
649 double fp3 = m_func->eval(x + h3);
650 double fm3 = m_func->eval(x - h3);
651 double fp4 = m_func->eval(x + h4);
652 double fm4 = m_func->eval(x - h4);
653 double fp5 = m_func->eval(x + h5);
654 double fm5 = m_func->eval(x - h5);
655 derivative = (42.0*(fp1-fm1) + 48.0*(fp2-fm2) + 27.0*(fp3-fm3) +
656 8.0*(fp4-fm4) + (fp5-fm5))/(512.0*h);
657 } // block needed against cross-initialization
658 break;
659 default:
660 std::string msg = "Specified filter length "+
661 gammalib::str(length)+" not implemented. Please "
662 "specify 5,7,9 or 11 as filter length.";
664 break;
665 }
666 break;
667
668 // Degree 4
669 case 4:
670 switch (length) {
671 case 7:
672 {
673 double h2 = 2.0 * h;
674 double h3 = 3.0 * h;
675 double fp1 = m_func->eval(x + h);
676 double fm1 = m_func->eval(x - h);
677 double fp2 = m_func->eval(x + h2);
678 double fm2 = m_func->eval(x - h2);
679 double fp3 = m_func->eval(x + h3);
680 double fm3 = m_func->eval(x - h3);
681 derivative = (39.0*(fp1-fm1) + 12.0*(fp2-fm2) - 5.0*(fp3-fm3)) /
682 (96.0*h);
683 } // block needed against cross-initialization
684 break;
685 case 9:
686 {
687 double h2 = 2.0 * h;
688 double h3 = 3.0 * h;
689 double h4 = 4.0 * h;
690 double fp1 = m_func->eval(x + h);
691 double fm1 = m_func->eval(x - h);
692 double fp2 = m_func->eval(x + h2);
693 double fm2 = m_func->eval(x - h2);
694 double fp3 = m_func->eval(x + h3);
695 double fm3 = m_func->eval(x - h3);
696 double fp4 = m_func->eval(x + h4);
697 double fm4 = m_func->eval(x - h4);
698 derivative = (27.0*(fp1-fm1) + 16.0*(fp2-fm2) - (fp3-fm3) -
699 2.0*(fp4-fm4)) / (96.0*h);
700 } // block needed against cross-initialization
701 break;
702 case 11:
703 {
704 double h2 = 2.0 * h;
705 double h3 = 3.0 * h;
706 double h4 = 4.0 * h;
707 double h5 = 4.0 * h;
708 double fp1 = m_func->eval(x + h);
709 double fm1 = m_func->eval(x - h);
710 double fp2 = m_func->eval(x + h2);
711 double fm2 = m_func->eval(x - h2);
712 double fp3 = m_func->eval(x + h3);
713 double fm3 = m_func->eval(x - h3);
714 double fp4 = m_func->eval(x + h4);
715 double fm4 = m_func->eval(x - h4);
716 double fp5 = m_func->eval(x + h5);
717 double fm5 = m_func->eval(x - h5);
718 derivative = (322.0*(fp1-fm1) + 256.0*(fp2-fm2) + 39.0*(fp3-fm3) -
719 32.0*(fp4-fm4) - 11.0*(fp5-fm5)) / (1536.0*h);
720 } // block needed against cross-initialization
721 break;
722 default:
723 std::string msg = "Specified filter length "+
724 gammalib::str(length)+" not implemented. Please "
725 "specify 7,9 or 11 as filter length.";
727 break;
728 }
729 break;
730
731 // Invalid degree
732 default:
733 std::string msg = "Specified degree "+gammalib::str(degree)+
734 " not implemented. Please specify 2 as degree.";
736 break;
737 }
738
739 // Return derivative
740 return derivative;
741}
742
743
744/***********************************************************************//**
745 * @brief Print derivative information
746 *
747 * @param[in] chatter Chattiness (defaults to NORMAL).
748 * @return String containing derivative information.
749 ***************************************************************************/
750std::string GDerivative::print(const GChatter& chatter) const
751{
752 // Initialise result string
753 std::string result;
754
755 // Continue only if chatter is not silent
756 if (chatter != SILENT) {
757
758 // Append header
759 result.append("=== GDerivative ===");
760
761 // Append information
762 result.append("\n"+gammalib::parformat("Relative precision"));
763 result.append(gammalib::str(eps()));
764 result.append("\n"+gammalib::parformat("Max. number of iterations"));
765 result.append(gammalib::str(max_iter()));
766 result.append("\n"+gammalib::parformat("Initial step fraction"));
767 result.append(gammalib::str(step_frac()));
768 if (silent()) {
769 result.append("\n"+gammalib::parformat("Warnings")+"suppressed");
770 }
771 else {
772 result.append("\n"+gammalib::parformat("Warnings"));
773 result.append("in standard output");
774 }
775
776 } // endif: chatter was not silent
777
778 // Return result
779 return result;
780}
781
782
783/*==========================================================================
784 = =
785 = Private methods =
786 = =
787 ==========================================================================*/
788
789/***********************************************************************//**
790 * @brief Initialise class members
791 ***************************************************************************/
793{
794 // Initialise members
795 m_func = NULL;
796 m_eps = 1.0e-6;
797 m_step_frac = 0.02;
798 m_tiny = 1.0e-7;
799 m_max_iter = 5;
800 m_iter = 0;
801 m_silent = false;
802
803 // Compute machine precision
804 //set_tiny();
805
806 // Return
807 return;
808}
809
810
811/***********************************************************************//**
812 * @brief Copy class members
813 *
814 * @param[in] dx Derivative.
815 ***************************************************************************/
817{
818 // Copy attributes
819 m_func = dx.m_func;
820 m_eps = dx.m_eps;
822 m_tiny = dx.m_tiny;
824 m_iter = dx.m_iter;
825 m_silent = dx.m_silent;
826
827 // Return
828 return;
829}
830
831
832/***********************************************************************//**
833 * @brief Delete class members
834 ***************************************************************************/
836{
837 // Return
838 return;
839}
840
841
842/***********************************************************************//**
843 * @brief Compute tiny number for Minuit2
844 *
845 * On fermi gives m_tiny = 8.88178e-16 for i=51.
846 ***************************************************************************/
848{
849 // Allocate tiny instance
851
852 // Calculate machine precision
853 double epstry = 0.5;
854 const double one = 1.0;
855
856 // Loop until we found
857 for (int i = 0; i < 100; ++i) {
858 epstry *= 0.5;
859 double epsp1 = one + epstry;
860 double epsbak = tiny(epsp1);
861 if (epsbak < epstry) {
862 m_tiny = 8.0 * epstry;
863 break;
864 }
865 }
866
867 // Return
868 return;
869}
870
871
872/***********************************************************************//**
873 * @brief Return one
874 ***************************************************************************/
875double GDerivative::tiny::one(void) const
876{
877 // Return
878 return m_one;
879}
880
881
882/***********************************************************************//**
883 * @brief Evaluate minimal difference between two floating points
884 ***************************************************************************/
886{
887 // Compute difference
888 double result = eps - one();
889
890 // Return result
891 return result;
892}
#define G_RIDDER
#define G_MINUIT2
#define G_SMOOTH_ROBUST
GDerivative class interface definition.
Generic matrix class definition.
#define G_VALUE
Gammalib tools definition.
GChatter
Definition GTypemaps.hpp:33
@ SILENT
Definition GTypemaps.hpp:34
double one(void) const
Return one.
double operator()(double eps) const
Evaluate minimal difference between two floating points.
Numerical derivatives class.
int m_iter
Number of iterations used.
void copy_members(const GDerivative &dx)
Copy class members.
double smooth_robust(const double &x, const double &h, const int &degree=2, const int &length=5)
Returns smooth noise-robust derivative.
int m_max_iter
Maximum number of iterations.
double minuit2(const double &x, double *err)
Returns derivative using Minuit2 algorithm.
GDerivative(void)
Void constructor.
GDerivative & operator=(const GDerivative &dx)
Assignment operator.
const bool & silent(void) const
Get silence flag.
virtual ~GDerivative(void)
Destructor.
double value(const double &x, const double &step=0.0)
Returns derivative.
void set_tiny(void)
Compute tiny number for Minuit2.
const double & step_frac(void) const
Get step fraction.
double m_eps
Derivative precision.
const double & eps(void) const
Get precision.
void init_members(void)
Initialise class members.
const int & max_iter(void) const
Return maximum number of iterations.
void free_members(void)
Delete class members.
double m_step_frac
Value fraction to use for initial step.
double m_tiny
Tiny number for minuit2.
double left_difference(const double &x, const double &h)
Returns gradient computed from left-sided function difference.
const GFunction * function(void) const
Get function.
double right_difference(const double &x, const double &h)
Returns gradient computed from right-sided function difference.
double ridder(const double &x, const double &h, double *err)
Returns derivative by Ridders' method.
bool m_silent
Suppress warnings.
GFunction * m_func
Pointer to function.
GDerivative * clone(void) const
Clone derivative.
std::string print(const GChatter &chatter=NORMAL) const
Print derivative information.
double difference(const double &x, const double &h)
Returns gradient computed from symmetric function difference.
void clear(void)
Clear derivative.
Single parameter function abstract base class.
Definition GFunction.hpp:44
virtual double eval(const double &x)=0
Generic matrix class definition.
Definition GMatrix.hpp:79
std::string parformat(const std::string &s, const int &indent=0)
Convert string in parameter format.
Definition GTools.cpp:1143
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition GTools.cpp:489
void warning(const std::string &origin, const std::string &message)
Emits warning.
Definition GTools.cpp:1386