GteLinearSystem.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 <LowLevel/GteWrapper.h>
15 #include <map>
16 
17 // Solve linear systems of equations where the matrix A is NxN. The return
18 // value of a function is 'true' when A is invertible. In this case the
19 // solution X and the solution is valid. If the return value is 'false', A
20 // is not invertible and X and Y are invalid, so do not use them. When a
21 // matrix is passed as Real*, the storage order is assumed to be the one
22 // consistent with your choice of GTE_USE_ROW_MAJOR or GTE_USE_COL_MAJOR.
23 //
24 // The linear solvers that use the conjugate gradient algorithm are based
25 // on the discussion in "Matrix Computations, 2nd edition" by G. H. Golub
26 // and Charles F. Van Loan, The Johns Hopkins Press, Baltimore MD, Fourth
27 // Printing 1993.
28 
29 namespace gte
30 {
31 
32 template <typename Real>
34 {
35 public:
36  // Solve 2x2, 3x3, and 4x4 systems by inverting the matrix directly. This
37  // avoids the overhead of Gaussian elimination in small dimensions.
38  static bool Solve(Matrix2x2<Real> const& A, Vector2<Real> const& B,
39  Vector2<Real>& X);
40 
41  static bool Solve(Matrix3x3<Real> const& A, Vector3<Real> const& B,
42  Vector3<Real>& X);
43 
44  static bool Solve(Matrix4x4<Real> const& A, Vector4<Real> const& B,
45  Vector4<Real>& X);
46 
47  // Solve A*X = B, where B is Nx1 and the solution X is Nx1.
48  static bool Solve(int N, Real const* A, Real const* B, Real* X);
49 
50  // Solve A*X = B, where B is NxM and the solution X is NxM.
51  static bool Solve(int N, int M, Real const* A, Real const* B, Real* X);
52 
53  // Solve A*X = B, where A is tridiagonal. The function expects the
54  // subdiagonal, diagonal, and superdiagonal of A. The diagonal input
55  // must have N elements. The subdiagonal and superdiagonal inputs must
56  // have N-1 elements.
57  static bool SolveTridiagonal(int N, Real const* subdiagonal,
58  Real const* diagonal, Real const* superdiagonal, Real const* B,
59  Real* X);
60 
61  // Solve A*X = B, where A is tridiagonal. The function expects the
62  // subdiagonal, diagonal, and superdiagonal of A. Moreover, the
63  // subdiagonal elements are a constant, the diagonal elements are a
64  // constant, and the superdiagonal elements are a constant.
65  static bool SolveConstantTridiagonal(int N, Real subdiagonal,
66  Real diagonal, Real superdiagonal, Real const* B, Real* X);
67 
68  // Solve A*X = B using the conjugate gradient method, where A is
69  // symmetric. You must specify the maximum number of iterations and a
70  // tolerance for terminating the iterations. Reasonable choices for
71  // tolerance are 1e-06f for 'float' or 1e-08 for 'double'.
72  static unsigned int SolveSymmetricCG(int N, Real const* A, Real const* B,
73  Real* X, unsigned int maxIterations, Real tolerance);
74 
75  // Solve A*X = B using the conjugate gradient method, where A is sparse
76  // and symmetric. The nonzero entries of the symmetrix matrix A are
77  // stored in a map whose keys are pairs (i,j) and whose values are real
78  // numbers. The pair (i,j) is the location of the value in the array.
79  // Only one of (i,j) and (j,i) should be stored since A is symmetric.
80  // The column vector B is stored as an array of contiguous values. You
81  // must specify the maximum number of iterations and a tolerance for
82  // terminating the iterations. Reasonable choices for tolerance are
83  // 1e-06f for 'float' or 1e-08 for 'double'.
84  typedef std::map<std::array<int, 2>, Real> SparseMatrix;
85  static unsigned int SolveSymmetricCG(int N, SparseMatrix const& A,
86  Real const* B, Real* X, unsigned int maxIterations, Real tolerance);
87 
88 private:
89  // Support for the conjugate gradient method.
90  static Real Dot(int N, Real const* U, Real const* V);
91  static void Mul(int N, Real const* A, Real const* X, Real* P);
92  static void Mul(int N, SparseMatrix const& A, Real const* X, Real* P);
93  static void UpdateX(int N, Real* X, Real alpha, Real const* P);
94  static void UpdateR(int N, Real* R, Real alpha, Real const* W);
95  static void UpdateP(int N, Real* P, Real beta, Real const* R);
96 };
97 
98 
99 template <typename Real>
101  Vector2<Real> const& B, Vector2<Real>& X)
102 {
103  bool invertible;
104  Matrix2x2<Real> invA = Inverse(A, &invertible);
105  if (invertible)
106  {
107  X = invA * B;
108  }
109  else
110  {
111  X = Vector2<Real>::Zero();
112  }
113  return invertible;
114 }
115 
116 template <typename Real>
118  Vector3<Real> const& B, Vector3<Real>& X)
119 {
120  bool invertible;
121  Matrix3x3<Real> invA = Inverse(A, &invertible);
122  if (invertible)
123  {
124  X = invA * B;
125  }
126  else
127  {
128  X = Vector3<Real>::Zero();
129  }
130  return invertible;
131 }
132 
133 template <typename Real>
135  Vector4<Real> const& B, Vector4<Real>& X)
136 {
137  bool invertible;
138  Matrix4x4<Real> invA = Inverse(A, &invertible);
139  if (invertible)
140  {
141  X = invA * B;
142  }
143  else
144  {
145  X = Vector4<Real>::Zero();
146  }
147  return invertible;
148 }
149 
150 template <typename Real>
151 bool LinearSystem<Real>::Solve(int N, Real const* A, Real const* B, Real* X)
152 {
153  Real determinant;
154  return GaussianElimination<Real>()(N, A, nullptr, determinant, B, X,
155  nullptr, 0, nullptr);
156 }
157 
158 template <typename Real>
159 bool LinearSystem<Real>::Solve(int N, int M, Real const* A, Real const* B,
160  Real* X)
161 {
162  Real determinant;
163  return GaussianElimination<Real>()(N, A, nullptr, determinant, nullptr,
164  nullptr, B, M, X);
165 }
166 
167 template <typename Real>
168 bool LinearSystem<Real>::SolveTridiagonal(int N, Real const* subdiagonal,
169  Real const* diagonal, Real const* superdiagonal, Real const* B,
170  Real* X)
171 {
172  if (diagonal[0] == (Real)0)
173  {
174  return false;
175  }
176 
177  std::vector<Real> tmp(N - 1);
178  Real expr = diagonal[0];
179  Real invExpr = ((Real)1) / expr;
180  X[0] = B[0] * invExpr;
181 
182  int i0, i1;
183  for (i0 = 0, i1 = 1; i1 < N; ++i0, ++i1)
184  {
185  tmp[i0] = superdiagonal[i0] * invExpr;
186  expr = diagonal[i1] - subdiagonal[i0] * tmp[i0];
187  if (expr == (Real)0)
188  {
189  return false;
190  }
191  invExpr = ((Real)1) / expr;
192  X[i1] = (B[i1] - subdiagonal[i0] * X[i0]) * invExpr;
193  }
194 
195  for (i0 = N - 1, i1 = N - 2; i1 >= 0; --i0, --i1)
196  {
197  X[i1] -= tmp[i1] * X[i0];
198  }
199  return true;
200 }
201 
202 template <typename Real>
203 bool LinearSystem<Real>::SolveConstantTridiagonal(int N, Real subdiagonal,
204  Real diagonal, Real superdiagonal, Real const* B, Real* X)
205 {
206  if (diagonal == (Real)0)
207  {
208  return false;
209  }
210 
211  std::vector<Real> tmp(N - 1);
212  Real expr = diagonal;
213  Real invExpr = ((Real)1) / expr;
214  X[0] = B[0] * invExpr;
215 
216  int i0, i1;
217  for (i0 = 0, i1 = 1; i1 < N; ++i0, ++i1)
218  {
219  tmp[i0] = superdiagonal * invExpr;
220  expr = diagonal - subdiagonal * tmp[i0];
221  if (expr == (Real)0)
222  {
223  return false;
224  }
225  invExpr = ((Real)1) / expr;
226  X[i1] = (B[i1] - subdiagonal * X[i0]) * invExpr;
227  }
228 
229  for (i0 = N - 1, i1 = N - 2; i1 >= 0; --i0, --i1)
230  {
231  X[i1] -= tmp[i1] * X[i0];
232  }
233  return true;
234 }
235 
236 template <typename Real>
237 unsigned int LinearSystem<Real>::SolveSymmetricCG(int N, Real const* A,
238  Real const* B, Real* X, unsigned int maxIterations, Real tolerance)
239 {
240  // The first iteration.
241  std::vector<Real> tmpR(N), tmpP(N), tmpW(N);
242  Real* R = &tmpR[0];
243  Real* P = &tmpP[0];
244  Real* W = &tmpW[0];
245  size_t numBytes = N * sizeof(Real);
246  memset(X, 0, numBytes);
247  Memcpy(R, B, numBytes);
248  Real rho0 = Dot(N, R, R);
249  Memcpy(P, R, numBytes);
250  Mul(N, A, P, W);
251  Real alpha = rho0 / Dot(N, P, W);
252  UpdateX(N, X, alpha, P);
253  UpdateR(N, R, alpha, W);
254  Real rho1 = Dot(N, R, R);
255 
256  // The remaining iterations.
257  unsigned int iteration;
258  for (iteration = 1; iteration <= maxIterations; ++iteration)
259  {
260  Real root0 = sqrt(rho1);
261  Real norm = Dot(N, B, B);
262  Real root1 = sqrt(norm);
263  if (root0 <= tolerance*root1)
264  {
265  break;
266  }
267 
268  Real beta = rho1 / rho0;
269  UpdateP(N, P, beta, R);
270  Mul(N, A, P, W);
271  alpha = rho1 / Dot(N, P, W);
272  UpdateX(N, X, alpha, P);
273  UpdateR(N, R, alpha, W);
274  rho0 = rho1;
275  rho1 = Dot(N, R, R);
276  }
277  return iteration;
278 }
279 
280 template <typename Real>
282  SparseMatrix const& A, Real const* B, Real* X, unsigned int maxIterations,
283  Real tolerance)
284 {
285  // The first iteration.
286  std::vector<Real> tmpR(N), tmpP(N), tmpW(N);
287  Real* R = &tmpR[0];
288  Real* P = &tmpP[0];
289  Real* W = &tmpW[0];
290  size_t numBytes = N * sizeof(Real);
291  memset(X, 0, numBytes);
292  Memcpy(R, B, numBytes);
293  Real rho0 = Dot(N, R, R);
294  Memcpy(P, R, numBytes);
295  Mul(N, A, P, W);
296  Real alpha = rho0 / Dot(N, P, W);
297  UpdateX(N, X, alpha, P);
298  UpdateR(N, R, alpha, W);
299  Real rho1 = Dot(N, R, R);
300 
301  // The remaining iterations.
302  unsigned int iteration;
303  for (iteration = 1; iteration <= maxIterations; ++iteration)
304  {
305  Real root0 = sqrt(rho1);
306  Real norm = Dot(N, B, B);
307  Real root1 = sqrt(norm);
308  if (root0 <= tolerance*root1)
309  {
310  break;
311  }
312 
313  Real beta = rho1 / rho0;
314  UpdateP(N, P, beta, R);
315  Mul(N, A, P, W);
316  alpha = rho1 / Dot(N, P, W);
317  UpdateX(N, X, alpha, P);
318  UpdateR(N, R, alpha, W);
319  rho0 = rho1;
320  rho1 = Dot(N, R, R);
321  }
322  return iteration;
323 }
324 
325 template <typename Real>
326 Real LinearSystem<Real>::Dot(int N, Real const* U, Real const* V)
327 {
328  Real dot = (Real)0;
329  for (int i = 0; i < N; ++i)
330  {
331  dot += U[i] * V[i];
332  }
333  return dot;
334 }
335 
336 template <typename Real>
337 void LinearSystem<Real>::Mul(int N, Real const* A, Real const* X, Real* P)
338 {
339 #if defined(GTE_USE_ROW_MAJOR)
340  LexicoArray2<true, Real> matA(N, N, const_cast<Real*>(A));
341 #else
342  LexicoArray2<false, Real> matA(N, N, const_cast<Real*>(A));
343 #endif
344 
345  memset(P, 0, N * sizeof(Real));
346  for (int row = 0; row < N; ++row)
347  {
348  for (int col = 0; col < N; ++col)
349  {
350  P[row] += matA(row, col) * X[col];
351  }
352  }
353 }
354 
355 template <typename Real>
356 void LinearSystem<Real>::Mul(int N, SparseMatrix const& A, Real const* X,
357  Real* P)
358 {
359  memset(P, 0, N * sizeof(Real));
360  for (auto const& element : A)
361  {
362  int i = element.first[0];
363  int j = element.first[1];
364  Real value = element.second;
365  P[i] += value * X[j];
366  if (i != j)
367  {
368  P[j] += value * X[i];
369  }
370  }
371 }
372 
373 template <typename Real>
374 void LinearSystem<Real>::UpdateX(int N, Real* X, Real alpha, Real const* P)
375 {
376  for (int i = 0; i < N; ++i)
377  {
378  X[i] += alpha*P[i];
379  }
380 }
381 
382 template <typename Real>
383 void LinearSystem<Real>::UpdateR(int N, Real* R, Real alpha, Real const* W)
384 {
385  for (int i = 0; i < N; ++i)
386  {
387  R[i] -= alpha*W[i];
388  }
389 }
390 
391 template <typename Real>
392 void LinearSystem<Real>::UpdateP(int N, Real* P, Real beta, Real const* R)
393 {
394  for (int i = 0; i < N; ++i)
395  {
396  P[i] = R[i] + beta*P[i];
397  }
398 }
399 
400 
401 }
GLfloat GLfloat GLfloat alpha
Definition: glcorearb.h:107
static bool SolveTridiagonal(int N, Real const *subdiagonal, Real const *diagonal, Real const *superdiagonal, Real const *B, Real *X)
static void UpdateX(int N, Real *X, Real alpha, Real const *P)
static unsigned int SolveSymmetricCG(int N, Real const *A, Real const *B, Real *X, unsigned int maxIterations, Real tolerance)
static Real Dot(int N, Real const *U, Real const *V)
GLsizei const GLfloat * value
Definition: glcorearb.h:819
static void Mul(int N, Real const *A, Real const *X, Real *P)
static bool Solve(Matrix2x2< Real > const &A, Vector2< Real > const &B, Vector2< Real > &X)
GLenum GLenum GLsizei void * row
Definition: glext.h:2725
static Vector Zero()
static void UpdateR(int N, Real *R, Real alpha, Real const *W)
static bool SolveConstantTridiagonal(int N, Real subdiagonal, Real diagonal, Real superdiagonal, Real const *B, Real *X)
void Memcpy(void *target, void const *source, size_t count)
Definition: GteWrapper.cpp:16
std::map< std::array< int, 2 >, Real > SparseMatrix
Quaternion< Real > Inverse(Quaternion< Real > const &d)
static void UpdateP(int N, Real *P, Real beta, Real const *R)


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