00001
00002 #ifndef vpdt_gaussian_h_
00003 #define vpdt_gaussian_h_
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include <vpdl/vpdt/vpdt_field_traits.h>
00017 #include <vpdl/vpdt/vpdt_field_default.h>
00018 #include <vpdl/vpdt/vpdt_dist_traits.h>
00019 #include <vpdl/vpdt/vpdt_access.h>
00020 #include <vpdl/vpdt/vpdt_eigen_sym_matrix.h>
00021 #include <vpdl/vpdt/vpdt_norm_metric.h>
00022 #include <vcl_limits.h>
00023 #include <vnl/vnl_erf.h>
00024
00025
00026
00027 template <class F, class Covar, class Metric, class Disambiguate= void >
00028 struct vpdt_gaussian_integrator;
00029
00030
00031
00032 template<class F,
00033 class Covar = typename vpdt_eigen_sym_matrix_gen<F>::type,
00034 class Metric = vpdt_norm_metric<F,Covar> >
00035 class vpdt_gaussian
00036 {
00037 public:
00038
00039 typedef F field_type;
00040
00041 typedef Covar covar_type;
00042
00043 typedef Metric metric_type;
00044
00045
00046 typedef typename vpdt_field_traits<F>::scalar_type T;
00047
00048 typedef typename vpdt_field_traits<F>::vector_type vector;
00049
00050 typedef typename vpdt_field_traits<F>::matrix_type matrix;
00051
00052
00053
00054
00055 vpdt_gaussian(unsigned int var_dim = vpdt_field_traits<F>::dimension)
00056 {
00057 vpdt_set_size(mean,var_dim);
00058 vpdt_set_size(covar,var_dim);
00059 vpdt_fill(mean,T(0));
00060 vpdt_fill(covar,T(0));
00061 }
00062
00063
00064 vpdt_gaussian(const F& m, const covar_type& c)
00065 : mean(m), covar(c) {}
00066
00067
00068 unsigned int dimension() const { return vpdt_size(mean); }
00069
00070
00071
00072 T density(const F& pt) const
00073 {
00074 return static_cast<T>(vcl_exp(-sqr_mahal_dist(pt)/2));
00075 }
00076
00077
00078
00079 T gradient_density(const F& pt, vector& g) const
00080 {
00081 T d = Metric::sqr_distance_deriv(pt,mean,covar,g);
00082 d = vcl_exp(-d/2);
00083 g *= -d/2;
00084 return d;
00085 }
00086
00087
00088
00089 T norm_const() const
00090 {
00091 return T(1)/vpdt_gaussian_integrator<F,Covar,Metric>::
00092 domain_integral(*this);
00093 }
00094
00095
00096
00097 T sqr_mahal_dist(const F& pt) const
00098 {
00099 return Metric::sqr_distance(pt,mean,covar);
00100 }
00101
00102
00103
00104
00105 T cumulative_prob(const F& pt) const
00106 {
00107 return vpdt_gaussian_integrator<F,Covar,Metric>::
00108 partial_integral(*this,pt);
00109 }
00110
00111
00112 void compute_mean(vector& m) const { m = mean; }
00113
00114
00115 void compute_covar(matrix& c) const
00116 {
00117
00118 Metric::compute_covar(c, mean, covar);
00119 }
00120
00121
00122
00123
00124
00125 F mean;
00126
00127 covar_type covar;
00128 };
00129
00130
00131
00132 template<class F, class C, class M >
00133 inline typename vpdt_dist_traits<vpdt_gaussian<F,C,M> >::scalar_type
00134 vpdt_log_density(const vpdt_gaussian<F,C,M>& d,
00135 const typename vpdt_dist_traits<vpdt_gaussian<F,C,M> >::field_type& pt)
00136 {
00137 typedef typename vpdt_dist_traits<vpdt_gaussian<F,C,M> >::scalar_type T;
00138 return static_cast<T>(-d.sqr_mahal_dist(pt)/2);
00139 }
00140
00141
00142 template<class F, class C, class M >
00143 inline typename vpdt_dist_traits<vpdt_gaussian<F,C,M> >::scalar_type
00144 vpdt_gradient_log_density(const vpdt_gaussian<F,C,M>& d,
00145 const typename vpdt_dist_traits<vpdt_gaussian<F,C,M> >::field_type& pt,
00146 typename vpdt_dist_traits<vpdt_gaussian<F,C,M> >::field_type& g)
00147 {
00148 typedef typename vpdt_dist_traits<vpdt_gaussian<F,C,M> >::scalar_type T;
00149 T logd = M::sqr_distance_deriv(pt,d.mean,d.covar,g);
00150 g /= -2;
00151 return static_cast<T>(-logd/2);
00152 }
00153
00154
00155
00156
00157
00158
00159
00160 template <class F>
00161 struct vpdt_gaussian_integrator<F, typename vpdt_eigen_sym_matrix_gen<F>::type,
00162 vpdt_norm_metric<F, typename vpdt_eigen_sym_matrix_gen<F>::type>,
00163 typename vpdt_field_traits<F>::type_is_vector >
00164 {
00165 typedef typename vpdt_eigen_sym_matrix_gen<F>::type Covar;
00166 typedef vpdt_norm_metric<F,typename vpdt_eigen_sym_matrix_gen<F>::type> Metric;
00167 typedef typename vpdt_field_traits<F>::scalar_type T;
00168
00169
00170 static inline T domain_integral(const vpdt_gaussian<F,Covar>& g)
00171 {
00172 const unsigned int d = g.dimension();
00173 const double two_pi = 2.0*vnl_math::pi;
00174 double two_pi_n = two_pi;
00175 for (unsigned int i=1; i<d; ++i)
00176 two_pi_n *= two_pi;
00177
00178 return static_cast<T>(vcl_sqrt(two_pi_n*Metric::covar_det(g.mean,g.covar)));
00179 }
00180
00181
00182 static inline T partial_integral(const vpdt_gaussian<F,Covar>& , const F& )
00183 {
00184
00185
00186 return vcl_numeric_limits<T>::quiet_NaN();
00187 }
00188 };
00189
00190
00191
00192
00193 template <class F>
00194 struct vpdt_gaussian_integrator<F,F,vpdt_norm_metric<F,F>,
00195 typename vpdt_field_traits<F>::type_is_vector >
00196 {
00197 typedef typename vpdt_field_traits<F>::scalar_type T;
00198
00199
00200 static inline T domain_integral(const vpdt_gaussian<F,F>& g)
00201 {
00202 const unsigned int d = g.dimension();
00203 const double two_pi = 2.0*vnl_math::pi;
00204 double val = 1.0;
00205 for (unsigned int i=0; i<d; ++i)
00206 val *= two_pi*g.covar[i];
00207
00208 return static_cast<T>(vcl_sqrt(val));
00209 }
00210
00211
00212 static inline T partial_integral(const vpdt_gaussian<F,F>& g, const F& pt)
00213 {
00214 const unsigned int d = g.dimension();
00215 double val = 1.0;
00216 for (unsigned int i=0; i<d; ++i)
00217 {
00218 if (vpdt_index(g.covar,i) <= T(0))
00219 {
00220 if (vpdt_index(pt,i) < vpdt_index(g.mean,i))
00221 return T(0);
00222 }
00223 else{
00224 double s2 = vcl_sqrt(2.0*vpdt_index(g.covar,i));
00225 val *= 0.5*vnl_erf((vpdt_index(pt,i)-vpdt_index(g.mean,i))/s2) + 0.5;
00226 }
00227 }
00228 return static_cast<T>(val);
00229 }
00230 };
00231
00232
00233
00234
00235 template <class F>
00236 struct vpdt_gaussian_integrator<F,typename vpdt_field_traits<F>::scalar_type,
00237 vpdt_norm_metric<F,typename vpdt_field_traits<F>::scalar_type>,
00238 typename vpdt_field_traits<F>::type_is_vector>
00239 {
00240 typedef typename vpdt_field_traits<F>::vector_type vector;
00241 typedef typename vpdt_field_traits<F>::scalar_type T;
00242
00243
00244 static inline T domain_integral(const vpdt_gaussian<F,T>& g)
00245 {
00246 const unsigned int d = g.dimension();
00247 const double two_pi = 2.0*vnl_math::pi;
00248 double val = 1.0;
00249 for (unsigned int i=0; i<d; ++i)
00250 val *= two_pi*g.covar;
00251
00252 return static_cast<T>(vcl_sqrt(val));
00253 }
00254
00255
00256 static inline T partial_integral(const vpdt_gaussian<F,T>& g, const F& pt)
00257 {
00258 const unsigned int d = g.dimension();
00259 if (g.covar<=T(0))
00260 {
00261 for (unsigned int i=0; i<d; ++i)
00262 if (vpdt_index(pt,i) < vpdt_index(g.mean,i))
00263 return T(0);
00264 return T(1);
00265 }
00266 double s2 = 1/vcl_sqrt(2.0*g.covar);
00267 double val = 1.0;
00268 for (unsigned int i=0; i<d; ++i)
00269 {
00270 val *= 0.5*vnl_erf(s2*(vpdt_index(pt,i)-vpdt_index(g.mean,i))) + 0.5;
00271 }
00272 return static_cast<T>(val);
00273 }
00274 };
00275
00276
00277
00278
00279 template <class F>
00280 struct vpdt_gaussian_integrator<F,F,vpdt_norm_metric<F,F>,
00281 typename vpdt_field_traits<F>::type_is_scalar>
00282 {
00283 typedef typename vpdt_field_traits<F>::scalar_type T;
00284
00285
00286 static inline T domain_integral(const vpdt_gaussian<F,F>& g)
00287 {
00288 return static_cast<T>(vcl_sqrt(2.0*vnl_math::pi*g.covar));
00289 }
00290
00291
00292 static inline T partial_integral(const vpdt_gaussian<F,F>& g, const F& pt)
00293 {
00294 if (g.covar<=T(0))
00295 {
00296 if (pt < g.mean)
00297 return T(0);
00298 return T(1);
00299 }
00300 double val = 0.5*vnl_erf((pt-g.mean)/vcl_sqrt(2.0*g.covar)) + 0.5;
00301 return static_cast<T>(val);
00302 }
00303 };
00304
00305
00306 #endif // vpdt_gaussian_h_