1 // Copyright (c) 2017 John Abbott, Anna M. Bigatti 2 3 // This file is part of the source of CoCoALib, the CoCoA Library. 4 5 // CoCoALib is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 10 // CoCoALib is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 15 // You should have received a copy of the GNU General Public License 16 // along with CoCoALib. If not, see <http://www.gnu.org/licenses/>. 17 18 #include "CoCoA/RootBound.H" 19 20 #include "CoCoA/BigIntOps.H" 21 #include "CoCoA/BigRatOps.H" 22 #include "CoCoA/NumTheory-gcd.H" 23 #include "CoCoA/RingZZ.H" 24 #include "CoCoA/SparsePolyIter.H" 25 #include "CoCoA/SparsePolyOps-RingElem.H" 26 //#include "CoCoA/SparsePolyRing.H" // from SparsePolyOps-RingElem.H 27 #include "CoCoA/VectorOps.H" 28 #include "CoCoA/error.H" 29 #include "CoCoA/verbose.H" 30 31 #include<algorithm> 32 using std::min; 33 #include <cmath> 34 using std::abs; 35 using std::log; 36 #include <iostream> 37 using std::endl; 38 #include <vector> 39 using std::vector; 40 41 namespace CoCoA 42 { 43 44 namespace // anonymous 45 { 46 RootBound_CheckArg(ConstRefRingElem f,const char * const FnName)47 void RootBound_CheckArg(ConstRefRingElem f, const char* const FnName) 48 { 49 const ring& P = owner(f); 50 if (!IsPolyRing(P) || !IsZero(characteristic(P))) 51 CoCoA_ERROR(ERR::BadArg, FnName); // must be a poly in char 0 52 if (IsZero(f) || deg(f) == 0) 53 CoCoA_ERROR(ERR::BadArg, FnName); // must have deg >= 1 54 if (UnivariateIndetIndex(f) < 0) 55 CoCoA_ERROR(ERR::BadArg, FnName); // not univariate 56 } 57 58 59 // This fn is now obsolete; fn below is better (but does use exp(...)) 60 // 61 // // upper bound for 1/(2^(1/d)-1) for d integer >= 2 62 // // For d > 4 the formula (185*d-64)/128 requires proof. 63 // BigRat BirkhoffScaleFactor(long d) 64 // { 65 // if (d < 2) CoCoA_ERROR(ERR::BadArg,"ScaleFactor"); 66 // if (d > 4) return BigRat(185*d-64, 128); // error less than 0.2% 67 // switch (d) 68 // { 69 // case 2: return BigRat(619,256); 70 // case 3: return BigRat(493,128); 71 // case 4: return BigRat(677,128); 72 // } 73 // CoCoA_ERROR(ERR::ShouldNeverGetHere, "ScaleFactor"); 74 // return BigRat(-1,1); // just to keep compiler quiet 75 // } 76 77 78 // Upper bound for Birkhoff's scale factor (excess is about 0.01%-0.1%) BirkhoffScaleFactor2(long d)79 double BirkhoffScaleFactor2(long d) 80 { 81 static const double log2 = std::log(2); 82 if (d < 2) CoCoA_ERROR(ERR::BadArg,"ScaleFactor"); 83 if (d >= 7) return (1+1.0/1024)*(d/log2-0.5); 84 return (1+1.0/1024)/(exp(log2/d)-1); 85 } 86 87 CoeffSizeEstimate(ConstRefRingElem f)88 long CoeffSizeEstimate(ConstRefRingElem f) 89 { 90 CoCoA_ASSERT(IsZZ(CoeffRing(owner(f)))); 91 long ans = 0; 92 for (SparsePolyIter it=BeginIter(f); !IsEnded(it); ++it) 93 { 94 ans += 1+FloorLog2(ConvertTo<BigInt>(coeff(it))); 95 } 96 return ans; 97 } 98 99 RootBound_preprocess(ConstRefRingElem f)100 RingElem RootBound_preprocess(ConstRefRingElem f) 101 { 102 RootBound_CheckArg(f, "RootBound_preprocess"); 103 104 VerboseLog VERBOSE("RootBound_preprocess"); 105 const PolyRing ZZx = NewPolyRing(RingZZ(), symbols("x")); 106 const PPMonoidElem x = indet(PPM(ZZx),0); 107 long GcdExp = 0; 108 long LastExp = -1; 109 BigInt CommonDenom(1); 110 BigInt CommonNumer; 111 for (SparsePolyIter it=BeginIter(f); !IsEnded(it); ++it) 112 { 113 const long d = deg(PP(it)); 114 if (LastExp != -1 && GcdExp != 1) 115 GcdExp = gcd(GcdExp, LastExp-d); 116 LastExp = d; 117 const BigRat c = ConvertTo<BigRat>(coeff(it)); 118 CommonNumer = gcd(CommonNumer, num(c)); 119 CommonDenom = lcm(CommonDenom, den(c)); 120 } 121 // Trick to make sure result has positive leading coeff. 122 if (sign(LC(f)) < 0) 123 CommonNumer = -CommonNumer; 124 125 RingElem ans(ZZx); 126 for (SparsePolyIter it=BeginIter(f); !IsEnded(it); ++it) 127 { 128 const long d = deg(PP(it)); 129 const BigRat c = ConvertTo<BigRat>(coeff(it)); 130 const RingElem IntCoeff(RingZZ(), (num(c)/CommonNumer)*(CommonDenom/den(c))); 131 PushBack(ans, IntCoeff, power(x, (d-LastExp)/GcdExp)); 132 } 133 if (VerbosityLevel() >= 50) 134 { 135 VERBOSE(50) << "Removed power of x: " << LastExp << endl; 136 VERBOSE(50) << "Poly was in x^" << GcdExp << endl; 137 } 138 return ans; 139 } 140 141 142 // Result is approximately exp(d) expressed as a rational of the form 143 // n*2^k where n is an integer less than 256 (and k is integer, of course!) ApproxExp(double d)144 BigRat ApproxExp(double d) 145 { 146 const double ln2 = std::log(2.0); 147 const long pwr2 = (-8) + static_cast<long>(std::floor(d/ln2)); 148 149 const double excess = d - pwr2*ln2; 150 const int numer = static_cast<int>(std::ceil(exp(excess))); 151 if (pwr2 < 0) return BigRat(numer,power(2,-pwr2)); 152 return BigRat(numer*power(2,pwr2), 1); 153 } 154 155 ApproxRoot(const BigRat & q,int n)156 BigRat ApproxRoot(const BigRat& q, int n) 157 { 158 if (n == 1) return q; 159 return ApproxExp(log(q)/n); 160 } 161 162 163 const double LogZero = -1.0e15; // "minus infinity" 164 165 166 // Returns vector<double> such that entry k contains 167 // log(abs(a_k/a_d)) where a_d is the leading coeff. 168 // if a_k is 0 then entry is LogZero (see defn above) LogCoeffVec(ConstRefRingElem f)169 vector<double> LogCoeffVec(ConstRefRingElem f) 170 { 171 CoCoA_ASSERT(!IsZero(f) && deg(f) > 0); 172 VerboseLog VERBOSE("LogCoeffVec"); 173 const int d = deg(f); 174 vector<double> LogCoeff(d, LogZero); 175 const double LogLCF = log(ConvertTo<BigRat>(LC(f))); // abs is implicit 176 for (SparsePolyIter it=++BeginIter(f); !IsEnded(it); ++it) 177 { 178 const int i = deg(PP(it)); 179 LogCoeff[i] = log(ConvertTo<BigRat>(coeff(it))) - LogLCF; // abs is implicit 180 } 181 VERBOSE(59) << "ans = " << LogCoeff << endl; 182 return LogCoeff; 183 } 184 185 186 // (exact) Root bound for polys of degree 1 RootBound_deg1(ConstRefRingElem f)187 BigRat RootBound_deg1(ConstRefRingElem f) 188 { 189 CoCoA_ASSERT(!IsZero(f) && deg(f) == 1); 190 if (NumTerms(f) == 1) return BigRat(0,1); 191 const BigRat lcf = ConvertTo<BigRat>(LC(f)); 192 return abs(ConvertTo<BigRat>(coeff(++BeginIter(f)))/lcf); 193 } 194 195 } // end of namespace anonymous 196 197 198 //------------------------------------------------------------------ 199 // Classical Cauchy bound. 200 // Ref: Wikipedia, "properties of polynomial roots" 201 LogRootBound_Cauchy(const vector<double> & LogCoeff)202 double LogRootBound_Cauchy(const vector<double>& LogCoeff) 203 { 204 CoCoA_ASSERT(!LogCoeff.empty()); 205 VerboseLog VERBOSE("LogRootBound_Cauchy"); 206 const int d = len(LogCoeff); // must have d > 0 207 if (d == 1) return LogCoeff[0]; 208 209 double MaxVal = LogZero; 210 VERBOSE(55) << "MaxVal = " << MaxVal << endl; 211 for (int i=0; i < d; ++i) 212 { 213 VERBOSE(55) << "Start Loop i=" << i << endl; 214 VERBOSE(55) << " LogCoeff[i] = " << LogCoeff[i] << endl; 215 if (LogCoeff[i] == LogZero) continue; 216 VERBOSE(55) << " val = " << LogCoeff[i] << endl; 217 if (LogCoeff[i] > MaxVal) MaxVal = LogCoeff[i]; 218 // MaxVal = std::max(LogCoeff[i], MaxVal); 219 VERBOSE(55) << " MaxVal = " << MaxVal << endl; 220 VERBOSE(55) << "End Loop i=" << i << endl; 221 } 222 223 const double ans = log(1 + ApproxExp(MaxVal)); // any cleverer way? 224 VERBOSE(51) << "RETURN " << ans << endl; 225 return ans; 226 } 227 228 RootBound_Cauchy(ConstRefRingElem f)229 BigRat RootBound_Cauchy(ConstRefRingElem f) 230 { 231 RootBound_CheckArg(f, "RootBound_Cauchy"); 232 233 const int d = deg(f); 234 if (d == 1) return RootBound_deg1(f); 235 if (IsMonomial(f)) return BigRat(0,1); 236 const double LogBound = LogRootBound_Cauchy(LogCoeffVec(f)); 237 return ApproxExp(LogBound); 238 } 239 240 //------------------------------------------------------------------ 241 // Classical Lagrange bound -- see also the LMS bound below! 242 // Ref: Wikipedia, "properties of polynomial roots" 243 LogRootBound_Lagrange(const vector<double> & LogCoeff)244 double LogRootBound_Lagrange(const vector<double>& LogCoeff) 245 { 246 CoCoA_ASSERT(!LogCoeff.empty()); 247 VerboseLog VERBOSE("LogRootBound_Lagrange"); 248 const int d = len(LogCoeff); // must have d > 0 249 if (d == 1) return LogCoeff[0]; 250 251 double MaxVal = LogZero; 252 for (int i=0; i < d; ++i) 253 { 254 if (LogCoeff[i] == LogZero) continue; 255 if (LogCoeff[i] > MaxVal) MaxVal = LogCoeff[i]; 256 } 257 258 // if (MaxVal == LogZero) return LogZero; 259 if (std::log(d) + MaxVal < 0) return 0; // 0 = log(1) 260 BigRat SumOfBigCoeffs; 261 const double LWB = MaxVal - std::log(d) - 7; // we shall ignore "negligible" values 262 VERBOSE(55) << "ignoring coeffs with logs below " << LWB << endl; 263 for (int i=0; i < d; ++i) 264 { 265 if (LogCoeff[i] < LWB) continue; 266 SumOfBigCoeffs += ApproxExp(LogCoeff[i]); 267 } 268 269 const double ans = std::max(0.0, log(SumOfBigCoeffs)); 270 VERBOSE(52) << "RETURN " << ans << endl; 271 return ans; 272 } 273 274 RootBound_Lagrange(ConstRefRingElem f)275 BigRat RootBound_Lagrange(ConstRefRingElem f) 276 { 277 RootBound_CheckArg(f, "RootBound_Lagrange"); 278 279 const int d = deg(f); 280 if (d == 1) return RootBound_deg1(f); 281 if (IsMonomial(f)) return BigRat(0,1); 282 const double LogBound = LogRootBound_Lagrange(LogCoeffVec(f)); 283 return ApproxExp(LogBound); 284 } 285 286 //------------------------------------------------------------------ 287 // This was the root bound used by Zassenhaus (1969) 288 LogRootBound_Birkhoff(const vector<double> & LogCoeff)289 double LogRootBound_Birkhoff(const vector<double>& LogCoeff) 290 { 291 CoCoA_ASSERT(!LogCoeff.empty()); 292 VerboseLog VERBOSE("LogRootBound_Birkhoff"); 293 const int d = len(LogCoeff); // must have d > 0 294 if (d == 1) return LogCoeff[0]; 295 296 double LogBinomial = 0.0; 297 double MaxVal = LogZero; 298 VERBOSE(55) << "MaxVal = " << MaxVal << endl; 299 for (int i=0; i < d; ++i) 300 { 301 VERBOSE(55) << "Start Loop i=" << i << endl; 302 VERBOSE(55) << " LogCoeff[i] = " << LogCoeff[i] << endl; 303 VERBOSE(55) << " LogBinom = " << LogBinomial << endl; 304 if (LogCoeff[i] != LogZero) 305 { 306 const double val = (LogCoeff[i]-LogBinomial)/(d-i); 307 VERBOSE(55) << " val = " << val << endl; 308 if (val > MaxVal) MaxVal = val; 309 // MaxVal = std::max(val, MaxVal); 310 VERBOSE(55) << " MaxVal = " << MaxVal << endl; 311 } 312 LogBinomial += std::log(d-i) - std::log(i+1); 313 VERBOSE(55) << "End Loop i=" << i << endl; 314 } 315 316 const double ScaleFactor = BirkhoffScaleFactor2(d); 317 VERBOSE(55) << "ScaleFactor = " << ScaleFactor << endl; 318 VERBOSE(55) << "Max log val = " << MaxVal << endl; 319 VERBOSE(52) << "RETURN " << std::log(ScaleFactor) + MaxVal << endl; 320 return std::log(ScaleFactor) + MaxVal; 321 } 322 323 RootBound_Birkhoff(ConstRefRingElem f)324 BigRat RootBound_Birkhoff(ConstRefRingElem f) 325 { 326 RootBound_CheckArg(f, "RootBound_Birkhoff"); 327 328 // VerboseLog VERBOSE("RootBound_Birkhoff"); 329 const int d = deg(f); 330 if (d == 1) return RootBound_deg1(f); 331 if (IsMonomial(f)) return BigRat(0,1); 332 const double LogBound = LogRootBound_Birkhoff(LogCoeffVec(f)); 333 return ApproxExp(LogBound); 334 335 // // const double LogZero = -1.0e15; // "minus infinity" 336 // vector<double> LogCoeff(d, LogZero); 337 // const double LogLCF = log(ConvertTo<BigRat>(LC(f))); 338 // for (SparsePolyIter it=++BeginIter(f); !IsEnded(it); ++it) 339 // { 340 // const int i = deg(PP(it)); 341 // LogCoeff[i] = log(ConvertTo<BigRat>(coeff(it)))-LogLCF; 342 // } 343 // VERBOSE(51) << "LogCoeff = " << LogCoeff << endl; 344 // double LogBinomial = 0.0; 345 // double MaxVal = LogZero; 346 // for (int i=0; i < d; ++i) 347 // { 348 // if (LogCoeff[i] == LogZero) continue; 349 // const double val = (LogCoeff[i]-LogBinomial)/(d-i); 350 // MaxVal = std::max(val, MaxVal); 351 // LogBinomial += std::log(d-i) - std::log(i+1); 352 // } 353 354 // const BigRat ScaleFactor = BirkhoffScaleFactor(d); 355 // VERBOSE(50) << "ScaleFactor = " << ScaleFactor << endl; 356 // VERBOSE(50) << "Max log val = " << MaxVal << endl; 357 // return ScaleFactor * ApproxExp(MaxVal); 358 } 359 360 361 // //------------------------------------------------------------------ 362 // // 2019-04-26: found this fn is an old (2011) test program... 363 // // Originally from a 1969 version of a Knuth book (Seminumerical Algorithms) 364 // // LMS bound (below) is always <= Knuth bound. So Knuth bound is superseded by LMS. 365 366 // double LogRootBound_Knuth(const vector<double>& LogCoeff) 367 // { 368 // CoCoA_ASSERT(!LogCoeff.empty()); 369 // const int d = len(LogCoeff); // must have d > 0 370 // if (d == 1) return LogCoeff[0]; 371 372 // double MaxVal = LogZero; 373 // for (int i=0; i < d; ++i) 374 // { 375 // if (LogCoeff[i] == LogZero) continue; 376 // const double val = LogCoeff[i]/(d-i); 377 // if (val > MaxVal) MaxVal = val; 378 // // MaxVal = std::max(val, MaxVal); 379 // } 380 381 // return std::log(2.0) + MaxVal; 382 // } 383 384 // BigRat RootBound_Knuth(ConstRefRingElem f) 385 // { 386 // RootBound_CheckArg(f, "RootBound_Knuth"); 387 388 // const int d = deg(f); 389 // if (d == 1) return RootBound_deg1(f); 390 // if (IsMonomial(f)) return BigRat(0,1); 391 // const double LogBound = LogRootBound_Knuth(LogCoeffVec(f)); 392 // return ApproxExp(LogBound); 393 // } 394 395 396 //------------------------------------------------------------------ 397 // LMS = Lagrange-Mignotte-Stefanescu, and slightly better than Fujiwara (1916) 398 // Supersedes bounds from Fujiwara (1916) and Knuth (Seminumerical Algms, 1969) 399 LogRootBound_LMS(const vector<double> & LogCoeff)400 double LogRootBound_LMS(const vector<double>& LogCoeff) 401 { 402 CoCoA_ASSERT(!LogCoeff.empty()); 403 VerboseLog VERBOSE("RootBound_LMS"); 404 const int d = len(LogCoeff); // must have d > 0 405 if (d == 1) return LogCoeff[0]; 406 407 double max1 = LogZero; 408 double max2 = LogZero; 409 for (int i=0; i < d; ++i) 410 { 411 if (LogCoeff[i] == LogZero) continue; 412 const double val = LogCoeff[i]/(d-i); 413 if (val < max2) continue; 414 if (val < max1) { max2 = val; continue; } 415 max2 = max1; max1 = val; 416 } 417 VERBOSE(55) << "max1 = " << max1 << " max2 = " << max2 << endl; 418 if (max2 == LogZero) return max1; 419 if (max2 < max1 - 36) return max1; // NB 36 = 51*ln(2) 420 return max1 + log(1+ApproxExp(max2-max1)); 421 } 422 423 424 // LMS = Lagrange-Mignotte-Stefanescu RootBound_LMS(ConstRefRingElem f)425 BigRat RootBound_LMS(ConstRefRingElem f) 426 { 427 RootBound_CheckArg(f, "RootBound_LMS"); 428 429 const int d = deg(f); 430 if (d == 1) return RootBound_deg1(f); 431 if (IsMonomial(f)) return BigRat(0,1); 432 const double LogBound = LogRootBound_LMS(LogCoeffVec(f)); 433 return ApproxExp(LogBound); 434 435 // VerboseLog VERBOSE("RootBound_LMS"); 436 // const int d = deg(f); 437 // if (d == 1) return RootBound_deg1(f); 438 // if (IsMonomial(f)) return BigRat(0,1); 439 // // const double LogZero = -1.0e15; // "minus infinity" 440 // vector<double> LogCoeff(d, LogZero); 441 // const double LogLCF = log(ConvertTo<BigRat>(LC(f))); 442 // for (SparsePolyIter it=++BeginIter(f); !IsEnded(it); ++it) 443 // { 444 // const int i = deg(PP(it)); 445 // LogCoeff[i] = log(ConvertTo<BigRat>(coeff(it))) - LogLCF; 446 // } 447 // VERBOSE(51) << "LogCoeff = " << LogCoeff << endl; 448 449 // double max1 = LogZero; 450 // double max2 = LogZero; 451 // for (int i=0; i < d; ++i) 452 // { 453 // if (LogCoeff[i] == LogZero) continue; 454 // double val = LogCoeff[i]/(d-i); 455 // if (val < max2) continue; 456 // if (val < max1) { max2 = val; continue; } 457 // max2 = max1; max1 = val; 458 // } 459 // VERBOSE(50) << "max1 = " << max1 << " max2 = " << max2 << endl; 460 // if (max2 == LogZero) return ApproxExp(max1); 461 // return ApproxExp(max1) + ApproxExp(max2); 462 } 463 464 465 //------------------------------------------------------------------ 466 467 // LogRootBound_simple is the best of the "simple" bounds LogRootBound_simple(const vector<double> & LogCoeff)468 double LogRootBound_simple(const vector<double>& LogCoeff) 469 { 470 const double LogBound_Cauchy = LogRootBound_Cauchy(LogCoeff); 471 const double LogBound_Lagrange = LogRootBound_Lagrange(LogCoeff); 472 const double LogBound_Birkhoff = LogRootBound_Birkhoff(LogCoeff); 473 const double LogBound_LMS = LogRootBound_LMS(LogCoeff); 474 VerboseLog VERBOSE("LogRootBound_simple"); 475 VERBOSE(51) << "LogBound_Cauchy = " << LogBound_Cauchy << endl; 476 VERBOSE(51) << "LogBound_Lagrange = " << LogBound_Lagrange << endl; 477 VERBOSE(51) << "LogBound_Birkhoff = " << LogBound_Birkhoff << endl; 478 VERBOSE(51) << "LogBound_LMS = " << LogBound_LMS << endl; 479 const double LogBound_min = min(min(LogBound_Cauchy, LogBound_Lagrange), 480 min(LogBound_Birkhoff, LogBound_LMS)); 481 VERBOSE(51) << "LogBound_min = " << LogBound_min << endl; 482 return LogBound_min; 483 } 484 RootBound_simple(ConstRefRingElem f)485 BigRat RootBound_simple(ConstRefRingElem f) 486 { 487 RootBound_CheckArg(f, "RootBound_simple"); 488 489 const int d = deg(f); // must have d > 0 490 if (d == 1) return RootBound_deg1(f); 491 if (IsMonomial(f)) return BigRat(0,1); 492 const double LogBound = LogRootBound_simple(LogCoeffVec(f)); 493 return ApproxExp(LogBound); 494 } 495 496 //------------------------------------------------------------------ 497 RootBound(ConstRefRingElem f,long NumGraeffeIters)498 BigRat RootBound(ConstRefRingElem f, long NumGraeffeIters) 499 { 500 RootBound_CheckArg(f, "RootBound"); 501 if (NumGraeffeIters < -1 || NumGraeffeIters > 25) 502 CoCoA_ERROR(ERR::ArgTooBig, "RootBound"); 503 504 VerboseLog VERBOSE("RootBound"); 505 if (IsMonomial(f)) 506 { 507 VERBOSE(50) << "Input is monomial --> ans is 0" << endl; 508 return BigRat(0,1); 509 } 510 RingElem g = RootBound_preprocess(f); 511 const long f_step = deg(f) - deg(PP(++BeginIter(f))); 512 const long d = deg(g); 513 VERBOSE(40) << "Preprocessed poly has deg: " << d << endl; 514 const long g_step = d - deg(PP(++BeginIter(g))); 515 VERBOSE(40) << "Input was poly in x^" << (f_step/g_step) << endl; 516 if (d == 1) 517 { 518 VERBOSE(40) << "Preprocessed poly is linear" << endl; 519 const BigRat lcg = ConvertTo<BigRat>(LC(g)); 520 const BigRat ConstCoeff = ConvertTo<BigRat>(coeff(++BeginIter(g))); 521 return ApproxRoot(abs(ConstCoeff/lcg), f_step/g_step); 522 } 523 BigRat B = RootBound_simple(g); 524 // BigRat RB_LMS = RootBound_LMS(g); 525 // BigRat RB_B = RootBound_Birkhoff(g); 526 // VERBOSE(40) << "LMS bound: " << RB_LMS << endl; 527 // VERBOSE(40) << "Birkhoff bound: " << RB_B << endl; 528 // BigRat B = min(RB_LMS, RB_B); 529 VERBOSE(40) << "Overall bound: " << B << endl; 530 531 int pwr = 1; 532 const long CoeffSize = CoeffSizeEstimate(g); 533 VERBOSE(40) << "CoeffSizeEstimate = " << CoeffSize << endl; 534 long MaxIters = NumGraeffeIters; 535 if (NumGraeffeIters < 0) 536 MaxIters = min(5L, 22-FloorLog2(CoeffSize)); 537 538 for (long NumIters = 1; NumIters <= MaxIters; ++NumIters) 539 { 540 VERBOSE(40) << "Graeffe loop [" << NumIters << "] start" << endl; 541 pwr *= 2; 542 g = graeffe(g); 543 const BigRat NewB = ApproxRoot(RootBound_simple(g), pwr); 544 VERBOSE(40) << "Graeffe loop [" << NumIters << "] Bound for transformed poly: " << NewB << endl << endl; 545 B = min(B, NewB); 546 VERBOSE(40) << "Graeffe loop [" << NumIters << "] Overall bound: " << B << endl << endl; 547 } 548 VERBOSE(40) << "After graeffe loop B = " << B << endl; 549 if (deg(f) != deg(g)) 550 { 551 B = ApproxRoot(B, f_step/g_step); 552 VERBOSE(40) << "Take " << f_step/g_step << " root.. B= " << B << endl; 553 } 554 return B; 555 } 556 557 LogRootBound(ConstRefRingElem f,long NumGraeffeIters)558 double LogRootBound(ConstRefRingElem f, long NumGraeffeIters) 559 { 560 CoCoA_ASSERT(NumGraeffeIters >= -1 && NumGraeffeIters <= 25); 561 VerboseLog VERBOSE("LogRootBound"); 562 if (IsMonomial(f)) 563 { 564 VERBOSE(50) << "Input is monomial --> ans is 0" << endl; 565 return LogZero; 566 } 567 RingElem g = RootBound_preprocess(f); 568 const long f_step = deg(f) - deg(PP(++BeginIter(f))); 569 const long d = deg(g); 570 VERBOSE(40) << "Preprocessed poly has deg: " << d << endl; 571 const long g_step = d - deg(PP(++BeginIter(g))); 572 VERBOSE(40) << "Input was poly in x^" << (f_step/g_step) << endl; 573 574 vector<double> LogCoeffs = LogCoeffVec(g); //not const; updated in graeffe loop 575 if (d == 1) 576 { 577 VERBOSE(40) << "Preprocessed poly was linear" << endl; 578 return LogCoeffs[0]/(f_step/g_step); 579 } 580 double LogBound = LogRootBound_simple(LogCoeffs); 581 VERBOSE(40) << "Initial log bound: " << LogBound << endl; 582 583 VERBOSE(40) << "CoeffSizeEstimate = " << CoeffSizeEstimate(g) << endl; 584 long MaxIters = NumGraeffeIters; 585 if (NumGraeffeIters < 0) 586 MaxIters = min(5L, 22-FloorLog2(CoeffSizeEstimate(g))); 587 588 int pwr = 1; 589 for (long NumIters = 1; NumIters <= MaxIters; ++NumIters) 590 { 591 VERBOSE(40) << "Graeffe loop [" << NumIters << "] start" << endl; 592 pwr *= 2; 593 g = graeffe(g); 594 LogCoeffs = LogCoeffVec(g); 595 const double NewLogBound = LogRootBound_simple(LogCoeffs)/pwr; 596 VERBOSE(45) << "Graeffe loop [" << NumIters << "] new log bound: " << NewLogBound << endl; 597 LogBound = std::min(LogBound, NewLogBound); 598 VERBOSE(45) << "Graeffe loop [" << NumIters << "] Overall log bound: " << LogBound << endl << endl; 599 } 600 VERBOSE(40) << "After graeffe loop Log bound = " << LogBound << endl; 601 if (deg(f) != deg(g)) 602 { 603 LogBound = LogBound/(f_step/g_step); 604 VERBOSE(40) << "Take " << f_step/g_step << " root.. LogBound= " << LogBound << endl; 605 } 606 return LogBound; 607 } 608 609 RootBound2(ConstRefRingElem f,long NumGraeffeIters)610 BigRat RootBound2(ConstRefRingElem f, long NumGraeffeIters) 611 { 612 RootBound_CheckArg(f, "RootBound2"); 613 if (NumGraeffeIters < -1 || NumGraeffeIters > 25) 614 CoCoA_ERROR(ERR::ArgTooBig, "RootBound2"); 615 616 const double LogBound = LogRootBound(f, NumGraeffeIters); 617 if (LogBound == LogZero) return BigRat(0,1); 618 return ApproxExp(LogBound); 619 } 620 621 } // end of namespace CoCoA 622 623 624 // RCS header/log in the next few lines 625 // $Header: /Volumes/Home_1/cocoa/cvs-repository/CoCoALib-0.99/src/AlgebraicCore/RootBound.C,v 1.12 2020/01/26 14:41:59 abbott Exp $ 626 // $Log: RootBound.C,v $ 627 // Revision 1.12 2020/01/26 14:41:59 abbott 628 // Summary: Revised includes after splitting NumTheory (redmine 1161) 629 // 630 // Revision 1.11 2019/09/11 09:51:17 abbott 631 // Summary: Fixed redmine bug 1310 632 // 633 // Revision 1.10 2019/03/27 14:26:17 bigatti 634 // (abbott) commented out BirkhoffScaleFactor (version 1) 635 // 636 // Revision 1.9 2018/08/06 13:48:21 bigatti 637 // -- removed include SparsePolyOps.H 638 // 639 // Revision 1.8 2018/05/22 14:16:40 abbott 640 // Summary: Split BigRat into BigRat (class defn + ctors) and BigRatOps 641 // 642 // Revision 1.7 2018/05/18 16:42:11 bigatti 643 // -- added include SparsePolyOps-RingElem.H 644 // 645 // Revision 1.6 2018/05/18 12:22:30 bigatti 646 // -- renamed IntOperations --> BigIntOps 647 // 648 // Revision 1.5 2018/05/17 16:00:14 bigatti 649 // -- sorted #includes 650 // -- renamed VectorOperations --> VectorOps 651 // -- added #include SparsePolyIter 652 // 653 // Revision 1.4 2018/04/20 18:51:25 abbott 654 // Summary: Changed ctors for BigInt/BigRat from string or from MPZ/MPQ 655 // 656 // Revision 1.3 2017/12/12 14:18:31 abbott 657 // Summary: Major revision 658 // 659 // Revision 1.2 2017/09/25 12:37:36 abbott 660 // Summary: Increased max num graeffe iters (to 25 from 20) 661 // 662 // Revision 1.1 2017/09/14 15:54:54 abbott 663 // Summary: Added RootBound 664 // 665 // 666