IT++ Logo
mog_generic.cpp
Go to the documentation of this file.
1
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>
37
38
39namespace itpp
40{
41
42
44
45
46void 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
69void 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
89void 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
110void 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
130bool MOG_generic::check_size(const vec &x_in) const
131{
132 if (x_in.size() == D) return true;
133 return false;
134}
135
136
137bool 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{
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
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;
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;
237
238}
239
240
242{
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{
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;
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
319
320
322{
323 log_max_K = std::log(std::numeric_limits<double>::max() / K);
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);
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
379void MOG_generic::set_weights(vec &weights_in)
380{
381 if (!valid) return;
382 set_weights_internal(weights_in);
383}
384
385
391
392
398
399
405
406
407void 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
438void 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));
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));
513
514 full = true;
515 setup_covs();
516}
517
519{
520 if (!valid) return;
522}
523
524
525
526double 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
550double 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
561double 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
586double 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
596double 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
621double 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
General array class.
Definition factory.h:40
int size() const
Returns the number of data elements in the array object.
Definition array.h:155
void set_size(int n, bool copy=false)
Resizing an Array<T>.
Definition array.h:257
Generic Mixture of Gaussians (MOG) class. Used as a base for other MOG classes.
Definition mog_generic.h:58
virtual double lhood(const vec &x_in)
calculate the likelihood of vector x_in
void set_diag_covs_unity()
Set the diagonal covariance vectors to be unity.
void convert_to_diag_internal()
ADD DOCUMENTATION HERE.
void set_weights_uniform()
Set all the weights to 1/K, where K is the number of Gaussians.
Array< mat > full_covs_inv
Pre-calcuated inverted version of each full covariance matrix.
virtual void setup_weights()
additional processing of the weight vector, done as the last step of weight initialisation
void set_diag_covs_internal(Array< vec > &diag_covs_in)
ADD DOCUMENTATION HERE.
bool check_size(const vec &x_in) const
Check if vector x_in has the same dimensionality as the model.
Array< mat > full_covs
full covariance matrices
void set_weights_uniform_internal()
ADD DOCUMENTATION HERE.
virtual void cleanup()
Release memory used by the model. The model will be empty.
void set_full_covs_unity()
Set the full covariance matrices to be unity.
int get_K() const
Return the number of Gaussians.
bool check_array_uniformity(const Array< vec > &A) const
Check if all vectors in Array X_in have the same dimensionality.
void init()
Initialise the model to be empty.
Array< vec > get_means() const
Obtain a copy of the array of mean vectors.
virtual void convert_to_diag()
Convert the model to use diagonal covariances.
void set_weights_internal(vec &_weigths)
ADD DOCUMENTATION HERE.
virtual double avg_log_lhood(const Array< vec > &X_in)
calculate the average log likelihood of an array of vectors X_in
void set_full_covs_internal(Array< mat > &full_covs_in)
ADD DOCUMENTATION HERE.
bool do_checks
indicates whether checks on input data are done
virtual void setup_covs()
additional processing of covariance vectors/matrices, done as the last step of covariance initialisat...
int K
number of gaussians
Array< vec > get_diag_covs() const
Obtain a copy of the array of diagonal covariance vectors.
vec get_weights() const
Obtain a copy of the weight vector.
int get_D() const
Return the dimensionality.
void convert_to_full_internal()
ADD DOCUMENTATION HERE.
virtual void setup_means()
additional processing of mean vectors, done as the last step of mean initialisation
void set_means_zero()
Set the means in the model to be zero.
virtual void setup_misc()
additional processing of miscellaneous parameters, done as the last step of overall initialisation
bool valid
indicates whether the parameters are valid
virtual double log_lhood(const vec &x_in)
calculate the log likelihood of vector x_in
virtual void convert_to_full()
Convert the model to have full covariance matrices.
void set_full_covs(Array< mat > &full_covs_in)
Set the full covariance matrices of the model.
void set_means(Array< vec > &means_in)
Set the means of the model.
virtual double log_lhood_single_gaus(const vec &x_in, const int k)
calculate the log likelihood of vector x_in using only Gaussian k
vec weights
weights
void set_means_internal(Array< vec > &means_in)
ADD DOCUMENTATION HERE.
virtual double log_lhood_internal(const vec &x_in)
ADD DOCUMENTATION HERE.
virtual void save(const std::string &name_in) const
Save the model's parameters to a model file.
Array< vec > diag_covs
diagonal covariance matrices, stored as vectors
void set_full_covs_unity_internal()
ADD DOCUMENTATION HERE.
void set_diag_covs(Array< vec > &diag_covs_in)
Set the diagonal covariance vectors of the model.
virtual void join(const MOG_generic &B_in)
Mathematically join the model with a user supplied model.
virtual double lhood_internal(const vec &x_in)
ADD DOCUMENTATION HERE.
bool is_valid() const
Returns true if the model's parameters are valid.
virtual double log_lhood_single_gaus_internal(const vec &x_in, const int k)
ADD DOCUMENTATION HERE.
int D
dimensionality
bool is_full() const
Returns true if the model has full covariance matrices.
Array< vec > diag_covs_inv_etc
Pre-calcuated inverted version of each diagonal covariance vector, where the covariance elements are ...
vec log_weights
Pre-calculated log versions of the weights.
vec log_det_etc
Gaussian specific pre-calcualted constants.
void set_diag_covs_unity_internal()
ADD DOCUMENTATION HERE.
Array< vec > means
means
void set_means_zero_internal()
ADD DOCUMENTATION HERE.
bool full
indicates whether we are using full or diagonal covariance matrices
double log_max_K
Pre-calcualted std::log(std::numeric_limits<double>::max() / K), where K is the number of Gaussians.
virtual void load(const std::string &name_in)
Initialise the model by loading the parameters from a model file.
void set_weights(vec &weights_in)
Set the weight vector of the model.
Array< mat > get_full_covs() const
Obtain a copy of the array of full covariance matrices.
bool paranoid
indicates whether we are paranoid about numerical stability
Automatic naming when saving.
Definition itfile.h:429
The IT++ file format reading and writing class.
Definition itfile.h:246
void close()
Close the file.
Definition itfile.cpp:530
bool exists(const std::string &name)
Returns true if the variable name exists in the file.
Definition itfile.cpp:644
Definitions of determinant calculations.
double det(const mat &X)
Determinant of real square matrix.
Definition det.cpp:43
Mat< T > diag(const Vec< T > &v, const int K=0)
Create a diagonal matrix using vector v as its diagonal.
Definition matfunc.h:557
#define it_assert(t, s)
Abort if t is not true.
Definition itassert.h:94
bool inv(const mat &X, mat &Y)
Inverse of real square matrix.
Definition inv.cpp:87
bool exist(const std::string &name)
Checks if a file named name already exists on the disk.
Definition binfile.cpp:98
double log_add(double log_a, double log_b)
Safe substitute for log(exp(log_a) + exp(log_b))
Definition log_exp.cpp:40
vec log(const vec &x)
The natural logarithm of the elements.
Definition log_exp.h:241
double trunc_exp(double x)
Truncated exponential function.
Definition log_exp.h:137
int size(const Vec< T > &v)
Length of vector.
Definition matfunc.h:55
T sum(const Vec< T > &v)
Sum of all elements in the vector.
Definition matfunc.h:59
double mean(const vec &v)
The mean value.
Definition misc_stat.cpp:36
Definitions of matrix inversion routines.
IT++ compatibility types and functions.
Definition of classes for the IT++ file format.
Logarithmic and exponenential functions - header file.
Various functions on vectors and matrices - header file.
Miscellaneous functions - header file.
Generic Mixture of Gaussians (MOG) class - header file.
itpp namespace
Definition itmex.h:37
const double m_2pi
Constant 2*Pi.
Definition misc.h:106
const Array< T > concat(const Array< T > &a, const T &e)
Append element e to the end of the Array a.
Definition array.h:486
SourceForge Logo

Generated on Tue Dec 10 2024 04:49:37 for IT++ by Doxygen 1.12.0