00001
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "vpdfl_pc_gaussian_builder.h"
00021
00022 #include <vcl_string.h>
00023 #include <vcl_cassert.h>
00024 #include <vcl_cstdlib.h>
00025 #include <mbl/mbl_data_wrapper.h>
00026 #include <vnl/vnl_math.h>
00027 #include <vnl/vnl_c_vector.h>
00028 #include <vnl/algo/vnl_symmetric_eigensystem.h>
00029 #include <vpdfl/vpdfl_gaussian_builder.h>
00030 #include <vpdfl/vpdfl_pdf_base.h>
00031 #include <vpdfl/vpdfl_pc_gaussian.h>
00032
00033
00034
00035 vpdfl_pc_gaussian_builder::vpdfl_pc_gaussian_builder() :
00036 partitionMethod_(vpdfl_pc_gaussian_builder::fixed),
00037 proportionOfVariance_(0),
00038 fixed_partition_(1)
00039 {
00040 }
00041
00042
00043
00044 vpdfl_pc_gaussian_builder::~vpdfl_pc_gaussian_builder()
00045 {
00046 }
00047
00048
00049
00050
00051
00052
00053 void vpdfl_pc_gaussian_builder::set_proportion_partition( double proportion)
00054 {
00055 assert(proportion >= 0.0);
00056 assert(proportion <= 1.0);
00057
00058 proportionOfVariance_ = proportion;
00059 partitionMethod_ = proportionate;
00060 }
00061
00062
00063
00064
00065 void vpdfl_pc_gaussian_builder::set_fixed_partition(int n_principle_components)
00066 {
00067 assert(n_principle_components >=0);
00068 fixed_partition_ = n_principle_components;
00069 partitionMethod_ = vpdfl_pc_gaussian_builder::fixed;
00070 }
00071
00072
00073
00074 vpdfl_pc_gaussian& vpdfl_pc_gaussian_builder::gaussian(vpdfl_pdf_base& model) const
00075 {
00076
00077 assert(model.is_class("vpdfl_pc_gaussian"));
00078 return static_cast<vpdfl_pc_gaussian&>( model);
00079 }
00080
00081
00082
00083 vpdfl_pdf_base* vpdfl_pc_gaussian_builder::new_model() const
00084 {
00085 return new vpdfl_pc_gaussian();
00086 }
00087
00088
00089
00090 void vpdfl_pc_gaussian_builder::build(vpdfl_pdf_base& model,
00091 const vnl_vector<double>& mean) const
00092 {
00093 vpdfl_pc_gaussian& g = gaussian(model);
00094 int n = mean.size();
00095
00096
00097 vnl_matrix<double> P(n,n);
00098 P.fill(0);
00099 P.fill_diagonal(1.0);
00100
00101 g.set(mean,P,vnl_vector<double>(0), min_var());
00102 }
00103
00104 #if 0 // this doesn't work
00105
00106 void vpdfl_pc_gaussian_builder::buildFromCovar(vpdfl_pc_gaussian& g,
00107 const vnl_vector<double>& mean,
00108 const vnl_matrix<double>& S,
00109 unsigned nPrinComps) const
00110 {
00111 int n = mean.size();
00112 vnl_matrix<double> evecs;
00113 vnl_vector<double> evals;
00114
00115 NR_CalcSymEigens(S,evecs,evals,0);
00116 vnl_vector<double> principleEVals(nPrinComps);
00117
00118
00119 for (int i=1;i<=nPrinComps;++i)
00120 if (evals(i)<min_var())
00121 principleEVals(i)=min_var();
00122 else
00123 principleEVals(i)=evals(i);
00124
00125 double sum = 0.0;
00126 for (int i=nPrinComps+1; i <= n; i++)
00127 sum += evals(i);
00128
00129
00130 double complementaryEVals = sum / (n - nPrinComps);
00131
00132 if (complementaryEVals < min_var()) complementaryEVals = min_var();
00133
00134 g.set(mean, evecs, principleEVals, complementaryEVals);
00135 }
00136 #endif
00137
00138
00139
00140
00141
00142 static void eValsFloorZero(vnl_vector<double> &v)
00143 {
00144 int n = v.size();
00145 double *v_data = v.data_block();
00146 int i=n-1;
00147 while (i && v_data[i] < 0.0)
00148 {
00149 v_data[i]=0.0;
00150 i--;
00151 }
00152 }
00153
00154
00155 void vpdfl_pc_gaussian_builder::build(vpdfl_pdf_base& model,
00156 mbl_data_wrapper<vnl_vector<double> >& data) const
00157 {
00158 vpdfl_pc_gaussian& g = gaussian(model);
00159
00160 unsigned long n_samples = data.size();
00161 assert (n_samples>=2L);
00162
00163 int n = data.current().size();
00164
00165 vnl_vector<double> mean;
00166
00167
00168 vnl_matrix<double> evecs(n,n);
00169 vnl_vector<double> evals(n);
00170 vnl_matrix<double> S;
00171
00172 meanCovar(mean,S,data);
00173
00174 vnl_symmetric_eigensystem_compute(S, evecs, evals);
00175
00176 evals.flip();
00177 evecs.fliplr();
00178
00179
00180 int n_principle_components = decide_partition(evals, n_samples, 0);
00181
00182 vnl_vector<double> principleEVals(n_principle_components);
00183
00184
00185 for (int i=0;i<n_principle_components;++i)
00186 if (evals(i)<min_var())
00187 principleEVals(i)=min_var();
00188 else
00189 principleEVals(i)=evals(i);
00190
00191 double eVsum = 0.0;
00192 for (int i=n_principle_components; i < n; i++)
00193 eVsum += evals(i);
00194
00195
00196 double complementaryEVals = eVsum / (n - n_principle_components);
00197
00198 if (complementaryEVals < min_var()) complementaryEVals = min_var();
00199
00200 g.set(mean, evecs, principleEVals, complementaryEVals);
00201 }
00202
00203
00204 void vpdfl_pc_gaussian_builder::mean_covar(vnl_vector<double>& mean, vnl_matrix<double>& S,
00205 mbl_data_wrapper<vnl_vector<double> >& data) const
00206 {
00207 unsigned long n_samples = data.size();
00208
00209 assert (n_samples!=0L);
00210
00211 int n_dims = data.current().size();
00212 vnl_vector<double> sum(n_dims);
00213 sum.fill(0);
00214
00215 S.set_size(0,0);
00216
00217 data.reset();
00218 for (unsigned long i=0;i<n_samples;i++)
00219 {
00220 sum += data.current();
00221 updateCovar(S,data.current(),1.0);
00222
00223 data.next();
00224 }
00225
00226 mean = sum;
00227 mean/=n_samples;
00228 S/=n_samples;
00229 updateCovar(S,mean,-1.0);
00230 }
00231
00232
00233 void vpdfl_pc_gaussian_builder::weighted_build(vpdfl_pdf_base& model,
00234 mbl_data_wrapper<vnl_vector<double> >& data,
00235 const vcl_vector<double>& wts) const
00236 {
00237 vpdfl_pc_gaussian& g = gaussian(model);
00238
00239 unsigned long n_samples = data.size();
00240
00241 if (n_samples<2L)
00242 {
00243 vcl_cerr<<"vpdfl_gaussian_builder::weighted_build() Too few examples available.\n";
00244 vcl_abort();
00245 }
00246
00247 data.reset();
00248 const int n = data.current().size();
00249 vnl_vector<double> sum(n);
00250 sum.fill(0.0);
00251 vnl_matrix<double> evecs(n,n);
00252 vnl_vector<double> evals(n);
00253 vnl_matrix<double> S;
00254 double w_sum = 0.0;
00255 double w;
00256 unsigned actual_samples = 0;
00257
00258 for (unsigned long i=0;i<n_samples;i++)
00259 {
00260 w = wts[i];
00261 if (w != 0.0)
00262 {
00263 actual_samples ++;
00264 w_sum += w;
00265 data.current().assert_finite();
00266 sum += w*data.current();
00267 updateCovar(S,data.current(),w);
00268 }
00269 data.next();
00270 }
00271
00272 updateCovar(S,sum,-1.0/w_sum);
00273 S*=actual_samples/((actual_samples - 1) *w_sum);
00274 sum/=w_sum;
00275
00276
00277
00278
00279 vnl_symmetric_eigensystem_compute(S, evecs, evals);
00280
00281 evals.flip();
00282 evecs.fliplr();
00283
00284
00285 #if 0
00286 vcl_cerr << 'S' << S <<vcl_endl
00287 << "evals" << evals <<vcl_endl
00288 << "evecs" << evecs <<vcl_endl;
00289 #endif
00290
00291 eValsFloorZero(evals);
00292
00293 int n_principle_components = decide_partition(evals, n);
00294
00295 vnl_vector<double> principleEVals(n_principle_components);
00296
00297
00298 for (int i=0;i<n_principle_components;++i)
00299 if (evals(i)<min_var())
00300 principleEVals(i)=min_var();
00301 else
00302 principleEVals(i)=evals(i);
00303 double eVsum = 0.0;
00304 for (int i=n_principle_components; i < n; i++)
00305 eVsum += evals(i);
00306
00307
00308 double complementaryEVals;
00309 if (n_principle_components != n)
00310 complementaryEVals = eVsum / (n - n_principle_components);
00311 else
00312 complementaryEVals = 0.0;
00313
00314 if (complementaryEVals < min_var()) complementaryEVals = min_var();
00315
00316 g.set(sum, evecs, principleEVals, complementaryEVals);
00317 }
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327 unsigned vpdfl_pc_gaussian_builder::decide_partition(const vnl_vector<double>& eVals, unsigned ,
00328 double ) const
00329 {
00330 assert (eVals.size() > 0);
00331 if (partitionMethod_ == vpdfl_pc_gaussian_builder::fixed)
00332 {
00333 return vnl_math_min(eVals.size(), (unsigned)fixed_partition()+1);;
00334 }
00335 else if (partitionMethod_ == proportionate)
00336 {
00337 double sum = vnl_c_vector<double>::sum(eVals.data_block(), eVals.size());
00338 assert (proportionOfVariance_ < 1.0 && proportionOfVariance_ > 0.0);
00339 double stopWhen = sum * proportionOfVariance_;
00340 sum = eVals(0);
00341 unsigned i=0;
00342 while (sum <= stopWhen)
00343 {
00344 i++;
00345 sum += eVals(i);
00346 }
00347 return i;
00348 }
00349 else
00350 {
00351 vcl_cerr << "vpdfl_pc_gaussian_builder::decide_partition(): Unexpected partition method: "
00352 << (short)partitionMethod_ <<vcl_endl;
00353 vcl_abort();
00354 return 0;
00355 }
00356 }
00357
00358
00359
00360 vcl_string vpdfl_pc_gaussian_builder::is_a() const
00361 {
00362 static vcl_string class_name_ = "vpdfl_pc_gaussian_builder";
00363 return class_name_;
00364 }
00365
00366
00367
00368
00369
00370 bool vpdfl_pc_gaussian_builder::is_class(vcl_string const& s) const
00371 {
00372 return vpdfl_gaussian_builder::is_class(s) || s==vpdfl_pc_gaussian_builder::is_a();
00373 }
00374
00375
00376
00377
00378
00379 short vpdfl_pc_gaussian_builder::version_no() const
00380 {
00381 return 2;
00382 }
00383
00384
00385
00386
00387
00388 vpdfl_builder_base* vpdfl_pc_gaussian_builder::clone() const
00389 {
00390 return new vpdfl_pc_gaussian_builder(*this);
00391 }
00392
00393
00394
00395
00396
00397 void vpdfl_pc_gaussian_builder::print_summary(vcl_ostream& os) const
00398 {
00399 vpdfl_gaussian_builder::print_summary(os);
00400 }
00401
00402
00403
00404
00405
00406 void vpdfl_pc_gaussian_builder::b_write(vsl_b_ostream& bfs) const
00407 {
00408 vsl_b_write(bfs, is_a());
00409 vsl_b_write(bfs, version_no());
00410 vpdfl_gaussian_builder::b_write(bfs);
00411 vsl_b_write(bfs,(short)partitionMethod_);
00412 vsl_b_write(bfs, proportionOfVariance_);
00413 vsl_b_write(bfs, fixed_partition_);
00414 }
00415
00416
00417
00418
00419
00420 void vpdfl_pc_gaussian_builder::b_read(vsl_b_istream& bfs)
00421 {
00422 if (!bfs) return;
00423
00424 vcl_string name;
00425 vsl_b_read(bfs,name);
00426 if (name != is_a())
00427 {
00428 vcl_cerr << "I/O ERROR: vsl_b_read(vsl_b_istream&, vpdfl_pc_gaussian_builder &)\n"
00429 << " Attempted to load object of type "
00430 << name <<" into object of type " << is_a() << vcl_endl;
00431 bfs.is().clear(vcl_ios::badbit);
00432 return;
00433 }
00434
00435 short temp;
00436 short version;
00437 vsl_b_read(bfs,version);
00438 switch (version)
00439 {
00440 case 1:
00441 vpdfl_gaussian_builder::b_read(bfs);
00442 vsl_b_read(bfs, temp);
00443 partitionMethod_ = partitionMethods(temp);
00444 vsl_b_read(bfs, proportionOfVariance_);
00445 fixed_partition_ = 75;
00446 break;
00447 case 2:
00448 vpdfl_gaussian_builder::b_read(bfs);
00449 vsl_b_read(bfs, temp);
00450 partitionMethod_ = partitionMethods(temp);
00451 vsl_b_read(bfs, proportionOfVariance_);
00452 vsl_b_read(bfs, fixed_partition_);
00453 break;
00454 default:
00455 vcl_cerr << "I/O ERROR: vsl_b_read(vsl_b_istream&, vpdfl_pc_gaussian_builder &)\n"
00456 << " Unknown version number "<< version << vcl_endl;
00457 bfs.is().clear(vcl_ios::badbit);
00458 return;
00459 }
00460 }