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 #include <mbl/mbl_parse_block.h>
00033 #include <mbl/mbl_read_props.h>
00034 #include <mbl/mbl_exception.h>
00035 #include <vul/vul_string.h>
00036
00037
00038
00039 vpdfl_pc_gaussian_builder::vpdfl_pc_gaussian_builder() :
00040 partitionMethod_(vpdfl_pc_gaussian_builder::fixed),
00041 proportionOfVariance_(0),
00042 fixed_partition_(1)
00043 {
00044 }
00045
00046
00047
00048 vpdfl_pc_gaussian_builder::~vpdfl_pc_gaussian_builder()
00049 {
00050 }
00051
00052
00053
00054
00055
00056
00057 void vpdfl_pc_gaussian_builder::set_proportion_partition( double proportion)
00058 {
00059 assert(proportion >= 0.0);
00060 assert(proportion <= 1.0);
00061
00062 proportionOfVariance_ = proportion;
00063 partitionMethod_ = proportionate;
00064 }
00065
00066
00067
00068
00069 void vpdfl_pc_gaussian_builder::set_fixed_partition(int n_principle_components)
00070 {
00071 assert(n_principle_components >=0);
00072 fixed_partition_ = n_principle_components;
00073 partitionMethod_ = vpdfl_pc_gaussian_builder::fixed;
00074 }
00075
00076
00077
00078 vpdfl_pc_gaussian& vpdfl_pc_gaussian_builder::gaussian(vpdfl_pdf_base& model) const
00079 {
00080
00081 assert(model.is_class("vpdfl_pc_gaussian"));
00082 return static_cast<vpdfl_pc_gaussian&>( model);
00083 }
00084
00085
00086
00087 vpdfl_pdf_base* vpdfl_pc_gaussian_builder::new_model() const
00088 {
00089 return new vpdfl_pc_gaussian();
00090 }
00091
00092
00093
00094 void vpdfl_pc_gaussian_builder::build(vpdfl_pdf_base& model,
00095 const vnl_vector<double>& mean) const
00096 {
00097 vpdfl_pc_gaussian& g = gaussian(model);
00098 int n = mean.size();
00099
00100
00101 vnl_matrix<double> P(n,n);
00102 P.fill(0);
00103 P.fill_diagonal(1.0);
00104
00105 g.set(mean,P,vnl_vector<double>(0), min_var());
00106 }
00107
00108 #if 0 // this doesn't work
00109
00110 void vpdfl_pc_gaussian_builder::buildFromCovar(vpdfl_pc_gaussian& g,
00111 const vnl_vector<double>& mean,
00112 const vnl_matrix<double>& S,
00113 unsigned nPrinComps) const
00114 {
00115 int n = mean.size();
00116 vnl_matrix<double> evecs;
00117 vnl_vector<double> evals;
00118
00119 NR_CalcSymEigens(S,evecs,evals,0);
00120 vnl_vector<double> principleEVals(nPrinComps);
00121
00122
00123 for (int i=1;i<=nPrinComps;++i)
00124 if (evals(i)<min_var())
00125 principleEVals(i)=min_var();
00126 else
00127 principleEVals(i)=evals(i);
00128
00129 double sum = 0.0;
00130 for (int i=nPrinComps+1; i <= n; i++)
00131 sum += evals(i);
00132
00133
00134 double complementaryEVals = sum / (n - nPrinComps);
00135
00136 if (complementaryEVals < min_var()) complementaryEVals = min_var();
00137
00138 g.set(mean, evecs, principleEVals, complementaryEVals);
00139 }
00140 #endif
00141
00142
00143
00144
00145
00146 static void eValsFloorZero(vnl_vector<double> &v)
00147 {
00148 int n = v.size();
00149 double *v_data = v.data_block();
00150 int i=n-1;
00151 while (i && v_data[i] < 0.0)
00152 {
00153 v_data[i]=0.0;
00154 i--;
00155 }
00156 }
00157
00158
00159 void vpdfl_pc_gaussian_builder::build(vpdfl_pdf_base& model,
00160 mbl_data_wrapper<vnl_vector<double> >& data) const
00161 {
00162 vpdfl_pc_gaussian& g = gaussian(model);
00163
00164 unsigned long n_samples = data.size();
00165 assert (n_samples>=2L);
00166
00167 int n = data.current().size();
00168
00169 vnl_vector<double> mean;
00170
00171
00172 vnl_matrix<double> evecs(n,n);
00173 vnl_vector<double> evals(n);
00174 vnl_matrix<double> S;
00175
00176 meanCovar(mean,S,data);
00177
00178 vnl_symmetric_eigensystem_compute(S, evecs, evals);
00179
00180 evals.flip();
00181 evecs.fliplr();
00182
00183
00184 int n_principle_components = decide_partition(evals, n_samples, 0);
00185
00186 vnl_vector<double> principleEVals(n_principle_components);
00187
00188
00189 for (int i=0;i<n_principle_components;++i)
00190 if (evals(i)<min_var())
00191 principleEVals(i)=min_var();
00192 else
00193 principleEVals(i)=evals(i);
00194
00195 double eVsum = 0.0;
00196 for (int i=n_principle_components; i < n; i++)
00197 eVsum += evals(i);
00198
00199
00200 double complementaryEVals = eVsum / (n - n_principle_components);
00201
00202 if (complementaryEVals < min_var()) complementaryEVals = min_var();
00203
00204 g.set(mean, evecs, principleEVals, complementaryEVals);
00205 }
00206
00207
00208 void vpdfl_pc_gaussian_builder::mean_covar(vnl_vector<double>& mean, vnl_matrix<double>& S,
00209 mbl_data_wrapper<vnl_vector<double> >& data) const
00210 {
00211 unsigned long n_samples = data.size();
00212
00213 assert (n_samples!=0L);
00214
00215 int n_dims = data.current().size();
00216 vnl_vector<double> sum(n_dims);
00217 sum.fill(0);
00218
00219 S.set_size(0,0);
00220
00221 data.reset();
00222 for (unsigned long i=0;i<n_samples;i++)
00223 {
00224 sum += data.current();
00225 updateCovar(S,data.current(),1.0);
00226
00227 data.next();
00228 }
00229
00230 mean = sum;
00231 mean/=n_samples;
00232 S/=n_samples;
00233 updateCovar(S,mean,-1.0);
00234 }
00235
00236
00237 void vpdfl_pc_gaussian_builder::weighted_build(vpdfl_pdf_base& model,
00238 mbl_data_wrapper<vnl_vector<double> >& data,
00239 const vcl_vector<double>& wts) const
00240 {
00241 vpdfl_pc_gaussian& g = gaussian(model);
00242
00243 unsigned long n_samples = data.size();
00244
00245 if (n_samples<2L)
00246 {
00247 vcl_cerr<<"vpdfl_gaussian_builder::weighted_build() Too few examples available.\n";
00248 vcl_abort();
00249 }
00250
00251 data.reset();
00252 const int n = data.current().size();
00253 vnl_vector<double> sum(n);
00254 sum.fill(0.0);
00255 vnl_matrix<double> evecs(n,n);
00256 vnl_vector<double> evals(n);
00257 vnl_matrix<double> S;
00258 double w_sum = 0.0;
00259 double w;
00260 unsigned actual_samples = 0;
00261
00262 for (unsigned long i=0;i<n_samples;i++)
00263 {
00264 w = wts[i];
00265 if (w != 0.0)
00266 {
00267 actual_samples ++;
00268 w_sum += w;
00269 data.current().assert_finite();
00270 sum += w*data.current();
00271 updateCovar(S,data.current(),w);
00272 }
00273 data.next();
00274 }
00275
00276 updateCovar(S,sum,-1.0/w_sum);
00277 S*=actual_samples/((actual_samples - 1) *w_sum);
00278 sum/=w_sum;
00279
00280
00281
00282
00283 vnl_symmetric_eigensystem_compute(S, evecs, evals);
00284
00285 evals.flip();
00286 evecs.fliplr();
00287
00288
00289 #if 0
00290 vcl_cerr << 'S' << S <<vcl_endl
00291 << "evals" << evals <<vcl_endl
00292 << "evecs" << evecs <<vcl_endl;
00293 #endif
00294
00295 eValsFloorZero(evals);
00296
00297 int n_principle_components = decide_partition(evals, n);
00298
00299 vnl_vector<double> principleEVals(n_principle_components);
00300
00301
00302 for (int i=0;i<n_principle_components;++i)
00303 if (evals(i)<min_var())
00304 principleEVals(i)=min_var();
00305 else
00306 principleEVals(i)=evals(i);
00307 double eVsum = 0.0;
00308 for (int i=n_principle_components; i < n; i++)
00309 eVsum += evals(i);
00310
00311
00312 double complementaryEVals;
00313 if (n_principle_components != n)
00314 complementaryEVals = eVsum / (n - n_principle_components);
00315 else
00316 complementaryEVals = 0.0;
00317
00318 if (complementaryEVals < min_var()) complementaryEVals = min_var();
00319
00320 g.set(sum, evecs, principleEVals, complementaryEVals);
00321 }
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331 unsigned vpdfl_pc_gaussian_builder::decide_partition(const vnl_vector<double>& eVals, unsigned ,
00332 double ) const
00333 {
00334 assert (eVals.size() > 0);
00335 if (partitionMethod_ == vpdfl_pc_gaussian_builder::fixed)
00336 {
00337 return vnl_math_min(eVals.size(), (unsigned)fixed_partition()+1);;
00338 }
00339 else if (partitionMethod_ == proportionate)
00340 {
00341 double sum = vnl_c_vector<double>::sum(eVals.data_block(), eVals.size());
00342 assert (proportionOfVariance_ < 1.0 && proportionOfVariance_ > 0.0);
00343 double stopWhen = sum * proportionOfVariance_;
00344 sum = eVals(0);
00345 unsigned i=0;
00346 while (sum <= stopWhen)
00347 {
00348 i++;
00349 sum += eVals(i);
00350 }
00351 return i;
00352 }
00353 else
00354 {
00355 vcl_cerr << "vpdfl_pc_gaussian_builder::decide_partition(): Unexpected partition method: "
00356 << (short)partitionMethod_ <<vcl_endl;
00357 vcl_abort();
00358 return 0;
00359 }
00360 }
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373 void vpdfl_pc_gaussian_builder::config_from_stream(vcl_istream & is)
00374 {
00375 vcl_string s = mbl_parse_block(is);
00376
00377 vcl_istringstream ss(s);
00378 mbl_read_props_type props = mbl_read_props_ws(ss);
00379
00380 if (props.find("mode_choice")!=props.end())
00381 {
00382 if (props["mode_choice"]=="fixed")
00383 partitionMethod_=fixed;
00384 else
00385 if (props["mode_choice"]=="proportionate")
00386 partitionMethod_=proportionate;
00387 else
00388 {
00389 vcl_string err_msg = "Unknown mode_choice: "+props["mode_choice"];
00390 throw mbl_exception_parse_error(err_msg);
00391 }
00392
00393 props.erase("mode_choice");
00394 }
00395
00396 if (props.find("var_prop")!=props.end())
00397 {
00398 proportionOfVariance_=vul_string_atof(props["var_prop"]);
00399 props.erase("var_prop");
00400 }
00401
00402 if (props.find("n_modes")!=props.end())
00403 {
00404 fixed_partition_=vul_string_atoi(props["n_modes"]);
00405 props.erase("n_modes");
00406 }
00407
00408 double mv=1.0e-6;
00409 if (props.find("min_var")!=props.end())
00410 {
00411 mv=vul_string_atof(props["min_var"]);
00412 props.erase("min_var");
00413 }
00414 set_min_var(mv);
00415
00416 try
00417 {
00418 mbl_read_props_look_for_unused_props(
00419 "vpdfl_axis_gaussian_builder::config_from_stream", props);
00420 }
00421 catch(mbl_exception_unused_props &e)
00422 {
00423 throw mbl_exception_parse_error(e.what());
00424 }
00425
00426 }
00427
00428
00429
00430
00431 vcl_string vpdfl_pc_gaussian_builder::is_a() const
00432 {
00433 static vcl_string class_name_ = "vpdfl_pc_gaussian_builder";
00434 return class_name_;
00435 }
00436
00437
00438
00439
00440
00441 bool vpdfl_pc_gaussian_builder::is_class(vcl_string const& s) const
00442 {
00443 return vpdfl_gaussian_builder::is_class(s) || s==vpdfl_pc_gaussian_builder::is_a();
00444 }
00445
00446
00447
00448
00449
00450 short vpdfl_pc_gaussian_builder::version_no() const
00451 {
00452 return 2;
00453 }
00454
00455
00456
00457
00458
00459 vpdfl_builder_base* vpdfl_pc_gaussian_builder::clone() const
00460 {
00461 return new vpdfl_pc_gaussian_builder(*this);
00462 }
00463
00464
00465
00466
00467
00468 void vpdfl_pc_gaussian_builder::print_summary(vcl_ostream& os) const
00469 {
00470 vpdfl_gaussian_builder::print_summary(os);
00471 if (partitionMethod_==fixed) os<<" mode_choice: fixed ";
00472 if (partitionMethod_==proportionate)
00473 os<<" mode_choice: proportionate ";
00474 os<<" var_prop: "<<proportionOfVariance_;
00475 os<<" n_fixed: "<<fixed_partition_<<' ';
00476 }
00477
00478
00479
00480
00481
00482 void vpdfl_pc_gaussian_builder::b_write(vsl_b_ostream& bfs) const
00483 {
00484 vsl_b_write(bfs, is_a());
00485 vsl_b_write(bfs, version_no());
00486 vpdfl_gaussian_builder::b_write(bfs);
00487 vsl_b_write(bfs,(short)partitionMethod_);
00488 vsl_b_write(bfs, proportionOfVariance_);
00489 vsl_b_write(bfs, fixed_partition_);
00490 }
00491
00492
00493
00494
00495
00496 void vpdfl_pc_gaussian_builder::b_read(vsl_b_istream& bfs)
00497 {
00498 if (!bfs) return;
00499
00500 vcl_string name;
00501 vsl_b_read(bfs,name);
00502 if (name != is_a())
00503 {
00504 vcl_cerr << "I/O ERROR: vsl_b_read(vsl_b_istream&, vpdfl_pc_gaussian_builder &)\n"
00505 << " Attempted to load object of type "
00506 << name <<" into object of type " << is_a() << vcl_endl;
00507 bfs.is().clear(vcl_ios::badbit);
00508 return;
00509 }
00510
00511 short temp;
00512 short version;
00513 vsl_b_read(bfs,version);
00514 switch (version)
00515 {
00516 case 1:
00517 vpdfl_gaussian_builder::b_read(bfs);
00518 vsl_b_read(bfs, temp);
00519 partitionMethod_ = partitionMethods(temp);
00520 vsl_b_read(bfs, proportionOfVariance_);
00521 fixed_partition_ = 75;
00522 break;
00523 case 2:
00524 vpdfl_gaussian_builder::b_read(bfs);
00525 vsl_b_read(bfs, temp);
00526 partitionMethod_ = partitionMethods(temp);
00527 vsl_b_read(bfs, proportionOfVariance_);
00528 vsl_b_read(bfs, fixed_partition_);
00529 break;
00530 default:
00531 vcl_cerr << "I/O ERROR: vsl_b_read(vsl_b_istream&, vpdfl_pc_gaussian_builder &)\n"
00532 << " Unknown version number "<< version << vcl_endl;
00533 bfs.is().clear(vcl_ios::badbit);
00534 return;
00535 }
00536 }