Reference documentation for deal.II version 9.0.0
polynomial.cc
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 #include <deal.II/base/exceptions.h>
17 #include <deal.II/base/point.h>
18 #include <deal.II/base/polynomial.h>
19 #include <deal.II/base/quadrature_lib.h>
20 #include <deal.II/base/std_cxx14/memory.h>
21 #include <deal.II/base/thread_management.h>
22 
23 #include <cmath>
24 #include <algorithm>
25 #include <limits>
26 
27 DEAL_II_NAMESPACE_OPEN
28 
29 
30 
31 // have a lock that guarantees that at most one thread is changing and
32 // accessing the @p{coefficients} arrays of classes implementing
33 // polynomials with tables. make this lock local to this file.
34 //
35 // having only one lock for all of these classes is probably not going
36 // to be a problem since we only need it on very rare occasions. if
37 // someone finds this is a bottleneck, feel free to replace it by a
38 // more fine-grained solution
39 namespace
40 {
41  Threads::Mutex coefficients_lock;
42 }
43 
44 
45 
46 namespace Polynomials
47 {
48 
49 // -------------------- class Polynomial ---------------- //
50 
51 
52  template <typename number>
53  Polynomial<number>::Polynomial (const std::vector<number> &a)
54  :
55  coefficients (a),
56  in_lagrange_product_form (false),
57  lagrange_weight (1.)
58  {}
59 
60 
61 
62  template <typename number>
63  Polynomial<number>::Polynomial (const unsigned int n)
64  :
65  coefficients (n+1, 0.),
66  in_lagrange_product_form (false),
67  lagrange_weight (1.)
68  {}
69 
70 
71 
72  template <typename number>
73  Polynomial<number>::Polynomial (const std::vector<Point<1> > &supp,
74  const unsigned int center)
75  :
76  in_lagrange_product_form (true)
77  {
78  Assert (supp.size()>0, ExcEmptyObject());
79  AssertIndexRange (center, supp.size());
80 
81  lagrange_support_points.reserve (supp.size()-1);
82  number tmp_lagrange_weight = 1.;
83  for (unsigned int i=0; i<supp.size(); ++i)
84  if (i!=center)
85  {
86  lagrange_support_points.push_back(supp[i](0));
87  tmp_lagrange_weight *= supp[center](0) - supp[i](0);
88  }
89 
90  // check for underflow and overflow
91  Assert (std::fabs(tmp_lagrange_weight) > std::numeric_limits<number>::min(),
92  ExcMessage ("Underflow in computation of Lagrange denominator."));
93  Assert (std::fabs(tmp_lagrange_weight) < std::numeric_limits<number>::max(),
94  ExcMessage ("Overflow in computation of Lagrange denominator."));
95 
96  lagrange_weight = static_cast<number>(1.)/tmp_lagrange_weight;
97  }
98 
99 
100 
101  template <typename number>
102  void
103  Polynomial<number>::value (const number x,
104  std::vector<number> &values) const
105  {
106  Assert (values.size() > 0, ExcZero());
107 
108  value(x,values.size()-1,values.data());
109  }
110 
111 
112 
113  template <typename number>
114  void
115  Polynomial<number>::value (const number x,
116  const unsigned int n_derivatives,
117  number *values) const
118  {
119  // evaluate Lagrange polynomial and derivatives
120  if (in_lagrange_product_form == true)
121  {
122  // to compute the value and all derivatives of a polynomial of the
123  // form (x-x_1)*(x-x_2)*...*(x-x_n), expand the derivatives like
124  // automatic differentiation does.
125  const unsigned int n_supp = lagrange_support_points.size();
126  switch (n_derivatives)
127  {
128  default:
129  values[0] = 1;
130  for (unsigned int d=1; d<=n_derivatives; ++d)
131  values[d] = 0;
132  for (unsigned int i=0; i<n_supp; ++i)
133  {
134  const number v = x-lagrange_support_points[i];
135 
136  // multiply by (x-x_i) and compute action on all derivatives,
137  // too (inspired from automatic differentiation: implement the
138  // product rule for the old value and the new variable 'v',
139  // i.e., expand value v and derivative one). since we reuse a
140  // value from the next lower derivative from the steps before,
141  // need to start from the highest derivative
142  for (unsigned int k=n_derivatives; k>0; --k)
143  values[k] = (values[k] * v + values[k-1]);
144  values[0] *= v;
145  }
146  // finally, multiply by the weight in the Lagrange
147  // denominator. Could be done instead of setting values[0] = 1
148  // above, but that gives different accumulation of round-off
149  // errors (multiplication is not associative) compared to when we
150  // computed the weight, and hence a basis function might not be
151  // exactly one at the center point, which is nice to have. We also
152  // multiply derivatives by k! to transform the product p_n =
153  // p^(n)(x)/k! into the actual form of the derivative
154  {
155  number k_faculty = 1;
156  for (unsigned int k=0; k<=n_derivatives; ++k)
157  {
158  values[k] *= k_faculty * lagrange_weight;
159  k_faculty *= static_cast<number>(k+1);
160  }
161  }
162  break;
163 
164  // manually implement case 0 (values only), case 1 (value + first
165  // derivative), and case 2 (up to second derivative) since they
166  // might be called often. then, we can unroll the loop.
167  case 0:
168  values[0] = 1;
169  for (unsigned int i=0; i<n_supp; ++i)
170  {
171  const number v = x-lagrange_support_points[i];
172  values[0] *= v;
173  }
174  values[0] *= lagrange_weight;
175  break;
176 
177  case 1:
178  values[0] = 1;
179  values[1] = 0;
180  for (unsigned int i=0; i<n_supp; ++i)
181  {
182  const number v = x-lagrange_support_points[i];
183  values[1] = values[1] * v + values[0];
184  values[0] *= v;
185  }
186  values[0] *= lagrange_weight;
187  values[1] *= lagrange_weight;
188  break;
189 
190  case 2:
191  values[0] = 1;
192  values[1] = 0;
193  values[2] = 0;
194  for (unsigned int i=0; i<n_supp; ++i)
195  {
196  const number v = x-lagrange_support_points[i];
197  values[2] = values[2] * v + values[1];
198  values[1] = values[1] * v + values[0];
199  values[0] *= v;
200  }
201  values[0] *= lagrange_weight;
202  values[1] *= lagrange_weight;
203  values[2] *= static_cast<number>(2) * lagrange_weight;
204  break;
205  }
206  return;
207  }
208 
209  Assert (coefficients.size() > 0, ExcEmptyObject());
210 
211  // if we only need the value, then call the other function since that is
212  // significantly faster (there is no need to allocate and free memory,
213  // which is really expensive compared to all the other operations!)
214  if (n_derivatives == 0)
215  {
216  values[0] = value(x);
217  return;
218  };
219 
220  // if there are derivatives needed, then do it properly by the full Horner
221  // scheme
222  const unsigned int m=coefficients.size();
223  std::vector<number> a(coefficients);
224  unsigned int j_faculty=1;
225 
226  // loop over all requested derivatives. note that derivatives @p{j>m} are
227  // necessarily zero, as they differentiate the polynomial more often than
228  // the highest power is
229  const unsigned int min_valuessize_m=std::min(n_derivatives+1, m);
230  for (unsigned int j=0; j<min_valuessize_m; ++j)
231  {
232  for (int k=m-2; k>=static_cast<int>(j); --k)
233  a[k]+=x*a[k+1];
234  values[j]=static_cast<number>(j_faculty)*a[j];
235 
236  j_faculty*=j+1;
237  }
238 
239  // fill higher derivatives by zero
240  for (unsigned int j=min_valuessize_m; j<=n_derivatives; ++j)
241  values[j] = 0;
242  }
243 
244 
245 
246  template <typename number>
247  void
249  {
250  // should only be called when the product form is active
251  Assert (in_lagrange_product_form == true, ExcInternalError());
252  Assert (coefficients.size() == 0, ExcInternalError());
253 
254  // compute coefficients by expanding the product (x-x_i) term by term
255  coefficients.resize (lagrange_support_points.size()+1);
256  if (lagrange_support_points.size() == 0)
257  coefficients[0] = 1.;
258  else
259  {
260  coefficients[0] = -lagrange_support_points[0];
261  coefficients[1] = 1.;
262  for (unsigned int i=1; i<lagrange_support_points.size(); ++i)
263  {
264  coefficients[i+1] = 1.;
265  for (unsigned int j=i; j>0; --j)
266  coefficients[j] = (-lagrange_support_points[i]*coefficients[j] +
267  coefficients[j-1]);
268  coefficients[0] *= -lagrange_support_points[i];
269  }
270  }
271  for (unsigned int i=0; i<lagrange_support_points.size()+1; ++i)
272  coefficients[i] *= lagrange_weight;
273 
274  // delete the product form data
275  std::vector<number> new_points;
276  lagrange_support_points.swap(new_points);
277  in_lagrange_product_form = false;
278  lagrange_weight = 1.;
279  }
280 
281 
282 
283  template <typename number>
284  void
285  Polynomial<number>::scale (std::vector<number> &coefficients,
286  const number factor)
287  {
288  number f = 1.;
289  for (typename std::vector<number>::iterator c = coefficients.begin();
290  c != coefficients.end(); ++c)
291  {
292  *c *= f;
293  f *= factor;
294  }
295  }
296 
297 
298 
299  template <typename number>
300  void
301  Polynomial<number>::scale (const number factor)
302  {
303  // to scale (x-x_0)*(x-x_1)*...*(x-x_n), scale
304  // support points by 1./factor and the weight
305  // likewise
306  if (in_lagrange_product_form == true)
307  {
308  number inv_fact = number(1.)/factor;
309  number accumulated_fact = 1.;
310  for (unsigned int i=0; i<lagrange_support_points.size(); ++i)
311  {
312  lagrange_support_points[i] *= inv_fact;
313  accumulated_fact *= factor;
314  }
315  lagrange_weight *= accumulated_fact;
316  }
317  // otherwise, use the function above
318  else
319  scale (coefficients, factor);
320  }
321 
322 
323 
324  template <typename number>
325  void
326  Polynomial<number>::multiply (std::vector<number> &coefficients,
327  const number factor)
328  {
329  for (typename std::vector<number>::iterator c = coefficients.begin();
330  c != coefficients.end(); ++c)
331  *c *= factor;
332  }
333 
334 
335 
336  template <typename number>
339  {
340  if (in_lagrange_product_form == true)
341  lagrange_weight *= s;
342  else
343  {
344  for (typename std::vector<number>::iterator c = coefficients.begin();
345  c != coefficients.end(); ++c)
346  *c *= s;
347  }
348  return *this;
349  }
350 
351 
352 
353  template <typename number>
356  {
357  // if we are in Lagrange form, just append the
358  // new points
359  if (in_lagrange_product_form == true && p.in_lagrange_product_form == true)
360  {
361  lagrange_weight *= p.lagrange_weight;
362  lagrange_support_points.insert (lagrange_support_points.end(),
363  p.lagrange_support_points.begin(),
364  p.lagrange_support_points.end());
365  }
366 
367  // cannot retain product form, recompute...
368  else if (in_lagrange_product_form == true)
369  transform_into_standard_form();
370 
371  // need to transform p into standard form as
372  // well if necessary. copy the polynomial to
373  // do this
374  std::unique_ptr<Polynomial<number> > q_data;
375  const Polynomial<number> *q = nullptr;
376  if (p.in_lagrange_product_form == true)
377  {
378  q_data = std_cxx14::make_unique<Polynomial<number>>(p);
379  q_data->transform_into_standard_form();
380  q = q_data.get();
381  }
382  else
383  q = &p;
384 
385  // Degree of the product
386  unsigned int new_degree = this->degree() + q->degree();
387 
388  std::vector<number> new_coefficients(new_degree+1, 0.);
389 
390  for (unsigned int i=0; i<q->coefficients.size(); ++i)
391  for (unsigned int j=0; j<this->coefficients.size(); ++j)
392  new_coefficients[i+j] += this->coefficients[j]*q->coefficients[i];
393  this->coefficients = new_coefficients;
394 
395  return *this;
396  }
397 
398 
399 
400  template <typename number>
403  {
404  // Lagrange product form cannot reasonably be
405  // retained after polynomial addition. we
406  // could in theory check if either this
407  // polynomial or the other is a zero
408  // polynomial and retain it, but we actually
409  // currently (r23974) assume that the addition
410  // of a zero polynomial changes the state and
411  // tests equivalence.
412  if (in_lagrange_product_form == true)
413  transform_into_standard_form();
414 
415  // need to transform p into standard form as
416  // well if necessary. copy the polynomial to
417  // do this
418  std::unique_ptr<Polynomial<number> > q_data;
419  const Polynomial<number> *q = nullptr;
420  if (p.in_lagrange_product_form == true)
421  {
422  q_data = std_cxx14::make_unique<Polynomial<number>>(p);
423  q_data->transform_into_standard_form();
424  q = q_data.get();
425  }
426  else
427  q = &p;
428 
429  // if necessary expand the number
430  // of coefficients we store
431  if (q->coefficients.size() > coefficients.size())
432  coefficients.resize (q->coefficients.size(), 0.);
433 
434  for (unsigned int i=0; i<q->coefficients.size(); ++i)
435  coefficients[i] += q->coefficients[i];
436 
437  return *this;
438  }
439 
440 
441 
442  template <typename number>
445  {
446  // Lagrange product form cannot reasonably be
447  // retained after polynomial addition
448  if (in_lagrange_product_form == true)
449  transform_into_standard_form();
450 
451  // need to transform p into standard form as
452  // well if necessary. copy the polynomial to
453  // do this
454  std::unique_ptr<Polynomial<number> > q_data;
455  const Polynomial<number> *q = nullptr;
456  if (p.in_lagrange_product_form == true)
457  {
458  q_data = std_cxx14::make_unique<Polynomial<number>>(p);
459  q_data->transform_into_standard_form();
460  q = q_data.get();
461  }
462  else
463  q = &p;
464 
465  // if necessary expand the number
466  // of coefficients we store
467  if (q->coefficients.size() > coefficients.size())
468  coefficients.resize (q->coefficients.size(), 0.);
469 
470  for (unsigned int i=0; i<q->coefficients.size(); ++i)
471  coefficients[i] -= q->coefficients[i];
472 
473  return *this;
474  }
475 
476 
477 
478  template <typename number >
479  bool
481  {
482  // need to distinguish a few cases based on
483  // whether we are in product form or not. two
484  // polynomials can still be the same when they
485  // are on different forms, but the expansion
486  // is the same
487  if (in_lagrange_product_form == true &&
488  p.in_lagrange_product_form == true)
489  return ((lagrange_weight == p.lagrange_weight) &&
490  (lagrange_support_points == p.lagrange_support_points));
491  else if (in_lagrange_product_form == true)
492  {
493  Polynomial<number> q = *this;
495  return (q.coefficients == p.coefficients);
496  }
497  else if (p.in_lagrange_product_form == true)
498  {
499  Polynomial<number> q = p;
501  return (q.coefficients == coefficients);
502  }
503  else
504  return (p.coefficients == coefficients);
505  }
506 
507 
508 
509  template <typename number>
510  template <typename number2>
511  void
512  Polynomial<number>::shift(std::vector<number> &coefficients,
513  const number2 offset)
514  {
515  // too many coefficients cause overflow in
516  // the binomial coefficient used below
517  Assert (coefficients.size() < 31, ExcNotImplemented());
518 
519  // Copy coefficients to a vector of
520  // accuracy given by the argument
521  std::vector<number2> new_coefficients(coefficients.begin(),
522  coefficients.end());
523 
524  // Traverse all coefficients from
525  // c_1. c_0 will be modified by
526  // higher degrees, only.
527  for (unsigned int d=1; d<new_coefficients.size(); ++d)
528  {
529  const unsigned int n = d;
530  // Binomial coefficients are
531  // needed for the
532  // computation. The rightmost
533  // value is unity.
534  unsigned int binomial_coefficient = 1;
535 
536  // Powers of the offset will be
537  // needed and computed
538  // successively.
539  number2 offset_power = offset;
540 
541  // Compute (x+offset)^d
542  // and modify all values c_k
543  // with k<d.
544  // The coefficient in front of
545  // x^d is not modified in this step.
546  for (unsigned int k=0; k<d; ++k)
547  {
548  // Recursion from Bronstein
549  // Make sure no remainders
550  // occur in integer
551  // division.
552  binomial_coefficient = (binomial_coefficient*(n-k))/(k+1);
553 
554  new_coefficients[d-k-1] += new_coefficients[d]
555  * binomial_coefficient
556  * offset_power;
557  offset_power *= offset;
558  }
559  // The binomial coefficient
560  // should have gone through a
561  // whole row of Pascal's
562  // triangle.
563  Assert (binomial_coefficient == 1, ExcInternalError());
564  }
565 
566  // copy new elements to old vector
567  coefficients.assign(new_coefficients.begin(), new_coefficients.end());
568  }
569 
570 
571 
572  template <typename number>
573  template <typename number2>
574  void
575  Polynomial<number>::shift (const number2 offset)
576  {
577  // shift is simple for a polynomial in product
578  // form, (x-x_0)*(x-x_1)*...*(x-x_n). just add
579  // offset to all shifts
580  if (in_lagrange_product_form == true)
581  {
582  for (unsigned int i=0; i<lagrange_support_points.size(); ++i)
583  lagrange_support_points[i] -= offset;
584  }
585  else
586  // do the shift in any case
587  shift (coefficients, offset);
588  }
589 
590 
591 
592  template <typename number>
595  {
596  // no simple form possible for Lagrange
597  // polynomial on product form
598  if (degree() == 0)
599  return Monomial<number>(0, 0.);
600 
601  std::unique_ptr<Polynomial<number> > q_data;
602  const Polynomial<number> *q = nullptr;
603  if (in_lagrange_product_form == true)
604  {
605  q_data = std_cxx14::make_unique<Polynomial<number>>(*this);
606  q_data->transform_into_standard_form();
607  q = q_data.get();
608  }
609  else
610  q = this;
611 
612  std::vector<number> newcoefficients (q->coefficients.size()-1);
613  for (unsigned int i=1 ; i<q->coefficients.size() ; ++i)
614  newcoefficients[i-1] = number(i) * q->coefficients[i];
615 
616  return Polynomial<number> (newcoefficients);
617  }
618 
619 
620 
621  template <typename number>
624  {
625  // no simple form possible for Lagrange
626  // polynomial on product form
627  std::unique_ptr<Polynomial<number> > q_data;
628  const Polynomial<number> *q = nullptr;
629  if (in_lagrange_product_form == true)
630  {
631  q_data = std_cxx14::make_unique<Polynomial<number>>(*this);
632  q_data->transform_into_standard_form();
633  q = q_data.get();
634  }
635  else
636  q = this;
637 
638  std::vector<number> newcoefficients (q->coefficients.size()+1);
639  newcoefficients[0] = 0.;
640  for (unsigned int i=0 ; i<q->coefficients.size() ; ++i)
641  newcoefficients[i+1] = q->coefficients[i]/number(i+1.);
642 
643  return Polynomial<number> (newcoefficients);
644  }
645 
646 
647 
648  template <typename number>
649  void
650  Polynomial<number>::print (std::ostream &out) const
651  {
652  if (in_lagrange_product_form == true)
653  {
654  out << lagrange_weight;
655  for (unsigned int i=0; i<lagrange_support_points.size(); ++i)
656  out << " (x-" << lagrange_support_points[i] << ")";
657  out << std::endl;
658  }
659  else
660  for (int i=degree(); i>=0; --i)
661  {
662  out << coefficients[i] << " x^" << i << std::endl;
663  }
664  }
665 
666 
667 
668 // ------------------ class Monomial -------------------------- //
669 
670  template <typename number>
671  std::vector<number>
673  double coefficient)
674  {
675  std::vector<number> result(n+1, 0.);
676  result[n] = coefficient;
677  return result;
678  }
679 
680 
681 
682  template <typename number>
683  Monomial<number>::Monomial (unsigned int n,
684  double coefficient)
685  : Polynomial<number>(make_vector(n, coefficient))
686  {}
687 
688 
689 
690  template <typename number>
691  std::vector<Polynomial<number> >
692  Monomial<number>::generate_complete_basis (const unsigned int degree)
693  {
694  std::vector<Polynomial<number> > v;
695  v.reserve(degree+1);
696  for (unsigned int i=0; i<=degree; ++i)
697  v.push_back (Monomial<number>(i));
698  return v;
699  }
700 
701 
702 
703 // ------------------ class LagrangeEquidistant --------------- //
704 
705  namespace internal
706  {
707  namespace LagrangeEquidistantImplementation
708  {
709  std::vector<Point<1> >
710  generate_equidistant_unit_points (const unsigned int n)
711  {
712  std::vector<Point<1> > points (n+1);
713  const double one_over_n = 1./n;
714  for (unsigned int k=0; k<=n; ++k)
715  points[k](0) = static_cast<double>(k)*one_over_n;
716  return points;
717  }
718  }
719  }
720 
721 
722 
724  const unsigned int support_point)
725  :
726  Polynomial<double> (internal::LagrangeEquidistantImplementation::
727  generate_equidistant_unit_points (n),
728  support_point)
729  {
730  Assert (coefficients.size() == 0, ExcInternalError());
731 
732  // For polynomial order up to 3, we have precomputed weights. Use these
733  // weights instead of the product form
734  if (n <= 3)
735  {
736  this->in_lagrange_product_form = false;
737  this->lagrange_weight = 1.;
738  std::vector<double> new_support_points;
739  this->lagrange_support_points.swap(new_support_points);
740  this->coefficients.resize (n+1);
741  compute_coefficients(n, support_point, this->coefficients);
742  }
743  }
744 
745 
746 
747  void
749  const unsigned int support_point,
750  std::vector<double> &a)
751  {
752  Assert(support_point<n+1, ExcIndexRange(support_point, 0, n+1));
753 
754  unsigned int n_functions=n+1;
755  Assert(support_point<n_functions,
756  ExcIndexRange(support_point, 0, n_functions));
757  double const *x=nullptr;
758 
759  switch (n)
760  {
761  case 1:
762  {
763  static const double x1[4]=
764  {
765  1.0, -1.0,
766  0.0, 1.0
767  };
768  x=&x1[0];
769  break;
770  }
771  case 2:
772  {
773  static const double x2[9]=
774  {
775  1.0, -3.0, 2.0,
776  0.0, 4.0, -4.0,
777  0.0, -1.0, 2.0
778  };
779  x=&x2[0];
780  break;
781  }
782  case 3:
783  {
784  static const double x3[16]=
785  {
786  1.0, -11.0/2.0, 9.0, -9.0/2.0,
787  0.0, 9.0, -45.0/2.0, 27.0/2.0,
788  0.0, -9.0/2.0, 18.0, -27.0/2.0,
789  0.0, 1.0, -9.0/2.0, 9.0/2.0
790  };
791  x=&x3[0];
792  break;
793  }
794  default:
795  Assert(false, ExcInternalError())
796  }
797 
798  Assert(x!=nullptr, ExcInternalError());
799  for (unsigned int i=0; i<n_functions; ++i)
800  a[i]=x[support_point*n_functions+i];
801  }
802 
803 
804 
805  std::vector<Polynomial<double> >
807  generate_complete_basis (const unsigned int degree)
808  {
809  if (degree==0)
810  // create constant polynomial
811  return std::vector<Polynomial<double> >
812  (1, Polynomial<double> (std::vector<double> (1,1.)));
813  else
814  {
815  // create array of Lagrange
816  // polynomials
817  std::vector<Polynomial<double> > v;
818  for (unsigned int i=0; i<=degree; ++i)
819  v.push_back(LagrangeEquidistant(degree,i));
820  return v;
821  }
822  }
823 
824 
825 
826 //----------------------------------------------------------------------//
827 
828 
829  std::vector<Polynomial<double> >
830  generate_complete_Lagrange_basis (const std::vector<Point<1> > &points)
831  {
832  std::vector<Polynomial<double> > p;
833  p.reserve (points.size());
834 
835  for (unsigned int i=0; i<points.size(); ++i)
836  p.emplace_back (points, i);
837  return p;
838  }
839 
840 
841 
842 // ------------------ class Legendre --------------- //
843 
844 
845 
846  Legendre::Legendre (const unsigned int k)
847  :
848  Polynomial<double> (0)
849  {
850  this->coefficients.clear();
851  this->in_lagrange_product_form = true;
852  this->lagrange_support_points.resize(k);
853 
854  // the roots of a Legendre polynomial are exactly the points in the
855  // Gauss-Legendre quadrature formula
856  if (k > 0)
857  {
858  QGauss<1> gauss(k);
859  for (unsigned int i=0; i<k; ++i)
860  this->lagrange_support_points[i] = gauss.get_points()[i][0];
861  }
862 
863  // compute the abscissa in zero of the product of monomials. The exact
864  // value should be sqrt(2*k+1), so set the weight to that value.
865  double prod = 1.;
866  for (unsigned int i=0; i<k; ++i)
867  prod *= this->lagrange_support_points[i];
868  this->lagrange_weight = std::sqrt(double(2*k+1)) / prod;
869  }
870 
871 
872 
873  std::vector<Polynomial<double> >
874  Legendre::generate_complete_basis (const unsigned int degree)
875  {
876  std::vector<Polynomial<double> > v;
877  v.reserve(degree+1);
878  for (unsigned int i=0; i<=degree; ++i)
879  v.push_back (Legendre(i));
880  return v;
881  }
882 
883 
884 
885 // ------------------ class Lobatto -------------------- //
886 
887 
888  Lobatto::Lobatto (const unsigned int p) : Polynomial<double> (compute_coefficients (p))
889  {
890  }
891 
892  std::vector<double> Lobatto::compute_coefficients (const unsigned int p)
893  {
894  switch (p)
895  {
896  case 0:
897  {
898  std::vector<double> coefficients (2);
899 
900  coefficients[0] = 1.0;
901  coefficients[1] = -1.0;
902  return coefficients;
903  }
904 
905  case 1:
906  {
907  std::vector<double> coefficients (2);
908 
909  coefficients[0] = 0.0;
910  coefficients[1] = 1.0;
911  return coefficients;
912  }
913 
914  case 2:
915  {
916  std::vector<double> coefficients (3);
917 
918  coefficients[0] = 0.0;
919  coefficients[1] = -1.0 * std::sqrt (3.);
920  coefficients[2] = std::sqrt (3.);
921  return coefficients;
922  }
923 
924  default:
925  {
926  std::vector<double> coefficients (p + 1);
927  std::vector<double> legendre_coefficients_tmp1 (p);
928  std::vector<double> legendre_coefficients_tmp2 (p - 1);
929 
930  coefficients[0] = -1.0 * std::sqrt (3.);
931  coefficients[1] = 2.0 * std::sqrt (3.);
932  legendre_coefficients_tmp1[0] = 1.0;
933 
934  for (unsigned int i = 2; i < p; ++i)
935  {
936  for (unsigned int j = 0; j < i - 1; ++j)
937  legendre_coefficients_tmp2[j] = legendre_coefficients_tmp1[j];
938 
939  for (unsigned int j = 0; j < i; ++j)
940  legendre_coefficients_tmp1[j] = coefficients[j];
941 
942  coefficients[0] = std::sqrt (2 * i + 1.) * ((1.0 - 2 * i) * legendre_coefficients_tmp1[0] / std::sqrt (2 * i - 1.) + (1.0 - i) * legendre_coefficients_tmp2[0] / std::sqrt (2 * i - 3.)) / i;
943 
944  for (unsigned int j = 1; j < i - 1; ++j)
945  coefficients[j] = std::sqrt (2 * i + 1.) * (std::sqrt (2 * i - 1.) * (2.0 * legendre_coefficients_tmp1[j - 1] - legendre_coefficients_tmp1[j]) + (1.0 - i) * legendre_coefficients_tmp2[j] / std::sqrt (2 * i - 3.)) / i;
946 
947  coefficients[i - 1] = std::sqrt (4 * i * i - 1.) * (2.0 * legendre_coefficients_tmp1[i - 2] - legendre_coefficients_tmp1[i - 1]) / i;
948  coefficients[i] = 2.0 * std::sqrt (4 * i * i - 1.) * legendre_coefficients_tmp1[i - 1] / i;
949  }
950 
951  for (int i = p; i > 0; --i)
952  coefficients[i] = coefficients[i - 1] / i;
953 
954  coefficients[0] = 0.0;
955  return coefficients;
956  }
957  }
958  }
959 
960  std::vector<Polynomial<double> > Lobatto::generate_complete_basis (const unsigned int p)
961  {
962  std::vector<Polynomial<double> > basis (p + 1);
963 
964  for (unsigned int i = 0; i <= p; ++i)
965  basis[i] = Lobatto (i);
966 
967  return basis;
968  }
969 
970 
971 
972 // ------------------ class Hierarchical --------------- //
973 
974 
975 // Reserve space for polynomials up to degree 19. Should be sufficient
976 // for the start.
977  std::vector<std::unique_ptr<const std::vector<double> > >
979 
980 
981 
982  Hierarchical::Hierarchical (const unsigned int k)
983  :
984  Polynomial<double> (get_coefficients(k))
985  {}
986 
987 
988 
989  void
990  Hierarchical::compute_coefficients (const unsigned int k_)
991  {
992  unsigned int k = k_;
993 
994  // first make sure that no other
995  // thread intercepts the operation
996  // of this function
997  // for this, acquire the lock
998  // until we quit this function
999  Threads::Mutex::ScopedLock lock(coefficients_lock);
1000 
1001  // The first 2 coefficients
1002  // are hard-coded
1003  if (k==0)
1004  k=1;
1005  // check: does the information
1006  // already exist?
1007  if ( (recursive_coefficients.size() < k+1) ||
1008  (recursive_coefficients[k].get() == nullptr))
1009  // no, then generate the
1010  // respective coefficients
1011  {
1012  // make sure that there is enough
1013  // space in the array for the
1014  // coefficients, so we have to resize
1015  // it to size k+1
1016 
1017  // but it's more complicated than
1018  // that: we call this function
1019  // recursively, so if we simply
1020  // resize it to k+1 here, then
1021  // compute the coefficients for
1022  // degree k-1 by calling this
1023  // function recursively, then it will
1024  // reset the size to k -- not enough
1025  // for what we want to do below. the
1026  // solution therefore is to only
1027  // resize the size if we are going to
1028  // *increase* it
1029  if (recursive_coefficients.size() < k+1)
1030  recursive_coefficients.resize (k+1);
1031 
1032  if (k<=1)
1033  {
1034  // create coefficients
1035  // vectors for k=0 and k=1
1036  //
1037  // allocate the respective
1038  // amount of memory and
1039  // later assign it to the
1040  // coefficients array to
1041  // make it const
1042  std::vector<double> c0(2);
1043  c0[0] = 1.;
1044  c0[1] = -1.;
1045 
1046  std::vector<double> c1(2);
1047  c1[0] = 0.;
1048  c1[1] = 1.;
1049 
1050  // now make these arrays
1051  // const
1053  std_cxx14::make_unique<const std::vector<double> >(std::move(c0));
1055  std_cxx14::make_unique<const std::vector<double> >(std::move(c1));
1056  }
1057  else if (k==2)
1058  {
1059  coefficients_lock.release ();
1061  coefficients_lock.acquire ();
1062 
1063  std::vector<double> c2(3);
1064 
1065  const double a = 1.; //1./8.;
1066 
1067  c2[0] = 0.*a;
1068  c2[1] = -4.*a;
1069  c2[2] = 4.*a;
1070 
1072  std_cxx14::make_unique<const std::vector<double> >(std::move(c2));
1073  }
1074  else
1075  {
1076  // for larger numbers,
1077  // compute the coefficients
1078  // recursively. to do so,
1079  // we have to release the
1080  // lock temporarily to
1081  // allow the called
1082  // function to acquire it
1083  // itself
1084  coefficients_lock.release ();
1085  compute_coefficients(k-1);
1086  coefficients_lock.acquire ();
1087 
1088  std::vector<double> ck (k+1);
1089 
1090  const double a = 1.; //1./(2.*k);
1091 
1092  ck[0] = - a*(*recursive_coefficients[k-1])[0];
1093 
1094  for (unsigned int i=1; i<=k-1; ++i)
1095  ck[i] = a*( 2.*(*recursive_coefficients[k-1])[i-1]
1096  - (*recursive_coefficients[k-1])[i] );
1097 
1098  ck[k] = a*2.*(*recursive_coefficients[k-1])[k-1];
1099  // for even degrees, we need
1100  // to add a multiple of
1101  // basis fcn phi_2
1102  if ( (k%2) == 0 )
1103  {
1104  double b = 1.; //8.;
1105  //for (unsigned int i=1; i<=k; i++)
1106  // b /= 2.*i;
1107 
1108  ck[1] += b*(*recursive_coefficients[2])[1];
1109  ck[2] += b*(*recursive_coefficients[2])[2];
1110  }
1111  // finally assign the newly
1112  // created vector to the
1113  // const pointer in the
1114  // coefficients array
1116  std_cxx14::make_unique<const std::vector<double> >(std::move(ck));
1117  };
1118  };
1119  }
1120 
1121 
1122 
1123  const std::vector<double> &
1124  Hierarchical::get_coefficients (const unsigned int k)
1125  {
1126  // first make sure the coefficients
1127  // get computed if so necessary
1129 
1130  // then get a pointer to the array
1131  // of coefficients. do that in a MT
1132  // safe way
1133  Threads::Mutex::ScopedLock lock (coefficients_lock);
1134  return *recursive_coefficients[k];
1135  }
1136 
1137 
1138 
1139  std::vector<Polynomial<double> >
1140  Hierarchical::generate_complete_basis (const unsigned int degree)
1141  {
1142  if (degree==0)
1143  // create constant
1144  // polynomial. note that we
1145  // can't use the other branch
1146  // of the if-statement, since
1147  // calling the constructor of
1148  // this class with argument
1149  // zero does _not_ create the
1150  // constant polynomial, but
1151  // rather 1-x
1152  return std::vector<Polynomial<double> >
1153  (1, Polynomial<double> (std::vector<double> (1,1.)));
1154  else
1155  {
1156  std::vector<Polynomial<double> > v;
1157  v.reserve(degree+1);
1158  for (unsigned int i=0; i<=degree; ++i)
1159  v.push_back (Hierarchical(i));
1160  return v;
1161  }
1162  }
1163 
1164 
1165 
1166 // ------------------ HermiteInterpolation --------------- //
1167 
1169  :
1170  Polynomial<double>(0)
1171  {
1172  this->coefficients.clear();
1173  this->in_lagrange_product_form = true;
1174 
1175  this->lagrange_support_points.resize(3);
1176  if (p==0)
1177  {
1178  this->lagrange_support_points[0] = -0.5;
1179  this->lagrange_support_points[1] = 1.;
1180  this->lagrange_support_points[2] = 1.;
1181  this->lagrange_weight = 2.;
1182  }
1183  else if (p==1)
1184  {
1185  this->lagrange_support_points[0] = 0.;
1186  this->lagrange_support_points[1] = 0.;
1187  this->lagrange_support_points[2] = 1.5;
1188  this->lagrange_weight = -2.;
1189  }
1190  else if (p==2)
1191  {
1192  this->lagrange_support_points[0] = 0.;
1193  this->lagrange_support_points[1] = 1.;
1194  this->lagrange_support_points[2] = 1.;
1195  }
1196  else if (p==3)
1197  {
1198  this->lagrange_support_points[0] = 0.;
1199  this->lagrange_support_points[1] = 0.;
1200  this->lagrange_support_points[2] = 1.;
1201  }
1202  else
1203  {
1204  this->lagrange_support_points.resize(4);
1205  this->lagrange_support_points[0] = 0.;
1206  this->lagrange_support_points[1] = 0.;
1207  this->lagrange_support_points[2] = 1.;
1208  this->lagrange_support_points[3] = 1.;
1209  this->lagrange_weight = 16.;
1210 
1211  if (p>4)
1212  {
1213  Legendre legendre(p-4);
1214  (*this) *= legendre;
1215  }
1216  }
1217  }
1218 
1219 
1220  std::vector<Polynomial<double> >
1222  {
1223  Assert(n>=3,
1224  ExcNotImplemented("Hermite interpolation makes no sense for "
1225  "degrees less than three"));
1226  std::vector<Polynomial<double> > basis (n + 1);
1227 
1228  for (unsigned int i = 0; i <= n; ++i)
1229  basis[i] = HermiteInterpolation (i);
1230 
1231  return basis;
1232  }
1233 
1234 
1235 // ------------------ HermiteLikeInterpolation --------------- //
1236  namespace
1237  {
1238  // Finds the zero position x_star such that the mass matrix entry (0,1)
1239  // with the Hermite polynomials evaluates to zero. The function has
1240  // originally been derived by a secant method for the integral entry
1241  // l_0(x) * l_1(x) but we only need to do one iteration because the zero
1242  // x_star is linear in the integral value.
1243  double find_support_point_x_star (const std::vector<double> &jacobi_roots)
1244  {
1245  // Initial guess for the support point position values: The zero turns
1246  // out to be between zero and the first root of the Jacobi polynomial,
1247  // but the algorithm is agnostic about that, so simply choose two points
1248  // that are sufficiently far apart.
1249  double guess_left = 0;
1250  double guess_right = 0.5;
1251  const unsigned int degree = jacobi_roots.size() + 3;
1252 
1253  // Compute two integrals of the product of l_0(x) * l_1(x)
1254  // l_0(x) = (x-y)*(x-jacobi_roots(0))*...*(x-jacobi_roos(degree-4))*(x-1)*(x-1)
1255  // l_1(x) = (x-0)*(x-jacobi_roots(0))*...*(x-jacobi_roots(degree-4))*(x-1)*(x-1)
1256  // where y is either guess_left or guess_right for the two integrals.
1257  // Note that the polynomials are not yet normalized here, which is not
1258  // necessary because we are only looking for the x_star where the matrix
1259  // entry is zero, for which the constants do not matter.
1260  QGauss<1> gauss(degree + 1);
1261  double integral_left = 0, integral_right = 0;
1262  for (unsigned int q=0; q<gauss.size(); ++q)
1263  {
1264  const double x = gauss.point(q)[0];
1265  double poly_val_common = x;
1266  for (unsigned int j=0; j<degree-3; ++j)
1267  poly_val_common *= Utilities::fixed_power<2>(x-jacobi_roots[j]);
1268  poly_val_common *= Utilities::fixed_power<4>(x - 1.);
1269  integral_left += gauss.weight(q)*(poly_val_common*(x - guess_left));
1270  integral_right += gauss.weight(q)*(poly_val_common*(x - guess_right));
1271  }
1272 
1273  // compute guess by secant method. Due to linearity in the root x_star,
1274  // this is the correct position after this single step
1275  return guess_right - (guess_right-guess_left)/(integral_right-integral_left)*integral_right;
1276  }
1277  }
1278 
1279 
1280 
1282  const unsigned int index)
1283  :
1284  Polynomial<double>(0)
1285  {
1286  AssertIndexRange(index, degree+1);
1287 
1288  this->coefficients.clear();
1289  this->in_lagrange_product_form = true;
1290 
1291  this->lagrange_support_points.resize(degree);
1292 
1293  if (degree == 0)
1294  this->lagrange_weight = 1.;
1295  else if (degree == 1)
1296  {
1297  if (index == 0)
1298  {
1299  this->lagrange_support_points[0] = 1.;
1300  this->lagrange_weight = -1.;
1301  }
1302  else
1303  {
1304  this->lagrange_support_points[0] = 0.;
1305  this->lagrange_weight = 1.;
1306  }
1307  }
1308  else if (degree == 2)
1309  {
1310  if (index == 0)
1311  {
1312  this->lagrange_support_points[0] = 1.;
1313  this->lagrange_support_points[1] = 1.;
1314  this->lagrange_weight = 1.;
1315  }
1316  else if (index == 1)
1317  {
1318  this->lagrange_support_points[0] = 0;
1319  this->lagrange_support_points[1] = 1;
1320  this->lagrange_weight = -2.;
1321  }
1322  else
1323  {
1324  this->lagrange_support_points[0] = 0.;
1325  this->lagrange_support_points[1] = 0.;
1326  this->lagrange_weight = 1.;
1327  }
1328  }
1329  else if (degree==3)
1330  {
1331  // 4 Polynomials with degree 3
1332  // entries (1,0) and (3,2) of the mass matrix will be equal to 0
1333  //
1334  // | x 0 x x |
1335  // | 0 x x x |
1336  // M = | x x x 0 |
1337  // | x x 0 x |
1338  //
1339  if (index==0)
1340  {
1341  this->lagrange_support_points[0] = 2./7.;
1342  this->lagrange_support_points[1] = 1.;
1343  this->lagrange_support_points[2] = 1.;
1344  this->lagrange_weight = -3.5;
1345  }
1346  else if (index==1)
1347  {
1348  this->lagrange_support_points[0] = 0.;
1349  this->lagrange_support_points[1] = 1.;
1350  this->lagrange_support_points[2] = 1.;
1351 
1352  // this magic value 5.5 is obtained when evaluating the general
1353  // formula below for the degree=3 case
1354  this->lagrange_weight = 5.5;
1355  }
1356  else if (index==2)
1357  {
1358  this->lagrange_support_points[0] = 0.;
1359  this->lagrange_support_points[1] = 0.;
1360  this->lagrange_support_points[2] = 1.;
1361  this->lagrange_weight = -5.5;
1362  }
1363  else if (index==3)
1364  {
1365  this->lagrange_support_points[0] = 0.;
1366  this->lagrange_support_points[1] = 0.;
1367  this->lagrange_support_points[2] = 5./7.;
1368  this->lagrange_weight = 3.5;
1369  }
1370  }
1371  else
1372  {
1373  // Higher order Polynomials degree>=4: the entries (1,0) and
1374  // (degree,degree-1) of the mass matrix will be equal to 0
1375  //
1376  // | x 0 x x x x x |
1377  // | 0 x x x . . . x x x |
1378  // | x x x x x x x |
1379  // | x x x x x x x |
1380  // | . . . |
1381  // M = | . . . |
1382  // | . . . |
1383  // | x x x x x x x |
1384  // | x x x x . . . x x 0 |
1385  // | x x x x x 0 x |
1386  //
1387  // We find the inner points as the zeros of the Jacobi polynomials
1388  // with alpha = beta = 2 which is the polynomial with the kernel
1389  // (1-x)^2 (1+x)^2, the two polynomials achieving zero value and zero
1390  // derivative at the boundary.
1391 
1392  std::vector<double> jacobi_roots = jacobi_polynomial_roots<double>(degree-3, 2, 2);
1393  AssertDimension(jacobi_roots.size(), degree-3);
1394 
1395  // iteration from variable support point N with secant method
1396  // initial values
1397 
1398  this->lagrange_support_points.resize(degree);
1399  if (index==0)
1400  {
1401  const double auxiliary_zero = find_support_point_x_star(jacobi_roots);
1402  this->lagrange_support_points[0] = auxiliary_zero;
1403  for (unsigned int m=0; m<degree-3; m++)
1404  this->lagrange_support_points[m+1] = jacobi_roots[m];
1405  this->lagrange_support_points[degree-2] = 1.;
1406  this->lagrange_support_points[degree-1] = 1.;
1407 
1408  // ensure that the polynomial evaluates to one at x=0
1409  this->lagrange_weight = 1./this->value(0);
1410  }
1411  else if (index==1)
1412  {
1413  this->lagrange_support_points[0] = 0.;
1414  for (unsigned int m=0; m<degree-3; m++)
1415  this->lagrange_support_points[m+1] = jacobi_roots[m];
1416  this->lagrange_support_points[degree-2] = 1.;
1417  this->lagrange_support_points[degree-1] = 1.;
1418 
1419  // Select the weight to make the derivative of the sum of P_0 and
1420  // P_1 in zero to be 0. The derivative in x=0 is simply given by
1421  // p~(0)/auxiliary_zero+p~'(0) + a*p~(0), where p~(x) is the
1422  // Lagrange polynomial in all points except the first one which is
1423  // the same for P_0 and P_1, and a is the weight we seek here. If
1424  // we solve this for a, we obtain the desired property. Since the
1425  // basis is nodal for all interior points, this property ensures
1426  // that the sum of all polynomials with weight 1 is one.
1427  std::vector<Point<1>> points(degree);
1428  double ratio = 1.;
1429  for (unsigned int i=0; i<degree; ++i)
1430  {
1431  points[i][0] = this->lagrange_support_points[i];
1432  if (i>0)
1433  ratio *= -this->lagrange_support_points[i];
1434  }
1435  Polynomial<double> helper(points, 0);
1436  std::vector<double> value_and_grad(2);
1437  helper.value(0., value_and_grad);
1438  Assert(std::abs(value_and_grad[0]) > 1e-10,
1439  ExcInternalError("There should not be a zero at x=0."));
1440 
1441  const double auxiliary_zero = find_support_point_x_star(jacobi_roots);
1442  this->lagrange_weight = (1./auxiliary_zero - value_and_grad[1]/value_and_grad[0])/ratio;
1443  }
1444  else if (index>=2 && index<degree-1)
1445  {
1446  this->lagrange_support_points[0] = 0.;
1447  this->lagrange_support_points[1] = 0.;
1448  for (unsigned int m=0, c=2; m<degree-3; m++)
1449  if (m+2 != index)
1450  this->lagrange_support_points[c++] = jacobi_roots[m];
1451  this->lagrange_support_points[degree-2] = 1.;
1452  this->lagrange_support_points[degree-1] = 1.;
1453 
1454  // ensure that the polynomial evaluates to one at the respective
1455  // nodal point
1456  this->lagrange_weight = 1./this->value(jacobi_roots[index-2]);
1457  }
1458  else if (index==degree-1)
1459  {
1460  this->lagrange_support_points[0] = 0.;
1461  this->lagrange_support_points[1] = 0.;
1462  for (unsigned int m=0; m<degree-3; m++)
1463  this->lagrange_support_points[m+2] = jacobi_roots[m];
1464  this->lagrange_support_points[degree-1] = 1.;
1465 
1466  std::vector<Point<1>> points(degree);
1467  double ratio = 1.;
1468  for (unsigned int i=0; i<degree; ++i)
1469  {
1470  points[i][0] = this->lagrange_support_points[i];
1471  if (i<degree-1)
1472  ratio *= 1.-this->lagrange_support_points[i];
1473  }
1474  Polynomial<double> helper(points, degree-1);
1475  std::vector<double> value_and_grad(2);
1476  helper.value(1., value_and_grad);
1477  Assert(std::abs(value_and_grad[0]) > 1e-10,
1478  ExcInternalError("There should not be a zero at x=1."));
1479 
1480  const double auxiliary_zero = find_support_point_x_star(jacobi_roots);
1481  this->lagrange_weight = (-1./auxiliary_zero - value_and_grad[1]/value_and_grad[0])/ratio;
1482  }
1483  else if (index==degree)
1484  {
1485  const double auxiliary_zero = find_support_point_x_star(jacobi_roots);
1486  this->lagrange_support_points[0] = 0.;
1487  this->lagrange_support_points[1] = 0.;
1488  for (unsigned int m=0; m<degree-3; m++)
1489  this->lagrange_support_points[m+2] = jacobi_roots[m];
1490  this->lagrange_support_points[degree-1] = 1.-auxiliary_zero;
1491 
1492  // ensure that the polynomial evaluates to one at x=1
1493  this->lagrange_weight = 1./this->value(1.);
1494  }
1495  }
1496  }
1497 
1498 
1499 
1500  std::vector<Polynomial<double> >
1502  {
1503  std::vector<Polynomial<double> > basis (degree + 1);
1504 
1505  for (unsigned int i = 0; i <= degree; ++i)
1506  basis[i] = HermiteLikeInterpolation (degree, i);
1507 
1508  return basis;
1509  }
1510 
1511 }
1512 
1513 // ------------------ explicit instantiations --------------- //
1514 
1515 namespace Polynomials
1516 {
1517  template class Polynomial<float>;
1518  template class Polynomial<double>;
1519  template class Polynomial<long double>;
1520 
1521  template void Polynomial<float>::shift(const float offset);
1522  template void Polynomial<float>::shift(const double offset);
1523  template void Polynomial<double>::shift(const double offset);
1524  template void Polynomial<long double>::shift(const long double offset);
1525  template void Polynomial<float>::shift(const long double offset);
1526  template void Polynomial<double>::shift(const long double offset);
1527 
1528  template class Monomial<float>;
1529  template class Monomial<double>;
1530  template class Monomial<long double>;
1531 }
1532 
1533 DEAL_II_NAMESPACE_CLOSE
void transform_into_standard_form()
Definition: polynomial.cc:248
LagrangeEquidistant(const unsigned int n, const unsigned int support_point)
Definition: polynomial.cc:723
#define AssertDimension(dim1, dim2)
Definition: exceptions.h:1248
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
const std::vector< Point< dim > > & get_points() const
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
#define AssertIndexRange(index, range)
Definition: exceptions.h:1284
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
static ::ExceptionBase & ExcIndexRange(int arg1, int arg2, int arg3)
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
double value(const double x) const
Definition: polynomial.h:787
Definition: point.h:104
std::vector< double > compute_coefficients(const unsigned int p)
Definition: polynomial.cc:892
static ::ExceptionBase & ExcMessage(std::string arg1)
#define Assert(cond, exc)
Definition: exceptions.h:1142
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
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
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 ::ExceptionBase & ExcZero()
static std::vector< Polynomial< double > > generate_complete_basis(const unsigned int p)
Definition: polynomial.cc:1221
static ::ExceptionBase & ExcInternalError()