GiNaCRA  0.6.4
MultivariatePolynomialFactory.h
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 #ifndef GINACRA_MULTIVARIATEPOLYNOMIALFACTORY_H
00024 #define GINACRA_MULTIVARIATEPOLYNOMIALFACTORY_H
00025 
00026 // #define GINACRA_MULTIVARIATEPOLYNOMIAL_CHECK_STAIRCASEBORDER // check whether a Groebner basis defines a finite set of monomials under the staircase (as it is the case for special GBs)
00027 // #define GINACRA_MULTIVARIATEMONOMIAL_CHECK_SPECIALGROEBNERBASIS // check for non-zero-dimensional system
00028 
00040 #include "MultivariatePolynomial.h"
00041 #include "MultivariateTerm.h"
00042 #include "MultivariateMonomial.h"
00043 #include "MultivariateCoefficient.h"
00044 #include "operators.h"
00045 #include <algorithm>
00046 
00047 namespace GiNaCRA
00048 {
00050     // Auxiliary structs //
00052 
00055     template<class monomialOrdering>
00056     struct symbol_is_greatereq_tdegree:
00057         public binary_function<symbol, symbol, bool>
00058     {
00059         MultivariatePolynomial<monomialOrdering> polynomial;
00060 
00061         symbol_is_greatereq_tdegree( const MultivariatePolynomial<monomialOrdering>& polynomial ):
00062             polynomial( polynomial )
00063         {}
00064 
00070         bool operator ()( const symbol& a, const symbol& b ) const
00071         {
00072             return polynomial.tdegree( a ) >= polynomial.tdegree( b );
00073         }
00074     };
00075 
00076     class MultivariatePolynomialFactory
00077     {
00078         private:
00079 
00080         public:
00081 
00083             // MultivariatePolynomial //
00085 
00090             template<class monomialOrdering>
00091             static void checkForSpecialGroebnerBasis( const list<MultivariatePolynomial<monomialOrdering> >& basis ) throw ( invalid_argument )
00092             {
00093                 if( basis.size() <= 0 )
00094                     throw invalid_argument( "MultivariatePolynomial::monomialsUnderTheStaircase: Given Groebner basis is empty." );
00095 
00096                 typename list<MultivariatePolynomial<monomialOrdering> >::const_iterator i         = basis.begin();
00097                 vector<symbol>                                                           variables = i->Variables();
00098                 // first iteration: gather degrees and check local properties
00099                 list<int> degrees = list<int>();
00100                 int       d       = 0;
00101 
00102                 for( ; i != basis.end(); ++i )
00103                 {
00104                     if( variables.size() != i->Variables().size() )
00105                         throw invalid_argument( "MultivariatePolynomial::checkForSpecialGroebnerBasis: Not all elements of the given special Groebner basis have the same number of variables." );
00106 
00107                     MultivariateTerm<monomialOrdering> t = MultivariateTerm<monomialOrdering>( *i );
00108                     d = t.tdegree();
00109 
00110                     if( d <= (*i - t).tdegree() )
00111                         throw invalid_argument( "MultivariatePolynomial::checkForSpecialGroebnerBasis: Not all leading monomials of the given special Groebner basis have a greater total degree than the remainders." );
00112 
00113                     degrees.push_back( d );
00114                 }
00115 
00116                 if( variables.size() != degrees.size() )
00117                     throw invalid_argument( "MultivariatePolynomial::checkForSpecialGroebnerBasis: There are not as many elements of the given special Groebner basis the number of variables." );
00118 
00119                 // second iteration: check global properties involving all degrees
00120                 i = basis.begin();
00121 
00122                 for( ; i != basis.end(); ++i )
00123                 {
00124                     MultivariatePolynomial<monomialOrdering> r = *i - MultivariateMonomial<monomialOrdering>( *i );
00125                     list<int>::const_iterator                j = degrees.begin();
00126                     d = *j;    // previous degree
00127                     ++j;
00128 
00129                     for( ; j != degrees.end(); ++j )
00130                     {
00131                         if( d < *j )
00132                             throw invalid_argument( "MultivariatePolynomial::checkForSpecialGroebnerBasis: Given special Groebner basis does not have decreasing degrees of its leading monomials." );
00133                     }
00134 
00135                     j = degrees.begin();
00136 
00137                     for( vector<symbol>::const_iterator v = variables.begin(); v != variables.end(); ++v )
00138                     {
00139                         if( *v != i->Variable() )
00140                         {
00141                             if( i->degree( *v ) >= *j )
00142                                 throw invalid_argument( "MultivariatePolynomial::checkForSpecialGroebnerBasis: Not all leading terms have a greater degree than all remainders." );
00143                         }
00144 
00145                         ++j;
00146                     }
00147                 }
00148             }
00149 
00157             template<class monomialOrdering>
00158             static const MultivariatePolynomial<monomialOrdering> generalPositionTemplate( const vector<symbol>& variables,
00159                                                                                            unsigned degree,
00160                                                                                            numeric index )
00161             {
00162                 list<symbol> l = sortVariables( variables );
00163                 ex p = numeric( 1 );
00164 
00165                 for( vector<symbol>::const_iterator i = l.begin(); i != l.end(); ++i )
00166                 {
00167                     p     += index * pow( *i, degree );
00168                     index *= index;    // index^(i+1)
00169                 }
00170 
00171                 return MultivariatePolynomial<monomialOrdering>( p, l );    // , pow(*l.begin(), degree)
00172             }
00173 
00182             template<class monomialOrdering>
00183             static const MultivariatePolynomial<monomialOrdering> deformation( const MultivariatePolynomial<monomialOrdering>& polynomial,
00184                                                                                const list<int>& degrees,
00185                                                                                const ex& radius,
00186                                                                                const infinitesimal_symbol& infinitesimal )
00187                     throw ( invalid_argument )
00188             {
00189                 const vector<symbol> variables = polynomial.Variables();
00190                 // construct deformation polynomial
00191                 list<int>::const_iterator      degree   = degrees.begin();
00192                 vector<symbol>::const_iterator variable = variables.begin();
00193                 ex                             newPolynomial;
00194 
00195                 for( ; degree != degrees.end(); ++degree, ++variable )
00196                     newPolynomial += pow( *variable, *degree );
00197 
00198                 variable = variables.begin();
00199                 ++variable;
00200 
00201                 for( ; variable != variables.end(); ++variable )
00202                     newPolynomial += pow( *variable, 2 );
00203 
00204                 newPolynomial *= radius;
00205                 newPolynomial -= numeric( 2 * variables.size() - 1 );
00206                 return MultivariatePolynomial<monomialOrdering>( infinitesimal * newPolynomial
00207                                                                  + (1 - infinitesimal) * static_cast<ex>(polynomial), variables );
00208             }
00209 
00219             template<class monomialOrdering>
00220             static const list<MultivariatePolynomial<monomialOrdering> > specialGroebnerBasis(
00221                     const MultivariatePolynomial<monomialOrdering>& polynomial,
00222                     list<int> degrees,
00223                     const ex& radius,
00224                     const infinitesimal_symbol& infinitesimal )
00225                     throw ( invalid_argument )
00226             {
00227                 MultivariatePolynomial<monomialOrdering> deformation = MultivariatePolynomialFactory::deformation<monomialOrdering>( polynomial,
00228                                                                                                                                      degrees, radius,
00229                                                                                                                                      infinitesimal );
00230                 list<symbol> variables = list<symbol>( polynomial.Variables() );    // Note: variables->size() == degrees.size()
00231                 int          k         = degrees.size();
00232                 // fill the list deformationDiffs with the partial derivatives of deformation w.r.t. all variables except the first
00233                 lst deformationDiffs = lst();
00234                 vector<symbol>::const_iterator v = variables.erase( variables.begin() );    // first symbol not needed
00235 
00236                 for( ; v != variables.end(); ++v )
00237                     deformationDiffs.append( deformation.diff( v ));
00238 
00239                 //
00240                 // Compute first deformation (w.r.t. first variable) as a deformation enriched by an appropriately large coefficient
00241                 // and reduced modulo each partial derivative of the other deformations.
00242                 //     Note:
00243                 // * the degree sequence should be descending but the last value should be larger than 2 because this polynomial whould
00244                 //   then be derived to a linear polynomial which is not wanted
00245                 // * The reduction is performed in order to remove the higher-degree terms in other variables of the first deformation
00246                 //   polynomial. This requires a reduction modulo each deformation derivative and w.r.t. their respective leading monomials.
00247 
00248                 // compute coefficient
00249                 numeric n     = 2 * numeric( degrees.size() ) - 3;
00250                 lst degreesEx = lst();
00251                 list<int>::const_iterator d = degrees.begin();
00252 
00253                 for( ; d != degrees.end(); ++d )
00254                     degreesEx.append( *d );
00255 
00256                 ex firstDegree = *degreesEx.begin();
00257                 degreesEx.remove_first();
00258                 deformation *= pow( prod( degreesEx ), 2 ) * pow( infinitesimal, n ) * pow( radius, n * firstDegree );    // reuse deformation as the first element of the Groebner basis
00259                 MultivariatePolynomial<monomialOrdering> firstDeformation = MultivariatePolynomial<monomialOrdering>( deformation,
00260                                                                                                                       polynomial.Variables() );
00261                 // compute reductions
00262                 v = variables.begin();
00263                 d = degrees.erase( degrees.begin() );
00264                 lst::const_iterator def = deformationDiffs.begin();
00265 
00266                 for( ; def != deformationDiffs.end(); ++def )
00267                 {
00268                     ex m = pow( *v, *d );
00269                     MultivariatePolynomial<monomialOrdering> g( *def, polynomial.Variables() );
00270                     firstDeformation = firstDeformation.reduction( g, m );    // omitted (cf. p. 491 in ISBN 0-387-94090-1 and ISBN-13: 978-3642069642): .reduction(g, m);
00271                     ++v;
00272                     ++d;
00273                 }
00274 
00275                 // fill the final output list
00276                 list<MultivariatePolynomial<monomialOrdering> > basis = list<MultivariatePolynomial<monomialOrdering> >();
00277                 basis.push_back( firstDeformation );
00278 
00279                 for( lst::const_iterator def = deformationDiffs.begin(); def != deformationDiffs.end(); ++def )
00280                     basis.push_back( MultivariatePolynomial<monomialOrdering>( *def, polynomial.Variables() ));
00281 
00282                 return basis;
00283             }
00284 
00289             template<class monomialOrdering>
00290             static const list<int> synthesizeSpecialGroebnerBasisDegrees( const MultivariatePolynomial<monomialOrdering>& polynomial )
00291             {
00292                 list<int>      degrees   = list<int>();
00293                 vector<symbol> variables = vector<symbol>( polynomial.Variables() );    // Note: variables->size() == degrees.size()
00294                 variables.sort( symbol_is_greatereq_tdegree<monomialOrdering>( polynomial ));    // sort ascendingly by degree (=> first variable corresponds to max. total degree)
00295 
00296                 for( vector<symbol>::const_iterator v = variables.begin(); v != variables.end(); ++v )
00297                 {
00298                     int d = max( polynomial.tdegree( *v ), 3 );    // do not go below a degree value of 4 (next even of 3) because these terms should be seperated from the squares in the deformation polynomial
00299                     degrees.push_back( d % 2 == 0 ? d + 2 : d + 1 );    // next even number strictly greater than d
00300                 }
00301 
00302                 return degrees;
00303             }
00304 
00314             template<class monomialOrdering>
00315             static const list<MultivariatePolynomial<monomialOrdering> > synthesizeSpecialGroebnerBasis(
00316                     const MultivariatePolynomial<monomialOrdering>& polynomial,
00317                     const ex& radius,
00318                     const infinitesimal_symbol& infinitesimal )
00319                     throw ( invalid_argument )
00320             {
00321                 return specialGroebnerBasis( polynomial, synthesizeSpecialGroebnerBasisDegrees( polynomial ), radius, infinitesimal );
00322             }
00323 
00325             // MultivariateMonomial //
00327 
00332             template<class monomialOrdering>
00333             static const list<MultivariateMonomial<monomialOrdering> > cornersOfTheStaircase(
00334                     const list<MultivariatePolynomial<monomialOrdering> >& gb )
00335                     throw ( invalid_argument )
00336             {
00337                 if( gb.size() <= 0 )
00338                     throw invalid_argument( "cornersOfTheStaircase: Given Groebner basis is empty." );
00339 
00340                 list<MultivariateMonomial<monomialOrdering> > lmons = list<MultivariateMonomial<monomialOrdering> >();
00341 
00342                 for( typename list<MultivariatePolynomial<monomialOrdering> >::const_iterator i = gb.begin(); i != gb.end(); ++i )
00343                     lmons.push_back( MultivariateMonomial<monomialOrdering>( *i ));    // constructs MultivariateMonomial directly from MultivariateMonomial.Lmon
00344 
00345                 return lmons;
00346             }
00347 
00352             template<class monomialOrdering>
00353             static const list<MultivariateMonomial<monomialOrdering> > monomialsUnderTheStaircase(
00354                     const list<MultivariatePolynomial<monomialOrdering> >& gb )
00355                     throw ( invalid_argument )
00356             {
00357                 if( gb.size() <= 0 )
00358                     throw invalid_argument( "MultivariateMonomial::monomialsUnderTheStaircase: Given Groebner basis is empty." );
00359 
00360                 // collect the degrees and corresponding main symbols for each main variable
00361                 list<int>    degrees = list<int>();
00362                 list<symbol> vars    = vector<symbol>();
00363 
00364                 for( typename list<MultivariatePolynomial<monomialOrdering> >::const_iterator i = gb.begin(); i != gb.end(); ++i )
00365                 {
00366                     vars.push_back( i->Variable() );
00367                     degrees.push_back( i->lmon().degree( i->Variable() ));
00368                 }
00369 
00370 #ifdef GINACRA_MULTIVARIATEMONOMIAL_CHECK_SPECIALGROEBNERBASIS
00371                 // check input to avoid non-termination (in case of non-zero-dimensional system)
00372                 MultivariatePolynomialFactory::checkForSpecialGroebnerBasis<monomialOrdering>( gb );
00373 #endif
00374                 // construct monomials under the staircase
00375                 list<MultivariateMonomial<monomialOrdering> > monomials = list<MultivariateMonomial<monomialOrdering> >();
00376                 monomials.push_back( MultivariateMonomial<monomialOrdering>( ex( 1 ), vars ));
00377                 list<int>::const_iterator degree = degrees.begin();
00378 
00379                 for( vector<symbol>::const_iterator var = vars.begin(); var != vars.end(); ++var )
00380                 {
00381 #ifdef GINACRA_MULTIVARIATEMONOMIAL_DEBUG
00382                     cout << "MultivariateMonomial::monomialsUnderTheStaircase: (" << *var << ", " << *degree << ")" << endl;
00383 #endif
00384                     searchMonomialsUnderTheStaircase( var, vars.end(), degree, MultivariateMonomial<monomialOrdering>( ex( 1 ), vars ), monomials );
00385                     ++degree;
00386                 }
00387 
00388                 return monomials;
00389             }
00390 
00397             template<class monomialOrdering>
00398             static const list<MultivariateTerm<monomialOrdering> > termsUnderTheStaircase(
00399                     const list<MultivariateMonomial<monomialOrdering> >& monomials,
00400                     const list<MultivariatePolynomial<monomialOrdering> >& gb,
00401                     ex& coeff = *(new ex( 1 )))
00402                     throw ( invalid_argument )
00403             {
00404                 if( monomials.size() <= 0 || gb.size() <= 0 )
00405                     throw invalid_argument( "termsUnderTheStaircase: Given list of monomials under the staircase or the given special Groebner basis is empty." );
00406 
00407                 list<MultivariateTerm<monomialOrdering> > terms = list<MultivariateTerm<monomialOrdering> >();
00408                 // fetch common leading coefficient of the given basis
00409                 coeff = coefficientLcm( gb );
00410 
00411                 // multiply appropriate powers of common coefficient to the monomials under the staircase
00412                 for( typename list<MultivariateMonomial<monomialOrdering> >::const_iterator i = monomials.begin(); i != monomials.end(); ++i )
00413                     terms.push_back( MultivariateTerm<monomialOrdering>( pow( coeff, i->tdegree() ) * static_cast<ex>(*i), i->Variables() ));    // since *i is a monomial, tdegree should determine the sum of exponents contained in *i
00414 
00415                 return terms;
00416             }
00417 
00422             template<class monomialOrdering>
00423             static const list<MultivariateMonomial<monomialOrdering> > borderOfTheStaircase(
00424                     const list<MultivariateMonomial<monomialOrdering> >& corners )
00425                     throw ( invalid_argument )
00426             {
00427                 if( corners.size() <= 0 )
00428                     throw invalid_argument( "borderOfTheStaircase: Given list of corners of the staircase is empty." );
00429 
00430                 list<MultivariateMonomial<monomialOrdering> > monomials = list<MultivariateMonomial<monomialOrdering> >();
00431 
00432                 for( typename list<MultivariateMonomial<monomialOrdering> >::const_iterator corners_current = corners.begin();
00433                         corners_current != corners.end(); ++corners_current )
00434                     searchBorderOfTheStaircase( corners_current, corners.begin(), corners.end(), *corners_current, monomials );
00435 
00436                 return monomials;
00437             }
00438 
00444             template<class monomialOrdering>
00445             static const list<MultivariateTerm<monomialOrdering> > borderTermsOfTheStaircase(
00446                     const list<MultivariateMonomial<monomialOrdering> >& border,
00447                     const list<MultivariatePolynomial<monomialOrdering> >& gb )
00448                     throw ( invalid_argument )
00449             {
00450                 if( border.size() <= 0 || gb.size() <= 0 )
00451                     throw invalid_argument( "borderTermsOfTheStaircase: Given border of the staircase or the given special Groebner basis is empty." );
00452 
00453                 list<MultivariateTerm<monomialOrdering> > terms = list<MultivariateTerm<monomialOrdering> >();
00454                 // fetch common leading coefficient of the given basis
00455                 const ex coeff = coefficientLcm( gb );
00456 
00457                 // multiply appropriate powers of common coefficient to the monomials under the staircase
00458                 for( typename list<MultivariateMonomial<monomialOrdering> >::const_iterator i = border.begin(); i != border.end(); ++i )
00459                     terms.push_back( MultivariateTerm<monomialOrdering>( pow( coeff, i->tdegree() ) * static_cast<ex>(*i), i->Variables() ));    // since *i is a monomial, tdegree should determine the sum of exponents contained in *i
00460 
00461                 return terms;
00462             }
00463 
00464             // Auxiliary methods
00465 
00470             template<class monomialOrdering>
00471             static MultivariatePolynomial<monomialOrdering> coefficientLcm( const list<MultivariatePolynomial<monomialOrdering> >& gb )
00472             {
00473                 lst lcoeffs = lst();
00474                 for( typename list<MultivariatePolynomial<monomialOrdering> >::const_iterator i = gb.begin(); i != gb.end(); ++i )
00475                     lcoeffs.append( i->lcoeff() );
00476                 return MultivariatePolynomial<monomialOrdering>( lcm( lcoeffs ), gb.front().Variables() );
00477             }
00478 
00487             template<class monomialOrdering>
00488             static void searchMonomialsUnderTheStaircase( vector<symbol>::const_iterator variables_current,
00489                                                           const vector<symbol>::const_iterator& variables_end,
00490                                                           list<int>::const_iterator degrees_current,
00491                                                           const MultivariateMonomial<monomialOrdering>& monomial,
00492                                                           list<MultivariateMonomial<monomialOrdering> >& monomials )
00493                     throw ( invalid_argument )
00494             {
00495 #ifdef GINACRA_MULTIVARIATEMONOMIAL_DEBUG
00496                 cout << "MultivariateMonomial::searchMonomialsUnderTheStaircase: degree " << *degrees_current << " symbol " << *variables_current
00497                      << endl;
00498 #endif
00499 
00500                 // terminate in case no new symbol is available for multiplication
00501                 if( variables_current == variables_end )
00502                     return;
00503 
00504                 // multiply with current variable
00505                 const MultivariateMonomial<monomialOrdering> m = monomial.mul( MultivariateMonomial<monomialOrdering>( *variables_current,
00506                                                                                                                        monomial.Variables() ));
00507 
00508                 // terminate in case the degree bound for this variable is met
00509                 if( m.degree( ex_to<symbol>( *variables_current )) >= *degrees_current )
00510                     return;
00511 
00512                 // add new monomial
00513                 monomials.push_back( m );
00514 
00515                 // try to multiply the next variables to the monomial
00516                 for( ; variables_current != variables_end; ++variables_current, ++degrees_current )
00517                     searchMonomialsUnderTheStaircase( variables_current, variables_end, degrees_current, m, monomials );
00518             }
00519 
00528             template<class monomialOrdering>
00529             static void searchBorderOfTheStaircase( typename list<MultivariateMonomial<monomialOrdering> >::const_iterator corners_current,
00530                                                     const typename list<MultivariateMonomial<monomialOrdering> >::const_iterator& corners_begin,
00531                                                     const typename list<MultivariateMonomial<monomialOrdering> >::const_iterator& corners_end,
00532                                                     const MultivariateMonomial<monomialOrdering>& monomial,
00533                                                     list<MultivariateMonomial<monomialOrdering> >& monomials )
00534                     throw ( invalid_argument )
00535             {
00536                 // append current products of corners
00537                 monomials.push_back( monomial );
00538                 // append all missing combinations of the current monomial (i.e. corner product) multiplied with other variables
00539                 list<symbol> variables = vector<symbol>();
00540                 list<int>    degrees   = list<int>();
00541 
00542                 for( typename list<MultivariateMonomial<monomialOrdering> >::const_iterator c = corners_begin; c != corners_end; ++c )
00543                 {
00544                     if( monomial != *c )
00545                     {
00546                         // corner is current monomial
00547                         const_iterator p = monomial.begin();
00548 
00549                         for( ; p != monomial.end(); ++p )
00550                         {
00551                             if( *p == *c )    // corner occurs in current monomial
00552                                 break;
00553                         }
00554 
00555                         if( p == monomial.end() )
00556                         {
00557                             // corner does not occur in current monomial, so add corresponding variable and max. degree
00558                             variables.push_back( c->Variable() );
00559                             degrees.push_back( c->degree() );
00560                         }
00561                     }
00562                 }
00563 
00564                 list<int>::const_iterator deg = degrees.begin();
00565 
00566                 for( vector<symbol>::const_iterator var = variables.begin(); var != variables.end(); ++deg, ++var )
00567                     searchMonomialsUnderTheStaircase( var, variables.end(), deg, monomial, monomials );
00568 
00569                 // proceed with the next corner combinations
00570                 while( true )
00571                 {
00572                     ++corners_current;    // choose next corner
00573 
00574                     if( corners_current == corners_end )
00575                         return;
00576 
00577                     searchBorderOfTheStaircase( corners_current, corners_begin, corners_end, monomial.mul( *corners_current ), monomials );
00578                 }
00579             }
00580 
00581     };
00582     // class MultivariatePolynomialFactory
00583 
00584 }    // namespace GiNaC
00585 
00586 #endif // GINACRA_MULTIVARIATEPOLYNOMIALFACTORY_H