/* 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 . */ #include "polynomial.h" #include "miscfunc.h" #include #include #include #include "nonclass.h" namespace LA { template void Polynomial::polydiv(const Polynomial &rhs, Polynomial &q, Polynomial &r) const { if(rhs[rhs.degree()]==(T)0) laerror("division by a polynomial with zero leading coefficient - simplify it first"); if(rhs.degree()==0) //scalar division { q= *this/rhs[0]; r.resize(0,false); r[0]=0; return; } int rdegree= rhs.degree(); int qdegree= degree()-rdegree; if(qdegree<0) { q.resize(0,false); q[0]=0; r= *this; return; } //general case q.resize(qdegree,false); r= *this; r.copyonwrite(); for(int i=degree(); i>=rdegree; --i) { T tmp= r[i]/rhs[rdegree]; q[i-rdegree]= tmp; r -= rhs.shifted(i-rdegree)*tmp; } r.resize(rhs.degree()-1,true); } template NRMat Sylvester(const Polynomial &p, const Polynomial &q) { int nm=p.degree()+q.degree(); NRMat a(nm,nm); a.clear(); for(int i=0; i=0; --j) a(i,i+p.degree()-j)=p[j]; for(int i=0; i=0; --j) a(q.degree()+i,i+q.degree()-j)=q[j]; return a; } template NRMat Polynomial::companion() const { if((*this)[degree()]==(T)0) laerror("zero coefficient at highest degree - simplify first"); NRMat a(degree(),degree()); a.clear(); for(int i=0; i NRVec::complextype> Polynomial::roots() const { laerror("roots not implemented for integer polynomials"); return NRVec::complextype>(1); } template<> NRVec::complextype> Polynomial::roots() const { laerror("roots not implemented for integer polynomials"); return NRVec::complextype>(1); } template NRVec::complextype> Polynomial::roots() const { NRMat a=this->companion(); NRVec::complextype> r(degree()); gdiagonalize(a,r,NULL,NULL); return r; } template NRVec Polynomial::realroots(const typename LA_traits::normtype thr) const { NRVec::complextype> r = roots(); NRVec rr(degree()); int nr=0; for(int i=0; i Polynomial lagrange_interpolation(const NRVec &x, const NRVec &y) { if(x.size()!=y.size()) laerror("vectors of different length in lagrange_interpolation"); if(x.size()<1) laerror("empty vector in lagrange_interpolation"); if(x.size()==1) { Polynomial p(0); p[0]=y[0]; return p; } int n=x.size()-1; Polynomial p(n); p.clear(); for(int i=0; i<=n; ++i) { T prod=(T)1; for(int j=0; j<=n; ++j) if(j!=i) prod *= (x[i]-x[j]); if(prod==(T)0) laerror("repeated x-value in lagrange_interpolation"); Polynomial tmp=polyfromroots(x,i); p += tmp * y[i] / prod; } return p; } template T Polynomial::newton(const T x0, const typename LA_traits::normtype thr, const int maxit) const { Polynomial d=derivative(1); T x=x0; for(int i=0; i Polynomial poly_gcd(const Polynomial &p, const Polynomial &q, const typename LA_traits::normtype thr, const int d) { Polynomial big,small; if(p.degree() < q.degree()) {big=q; small=p;} else {big=p; small=q;} small.simplify(thr); if(small.degree()==0) return small; Polynomial help; do { help=small; small= big%small; big=help; small.simplify(thr); } while((d<0 && small.degree() != 0) || (d>=0 && small.degree()>=d)); return big; } template <> Polynomial svd_gcd(const Polynomial &p, const Polynomial &q, const typename LA_traits::normtype thr) { laerror("SVD gcd only for floating point numbers"); return p; } template <> Polynomial svd_gcd(const Polynomial &p, const Polynomial &q, const typename LA_traits::normtype thr) { laerror("SVD gcd only for floating point numbers"); return p; } template Polynomial svd_gcd(const Polynomial &p, const Polynomial &q, const typename LA_traits::normtype thr) { Polynomial big,small; if(p.degree() < q.degree()) {big=q; small=p;} else {big=p; small=q;} small.simplify(thr); if(small.degree()==0) return small; NRMat s = Sylvester(p,q); NRMat u(s.nrows(),s.nrows()),v(s.ncols(),s.ncols()); NRVec::normtype> w(s.nrows()); singular_decomposition(s,&u,w,&v,0); int rank=0; for(int i=0; ithr*::sqrt((double)big.degree()*small.degree())) ++rank; int d=big.degree()+small.degree()-rank; return poly_gcd(big,small,thr,d); } template Polynomial Polynomial::pow(const int n) const { if(n<0) laerror("negative exponent in polynomial::pow"); if(n==0) {Polynomial r(0); r[0]=(T)1; return r;} return positive_power(*this,n); } template Polynomial Polynomial::powx(const int i) const { if(i<0) laerror("negative exponent in polynomial::pow"); if(i==0) {Polynomial r(0); r[0]= this->sum(); return r;} if(i==1) return *this; Polynomial r(i*this->degree()); r.clear(); for(int j=0; j<=this->degree(); ++j) r[j*i] = (*this)[j]; return r; } template void Polynomial::binomial(const int n) { resize(n,false); for(int i=0; i<=n; ++i) (*this)[i] = (T) binom(n,i); } template Polynomial Polynomial::composition(const Polynomial &rhs) const { return value(*this,rhs); } /***************************************************************************//** * forced instantization in the corresponding object file ******************************************************************************/ template class Polynomial; template class Polynomial; template class Polynomial; template class Polynomial >; #define INSTANTIZE(T) \ template NRMat Sylvester(const Polynomial &p, const Polynomial &q); \ template Polynomial lagrange_interpolation(const NRVec &x, const NRVec &y); \ template Polynomial poly_gcd(const Polynomial &p, const Polynomial &q, const typename LA_traits::normtype thr,const int d); \ template Polynomial svd_gcd(const Polynomial &p, const Polynomial &q, const typename LA_traits::normtype thr); \ INSTANTIZE(int) INSTANTIZE(unsigned int) INSTANTIZE(double) INSTANTIZE(std::complex) #define INSTANTIZE2(T) \ template Polynomial hermite_polynomial(int); \ INSTANTIZE2(int) INSTANTIZE2(double) }//namespace