/* LA: linear algebra C++ interface library Copyright (C) 2021 Jiri Pittner or This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef _POLYNOMIAL_H #define _POLYNOMIAL_H #include "la_traits.h" #include "vec.h" #include "nonclass.h" #include "matexp.h" namespace LA { template class Polynomial : public NRVec { private: int size() const; //prevent confusion with vector size public: Polynomial(): NRVec() {}; template Polynomial(const T (&a)[SIZE]) : NRVec(a) {}; Polynomial(const NRVec &v) : NRVec(v) {}; //allow implicit conversion from NRVec Polynomial(const int n) : NRVec(n+1) {}; Polynomial(const T &a, const int n) : NRVec(n+1) {NRVec::clear(); (*this)[0]=a;}; int degree() const {return NRVec::size()-1;}; void resize(const int n, const bool preserve=true) {NRVec::resize(n+1,preserve);} Polynomial& operator+=(const T &a) {NOT_GPU(*this); NRVec::copyonwrite(); (*this)[0]+=a; return *this;} Polynomial& operator-=(const T &a) {NOT_GPU(*this); NRVec::copyonwrite(); (*this)[0]-=a; return *this;} Polynomial operator+(const T &a) const {return Polynomial(*this) += a;}; Polynomial operator-(const T &a) const {return Polynomial(*this) -= a;}; Polynomial operator-() const {return NRVec::operator-();} Polynomial operator*(const T &a) const {return NRVec::operator*(a);} Polynomial operator/(const T &a) const {return NRVec::operator/(a);} Polynomial& operator*=(const T &a) {NRVec::operator*=(a); return *this;} Polynomial& operator/=(const T &a) {NRVec::operator/=(a); return *this;} Polynomial& operator+=(const Polynomial &rhs) { NOT_GPU(*this); NRVec::copyonwrite(); if(rhs.degree()>degree()) resize(rhs.degree(),true); for(int i=0; i<=rhs.degree(); ++i) (*this)[i] += rhs[i]; return *this; } Polynomial& operator-=(const Polynomial &rhs) { NOT_GPU(*this); NRVec::copyonwrite(); if(rhs.degree()>degree()) resize(rhs.degree(),true); for(int i=0; i<=rhs.degree(); ++i) (*this)[i] -= rhs[i]; return *this; } Polynomial operator+(const Polynomial &rhs) const {return Polynomial(*this) += rhs;}; Polynomial operator-(const Polynomial &rhs) const {return Polynomial(*this) -= rhs;}; Polynomial operator*(const Polynomial &rhs) const //NOTE: naive implementation! For very long polynomials FFT-based methods should be used { NOT_GPU(*this); Polynomial r(degree()+rhs.degree()); r.clear(); for(int i=0; i<=rhs.degree(); ++i) for(int j=0; j<=degree(); ++j) r[i+j] += rhs[i]*(*this)[j]; return r; }; Polynomial& operator*=(const Polynomial &rhs) {*this = (*this)*rhs; return *this;}; void simplify(const typename LA_traits::normtype thr=0) { NOT_GPU(*this); this->copyonwrite(); int n=degree(); while(n>0 && MYABS((*this)[n])<=thr) --n; resize(n,true); }; void normalize() {if((*this)[degree()]==(T)0) laerror("zero coefficient at highest degree - simplify first"); *this /= (*this)[degree()];}; Polynomial shifted(const int shift) const { if(shift==0) return *this; if(shift>0) { Polynomial r(degree()+shift); for(int i=0; i=i-d+1; --j) prod *= j; r[i-d] = (*this)[i]* ((T)prod); } return r; }; Polynomial integral(const int d=1) const { if(d==0) return *this; if(d<0) return derivative(-d); NOT_GPU(*this); int n=degree(); Polynomial r(n+d); for(int i=0; i companion() const; //matrix which has this characteristic polynomial NRVec::complextype> roots() const; //implemented for complex and double only NRVec realroots(const typename LA_traits::normtype thr) const; T newton(const T x0, const typename LA_traits::normtype thr=1e-14, const int maxit=1000) const; //solve root from the guess Polynomial pow(const int i) const; //integer power Polynomial powx(const int i) const; //substitute x^i for x in the polynomial void binomial(const int n); //(1+x)^n }; //this is very general, can be used also for composition (nesting) of polynomials //for an alternative algorithm which minimizes number of multiplications cf. also matexp.h template C value(const Polynomial &p, const C &x) { C sum(x); sum=0; //get matrix dimension if C is a matrix for(int i=p.degree(); i>0; --i) { sum+= p[i]; sum= sum*x; //not *= for matrices } sum += p[0]; return sum; } //evaluate only even powers template C even_value(const Polynomial &p, const C &x) { C sum(x); sum=0; //get matrix dimension if C is a matrix int d=p.degree(); if(d&1) --d; C x2 = x*x; for(int i=d; i>0; i-=2) { sum+= p[i]; sum= sum*x2; //not *= for matrices } sum += p[0]; return sum; } //evaluate only odd powers template C odd_value(const Polynomial &p, const C &x) { C sum(x); sum=0; //get matrix dimension if C is a matrix int d=p.degree(); if(d==0) return sum; if((d&1)==0) --d; C x2 = x*x; for(int i=d; i>2; i-=2) { sum+= p[i]; sum= sum*x2; //not *= for matrices } sum += p[1]; sum *= x; return sum; } template NRVec values(const Polynomial &p, const NRVec &x) { NRVec r(x.size()); for(int i=0; i inline Polynomial operator+(const T &a, const Polynomial &rhs) {return Polynomial(rhs)+=a;} template inline Polynomial operator-(const T &a, const Polynomial &rhs) {return Polynomial(rhs)-=a;} //Sylvester matrix template extern NRMat Sylvester(const Polynomial &p, const Polynomial &q); //polynomial from given roots template Polynomial polyfromroots(const NRVec &roots, const int skip= -1) { Polynomial p(0); p[0]=(T)1; for(int i=0; i extern Polynomial lagrange_interpolation(const NRVec &x, const NRVec &y); template extern Polynomial poly_gcd(const Polynomial &p, const Polynomial &q, const typename LA_traits::normtype thr=0, const int d= -1); template extern Polynomial svd_gcd(const Polynomial &p, const Polynomial &q, const typename LA_traits::normtype thr=0); template Polynomial poly_lcm(const Polynomial &p, const Polynomial &q, const typename LA_traits::normtype thr=0) { return p*q/poly_gcd(p,q,thr); } template Polynomial hermite_polynomial(int n) //physicists definition { Polynomial h(n); h.clear(); h[n]=ipow((T)2,n); for(int m=1; n-2*m>=0; m+=1) { int i=n-2*m; h[i] = (-h[i+2] *(i+2)*(i+1)) /(4*m); } return h; } }//namespace #endif