toon-members
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Toon-members] TooN Cholesky.h doc/Choleskydoc.h


From: Ethan Eade
Subject: [Toon-members] TooN Cholesky.h doc/Choleskydoc.h
Date: Mon, 15 Jan 2007 18:00:54 +0000

CVSROOT:        /cvsroot/toon
Module name:    TooN
Changes by:     Ethan Eade <ethaneade>  07/01/15 18:00:54

Modified files:
        .              : Cholesky.h 
Added files:
        doc            : Choleskydoc.h 

Log message:
        Cholesky now computes LDL^T instead of LL^T.  It is much faster, and
        preserves the old interface.  Any code that used it before should still
        work, however the get_L() method is deprecated in favor of others.
        
        Also added new methods for transforming the inverse.
        
        Algorithms for fixed-size matrices are now implemented in compile-time
        generated code instead of externally generated code.  The quality of
        generated code is identical on gcc-4.1 (the only one I checked).

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/TooN/Cholesky.h?cvsroot=toon&r1=1.12&r2=1.13
http://cvs.savannah.gnu.org/viewcvs/TooN/doc/Choleskydoc.h?cvsroot=toon&rev=1.1

Patches:
Index: Cholesky.h
===================================================================
RCS file: /cvsroot/toon/TooN/Cholesky.h,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -b -r1.12 -r1.13
--- Cholesky.h  23 Jul 2006 10:17:11 -0000      1.12
+++ Cholesky.h  15 Jan 2007 18:00:53 -0000      1.13
@@ -17,233 +17,381 @@
 //     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  
USA
 
 
-#ifndef __CHOLESKY_H
-#define __CHOLESKY_H
+#ifndef CHOLESKY_H
+#define CHOLESKY_H
 
 #include <iostream>
 
 #include <TooN/lapack.h>
 
 #include <TooN/TooN.h>
