contrib/brl/bbas/bsta/algo/bsta_sigma_normalizer.cxx
Go to the documentation of this file.
00001 #include "bsta_sigma_normalizer.h"
00002 //:
00003 // \file
00004 // \brief A class for adjusting sample standard deviation values such that the probability of underestimation of the true std. dev. is fixed.
00005 
00006 #include <vcl_iostream.h>
00007 
00008 #include <vnl/vnl_vector_fixed.h>
00009 #include <vnl/vnl_gamma.h>
00010 #include <vnl/vnl_least_squares_function.h>
00011 #include <vnl/algo/vnl_levenberg_marquardt.h>
00012 
00013 bsta_sigma_normalizer::bsta_sigma_normalizer(float under_estimation_probability, unsigned int N_PRECOMPUTED) : N_PRECOMPUTED_(N_PRECOMPUTED), unbias_const_(N_PRECOMPUTED+1, 0.0f)
00014 {
00015   class gammainc_error_fn : public vnl_least_squares_function
00016   {
00017    public:
00018     gammainc_error_fn(unsigned int ndof, float under_estimation_prob) : vnl_least_squares_function(1,1,no_gradient), ndof_(ndof), p_(under_estimation_prob) {}
00019 
00020     virtual void f(vnl_vector<double> const& x, vnl_vector<double>& fx)
00021     {
00022       // don't allow x to become negative
00023       if (x[0] < 0.0f) {
00024         fx[0] = x[0] - p_; // so error function is c0 continuous at x=0
00025         return;
00026       }
00027       double cdf_prob = vnl_cum_prob_chi2(ndof_, x[0]);
00028       fx[0] = cdf_prob - p_;
00029       return;
00030     }
00031    private:
00032     unsigned int ndof_;
00033     float p_;
00034   };
00035 
00036   // sanity check on probability
00037   if (under_estimation_probability < 1e-4) {
00038     vcl_cout << "error : boxm_sigma_normalizer : under_estimation_probability " << under_estimation_probability << " too low" << vcl_endl;
00039     return;
00040   }
00041   if (under_estimation_probability > (1 - 1e-4)) {
00042     vcl_cout << "error : boxm_sigma_normalizer : under_estimation_probability " << under_estimation_probability << " too high" << vcl_endl;
00043     return;
00044   }
00045 
00046   // populate array of normalization factors for easy lookup
00047   vnl_vector_fixed<double,1> x(1.0);
00048 
00049   for (unsigned int n=2; n<= N_PRECOMPUTED_; ++n) {
00050     gammainc_error_fn f(n-1, under_estimation_probability);
00051     vnl_levenberg_marquardt minimizer(f);
00052     minimizer.set_f_tolerance(1e-8);
00053     minimizer.set_x_tolerance(1e-8);
00054 
00055     minimizer.minimize(x);
00056     //minimizer.diagnose_outcome();
00057     double end_error = minimizer.get_end_error();
00058     if (end_error > 1e-3) {
00059       vcl_cerr << "error: boxm_sigma_normalizer: levenberg_marquardt final error = " << end_error << '\n';
00060     }
00061     float unbias_constant = (float)vcl_sqrt((float)(n-1) / x[0]);
00062 
00063     unbias_const_[n] = unbias_constant;
00064   }
00065   // sigma is undefined for samples sizes of 0 and 1, but we can linearly interpolate to get values anyway
00066   unbias_const_[1] = unbias_const_[2] - (unbias_const_[3] - unbias_const_[2]);
00067   unbias_const_[0] = unbias_const_[1] - (unbias_const_[2] - unbias_const_[1]);
00068 }
00069 
00070 
00071 float bsta_sigma_normalizer::normalization_factor(float number_of_observations) const
00072 {
00073   if (number_of_observations <= 1.0f) {
00074     return normalization_factor_int((unsigned int)1);
00075   }
00076 
00077   // linearly interpolate between integer values
00078   float nobs_floor = vcl_floor(number_of_observations);
00079   float nobs_ceil = vcl_ceil(number_of_observations);
00080   float floor_weight = nobs_ceil - number_of_observations;
00081   float norm_factor = (normalization_factor_int((unsigned int)nobs_floor) * floor_weight) + (normalization_factor_int((unsigned int)nobs_ceil) * (1.0f - floor_weight));
00082 
00083   return norm_factor;
00084 }
00085 
00086 
00087 float bsta_sigma_normalizer::normalization_factor_int(unsigned int number_of_observations) const
00088 {
00089   if (number_of_observations < 2) {
00090     return unbias_const_[1];
00091   }
00092 
00093   if (number_of_observations <= N_PRECOMPUTED_) {
00094     return unbias_const_[number_of_observations];
00095   }
00096   // else nobs >= N_PRECOMPUTED_
00097   // approximate for big n with function a = m /nobs + b
00098   static const float m = (unbias_const_[N_PRECOMPUTED_] - unbias_const_[N_PRECOMPUTED_ - 5])/(1.0f/N_PRECOMPUTED_ - 1.0f/(N_PRECOMPUTED_ - 5));
00099   static const float b = unbias_const_[N_PRECOMPUTED_]  - m*(1.0f/N_PRECOMPUTED_);
00100   return m/number_of_observations + b;
00101 }
00102 
00103 //: Binary write boxm2_scene to stream
00104 void vsl_b_write(vsl_b_ostream& /*os*/, bsta_sigma_normalizer const& /*bit_scene*/) {}
00105 //: Binary write boxm2_scene pointer to stream
00106 void vsl_b_write(vsl_b_ostream& /*os*/, bsta_sigma_normalizer* const& /*ph*/) {}
00107 //: Binary write boxm2_scene smart pointer to stream
00108 void vsl_b_write(vsl_b_ostream& /*os*/, bsta_sigma_normalizer_sptr&) {}
00109 //: Binary write boxm2_scene smart pointer to stream
00110 void vsl_b_write(vsl_b_ostream& /*os*/, bsta_sigma_normalizer_sptr const&) {}
00111 
00112 //: Binary load boxm scene from stream.
00113 void vsl_b_read(vsl_b_istream& /*is*/, bsta_sigma_normalizer& /*bit_scene*/) {}
00114 //: Binary load boxm scene pointer from stream.
00115 void vsl_b_read(vsl_b_istream& /*is*/, bsta_sigma_normalizer* /*ph*/) {}
00116 //: Binary load boxm scene smart pointer from stream.
00117 void vsl_b_read(vsl_b_istream& /*is*/, bsta_sigma_normalizer_sptr&) {}
00118 //: Binary load boxm scene smart pointer from stream.
00119 void vsl_b_read(vsl_b_istream& /*is*/, bsta_sigma_normalizer_sptr const&) {}
00120 
00121