diff --git a/polynomial.cc b/polynomial.cc index 69bb6d6..80c4852 100644 --- a/polynomial.cc +++ b/polynomial.cc @@ -19,6 +19,7 @@ #include "polynomial.h" #include #include +#include namespace LA { @@ -77,8 +78,8 @@ 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 +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) +{ +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); +} + /***************************************************************************//** @@ -170,6 +214,9 @@ 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) diff --git a/polynomial.h b/polynomial.h index b847ddd..23da258 100644 --- a/polynomial.h +++ b/polynomial.h @@ -75,6 +75,7 @@ public: void simplify(const typename LA_traits::normtype thr=0) { NOT_GPU(*this); + this->copyonwrite(); int n=degree(); while(n>0 && abs((*this)[n])<=thr) --n; resize(n,true); @@ -148,8 +149,6 @@ public: 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 - //@@@gcd, lcm euler and svd - }; //this is very general, can be used also for nesting polynomials @@ -203,6 +202,17 @@ template 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); +} }//namespace diff --git a/t.cc b/t.cc index f426e75..ac3e4af 100644 --- a/t.cc +++ b/t.cc @@ -2203,18 +2203,23 @@ cout << (value(p,u)*value(q,u) -value(r,u)).norm()<>n ; NRVec r(n); -r.randomize(1.); +//r.randomize(1.); +//wilkinson's ill-conditionel polynomial +for(int i=0; i p=polyfromroots(r); cout < rr= p.realroots(1e-10); +rr.resize(n,true); +cout <>n; +NRVec rr(n); +rr.randomize(1.); +rr.sort(0); +if(rr.size()>2) rr[1]=rr[0];//make a degenerate root +NRVec pr(2*n); +NRVec qr(2*n); +pr.randomize(1.); +qr.randomize(1.); +for(int i=0; i p=polyfromroots(pr); +Polynomial q=polyfromroots(qr); +Polynomial g=poly_gcd(p,q,1e-8); +cout <<"GCD ="< gg=svd_gcd(p,q,1e-13); +cout <<"SVDGCD ="< rrr=g.realroots(1e-5); +NRVec rrrr=gg.realroots(1e-5); +cout <