GiNaCRA  0.6.4
UnivariatePolynomial.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_UNIVARIATEPOLYNOMIAL_DEBUG
00024 
00034 #include <assert.h>
00035 
00036 #include "UnivariatePolynomial.h"
00037 #include "operators.h"
00038 #include "RealAlgebraicNumberIR.h"
00039 
00040 using GiNaC::ex;
00041 using GiNaC::is_exactly_a;
00042 
00043 namespace GiNaCRA
00044 {
00046     // Con- and destructors //
00048 
00049     UnivariatePolynomial::UnivariatePolynomial( const ex& p, const symbol& s, bool enableCheck ) throw ( invalid_argument ):
00050         Polynomial( p.expand().collect( s )),
00051         mVariable( s ),
00052         mEnabledPolynomialCheck( enableCheck )
00053     {
00054         if( enableCheck &&!this->is_polynomial( s ))
00055             throw invalid_argument( "Specified expression is no polynomial in the given variable." );
00056     }
00057 
00059     // Methods from ex //
00061 
00062     void UnivariatePolynomial::do_print( const print_context& c, unsigned level ) const
00063     {
00064         c.s << static_cast<ex>(*this) << '(' << mVariable << ')';
00065     }
00066 
00068     // Operators //
00070 
00071     // assignment operators
00072 
00073     const UnivariatePolynomial& UnivariatePolynomial::operator = ( const UnivariatePolynomial& o )
00074     {
00075         ex::operator = ( o );
00076         mVariable               = o.mVariable;
00077         mEnabledPolynomialCheck = o.mEnabledPolynomialCheck;
00078         return *this;
00079     }
00080 
00081     const UnivariatePolynomial& UnivariatePolynomial::operator = ( const ex& o )
00082     {
00083         ex oNorm = ex( o );
00084         ex::operator = ( oNorm );
00085         // convention: new polynomial has current main variable
00086         return *this;
00087     }
00088 
00090     // Operations //
00092 
00093     UnivariatePolynomial UnivariatePolynomial::trunc() const
00094     {
00095         ex e    = *this;
00096         ex ex_s = this->variable();
00097         if( e.degree( ex_s ) == 0 )
00098             return *this;
00099         else
00100             return UnivariatePolynomial( e - e.lcoeff( ex_s ) * pow( this->variable(), e.degree( ex_s )), this->variable(), mEnabledPolynomialCheck );
00101     }
00102 
00103     UnivariatePolynomial UnivariatePolynomial::sepapart() const
00104     {
00105         if( isConstant() )    // prevent division by zero
00106             return UnivariatePolynomial( 0, mVariable );
00107         // @see Lemma 10.13 in ISBN 0-387-94090-1
00108         return UnivariatePolynomial( this->quo( this->gcd( this->diff().primpart() )), mVariable, mEnabledPolynomialCheck ).primpart();
00109     }
00110 
00111     UnivariatePolynomial UnivariatePolynomial::nonzeropart() const
00112     {
00113         int l = ldegree();
00114         symbol variable = mVariable;
00115         ex result       = coeff( l );
00116         for( int d = l + 1; d <= degree(); ++d )
00117             result += coeff( d ) * pow( variable, d - l );
00118         return UnivariatePolynomial( result, variable );
00119     }
00120 
00122     // Arithmetic Operations //
00124 
00125     const list<UnivariatePolynomial> UnivariatePolynomial::subresultants( const UnivariatePolynomial& p,
00126                                                                           const UnivariatePolynomial& q,
00127                                                                           const subresultantStrategy strategy )
00128     {
00129         // INIT: Check and normalize input, initialize local variables
00130         if( !p.isCompatible( q ))
00131             throw invalid_argument( "Symbols of the two univariate polynomials do not match." );
00132         std::list<UnivariatePolynomial> subresultants = std::list<UnivariatePolynomial>();    // the desired list of subresultants
00133         symbol variable = p.mVariable;
00134 
00135         UnivariatePolynomial a, b;    // a shall receive the smaller-degree polynomial
00136         if( p.degree() < q.degree() )
00137         {
00138             a = q;
00139             b = p;
00140         }
00141         else
00142         {
00143             a = p;
00144             b = q;
00145         }
00146 
00147         // aDeg >= bDeg shall hold, so switch in case it does not hold
00148         if( b.isZero() )
00149             return list<UnivariatePolynomial>( 1, a );
00150         // initiate with input polynomials
00151         subresultants.push_front( a );
00152         subresultants.push_front( b );
00153         //            if( aDeg < 2 )
00154         //                return subresultants;
00155         UnivariatePolynomial tmp = UnivariatePolynomial( b );    // the smaller degree
00156         b                        = UnivariatePolynomial( GiNaC::prem( a, -b, variable, false ), variable, false );
00157         a                        = tmp;
00158 
00159         int aDeg = a.degree();
00160         int bDeg = b.degree();
00161         ex subresLcoeff = GiNaC::pow( a.lcoeff(), aDeg - bDeg );    // initialized on the basis of the smaller-degree polynomial
00162 
00163         // MAIN: start main loop containing different computation strategies
00164         while( true )
00165         {
00166             if( b.isZero() )
00167                 return subresultants;
00168             aDeg = a.degree();
00169             bDeg = b.degree();
00170             subresultants.push_front( b );
00171             int delta = aDeg - bDeg;
00172             UnivariatePolynomial c = b;
00173             if( delta > 1 )
00174             {    // compute c
00175                 switch( strategy )
00176                 {
00177                     case GENERIC_SUBRESULTANTSTRATEGY:
00178                     {
00179                         ex reductionCoeff;
00180                         GiNaC::divide( GiNaC::pow( b.lcoeff(), delta - 1 ), GiNaC::pow( subresLcoeff, delta - 1 ), reductionCoeff, false );
00181                         c = UnivariatePolynomial( reductionCoeff * b, variable, false );
00182                         break;
00183                     }
00184                     case LAZARDS_SUBRESULTANTSTRATEGY:
00186                         break;
00187                     case DUCOS_SUBRESULTANTSTRATEGY:
00189                         break;
00190                 }
00191                 subresultants.push_front( c );
00192             }
00193             // else: c == b
00194             if( bDeg == 0 )
00195                 return subresultants;
00196             switch( strategy )
00197             {
00198                 case GENERIC_SUBRESULTANTSTRATEGY:
00199                 {
00200                     ex reducedNewB;
00201                     GiNaC::divide( GiNaC::prem( a, -b, variable, false ), GiNaC::pow( subresLcoeff, delta ) * a.lcoeff(), reducedNewB, false );
00202                     b = UnivariatePolynomial( reducedNewB, variable, false );
00203                     break;
00204                 }
00205                 case LAZARDS_SUBRESULTANTSTRATEGY:
00207                     break;
00208                 case DUCOS_SUBRESULTANTSTRATEGY:
00210                     break;
00211             }
00212             a            = c;
00213             subresLcoeff = a.lcoeff();
00214         }
00215     }
00216 
00217     const vector<ex> UnivariatePolynomial::subresultantCoefficients( const UnivariatePolynomial& a,
00218                                                                      const UnivariatePolynomial& b,
00219                                                                      const subresultantStrategy strategy )
00220     {
00221         list<UnivariatePolynomial> subres       = UnivariatePolynomial::subresultants( a, b, strategy );
00222         vector<ex>                 subresCoeffs = vector<ex>();
00223         for( list<UnivariatePolynomial>::const_iterator s = subres.begin(); s != subres.end(); ++s )
00224             subresCoeffs.push_back( s->lcoeff() );
00225         return subresCoeffs;
00226     }
00227 
00228     const vector<ex> UnivariatePolynomial::principalSubresultantCoefficients( const UnivariatePolynomial& a,
00229                                                                               const UnivariatePolynomial& b,
00230                                                                               const subresultantStrategy strategy )
00231     {
00232         list<UnivariatePolynomial> subres       = UnivariatePolynomial::subresultants( a, b, strategy );
00233         vector<ex>                 subresCoeffs = vector<ex>( subres.size() );
00234         int                        i            = 0;
00235         for( list<UnivariatePolynomial>::const_iterator s = subres.begin(); s != subres.end(); ++s )
00236         {
00237             if( s->degree() < i )
00238                 break;    // this and all further subresultants won't have a non-zero i-th coefficient
00239             subresCoeffs[i] = s->coeff( i );
00240             ++i;
00241         }
00242         subresCoeffs.resize( i );
00243         return subresCoeffs;
00244     }
00245 
00247     // Relational Operations //
00249 
00251     // Static Methods //
00253 
00254     list<UnivariatePolynomial> UnivariatePolynomial::standardSturmSequence( const UnivariatePolynomial& a,
00255                                                                             const UnivariatePolynomial& b )
00256             throw ( invalid_argument )
00257     {
00258         if( !a.isCompatible( b ))
00259             throw invalid_argument( "Symbols of the two univariate polynomials do not match." );
00260         list<UnivariatePolynomial> seq = list<UnivariatePolynomial>();    // Sturm sequence to compute
00261         ex p            = a, q = b;
00262         symbol variable = a.mVariable;
00263         seq.push_back( a );
00264         while( !q.is_zero() )
00265         {
00266             seq.push_back( UnivariatePolynomial( q, variable ));
00267             q = -(GiNaC::rem( p, q, variable ));
00268             p = seq.back();
00269         }
00270         return seq;
00271     }
00272 
00273     bool UnivariatePolynomial::univariatePolynomialIsLess( const UnivariatePolynomial& a, const UnivariatePolynomial& b )
00274     {
00275         return !a.isEqual( b ) && a.compare( b ) < 0;
00276     }
00277 
00278     bool UnivariatePolynomial::univariatePolynomialIsLessLowDeg( const UnivariatePolynomial& a, const UnivariatePolynomial& b )
00279     {
00280         return a.degree() < b.degree() || (a.degree() == b.degree() && univariatePolynomialIsLess( a, b ));
00281     }
00282 
00283     bool UnivariatePolynomial::univariatePolynomialIsLessOddDeg( const UnivariatePolynomial& a, const UnivariatePolynomial& b )
00284     {
00285         return GiNaC::is_odd( a.degree() ) || (a.degree() == b.degree() && univariatePolynomialIsLess( a, b ));
00286         GiNaC::is_odd( a.degree() ) || a.compare( b ) < 0;
00287     }
00288 
00289     bool UnivariatePolynomial::univariatePolynomialIsLessOddLowDeg( const UnivariatePolynomial& a, const UnivariatePolynomial& b )
00290     {
00291         return (a.degree() < b.degree() && GiNaC::is_odd( a.degree() )) || (a.degree() == b.degree() && univariatePolynomialIsLess( a, b ));
00292         GiNaC::is_odd( a.degree() ) || a.compare( b ) < 0;
00293     }
00294 
00295     bool UnivariatePolynomial::univariatePolynomialIsLessEvenDeg( const UnivariatePolynomial& a, const UnivariatePolynomial& b )
00296     {
00297         return GiNaC::is_even( a.degree() ) || (a.degree() == b.degree() && univariatePolynomialIsLess( a, b ));
00298     }
00299 
00300     bool UnivariatePolynomial::univariatePolynomialIsLessEvenLowDeg( const UnivariatePolynomial& a, const UnivariatePolynomial& b )
00301     {
00302         return (a.degree() < b.degree() && GiNaC::is_even( a.degree() )) || (a.degree() == b.degree() && univariatePolynomialIsLess( a, b ));
00303     }
00304 }    // namespace GiNaC
00305