contrib/brl/bbas/bsta/bsta_basic_functors.h
Go to the documentation of this file.
00001 // This is brl/bbas/bsta/bsta_basic_functors.h
00002 #ifndef bsta_basic_functors_h_
00003 #define bsta_basic_functors_h_
00004 //:
00005 // \file
00006 // \brief Basic functors for simple operations on Gaussian mixtures
00007 // \author Matt Leotta (mleotta@lems.brown.edu)
00008 // \date January 30, 2006
00009 //
00010 // \verbatim
00011 //  Modifications
00012 //   (none yet)
00013 // \endverbatim
00014 
00015 #include <vcl_vector.h>
00016 #include <bsta/bsta_attributes.h>
00017 #include <bsta/bsta_gaussian_indep.h>
00018 #include <bsta/bsta_gaussian_sphere.h>
00019 #include <vpdl/vpdt/vpdt_enable_if.h>
00020 #include <vpdl/vpdt/vpdt_dist_traits.h>
00021 #include <vpdl/vpdt/vpdt_mixture_accessors.h>
00022 
00023 //: A functor to return the probability density at a sample
00024 template <class dist_>
00025 class bsta_prob_density_functor
00026 {
00027  public:
00028   typedef typename dist_::math_type T;
00029   typedef typename dist_::vector_type vector_;
00030   typedef T return_T;
00031   typedef return_T return_type; // for compatibility with vpdl/vdpt
00032   enum { return_dim = 1 };
00033 
00034   //: The main function
00035   bool operator() ( const dist_& d, const vector_& sample, return_T& retval ) const
00036   {
00037     retval = d.prob_density(sample);
00038     return true;
00039   }
00040 };
00041 
00042 //: A functor to return the probability density with additional covariance
00043 template <class mix_dist_>
00044 class bsta_prob_density_addcovar_functor
00045 {
00046  public:
00047   typedef typename mix_dist_::dist_type::math_type T;
00048   typedef typename mix_dist_::dist_type::vector_type vector_;
00049   typedef typename mix_dist_::dist_type::covar_type covar_t_;
00050   typedef T return_T;
00051   typedef return_T return_type; // for compatibility with vpdl/vdpt
00052   enum { return_dim = 1 };
00053   //: The main function
00054   bool operator() ( const mix_dist_& d, const vector_& sample,
00055                     const covar_t_& add_covar, return_T& retval ) const
00056   {
00057     unsigned nc = d.num_components();
00058     vcl_vector<covar_t_> initial_covars(nc);
00059     mix_dist_& non_const_d = const_cast<mix_dist_&>(d);
00060     for (unsigned i = 0; i<nc; ++i) {
00061       initial_covars[i]=(d.distribution(i)).covar();
00062       non_const_d.distribution(i).set_covar(initial_covars[i]+add_covar);
00063     }
00064     retval = non_const_d.prob_density(sample);
00065     for (unsigned i = 0; i<nc; ++i)
00066       non_const_d.distribution(i).set_covar(initial_covars[i]);
00067     return true;
00068   }
00069 };
00070 
00071 
00072 //: A functor to return the probability integrated over a box
00073 template <class dist_>
00074 class bsta_probability_functor
00075 {
00076  public:
00077   typedef typename dist_::math_type T;
00078   typedef typename dist_::vector_type vector_;
00079   typedef T return_T;
00080   typedef return_T return_type; // for compatibility with vpdl/vdpt
00081   enum { return_dim = 1 };
00082 
00083   //: The main function
00084   bool operator() ( const dist_& d, const vector_& min_pt,
00085                     const vector_& max_pt, return_T& retval ) const
00086   {
00087     retval = d.probability(min_pt,max_pt);
00088     return true;
00089   }
00090 };
00091 
00092 //: A functor to return the probability with added covariance
00093 template <class mix_dist_>
00094 class bsta_probability_addcovar_functor
00095 {
00096  public:
00097   typedef typename mix_dist_::dist_type::math_type T;
00098   typedef typename mix_dist_::dist_type::vector_type vector_;
00099   typedef typename mix_dist_::dist_type::covar_type covar_t_;
00100   typedef T return_T;
00101   typedef return_T return_type; // for compatibility with vpdl/vdpt
00102   enum { return_dim = 1 };
00103   //: The main function
00104   bool operator() ( const mix_dist_& d,
00105                     const vector_& min_pt,
00106                     const vector_& max_pt,
00107                     const covar_t_& add_covar,
00108                     return_T& retval ) const
00109   {
00110     unsigned nc = d.num_components();
00111     mix_dist_& non_const_d = const_cast<mix_dist_&>(d);
00112     vcl_vector<covar_t_> initial_covars(nc);
00113     for (unsigned i = 0; i<nc; ++i){
00114       initial_covars[i]=(d.distribution(i)).covar();
00115       non_const_d.distribution(i).set_covar(initial_covars[i]+add_covar);
00116     }
00117     retval = d.probability(min_pt, max_pt);
00118     for (unsigned i = 0; i<nc; ++i)
00119       non_const_d.distribution(i).set_covar(initial_covars[i]);
00120     return true;
00121   }
00122 };
00123 
00124 //: A functor to return the mean of the Gaussian
00125 // \note the distribution must be Gaussian
00126 template <class dist_, class Disambiguate = void>
00127 class bsta_mean_functor
00128 {
00129  public:
00130   typedef typename dist_::math_type T;
00131   typedef typename dist_::vector_type vector_;
00132   typedef vector_ return_T;
00133   typedef return_T return_type; // for compatibility with vpdl/vdpt
00134   //: is this functor valid for its distribution type
00135   static const bool valid_functor = true;
00136   enum { return_dim = dist_::dimension };
00137 
00138   //: rebind this functor to another distribution type
00139   template <class other_dist>
00140   struct rebind {
00141     typedef bsta_mean_functor<other_dist> other;
00142   };
00143 
00144   //: The main function
00145   bool operator() ( const dist_& d, return_T& retval ) const
00146   {
00147     retval = d.mean();
00148     return true;
00149   }
00150 };
00151 
00152 //: for compatibility with vpdl/vpdt
00153 template <class dist_>
00154 class bsta_mean_functor<dist_, typename vpdt_enable_if<vpdt_is_mixture<dist_> >::type >
00155 {
00156  public:
00157   typedef typename dist_::field_type return_type;
00158   enum { return_dim = dist_::dimension };
00159   //: is this functor valid for its distribution type
00160   static const bool valid_functor = false;
00161 
00162   //: rebind this functor to another distribution type
00163   template <class other_dist>
00164   struct rebind {
00165     typedef bsta_mean_functor<other_dist> other;
00166   };
00167 
00168   //: The main function
00169   bool operator() ( const dist_& /*d*/, return_type& /*retval*/ ) const
00170   {
00171     return false;
00172   }
00173 };
00174 
00175 
00176 //: A functor to return the variance of the Gaussian
00177 // \note the distribution must be spherical Gaussian
00178 template <class dist_>
00179 class bsta_var_functor
00180 {
00181  public:
00182   typedef typename dist_::math_type T;
00183   typedef T return_T;
00184   typedef return_T return_type; // for compatibility with vpdl/vdpt
00185   enum { return_dim = 1 };
00186   //: is this functor valid for its distribution type
00187   static const bool valid_functor = false;
00188 
00189   //: rebind this functor to another distribution type
00190   template <class other_dist>
00191   struct rebind {
00192     typedef bsta_var_functor<other_dist> other;
00193   };
00194 
00195   //: The main function
00196 #if 0
00197   bool operator() (dist_ const& d, return_T& retval) const
00198   {
00199     retval = d.var();
00200     return true;
00201   }
00202 #else
00203   bool operator() (dist_ const&, return_T&) const
00204   {
00205     return false;
00206   }
00207 #endif
00208 };
00209 
00210 //: A functor to return the variance of the Gaussian
00211 // \note the distribution must be a spherical Gaussian with one dimensions
00212 //       the default template does nothing.
00213 //       This solution is really just a hack.
00214 //       The correct solution requires is_base_of from Boost or TR1.
00215 //       This class should work for any derived class of bsta_gaussian_indep
00216 template <class T>
00217 class bsta_var_functor<bsta_num_obs<bsta_gaussian_sphere<T,1> > >
00218 {
00219  public:
00220   typedef bsta_gaussian_sphere<T,1> dist_;
00221   typedef typename dist_::vector_type vector_;
00222   typedef vector_ return_T;
00223   typedef return_T return_type; // for compatibility with vpdl/vdpt
00224   enum { return_dim = dist_::dimension };
00225   //: is this functor valid for its distribution type
00226   static const bool valid_functor = true;
00227 
00228   //: rebind this functor to another distribution type
00229   template <class other_dist>
00230   struct rebind {
00231     typedef bsta_var_functor<other_dist> other;
00232   };
00233 
00234   //: The main function
00235   bool operator() ( const dist_& d, return_T& retval ) const
00236   {
00237     retval = d.var();
00238     return true;
00239   }
00240 };
00241 
00242 
00243 //: A functor to return the variance of the Gaussian
00244 // \note the distribution must be an independent Gaussian
00245 //       the default template does nothing
00246 template <class dist_>
00247 class bsta_diag_covar_functor
00248 {
00249  public:
00250   typedef typename dist_::math_type T;
00251   typedef typename dist_::vector_type vector_;
00252   typedef vector_ return_T;
00253   typedef return_T return_type; // for compatibility with vpdl/vdpt
00254   enum { return_dim = dist_::dimension };
00255   //: is this functor valid for its distribution type
00256   static const bool valid_functor = false;
00257 
00258   //: rebind this functor to another distribution type
00259   template <class other_dist>
00260   struct rebind {
00261     typedef bsta_diag_covar_functor<other_dist> other;
00262   };
00263 
00264   //: The main function
00265 #if 0
00266   bool operator() (dist_ const& d, return_T& retval) const
00267   {
00268     retval = d.var();
00269     return true;
00270   }
00271 #else
00272   bool operator() (dist_ const&, return_T&) const
00273   {
00274     return false;
00275   }
00276 #endif
00277 };
00278 
00279 
00280 //: A functor to return the variance of the Gaussian
00281 // \note the distribution must be an independent Gaussian
00282 //       the default template does nothing.
00283 //       This solution is really just a hack.
00284 //       The correct solution requires is_base_of from Boost or TR1.
00285 //       This class should work for any derived class of bsta_gaussian_indep
00286 template <class T, unsigned n>
00287 class bsta_diag_covar_functor<bsta_num_obs<bsta_gaussian_indep<T,n> > >
00288 {
00289  public:
00290   typedef bsta_gaussian_indep<T,n> dist_;
00291   typedef typename dist_::vector_type vector_;
00292   typedef vector_ return_T;
00293   typedef return_T return_type; // for compatibility with vpdl/vdpt
00294   enum { return_dim = dist_::dimension };
00295   //: is this functor valid for its distribution type
00296   static const bool valid_functor = true;
00297 
00298   //: rebind this functor to another distribution type
00299   template <class other_dist>
00300   struct rebind {
00301     typedef bsta_diag_covar_functor<other_dist> other;
00302   };
00303 
00304   //: The main function
00305   bool operator() ( const dist_& d, return_T& retval ) const
00306   {
00307     retval = d.diag_covar();
00308     return true;
00309   }
00310 };
00311 
00312 
00313 //: A functor to return the determinant of the covariance of the Gaussian
00314 // \note the distribution must be Gaussian
00315 template <class dist_>
00316 class bsta_det_covar_functor
00317 {
00318  public:
00319   typedef typename dist_::math_type T;
00320   typedef T return_T;
00321   typedef return_T return_type; // for compatibility with vpdl/vdpt
00322   enum { return_dim = 1 };
00323 
00324   //: The main function
00325   bool operator() ( const dist_& d, return_T& retval ) const
00326   {
00327     retval = d.det_covar();
00328     return true;
00329   }
00330 };
00331 
00332 
00333 //: A functor to return the weight of the component with given index
00334 // "Disambiguate" is for compatibility with vpdl/vpdt.
00335 // \note the distribution must be a mixture
00336 template <class mixture_, class Disambiguate=void>
00337 class bsta_weight_functor
00338 {
00339  public:
00340   typedef typename mixture_::math_type T;
00341   typedef T return_T;
00342   typedef return_T return_type; // for compatibility with vpdl/vdpt
00343   enum { return_dim = 1 };
00344   //: is this functor valid for its distribution type
00345   static const bool valid_functor = false;
00346 
00347   //: rebind this functor to another distribution type
00348   template <class other_dist>
00349   struct rebind {
00350     typedef bsta_weight_functor<other_dist> other;
00351   };
00352 
00353   //: Constructor
00354   bsta_weight_functor(unsigned int index = 0) {}
00355 
00356   //: The main function
00357   bool operator() ( const mixture_& mix, return_T& retval ) const
00358   {
00359     return false;
00360   }
00361 };
00362 
00363 
00364 //: A functor to return the weight of the component with given index
00365 // \note the distribution must be a mixture
00366 template <class mixture_>
00367 class bsta_weight_functor<mixture_,
00368           typename vpdt_enable_if<vpdt_is_mixture<mixture_> >::type>
00369 {
00370  public:
00371   typedef typename mixture_::math_type T;
00372   typedef T return_T;
00373   typedef return_T return_type; // for compatibility with vpdl/vdpt
00374   enum { return_dim = 1 };
00375   //: is this functor valid for its distribution type
00376   static const bool valid_functor = true;
00377 
00378   //: rebind this functor to another distribution type
00379   template <class other_dist>
00380   struct rebind {
00381     typedef bsta_weight_functor<other_dist> other;
00382   };
00383 
00384   //: Constructor
00385   bsta_weight_functor(unsigned int index = 0) : idx(index) {}
00386 
00387   //: The main function
00388   bool operator() ( const mixture_& mix, return_T& retval ) const
00389   {
00390     if (idx < mix.num_components()){
00391       retval = mix.weight(idx);
00392       return true;
00393     }
00394     return false;
00395   }
00396 
00397   unsigned int idx;
00398 };
00399 
00400 
00401 //: A vpdt specialization to make the weight functor work as a mixture accessor
00402 // This is needed because weight is not a property of the mixture component,
00403 // it is a property on the mixture itself that is defined for each component.
00404 template <class mixture_>
00405 class vpdt_mixture_accessor<mixture_,
00406           bsta_weight_functor<typename mixture_::component_type>,
00407           typename vpdt_enable_if<vpdt_is_mixture<mixture_> >::type>
00408 {
00409  public:
00410   //: the accessor type
00411   typedef bsta_weight_functor<typename mixture_::component_type> accessor_type;
00412   //: the functor return type
00413   typedef typename vpdt_dist_traits<mixture_>::scalar_type return_type;
00414   //: the distribution operated on by the functor
00415   typedef mixture_ distribution_type;
00416   //: is this functor valid for its distribution type
00417   static const bool valid_functor = true;
00418 
00419   //: rebind this functor to another distribution type
00420   template <class other_dist, class other_accessor = accessor_type>
00421   struct rebind {
00422     typedef vpdt_mixture_accessor<other_dist,other_accessor> other;
00423   };
00424 
00425   //: Constructor
00426   vpdt_mixture_accessor(unsigned int index = 0)
00427   : idx(index) {}
00428 
00429   //: Constructor
00430   vpdt_mixture_accessor(const accessor_type& a, unsigned int index = 0)
00431   : idx(index) {}
00432 
00433   //: The main function
00434   bool operator() ( const mixture_& mix, return_type& retval ) const
00435   {
00436     if (idx < mix.num_components()){
00437       retval = mix.weight(idx);
00438       return true;
00439     }
00440     return false;
00441   }
00442 
00443   //: The component index
00444   unsigned int idx;
00445 };
00446 
00447 
00448 //: A functor to apply another functor to one distribution in the mixture
00449 // \note the distribution must be a mixture
00450 template <class mixture_, class functor_>
00451 class bsta_mixture_functor
00452 {
00453  public:
00454   typedef typename mixture_::math_type T;
00455   typedef typename functor_::return_T return_T;
00456   typedef return_T return_type; // for compatibility with vpdl/vdpt
00457   enum { return_dim = functor_::return_dim };
00458 
00459   //: Constructor
00460   bsta_mixture_functor(const functor_& f, unsigned int index = 0 )
00461   : functor(f), idx(index) {}
00462 
00463   //: The main function
00464   bool operator() ( const mixture_& mix, return_T& retval ) const
00465   {
00466     if (idx < mix.num_components() && mix.weight(idx) > T(0)){
00467       return functor(mix.distribution(idx),retval);
00468     }
00469     return false;
00470   }
00471 
00472   //: The functor to apply
00473   functor_ functor;
00474   //: The index to apply to
00475   unsigned int idx;
00476 };
00477 
00478 
00479 //: A functor to apply another functor with data to one distribution in the mixture
00480 // \note the distribution must be a mixture
00481 template <class mixture_, class functor_>
00482 class bsta_mixture_data_functor
00483 {
00484  public:
00485   typedef typename mixture_::math_type T;
00486   typedef typename functor_::return_T return_T;
00487   typedef return_T return_type; // for compatibility with vpdl/vdpt
00488   typedef typename mixture_::vector_type vector_;
00489   enum { return_dim = functor_::return_dim };
00490 
00491   //: Constructor
00492   bsta_mixture_data_functor(const functor_& f, unsigned int index = 0 )
00493   : functor(f), idx(index) {}
00494 
00495   //: The main function
00496   bool operator() ( const mixture_& mix, const vector_& sample, return_T& retval ) const
00497   {
00498     if (idx < mix.num_components() && mix.weight(idx) > T(0)){
00499       return functor(mix.distribution(idx),sample,retval);
00500     }
00501     return false;
00502   }
00503 
00504   //: The functor to apply
00505   functor_ functor;
00506   //: The index to apply to
00507   unsigned int idx;
00508 };
00509 
00510 
00511 //: A functor to apply another functor to each distribution and produce a weighted sum
00512 // \note the distribution must be a mixture
00513 template <class mixture_, class functor_>
00514 class bsta_weighted_sum_functor
00515 {
00516  public:
00517   typedef typename mixture_::math_type T;
00518   typedef typename functor_::return_T return_T;
00519   typedef return_T return_type; // for compatibility with vpdl/vdpt
00520   enum { return_dim = functor_::return_dim };
00521 
00522   //: Constructor
00523   bsta_weighted_sum_functor() : functor() {}
00524   //: Constructor
00525   bsta_weighted_sum_functor(const functor_& f)
00526   : functor(f) {}
00527 
00528   //: The main function
00529   bool operator() ( const mixture_& mix, return_T& retval ) const
00530   {
00531     const unsigned int nc = mix.num_components();
00532     if (nc > 0) {
00533       return_T temp;
00534       if ( !functor(mix.distribution(0),temp) )
00535         return false;
00536       retval = mix.weight(0) * temp;
00537       for (unsigned int idx=1; idx<nc; ++idx){
00538         if ( !functor(mix.distribution(idx),temp) )
00539           return false;
00540         retval += mix.weight(idx) * temp;
00541       }
00542       return true;
00543     }
00544     return false;
00545   }
00546 
00547   //: The functor to apply
00548   functor_ functor;
00549 };
00550 
00551 
00552 //: A functor to apply another functor with data to each distribution and produce a weighted sum
00553 // \note the distribution must be a mixture
00554 template <class mixture_, class functor_>
00555 class bsta_weighted_sum_data_functor
00556 {
00557  public:
00558   typedef typename mixture_::math_type T;
00559   typedef typename functor_::return_T return_T;
00560   typedef return_T return_type; // for compatibility with vpdl/vdpt
00561   typedef typename mixture_::vector_type vector_;
00562   enum { return_dim = functor_::return_dim };
00563 
00564   //: Constructor
00565   bsta_weighted_sum_data_functor() : functor() {}
00566   //: Constructor
00567   bsta_weighted_sum_data_functor(const functor_& f)
00568   : functor(f) {}
00569 
00570   //: The main function
00571   bool operator() ( const mixture_& mix, const vector_& sample, return_T& retval ) const
00572   {
00573     const unsigned int nc = mix.num_components();
00574     if (nc > 0)
00575     {
00576       return_T temp;
00577       if ( !functor(mix.distribution(0),sample,temp) )
00578         return false;
00579       retval = mix.weight(0) * temp;
00580       for (unsigned int idx=1; idx<nc; ++idx){
00581         if ( !functor(mix.distribution(idx),sample,temp) )
00582           return false;
00583         retval += mix.weight(idx) * temp;
00584       }
00585       return true;
00586     }
00587     return false;
00588   }
00589 
00590   //: The functor to apply
00591   functor_ functor;
00592 };
00593 
00594 
00595 //: A functor to count the number of components in the mixture
00596 // \note the distribution must be a mixture
00597 template <class mixture_>
00598 class bsta_mixture_size_functor
00599 {
00600  public:
00601   typedef typename mixture_::math_type T;
00602   typedef unsigned int return_T;
00603   typedef return_T return_type; // for compatibility with vpdl/vdpt
00604   enum { return_dim = 1 };
00605 
00606   //: The main function
00607   bool operator() ( const mixture_& mix, return_T& retval ) const
00608   {
00609     retval = mix.num_components();
00610     return true;
00611   }
00612 };
00613 
00614 
00615 #endif // bsta_basic_functors_h_