Simpatico  v1.10
Polynomial.h
1 #ifndef UTIL_POLYNOMIAL_H
2 #define UTIL_POLYNOMIAL_H
3 
4 /*
5 * Util Package - C++ Utilities for Scientific Computation
6 *
7 * Copyright 2010 - 2017, The Regents of the University of Minnesota
8 * Distributed under the terms of the GNU General Public License.
9 */
10 
11 #include <util/containers/GArray.h> // base class
12 #include <util/containers/DArray.h> // base class
13 #include <util/math/Rational.h> // default template argument
14 #include <util/math/Binomial.h> // default in implementation
15 #include <util/containers/DArray.h> // used in implementation
16 #include <util/global.h>
17 
18 
19 #include <iostream>
20 
21 namespace Util
22 {
23 
29  template <typename T = Rational>
30  class Polynomial : private GArray<T>
31  {
32 
33  public:
34 
36 
37 
47  Polynomial(int capacity = 10);
48 
56  explicit Polynomial(T c);
57 
67  Polynomial(Array<T> const & coeffs);
68 
74  Polynomial(Polynomial<T> const & other);
75 
81  template <typename U>
82  Polynomial<T>& operator = (Polynomial<U> const & other);
83 
90  void setToZero();
91 
93 
95 
96  // Get a specific coefficient by index.
97  using GArray<T>::operator [];
98 
105  int degree() const;
106 
107  // Logical size of the coefficient array.
108  using GArray<T>::size;
109 
110  // Physical capacity of the coefficient array.
111  using GArray<T>::capacity;
112 
114 
116 
125 
134 
143 
152 
161 
170 
179 
181 
183 
191  Polynomial<T> integrate() const;
192 
201 
212  Polynomial<T> reflect() const;
213 
222  Polynomial<T> shift(T a) const;
223 
225 
227 
234  T operator () (T x) const;
235 
242  double evaluate (double x) const;
243 
245 
246  // Static public member functions
247 
253  static Polynomial<T> monomial(int n);
254 
255  };
256 
257  // Inline methods
258 
259  /*
260  * Constructor.
261  */
262  template <typename T>
263  inline
265  { GArray<T>::reserve(capacity); }
266 
267  /*
268  * Construct a constant polynomial f(x) = c.
269  */
270  template <typename T>
271  inline
273  {
274  GArray<T>::reserve(10);
276  }
277 
278  /*
279  * Construct from array of coefficients.
280  */
281  template <typename T>
282  inline
284  {
285  if (coeffs.capacity() > 0) {
286  GArray<T>::reserve(coeffs.capacity());
287  for (int i = 0; i < coeffs.capacity(); ++i) {
288  GArray<T>::append(coeffs[i]);
289  }
290  }
291  }
292 
293  /*
294  * Copy constructor
295  */
296  template <typename T>
297  inline
299  {
300  GArray<T>::reserve(other.capacity());
301  if (other.size() > 0) {
302  for (int i = 0; i < other.size(); ++i) {
303  GArray<T>::append(other[i]);
304  }
305  }
306  }
307 
308  /*
309  * Assignment from another polynomial.
310  */
311  template <typename T>
312  template <typename U>
313  inline
315  {
316  setToZero();
317  if (other.size() >= 0) {
318  if (other.size() > capacity()) {
319  GArray<T>::reserve(other.capacity());
320  }
321  T element;
322  for (int i = 0; i < other.size(); ++i) {
323  element = other[i];
324  GArray<T>::append(element);
325  }
326  }
327  return *this;
328  }
329 
330  /*
331  * Set this polynomial to zero.
332  */
333  template <typename T>
334  inline
336  { GArray<T>::clear(); }
337 
338  /*
339  * Return degree of polynomial (size of coeff. array - 1).
340  */
341  template <typename T>
342  inline
344  { return GArray<T>::size() - 1; }
345 
346  /*
347  * Addition assignment operator : add another polynomial to this one.
348  */
349  template <typename T>
351  {
352  if (a.size() > 0) {
353  int min = a.size() > size() ? size() : a.size();
354  if (min > 0) {
355  for (int i = 0; i < min; ++i) {
356  (*this)[i] += a[i];
357  }
358  }
359  if (a.size() > size()) {
360  UTIL_CHECK(min == size());
361  for (int i = size(); i < a.size(); ++i) {
362  GArray<T>::append(a[i]);
363  }
364  }
365  }
366  return *this;
367  }
368 
369  /*
370  * Add a constant to this polynomial.
371  */
372  template <typename T>
374  {
375  if (size() == 0) {
376  (*this).append(a);
377  } else {
378  (*this)[0] += a;
379  }
380  return *this;
381  }
382 
383  /*
384  * Subtract assignment operator : subtract another polynomial from this.
385  */
386  template <typename T>
388  {
389  if (a.size() > 0) {
390  int min = a.size() > size() ? size() : a.size();
391  if (min > 0) {
392  for (int i = 0; i < min; ++i) {
393  (*this)[i] -= a[i];
394  }
395  }
396  if (a.size() > size()) {
397  UTIL_CHECK(min == size());
398  for (int i = size(); i < a.size(); ++i) {
399  GArray<T>::append(-a[i]);
400  }
401  }
402  }
403  return *this;
404  }
405 
406  /*
407  * Subtract a constant from this polynomial.
408  */
409  template <typename T>
411  {
412  if (size() == 0) {
413  (*this).append(-a);
414  } else {
415  (*this)[0] -= a;
416  }
417  return *this;
418  }
419 
420  /*
421  * Multipication assignment operator : multiply this by a scalar.
422  */
423  template <typename T>
424  inline
426  {
427  if (size() >= 0) {
428  for (int i = 0; i < size(); ++i) {
429  (*this)[i] *= a;
430  }
431  }
432  return *this;
433  }
434 
435  /*
436  * Division by scalar assignment operator.
437  */
438  template <typename T>
439  inline
441  {
442  if (size() >= 0) {
443  for (int i = 0; i < size(); ++i) {
444  (*this)[i] /= a;
445  }
446  }
447  return *this;
448  }
449 
450  /*
451  * Multiplication assignment operator : multiply this by a polynomial.
452  */
453  template <typename T>
455  {
456  // If this polynomial is zero (size == 0), do nothing. Otherwise:
457  if (size() > 0) {
458 
459  if (a.size() == 0) {
460  // If polynomial a is zero, set this one to zero (clear it).
461  setToZero();
462  } else {
463 
464  // Compute size of new array of coefficients (degree + 1)
465  int n = size() + a.size() - 1;
466 
467  // Make a copy of coefficients of this polynomial
468  GArray<T> b(*this);
469 
470  // Clear this array of coefficients and reserve enough space
471  setToZero();
472  if (n > capacity()) {
474  }
475 
476  // Set all coefficients of resized array to zero
477  int i;
478  T zero = 0;
479  for (i = 0; i < n; ++i) {
480  GArray<T>::append(zero);
481  }
482 
483  // Compute new coefficients as a double sum
484  int j, k;
485  for (i = 0; i < a.size(); ++i) {
486  for (j = 0; j < b.size(); ++j) {
487  k = i + j;
488  UTIL_ASSERT(k < n);
489  (*this)[k] += a[i]*b[j];
490  }
491  }
492 
493  }
494  }
495  return *this;
496  }
497 
498  /*
499  * Compute and return indefinite integral of this polynomial.
500  */
501  template <typename T>
503  {
504  if (size() == 0) {
505  Polynomial<T> b;
506  b.setToZero();
507  return b;
508  } else {
509  // Construct and compute coefficient array for integral
510  DArray<T> coeffs;
511  coeffs.allocate(size()+1);
512  coeffs[0] = T(0);
513  for (int i = 0; i < size(); ++i) {
514  coeffs[i+1] = (*this)[i];
515  coeffs[i+1] /= T(i+1);
516  }
517 
518  // Construct and return associated Polynomial
519  Polynomial<T> b(coeffs);
520  return b;
521  }
522  }
523 
524  /*
525  * Compute and return the derivatvie of this polynomial.
526  */
527  template <typename T>
529  {
530  if (size() <= 1) {
531 
532  // If this polynomial is null or constant, return null
533  Polynomial<T> b;
534  b.setToZero();
535  return b;
536 
537  } else {
538 
539  // Construct coefficient array for derivative polynomial
540  DArray<T> coeffs;
541  coeffs.allocate(size()-1);
542  for (int i = 1; i < size(); ++i) {
543  coeffs[i-1] = (*this)[i];
544  coeffs[i-1] *= T(i);
545  }
546 
547  // Construct and return associated Polynomial
548  Polynomial<T> b(coeffs);
549  return b;
550  }
551  }
552 
553  /*
554  * Compute and return reflection g(x) = f(-x) this polynomial f(x).
555  */
556  template <typename T>
558  {
559  // Make copy
560  Polynomial<T> b(*this);
561 
562  // Reverse odd power coefficients
563  for (int i = 0; i < b.size(); ++i) {
564  if (i%2 != 0) {
565  b[i] *= -1;
566  }
567  }
568 
569  return b;
570  }
571 
572  /*
573  * Compute and return reflection g(x) = f(-x) this polynomial f(x).
574  */
575  template <typename T>
577  {
578  // Make copy of this
579  Polynomial<T> b(*this);
580 
581  int degree = size() - 1;
582  if (degree > 0) {
583  Binomial::setup(degree);
584  int n, m;
585  T p;
586  for (n = 1; n <= degree; ++n) {
587  p = b[n]*a;
588  for (m = 1; m <= n; ++m) {
589  b[n -m] += Binomial::coeff(n, m)*p;
590  p *= a;
591  }
592  }
593  }
594 
595  return b;
596  }
597 
598  /*
599  * Evaluate polynomial at specific argument.
600  */
601  template <typename T>
602  inline T Polynomial<T>::operator () (T x) const
603  {
604  if (size() > 0) {
605  int degree = size() - 1;
606  T value = (*this)[degree];
607  if (degree > 0) {
608  for (int i = degree-1; i >= 0; --i) {
609  value *= x;
610  value += (*this)[i];
611  }
612  }
613  return value;
614  } else {
615  return T(0);
616  }
617  }
618 
619  /*
620  * Evaluate polynomial at specific floating point argument.
621  */
622  template <typename T>
623  inline double Polynomial<T>::evaluate (double x) const
624  {
625  if (size() > 0) {
626  int degree = size()-1;
627  double value = (double)(*this)[degree];
628  if (degree > 0) {
629  for (int i = degree-1; i >= 0; --i) {
630  value *= x;
631  value += (double)(*this)[i];
632  }
633  }
634  return value;
635  } else {
636  return 0.0;
637  }
638  }
639 
640  // Static function
641 
645  template <typename T>
647  {
648  UTIL_CHECK(power >= 0);
649  Polynomial<T> a(power+1);
650 
651  // Append zero coefficients.
652  T zero(0);
653  for (int i = 0; i <= power; ++i) {
654  a.GArray<T>::append(zero);
655  }
656 
657  // Set coefficient of highest power to unity
658  a[power] = T(1);
659 
660  return a;
661  }
662 
663  // Related non-member functions
664 
675  template <typename T>
677  {
678  if (a.size() != b.size()) return false;
679  if (a.size() > 0) {
680  for (int i = 0; i < a.size(); ++i) {
681  if (a[i] != b[i]) return false;
682  }
683  }
684  return true;
685  }
686 
694  template <typename T>
696  { return !(a == b); }
697 
704  template <typename T>
705  inline
707  {
708  Polynomial<T> b(a);
709  if (a.size() > 0) {
710  for (int i = 0; i < a.size(); ++i) {
711  b[i] *= -1;
712  }
713  }
714  return b;
715  }
716 
717  template <typename T>
718  std::ostream& operator << (std::ostream& out, Polynomial<T> const & p)
719  {
720  out << "( ";
721  if (p.size() > 0) {
722  for (int i = 0; i < p.size(); ++i) {
723  out << p[i] << " ";
724  }
725  }
726  out << ")";
727  return out;
728  }
729 }
730 #endif
int capacity() const
Return physical capacity of array.
static int coeff(int n, int m)
Return coefficient "n choose m", or C(n, m) = n!/(m!(n-m)!).
Definition: Binomial.cpp:47
Polynomial< T > & operator*=(T a)
Multiply this polynomial by a scalar.
Definition: Polynomial.h:425
An automatically growable array, analogous to a std::vector.
Definition: GArray.h:33
Polynomial< T > operator-(Polynomial< T > const &a)
Unary negation of polynomial.
Definition: Polynomial.h:706
void append(const Data &data)
Append an element to the end of the sequence.
Definition: GArray.h:306
void clear()
Reset to empty state.
Definition: GArray.h:299
void setToZero()
Assign this polynomial a value of zero.
Definition: Polynomial.h:335
void reserve(int capacity)
Reserve memory for specified number of elements.
Definition: GArray.h:255
int size() const
Return logical size of this array (i.e., current number of elements).
Array container class template.
Definition: AutoCorrArray.h:28
File containing preprocessor macros for error handling.
Polynomial< T > & operator+=(const Polynomial< T > &a)
Add another polynomial to this one.
Definition: Polynomial.h:350
Polynomial< T > differentiate() const
Compute and return derivative of this polynomial.
Definition: Polynomial.h:528
bool operator==(const PointSymmetry &A, const PointSymmetry &B)
Are two PointSymmetry objects equivalent?
Polynomial< T > & operator/=(T a)
Divide this polynomial by a scalar.
Definition: Polynomial.h:440
T operator()(T x) const
Evaluate polynomial at specific argument of type T.
Definition: Polynomial.h:602
double evaluate(double x) const
Evaluate polynomial at specific floating point argument.
Definition: Polynomial.h:623
static void setup(int nMax)
Precompute all combinations C(n, m) up to n = nMax.
Definition: Binomial.cpp:17
Utility classes for scientific computation.
Definition: accumulators.mod:1
int degree() const
Return degree of polynomial.
Definition: Polynomial.h:343
Dynamically allocatable contiguous array template.
Definition: DArray.h:31
static Polynomial< T > monomial(int n)
Return a monomial f(x) = x^{n}.
Definition: Polynomial.h:646
#define UTIL_CHECK(condition)
Assertion macro suitable for serial or parallel production code.
Definition: global.h:68
Polynomial< T > & operator-=(const Polynomial< T > &a)
Subtract another polynomial from this one.
Definition: Polynomial.h:387
Polynomial< T > shift(T a) const
Compute and return shifted polynomial f(x+a).
Definition: Polynomial.h:576
Polynomial(int capacity=10)
Construct a zero polynomial.
Definition: Polynomial.h:264
int capacity() const
Return allocated size.
Definition: Array.h:153
void allocate(int capacity)
Allocate the underlying C array.
Definition: DArray.h:191
Polynomial< T > & operator=(Polynomial< U > const &other)
Assignment from another polynomial.
Polynomial< T > integrate() const
Compute and return indefinite integral of this polynomial.
Definition: Polynomial.h:502
Polynomial< T > reflect() const
Compute and return reflected polynomial f(-x).
Definition: Polynomial.h:557
#define UTIL_ASSERT(condition)
Assertion macro suitable for debugging serial or parallel code.
Definition: global.h:75
A Polynomial (i.e,.
Definition: Polynomial.h:30
bool operator!=(const PointSymmetry &A, const PointSymmetry &B)
Are two PointSymmetry objects not equivalent?