GiNaCRA  0.6.4
RationalUnivariatePolynomial.cpp
Go to the documentation of this file.
00001 /*
00002  * GiNaCRA - GiNaC Real Algebra package
00003  * Copyright (C) 2010-2012  Ulrich Loup, Joachim Redies, Sebastian Junges
00004  *
00005  * This file is part of GiNaCRA.
00006  *
00007  * GiNaCRA is free software: you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation, either version 3 of the License, or
00010  * (at your option) any later version.
00011  *
00012  * GiNaCRA is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with GiNaCRA.  If not, see <http://www.gnu.org/licenses/>.
00019  *
00020  */
00021 
00022 
00023 //#define GINACRA_UNIVARIATERATIONALPOLYNOMIAL_DEBUG
00024 
00034 #include <assert.h>
00035 
00036 #include "utilities.h"
00037 #include "RationalUnivariatePolynomial.h"
00038 #include "operators.h"
00039 
00040 using GiNaC::is_exactly_a;
00041 
00042 namespace GiNaCRA
00043 {
00045     // Con- and destructors //
00047 
00048     RationalUnivariatePolynomial::RationalUnivariatePolynomial( const UnivariatePolynomial& p ) throw ( invalid_argument ):
00049         UnivariatePolynomial( p )
00050     {
00051         if( !GiNaC::is_rational_polynomial( p, p.variable() ))
00052         {
00053             stringstream stream;
00054             stream << "The specified univariate polynomial " << *this << " is not rational in " << p.variable() << ".";
00055             throw invalid_argument( stream.str() );
00056         }
00057         // setflag(status_flags::expanded | info_flags::rational_polynomial);
00058     }
00059 
00060     RationalUnivariatePolynomial::RationalUnivariatePolynomial( const ex& p, const symbol& s ) throw ( invalid_argument ):
00061         UnivariatePolynomial( p, s )
00062     {
00063         if( !GiNaC::is_rational_polynomial( *this, s ))    // need to take *this for the check because *this is expanded already
00064         {
00065             stringstream stream;
00066             stream << "The specified expression " << *this << " is not rational in " << s << ".";
00067             throw invalid_argument( stream.str() );
00068         }
00069         // setflag(status_flags::expanded | info_flags::rational_polynomial);
00070     }
00071 
00073     // Operators //
00075 
00076     // const RationalUnivariatePolynomial RationalUnivariatePolynomial::operator*(const RationalUnivariatePolynomial& o)
00077     // {
00078     //     return RationalUnivariatePolynomial(*this * o, mVariable);
00079     // }
00080 
00082     // Operations //
00084 
00085     GiNaC::sign RationalUnivariatePolynomial::sgn( const numeric& a ) const
00086     {
00087         numeric p_a = ex_to<numeric>( evaluateAt( a ));    // safe because of the constructor
00088         if( p_a < 0 )
00089             return GiNaC::NEGATIVE_SIGN;
00090         if( p_a > 0 )
00091             return GiNaC::POSITIVE_SIGN;
00092         return GiNaC::ZERO_SIGN;
00093     }
00094 
00095     numeric RationalUnivariatePolynomial::evaluateAt( const numeric& a ) const
00096     {
00097         // use Horner's method for polynomial evaluation
00098         numeric result = 0;
00099         for( int d = this->degree(); d >= 0; --d )
00100             result = this->coeff( d ) + result * a;
00101         return result;
00102     }
00103 
00104     numeric RationalUnivariatePolynomial::oneNorm() const
00105     {
00106         // compute the sum of the absolute values of the numeric coefficients
00107         numeric sum = 0;
00108         for( int i = UnivariatePolynomial::ldegree(); i <= UnivariatePolynomial::degree(); i++ )
00109             sum += abs( coeff( i ));
00110         return sum;
00111     }
00112 
00113     numeric RationalUnivariatePolynomial::twoNorm() const
00114     {
00115         // compute the sum of the squares of the absolute values of the numeric coefficients
00116         numeric sum = 0;
00117         for( int i = ldegree(); i <= degree(); i++ )
00118             sum += ex_to<numeric>( pow( coeff( i ), 2 ));
00119         return GiNaC::sqrt( sum );
00120     }
00121 
00122     numeric RationalUnivariatePolynomial::maximumNorm() const
00123     {
00124         // compute the maximum of the absolute values of the numeric coefficients
00125         numeric max = 0;
00126         for( int i = ldegree(); i <= degree(); i++ )
00127         {
00128             ex c = abs( ex_to<numeric>( coeff( i )));
00129             if( c > max )
00130                 max = ex_to<numeric>( c );
00131         }
00132         return max;
00133     }
00134 
00135     numeric RationalUnivariatePolynomial::cauchyBound() const
00136     {
00137         numeric lcf = abs( UnivariatePolynomial::lcoeff() );    // we have to perform the conversion of coefficients because it is not clear whether we have a numeric or a RealAlgebraicNumberIR
00138         if( lcf == 0 )
00139             return 0;
00140         numeric sum = 0;
00141         for( int i = UnivariatePolynomial::ldegree(); i <= UnivariatePolynomial::degree(); ++i )
00142             sum += abs( UnivariatePolynomial::coeff( i )) / lcf;
00143         return sum;
00144     }
00145 
00146     unsigned RationalUnivariatePolynomial::countRealRoots() const
00147     {
00148         list<RationalUnivariatePolynomial> seq = standardSturmSequence( *this, this->diff() );
00149         numeric c = this->cauchyBound();
00150         OpenInterval i( -c, c );
00151         return signVariations( seq, i.left() ) - signVariations( seq, i.right() );
00152     }
00153 
00154     numeric RationalUnivariatePolynomial::approximateRealRoot( const numeric start, const OpenInterval& i, unsigned steps ) const
00155     {
00156         numeric pivot                  = start;
00157         RationalUnivariatePolynomial p = this->diff();
00158         while( this->sgn( pivot ) != GiNaC::ZERO_SIGN )
00159         {
00160             pivot = pivot - this->evaluateAt( pivot ) / p.evaluateAt( pivot );
00161             if( steps == 0 ||!i.contains( pivot ))    // failed
00162                 return start;
00163             --steps;
00164         }
00165         // success
00166         return pivot;
00167     }
00168 
00170     // Static Methods //
00172 
00173     list<RationalUnivariatePolynomial> RationalUnivariatePolynomial::standardSturmSequence( const RationalUnivariatePolynomial& a,
00174                                                                                             const RationalUnivariatePolynomial& b )
00175     {
00176         list<UnivariatePolynomial>         seqUnivariate = UnivariatePolynomial::standardSturmSequence( a, b );
00177         list<RationalUnivariatePolynomial> seq           = list<RationalUnivariatePolynomial>();    // Sturm sequence to compute
00178         for( list<UnivariatePolynomial>::const_iterator i = seqUnivariate.begin(); i != seqUnivariate.end(); ++i )
00179             seq.push_back( RationalUnivariatePolynomial( *i ));
00180         return seq;
00181     }
00182 
00183     unsigned RationalUnivariatePolynomial::signVariations( const list<RationalUnivariatePolynomial>& seq, const numeric& a )
00184     {
00185         bool     sign  = seq.front().sgn( a ) >= GiNaC::ZERO_SIGN ? true : false;    // only positive (incl. zero) [1] and negative values [0] count
00186         unsigned count = 0;
00187         for( list<RationalUnivariatePolynomial>::const_iterator iter = seq.begin(); iter != seq.end(); ++iter )
00188         {
00189             if( sign xor( iter->sgn( a ) >= GiNaC::ZERO_SIGN ))
00190             {
00191                 ++count;
00192                 sign = !sign;
00193             }
00194         }
00195         return count;
00196     }
00197 
00198     int RationalUnivariatePolynomial::calculateSturmCauchyIndex( const RationalUnivariatePolynomial& p, const RationalUnivariatePolynomial& q )
00199     {
00200         if( p.is_zero() )
00201             throw invalid_argument( "Can not compute the Cauchy index of a zero polynomial." );
00202         const list<RationalUnivariatePolynomial> SRemS      = RationalUnivariatePolynomial::standardSturmSequence( p, q );
00203         const numeric                            upperBound = p.cauchyBound();
00204         assert( upperBound > 0 );
00205 
00206         //TODO make it faster by only iterating once. This needs an own method to calculate signVariations with two numeric parameters.
00207         return (((int)RationalUnivariatePolynomial::signVariations( SRemS, -upperBound ))
00208                 - ((int)RationalUnivariatePolynomial::signVariations( SRemS, upperBound )));
00209     }
00210 
00211     int RationalUnivariatePolynomial::calculateRemainderTarskiQuery( const RationalUnivariatePolynomial& p, const RationalUnivariatePolynomial& q )
00212     {
00213         return RationalUnivariatePolynomial::calculateSturmCauchyIndex( p, (RationalUnivariatePolynomial)p.diff() * q );
00214     }
00215 
00216     //
00217     //    std::list<int> RationalUnivariatePolynomial::signDeterminationHelperRows(std::list<std::vector<Sign> > signs) {
00218     //        list<int> L1, L2, L3;
00219     //        unsigned n = signs.first.size();
00220     //
00221     //    }
00222     //
00223     //    std::list<std::vector<Sign> > RationalUnivariatePolynomial::calculateSignDetermination(const RationalUnivariatePolynomial& z, const std::vector<RationalUnivariatePolynomial>& polynomials) {
00224     //        int tq = calculateRemainderTarskiQuery(RationalUnivariatePolynomial(1,z.Variable()),z);
00225     //        int nrRoots  = std::abs(tq);
00226     //        set<std::vector<Sign> > realizedSignConditions;
00227     //
00228     //        //return the empty set, since there are no roots.
00229     //        if (nrRoots == 0) return realizedSignConditions;
00230     //
00231     //
00232     //        RationalUnivariatePolynomial polynomialsSquared;
00233     //        //We iterate backwards. Not sure why, but we are following the description from the book here.
00234     //        //TODO explain why we do not iterate forward.
00235     //        for(int i = polynomials.size(); i >= 0; i-- ) {
00236     //            polynomialSquared = polynomials[i].square()
00237     //            int tqp = calculateRemainderTarskiQuery(polynomials[i],z);
00238     //            int tqpp = calculateRemainderTarskiQuery(polynomialSquared, z);
00239     //            assert((tqp+tqpp)%2 == 0); // otherwise next division is inaccurate!
00240     //
00241     //            //Calculate the numbers using equality 10.13 from page 384.
00242     //            //Explicitly calculated in Proposition 2.65 from page 64.
00243     //            int nrPositives = (tqp + tqpp)/2
00244     //            int nrNegatives = (tqpp - tqp)/2;
00245     //            int nrZeroes = tq - tqpp;
00246     //
00247     //            //Count how many different signs.
00248     //            int differentsigns = 0;
00249     //            //If differentsigns becomes two, we would like to know which wasnt there.
00250     //            Sign nonexistant;
00251     //            if (nrPositives > 0) {
00252     //                differentsigns++;
00253     //                nonexistant = POSITIVESIGN;
00254     //            }
00255     //            if (nrNegatives > 0) {
00256     //                differentsigns++;
00257     //                nonexistant = NEGATIVESIGN;
00258     //            }
00259     //            if (nrZeroes > 0) {
00260     //                differentsigns++;
00261     //                nonexistant = ZEROSIGN;
00262     //            }
00263     //            // The signs can be -, 0, +, so no more than 3, and at least one of them has to be there, since z has roots.
00264     //            assert(differentsigns <= 3 && differentsigns > 1);
00265     //
00266     //            //We are using matrix-tensorproducts, so we have to represent this as a matrix.
00267     //            //TODO implement another method which computes the elements directly and compare their speed.
00268     //            matrix m(2,2);
00269     //            //TODO check the order, perhaps another order is faster?
00270     //            if(differentsigns == 2) {
00271     //                if(nonexistant == ZEROSIGN) {
00272     //                    m = 1, 1,
00273     //                        1, -1;
00274     //                } else if (nonexistant == POSITIVESIGN) {
00275     //                    m = 1, 1,
00276     //                        0, -1;
00277     //                } else {
00278     //                    m = 1, 1,
00279     //                        0, 1;
00280     //                }
00281     //            } else if(differentsigns == 3) {
00282     //                m = matrix(3,3);
00283     //                m = 1, 1, 1,
00284     //                    0, 1, -1,
00285     //                    0, 1, 1;
00286     //            } else {
00287     //                m = matrix(1,1);
00288     //                m = 1;
00289     //            }
00290     //
00291     //            // In the first step, we do not have to do more.
00292     //            if(i == polynomials.size())  {
00293     //
00294     //                continue;
00295     //            }
00296     //
00297     //            //In the next step we want to solve mx = b.
00298     //            matrix b;
00299     //            matrix x;
00300     //        }
00301     //    }
00302 
00303 }    // namespace GiNaC
00304