00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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);
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
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;
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
00230 std::valarray<T> sub(div.fx.shift(i-diff));
00231
00232
00233 sub*= res;
00234
00235 quot.fx -= sub;
00236
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
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
00257 if( LP_almost_zero(root,threshold) )
00258 break;
00259
00260
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
00270 sample = sample - root/gradient;
00271 }
00272
00273 sample = -(sample);
00274
00275 if(i == cutoff)
00276 return false;
00277 else
00278 return true;
00279 }
00280
00284 bool quadratic_formula(T& root1, T& root2)
00285 {
00286
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
00324
00325 LinearPolynomial lp(root,2);
00326
00327 temp /= lp;
00328
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 {
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 {
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
00356 retval.fx[0] = -retval(x_root);
00357
00358 return retval;
00359 }
00360
00361 LinearPolynomial integrate_with_origin(T y_origin)
00362 {
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
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