JWS C Library
C language utility library
bmm.c
Go to the documentation of this file.
00001 /*
00002  * This work is licensed under a Creative Commons 
00003  * Attribution-Noncommercial-Share Alike 3.0 United States License.
00004  * 
00005  *    http://creativecommons.org/licenses/by-nc-sa/3.0/us/
00006  * 
00007  * You are free:
00008  * 
00009  *    to Share - to copy, distribute, display, and perform the work
00010  *    to Remix - to make derivative works
00011  * 
00012  * Under the following conditions:
00013  * 
00014  *    Attribution. You must attribute the work in the manner specified by the
00015  *    author or licensor (but not in any way that suggests that they endorse you
00016  *    or your use of the work).
00017  * 
00018  *    Noncommercial. You may not use this work for commercial purposes.
00019  * 
00020  *    Share Alike. If you alter, transform, or build upon this work, you may
00021  *    distribute the resulting work only under the same or similar license to
00022  *    this one.
00023  * 
00024  * For any reuse or distribution, you must make clear to others the license
00025  * terms of this work. The best way to do this is by including this header.
00026  * 
00027  * Any of the above conditions can be waived if you get permission from the
00028  * copyright holder.
00029  * 
00030  * Apart from the remix rights granted under this license, nothing in this
00031  * license impairs or restricts the author's moral rights.
00032  */
00033 
00034 
00046 #include <jwsc/config.h>
00047 
00048 #include <stdlib.h>
00049 #include <stdio.h>
00050 #include <assert.h>
00051 #include <math.h>
00052 #include <inttypes.h>
00053 
00054 #include "jwsc/base/limits.h"
00055 #include "jwsc/vector/vector.h"
00056 #include "jwsc/vector/vector_math.h"
00057 #include "jwsc/matrix/matrix.h"
00058 #include "jwsc/matrix/matrix_math.h"
00059 #include "jwsc/matblock/matblock.h"
00060 #include "jwsc/prob/mv_pmf.h"
00061 #include "jwsc/stat/stat.h"
00062 #include "jwsc/stat/kmeans.h"
00063 #include "jwsc/stat/bmm.h"
00064 
00065 
00067 static void bmm_e_step_d
00068 (
00069     const Matrix_d*   mu,
00070     const Vector_d*   pi,
00071     Matrix_d*         gamma,
00072     const Matrix_u32* x
00073 )
00074 {
00075     double   b;
00076     double   C_n;
00077     uint32_t k, K;
00078     uint32_t n, N;
00079 
00080     Vector_u32* x_n  = 0;
00081     Vector_d*   mu_k = 0;
00082 
00083     K = pi->num_elts;
00084     N = x->num_rows;
00085 
00086     create_zero_matrix_d(&gamma, N, K);
00087 
00088     for (n = 0; n < N; n++)
00089     {
00090         copy_vector_from_matrix_u32(&x_n, x, MATRIX_ROW_VECTOR, n);
00091         C_n = 0;
00092 
00093         for (k = 0; k < K; k++)
00094         {
00095             copy_vector_from_matrix_d(&mu_k, mu, MATRIX_ROW_VECTOR, k);
00096 
00097             mv_bernoulli_pmf_d(&b, mu_k, x_n);
00098 
00099             gamma->elts[ n ][ k ] = pi->elts[ k ] * b;
00100 
00101             C_n += gamma->elts[ n ][ k ];
00102         }
00103 
00104         assert(C_n > 0);
00105 
00106         for (k = 0; k < K; k++)
00107         {
00108             gamma->elts[ n ][ k ] /= C_n;
00109         }
00110     }
00111 
00112     free_vector_u32(x_n);
00113     free_vector_d(mu_k);
00114 }
00115 
00116 
00118 static void bmm_m_step_d
00119 (
00120     Matrix_d*         mu,
00121     Vector_d*         pi,
00122     const Matrix_d*   gamma,
00123     const Matrix_u32* x
00124 )
00125 {
00126     uint32_t k, K;
00127     uint32_t n, N;
00128     uint32_t d, D;
00129 
00130     Vector_d* mu_k    = NULL;
00131 
00132     K = pi->num_elts;
00133     N = x->num_rows;
00134     D = x->num_cols;
00135 
00136     create_zero_vector_d(&pi, K);
00137 
00138     // mu
00139     create_matrix_d(&mu, K, D);
00140     for (k = 0; k < K; k++)
00141     {
00142         create_zero_vector_d(&mu_k, D);
00143 
00144         for (n = 0; n < N; n++)
00145         {
00146             for (d = 0; d < D; d++)
00147             {
00148                 mu_k->elts[ d ] += gamma->elts[ n ][ k ]*x->elts[ n ][ d ];
00149             }
00150 
00151             pi->elts[ k ] += gamma->elts[ n ][ k ];
00152         }
00153 
00154         assert(pi->elts[ k ] > 0);
00155 
00156         multiply_vector_by_scalar_d(&mu_k, mu_k, 1.0 / pi->elts[ k ]);
00157         copy_vector_into_matrix_d(&mu, mu, mu_k, MATRIX_ROW_VECTOR, k);
00158     }
00159 
00160     // pi
00161     multiply_vector_by_scalar_d(&pi, pi, 1.0 / N);
00162 
00163     free_vector_d(mu_k);
00164 }
00165 
00166 
00172 double bmm_log_likelihood_d
00173 (
00174     const Matrix_d*   mu,
00175     const Vector_d*   pi,
00176     const Matrix_u32* x
00177 )
00178 {
00179     uint32_t n, N;
00180     uint32_t k, K;
00181     double   p, q;
00182     double   ll;
00183 
00184     Vector_u32* x_n  = NULL;
00185     Vector_d*   mu_k = NULL;
00186 
00187     N = x->num_rows;
00188     K = pi->num_elts;
00189 
00190     ll = 0;
00191 
00192     for (n = 0; n < N; n++)
00193     {
00194         p = 0;
00195         copy_vector_from_matrix_u32(&x_n, x, MATRIX_ROW_VECTOR, n);
00196 
00197         for (k = 0; k < K; k++)
00198         {
00199             copy_vector_from_matrix_d(&mu_k, mu, MATRIX_ROW_VECTOR, k);
00200 
00201             mv_bernoulli_pmf_d(&q, mu_k, x_n);
00202 
00203             p += pi->elts[ k ] * q;
00204 
00205 #if defined(JWSC_HAVE_ISNAN) && defined(JWSC_HAVE_ISINF)
00206             assert(!isnan(p) && !isinf(p));
00207 #endif
00208         }
00209 
00210         ll += log((p < JWSC_MIN_LOG_ARG) ? JWSC_MIN_LOG_ARG : p);
00211     }
00212 
00213     free_vector_u32(x_n);
00214     free_vector_d(mu_k);
00215 
00216     return ll;
00217 }
00218 
00219 
00231 void bmm_kmeans_init_d
00232 (
00233     Matrix_d**        mu_out,
00234     Vector_d**        pi_out,
00235     const Matrix_u32* x,
00236     uint32_t          K
00237 )
00238 {
00239     uint32_t d, D;
00240     uint32_t n, nn, N;
00241     uint32_t k;
00242 
00243     Vector_i32* members = NULL;
00244     Vector_u32* counts  = NULL;
00245     Matrix_d*   x_d     = NULL;
00246     Matrix_d*   x_k     = NULL;
00247 
00248     D = x->num_cols;
00249     N = x->num_rows;
00250 
00251     create_matrix_d(&x_d, N, D);
00252     for (n = 0; n < N; n++)
00253     {
00254         for (d = 0; d < D; d++)
00255         {
00256             x_d->elts[ n ][ d ] = (double)x->elts[ n ][ d ];
00257         }
00258     }
00259 
00260     init_kmeans_randomly_d(mu_out, x_d, K);
00261     kmeans_d(mu_out, &members, x_d, K, 2);
00262 
00263     create_zero_vector_u32(&counts, K);
00264 
00265     for (n = 0; n < N; n++)
00266     {
00267         k = members->elts[ n ];
00268         counts->elts[ k ]++;
00269     }
00270     for (k = 0; k < K; k++)
00271     {
00272         create_matrix_d(&x_k, counts->elts[ k ], D);
00273 
00274         nn = 0;
00275         for (n = 0; n < N; n++)
00276         {
00277             if (k == members->elts[ n ])
00278             {
00279                 for (d = 0; d < D; d++)
00280                 {
00281                     x_k->elts[ nn ][ d ] = x_d->elts[ n ][ d ];
00282                 }
00283                 nn++;
00284             }
00285         }
00286     }
00287 
00288     create_vector_d(pi_out, K);
00289     for (k = 0; k < K; k++)
00290     {
00291         (*pi_out)->elts[ k ] = counts->elts[ k ] / (double)N;
00292     }
00293 
00294     free_vector_i32(members);
00295     free_vector_u32(counts);
00296     free_matrix_d(x_k);
00297     free_matrix_d(x_d);
00298 }
00299 
00300 
00310 void train_bmm_d
00311 (
00312     Matrix_d**        mu_out,
00313     Vector_d**        pi_out,
00314     const Matrix_u32* x,
00315     uint32_t          K
00316 )
00317 {
00318     double   ll, ll_prev;
00319 
00320     Matrix_d*   mu;
00321     Vector_d*   pi;
00322     Matrix_d*   gamma = 0;
00323 
00324     bmm_kmeans_init_d(mu_out, pi_out, x, K);
00325     mu    = *mu_out;
00326     pi    = *pi_out;
00327 
00328     create_matrix_d(&gamma, x->num_rows, pi->num_elts);
00329 
00330     ll_prev = 0;
00331     ll      = log(0);
00332 
00333     while (fabs(ll - ll_prev) > 1.0e-10)
00334     {
00335         bmm_e_step_d(mu, pi, gamma, x);
00336         bmm_m_step_d(mu, pi, gamma, x);
00337 
00338         ll_prev = ll;
00339         ll = bmm_log_likelihood_d(mu, pi, x);
00340     }
00341 
00342     free_matrix_d(gamma);
00343 }