Flow123d  JS_before_hm-1002-gafa1d04
interpolant.hh
Go to the documentation of this file.
1 /*!
2  *
3  * Copyright (C) 2015 Technical University of Liberec. All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU General Public License version 3 as published by the
7  * Free Software Foundation. (http://www.gnu.org/licenses/gpl-3.0.en.html)
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12  *
13  *
14  * @file interpolant.hh
15  * @brief
16  */
17 
18 #ifndef INTERPOLATION_H
19 #define INTERPOLATION_H
20 
21 #include <utility>
22 #include <vector>
23 #include "tools/include_fadbad.hh" // for "fadbad.h"
24 
25 template <class Type> class FunctorBase;
26 template <class Type> class IFunctorBase;
27 
28 /** This pair contains both the function and the first derivative values and is used
29  * to as return value for functions of interpolation objects.
30  * The reason is that the FADBAD++ library computes both function value and derivative value
31  * at the same time. So when we use FADBAD++ in interpolant classes to compute
32  * derivates, we also return both values and we stick to it in interpolation evaluation also.
33  * We use the form \verbatim pair<function_value, derivative_value> \endverbatim.
34  */
35 typedef std::pair<double,double> DiffValue;
36 
37 
38 /** Enumerates possible kinds of extrapolation.
39  */
41  {
42  typedef enum {constant, ///< means that the values at the boundary points will be used outside the interval_miss_a
43  linear, ///< means that the linear approximation on the first and last subintervals will be used outside the interval
44  functor ///< means that the original functor will be called outside interpolation interval
45  } Type;
46  };
47 
48 /** Enumerates possible norms in which the interpolation error can be computed.
49  */
50  struct ErrorNorm
51  {
52  typedef enum {l2, ///< L2 norm
53  lp, ///< Lp norm
54  w21, ///< W21 norm
55  wp1, ///< Wp1 norm
56  max ///< Maximum norm
57  } Type;
58  };
59 
60 /** Enumerates types of variable fixation in implicit interpolant.
61  */
62  struct IFixVariable
63  {
64  typedef enum { fix_x, ///< x variable will be fixed with given value
65  fix_y, ///< y variable will be fixed with given value
66  no_fix ///< no variable is fixed (used when InterpolantImplicit is created)
67  } Type;
68  };
69 
70 ///Base class for interpolation.
71 /** This class serves as the common interface for interpolation classes.
72  * It provides functions for setting the common parameters of an interpolation
73  * such as interval, size of the table and extrapolation.
74  *
75  * @see Interpolant
76  * @see InterpolantImplicit
77  */
79 {
80 public:
81  ///Default constructor.
83 
84  ///Destructor.
85  virtual ~InterpolantBase();
86 
87  ///@name Interpolation.
88  //@{
89  ///Returns error of the interpolation.
90  /**It is equal to the chosen norm of the difference divided by the lenght of interval.
91  * Returns -1.0 if the interpolation has not been computed yet.
92  */
93  double error();
94 
95  //Gettters
96  double bound_a() const; ///< Returns left boundary of the interval.
97  double bound_b() const; ///< Returns right boundary of the interval.
98  unsigned int size() const; ///< Returns the size of the interpolation table.
99 
100  ///Sets the interpolation interval boundaries.
101  /** @param bound_a is the left boundary of the interval
102  * @param bound_b is the right boundary of the interval
103  */
104  void set_interval(double bound_a,double bound_b);
105 
106  ///Sets size of the interpolation table. It is also equal to the number of intervals.
107  /** @param size is the new size of the interpolation table
108  */
109  void set_size(unsigned int size);
110 
111  ///Sets the type of norm used for computing estimate of the error of the interpolation.
112  /** @param norm_type is the type of norm in which the error of interpolation is computed
113  * @param p is the exponent used in norms \f$ L_p \f$ and \f$ W_p^1 \f$
114  */
115  void set_norm(ErrorNorm::Type norm_type=ErrorNorm::max, double p=2);
116 
117  /// Sets automatic choice of the size of the table.
118  /** When @p interpolate is called than the size is increased (by smaller interval dividing)
119  * until the given tolerance or the maximum size of the interpolation table is reached.
120  * @param user_tol is the tolerance which should the interpolation meet
121  * @param init_size is the initial choice of table size
122  * @param max_size is maximal size of the table that user allows
123  */
124  void set_size_automatic(double user_tol, unsigned int init_size, unsigned int max_size=default_max_size);
125 
126  ///Sets the type of extrapolation. Functor type is default.
127  /** @param extrapolation is the type of extrapolation (defined by enumeration @p ExtrapolationType)
128  */
129  void set_extrapolation(Extrapolation::Type extrapolation);
130 
131  ///Creates piecewise polynomial interpolation.
132  /** @return
133  * - 0 if interpolation has been created
134  * - 1 if the tolerance has not been satisfied (in case of automatic choice of size)
135  */
136  virtual int interpolate() = 0;
137  //@}
138 
139  /** @name Evaluation statistics.
140  * These members are used recording the statistics of the evaluation.
141  */
142  //@{
143  ///Structure that keeps statistics of evaluation.
144  typedef struct {
145  unsigned int interval_miss_a, ///< counts left misses of the interval
146  interval_miss_b, ///< counts right misses of the interval
147  total_calls; ///< counts total calls of evaluation
148 
149  double min, ///< minimal x for which the evaluation was called outside the interval (initially is equal the left boundary)
150  max; ///< maximal x for which the evaluation was called outside the interval ((initially is equal the right boundary)
151  } EvalStatistics;
152 
153  EvalStatistics statistics() const; ///< Returns structure with evaluation statistics.
154 
155  ///Resets all measured statistics.
156  void reset_stat();
157 
158  ///Can be called to check automatically the evaluation statistics and possibly reinterpolate.
159  /** The function computes ratio of evaluations outside the interpolation interval - on each side of the interval.
160  * Then it compares the results with given percentage and accordingly changes (only streches) the interval and reinterpolate.
161  * @param percentage is the percentage of evaluations outside the interval (on one side)
162  */
163  void check_stats_and_reinterpolate(double percentage=0.3);
164  //@}
165 
166 protected:
167  double bound_a_, ///< Left interval boundary.
168  bound_b_, ///< Right interval boundary.
169  step, ///< Chosen interpolation step.
170  a_div_step; ///< bound_ divided by step - precomputed value for evaluation
171 
172  unsigned int size_, ///< Number of dividing intervals.
173  n_nodes; ///< Number of nodes in the interval \f$(a,b)\f$.
174 
175  double user_tol; ///< User set tolerance which is used during automatic step choice.
176  unsigned int max_size;///< Maximal size of the interpolation table.
177  bool automatic_size; ///< Is true if step/size should be chosen automatically.
178  ErrorNorm::Type norm_type; ///< Type of norm used to compute error of the interpolation.
179  double p; ///< Exponent used in norms \f$ L_p \f$ and \f$ W_p^1 \f$ when computing error.
180 
181  double error_; ///< Error of the interpolation.
182 
183  /** Extrapolation type - 'what' is evaluated outside the interpolation interval.
184  * Default value after interpolant construction is InterpolantBase::functor.
185  */
187 
188 
189  const static unsigned int n_derivatives; ///< Defines how many derivatives we allow to be returned from Taylor's coeficients.
190  const static unsigned int default_max_size; ///< Default maximal size of the interpolation table.
191  const static double simpson_tolerance; ///< Tolerance in Adaptive Simpson intergration. @see AdaptiveSimpson
192 
193  ///Recursive factorial function (used in Taylor row expansion in n-th derivative computation).
194  long fact (long x);
195 
196 
197  ///@name Internal check system.
198  /// This is internal check system which checks the values of parameters before making interpolation.
199  //@{
200  struct Check{
201  ///Enumerates parameters that must be set before creation of the interpolant.
202  enum {functor, bound_a, bound_b, size
203  } Type;
204  };
205  ///Vector of boolean values telling us which parameters are set or not.
207  ///Checks that the parameters are set before interpolation.
208  void check_all();
209  //@}
210 
211 
212  //currently not used
213  //bool use_statistics; ///< Is true if statistics is checked (it must be switched of during error computation)
214  EvalStatistics stats; ///< Structure which keeps evaluation statistics. See \ref InterpolantBase::eval_statistics.
215 
216 };
217 
218 
219 /// The main class for interpolation of functors.
220 /** This class is a wrapper of a functor (defined by class \ref FunctorBase) which provides
221  * computation of derivates and interpolation of the functor. We will describe the functionality
222  * in the following paragrahphs.
223  *
224  * ## Evaluation of a functor and its derivatives
225  *
226  * Beside the interpolation, the class provides calling of the functor itself.
227  * All functions evaluating directly the functor starts with '`f_`', e.g. function \ref f_val computes the functor value.
228  *
229  * We use the FADBAD++ library ([website](http://www.fadbad.com)) to compute derivatives of the functor. First derivatives
230  * can be obtained by function \ref f_diff which uses backward automatic differentiation. Higher order derivatives can be
231  * obtained via \ref f_diffn which uses Taylor expansion method.
232  *
233  * ## Interpolation
234  *
235  * Sofar we provide only a piecewise linear interpolation. Both the function and its derivative can be
236  * interpolated. User has to provide the functor object to the constructor or later to the function \ref set_functor.
237  * Then one must set at least the interval \f$ [a,b]\f$ by \ref set_interval and the size of the interpolation table
238  * by \ref set_size before calling \ref interpolate. Otherwise assert will crash the program in debug build.
239  *
240  * When user wants the size to be chosen automatically then \ref set_size_automatic must be called at first.
241  * An initial guess of size of the interpolation table and a tolerance which is assumed to be the maximum relative difference
242  * between the function and the interpolant (sum of value and derivative difference) must be provided.
243  * Futher user can set the maximum size of the interpolation (default 1000) table which will not be exceeded and the type of norm
244  * in which the estimate of the error of interpolation will be computed (enumerated in \ref ErrorNorm, default maximal norm).
245  * See one of the following paragraphs to learn how we deal with the error of the interpolation.
246  *
247  * Outside the given interval the interpolation is extrapolated. User can choose among several types of extrapolation
248  * which are enumerated in \ref Extrapolation. Constant and linear extrapolation use the first and last interpolating polynomials
249  * to compute the value. Functor type means that the functor itself will be evaluated outside the interval. Type of extrapolation
250  * can be changed by \ref set_extrapolation function. Calling functor is the default type of extrapolation.
251  *
252  *
253  * ### Error of the interpolation
254  *
255  * We are interested in the maximum difference between the function value and its interpolation.
256  * When interpolating also the derivative, we need to compute the difference between derivative and
257  * its interpolation too.
258  * Therefore we would like to compute something like the L-infinity norm, relative to function value and its derivative.
259  * Let \f$ f(x), f'(x) \f$ be the function and its derivative and \f$ g(x), g'(x)\f$ interpolation of the function and interpolation
260  * of the derivative on the interval \f$ I \f$. We suggest an approximation of the infinity norm:
261  * \f[
262  * \|f-g\|_\infty = \sup_{x\in I} F(x) = \sup_{x\in I} \left( \frac{|f(x)-g(x)|}{|f(x)| + tol} + \frac{|f'(x)-g'(x)|}{|f'(x)| + tol} \right)
263  * \approx \max_{x\in J} \left( \frac{|f(x)-g(x)|}{|f(x)| + tol} + \frac{|f'(x)-g'(x)|}{|f'(x)| + tol} \right)
264  * \f]
265  * where \f$ J \f$ is set of points that lies in the middle of two neighboring nodes. \f$ tol \f$ is a given tolerance for zero (avoids zero division).
266  * When computing the size of the interpolation table automatically, we compare the user tolerance \f$ TOL \f$ given by \ref set_size_automatic funtion
267  * directly with the estimated value of the supremum norm.
268  *
269  * This approach is fast and when computing the size automatically, we use the computed values (middle points, function and derivative values) in next
270  * interpolation. On the other hand this does not work good around zero points of the function where the value is small and the fraction becomes large or does
271  * not converge when dividing the intervals (\f$ x^2 \f$ is a good example).
272  *
273  * Therefore we provide also error estimation with \f$ L_p \f$ and \f$ W_p^1 \f$ norm. Then the user given tolerance is compared
274  * as it is stated in the following inequation:
275  * \f[
276  * \left( \frac{\int \limits_I F^p(x) \,\rm{d} x}{|I|} \right)^{\frac{1}{p}} \leq TOL.
277  * \f]
278  * This approach is much more expensive but can give better results.
279  *
280  * TODO: Improve error computation. Suggest more robust method.
281  *
282  * ### Evaluation statistics
283  *
284  * We collect some statistics during the evaluation of the interpolant in the struct \ref InterpolantBase::EvalStatistics -- total number of calls, number of evaluations
285  * inside the interpolation interval and number of evaluation outside the interval. One can use these statistics to decide whether it is necessary
286  * to widen the interval and recompute the interpolation. Function \ref check_stats_and_reinterpolate is provided to do this automatically
287  * according to the given percentage of evaluation outside the interval.
288  *
289  */
290 
292 {
293 public:
294  ///Default constructor.
295  Interpolant();
296 
297  ///Constructor with functor setting.
298  /**
299  * @param func is the pointer to functor
300  * @param interpolate_derivative is true when derivate is also interpolated
301  * @tparam Func is the functor type
302  * @tparam Type is the template type of the functor (e.g. double)
303  */
304  template<template<class> class Func, class Type >
305  Interpolant(Func<Type>* func, bool interpolate_derivative=false);
306 
307  ///Destructor.
308  virtual ~Interpolant(void);
309 
310  ///@name Evaluation.
311  //@{
312  ///Returns interpolated value.
313  /** @param x is the point at which we evaluate the interpolation
314  */
315  double val(double x);
316 
317  ///Do NOT use, only for testing purpose.
318  /** TODO: After testing it can be removed and
319  * \ref val_p1 can be made private again.
320  */
321  double val_test(double x);
322 
323  ///Do NOT use, unless you are 100% sure.
324  /** This function evaluates the P1 interpolant at x.
325  * It does not check the interval, does not provide extrapolation
326  * and does not collect statistics.
327  *
328  * Can be used to POSSIBLY speed the evaluation just a little bit,
329  * if you are absolutely sure that you evaluate the interpolant
330  * only on the given interval and do not want to collect statistics.
331  *
332  * Same can be done with \ref diff_p1 if it is made public.
333  *
334  * Used in unit_test benchmark to compare with val function.
335  */
336  double val_p1(double x);
337 
338  ///Returns interpolated value of the derivation.
339  /** @param x is the point at which we evaluate the interpolation
340  */
341  DiffValue diff(double x);
342 
343  ///Returns value of the original functor.
344  /** @param x is the point at which we evaluate the original functor
345  */
346  double f_val(double x);
347 
348  ///Returns 1st derivative of original functor using FADBAD.
349  /** @param x is the point at which we evaluate the original functor
350  */
351  DiffValue f_diff (double x);
352 
353  /** Returns n-th derivative of original functor using FADBAD.
354  * Uses coeficients in Taylor's row.
355  * @param x is the point at which we evaluate the original functor
356  * @param n is the order of the derivative we want
357  */
358  double f_diffn(double x, unsigned int n);
359  //@}
360 
361 
362  ///@name Interpolation.
363  //@{
364  ///Creates piecewise interpolation with polynomials of selected degree.
365  virtual int interpolate();
366 
367  ///Sets the functor.
368  /** Can be used when the functor is not set in the constructor.
369  * @param func is the pointer to functor
370  * @param interpolate_derivative is true when derivate is also interpolated
371  * @tparam Func is the functor type
372  * @tparam Type is the template type of the functor (e.g. double)
373  */
374  template<template<class> class Func, class Type >
375  void set_functor(Func<Type>* func, bool interpolate_derivative=false);
376  //@}
377 
378 protected:
379  class FuncError_lp;
381 
382  FunctorBase<double>* func; ///< Pointer to original functor with double type.
383  FunctorBase<B<double> >* func_diff; ///< Pointer to original functor with FADBAD B type.
384  FunctorBase<T<double> >* func_diffn; ///< Pointer to original functor with FADBAD T type.
385 
386  bool interpolate_derivative; ///< Is true if we want to interpolate the derivative too.
387 
388  //std::vector<double> x_vec; ///< Vector of nodes.
389  std::vector<double> f_vec; ///< Vector of function values at nodes.
390  std::vector<double> df_vec; ///< Vector of function derivatives values at nodes.
391  //std::vector<double> p1_vec; ///< Vector of linear coeficients of P1 interpolation.
392  //std::vector<double> p1d_vec; ///< Vector of linear coeficients of P1 interpolation.
393 
394  //Creates piecewise constant interpolation.
395  //void interpolate_p0();
396 
397  ///Creates piecewise linear interpolation.
398  //void interpolate_p1();
399 
400  ///Computes estimate of interpolation error in maximum norm.
401  void compute_error(double tol, std::vector<double>& f, std::vector<double>& df);
402 
403  ///Computes estimate of interpolation error with given norm.
404  void compute_error(double tol, double p, ErrorNorm::Type norm_type);
405 
406  void swap_middle_values(std::vector<double>& f, std::vector<double>& df);
407 
408  ///Creates table of nodes and function values.
409  /** Creates vector of nodes according to the table size
410  * and computes function and derivative values at the nodes.
411  */
412  void compute_values();
413 
414  ///Finds interval on which @p x lies.
415  //unsigned int find_interval(double x);
416 
417 
418  ///Function that evaluates the derivative of P1 interpolant at @p x.
419  DiffValue diff_p1(double x);
420 };
421 
422 
423 
424 
425 
427 {
428 public:
429 
430  ///@name Construction.
431  //@{
432  ///constructor
434 
435  ///Constructor with functor setting.
436  /**
437  * @param func is the pointer to functor
438  * @param interpolate_derivative is true when derivate is also interpolated
439  * @tparam Func is the functor type
440  * @tparam Type is the template type of the functor (e.g. double)
441  */
442  template<template<class> class Func, class Type >
443  InterpolantImplicit(Func<Type>* func, bool interpolate_derivative=false);
444 
445  ///destructor
446  virtual ~InterpolantImplicit(void);
447 
448  ///Sets the implicit functor.
449  /**
450  * @param func is the pointer to implicit functor.
451  * @tparam Func is the functor class.
452  * @tparam Type is the template type of the functor (e.g. double)
453  */
454  template<template<class> class Func, class Type >
455  void set_functor(Func<Type>* func, bool interpolate_derivative=false);
456 
457  //@}
458 
459  ///@name Evaluation.
460  //@{
461 
462  /** Fixes the chosen variable and sets its fixed value.
463  * @param fix is the chosen variable (no_fix, fix_x or fix_y)
464  * @param value is the fixed value
465  */
466  void fix_variable(IFixVariable::Type fix, double value);
467 
468  ///Returns interpolated value.
469  /** @param u is the point at which we evaluate the interpolation
470  */
471  double val(double u);
472 
473  ///Returns interpolated value of the derivation.
474  /** @param u is the point at which we evaluate the interpolation
475  */
476  DiffValue diff(double u);
477 
478  ///Returns interpolated value of the derivation.
479  /** @param x is the point at which we evaluate the interpolation
480  */
481  //double diffn(const double& x, const unsigned int& n);
482 
483  ///Returns value of the original functor.
484  /** @param x is function variable.
485  * @param y is function variable.
486  */
487  double f_val(double x, double y);
488 
489  ///Returns value of the original functor when one of the variables is fixed.
490  /** @param u is function variable (the one not fixed).
491  */
492  double f_val(double u);
493 
494  ///Returns 1st derivative of original functor using FADBAD.
495  /** @param x is function variable.
496  * @param y is function variable.
497  */
498  DiffValue f_diff (double x, double y);
499 
500  /** Returns n-th derivative of original functor using FADBAD.
501  * Uses coeficients in Taylor's row.
502  * @param u is the point at which we evaluate the original functor
503  * @param n is the order of the derivative we want
504  */
505  double f_diffn(double u, unsigned int n);
506  //@}
507 
508 
509  ///@name Interpolation.
510  //@{
511 
512  ///Creates piecewise interpolation with polynomials of selected degree.
513  virtual int interpolate();
514 
515 
516  //@}
517 
518 
519 protected:
520 
521  template<class Type=double>
523 
528 
529  bool interpolate_derivative; ///< Is true if we want to interpolate the derivative too.
530 
532 
534  double fix_val;
535 
536  ///@name Interpolation.
537  //@{
538 
539  ///Creates piecewise linear interpolation.
540  void interpolate_p1();
541 
542  //@}
543 
544 };
545 
546 #endif
FunctorBase< B< double > > * func_diff
Pointer to original functor with FADBAD B type.
Definition: interpolant.hh:383
bool automatic_size
Is true if step/size should be chosen automatically.
Definition: interpolant.hh:177
ErrorNorm::Type norm_type
Type of norm used to compute error of the interpolation.
Definition: interpolant.hh:178
Lp norm.
Definition: interpolant.hh:53
static const double simpson_tolerance
Tolerance in Adaptive Simpson intergration.
Definition: interpolant.hh:191
bool interpolate_derivative
Is true if we want to interpolate the derivative too.
Definition: interpolant.hh:529
static const unsigned int default_max_size
Default maximal size of the interpolation table.
Definition: interpolant.hh:190
Abstract templated implicit functor class.
Definition: functors.hh:128
unsigned int total_calls
counts total calls of evaluation
Definition: interpolant.hh:145
double user_tol
User set tolerance which is used during automatic step choice.
Definition: interpolant.hh:175
std::vector< double > df_vec
Vector of function derivatives values at nodes.
Definition: interpolant.hh:390
FunctorBase< T< double > > * func_diffn
Pointer to original functor with FADBAD T type.
Definition: interpolant.hh:384
std::pair< double, double > DiffValue
Definition: interpolant.hh:26
Base class for interpolation.
Definition: interpolant.hh:78
std::vector< double > f_vec
Vector of function values at nodes.
Definition: interpolant.hh:389
double error_
Error of the interpolation.
Definition: interpolant.hh:181
static constexpr bool value
Definition: json.hpp:87
IFunctorBase< B< double > > * func_diff
Definition: interpolant.hh:526
Interpolant * explicit_interpolant
Definition: interpolant.hh:531
Wp1 norm.
Definition: interpolant.hh:55
means that the linear approximation on the first and last subintervals will be used outside the inter...
Definition: interpolant.hh:43
Structure that keeps statistics of evaluation.
Definition: interpolant.hh:144
unsigned int max_size
Maximal size of the interpolation table.
Definition: interpolant.hh:176
Abstract templated explicit functor class.
FunctorBase< double > * func
Pointer to original functor with double type.
Definition: interpolant.hh:380
means that the values at the boundary points will be used outside the interval_miss_a ...
Definition: interpolant.hh:42
W21 norm.
Definition: interpolant.hh:54
double step
Chosen interpolation step.
Definition: interpolant.hh:167
means that the original functor will be called outside interpolation interval
Definition: interpolant.hh:44
IFixVariable::Type fix_
Definition: interpolant.hh:533
std::vector< bool > checks
Vector of boolean values telling us which parameters are set or not.
Definition: interpolant.hh:206
EvalStatistics stats
Structure which keeps evaluation statistics. See InterpolantBase::eval_statistics.
Definition: interpolant.hh:214
Extrapolation::Type extrapolation
Definition: interpolant.hh:186
The main class for interpolation of functors.
Definition: interpolant.hh:291
IFunctorBase< T< double > > * func_diffn
Definition: interpolant.hh:527
IFunctorBase< double > * func
Definition: interpolant.hh:525
FuncExplicit< double > * func_u
Definition: interpolant.hh:522
bool interpolate_derivative
Is true if we want to interpolate the derivative too.
Definition: interpolant.hh:386
static const unsigned int n_derivatives
Defines how many derivatives we allow to be returned from Taylor&#39;s coeficients.
Definition: interpolant.hh:189
y variable will be fixed with given value
Definition: interpolant.hh:65
double p
Exponent used in norms and when computing error.
Definition: interpolant.hh:179
double min
minimal x for which the evaluation was called outside the interval (initially is equal the left bound...
Definition: interpolant.hh:149
Maximum norm.
Definition: interpolant.hh:56
unsigned int size_
Number of dividing intervals.
Definition: interpolant.hh:172