Reference documentation for deal.II version 9.0.0
polynomial.h
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2000 - 2018 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE at
12 // the top level of the deal.II distribution.
13 //
14 // ---------------------------------------------------------------------
15 
16 #ifndef dealii_polynomial_h
17 #define dealii_polynomial_h
18 
19 
20 
21 #include <deal.II/base/config.h>
22 #include <deal.II/base/exceptions.h>
23 #include <deal.II/base/subscriptor.h>
24 #include <deal.II/base/point.h>
25 
26 #include <memory>
27 #include <vector>
28 
29 DEAL_II_NAMESPACE_OPEN
30 
40 namespace Polynomials
41 {
42 
61  template <typename number>
62  class Polynomial : public Subscriptor
63  {
64  public:
73  Polynomial (const std::vector<number> &coefficients);
74 
78  Polynomial (const unsigned int n);
79 
87  Polynomial (const std::vector<Point<1> > &lagrange_support_points,
88  const unsigned int evaluation_point);
89 
93  Polynomial ();
94 
102  number value (const number x) const;
103 
114  void value (const number x,
115  std::vector<number> &values) const;
116 
128  void value (const number x,
129  const unsigned int n_derivatives,
130  number *values) const;
131 
137  unsigned int degree () const;
138 
146  void scale (const number factor);
147 
163  template <typename number2>
164  void shift (const number2 offset);
165 
170 
175  Polynomial<number> primitive () const;
176 
180  Polynomial<number> &operator *= (const double s);
181 
186 
191 
196 
200  bool operator == (const Polynomial<number> &p) const;
201 
205  void print(std::ostream &out) const;
206 
211  template <class Archive>
212  void serialize (Archive &ar, const unsigned int version);
213 
214  protected:
215 
219  static void scale (std::vector<number> &coefficients,
220  const number factor);
221 
225  template <typename number2>
226  static void shift (std::vector<number> &coefficients,
227  const number2 shift);
228 
232  static void multiply (std::vector<number> &coefficients,
233  const number factor);
234 
241 
250  std::vector<number> coefficients;
251 
257 
262  std::vector<number> lagrange_support_points;
263 
269  };
270 
271 
278  template <typename number>
279  class Monomial : public Polynomial<number>
280  {
281  public:
286  Monomial(const unsigned int n,
287  const double coefficient = 1.);
288 
295  static
296  std::vector<Polynomial<number> >
297  generate_complete_basis (const unsigned int degree);
298 
299  private:
303  static std::vector<number> make_vector(unsigned int n,
304  const double coefficient);
305  };
306 
307 
325  class LagrangeEquidistant: public Polynomial<double>
326  {
327  public:
333  LagrangeEquidistant (const unsigned int n,
334  const unsigned int support_point);
335 
344  static
345  std::vector<Polynomial<double> >
346  generate_complete_basis (const unsigned int degree);
347 
348  private:
349 
354  static
355  void
356  compute_coefficients (const unsigned int n,
357  const unsigned int support_point,
358  std::vector<double> &a);
359  };
360 
361 
362 
369  std::vector<Polynomial<double> >
370  generate_complete_Lagrange_basis (const std::vector<Point<1> > &points);
371 
372 
373 
389  class Legendre : public Polynomial<double>
390  {
391  public:
395  Legendre (const unsigned int p);
396 
403  static
404  std::vector<Polynomial<double> >
405  generate_complete_basis (const unsigned int degree);
406  };
407 
429  class Lobatto : public Polynomial<double>
430  {
431  public:
436  Lobatto (const unsigned int p = 0);
437 
442  static std::vector<Polynomial<double> >
443  generate_complete_basis (const unsigned int p);
444 
445  private:
449  std::vector<double> compute_coefficients (const unsigned int p);
450  };
451 
452 
453 
493  class Hierarchical : public Polynomial<double>
494  {
495  public:
500  Hierarchical (const unsigned int p);
501 
512  static
513  std::vector<Polynomial<double> >
514  generate_complete_basis (const unsigned int degree);
515 
516  private:
520  static void compute_coefficients (const unsigned int p);
521 
526  static const std::vector<double> &
527  get_coefficients (const unsigned int p);
528 
537  static std::vector<std::unique_ptr<const std::vector<double> > > recursive_coefficients;
538  };
539 
540 
541 
572  class HermiteInterpolation : public Polynomial<double>
573  {
574  public:
579  HermiteInterpolation (const unsigned int p);
580 
586  static std::vector<Polynomial<double> >
587  generate_complete_basis (const unsigned int p);
588  };
589 
590 
591 
693  class HermiteLikeInterpolation : public Polynomial<double>
694  {
695  public:
700  HermiteLikeInterpolation (const unsigned int degree,
701  const unsigned int index);
702 
707  static std::vector<Polynomial<double> >
708  generate_complete_basis (const unsigned int degree);
709  };
710 
711 
712 
713  /*
714  * Evaluate a Jacobi polynomial @f$ P_n^{\alpha, \beta}(x) @f$ specified by the
715  * parameters @p alpha, @p beta, @p n, where @p n is the degree of the
716  * Jacobi polynomial.
717  *
718  * @note The Jacobi polynomials are not orthonormal and are defined on the
719  * unit interval @f$[0, 1]@f$ as usual for deal.II, rather than @f$[-1, +1]@f$ often
720  * used in literature. @p x is the point of evaluation.
721  */
722  template <typename Number>
723  Number
724  jacobi_polynomial_value(const unsigned int degree,
725  const int alpha,
726  const int beta,
727  const Number x);
728 
729 
742  template <typename Number>
743  std::vector<Number>
744  jacobi_polynomial_roots(const unsigned int degree,
745  const int alpha,
746  const int beta);
747 }
748 
749 
752 /* -------------------------- inline functions --------------------- */
753 
754 namespace Polynomials
755 {
756  template <typename number>
757  inline
759  :
760  in_lagrange_product_form (false),
761  lagrange_weight (1.)
762  {}
763 
764 
765 
766  template <typename number>
767  inline
768  unsigned int
770  {
771  if (in_lagrange_product_form == true)
772  {
773  return lagrange_support_points.size();
774  }
775  else
776  {
777  Assert (coefficients.size()>0, ExcEmptyObject());
778  return coefficients.size() - 1;
779  }
780  }
781 
782 
783 
784  template <typename number>
785  inline
786  number
787  Polynomial<number>::value (const number x) const
788  {
789  if (in_lagrange_product_form == false)
790  {
791  Assert (coefficients.size() > 0, ExcEmptyObject());
792 
793  // Horner scheme
794  const unsigned int m=coefficients.size();
795  number value = coefficients.back();
796  for (int k=m-2; k>=0; --k)
797  value = value*x + coefficients[k];
798  return value;
799  }
800  else
801  {
802  // direct evaluation of Lagrange polynomial
803  const unsigned int m = lagrange_support_points.size();
804  number value = 1.;
805  for (unsigned int j=0; j<m; ++j)
806  value *= x-lagrange_support_points[j];
807  value *= lagrange_weight;
808  return value;
809  }
810  }
811 
812 
813 
814  template <typename number>
815  template <class Archive>
816  inline
817  void
818  Polynomial<number>::serialize (Archive &ar, const unsigned int)
819  {
820  // forward to serialization function in the base class.
821  ar &static_cast<Subscriptor &>(*this);
822  ar &coefficients;
823  ar &in_lagrange_product_form;
824  ar &lagrange_support_points;
825  ar &lagrange_weight;
826  }
827 
828 
829 
830  template <typename Number>
831  Number
832  jacobi_polynomial_value(const unsigned int degree,
833  const int alpha,
834  const int beta,
835  const Number x)
836  {
837  Assert(alpha >=0 && beta >= 0,
838  ExcNotImplemented("Negative alpha/beta coefficients not supported"));
839  // the Jacobi polynomial is evaluated using a recursion formula.
840  Number p0, p1;
841 
842  // The recursion formula is defined for the interval [-1, 1], so rescale
843  // to that interval here
844  const Number xeval = Number(-1) + 2. * x;
845 
846  // initial values P_0(x), P_1(x):
847  p0 = 1.0;
848  if (degree==0)
849  return p0;
850  p1 = ((alpha+beta+2)*xeval + (alpha-beta))/2;
851  if (degree==1)
852  return p1;
853 
854  for (unsigned int i=1; i<degree; ++i)
855  {
856  const Number v = 2*i + (alpha + beta);
857  const Number a1 = 2*(i+1)*(i + (alpha + beta + 1))*v;
858  const Number a2 = (v + 1)*(alpha*alpha - beta*beta);
859  const Number a3 = v*(v + 1)*(v + 2);
860  const Number a4 = 2*(i+alpha)*(i+beta)*(v + 2);
861 
862  const Number pn = ((a2 + a3*xeval)*p1 - a4*p0)/a1;
863  p0 = p1;
864  p1 = pn;
865  }
866  return p1;
867  }
868 
869 
870 
871  template <typename Number>
872  std::vector<Number>
873  jacobi_polynomial_roots(const unsigned int degree,
874  const int alpha,
875  const int beta)
876  {
877  std::vector<Number> x(degree, 0.5);
878 
879  // compute zeros with a Newton algorithm.
880 
881  // Set tolerance. For long double we might not always get the additional
882  // precision in a run time environment (e.g. with valgrind), so we must
883  // limit the tolerance to double. Since we do a Newton iteration, doing
884  // one more iteration after the residual has indicated convergence will be
885  // enough for all number types due to the quadratic convergence of
886  // Newton's method
887 
888  const Number tolerance
889  = 4 * std::max(static_cast<Number>(std::numeric_limits<double>::epsilon()),
890  std::numeric_limits<Number>::epsilon());
891 
892  // The following implementation follows closely the one given in the
893  // appendix of the book by Karniadakis and Sherwin: Spectral/hp element
894  // methods for computational fluid dynamics (Oxford University Press,
895  // 2005)
896 
897  // If symmetric, we only need to compute the half of points
898  const unsigned int n_points = (alpha == beta ? degree/2 : degree);
899  for (unsigned int k=0; k<n_points; ++k)
900  {
901  // we take the zeros of the Chebyshev polynomial (alpha=beta=-0.5) as
902  // initial values, corrected by the initial value
903  Number r = 0.5-0.5*std::cos(static_cast<Number> (2*k+1)/(2*degree) *
904  numbers::PI );
905  if (k>0)
906  r = (r + x[k-1])/2;
907 
908  unsigned int converged = numbers::invalid_unsigned_int;
909  for (unsigned int it=1; it<1000; ++it)
910  {
911  Number s = 0.;
912  for (unsigned int i=0; i<k; ++i)
913  s += 1./(r - x[i]);
914 
915  // derivative of P_n^{alpha,beta}, rescaled to [0, 1]
916  const Number J_x = (alpha+beta+degree+1)*
917  jacobi_polynomial_value(degree-1, alpha+1,
918  beta+1, r);
919 
920  // value of P_n^{alpha,beta}
921  const Number f = jacobi_polynomial_value(degree, alpha, beta, r);
922  const Number delta = f/(f*s - J_x);
923  r += delta;
924  if (converged == numbers::invalid_unsigned_int &&
925  std::abs(delta) < tolerance)
926  converged = it;
927 
928  // do one more iteration to ensure accuracy also for tighter
929  // types than double (e.g. long double)
930  if (it == converged + 1)
931  break;
932  }
933 
935  ExcMessage("Newton iteration for zero of Jacobi polynomial "
936  "did not converge."));
937 
938  x[k] = r;
939  }
940 
941  // in case we assumed symmetry, fill up the missing values
942  for (unsigned int k=n_points; k<degree; ++k)
943  x[k] = 1.0-x[degree-k-1];
944 
945  return x;
946  }
947 
948 }
949 DEAL_II_NAMESPACE_CLOSE
950 
951 #endif
static const unsigned int invalid_unsigned_int
Definition: types.h:173
void serialize(Archive &ar, const unsigned int version)
Definition: polynomial.h:818
Polynomial< number > & operator*=(const double s)
Definition: polynomial.cc:338
void scale(const number factor)
Definition: polynomial.cc:301
void transform_into_standard_form()
Definition: polynomial.cc:248
bool operator==(const Polynomial< number > &p) const
Definition: polynomial.cc:480
LagrangeEquidistant(const unsigned int n, const unsigned int support_point)
Definition: polynomial.cc:723
Polynomial< number > derivative() const
Definition: polynomial.cc:594
void shift(const number2 offset)
Definition: polynomial.cc:575
static std::vector< Polynomial< double > > generate_complete_basis(const unsigned int p)
Definition: polynomial.cc:960
unsigned int degree() const
Definition: polynomial.h:769
static std::vector< Polynomial< double > > generate_complete_basis(const unsigned int degree)
Definition: polynomial.cc:1140
Legendre(const unsigned int p)
Definition: polynomial.cc:846
static std::vector< Polynomial< double > > generate_complete_basis(const unsigned int degree)
Definition: polynomial.cc:874
Polynomial< number > & operator-=(const Polynomial< number > &p)
Definition: polynomial.cc:444
static std::vector< std::unique_ptr< const std::vector< double > > > recursive_coefficients
Definition: polynomial.h:537
std::vector< Polynomial< double > > generate_complete_Lagrange_basis(const std::vector< Point< 1 > > &points)
Definition: polynomial.cc:830
std::vector< Number > jacobi_polynomial_roots(const unsigned int degree, const int alpha, const int beta)
Definition: polynomial.h:873
static void compute_coefficients(const unsigned int n, const unsigned int support_point, std::vector< double > &a)
Definition: polynomial.cc:748
static std::vector< Polynomial< double > > generate_complete_basis(const unsigned int degree)
Definition: polynomial.cc:807
Monomial(const unsigned int n, const double coefficient=1.)
Definition: polynomial.cc:683
number value(const number x) const
Definition: polynomial.h:787
Definition: point.h:104
void print(std::ostream &out) const
Definition: polynomial.cc:650
std::vector< double > compute_coefficients(const unsigned int p)
Definition: polynomial.cc:892
static const double PI
Definition: numbers.h:127
static ::ExceptionBase & ExcMessage(std::string arg1)
static void multiply(std::vector< number > &coefficients, const number factor)
Definition: polynomial.cc:326
#define Assert(cond, exc)
Definition: exceptions.h:1142
Polynomial< number > & operator+=(const Polynomial< number > &p)
Definition: polynomial.cc:402
HermiteInterpolation(const unsigned int p)
Definition: polynomial.cc:1168
Lobatto(const unsigned int p=0)
Definition: polynomial.cc:888
static std::vector< Polynomial< number > > generate_complete_basis(const unsigned int degree)
Definition: polynomial.cc:692
static std::vector< number > make_vector(unsigned int n, const double coefficient)
Definition: polynomial.cc:672
Hierarchical(const unsigned int p)
Definition: polynomial.cc:982
HermiteLikeInterpolation(const unsigned int degree, const unsigned int index)
Definition: polynomial.cc:1281
std::vector< number > coefficients
Definition: polynomial.h:250
Polynomial< number > primitive() const
Definition: polynomial.cc:623
static void compute_coefficients(const unsigned int p)
Definition: polynomial.cc:990
static const std::vector< double > & get_coefficients(const unsigned int p)
Definition: polynomial.cc:1124
std::vector< number > lagrange_support_points
Definition: polynomial.h:262
static std::vector< Polynomial< double > > generate_complete_basis(const unsigned int degree)
Definition: polynomial.cc:1501
static ::ExceptionBase & ExcEmptyObject()
static ::ExceptionBase & ExcNotImplemented()
static std::vector< Polynomial< double > > generate_complete_basis(const unsigned int p)
Definition: polynomial.cc:1221