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