contrib/brl/bbas/bsta/bsta_gaussian_full.txx
Go to the documentation of this file.
00001 // This is brl/bbas/bsta/bsta_gaussian_full.txx
00002 #ifndef bsta_gaussian_full_txx_
00003 #define bsta_gaussian_full_txx_
00004 //:
00005 // \file
00006 
00007 #include "bsta_gaussian_full.h"
00008 #include <vcl_algorithm.h>
00009 #include <vcl_limits.h>
00010 #if 0
00011 #include <vcl_cassert.h>
00012 #endif
00013 
00014 #include <vnl/algo/vnl_svd.h>
00015 #include <vnl/algo/vnl_determinant.h>
00016 #include <vnl/vnl_inverse.h>
00017 
00018 namespace {
00019 
00020 //: Unroll the mahalanobis distance off diagonal terms
00021 template <class T, unsigned n, unsigned i, unsigned j>
00022 struct compute_sqr_mahalanobis_helper
00023 {
00024   static inline T value(const vnl_vector_fixed<T,n>& d,
00025                         const vnl_matrix_fixed<T,n,n>& inv_covar)
00026   {
00027     return 2*d[i-1]*d[j-1]*inv_covar(i-1,j-1)
00028         + compute_sqr_mahalanobis_helper<T,n,i,j-1>::value(d,inv_covar);
00029   }
00030 };
00031 
00032 //: base case
00033 // this is partial specialization: expect MSVC6 to complain
00034 template <class T, unsigned n, unsigned i>
00035 struct compute_sqr_mahalanobis_helper<T,n,i,0>
00036 {
00037   static inline T value(const vnl_vector_fixed<T,n>& /*d*/,
00038                         const vnl_matrix_fixed<T,n,n>& /*inv_covar*/)
00039   { return 0; }
00040 };
00041 
00042 //: Unroll the mahalanobis distance calculation
00043 template <class T, unsigned n, unsigned i>
00044 struct bsta_gaussian_full_compute_sqr_mahalanobis
00045 {
00046 static inline T value(const vnl_vector_fixed<T,n>& d,
00047                       const vnl_matrix_fixed<T,n,n>& inv_covar)
00048   {
00049     return d[i-1]*d[i-1]*inv_covar(i-1,i-1)
00050         + compute_sqr_mahalanobis_helper<T,n,i,i-1>::value(d,inv_covar)
00051         + bsta_gaussian_full_compute_sqr_mahalanobis<T,n,i-1>::value(d,inv_covar);
00052   }
00053 };
00054 
00055 //: base case
00056 // this is partial specialization: expect MSVC6 to complain
00057 template <class T, unsigned n>
00058 struct bsta_gaussian_full_compute_sqr_mahalanobis<T,n,0>
00059 {
00060   static inline T value(const vnl_vector_fixed<T,n>& /*d*/,
00061                         const vnl_matrix_fixed<T,n,n>& /*inv_covar*/)
00062   { return 0; }
00063 };
00064 
00065 
00066 //: compute the inverse
00067 template <class T, unsigned n>
00068 inline vnl_matrix_fixed<T,n,n>* make_inverse(const vnl_matrix_fixed<T,n,n>& M)
00069 { return new vnl_matrix_fixed<T,n,n>(vnl_svd_inverse(M.as_ref())); }
00070 
00071 template <class T>
00072 inline vnl_matrix_fixed<T,4,4>* make_inverse(const vnl_matrix_fixed<T,4,4>& M)
00073 { return new vnl_matrix_fixed<T,4,4>(vnl_inverse(M)); }
00074 
00075 template <class T>
00076 inline vnl_matrix_fixed<T,3,3>* make_inverse(const vnl_matrix_fixed<T,3,3>& M)
00077 { return new vnl_matrix_fixed<T,3,3>(vnl_inverse(M)); }
00078 
00079 template <class T>
00080 inline vnl_matrix_fixed<T,2,2>* make_inverse(const vnl_matrix_fixed<T,2,2>& M)
00081 { return new vnl_matrix_fixed<T,2,2>(vnl_inverse(M)); }
00082 
00083 template <class T>
00084 inline vnl_matrix_fixed<T,1,1>* make_inverse(const vnl_matrix_fixed<T,1,1>& M)
00085 { return new vnl_matrix_fixed<T,1,1>(vnl_inverse(M)); }
00086 
00087 };
00088 
00089 
00090 //: The squared Mahalanobis distance to this point
00091 template <class T, unsigned int n>
00092 T
00093 bsta_gaussian_full<T,n>::sqr_mahalanobis_dist(const vnl_vector_fixed<T,n>& pt) const
00094 {
00095   if (det_covar_<=T(0))
00096     return vcl_numeric_limits<T>::infinity();
00097   vnl_vector_fixed<T,n> d = bsta_gaussian<T,n>::mean_-pt;
00098 #if 0
00099   assert((sqr_mahalanobis_dist<T,n,n>::value(d,diag_covar_)) > 0);
00100 #endif
00101   return bsta_gaussian_full_compute_sqr_mahalanobis<T,n,n>::value(d,inv_covar());
00102 }
00103 
00104 
00105 //: The squared Mahalanobis distance to this point
00106 template <class T, unsigned int n>
00107 void
00108 bsta_gaussian_full<T,n>::compute_det()
00109 {
00110   det_covar_ = vnl_determinant(covar_);
00111 }
00112 
00113 
00114 //: Update the covariance (and clear cached values)
00115 template <class T, unsigned int n>
00116 void
00117 bsta_gaussian_full<T,n>::set_covar(const vnl_matrix_fixed<T,n,n>& covar)
00118 {
00119   delete inv_covar_;
00120   inv_covar_ = NULL;
00121   covar_ = covar;
00122   compute_det();
00123 }
00124 
00125 
00126 //: Return the inverse of the covariance matrix
00127 // \note this matrix is cached and updated only when needed
00128 template <class T, unsigned int n>
00129 const vnl_matrix_fixed<T,n,n>&
00130 bsta_gaussian_full<T,n>::inv_covar() const
00131 {
00132   if (!inv_covar_){
00133     vnl_matrix_fixed<T,n,n> C = covar_;
00134     if (det_covar_ == T(0)){
00135       // if the matrix is singular we can add a small lambda*I
00136       // before inverting to avoid divide by zero
00137       // Is this the best way to handle this?
00138       T lambda = T(0);
00139       for (unsigned i=0; i<n; ++i)
00140         lambda = vcl_max(lambda,C(i,i));
00141       lambda *= 1e-4f;
00142       for (unsigned i=0; i<n; ++i)
00143         C(i,i) += lambda;
00144     }
00145     inv_covar_ = make_inverse(C);
00146   }
00147   return *inv_covar_;
00148 }
00149 
00150 
00151 #define BSTA_GAUSSIAN_FULL_INSTANTIATE(T,n) \
00152 template class bsta_gaussian_full<T,n >
00153 
00154 
00155 #endif // bsta_gaussian_full_txx_