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_UNIVARIATERATIONALPOLYNOMIAL_DEBUG 00024 00034 #include <assert.h> 00035 00036 #include "utilities.h" 00037 #include "RationalUnivariatePolynomial.h" 00038 #include "operators.h" 00039 00040 using GiNaC::is_exactly_a; 00041 00042 namespace GiNaCRA 00043 { 00045 // Con- and destructors // 00047 00048 RationalUnivariatePolynomial::RationalUnivariatePolynomial( const UnivariatePolynomial& p ) throw ( invalid_argument ): 00049 UnivariatePolynomial( p ) 00050 { 00051 if( !GiNaC::is_rational_polynomial( p, p.variable() )) 00052 { 00053 stringstream stream; 00054 stream << "The specified univariate polynomial " << *this << " is not rational in " << p.variable() << "."; 00055 throw invalid_argument( stream.str() ); 00056 } 00057 // setflag(status_flags::expanded | info_flags::rational_polynomial); 00058 } 00059 00060 RationalUnivariatePolynomial::RationalUnivariatePolynomial( const ex& p, const symbol& s ) throw ( invalid_argument ): 00061 UnivariatePolynomial( p, s ) 00062 { 00063 if( !GiNaC::is_rational_polynomial( *this, s )) // need to take *this for the check because *this is expanded already 00064 { 00065 stringstream stream; 00066 stream << "The specified expression " << *this << " is not rational in " << s << "."; 00067 throw invalid_argument( stream.str() ); 00068 } 00069 // setflag(status_flags::expanded | info_flags::rational_polynomial); 00070 } 00071 00073 // Operators // 00075 00076 // const RationalUnivariatePolynomial RationalUnivariatePolynomial::operator*(const RationalUnivariatePolynomial& o) 00077 // { 00078 // return RationalUnivariatePolynomial(*this * o, mVariable); 00079 // } 00080 00082 // Operations // 00084 00085 GiNaC::sign RationalUnivariatePolynomial::sgn( const numeric& a ) const 00086 { 00087 numeric p_a = ex_to<numeric>( evaluateAt( a )); // safe because of the constructor 00088 if( p_a < 0 ) 00089 return GiNaC::NEGATIVE_SIGN; 00090 if( p_a > 0 ) 00091 return GiNaC::POSITIVE_SIGN; 00092 return GiNaC::ZERO_SIGN; 00093 } 00094 00095 numeric RationalUnivariatePolynomial::evaluateAt( const numeric& a ) const 00096 { 00097 // use Horner's method for polynomial evaluation 00098 numeric result = 0; 00099 for( int d = this->degree(); d >= 0; --d ) 00100 result = this->coeff( d ) + result * a; 00101 return result; 00102 } 00103 00104 numeric RationalUnivariatePolynomial::oneNorm() const 00105 { 00106 // compute the sum of the absolute values of the numeric coefficients 00107 numeric sum = 0; 00108 for( int i = UnivariatePolynomial::ldegree(); i <= UnivariatePolynomial::degree(); i++ ) 00109 sum += abs( coeff( i )); 00110 return sum; 00111 } 00112 00113 numeric RationalUnivariatePolynomial::twoNorm() const 00114 { 00115 // compute the sum of the squares of the absolute values of the numeric coefficients 00116 numeric sum = 0; 00117 for( int i = ldegree(); i <= degree(); i++ ) 00118 sum += ex_to<numeric>( pow( coeff( i ), 2 )); 00119 return GiNaC::sqrt( sum ); 00120 } 00121 00122 numeric RationalUnivariatePolynomial::maximumNorm() const 00123 { 00124 // compute the maximum of the absolute values of the numeric coefficients 00125 numeric max = 0; 00126 for( int i = ldegree(); i <= degree(); i++ ) 00127 { 00128 ex c = abs( ex_to<numeric>( coeff( i ))); 00129 if( c > max ) 00130 max = ex_to<numeric>( c ); 00131 } 00132 return max; 00133 } 00134 00135 numeric RationalUnivariatePolynomial::cauchyBound() const 00136 { 00137 numeric lcf = abs( UnivariatePolynomial::lcoeff() ); // we have to perform the conversion of coefficients because it is not clear whether we have a numeric or a RealAlgebraicNumberIR 00138 if( lcf == 0 ) 00139 return 0; 00140 numeric sum = 0; 00141 for( int i = UnivariatePolynomial::ldegree(); i <= UnivariatePolynomial::degree(); ++i ) 00142 sum += abs( UnivariatePolynomial::coeff( i )) / lcf; 00143 return sum; 00144 } 00145 00146 unsigned RationalUnivariatePolynomial::countRealRoots() const 00147 { 00148 list<RationalUnivariatePolynomial> seq = standardSturmSequence( *this, this->diff() ); 00149 numeric c = this->cauchyBound(); 00150 OpenInterval i( -c, c ); 00151 return signVariations( seq, i.left() ) - signVariations( seq, i.right() ); 00152 } 00153 00154 numeric RationalUnivariatePolynomial::approximateRealRoot( const numeric start, const OpenInterval& i, unsigned steps ) const 00155 { 00156 numeric pivot = start; 00157 RationalUnivariatePolynomial p = this->diff(); 00158 while( this->sgn( pivot ) != GiNaC::ZERO_SIGN ) 00159 { 00160 pivot = pivot - this->evaluateAt( pivot ) / p.evaluateAt( pivot ); 00161 if( steps == 0 ||!i.contains( pivot )) // failed 00162 return start; 00163 --steps; 00164 } 00165 // success 00166 return pivot; 00167 } 00168 00170 // Static Methods // 00172 00173 list<RationalUnivariatePolynomial> RationalUnivariatePolynomial::standardSturmSequence( const RationalUnivariatePolynomial& a, 00174 const RationalUnivariatePolynomial& b ) 00175 { 00176 list<UnivariatePolynomial> seqUnivariate = UnivariatePolynomial::standardSturmSequence( a, b ); 00177 list<RationalUnivariatePolynomial> seq = list<RationalUnivariatePolynomial>(); // Sturm sequence to compute 00178 for( list<UnivariatePolynomial>::const_iterator i = seqUnivariate.begin(); i != seqUnivariate.end(); ++i ) 00179 seq.push_back( RationalUnivariatePolynomial( *i )); 00180 return seq; 00181 } 00182 00183 unsigned RationalUnivariatePolynomial::signVariations( const list<RationalUnivariatePolynomial>& seq, const numeric& a ) 00184 { 00185 bool sign = seq.front().sgn( a ) >= GiNaC::ZERO_SIGN ? true : false; // only positive (incl. zero) [1] and negative values [0] count 00186 unsigned count = 0; 00187 for( list<RationalUnivariatePolynomial>::const_iterator iter = seq.begin(); iter != seq.end(); ++iter ) 00188 { 00189 if( sign xor( iter->sgn( a ) >= GiNaC::ZERO_SIGN )) 00190 { 00191 ++count; 00192 sign = !sign; 00193 } 00194 } 00195 return count; 00196 } 00197 00198 int RationalUnivariatePolynomial::calculateSturmCauchyIndex( const RationalUnivariatePolynomial& p, const RationalUnivariatePolynomial& q ) 00199 { 00200 if( p.is_zero() ) 00201 throw invalid_argument( "Can not compute the Cauchy index of a zero polynomial." ); 00202 const list<RationalUnivariatePolynomial> SRemS = RationalUnivariatePolynomial::standardSturmSequence( p, q ); 00203 const numeric upperBound = p.cauchyBound(); 00204 assert( upperBound > 0 ); 00205 00206 //TODO make it faster by only iterating once. This needs an own method to calculate signVariations with two numeric parameters. 00207 return (((int)RationalUnivariatePolynomial::signVariations( SRemS, -upperBound )) 00208 - ((int)RationalUnivariatePolynomial::signVariations( SRemS, upperBound ))); 00209 } 00210 00211 int RationalUnivariatePolynomial::calculateRemainderTarskiQuery( const RationalUnivariatePolynomial& p, const RationalUnivariatePolynomial& q ) 00212 { 00213 return RationalUnivariatePolynomial::calculateSturmCauchyIndex( p, (RationalUnivariatePolynomial)p.diff() * q ); 00214 } 00215 00216 // 00217 // std::list<int> RationalUnivariatePolynomial::signDeterminationHelperRows(std::list<std::vector<Sign> > signs) { 00218 // list<int> L1, L2, L3; 00219 // unsigned n = signs.first.size(); 00220 // 00221 // } 00222 // 00223 // std::list<std::vector<Sign> > RationalUnivariatePolynomial::calculateSignDetermination(const RationalUnivariatePolynomial& z, const std::vector<RationalUnivariatePolynomial>& polynomials) { 00224 // int tq = calculateRemainderTarskiQuery(RationalUnivariatePolynomial(1,z.Variable()),z); 00225 // int nrRoots = std::abs(tq); 00226 // set<std::vector<Sign> > realizedSignConditions; 00227 // 00228 // //return the empty set, since there are no roots. 00229 // if (nrRoots == 0) return realizedSignConditions; 00230 // 00231 // 00232 // RationalUnivariatePolynomial polynomialsSquared; 00233 // //We iterate backwards. Not sure why, but we are following the description from the book here. 00234 // //TODO explain why we do not iterate forward. 00235 // for(int i = polynomials.size(); i >= 0; i-- ) { 00236 // polynomialSquared = polynomials[i].square() 00237 // int tqp = calculateRemainderTarskiQuery(polynomials[i],z); 00238 // int tqpp = calculateRemainderTarskiQuery(polynomialSquared, z); 00239 // assert((tqp+tqpp)%2 == 0); // otherwise next division is inaccurate! 00240 // 00241 // //Calculate the numbers using equality 10.13 from page 384. 00242 // //Explicitly calculated in Proposition 2.65 from page 64. 00243 // int nrPositives = (tqp + tqpp)/2 00244 // int nrNegatives = (tqpp - tqp)/2; 00245 // int nrZeroes = tq - tqpp; 00246 // 00247 // //Count how many different signs. 00248 // int differentsigns = 0; 00249 // //If differentsigns becomes two, we would like to know which wasnt there. 00250 // Sign nonexistant; 00251 // if (nrPositives > 0) { 00252 // differentsigns++; 00253 // nonexistant = POSITIVESIGN; 00254 // } 00255 // if (nrNegatives > 0) { 00256 // differentsigns++; 00257 // nonexistant = NEGATIVESIGN; 00258 // } 00259 // if (nrZeroes > 0) { 00260 // differentsigns++; 00261 // nonexistant = ZEROSIGN; 00262 // } 00263 // // The signs can be -, 0, +, so no more than 3, and at least one of them has to be there, since z has roots. 00264 // assert(differentsigns <= 3 && differentsigns > 1); 00265 // 00266 // //We are using matrix-tensorproducts, so we have to represent this as a matrix. 00267 // //TODO implement another method which computes the elements directly and compare their speed. 00268 // matrix m(2,2); 00269 // //TODO check the order, perhaps another order is faster? 00270 // if(differentsigns == 2) { 00271 // if(nonexistant == ZEROSIGN) { 00272 // m = 1, 1, 00273 // 1, -1; 00274 // } else if (nonexistant == POSITIVESIGN) { 00275 // m = 1, 1, 00276 // 0, -1; 00277 // } else { 00278 // m = 1, 1, 00279 // 0, 1; 00280 // } 00281 // } else if(differentsigns == 3) { 00282 // m = matrix(3,3); 00283 // m = 1, 1, 1, 00284 // 0, 1, -1, 00285 // 0, 1, 1; 00286 // } else { 00287 // m = matrix(1,1); 00288 // m = 1; 00289 // } 00290 // 00291 // // In the first step, we do not have to do more. 00292 // if(i == polynomials.size()) { 00293 // 00294 // continue; 00295 // } 00296 // 00297 // //In the next step we want to solve mx = b. 00298 // matrix b; 00299 // matrix x; 00300 // } 00301 // } 00302 00303 } // namespace GiNaC 00304