vpdt_mixture_of.h
Go to the documentation of this file.
1 // This is core/vpdl/vpdt/vpdt_mixture_of.h
2 #ifndef vpdt_mixture_of_h_
3 #define vpdt_mixture_of_h_
4 //:
5 // \file
6 // \author Matthew Leotta
7 // \date February 24, 2009
8 // \brief A mixture of a fixed type of distributions
9 //
10 // \verbatim
11 // Modifications
12 // None
13 // \endverbatim
14 
15 #include <vector>
16 #include <algorithm>
17 #include <iostream>
18 #include <memory>
19 #ifdef _MSC_VER
20 # include <vcl_msvc_warnings.h>
21 #endif
24 #include <cassert>
25 
26 // forward declarations
27 template<class dist_t> class vpdt_mixture_of;
28 
29 template <class dist>
30 typename vpdt_dist_traits<vpdt_mixture_of<dist> >::scalar_type
32  const typename vpdt_dist_traits<vpdt_mixture_of<dist> >::field_type& min_pt,
33  const typename vpdt_dist_traits<vpdt_mixture_of<dist> >::field_type& max_pt);
34 
35 
36 template <class dist>
38 {
39  static const bool value = true;
40 };
41 
42 
43 //: A mixture of a fixed type of distributions
44 // A mixture is a weighted linear combination of other mixtures.
45 // This class represents a mixture of a specific type of distribution.
46 // Each component in the mixture has its own weight and parameters,
47 // but each must be of the same type.
48 // \tparam dist_t is the type of a component distribution
49 // \sa vpdl_mixture
50 template<class dist_t>
51 class vpdt_mixture_of
52 {
53  public:
54  //: the data type to represent a point in the field
55  typedef typename dist_t::field_type field_type;
56  //: define the component type
57  typedef dist_t component_type;
58 
59  //: define the fixed dimension (normally specified by template parameter n)
60  static const unsigned int n = vpdt_field_traits<field_type>::dimension;
61  //: the data type to represent a point in the field
62  typedef typename dist_t::field_type F;
63  //: define the scalar type (normally specified by template parameter T)
65  //: define the vector type
67  //: the data type used for matrices
69 
70  private:
71  //: A struct to hold the component distributions and weights
72  // This class is private and should not be used outside of the mixture.
73  struct component
74  {
75  //: Constructor
77  //: Constructor
78  component(const component_type& d, const T& w = T(0) )
79  : distribution(d), weight(w) {}
80 
81  //: Used to sort by decreasing weight
82  bool operator< (const component& rhs) const
83  { return this->weight > rhs.weight; }
84 
85  // ============ Data =============
86 
87  //: The distribution
89  //: The weight
91  };
92 
93  //: This functor is used by default for sorting with STL
94  // The default sorting is decreasing by weight
96  {
97  public:
98  bool operator() (const component* c1, const component* c2) const
99  { return c1->weight > c2->weight; }
100  };
101 
102  //: This adaptor allows users to define ordering functors on the components without accessing the components directly
103  template <class comp_type_>
105  {
106  public:
107  sort_adaptor(comp_type_ c) : comp(c) {}
108  bool operator() (const component* const c1, const component* const c2) const
109  { return comp(c1->distribution, c1->weight, c2->distribution, c2->weight); }
110  comp_type_ comp;
111  };
112 
113  //: The vector of components
114  std::vector<component*> components_;
115 
116  public:
117  // Default Constructor
119 
120  // Copy Constructor
122  : components_(other.components_.size(),nullptr)
123  {
124  // deep copy of the data
125  for (unsigned int i=0; i<components_.size(); ++i) {
126  components_[i] = new component(*other.components_[i]);
127  }
128  }
129 
130  // Destructor
132  {
133  for (unsigned int i=0; i<components_.size(); ++i) {
134  delete components_[i];
135  }
136  }
137 
138  //: Assignment operator
140  {
141  if (this != &rhs) {
142  for (unsigned int i=0; i<components_.size(); ++i) {
143  delete components_[i];
144  }
145  components_.clear();
146  for (unsigned int i=0; i<rhs.components_.size(); ++i) {
147  components_.push_back(new component(*rhs.components_[i]));
148  }
149  }
150  return *this;
151  }
152 
153  //: Return the run time dimension, which does not equal \c n when \c n==0
154  unsigned int dimension() const
155  {
156  if (n > 0 || num_components() == 0)
157  return n;
158  return components_[0]->distribution.dimension();
159  }
160 
161  //: Return the number of components in the mixture
162  unsigned int num_components() const { return components_.size(); }
163 
164  //: Access (const) a component distribution of the mixture
165  const dist_t& distribution(unsigned int index) const
166  {
167  assert(index < num_components());
168  return components_[index]->distribution;
169  }
170 
171  //: Access a component distribution of the mixture
172  dist_t& distribution(unsigned int index)
173  {
174  assert(index < num_components());
175  return components_[index]->distribution;
176  }
177 
178  //: Return the weight of a component in the mixture
179  T weight(unsigned int index) const
180  {
181  assert(index < num_components());
182  return components_[index]->weight;
183  }
184 
185  //: Set the weight of a component in the mixture
186  void set_weight(unsigned int index, const T& w)
187  {
188  assert(index < num_components());
189  assert(w >= T(0));
190  components_[index]->weight = w;
191  }
192 
193  //: Insert a new component at the end of the vector
194  bool insert(const dist_t& d, const T& wght = T(0))
195  {
196  assert(d.dimension() == this->dimension() || num_components() == 0);
197  components_.push_back(new component(d, wght));
198  return true;
199  }
200 
201  //: Remove the last component in the vector
202  bool remove_last()
203  {
204  if (components_.empty())
205  return false;
206  delete components_.back();
207  components_.pop_back();
208  return true;
209  }
210 
211  //: Compute the unnormalized density at this point
212  T density(const F& pt) const
213  {
214  typedef typename std::vector<component*>::const_iterator comp_itr;
215  T prob = 0;
216  for (comp_itr i = components_.begin(); i != components_.end(); ++i) {
217  // must use prob_density here to get meaningful results
218  prob += (*i)->weight * (*i)->distribution.prob_density(pt);
219  }
220  return prob;
221  }
222 
223  //: Compute the gradient of the unnormalized density at a point
224  // \return the density at \a pt since it is usually needed as well, and
225  // is often trivial to compute while computing gradient
226  // \retval g the gradient vector
227  T gradient_density(const F& pt, vector& g) const
228  {
229  const unsigned int d = this->dimension();
230  vpdt_set_size(g,d);
231  vpdt_fill(g,T(0));
232  typedef typename std::vector<component*>::const_iterator comp_itr;
233  T dens = 0;
234  for (comp_itr i = components_.begin(); i != components_.end(); ++i) {
235  vector g_i;
236  T w_i = (*i)->distribution.norm_const() * (*i)->weight;
237  dens += w_i * (*i)->distribution.gradient_density(pt,g_i);
238  g_i *= w_i;
239  g += g_i;
240  }
241  return dens;
242  }
243 
244  //: Evaluate the cumulative distribution function at a point
245  // This is the integral of the density function from negative infinity
246  // (in all dimensions) to the point in question
247  T cumulative_prob(const F& pt) const
248  {
249  typedef typename std::vector<component*>::const_iterator comp_itr;
250  T prob = 0;
251  T sum_w = 0;
252  for (comp_itr i = components_.begin(); i != components_.end(); ++i) {
253  prob += (*i)->weight * (*i)->distribution.cumulative_prob(pt);
254  sum_w += (*i)->weight;
255  }
256  assert(sum_w > T(0));
257  return prob/sum_w;
258  }
259 
260  //: Compute the mean of the distribution.
261  // weighted average of the component means
262  void compute_mean(F& mean) const
263  {
264  const unsigned int d = this->dimension();
265  vpdt_set_size(mean,d);
266  vpdt_fill(mean,T(0));
267 
268  typedef typename std::vector<component*>::const_iterator comp_itr;
269  F cmp_mean;
270  T sum_w = T(0);
271  for (comp_itr i = components_.begin(); i != components_.end(); ++i) {
272  (*i)->distribution.compute_mean(cmp_mean);
273  cmp_mean *= (*i)->weight;
274  sum_w += (*i)->weight;
275  mean += cmp_mean;
276  }
277  assert(sum_w > 0);
278  mean /= sum_w;
279  }
280 
281  //: Compute the covariance of the distribution.
282  void compute_covar(matrix& covar) const
283  {
284  const unsigned int d = this->dimension();
285  F mean;
286  vpdt_set_size(covar,d);
287  vpdt_fill(covar,T(0));
288  vpdt_set_size(mean,d);
289  vpdt_fill(mean,T(0));
290 
291  typedef typename std::vector<component*>::const_iterator comp_itr;
292  F cmp_mean;
293  matrix cmp_covar;
294  T sum_w = T(0);
295  for (comp_itr i = components_.begin(); i != components_.end(); ++i) {
296  const T& wgt = (*i)->weight;
297  (*i)->distribution.compute_covar(cmp_covar);
298  (*i)->distribution.compute_mean(cmp_mean);
299  cmp_covar += outer_product(cmp_mean,cmp_mean);
300  cmp_covar *= wgt;
301  cmp_mean *= wgt;
302  sum_w += wgt;
303  covar += cmp_covar;
304  mean += cmp_mean;
305  }
306  assert(sum_w > 0);
307  covar -= outer_product(mean,mean);
308  covar /= sum_w;
309  }
310 
311  //: The normalization constant for the density
312  // When density() is multiplied by this value it becomes prob_density
313  // norm_const() is reciprocal of the integral of density over the entire field
314  T norm_const() const
315  {
316  typedef typename std::vector<component*>::const_iterator comp_itr;
317  T sum = 0;
318  for (comp_itr i = components_.begin(); i != components_.end(); ++i)
319  sum += (*i)->weight;
320  assert(sum > 0);
321  return 1/sum;
322  }
323 
324  //: Normalize the weights of the components to add to 1.
326  {
327  typedef typename std::vector<component*>::iterator comp_itr;
328  T norm = norm_const();
329  for (comp_itr i = components_.begin(); i != components_.end(); ++i)
330  (*i)->weight *= norm;
331  }
332 
333  //: Sort the components in order of decreasing weight
334  void sort() { std::sort(components_.begin(), components_.end(), sort_weight() ); }
335 
336  //: Sort the components in the range \a idx1 to \a idx2 in order of decreasing weight
337  void sort(unsigned int idx1, unsigned int idx2)
338  { std::sort(components_.begin()+idx1, components_.begin()+idx2+1, sort_weight() ); }
339 
340  //: Sort the components using any StrictWeakOrdering function
341  // The prototype should be
342  // \code
343  // template <class dist_t>
344  // bool functor(const dist_t& d1, const vpdt_dist_traits<dist_t>::scalar_type& w1,
345  // const dist_t& d2, const vpdt_dist_traits<dist_t>::scalar_type& w2);
346  // \endcode
347  template <class comp_type_>
348  void sort(comp_type_ comp)
349  { std::sort(components_.begin(), components_.end(), sort_adaptor<comp_type_>(comp)); }
350 
351  //: Sort the components in the range \a idx1 to \a idx2 using any StrictWeakOrdering function
352  template <class comp_type_>
353  void sort(comp_type_ comp, unsigned int idx1, unsigned int idx2)
354  { std::sort(components_.begin()+idx1, components_.begin()+idx2+1, sort_adaptor<comp_type_>(comp)); }
355 
356  friend T vpdt_box_prob<dist_t>(const vpdt_mixture_of<dist_t>& d, const F& min_pt, const F& max_pt);
357 };
358 
359 
360 //: The probability of being in an axis-aligned box.
361 // The box is defined by two points, the minimum and maximum.
362 // Implemented in terms of \c vpdt_cumulative_prob() by default.
363 template <class dist>
364 typename vpdt_dist_traits<vpdt_mixture_of<dist> >::scalar_type
366  const typename vpdt_dist_traits<vpdt_mixture_of<dist> >::field_type& min_pt,
367  const typename vpdt_dist_traits<vpdt_mixture_of<dist> >::field_type& max_pt)
368 {
369  typedef typename vpdt_dist_traits<vpdt_mixture_of<dist> >::scalar_type T;
370  typedef typename std::vector<typename vpdt_mixture_of<dist>::component*>::const_iterator comp_itr;
371  T prob = 0;
372  T sum_w = 0;
373  for (comp_itr i = d.components_.begin(); i != d.components_.end(); ++i) {
374  prob += (*i)->weight * vpdt_box_prob((*i)->distribution,min_pt,max_pt);
375  sum_w += (*i)->weight;
376  }
377  assert(sum_w > T(0));
378  return prob/sum_w;
379 }
380 
381 
382 #endif // vpdt_mixture_of_h_
dist_t::field_type F
the data type to represent a point in the field.
bool insert(const dist_t &d, const T &wght=T(0))
Insert a new component at the end of the vector.
unsigned int dimension() const
Return the run time dimension, which does not equal n when n==0.
T norm_const() const
The normalization constant for the density.
The distribution traits class.
void set_weight(unsigned int index, const T &w)
Set the weight of a component in the mixture.
T gradient_density(const F &pt, vector &g) const
Compute the gradient of the unnormalized density at a point.
bool operator<(const component &rhs) const
Used to sort by decreasing weight.
A mixture of a fixed type of distributions.
T weight(unsigned int index) const
Return the weight of a component in the mixture.
This adaptor allows users to define ordering functors on the components without accessing the compone...
T cumulative_prob(const F &pt) const
Evaluate the cumulative distribution function at a point.
vpdt_field_traits< field_type >::scalar_type T
define the scalar type (normally specified by template parameter T).
The basic functions for probability calculations.
void normalize_weights()
Normalize the weights of the components to add to 1.
bool remove_last()
Remove the last component in the vector.
void compute_mean(F &mean) const
Compute the mean of the distribution.
void compute_covar(matrix &covar) const
Compute the covariance of the distribution.
void sort(comp_type_ comp)
Sort the components using any StrictWeakOrdering function.
static const bool value
component(const component_type &d, const T &w=T(0))
Constructor.
dist_t & distribution(unsigned int index)
Access a component distribution of the mixture.
vpdt_field_traits< field_type >::vector_type vector
define the vector type.
dist_t component_type
define the component type.
void sort()
Sort the components in order of decreasing weight.
vpdt_mixture_of< dist_t > & operator=(const vpdt_mixture_of< dist_t > &rhs)
Assignment operator.
void vpdt_set_size(vnl_vector< T > &v, unsigned int s)
Set the size of a vnl_vector.
Definition: vpdt_access.h:63
The field traits class (scalar).
bool operator()(const component *const c1, const component *const c2) const
vpdt_field_traits< field_type >::matrix_type matrix
the data type used for matrices.
This functor is used by default for sorting with STL.
static const unsigned int n
define the fixed dimension (normally specified by template parameter n).
void sort(unsigned int idx1, unsigned int idx2)
Sort the components in the range idx1 to idx2 in order of decreasing weight.
vpdt_mixture_of(const vpdt_mixture_of< dist_t > &other)
specialized template trait classes for properties of a distribution type
dist_t::field_type field_type
the data type to represent a point in the field.
void sort(comp_type_ comp, unsigned int idx1, unsigned int idx2)
Sort the components in the range idx1 to idx2 using any StrictWeakOrdering function.
A struct to hold the component distributions and weights.
component_type distribution
The distribution.
void vpdt_fill(vnl_vector< T > &v, const T &val)
Fill a vnl_vector.
Definition: vpdt_access.h:78
const dist_t & distribution(unsigned int index) const
Access (const) a component distribution of the mixture.
bool operator()(const component *c1, const component *c2) const
T density(const F &pt) const
Compute the unnormalized density at this point.
vpdt_dist_traits< vpdt_mixture_of< dist > >::scalar_type vpdt_box_prob(const vpdt_mixture_of< dist > &d, const typename vpdt_dist_traits< vpdt_mixture_of< dist > >::field_type &min_pt, const typename vpdt_dist_traits< vpdt_mixture_of< dist > >::field_type &max_pt)
The probability of being in an axis-aligned box.
std::vector< component * > components_
The vector of components.
unsigned int num_components() const
Return the number of components in the mixture.
float outer_product(const float &v1, const float &v2)
vnl defines outer_product for vectors but not scalars.
Definition: vpdt_access.h:149