KalmanLinearAlgebra.h
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 ///
3 /// \file KalmanLinearAlgebra.h
4 ///
5 /// \brief Kalman filter linear algebra typedefs.
6 ///
7 /// \author H. Greenlee
8 ///
9 /// There are various linear algebra typedefs defined in this header:
10 ///
11 /// 1. KVector<N>::type - Vector, dimension N.
12 /// 2. KSymMatrix<N>::type - Symmetric matrix, dimension NxN.
13 /// 3. KMatrix<N,M>::type - A matrix with dimension NxM.
14 /// 4. KHMatrix<N>::type - Matrix with dimension Nx5 (H-matrix).
15 /// 5. KGMatrix<N>::type - Matrix with dimension 5xN (gain matrix).
16 /// 6. TrackVector - Track state vector, fixed dimension 5
17 /// 7. TrackError - Track error matrix, fixed dimension 5x5.
18 /// 8. TrackMatrix - General matrix, fixed dimension 5x5.
19 ///
20 /// The above typedefs refer to some ublas (boost/numeric/ublas)
21 /// linear algebra class. The templated typedefs are defined as a
22 /// member of a template class because c++ doesn't have template
23 /// typedefs.
24 ///
25 /// All linear algebra objects use the following storage model.
26 ///
27 /// 1. Matrices are stored in row major order (normal c/c++ convention).
28 /// 2. Symmetric matrices are stored in lower triangular format.
29 /// 3. Amount of preallocated stack memory is specified at compilation
30 /// time (the actual size of objects must still be specified at run
31 /// time).
32 ///
33 /// Surprisingly, the ublas linear algebra package does not have any
34 /// built-in symmetric matrix inverse function. We provide one here
35 /// as free function syminvert.
36 ///
37 ////////////////////////////////////////////////////////////////////////
38 
39 #ifndef KALMANLINEARALGEBRA_H
40 #define KALMANLINEARALGEBRA_H
41 
42 #include <cmath>
43 #include "boost/serialization/array_wrapper.hpp" // workaround for deficiency in boost 1.64
44 #include "boost/numeric/ublas/vector.hpp"
45 #include "boost/numeric/ublas/matrix.hpp"
46 #include "boost/numeric/ublas/symmetric.hpp"
47 #include "boost/numeric/ublas/lu.hpp"
48 
49 namespace trkf {
50 
51  /// Define a shortened alias for ublas namespace.
52  namespace ublas = boost::numeric::ublas;
53 
54  /// Vector, dimension N.
55  template<int N>
56  struct KVector
57  {
58  typedef ublas::vector<double, ublas::bounded_array<double, N> > type;
59  };
60 
61  /// Symmetric matrix, dimension NxN.
62  template<int N>
63  struct KSymMatrix
64  {
65  typedef ublas::symmetric_matrix<double, ublas::lower, ublas::row_major, ublas::bounded_array<double, N*(N+1)/2> > type;
66  };
67 
68  /// General matrix, dimension NxM.
69  template<int N, int M>
70  struct KMatrix
71  {
72  typedef ublas::matrix<double, ublas::row_major, ublas::bounded_array<double, N*M> > type;
73  };
74 
75  /// Kalman H-matrix, dimension Nx5.
76  template<int N>
77  struct KHMatrix
78  {
79  typedef typename KMatrix<N,5>::type type;
80  };
81 
82  /// Kalman gain matrix, dimension 5xN.
83  template<int N>
84  struct KGMatrix
85  {
86  typedef typename KMatrix<5,N>::type type;
87  };
88 
89  /// Track state vector, dimension 5.
90  typedef typename KVector<5>::type TrackVector;
91 
92  /// Track error matrix, dimension 5x5.
93  typedef typename KSymMatrix<5>::type TrackError;
94 
95  /// General 5x5 matrix.
96  typedef typename KMatrix<5,5>::type TrackMatrix;
97 
98  /// Invert symmetric matrix (return false if singular).
99  ///
100  /// The method used is Cholesky decomposition.
101  /// This method is efficient and stable for positive-definite matrices.
102  /// In case the matrix is not positive-definite, this method will usually
103  /// work, but there can be some numerical pathologies, including "false
104  /// singular" failures, and numerical instability.
105  /// In the Kalman filter, we expect that this method will be used
106  /// exclusively for positive-definite matrices.
107  ///
108  template <class T, class TRI, class L, class A>
109  bool syminvert(ublas::symmetric_matrix<T, TRI, L, A>& m)
110  {
111  typedef typename ublas::symmetric_matrix<T, TRI, L, A>::size_type size_type;
112  typedef typename ublas::symmetric_matrix<T, TRI, L, A>::value_type value_type;
113 
114  // In situ Cholesky decomposition m = LDL^T.
115  // D is diagonal matrix.
116  // L is lower triangular with ones on the diagonal (ones not stored).
117 
118  for(size_type i = 0; i < m.size1(); ++i) {
119  for(size_type j = 0; j <= i; ++j) {
120 
121  value_type ele = m(i,j);
122 
123  for(size_type k = 0; k < j; ++k)
124  ele -= m(k,k) * m(i,k) * m(j,k);
125 
126  // Diagonal elements (can't have zeroes).
127 
128  if(i == j) {
129  if(ele == 0.)
130  return false;
131  }
132 
133  // Off-diagonal elements.
134 
135  else
136  ele = ele / m(j,j);
137 
138  // Replace element.
139 
140  m(i,j) = ele;
141  }
142  }
143 
144  // In situ inversion of D by simple division.
145  // In situ inversion of L by back-substitution.
146 
147  for(size_type i = 0; i < m.size1(); ++i) {
148  for(size_type j = 0; j <= i; ++j) {
149 
150  value_type ele = m(i,j);
151 
152  // Diagonal elements.
153 
154  if(i == j)
155  m(i,i) = 1./ele;
156 
157  // Off diagonal elements.
158 
159  else {
160  value_type sum = -ele;
161  for(size_type k = j+1; k < i; ++k)
162  sum -= m(i,k) * m(k,j);
163  m(i,j) = sum;
164  }
165  }
166  }
167 
168  // Recompose the inverse matrix in situ by matrix multiplication m = L^T DL.
169 
170  for(size_type i = 0; i < m.size1(); ++i) {
171  for(size_type j = 0; j <= i; ++j) {
172 
173  value_type sum = m(i,i);
174  if(i != j)
175  sum *= m(i,j);
176 
177  for(size_type k = i+1; k < m.size1(); ++k)
178  sum += m(k,k) * m(k,i) * m(k,j);
179 
180  m(i,j) = sum;
181  }
182  }
183 
184  // Done (success).
185 
186  return true;
187  }
188 
189  /// Invert general square matrix by LU decomposition with partial pivoting.
190  /// Return false if singular or not square.
191  ///
192  template <class T, class L, class A>
193  bool invert(ublas::matrix<T, L, A>& m)
194  {
195  // Make sure matrix is square.
196 
197  if(m.size1() != m.size2())
198  return false;
199 
200  // Create permutation matrix for pivoting.
201 
202  ublas::permutation_matrix<std::size_t> pm(m.size1());
203 
204  // Make temp copy of input matrix.
205 
206  ublas::matrix<T, L, A> mcopy(m);
207 
208  // Do LU factorization with partial pivoting.
209  // This step will fail if matrix is singular.
210 
211  int res = lu_factorize(mcopy, pm);
212  if( res != 0 )
213  return false;
214 
215  // Set original matrix to the identity matrix.
216 
217  m.assign(ublas::identity_matrix<T>(m.size1()));
218 
219  // Do backsubstitution.
220 
221  lu_substitute(mcopy, pm, m);
222 
223  // Done (success).
224 
225  return true;
226  }
227 
228  /// Trace of matrix.
229  ///
230  template <class M>
231  typename M::value_type trace(const M& m)
232  {
233  typename M::size_type n = std::min(m.size1(), m.size2());
234  typename M::value_type result = 0.;
235 
236  for(typename M::size_type i = 0; i < n; ++i)
237  result += m(i,i);
238 
239  return result;
240  }
241 }
242 
243 #endif
Kalman gain matrix, dimension 5xN.
static QCString result
ublas::matrix< double, ublas::row_major, ublas::bounded_array< double, N *M > > type
KSymMatrix< 5 >::type TrackError
Track error matrix, dimension 5x5.
Define a shortened alias for ublas namespace.
M::value_type trace(const M &m)
KMatrix< N, 5 >::type type
ublas::vector< double, ublas::bounded_array< double, N > > type
std::void_t< T > n
bool syminvert(ublas::symmetric_matrix< T, TRI, L, A > &m)
General matrix, dimension NxM.
bool invert(ublas::matrix< T, L, A > &m)
KVector< 5 >::type TrackVector
Track state vector, dimension 5.
Kalman H-matrix, dimension Nx5.
T min(sqlite3 *const db, std::string const &table_name, std::string const &column_name)
Definition: statistics.h:55
KMatrix< 5, 5 >::type TrackMatrix
General 5x5 matrix.
KMatrix< 5, N >::type type
Symmetric matrix, dimension NxN.