TooN 2.1
wls.h
00001 // -*- c++ -*-
00002 
00003 // Copyright (C) 2005,2009 Tom Drummond (twd20@cam.ac.uk)
00004 //
00005 // This file is part of the TooN Library.  This library is free
00006 // software; you can redistribute it and/or modify it under the
00007 // terms of the GNU General Public License as published by the
00008 // Free Software Foundation; either version 2, or (at your option)
00009 // any later version.
00010 
00011 // This library is distributed in the hope that it will be useful,
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 // GNU General Public License for more details.
00015 
00016 // You should have received a copy of the GNU General Public License along
00017 // with this library; see the file COPYING.  If not, write to the Free
00018 // Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
00019 // USA.
00020 
00021 // As a special exception, you may use this file as part of a free software
00022 // library without restriction.  Specifically, if other files instantiate
00023 // templates or use macros or inline functions from this file, or you compile
00024 // this file and link it with other files to produce an executable, this
00025 // file does not by itself cause the resulting executable to be covered by
00026 // the GNU General Public License.  This exception does not however
00027 // invalidate any other reasons why the executable file might be covered by
00028 // the GNU General Public License.
00029 
00030 #ifndef TOON_INCLUDE_WLS_H
00031 #define TOON_INCLUDE_WLS_H
00032 
00033 #include <TooN/TooN.h>
00034 #include <TooN/Cholesky.h>
00035 #include <TooN/helpers.h>
00036 
00037 #include <cmath>
00038 
00039 namespace TooN {
00040 
00041 /// Performs Gauss-Newton weighted least squares computation.
00042 /// @param Size The number of dimensions in the system
00043 /// @param Precision The numerical precision used (double, float etc)
00044 /// @param Decomposition The class used to invert the inverse Covariance matrix (must have one integer size and one typename precision template arguments) this is Cholesky by default, but could also be SQSVD
00045 /// @ingroup gEquations
00046 template <int Size=Dynamic, class Precision=DefaultPrecision,
00047           template<int DecompSize, class DecompPrecision> class Decomposition = Cholesky>
00048 class WLS {
00049 public:
00050 
00051     /// Default constructor or construct with the number of dimensions for the Dynamic case
00052     WLS(int size=0) :
00053         my_C_inv(size,size),
00054         my_vector(size),
00055         my_decomposition(size),
00056         my_mu(size)
00057     {
00058         clear();
00059     }
00060 
00061     /// Clear all the measurements and apply a constant regularisation term. 
00062     void clear(){
00063         my_C_inv = Zeros;
00064         my_vector = Zeros;
00065     }
00066 
00067     /// Applies a constant regularisation term. 
00068     /// Equates to a prior that says all the parameters are zero with \f$\sigma^2 = \frac{1}{\text{val}}\f$.
00069     /// @param val The strength of the prior
00070     void add_prior(Precision val){
00071         for(int i=0; i<my_C_inv.num_rows(); i++){
00072             my_C_inv(i,i)+=val;
00073         }
00074     }
00075   
00076     /// Applies a regularisation term with a different strength for each parameter value. 
00077     /// Equates to a prior that says all the parameters are zero with \f$\sigma_i^2 = \frac{1}{\text{v}_i}\f$.
00078     /// @param v The vector of priors
00079     template<class B2>
00080     void add_prior(const Vector<Size,Precision,B2>& v){
00081         SizeMismatch<Size,Size>::test(my_C_inv.num_rows(), v.size());
00082         for(int i=0; i<my_C_inv.num_rows(); i++){
00083             my_C_inv(i,i)+=v[i];
00084         }
00085     }
00086 
00087     /// Applies a whole-matrix regularisation term. 
00088     /// This is the same as adding the \f$m\f$ to the inverse covariance matrix.
00089     /// @param m The inverse covariance matrix to add
00090     template<class B2>
00091     void add_prior(const Matrix<Size,Size,Precision,B2>& m){
00092         my_C_inv+=m;
00093     }
00094 
00095     /// Add a single measurement 
00096     /// @param m The value of the measurement
00097     /// @param J The Jacobian for the measurement \f$\frac{\partial\text{m}}{\partial\text{param}_i}\f$
00098     /// @param weight The inverse variance of the measurement (default = 1)
00099     template<class B2>
00100     inline void add_mJ(Precision m, const Vector<Size, Precision, B2>& J, Precision weight = 1) {
00101         
00102         //Upper right triangle only, for speed
00103         for(int r=0; r < my_C_inv.num_rows(); r++)
00104         {
00105             double Jw = weight * J[r];
00106             my_vector[r] += m * Jw;
00107             for(int c=r; c < my_C_inv.num_rows(); c++)
00108                 my_C_inv[r][c] += Jw * J[c];
00109         }
00110     }
00111 
00112     /// Add multiple measurements at once (much more efficiently)
00113     /// @param m The measurements to add
00114     /// @param J The Jacobian matrix \f$\frac{\partial\text{m}_i}{\partial\text{param}_j}\f$
00115     /// @param invcov The inverse covariance of the measurement values
00116     template<int N, class B1, class B2, class B3>
00117     inline void add_mJ(const Vector<N,Precision,B1>& m,
00118                        const Matrix<Size,N,Precision,B2>& J,
00119                        const Matrix<N,N,Precision,B3>& invcov){
00120         const Matrix<Size,N,Precision> temp =  J * invcov;
00121         my_C_inv += temp * J.T();
00122         my_vector += temp * m;
00123     }
00124 
00125     /// Add multiple measurements at once (much more efficiently)
00126     /// @param m The measurements to add
00127     /// @param J The Jacobian matrix \f$\frac{\partial\text{m}_i}{\partial\text{param}_j}\f$
00128     /// @param invcov The inverse covariance of the measurement values
00129     template<int N, class B1, class B2, class B3>
00130     inline void add_mJ_rows(const Vector<N,Precision,B1>& m,
00131                        const Matrix<N,Size,Precision,B2>& J,
00132                        const Matrix<N,N,Precision,B3>& invcov){
00133         const Matrix<Size,N,Precision> temp =  J.T() * invcov;
00134         my_C_inv += temp * J;
00135         my_vector += temp * m;
00136     }
00137 
00138     /// Add a single measurement at once with a sparse Jacobian (much, much more efficiently)
00139     /// @param m The measurements to add
00140     /// @param J1 The first block of the Jacobian matrix \f$\frac{\partial\text{m}_i}{\partial\text{param}_j}\f$
00141     /// @param index1 starting index for the first block
00142     /// @param invcov The inverse covariance of the measurement values
00143     template<int N, typename B1>
00144     inline void add_sparse_mJ(const Precision m,
00145                        const Vector<N,Precision,B1>& J1, const int index1,
00146                        const Precision weight = 1){
00147         //Upper right triangle only, for speed
00148         for(int r=0; r < J1.size(); r++)
00149         {
00150             double Jw = weight * J1[r];
00151             my_vector[r+index1] += m * Jw;
00152             for(int c = r; c < J1.size(); c++)
00153                 my_C_inv[r+index1][c+index1] += Jw * J1[c];
00154         }
00155     }
00156 
00157     /// Add multiple measurements at once with a sparse Jacobian (much, much more efficiently)
00158     /// @param m The measurements to add
00159     /// @param J1 The first block of the Jacobian matrix \f$\frac{\partial\text{m}_i}{\partial\text{param}_j}\f$
00160     /// @param index1 starting index for the first block
00161     /// @param invcov The inverse covariance of the measurement values
00162     template<int N, int S1, class P1, class P2, class P3, class B1, class B2, class B3>
00163     inline void add_sparse_mJ_rows(const Vector<N,P1,B1>& m,
00164                        const Matrix<N,S1,P2,B2>& J1, const int index1,
00165                        const Matrix<N,N,P3,B3>& invcov){
00166         const Matrix<S1,N,Precision> temp1 = J1.T() * invcov;
00167         const int size1 = J1.num_cols();
00168         my_C_inv.slice(index1, index1, size1, size1) += temp1 * J1;
00169         my_vector.slice(index1, size1) += temp1 * m;
00170     }
00171 
00172     /// Add multiple measurements at once with a sparse Jacobian (much, much more efficiently)
00173     /// @param m The measurements to add
00174     /// @param J1 The first block of the Jacobian matrix \f$\frac{\partial\text{m}_i}{\partial\text{param}_j}\f$
00175     /// @param index1 starting index for the first block
00176     /// @param J2 The second block of the Jacobian matrix \f$\frac{\partial\text{m}_i}{\partial\text{param}_j}\f$
00177     /// @param index2 starting index for the second block
00178     /// @param invcov The inverse covariance of the measurement values
00179     template<int N, int S1, int S2, class B1, class B2, class B3, class B4>
00180     inline void add_sparse_mJ_rows(const Vector<N,Precision,B1>& m,
00181                        const Matrix<N,S1,Precision,B2>& J1, const int index1,
00182                        const Matrix<N,S2,Precision,B3>& J2, const int index2,
00183                        const Matrix<N,N,Precision,B4>& invcov){
00184         const Matrix<S1,N,Precision> temp1 = J1.T() * invcov;
00185         const Matrix<S2,N,Precision> temp2 = J2.T() * invcov;
00186         const Matrix<S1,S2,Precision> mixed = temp1 * J2;
00187         const int size1 = J1.num_cols();
00188         const int size2 = J2.num_cols();
00189         my_C_inv.slice(index1, index1, size1, size1) += temp1 * J1;
00190         my_C_inv.slice(index2, index2, size2, size2) += temp2 * J2;
00191         my_C_inv.slice(index1, index2, size1, size2) += mixed;
00192         my_C_inv.slice(index2, index1, size2, size1) += mixed.T();
00193         my_vector.slice(index1, size1) += temp1 * m;
00194         my_vector.slice(index2, size2) += temp2 * m;
00195     }
00196 
00197     /// Process all the measurements and compute the weighted least squares set of parameter values
00198     /// stores the result internally which can then be accessed by calling get_mu()
00199     void compute(){
00200     
00201         //Copy the upper right triangle to the empty lower-left.
00202         for(int r=1; r < my_C_inv.num_rows(); r++)
00203             for(int c=0; c < r; c++)
00204                 my_C_inv[r][c] = my_C_inv[c][r];
00205 
00206         my_decomposition.compute(my_C_inv);
00207         my_mu=my_decomposition.backsub(my_vector);
00208     }
00209 
00210     /// Combine measurements from two WLS systems
00211     /// @param meas The measurements to combine with
00212     void operator += (const WLS& meas){
00213         my_vector+=meas.my_vector;
00214         my_C_inv += meas.my_C_inv;
00215     }
00216 
00217     /// Returns the inverse covariance matrix
00218     Matrix<Size,Size,Precision>& get_C_inv() {return my_C_inv;}
00219     /// Returns the inverse covariance matrix
00220     const Matrix<Size,Size,Precision>& get_C_inv() const {return my_C_inv;}
00221     Vector<Size,Precision>& get_mu(){return my_mu;}  ///<Returns the update. With no prior, this is the result of \f$J^\dagger e\f$.
00222     const Vector<Size,Precision>& get_mu() const {return my_mu;} ///<Returns the update. With no prior, this is the result of \f$J^\dagger e\f$.
00223     Vector<Size,Precision>& get_vector(){return my_vector;} ///<Returns the  vector \f$J^{\mathsf T} e\f$
00224     const Vector<Size,Precision>& get_vector() const {return my_vector;} ///<Returns the  vector \f$J^{\mathsf T} e\f$
00225     Decomposition<Size,Precision>& get_decomposition(){return my_decomposition;} ///< Return the decomposition object used to compute \f$(J^{\mathsf T}  J + P)^{-1}\f$
00226     const Decomposition<Size,Precision>& get_decomposition() const {return my_decomposition;} ///< Return the decomposition object used to compute \f$(J^{\mathsf T}  J + P)^{-1}\f$
00227 
00228 
00229 private:
00230     Matrix<Size,Size,Precision> my_C_inv;
00231     Vector<Size,Precision> my_vector;
00232     Decomposition<Size,Precision> my_decomposition;
00233     Vector<Size,Precision> my_mu;
00234 
00235     // comment out to allow bitwise copying
00236     // WLS( WLS& copyof );
00237     // int operator = ( WLS& copyof );
00238 };
00239 
00240 }
00241 
00242 #endif