core/vpdl/vpdl_distribution.txx
Go to the documentation of this file.
00001 // This is core/vpdl/vpdl_distribution.txx
00002 #ifndef vpdl_distribution_txx_
00003 #define vpdl_distribution_txx_
00004 //:
00005 // \file
00006 
00007 #include "vpdl_distribution.h"
00008 #include <vpdl/vpdt/vpdt_access.h>
00009 #include <vcl_limits.h>
00010 #include <vcl_cassert.h>
00011 
00012 //: Default implementation of numerical CDF inverse computation.
00013 // This function is called by the virtual function inverse_cdf() by default
00014 // in the univariate case.
00015 
00016 template <class T>
00017 T vpdl_compute_inverse_cdf(const vpdl_distribution<T,1>& /*dist*/, double /*p*/)
00018 {
00019   // FIXME: implement CDF inverse computation here
00020   return T(0.0);
00021 }
00022 
00023 
00024 namespace{
00025 
00026 //: Define helper classes to create partial specialization of member functions.
00027 template <class T, unsigned int n>
00028 class inverse_cdf_helper
00029 {
00030  public:
00031   typedef typename vpdl_distribution<T,n>::vector vector;
00032 
00033   //: Do the actual inversion
00034   static inline vector invert(const vpdl_distribution<T,n>& /*dist*/, const T& /*p*/)
00035   {
00036     return vector(vcl_numeric_limits<T>::quiet_NaN());
00037   }
00038 };
00039 
00040 template <class T>
00041 class inverse_cdf_helper<T,1>
00042 {
00043  public:
00044   typedef typename vpdl_distribution<T,1>::vector vector;
00045 
00046   //: Do the actual inversion
00047   static inline vector invert(const vpdl_distribution<T,1>& dist, const T& p)
00048   {
00049     return vpdl_compute_inverse_cdf(dist,p);
00050   }
00051 };
00052 
00053 template <class T>
00054 class inverse_cdf_helper<T,0>
00055 {
00056  public:
00057   typedef typename vpdl_distribution<T,0>::vector vector;
00058 
00059   //: Do the actual inversion
00060   static inline vector invert(const vpdl_distribution<T,0>& dist, const T& /*p*/)
00061   {
00062     return vector(dist.dimension(), vcl_numeric_limits<T>::quiet_NaN());
00063   }
00064 };
00065 
00066 }
00067 
00068 
00069 //: Compute the inverse of the cumulative_prob() function
00070 // The value of x: P(x'<x) = P for x' drawn from the distribution.
00071 // This is only valid for univariate distributions
00072 // multivariate distributions will return -infinity
00073 template <class T, unsigned int n>
00074 typename vpdl_distribution<T,n>::vector
00075 vpdl_distribution<T,n>::inverse_cdf(const T& p) const
00076 {
00077   // use a static helper class to do partial specialization
00078   return inverse_cdf_helper<T,n>::invert(*this, p);
00079 }
00080 
00081 
00082 //: The probability of being in an axis-aligned box
00083 // The box is defined by two points, the minimum and maximum.
00084 // Implemented in terms of \c cumulative_prob() by default.
00085 template <class T, unsigned int n>
00086 T vpdl_distribution<T,n>::box_prob(const vector& min_pt,
00087                                    const vector& max_pt) const
00088 {
00089   const unsigned int dim = this->dimension();
00090 
00091   // return zero for ill-defined box
00092   for (unsigned int j=0; j<dim; ++j){
00093     if (vpdt_index(max_pt,j)<=vpdt_index(min_pt,j))
00094       return T(0);
00095   }
00096 
00097   // this method is not tractable for large dimensions
00098   assert(sizeof(unsigned long)*8 > dim);
00099   // compute the number of corners of the box (2^dim)
00100   const unsigned long num_corners = 1 << dim;
00101 
00102   T prob = T(0);
00103   vector corner(min_pt);
00104   for (unsigned long i=0; i<num_corners; ++i)
00105   {
00106     // In odd dimensions, corners with an odd number of maximal axis
00107     // are added to the sum.  In even dimensions, corners with an even
00108     // number of maximal axis are added. The other corners are subtracted.
00109     bool plus = (dim%2 != 1);
00110     // create the corner position by selecting elements from max_pt and min_pt
00111     for (unsigned int j=0; j<dim; ++j){
00112       bool is_max = (i>>j) & 1;
00113       plus ^= is_max; // toggle plus if is_max
00114       vpdt_index(corner,j) = is_max?vpdt_index(max_pt,j):vpdt_index(min_pt,j);
00115     }
00116     if (plus)
00117       prob += cumulative_prob(corner);
00118     else
00119       prob -= cumulative_prob(corner);
00120   }
00121 
00122   return prob;
00123 }
00124 
00125 
00126 #undef VPDL_DISTRIBUTION_INSTANTIATE
00127 #define VPDL_DISTRIBUTION_INSTANTIATE(T,n) \
00128 template class vpdl_distribution<T,n >
00129 
00130 // instantiate this function only for n == 1
00131 #undef VPDL_INVERSE_CDF_INSTANTIATE
00132 #define VPDL_INVERSE_CDF_INSTANTIATE(T) \
00133 template T vpdl_compute_inverse_cdf(const vpdl_distribution<T,1>& dist, double p)
00134 
00135 #endif // vpdl_distribution_txx_