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