Theoretica
Mathematical Library
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
24 template<typename Type = real>
25 class polynomial {
26 public:
27
29 std::vector<Type> coeff;
30
32 polynomial() = default;
33
35 polynomial(Type a) : coeff({a}) {}
36
41 template <typename Vector, enable_vector<Vector> = true>
42 explicit polynomial(const Vector& c) {
43
44 coeff.resize(c.size());
45
46 for (size_t i = 0; i < c.size(); ++i)
47 coeff[i] = c[i];
48 }
49
51 polynomial(std::initializer_list<Type> l) : coeff(l) {}
52
53
55 inline const Type& at(unsigned int i) const {
56 return coeff.at(i);
57 }
58
60 inline Type& at(unsigned int i) {
61 return coeff.at(i);
62 }
63
64
66 inline const Type& operator[](unsigned int i) const {
67 return coeff[i];
68 }
69
70
72 inline Type& operator[](unsigned int i) {
73 return coeff[i];
74 }
75
76
78 template<typename EvalType = Type>
79 inline EvalType eval(EvalType x) const {
80
81 EvalType sum = EvalType(0.0);
82
83 // Evaluate using Horner's method
84 for (unsigned int i = 0; i < coeff.size(); ++i)
85 sum = coeff[coeff.size() - i - 1] + x * sum;
86
87 return sum;
88 }
89
90
92 template<typename EvalType = Type>
93 inline EvalType operator()(EvalType x) const {
94 return eval(x);
95 }
96
97
100 inline unsigned int find_order() const {
101
102 for (int i = coeff.size() - 1; i >= 0; --i) {
103 if(abs(coeff[i]) > MACH_EPSILON)
104 return i;
105 }
106
107 return 0;
108 }
109
110
112 inline void trim() {
113
114 for (unsigned int i = coeff.size() - 1; i >= 0; --i) {
115 if(abs(coeff[i]) > MACH_EPSILON)
116 break;
117
118 coeff.pop_back();
119 }
120 }
121
122
124 inline size_t size() const {
125 return coeff.size();
126 }
127
128
130 inline polynomial operator+(const polynomial& p) const {
131
132 polynomial r;
133 r.coeff.resize(max(coeff.size(), p.size()));
134
135 unsigned int i = 0;
136
137 for (; i < min(coeff.size(), p.size()); ++i)
138 r[i] = coeff[i] + p[i];
139
140 if (coeff.size() > p.size())
141 for (; i < coeff.size(); ++i)
142 r[i] = coeff[i];
143 else
144 for (; i < p.size(); ++i)
145 r[i] = p[i];
146
147 return r;
148 }
149
150
152 inline polynomial operator-(const polynomial& p) const {
153
154 polynomial r;
155 r.coeff.resize(max(coeff.size(), p.size()));
156
157 unsigned int i = 0;
158
159 for (; i < min(r.size(), p.size()); ++i)
160 r[i] = coeff[i] - p[i];
161
162 if (coeff.size() > p.size())
163 for (; i < coeff.size(); ++i)
164 r[i] = coeff[i];
165 else
166 for (; i < p.size(); ++i)
167 r[i] = -p[i];
168
169 return r;
170 }
171
172
174 inline polynomial operator*(const polynomial& p) const {
175
177 r.coeff.resize(this->size() + p.size() - 1);
178
179 for (unsigned int i = 0; i < size(); ++i) {
180 for (unsigned int j = 0; j < p.size(); ++j) {
181 r[i + j] += coeff[i] * p[j];
182 }
183 }
184
185 return r;
186 }
187
188
190 inline polynomial operator/(const polynomial& d) const {
191
192 const unsigned int d_order = d.find_order();
193 const unsigned int this_order = find_order();
194
195 if(d_order == 0 && d[0] == 0) {
196 TH_MATH_ERROR("polynomial::operator/", d[0], MathError::DivByZero);
197 return polynomial(nan());
198 }
199
200 // Remainder
201 polynomial r = *this;
202
203 // Quotient
205 unsigned int i = 0;
206
207 while(i < this_order) {
208
209 // Compute only once the degree of the polynomial
210 const unsigned int r_order = r.find_order();
211
212 // Stop execution if the division is complete
213 // (when the remainder is 0 or has lower degree)
214 if((r_order == 0 && (abs(r[0]) < MACH_EPSILON)) || r_order < d_order)
215 break;
216
217 // Simple division between highest degree terms
219 r[r_order] / d[d_order],
220 r_order - d_order);
221
222 // Add monomial to quotient and subtract the
223 // monomial times the dividend from the remainder
224 q += t;
225 r -= t * d;
226
227 i++;
228 }
229
230 // The algorithm has stopped iterating after a number
231 // of the dividend's degree counts
232 if(i == this_order) {
233 TH_MATH_ERROR("polynomial::operator/", i, MathError::NoConvergence);
234 return polynomial(nan());
235 }
236
237 return q;
238 }
239
240
242 inline polynomial operator*(Type a) const {
243
244 polynomial r = polynomial(*this);
245
246 for (unsigned int i = 0; i < size(); ++i)
247 r.coeff[i] *= a;
248
249 return r;
250 }
251
252
254 inline polynomial operator/(Type a) const {
255
256 if(abs(a) < MACH_EPSILON) {
257 TH_MATH_ERROR("polynomial::operator/", a, MathError::DivByZero);
258 }
259
260 polynomial r = polynomial(*this);
261
262 for (unsigned int i = 0; i < size(); ++i)
263 r.coeff[i] /= a;
264
265 return r;
266 }
267
268
270 inline polynomial& operator+=(const polynomial& p) {
271
272 // Make room for the new coefficients
273 if(coeff.size() < p.size())
274 coeff.resize(p.size(), Type(0));
275
276 for (unsigned int i = 0; i < min(size(), p.size()); ++i)
277 coeff[i] += p[i];
278
279 return *this;
280 }
281
282
284 inline polynomial& operator-=(const polynomial& p) {
285
286 // Make room for the new coefficients
287 if(coeff.size() < p.size())
288 coeff.resize(p.size(), Type(0));
289
290 for (unsigned int i = 0; i < min(coeff.size(), p.size()); ++i)
291 coeff[i] -= p[i];
292
293 return *this;
294 }
295
296
298 inline polynomial& operator*=(const polynomial& p) {
299
301 r.coeff.resize(this->size() + p.size() - 1, Type(0));
302
303 for (unsigned int i = 0; i < coeff.size(); ++i)
304 for (unsigned int j = 0; j < p.size(); ++j)
305 r[i + j] += coeff[i] * p[j];
306
307 *this = r;
308 return *this;
309 }
310
311
313 inline polynomial& operator*=(Type a) {
314
315 for (unsigned int i = 0; i < coeff.size(); ++i)
316 coeff[i] *= a;
317
318 return *this;
319 }
320
321
323 inline polynomial& operator/=(const polynomial& a) {
324 return (*this = (*this / a));
325 }
326
327
329 inline polynomial& operator/=(Type a) {
330
331 if(abs(a) < MACH_EPSILON) {
332 TH_MATH_ERROR("polynomial::operator/=", a, MathError::DivByZero);
333 return *this;
334 }
335
336 for (unsigned int i = 0; i < coeff.size(); ++i)
337 coeff[i] /= a;
338
339 return *this;
340 }
341
342
344 inline bool operator==(const polynomial& other) const {
345
346 const unsigned int n = min(other.size(), this->size());
347 for (unsigned int i = 0; i < n; ++i) {
348 if(abs(other.coeff[i] - coeff[i]) >= MACH_EPSILON)
349 return false;
350 }
351
352 if(size() > other.size()) {
353 for (unsigned int i = 0; i < size(); ++i) {
354 if(abs(coeff[i]) >= MACH_EPSILON)
355 return false;
356 }
357 } else {
358 for (unsigned int i = 0; i < other.size(); ++i) {
359 if(abs(other.coeff[i]) >= MACH_EPSILON)
360 return false;
361 }
362 }
363
364 return true;
365 }
366
367
370 inline auto begin() {
371 return coeff.begin();
372 }
373
374
377 inline auto end() {
378 return coeff.end();
379 }
380
381
384 inline auto cbegin() {
385 return coeff.cbegin();
386 }
387
388
391 inline auto cend() {
392 return coeff.cend();
393 }
394
395
397 inline vec<complex<>, 2> quadratic_roots() const {
398
399 const int order = find_order();
400
401 // Check that the polynomial is quadratic
402 if(order != 2) {
403 TH_MATH_ERROR("quadratic_roots", order, MathError::ImpossibleOperation);
404 return vec<complex<>, 2>({nan(), nan()});
405 }
406
407 const Type p = coeff[1] / coeff[2];
408 const Type q = coeff[0] / coeff[2];
409
410 // Case when 0 is a root
411 if(abs(q) < MACH_EPSILON)
412 return {complex<>(-p), complex<>(0)};
413
414 complex<> z1, z2;
415
416 // Use Vieta's theorem to avoid catastrophic cancellation
417 if(abs(p) > 1) {
418
419 z1 = -sgn(p) * (abs(p) / 2.0
420 + abs(p) * sqrt(complex<>(0.25 - (q / p) / p)));
421 z2 = q / z1;
422
423 } else {
424
425 const complex<> s = sqrt(complex<>(0.25 * square(p) - q));
426 z1 = -p / 2.0 + s;
427 z2 = -p / 2.0 - s;
428 }
429
430 return {z1, z2};
431 }
432
433
435 inline static polynomial<Type> from_roots(
436 const std::vector<Type>& roots) {
437
438 polynomial<Type> P = {1};
439
440 // P = product((x - r_i))
441 for (unsigned int i = 0; i < roots.size(); ++i)
442 P *= polynomial<Type>({roots[i] * -1, 1});
443
444 return P;
445 }
446
447
449 inline static polynomial<Type> monomial(Type c, unsigned int order) {
450
451 polynomial m;
452 m.coeff = std::vector<Type>(order + 1, Type(0));
453 m.coeff[order] = c;
454 return m;
455 }
456
457
458 // Friend operators to enable equations of the form
459 // (Type) op. (polynomial<Type>)
460
461 inline friend polynomial<Type> operator+(
462 Type r, const polynomial<Type>& z) {
463
464 return z + polynomial(r);
465 }
466
467 inline friend polynomial<Type> operator-(
468 Type r, const polynomial<Type>& z) {
469
470 return (z * -1) + polynomial(r);
471 }
472
473 inline friend polynomial<Type> operator*(
474 Type r, const polynomial<Type>& z) {
475
476 return z * r;
477 }
478
479
480#ifndef THEORETICA_NO_PRINT
481
483 inline std::string to_string(
484 const std::string& unknown = "x",
485 const std::string& exponentiation = "^") const {
486
487 std::stringstream res;
488 const int sz = coeff.size();
489
490 if (size() == 0) {
491 res << Type(0.0);
492 return res.str();
493 }
494
495 res << coeff[sz - 1];
496
497 if (size() > 1)
498 res << "*" << unknown << exponentiation << (sz - 1) << " ";
499
500 for (int i = sz - 2; i >= 0; --i) {
501
502 if(abs(coeff[i]) < MACH_EPSILON)
503 continue;
504
505 res << (coeff[i] >= 0 ? "+ " : "- ");
506 res << abs(coeff[i]);
507
508 if(i) {
509 res << "*" << unknown << exponentiation << i;
510 res << " ";
511 }
512 }
513
514 return res.str();
515 }
516
517
519 inline operator std::string() {
520 return to_string();
521 }
522
523
526 friend std::ostream& operator<<(std::ostream& out, const polynomial& obj) {
527 return out << obj.to_string();
528 }
529
530#endif
531
532
533 };
534
535}
536
537#endif
A polynomial of arbitrary order.
Definition polynomial.h:25
polynomial & operator/=(const polynomial &a)
Multiply a polynomial by a scalar value.
Definition polynomial.h:323
polynomial()=default
Default constructor.
polynomial & operator+=(const polynomial &p)
Sum a polynomial to this one.
Definition polynomial.h:270
auto begin()
Get an iterator for the first coefficient of the polynomial.
Definition polynomial.h:370
polynomial(std::initializer_list< Type > l)
Initialize from an std::initializer_list.
Definition polynomial.h:51
auto cbegin()
Get a const iterator for the first coefficient of the polynomial.
Definition polynomial.h:384
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:42
EvalType eval(EvalType x) const
Evaluate the polynomial using x as variable.
Definition polynomial.h:79
polynomial operator/(const polynomial &d) const
Polynomial division.
Definition polynomial.h:190
void trim()
Remove trailing zero coefficients.
Definition polynomial.h:112
EvalType operator()(EvalType x) const
Evaluate the polynomial using x as variable.
Definition polynomial.h:93
polynomial & operator*=(const polynomial &p)
Multiply two polynomials.
Definition polynomial.h:298
Type & at(unsigned int i)
Access i-th coefficient by reference, with bound checking.
Definition polynomial.h:60
polynomial(Type a)
Initialize as a constant.
Definition polynomial.h:35
auto end()
Get an iterator for the one plus last coefficient of the polynomial.
Definition polynomial.h:377
vec< complex<>, 2 > quadratic_roots() const
Compute the roots of a quadratic polynomial.
Definition polynomial.h:397
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:526
polynomial & operator-=(const polynomial &p)
Subtract a polynomial from this one.
Definition polynomial.h:284
const Type & operator[](unsigned int i) const
Get the n-th order coefficient by constant reference.
Definition polynomial.h:66
static polynomial< Type > monomial(Type c, unsigned int order)
Returns a monomial of the given degree and coefficient.
Definition polynomial.h:449
bool operator==(const polynomial &other) const
Check whether two polynomials are equal.
Definition polynomial.h:344
polynomial operator*(const polynomial &p) const
Multiply two polynomials.
Definition polynomial.h:174
polynomial & operator/=(Type a)
Divide a polynomial by a scalar value.
Definition polynomial.h:329
const Type & at(unsigned int i) const
Get i-th coefficient by constant reference, with bound checking.
Definition polynomial.h:55
Type & operator[](unsigned int i)
Get the n-th order coefficient by reference.
Definition polynomial.h:72
unsigned int find_order() const
Find the true order of the polynomial (ignoring trailing null coefficients)
Definition polynomial.h:100
auto cend()
Get a const iterator for the one plus last coefficient of the polynomial.
Definition polynomial.h:391
size_t size() const
Get the number of coefficients.
Definition polynomial.h:124
polynomial operator+(const polynomial &p) const
Sum two polynomials.
Definition polynomial.h:130
polynomial operator-(const polynomial &p) const
Subtract a polynomial from another.
Definition polynomial.h:152
polynomial operator/(Type a) const
Divide a polynomial by a scalar.
Definition polynomial.h:254
std::string to_string(const std::string &unknown="x", const std::string &exponentiation="^") const
Convert the polynomial to string representation.
Definition polynomial.h:483
polynomial & operator*=(Type a)
Multiply a polynomial by a scalar value.
Definition polynomial.h:313
std::vector< Type > coeff
Coefficients of the polynomial, coeff[n] is the n-th order coefficient.
Definition polynomial.h:29
polynomial operator*(Type a) const
Multiply a polynomial by a scalar.
Definition polynomial.h:242
static polynomial< Type > from_roots(const std::vector< Type > &roots)
Construct a polynomial from its roots.
Definition polynomial.h:435
#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:238
Main namespace of the library which contains all functions and objects.
Definition algebra.h:27
auto min(const Vector &X)
Finds the minimum value inside a dataset.
Definition dataset.h:351
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:198
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:219
std::vector< real > 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:650
auto max(const Vector &X)
Finds the maximum value inside a dataset.
Definition dataset.h:330
TH_CONSTEXPR real nan()
Return a quiet NaN number in floating point representation.
Definition error.h:78
@ 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
int sgn(real x)
Return the sign of x (1 if positive, -1 if negative, 0 if null)
Definition real_analysis.h:259
dual2 square(dual2 x)
Return the square of a second order dual number.
Definition dual2_functions.h:23