src/tools/tPolynomial.h

Go to the documentation of this file.
00001 /*
00002 
00003 *************************************************************************
00004 
00005 ArmageTron -- Just another Tron Lightcycle Game in 3D.
00006 Copyright (C) 2000  Manuel Moos (manuel@moosnet.de)
00007 
00008 **************************************************************************
00009 
00010 This program is free software; you can redistribute it and/or
00011 modify it under the terms of the GNU General Public License
00012 as published by the Free Software Foundation; either version 2
00013 of the License, or (at your option) any later version.
00014 
00015 This program is distributed in the hope that it will be useful,
00016 but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 GNU General Public License for more details.
00019 
00020 You should have received a copy of the GNU General Public License
00021 along with this program; if not, write to the Free Software
00022 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00023 
00024 ***************************************************************************
00025 
00026 */
00027 
00028 #ifndef ArmageTron_tPolynomial_H
00029 #define ArmageTron_tPolynomial_H
00030 
00031 #include "tError.h"
00032 #include <math.h>
00033 #include "tArray.h"
00034 
00035 #include <iostream>
00036 #include <string>
00037 
00038 #define REAL float
00039 #define MAX(a, b) ((a>b)?a:b)
00040 #define MIN(a, b) ((a<b)?a:b)
00041 
00042 
00044 template <typename T>
00045 class tPolynomial
00046 {
00047 public:
00048 
00049     tPolynomial();  
00050     explicit tPolynomial(int count);  
00051     tPolynomial(REAL newCoefs[], int count);  
00052     tPolynomial(REAL value);  
00053     tPolynomial(tArray<REAL> newCoefs);  
00054     tPolynomial(const tPolynomial<T> &tf);  
00055     tPolynomial(std::string str);  
00056 
00057     virtual ~tPolynomial() 
00058     {
00059     }
00060 
00061     void parse(std::string str);
00062 
00063     virtual REAL evaluate( REAL currentVarValue ) const; 
00064     inline REAL operator()( REAL currentVarValue ) const; 
00065 
00066     tPolynomial<T> const operator*( REAL constant ) const;
00067     tPolynomial<T> const operator*( const tPolynomial<T> & tfRight ) const ;
00068     tPolynomial<T> const operator+( REAL constant ) const ;
00069     tPolynomial<T> const operator+( const tPolynomial<T> &tfRight ) const ;
00070     tPolynomial<T> & operator+=( const tPolynomial<T> &tfRight ) ;
00071 
00072     tPolynomial<T> const substitute( const tPolynomial<T> &other ) const;
00073 
00074     REAL &operator[](int index); // Allow both reading and writing of element
00075     REAL const &operator[](int index) const; // Allow reading of element even when the object is const
00076     void operator=(tPolynomial<T> const &other);
00077 
00078     void addConstant(REAL constant) {
00079         if (coefs.Len()==0) {
00080             coefs.SetLen(1);
00081             coefs[0] = 0;
00082         } 
00083         coefs[0] += constant;
00084     }
00085 
00086     tPolynomial<T> adaptToNewReferenceVarValue(REAL currentVarValue) const;
00087     tPolynomial<T> translate(REAL currentVarValue) const;
00088     void changeRate(REAL newRate, int newRateLength, REAL currentVarValue);
00089 
00090     void setRates(REAL newValues[], int newValuesLength, REAL currentVarValue);
00091     void setRates(tArray<REAL> newValues, REAL currentVarValue);
00092 
00093     virtual T & ReadSync( T & m );
00094     virtual T & WriteSync( T & m ) const;
00095 
00096     template<typename D>
00097     friend bool operator == (const tPolynomial<D> & left, const tPolynomial<D> & right);
00098     template<typename D>
00099     friend bool operator != (const tPolynomial<D> & left, const tPolynomial<D> & right);
00100 
00101     virtual std::string toString() const;
00102     tPolynomial<T> const clamp(REAL min, REAL max, REAL currentVarValue);
00103 
00104     int Len() const{
00105         return coefs.Len();
00106     };
00107 
00108     void setAtSameReferenceVarValue(const tPolynomial<T> & other);
00109 protected:
00110     void setReferenceVarValue(REAL newReferenceVarValue) {
00111         referenceVarValue = newReferenceVarValue;
00112     }
00113     void growCoefsArray(int newLength);
00114 
00115     // Variables
00116     REAL referenceVarValue; 
00117     tArray<REAL> coefs;
00118 };
00119 
00120 //These templates are probably only useable with nMessage as parameter.
00121 //The reason they're templates is that nMessage isn't available in src/tools
00122 //and that tPolynomial might be needed to be in src/tools in the future.
00123 //Imagine a constructor for vValue that converts from a tPolynomial as an
00124 //example (or the other way, as far as possible). --wrtlprnft
00125 
00126 template<typename T>
00127 T & operator << ( T & m, tPolynomial<T> const & f ); 
00128 template<typename T>
00129 T & operator >> ( T & m, tPolynomial<T> & f );       
00130 template<typename T>
00131 bool operator == (const tPolynomial<T> & left, const tPolynomial<T> & right);
00132 template<typename T>
00133 bool operator != (const tPolynomial<T> & left, const tPolynomial<T> & right);
00134 
00135 template <typename T>
00136 tPolynomial<T>::tPolynomial(int count)  
00137         : referenceVarValue(0.0),
00138         coefs(count)
00139 {
00140     // Initialise to all 0's
00141     for (int i=0; i<coefs.Len(); i++)
00142         coefs[i] = 0.0f;
00143 }
00144 
00145 template <typename T>
00146 tPolynomial<T>::tPolynomial()  
00147         : referenceVarValue(0.0),
00148         coefs(0)
00149 {
00150     // Empty
00151 }
00152 
00153 template <typename T>
00154 tPolynomial<T>::tPolynomial(REAL newCoefs[], int count)  
00155         : referenceVarValue(0.0),
00156         coefs(count)
00157 {
00158     for (int i=0; i<coefs.Len(); i++)
00159         coefs[i] = newCoefs[i];
00160 }
00161 
00162 template <typename T>
00163 tPolynomial<T>::tPolynomial(REAL value)  
00164         : referenceVarValue(0.0),
00165         coefs(1)
00166 {
00167     coefs[0] = value;
00168 }
00169 
00170 template <typename T>
00171 tPolynomial<T>::tPolynomial(tArray<REAL> newCoefs)  
00172         : referenceVarValue(0.0),
00173         coefs(newCoefs)
00174 {
00175     // Empty
00176 }
00177 
00178 template <typename T>
00179 tPolynomial<T>::tPolynomial(const tPolynomial<T> &tf)  
00180         : referenceVarValue(tf.referenceVarValue),
00181         coefs(tf.coefs)
00182 {
00183     // Empty
00184 }
00185 
00186 // *******************************************************************************
00187 // *
00188 // *    operator ( )
00189 // *
00190 // *******************************************************************************
00194 // *******************************************************************************
00195 
00196 template <typename T>
00197 REAL tPolynomial<T>::operator ( )( REAL currentVarValue ) const
00198 {
00199     return evaluate( currentVarValue );
00200 }
00201 
00202 // *******************************************************************************
00203 // *
00204 // *    operator <<
00205 // *
00206 // *******************************************************************************
00212 // *******************************************************************************
00213 
00214 template<typename T> T & operator << ( T & m, tPolynomial<T> const & f )
00215 {
00216     // write ID for compatibility with future extensions
00217     unsigned short ID = 1;
00218     m.Write( ID );
00219 
00220     return f.WriteSync(m);
00221 }
00222 
00223 // *******************************************************************************
00224 // *
00225 // *    operator >>
00226 // *
00227 // *******************************************************************************
00233 // *******************************************************************************
00234 
00235 template<typename T> T & operator >> ( T & m, tPolynomial<T> & f )
00236 {
00237     // write ID for compatibility with future extensions
00238     unsigned short ID;
00239     m.Read(ID);
00240     tASSERT( ID == 1 ) ;
00241 
00242     return f.ReadSync(m);
00243 }
00244 
00248 #define DELTA 1e-3
00249 
00250 template<typename T>
00251 bool operator == (const tPolynomial<T> & left, const tPolynomial<T> & right)
00252 {
00253     tPolynomial<T> tRebasedRight;
00254 
00255     // Do both polynomial have the same baseValue?
00256     if (false == ( fabs(left.referenceVarValue - right.referenceVarValue) < DELTA)) {
00257         // Bring back both polynomial to the same baseValue for easy comparision
00258         tRebasedRight = right.adaptToNewReferenceVarValue(left.referenceVarValue);
00259     }
00260     else {
00261         // They have similar baseValue, no need to adjust.
00262         tRebasedRight = right;
00263     }
00264 
00265 
00266     // If the length of the coefs array differ, then the extra elements should be 0
00267     int maxLength = MAX(left.coefs.Len(), right.coefs.Len());
00268     int minLength = MIN(left.coefs.Len(), right.coefs.Len());
00269 
00270     bool res = true;
00271 
00272     // Inspect the common coefficients (ie defined for both polynomial)
00273     for (int i=0; i<minLength; i++) {
00274         if ( fabs(left[i] - tRebasedRight[i]) >= DELTA ) {
00275             res = false;
00276             break;
00277         }
00278     }
00279 
00280     for (int i=minLength; i<maxLength; i++) {
00281         // The polynomial that is defined up to that length should have its elements set to 0.0
00282         if (left.coefs.Len()>tRebasedRight.coefs.Len()) {
00283             if (fabs(left[i]) >= DELTA) {
00284                 res = false;
00285                 break;
00286             }
00287         }
00288         else {
00289             if (fabs(tRebasedRight[i]) >= DELTA) {
00290                 res = false;
00291                 break;
00292             }
00293         }
00294     }
00295     return res;
00296 }
00297 
00298 template<typename T>
00299 bool operator != (const tPolynomial<T> & left, const tPolynomial<T> & right)
00300 {
00301     return !(left == right);
00302 }
00303 
00304 
00308 template <typename T>
00309 tPolynomial<T> tPolynomial<T>::adaptToNewReferenceVarValue(REAL currentVarValue) const
00310 {
00311     tPolynomial<T> tf(*this);
00312 
00313     // Compute the coefficients at "currentVarValue" (var for short)
00314     // c0' = c0 + (c1/sum(1))*var + (c2/sum(2))*var^2 + ... + (c[N]/sum(N))*var^N
00315     // c1' = c1 + (c2/sum(1))*var + ... + (c[N]/sum(N-1))*var^(N-1)
00316     // c2' = c2 + ... + (c[N]/sum(N-2))*var^(N-2)
00317     // ...
00318     // c[N-1] = c[N-1] + (c[N]/sum(1))*var
00319     // c[N] = c[N]
00320     //
00321     // so:
00322     // [0   , 0 , a] at currentVarValue=0 will become
00323     // [9a/2, 3a, a] at currentVarValue=3
00324 
00325     REAL deltaVariableValue = currentVarValue - referenceVarValue;
00326 
00327     // Compute for each coefficient their new value
00328     for (int coefIndex=0; coefIndex<coefs.Len(); coefIndex++) {
00329         REAL newCoefValue = 0.0;
00330         for (int j=coefs.Len()-1; j>coefIndex; j--) {
00331             newCoefValue = (newCoefValue + coefs[j] ) * deltaVariableValue /(j - coefIndex);
00332         }
00333         tf.coefs[coefIndex] += newCoefValue;
00334     }
00335 
00336     tf.setReferenceVarValue(currentVarValue);
00337     return tf;
00338 }
00339 
00343 template <typename T>
00344 tPolynomial<T> tPolynomial<T>::translate(REAL currentVarValue) const
00345 {
00346     tPolynomial<T> tf(*this);
00347 
00348     // Compute the coefficients at "currentVarValue" (var for short)
00349     // c0' = c0 + (c1)*var + (c2)*var^2 + ... + (c[N])*var^N
00350     // c1' = c1 + (c2)*var + ... + (c[N])*var^(N-1)
00351     // c2' = c2 + ... + (c[N])*var^(N-2)
00352     // ...
00353     // c[N-1] = c[N-1] + (c[N])*var
00354     // c[N] = c[N]
00355     //
00356     // so:
00357     // [0   , 0 , a] at currentVarValue=0 will become
00358     // [9a, 6a, a] at currentVarValue=3
00359 
00360     REAL deltaVariableValue = currentVarValue - referenceVarValue;
00361 
00362     // Compute for each coefficient their new value
00363     for (int coefIndex=0; coefIndex<coefs.Len(); coefIndex++) {
00364         REAL newCoefValue = 0.0;
00365         for (int j=coefs.Len()-1; j>coefIndex; j--) {
00366             newCoefValue = (newCoefValue + coefs[j] ) * deltaVariableValue;
00367         }
00368         tf.coefs[coefIndex] += newCoefValue;
00369     }
00370 
00371     tf.setReferenceVarValue(currentVarValue);
00372     return tf;
00373 }
00374 
00378 template <typename T>
00379 void tPolynomial<T>::changeRate(REAL newRate, int newRateIndex, REAL currentVarValue)
00380 {
00381     if (coefs.Len() <= newRateIndex) {
00382         int oldLength = coefs.Len();
00383         coefs.SetLen(newRateIndex + 1);
00384         for (int i=oldLength; i<newRateIndex; i++) {
00385             coefs[i] = 0.0;
00386         }
00387     }
00388 
00389     *this = adaptToNewReferenceVarValue(currentVarValue);
00390 
00391     coefs[newRateIndex] = newRate;
00392 }
00393 
00397 template <typename T>
00398 void tPolynomial<T>::setRates(REAL newValues[], int newValuesLength, REAL currentVarValue)
00399 {
00400     if (coefs.Len() < newValuesLength) {
00401         int oldLength = coefs.Len();
00402         coefs.SetLen(newValuesLength + 1);
00403         for (int i=oldLength; i<newValuesLength; i++) {
00404             coefs[i] = 0.0;
00405         }
00406     }
00407 
00408     setReferenceVarValue(currentVarValue);
00409 
00410     for (int i=0; i<newValuesLength; i++) {
00411         coefs[i] = newValues[i];
00412     }
00413 }
00414 
00415 template <typename T>
00416 void tPolynomial<T>::setRates(tArray<REAL> newValues, REAL currentVarValue)
00417 {
00418     coefs = newValues;
00419     setReferenceVarValue(currentVarValue);
00420 }
00421 
00422 template <typename T>
00423 REAL tPolynomial<T>::evaluate( REAL currentVarValue ) const
00424 {
00425     REAL deltaVariableValue = (currentVarValue - referenceVarValue);
00426 
00427     REAL res = 0.0;
00428 
00429     // Compute res = c[0] + c[1]*var + (c[2]/2)*var^2 + ... + (c[N]/N)*var^N
00430     for (int i=coefs.Len()-1; i>0; i--) {
00431         res = (res + coefs[i]/i) * deltaVariableValue;
00432     }
00433     if (coefs.Len()!=0)
00434         res += (coefs[0]);
00435 
00436     return res;
00437 
00438 }
00439 
00440 template <typename T>
00441 T & tPolynomial<T>::WriteSync( T & m ) const
00442 {
00443     m << referenceVarValue;
00444     // write length
00445     m << coefs.Len();
00446 
00447     for (int i=0; i<coefs.Len(); i++)
00448     {
00449         m << coefs[i];
00450     }
00451 
00452     return m;
00453 }
00454 
00455 template <typename T>
00456 T & tPolynomial<T>::ReadSync( T & m )
00457 {
00458     m >> referenceVarValue;
00459 
00460     // Read the length
00461     int newLength = 0;
00462     m >> newLength;
00463     coefs.SetLen(newLength);
00464 
00465     for (int i=0; i<coefs.Len(); i++)
00466     {
00467         m >> coefs[i];
00468     }
00469 
00470     return m;
00471 }
00472 
00473 template <typename T>
00474 tPolynomial<T> const tPolynomial<T>::operator*( REAL constant ) const {
00475     tPolynomial<T> tf(*this);
00476 
00477     for (int i=0; i<coefs.Len(); i++) {
00478         tf[i] *= constant;
00479     }
00480     return tf;
00481 }
00482 
00483 template <typename T>
00484 tPolynomial<T> const tPolynomial<T>::operator*( const tPolynomial<T> & tfRight ) const {
00485     tPolynomial<T> tf;
00486     tf.setAtSameReferenceVarValue(tfRight);
00487 
00488     // If any Polygonial is of size 0, then the resulting one is too
00489     // Otherwise, it is the sum of both lenght, minus 1.
00490     int newLength =
00491         (0 == this->coefs.Len() || 0 == tfRight.coefs.Len())
00492         ? 0
00493         : (this->coefs.Len() + tfRight.coefs.Len() - 1);
00494 
00495     int oldLength = tf.coefs.Len();
00496     tf.coefs.SetLen(newLength);
00497     for (int i=oldLength; i<newLength; i++) {
00498         tf[i] = 0.0;
00499     }
00500 
00501     if (0 == newLength) {
00502         // Special case, nothing needs to be done
00503     }
00504     else {
00505         for (int i=0; i<this->coefs.Len(); i++) {
00506             for (int j=0; j<tfRight.coefs.Len(); j++) {
00507                 tf[i+j] += (this->coefs[i]) * tfRight[j];
00508             }
00509         }
00510     }
00511     return tf;
00512 }
00513 
00514 template <typename T>
00515 tPolynomial<T> const tPolynomial<T>::operator+( REAL constant ) const {
00516     tPolynomial<T> tf(*this);
00517     tf[0] += constant;
00518     return tf;
00519 }
00520 
00521 template <typename T>
00522 tPolynomial<T> const tPolynomial<T>::operator+( const tPolynomial<T> &tfRight ) const {
00523     // Bring the polynomial to the same baseValue, so that the terms mean the same thing
00524     tPolynomial<T> tRebasedRight(tfRight.adaptToNewReferenceVarValue(this->referenceVarValue));
00525 
00526     int maxLength = MAX(this->coefs.Len(), tfRight.coefs.Len());
00527 
00528     // Set the lenght to the longest member of the addition
00529     tRebasedRight.coefs.SetLen(maxLength);
00530 
00531     for (int i=0; i<this->coefs.Len(); i++) {
00532         tRebasedRight[i] += coefs[i];
00533     }
00534 
00535     return tRebasedRight;
00536 }
00537 
00538 template <typename T>
00539 tPolynomial<T> & tPolynomial<T>::operator+=( const tPolynomial<T> &tfRight ) {
00540     // Bring the polynomial to the same baseValue, so that the terms mean the same thing
00541     tPolynomial<T> tRebasedRight = tfRight.adaptToNewReferenceVarValue(this->referenceVarValue);
00542 
00543     int maxLength = MAX(this->coefs.Len(), tfRight.coefs.Len());
00544     // Set the lenght to the longest member of the addition
00545     coefs.SetLen(maxLength);
00546 
00547     for (int i=0; i<maxLength; i++) {
00548         coefs[i] += tRebasedRight[i];
00549     }
00550 
00551     return *this;
00552 }
00553 
00557 template <typename T>
00558 tPolynomial<T> const tPolynomial<T>::substitute( const tPolynomial<T> &other ) const {
00559   tPolynomial<T> tf(0);
00560   tf.setAtSameReferenceVarValue(other);
00561   for(int i=this->Len()-1; i>0; i--) {
00562     tf = (tf + (*this)[i]) * other;
00563   }
00564   if(0 != this->Len()) {
00565     tf = tf + (*this)[0];
00566   }
00567 
00568   return tf;
00569 }
00570 
00571 template<typename T>
00572 REAL &tPolynomial<T>::operator[](int index) // Allow both reading and writing of element
00573 {
00574     // Manually growing the array to set all new elements to 0
00575     if (index >= coefs.Len()) {
00576         int previousLength = coefs.Len();
00577         coefs.SetLen(index + 1);
00578         for (int i=previousLength; i<coefs.Len(); i++) {
00579             coefs[i] = 0.0;
00580         }
00581     }
00582 
00583     return coefs[index];
00584 }
00585 
00586 template <typename T>
00587 REAL const &tPolynomial<T>::operator[](int index) const // Allow reading of element even when the object is const
00588 {
00589     return coefs[index];
00590 }
00591 
00592 template <typename T>
00593 void tPolynomial<T>::operator=(tPolynomial<T> const &other)
00594 {
00595     coefs = other.coefs;
00596     referenceVarValue = other.referenceVarValue;
00597 }
00598 
00599 template <typename T>
00600 tPolynomial<T>::tPolynomial(std::string str)
00601   : referenceVarValue(0.0),
00602      coefs(0)
00603 {
00604   parse(str);
00605 }
00606 
00607 template <typename T>
00608 void tPolynomial<T>::parse(std::string str)
00609 {
00610     int pos;
00611     int prevPos = 0;
00612     int index = 0;
00613 
00614 #define TPOLYNOMIAL_DELIMITER ';'
00615 
00616     pos = str.find(TPOLYNOMIAL_DELIMITER, 0);
00617     if(-1 != pos) {
00618       do{
00619         REAL value = atof(str.substr(prevPos, pos).c_str());
00620         coefs.SetLen(index + 2); // +1 because to write at index n, the len must be n+1. +1 to allocate a place for the element after the last ':'
00621         coefs[index] = value;
00622         
00623         prevPos = pos + 1;
00624         index ++;
00625       }
00626       while ( (pos = str.find(TPOLYNOMIAL_DELIMITER, prevPos)) != -1) ;
00627 
00628       coefs[index] = atof(str.substr(prevPos, pos).c_str());
00629 
00630     }
00631     else {
00632       coefs.SetLen(1);
00633       coefs[0] = atof(str.c_str());
00634     }
00635 }
00636 
00637 template <typename T>
00638 std::string tPolynomial<T>::toString() const {
00639     std::ostringstream ostr("");
00640 
00641     ostr << "base :" << referenceVarValue << " lenght:" << coefs.Len();
00642 
00643     for (int i=0; i<coefs.Len(); i++) {
00644         ostr << " c[" << i << "]:" << coefs[i];
00645     }
00646     return ostr.str();
00647 }
00648 
00649 
00654 template <typename T>
00655 tPolynomial<T> const tPolynomial<T>::clamp(REAL minValue, REAL maxValue, REAL currentVarValue)
00656 {
00657     tPolynomial<T> tf(*this);
00658 
00659     REAL valueAt = evaluate(currentVarValue);
00660     if (valueAt < minValue) {
00661         tf[0] = minValue;
00662         for (int i=1; i<coefs.Len(); i++) {
00663             if (tf[i] < 0) {
00664                 tf[i] = 0.0;
00665             }
00666         }
00667     }
00668     if (maxValue < valueAt) {
00669         tf[0] = maxValue;
00670         for (int i=1; i<coefs.Len(); i++) {
00671             if (tf[i] > 0) {
00672                 tf[i] = 0.0;
00673             }
00674         }
00675     }
00676 
00677     return tf;
00678 }
00679 
00683 template <typename T>
00684 void tPolynomial<T>::setAtSameReferenceVarValue(tPolynomial<T> const &other)
00685 {
00686   REAL a = other.referenceVarValue;
00687   referenceVarValue = a;
00688   //  referenceVarValue = other.referenceVarValue;
00689 }
00690 
00691 // *******************************************************
00692 // *******************************************************
00693 // *******************************************************
00694 // *******************************************************
00695 
00696 
00697 
00698 
00699 
00700 #endif
00701 

Generated on Sat Mar 15 22:56:01 2008 for Armagetron Advanced by  doxygen 1.5.4