contrib/mul/vpdfl/vpdfl_axis_gaussian.cxx
Go to the documentation of this file.
00001 // This is mul/vpdfl/vpdfl_axis_gaussian.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 // \file
00007 // \author Tim Cootes
00008 // \date 12-Apr-2001
00009 // \brief Multi-variate Gaussian PDF, with a diagonal covariance matrix
00010 
00011 #include "vpdfl_axis_gaussian.h"
00012 #include <vcl_cmath.h>
00013 #include <vnl/vnl_math.h>
00014 #include <vcl_cstdlib.h>
00015 #include <vcl_string.h>
00016 #include <vcl_cassert.h>
00017 #include <vsl/vsl_indent.h>
00018 #include <vpdfl/vpdfl_axis_gaussian_sampler.h>
00019 #include <vpdfl/vpdfl_sampler_base.h>
00020 #include <vpdfl/vpdfl_prob_chi2.h>
00021 
00022 
00023 //=======================================================================
00024 // Dflt ctor
00025 //=======================================================================
00026 
00027 vpdfl_axis_gaussian::vpdfl_axis_gaussian()
00028 {
00029 }
00030 
00031 //=======================================================================
00032 // Destructor
00033 //=======================================================================
00034 
00035 vpdfl_axis_gaussian::~vpdfl_axis_gaussian()
00036 {
00037 }
00038 
00039 //=======================================================================
00040 
00041 void vpdfl_axis_gaussian::calcLogK()
00042 {
00043   const double *v_data = variance().data_block();
00044   int n = n_dims();
00045   double log_v_sum = 0.0;
00046   for (int i=0;i<n;i++)
00047     log_v_sum+=vcl_log(v_data[i]);
00048 
00049   log_k_ = -0.5 * (n*vcl_log(2 * vnl_math::pi) + log_v_sum);
00050 }
00051 
00052 void vpdfl_axis_gaussian::calcSD()
00053 {
00054   sd_ = variance();
00055   int n = sd_.size();
00056   for (int i=0;i<n;i++) sd_[i] = vcl_sqrt(sd_[i]);
00057 }
00058 
00059 
00060 void vpdfl_axis_gaussian::set(const vnl_vector<double>& m,
00061                               const vnl_vector<double>& v)
00062 {
00063   set_mean(m);
00064   set_variance(v);
00065 
00066   calcLogK();
00067   calcSD();
00068 }
00069 
00070 // ====================================================================
00071 
00072 //: Mahalanobis distance squared from the mean.
00073 double vpdfl_axis_gaussian::dx_sigma_dx(const vnl_vector<double> &x) const
00074 {
00075   int n = x.size();
00076 #ifndef NDEBUG
00077   if (n!=n_dims())
00078   {
00079     vcl_cerr<<"ERROR: vpdfl_axis_gaussian::log_p: Target vector has "
00080             <<n<<" dimensions, not the required "<<n_dims()<<vcl_endl;
00081     vcl_abort();
00082   }
00083 #endif
00084 
00085   const double* x_data = x.data_block();
00086   const double* m_data = mean().data_block();
00087   const double* v_data = variance().data_block();
00088 
00089   double sum=0.0;
00090   for (int i=0;i<n;++i)
00091   {
00092     double dx=x_data[i]-m_data[i];
00093     sum+=(dx*dx)/v_data[i];
00094   }
00095   return sum;
00096 }
00097 
00098   // Probability densities:
00099 double vpdfl_axis_gaussian::log_p(const vnl_vector<double>& x) const
00100 {
00101   return log_k() - 0.5*dx_sigma_dx(x);
00102 }
00103 
00104 void vpdfl_axis_gaussian::gradient(vnl_vector<double>& g,
00105                                    const vnl_vector<double>& x,
00106                                    double& p) const
00107 {
00108   unsigned int n = n_dims();
00109   assert(x.size() == n);
00110 
00111   if (g.size()!=n) g.set_size(n);
00112 
00113   double* g_data = g.data_block();
00114   const double* x_data = x.data_block();
00115   const double* m_data = mean().data_block();
00116   const double* v_data = variance().data_block();
00117 
00118   double sum=0.0;
00119 
00120   for (unsigned int i=0;i<n;++i)
00121   {
00122     double dx=x_data[i]-m_data[i];
00123     sum+=(dx*dx)/v_data[i];
00124     g_data[i]= -dx/v_data[i];
00125   }
00126 
00127   p = vcl_exp(log_k() - 0.5*sum);
00128 
00129   g*=p;
00130 }
00131 
00132 //: Gradient and value of log(p(x)) at x
00133 //  Computes gradient df/dx of f(x)=log(p(x)) at x.
00134 void vpdfl_axis_gaussian::gradient_logp(vnl_vector<double>& g,
00135                                    const vnl_vector<double>& x) const
00136 {
00137   unsigned int n = n_dims();
00138   assert(x.size() == n);
00139 
00140   if (g.size()!=n) g.set_size(n);
00141 
00142   double* g_data = g.data_block();
00143   const double* x_data = x.data_block();
00144   const double* m_data = mean().data_block();
00145   const double* v_data = variance().data_block();
00146 
00147   for (unsigned int i=0;i<n;++i)
00148   {
00149     g_data[i]= (m_data[i]-x_data[i])/v_data[i];
00150   }
00151 }
00152 
00153 // ====================================================================
00154 
00155 vpdfl_sampler_base* vpdfl_axis_gaussian::new_sampler() const
00156 {
00157   vpdfl_axis_gaussian_sampler *i = new vpdfl_axis_gaussian_sampler;
00158   i->set_model(*this);
00159   return i;
00160 }
00161 
00162 
00163 double vpdfl_axis_gaussian::log_prob_thresh(double pass_proportion) const
00164 {
00165   // The Mahalanobis distance of n-D Gaussian is distributed as Chi^2(n),
00166   // by definition, Chi^2 is the sum of independent Normal RVs.
00167   return log_k() - 0.5 * vpdfl_chi2_for_cum_prob (pass_proportion, n_dims());
00168 }
00169 
00170 
00171 void vpdfl_axis_gaussian::nearest_plausible(vnl_vector<double>& x,
00172   double log_p_min) const
00173 {
00174   unsigned n = x.size();
00175 
00176   // calculate radius of plausible region in standard deviations.
00177   log_p_min -= log_k();
00178   assert(log_p_min <0); // Check sd_limit is positive and real.
00179 
00180   const double sd_limit_sqr = -2.0*log_p_min;
00181   // distance to x in standard deviations
00182   const double x_dist_sqr = dx_sigma_dx(x);
00183 
00184   if (sd_limit_sqr >= x_dist_sqr) return;
00185 
00186   const double corrective_factor = vcl_sqrt(sd_limit_sqr / x_dist_sqr);
00187 
00188   for (unsigned i=0;i<n;++i)
00189     x(i) = ((x(i)-mean()(i)) * corrective_factor) + mean()(i);
00190 }
00191 
00192 //=======================================================================
00193 
00194 vcl_string vpdfl_axis_gaussian::is_a() const
00195 {
00196   static const vcl_string s_ = "vpdfl_axis_gaussian";
00197   return s_;
00198 }
00199 
00200 //=======================================================================
00201 
00202 bool vpdfl_axis_gaussian::is_class(vcl_string const& s) const
00203 {
00204   return s==vpdfl_axis_gaussian::is_a() || vpdfl_pdf_base::is_class(s);
00205 }
00206 
00207 //=======================================================================
00208 
00209 short vpdfl_axis_gaussian::version_no() const
00210 {
00211   return 1;
00212 }
00213 
00214 //=======================================================================
00215 
00216 vpdfl_pdf_base* vpdfl_axis_gaussian::clone() const
00217 {
00218   return new vpdfl_axis_gaussian(*this);
00219 }
00220 
00221 //=======================================================================
00222 
00223 void vpdfl_axis_gaussian::print_summary(vcl_ostream& os) const
00224 {
00225   vpdfl_pdf_base::print_summary(os);
00226 }
00227 
00228 //=======================================================================
00229 
00230 void vpdfl_axis_gaussian::b_write(vsl_b_ostream& bfs) const
00231 {
00232   vsl_b_write(bfs,version_no());
00233   vpdfl_pdf_base::b_write(bfs);
00234 }
00235 
00236 //=======================================================================
00237 
00238 void vpdfl_axis_gaussian::b_read(vsl_b_istream& bfs)
00239 {
00240   if (!bfs) return;
00241 
00242   short version;
00243   vsl_b_read(bfs,version);
00244   switch (version)
00245   {
00246     case (1):
00247       vpdfl_pdf_base::b_read(bfs);
00248       break;
00249     default:
00250       vcl_cerr << "I/O ERROR: vsl_b_read(vsl_b_istream&, vpdfl_axis_gaussian &)\n"
00251                << "           Unknown version number "<< version << vcl_endl;
00252       bfs.is().clear(vcl_ios::badbit); // Set an unrecoverable IO error on stream
00253       return;
00254   }
00255 
00256   calcLogK();
00257   calcSD();
00258 }