IT++ Logo
mog_generic.cpp
Go to the documentation of this file.
1 
29 #include <itpp/stat/mog_generic.h>
30 #include <itpp/base/algebra/inv.h>
31 #include <itpp/base/algebra/det.h>
32 #include <itpp/base/matfunc.h>
33 #include <itpp/base/itfile.h>
34 #include <itpp/base/itcompat.h>
35 #include <itpp/base/math/misc.h>
36 #include <itpp/base/math/log_exp.h>
37 
38 
39 namespace itpp
40 {
41 
42 
44 
45 
46 void MOG_generic::init(const int &K_in, const int &D_in, bool full_in)
47 {
48  valid = false;
49 
50  it_assert(K_in >= 0, "MOG_generic::init(): number of Gaussians must be greater than zero");
51  it_assert(D_in >= 0, "MOG_generic::init(): dimensionality must be greater than zero");
52 
53  K = K_in;
54  D = D_in;
55  full = full_in;
56 
60  setup_misc();
61 
62  valid = true;
63  do_checks = true;
64  paranoid = false;
65 
66 }
67 
68 
69 void MOG_generic::init(Array<vec> &means_in, bool full_in)
70 {
71  valid = false;
72 
73  K = means_in.size();
74  D = means_in(0).size();
75  full = full_in;
76 
77  it_assert(check_array_uniformity(means_in), "MOG_generic::init(): 'means' is empty or contains vectors of varying dimensionality");
78  set_means(means_in);
81  setup_misc();
82 
83  valid = true;
84  do_checks = true;
85  paranoid = false;
86 }
87 
88 
89 void MOG_generic::init(Array<vec> &means_in, Array<vec> &diag_covs_in, vec &weights_in)
90 {
91  valid = false;
92 
93  K = means_in.size();
94  D = means_in(0).size();
95  full = false;
96 
97  it_assert(check_array_uniformity(means_in), "MOG_generic::init(): 'means' is empty or contains vectors of varying dimensionality");
98 
99  set_means_internal(means_in);
100  set_diag_covs_internal(diag_covs_in);
101  set_weights_internal(weights_in);
102  setup_misc();
103 
104  valid = true;
105  do_checks = true;
106  paranoid = false;
107 }
108 
109 
110 void MOG_generic::init(Array<vec> &means_in, Array<mat> &full_covs_in, vec &weights_in)
111 {
112  valid = false;
113 
114  K = means_in.size();
115  D = means_in(0).size();
116  full = true;
117 
118  it_assert(check_array_uniformity(means_in), "MOG_generic::init(): 'means' is empty or contains vectors of varying dimensionality");
119  set_means_internal(means_in);
120  set_full_covs_internal(full_covs_in);
121  set_weights_internal(weights_in);
122  setup_misc();
123 
124  valid = true;
125  do_checks = true;
126  paranoid = false;
127 }
128 
129 
130 bool MOG_generic::check_size(const vec &x_in) const
131 {
132  if (x_in.size() == D) return true;
133  return false;
134 }
135 
136 
137 bool MOG_generic::check_size(const Array<vec> &X_in) const
138 {
139  if (check_array_uniformity(X_in)) return check_size(X_in(0));
140  return false;
141 }
142 
143 
145 {
146  int rows = A.size();
147  int cols = A(0).size();
148 
149  if (!rows || !cols) return false;
150 
151  for (int row = 1; row < rows; row++) if (A(row).size() != cols) return false;
152  return true;
153 }
154 
155 
157 {
158  means.set_size(K);
159  for (int k = 0; k < K; k++) { means(k).set_size(D); means(k) = 0.0; }
160  setup_means();
161 }
162 
163 
165 {
166  it_assert((means_in.size() == K), "MOG_generic::set_means_internal(): number of vectors in 'means' is not equivalent to number of Gaussians");
167 
168  for (int k = 0; k < K; k++)
169  it_assert((means_in(k).size() == D), "MOG_generic::set_means_internal(): dimensionality mismatch between model and one or more vectors in 'means'");
170 
171  for (int k = 0; k < K; k++)
172  for (int d = 0; d < D; d++)
173  it_assert(std::isfinite(means_in(k)(d)), "MOG_generic::set_means_internal(): 'means' has a non-finite value");
174 
175  means = means_in;
176  setup_means();
177 }
178 
179 
181 {
182  it_assert((diag_covs_in.size() == K), "MOG_generic::set_diag_covs_internal(): number of vectors in 'diag_covs' does not match number of Gaussians");
183 
184  for (int k = 0; k < K; k++)
185  it_assert((diag_covs_in(k).size() == D), "MOG_generic::set_diag_covs_internal(): dimensionality mismatch between model and one or more vectors in 'diag_covs'");
186 
187  for (int k = 0; k < K; k++)
188  for (int d = 0; d < D; d++) {
189  it_assert((diag_covs_in(k)(d) > 0.0), "MOG_generic::set_diag_covs_internal(): 'diag_covs' has a zero or negative value");
190  it_assert(std::isfinite(diag_covs_in(k)(d)), "MOG_generic::set_diag_covs_internal(): 'diag_covs' has a non-finite value");
191  }
192 
193  full_covs.set_size(0);
194  diag_covs = diag_covs_in;
195  full = false;
196  setup_covs();
197 }
198 
199 
201 {
202  it_assert((full_covs_in.size() == K), "MOG_generic::set_full_covs_internal(): number of matrices in 'full_covs' does not match number of Gaussians");
203 
204  for (int k = 0; k < K; k++)
205  it_assert(((full_covs_in(k).rows() == D) && (full_covs_in(k).cols() == D)), "MOG_generic::set_full_covs_internal(): dimensionality mismatch between model and one or more matrices in 'full_covs'");
206 
207  for (int k = 0; k < K; k++)
208  for (int i = 0; i < D; i++)
209  for (int j = 0; j < D; j++) {
210  it_assert(std::isfinite(full_covs_in(k)(i, j)), "MOG_generic::set_full_covs_internal(): 'full_covs' has a non-finite value");
211  if (i == j) {
212  it_assert(full_covs_in(k)(i, j) > 0.0,
213  "MOG_generic::set_full_covs_internal(): 'full_covs' has "
214  "a zero or negative value on a diagonal");
215  }
216  }
217 
218  full_covs = full_covs_in;
219  diag_covs.set_size(0);
220  full = true;
221  setup_covs();
222 }
223 
224 
226 {
227 
228  it_assert((weights_in.size() == K), "MOG_generic::set_weights_internal(): number of elements in 'weights' does not match number of Gaussians");
229 
230  for (int k = 0; k < K; k++) {
231  it_assert((weights_in(k) >= 0), "MOG_generic::set_weights_internal(): 'weights' has a negative value");
232  it_assert(std::isfinite(weights_in(k)), "MOG_generic::set_weights_internal(): 'weights' has a non-finite value");
233  }
234 
235  weights = weights_in;
236  setup_weights();
237 
238 }
239 
240 
242 {
243  full_covs.set_size(0);
245 
246  for (int k = 0; k < K; k++) { diag_covs(k).set_size(D); diag_covs(k) = 1.0; }
247 
248  full = false;
249  setup_covs();
250 }
251 
252 
254 {
256  diag_covs.set_size(0);
257 
258  for (int k = 0; k < K; k++) {
259  full_covs(k).set_size(D, D);
260  full_covs(k) = 0.0;
261  for (int d = 0;d < D;d++) full_covs(k)(d, d) = 1.0;
262  }
263 
264  full = true;
265  setup_covs();
266 }
267 
268 
270 {
271  weights.set_size(K);
272  weights = 1.0 / K;
273  setup_weights();
274 }
275 
276 
278 
280 {
281 
282  double Ddiv2_log_2pi = D / 2.0 * std::log(m_2pi);
283  log_det_etc.set_size(K);
284 
285  if (full) {
288  for (int k = 0;k < K;k++) full_covs_inv(k) = inv(full_covs(k));
289  for (int k = 0;k < K;k++) log_det_etc(k) = -Ddiv2_log_2pi - 0.5 * std::log(det(full_covs(k)));
290  }
291  else {
294  for (int k = 0;k < K;k++) diag_covs_inv_etc(k).set_size(D);
295 
296  for (int k = 0;k < K;k++) {
297  double acc = 0.0;
298  vec & diag_cov = diag_covs(k);
299  vec & diag_cov_inv_etc = diag_covs_inv_etc(k);
300 
301  for (int d = 0;d < D;d++) {
302  double tmp = diag_cov(d);
303  diag_cov_inv_etc(d) = 1.0 / (2.0 * tmp);
304  acc += std::log(tmp);
305  }
306 
307  log_det_etc(k) = -Ddiv2_log_2pi - 0.5 * acc;
308 
309  }
310  }
311 }
312 
313 
315 {
316  weights /= sum(weights);
318 }
319 
320 
322 {
324  tmpvecD.set_size(D);
325  tmpvecK.set_size(K);
326 }
327 
328 
330 {
331 
332  valid = false;
333  do_checks = true;
334  K = 0;
335  D = 0;
336 
337  tmpvecD.set_size(0);
338  tmpvecK.set_size(0);
339  means.set_size(0);
340  diag_covs.set_size(0);
341  full_covs.set_size(0);
342  weights.set_size(0);
343  log_det_etc.set_size(0);
344  log_weights.set_size(0);
347 
348 }
349 
350 
352 {
353  if (!valid) return;
354  set_means_internal(means_in);
355 }
356 
357 
359 {
360  if (!valid) return;
362 }
363 
364 
366 {
367  if (!valid) return;
368  set_diag_covs_internal(diag_covs_in);
369 }
370 
371 
373 {
374  if (!valid) return;
375  set_full_covs_internal(full_covs_in);
376 }
377 
378 
379 void MOG_generic::set_weights(vec &weights_in)
380 {
381  if (!valid) return;
382  set_weights_internal(weights_in);
383 }
384 
385 
387 {
388  if (!valid) return;
390 }
391 
392 
394 {
395  if (!valid) return;
397 }
398 
399 
401 {
402  if (!valid) return;
404 }
405 
406 
407 void MOG_generic::load(const std::string &name_in)
408 {
409  valid = false;
410 
411  it_assert(exist(name_in), "MOG_generic::load(): couldn't access file '" + name_in + "'");
412  it_file ff(name_in);
413 
414  bool contents = ff.exists("means") && (ff.exists("diag_covs") || ff.exists("full_covs")) && ff.exists("weights");
415  it_assert(contents, "MOG_generic::load(): file '" + name_in + "' doesn't appear to be a model file");
416 
417  Array<vec> means_in;
418  ff >> Name("means") >> means_in;
419  vec weights_in;
420  ff >> Name("weights") >> weights_in;
421 
422  if (ff.exists("full_covs")) {
423  Array<mat> full_covs_in;
424  ff >> Name("full_covs") >> full_covs_in;
425  init(means_in, full_covs_in, weights_in);
426  }
427  else {
428  Array<vec> diag_covs_in;
429  ff >> Name("diag_covs") >> diag_covs_in;
430  init(means_in, diag_covs_in, weights_in);
431  }
432 
433  ff.close();
434 
435 }
436 
437 
438 void MOG_generic::save(const std::string &name_in) const
439 {
440  if (!valid) return;
441 
442  it_file ff(name_in);
443 
444  ff << Name("means") << means;
445  if (full) ff << Name("full_covs") << full_covs;
446  else ff << Name("diag_covs") << diag_covs;
447  ff << Name("weights") << weights;
448 
449  ff.close();
450 
451 }
452 
454 {
455 
456  if (!valid) return;
457  if (!B_in.is_valid()) return;
458 
459  it_assert((full == B_in.is_full()), "MOG_generic::join(): given model must be of the same type");
460  it_assert((B_in.get_D() == D), "MOG_generic::join(): given model has different dimensionality");
461  it_assert((B_in.get_K() > 0), "MOG_generic::join(): given model has no components");
462 
463  int new_K = K + B_in.get_K();
464  vec new_weights(new_K);
465  vec B_in_weights = B_in.get_weights();
466 
467  double alpha = double(K) / double(new_K);
468  double beta = double(B_in.get_K()) / double(new_K);
469 
470  for (int k = 0;k < K;k++) new_weights(k) = alpha * weights(k);
471  for (int k = K;k < new_K;k++) new_weights(k) = beta * B_in_weights(k);
472 
473  Array<vec> new_means = concat(means, B_in.get_means());
474 
475  if (full) {
476  Array<mat> new_full_covs = concat(full_covs, B_in.get_full_covs());
477  init(new_means, new_full_covs, new_weights);
478  }
479  else {
480  Array<vec> new_diag_covs = concat(diag_covs, B_in.get_diag_covs());
481  init(new_means, new_diag_covs, new_weights);
482  }
483 }
484 
485 
487 {
488  if (!full) return;
489 
491  for (int k = 0;k < K;k++) diag_covs(k) = diag(full_covs(k));
492  full_covs.set_size(0);
493 
494  full = false;
495  setup_covs();
496 }
497 
498 
500 {
501  if (!valid) return;
503 }
504 
505 
507 {
508  if (full) return;
509 
511  for (int k = 0;k < K;k++) full_covs(k) = diag(diag_covs(k));
512  diag_covs.set_size(0);
513 
514  full = true;
515  setup_covs();
516 }
517 
519 {
520  if (!valid) return;
522 }
523 
524 
525 
526 double MOG_generic::log_lhood_single_gaus_internal(const vec &x_in, const int k)
527 {
528 
529  const vec & mean = means(k);
530 
531  if (full) {
532  for (int d = 0;d < D;d++) tmpvecD[d] = x_in[d] - mean[d];
533  double tmpval = tmpvecD * (full_covs_inv(k) * tmpvecD);
534  return(log_det_etc[k] - 0.5*tmpval);
535  }
536  else {
537  const vec & diag_cov_inv_etc = diag_covs_inv_etc(k);
538 
539  double acc = 0.0;
540 
541  for (int d = 0; d < D; d++) {
542  double tmpval = x_in[d] - mean[d];
543  acc += (tmpval * tmpval) * diag_cov_inv_etc[d];
544  }
545  return(log_det_etc[k] - acc);
546  }
547 
548 }
549 
550 double MOG_generic::log_lhood_single_gaus(const vec &x_in, const int k)
551 {
552  if (do_checks) {
553  it_assert(valid, "MOG_generic::log_lhood_single_gaus(): model not valid");
554  it_assert(check_size(x_in), "MOG_generic::log_lhood_single_gaus(): x has wrong dimensionality");
555  it_assert(((k >= 0) && (k < K)), "MOG_generic::log_lhood_single_gaus(): k specifies a non-existant Gaussian");
556  }
557  return log_lhood_single_gaus_internal(x_in, k);
558 }
559 
560 
561 double MOG_generic::log_lhood_internal(const vec &x_in)
562 {
563 
564  bool danger = paranoid;
565 
566  for (int k = 0;k < K;k++) {
567  double tmp = log_weights[k] + log_lhood_single_gaus_internal(x_in, k);
568  tmpvecK[k] = tmp;
569 
570  if (tmp >= log_max_K) danger = true;
571  }
572 
573  if (danger) {
574  double log_sum = tmpvecK[0];
575  for (int k = 1; k < K; k++) log_sum = log_add(log_sum, tmpvecK[k]);
576  return(log_sum);
577  }
578  else {
579  double sum = 0.0;
580  for (int k = 0;k < K;k++) sum += std::exp(tmpvecK[k]);
581  return(std::log(sum));
582  }
583 }
584 
585 
586 double MOG_generic::log_lhood(const vec &x_in)
587 {
588  if (do_checks) {
589  it_assert(valid, "MOG_generic::log_lhood(): model not valid");
590  it_assert(check_size(x_in), "MOG_generic::log_lhood(): x has wrong dimensionality");
591  }
592  return log_lhood_internal(x_in);
593 }
594 
595 
596 double MOG_generic::lhood_internal(const vec &x_in)
597 {
598 
599  bool danger = paranoid;
600 
601  for (int k = 0;k < K;k++) {
602  double tmp = log_weights[k] + log_lhood_single_gaus_internal(x_in, k);
603  tmpvecK[k] = tmp;
604 
605  if (tmp >= log_max_K) danger = true;
606  }
607 
608  if (danger) {
609  double log_sum = tmpvecK[0];
610  for (int k = 1; k < K; k++) log_sum = log_add(log_sum, tmpvecK[k]);
611  return(trunc_exp(log_sum));
612  }
613  else {
614  double sum = 0.0;
615  for (int k = 0;k < K;k++) sum += std::exp(tmpvecK[k]);
616  return(sum);
617  }
618 }
619 
620 
621 double MOG_generic::lhood(const vec &x_in)
622 {
623 
624  if (do_checks) {
625  it_assert(valid, "MOG_generic::lhood(): model not valid");
626  it_assert(check_size(x_in), "MOG_generic::lhood(): x has wrong dimensionality");
627  }
628  return lhood_internal(x_in);
629 }
630 
631 
633 {
634  if (do_checks) {
635  it_assert(valid, "MOG_generic::avg_log_lhood(): model not valid");
636  it_assert(check_size(X_in), "MOG_generic::avg_log_lhood(): X is empty or at least one vector has the wrong dimensionality");
637  }
638 
639  const int N = X_in.size();
640  double acc = 0.0;
641  for (int n = 0;n < N;n++) acc += log_lhood_internal(X_in(n));
642  return(acc / N);
643 }
644 
645 
646 
647 } // namespace itpp
SourceForge Logo

Generated on Sat Jul 6 2013 10:54:25 for IT++ by Doxygen 1.8.2