GCOP  1.0
gmm.h
Go to the documentation of this file.
00001 // This file is part of libgcop, a library for Geometric Control, Optimization, and Planning (GCOP)
00002 //
00003 // Copyright (C) 2004-2014 Marin Kobilarov <marin(at)jhu.edu>
00004 //
00005 // This Source Code Form is subject to the terms of the Mozilla
00006 // Public License v. 2.0. If a copy of the MPL was not distributed
00007 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
00008 
00009 #ifndef GCOP_GMM_H
00010 #define GCOP_GMM_H
00011 
00012 #include "normal.h"
00013 
00014 namespace gcop {
00015   using namespace Eigen;
00016   using namespace std;
00017   
00023   template<int _n = Dynamic>
00024   class Gmm {
00025   public:
00026   typedef Matrix<double, _n, 1> Vectornd;
00027   typedef Matrix<double, _n, _n> Matrixnd;
00028 
00034     Gmm(int n, int k = 1);
00035 
00036     virtual ~Gmm();
00037 
00038     bool Update();
00039 
00040     double L(const Vectornd &x) const;
00041 
00042     double Sample(Vectornd &x);
00043  
00044     void Init(const Vectornd &xlb, const Vectornd &xub);
00045     
00054     void Fit(const vector<pair<Vectornd, double> > &xps, double a = 1,
00055              int iter = 50, const Matrixnd *S = 0);
00056     
00057   int k;              
00058   vector<Normal<_n>> ns;  
00059   vector<double> ws;  
00060   vector<double> cdf; 
00061   
00062   double tol; 
00063   
00064   protected:
00065   Vectornd t2;
00066   Matrixnd t3;
00067   };
00068 
00069 
00070   template<int _n>
00071     Gmm<_n>::Gmm(int n, int k) :
00072   k(k), ns(k, Normal<_n>(n)), ws(k), cdf(k)
00073 {
00074   assert(n > 0);
00075   assert(k > 0);
00076 
00077     //  ns = new Normal*[k];
00078     //  ws = new double[k];
00079     //  cdf = new double[k];
00080 
00081   for (int i = 0; i < k; ++i) {
00082     //    ns[i] = new Normal(n);
00083     ws[i] = 1/((double)k);
00084     cdf[i] = (i+1)/((double)k);
00085 
00086     ns[i].mu.setZero();
00087     ns[i].P = VectorXd::Constant(n, 1).asDiagonal();
00088   }
00089 
00090   tol = .01;
00091 
00092   if (_n == Dynamic) {
00093     t2.resize(n);
00094     t3.resize(n, n);    
00095   }
00096 }
00097 
00098 
00099   template<int _n>
00100 Gmm<_n>::~Gmm()
00101 {
00102   /*
00103   for (int i = 0; i < k; ++i)
00104     delete ns[i];
00105   delete cdf;
00106   delete ws;
00107   delete ns;
00108   */
00109 }
00110 
00111 
00112   template<int _n>
00113 bool Gmm<_n>::Update()
00114 {
00115   if (k == 1) {
00116     ws[0] = 1;
00117     cdf[0] = 1;
00118     return ns[0].Update();
00119 
00120   } else {
00121     /*
00122     bool ok = true;
00123     double wn = 0;
00124     for (int i = 0; i < k; ++i) {
00125       ok = ok && ns[i]->Update();
00126       wn += ws[i];
00127     }
00128 
00129     for (int i = 0; i < k; ++i) {
00130       ws[i] /= wn;
00131       cdf[i] = (i ? cdf[i - 1] + ws[i] : ws[i]); 
00132     }
00133     return ok;
00134     */    
00135 
00136 
00137     // No need to call update since it is called after EM
00138 
00139     bool ok = true;
00140     for (int i = 0; i < k; ++i) {
00141       cdf[i] = (i ? cdf[i - 1] + ws[i] : ws[i]); 
00142       ok = ok && ns[i].pd;
00143     }
00144     return ok;
00145   }
00146 }
00147 
00148   template<int _n>
00149 double Gmm<_n>::L(const Vectornd &x) const
00150 {
00151   if (k == 1) {
00152     return ns[0].L(x);
00153   } else {
00154     
00155     double l = 0;
00156     for (int i = 0; i < k; ++i)
00157       l += ws[i]*ns[i].L(x);    
00158     return l;
00159   }
00160 }
00161 
00162 
00163   template<int _n>
00164 double Gmm<_n>::Sample(Vectornd &x)
00165 {
00166   if (k == 1) {
00167     return ns[0].Sample(x);
00168 
00169   } else {
00170     // for now this is unefficient if k is big
00171     // TODO: implement as binary search
00172     double uc = rand()/(double)RAND_MAX;
00173     int i = 0;
00174     while (uc > cdf[i])
00175       ++i;
00176     
00177     assert(i < k);
00178     return ns[i].Sample(x);
00179   }
00180 }
00181 
00182   template<int _n>
00183 void Gmm<_n>::Init(const Vectornd &xlb, const Vectornd &xub)
00184 {
00185   Vectornd dx = xub - xlb;   // range
00186   Vectornd r = dx/pow(k, 1.0/dx.size())/2;     // radius
00187   Matrixnd P = (r.cwiseProduct(r)).asDiagonal();
00188   for (int i = 0; i < k; ++i) {    
00189     ns[i].mu = xlb + dx.cwiseProduct(VectorXd::Random(xlb.size()));
00190     ns[i].P = P;
00191     ws[i] = 1.0/k;
00192     ns[i].Update();
00193   }
00194 
00195   Update();
00196 }
00197 
00198 
00199   template<int _n>
00200     void Gmm<_n>::Fit(const vector<pair<Vectornd, double> > &xps, double a, int iter, const Matrixnd *S)
00201 {
00202   int N = xps.size();
00203 
00204   if (k == 1) {
00205     ns[0].Fit(xps, a);
00206     if (S)
00207       ns[0].P += *S;
00208     return;
00209   }
00210 
00211   assert(N > 0);
00212 
00213   double ps[N][k];
00214 
00215   for (int l = 0; l < iter; ++l) {
00216 
00217     // E-step
00218 
00219     for (int j = 0; j < N; ++j) {
00220       
00221       const Vectornd &x = xps[j].first;      
00222       double p = xps[j].second;
00223 
00224       double norm = 0;
00225       double *psj = ps[j];
00226 
00227       for (int i = 0; i < k; ++i) {
00228         psj[i] = p*ns[i].L(x);    // likelihood of each sample        
00229         norm += psj[i];
00230       }
00231 
00232       //    assert(norm > 1e-10);
00233       //      cout << "    normalized: ps[" << j << "]=";
00234       for (int i = 0; i < k; ++i) {
00235         psj[i] /= norm;
00236         //        cout << psj[i] << " ";
00237       }    
00238       //      cout << endl;
00239     }  
00240     
00241     
00242     // M-step
00243     double maxd = 0;
00244 
00245     for (int i = 0; i < k; ++i) {
00246       double t1 = 0;
00247       //      Vectornd t2; = VectorXd::Zero(ns[0].mu.size());
00248       t2.setZero();//Redundancy
00249       //MatrixXd t3 = MatrixXd::Zero(ns[0].mu.size(), ns[0].mu.size());
00250       t3.setZero();
00251       
00252       for (int j = 0; j < N; ++j) {
00253         const VectorXd &x = xps[j].first;
00254         t1 += ps[j][i];
00255         t2 += ps[j][i]*x;
00256         t3 += (ps[j][i]*x)*x.transpose();
00257       }
00258       
00259       ws[i] = t1;
00260 
00261       VectorXd mu = t2/t1;
00262 
00263       double d = (mu - ns[i].mu).norm();
00264       if (maxd < d)
00265         maxd = d;
00266 
00267       ns[i].mu = mu;
00268       ns[i].P = (t3 - t2*(t2.transpose()/t1))/t1;        
00269       if (S)
00270         ns[i].P += *S;
00271 
00272 
00273       if (!ns[i].Update()) // set Pinv, det, norm
00274         return;
00275     }
00276     
00277     if (maxd < tol) {
00278       //cout << "[W] Gmm::Fit: tolerance " << maxd << " reached after " << l << " iterations!" << endl;
00279       break;
00280     }
00281   }
00282 }
00283 
00284 
00285 }
00286 
00287 #endif