-#include <TooN/util.h>
+#include <TooN/helpers.h>
 #include <limits>
 
 #ifndef TOON_NO_NAMESPACE
 namespace TooN {
 #endif 
     namespace util {
-       template <int Size, class A1, class A2, class A3, class A4> inline
-       void cholesky_backsub(const FixedMatrix<Size,Size,A1>& L, const 
FixedVector<Size,A2>& invdiag, const FixedVector<Size,A3>& v, 
FixedVector<Size,A4>& x) 
-       {
-           Vector<Size> t;
-           // forward substitution
-           for (int i=0; i<Size; i++) {
-               double b = v[i];
-               for (int j=0; j<i;j++)
-                   b -= L[i][j]*t[j];
-               t[i] = b*invdiag[i];
-           }
-           // back substitution
-           for (int i=Size-1; i >=0; i--) {
-               double b = t[i];
-               for (int j=i+1; j<Size;j++)
-                   b -= L[j][i]*x[j];
-               x[i] = b*invdiag[i];
+       
+       template <int B, int E> struct Dot3 {
+           template <class V1, class V2, class V3> static inline double 
eval(const V1& a, const V2& b, const V3& c) { return a[B]*b[B]*c[B] + 
Dot3<B+1,E>::eval(a,b,c); }
+       };
+       template <int B> struct Dot3<B,B> {
+           template <class V1, class V2, class V3> static inline double 
eval(const V1& a, const V2& b, const V3& c) { return a[B]*b[B]*c[B]; }
+       };
+
+       //
+       // Forward Sub
+       //
+       template <int N, int I=0> struct Forwardsub_L {
+           template <class A1, class A2, class A3> static inline void 
eval(const FixedMatrix<N,N,A1>& L, const FixedVector<N,A2>& v, 
FixedVector<N,A3>& x) {
+               x[I] = v[I] - Dot<0,I-1>::eval(L[I], x);
+               Forwardsub_L<N,I+1>::eval(L, v, x);
            }
+       };
+       template <int N> struct Forwardsub_L<N,0> {
+           template <class A1, class A2, class A3> static inline void 
eval(const FixedMatrix<N,N,A1>& L, const FixedVector<N,A2>& v, 
FixedVector<N,A3>& x) {
+               x[0] = v[0];
+               Forwardsub_L<N,1>::eval(L, v, x);
        }
+       };
+       template <int N> struct Forwardsub_L<N,N> {
+           template <class A1, class A2, class A3> static inline void 
eval(const FixedMatrix<N,N,A1>& L, const FixedVector<N,A2>& v, 
FixedVector<N,A3>& x) {}
+       };
 
-       inline double dynamic_dot(const double* a, const double* b, int size)
-       {
-           double sum = 0;
-           const double* const end = a+size;
-           for (;a != end; ++a, ++b)
-               sum += *a * *b; 
-           return sum;
+       //
+       // Back Sub
+       //
+       template <int N, int I=N> struct Backsub_LT {
+           template <class A1, class A2, class A3, class A4> static inline 
void eval(const FixedMatrix<N,N,A1>& L, const FixedVector<N,A2>& v, 
+                                                                               
      const FixedVector<N,A3>& invdiag, FixedVector<N,A4>& x) {
+               x[I] = v[I]*invdiag[I] - Dot<I+1,N-1>::eval(L.T()[I], x);
+               Backsub_LT<N,I-1>::eval(L, v, invdiag, x);
        }
-
-
-       template <class A1, class A2, class V, class A4>
-       void cholesky_backsub(const DynamicMatrix<A1>& L, const 
DynamicVector<A2>& invdiag, const V& v, DynamicVector<A4>& x) 
-       {
-           const int Size = L.num_rows();
-           Vector<> t(Size);
-           // forward substitution
-           for (int i=0; i<Size; i++) {
-               const double* Li = &L(i,0);
-               t[i] = invdiag[i] * (v[i] - dynamic_dot(Li, t.get_data_ptr(), 
i));
-           }
-           // back substitution
-           for (int i=Size-1; i >=0; i--) {
-               double b = t[i];
-               const double* Lji = &L(i+1,i);
-               for (int j=i+1; j<Size;j++, Lji += Size)
-                   b -= *Lji * x[j];
-               x[i] = b*invdiag[i];
+       };
+       template <int N> struct Backsub_LT<N,N> {
+           template <class A1, class A2, class A3, class A4> static inline 
void eval(const FixedMatrix<N,N,A1>& L, const FixedVector<N,A2>& v, 
+                                                                               
      const FixedVector<N,A3>& invdiag, FixedVector<N,A4>& x) {
+               x[N-1] = v[N-1]*invdiag[N-1];
+               Backsub_LT<N,N-2>::eval(L, v, invdiag, x);
            }
+       };
+       template <int N> struct Backsub_LT<N,0> {
+           template <class A1, class A2, class A3, class A4> static inline 
void eval(const FixedMatrix<N,N,A1>& L, const FixedVector<N,A2>& v, 
+                                                                               
      const FixedVector<N,A3>& invdiag, FixedVector<N,A4>& x) {
+               x[0] = v[0]*invdiag[0] - Dot<1,N-1>::eval(L.T()[0], x);
        }
+       };
        
-       template <int Size, class A1, class A2, class A3> inline int 
cholesky_compute(const FixedMatrix<Size,Size,A1>& M, FixedMatrix<Size,Size,A2>& 
L, FixedVector<Size,A3>& invdiag) 
+       template <int N, class A1, class A2, class A3, class A4>
+       void cholesky_solve(const FixedMatrix<N,N,A1>& L, const 
FixedVector<N,A2>& invdiag, const FixedVector<N,A3>& v, FixedVector<N,A4>& x) 
        {
-           int rank = Size;
-           const double eps = std::numeric_limits<double>::min();
-           for(int i=0;i<Size;i++) {
-               double a=M[i][i];
-               for(int k=0;k<i;k++) 
-                   a-=L[i][k]*L[i][k];
-               if (a < eps) {
-                   --rank;
-                   L[i][i] = invdiag[i] = 0;
-               } else {
-                   L[i][i]=sqrt(a);
-                   invdiag[i] = 1.0/L[i][i];
-               }
-               for(int j=i+1;j<Size;j++) {
-                   L[i][j] = 0;
-                   a=M[i][j];
-                   for(int k=0;k<i;k++) 
-                       a-=L[i][k]*L[j][k];
-                   L[j][i]=a*invdiag[i];
-               }
+           Vector<N> t;
+           Forwardsub_L<N>::eval(L, v, t);
+           Backsub_LT<N>::eval(L, t, invdiag, x);
            }
-           return rank;
+
+       //
+       // Compute cholesky
+       //
+       template <int N, int I, int J=I+1> struct CholeskyInner {
+           template <class A1, class A2, class A3> static inline void 
eval(const FixedMatrix<N,N,A1>& M, FixedMatrix<N,N,A2>& L, const 
FixedVector<N,A3>& invdiag) {
+               const double a = M[I][J] - Dot<0,I-1>::eval(L[I], L.T()[J]);
+               L[I][J] = a;
+               L[J][I] = a * invdiag[I];
+               CholeskyInner<N, I, J+1>::eval(M, L, invdiag);
        }
+       };
 
-       template <class A1, class A2, class A3> inline int 
cholesky_compute(const DynamicMatrix<A1>& M, DynamicMatrix<A2>& L, 
DynamicVector<A3>& invdiag) 
-       {
-           const int Size = M.num_rows();
-           int rank = Size;
-           const double eps = std::numeric_limits<double>::min();
-           for(int i=0;i<Size;i++) {
-               double* const Li = &L(i,0);
-               double a = M(i,i);
-               for (int j=0; j<i; ++j) {
-                   double sum = invdiag[j] * (M(j,i) - dynamic_dot(Li, 
&L(j,0), j));
-                   Li[j] = sum;
-                   a -= sum*sum;
-               }
-               if (eps < a) {
-                   const double s = sqrt(a);
-                   Li[i]= s;
-                   invdiag[i] = 1.0/s;
+       template <int N, int I> struct CholeskyInner<N,I,N> {
+           template <class A1, class A2, class A3> static inline void 
eval(const FixedMatrix<N,N,A1>& M, FixedMatrix<N,N,A2>& L, const 
FixedVector<N,A3>& invdiag) {}
+       };
+       template <int N, int I=0> struct CholeskyOuter {
+           template <class A1, class A2, class A3> static inline void 
eval(const FixedMatrix<N,N,A1>& M, FixedMatrix<N,N,A2>& L, FixedVector<N,A3>& 
invdiag, int& rank) {
+               const double a = M[I][I] - Dot<0,I-1>::eval(L[I], L.T()[I]);
+               if (0 < a) {
+                   L[I][I] = a;
+                   invdiag[I] = 1.0/a;
+                   ++rank;
                } else {
-                   --rank;
-                   Li[i] = invdiag[i] = 0;
+                   L[I][I] = invdiag[I] = 0;
+                   return;
                }
+               CholeskyInner<N,I>::eval(M,L,invdiag);
+               CholeskyOuter<N,I+1>::eval(M,L,invdiag,rank);
            }
+       };
+       template <int N> struct CholeskyOuter<N,N> {
+           template <class A1, class A2, class A3> static inline void 
eval(const FixedMatrix<N,N,A1>& M, FixedMatrix<N,N,A2>& L, FixedVector<N,A3>& 
invdiag, int& rank) {}
+       };
+
+
+       template <int N, class A1, class A2, class A3> int 
cholesky_compute(const FixedMatrix<N,N,A1>& M, FixedMatrix<N,N,A2>& L, 
FixedVector<N,A3>& invdiag)
+       {
+           int rank=0;
+           CholeskyOuter<N>::eval(M, L, invdiag, rank);
            return rank;
        }
 
+       //
+       // Compute inverse
+       //
+       template <int N, int Col, int I=Col+1> struct InverseForward {
+           template <class A1, class A2> static inline void eval(const 
FixedMatrix<N,N,A1>& L, FixedVector<N,A2>& t) {
+               t[I] = -(L[I][Col] + Dot<Col+1,I-1>::eval(L[I], t));
+               InverseForward<N,Col,I+1>::eval(L,t);
+           }
+       };
+       template <int N, int Col> struct InverseForward<N,Col,N> { 
+           template <class A1, class A2> static inline void eval(const 
FixedMatrix<N,N,A1>& L, FixedVector<N,A2>& t) {} 
+       };
 
-       template <int S, class A1, class A2, class A3> inline void 
cholesky_inverse(const FixedMatrix<S,S,A1>& L, const FixedVector<S,A2>& 
invdiag, FixedMatrix<S,S,A3>& I)
-       {
-           for (int col = 0; col<S; col++) {
-               Vector<S> t,x;
-               t[col] = invdiag[col];
-               for (int i=col+1; i<S; i++) {
-                   double psum = 0;
-                   for (int j=col; j<i; j++)
-                       psum -= L[i][j]*t[j];               
-                   t[i] = invdiag[i] * psum;
-               }
-               for (int i=S-1; i>col; i--) {
-                   double psum = t[i];
-                   for (int j=i+1; j<S; j++)
-                       psum -= L[j][i]*x[j];
-                   I[i][col] = I[col][i] = x[i] = invdiag[i] * psum;
-               }
-               double psum = t[col];
-               for (int j=col+1; j<S; j++)
-                   psum -= L[j][col]*x[j];             
-               I[col][col] = invdiag[col]*psum;
+       template <int N, int Col, int I=N-1> struct InverseBack {
+           template <class A1, class A2, class A3, class A4> static inline 
void eval(const FixedMatrix<N,N,A1>& L, const FixedVector<N,A2>& t, 
+                                                                               
      const FixedVector<N,A3>& invdiag, FixedMatrix<N,N,A4>& Inv) {
+               Inv[I][Col] = Inv[Col][I] = invdiag[I]*t[I] - 
Dot<I+1,N-1>::eval(L.T()[I], Inv[Col]);
+               InverseBack<N,Col,I-1>::eval(L, t, invdiag, Inv);
+           }
+       };
+       template <int N, int Col> struct InverseBack<N,Col,Col> {
+           template <class A1, class A2, class A3, class A4> static inline 
void eval(const FixedMatrix<N,N,A1>& L, const FixedVector<N,A2>& t, 
+                                                                               
      const FixedVector<N,A3>& invdiag, FixedMatrix<N,N,A4>& Inv) {
+               Inv[Col][Col] = invdiag[Col] - Dot<Col+1,N-1>::eval(L.T()[Col], 
Inv[Col]);
            }
+       };
+       
+       template <int N, int Col=0> struct InverseOuter {
+           template <class A1, class A2, class A3> static inline void 
eval(const FixedMatrix<N,N,A1>& L, const FixedVector<N,A2>& invdiag, 
FixedMatrix<N,N,A3>& Inv) {
+               Vector<N> t;
+               InverseForward<N,Col>::eval(L, t);
+               InverseBack<N,Col>::eval(L, t, invdiag, Inv);
+               InverseOuter<N,Col+1>::eval(L,invdiag,Inv);
        }
+       };
+       template <int N> struct InverseOuter<N,N> {
+           template <class A1, class A2, class A3> static inline void 
eval(const FixedMatrix<N,N,A1>& L, const FixedVector<N,A2>& invdiag, 
FixedMatrix<N,N,A3>& Inv) {}
+       };
 
-       template <class A1, class A2, class A3> inline void 
cholesky_inverse(const DynamicMatrix<A1>& L, const DynamicVector<A2>& invdiag, 
DynamicMatrix<A3>& I)
+       template <int S, class A1, class A2, class A3> void 
cholesky_inverse(const FixedMatrix<S,S,A1>& L, const FixedVector<S,A2>& 
invdiag, FixedMatrix<S,S,A3>& I)
        {
-           int S = L.num_rows();
-           for (int col = 0; col<S; col++) {
-               Vector<> t(S),x(S);
-               t[col] = invdiag[col];
-               for (int i=col+1; i<S; i++) {
-                   const double* Li = &L(i,0);
-                   double psum = 0;
-                   for (int j=col; j<i; j++)
-                       psum -= Li[j]*t[j];
-                   t[i] = invdiag[i] * psum;
-               }
-               for (int i=S-1; i>col; i--) {
-                   const double* Lji = &L(i+1,i);
-                   double psum = t[i];
-                   for (int j=i+1; j<S; j++, Lji += S)
-                       psum -= *Lji * x[j];
-                   I(i,col) = I(col,i) = x[i] = invdiag[i] * psum;
+           InverseOuter<S>::eval(L, invdiag, I);
                }
-               double psum = t[col];
-               const double* Ljc = &L(col+1,col);
-               for (int j=col+1; j<S; j++, Ljc += S)
-                   psum -= *Ljc * x[j];                
-               I(col,col) = invdiag[col]*psum;
+
+       //
+       // Cholesky update
+       //
+       template <int N, int I, int J=I-1> struct UpdateInner {
+           template <class LT, class PT, class FT, class ST> static inline 
void eval(LT& L, const PT& p, const FT& F, const ST sigma) {
+               const double old = L[I][J];
+               L[I][J] = old + (sigma * p[J]) * F[J];
+               UpdateInner<N,I,J-1>::eval(L, p, F, sigma + old * p[J]);
            }
+       };
+
+       template <int N, int I> struct UpdateInner<N,I,-1> {
+           template <class LT, class PT, class FT, class ST> static inline 
void eval(LT& L, const PT& p, const FT& F, const ST sigma) {}
+       };
+           
+       template <int N, int I=1> struct UpdateOuter {
+           template <class LT, class PT, class FT> static inline void eval(LT& 
L, const PT& p, const FT& F) {
+               UpdateInner<N,I>::eval(L, p, F, p[I]);
+               UpdateOuter<N,I+1>::eval(L, p ,F);
        }
+       };
 
+       template <int N> struct UpdateOuter<N,N> {
+           template <class LT, class PT, class FT> static inline void eval(LT& 
L, const PT& p, const FT& F) {}
+       };
        
+       template <class P, int N, class A1, class A2> void 
cholesky_update(TooN::FixedMatrix<N,N,A1>& L, TooN::FixedVector<N,A2>& invdiag, 
const P& p)
+       {
+           double F[N-1];
+           double alpha = 1;
+           for (int i=0; i<N-1; ++i) {
+               const double p2 = p[i]*p[i];
+               const double di = L[i][i];
+               L[i][i] += alpha * p2;
+               invdiag[i] = 1.0/L[i][i];
+               const double a_over_d = alpha*invdiag[i];
+               F[i] = a_over_d;
+               alpha = di * a_over_d;
+           }
+           L[N-1][N-1] += alpha * (p[N-1]*p[N-1]);
+           invdiag[N-1] = 1.0/L[N-1][N-1];
+               
+           UpdateOuter<N>::eval(L, p, F);
+       }
     }
 
-    template <int Size=-1>
+    template <int N=-1>
     class Cholesky {
     public:
 
        template<class Accessor>
-       Cholesky(const FixedMatrix<Size,Size,Accessor>& m){
+       Cholesky(const FixedMatrix<N,N,Accessor>& m){
            compute(m);
        }
     
        template<class Accessor>
-       void compute(const FixedMatrix<Size,Size,Accessor>& m){
+       void compute(const FixedMatrix<N,N,Accessor>& m){
            rank = util::cholesky_compute(m,L,invdiag);
        }
        int get_rank() const { return rank; }
 
        double get_determinant() const {
            double det = L[0][0];
-           for (int i=1; i<Size; i++)
+           for (int i=1; i<N; i++)
                det *= L[i][i];
-           return det*det;
+           return det;
+       }
+
+       const Matrix<N>& get_L_D() const { return L; }
+
+       template <class A1, class A2> static void sqrt(const 
FixedMatrix<N,N,A1>& A, FixedMatrix<N,N,A2>& L) {
+           for (int i=0; i<N; ++i) {
+               double a = A[i][i];
+               for (int k=0; k<i; ++k)
+                   a -= L[i][k]*L[i][k];
+               if (0<a) {
+                   L[i][i] = ::sqrt(a);
+               } else {
+                   Zero(L.slice(i,i,N-i,N-i));
+                   return;
+               }
+               const double id = 1.0/L[i][i];
+               for (int j=i+1; j<N; ++j) {
+                   L[i][j] = 0;
+                   double a = A[i][j];
+                   for (int k=0; k<i; ++k)
+                       a -= L[i][k]*L[j][k];
+                   L[j][i] = a * id;
+               }
+           }
        }
 
-       const Matrix<Size>& get_L() const {
+       template <class A1> static Matrix<N> sqrt(const FixedMatrix<N,N,A1>& A) 
{ 
+           Matrix<N> L;
+           Cholesky<N>::sqrt(A,L);
            return L;
        }
 
+       template <class A> void get_sqrt(FixedMatrix<N,N,A>& M) const {
+           for (int i=0; i<N; ++i) {
+               const double root_d = ::sqrt(L[i][i]);
+               M[i][i] = root_d;
+               for (int j=i+1; j<N; ++j) {
+                   M[j][i] = L[j][i]*root_d;
+                   M[i][j] = 0;
+               }
+           }
+       }
+
+       Matrix<N> get_sqrt() const {
+           Matrix<N> S;
+           get_sqrt(S);
+           return S;
+       }
+       
+       Matrix<N> get_L() const __attribute__ ((deprecated)) { return 
get_sqrt(); }
+       
+       template <class A> void get_inv_sqrt(FixedMatrix<N,N,A>& M) const {
+           Vector<N> root;
+           for (int i=0; i<N; ++i)
+               root[i] = ::sqrt(invdiag[i]);
+           for (int j=0; j<N; ++j) {
+               for (int i=j+1; i<N; ++i) {
+                   double sum = L[i][j];
+                   for (int k=j+1; k<i; ++k)
+                       sum += L[i][k]*M[j][k];
+                   M[j][i] = -sum;
+                   M[i][j] = 0;
+               }
+               M[j][j] = root[j];
+               for (int i=j+1; i<N; ++i)
+                   M[j][i] *= root[i];
+           }
+       }
+       
+       template <class A> double mahalanobis(const FixedVector<N,A>& v) const {
+           Vector<N> L_inv_v;
+           util::Forwardsub_L<N>::eval(L, v, L_inv_v);
+           return util::Dot3<0,N-1>::eval(L_inv_v, L_inv_v, invdiag);
+       }
+
+       template <class F, int M, class A1, class A2> void 
transform_inverse(const FixedMatrix<M,N,A1>& J, FixedMatrix<M,M,A2>& T) const {
+           Matrix<M,N> L_inv_JT;
+           for (int i=0; i<M; ++i)
+               util::Forwardsub_L<N>::eval(L, J[i], L_inv_JT[i]);
+           for (int i=0; i<M; ++i) {           
+               F::eval(T[i][i],util::Dot3<0,N-1>::eval(L_inv_JT[i], 
L_inv_JT[i], invdiag));
+               for (int j=i+1; j<M; ++j) {
+                   const double x = util::Dot3<0,N-1>::eval(L_inv_JT[i], 
L_inv_JT[j], invdiag);
+                   F::eval(T[i][j],x);
+                   F::eval(T[j][i],x);
+               }
+           }
+       }
+       template <int M, class A1, class A2> void transform_inverse(const 
FixedMatrix<M,N,A1>& J, FixedMatrix<M,M,A2>& T) const {
+           transform_inverse<util::Assign>(J,T);
+       }
+       template <int M, class A> Matrix<M> transform_inverse(const 
FixedMatrix<M,N,A>& J) const {
+           Matrix<M> T;
+           transform_inverse(J,T);
+           return T;
+       }
+
+       template <class A1, class A2> inline 
+       void inverse_times(const FixedVector<N,A1>& v, FixedVector<N,A2>& x) 
const
+       {
+           util::cholesky_solve(L, invdiag, v, x);
+       }
+
        template <class Accessor> inline 
-       Vector<Size> backsub(const FixedVector<Size,Accessor>& v) const
+       Vector<N> inverse_times(const FixedVector<N,Accessor>& v) const
        {
-           Vector<Size> x;
-           util::cholesky_backsub(L, invdiag, v, x);
+           Vector<N> x;
+           inverse_times(v, x);
            return x;
        }
       
-       template <class Accessor, int Cols> inline Matrix<Size,Cols> 
inverse_times(const FixedMatrix<Size,Cols,Accessor>& m)
+       template <class Accessor> inline 
+       Vector<N> backsub(const FixedVector<N,Accessor>& v) const { return 
inverse_times(v); }
+      
+       template <class A, int M> inline Matrix<N,M> inverse_times(const 
FixedMatrix<N,M,A>& m)
        {
-           Matrix<Cols, Size> result;
-           for (int i=0; i<Cols; i++)
-               result[i] = backsub(m.T()[i]);
-           return result.T();
+           Matrix<N,M> result;
+           for (int i=0; i<M; i++)
+               inverse_times(m.T()[i], result.T()[i]);
+           return result;
        }
 
-       template <class A> void get_inverse(FixedMatrix<Size,Size,A>& M) const {
+       template <class A> void get_inverse(FixedMatrix<N,N,A>& M) const {
            util::cholesky_inverse(L, invdiag, M);
        }
 
-       Matrix<Size,Size> get_inverse() const {
-           Matrix<Size,Size> M;
+       Matrix<N> get_inverse() const {
+           Matrix<N> M;
            get_inverse(M);
            return M;
        }
 
+       template <int M, class A>  void update(const FixedMatrix<N,M,A>& V) {
+           for (int i=0; i<M; ++i) {
+               Vector<N> p;
+               util::Forwardsub_L<N>::eval(L, V.T()[i], p);
+               util::cholesky_update(L, invdiag, p);
+           }
+       }
+
+       template <class A>  void update(const FixedVector<N,A>& v) {
+           Vector<N> p;
+           util::Forwardsub_L<N>::eval(L, v, p);
+           util::cholesky_update(L, invdiag, p);
+       }
+       
     private:
-       Matrix<Size,Size,RowMajor> L;
-       Vector<Size> invdiag;
+       Matrix<N> L;
+       Vector<N> invdiag;
        int rank;
     };
   
@@ -252,14 +400,20 @@
     public:
 
        template<class Accessor>
-       Cholesky(const DynamicMatrix<Accessor>& m) : L(m.num_rows(), 
m.num_cols()), invdiag(m.num_rows()) {
-           assert(m.num_rows() == m.num_cols());
+       Cholesky(const DynamicMatrix<Accessor>& m) {
            compute(m);
        }
 
        template<class Accessor>
        void compute(const DynamicMatrix<Accessor>& m){
-           rank = util::cholesky_compute(m,L,invdiag);
+           assert(m.num_rows() == m.num_cols());
+           L.assign(m);
+           int N = L.num_rows();
+           int info;
+           dpotrf_("L", &N, L.get_data_ptr(), &N, &info);
+           assert(info >= 0);
+           if (info > 0)
+               rank = info-1;
        }
        int get_rank() const { return rank; }
 
@@ -267,8 +421,12 @@
        Vector<> backsub(const V& v) const
        {
            assert(v.size() == L.num_rows());
-           Vector<> x(L.num_rows());
-           util::cholesky_backsub(L, invdiag, v, x);
+           Vector<> x = v;
+           int N=L.num_rows();
+           int NRHS=1;
+           int info;
+           dpotrs_("L", &N, &NRHS, L.get_data_ptr(), &N, x.get_data_ptr(), &N, 
&info);     
+           assert(info==0);
            return x;
        }
 
@@ -284,8 +442,12 @@
        }
 
        template <class Mat> void get_inverse(Mat& M) const {
-           assert(M.num_rows() == M.num_cols() && M.num_rows() == 
L.num_rows());
-           util::cholesky_inverse(L, invdiag, M);
+           M = L;
+           int N = L.num_rows();
+           int info;
+           dpotri_("L", &N, M.get_data_ptr(), &N, &info);
+           assert(info == 0);
+           TooN::Symmetrize(M);
        }
 
        Matrix<> get_inverse() const {
@@ -296,7 +458,6 @@
 
     private:
        Matrix<> L;
-       Vector<> invdiag;
        int rank;
     };
 

Index: doc/Choleskydoc.h
===================================================================
RCS file: doc/Choleskydoc.h
diff -N doc/Choleskydoc.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ doc/Choleskydoc.h   15 Jan 2007 18:00:54 -0000      1.1
@@ -0,0 +1,168 @@
+/*
+  Copyright (c) 2005 Paul Smith
+
+  Permission is granted to copy, distribute and/or modify this document under
+  the terms of the GNU Free Documentation License, Version 1.2 or any later
+  version published by the Free Software Foundation; with no Invariant
+  Sections, no Front-Cover Texts, and no Back-Cover Texts.
+
+  You should have received a copy of the GNU Free Documentation License
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc.
+  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+// A proxy version of the LU class,
+// cleaned up to present a comprehensible
+// version of the LU interface
+
+#ifdef DOXYGEN_INCLUDE_ONLY_FOR_DOCS
+
+
+#include <iostream>
+
+#include <TooN/lapack.h>
+
+#include <TooN/TooN.h>
+#include <TooN/helpers.h>
+#include <limits>
+
+namespace TooN {
+/// @class Cholesky Choleskydoc.h TooN/Cholesky.h
+/// Decomposes a positive-semidefinite symmetric matrix A (such as a 
covariance) into L*D*L^T, where L is lower-triangular and D is diagonal.
+/// Also can compute A = S*S^T, with S lower triangular.  The LDL^T form is 
faster to compute than the class Cholesky decomposition.
+/// The decomposition can be used to compute A^-1*x, A^-1*M, M*A^-1*M^T, and 
A^-1 itself, though the latter rarely needs to be explicitly represented.
+/// Also efficiently computes det(A) and rank(A).
+/// It can be used as follows:
+/// @code
+/// // Declare some matrices.
+/// Matrix<3> A = ...; // we'll pretend it is pos-def
+/// Matrix<2,3> M;
+/// Matrix<2> B;
+/// Vector<3> y = (make_Vector, 2,3,4);
+/// // create the Cholesky decomposition of A
+/// Cholesky<3> chol(A);
+/// // compute x = A^-1 * y
+/// Vector<3> x = cholA.inverse_times(y);
+/// Identical to above
+/// x = cholA.backsub(y);
+/// // compute B = M*A^-1*M^T
+/// B = cholA.transform_inverse(M);
+/// //compute A^-1
+/// Matrix<3> Ainv = cholA.get_inverse();
+/// Matrix<3> C = ... // again, C is pos-def
+/// //compute the 'square-root' of C
+/// Matrix<3> L = Cholesky<3>::sqrt(C);
+/// @endcode
+/// @ingroup gDecomps
+template <int N>
+class Cholesky {
+public:
+
+    /// Construct the Cholesky-ish decomposition of a matrix. This initialises 
the class, and
+    /// performs the decomposition immediately.
+    /// Run time is O(N^3)
+    template<class Accessor> Cholesky(const FixedMatrix<N,N,Accessor>& m);
+    
+    /// Compute the LDL^T decomposition of another matrix.
+    /// Run time is O(N^3)
+    template<class Accessor> void compute(const FixedMatrix<N,N,Accessor>& m);
+
+    /// Get the rank of the matrix
+    int get_rank() const;
+
+    /// Get the determinant
+    double get_determinant() const;
+
+    /// Get the internal representation of L and D.
+    /// L has 1's on the diagonal, so here D is stored in its diagonal.
+    /// L is lower triangular; the upper-triangular contents are not 
initialized.
+    /// Not yet present in Cholesky<-1>
+    const Matrix<N>& get_L_D() const { return L; }
+
+    /// Compute the lower-triangular 'square-root' L of A, s.t. A = L*L^T
+    /// Run time is O(N^3)
+    /// Not yet present in Cholesky<-1>
+    template <class A1, class A2> static void sqrt(const FixedMatrix<N,N,A1>& 
A, FixedMatrix<N,N,A2>& L);
+
+    /// Compute the lower-triangular 'square-root' L, of A, s.t. A = L*L^T
+    /// Run time is O(N^3)
+    /// Not yet present in Cholesky<-1>
+    template <class A1> static Matrix<N> sqrt(const FixedMatrix<N,N,A1>& A);
+
+    /// Compute the lower-triangular 'square-root' L of the decomposed matrix, 
s.t. A = L*L^T
+    /// L is stored in M
+    /// Not yet present in Cholesky<-1>
+    template <class A> void get_sqrt(FixedMatrix<N,N,A>& M) const;
+
+    /// Compute the lower-triangular 'square-root' L of the decomposed matrix, 
s.t. A = L*L^T
+    /// Not yet present in Cholesky<-1>
+    Matrix<N> get_sqrt() const;
+       
+    /// Compute the lower-triangular 'square-root' L of the decomposed matrix, 
s.t. A = L*L^T
+    /// @deprecated Use get_sqrt, or the static sqrt function
+    Matrix<N> get_L() const __attribute__ ((deprecated));
+       
+    /// Compute the lower-triangular 'square-root' L of the inverse of the 
decomposed matrix, s.t. A^-1 = L*L^T
+    /// Not yet present in Cholesky<-1>
+    template <class A> void get_inv_sqrt(FixedMatrix<N,N,A>& M) const;
+       
+    /// Compute the Mahalanobis squared magnitude of x, d = x*A^-1*x
+    /// Run time is O(N^2)
+    /// Not yet present in Cholesky<-1>
+    template <class A> double mahalanobis(const FixedVector<N,A>& v) const;
+
+    /// Compute J*A^-1*J^T, and store in T using F::eval (for instance, F 
might be util::PlusAssign to add the result to T)
+    /// Run time is O(MN^2 + NM^2)
+    /// Not yet present in Cholesky<-1>
+    template <class F, int M, class A1, class A2> void transform_inverse(const 
FixedMatrix<M,N,A1>& J, FixedMatrix<M,M,A2>& T) const;
+
+    /// Compute J*A^-1*J^T, and store in T
+    /// Run time is O(MN^2 + NM^2)
+    /// Not yet present in Cholesky<-1>
+    template <int M, class A1, class A2> void transform_inverse(const 
FixedMatrix<M,N,A1>& J, FixedMatrix<M,M,A2>& T) const;
+
+    /// Compute J*A^-1*J^T
+    /// Run time is O(MN^2 + NM^2)
+    /// Not yet present in Cholesky<-1>
+    template <int M, class A> Matrix<M> transform_inverse(const 
FixedMatrix<M,N,A>& J) const;
+
+    /// Compute x = A^-1*v
+    /// Run time is O(N^2)
+    /// Not yet present in Cholesky<-1>
+    template <class A1, class A2> inline void inverse_times(const 
FixedVector<N,A1>& v, FixedVector<N,A2>& x) const;
+
+    /// Compute A^-1*v
+    /// Run time is O(N^2)
+    /// Not yet present in Cholesky<-1>
+    template <class Accessor> inline Vector<N> inverse_times(const 
FixedVector<N,Accessor>& v) const;
+
+    /// Compute x = A^-1*v
+    /// Run time is O(N^2)
+    template <class Accessor> inline Vector<N> backsub(const 
FixedVector<N,Accessor>& v) const;
+      
+    /// Compute A^-1*B
+    /// Run time is O(MN^2)
+    /// Not yet present in Cholesky<-1>
+    template <class A, int M> inline Matrix<N,M> inverse_times(const 
FixedMatrix<N,M,A>& B);
+
+    /// Compute A^-1 and store in M
+    /// Run time is O(N^3)
+    template <class A> void get_inverse(FixedMatrix<N,N,A>& M) const;
+
+    /// Compute A^-1
+    /// Run time is O(N^3)
+    Matrix<N> get_inverse() const;
+       
+    /// Update the decomposition for A' = A + V*V^T
+    /// Run time is O(MN^2), but for small N, it's faster to compute A' and 
recompute the decomposition
+    /// Not yet present in Cholesky<-1>
+    template <int M, class A>  void update(const FixedMatrix<N,M,A>& V);
+
+    /// Update the decomposition for A' = A + v*v^T
+    /// Run time is O(N^2), but for small N, it's faster to compute A' and 
recompute the decomposition
+    /// Not yet present in Cholesky<-1>
+    template <class A>  void update(const FixedVector<N,A>& v);
+};
+
+#endif




reply via email to

[Prev in Thread] Current Thread [Next in Thread]