00001
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "vpdfl_gaussian.h"
00017
00018 #include <vcl_cassert.h>
00019 #include <vcl_cstdlib.h>
00020 #include <vcl_string.h>
00021 #include <vcl_cmath.h>
00022
00023 #include <vsl/vsl_indent.h>
00024 #include <vnl/vnl_math.h>
00025 #include <mbl/mbl_matxvec.h>
00026 #include <mbl/mbl_matrix_products.h>
00027 #include <vnl/algo/vnl_symmetric_eigensystem.h>
00028 #include <vnl/io/vnl_io_matrix.h>
00029 #include <vpdfl/vpdfl_gaussian_sampler.h>
00030 #include <vpdfl/vpdfl_sampler_base.h>
00031 #include <vpdfl/vpdfl_prob_chi2.h>
00032
00033
00034 static inline bool almostEqualsOne(double value);
00035 static bool columnsAreUnitNorm(const vnl_matrix<double>& vecs);
00036 #if 0
00037 static bool vectorHasDescendingOrder(const vnl_vector<double>& v);
00038 #endif
00039
00040
00041
00042 vpdfl_gaussian::vpdfl_gaussian()
00043 {
00044 }
00045
00046
00047
00048 vpdfl_gaussian::~vpdfl_gaussian()
00049 {
00050 }
00051
00052
00053
00054 void vpdfl_gaussian::calcLogK()
00055 {
00056 const double *v_data = evals_.data_block();
00057 int n = n_dims();
00058 double log_v_sum = 0.0;
00059 for (int i=0;i<n;i++) log_v_sum+=vcl_log(v_data[i]);
00060
00061 log_k_ = -0.5 * (n*vcl_log(2 * vnl_math::pi) + log_v_sum);
00062 }
00063
00064
00065
00066
00067
00068 void vpdfl_gaussian::set(const vnl_vector<double>& mean,
00069 const vnl_matrix<double>& evecs,
00070 const vnl_vector<double>& evals)
00071 {
00072 const unsigned int m = evecs.rows();
00073 const unsigned int n = evecs.cols();
00074 assert(evals.size() == m);
00075 assert(mean.size() == m);
00076
00077
00078 assert(columnsAreUnitNorm(evecs));
00079
00080
00081
00082
00083
00084
00085
00086 vnl_vector<double> v(m);
00087 for (unsigned int i=0; i<m; i++)
00088 {
00089 double &vi = v(i);
00090 vi = 0.0;
00091 for (unsigned int j=0; j<n; j++)
00092 vi += vnl_math_sqr(evecs(i,j)) * evals(i);
00093 }
00094
00095 set(mean, v, evecs, evals);
00096 }
00097
00098
00099
00100 void vpdfl_gaussian::set(const vnl_vector<double>& m,
00101 const vnl_vector<double>& v,
00102 const vnl_matrix<double>& evecs,
00103 const vnl_vector<double>& evals)
00104 {
00105 set_mean(m);
00106 set_variance(v);
00107
00108 evecs_ = evecs;
00109 evals_ = evals;
00110
00111 calcLogK();
00112 }
00113
00114
00115
00116 void vpdfl_gaussian::set_mean(const vnl_vector<double>& mean)
00117 {
00118 vpdfl_pdf_base::set_mean(mean);
00119 }
00120
00121
00122
00123
00124
00125
00126 void vpdfl_gaussian::set(const vnl_vector<double>& mean,
00127 const vnl_matrix<double>& covar,
00128 double min_eval)
00129 {
00130 unsigned int n = mean.size();
00131 assert(covar.rows()==n && covar.cols()==n);
00132
00133 vnl_matrix<double> evecs;
00134 vnl_vector<double> evals;
00135
00136 vnl_symmetric_eigensystem_compute(covar, evecs, evals);
00137
00138 evals.flip();
00139 evecs.fliplr();
00140
00141
00142
00143 for (unsigned int i=0;i<n;++i)
00144 if (evals(i)<min_eval) evals(i)=min_eval;
00145
00146 set(mean, evecs, evals);
00147 }
00148
00149
00150
00151 static bool almostEqualsOne(double value)
00152 {
00153 const double upper = 1 + 1e-06;
00154 const double lower = 1 - 1e-06;
00155 return value > lower && value < upper;
00156 }
00157
00158
00159
00160 static bool columnsAreUnitNorm(const vnl_matrix<double>& vecs)
00161 {
00162 const int m = vecs.rows();
00163 const int n = vecs.cols();
00164 for (int j=0; j<n; j++)
00165 {
00166 double sumsq = 0.0;
00167 for (int i=0; i<m; i++)
00168 sumsq += vnl_math_sqr(vecs(i,j));
00169 if (!almostEqualsOne(sumsq)) return false;
00170 }
00171 return true;
00172 }
00173
00174
00175 #if 0
00176 static bool vectorHasDescendingOrder(const vnl_vector<double>& v)
00177 {
00178 int n = v.size();
00179 for (int i = 1; i < n; i++)
00180 if (v(i-1) < v(i)) return false;
00181 return true;
00182 }
00183 #endif
00184
00185
00186
00187 vnl_matrix<double> vpdfl_gaussian::covariance() const
00188 {
00189 vnl_matrix<double> Cov;
00190 mbl_matrix_product_adb(Cov, evecs_, evals_, evecs_.transpose());
00191 return Cov;
00192 }
00193
00194
00195
00196 vpdfl_sampler_base* vpdfl_gaussian::new_sampler() const
00197 {
00198 vpdfl_gaussian_sampler *i = new vpdfl_gaussian_sampler;
00199 i->set_model(*this);
00200 return i;
00201 }
00202
00203
00204
00205
00206
00207 double vpdfl_gaussian::dx_sigma_dx(const vnl_vector<double>& x) const
00208 {
00209 unsigned int n = n_dims();
00210 #ifndef NDEBUG
00211 if (n!=x.size())
00212 {
00213 vcl_cerr<<"ERROR: vpdfl_gaussian::dx_sigma_dx: Target vector has "
00214 <<n<<" dimensions, not the required "<<n_dims()<<vcl_endl;
00215 vcl_abort();
00216 }
00217 #endif
00218
00219 b_.set_size(n);
00220
00221 dx_=x;
00222 dx_-=mean();
00223
00224
00225 mbl_matxvec_prod_vm(dx_, eigenvecs(),b_);
00226
00227 const double* b_data = b_.data_block() ;
00228 const double* v_data = eigenvals().data_block() ;
00229
00230 double sum=0.0;
00231
00232 unsigned int i=n;
00233 while (i-- != 0)
00234 {
00235 double db=b_data[i];
00236 sum+=(db*db)/v_data[i];
00237 }
00238 return sum;
00239 }
00240
00241
00242 double vpdfl_gaussian::log_p(const vnl_vector<double>& x) const
00243 {
00244 return log_k() - 0.5*dx_sigma_dx(x);
00245 }
00246
00247
00248
00249 void vpdfl_gaussian::gradient(vnl_vector<double>& g,
00250 const vnl_vector<double>& x,
00251 double& p) const
00252 {
00253 unsigned int n = n_dims();
00254 dx_ = x;
00255 dx_ -= mean();
00256
00257 if (b_.size()!=n) b_.set_size(n);
00258
00259
00260
00261 mbl_matxvec_prod_vm(dx_, eigenvecs(),b_);
00262
00263 if (g.size()!=n) g.set_size(n);
00264
00265 double* b_data = b_.data_block();
00266 const double* v_data = eigenvals().data_block();
00267
00268 double sum=0.0;
00269
00270 for (unsigned int i=0;i<n;++i)
00271 {
00272 double db=b_data[i];
00273 sum+=(db*db)/v_data[i];
00274
00275 b_data[i]/=v_data[i];
00276 }
00277
00278 p = vcl_exp(log_k() - 0.5*sum);
00279
00280 b_*=(-1.0*p);
00281
00282
00283 mbl_matxvec_prod_mv(eigenvecs(),b_,g);
00284 }
00285
00286
00287
00288 double vpdfl_gaussian::log_prob_thresh(double pass_proportion) const
00289 {
00290
00291
00292 return log_k() - 0.5 * vpdfl_chi2_for_cum_prob (pass_proportion, n_dims());
00293 }
00294
00295
00296
00297 void vpdfl_gaussian::nearest_plausible(vnl_vector<double>& x, double log_p_min) const
00298 {
00299
00300 log_p_min -= log_k();
00301 assert(log_p_min <0);
00302 const double sd_limit_sqr = -2.0*log_p_min;
00303 const double x_dist_sqr = dx_sigma_dx(x);
00304
00305 unsigned int n = n_dims();
00306
00307 if (sd_limit_sqr >= x_dist_sqr) return;
00308
00309 const double corrective_factor = vcl_sqrt(sd_limit_sqr / x_dist_sqr);
00310
00311 for (unsigned i=0;i<n;++i)
00312 x(i) = ((x(i)-mean()(i)) * corrective_factor) + mean()(i);
00313 }
00314
00315
00316
00317
00318
00319 vcl_string vpdfl_gaussian::is_a() const
00320 {
00321 static vcl_string class_name_ = "vpdfl_gaussian";
00322 return class_name_;
00323 }
00324
00325
00326
00327
00328
00329 bool vpdfl_gaussian::is_class(vcl_string const& s) const
00330 {
00331 return vpdfl_pdf_base::is_class(s) || s==vpdfl_gaussian::is_a();
00332 }
00333
00334
00335
00336
00337
00338 short vpdfl_gaussian::version_no() const
00339 {
00340 return 1;
00341 }
00342
00343
00344
00345
00346
00347 vpdfl_pdf_base* vpdfl_gaussian::clone() const
00348 {
00349 return new vpdfl_gaussian(*this);
00350 }
00351
00352
00353
00354
00355
00356 #if 0 // commented out
00357 static void ShowStartVec(vcl_ostream& os, const vnl_vector<double>& v)
00358 {
00359 int n = 3;
00360 if (n>v.size()) n=v.size();
00361 os<<'(';
00362 for (int i=0;i<n;++i) os<<v(i)<<' ';
00363 if (v.size()>n) os<<"...";
00364 os<<")\n";
00365 }
00366
00367 static void ShowStartMat(vcl_ostream& os, const vnl_matrix<double>& A)
00368 {
00369 os << A.rows() << " by " << A.cols() << " Matrix\n";
00370
00371 int m = 3, n= 3;
00372 if (m>A.rows()) m=A.rows();
00373 if (n>A.cols()) n=A.cols();
00374 vsl_indent_inc(os);
00375
00376 for (int i=0;i<m;++i)
00377 {
00378 os<<vsl_indent()<<'(';
00379
00380 for ( int j=0; j<n; ++j)
00381 os<<A(i,j)<<' ';
00382 if (A.cols()>n) os<<"...";
00383 os<<")\n";
00384 }
00385 if (A.rows()>m) os <<vsl_indent()<<"(...\n";
00386
00387 vsl_indent_dec(os);
00388 }
00389 #endif // commented out
00390
00391 void vpdfl_gaussian::print_summary(vcl_ostream& os) const
00392 {
00393 vpdfl_pdf_base::print_summary(os);
00394 os << vcl_endl;
00395 if (n_dims()!=1)
00396 {
00397 os<<vsl_indent()<<"Eigenvectors: "; vsl_print_summary(os, eigenvecs() );
00398 os<<vsl_indent()<<"log_k: "<< log_k_ <<vcl_endl;
00399
00400 }
00401 }
00402
00403
00404
00405
00406
00407 void vpdfl_gaussian::b_write(vsl_b_ostream& bfs) const
00408 {
00409 vsl_b_write(bfs,is_a());
00410 vsl_b_write(bfs,version_no());
00411 vpdfl_pdf_base::b_write(bfs);
00412 vsl_b_write(bfs,evecs_);
00413 vsl_b_write(bfs,evals_);
00414 vsl_b_write(bfs,log_k_);
00415 }
00416
00417
00418
00419
00420
00421 void vpdfl_gaussian::b_read(vsl_b_istream& bfs)
00422 {
00423 if (!bfs) return;
00424
00425 vcl_string name;
00426 vsl_b_read(bfs,name);
00427 if (name != is_a())
00428 {
00429 vcl_cerr << "I/O ERROR: vsl_b_read(vsl_b_istream&, vpdfl_gaussian &)\n"
00430 << " Attempted to load object of type "
00431 << name <<" into object of type " << is_a() << vcl_endl;
00432 bfs.is().clear(vcl_ios::badbit);
00433 return;
00434 }
00435
00436 short version;
00437 vsl_b_read(bfs,version);
00438 switch (version)
00439 {
00440 case (1):
00441 vpdfl_pdf_base::b_read(bfs);
00442 vsl_b_read(bfs,evecs_);
00443 vsl_b_read(bfs,evals_);
00444 vsl_b_read(bfs,log_k_);
00445 break;
00446 default:
00447 vcl_cerr << "I/O ERROR: vsl_b_read(vsl_b_istream&, vpdfl_gaussian &)\n"
00448 << " Unknown version number "<< version << vcl_endl;
00449 bfs.is().clear(vcl_ios::badbit);
00450 return;
00451 }
00452 }
00453
00454