GteBandedMatrix.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 
11 #include <cmath>
12 #include <vector>
13 
14 namespace gte
15 {
16 
17 template <typename Real>
19 {
20 public:
21  // Construction and destruction.
22  ~BandedMatrix();
23  BandedMatrix(int size, int numLBands, int numUBands);
24 
25  // Member access.
26  inline int GetSize() const;
27  inline std::vector<Real>& GetDBand();
28  inline std::vector<Real> const& GetDBand() const;
29  inline std::vector<std::vector<Real>>& GetLBands();
30  inline std::vector<std::vector<Real>> const& GetLBands() const;
31  inline std::vector<std::vector<Real>>& GetUBands();
32  inline std::vector<std::vector<Real>> const& GetUBands() const;
33  Real& operator()(int r, int c);
34  Real const& operator()(int r, int c) const;
35 
36  // Factor the square banded matrix A into A = L*L^T, where L is a
37  // lower-triangular matrix (L^T is an upper-triangular matrix). This is
38  // an LU decomposition that allows for stable inversion of A to solve
39  // A*X = B. The return value is 'true' iff the factorizing is successful
40  // (L is invertible). If successful, A contains the Cholesky
41  // factorization: L in the lower-triangular part of A and L^T in the
42  // upper-triangular part of A.
43  bool CholeskyFactor();
44 
45  // Solve the linear system A*X = B, where A is an NxN banded matrix and B
46  // is an Nx1 vector. The unknown X is also Nx1. The input to this
47  // function is B. The output X is computed and stored in B. The return
48  // value is 'true' iff the system has a solution. The matrix A and the
49  // vector B are both modified by this function. If successful, A contains
50  // the Cholesky factorization: L in the lower-triangular part of A and
51  // L^T in the upper-triangular part of A.
52  bool SolveSystem(Real* bVector);
53 
54  // Solve the linear system A*X = B, where A is an NxN banded matrix and
55  // B is an NxM matrix. The unknown X is also NxM. The input to this
56  // function is B. The output X is computed and stored in B. The return
57  // value is 'true' iff the system has a solution. The matrix A and the
58  // vector B are both modified by this function. If successful, A contains
59  // the Cholesky factorization: L in the lower-triangular part of A and
60  // L^T in the upper-triangular part of A.
61  //
62  // 'bMatrix' must have the storage order specified by the template
63  // parameter.
64  template <bool RowMajor>
65  bool SolveSystem(Real* bMatrix, int numBColumns);
66 
67  // Compute the inverse of the banded matrix. The return value is 'true'
68  // when the matrix is invertible, in which case the 'inverse' output is
69  // valid. The return value is 'false' when the matrix is not invertible,
70  // in which case 'inverse' is invalid and should not be used. The
71  // input matrix 'inverse' must be the same size as 'this'.
72  //
73  // 'bMatrix' must have the storage order specified by the template
74  // parameter.
75  template <bool RowMajor>
76  bool ComputeInverse(Real* inverse) const;
77 
78 private:
79  // The linear system is L*U*X = B, where A = L*U and U = L^T, Reduce this
80  // to U*X = L^{-1}*B. The return value is 'true' iff the operation is
81  // successful.
82  bool SolveLower(Real* dataVector) const;
83 
84  // The linear system is U*X = L^{-1}*B. Reduce this to
85  // X = U^{-1}*L^{-1}*B. The return value is 'true' iff the operation is
86  // successful.
87  bool SolveUpper(Real* dataVector) const;
88 
89  // The linear system is L*U*X = B, where A = L*U and U = L^T, Reduce this
90  // to U*X = L^{-1}*B. The return value is 'true' iff the operation is
91  // successful. See the comments for SolveSystem(Real*,int) about the
92  // storage for dataMatrix.
93  template <bool RowMajor>
94  bool SolveLower(Real* dataMatrix, int numColumns) const;
95 
96  // The linear system is U*X = L^{-1}*B. Reduce this to
97  // X = U^{-1}*L^{-1}*B. The return value is 'true' iff the operation is
98  // successful. See the comments for SolveSystem(Real*,int) about the
99  // storage for dataMatrix.
100  template <bool RowMajor>
101  bool SolveUpper(Real* dataMatrix, int numColumns) const;
102 
103  int mSize;
104  std::vector<Real> mDBand;
105  std::vector<std::vector<Real>> mLBands, mUBands;
106 
107  // For return by operator()(int,int) for valid indices not in the bands,
108  // in which case the matrix entries are zero,
109  mutable Real mZero;
110 };
111 
112 
113 template <typename Real>
115 {
116 }
117 
118 template <typename Real>
119 BandedMatrix<Real>::BandedMatrix(int size, int numLBands, int numUBands)
120  :
121  mSize(size),
122  mZero((Real)0)
123 {
124  if (size > 0
125  && 0 <= numLBands && numLBands < size
126  && 0 <= numUBands && numUBands < size)
127  {
128  mDBand.resize(size);
129  std::fill(mDBand.begin(), mDBand.end(), (Real)0);
130 
131  if (numLBands > 0)
132  {
133  mLBands.resize(numLBands);
134  int numElements = size - 1;
135  for (auto& band : mLBands)
136  {
137  band.resize(numElements--);
138  std::fill(band.begin(), band.end(), (Real)0);
139  }
140  }
141 
142  if (numUBands > 0)
143  {
144  mUBands.resize(numUBands);
145  int numElements = size - 1;
146  for (auto& band : mUBands)
147  {
148  band.resize(numElements--);
149  std::fill(band.begin(), band.end(), (Real)0);
150  }
151  }
152  }
153  else
154  {
155  // Invalid argument to BandedMatrix constructor.
156  mSize = 0;
157  }
158 }
159 
160 template <typename Real> inline
162 {
163  return mSize;
164 }
165 
166 template <typename Real> inline
167 std::vector<Real>& BandedMatrix<Real>::GetDBand()
168 {
169  return mDBand;
170 }
171 
172 template <typename Real> inline
173 std::vector<Real> const& BandedMatrix<Real>::GetDBand() const
174 {
175  return mDBand;
176 }
177 
178 template <typename Real> inline
179 std::vector<std::vector<Real>>& BandedMatrix<Real>::GetLBands()
180 {
181  return mLBands;
182 }
183 
184 template <typename Real> inline
185 std::vector<std::vector<Real>> const& BandedMatrix<Real>::GetLBands() const
186 {
187  return mLBands;
188 }
189 
190 template <typename Real> inline
191 std::vector<std::vector<Real>>& BandedMatrix<Real>::GetUBands()
192 {
193  return mUBands;
194 }
195 
196 template <typename Real> inline
197 std::vector<std::vector<Real>> const& BandedMatrix<Real>::GetUBands() const
198 {
199  return mUBands;
200 }
201 
202 template <typename Real>
204 {
205  if (0 <= r && r < mSize && 0 <= c && c < mSize)
206  {
207  int band = c - r;
208  if (band > 0)
209  {
210  int const numUBands = static_cast<int>(mUBands.size());
211  if (--band < numUBands && r < mSize - 1 - band)
212  {
213  return mUBands[band][r];
214  }
215  }
216  else if (band < 0)
217  {
218  band = -band;
219  int const numLBands = static_cast<int>(mLBands.size());
220  if (--band < numLBands && c < mSize - 1 - band)
221  {
222  return mLBands[band][c];
223  }
224  }
225  else
226  {
227  return mDBand[r];
228  }
229  }
230  // else invalid index
231 
232 
233  // Set the value to zero in case someone unknowingly modified mZero on a
234  // previous call to operator(int,int).
235  mZero = (Real)0;
236  return mZero;
237 }
238 
239 template <typename Real>
240 Real const& BandedMatrix<Real>::operator()(int r, int c) const
241 {
242  if (0 <= r && r < mSize && 0 <= c && c < mSize)
243  {
244  int band = c - r;
245  if (band > 0)
246  {
247  int const numUBands = static_cast<int>(mUBands.size());
248  if (--band < numUBands && r < mSize - 1 - band)
249  {
250  return mUBands[band][r];
251  }
252  }
253  else if (band < 0)
254  {
255  band = -band;
256  int const numLBands = static_cast<int>(mLBands.size());
257  if (--band < numLBands && c < mSize - 1 - band)
258  {
259  return mLBands[band][c];
260  }
261  }
262  else
263  {
264  return mDBand[r];
265  }
266  }
267  // else invalid index
268 
269 
270  // Set the value to zero in case someone unknowingly modified mZero on a
271  // previous call to operator(int,int).
272  mZero = (Real)0;
273  return mZero;
274 }
275 
276 template <typename Real>
278 {
279  if (mDBand.size() == 0 || mLBands.size() != mUBands.size())
280  {
281  // Invalid number of bands.
282  return false;
283  }
284 
285  int const sizeM1 = mSize - 1;
286  int const numBands = static_cast<int>(mLBands.size());
287 
288  int k, kMax;
289  for (int i = 0; i < mSize; ++i)
290  {
291  int jMin = i - numBands;
292  if (jMin < 0)
293  {
294  jMin = 0;
295  }
296 
297  int j;
298  for (j = jMin; j < i; ++j)
299  {
300  kMax = j + numBands;
301  if (kMax > sizeM1)
302  {
303  kMax = sizeM1;
304  }
305 
306  for (k = i; k <= kMax; ++k)
307  {
308  operator()(k, i) -= operator()(i, j)*operator()(k, j);
309  }
310  }
311 
312  kMax = j + numBands;
313  if (kMax > sizeM1)
314  {
315  kMax = sizeM1;
316  }
317 
318  for (k = 0; k < i; ++k)
319  {
320  operator()(k, i) = operator()(i, k);
321  }
322 
323  Real diagonal = operator()(i, i);
324  if (diagonal <= (Real)0)
325  {
326  return false;
327  }
328  Real invSqrt = ((Real)1) / sqrt(diagonal);
329  for (k = i; k <= kMax; ++k)
330  {
331  operator()(k, i) *= invSqrt;
332  }
333  }
334 
335  return true;
336 }
337 
338 template <typename Real>
340 {
341  return CholeskyFactor()
342  && SolveLower(bVector)
343  && SolveUpper(bVector);
344 }
345 
346 template <typename Real>
347 template <bool RowMajor>
348 bool BandedMatrix<Real>::SolveSystem(Real* bMatrix, int numBColumns)
349 {
350  return CholeskyFactor()
351  && SolveLower<RowMajor>(bMatrix, numBColumns)
352  && SolveUpper<RowMajor>(bMatrix, numBColumns);
353 }
354 
355 template <typename Real>
356 template <bool RowMajor>
357 bool BandedMatrix<Real>::ComputeInverse(Real* inverse) const
358 {
359  LexicoArray2<RowMajor, Real> invA(mSize, mSize, inverse);
360 
361  BandedMatrix<Real> tmpA = *this;
362  for (int row = 0; row < mSize; ++row)
363  {
364  for (int col = 0; col < mSize; ++col)
365  {
366  if (row != col)
367  {
368  invA(row, col) = (Real)0;
369  }
370  else
371  {
372  invA(row, row) = (Real)1;
373  }
374  }
375  }
376 
377  // Forward elimination.
378  for (int row = 0; row < mSize; ++row)
379  {
380  // The pivot must be nonzero in order to proceed.
381  Real diag = tmpA(row, row);
382  if (diag == (Real)0)
383  {
384  return false;
385  }
386 
387  Real invDiag = ((Real)1) / diag;
388  tmpA(row, row) = (Real)1;
389 
390  // Multiply the row to be consistent with diagonal term of 1.
391  int colMin = row + 1;
392  int colMax = colMin + static_cast<int>(mUBands.size());
393  if (colMax > mSize)
394  {
395  colMax = mSize;
396  }
397 
398  int c;
399  for (c = colMin; c < colMax; ++c)
400  {
401  tmpA(row, c) *= invDiag;
402  }
403  for (c = 0; c <= row; ++c)
404  {
405  invA(row, c) *= invDiag;
406  }
407 
408  // Reduce the remaining rows.
409  int rowMin = row + 1;
410  int rowMax = rowMin + static_cast<int>(mLBands.size());
411  if (rowMax > mSize)
412  {
413  rowMax = mSize;
414  }
415 
416  for (int r = rowMin; r < rowMax; ++r)
417  {
418  Real mult = tmpA(r, row);
419  tmpA(r, row) = (Real)0;
420  for (c = colMin; c < colMax; ++c)
421  {
422  tmpA(r, c) -= mult*tmpA(row, c);
423  }
424  for (c = 0; c <= row; ++c)
425  {
426  invA(r, c) -= mult*invA(row, c);
427  }
428  }
429  }
430 
431  // Backward elimination.
432  for (int row = mSize - 1; row >= 1; --row)
433  {
434  int rowMax = row - 1;
435  int rowMin = row - static_cast<int>(mUBands.size());
436  if (rowMin < 0)
437  {
438  rowMin = 0;
439  }
440 
441  for (int r = rowMax; r >= rowMin; --r)
442  {
443  Real mult = tmpA(r, row);
444  tmpA(r, row) = (Real)0;
445  for (int c = 0; c < mSize; ++c)
446  {
447  invA(r, c) -= mult*invA(row, c);
448  }
449  }
450  }
451 
452  return true;
453 }
454 
455 template <typename Real>
456 bool BandedMatrix<Real>::SolveLower(Real* dataVector) const
457 {
458  int const size = static_cast<int>(mDBand.size());
459  for (int r = 0; r < size; ++r)
460  {
461  Real lowerRR = operator()(r, r);
462  if (lowerRR >(Real)0)
463  {
464  for (int c = 0; c < r; ++c)
465  {
466  Real lowerRC = operator()(r, c);
467  dataVector[r] -= lowerRC * dataVector[c];
468  }
469  dataVector[r] /= lowerRR;
470  }
471  else
472  {
473  return false;
474  }
475  }
476  return true;
477 }
478 
479 template <typename Real>
480 bool BandedMatrix<Real>::SolveUpper(Real* dataVector) const
481 {
482  int const size = static_cast<int>(mDBand.size());
483  for (int r = size - 1; r >= 0; --r)
484  {
485  Real upperRR = operator()(r, r);
486  if (upperRR > (Real)0)
487  {
488  for (int c = r + 1; c < size; ++c)
489  {
490  Real upperRC = operator()(r, c);
491  dataVector[r] -= upperRC * dataVector[c];
492  }
493 
494  dataVector[r] /= upperRR;
495  }
496  else
497  {
498  return false;
499  }
500  }
501  return true;
502 }
503 
504 template <typename Real>
505 template <bool RowMajor>
506 bool BandedMatrix<Real>::SolveLower(Real* dataMatrix, int numColumns) const
507 {
508  LexicoArray2<RowMajor, Real> data(mSize, numColumns, dataMatrix);
509 
510  for (int r = 0; r < mSize; ++r)
511  {
512  Real lowerRR = operator()(r, r);
513  if (lowerRR >(Real)0)
514  {
515  for (int c = 0; c < r; ++c)
516  {
517  Real lowerRC = operator()(r, c);
518  for (int bCol = 0; bCol < numColumns; ++bCol)
519  {
520  data(r, bCol) -= lowerRC * data(c, bCol);
521  }
522  }
523 
524  Real inverse = ((Real)1) / lowerRR;
525  for (int bCol = 0; bCol < numColumns; ++bCol)
526  {
527  data(r, bCol) *= inverse;
528  }
529  }
530  else
531  {
532  return false;
533  }
534  }
535  return true;
536 }
537 
538 template <typename Real>
539 template <bool RowMajor>
540 bool BandedMatrix<Real>::SolveUpper(Real* dataMatrix, int numColumns) const
541 {
542  LexicoArray2<RowMajor, Real> data(mSize, numColumns, dataMatrix);
543 
544  for (int r = mSize - 1; r >= 0; --r)
545  {
546  Real upperRR = operator()(r, r);
547  if (upperRR > (Real)0)
548  {
549  for (int c = r + 1; c < mSize; ++c)
550  {
551  Real upperRC = operator()(r, c);
552  for (int bCol = 0; bCol < numColumns; ++bCol)
553  {
554  data(r, bCol) -= upperRC * data(c, bCol);
555  }
556  }
557 
558  Real inverse = ((Real)1) / upperRR;
559  for (int bCol = 0; bCol < numColumns; ++bCol)
560  {
561  data(r, bCol) *= inverse;
562  }
563  }
564  else
565  {
566  return false;
567  }
568  }
569  return true;
570 }
571 
572 
573 }
std::vector< std::vector< Real > > mLBands
std::vector< Real > & GetDBand()
std::vector< Real > mDBand
BandedMatrix(int size, int numLBands, int numUBands)
std::vector< std::vector< Real > > & GetLBands()
GLsizeiptr size
Definition: glcorearb.h:659
Real & operator()(int r, int c)
const GLubyte * c
Definition: glext.h:11671
std::vector< std::vector< Real > > mUBands
GLenum GLenum GLsizei void * row
Definition: glext.h:2725
bool SolveUpper(Real *dataVector) const
bool SolveLower(Real *dataVector) const
bool SolveSystem(Real *bVector)
GLboolean * data
Definition: glcorearb.h:126
std::vector< std::vector< Real > > & GetUBands()
GLboolean r
Definition: glcorearb.h:1217
bool ComputeInverse(Real *inverse) const
int GetSize() const


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