GteCubicRootsQR.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 <array>
11 #include <cmath>
12 #include <cstdint>
13 
14 // An implementation of the QR algorithm described in "Matrix Computations,
15 // 2nd edition" by G. H. Golub and C. F. Van Loan, The Johns Hopkins
16 // University Press, Baltimore MD, Fourth Printing 1993. In particular,
17 // the implementation is based on Chapter 7 (The Unsymmetric Eigenvalue
18 // Problem), Section 7.5 (The Practical QR Algorithm). The algorithm is
19 // specialized for the companion matrix associated with a cubic polynomial.
20 
21 namespace gte
22 {
23 
24 template <typename Real>
26 {
27 public:
28  typedef std::array<std::array<Real, 3>, 3> Matrix;
29 
30  // Solve p(x) = c0 + c1 * x + c2 * x^2 + x^3 = 0.
31  uint32_t operator() (uint32_t maxIterations, Real c0, Real c1, Real c2,
32  uint32_t& numRoots, std::array<Real, 3>& roots);
33 
34  // Compute the real eigenvalues of the upper Hessenberg matrix A. The
35  // matrix is modified by in-place operations, so if you need to remember
36  // A, you must make your own copy before calling this function.
37  uint32_t operator() (uint32_t maxIterations, Matrix& A,
38  uint32_t& numRoots, std::array<Real, 3>& roots);
39 
40 private:
41  void DoIteration(std::array<Real, 3> const& V, Matrix& A);
42 
43  template <int N>
44  std::array<Real, N> House(std::array<Real, N> const& X);
45 
46  template <int N>
47  void RowHouse(int rmin, int rmax, int cmin, int cmax,
48  std::array<Real, N> const& V, std::array<Real, N> const& MV, Matrix& A);
49 
50  template <int N>
51  void ColHouse(int rmin, int rmax, int cmin, int cmax,
52  std::array<Real, N> const& V, std::array<Real, N> const& MV, Matrix& A);
53 
54  void GetQuadraticRoots(int i0, int i1, Matrix const & A,
55  uint32_t& numRoots, std::array<Real, 3>& roots);
56 };
57 
58 
59 template <typename Real>
60 uint32_t CubicRootsQR<Real>::operator() (uint32_t maxIterations, Real c0, Real c1, Real c2,
61  uint32_t& numRoots, std::array<Real, 3>& roots)
62 {
63  // Create the companion matrix for the polynomial. The matrix is in upper
64  // Hessenberg form.
65  Matrix A;
66  A[0][0] = (Real)0;
67  A[0][1] = (Real)0;
68  A[0][2] = -c0;
69  A[1][0] = (Real)1;
70  A[1][1] = (Real)0;
71  A[1][2] = -c1;
72  A[2][0] = (Real)0;
73  A[2][1] = (Real)1;
74  A[2][2] = -c2;
75 
76  // Avoid the QR-cycle when c1 = c2 = 0 and avoid the slow convergence
77  // when c1 and c2 are nearly zero.
78  std::array<Real, 3> V{
79  (Real)1,
80  (Real)0.36602540378443865,
81  (Real)0.36602540378443865 };
82  DoIteration(V, A);
83 
84  return operator()(maxIterations, A, numRoots, roots);
85 }
86 
87 template <typename Real>
88 uint32_t CubicRootsQR<Real>::operator() (uint32_t maxIterations, Matrix& A,
89  uint32_t& numRoots, std::array<Real, 3>& roots)
90 {
91  numRoots = 0;
92  std::fill(roots.begin(), roots.end(), (Real)0);
93 
94  for (uint32_t numIterations = 0; numIterations < maxIterations; ++numIterations)
95  {
96  // Apply a Francis QR iteration.
97  Real tr = A[1][1] + A[2][2];
98  Real det = A[1][1] * A[2][2] - A[1][2] * A[2][1];
99  std::array<Real, 3> X{
100  A[0][0] * A[0][0] + A[0][1] * A[1][0] - tr * A[0][0] + det,
101  A[1][0] * (A[0][0] + A[1][1] - tr),
102  A[1][0] * A[2][1] };
103  std::array<Real, 3> V = House<3>(X);
104  DoIteration(V, A);
105 
106  // Test for uncoupling of A.
107  Real tr01 = A[0][0] + A[1][1];
108  if (tr01 + A[1][0] == tr01)
109  {
110  numRoots = 1;
111  roots[0] = A[0][0];
112  GetQuadraticRoots(1, 2, A, numRoots, roots);
113  return numIterations;
114  }
115 
116  Real tr12 = A[1][1] + A[2][2];
117  if (tr12 + A[2][1] == tr12)
118  {
119  numRoots = 1;
120  roots[0] = A[2][2];
121  GetQuadraticRoots(0, 1, A, numRoots, roots);
122  return numIterations;
123  }
124  }
125  return maxIterations;
126 }
127 
128 template <typename Real>
129 void CubicRootsQR<Real>::DoIteration(std::array<Real, 3> const& V, Matrix& A)
130 {
131  Real multV = ((Real)-2) / (V[0] * V[0] + V[1] * V[1] + V[2] * V[2]);
132  std::array<Real, 3> MV{ multV * V[0], multV * V[1], multV * V[2] };
133  RowHouse<3>(0, 2, 0, 2, V, MV, A);
134  ColHouse<3>(0, 2, 0, 2, V, MV, A);
135 
136  std::array<Real, 2> Y{ A[1][0], A[2][0] };
137  std::array<Real, 2> W = House<2>(Y);
138  Real multW = ((Real)-2) / (W[0] * W[0] + W[1] * W[1]);
139  std::array<Real, 2> MW{ multW * W[0], multW * W[1] };
140  RowHouse<2>(1, 2, 0, 2, W, MW, A);
141  ColHouse<2>(0, 2, 1, 2, W, MW, A);
142 }
143 
144 template <typename Real>
145 template <int N>
146 std::array<Real, N> CubicRootsQR<Real>::House(std::array<Real, N> const & X)
147 {
148  std::array<Real, N> V;
149  Real length = (Real)0;
150  for (int i = 0; i < N; ++i)
151  {
152  length += X[i] * X[i];
153  }
154  length = sqrt(length);
155  if (length != (Real)0)
156  {
157  Real sign = (X[0] >= (Real)0 ? (Real)1 : (Real)-1);
158  Real denom = X[0] + sign * length;
159  for (int i = 1; i < N; ++i)
160  {
161  V[i] = X[i] / denom;
162  }
163  }
164  V[0] = (Real)1;
165  return V;
166 }
167 
168 template <typename Real>
169 template <int N>
170 void CubicRootsQR<Real>::RowHouse(int rmin, int rmax, int cmin, int cmax,
171  std::array<Real, N> const& V, std::array<Real, N> const& MV, Matrix& A)
172 {
173  std::array<Real, 3> W; // only elements cmin through cmax are used
174 
175  for (int c = cmin; c <= cmax; ++c)
176  {
177  W[c] = (Real)0;
178  for (int r = rmin, k = 0; r <= rmax; ++r, ++k)
179  {
180  W[c] += V[k] * A[r][c];
181  }
182  }
183 
184  for (int r = rmin, k = 0; r <= rmax; ++r, ++k)
185  {
186  for (int c = cmin; c <= cmax; ++c)
187  {
188  A[r][c] += MV[k] * W[c];
189  }
190  }
191 }
192 
193 template <typename Real>
194 template <int N>
195 void CubicRootsQR<Real>::ColHouse(int rmin, int rmax, int cmin, int cmax,
196  std::array<Real, N> const& V, std::array<Real, N> const& MV, Matrix& A)
197 {
198  std::array<Real, 3> W; // only elements rmin through rmax are used
199 
200  for (int r = rmin; r <= rmax; ++r)
201  {
202  W[r] = (Real)0;
203  for (int c = cmin, k = 0; c <= cmax; ++c, ++k)
204  {
205  W[r] += V[k] * A[r][c];
206  }
207  }
208 
209  for (int r = rmin; r <= rmax; ++r)
210  {
211  for (int c = cmin, k = 0; c <= cmax; ++c, ++k)
212  {
213  A[r][c] += W[r] * MV[k];
214  }
215  }
216 }
217 
218 template <typename Real>
219 void CubicRootsQR<Real>::GetQuadraticRoots(int i0, int i1, Matrix const& A,
220  uint32_t& numRoots, std::array<Real, 3>& roots)
221 {
222  // Solve x^2 - t * x + d = 0, where t is the trace and d is the
223  // determinant of the 2x2 matrix defined by indices i0 and i1. The
224  // discriminant is D = (t/2)^2 - d. When D >= 0, the roots are real
225  // values t/2 - sqrt(D) and t/2 + sqrt(D). To avoid potential numerical
226  // issues with subtractive cancellation, the roots are computed as
227  // r0 = t/2 + sign(t/2)*sqrt(D), r1 = trace - r0.
228  Real trace = A[i0][i0] + A[i1][i1];
229  Real halfTrace = trace * (Real)0.5;
230  Real determinant = A[i0][i0] * A[i1][i1] - A[i0][i1] * A[i1][i0];
231  Real discriminant = halfTrace * halfTrace - determinant;
232  if (discriminant >= (Real)0)
233  {
234  Real sign = (trace >= (Real)0 ? (Real)1 : (Real)-1);
235  Real root = halfTrace + sign * sqrt(discriminant);
236  roots[numRoots++] = root;
237  roots[numRoots++] = trace - root;
238  }
239 }
240 
241 }
void GetQuadraticRoots(int i0, int i1, Matrix const &A, uint32_t &numRoots, std::array< Real, 3 > &roots)
const GLubyte * c
Definition: glext.h:11671
void ColHouse(int rmin, int rmax, int cmin, int cmax, std::array< Real, N > const &V, std::array< Real, N > const &MV, Matrix &A)
GLuint GLsizei GLsizei * length
Definition: glcorearb.h:790
std::array< Real, N > House(std::array< Real, N > const &X)
GLboolean r
Definition: glcorearb.h:1217
void DoIteration(std::array< Real, 3 > const &V, Matrix &A)
std::array< std::array< Real, 3 >, 3 > Matrix
void RowHouse(int rmin, int rmax, int cmin, int cmax, std::array< Real, N > const &V, std::array< Real, N > const &MV, Matrix &A)
uint32_t operator()(uint32_t maxIterations, Real c0, Real c1, Real c2, uint32_t &numRoots, std::array< Real, 3 > &roots)


geometric_tools_engine
Author(s): Yijiang Huang
autogenerated on Thu Jul 18 2019 03:59:59