core/vnl/algo/vnl_ldl_cholesky.h
Go to the documentation of this file.
00001 // This is core/vnl/algo/vnl_ldl_cholesky.h
00002 #ifndef vnl_ldl_cholesky_h_
00003 #define vnl_ldl_cholesky_h_
00004 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00005 #pragma interface
00006 #endif
00007 //:
00008 // \file
00009 // \brief Updateable Cholesky decomposition: A=LDL'
00010 // \author Tim Cootes
00011 // \date   29 Mar 2006
00012 
00013 #include <vnl/vnl_vector.h>
00014 #include <vnl/vnl_matrix.h>
00015 
00016 //: Updateable Cholesky decomposition: A=LDL'
00017 //  A class to hold the Cholesky decomposition of a positive definite
00018 //  symmetric matrix, using the form A=LDL', where L is lower triangular
00019 //  with ones on the leading diagonal, and D is a diagonal matrix.
00020 //  This differs from vnl_cholesky, which decomposes as A=LL', without
00021 //  a constraint on the diagonal.  The advantage of the LDL' form is that
00022 //  it can be efficiently updated.  Thus given the decomposition of A,
00023 //  we can compute the decomposition of (A+v.v') in O(n^2) time.
00024 //
00025 //  This can be used to solve linear systems, compute determinants and inverses.
00026 //
00027 //  To check that the decomposition can be used safely for solving a linear
00028 //  equation it is wise to construct with mode==estimate_condition and
00029 //  check that rcond()>sqrt(machine precision).  If this is not the case
00030 //  it might be a good idea to use vnl_svd instead.
00031 class vnl_ldl_cholesky
00032 {
00033  public:
00034   //: Modes of computation.  See constructor for details.
00035   enum Operation {
00036     quiet,
00037     verbose,
00038     estimate_condition
00039   };
00040 
00041   //: Make cholesky decomposition of M optionally computing the reciprocal condition number.
00042   vnl_ldl_cholesky(vnl_matrix<double> const& M, Operation mode = verbose);
00043  ~vnl_ldl_cholesky() {}
00044 
00045   //: Solve LS problem M x = b
00046   vnl_vector<double> solve(vnl_vector<double> const& b) const;
00047 
00048   //: Solve LS problem M x = b
00049   void solve(vnl_vector<double> const& b, vnl_vector<double>* x) const;
00050 
00051   //: Solve equation of form Lx=y (in-place)
00052   //  x is overwritten with solution
00053   void solve_lx(vnl_vector<double>& y);
00054 
00055   //: Compute determinant
00056   double determinant() const;
00057 
00058   //: Compute rank-1 update, ie the decomposition of (M+v.v')
00059   //  If the initial state is the decomposition of M, then
00060   //  L and D are updated so that on exit  LDL'=M+v.v'
00061   void rank1_update(const vnl_vector<double>& v);
00062 
00063   //: Multi-rank update, ie the decomposition of (M+W.W')
00064   //  If the initial state is the decomposition of M, then
00065   //  L and D are updated so that on exit  LDL'=M+W.W'
00066   void update(const vnl_matrix<double>& W);
00067 
00068   //:   Compute inverse.  Not efficient.
00069   //  Note that you rarely need the inverse - backsubstitution
00070   //  is faster and less prone to rounding errors.
00071   vnl_matrix<double> inverse() const;
00072 
00073   //: Return lower-triangular factor.
00074   const vnl_matrix<double>& lower_triangle() const { return L_; }
00075 
00076   //: Return upper-triangular factor.
00077   vnl_matrix<double> upper_triangle() const { return L_.transpose(); }
00078 
00079   //: Return elements of diagonal matrix D in LDL'
00080   const vnl_vector<double>& diagonal() const { return d_; }
00081 
00082   //: Efficient computation of x' * inv(M) * x
00083   //  Useful when M is a covariance matrix!
00084   double xt_m_inv_x(const vnl_vector<double>& x) const;
00085 
00086   //: Efficient computation of x' * M * x
00087   //  Twice as fast as explicitly computing x' * M * x
00088   double xt_m_x(const vnl_vector<double>& x) const;
00089 
00090   //: A Success/failure flag
00091   int rank_deficiency() const { return num_dims_rank_def_; }
00092 
00093   //: Return reciprocal condition number (smallest/largest singular values).
00094   // As long as rcond()>sqrt(precision) the decomposition can be used for
00095   // solving equations safely.
00096   // Not calculated unless Operation mode at construction was estimate_condition.
00097   double rcond() const { return rcond_; }
00098 
00099   //: Return computed nullvector.
00100   // Not calculated unless Operation mode at construction was estimate_condition.
00101   vnl_vector<double>      & nullvector()       { return nullvector_; }
00102   vnl_vector<double> const& nullvector() const { return nullvector_; }
00103 
00104  protected:
00105   // Data Members--------------------------------------------------------------
00106 
00107   //: Lower triangular matrix
00108   vnl_matrix<double> L_;
00109 
00110   //: Elements of diagonal matrix
00111   vnl_vector<double> d_;
00112 
00113   //: 1/(condition number)
00114   double rcond_;
00115   long num_dims_rank_def_;
00116   vnl_vector<double> nullvector_;
00117 
00118  private:
00119   //: Copy constructor - privatised to avoid it being used
00120   vnl_ldl_cholesky(vnl_ldl_cholesky const & that);
00121   //: Assignment operator - privatised to avoid it being used
00122   vnl_ldl_cholesky& operator=(vnl_ldl_cholesky const & that);
00123 
00124   //: Solve Mx=b, overwriting input vector with the solution.
00125   //  x points to beginning of an n-element vector containing b
00126   //  On exit, x[i] filled with solution vector.
00127   void inplace_solve(double* x) const;
00128 };
00129 
00130 #endif // vnl_ldl_cholesky_h_