contrib/mul/mcal/mcal_extract_mode.cxx
Go to the documentation of this file.
00001 //:
00002 // \file
00003 // \brief Functions to learn modes from subsets of data
00004 // \author Tim Cootes
00005 
00006 #include "mcal_extract_mode.h"
00007 #include <vnl/algo/vnl_symmetric_eigensystem.h>
00008 #include <vcl_algorithm.h>
00009 #include <vcl_iostream.h>
00010 #include <mbl/mbl_data_array_wrapper.h>
00011 #include <mcal/mcal_pca.h>
00012 
00013 //: Computes one mode from used elements of each \p dv
00014 //  Effectives computes the first eigenvector of the
00015 //  covariance matrix formed from selecting the used elements
00016 //  of each \p dv[i], ie \p dv[i][used[j]].
00017 //  Resulting vector is returned as a full length vector
00018 //  (the same size as \p dv[i]).
00019 //
00020 //  The contribution of this vector is removed from each \p dv,
00021 //  \p dv[i]-=mode*b, where \p b=dv[i].mode
00022 void mcal_extract_mode(vcl_vector<vnl_vector<double> >& dv,
00023                        const vcl_vector<unsigned>& used,
00024                        vnl_vector<double>& mode,
00025                        double& var)
00026 {
00027   if (used.size()==0)
00028   {
00029     // Use all elements
00030     mcal_extract_mode(dv,mode,var);
00031     return;
00032   }
00033 
00034   unsigned ns=dv.size();
00035   unsigned nd=dv[0].size();
00036 
00037   // Extract the elements into a new set of vectors
00038   vcl_vector<vnl_vector<double> > v(ns);
00039   for (unsigned i=0;i<ns;++i)
00040   {
00041     v[i].set_size(used.size());
00042     for (unsigned j=0;j<used.size();++j)
00043       v[i][j]=dv[i][used[j]];
00044   }
00045 
00046   // Perform PCA
00047   // We assume data to be zero mean
00048   vnl_vector<double> zero_mean(v[0].size(),0.0),mode_var0;
00049   vnl_matrix<double> modes0;
00050   mcal_pca pca;
00051   pca.set_mode_choice(1,1,1.0);
00052   mbl_data_array_wrapper<vnl_vector<double> > data(v);
00053   pca.build_about_mean(data,zero_mean,modes0,mode_var0);
00054 
00055   // Reconstruct mode from first mode of PCA
00056   var = mode_var0[0];
00057   mode.set_size(nd);
00058   mode.fill(0.0);
00059   vnl_vector<double> sub_mode = modes0.get_column(0);
00060   for (unsigned j=0;j<used.size();++j)
00061     mode[used[j]] = sub_mode[j];
00062 
00063   // Compute parameters and remove effect from dv
00064   for (unsigned i=0;i<ns;++i)
00065   {
00066     double b = dot_product(sub_mode,v[i]);
00067     dv[i] -= b*mode;
00068   }
00069 }
00070 
00071 //: Computes one mode by applying PCA to \p dv
00072 //  Effectives computes the first eigenvector of the
00073 //  covariance matrix.
00074 //  The contribution of this vector is removed from each \p dv,
00075 //  \p dv[i]-=mode*b, where \p b=dv[i].mode
00076 void mcal_extract_mode(vcl_vector<vnl_vector<double> >& dv,
00077                        vnl_vector<double>& mode,
00078                        double& var)
00079 {
00080   unsigned ns=dv.size();
00081 
00082   // Perform PCA
00083   // We assume data to be zero mean
00084   vnl_vector<double> zero_mean(dv[0].size(),0.0),mode_var0;
00085   vnl_matrix<double> modes0;
00086   mcal_pca pca;
00087   pca.set_mode_choice(1,1,1.0);
00088   mbl_data_array_wrapper<vnl_vector<double> > data(dv);
00089   pca.build_about_mean(data,zero_mean,modes0,mode_var0);
00090 
00091   // Reconstruct mode from first mode of PCA
00092   var = mode_var0[0];
00093   mode = modes0.get_column(0);
00094 
00095   // Compute parameters and remove effect from dv
00096   for (unsigned i=0;i<ns;++i)
00097   {
00098     double b = dot_product(mode,dv[i]);
00099     dv[i] -= b*mode;
00100   }
00101 }
00102 
00103 
00104 //: Compute modes and associated variance of supplied data
00105 //  \param used[i] indicates the set of elements to be used for
00106 //  mode i.  Modes beyond \p used.size() will use all elements.
00107 void mcal_extract_modes(vcl_vector<vnl_vector<double> >& dv,
00108                         const vcl_vector<vcl_vector<unsigned> >& used,
00109                         unsigned max_modes, double var_prop,
00110                         vnl_matrix<double>& modes,
00111                         vnl_vector<double>& mode_var)
00112 {
00113   unsigned ns=dv.size();
00114 
00115   // Compute total variance, and threshold
00116   double total_var=0;
00117   for (unsigned i=0;i<ns;++i)
00118     total_var += dv[i].squared_magnitude();
00119 
00120   total_var/=ns;
00121   double var_thresh = var_prop*total_var;
00122 
00123   vcl_vector<vnl_vector<double> > mode_set(used.size());
00124   vcl_vector<double> var_set(used.size());
00125 
00126   double var_sum=0.0;
00127 
00128   // Extract all modes associated with known used subsets
00129   for (unsigned i=0;i<used.size();++i)
00130   {
00131     mcal_extract_mode(dv,used[i],mode_set[i],var_set[i]);
00132     var_sum+=var_set[i];
00133   }
00134 
00135   // Now find the modes required to explain the remainder of the
00136   // data.
00137 
00138   if (var_sum<var_thresh && used.size()<max_modes)
00139   {
00140     // Perform PCA
00141     // We assume data to be zero mean
00142     vnl_vector<double> mean0(dv[0].size()),mode_var0;
00143     mean0.fill(0.0);  // Zero mean
00144     vnl_matrix<double> modes0;
00145     mcal_pca pca;
00146     pca.set_mode_choice(1,max_modes-used.size(),1.0);
00147     mbl_data_array_wrapper<vnl_vector<double> > data(dv);
00148     pca.build_about_mean(data,mean0,modes0,mode_var0);
00149 
00150     // Add modes until we pass threshold on variance or n.modes.
00151     unsigned m=0;
00152     while (mode_set.size()<max_modes &&
00153            var_sum<var_thresh && m<mode_var0.size())
00154     {
00155       // Add mode m
00156       vnl_vector<double> mode=modes0.get_column(m);
00157       mode_set.push_back(mode);
00158       var_set.push_back(mode_var0[m]);
00159       var_sum += mode_var0[m];
00160       m++;  // Move to next mode
00161     }
00162   }
00163 
00164   unsigned nd = dv[0].size();
00165   unsigned n_modes = mode_set.size();
00166 
00167   // Construct the output data
00168   modes.set_size(nd,n_modes);
00169   mode_var.set_size(n_modes);
00170   for (unsigned i=0;i<n_modes;++i)
00171   {
00172     modes.set_column(i,mode_set[i]);
00173     mode_var[i]=var_set[i];
00174   }
00175 }
00176