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