LinearPolynomial.h

00001 /***************************************************************************
00002  *   Copyright (C) 2004 by Jacques Gasselin                                *
00003  *   jgasseli@student.rmit.edu.au                                          *
00004  *                                                                         *
00005  *   This program is free software; you can redistribute it and/or modify  *
00006  *   it under the terms of the GNU Library General Public License as       *
00007  *   published by the Free Software Foundation; either version 2 of the    *
00008  *   License, or (at your option) any later version.                       *
00009  *                                                                         *
00010  *   This program is distributed in the hope that it will be useful,       *
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00013  *   GNU General Public License for more details.                          *
00014  *                                                                         *
00015  *   You should have received a copy of the GNU Library General Public     *
00016  *   License along with this program; if not, write to the                 *
00017  *   Free Software Foundation, Inc.,                                       *
00018  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
00019  ***************************************************************************/
00020 #ifndef LINEARPOLYNOMIAL_H
00021 #define LINEARPOLYNOMIAL_H
00022 
00026 #include <vector>
00027 #include <valarray>
00028 
00029 namespace mathglpp
00030 {
00031 
00032 template <typename T>
00033 inline bool LP_almost_zero (T arg, T threshold) { return (std::abs(arg) <  std::abs(threshold)); }
00034 
00035 template <typename T>
00036 inline void LP_new_sample (T& arg1) { arg1+=T(1); }
00037 
00038 template <typename T = double >
00039 class LinearPolynomial
00040 {
00041 public:
00042     LinearPolynomial(size_t size)
00043     :fx(size),remainder(0)
00044     { }
00045 
00046     LinearPolynomial(const T& val, size_t size)
00047     :fx(val,size),remainder(0)
00048     { }
00049 
00050     LinearPolynomial(const T* p, size_t size)
00051     :fx(p,size),remainder(0)
00052     { }
00053 
00054     LinearPolynomial(const LinearPolynomial& lp)
00055     :fx(lp.fx),remainder(0)
00056     { }
00057 
00058     ~LinearPolynomial()
00059     { }
00060 
00061     inline T rem() const { return remainder; }
00062     inline size_t size() const { return fx.size(); }
00063     inline T& operator[] (size_t ind) { return fx[ind]; }
00064 
00065     inline T evaluate(T x) const
00066     {
00067         T sum = 0;
00068         for(register size_t i = 0; i < size(); ++i)
00069             sum += fx[i] * std::pow(x,i);
00070         return sum;
00071     }
00072 
00073     T operator() (T x) const
00074     {
00075         return evaluate(x);
00076     }
00077 
00078 
00079     LinearPolynomial& operator= (const LinearPolynomial& lp)
00080     {
00081         fx.upto_resize(lp.size());
00082         fx = lp.fx;
00083         return *this;
00084     }
00085 
00086     LinearPolynomial operator+ (const LinearPolynomial& lp) const
00087     {
00088         LinearPolynomial retval(*this);
00089         retval += lp;
00090         return retval;
00091     }
00092 
00093     LinearPolynomial& operator+= (const LinearPolynomial& lp)
00094     {
00095         assert(&lp);
00096         fx.upto_resize(lp.fx); //resize
00097         assert(fx.size() >= lp.size());
00098         fx += lp.fx;
00099         return *this;
00100     }
00101 
00102     LinearPolynomial operator- (const LinearPolynomial& lp) const
00103     {
00104         LinearPolynomial retval(*this);
00105         retval -= lp;
00106         return retval;
00107     }
00108 
00109     LinearPolynomial& operator-= (const LinearPolynomial& lp)
00110     {
00111         std::valarray<T> fx_old(fx);
00112         fx.resize(lp.fx);
00113         fx = fx_old;
00114         
00115         fx -= lp.fx;
00116         return *this;
00117     }
00118 
00119     inline LinearPolynomial operator* (T val) const
00120     {
00121         LinearPolynomial retval(*this);
00122         retval.fx *= val;
00123         return retval;
00124     }
00125 
00126     inline LinearPolynomial& operator*= (T val)
00127     {
00128         fx *= val;
00129         return *this;
00130     }
00131 
00132     LinearPolynomial operator* (const LinearPolynomial& lp) const
00133     {
00134         LinearPolynomial retval(T(0), (lp.size() + size() - 1));
00135 
00136         std::valarray<T> fx_old(fx);
00137         fx.resize(retval.size());
00138         fx = fx_old;
00139 
00140 
00141         for(register int i = 0; i < lp.size(); ++i)
00142         {
00143             retval.fx += fx.shift(-i) * lp.fx[i];
00144             //std::cout<<retval;
00145         };
00146 
00147         fx.resize(fx_old.size());
00148         fx = fx_old;
00149         
00150         return retval;
00151     }
00152 
00153     LinearPolynomial& operator*= (const LinearPolynomial& lp)
00154     {
00155     
00156         std::valarray<T> fx_old(fx);
00157         fx.resize(size()+lp.size()-1);
00158         fx = fx_old;
00159 
00160         LinearPolynomial temp(*this);
00161 
00162         fx = 0; //clear
00163 
00164         for(register size_t i = 0; i < lp.size(); ++i)
00165             fx += (temp.fx.shift(-i) * lp.fx[i]);
00166 
00167         return *this;
00168     }
00169 
00170     inline LinearPolynomial operator/ (T val) const
00171     {
00172         LinearPolynomial retval(*this);
00173         retval /= val;
00174         return val;
00175     }
00176 
00177     inline LinearPolynomial& operator/= (T val)
00178     {
00179         fx /= val;
00180         return *this;
00181     }
00182 
00183     LinearPolynomial operator/ (const LinearPolynomial& divisor) const
00184     {
00185         LinearPolynomial div(divisor);
00186         LinearPolynomial quot(*this);
00187         size_t diff = size() - div.size();
00188         size_t old_divSize = div.size();
00189         LinearPolynomial retval(T(0), 1 + diff);
00190 
00191         std::valarray<T> div_fx_old(div.fx);
00192         div.fx.resize(quot.fx);
00193         div.fx = div_fx_old;
00194         T res;
00195 
00196         for(register size_t i = 0; i <= diff; ++i)
00197         {
00198             res = quot.fx[quot.size()-1-i]/div.fx[old_divSize-1];
00199             quot.fx -= (div.fx.shift(i-diff) * res);
00200             retval.fx[diff-i] = res;
00201         };
00202 
00203         retval.remainder = quot[0];
00204 
00205         return retval;
00206     }
00207 
00208     LinearPolynomial& operator/= (const LinearPolynomial& divisor)
00209     {
00210         LinearPolynomial div(divisor);
00211         LinearPolynomial quot(*this);
00212         size_t diff = size() - div.size();
00213         size_t old_divSize = div.size();
00214         
00215         std::valarray<T> fx_old(fx);
00216         fx.resize(1+diff);
00217         fx = fx_old;
00218 
00219         
00220         std::valarray<T> div_fx_old(div.fx);
00221         div.fx.resize(quot.fx);
00222         div.fx = div_fx_old;
00223 
00224         T res;
00225 
00226         for(register size_t i = 0; i <= diff; ++i)
00227         {
00228             res = quot.fx[quot.size()-1-i]/div.fx[old_divSize-1];
00229             //std::cout << "res: "<<res<<", q.fx[]: "<<quot.fx[quot.size()-1-i]<<", d.fx[]: "<<div.fx[old_divSize-1]<<endl;
00230             std::valarray<T> sub(div.fx.shift(i-diff));
00231             //std::cout<< "sub: "<<sub;
00232             //std::cout<< "quot.fx: "<<quot.fx;
00233             sub*= res;
00234             //std::cout<< "sub * res: "<<sub;
00235             quot.fx -=  sub;
00236             //std::cout<< "quot.fx: "<<quot.fx;
00237             fx[diff-i] = res;
00238         }
00239 
00240         remainder = quot[0];
00241 
00242         return *this;
00243     }
00244 
00246     bool Newton_Raphson(const LinearPolynomial& derivative, T& sample, T threshold = 0.00000000001, int cutoff = 40)
00247     {
00248         //choose a sample point
00249         T root;
00250         T gradient = T(1);
00251         int i;
00252 
00253         for(i = 0; i < cutoff; ++i)
00254         {
00255             root = evaluate(sample);
00256             //std::cout << "root: "<< root <<", \tat: "<< sample << ", threshold: " << threshold << endl;
00257             if( LP_almost_zero(root,threshold) )
00258                 break;//root found
00259 
00260             //find a guaranteed root as long as the gradient is not close to 0
00261             gradient = derivative.evaluate(sample);
00262 
00263             while( LP_almost_zero(gradient, T(0.0000001)) )
00264             {
00265                 LP_new_sample(sample);
00266                 gradient = derivative.evaluate(sample);
00267             }
00268 
00269             //recalculate sample position
00270             sample = sample - root/gradient;
00271         }
00272 
00273         sample = -(sample);
00274 
00275         if(i == cutoff)//complex roots, probably...
00276             return false;
00277         else
00278             return true;
00279     }
00280 
00284     bool quadratic_formula(T& root1, T& root2)
00285     {
00286         //x = (-b +/- sqrt(b^2 - 4ac))/2a
00287         bool non_complex = true;
00288         T b = fx[1];
00289         T a2 = 2*fx[2];
00290         T c = fx[0];
00291         T discriminant = b*b - 2*a2*c;
00292         if( discriminant < T(0) )
00293         {
00294             non_complex = false;
00295             root1 = -b/a2;
00296             root2 = discriminant;
00297         }
00298         else
00299         {
00300             T sqrtDisc = sqrt(discriminant);
00301             root1 = -b/a2 + sqrtDisc;
00302             root2 = -b/a2 - sqrtDisc;
00303         }
00304 
00305         return non_complex;
00306     }
00307 
00308     std::vector<T> findRoots(void)
00309     {
00310         LinearPolynomial temp(*this);
00311         LinearPolynomial derivative(*this);
00312 
00313         std::vector<T> retval;
00314         retval.resize(size()-1);
00315         T root[] = { 0, 1 };
00316         register int i;
00317 
00318         for(i = 0; temp.size() > 3; ++i)
00319         {
00320             derivative = temp.derivate();
00321             temp.Newton_Raphson(derivative,root[0]);
00322             retval[i] = -root[0];
00323             //std::cout<<"root[]: "<<root[0]<<", "<<root[1]<<endl;
00324             //std::cout<<"temp, before: "<<temp;
00325             LinearPolynomial lp(root,2);
00326             //std::cout<<"divisor: "<<lp;
00327             temp /= lp;
00328             //std::cout<<"temp, after: "<<temp;
00329         };
00330 
00331         if(temp.size() > 2)
00332         {
00333             temp.quadratic_formula(retval[i], retval[i+1]);
00335         }
00336         else
00337             retval[i] = -temp[0];
00338 
00339         return retval;
00340     }
00341 
00342     LinearPolynomial derivate(void)
00343     {//analytical derivative
00344         LinearPolynomial retval(T(0), (size() > 1 ? size()-1 : 1));
00345         for(register size_t i = 0; i < size()-1; ++i)
00346             retval.fx[i] = fx[i+1]*T((i+1));
00347         return retval;
00348     }
00349 
00350     LinearPolynomial integrate_with_root(T x_root)
00351     {//analytical integral
00352         LinearPolynomial retval(T(0), size() + 1);
00353         for(register int i = 1; i < size()+1; ++i)
00354             retval.fx[i] = fx[i-1]/T(i);
00355         //get the constant
00356         retval.fx[0] = -retval(x_root);
00357 
00358         return retval;
00359     }
00360 
00361     LinearPolynomial integrate_with_origin(T y_origin)
00362     {//analytical integral
00363         LinearPolynomial retval(T(0), size() + 1);
00364         for(register size_t i = 1; i < size()+1; ++i)
00365             retval.fx[i] = fx[i-1]/T(i);
00366         //get the constant
00367         retval.fx[0] = y_origin-retval(0);
00368 
00369         return retval;
00370     }
00371 
00372     template <class _CharT, class _Traits>
00373     friend std::basic_ostream<_CharT, _Traits>& operator <<
00374       ( std::basic_ostream<_CharT, _Traits>& out, const LinearPolynomial& lp)
00375     {
00376         out<<"y = ";
00377         for(register size_t i = lp.size()-1; i > 0; --i)
00378         {
00379             out<<lp.fx[i]<<"x^"<<i<<" + ";
00380         };
00381         if(lp.remainder == T(0))
00382             out<<lp.fx[0]<<std::endl;
00383         else
00384             out<<lp.fx[0]<<" & Remainder: "<<lp.remainder<<std::endl;
00385 
00386         return out;
00387     }
00388 
00389 protected:
00390     std::valarray<T> fx;
00391     T remainder;
00392 };
00393 
00394 };
00395 #endif

Generated on Wed Oct 3 12:50:49 2007 for MathGL++ by  doxygen 1.5.2