Theoretica
Scientific Computing
Loading...
Searching...
No Matches
polynomial.h
Go to the documentation of this file.
1
5
6#ifndef THEORETICA_POLYNOMIAL_H
7#define THEORETICA_POLYNOMIAL_H
8
9#ifndef THEORETICA_NO_PRINT
10#include <sstream>
11#include <ostream>
12#endif
13
14#include "../core/real_analysis.h"
15#include "../algebra/vec.h"
16#include "../complex/complex.h"
17#include "../complex/complex_analysis.h"
18
19
20namespace theoretica {
21
27 template<typename Type = real>
28 class polynomial {
29
30 private:
31
33 vec<Type> coeff {Type(0.0)};
34
35 public:
36
38 polynomial() = default;
39
41 polynomial(Type a) : coeff({a}) {}
42
47 template<typename Vector, enable_vector<Vector> = true>
48 explicit polynomial(const Vector& c) {
49
50 coeff.resize(c.size());
51
52 for (size_t i = 0; i < c.size(); ++i)
53 coeff[i] = c[i];
54 }
55
56
58 polynomial(std::initializer_list<Type> l) : coeff(l) {}
59
60
63 template<typename ...Args>
64 polynomial(Args... args) : coeff({args...}) {}
65
66
68 inline const Type& at(unsigned int i) const {
69 return coeff.at(i);
70 }
71
73 inline Type& at(unsigned int i) {
74 return coeff.at(i);
75 }
76
77
79 inline const Type& operator[](unsigned int i) const {
80 return coeff[i];
81 }
82
83
85 inline Type& operator[](unsigned int i) {
86 return coeff[i];
87 }
88
89
92 template<typename InputType = Type>
93 inline Type eval(InputType x) const {
94
95 Type sum = Type(0.0);
96
97 // Evaluate using Horner's method
98 for (unsigned int i = 0; i < coeff.size(); ++i)
99 sum = coeff[coeff.size() - i - 1] + sum * x;
100
101 return sum;
102 }
103
104
107 template<typename InputType = Type>
108 inline Type operator()(InputType x) const {
109 return eval(x);
110 }
111
112
115 inline unsigned int degree(real tolerance = MACH_EPSILON) const {
116
117 for (int i = coeff.size() - 1; i >= 0; --i) {
118 if(abs(coeff[i]) > MACH_EPSILON)
119 return i;
120 }
121
122 return 0;
123 }
124
125
128
129 size_t new_size = coeff.size();
130 for (size_t i = coeff.size() - 1; i > 0; --i) {
131
132 if(abs(coeff[i]) > tolerance)
133 break;
134
135 new_size--;
136 }
137
138 if (new_size == 0) {
139 coeff.resize(1);
140 coeff[0] = Type(0.0);
141 return;
142 }
143
144 if (new_size < coeff.size())
145 coeff.resize(new_size);
146 }
147
148
150 inline const vec<Type>& coeffs() const {
151 return coeff;
152 }
153
154
156 inline vec<Type>& coeffs() {
157 return coeff;
158 }
159
160
162 inline size_t size() const {
163 return coeff.size();
164 }
165
166
168 inline void resize(size_t sz) {
169 coeff.resize(sz);
170 }
171
172
174 inline polynomial operator+(const polynomial& p) const {
175
177 r.coeff.resize(max(coeff.size(), p.size()));
178
179 unsigned int i = 0;
180
181 for (; i < min(coeff.size(), p.size()); ++i)
182 r[i] = coeff[i] + p[i];
183
184 if (coeff.size() > p.size())
185 for (; i < coeff.size(); ++i)
186 r[i] = coeff[i];
187 else
188 for (; i < p.size(); ++i)
189 r[i] = p[i];
190
191 return r;
192 }
193
194
196 inline polynomial operator-(const polynomial& p) const {
197
199 r.coeff.resize(max(coeff.size(), p.size()));
200
201 unsigned int i = 0;
202
203 for (; i < min(r.size(), p.size()); ++i)
204 r[i] = coeff[i] - p[i];
205
206 if (coeff.size() > p.size())
207 for (; i < coeff.size(); ++i)
208 r[i] = coeff[i];
209 else
210 for (; i < p.size(); ++i)
211 r[i] = -p[i];
212
213 return r;
214 }
215
216
218 inline polynomial operator*(const polynomial& p) const {
219
221 r.coeff.resize(this->size() + p.size() - 1);
222
223 for (unsigned int i = 0; i < size(); ++i) {
224 for (unsigned int j = 0; j < p.size(); ++j) {
225 r[i + j] += coeff[i] * p[j];
226 }
227 }
228
229 return r;
230 }
231
232
234 inline polynomial operator/(const polynomial& d) const {
235
236 const unsigned int d_order = d.degree();
237 const unsigned int this_order = degree();
238
239 if(d_order == 0 && d[0] == 0) {
240 TH_MATH_ERROR("polynomial::operator/", d[0], MathError::DivByZero);
241 return polynomial(nan());
242 }
243
244 // Remainder
245 polynomial r = *this;
246
247 // Quotient
249 unsigned int i = 0;
250
251 while(i <= this_order) {
252
253 // Compute only once the degree of the polynomial
254 const unsigned int r_order = r.degree();
255
256 // Stop execution if the division is complete
257 // (when the remainder is 0 or has lower degree)
258 if((r_order == 0 && (abs(r[0]) < MACH_EPSILON)) || r_order < d_order)
259 break;
260
261 // Simple division between highest degree terms
263 r[r_order] / d[d_order],
264 r_order - d_order);
265
266 // Add monomial to quotient and subtract the
267 // monomial times the dividend from the remainder
268 q += t;
269 r -= t * d;
270
271 i++;
272 }
273
274 // Check if division failed to converge
275 if(i > this_order && r.degree() >= d_order) {
276 TH_MATH_ERROR("polynomial::operator/", i, MathError::NoConvergence);
277 return polynomial(nan());
278 }
279
280 return q;
281 }
282
283
285 template<typename ScalarType, disable_vector<ScalarType> = true>
287 return polynomial(coeff * a);
288 }
289
290
292 template<typename ScalarType, disable_vector<ScalarType> = true>
294
295 if(abs(a) < MACH_EPSILON) {
296 TH_MATH_ERROR("polynomial::operator/", a, MathError::DivByZero);
297 }
298
299 polynomial r = polynomial(*this);
300
301 for (unsigned int i = 0; i < size(); ++i)
302 r.coeff[i] /= a;
303
304 return r;
305 }
306
307
310
311 // Make room for the new coefficients
312 if(coeff.size() < p.size())
313 coeff.resize(p.size(), Type(0));
314
315 for (unsigned int i = 0; i < min(size(), p.size()); ++i)
316 coeff[i] += p[i];
317
318 return *this;
319 }
320
321
324
325 // Make room for the new coefficients
326 if(coeff.size() < p.size())
327 coeff.resize(p.size(), Type(0));
328
329 for (unsigned int i = 0; i < min(coeff.size(), p.size()); ++i)
330 coeff[i] -= p[i];
331
332 return *this;
333 }
334
335
338
340 r.coeff.resize(this->size() + p.size() - 1, Type(0));
341
342 for (unsigned int i = 0; i < coeff.size(); ++i)
343 for (unsigned int j = 0; j < p.size(); ++j)
344 r[i + j] += coeff[i] * p[j];
345
346 *this = r;
347 return *this;
348 }
349
350
352 template<typename ScalarType, disable_vector<ScalarType> = true>
354
355 for (unsigned int i = 0; i < coeff.size(); ++i)
356 coeff[i] *= a;
357
358 return *this;
359 }
360
361
363 inline polynomial& operator/=(const polynomial& a) {
364 return (*this = (*this / a));
365 }
366
367
369 template<typename ScalarType, disable_vector<ScalarType> = true>
371
372 if(abs(a) < MACH_EPSILON) {
373 TH_MATH_ERROR("polynomial::operator/=", a, MathError::DivByZero);
374 return *this;
375 }
376
377 for (unsigned int i = 0; i < coeff.size(); ++i)
378 coeff[i] /= a;
379
380 return *this;
381 }
382
383
385 inline bool operator==(const polynomial& other) const {
386
387 if (other.size() == 0 && size() == 0)
388 return true;
389
390 const size_t other_degree = other.degree();
391 const size_t this_degree = degree();
392
394 return false;
395
396 for (size_t i = 0; i <= this_degree; ++i)
397 if (abs(coeff[i] - other[i]) > MACH_EPSILON)
398 return false;
399
400 return true;
401 }
402
403
406 inline auto begin() {
407 return coeff.begin();
408 }
409
410
413 inline auto end() {
414 return coeff.end();
415 }
416
417
420 inline auto cbegin() const {
421 return coeff.cbegin();
422 }
423
424
427 inline auto cend() const {
428 return coeff.cend();
429 }
430
431
433 inline vec<complex<>, 2> quadratic_roots() const {
434
435 const int order = degree();
436
437 // Check that the polynomial is quadratic
438 if(order != 2) {
440 return vec<complex<>, 2>({nan(), nan()});
441 }
442
443 complex<> z1, z2;
444 const Type a = coeff[2];
445 const Type b = coeff[1];
446 const Type c = coeff[0];
447
448 // Linear case
449 if (abs(a) < MACH_EPSILON) {
450
451 if (abs(b) < MACH_EPSILON)
452 return {nan(), nan()};
453
454 return {-c/b, -c/b};
455 }
456
457 const Type discriminant = b * b - 4 * a * c;
459
460 const real sign = (b > 0) ? 1 : -1;
461 const complex<> q = -0.5 * (b + sign * delta);
462
463 if (abs(q) < MACH_EPSILON)
464 return {0.0, 0.0};
465
466 z1 = q / a;
467 z2 = c / q;
468
469 return {z1, z2};
470 }
471
472
475 template<typename Vector, enable_vector<Vector> = true>
476 inline static polynomial<Type> from_roots(const Vector& roots) {
477
479 p.resize(roots.size() + 1);
480 p[0] = Type(1.0);
481
482 for (size_t i = 0; i < roots.size(); i++)
483 p *= polynomial<Type>({-roots[i], 1});
484
485 return p;
486 }
487
488
490 inline static polynomial<Type> monomial(Type c, unsigned int order) {
491
493 m.coeff = vec<Type>(order + 1, Type(0.0));
494 m.coeff[order] = c;
495 return m;
496 }
497
498
499 // Friend operators to enable equations of the form
500 // (Type) op. (polynomial<Type>)
501
502 inline friend polynomial<Type> operator+(
503 Type r, const polynomial<Type>& z) {
504
505 return z + polynomial(r);
506 }
507
508 inline friend polynomial<Type> operator-(
509 Type r, const polynomial<Type>& z) {
510
511 return (z * -1) + polynomial(r);
512 }
513
514 template<typename ScalarType, disable_vector<ScalarType> = true>
516 return z * r;
517 }
518
519
520#ifndef THEORETICA_NO_PRINT
521
523 inline std::string to_string(
524 const std::string& unknown = "x",
525 const std::string& exponentiation = "^") const {
526
527 std::stringstream res;
528 const int sz = coeff.size();
529
530 if (size() == 0) {
531 res << Type(0.0);
532 return res.str();
533 }
534
535 res << coeff[sz - 1];
536
537 if (size() > 1)
538 res << "*" << unknown << exponentiation << (sz - 1) << " ";
539
540 for (int i = sz - 2; i >= 0; --i) {
541
542 if(abs(coeff[i]) < MACH_EPSILON)
543 continue;
544
545 res << (coeff[i] >= 0 ? "+ " : "- ");
546 res << abs(coeff[i]);
547
548 if(i) {
549 res << "*" << unknown << exponentiation << i;
550 res << " ";
551 }
552 }
553
554 return res.str();
555 }
556
557
559 inline operator std::string() {
560 return to_string();
561 }
562
563
566 friend std::ostream& operator<<(std::ostream& out, const polynomial& obj) {
567 return out << obj.to_string();
568 }
569
570#endif
571
572
573 };
574
575}
576
577#endif
Complex number in algebraic form .
Definition complex.h:26
A polynomial of arbitrary order with coefficients of a specified type.
Definition polynomial.h:28
polynomial & operator/=(const polynomial &a)
Divide a polynomial by a polynomial.
Definition polynomial.h:363
polynomial()=default
Default constructor.
polynomial & operator+=(const polynomial &p)
Sum a polynomial to this one.
Definition polynomial.h:309
auto begin()
Get an iterator for the first coefficient of the polynomial.
Definition polynomial.h:406
polynomial operator/(ScalarType a) const
Divide a polynomial by a scalar, provided it has coefficients supporting division.
Definition polynomial.h:293
polynomial(std::initializer_list< Type > l)
Initialize from an std::initializer_list.
Definition polynomial.h:58
void trim(real tolerance=MACH_EPSILON)
Remove trailing zero coefficients.
Definition polynomial.h:127
polynomial operator*(ScalarType a) const
Multiply a polynomial by a scalar.
Definition polynomial.h:286
polynomial(const Vector &c)
Initialize from a vector of coefficients where the n-th order coefficient is given by the n-th elemen...
Definition polynomial.h:48
polynomial operator/(const polynomial &d) const
Polynomial division.
Definition polynomial.h:234
void resize(size_t sz)
Change the number of coefficients of the polynomial.
Definition polynomial.h:168
vec< Type > & coeffs()
Get the coefficients of the polynomial as reference.
Definition polynomial.h:156
polynomial & operator*=(const polynomial &p)
Multiply two polynomials.
Definition polynomial.h:337
const vec< Type > & coeffs() const
Get the coefficients of the polynomial as const reference.
Definition polynomial.h:150
Type & at(unsigned int i)
Access i-th coefficient by reference, with bound checking.
Definition polynomial.h:73
unsigned int degree(real tolerance=MACH_EPSILON) const
Find the true order of the polynomial (ignoring trailing null coefficients)
Definition polynomial.h:115
polynomial(Type a)
Initialize as a constant.
Definition polynomial.h:41
auto end()
Get an iterator for the one plus last coefficient of the polynomial.
Definition polynomial.h:413
vec< complex<>, 2 > quadratic_roots() const
Compute the roots of a quadratic polynomial.
Definition polynomial.h:433
polynomial & operator*=(ScalarType a)
Multiply a polynomial by a scalar value.
Definition polynomial.h:353
friend std::ostream & operator<<(std::ostream &out, const polynomial &obj)
Stream the polynomial in string representation to an output stream (std::ostream)
Definition polynomial.h:566
polynomial & operator-=(const polynomial &p)
Subtract a polynomial from this one.
Definition polynomial.h:323
const Type & operator[](unsigned int i) const
Get the n-th order coefficient by constant reference.
Definition polynomial.h:79
static polynomial< Type > monomial(Type c, unsigned int order)
Returns a monomial of the given degree and coefficient.
Definition polynomial.h:490
bool operator==(const polynomial &other) const
Check whether two polynomials are equal.
Definition polynomial.h:385
polynomial operator*(const polynomial &p) const
Multiply two polynomials.
Definition polynomial.h:218
const Type & at(unsigned int i) const
Get i-th coefficient by constant reference, with bound checking.
Definition polynomial.h:68
Type & operator[](unsigned int i)
Get the n-th order coefficient by reference.
Definition polynomial.h:85
Type eval(InputType x) const
Evaluate the polynomial for a given value.
Definition polynomial.h:93
polynomial & operator/=(ScalarType a)
Divide a polynomial by a scalar value, provided it has coefficients supporting division.
Definition polynomial.h:370
polynomial(Args... args)
Construct a polynomial from its coefficients, where the n-th order coefficient is given by the n-th e...
Definition polynomial.h:64
size_t size() const
Get the number of coefficients.
Definition polynomial.h:162
auto cend() const
Get a const iterator for the one plus last coefficient of the polynomial.
Definition polynomial.h:427
static polynomial< Type > from_roots(const Vector &roots)
Construct a polynomial from its roots Uses numerically stable pairwise multiplication with sorted roo...
Definition polynomial.h:476
polynomial operator+(const polynomial &p) const
Sum two polynomials.
Definition polynomial.h:174
polynomial operator-(const polynomial &p) const
Subtract a polynomial from another.
Definition polynomial.h:196
std::string to_string(const std::string &unknown="x", const std::string &exponentiation="^") const
Convert the polynomial to string representation.
Definition polynomial.h:523
auto cbegin() const
Get a const iterator for the first coefficient of the polynomial.
Definition polynomial.h:420
Type operator()(InputType x) const
Evaluate the polynomial for a given value.
Definition polynomial.h:108
A statically allocated N-dimensional vector with elements of the given type.
Definition vec.h:92
#define TH_MATH_ERROR(F_NAME, VALUE, EXCEPTION)
TH_MATH_ERROR is a macro which throws exceptions or modifies errno (depending on which compilation op...
Definition error.h:219
Main namespace of the library which contains all functions and objects.
Definition algebra.h:27
double real
A real number, defined as a floating point type.
Definition constants.h:207
auto min(const Vector &X)
Finds the minimum value inside a dataset.
Definition dataset.h:347
dual2 sqrt(dual2 x)
Compute the square root of a second order dual number.
Definition dual2_functions.h:54
dual2 abs(dual2 x)
Compute the absolute value of a second order dual number.
Definition dual2_functions.h:242
Vector make_error()
Create a vector representing an error state, with all NaN values.
Definition algebra.h:103
auto sum(const Vector &X)
Compute the sum of a vector of real values using pairwise summation to reduce round-off error.
Definition dataset.h:215
auto max(const Vector &X)
Finds the maximum value inside a dataset.
Definition dataset.h:326
Vector roots(RealFunction f, real a, real b, real tol=OPTIMIZATION_TOL, real steps=10)
Find the roots of a univariate real function inside a given interval, by first searching for candidat...
Definition roots.h:649
TH_CONSTEXPR real nan()
Return a quiet NaN number in floating point representation.
Definition error.h:74
@ ImpossibleOperation
Mathematically impossible operation.
@ NoConvergence
Algorithm did not converge.
@ DivByZero
Division by zero.
constexpr real MACH_EPSILON
Machine epsilon for the real type.
Definition constants.h:216