SRIMatrix.hpp
Go to the documentation of this file.
1 //==============================================================================
2 //
3 // This file is part of GNSSTk, the ARL:UT GNSS Toolkit.
4 //
5 // The GNSSTk is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU Lesser General Public License as published
7 // by the Free Software Foundation; either version 3.0 of the License, or
8 // any later version.
9 //
10 // The GNSSTk 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 Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with GNSSTk; if not, write to the Free Software Foundation,
17 // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
18 //
19 // This software was developed by Applied Research Laboratories at the
20 // University of Texas at Austin.
21 // Copyright 2004-2022, The Board of Regents of The University of Texas System
22 //
23 //==============================================================================
24 
25 //==============================================================================
26 //
27 // This software was developed by Applied Research Laboratories at the
28 // University of Texas at Austin, under contract to an agency or agencies
29 // within the U.S. Department of Defense. The U.S. Government retains all
30 // rights to use, duplicate, distribute, disclose, or release this software.
31 //
32 // Pursuant to DoD Directive 523024
33 //
34 // DISTRIBUTION STATEMENT A: This software has been approved for public
35 // release, distribution is unlimited.
36 //
37 //==============================================================================
38 
43 //------------------------------------------------------------------------------------
44 #ifndef SQUAREROOTINFORMATION_MATRICIES_INCLUDE
45 #define SQUAREROOTINFORMATION_MATRICIES_INCLUDE
46 
47 //------------------------------------------------------------------------------------
48 // system includes
49 // GNSSTk
50 #include "Matrix.hpp"
51 #include "Vector.hpp"
52 
53 namespace gnsstk
54 {
55  // ----------------- Declarations ------------------------------------
56 
57  // This routine uses the Householder algorithm to update the SRI
58  // state and covariance.
59  // Input:
60  // R a priori SRI matrix (upper triangular, dimension N)
61  // Z a priori SRI data vector (length N)
62  // A concatentation of H and D : A = H || D, where
63  // H Measurement partials, an M by N matrix.
64  // D Data vector, of length M
65  // H and D may have row dimension > M; then pass M:
66  // M (optional) Row dimension of H and D
67  // Output:
68  // Updated R and Z. H is trashed, but the data vector D
69  // contains the residuals of fit (D - A*state).
70  // Return values:
71  // SrifMU returns void, but throws exceptions if the input matrices
72  // or vectors have incompatible dimensions.
73  //
74  // Measurment noise associated with H and D must be white
75  // with unit covariance. If necessary, the data can be 'whitened'
76  // before calling this routine in order to satisfy this requirement.
77  // This is done as follows. Compute the lower triangular square root
78  // of the covariance matrix, L, and replace H with inverse(L)*H and
79  // D with inverse(L)*D.
80  //
81  // The Householder transformation is simply an orthogonal
82  // transformation designed to make the elements below the diagonal
83  // zero. It works by explicitly performing the transformation, one
84  // column at a time, without actually constructing the transformation
85  // matrix. The matrix is transformed as follows
86  // [ A(m,n) ] => [ sum a ]
87  // [ ] => [ 0 A'(m-1,n-1) ]
88  // after which the same transformation is applied to A' matrix, until A'
89  // has only one row or column. The transformation that zeros the diagonal
90  // below the (k,k) element also replaces the (k,k) element and modifies
91  // the matrix elements for columns >= k and rows >=k, but does not affect
92  // the matrix for columns < k or rows < k.
93  // Column k (=0..min(m,n)-1) of the input matrix A(m,n) can be zeroed
94  // below the diagonal (columns < k have already been so zeroed) as follows:
95  // let y be the vector equal to column k at the diagonal and below,
96  // ( so y(j)==A(k+j,k), y(0)==A(k,k), y.size = m-k )
97  // let sum = -sign(y(0))*|y|,
98  // define vector u by u(0) = y(0)-sum, u(j)=y(j) for j>0 (j=1..m-k)
99  // and finally define b = 1/(sum*u(0)).
100  // Redefine column k with A(k,k)=sum and A(k+j,k)=0, j=1..m, and
101  // then for each column j > k, (j=k+1..n)
102  // compute g = b*sum[u(i)*A(k+i,j)], i=0..m-k-1,
103  // replace A(k+i,j) with A(k+i,j)+g*u(i), for i=0..m-k-1
104  // Most algorithms don't handle special cases:
105  // 1. If column k is already zero below the diagonal, but A(k,k)!=0, then
106  // y=[A(k,k),0,0,...0], sum=-A(k,k), u(0)=2A(k,k), u=[2A(k,k),0,0,...0]
107  // and b = -1/(2*A(k,k)^2). Then, zeroing column k only changes the sign
108  // of A(k,k), and for the other columns j>k, g = -A(k,j)/A(k,k) and only
109  // row k is changed.
110  // 2. If column k is already zero below the diagonal, AND A(k,k) is zero,
111  // then y=0,sum=0,u=0 and b is infinite...the transformation is undefined.
112  // However this column should be skipped (Biermann Appendix VII.B).
113  //
114  // Ref: Bierman, G.J. "Factorization Methods for Discrete Sequential
115  // Estimation," Academic Press, 1977.
116 
123  template <class T>
124  void SrifMU(Matrix<T>& R, Vector<T>& Z, Matrix<T>& A, unsigned int M = 0);
125 
144  template <class T>
145  void SrifMU(Matrix<T>& R, Vector<T>& Z, const Matrix<T>& H, Vector<T>& D,
146  unsigned int M = 0);
147 
148  // Compute Cholesky decomposition of symmetric positive definite matrix using
149  // Crout algorithm. A = L*L^T where A and L are (nxn) and L is lower
150  // triangular reads: [ A00 A01 A02 ... A0n ] = [ L00 0 0 0 ... 0 ][ L00
151  // L10 L20 ... L0n ] [ A10 A11 A12 ... A1n ] = [ L10 L11 0 0 ... 0 ][ 0
152  // L11 L21 ... L1n ] [ A20 A21 A22 ... A2n ] = [ L20 L21 L22 0 ... 0 ][ 0
153  // 0 L22 ... L2n ]
154  // ... ... ...
155  // [ An0 An1 An2 ... Ann ] = [ Ln0 Ln1 Ln2 0 ... Lnn][ 0 0 0 ... Lnn ]
156  // but multiplying out gives
157  // A = [ L00^2
158  // [ L00*L10 L11^2+L10^2
159  // [ L00*L20 L11*L21+L10*L20 L22^2+L21^2+L20^2
160  // ...
161  // Aii = Lii^2 + sum(k=0,i-1) Lik^2
162  // Aij = Lij*Ljj + sum(k=0,j-1) Lik*Ljk
163  // These can be inverted by looping over columns, and filling L from diagonal
164  // down.
165 
175  template <class T>
176  Matrix<T> lowerCholesky(const Matrix<T>& A, const T ztol = T(1.e-16));
177 
186  template <class T>
187  Matrix<T> upperCholesky(const Matrix<T>& A, const T ztol = T(1.e-16));
188 
197  template <class T> Matrix<T> inverseCholesky(const Matrix<T>& A);
198 
199  // Invert the upper triangular matrix stored in the square matrix UT, using a
200  // very efficient algorithm. Throw MatrixException if the matrix is singular.
201  // If the pointers are defined, on exit (but not if an exception is thrown),
202  // they return the smallest and largest eigenvalues of the matrix.
203 
217  template <class T>
218  Matrix<T> inverseUT(const Matrix<T>& UT, T *ptrSmall = NULL,
219  T *ptrBig = NULL);
220 
221  // Given an upper triangular matrix UT, compute the symmetric matrix
222  // UT * transpose(UT) using a very efficient algorithm.
230  template <class T> Matrix<T> UTtimesTranspose(const Matrix<T>& UT);
231 
244  template <class T>
245  Matrix<T> inverseLT(const Matrix<T>& LT, T *ptrSmall = NULL,
246  T *ptrBig = NULL);
247 
258  template <class T> Matrix<T> LDL(const Matrix<T>& A, Vector<T>& D);
259 
270  template <class T> Matrix<T> UDU(const Matrix<T>& A, Vector<T>& D);
271 
272  // ----------------- Implementations ---------------------------------
273  //---------------------------------------------------------------------------------
274  // This routine uses the Householder algorithm to update the SRI
275  // state and covariance.
276  // Input:
277  // R a priori SRI matrix (upper triangular, dimension N)
278  // Z a priori SRI data vector (length N)
279  // A concatentation of H and D : A = H || D, where
280  // H Measurement partials, an M by N matrix.
281  // D Data vector, of length M
282  // H and D may have row dimension > M; then pass M:
283  // M (optional) Row dimension of H and D
284  // Output:
285  // Updated R and Z. H is trashed, but the data vector D
286  // contains the residuals of fit (D - A*state).
287  // Return values:
288  // SrifMU returns void, but throws exceptions if the input matrices
289  // or vectors have incompatible dimensions.
290  //
291  // Measurment noise associated with H and D must be white
292  // with unit covariance. If necessary, the data can be 'whitened'
293  // before calling this routine in order to satisfy this requirement.
294  // This is done as follows. Compute the lower triangular square root
295  // of the covariance matrix, L, and replace H with inverse(L)*H and
296  // D with inverse(L)*D.
297  //
298  // The Householder transformation is simply an orthogonal
299  // transformation designed to make the elements below the diagonal
300  // zero. It works by explicitly performing the transformation, one
301  // column at a time, without actually constructing the transformation
302  // matrix. The matrix is transformed as follows
303  // [ A(m,n) ] => [ sum a ]
304  // [ ] => [ 0 A'(m-1,n-1) ]
305  // after which the same transformation is applied to A' matrix, until A'
306  // has only one row or column. The transformation that zeros the diagonal
307  // below the (k,k) element also replaces the (k,k) element and modifies
308  // the matrix elements for columns >= k and rows >=k, but does not affect
309  // the matrix for columns < k or rows < k.
310  // Column k (=0..min(m,n)-1) of the input matrix A(m,n) can be zeroed
311  // below the diagonal (columns < k have already been so zeroed) as follows:
312  // let y be the vector equal to column k at the diagonal and below,
313  // ( so y(j)==A(k+j,k), y(0)==A(k,k), y.size = m-k )
314  // let sum = -sign(y(0))*|y|,
315  // define vector u by u(0) = y(0)-sum, u(j)=y(j) for j>0 (j=1..m-k)
316  // and finally define b = 1/(sum*u(0)).
317  // Redefine column k with A(k,k)=sum and A(k+j,k)=0, j=1..m, and
318  // then for each column j > k, (j=k+1..n)
319  // compute g = b*sum[u(i)*A(k+i,j)], i=0..m-k-1,
320  // replace A(k+i,j) with A(k+i,j)+g*u(i), for i=0..m-k-1
321  // Most algorithms don't handle special cases:
322  // 1. If column k is already zero below the diagonal, but A(k,k)!=0, then
323  // y=[A(k,k),0,0,...0], sum=-A(k,k), u(0)=2A(k,k), u=[2A(k,k),0,0,...0]
324  // and b = -1/(2*A(k,k)^2). Then, zeroing column k only changes the sign
325  // of A(k,k), and for the other columns j>k, g = -A(k,j)/A(k,k) and only
326  // row k is changed.
327  // 2. If column k is already zero below the diagonal, AND A(k,k) is zero,
328  // then y=0,sum=0,u=0 and b is infinite...the transformation is undefined.
329  // However this column should be skipped (Biermann Appendix VII.B).
330  //
331  // Ref: Bierman, G.J. "Factorization Methods for Discrete Sequential
332  // Estimation," Academic Press, 1977.
333 
340  template <class T>
341  void SrifMU(Matrix<T>& R, Vector<T>& Z, Matrix<T>& A, unsigned int M)
342  {
343  if (A.cols() <= 1 || A.cols() != R.cols() + 1 || Z.size() < R.rows())
344  {
345  if (A.cols() > 1 && R.rows() == 0 && Z.size() == 0)
346  {
347  // create R and Z
348  R = Matrix<double>(A.cols() - 1, A.cols() - 1, 0.0);
349  Z = Vector<double>(A.cols() - 1, 0.0);
350  }
351  else
352  {
353  std::ostringstream oss;
354  oss << "Invalid input dimensions:\n R has dimension " << R.rows()
355  << "x" << R.cols() << ",\n Z has length " << Z.size()
356  << ",\n and A has dimension " << A.rows() << "x" << A.cols();
357  GNSSTK_THROW(MatrixException(oss.str()));
358  }
359  }
360 
361  const T EPS = -T(1.e-200);
362  unsigned int m = M, n = R.rows();
363  if (m == 0 || m > A.rows())
364  {
365  m = A.rows();
366  }
367  unsigned int np1 = n + 1; // if np1 = n, state vector Z is not updated
368  unsigned int i, j, k;
369  T dum, delta, beta;
370 
371  for (j = 0; j < n; j++)
372  { // loop over columns
373  T sum = T(0);
374  for (i = 0; i < m; i++)
375  sum += A(i, j) *
376  A(i, j); // sum squares of elements in this column below d
377  if (sum <= T(0))
378  {
379  continue;
380  }
381 
382  dum = R(j, j);
383  sum += dum * dum; // add diagonal element
384  sum = (dum > T(0) ? -T(1) : T(1)) * ::sqrt(sum);
385  delta = dum - sum;
386  R(j, j) = sum;
387 
388  if (j + 1 > np1)
389  {
390  break;
391  }
392 
393  beta = sum * delta; // beta must be negative
394  if (beta > EPS)
395  {
396  continue;
397  }
398  beta = T(1) / beta;
399 
400  for (k = j + 1; k < np1; k++)
401  { // columns to right of diagonal
402  sum = delta * (k == n ? Z(j) : R(j, k));
403  for (i = 0; i < m; i++)
404  sum += A(i, j) * A(i, k);
405  if (sum == T(0))
406  {
407  continue;
408  }
409 
410  sum *= beta;
411  if (k == n)
412  {
413  Z(j) += sum * delta;
414  }
415  else
416  {
417  R(j, k) += sum * delta;
418  }
419 
420  for (i = 0; i < m; i++)
421  A(i, k) += sum * A(i, j);
422  }
423  }
424  } // end SrifMU
425 
426  //---------------------------------------------------------------------------------
427  // This is simply SrifMU(R,Z,A) with H and D passed in rather
428  // than concatenated into a single Matrix A = H || D.
429 
448  template <class T>
449  void SrifMU(Matrix<T>& R, Vector<T>& Z, const Matrix<T>& H, Vector<T>& D,
450  unsigned int M)
451  {
452  try
453  {
454  Matrix<T> A;
455  A = H || D;
456 
457  SrifMU(R, Z, A, M);
458 
459  // copy residuals out of A into D
460  D = Vector<T>(A.colCopy(A.cols() - 1));
461  }
462  catch (MatrixException& me)
463  {
464  GNSSTK_RETHROW(me);
465  }
466  }
467 
468  //---------------------------------------------------------------------------------
469  // Compute Cholesky decomposition of symmetric positive definite matrix using
470  // Crout algorithm. A = L*L^T where A and L are (nxn) and L is lower
471  // triangular reads: [ A00 A01 A02 ... A0n ] = [ L00 0 0 0 ... 0 ][ L00
472  // L10 L20 ... L0n ] [ A10 A11 A12 ... A1n ] = [ L10 L11 0 0 ... 0 ][ 0
473  // L11 L21 ... L1n ] [ A20 A21 A22 ... A2n ] = [ L20 L21 L22 0 ... 0 ][ 0
474  // 0 L22 ... L2n ]
475  // ... ... ...
476  // [ An0 An1 An2 ... Ann ] = [ Ln0 Ln1 Ln2 0 ... Lnn][ 0 0 0 ... Lnn ]
477  // but multiplying out gives
478  // A = [ L00^2
479  // [ L00*L10 L11^2+L10^2
480  // [ L00*L20 L11*L21+L10*L20 L22^2+L21^2+L20^2
481  // ...
482  // Aii = Lii^2 + sum(k=0,i-1) Lik^2
483  // Aij = Lij*Ljj + sum(k=0,j-1) Lik*Ljk
484  // These can be inverted by looping over columns, and filling L from diagonal
485  // down.
486 
496  template <class T>
497  Matrix<T> lowerCholesky(const Matrix<T>& A, const T ztol)
498  {
499  if (A.rows() != A.cols() || A.rows() == 0)
500  {
501  std::ostringstream oss;
502  oss << "Invalid input dimensions: " << A.rows() << "x" << A.cols();
503  GNSSTK_THROW(MatrixException(oss.str()));
504  }
505 
506  const unsigned int n = A.rows();
507  unsigned int i, j, k;
508  Matrix<T> L(n, n, T(0));
509 
510  for (j = 0; j < n; j++)
511  { // loop over cols
512  T d(A(j, j));
513  for (k = 0; k < j; k++)
514  d -= L(j, k) * L(j, k);
515  if (d <= ztol)
516  {
517  std::ostringstream oss;
518  oss << "Non-positive eigenvalue " << std::scientific << d
519  << " at col " << j
520  << ": lowerCholesky() requires positive-definite input";
521  GNSSTK_THROW(SingularMatrixException(oss.str()));
522  }
523  L(j, j) = ::sqrt(d);
524  for (i = j + 1; i < n; i++)
525  { // loop over rows below diagonal
526  d = A(i, j);
527  for (k = 0; k < j; k++)
528  d -= L(i, k) * L(j, k);
529  L(i, j) = d / L(j, j);
530  }
531  }
532 
533  return L;
534  }
535 
536  //---------------------------------------------------------------------------------
545  template <class T>
546  Matrix<T> upperCholesky(const Matrix<T>& A, const T ztol)
547  {
548  if (A.rows() != A.cols() || A.rows() == 0)
549  {
550  std::ostringstream oss;
551  oss << "Invalid input dimensions: " << A.rows() << "x" << A.cols();
552  GNSSTK_THROW(MatrixException(oss.str()));
553  }
554 
555  const unsigned int n = A.cols();
556  unsigned int i, j, k;
557  Matrix<T> U(n, n, T(0));
558  Matrix<T> P = A;
559 
560  // loop over columns in reverse order
561  for (j = n - 1; j >= 0; j--)
562  {
563  T d(P(j, j)); // d = diagonal element j
564  if (d <= ztol)
565  {
566  std::ostringstream oss;
567  oss << "Non-positive eigenvalue " << std::scientific << d
568  << " at col " << j
569  << ": upperCholesky() requires positive-definite input";
570  GNSSTK_THROW(SingularMatrixException(oss.str()));
571  }
572  U(j, j) = ::sqrt(d);
573  d = T(1) / U(j, j);
574 
575  for (k = 0; k < j; k++)
576  U(k, j) = d * P(k, j);
577  for (k = 0; k < j; k++)
578  {
579  for (i = 0; i <= k; i++)
580  P(i, k) -= U(k, j) * U(i, j);
581  }
582 
583  if (j == 0)
584  {
585  break; // since j is unsigned
586  }
587  }
588 
589  return U;
590  }
591 
592  //---------------------------------------------------------------------------------
601  template <class T> Matrix<T> inverseCholesky(const Matrix<T>& A)
602  {
603  try
604  {
605  Matrix<T> L(lowerCholesky(A));
606  Matrix<T> Uinv(inverseUT(transpose(L)));
607  Matrix<T> Ainv(UTtimesTranspose(Uinv));
608  return Ainv;
609  }
610  catch (MatrixException& me)
611  {
612  me.addText("Called by inverseCholesky()");
613  GNSSTK_RETHROW(me);
614  }
615  }
616 
617  //---------------------------------------------------------------------------------
618  // Invert the upper triangular matrix stored in the square matrix UT, using a
619  // very efficient algorithm. Throw MatrixException if the matrix is singular.
620  // If the pointers are defined, on exit (but not if an exception is thrown),
621  // they return the smallest and largest eigenvalues of the matrix.
622 
635  template <class T>
636  Matrix<T> inverseUT(const Matrix<T>& UT, T *ptrSmall, T *ptrBig)
637  {
638  if (UT.rows() != UT.cols() || UT.rows() == 0)
639  {
640  std::ostringstream oss;
641  oss << "Invalid input dimensions: " << UT.rows() << "x" << UT.cols();
642  GNSSTK_THROW(MatrixException(oss.str()));
643  }
644 
645  unsigned int i, j, k, n = UT.rows();
646  T big(0), small(0), sum, dum;
647  Matrix<T> Inv(UT);
648 
649  // start at the last row,col
650  dum = UT(n - 1, n - 1);
651  if (dum == T(0))
652  {
653  GNSSTK_THROW(SingularMatrixException("Singular matrix at element 0"));
654  }
655 
656  big = small = fabs(dum);
657  Inv(n - 1, n - 1) = T(1) / dum;
658 
659  if (n > 1)
660  {
661  // zero row n-1 to left of diagonal
662  for (i = 0; i < n - 1; i++)
663  Inv(n - 1, i) = 0;
664 
665  // move to rows i = n-2 to 0; NB i is unsigned, so break loop at bottom
666  for (i = n - 2;; i--)
667  {
668  if (UT(i, i) == T(0))
669  {
670  std::ostringstream oss;
671  oss << "Singular matrix at element " << i;
672  GNSSTK_THROW(MatrixException(oss.str()));
673  }
674 
675  if (fabs(UT(i, i)) > big)
676  {
677  big = fabs(UT(i, i));
678  }
679  if (fabs(UT(i, i)) < small)
680  {
681  small = fabs(UT(i, i));
682  }
683  dum = T(1) / UT(i, i);
684  Inv(i, i) = dum; // diagonal element first
685 
686  // now do off-diagonal elements (i,i+1) to (i,n-1): row i to right
687  for (j = i + 1; j < n; j++)
688  {
689  sum = T(0);
690  for (k = i + 1; k <= j; k++)
691  sum += Inv(k, j) * UT(i, k);
692  Inv(i, j) = -sum * dum;
693  }
694  for (j = 0; j < i; j++)
695  Inv(i, j) = 0; // zero row i to left of diag
696 
697  if (i == 0)
698  {
699  break; // NB i is unsigned, hence 0-1 = 4294967295!
700  }
701  }
702  }
703 
704  if (ptrSmall)
705  {
706  *ptrSmall = small;
707  }
708  if (ptrBig)
709  {
710  *ptrBig = big;
711  }
712 
713  return Inv;
714  }
715 
716  //---------------------------------------------------------------------------------
717  // Given an upper triangular matrix UT, compute the symmetric matrix
718  // UT * transpose(UT) using a very efficient algorithm.
725  template <class T> Matrix<T> UTtimesTranspose(const Matrix<T>& UT)
726  {
727  const unsigned int n = UT.rows();
728  if (n == 0 || UT.cols() != n)
729  {
730  std::ostringstream oss;
731  oss << "Invalid input dimensions: " << UT.rows() << "x" << UT.cols();
732  GNSSTK_THROW(MatrixException(oss.str()));
733  }
734 
735  unsigned int i, j, k;
736  T sum;
737  Matrix<T> S(n, n);
738 
739  for (i = 0; i < n - 1; i++)
740  { // loop over rows of UT, except the last
741  sum = T(0); // diagonal element (i,i)
742  for (j = i; j < n; j++)
743  sum += UT(i, j) * UT(i, j);
744  S(i, i) = sum;
745  for (j = i + 1; j < n; j++)
746  { // loop over columns to right of (i,i)
747  sum = T(0);
748  for (k = j; k < n; k++)
749  sum += UT(i, k) * UT(j, k);
750  S(i, j) = S(j, i) = sum;
751  }
752  }
753  S(n - 1, n - 1) =
754  UT(n - 1, n - 1) * UT(n - 1, n - 1); // the last diagonal element
755 
756  return S;
757  }
758 
759  //---------------------------------------------------------------------------------
772  template <class T>
773  Matrix<T> inverseLT(const Matrix<T>& LT, T *ptrSmall, T *ptrBig)
774  {
775  if (LT.rows() != LT.cols() || LT.rows() == 0)
776  {
777  std::ostringstream oss;
778  oss << "Invalid input dimensions: " << LT.rows() << "x" << LT.cols();
779  GNSSTK_THROW(MatrixException(oss.str()));
780  }
781 
782  unsigned int i, j, k, n = LT.rows();
783  T big(0), small(0), sum, dum;
784  Matrix<T> Inv(LT.rows(), LT.cols(), T(0));
785 
786  // start at the first row,col
787  dum = LT(0, 0);
788  if (dum == T(0))
789  {
790  SingularMatrixException e("Singular matrix at element 0");
791  GNSSTK_THROW(e);
792  }
793 
794  big = small = fabs(dum);
795  Inv(0, 0) = T(1) / dum;
796  if (n == 1)
797  {
798  return Inv; // 1x1 matrix
799  }
800  // for(i=1; i<n; i++) Inv(0,i)=0; // zero out columns to right of
801  // 0,0
802 
803  // now move to rows i = 1 to n-1
804  for (i = 1; i < n; i++)
805  {
806  if (LT(i, i) == T(0))
807  {
808  GNSSTK_THROW(
809  SingularMatrixException("Singular matrix at element 0"));
810  }
811 
812  if (fabs(LT(i, i)) > big)
813  {
814  big = fabs(LT(i, i));
815  }
816  if (fabs(LT(i, i)) < small)
817  {
818  small = fabs(LT(i, i));
819  }
820  dum = T(1) / LT(i, i);
821  Inv(i, i) = dum; // diagonal element first
822 
823  // now do off-diagonal elements to left of diag (i,0) to (i,i-1)
824  for (j = 0; j < i; j++)
825  {
826  sum = T(0);
827  for (k = j; k < i; k++)
828  sum += LT(i, k) * Inv(k, j);
829  if (sum != T(0))
830  {
831  Inv(i, j) = -sum * dum;
832  }
833  }
834  // for(j=i+1; j<n; j++) Inv(i,j) = 0; // row i right of diagonal = 0
835  }
836 
837  if (ptrSmall)
838  {
839  *ptrSmall = small;
840  }
841  if (ptrBig)
842  {
843  *ptrBig = big;
844  }
845 
846  return Inv;
847  }
848 
849  //---------------------------------------------------------------------------------
860  template <class T> Matrix<T> LDL(const Matrix<T>& A, Vector<T>& D)
861  {
862  try
863  {
864  if (A.rows() != A.cols() || A.rows() == 0)
865  {
866  std::ostringstream oss;
867  oss << "Invalid input dimensions: " << A.rows() << "x" << A.cols();
868  GNSSTK_THROW(MatrixException(oss.str()));
869  }
870 
871  const unsigned int N(A.rows());
872  Matrix<T> L;
873  try
874  {
875  L = lowerCholesky(A);
876  }
877  catch (MatrixException& me)
878  {
879  me.addText("lowerCholesky failed");
880  GNSSTK_RETHROW(me);
881  }
882 
883  D = L.diagCopy(); // have to square these later
884 
885  unsigned int i, j;
886  // scale column j of L by 1/L(j,j) = 1/sqrt(D(j))
887  for (j = 0; j < N; j++)
888  {
889  T d(D(j));
890  // if(d <= 0) never happens - Cholesky will catch
891  D(j) = d * d;
892  L(j, j) = T(1);
893  for (i = j + 1; i < N; i++) // scale column below diagonal by d
894  L(i, j) /= d;
895  }
896 
897  return L;
898  }
899  catch (MatrixException& me)
900  {
901  me.addText("Called by LDL()");
902  GNSSTK_RETHROW(me);
903  }
904  }
905 
906  //---------------------------------------------------------------------------------
917  template <class T> Matrix<T> UDU(const Matrix<T>& A, Vector<T>& D)
918  {
919  try
920  {
921  if (A.rows() != A.cols() || A.rows() == 0)
922  {
923  std::ostringstream oss;
924  oss << "Invalid input dimensions: " << A.rows() << "x" << A.cols();
925  GNSSTK_THROW(MatrixException(oss.str()));
926  }
927 
928  const unsigned int N(A.rows());
929  Matrix<T> U;
930  try
931  {
932  U = upperCholesky(A);
933  }
934  catch (MatrixException& me)
935  {
936  me.addText("upperCholesky failed");
937  GNSSTK_RETHROW(me);
938  }
939 
940  D = U.diagCopy(); // have to square these later
941 
942  unsigned int i, j;
943  // scale column j of U by 1/U(j,j) = 1/sqrt(D(j))
944  for (j = 0; j < N; j++)
945  {
946  T d(D(j));
947  // if(d <= 0) never happens - Cholesky will catch
948  D(j) = d * d;
949  U(j, j) = T(1);
950  for (i = 0; i < j; i++) // scale column above diagonal by d
951  U(i, j) /= d;
952  }
953 
954  return U;
955  }
956  catch (MatrixException& me)
957  {
958  me.addText("Called by UDU()");
959  GNSSTK_RETHROW(me);
960  }
961  }
962 
963 } // end namespace gnsstk
964 
965 #endif // SQUAREROOTINFORMATION_MATRICIES_INCLUDE
gnsstk::UTtimesTranspose
Matrix< T > UTtimesTranspose(const Matrix< T > &UT)
Definition: SRIMatrix.hpp:725
gnsstk::lowerCholesky
SparseMatrix< T > lowerCholesky(const SparseMatrix< T > &A)
Definition: SparseMatrix.hpp:2065
gnsstk::inverseUT
Matrix< T > inverseUT(const Matrix< T > &UT, T *ptrSmall=NULL, T *ptrBig=NULL)
Definition: SRIMatrix.hpp:636
gnsstk::sum
T sum(const ConstVectorBase< T, BaseClass > &l)
Definition: VectorBaseOperators.hpp:84
gnsstk::ConstMatrixBase< T, Matrix< T > >::diagCopy
Vector< T > diagCopy(void) const
Definition: MatrixBase.hpp:184
gnsstk::Matrix::cols
size_t cols() const
The number of columns in the matrix.
Definition: Matrix.hpp:167
gnsstk::LDL
Matrix< T > LDL(const Matrix< T > &A, Vector< T > &D)
Definition: SRIMatrix.hpp:860
NULL
#define NULL
Definition: getopt1.c:64
gnsstk::Matrix::rows
size_t rows() const
The number of rows in the matrix.
Definition: Matrix.hpp:165
gnsstk
For Sinex::InputHistory.
Definition: BasicFramework.cpp:50
gnsstk::SrifMU
void SrifMU(Matrix< T > &R, Vector< T > &Z, SparseMatrix< T > &A, const unsigned int M)
Definition: SparseMatrix.hpp:2467
gnsstk::transpose
SparseMatrix< T > transpose(const SparseMatrix< T > &M)
transpose
Definition: SparseMatrix.hpp:829
gnsstk::Matrix
Definition: Matrix.hpp:72
gnsstk::UDU
Matrix< T > UDU(const Matrix< T > &A, Vector< T > &D)
Definition: SRIMatrix.hpp:917
gnsstk::inverseLT
SparseMatrix< T > inverseLT(const SparseMatrix< T > &LT, T *ptrSmall, T *ptrBig)
Compute inverse of lower-triangular SparseMatrix.
Definition: SparseMatrix.hpp:2154
gnsstk::beta
double beta(double x, double y)
Definition: SpecialFuncs.cpp:204
GNSSTK_RETHROW
#define GNSSTK_RETHROW(exc)
Definition: Exception.hpp:369
gnsstk::upperCholesky
SparseMatrix< T > upperCholesky(const SparseMatrix< T > &A)
Definition: SparseMatrix.hpp:2262
gnsstk::Vector
Definition: Vector.hpp:67
gnsstk::TrackingCode::P
@ P
Legacy GPS precise code.
gnsstk::inverseCholesky
Matrix< T > inverseCholesky(const Matrix< T > &A)
Definition: SRIMatrix.hpp:601
gnsstk::Vector::size
size_t size() const
STL size.
Definition: Vector.hpp:207
gnsstk::ConstMatrixBase< T, Matrix< T > >::colCopy
Vector< T > colCopy(size_t c, size_t r=0) const
Definition: MatrixBase.hpp:146
GNSSTK_THROW
#define GNSSTK_THROW(exc)
Definition: Exception.hpp:366
Matrix.hpp
Vector.hpp


gnsstk
Author(s):
autogenerated on Wed Oct 25 2023 02:40:41