Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members

vpdfl_gaussian_builder.cxx

Go to the documentation of this file.
00001 // This is mul/vpdfl/vpdfl_gaussian_builder.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 // \file
00007 // \brief Multi-variate gaussian PDF with arbitrary axes.
00008 // \author Tim Cootes
00009 // \date 16-Oct-98
00010 //
00011 // Modifications
00012 // \verbatim
00013 //    IMS   Converted to VXL 18 April 2000
00014 // \endverbatim
00015 
00016 //=======================================================================
00017 // inclusions
00018 //=======================================================================
00019 
00020 #include "vpdfl_gaussian_builder.h"
00021 
00022 #include <vcl_cstdlib.h>
00023 #include <vcl_string.h>
00024 #include <vcl_cassert.h>
00025 #include <mbl/mbl_data_wrapper.h>
00026 #include <vpdfl/vpdfl_gaussian.h>
00027 #include <vnl/algo/vnl_symmetric_eigensystem.h>
00028 
00029 #include <mbl/mbl_parse_block.h>
00030 #include <mbl/mbl_read_props.h>
00031 #include <vul/vul_string.h>
00032 #include <mbl/mbl_exception.h>
00033 
00034 // Weights smaller than this are assumed to be zero
00035 const double min_wt = 1e-8;
00036 
00037 //=======================================================================
00038 // Dflt ctor
00039 //=======================================================================
00040 
00041 vpdfl_gaussian_builder::vpdfl_gaussian_builder()
00042   : min_var_(1.0e-6)
00043 {
00044 }
00045 
00046 //=======================================================================
00047 // Destructor
00048 //=======================================================================
00049 
00050 vpdfl_gaussian_builder::~vpdfl_gaussian_builder()
00051 {
00052 }
00053 
00054 //=======================================================================
00055 
00056 vpdfl_gaussian& vpdfl_gaussian_builder::gaussian(vpdfl_pdf_base& model) const
00057 {
00058     // need a vpdfl_gaussian
00059   assert(model.is_class("vpdfl_gaussian"));
00060   return static_cast<vpdfl_gaussian&>(model);
00061 }
00062 //=======================================================================
00063 
00064 vpdfl_pdf_base* vpdfl_gaussian_builder::new_model() const
00065 {
00066   return new vpdfl_gaussian;
00067 }
00068 
00069 //=======================================================================
00070 //: Define lower threshold on variance for built models
00071 //=======================================================================
00072 void vpdfl_gaussian_builder::set_min_var(double min_var)
00073 {
00074   min_var_ = min_var;
00075 }
00076 
00077 //=======================================================================
00078 //: Get lower threshold on variance for built models
00079 //=======================================================================
00080 double vpdfl_gaussian_builder::min_var() const
00081 {
00082   return min_var_;
00083 }
00084 
00085 //=======================================================================
00086 
00087 void vpdfl_gaussian_builder::build(vpdfl_pdf_base& model,
00088                                    const vnl_vector<double>& mean) const
00089 {
00090   vpdfl_gaussian& g = gaussian(model);
00091   int n = mean.size();
00092 
00093   vnl_vector<double> var(n);
00094   for (int i=0;i<n;i++) var(i)=min_var_;
00095 
00096   // Generate an identity matrix for eigenvectors
00097   vnl_matrix<double> P(n,n);
00098   for (int i=0;i<n;++i)
00099     for (int j=0;j<n;++j) P(i,j) = 0.0;
00100 
00101   for (int i=0;i<n;++i) P(i,i) = 1.0;
00102 
00103   g.set(mean,var,P,var);
00104 }
00105 //=======================================================================
00106 
00107 void vpdfl_gaussian_builder::updateCovar(vnl_matrix<double>& S,
00108                                          const vnl_vector<double>& vec,
00109                                          double w) const
00110 {
00111   unsigned int n = vec.size();
00112   const double *v = vec.data_block();
00113   if (S.rows()!=n)
00114   {
00115     S.set_size(n,n);
00116     double **S_data = S.data_array();
00117     for (unsigned int i=0; i<n; ++i)
00118       for (unsigned int j=0; j<n; ++j)
00119         S_data[j][i] = w*v[i]*v[j];
00120   }
00121   else
00122   {
00123     double **S_data = S.data_array();
00124     double * S_row;
00125     for (unsigned int i=0; i<n; ++i)
00126     {
00127       S_row = S_data[i];
00128       double vw = w*v[i];
00129       for (unsigned int j=0; j<n; ++j)
00130         S_row[j] += vw*v[j];
00131     }
00132   }
00133 }
00134   //=======================================================================
00135 
00136     //: Build model from mean and covariance
00137 void vpdfl_gaussian_builder::buildFromCovar(vpdfl_gaussian& g,
00138                                             const vnl_vector<double>& mean,
00139                                             const vnl_matrix<double>& S) const
00140 {
00141   unsigned int n = mean.size();
00142   vnl_matrix<double> evecs(S.rows(), S.rows());
00143   vnl_vector<double> evals(S.rows());
00144 
00145 
00146   vnl_symmetric_eigensystem_compute(S, evecs, evals);
00147   // eigenvalues are lowest first here
00148   evals.flip();
00149   evecs.fliplr();
00150   // eigenvalues are highest first now
00151 
00152   // Apply threshold to variance
00153   double *ev = evals.data_block();
00154   for (unsigned int i=0;i<n;++i)
00155     if (ev[i]<min_var_) ev[i]=min_var_;
00156 
00157   g.set(mean,evecs,evals);
00158 }
00159 
00160 //=======================================================================
00161 
00162 void vpdfl_gaussian_builder::build(vpdfl_pdf_base& model,
00163                                    mbl_data_wrapper<vnl_vector<double> >& data) const
00164 {
00165   vpdfl_gaussian& g = gaussian(model);
00166 
00167   unsigned long n_samples = data.size();
00168 
00169   assert(n_samples >= 2L); // Not enough examples available
00170 
00171   vnl_vector<double> mean;
00172   vnl_matrix<double> S;
00173 
00174   meanCovar(mean,S,data);
00175   buildFromCovar(g,mean,S);
00176 }
00177 //=======================================================================
00178 
00179 //: Computes mean and covariance of given data
00180 void vpdfl_gaussian_builder::meanCovar(vnl_vector<double>& mean, vnl_matrix<double>& S,
00181                                        mbl_data_wrapper<vnl_vector<double> >& data) const
00182 {
00183   unsigned long n_samples = data.size();
00184 
00185   assert(n_samples!=0L);
00186 
00187   data.reset();
00188   int n_dims = data.current().size();
00189   vnl_vector<double> sum(n_dims);
00190   sum.fill(0);
00191 
00192   S.set_size(0,0);
00193 
00194   data.reset();
00195   for (unsigned long i=0;i<n_samples;i++)
00196   {
00197     sum += data.current();
00198     updateCovar(S,data.current(),1.0);
00199 
00200     data.next();
00201   }
00202 
00203   mean = sum / (double) n_samples;
00204   updateCovar(S, mean, - (double)n_samples);
00205   S/=(n_samples-1);
00206 }
00207 
00208 //=======================================================================
00209 
00210 void vpdfl_gaussian_builder::weighted_build(vpdfl_pdf_base& model,
00211                                             mbl_data_wrapper<vnl_vector<double> >& data,
00212                                             const vcl_vector<double>& wts) const
00213 {
00214   vpdfl_gaussian& g = gaussian(model);
00215 
00216   unsigned long n_samples = data.size();
00217 
00218   assert(n_samples>=2L); // Need enough samples
00219 
00220   data.reset();
00221   int n_dims = data.current().size();
00222   vnl_vector<double> sum(n_dims);
00223   sum.fill(0);
00224   vnl_matrix<double> S;
00225   double w_sum = 0.0;
00226   unsigned actual_samples = 0;
00227 
00228   data.reset();
00229   for (unsigned long i=0;i<n_samples;i++)
00230   {
00231     double w = wts[i];
00232     if (w >= min_wt) actual_samples ++;
00233     w_sum += w;
00234     sum += w*data.current();
00235     updateCovar(S,data.current(),w);
00236 
00237     data.next();
00238   }
00239 
00240   if (w_sum/n_samples<min_wt)  // ie near zero
00241   {
00242     vcl_cerr<<"vpdfl_gaussian_builder::weighted_build() :\n"
00243             <<"Weights too close to zero. Sum = "<<w_sum<<vcl_endl;
00244     vcl_abort();
00245   }
00246 
00247   if (actual_samples==0)
00248   {
00249     vcl_cerr<<"vpdfl_gaussian_builder::weighted_build() :\nAll weights zero.\n";
00250     vcl_abort();
00251   }
00252 
00253   if (actual_samples==1)
00254   {
00255 #if 0
00256     vcl_cerr<<"vpdfl_gaussian_builder::weighted_build() :\n"
00257             <<" Warning: Only one sample has non-zero weight.\n";
00258 #endif
00259     // Build minimal model about the mean (the one non-zero sample)
00260     sum/=w_sum;
00261     build(g,sum);
00262     return;
00263   }
00264 
00265   S*=actual_samples/((actual_samples - 1) *w_sum);
00266   sum/=w_sum;
00267   updateCovar(S, sum, -1.0);  // Remove mean.mean'
00268   // now sum = weighted mean
00269   // and S = weighted covariance corrected for unbiased rather than ML result.
00270 
00271   buildFromCovar(g,sum,S);
00272 }
00273 //=======================================================================
00274 // Method: is_a
00275 //=======================================================================
00276 
00277 vcl_string vpdfl_gaussian_builder::is_a() const
00278 {
00279   static vcl_string class_name_ = "vpdfl_gaussian_builder";
00280   return class_name_;
00281 }
00282 
00283 //=======================================================================
00284 // Method: is_class
00285 //=======================================================================
00286 
00287 bool vpdfl_gaussian_builder::is_class(vcl_string const& s) const
00288 {
00289   return vpdfl_builder_base::is_class(s) || s==vpdfl_gaussian_builder::is_a();
00290 }
00291 
00292 //=======================================================================
00293 // Method: version_no
00294 //=======================================================================
00295 
00296 short vpdfl_gaussian_builder::version_no() const
00297 {
00298   return 1;
00299 }
00300 
00301 //=======================================================================
00302 // Method: clone
00303 //=======================================================================
00304 
00305 vpdfl_builder_base* vpdfl_gaussian_builder::clone() const
00306 {
00307   return new vpdfl_gaussian_builder(*this);
00308 }
00309 
00310 //=======================================================================
00311 // Method: print
00312 //=======================================================================
00313 
00314 void vpdfl_gaussian_builder::print_summary(vcl_ostream& os) const
00315 {
00316   os << "Min. var. : "<< min_var_;
00317 }
00318 
00319 //=======================================================================
00320 // Method: save
00321 //=======================================================================
00322 
00323 void vpdfl_gaussian_builder::b_write(vsl_b_ostream& bfs) const
00324 {
00325   vsl_b_write(bfs,is_a());
00326   vsl_b_write(bfs,version_no());
00327   vsl_b_write(bfs,min_var_);
00328 }
00329 
00330 //=======================================================================
00331 // Method: load
00332 //=======================================================================
00333 
00334 void vpdfl_gaussian_builder::b_read(vsl_b_istream& bfs)
00335 {
00336   if (!bfs) return;
00337 
00338   vcl_string name;
00339   vsl_b_read(bfs,name);
00340   if (name != is_a())
00341   {
00342     vcl_cerr << "I/O ERROR: vsl_b_read(vsl_b_istream&, vpdfl_gaussian_builder &)\n"
00343              << "           Attempted to load object of type "
00344              << name <<" into object of type " << is_a() << vcl_endl;
00345     bfs.is().clear(vcl_ios::badbit); // Set an unrecoverable IO error on stream
00346     return;
00347   }
00348 
00349   short version;
00350   vsl_b_read(bfs,version);
00351   switch (version)
00352   {
00353     case (1):
00354       vsl_b_read(bfs,min_var_);
00355       break;
00356     default:
00357       vcl_cerr << "I/O ERROR: vsl_b_read(vsl_b_istream&, vpdfl_gaussian_builder &)\n"
00358                << "           Unknown version number "<< version << vcl_endl;
00359       bfs.is().clear(vcl_ios::badbit); // Set an unrecoverable IO error on stream
00360       return;
00361   }
00362 }
00363 
00364 //: Read initialisation settings from a stream.
00365 // Parameters:
00366 // \verbatim
00367 // {
00368 //   min_var: 1.0e-6
00369 // }
00370 // \endverbatim
00371 // \throw mbl_exception_parse_error if the parse fails.
00372 void vpdfl_gaussian_builder::config_from_stream(vcl_istream & is)
00373 {
00374   vcl_string s = mbl_parse_block(is);
00375 
00376   vcl_istringstream ss(s);
00377   mbl_read_props_type props = mbl_read_props_ws(ss);
00378 
00379   double mv=1.0e-6;
00380 
00381   if (!props["min_var"].empty())
00382   {
00383     mv=vul_string_atof(props["min_var"]);
00384   }
00385   set_min_var(mv);
00386   props.erase("min_var");
00387   try
00388   {
00389     mbl_read_props_look_for_unused_props(
00390         "vpdfl_gaussian_builder::config_from_stream", props);
00391   }
00392   catch(mbl_exception_unused_props &e)
00393   {
00394     throw mbl_exception_parse_error(e.what());
00395   }
00396 
00397 }
00398 
00399 
00400 //==================< end of vpdfl_gaussian_builder.cxx >====================

Generated on Thu Jan 10 14:43:32 2008 for contrib/mul/vpdfl by  doxygen 1.4.4