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