GiNaCRA
0.6.4
|
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