All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
deriv_gsl.h
Go to the documentation of this file.
1 /*
2  -------------------------------------------------------------------
3 
4  Copyright (C) 2006-2014, Andrew W. Steiner
5 
6  This file is part of O2scl.
7 
8  O2scl is free software; you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 3 of the License, or
11  (at your option) any later version.
12 
13  O2scl is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with O2scl. If not, see <http://www.gnu.org/licenses/>.
20 
21  -------------------------------------------------------------------
22 */
23 /* deriv/deriv.c
24  *
25  * Copyright (C) 2004, 2007 Brian Gough
26  *
27  * This program is free software; you can redistribute it and/or modify
28  * it under the terms of the GNU General Public License as published by
29  * the Free Software Foundation; either version 3 of the License, or (at
30  * your option) any later version.
31  *
32  * This program is distributed in the hope that it will be useful, but
33  * WITHOUT ANY WARRANTY; without even the implied warranty of
34  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
35  * General Public License for more details.
36  *
37  * You should have received a copy of the GNU General Public License
38  * along with this program; if not, write to the Free Software
39  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
40  * 02110-1301, USA.
41  */
42 
43 #ifndef O2SCL_DERIV_GSL_H
44 #define O2SCL_DERIV_GSL_H
45 
46 /** \file deriv_gsl.h
47  \brief File defining \ref o2scl::deriv_gsl
48 */
49 
50 #include <iostream>
51 #include <cmath>
52 #include <limits>
53 
54 #include <gsl/gsl_deriv.h>
55 #include <gsl/gsl_errno.h>
56 
57 #include <o2scl/deriv.h>
58 #include <o2scl/funct.h>
59 
60 #ifndef DOXYGEN_NO_O2NS
61 namespace o2scl {
62 #endif
63 
64  /** \brief Numerical differentiation (GSL)
65 
66  This class computes the numerical derivative of a function. The
67  stepsize \ref h should be specified before use. If similar
68  functions are being differentiated in succession, the user may
69  be able to increase the speed of later derivatives by setting
70  the new stepsize equal to the optimized stepsize from the
71  previous differentiation, by setting \ref h to \ref h_opt.
72 
73  The derivative computation will never fail, but the results
74  will be incorrect for sufficiently difficult functions or if
75  the step size is not properly chosen.
76 
77  Some successive derivative computations can be made more
78  efficient by using the optimized stepsize in \ref
79  deriv_gsl::h_opt , which is set by the most recent last
80  derivative computation.
81 
82  Setting \ref deriv_base::verbose to a number greater than zero
83  results in output for each call to \ref central_deriv() which
84  looks like:
85  \verbatim
86  deriv_gsl:
87  step: 1.000000e-04
88  abscissas: 4.999500e-01 4.999000e-01 5.000500e-01 5.001000e-01
89  ordinates: 4.793377e-01 4.793816e-01 4.794694e-01 4.795132e-01
90  res: 8.775825e-01 trc: 1.462163e-09 rnd: 7.361543e-12
91  \endverbatim
92  where the last line contains the result (<tt>res</tt>), the
93  truncation error (<tt>trc</tt>) and the rounding error
94  (<tt>rnd</tt>). If \ref deriv_base::verbose is greater than 1, a
95  keypress is required after each iteration.
96 
97  Computing first derivatives requires either 1 or 2 calls to \ref
98  central_deriv() and thus either 4 or 8 function calls. This
99  class never calls the error handler.
100 
101  \note Second and third derivatives are computed by naive nested
102  applications of the formula for the first derivative. No
103  uncertainty for these derivatives is provided.
104 
105  An example demonstrating the usage of this class is given in
106  <tt>examples/ex_deriv.cpp</tt> and the \ref ex_deriv_sect .
107 
108  \future Include the forward and backward GSL derivatives?
109  */
110  template<class func_t=funct11> class deriv_gsl :
111  public deriv_base<func_t> {
112 
113  public:
114 
115  deriv_gsl() {
116  h=0.0;
117  h_opt=0.0;
118  }
119 
120  virtual ~deriv_gsl() {}
121 
122  /** \brief Initial stepsize
123 
124  This should be specified before a call to deriv() or
125  deriv_err(). If it is zero, then \f$ x 10^{-4} \f$ will used,
126  or if \c x is zero, then \f$ 10^{-4} \f$ will be used.
127  */
128  double h;
129 
130  /** \brief The last value of the optimized stepsize
131 
132  This is initialized to zero in the constructor and set by
133  deriv_err() to the most recent value of the optimized stepsize.
134  */
135  double h_opt;
136 
137  /** \brief Calculate the first derivative of \c func w.r.t. x and
138  uncertainty
139  */
140  virtual int deriv_err(double x, func_t &func, double &dfdx, double &err) {
141  return deriv_tlate<func_t>(x,func,dfdx,err);
142  }
143 
144  /// Return string denoting type ("deriv_gsl")
145  virtual const char *type() { return "deriv_gsl"; }
146 
147 #ifndef DOXYGEN_INTERNAL
148 
149  protected:
150 
151  /** \brief Internal template version of the derivative function
152  */
153  template<class func2_t> int deriv_tlate(double x, func2_t &func,
154  double &dfdx, double &err) {
155  double hh;
156  if (h==0.0) {
157  if (x==0.0) hh=1.0e-4;
158  else hh=1.0e-4*x;
159  } else {
160  hh=h;
161  }
162 
163  double r_0, round, trunc, error;
164 
165  central_deriv(x,h,r_0,round,trunc,func);
166  error = round + trunc;
167 
168  if (round < trunc && (round > 0 && trunc > 0)) {
169  double r_opt, round_opt, trunc_opt, error_opt;
170 
171  /* Compute an optimised stepsize to minimize the total error,
172  using the scaling of the truncation error (O(h^2)) and
173  rounding error (O(1/h)). */
174 
175  h_opt = h * pow (round / (2.0 * trunc), 1.0 / 3.0);
176  central_deriv(x,h_opt,r_opt,round_opt,trunc_opt,func);
177  error_opt = round_opt + trunc_opt;
178 
179  /* Check that the new error is smaller, and that the new derivative
180  is consistent with the error bounds of the original estimate. */
181 
182  if (error_opt < error && fabs (r_opt - r_0) < 4.0 * error) {
183  r_0 = r_opt;
184  error = error_opt;
185  }
186  }
187 
188  dfdx=r_0;
189  err=error;
190 
191  return 0;
192  }
193 
194  /** \brief Internal version of calc_err() for second
195  and third derivatives
196  */
197  virtual int deriv_err_int
198  (double x, funct11 &func, double &dfdx, double &err) {
199  return deriv_tlate<>(x,func,dfdx,err);
200  }
201 
202  /** \brief Compute derivative using 5-point rule
203 
204  Compute the derivative using the 5-point rule (x-h, x-h/2, x,
205  x+h/2, x+h) and the error using the difference between the
206  5-point and the 3-point rule (x-h,x,x+h). Note that the
207  central point is not used for either.
208 
209  This must be a class template because it is used by
210  both deriv_err() and deriv_err_int().
211  */
212  template<class func2_t>
213  int central_deriv(double x, double hh, double &result,
214  double &abserr_round, double &abserr_trunc,
215  func2_t &func) {
216 
217  double fm1, fp1, fmh, fph;
218 
219  double eps=std::numeric_limits<double>::epsilon();
220 
221  fm1=func(x-hh);
222  fp1=func(x+hh);
223 
224  fmh=func(x-hh/2);
225  fph=func(x+hh/2);
226 
227  double r3 = 0.5 * (fp1 - fm1);
228  double r5 = (4.0 / 3.0) * (fph - fmh) - (1.0 / 3.0) * r3;
229 
230  double e3 = (fabs (fp1) + fabs (fm1)) * eps;
231  double e5 = 2.0 * (fabs (fph) + fabs (fmh)) * eps + e3;
232 
233  /* The next term is due to finite precision in x+h = O (eps * x) */
234 
235  double dy=GSL_MAX(fabs(r3/hh),fabs(r5/hh))*fabs(x/hh)*eps;
236 
237  /* The truncation error in the r5 approximation itself is O(h^4).
238  However, for safety, we estimate the error from r5-r3, which is
239  O(h^2). By scaling h we will minimise this estimated error, not
240  the actual truncation error in r5.
241  */
242 
243  result = r5 / hh;
244  /* Estimated truncation error O(h^2) */
245  abserr_trunc = fabs ((r5 - r3) / hh);
246  /* Rounding error (cancellations) */
247  abserr_round = fabs (e5 / hh) + dy;
248 
249  if (this->verbose>0) {
250  std::cout << "deriv_gsl: " << std::endl;
251  std::cout << "step: " << hh << std::endl;
252  std::cout << "abscissas: " << x-hh/2 << " " << x-hh << " "
253  << x+hh/2 << " " << x+hh << std::endl;
254  std::cout << "ordinates: " << fm1 << " " << fmh << " " << fph << " "
255  << fp1 << std::endl;
256  std::cout << "res: " << result << " trc: " << abserr_trunc
257  << " rnd: " << abserr_round << std::endl;
258  if (this->verbose>1) {
259  char ch;
260  std::cin >> ch;
261  }
262  }
263 
264  return 0;
265  }
266 
267 #endif
268 
269  };
270 
271 #ifndef DOXYGEN_NO_O2NS
272 }
273 #endif
274 
275 #endif
276 
277 
278 
double h_opt
The last value of the optimized stepsize.
Definition: deriv_gsl.h:135
int central_deriv(double x, double hh, double &result, double &abserr_round, double &abserr_trunc, func2_t &func)
Compute derivative using 5-point rule.
Definition: deriv_gsl.h:213
std::function< double(double)> funct11
One-dimensional function typedef.
Definition: funct.h:44
virtual int deriv_err(double x, func_t &func, double &dfdx, double &err)
Calculate the first derivative of func w.r.t. x and uncertainty.
Definition: deriv_gsl.h:140
double h
Initial stepsize.
Definition: deriv_gsl.h:128
Numerical differentiation base [abstract base].
Definition: deriv.h:55
Numerical differentiation (GSL)
Definition: deriv_gsl.h:110
virtual const char * type()
Return string denoting type ("deriv_gsl")
Definition: deriv_gsl.h:145
int verbose
Output control.
Definition: deriv.h:142
int deriv_tlate(double x, func2_t &func, double &dfdx, double &err)
Internal template version of the derivative function.
Definition: deriv_gsl.h:153
virtual int deriv_err_int(double x, funct11 &func, double &dfdx, double &err)
Internal version of calc_err() for second and third derivatives.
Definition: deriv_gsl.h:198

Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).
Hosted at Get Object-oriented Scientific Computing
Lib at SourceForge.net. Fast, secure and Free Open Source software
downloads..