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