GiNaCRA  0.6.4
utilities.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 
00032 #include <sstream>
00033 #include <string>
00034 #include <assert.h>
00035 
00036 using namespace std;
00037 
00038 #include "utilities.h"
00039 
00040 namespace GiNaC
00041 {
00042     const ex prod( const lst& l ) throw ( invalid_argument )
00043     {
00044         lst::const_iterator i = l.begin();
00045         ex prod = *i;    // invariant: prod is the product of the elements of l traversed so far
00046         ++i;
00047         for( ; i != l.end(); ++i )
00048             prod *= *i;
00049         return prod;
00050     }
00051 
00052     const ex lcm( const lst& l ) throw ( invalid_argument )
00053     {
00054         lst::const_iterator i = l.begin();
00055         ex currentLcm = *i;    // invariant: currentLcm is the lcm of the elements of l traversed so far
00056         ++i;
00057         for( ; i != l.end(); ++i )
00058             currentLcm = lcm( currentLcm, *i );
00059         return currentLcm;
00060     }
00061 
00062     long lcm( long a, long b )
00063     {
00064         long temp = gcd( a, b );
00065         return temp ? (a / temp * b) : 0;
00066     }
00067 
00068     long gcd( long a, long b )
00069     {
00070         assert( a != 0 );
00071         while( true )
00072         {
00073             a = a % b;
00074             if( a == 0 )
00075                 return b;
00076             b = b % a;
00077             if( b == 0 )
00078                 return a;
00079         }
00080     }
00081 
00082     long numerator( long a, long b )
00083     {
00084         return a / gcd( a, b );
00085     }
00086 
00087     long denominator( long a, long b )
00088     {
00089         return b / gcd( a, b );
00090     }
00091 
00092     bool is_constant( const ex& polynomial, const vector<symbol>& symbolLst )
00093     {
00094         for( vector<symbol>::const_iterator it = symbolLst.begin(); it != symbolLst.end(); ++it )
00095             if( polynomial.degree( *it ) != 0 )
00096                 return false;
00097         return true;
00098     }
00099 
00100     bool is_rational_polynomial( const ex& p, const symbol& x )
00101     {
00102         for( int i = p.ldegree( x ); i <= p.degree( x ); ++i )
00103         {
00104             ex c = p.coeff( x, i );
00105             if( !(is_exactly_a<numeric>( c ) && ex_to<numeric>( c ).is_rational()))
00106                 return false;
00107         }
00108         if( !p.info( info_flags::rational_polynomial ))
00109             return false;
00110         return true;
00111     }
00112 
00113     bool is_realalgebraic_polynomial( const ex& p, const symbol& x )
00114     {
00115         for( int i = p.ldegree( x ); i <= p.degree( x ); ++i )
00116         {
00117             if( !is_realalgebraic_term( p.coeff( x, i )))
00118                 return false;
00119         }
00120         return true;
00121     }
00122 
00123     bool is_realalgebraic_term( const ex& p )
00124     {
00125         if( p.info( GiNaC::info_flags::numeric )
00126                 && (p.info( GiNaC::info_flags::rational ) || (p.info( GiNaC::info_flags::real ) && p.info( GiNaC::info_flags::algebraic ))))
00127         {
00128             return true;
00129         }
00130         else if( GiNaC::is_exactly_a<GiNaC::power>( p ))
00131         {
00132             if( !is_realalgebraic_term( *p.begin() ))
00133                 return false;
00134             return true;
00135         }
00136         else if( GiNaC::is_exactly_a<GiNaC::add>( p ) || GiNaC::is_exactly_a<GiNaC::mul>( p ) || GiNaC::is_exactly_a<GiNaC::ncmul>( p )
00137                  || GiNaC::is_exactly_a<GiNaC::pseries>( p ))
00138         {
00139             for( const_iterator i = p.begin(); i != p.end(); ++i )
00140                 if( !is_realalgebraic_term( *i ))
00141                     return false;
00142             return true;
00143         }
00144         return false;
00145     }
00146 
00147     sign sgn( const numeric& n )
00148     {
00149         return n == 0 ? ZERO_SIGN : n > 0 ? POSITIVE_SIGN : NEGATIVE_SIGN;
00150     }
00151 
00152     const ex monpart( const ex& polynomial, const vector<symbol>& symbolLst )
00153     {
00154         ex coefficient = ex( 1 );
00155         ex monomial    = ex( 1 );
00156         isolateByVariables( polynomial, symbolLst, coefficient, monomial );
00157         return monomial;
00158     }
00159 
00160     const ex coeffpart( const ex& polynomial, const vector<symbol>& symbolLst )
00161     {
00162         ex coefficient = ex( 1 );
00163         ex monomial    = ex( 1 );
00164         isolateByVariables( polynomial, symbolLst, coefficient, monomial );
00165         return coefficient;
00166     }
00167 
00168     void isolateByVariables( const ex& polynomial, const vector<symbol>& symbolLst, ex& coefficient, ex& monomial )
00169     {
00170         coefficient = ex( 1 );
00171         monomial    = ex( 1 );
00172 
00173         // isolate monomial and coefficient in case polynomial has only one term
00174 
00175         if( is_constant( polynomial, symbolLst ))
00176         {    // polynomial is constant in the current list of variables, so is a coefficient with the 1 monomial
00177             coefficient = polynomial;
00178         }
00179         else if( is_exactly_a<GiNaC::mul>( polynomial ))    // GiNaC::mul because of overriding the name "mul" by the current function
00180         {    // polynomial is just a product
00181             for( const_iterator j = polynomial.begin(); j != polynomial.end(); ++j )    // iterate through the possible powers
00182             {
00183                 vector<symbol>::const_iterator s = symbolLst.begin();
00184                 for( ; s != symbolLst.end(); ++s )    // only take symbols given in the list (all other things are coefficient)
00185                 {
00186                     if( j->degree( *s ) > 0 )
00187                     {
00188                         monomial = monomial * *j;
00189                         break;
00190                     }
00191                 }
00192                 if( s == symbolLst.end() )    // current power is not build upon a variable, so it belongs to the coefficient
00193                     coefficient = coefficient * *j;
00194             }
00195         }
00196         else if( GiNaC::is_exactly_a<GiNaC::power>( polynomial ) || GiNaC::is_exactly_a<GiNaC::symbol>( polynomial ))
00197         {
00198             vector<symbol>::const_iterator s = symbolLst.begin();
00199             for( ; s != symbolLst.end(); ++s )    // only take symbols given in the list (all other things are coefficient)
00200             {
00201                 if( polynomial.degree( *s ) > 0 )
00202                 {
00203                     monomial = polynomial;
00204                     return;
00205                 }
00206             }
00207             coefficient = polynomial;
00208         }
00209         else if( is_exactly_a<numeric>( polynomial ))
00210             coefficient = polynomial;
00211         else if( polynomial.is_zero() )
00212             coefficient = ex( 0 );
00213         // in all other cases, the polynomial has several terms
00214     }
00215 
00216     const GiNaC::ex rationalize( const GiNaC::ex& p, const vector<GiNaC::symbol>& symbolLst )
00217     {
00218         GiNaC::ex pExpanded = p.expand();
00219         if( GiNaC::is_exactly_a<GiNaC::add>( pExpanded ))
00220         {
00221             GiNaC::ex pRational;
00222             for( GiNaC::const_iterator i = p.begin(); i != p.end(); ++i )    // iterate through the summands
00223                 pRational += rationalize( *i, symbolLst );
00224             return pRational;
00225         }
00226         GiNaC::ex coefficient = ex( 1 );
00227         GiNaC::ex monomial    = ex( 1 );
00228         isolateByVariables( p, symbolLst, coefficient, monomial );
00229         assert( GiNaC::is_exactly_a<GiNaC::numeric>( coefficient ));
00230         GiNaC::numeric coefficientNum = GiNaC::ex_to<numeric>( coefficient );
00231         if( !coefficientNum.is_rational() )
00232             return rationalize( coefficientNum ) * monomial;
00233         return coefficientNum * monomial;
00234     }
00235 
00236     const GiNaC::ex rationalize( const GiNaC::ex& p, const GiNaC::symbol& s )
00237     {
00238         return rationalize( p, vector<GiNaC::symbol>( 1, s ));
00239     }
00240 
00241     const GiNaC::numeric rationalize( const GiNaC::numeric& n )
00242     {
00243         return numeric( cln::rationalize( n.to_double() ));
00244     }
00245 
00246     const vector<symbol> sortVariables( const vector<symbol>& l )
00247     {
00248         vector<symbol> newL = vector<symbol>( l.begin(), l.end() );
00249         sort( newL.begin(), newL.end(), symbol_is_less_lex );
00250         return newL;
00251     }
00252 
00253     bool symbol_is_lesseq_lex( const symbol& a, const symbol& b )
00254     {
00255         stringstream sA, sB;
00256         sA << a;
00257         sB << b;
00258         return sA.str().compare( sB.str() ) <= 0;
00259     }
00260 
00261     bool symbol_is_less_lex( const symbol& a, const symbol& b )
00262     {
00263         stringstream sA, sB;
00264         sA << a;
00265         sB << b;
00266         return sA.str().compare( sB.str() ) <= 0;
00267     }
00268 
00269     const map<int, ex> signedSubresultants( const ex& A, const ex& B, const symbol& sym )
00270     {
00271         ex P      = A;
00272         ex Q      = B;
00273         ex ex_sym = sym;    // avoid complicated casts like symbol -> ex
00274         int p = P.degree( ex_sym );
00275         int q = Q.degree( ex_sym );
00276         ex a             = P.lcoeff( ex_sym );    // leading coefficient of P
00277         ex b             = Q.lcoeff( ex_sym );    // leading coefficient of Q
00278         ex epsilon_p_q_1 = pow( (-1), (p - q - 1) * (p - q - 1 + 1) / 2 );
00279 
00280         int          j, k;
00281         map<int, ex> H;
00282         map<int, ex> h;
00283         map<int, ex> h_;
00284 
00285         if( p > q )
00286         {
00287             j        = q;
00288             h[q]     = epsilon_p_q_1 * pow( b, p - q );
00289             H[q]     = epsilon_p_q_1 * pow( b, p - q - 1 ) * Q;
00290             H[q - 1] = -rem( b * h[q] * P, Q, ex_sym, false );
00291         }
00292 
00293         else if( p == q )
00294         {
00295             j        = q;
00296             h[q]     = 1;
00297             H[q - 1] = -rem( b * P, Q, ex_sym );
00298         }
00299 
00300         else    // p < q
00301         {
00302             j        = p;
00303             h[p]     = pow( a, q - p );
00304             H[p]     = pow( a, q - p - 1 ) * P;
00305             H[p - 1] = -rem( a * h[p] * Q, P, ex_sym, false );
00306         }
00307 
00308         map<int, ex>::const_iterator itti = H.find( j - 1 );
00309         if( itti != H.end() && H[j - 1] == 0 )
00310             return H;
00311         else
00312         {
00313             k = H[j - 1].degree( ex_sym );
00314             while( true )
00315             {
00316                 if( k == j - 1 )
00317                 {
00318                     // The following line is missing in the paper
00319                     // but the algorithm is not working
00320                     // without it. If it is missing
00321                     // h[j-1] is just initialized with 0.
00322                     // See the definition of h on page 5 in the paper !
00323                     h[j - 1] = H[j - 1].lcoeff( ex_sym );
00324                     //H[k-1] = -rem(pow(h[j-1], 2) * H[j], H[j-1], ex_sym, false) / pow(h[j], 2);
00325                     if( !divide( -rem( pow( h[j - 1], 2 ) * H[j], H[j - 1], ex_sym, false ), pow( h[j], 2 ), H[k - 1] ))
00326                         assert( false == true );    // Division Error!
00327 
00328                     if( p == q && q == j )
00329                     {
00330                         //H[q-2] = -rem(pow(h[q-1], 2) * Q, H[q-1], ex_sym, false) / b;
00331                         if( !divide( -rem( pow( h[q - 1], 2 ) * Q, H[q - 1], ex_sym, false ), b, H[q - 2] ))
00332                             assert( false == true );    // Division Error!
00333                     }
00334                 }
00335 
00336                 if( k < j - 1 )
00337                 {
00338                     h_[j - 1] = H[j - 1].lcoeff( ex_sym );
00339 
00340                     for( int delta = 1; delta <= j - k - 1; delta++ )
00341                     {
00342                         //h_[j-delta-1] = pow(-1, delta) * (h_[j-1] * h_[j-delta]) / h[j];
00343                         if( !divide( pow( -1, delta ) * (h_[j - 1] * h_[j - delta]), h[j], h_[j - delta - 1] ))
00344                             assert( false == true );    // Division Error!
00345                     }
00346 
00347                     h[k] = h_[k];
00348 
00349                     //H[k] = (h[k] * H[j-1])/h_[j-1];
00350                     if( !divide( (h[k] * H[j - 1]), h_[j - 1], H[k] ))
00351                         assert( false == true );    // Division Error!
00352 
00353                     //H[k-1] = -rem(h_[j-1] * h[k] * H[j], H[j-1], ex_sym, false) / pow(h[j], 2);
00354                     if( !divide( -rem( h_[j - 1] * h[k] * H[j], H[j - 1], ex_sym, false ), pow( h[j], 2 ), H[k - 1] ))
00355                         assert( false == true );    // Division Error!
00356 
00357                     if( p == q && q == j )
00358                     {
00359                         //H[k-1] = -rem(h_[q-1] * h[k] * Q, H[j-1], ex_sym, false) / b;
00360                         if( !divide( -rem( h_[q - 1] * h[k] * Q, H[j - 1], ex_sym, false ), b, H[k - 1] ))
00361                             assert( false == true );    // Division Error!
00362                     }
00363                 }
00364 
00365                 itti = H.find( k - 1 );
00366 
00367                 if( itti != H.end() && H[k - 1] == 0 )
00368                     return H;
00369 
00370                 else
00371                 {
00372                     j = k;
00373                     k = H[k - 1].degree( ex_sym );
00374                 }
00375             }
00376         }
00377 
00378         return H;
00379     }
00380 
00381     const vector<ex> signedSubresultantsCoefficients( const ex& A, const ex& B, const symbol& sym ) throw ( invalid_argument )
00382     {
00383         ex ex_x = sym;
00384         int a = A.degree( ex_x );
00385         // may if (a < b && a != 0 && b != 0) ??
00386         //if( a <= b )    // VERY DANGEROUS USE !!
00387         //    throw invalid_argument( "The degree of A must be greater than the degree of B!" );
00388         //else
00389         //{
00390         map<int, ex> H = signedSubresultants( A, B, sym );
00391         vector<ex>   sRes( a + 1 );
00392         for( int i = 0; i < a; i++ )
00393             sRes[i] = ex( H[i].coeff( ex_x, i ));
00394         sRes[a] = ex( A.coeff( ex_x, a ));
00395         return sRes;
00396         //}
00397     }
00398 
00399 }    // namespace GiNaC
00400