GteRootsPolynomial.h
Go to the documentation of this file.
1 // David Eberly, Geometric Tools, Redmond WA 98052
2 // Copyright (c) 1998-2017
3 // Distributed under the Boost Software License, Version 1.0.
4 // http://www.boost.org/LICENSE_1_0.txt
5 // http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
6 // File Version: 3.0.0 (2016/06/19)
7 
8 #pragma once
9 
10 #include <GTEngineDEF.h>
11 #include <cmath>
12 #include <map>
13 #include <vector>
14 
15 // The Find functions return the number of roots, if any, and this number
16 // of elements of the outputs are valid. If the polynomial is identically
17 // zero, Find returns 1.
18 //
19 // Some root-bounding algorithms for real-valued roots are mentioned next for
20 // the polynomial p(t) = c[0] + c[1]*t + ... + c[d-1]*t^{d-1} + c[d]*t^d.
21 //
22 // 1. The roots must be contained by the interval [-M,M] where
23 // M = 1 + max{|c[0]|, ..., |c[d-1]|}/|c[d]| >= 1
24 // is called the Cauchy bound.
25 //
26 // 2. You may search for roots in the interval [-1,1]. Define
27 // q(t) = t^d*p(1/t) = c[0]*t^d + c[1]*t^{d-1} + ... + c[d-1]*t + c[d]
28 // The roots of p(t) not in [-1,1] are the roots of q(t) in [-1,1].
29 //
30 // 3. Between two consecutive roots of the derivative p'(t), say, r0 < r1,
31 // the function p(t) is strictly monotonic on the open interval (r0,r1).
32 // If additionally, p(r0) * p(r1) <= 0, then p(x) has a unique root on
33 // the closed interval [r0,r1]. Thus, one can compute the derivatives
34 // through order d for p(t), find roots for the derivative of order k+1,
35 // then use these to bound roots for the derivative of order k.
36 //
37 // 4. Sturm sequences of polynomials may be used to determine bounds on the
38 // roots. This is a more sophisticated approach to root bounding than item 3.
39 // Moreover, a Sturm sequence allows you to compute the number of real-valued
40 // roots on a specified interval.
41 //
42 // 5. For the low-degree Solve* functions, see
43 // http://www.geometrictools.com/Documentation/LowDegreePolynomialRoots.pdf
44 
45 namespace gte
46 {
47 
48 template <typename Real>
50 {
51 public:
52  // Low-degree root finders. These use exact rational arithmetic for
53  // theoretically correct root classification. The roots themselves are
54  // computed with mixed types (rational and floating-point arithmetic).
55  // The Rational type must support rational arithmetic (+, -, *, /); for
56  // example, BSRational<UIntegerAP32> suffices. The Rational class must
57  // have single-input constructors where the input is type Real. This
58  // ensures you can call the Solve* functions with floating-point inputs;
59  // they will be converted to Rational implicitly. The highest-order
60  // coefficients must be nonzero (p2 != 0 for quadratic, p3 != 0 for
61  // cubic, and p4 != 0 for quartic).
62 
63  template <typename Rational>
64  static void SolveQuadratic(Rational const& p0, Rational const& p1,
65  Rational const& p2, std::map<Real, int>& rmMap);
66 
67  template <typename Rational>
68  static void SolveCubic(Rational const& p0, Rational const& p1,
69  Rational const& p2, Rational const& p3, std::map<Real, int>& rmMap);
70 
71  template <typename Rational>
72  static void SolveQuartic(Rational const& p0, Rational const& p1,
73  Rational const& p2, Rational const& p3, Rational const& p4,
74  std::map<Real, int>& rmMap);
75 
76  // Return only the number of real-valued roots and their multiplicities.
77  // info.size() is the number of real-valued roots and info[i] is the
78  // multiplicity of root corresponding to index i.
79  template <typename Rational>
80  static void GetRootInfoQuadratic(Rational const& p0, Rational const& p1,
81  Rational const& p2, std::vector<int>& info);
82 
83  template <typename Rational>
84  static void GetRootInfoCubic(Rational const& p0, Rational const& p1,
85  Rational const& p2, Rational const& p3, std::vector<int>& info);
86 
87  template <typename Rational>
88  static void GetRootInfoQuartic(Rational const& p0, Rational const& p1,
89  Rational const& p2, Rational const& p3, Rational const& p4,
90  std::vector<int>& info);
91 
92 
93  // General equations: sum_{i=0}^{d} c(i)*t^i = 0. The input array 'c'
94  // must have at least d+1 elements and the output array 'root' must have
95  // at least d elements.
96 
97  // Find the roots on (-infinity,+infinity).
98  static int Find(int degree, Real const* c, unsigned int maxIterations,
99  Real* roots);
100 
101  // If you know that p(tmin) * p(tmax) <= 0, then there must be at least
102  // one root in [tmin, tmax]. Compute it using bisection.
103  static bool Find(int degree, Real const* c, Real tmin, Real tmax,
104  unsigned int maxIterations, Real& root);
105 
106 private:
107  // Support for the Solve* functions.
108  template <typename Rational>
109  static void SolveDepressedQuadratic(Rational const& c0,
110  std::map<Rational, int>& rmMap);
111 
112  template <typename Rational>
113  static void SolveDepressedCubic(Rational const& c0, Rational const& c1,
114  std::map<Rational, int>& rmMap);
115 
116  template <typename Rational>
117  static void SolveDepressedQuartic(Rational const& c0, Rational const& c1,
118  Rational const& c2, std::map<Rational, int>& rmMap);
119 
120  template <typename Rational>
121  static void SolveBiquadratic(Rational const& c0, Rational const& c2,
122  std::map<Rational, int>& rmMap);
123 
124  // Support for the GetNumRoots* functions.
125  template <typename Rational>
126  static void GetRootInfoDepressedQuadratic(Rational const& c0,
127  std::vector<int>& info);
128 
129  template <typename Rational>
130  static void GetRootInfoDepressedCubic(Rational const& c0,
131  Rational const& c1, std::vector<int>& info);
132 
133  template <typename Rational>
134  static void GetRootInfoDepressedQuartic(Rational const& c0,
135  Rational const& c1, Rational const& c2, std::vector<int>& info);
136 
137  template <typename Rational>
138  static void GetRootInfoBiquadratic(Rational const& c0,
139  Rational const& c2, std::vector<int>& info);
140 
141  // Support for the Find functions.
142  static int FindRecursive(int degree, Real const* c, Real tmin, Real tmax,
143  unsigned int maxIterations, Real* roots);
144 
145  static Real Evaluate(int degree, Real const* c, Real t);
146 };
147 
148 // FOR INTERNAL USE ONLY. Do not define GTE_ROOTS_LOW_DEGREE_UNIT_TEST in
149 // your own code.
150 #if defined(GTE_ROOTS_LOW_DEGREE_UNIT_TEST)
151 extern void RootsLowDegreeBlock(int);
152 #define GTE_ROOTS_LOW_DEGREE_BLOCK(block) RootsLowDegreeBlock(block)
153 #else
154 #define GTE_ROOTS_LOW_DEGREE_BLOCK(block)
155 #endif
156 
157 
158 template <typename Real>
159 template <typename Rational>
161  Rational const& p1, Rational const& p2, std::map<Real, int>& rmMap)
162 {
163  Rational const rat2 = 2;
164  Rational q0 = p0 / p2;
165  Rational q1 = p1 / p2;
166  Rational q1half = q1 / rat2;
167  Rational c0 = q0 - q1half * q1half;
168 
169  std::map<Rational, int> rmLocalMap;
170  SolveDepressedQuadratic(c0, rmLocalMap);
171 
172  rmMap.clear();
173  for (auto& rm : rmLocalMap)
174  {
175  Rational root = rm.first - q1half;
176  rmMap.insert(std::make_pair((Real)root, rm.second));
177  }
178 }
179 
180 template <typename Real>
181 template <typename Rational>
182 void RootsPolynomial<Real>::SolveCubic(Rational const& p0,
183  Rational const& p1, Rational const& p2, Rational const& p3,
184  std::map<Real, int>& rmMap)
185 {
186  Rational const rat2 = 2, rat3 = 3;
187  Rational q0 = p0 / p3;
188  Rational q1 = p1 / p3;
189  Rational q2 = p2 / p3;
190  Rational q2third = q2 / rat3;
191  Rational c0 = q0 - q2third * (q1 - rat2 * q2third * q2third);
192  Rational c1 = q1 - q2 * q2third;
193 
194  std::map<Rational, int> rmLocalMap;
195  SolveDepressedCubic(c0, c1, rmLocalMap);
196 
197  rmMap.clear();
198  for (auto& rm : rmLocalMap)
199  {
200  Rational root = rm.first - q2third;
201  rmMap.insert(std::make_pair((Real)root, rm.second));
202  }
203 }
204 
205 template <typename Real>
206 template <typename Rational>
207 void RootsPolynomial<Real>::SolveQuartic(Rational const& p0,
208  Rational const& p1, Rational const& p2, Rational const& p3,
209  Rational const& p4, std::map<Real, int>& rmMap)
210 {
211  Rational const rat2 = 2, rat3 = 3, rat4 = 4, rat6 = 6;
212  Rational q0 = p0 / p4;
213  Rational q1 = p1 / p4;
214  Rational q2 = p2 / p4;
215  Rational q3 = p3 / p4;
216  Rational q3fourth = q3 / rat4;
217  Rational q3fourthSqr = q3fourth * q3fourth;
218  Rational c0 = q0 - q3fourth * (q1 - q3fourth * (q2 - q3fourthSqr * rat3));
219  Rational c1 = q1 - rat2 * q3fourth * (q2 - rat4 * q3fourthSqr);
220  Rational c2 = q2 - rat6 * q3fourthSqr;
221 
222  std::map<Rational, int> rmLocalMap;
223  SolveDepressedQuartic(c0, c1, c2, rmLocalMap);
224 
225  rmMap.clear();
226  for (auto& rm : rmLocalMap)
227  {
228  Rational root = rm.first - q3fourth;
229  rmMap.insert(std::make_pair((Real)root, rm.second));
230  }
231 }
232 
233 template <typename Real>
234 template <typename Rational>
236  Rational const& p1, Rational const& p2, std::vector<int>& info)
237 {
238  Rational const rat2 = 2;
239  Rational q0 = p0 / p2;
240  Rational q1 = p1 / p2;
241  Rational q1half = q1 / rat2;
242  Rational c0 = q0 - q1half * q1half;
243 
244  info.clear();
245  info.reserve(2);
247 }
248 
249 template <typename Real>
250 template <typename Rational>
252  Rational const& p1, Rational const& p2, Rational const& p3,
253  std::vector<int>& info)
254 {
255  Rational const rat2 = 2, rat3 = 3;
256  Rational q0 = p0 / p3;
257  Rational q1 = p1 / p3;
258  Rational q2 = p2 / p3;
259  Rational q2third = q2 / rat3;
260  Rational c0 = q0 - q2third * (q1 - rat2 * q2third * q2third);
261  Rational c1 = q1 - q2 * q2third;
262 
263  info.clear();
264  info.reserve(3);
265  GetRootInfoDepressedCubic(c0, c1, info);
266 }
267 
268 template <typename Real>
269 template <typename Rational>
271  Rational const& p1, Rational const& p2, Rational const& p3,
272  Rational const& p4, std::vector<int>& info)
273 {
274  Rational const rat2 = 2, rat3 = 3, rat4 = 4, rat6 = 6;
275  Rational q0 = p0 / p4;
276  Rational q1 = p1 / p4;
277  Rational q2 = p2 / p4;
278  Rational q3 = p3 / p4;
279  Rational q3fourth = q3 / rat4;
280  Rational q3fourthSqr = q3fourth * q3fourth;
281  Rational c0 = q0 - q3fourth * (q1 - q3fourth * (q2 - q3fourthSqr * rat3));
282  Rational c1 = q1 - rat2 * q3fourth * (q2 - rat4 * q3fourthSqr);
283  Rational c2 = q2 - rat6 * q3fourthSqr;
284 
285  info.clear();
286  info.reserve(4);
287  GetRootInfoDepressedQuartic(c0, c1, c2, info);
288 }
289 
290 template <typename Real>
291 int RootsPolynomial<Real>::Find(int degree, Real const* c,
292  unsigned int maxIterations, Real* roots)
293 {
294  if (degree >= 0 && c)
295  {
296  Real const zero = (Real)0;
297  while (degree >= 0 && c[degree] == zero)
298  {
299  --degree;
300  }
301 
302  if (degree > 0)
303  {
304  // Compute the Cauchy bound.
305  Real const one = (Real)1;
306  Real invLeading = one / c[degree];
307  Real maxValue = zero;
308  for (int i = 0; i < degree; ++i)
309  {
310  Real value = std::abs(c[i] * invLeading);
311  if (value > maxValue)
312  {
313  maxValue = value;
314  }
315  }
316  Real bound = one + maxValue;
317 
318  return FindRecursive(degree, c, -bound, bound, maxIterations,
319  roots);
320  }
321  else if (degree == 0)
322  {
323  // The polynomial is a nonzero constant.
324  return 0;
325  }
326  else
327  {
328  // The polynomial is identically zero.
329  roots[0] = zero;
330  return 1;
331  }
332  }
333  else
334  {
335  // Invalid degree or c.
336  return 0;
337  }
338 }
339 
340 template <typename Real>
341 bool RootsPolynomial<Real>::Find(int degree, Real const* c, Real tmin,
342  Real tmax, unsigned int maxIterations, Real& root)
343 {
344  Real const zero = (Real)0;
345  Real pmin = Evaluate(degree, c, tmin);
346  if (pmin == zero)
347  {
348  root = tmin;
349  return true;
350  }
351  Real pmax = Evaluate(degree, c, tmax);
352  if (pmax == zero)
353  {
354  root = tmax;
355  return true;
356  }
357 
358  if (pmin*pmax > zero)
359  {
360  // It is not known whether the interval bounds a root.
361  return false;
362  }
363 
364  if (tmin >= tmax)
365  {
366  // Invalid ordering of interval endpoitns.
367  return false;
368  }
369 
370  for (unsigned int i = 1; i <= maxIterations; ++i)
371  {
372  root = ((Real)0.5) * (tmin + tmax);
373 
374  // This test is designed for 'float' or 'double' when tmin and tmax
375  // are consecutive floating-point numbers.
376  if (root == tmin || root == tmax)
377  {
378  break;
379  }
380 
381  Real p = Evaluate(degree, c, root);
382  Real product = p * pmin;
383  if (product < zero)
384  {
385  tmax = root;
386  pmax = p;
387  }
388  else if (product > zero)
389  {
390  tmin = root;
391  pmin = p;
392  }
393  else
394  {
395  break;
396  }
397  }
398 
399  return true;
400 }
401 
402 template <typename Real>
403 template <typename Rational>
405  std::map<Rational, int>& rmMap)
406 {
407  Rational const zero = 0;
408  if (c0 < zero)
409  {
410  // Two simple roots.
411  Rational root1 = (Rational)sqrt(-(double)c0);
412  Rational root0 = -root1;
413  rmMap.insert(std::make_pair(root0, 1));
414  rmMap.insert(std::make_pair(root1, 1));
416  }
417  else if (c0 == zero)
418  {
419  // One double root.
420  rmMap.insert(std::make_pair(zero, 2));
422  }
423  else // c0 > 0
424  {
425  // A complex-conjugate pair of roots.
426  // Complex z0 = -q1/2 - i*sqrt(c0);
427  // Complex z0conj = -q1/2 + i*sqrt(c0);
429  }
430 }
431 
432 template <typename Real>
433 template <typename Rational>
435  Rational const& c1, std::map<Rational, int>& rmMap)
436 {
437  // Handle the special case of c0 = 0, in which case the polynomial
438  // reduces to a depressed quadratic.
439  Rational const zero = 0;
440  if (c0 == zero)
441  {
442  SolveDepressedQuadratic(c1, rmMap);
443  auto iter = rmMap.find(zero);
444  if (iter != rmMap.end())
445  {
446  // The quadratic has a root of zero, so the multiplicity must be
447  // increased.
448  ++iter->second;
450  }
451  else
452  {
453  // The quadratic does not have a root of zero. Insert the one
454  // for the cubic.
455  rmMap.insert(std::make_pair(zero, 1));
457  }
458  return;
459  }
460 
461  // Handle the special case of c0 != 0 and c1 = 0.
462  double const oneThird = 1.0 / 3.0;
463  if (c1 == zero)
464  {
465  // One simple real root.
466  Rational root0;
467  if (c0 > zero)
468  {
469  root0 = (Rational)-pow((double)c0, oneThird);
471  }
472  else
473  {
474  root0 = (Rational)pow(-(double)c0, oneThird);
476  }
477  rmMap.insert(std::make_pair(root0, 1));
478 
479  // One complex conjugate pair.
480  // Complex z0 = root0*(-1 - i*sqrt(3))/2;
481  // Complex z0conj = root0*(-1 + i*sqrt(3))/2;
482  return;
483  }
484 
485  // At this time, c0 != 0 and c1 != 0.
486  Rational const rat2 = 2, rat3 = 3, rat4 = 4, rat27 = 27, rat108 = 108;
487  Rational delta = -(rat4 * c1 * c1 * c1 + rat27 * c0 * c0);
488  if (delta > zero)
489  {
490  // Three simple roots.
491  Rational deltaDiv108 = delta / rat108;
492  Rational betaRe = -c0 / rat2;
493  Rational betaIm = (Rational)sqrt((double)deltaDiv108);
494  Rational theta = (Rational)atan2((double)betaIm, (double)betaRe);
495  Rational thetaDiv3 = theta / rat3;
496  double angle = (double)thetaDiv3;
497  Rational cs = (Rational)cos(angle);
498  Rational sn = (Rational)sin(angle);
499  Rational rhoSqr = betaRe * betaRe + betaIm * betaIm;
500  Rational rhoPowThird = (Rational)pow((double)rhoSqr, 1.0 / 6.0);
501  Rational temp0 = rhoPowThird * cs;
502  Rational temp1 = rhoPowThird * sn * (Rational)sqrt(3.0);
503  Rational root0 = rat2 * temp0;
504  Rational root1 = -temp0 - temp1;
505  Rational root2 = -temp0 + temp1;
506  rmMap.insert(std::make_pair(root0, 1));
507  rmMap.insert(std::make_pair(root1, 1));
508  rmMap.insert(std::make_pair(root2, 1));
510  }
511  else if (delta < zero)
512  {
513  // One simple root.
514  Rational deltaDiv108 = delta / rat108;
515  Rational temp0 = -c0 / rat2;
516  Rational temp1 = (Rational)sqrt(-(double)deltaDiv108);
517  Rational temp2 = temp0 - temp1;
518  Rational temp3 = temp0 + temp1;
519  if (temp2 >= zero)
520  {
521  temp2 = (Rational)pow((double)temp2, oneThird);
523  }
524  else
525  {
526  temp2 = (Rational)-pow(-(double)temp2, oneThird);
528  }
529  if (temp3 >= zero)
530  {
531  temp3 = (Rational)pow((double)temp3, oneThird);
533  }
534  else
535  {
536  temp3 = (Rational)-pow(-(double)temp3, oneThird);
538  }
539  Rational root0 = temp2 + temp3;
540  rmMap.insert(std::make_pair(root0, 1));
541 
542  // One complex conjugate pair.
543  // Complex z0 = (-root0 - i*sqrt(3*root0*root0+4*c1))/2;
544  // Complex z0conj = (-root0 + i*sqrt(3*root0*root0+4*c1))/2;
545  }
546  else // delta = 0
547  {
548  // One simple root and one double root.
549  Rational root0 = -rat3 * c0 / (rat2 * c1);
550  Rational root1 = -rat2 * root0;
551  rmMap.insert(std::make_pair(root0, 2));
552  rmMap.insert(std::make_pair(root1, 1));
554  }
555 }
556 
557 template <typename Real>
558 template <typename Rational>
560  Rational const& c1, Rational const& c2, std::map<Rational, int>& rmMap)
561 {
562  // Handle the special case of c0 = 0, in which case the polynomial
563  // reduces to a depressed cubic.
564  Rational const zero = 0;
565  if (c0 == zero)
566  {
567  SolveDepressedCubic(c1, c2, rmMap);
568  auto iter = rmMap.find(zero);
569  if (iter != rmMap.end())
570  {
571  // The cubic has a root of zero, so the multiplicity must be
572  // increased.
573  ++iter->second;
575  }
576  else
577  {
578  // The cubic does not have a root of zero. Insert the one
579  // for the quartic.
580  rmMap.insert(std::make_pair(zero, 1));
582  }
583  return;
584  }
585 
586  // Handle the special case of c1 = 0, in which case the quartic is a
587  // biquadratic x^4 + c1*x^2 + c0 = (x^2 + c2/2)^2 + (c0 - c2^2/4).
588  if (c1 == zero)
589  {
590  SolveBiquadratic(c0, c2, rmMap);
591  return;
592  }
593 
594  // At this time, c0 != 0 and c1 != 0, which is a requirement for the
595  // general solver that must use a root of a special cubic polynomial.
596  Rational const rat2 = 2, rat4 = 4, rat8 = 8, rat12 = 12, rat16 = 16;
597  Rational const rat27 = 27, rat36 = 36;
598  Rational c0sqr = c0 * c0, c1sqr = c1 * c1, c2sqr = c2 * c2;
599  Rational delta = c1sqr * (-rat27 * c1sqr + rat4 * c2 *
600  (rat36 * c0 - c2sqr)) + rat16 * c0 * (c2sqr * (c2sqr - rat8 * c0) +
601  rat16 * c0sqr);
602  Rational a0 = rat12 * c0 + c2sqr;
603  Rational a1 = rat4 * c0 - c2sqr;
604 
605  if (delta > zero)
606  {
607  if (c2 < zero && a1 < zero)
608  {
609  // Four simple real roots.
610  std::map<Real, int> rmCubicMap;
611  SolveCubic(c1sqr - rat4 * c0 * c2, rat8 * c0, rat4 * c2, -rat8,
612  rmCubicMap);
613  Rational t = (Rational)rmCubicMap.rbegin()->first;
614  Rational alphaSqr = rat2 * t - c2;
615  Rational alpha = (Rational)sqrt((double)alphaSqr);
616  double sgnC1;
617  if (c1 > zero)
618  {
619  sgnC1 = 1.0;
621  }
622  else
623  {
624  sgnC1 = -1.0;
626  }
627  Rational arg = t * t - c0;
628  Rational beta = (Rational)(sgnC1 * sqrt(std::max((double)arg, 0.0)));
629  Rational D0 = alphaSqr - rat4 * (t + beta);
630  Rational sqrtD0 = (Rational)sqrt(std::max((double)D0, 0.0));
631  Rational D1 = alphaSqr - rat4 * (t - beta);
632  Rational sqrtD1 = (Rational)sqrt(std::max((double)D1, 0.0));
633  Rational root0 = (alpha - sqrtD0) / rat2;
634  Rational root1 = (alpha + sqrtD0) / rat2;
635  Rational root2 = (-alpha - sqrtD1) / rat2;
636  Rational root3 = (-alpha + sqrtD1) / rat2;
637  rmMap.insert(std::make_pair(root0, 1));
638  rmMap.insert(std::make_pair(root1, 1));
639  rmMap.insert(std::make_pair(root2, 1));
640  rmMap.insert(std::make_pair(root3, 1));
641  }
642  else // c2 >= 0 or a1 >= 0
643  {
644  // Two complex-conjugate pairs. The values alpha, D0, and D1 are
645  // those of the if-block.
646  // Complex z0 = (alpha - i*sqrt(-D0))/2;
647  // Complex z0conj = (alpha + i*sqrt(-D0))/2;
648  // Complex z1 = (-alpha - i*sqrt(-D1))/2;
649  // Complex z1conj = (-alpha + i*sqrt(-D1))/2;
651  }
652  }
653  else if (delta < zero)
654  {
655  // Two simple real roots, one complex-conjugate pair.
656  std::map<Real, int> rmCubicMap;
657  SolveCubic(c1sqr - rat4 * c0 * c2, rat8 * c0, rat4 * c2, -rat8,
658  rmCubicMap);
659  Rational t = (Rational)rmCubicMap.rbegin()->first;
660  Rational alphaSqr = rat2 * t - c2;
661  Rational alpha = (Rational)sqrt(std::max((double)alphaSqr, 0.0));
662  double sgnC1;
663  if (c1 > zero)
664  {
665  sgnC1 = 1.0; // Leads to BLOCK(18)
666  }
667  else
668  {
669  sgnC1 = -1.0; // Leads to BLOCK(19)
670  }
671  Rational arg = t * t - c0;
672  Rational beta = (Rational)(sgnC1 * sqrt(std::max((double)arg, 0.0)));
673  Rational root0, root1;
674  if (sgnC1 > 0.0)
675  {
676  Rational D1 = alphaSqr - rat4 * (t - beta);
677  Rational sqrtD1 = (Rational)sqrt(std::max((double)D1, 0.0));
678  root0 = (-alpha - sqrtD1) / rat2;
679  root1 = (-alpha + sqrtD1) / rat2;
680 
681  // One complex conjugate pair.
682  // Complex z0 = (alpha - i*sqrt(-D0))/2;
683  // Complex z0conj = (alpha + i*sqrt(-D0))/2;
685  }
686  else
687  {
688  Rational D0 = alphaSqr - rat4 * (t + beta);
689  Rational sqrtD0 = (Rational)sqrt(std::max((double)D0, 0.0));
690  root0 = (alpha - sqrtD0) / rat2;
691  root1 = (alpha + sqrtD0) / rat2;
692 
693  // One complex conjugate pair.
694  // Complex z0 = (-alpha - i*sqrt(-D1))/2;
695  // Complex z0conj = (-alpha + i*sqrt(-D1))/2;
697  }
698  rmMap.insert(std::make_pair(root0, 1));
699  rmMap.insert(std::make_pair(root1, 1));
700  }
701  else // delta = 0
702  {
703  if (a1 > zero || (c2 > zero && (a1 != zero || c1 != zero)))
704  {
705  // One double real root, one complex-conjugate pair.
706  Rational const rat9 = 9;
707  Rational root0 = -c1 * a0 / (rat9 * c1sqr - rat2 * c2 * a1);
708  rmMap.insert(std::make_pair(root0, 2));
709 
710  // One complex conjugate pair.
711  // Complex z0 = -root0 - i*sqrt(c2 + root0^2);
712  // Complex z0conj = -root0 + i*sqrt(c2 + root0^2);
714  }
715  else
716  {
717  Rational const rat3 = 3;
718  if (a0 != zero)
719  {
720  // One double real root, two simple real roots.
721  Rational const rat9 = 9;
722  Rational root0 = -c1 * a0 / (rat9 * c1sqr - rat2 * c2 * a1);
723  Rational alpha = rat2 * root0;
724  Rational beta = c2 + rat3 * root0 * root0;
725  Rational discr = alpha * alpha - rat4 * beta;
726  Rational temp1 = (Rational)sqrt((double)discr);
727  Rational root1 = (-alpha - temp1) / rat2;
728  Rational root2 = (-alpha + temp1) / rat2;
729  rmMap.insert(std::make_pair(root0, 2));
730  rmMap.insert(std::make_pair(root1, 1));
731  rmMap.insert(std::make_pair(root2, 1));
733  }
734  else
735  {
736  // One triple real root, one simple real root.
737  Rational root0 = -rat3 * c1 / (rat4 * c2);
738  Rational root1 = -rat3 * root0;
739  rmMap.insert(std::make_pair(root0, 3));
740  rmMap.insert(std::make_pair(root1, 1));
742  }
743  }
744  }
745 }
746 
747 template <typename Real>
748 template <typename Rational>
750  Rational const& c2, std::map<Rational, int>& rmMap)
751 {
752  // Solve 0 = x^4 + c2*x^2 + c0 = (x^2 + c2/2)^2 + a1, where
753  // a1 = c0 - c2^2/2. We know that c0 != 0 at the time of the function
754  // call, so x = 0 is not a root. The condition c1 = 0 implies the quartic
755  // Delta = 256*c0*a1^2.
756 
757  Rational const zero = 0, rat2 = 2, rat256 = 256;
758  Rational c2Half = c2 / rat2;
759  Rational a1 = c0 - c2Half * c2Half;
760  Rational delta = rat256 * c0 * a1 * a1;
761  if (delta > zero)
762  {
763  if (c2 < zero)
764  {
765  if (a1 < zero)
766  {
767  // Four simple roots.
768  Rational temp0 = (Rational)sqrt(-(double)a1);
769  Rational temp1 = -c2Half - temp0;
770  Rational temp2 = -c2Half + temp0;
771  Rational root1 = (Rational)sqrt((double)temp1);
772  Rational root0 = -root1;
773  Rational root2 = (Rational)sqrt((double)temp2);
774  Rational root3 = -root2;
775  rmMap.insert(std::make_pair(root0, 1));
776  rmMap.insert(std::make_pair(root1, 1));
777  rmMap.insert(std::make_pair(root2, 1));
778  rmMap.insert(std::make_pair(root3, 1));
780  }
781  else // a1 > 0
782  {
783  // Two simple complex conjugate pairs.
784  // double thetaDiv2 = atan2(sqrt(a1), -c2/2) / 2.0;
785  // double cs = cos(thetaDiv2), sn = sin(thetaDiv2);
786  // double length = pow(c0, 0.25);
787  // Complex z0 = length*(cs + i*sn);
788  // Complex z0conj = length*(cs - i*sn);
789  // Complex z1 = length*(-cs + i*sn);
790  // Complex z1conj = length*(-cs - i*sn);
792  }
793  }
794  else // c2 >= 0
795  {
796  // Two simple complex conjugate pairs.
797  // Complex z0 = -i*sqrt(c2/2 - sqrt(-a1));
798  // Complex z0conj = +i*sqrt(c2/2 - sqrt(-a1));
799  // Complex z1 = -i*sqrt(c2/2 + sqrt(-a1));
800  // Complex z1conj = +i*sqrt(c2/2 + sqrt(-a1));
802  }
803  }
804  else if (delta < zero)
805  {
806  // Two simple real roots.
807  Rational temp0 = (Rational)sqrt(-(double)a1);
808  Rational temp1 = -c2Half + temp0;
809  Rational root1 = (Rational)sqrt((double)temp1);
810  Rational root0 = -root1;
811  rmMap.insert(std::make_pair(root0, 1));
812  rmMap.insert(std::make_pair(root1, 1));
813 
814  // One complex conjugate pair.
815  // Complex z0 = -i*sqrt(c2/2 + sqrt(-a1));
816  // Complex z0conj = +i*sqrt(c2/2 + sqrt(-a1));
818  }
819  else // delta = 0
820  {
821  if (c2 < zero)
822  {
823  // Two double real roots.
824  Rational root1 = (Rational)sqrt(-(double)c2Half);
825  Rational root0 = -root1;
826  rmMap.insert(std::make_pair(root0, 2));
827  rmMap.insert(std::make_pair(root1, 2));
829  }
830  else // c2 > 0
831  {
832  // Two double complex conjugate pairs.
833  // Complex z0 = -i*sqrt(c2/2); // multiplicity 2
834  // Complex z0conj = +i*sqrt(c2/2); // multiplicity 2
836  }
837  }
838 }
839 
840 template <typename Real>
841 template <typename Rational>
843  std::vector<int>& info)
844 {
845  Rational const zero = 0;
846  if (c0 < zero)
847  {
848  // Two simple roots.
849  info.push_back(1);
850  info.push_back(1);
851  }
852  else if (c0 == zero)
853  {
854  // One double root.
855  info.push_back(2); // root is zero
856  }
857  else // c0 > 0
858  {
859  // A complex-conjugate pair of roots.
860  }
861 }
862 
863 template <typename Real>
864 template <typename Rational>
866  Rational const& c1, std::vector<int>& info)
867 {
868  // Handle the special case of c0 = 0, in which case the polynomial
869  // reduces to a depressed quadratic.
870  Rational const zero = 0;
871  if (c0 == zero)
872  {
873  if (c1 == zero)
874  {
875  info.push_back(3); // triple root of zero
876  }
877  else
878  {
879  info.push_back(1); // simple root of zero
881  }
882  return;
883  }
884 
885  Rational const rat4 = 4, rat27 = 27;
886  Rational delta = -(rat4 * c1 * c1 * c1 + rat27 * c0 * c0);
887  if (delta > zero)
888  {
889  // Three simple real roots.
890  info.push_back(1);
891  info.push_back(1);
892  info.push_back(1);
893  }
894  else if (delta < zero)
895  {
896  // One simple real root.
897  info.push_back(1);
898  }
899  else // delta = 0
900  {
901  // One simple real root and one double real root.
902  info.push_back(1);
903  info.push_back(2);
904  }
905 }
906 
907 template <typename Real>
908 template <typename Rational>
910  Rational const& c1, Rational const& c2, std::vector<int>& info)
911 {
912  // Handle the special case of c0 = 0, in which case the polynomial
913  // reduces to a depressed cubic.
914  Rational const zero = 0;
915  if (c0 == zero)
916  {
917  if (c1 == zero)
918  {
919  if (c2 == zero)
920  {
921  info.push_back(4); // quadruple root of zero
922  }
923  else
924  {
925  info.push_back(2); // double root of zero
927  }
928  }
929  else
930  {
931  info.push_back(1); // simple root of zero
932  GetRootInfoDepressedCubic(c1, c2, info);
933  }
934  return;
935  }
936 
937  // Handle the special case of c1 = 0, in which case the quartic is a
938  // biquadratic x^4 + c1*x^2 + c0 = (x^2 + c2/2)^2 + (c0 - c2^2/4).
939  if (c1 == zero)
940  {
941  GetRootInfoBiquadratic(c0, c2, info);
942  return;
943  }
944 
945  // At this time, c0 != 0 and c1 != 0, which is a requirement for the
946  // general solver that must use a root of a special cubic polynomial.
947  Rational const rat4 = 4, rat8 = 8, rat12 = 12, rat16 = 16;
948  Rational const rat27 = 27, rat36 = 36;
949  Rational c0sqr = c0 * c0, c1sqr = c1 * c1, c2sqr = c2 * c2;
950  Rational delta = c1sqr * (-rat27 * c1sqr + rat4 * c2 *
951  (rat36 * c0 - c2sqr)) + rat16 * c0 * (c2sqr * (c2sqr - rat8 * c0) +
952  rat16 * c0sqr);
953  Rational a0 = rat12 * c0 + c2sqr;
954  Rational a1 = rat4 * c0 - c2sqr;
955 
956  if (delta > zero)
957  {
958  if (c2 < zero && a1 < zero)
959  {
960  // Four simple real roots.
961  info.push_back(1);
962  info.push_back(1);
963  info.push_back(1);
964  info.push_back(1);
965  }
966  else // c2 >= 0 or a1 >= 0
967  {
968  // Two complex-conjugate pairs.
969  }
970  }
971  else if (delta < zero)
972  {
973  // Two simple real roots, one complex-conjugate pair.
974  info.push_back(1);
975  info.push_back(1);
976  }
977  else // delta = 0
978  {
979  if (a1 > zero || (c2 > zero && (a1 != zero || c1 != zero)))
980  {
981  // One double real root, one complex-conjugate pair.
982  info.push_back(2);
983  }
984  else
985  {
986  if (a0 != zero)
987  {
988  // One double real root, two simple real roots.
989  info.push_back(2);
990  info.push_back(1);
991  info.push_back(1);
992  }
993  else
994  {
995  // One triple real root, one simple real root.
996  info.push_back(3);
997  info.push_back(1);
998  }
999  }
1000  }
1001 }
1002 
1003 template <typename Real>
1004 template <typename Rational>
1006  Rational const& c2, std::vector<int>& info)
1007 {
1008  // Solve 0 = x^4 + c2*x^2 + c0 = (x^2 + c2/2)^2 + a1, where
1009  // a1 = c0 - c2^2/2. We know that c0 != 0 at the time of the function
1010  // call, so x = 0 is not a root. The condition c1 = 0 implies the quartic
1011  // Delta = 256*c0*a1^2.
1012 
1013  Rational const zero = 0, rat2 = 2, rat256 = 256;
1014  Rational c2Half = c2 / rat2;
1015  Rational a1 = c0 - c2Half * c2Half;
1016  Rational delta = rat256 * c0 * a1 * a1;
1017  if (delta > zero)
1018  {
1019  if (c2 < zero)
1020  {
1021  if (a1 < zero)
1022  {
1023  // Four simple roots.
1024  info.push_back(1);
1025  info.push_back(1);
1026  info.push_back(1);
1027  info.push_back(1);
1028  }
1029  else // a1 > 0
1030  {
1031  // Two simple complex conjugate pairs.
1032  }
1033  }
1034  else // c2 >= 0
1035  {
1036  // Two simple complex conjugate pairs.
1037  }
1038  }
1039  else if (delta < zero)
1040  {
1041  // Two simple real roots, one complex conjugate pair.
1042  info.push_back(1);
1043  info.push_back(1);
1044  }
1045  else // delta = 0
1046  {
1047  if (c2 < zero)
1048  {
1049  // Two double real roots.
1050  info.push_back(2);
1051  info.push_back(2);
1052  }
1053  else // c2 > 0
1054  {
1055  // Two double complex conjugate pairs.
1056  }
1057  }
1058 }
1059 
1060 template <typename Real>
1061 int RootsPolynomial<Real>::FindRecursive(int degree, Real const* c,
1062  Real tmin, Real tmax, unsigned int maxIterations, Real* roots)
1063 {
1064  // The base of the recursion.
1065  Real const zero = (Real)0;
1066  Real root = zero;
1067  if (degree == 1)
1068  {
1069  int numRoots;
1070  if (c[1] != zero)
1071  {
1072  root = -c[0] / c[1];
1073  numRoots = 1;
1074  }
1075  else if (c[0] == zero)
1076  {
1077  root = zero;
1078  numRoots = 1;
1079  }
1080  else
1081  {
1082  numRoots = 0;
1083  }
1084 
1085  if (numRoots > 0 && tmin <= root && root <= tmax)
1086  {
1087  roots[0] = root;
1088  return 1;
1089  }
1090  return 0;
1091  }
1092 
1093  // Find the roots of the derivative polynomial scaled by 1/degree. The
1094  // scaling avoids the factorial growth in the coefficients; for example,
1095  // without the scaling, the high-order term x^d becomes (d!)*x through
1096  // multiple differentiations. With the scaling we instead get x. This
1097  // leads to better numerical behavior of the root finder.
1098  int derivDegree = degree - 1;
1099  std::vector<Real> derivCoeff(derivDegree + 1);
1100  std::vector<Real> derivRoots(derivDegree);
1101  for (int i = 0; i <= derivDegree; ++i)
1102  {
1103  derivCoeff[i] = c[i + 1] * (Real)(i + 1) / (Real)degree;
1104  }
1105  int numDerivRoots = FindRecursive(degree - 1, &derivCoeff[0], tmin, tmax,
1106  maxIterations, &derivRoots[0]);
1107 
1108  int numRoots = 0;
1109  if (numDerivRoots > 0)
1110  {
1111  // Find root on [tmin,derivRoots[0]].
1112  if (Find(degree, c, tmin, derivRoots[0], maxIterations, root))
1113  {
1114  roots[numRoots++] = root;
1115  }
1116 
1117  // Find root on [derivRoots[i],derivRoots[i+1]].
1118  for (int i = 0; i <= numDerivRoots - 2; ++i)
1119  {
1120  if (Find(degree, c, derivRoots[i], derivRoots[i + 1],
1121  maxIterations, root))
1122  {
1123  roots[numRoots++] = root;
1124  }
1125  }
1126 
1127  // Find root on [derivRoots[numDerivRoots-1],tmax].
1128  if (Find(degree, c, derivRoots[numDerivRoots - 1], tmax,
1129  maxIterations, root))
1130  {
1131  roots[numRoots++] = root;
1132  }
1133  }
1134  else
1135  {
1136  // The polynomial is monotone on [tmin,tmax], so has at most one root.
1137  if (Find(degree, c, tmin, tmax, maxIterations, root))
1138  {
1139  roots[numRoots++] = root;
1140  }
1141  }
1142  return numRoots;
1143 }
1144 
1145 template <typename Real>
1146 Real RootsPolynomial<Real>::Evaluate(int degree, Real const* c, Real t)
1147 {
1148  int i = degree;
1149  Real result = c[i];
1150  while (--i >= 0)
1151  {
1152  result = t * result + c[i];
1153  }
1154  return result;
1155 }
1156 
1157 
1158 }
static int FindRecursive(int degree, Real const *c, Real tmin, Real tmax, unsigned int maxIterations, Real *roots)
GLfloat GLfloat GLfloat alpha
Definition: glcorearb.h:107
gte::BSNumber< UIntegerType > abs(gte::BSNumber< UIntegerType > const &number)
Definition: GteBSNumber.h:966
static void GetRootInfoCubic(Rational const &p0, Rational const &p1, Rational const &p2, Rational const &p3, std::vector< int > &info)
static void SolveDepressedQuadratic(Rational const &c0, std::map< Rational, int > &rmMap)
GLfloat angle
Definition: glext.h:6466
GLsizei const GLfloat * value
Definition: glcorearb.h:819
static void GetRootInfoDepressedQuadratic(Rational const &c0, std::vector< int > &info)
static void GetRootInfoQuartic(Rational const &p0, Rational const &p1, Rational const &p2, Rational const &p3, Rational const &p4, std::vector< int > &info)
const GLubyte * c
Definition: glext.h:11671
#define GTE_ROOTS_LOW_DEGREE_BLOCK(block)
static void SolveBiquadratic(Rational const &c0, Rational const &c2, std::map< Rational, int > &rmMap)
static void SolveQuadratic(Rational const &p0, Rational const &p1, Rational const &p2, std::map< Real, int > &rmMap)
static void GetRootInfoBiquadratic(Rational const &c0, Rational const &c2, std::vector< int > &info)
static void SolveDepressedQuartic(Rational const &c0, Rational const &c1, Rational const &c2, std::map< Rational, int > &rmMap)
static void GetRootInfoDepressedCubic(Rational const &c0, Rational const &c1, std::vector< int > &info)
static Real Evaluate(int degree, Real const *c, Real t)
static void GetRootInfoDepressedQuartic(Rational const &c0, Rational const &c1, Rational const &c2, std::vector< int > &info)
GLdouble GLdouble t
Definition: glext.h:239
static void GetRootInfoQuadratic(Rational const &p0, Rational const &p1, Rational const &p2, std::vector< int > &info)
static void SolveQuartic(Rational const &p0, Rational const &p1, Rational const &p2, Rational const &p3, Rational const &p4, std::map< Real, int > &rmMap)
GLfloat GLfloat p
Definition: glext.h:11668
GLuint64EXT * result
Definition: glext.h:10003
static void SolveCubic(Rational const &p0, Rational const &p1, Rational const &p2, Rational const &p3, std::map< Real, int > &rmMap)
static int Find(int degree, Real const *c, unsigned int maxIterations, Real *roots)
static void SolveDepressedCubic(Rational const &c0, Rational const &c1, std::map< Rational, int > &rmMap)


geometric_tools_engine
Author(s): Yijiang Huang
autogenerated on Thu Jul 18 2019 04:00:01