BWAPI
|
00001 /**************************************************************************** 00002 * Core Library Version 1.7, August 2004 00003 * Copyright (c) 1995-2004 Exact Computation Project 00004 * All rights reserved. 00005 * 00006 * This file is part of CORE (http://cs.nyu.edu/exact/core/); you may 00007 * redistribute it under the terms of the Q Public License version 1.0. 00008 * See the file LICENSE.QPL distributed with CORE. 00009 * 00010 * Licensees holding a valid commercial license may use this file in 00011 * accordance with the commercial license agreement provided with the 00012 * software. 00013 * 00014 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 00015 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 00016 * 00017 * 00018 * File: Sturm.h 00019 * 00020 * Description: 00021 * The templated class Sturm implements Sturm sequences. 00022 * Basic capabilities include: 00023 * counting number of roots in an interval, 00024 * isolating all roots in an interval 00025 * isolating the i-th largest (or smallest) root in interval 00026 * It is based on the Polynomial class. 00027 * 00028 * BigFloat intervals are used for this (new) version. 00029 * It is very important that the BigFloats used in these intervals 00030 * have no error at the beginning, and this is maintained 00031 * by refinement. Note that if x, y are error-free BigFloats, 00032 * then (x+y)/2 may not be error-free (in current implementaion. 00033 * We have to call a special "exact divide by 2" method, 00034 * (x+y).div2() for this purpose. 00035 * 00036 * CONVENTION: an interval defined by a pair of BigFloats x, y 00037 * has this interpretation: 00038 * (1) if x>y, it represents an invalid interval. 00039 * (2) if x=y, it represents a unique point x. 00040 * (3) if x<y, it represents the open interval (x,y). 00041 * In this case, we always may sure that x, y are not zeros. 00042 * 00043 * TODO LIST and Potential Bugs: 00044 * (1) Split an isolating interval to give definite sign (done) 00045 * (2) Should have a test for square-free polynomials (done) 00046 * 00047 * Author: Chee Yap and Sylvain Pion, Vikram Sharma 00048 * Date: July 20, 2002 00049 * 00050 * WWW URL: http://cs.nyu.edu/exact/ 00051 * Email: exact@cs.nyu.edu 00052 * 00053 * $URL: svn+ssh://scm.gforge.inria.fr/svn/cgal/branches/CGAL-3.5-branch/Core/include/CGAL/CORE/poly/Sturm.h $ 00054 * $Id: Sturm.h 43611 2008-06-15 16:21:29Z spion $ 00055 ***************************************************************************/ 00056 00057 00058 #ifndef CORE_STURM_H 00059 #define CORE_STURM_H 00060 00061 #include "CGAL/CORE/BigFloat.h" 00062 #include "CGAL/CORE/Expr.h" 00063 #include "CGAL/CORE/poly/Poly.h" 00064 00065 CORE_BEGIN_NAMESPACE 00066 00067 // ================================================== 00068 // Sturm Class 00069 // ================================================== 00070 00071 template < class NT > 00072 class Sturm { 00073 public: 00074 int len; // len is 1 less than the number of non-zero entries in array seq. 00075 // I.e., len + 1 = length of the Sturm Sequence 00076 // N.B. When len = -1 or len = 0 are special, 00077 // the array seq is not used! 00078 // Hence, one must test these special cases 00079 Polynomial<NT> * seq; // array of polynomials of length "len+1" 00080 Polynomial<NT> g;//GCD of input polynomial P and it's derivative P' 00081 NT cont;//Content of the square-free part of input polynomial P 00082 //Thus P = g * cont * seq[0] 00083 static int N_STOP_ITER; // Stop IterE after this many iterations. This 00084 // is initialized below, outside the Newton class 00085 bool NEWTON_DIV_BY_ZERO; // This is set to true when there is divide by 00086 // zero in Newton iteration (at critical value) 00087 // User is responsible to check this and to reset. 00088 typedef Polynomial<NT> PolyNT; 00089 00090 // =============================================================== 00091 // CONSTRUCTORS 00092 // =============================================================== 00093 // Null Constructor 00094 Sturm() : len(0), NEWTON_DIV_BY_ZERO(false) {} 00095 00096 // Constructor from a polynomial 00097 Sturm(Polynomial<NT> pp) : NEWTON_DIV_BY_ZERO(false) { 00098 len = pp.getTrueDegree(); 00099 if (len <= 0) return; // hence, seq is not defined in these cases 00100 seq = new Polynomial<NT> [len+1]; 00101 seq[0] = pp; 00102 g = seq[0].sqFreePart(); 00103 cont = content(seq[0]); 00104 seq[0].primPart(); 00105 seq[1] = differentiate(seq[0]); 00106 int i; 00107 for (i=2; i <= len; i++) { 00108 seq[i] = seq[i-2]; 00109 seq[i].negPseudoRemainder(seq[i-1]); 00110 if (zeroP(seq[i])){ 00111 len = i-1;//Since len is one less than the number of non-zero entries. 00112 break; 00113 } 00114 seq[i].primPart(); // Primitive part is important to speed 00115 // up large polynomials! However, for first 2 polymials, 00116 // we MUST NOT take primitive part, because we 00117 // want to use them in Newton Iteration 00118 } 00119 } 00120 00121 // Chee: 7/31/04 00122 // We need BigFloat version of Sturm(Polynomial<NT>pp) because 00123 // of curve verticalIntersection() ... . We also introduce 00124 // various support methods in BigFloat.h (exact_div, gcd, etc). 00125 // Constructor from a BigFloat polynomial 00126 // Need the fake argument to avoid compiler overloading errors 00127 Sturm(Polynomial<BigFloat> pp, bool fake) : NEWTON_DIV_BY_ZERO(false) { 00128 len = pp.getTrueDegree(); 00129 if (len <= 0) return; // hence, seq is not defined in these cases 00130 seq = new Polynomial<NT> [len+1]; 00131 seq[0] = pp; 00132 g = seq[0].sqFreePart(); 00133 cont = content(seq[0]); 00134 seq[0].primPart(); 00135 seq[1] = differentiate(seq[0]); 00136 int i; 00137 for (i=2; i <= len; i++) { 00138 seq[i] = seq[i-2]; 00139 seq[i].negPseudoRemainder(seq[i-1]); 00140 if (zeroP(seq[i])){ 00141 len = i-1;//Since len is one less than the number of non-zero entries. 00142 //len = i; 00143 break; 00144 } 00145 seq[i].primPart(); // Primitive part is important to speed 00146 // up large polynomials! However, for first 2 polymials, 00147 // we DO NOT take primitive part, because we 00148 // want to use them in Newton Iteration 00149 } 00150 } 00151 00152 // Constructor from an array of NT's 00153 // -- this code is identical to constructing from a polynomial... 00154 Sturm(int n, NT * c) : NEWTON_DIV_BY_ZERO(false) { 00155 Polynomial<NT> pp(n, c); // create the polynomial pp first and call the 00156 (*this) = Sturm<NT>(pp);//constructor from a polynomial 00157 } 00158 00159 // copy constructor 00160 Sturm(const Sturm&s) : len(s.len), NEWTON_DIV_BY_ZERO(s.NEWTON_DIV_BY_ZERO) { 00161 if (len <= 0) return; 00162 seq = new Polynomial<NT> [len+1]; 00163 for (int i=0; i<=len; i++) 00164 seq[i] = s.seq[i]; 00165 } 00166 00167 // assignment operator 00168 const Sturm& operator=(const Sturm& o) { 00169 if (this == &o) 00170 return *this; 00171 if (len > 0) 00172 delete[] seq; 00173 NEWTON_DIV_BY_ZERO = o.NEWTON_DIV_BY_ZERO; 00174 len = o.len; 00175 if (len > 0) { 00176 seq = new Polynomial<NT>[len+1]; 00177 for (int i=0; i<=len; i++) 00178 seq[i] = o.seq[i]; 00179 } 00180 return *this; 00181 } 00182 00183 // destructor 00184 ~Sturm() { 00185 if (len != 0) 00186 delete[] seq; 00187 } 00188 00189 // METHODS 00190 00191 // dump functions 00192 void dump(std::string msg) const { 00193 std::cerr << msg << std::endl; 00194 if (len <= 0) std::cerr << " len = " << len << std::endl; 00195 else 00196 for (int i=0; i<=len; i++) 00197 std::cerr << " seq[" << i << "] = " << seq[i] << std::endl; 00198 } 00199 void dump() const { 00200 dump(""); 00201 } 00202 00203 // signVariations(x, sx) 00204 // where sx = sign of evaluating seq[0] at x 00205 // PRE-CONDITION: sx != 0 and len > 0 00206 int signVariations(const BigFloat & x, int sx) const { 00207 assert((sx != 0) && (len >0)); 00208 int cnt = 0; 00209 int last_sign = sx; 00210 for (int i=1; i<=len; i++) {// Chee (4/29/04): Bug fix, 00211 // should start iteration at i=1, not i=0. Potential error 00212 // if seq[0].eval(x)=0 (though not in our usage). 00213 int sgn = sign(seq[i].evalExactSign(x)); 00214 if (sgn*last_sign < 0) { 00215 cnt++; 00216 last_sign *= -1; 00217 } 00218 } 00219 return cnt; 00220 } 00221 00222 // signVariations(x) 00223 // --the first polynomial eval is not yet done 00224 // --special return value of -1, indicating x is root! 00225 int signVariations(const BigFloat & x) const { 00226 if (len <= 0) return len; 00227 int signx = sign(seq[0].evalExactSign(x)); 00228 if (signx == 0) 00229 return (-1); // THIS indicates that x is a root... 00230 // REMARK: in our usage, this case does not arise 00231 return signVariations(x, signx); 00232 }//signVariations(x) 00233 00234 // signVariation at +Infinity 00235 int signVariationsAtPosInfty() const { 00236 if (len <= 0) return len; 00237 int cnt = 0; 00238 int last_sign = sign(seq[0].coeff[seq[0].getTrueDegree()]); 00239 assert(last_sign != 0); 00240 for (int i=1; i<=len; i++) { 00241 int sgn = sign(seq[i].coeff[seq[i].getTrueDegree()]); 00242 if (sgn*last_sign < 0) 00243 cnt++; 00244 if (sgn != 0) 00245 last_sign = sgn; 00246 } 00247 return cnt; 00248 } 00249 00250 // signVariation at -Infinity 00251 int signVariationsAtNegInfty() const { 00252 if (len <= 0) return len; 00253 int cnt = 0; 00254 int last_sign = sign(seq[0].coeff[seq[0].getTrueDegree()]); 00255 if (seq[0].getTrueDegree() % 2 != 0) 00256 last_sign *= -1; 00257 assert(last_sign != 0); 00258 for (int i=1; i<=len; i++) { 00259 int parity = (seq[i].getTrueDegree() % 2 == 0) ? 1 : -1; 00260 int sgn = parity * sign(seq[i].coeff[seq[i].getTrueDegree()]); 00261 if (sgn*last_sign < 0) 00262 cnt++; 00263 if (sgn != 0) 00264 last_sign = sgn; 00265 } 00266 return cnt; 00267 } 00268 00269 // numberOfRoots(x,y): 00270 // COUNT NUMBER OF ROOTS in the close interval [x,y] 00271 // IMPORTANT: Must get it right even if x, y are roots 00272 // Assert("x and y are exact") 00273 // [If the user is unsure of this assertion, do 00274 // "x.makeExact(); y.makeExact()" before calling]. 00276 int numberOfRoots(const BigFloat &x, const BigFloat &y) const { 00277 assert(x <= y); // we allow x=y 00278 if (len <= 0) return len; // return of -1 means infinity of roots! 00279 int signx = sign(seq[0].evalExactSign(x)); 00280 if (x == y) return ((signx == 0) ? 1 : 0); 00281 int signy = sign(seq[0].evalExactSign(y)); 00282 // easy case: THIS SHOULD BE THE OVERWHELMING MAJORITY 00283 00284 if (signx != 0 && signy != 0) 00285 return (signVariations(x, signx) - signVariations(y, signy)); 00286 // harder case: THIS SHOULD BE VERY INFREQUENT 00287 BigFloat sep = (seq[0].sepBound()).div2(); 00288 BigFloat newx, newy; 00289 if (signx == 0) 00290 newx = x - sep; 00291 else 00292 newx = x; 00293 if (signy == 0) 00294 newy = y + sep; 00295 else 00296 newy = y; 00297 return (signVariations(newx, sign(seq[0].evalExactSign(newx))) 00298 - signVariations(newy, sign(seq[0].evalExactSign(newy))) ); 00299 }//numberOfRoots 00300 00301 // numberOfRoots(): 00302 // Counts the number of real roots of a polynomial 00304 int numberOfRoots() const { 00305 if (len <= 0) return len; // return of -1 means infinity of roots! 00306 // BigFloat bd = seq[0].CauchyUpperBound(); 00307 // return numberOfRoots(-bd, bd); 00308 return signVariationsAtNegInfty() - signVariationsAtPosInfty(); 00309 } 00310 00311 // numberOfRoots above or equal to x: 00312 // Default value x=0 (i.e., number of positive roots) 00313 // assert(len >= 0) 00315 int numberOfRootsAbove(const BigFloat &x = 0) const { 00316 if (len <= 0) return len; // return of -1 means infinity of roots! 00317 int signx = sign(seq[0].evalExactSign(x)); 00318 if (signx != 0) 00319 return signVariations(x, signx) - signVariationsAtPosInfty(); 00320 BigFloat newx = x - (seq[0].sepBound()).div2(); 00321 return signVariations(newx, sign(seq[0].evalExactSign(newx))) 00322 - signVariationsAtPosInfty(); 00323 } 00324 00325 // numberOfRoots below or equal to x: 00326 // Default value x=0 (i.e., number of negative roots) 00327 // assert(len >= 0) 00329 int numberOfRootsBelow(const BigFloat &x = 0) const { 00330 if (len <= 0) return len; // return of -1 means infinity of roots! 00331 int signx = sign(seq[0].evalExactSign(x)); 00332 if (signx != 0) 00333 return signVariationsAtNegInfty() - signVariations(x, signx); 00334 BigFloat newx = x + (seq[0].sepBound()).div2(); 00335 return signVariationsAtNegInfty() 00336 - signVariations(newx, sign(seq[0].evalExactSign(newx))); 00337 } 00338 00339 00343 00354 void isolateRoots(const BigFloat &x, const BigFloat &y, 00355 BFVecInterval &v) const { 00356 assert(x<=y); 00357 00358 int n = numberOfRoots(x,y); 00359 if (n == 0) return; 00360 if (n == 1) { 00361 if ((x > 0) || (y < 0)) // usual case: 0 is not in interval 00362 v.push_back(std::make_pair(x, y)); 00363 else { // if 0 is inside our interval (this extra 00364 // service is not strictly necessary!) 00365 if (seq[0].coeff[0] == 0) 00366 v.push_back(std::make_pair(BigFloat(0), BigFloat(0))); 00367 else if (numberOfRoots(0,y) == 0) 00368 v.push_back(std::make_pair(x, BigFloat(0))); 00369 else 00370 v.push_back(std::make_pair(BigFloat(0), y)); 00371 } 00372 } else { // n > 1 00373 BigFloat mid = (x+y).div2(); // So mid is exact. 00374 if (sign(seq[0].evalExactSign(mid)) != 0) { // usual case: mid is non-root 00375 isolateRoots(x, mid, v); 00376 isolateRoots(mid, y, v); 00377 } else { // special case: mid is a root 00378 BigFloat tmpEps = (seq[0].sepBound()).div2(); // this is exact! 00379 if(mid-tmpEps > x )//Since otherwise there are no roots in (x,mid) 00380 isolateRoots(x, (mid-tmpEps).makeCeilExact(), v); 00381 v.push_back(std::make_pair(mid, mid)); 00382 if(mid+tmpEps < y)//Since otherwise there are no roots in (mid,y) 00383 isolateRoots((mid+tmpEps).makeFloorExact(), y, v); 00384 } 00385 } 00386 }//isolateRoots(x,y,v) 00387 00388 // isolateRoots(v) 00390 00392 void isolateRoots(BFVecInterval &v) const { 00393 if (len <= 0) { 00394 v.clear(); return; 00395 } 00396 BigFloat bd = seq[0].CauchyUpperBound(); 00397 // Note: bd is an exact BigFloat (this is important) 00398 isolateRoots(-bd, bd, v); 00399 } 00400 00401 // isolateRoot(i) 00405 BFInterval isolateRoot(int i = 0) const { 00406 if (len <= 0) 00407 return BFInterval(1,0); // ERROR CONDITION 00408 if (i == 0) 00409 return mainRoot(); 00410 BigFloat bd = seq[0].CauchyUpperBound(); 00411 return isolateRoot(i, -bd, bd); 00412 } 00413 00414 // isolateRoot(i, x, y) 00416 00419 BFInterval isolateRoot(int i, BigFloat x, BigFloat y) const { 00420 int n = numberOfRoots(x,y); 00421 if (i < 0) {//then we want the n-i+1 root 00422 i += n+1; 00423 if (i <= 0) 00424 return BFInterval(1,0); // ERROR CONDITION 00425 } 00426 if (n < i) 00427 return BFInterval(1,0); // ERROR CONDITION INDICATED 00428 //Now 0< i <= n 00429 if (n == 1) { 00430 if ((x>0) || (y<0)) return BFInterval(x, y); 00431 if (seq[0].coeff[0] == NT(0)) return BFInterval(0,0); 00432 if (numberOfRoots(0, y)==0) return BFInterval(x,0); 00433 return BFInterval(0,y); 00434 } 00435 BigFloat m = (x+y).div2(); 00436 n = numberOfRoots(x, m); 00437 if (n >= i) 00438 return isolateRoot(i, x, m); 00439 // Now (n < i) but we have to be careful if m is a root 00440 if (sign(seq[0].evalExactSign(m)) != 0) // usual case 00441 return isolateRoot(i-n, m, y); 00442 else 00443 return isolateRoot(i-n+1, m, y); 00444 } 00445 00446 // same as isolateRoot(i). 00447 BFInterval diamond(int i) const { 00448 return isolateRoot(i); 00449 } 00450 00451 // First root above 00452 BFInterval firstRootAbove(const BigFloat &e) const { 00453 if (len <= 0) 00454 return BFInterval(1,0); // ERROR CONDITION 00455 return isolateRoot(1, e, seq[0].CauchyUpperBound()); 00456 } 00457 00458 // Main root (i.e., first root above 0) 00459 BFInterval mainRoot() const { 00460 if (len <= 0) 00461 return BFInterval(1,0); // ERROR CONDITION 00462 return isolateRoot(1, 0, seq[0].CauchyUpperBound()); 00463 } 00464 00465 // First root below 00466 BFInterval firstRootBelow(const BigFloat &e) const { 00467 if (len <= 0) 00468 return BFInterval(1,0); // ERROR CONDITION 00469 BigFloat bd = seq[0].CauchyUpperBound(); // bd is exact 00470 int n = numberOfRoots(-bd, e); 00471 if (n <= 0) 00472 return BFInterval(1,0); 00473 BigFloat bdBF = BigFloat(ceil(bd)); 00474 if (n == 1) 00475 return BFInterval(-bdBF, e); 00476 return isolateRoot(n, -bdBF, e); 00477 } 00478 00479 // Refine an interval I to absolute precision 2^{-aprec} 00480 // THIS USES bisection only! Use only for debugging (it is too slow) 00481 // 00482 BFInterval refine(const BFInterval& I, int aprec) const { 00483 // assert( There is a unique root in I ) 00484 // We repeat binary search till the following holds 00485 // width/2^n <= eps (eps = 2^(-aprec)) 00486 // => log(width/eps) <= n 00487 // => n = ceil(log(width/eps)) this many steps of binary search 00488 // will work. 00489 // At each step we verify 00490 // seq[0].evalExactSign(J.first) * seq[0].evalExactSign(J.second) < 0 00491 00492 BigFloat width = I.second - I.first; 00493 if (width <= 0) return I; // Nothing to do if the 00494 // interval I is exact or inconsistent 00495 BigFloat eps = BigFloat::exp2(-aprec); // eps = 2^{-aprec} 00496 extLong n = width.uMSB() + (extLong)aprec; 00497 00498 00499 BFInterval J = I; // Return value is the Interval J 00500 BigFloat midpoint; 00501 while(n >= 0) { 00502 midpoint = (J.second + J.first).div2(); 00503 BigFloat m = seq[0].evalExactSign(midpoint); 00504 if (m == 0) { 00505 J.first = J.second = midpoint; 00506 return J; 00507 } 00508 if (seq[0].evalExactSign(J.first) * m < 0) { 00509 J.second = midpoint; 00510 } else { 00511 J.first = midpoint; 00512 } 00513 00514 n--; 00515 } 00516 00517 return J; 00518 }//End Refine 00519 00520 // Refine First root above 00521 BFInterval refinefirstRootAbove(const BigFloat &e, int aprec) const { 00522 BFInterval I = firstRootAbove(e); 00523 return refine(I,aprec); 00524 } 00525 00526 // Refine First root below 00527 BFInterval refinefirstRootBelow(const BigFloat &e, int aprec) const { 00528 BFInterval I = firstRootBelow(e); 00529 return refine(I,aprec); 00530 } 00531 00532 // refineAllRoots(v, aprec) 00533 // will modify v so that v is a list of isolating intervals for 00534 // the roots of the polynomial in *this. The size of these intervals 00535 // are at most 2^{-aprec}. 00536 // If v is non-null, we assume it is a list of initial isolating intervals. 00537 // If v is null, we will first call isolateRoots(v) to set this up. 00538 void refineAllRoots( BFVecInterval &v, int aprec) { 00539 BFVecInterval v1; 00540 BFInterval J; 00541 if (v.empty()) 00542 isolateRoots(v); 00543 00544 for (BFVecInterval::const_iterator it = v.begin(); 00545 it != v.end(); ++it) { // Iterate through all the intervals 00546 //refine them to the given precision aprec 00547 J = refine(BFInterval(it->first, it->second), aprec); 00548 v1.push_back(std::make_pair(J.first, J.second)); 00549 } 00550 v.swap(v1); 00551 }//End of refineAllRoots 00552 00553 // This is the new version of "refineAllRoots" 00554 // based on Newton iteration 00555 // It should be used instead of refineAllRoots! 00556 void newtonRefineAllRoots( BFVecInterval &v, int aprec) { 00557 00558 BFVecInterval v1; 00559 BFInterval J; 00560 00561 if (v.empty()) 00562 isolateRoots(v); 00563 for (BFVecInterval::iterator it = v.begin(); 00564 it != v.end(); ++it) { // Iterate through all the intervals 00565 //refine them to the given precision aprec 00566 J = newtonRefine(*it, aprec); 00567 00568 if (NEWTON_DIV_BY_ZERO) { 00569 J.first = 1; 00570 J.second = 0; // indicating divide by zero 00571 } 00572 v1.push_back(std::make_pair(J.first, J.second)); 00573 } 00574 v.swap(v1); 00575 }//End of newtonRefineAllRoots 00576 00599 BigFloat newtonIterN(long n, const BigFloat& bf, BigFloat& del, 00600 unsigned long & err, extLong& fuMSB, extLong& ffuMSB) { 00601 if (len <= 0) return bf; // Nothing to do! User must 00602 // check this possibility! 00603 BigFloat val = bf; 00604 // val.makeExact(); // val is exact 00605 00606 // newton iteration 00607 for (int i=0; i<n; i++) { 00609 // Filtered Eval 00611 BigFloat ff = seq[1].evalExactSign(val, 3*ffuMSB); //3 is a slight hack 00612 ffuMSB = ff.uMSB(); 00613 //ff is guaranteed to have the correct sign as the exact evaluation. 00615 00616 if (ff == 0) { 00617 NEWTON_DIV_BY_ZERO = true; 00618 del = 0; 00619 core_error("Zero divisor in Newton Iteration", 00620 __FILE__, __LINE__, false); 00621 return 0; 00622 } 00623 00625 // Filtered Eval 00627 BigFloat f= seq[0].evalExactSign(val, 3*fuMSB); //3 is a slight hack 00628 fuMSB = f.uMSB(); 00630 00631 if (f == 0) { 00632 NEWTON_DIV_BY_ZERO = false; 00633 del = 0; // Indicates that we have reached the exact root 00634 // This is because eval(val) is exact!!! 00635 return val; // val is the exact root, before the last iteration 00636 } 00637 del = f/ff; // But the accuracy of "f/ff" must be controllable 00638 // by the caller... 00639 err = del.err(); 00640 del.makeExact(); // makeExact() is necessary 00641 val -= del; 00642 // val.makeExact(); // -- unnecessary... 00643 } 00644 return val; 00645 }//newtonIterN 00646 00647 //Another version of newtonIterN which does not return the error 00648 //and passing the uMSB as arguments; it is easier for the user to call 00649 //this. 00650 BigFloat newtonIterN(long n, const BigFloat& bf, BigFloat& del){ 00651 unsigned long err; 00652 extLong fuMSB=0, ffuMSB=0; 00653 return newtonIterN(n, bf, del, err, fuMSB, ffuMSB); 00654 } 00655 00656 // v = newtonIterE(prec, bf, del, fuMSB, ffuMSB) 00657 // 00658 // return the value v which is obtained by Newton iteration 00659 // until del.uMSB < -prec, starting from initial value of bf. 00660 // Returned value is an exact BigFloat. 00661 // We guarantee at least one Newton step (so del is defined). 00662 // 00663 // The parameters fuMSB and ffuMSB are precision parameters for 00664 // evaluating coefficients of f(x) and f'(x), used similarly 00665 // as described above for newtonIterN(....) 00666 // 00667 // Return by reference "del" (difference between returned val and value 00668 // in the previous Newton iteration). This "del" is an upper bound 00669 // on the last (f/f')-value in Newton iteration. 00670 // 00671 // IN particular, if v is in the Newton zone of a root z^*, then z^* is 00672 // guaranteed to lie inside [v-del, v+del]. 00673 // 00674 // Note that this is dangerous unless you know that bf is already 00675 // in the Newton zone. So we use the global N_STOP_ITER to 00676 // prevent infinite loop. 00677 00678 BigFloat newtonIterE(int prec, const BigFloat& bf, BigFloat& del, 00679 extLong& fuMSB, extLong& ffuMSB) { 00680 // usually, prec is positive 00681 int count = N_STOP_ITER; // upper bound on number of iterations 00682 int stepsize = 1; 00683 BigFloat val = bf; 00684 unsigned long err = 0; 00685 00686 do { 00687 val = newtonIterN(stepsize, val, del, err, fuMSB, ffuMSB); 00688 count -= stepsize; 00689 stepsize++; // heuristic 00690 } while ((del != 0) && ((del.uMSB() >= -prec) && (count >0))) ; 00691 00692 if (count == 0) core_error("newtonIterE: reached count=0", 00693 __FILE__, __LINE__, true); 00694 del = BigFloat(core_abs(del.m()), err, del.exp() ); 00695 del.makeCeilExact(); 00696 return val; 00697 } 00698 00699 //Another version of newtonIterE which avoids passing the uMSB's. 00700 BigFloat newtonIterE(int prec, const BigFloat& bf, BigFloat& del){ 00701 extLong fuMSB=0, ffuMSB=0; 00702 return newtonIterE(prec, bf, del, fuMSB, ffuMSB); 00703 } 00704 // A Smale bound which is an \'a posteriori condition. Applying 00705 // Newton iteration to any point z satisfying this condition we are 00706 // sure to converge to the nearest root in a certain interval of z. 00707 // The condition is for all k >= 2, 00708 // | \frac{p^(k)(z)}{k!p'(z)} |^{1\(k-1)} < 1/8 * |\frac{p'(z)}{p(z)}| 00709 // Note: code below has been streamlined (Chee) 00710 /* 00711 bool smaleBound(const Polynomial<NT> * p, BigFloat z){ 00712 int deg = p[0].getTrueDegree(); 00713 BigFloat max, temp, temp1, temp2; 00714 temp2 = p[1].eval(z); 00715 temp = core_abs(temp2/p[0].eval(z))/8; 00716 BigInt fact_k = 2; 00717 for(int k = 2; k <= deg; k++){ 00718 temp1 = core_abs(p[k].eval(z)/(fact_k*temp2)); 00719 if(k-1 == 2) 00720 temp1 = sqrt(temp1); 00721 else 00722 temp1 = root(temp1, k-1); 00723 if(temp1 >= temp) return false; 00724 } 00725 return true; 00726 } 00727 */ 00728 00729 //An easily computable Smale's point estimate for Newton as compared to the 00730 //one above. The criterion is 00731 // 00732 // ||f||_{\infty} * \frac{|f(z)|}{|f'(z)|^2} 00733 // * \frac{\phi'(|z|)^2}{\phi(|z|)} < 0.03 00734 // where 00735 // \phi(r) = \sum_{i=0}{m}r^i, 00736 // m = deg(f) 00737 // 00738 //It is given as Theorem B in [Smale86]. 00739 //Reference:- Chapter 8 in Complexity and Real Computation, by 00740 // Blum, Cucker, Shub and Smale 00741 // 00742 //For our implementation we calculate an upper bound on 00743 //the second fraction in the inequality above. For r>0, 00744 // 00745 // \phi'(r)^2 m^2 (r^m + 1)^2 00746 // --------- < ------------------- (1) 00747 // \phi(r) (r-1) (r^{m+1} - 1) 00748 // 00749 // Alternatively, we have 00750 // 00751 // \phi'(r)^2 (mr^{m+1} + 1)^2 00752 // --------- < ------------------- (2) 00753 // \phi(r) (r-1)^3 (r^{m+1} - 1) 00754 // 00755 // The first bound is better when r > 1. 00756 // The second bound is better when r << 1. 00757 // Both bounds (1) and (2) assumes r is not equal to 1. 00758 // When r=1, the exact value is 00759 // 00760 // \phi'(r)^2 m^2 (m + 1) 00761 // --------- = ----------- (3) 00762 // \phi(r) 4 00763 // 00764 // REMARK: smaleBoundTest(z) actually computes an upper bound 00765 // on alpha(f,z), and compares it to 0.02 (then our theory 00766 // says that z is a robust approximate zero). 00767 // 00768 bool smaleBoundTest(const BigFloat& z){ 00769 assert(z.isExact()); // the bound only makes sense for exact z 00770 00771 #ifdef CORE_DEBUG 00772 std::cout <<"Computing Smale's bound = " << std::endl; 00773 #endif 00774 00775 if(seq[0].evalExactSign(z) == 0)// Reached the exact root. 00776 return true; 00777 00778 BigFloat fprime = core_abs(seq[1].evalExactSign(z)); 00779 fprime.makeFloorExact(); 00780 if (fprime == 0) return false; // z is a critical value! 00781 BigFloat temp = // evalExactSign(z) may have error. 00782 core_abs(seq[0].evalExactSign(z)); 00783 temp = (temp.makeCeilExact()/power(fprime, 2)).makeCeilExact(); 00784 temp = temp*seq[0].height(); // remains exact 00785 //Thus, temp >= ||f||_{\infty} |\frac{f(z)}{f'(z)^2}| 00786 00787 int m = seq[0].getTrueDegree(); 00788 BigFloat x = core_abs(z); 00789 if (x==1) // special case, using (3) 00790 return (temp * BigFloat(m*m*(m+1)).div2().div2() < 0.02); 00791 00792 BigFloat temp1; 00793 if (x>1) { // use formula (1) 00794 temp1 = power(m* (power(x, m)+1), 2); // m^2*(x^m + 1)^2 00795 temp1 /= ((x - 1)*(power(x, m+1) - 1)); // formula (1) 00796 } else { // use formula (2) 00797 temp1 = power(m*(power(x, m+1) +1), 2); // (m*x^{m+1} + 1)^2 00798 temp1 /= (power(x - 1,3)*(power(x, m+1) -1)); // formula (2) 00799 } 00800 00801 #ifdef CORE_DEBUG 00802 std::cout <<"Value returned by Smale bound = " << temp * temp1.makeCeilExact() << std::endl; 00803 #endif 00804 00805 if(temp * temp1.makeCeilExact() < 0.03) // make temp1 exact! 00806 return true; 00807 else 00808 return false; 00809 }//smaleBoundTest 00810 00811 00812 // yapsBound(p) 00813 // returns a bound on size of isolating interval of polynomial p 00814 // which is guaranteed to be in the Newton Zone. 00815 // N.B. p MUST be square-free 00816 // 00817 // Reference: Theorem 6.37, p.184 of Yap's book 00818 // [Fundamental Problems of Algorithmic Algebra] 00819 00820 BigFloat yapsBound(const Polynomial<NT> & p) const { 00821 int deg = p.getTrueDegree(); 00822 return 1/(1 + pow(BigFloat(deg), 3*deg+9) 00823 *pow(BigFloat(2+p.height()),6*deg)); 00824 } 00825 00826 //newtonRefine(J, a) 00827 // 00828 // ASSERT(J is an isolating interval for some root x^*) 00829 // 00830 // ASSERT(J.first and J.second are exact BigFloats) 00831 // 00832 // Otherwise, the boundaries of the interval are not well defined. 00833 // We will return a refined interval with exact endpoints, 00834 // still called J, containing x^* and 00835 // 00836 // |J| < 2^{-a}. 00837 // 00838 // TO DO: write a version of newtonRefine(J, a, sign) where 00839 // sign=J.first.sign(), since you may already know the sign 00840 // of J.first. This will skip the preliminary stuff in the 00841 // current version. 00842 // 00843 BFInterval newtonRefine(BFInterval &J, int aprec) { 00844 00845 #ifdef CORE_DEBUG_NEWTON 00846 std::cout << "In newtonRefine, input J=" << J.first 00847 << ", " << J.second << " precision = " << aprec << std::endl; 00848 #endif 00849 00850 if (len <= 0) return J; // Nothing to do! User must 00851 // check this possibility! 00852 00853 00854 if((J.second - J.first).uMSB() < -aprec){ 00855 return (J); 00856 } 00857 int xSign, leftSign, rightSign; 00858 00859 leftSign = sign(seq[0].evalExactSign(J.first)); 00860 if (leftSign == 0) { 00861 J.second = J.first; 00862 return J; 00863 } 00864 00865 rightSign = sign(seq[0].evalExactSign(J.second)); 00866 if (rightSign == 0) { 00867 J.first = J.second; 00868 return J; 00869 } 00870 00871 assert( leftSign * rightSign < 0 ); 00872 00873 //N is number of times Newton is called without checking 00874 // whether the result is still in the interval or not 00875 #define NO_STEPS 2 00876 // REMARK: NO_STEPS=1 is incorrect, as it may lead to 00877 // linear convergence (it is somewhat similar to Dekker-Brent's 00878 // idea of guaranteeing that bisection does not 00879 // destroy the superlinear convergence of Newton. 00880 int N = NO_STEPS; 00881 00882 BigFloat x, del, olddel, temp; 00883 unsigned long err; 00884 BigFloat yap = yapsBound(seq[0]); 00885 00886 BigFloat old_width = J.second - J.first; 00887 x = (J.second + J.first).div2(); 00888 00889 // initial estimate for the evaluation of filter to floating point precision 00890 extLong fuMSB=54, ffuMSB=54; 00891 00892 //MAIN WHILE LOOP. We ensure that J always contains the root 00893 00894 while ( !smaleBoundTest(x) && 00895 (J.second - J.first) > yap && 00896 (J.second - J.first).uMSB() >= -aprec) { 00897 x = newtonIterN(N, x, del, err, fuMSB, ffuMSB); 00898 if ((del == 0)&&(NEWTON_DIV_BY_ZERO == false)) { // reached exact root! 00899 J.first = J.second = x; 00900 return J; 00901 } 00902 00903 BigFloat left(x), right(x); 00904 if (del>0) { 00905 left -= del; right += del; 00906 } else { 00907 left += del; right -= del; 00908 } 00909 00910 // update interval 00911 if ((left > J.first)&&(left <J.second)) { 00912 int lSign = sign(seq[0].evalExactSign(left)); 00913 if (lSign == leftSign) // leftSign=sign of J.first 00914 J.first = left; 00915 else if (lSign == 0) { 00916 J.first = J.second = left; 00917 return J; 00918 } else { 00919 J.second = left; 00920 } 00921 } 00922 if ((right < J.second)&&(right >J.first)) { 00923 int rSign = sign(seq[0].evalExactSign(right)); 00924 if (rSign == rightSign) 00925 J.second = right; 00926 else if (rSign == 0) { 00927 J.first = J.second = right; 00928 return J; 00929 } else { 00930 J.first = right; 00931 } 00932 } 00933 BigFloat width = J.second - J.first; 00934 00935 //left and right are exact, since x is exact. 00936 if (width*2 <= old_width && !NEWTON_DIV_BY_ZERO) { 00937 // we can get a better root: 00938 00939 // No, it is not necessary to update x to 00940 // the midpoint of the new interval J. 00941 // REASON: basically, it is hard to be smarter than Newton's method! 00942 // Newton might bring x very close to one endpoint, but it can be 00943 // because the root is near there! In any case, 00944 // by setting x to the center of J, you only gain at most 00945 // one bit of accuracy, but you stand to loose an 00946 // arbitrary amount of bits of accuracy if you are unlucky! 00947 // So I will comment out the next line. --Chee (Aug 9, 2004). 00948 // 00949 // x = (J.second + J.first).div2(); 00950 if (J.first > x || J.second < x) 00951 x = (J.second + J.first).div2(); 00952 00953 old_width = width; // update width 00954 00955 N ++; // be more confident or aggressive 00956 // (perhaps we should double N) 00957 // 00958 } else {// Either NEWTON_DIV_BY_ZERO=true 00959 // Or width has not decreased sufficiently 00960 x = (J.second + J.first).div2();//Reset x to midpoint since it was the 00961 //value from a failed Newton step 00962 xSign = sign(seq[0].evalExactSign(x)); 00963 if (xSign == rightSign) { 00964 J.second = x; 00965 } else if (xSign == leftSign) { 00966 J.first = x; 00967 } else { // xSign must be 0 00968 J.first = J.second = x; return J; 00969 } 00970 x = (J.second + J.first).div2(); 00971 00972 old_width = old_width.div2(); // update width 00973 00974 // reduce value of N: 00975 N = core_max(N-1, NO_STEPS); // N must be at least NO_STEPS 00976 } 00977 }//MAIN WHILE LOOP 00978 00979 if((J.second - J.first).uMSB() >= -aprec){ // The interval J 00980 //still hasn't reached the required precision. 00981 //But we know the current value of x (call it x_0) 00982 //is in the strong Newton basin of the 00983 //root x^* (because it passes Smale's bound) 00985 //Both x_0 and the root x^* are in the interval J. 00986 //Let NB(x^*) be the strong Newton basin of x^*. By definition, 00987 //x_0 is in NB(x^*) means that: 00988 // 00989 // x_0 is in NB(x^*) iff |x_n-x^*| \le 2^{-2^{n}+1} |x_0-x^*| 00990 // 00991 // where x_n is the n-th iterate of Newton. 00992 // 00993 // LEMMA 1: if x_0 \in NB(x^*) then 00994 // |x_0 - x^*| <= 2|del| (*) 00995 // and 00996 // |x_1 - x^*| <= |del| (**) 00997 // 00998 // where del = -f(x_0)/f'(x_0) and x_1 = x_0 + del 00999 //Proof: 01000 //Since x_0 is in the strong Newton basin, we have 01001 // |x_1-x^*| <= |x_0-x^*|/2. (***) 01002 //The bound (*) is equivalent to 01003 // |x_0-x^*|/2 <= |del|. 01004 //This is equivalent to 01005 // |x_0-x^*| - |del| <= |x_0-x^*|/2, 01006 //which follows from 01007 // |x_0-x^* + del| <= |x_0-x^*|/2, 01008 //which is equivalent to (***). 01009 //The bound (**) follows from (*) and (***). 01010 //QED 01011 // 01012 // COMMENT: the above derivation refers to the exact values, 01013 // but what we compute is X_1 where X_1 is an approximation to 01014 // x_1. However, let us write X_1 = x_0 - DEL, where DEL is 01015 // an approximation to del. 01016 // 01017 // LEMMA 2: If |DEL| >= |del|, 01018 // then (**) holds with X_1 and DEL in place of x_1 and del. 01019 // 01020 // NOTE: We implemented this DEL in newtonIterE. 01021 01022 #ifdef CORE_DEBUG 01023 std::cout << "Inside Newton Refine: Refining Part " << std::endl; 01024 01025 if((J.second - J.first) > yap) 01026 std::cout << "Smales Bound satisfied " << std::endl; 01027 else 01028 std::cout << "Chees Bound satisfied " << std::endl; 01029 #endif 01030 xSign = sign(seq[0].evalExactSign(x)); 01031 if(xSign == 0){ 01032 J.first = J.second = x; 01033 return J; // missing before! 01034 } 01035 01036 //int k = clLg((-(J.second - J.first).lMSB() + aprec).asLong()); 01037 x = newtonIterE(aprec, x, del, fuMSB, ffuMSB); 01038 xSign = sign(seq[0].evalExactSign(x)); 01039 01040 if(xSign == leftSign){//Root is greater than x 01041 J.first = x; 01042 J.second = x + del; // justified by Lemma 2 above 01043 }else if(xSign == rightSign){//Root is less than x 01044 J.first = x - del; // justified by Lemma 2 above 01045 J.second = x ; 01046 }else{//x is the root 01047 J.first = J.second = x; 01048 } 01049 } 01050 01051 01052 01053 #ifdef CORE_DEBUG 01054 std::cout << " Returning from Newton Refine: J.first = " << J.first 01055 << " J.second = " << J.second << " aprec = " << aprec 01056 << " Sign at the interval endpoints = " 01057 << sign(seq[0].evalExactSign(J.first)) 01058 << " : " << sign(seq[0].evalExactSign(J.second)) << " Err at starting = " 01059 << J.first.err() << " Err at end = " << J.second.err() << std::endl; 01060 #endif 01061 01062 assert( (seq[0].evalExactSign(J.first) * seq[0].evalExactSign(J.second) <= 0) ); 01063 01064 #ifdef CORE_DEBUG_NEWTON 01065 if (seq[0].evalExactSign(J.first) * seq[0].evalExactSign(J.second) > 0) 01066 std::cout <<" ERROR! Root is not in the Interval " << std::endl; 01067 if(J.second - J.first > BigFloat(1).exp2(-aprec)) 01068 std::cout << "ERROR! Newton Refine failed to achieve the desired precision" << std::endl; 01069 #endif 01070 01071 return(J); 01072 }//End of newton refine 01073 01074 };// Sturm class 01075 01076 // ================================================== 01077 // Static initialization 01078 // ================================================== 01079 template <class NT> 01080 int Sturm<NT>:: N_STOP_ITER = 10000; // stop IterE after this many loops 01081 // Reset this as needed 01082 01083 // ================================================== 01084 // Helper Functions 01085 // ================================================== 01086 01087 // isZeroIn(I): 01088 // returns true iff 0 is in the closed interval I 01089 CORE_INLINE bool isZeroIn(BFInterval I) { 01090 return ((I.first <= 0.0) && (I.second >= 0.0)); 01091 } 01092 01094 // DIAGNOSTIC TOOLS 01096 // Polynomial tester: P is polynomial to be tested 01097 // prec is the bit precision for root isolation 01098 // n is the number of roots predicted 01099 01100 template<class NT> 01101 CORE_INLINE void testSturm(const Polynomial<NT>&P, int prec, int n = -1) { 01102 Sturm<NT> Ss (P); 01103 BFVecInterval v; 01104 Ss.refineAllRoots(v, prec); 01105 std::cout << " Number of roots is " << v.size() <<std::endl; 01106 if ((n >= 0) & (v.size() == (unsigned)n)) 01107 std::cout << " (CORRECT!)" << std::endl; 01108 else 01109 std::cout << " (ERROR!) " << std::endl; 01110 int i = 0; 01111 for (BFVecInterval::const_iterator it = v.begin(); 01112 it != v.end(); ++it) { 01113 std::cout << ++i << "th Root is in [" 01114 << it->first << " ; " << it->second << "]" << std::endl; 01115 } 01116 }// testSturm 01117 01118 // testNewtonSturm( Poly, aprec, n) 01119 // will run the Newton-Sturm refinement to isolate the roots of Poly 01120 // until absolute precision aprec. 01121 // n is the predicated number of roots 01122 // (will print an error message if n is wrong) 01123 template<class NT> 01124 CORE_INLINE void testNewtonSturm(const Polynomial<NT>&P, int prec, int n = -1) { 01125 Sturm<NT> Ss (P); 01126 BFVecInterval v; 01127 Ss.newtonRefineAllRoots(v, prec); 01128 std::cout << " Number of roots is " << v.size(); 01129 if ((n >= 0) & (v.size() == (unsigned)n)) 01130 std::cout << " (CORRECT!)" << std::endl; 01131 else 01132 std::cout << " (ERROR!) " << std::endl; 01133 01134 int i = 0; 01135 for (BFVecInterval::iterator it = v.begin(); 01136 it != v.end(); ++it) { 01137 std::cout << ++i << "th Root is in [" 01138 << it->first << " ; " << it->second << "]" << std::endl; 01139 if(it->second - it->first <= (1/power(BigFloat(2), prec))) 01140 std::cout << " (CORRECT!) Precision attained" << std::endl; 01141 else 01142 std::cout << " (ERROR!) Precision not attained" << std::endl; 01143 } 01144 }// testNewtonSturm 01145 01146 CORE_END_NAMESPACE 01147 01148 #endif