Controlpp
Loading...
Searching...
No Matches
Polynom.hpp
Go to the documentation of this file.
1#pragma once
2
3// std
4#include <cstdint>
5#include <ostream>
6#include <initializer_list>
7#include <iterator>
8#include <concepts>
9#include <complex>
10#include <limits>
11
12// eigen
13#include <Eigen/Core>
14#include <Eigen/Dense>
15#include <Eigen/Eigenvalues>
16
17#include "math.hpp"
18
19namespace controlpp
20{
21
38 template<class T, int Order>
39 class Polynom{
40 public:
41 using value_type = T;
42 static constexpr int eigen_vector_size = (Order == Eigen::Dynamic) ? Eigen::Dynamic : Order + 1;
43 using vector_type = Eigen::Vector<T, eigen_vector_size>;
44
45 private:
46 vector_type vector_;
47
48 public:
49
51 Polynom() = default;
52
54 Polynom(const Polynom&) = default;
55
56 template<int OtherOrder>
57 requires(OtherOrder < Order)
59 size_t i = 0;
60 for(; i < other.size(); ++i){
61 this->at(i) = other.at(i);
62 }
63 for(; i < this->size(); ++i){
64 this->at(i) = static_cast<T>(0);
65 }
66 }
67
68 template<class... Args>
69 requires(Order != Eigen::Dynamic && (std::convertible_to<Args, T> && ...))
70 explicit Polynom(Args&&... args) : vector_(std::forward<Args>(args)...){}
71
72 template<class... Args>
73 requires(Order == Eigen::Dynamic && (std::convertible_to<Args, T> && ...))
74 explicit Polynom(Args&&... args) : vector_(Eigen::Vector<T, sizeof...(Args)>(std::forward<Args>(args)...)){}
75
76
78 Polynom& operator=(const Polynom&) = default;
79
81 template<int M>
82 requires(M < Order)
83 Polynom& operator=(const Polynom<T, M>& other){
84 size_t i = 0;
85 for(; i < other.size(); ++i){
86 this->at(i) = other.at(i);
87 }
88 for(; i < this->size(); ++i){
89 this->at(i) = static_cast<T>(0);
90 }
91 return *this;
92 }
93
96 template<int M>
97 requires((Order != Eigen::Dynamic) && (M == Order+1))
98 explicit Polynom(const T (&array)[M]) : vector_(array){}
99
102 template<int M>
103 requires((Order != Eigen::Dynamic) && (M < Order+1))
104 explicit Polynom(const T (&array)[M]){
105 size_t i = 0;
106 for(; i < M; ++i){
107 this->vector_[i] = array[i];
108 }
109 for(; i < this->size(); ++i){
110 this->vector_[i] = static_cast<T>(0);
111 }
112 }
113
119 explicit Polynom(const T* values, size_t length){
120 if constexpr (Order == Eigen::Dynamic){
121 this->vector_.resize(length);
122 }
123 size_t i = 0;
124 for(; i < length && i < this->size(); ++i){
125 this->vector_(i) = values[i];
126 }
127 for(; i < this->size(); ++i){
128 this->vector_(i) = static_cast<T>(0);
129 }
130 }
131
137 template<int M>
138 requires(Order == Eigen::Dynamic)
139 explicit Polynom(const T (&array)[M])
140 : Polynom(array, M){}
141
144 template<int M>
145 requires((Order != Eigen::Dynamic) && (M != Eigen::Dynamic) && (M == Order+1))
146 explicit Polynom(const Eigen::Vector<T, M>& vector) : vector_(vector){}
147
148 template<class U>
149 requires(std::constructible_from<Eigen::Vector<T, eigen_vector_size>, U>)
150 explicit Polynom(const U& vector_expression) : vector_(vector_expression){}
151
152 template<int M>
153 requires((Order != Eigen::Dynamic) && (M != Eigen::Dynamic) && (M < Order+1))
154 explicit Polynom(const Eigen::Vector<T, M>& vector){
155 size_t i = 0;
156 for(; i < vector.size(); ++i){
157 this->vector_[i] = vector(i);
158 }
159 for(; i < this->size(); ++i){
160 this->vector_[i] = static_cast<T>(0);
161 }
162 }
163
164 template<std::same_as<T> U>
165 requires(Order == Eigen::Dynamic)
166 explicit Polynom(const Eigen::Vector<U, Eigen::Dynamic>& vector) : vector_(vector.size()){
167 this->vector_ = vector;
168 }
169
170 template<int M>
171 requires(Order == Eigen::Dynamic && M != Eigen::Dynamic)
172 explicit Polynom(const Eigen::Vector<T, M>& vector) : vector_(M){
173 this->vector_ = vector;
174 }
175
179 const T& at(size_t i) const {return this->vector_[i];}
180
184 T& at(size_t i) {return this->vector_[i];}
185
189 const T& operator[](size_t i) const {return this->at(i);}
190
194 T& operator[](size_t i) {return this->at(i);}
195
198 vector_type& vector(){return this->vector_;}
199
202 const vector_type& vector() const {return this->vector_;}
203
207 size_t size() const {return this->vector_.size();}
208
212 size_t order() const {
213 size_t result = this->size()-1;
214 for(size_t i = 0; i < this->size(); ++i){
215 const T& elem = this->at(this->size() - 1 - i);
216 const T zero(0);
217 if(elem != zero){
218 break;
219 }
220 --result;
221 }
222 return result;
223 }
224
226 void setZero() {this->vector_.setZero();}
227
232 T eval(const T& x) const {
233 T sum = static_cast<T>(0);
234 for(int i = this->size()-1; i >= 0; --i){
235 sum = sum * x + this->at(i);
236 }
237 return sum;
238 }
239
245 T operator() (const T& x) const {
246 return this->eval(x);
247 }
248
254 template<int M>
255 Eigen::Vector<T, M> eval(const Eigen::Vector<T, M>& x_vec) const {
256 Eigen::Vector<T, M> sum_vec;
257 if constexpr (M == Eigen::Dynamic) sum_vec.resize(x_vec.size());
258 sum_vec.setZero();
259
260 for(int i = this->size()-1; i >= 0; --i){
261 sum_vec.array() = sum_vec.array() * x_vec.array() + this->at(i);
262 }
263
264 return sum_vec;
265 }
266
272 template<int M>
273 Eigen::Vector<T, M> operator() (const Eigen::Vector<T, M>& x_vec) const {
274 return this->eval(x_vec);
275 }
276
281 std::complex<T> eval(const std::complex<T>& x) const {
282 std::complex<T> sum(static_cast<T>(0), static_cast<T>(0));
283 for(int i = this->size()-1; i >= 0; --i){
284 sum = sum * x + this->at(i);
285 }
286 return sum;
287 }
288
294 std::complex<T> operator() (const std::complex<T>& x) const {
295 return this->eval(x);
296 }
297
303 template<int M>
304 Eigen::Vector<std::complex<T>, M> eval(const Eigen::Vector<std::complex<T>, M>& x_vec) const {
305 Eigen::Vector<std::complex<T>, M> sum_vec;
306 if constexpr (M == Eigen::Dynamic) sum_vec.resize(x_vec.size());
307 sum_vec.setZero();
308
309 for(int i = this->size()-1; i >= 0; --i){
310 sum_vec.array() = sum_vec.array() * x_vec.array() + this->at(i);
311 }
312
313 return sum_vec;
314 }
315
321 template<int M>
322 Eigen::Vector<std::complex<T>, M> operator() (const Eigen::Vector<std::complex<T>, M>& x_vec) const {
323 return this->eval(x_vec);
324 }
325
331 bool is_zero(T epsilon = std::numeric_limits<T>::min()) const {
332 for(size_t i = 0; i < this->size(); ++i){
333 if((this->at(i) >= epsilon)){
334 return false;
335 }
336 }
337 return true;
338 }
339
343 void print (std::ostream& stream, std::string_view var="x") const {
344 if(this->is_zero()){
345 stream << '0';
346 return;
347 }
348 for(size_t i = 0; i < this->size(); ++i){
349 if(this->at(i) != static_cast<T>(0)){
350 const auto value = this->at(i);
351 if(value > 0){
352 if(i > 0) stream << " + ";
353
354 stream << value;
355
356 if(i == 1) stream << ' ' << var;
357 else if(i > 1) stream << ' ' << var << '^' << i;
358 }else if(value < 0){
359 if(i == 0) stream << "- ";
360 else if(i > 0) stream << " - ";
361
362 stream << (-value);
363
364 if(i == 1) stream << ' ' << var;
365 else if(i > 1) stream << ' ' << var << '^' << i;
366 }
367 }
368 }
369 }
370
371 void print (std::ostream& stream, std::function<std::string(int i)> var) const {
372 if(this->is_zero()){
373 stream << '0';
374 return;
375 }
376 for(size_t i = 0; i < this->size(); ++i){
377 if(this->at(i) != static_cast<T>(0)){
378 const auto value = this->at(i);
379 if(value > 0){
380 if(i > 0) stream << " + ";
381
382 stream << value;
383
384 if(i == 1) stream << ' ' << var(i);
385 else if(i > 1) stream << ' ' << var(i) << '^' << i;
386 }else if(value < 0){
387 if(i == 0) stream << "- ";
388 else if(i > 0) stream << " - ";
389
390 stream << (-value);
391
392 if(i == 1) stream << ' ' << var(i);
393 else if(i > 1) stream << ' ' << var(i) << '^' << i;
394 }
395 }
396 }
397 }
398
403 friend std::ostream& operator<< (std::ostream& stream, const Polynom& poly){
404 poly.print(stream, "x");
405 return stream;
406 }
407
408 template<int M>
409 requires(M <= Order)
410 Polynom& operator+=(const Polynom<T, M>& other){
411 for(size_t i = 0; i < other.size(); ++i){
412 this->at(i) += other.at(i);
413 }
414 return *this;
415 }
416
417 template<int M>
418 requires(M <= Order)
419 Polynom& operator-=(const Polynom<T, M>& other){
420 for(size_t i = 0; i < other.size(); ++i){
421 this->at(i) -= other.at(i);
422 }
423 return *this;
424 }
425
426 template<std::convertible_to<T> U>
427 Polynom& operator*=(const U& num){
428 this->vector() *= static_cast<T>(num);
429 return *this;
430 }
431
432 template<std::convertible_to<T> U>
433 Polynom& operator/=(const U& num){
434 this->vector() /= static_cast<T>(num);
435 return *this;
436 }
437 };
438
439 // -----------------------------------------------------------------------------------------------
440 // Roots, Zeros
441 // -----------------------------------------------------------------------------------------------
442
446 template<class T>
447 Eigen::Vector<std::complex<T>, 0> zeros([[maybe_unused]] const Polynom<T, 0>& polynom){
448 return Eigen::Vector<std::complex<T>, 0>();
449 }
450
464 template<class T>
465 Eigen::Vector<std::complex<T>, 1> zeros(const Polynom<T, 1>& polynom){
466 const std::complex x0 = - polynom[0] / polynom[1];
467 Eigen::Vector<std::complex<T>, 1> result(x0);
468 return result;
469 }
470
482 template<class T>
483 Eigen::Vector<std::complex<T>, 2> zeros(const Polynom<T, 2>& polynom){
484 const std::complex c = polynom[0];
485 const std::complex b = polynom[1];
486 const std::complex a = polynom[2];
487 const std::complex x1 = (-b - std::sqrt(b * b - static_cast<T>(4) * a * c)) / (static_cast<T>(2) * a);
488 const std::complex x2 = (-b + std::sqrt(b * b - static_cast<T>(4) * a * c)) / (static_cast<T>(2) * a);
489 const Eigen::Vector<std::complex<T>, 2> result(x1, x2);
490 return result;
491 }
492
499 template<class T, int N>
500 requires(N > 1)
501 Eigen::Vector<std::complex<T>, N> zeros(const Polynom<T, N>& polynom){
502 const Eigen::Matrix<T, N, N> C = controlpp::companion(polynom.vector());
503 const Eigen::Vector<std::complex<T>, N> result = C.eigenvalues();
504 return result;
505 }
506
507 // -----------------------------------------------------------------------------------------------
508 // Comparison Operators
509 // -----------------------------------------------------------------------------------------------
510
517 template<class T, int N>
518 bool operator==(const Polynom<T, N>& lhs, const Polynom<T, N>& rhs){
519 return lhs.vector() == rhs.vector();
520 }
521
522 template<class T, int N>
523 bool operator!=(const Polynom<T, N>& lhs, const Polynom<T, N>& rhs){
524 return lhs.vector() != rhs.vector();
525 }
526
527 // -----------------------------------------------------------------------------------------------
528 // Arithmetic Operators
529 // -----------------------------------------------------------------------------------------------
530
531 // operator +
532 // ----------
533
534 template<class T, int Nl, int Nr>
535 Polynom<T, (Nl > Nr) ? Nl : Nr> operator+(const Polynom<T, Nl>& lhs, const Polynom<T, Nr>& rhs){
536 if constexpr (Nl > Nr){
537 Polynom<T, Nl> result;
538 result.vector().head(rhs.size()) = lhs.vector().head(rhs.size()) + rhs.vector();
539 result.vector().tail(lhs.size() - rhs.size()) = lhs.vector().tail(lhs.size() - rhs.size());
540 return result;
541 }else if constexpr (Nl == Nr){
542 return Polynom<T, Nl>(lhs.vector() + rhs.vector());
543 }else{
544 Polynom<T, Nr> result;
545 result.vector().head(lhs.size()) = lhs.vector() + rhs.vector().head(lhs.size());
546 result.vector().tail(rhs.size() - lhs.size()) = rhs.vector().tail(rhs.size() - lhs.size());
547 return result;
548 }
549 }
550
551 template<class Tpoly, std::convertible_to<Tpoly> Tscalar, int N>
552 Polynom<Tpoly, N> operator+(const Tscalar& lhs, const Polynom<Tpoly, N>& rhs){
553 Polynom<Tpoly, N> result(rhs);
554 result[0] += static_cast<Tpoly>(lhs);
555 return result;
556 }
557
558 template<class Tpoly, std::convertible_to<Tpoly> Tscalar, int N>
559 Polynom<Tpoly, N> operator+(const Polynom<Tpoly, N>& lhs, const Tscalar& rhs){
560 return ((static_cast<Tpoly>(rhs) + lhs).eval());
561 }
562
563 // operator -
564 // ----------
565
566 template<class T, int N>
568 return Polynom<T, N>((-poly.vector()).eval());
569 }
570
571 template<class T, int Nl, int Nr>
572 Polynom<T, (Nl > Nr) ? Nl : Nr> operator-(const Polynom<T, Nl>& lhs, const Polynom<T, Nr>& rhs){
573 if constexpr (Nl > Nr){
574 Polynom<T, Nl> result;
575 result.vector().head(rhs.size()) = lhs.vector().head(rhs.size()) - rhs.vector();
576 result.vector().tail(lhs.size() - rhs.size()) = lhs.vector().tail(lhs.size() - rhs.size());
577 return result;
578 }else if constexpr (Nl == Nr){
579 return Polynom<T, Nl>(lhs.vector() - rhs.vector());
580 }else{
581 Polynom<T, Nr> result;
582 result.vector().head(lhs.size()) = lhs.vector() + rhs.vector().head(lhs.size());
583 result.vector().tail(rhs.size() - lhs.size()) = -rhs.vector().tail(rhs.size() - lhs.size());
584 return result;
585 }
586 }
587
588 template<class Tpoly, std::convertible_to<Tpoly> Tscalar, int N>
589 Polynom<Tpoly, N> operator-(const Tscalar& lhs, const Polynom<Tpoly, N>& rhs){
590 Polynom<Tpoly, N> result(-rhs);
591 result[0] += static_cast<Tpoly>(lhs);
592 return result;
593 }
594
595 template<class Tpoly, std::convertible_to<Tpoly> Tscalar, int N>
596 Polynom<Tpoly, N> operator-(const Polynom<Tpoly, N>& lhs, const Tscalar& rhs){
597 Polynom<Tpoly, N> result(lhs);
598 result[0] -= static_cast<Tpoly>(rhs);
599 return result;
600 }
601
602 // operator *
603 // ----------
604
605 template<class T, int lOrder, int rOrder>
608 result.setZero();
609
610 for(size_t i = 0; i < rhs.size(); ++i){
611 result.vector().segment(i, lhs.size()) += lhs.vector() * rhs[i];
612 }
613
614 return result;
615 }
616
617 template<class Tpoly, std::convertible_to<Tpoly> Tscalar, int Order>
619 return Polynom<Tpoly, Order>((lhs.vector() * static_cast<Tpoly>(rhs)).eval());
620 }
621
622 template<class Tpoly, std::convertible_to<Tpoly> Tscalar, int Order>
624 return Polynom<Tpoly, Order>(rhs * static_cast<Tpoly>(lhs));
625 }
626
627 // operator /
628 // ----------
629
630 template<class Tpoly, std::convertible_to<Tpoly> Tscalar, int Order>
632 return Polynom<Tpoly, Order>(lhs.vector() / static_cast<Tscalar>(rhs));
633 }
634
635
636 namespace polynom{
637
638 template<class T>
639 inline const Polynom<T, 1> x(0, 1);
640 }
641
642// -----------------------------------------------------------------------------------------------------------------
643// -----------------------------------------------------------------------------------------------------------------
644// -----------------------------------------------------------------------------------------------------------------
645
664 template<class T, int Order>
666 public:
667 using value_type = T;
668 using vector_type = Eigen::Vector<T, Order+1>;
669
670 private:
671 vector_type vector_;
672
673 public:
674
676 FixedPolynom() = default;
677
679 FixedPolynom(const FixedPolynom&) = default;
680
681 template<std::convertible_to<T> U>
682 FixedPolynom(const U& value) : vector_(Eigen::Vector<T, Order+1>::Zero()){
683 vector_(0) = static_cast<T>(value);
684 }
685
686 template<int M>
687 requires(M < Order)
689 size_t i = 0;
690 for(; i < other.size(); ++i){
691 this->at(i) = other.at(i);
692 }
693 for(; i < this->size(); ++i){
694 this->at(i) = static_cast<T>(0);
695 }
696 };
697
700
701 template<int M>
702 requires(M < Order)
703 FixedPolynom& operator=(const FixedPolynom<T, M>& other){
704 size_t i = 0;
705 for(; i < other.size(); ++i){
706 this->at(i) = other.at(i);
707 }
708 for(; i < this->size(); ++i){
709 this->at(i) = static_cast<T>(0);
710 }
711 return *this;
712 };
713
714
717 explicit FixedPolynom(const T (&values)[Order+1]){
718 for(size_t i = 0; i < this->size(); ++i){
719 this->vector_[i] = values[i];
720 }
721 }
722
723 template<int M>
724 requires(M < Order+1)
725 explicit FixedPolynom(const T (&values)[M]){
726 size_t i = 0;
727 for(; i < M; ++i){
728 this->vector_[i] = values[i];
729 }
730 for(; i < this->size(); ++i){
731 this->vector_[i] = static_cast<T>(0);
732 }
733 }
734
737 explicit FixedPolynom(const Eigen::Vector<T, Order+1>& vector) : vector_(vector){}
738
739 template<int M>
740 requires(M < Order+1)
741 explicit FixedPolynom(const Eigen::Vector<T, M>& vector){
742 size_t i = 0;
743 for(; i < vector.size(); ++i){
744 this->vector_[i] = vector[i];
745 }
746 for(; i < this->size(); ++i){
747 this->vector_[i] = static_cast<T>(0);
748 }
749 }
750
751 FixedPolynom& operator=(const T (&values)[Order+1]) {
752 this->vector_ = values;
753 return *this;
754 }
755
756 template<int M>
757 requires(M < Order+1)
758 FixedPolynom& operator=(const T (&values)[M]) {
759 size_t i = 0;
760 for(; i < M; ++i){
761 this->vector_[i] = values[i];
762 }
763 for(; i < this->size(); ++i){
764 this->vector_[i] = static_cast<T>(0);
765 }
766 return *this;
767 }
768
769 explicit FixedPolynom(const Polynom<T, Order>& poly) : FixedPolynom(poly.vector()){}
770
771 template<int M>
772 requires(M < Order)
773 explicit FixedPolynom(const Polynom<T, M>& poly){
774 size_t i = 0;
775 for(; i < M; ++i){
776 this->vector_[i] = poly[i];
777 }
778 for(; i < this->size(); ++i){
779 this->vector_[i] = static_cast<T>(0);
780 }
781 }
782
783 operator Polynom<T, Order>() const {return Polynom<T, Order>(this->vector_);}
784
787 FixedPolynom& operator=(const Eigen::Vector<T, Order+1>& vector){
788 this->vector_ = vector;
789 return *this;
790 }
791
792 template<int M>
793 requires(M < Order+1)
794 FixedPolynom& operator=(const Eigen::Vector<T, M>& vector){
795 size_t i = 0;
796 for(; i < M; ++i){
797 this->vector_[i] = vector[i];
798 }
799 for(; i < this->size(); ++i){
800 this->vector_[i] = static_cast<T>(0);
801 }
802 return *this;
803 }
804
808 const T& operator[](size_t i) const {return this->vector_[i];}
809
813 T& operator[](size_t i) {return this->vector_[i];}
814
818 const T& at(size_t i) const {return this->vector_[i];}
819
823 T& at(size_t i) {return this->vector_[i];}
824
827 vector_type& vector(){return this->vector_;}
828
831 const vector_type& vector() const {return this->vector_;}
832
836 size_t size() const {return Order+1;}
837
841 size_t order() const {
842 size_t result = Order;
843 const T zero(0);
844 for(size_t i = 0; i < this->size(); ++i){
845 if(this->at(this->size() - i - 1) != zero){
846 break;
847 }
848 --result;
849 }
850 return result;
851 }
852
854 void setZero() {this->vector_.setZero();}
855
859 void print (std::ostream& stream, std::string_view var="x") const {
860 std::string_view plus = "";
861 for(size_t i = 0; i < this->size(); ++i){
862 if(this->at(i) != static_cast<T>(0)){
863 stream << plus << this->at(i) << ' ' << var << '^' << i;
864 plus = " + ";
865 }
866 }
867 }
868
873 friend std::ostream& operator<< (std::ostream& stream, const FixedPolynom& poly){
874 poly.print(stream, "x");
875 return stream;
876 }
877
878 template<int M>
879 requires(M <= Order)
880 FixedPolynom& operator+=(const FixedPolynom<T, M>& other){
881 for(size_t i = 0; i < other->size(); ++i){
882 this->at(i) += other.at(i);
883 }
884 return *this;
885 }
886
887 template<int M>
888 requires(M <= Order)
889 FixedPolynom& operator-=(const FixedPolynom<T, M>& other){
890 for(size_t i = 0; i < other->size(); ++i){
891 this->at(i) -= other.at(i);
892 }
893 return *this;
894 }
895 };
896
897 // -----------------------------------------------------------------------------------------------
898 // Comparison Operators
899 // -----------------------------------------------------------------------------------------------
900
907 template<class T, int N>
909 return lhs.vector() == rhs.vector();
910 }
911
912 template<class T, int N>
914 return lhs.vector() != rhs.vector();
915 }
916
917 // -----------------------------------------------------------------------------------------------
918 // Arithmetic Operators
919 // -----------------------------------------------------------------------------------------------
920
921 // operator +
922 // ----------
923
924 template<class T, int N>
926 return FixedPolynom<T, N>(lhs.vector() + rhs.vector());
927 }
928
929 template<class Tpoly, std::convertible_to<Tpoly> Tscalar, int N>
930 requires (N >= 1)
931 FixedPolynom<Tpoly, N> operator+(const Tscalar& lhs, const FixedPolynom<Tpoly, N>& rhs){
932 FixedPolynom<Tpoly, N> result(rhs);
933 result[0] += static_cast<Tpoly>(lhs);
934 return result;
935 }
936
937 template<class Tpoly, std::convertible_to<Tpoly> Tscalar, int N>
938 requires (N >= 1)
939 FixedPolynom<Tpoly, N> operator+(const FixedPolynom<Tpoly, N>& lhs, const Tscalar& rhs){
940 return (static_cast<Tpoly>(rhs) + lhs);
941 }
942
943 // operator -
944 // ----------
945
946 template<class T, int N>
948 return FixedPolynom<T, N>(lhs.vector() - rhs.vector());
949 }
950
951 template<class Tpoly, std::convertible_to<Tpoly> Tscalar, int N>
952 requires (N >= 1)
953 FixedPolynom<Tpoly, N> operator-(const Tscalar& lhs, const FixedPolynom<Tpoly, N>& rhs){
954 FixedPolynom<Tpoly, N> result(-rhs);
955 result[0] += static_cast<Tpoly>(lhs);
956 return result;
957 }
958
959 template<class Tpoly, std::convertible_to<Tpoly> Tscalar, int N>
960 requires (N >= 1)
961 FixedPolynom<Tpoly, N> operator-(const FixedPolynom<Tpoly, N>& lhs, const Tscalar& rhs){
962 FixedPolynom<Tpoly, N> result(lhs);
963 result[0] -= static_cast<Tpoly>(rhs);
964 return result;
965 }
966
967 template<class T, int N>
971
972 // operator *
973 // ----------
974
981 template<class T, int N>
983 FixedPolynom<T, N> result;
984 result.setZero();
985
986 for(size_t i = 0; i < lhs.size(); ++i){
987 result.vector().tail(lhs.size()-i) += lhs.vector().head(lhs.size()-i) * rhs[i];
988 }
989
990 return result;
991 }
992
993 template<class Tpoly, std::convertible_to<Tpoly> Tscalar, int N>
995 return FixedPolynom<Tpoly, N>(lhs.vector() * static_cast<Tpoly>(rhs));
996 }
997
998 template<class Tpoly, std::convertible_to<Tpoly> Tscalar, int N>
1000 return (rhs * static_cast<Tpoly>(lhs));
1001 }
1002
1003 // operator /
1004 // ----------
1005
1006 template<class Tpoly, std::convertible_to<Tpoly> Tscalar, int N>
1008 return FixedPolynom<Tpoly, N>(lhs.vector() / static_cast<Tscalar>(rhs));
1009 }
1010} // namespace controlpp
1011
1012namespace Eigen {
1013 template<typename T, int N>
1014 struct NumTraits<controlpp::FixedPolynom<T, N>> {
1016 using Real = Self; // or T if you want to treat real parts differently
1018 using Literal = Self;
1019 using Nested = Self;
1020
1021 enum {
1022 IsComplex = 0,
1023 IsInteger = 0,
1024 IsSigned = 1,
1025 RequireInitialization = 1,
1026 ReadCost = 1,
1027 AddCost = 5,
1028 MulCost = 10
1030
1031 static inline Self epsilon() { return Self(); }
1032 static inline Self dummy_precision() { return Self(); }
1033 static inline Self highest() { return Self(); }
1034 static inline Self lowest() { return Self(); }
1035 };
1036
1037 // ResultType for operator +
1038 // -------------------------
1039
1040 template <class Tpoly, std::convertible_to<Tpoly> Tscalar, int N>
1041 struct ScalarBinaryOpTraits<
1042 Tscalar,
1043 controlpp::FixedPolynom<Tpoly, N>,
1044 internal::scalar_sum_op<Tscalar, controlpp::FixedPolynom<Tpoly, N>>>
1045 {
1046 using ReturnType = decltype(std::declval<Tscalar>() + std::declval<controlpp::FixedPolynom<Tpoly, N>>());
1047 };
1048
1049 template <class Tpoly, std::convertible_to<Tpoly> Tscalar, int N>
1050 struct ScalarBinaryOpTraits<
1051 controlpp::FixedPolynom<Tpoly, N>,
1052 Tscalar,
1053 internal::scalar_sum_op<controlpp::FixedPolynom<Tpoly, N>, Tscalar>>
1054 {
1055 using ReturnType = decltype(std::declval<controlpp::FixedPolynom<Tpoly, N>>() + std::declval<Tscalar>());
1056 };
1057
1058 template <class Tpoly, int N>
1059 struct ScalarBinaryOpTraits<
1060 controlpp::FixedPolynom<Tpoly, N>,
1061 controlpp::FixedPolynom<Tpoly, N>,
1062 internal::scalar_sum_op<controlpp::FixedPolynom<Tpoly, N>, controlpp::FixedPolynom<Tpoly, N>>>
1063 {
1064 using ReturnType = decltype(std::declval<controlpp::FixedPolynom<Tpoly, N>>() + std::declval<controlpp::FixedPolynom<Tpoly, N>>());
1065 };
1066
1067 // ResultType for operator -
1068 // -------------------------
1069
1070 template <class Tpoly, std::convertible_to<Tpoly> Tscalar, int N>
1071 struct ScalarBinaryOpTraits<
1072 Tscalar,
1073 controlpp::FixedPolynom<Tpoly, N>,
1074 internal::scalar_difference_op<Tscalar, controlpp::FixedPolynom<Tpoly, N>>>
1075 {
1076 using ReturnType = decltype(std::declval<Tscalar>() - std::declval<controlpp::FixedPolynom<Tpoly, N>>());
1077 };
1078
1079 template <class Tpoly, std::convertible_to<Tpoly> Tscalar, int N>
1080 struct ScalarBinaryOpTraits<
1081 controlpp::FixedPolynom<Tpoly, N>,
1082 Tscalar,
1083 internal::scalar_difference_op<controlpp::FixedPolynom<Tpoly, N>, Tscalar>>
1084 {
1085 using ReturnType = decltype(std::declval<controlpp::FixedPolynom<Tpoly, N>>() - std::declval<Tscalar>());
1086 };
1087
1088 template <class Tpoly, int N>
1089 struct ScalarBinaryOpTraits<
1090 controlpp::FixedPolynom<Tpoly, N>,
1091 controlpp::FixedPolynom<Tpoly, N>,
1092 internal::scalar_difference_op<controlpp::FixedPolynom<Tpoly, N>, controlpp::FixedPolynom<Tpoly, N>>>
1093 {
1094 using ReturnType = decltype(std::declval<controlpp::FixedPolynom<Tpoly, N>>() - std::declval<controlpp::FixedPolynom<Tpoly, N>>());
1095 };
1096
1097 // ResultType for operator *
1098 // -------------------------
1099
1100 template <class Tpoly, std::convertible_to<Tpoly> Tscalar, int N>
1101 struct ScalarBinaryOpTraits<
1102 Tscalar,
1103 controlpp::FixedPolynom<Tpoly, N>,
1104 internal::scalar_product_op<Tscalar, controlpp::FixedPolynom<Tpoly, N>>>
1105 {
1106 using ReturnType = decltype(std::declval<Tscalar>() * std::declval<controlpp::FixedPolynom<Tpoly, N>>());
1107 };
1108
1109 template <class Tpoly, std::convertible_to<Tpoly> Tscalar, int N>
1110 struct ScalarBinaryOpTraits<
1111 controlpp::FixedPolynom<Tpoly, N>,
1112 Tscalar,
1113 internal::scalar_product_op<controlpp::FixedPolynom<Tpoly, N>, Tscalar>>
1114 {
1115 using ReturnType = decltype(std::declval<controlpp::FixedPolynom<Tpoly, N>>() * std::declval<Tscalar>());
1116 };
1117
1118 template <class Tpoly, int N>
1119 struct ScalarBinaryOpTraits<
1120 controlpp::FixedPolynom<Tpoly, N>,
1121 controlpp::FixedPolynom<Tpoly, N>,
1122 internal::scalar_product_op<controlpp::FixedPolynom<Tpoly, N>, controlpp::FixedPolynom<Tpoly, N>>>
1123 {
1124 using ReturnType = decltype(std::declval<controlpp::FixedPolynom<Tpoly, N>>() * std::declval<controlpp::FixedPolynom<Tpoly, N>>());
1125 };
1126
1127 // ResultType for operator /
1128 // -------------------------
1129
1130 template <class Tpoly, std::convertible_to<Tpoly> Tscalar, int N>
1131 struct ScalarBinaryOpTraits<
1132 Tscalar,
1133 controlpp::FixedPolynom<Tpoly, N>,
1134 internal::scalar_quotient_op<Tscalar, controlpp::FixedPolynom<Tpoly, N>>>
1135 {
1136 using ReturnType = decltype(std::declval<Tscalar>() / std::declval<controlpp::FixedPolynom<Tpoly, N>>());
1137 };
1138
1139 template <class Tpoly, std::convertible_to<Tpoly> Tscalar, int N>
1140 struct ScalarBinaryOpTraits<
1141 controlpp::FixedPolynom<Tpoly, N>,
1142 Tscalar,
1143 internal::scalar_quotient_op<controlpp::FixedPolynom<Tpoly, N>, Tscalar>>
1144 {
1145 using ReturnType = decltype(std::declval<controlpp::FixedPolynom<Tpoly, N>>() / std::declval<Tscalar>());
1146 };
1147
1148 template <class Tpoly, int N>
1149 struct ScalarBinaryOpTraits<
1150 controlpp::FixedPolynom<Tpoly, N>,
1151 controlpp::FixedPolynom<Tpoly, N>,
1152 internal::scalar_quotient_op<controlpp::FixedPolynom<Tpoly, N>, controlpp::FixedPolynom<Tpoly, N>>>
1153 {
1154 using ReturnType = decltype(std::declval<controlpp::FixedPolynom<Tpoly, N>>() / std::declval<controlpp::FixedPolynom<Tpoly, N>>());
1155 };
1156}// Eigen
Describes a mathematical polynomial of fixed size.
Definition Polynom.hpp:665
const vector_type & vector() const
Returns the underlying vector that holds the values.
Definition Polynom.hpp:831
size_t order() const
returns the order of the polynomial
Definition Polynom.hpp:841
FixedPolynom & operator=(const Eigen::Vector< T, Order+1 > &vector)
Assigns the values of a vector to this polynomial.
Definition Polynom.hpp:787
T & at(size_t i)
Access elements at the i-th position.
Definition Polynom.hpp:823
FixedPolynom & operator=(const FixedPolynom &)=default
Copy assignment operator.
FixedPolynom(const Eigen::Vector< T, M > &vector)
Definition Polynom.hpp:741
T & operator[](size_t i)
Access elements at the i-th position.
Definition Polynom.hpp:813
FixedPolynom & operator=(const T(&values)[Order+1])
Definition Polynom.hpp:751
const T & operator[](size_t i) const
Access elements at the i-th position.
Definition Polynom.hpp:808
void print(std::ostream &stream, std::string_view var="x") const
prints polynomial to an output character stream with a variale
Definition Polynom.hpp:859
FixedPolynom(const Eigen::Vector< T, Order+1 > &vector)
Constructs a polynomial from a vector.
Definition Polynom.hpp:737
FixedPolynom(const Polynom< T, M > &poly)
Definition Polynom.hpp:773
const T & at(size_t i) const
Access elements at the i-th position.
Definition Polynom.hpp:818
void setZero()
sets all entries to zero
Definition Polynom.hpp:854
FixedPolynom(const FixedPolynom< T, M > &other)
Definition Polynom.hpp:688
FixedPolynom(const T(&values)[Order+1])
Constructs a polynomial from an array.
Definition Polynom.hpp:717
FixedPolynom()=default
decault constructs the polynomials with the default values of their data type
Eigen::Vector< T, Order+1 > vector_type
Definition Polynom.hpp:668
vector_type & vector()
Returns the underlying vector that holds the values.
Definition Polynom.hpp:827
T value_type
Definition Polynom.hpp:667
FixedPolynom(const FixedPolynom &)=default
Copy constructor.
friend std::ostream & operator<<(std::ostream &stream, const FixedPolynom &poly)
prints the polynomial (pretty) to an output stream with "x" as the symbol name of the variable
Definition Polynom.hpp:873
FixedPolynom(const U &value)
Definition Polynom.hpp:682
size_t size() const
returns the size of the polynomial
Definition Polynom.hpp:836
FixedPolynom(const T(&values)[M])
Definition Polynom.hpp:725
FixedPolynom(const Polynom< T, Order > &poly)
Definition Polynom.hpp:769
Describes a mathematical polynomial.
Definition Polynom.hpp:39
T & operator[](size_t i)
Access elements at the i-th position.
Definition Polynom.hpp:194
void setZero()
sets all entries to zero
Definition Polynom.hpp:226
void print(std::ostream &stream, std::function< std::string(int i)> var) const
Definition Polynom.hpp:371
bool is_zero(T epsilon=std::numeric_limits< T >::min()) const
Checks if every element in the polynomial is zero.
Definition Polynom.hpp:331
size_t size() const
returns the size of the polynomial
Definition Polynom.hpp:207
Polynom & operator/=(const U &num)
Definition Polynom.hpp:433
Eigen::Vector< T, eigen_vector_size > vector_type
Definition Polynom.hpp:43
T value_type
Definition Polynom.hpp:41
T operator()(const T &x) const
Evaluates the polynomial at position x
Definition Polynom.hpp:245
friend std::ostream & operator<<(std::ostream &stream, const Polynom &poly)
prints the polynomial (pretty) to an output stream with "x" as the symbol name of the variable
Definition Polynom.hpp:403
const T & at(size_t i) const
Access elements at the i-th position.
Definition Polynom.hpp:179
Polynom(Args &&... args)
Definition Polynom.hpp:74
Polynom(Args &&... args)
Definition Polynom.hpp:70
Polynom(const T *values, size_t length)
Constructs a dynamically sized polynomial from an array.
Definition Polynom.hpp:119
const T & operator[](size_t i) const
Access elements at the i-th position.
Definition Polynom.hpp:189
Polynom(const T(&array)[M])
Constructs a dynamically sized polynomial from an array.
Definition Polynom.hpp:139
void print(std::ostream &stream, std::string_view var="x") const
prints polynomial to an output character stream with a variale
Definition Polynom.hpp:343
Polynom(const T(&array)[M])
Constructs a polynomial from an array.
Definition Polynom.hpp:104
Polynom & operator=(const Polynom &)=default
Copy assignment operator from polynomials with equal compile time size.
vector_type & vector()
Returns the underlying vector that holds the values.
Definition Polynom.hpp:198
Eigen::Vector< T, M > eval(const Eigen::Vector< T, M > &x_vec) const
Evaluates the polynomial at positions of the vector x_vec
Definition Polynom.hpp:255
Polynom(const Polynom &)=default
Copy constructor.
static constexpr int eigen_vector_size
Definition Polynom.hpp:42
size_t order() const
returns the order of the polynomial
Definition Polynom.hpp:212
Polynom()=default
decault constructs the polynomials with the default values of their data type
T eval(const T &x) const
Evaluates the polynomial at position x.
Definition Polynom.hpp:232
const vector_type & vector() const
Returns the underlying vector that holds the values.
Definition Polynom.hpp:202
Polynom & operator*=(const U &num)
Definition Polynom.hpp:427
Polynom(const Eigen::Vector< T, M > &vector)
Definition Polynom.hpp:172
T & at(size_t i)
Access elements at the i-th position.
Definition Polynom.hpp:184
Polynom(const U &vector_expression)
Definition Polynom.hpp:150
std::complex< T > eval(const std::complex< T > &x) const
Evaluates the polynomial at position x.
Definition Polynom.hpp:281
Polynom(const T(&array)[M])
Constructs a polynomial from an array.
Definition Polynom.hpp:98
Polynom(const Eigen::Vector< U, Eigen::Dynamic > &vector)
Definition Polynom.hpp:166
Polynom(const Polynom< T, OtherOrder > &other)
Definition Polynom.hpp:58
Eigen::Vector< std::complex< T >, M > eval(const Eigen::Vector< std::complex< T >, M > &x_vec) const
Evaluates the polynomial at positions of the vector x_vec
Definition Polynom.hpp:304
const Eigen::Vector< T, Eigen::Dynamic > & values(const Bode< T > &bode)
Returns the complex values of the bode data.
Definition Bode.hpp:521
Bode< T > operator+(const Bode< T > &l, const Bode< T > &r)
Adds two bode plots together.
Definition Bode.hpp:846
Definition Polynom.hpp:1012
const Polynom< T, 1 > x(0, 1)
The main namespace for the Control++ library.
Definition Bode.cpp:3
bool operator==(const Polynom< T, N > &lhs, const Polynom< T, N > &rhs)
Compares two polynomials for equality.
Definition Polynom.hpp:518
Bode< T > operator-(const Bode< T > &l, const Bode< T > &r)
Definition Bode.hpp:936
Bode< T > operator*(const Bode< T > &l, const Bode< T > &r)
Definition Bode.hpp:979
Eigen::Vector< std::complex< T >, NumOrder > zeros(const ContinuousTransferFunction< T, NumOrder, DenOrder > &tf)
Definition ContinuousTransferFunction.hpp:238
Bode< T > operator/(const Bode< T > &l, const Bode< T > &r)
TODO: make it also work for bode that have different frequency vectors.
Definition Bode.hpp:1026
Eigen::Matrix< T, N-1, N-1 > companion(const Eigen::Vector< T, N > &v)
Creates a companion matrix from a vector.
Definition math.hpp:314
bool operator!=(const Polynom< T, N > &lhs, const Polynom< T, N > &rhs)
Definition Polynom.hpp:523
static Self dummy_precision()
Definition Polynom.hpp:1032
static Self lowest()
Definition Polynom.hpp:1034
static Self highest()
Definition Polynom.hpp:1033
static Self epsilon()
Definition Polynom.hpp:1031
decltype(std::declval< Tscalar >()/std::declval< controlpp::FixedPolynom< Tpoly, N > >()) ReturnType
Definition Polynom.hpp:1136
decltype(std::declval< Tscalar >()+std::declval< controlpp::FixedPolynom< Tpoly, N > >()) ReturnType
Definition Polynom.hpp:1046
decltype(std::declval< Tscalar >() *std::declval< controlpp::FixedPolynom< Tpoly, N > >()) ReturnType
Definition Polynom.hpp:1106
decltype(std::declval< Tscalar >() - std::declval< controlpp::FixedPolynom< Tpoly, N > >()) ReturnType
Definition Polynom.hpp:1076
decltype(std::declval< controlpp::FixedPolynom< Tpoly, N > >() - std::declval< Tscalar >()) ReturnType
Definition Polynom.hpp:1085
decltype(std::declval< controlpp::FixedPolynom< Tpoly, N > >() *std::declval< Tscalar >()) ReturnType
Definition Polynom.hpp:1115
decltype(std::declval< controlpp::FixedPolynom< Tpoly, N > >()/std::declval< Tscalar >()) ReturnType
Definition Polynom.hpp:1145
decltype(std::declval< controlpp::FixedPolynom< Tpoly, N > >()+std::declval< Tscalar >()) ReturnType
Definition Polynom.hpp:1055
decltype(std::declval< controlpp::FixedPolynom< Tpoly, N > >()/std::declval< controlpp::FixedPolynom< Tpoly, N > >()) ReturnType
Definition Polynom.hpp:1154
decltype(std::declval< controlpp::FixedPolynom< Tpoly, N > >()+std::declval< controlpp::FixedPolynom< Tpoly, N > >()) ReturnType
Definition Polynom.hpp:1064
decltype(std::declval< controlpp::FixedPolynom< Tpoly, N > >() *std::declval< controlpp::FixedPolynom< Tpoly, N > >()) ReturnType
Definition Polynom.hpp:1124
decltype(std::declval< controlpp::FixedPolynom< Tpoly, N > >() - std::declval< controlpp::FixedPolynom< Tpoly, N > >()) ReturnType
Definition Polynom.hpp:1094