root/bdm/stat/emix.h @ 189

Revision 189, 8.1 kB (checked in by smidl, 16 years ago)

extend MixEF to allow for EM algorithm and alow estimation of weighted empirical density

  • Property svn:eol-style set to native
Line 
1/*!
2  \file
3  \brief Probability distributions for Mixtures of pdfs
4  \author Vaclav Smidl.
5
6  -----------------------------------
7  BDM++ - C++ library for Bayesian Decision Making under Uncertainty
8
9  Using IT++ for numerical operations
10  -----------------------------------
11*/
12
13#ifndef MX_H
14#define MX_H
15
16#include "libBM.h"
17#include "libEF.h"
18//#include <std>
19
20using namespace itpp;
21
22//this comes first because it is used inside emix!
23
24/*! \brief Class representing ratio of two densities
25which arise e.g. by applying the Bayes rule.
26It represents density in the form:
27\f[
28f(rv|rvc) = \frac{f(rv,rvc)}{f(rvc)}
29\f]
30where \f$ f(rvc) = \int f(rv,rvc) d\ rv \f$.
31
32In particular this type of arise by conditioning of a mixture model.
33
34At present the only supported operation is evalcond().
35 */
36class mratio: public mpdf {
37        protected:
38        //! Nominator in the form of mpdf
39                const epdf* nom;
40        //!Denominator in the form of epdf
41                epdf* den;
42        //!flag for destructor
43                bool destroynom;
44        public:
45        //!Default constructor. By default, the given epdf is not copied!
46        //! It is assumed that this function will be used only temporarily.
47                mratio(const epdf* nom0, const RV &rv, bool copy=false):mpdf(rv,RV()){
48                        if (copy){
49//                      nom = nom0->_copy_();
50                                destroynom=true;
51                        } else {
52                                nom = nom0;
53                                destroynom = false;
54                        }
55                        rvc = nom->_rv().subt(rv);
56                        it_assert_debug(rvc.length()>0,"Makes no sense to use this object!");
57                        den = nom->marginal(rvc);
58                };
59                double evalcond(const vec &val, const vec &cond) {
60                        return exp(nom->evalpdflog(concat(val,cond)) - den->evalpdflog(cond));
61                }
62        //! Object takes ownership of nom and will destroy it
63                void ownnom(){destroynom=true;}
64        //! Default destructor
65                ~mratio(){delete den; if (destroynom) {delete nom;}}
66};
67
68/*!
69* \brief Mixture of epdfs
70
71Density function:
72\f[
73f(x) = \sum_{i=1}^{n} w_{i} f_i(x), \quad \sum_{i=1}^n w_i = 1.
74\f]
75where \f$f_i(x)\f$ is any density on random variable \f$x\f$, called \a component,
76
77*/
78class emix : public epdf {
79protected:
80        //! weights of the components
81        vec w;
82        //! Component (epdfs)
83        Array<epdf*> Coms;
84        //!Flag if owning Coms
85        bool destroyComs;
86public:
87        //!Default constructor
88        emix ( const RV &rv ) : epdf ( rv ) {};
89        //! Set weights \c w and components \c Coms
90        //!By default Coms are copied inside. \param copy can be set to false if Coms live externally. Use method ownComs() if Coms should be destroyed by the destructor.
91        void set_parameters ( const vec &w, const Array<epdf*> &Coms, bool copy=true );
92
93        vec sample() const;
94        vec mean() const {
95                int i; vec mu = zeros ( rv.count() );
96                for ( i = 0;i < w.length();i++ ) {mu += w ( i ) * Coms ( i )->mean(); }
97                return mu;
98        }
99        double evalpdflog ( const vec &val ) const {
100                int i;
101                double sum = 0.0;
102                for ( i = 0;i < w.length();i++ ) {sum += w ( i ) * exp(Coms ( i )->evalpdflog ( val ));}
103                return log ( sum );
104        };
105        vec evalpdflog_m ( const mat &Val ) const {
106                vec x=ones(Val.cols());
107                vec y(Val.cols());
108                for (int i = 0; i < w.length(); i++ ) {
109                        y = w ( i )*exp(Coms ( i )->evalpdflog_m ( Val ) );
110                        elem_mult_inplace(y,x); //result is in x
111                }
112                return log(x);
113        };
114        mat evalpdflog_M ( const mat &Val ) const {
115                mat X(w.length(), Val.cols());
116                for (int i = 0; i < w.length(); i++ ) {
117                        X.set_row(i, w ( i )*exp(Coms ( i )->evalpdflog_m ( Val ) ));
118                }
119                return X;
120        };
121
122        emix* marginal ( const RV &rv ) const;
123        mratio* condition ( const RV &rv ) const; //why not mratio!!
124
125//Access methods
126        //! returns a pointer to the internal mean value. Use with Care!
127        vec& _w() {return w;}
128        virtual ~emix() {if ( destroyComs ) {for ( int i=0;i<Coms.length();i++ ) {delete Coms ( i );}}}
129        //! Auxiliary function for taking ownership of the Coms()
130        void ownComs() {destroyComs=true;}
131};
132
133/*! \brief Chain rule decomposition of epdf
134
135Probability density in the form of Chain-rule decomposition:
136\[
137f(x_1,x_2,x_3) = f(x_1|x_2,x_3)f(x_2,x_3)f(x_3)
138\]
139Note that
140*/
141class mprod: public compositepdf, public mpdf {
142protected:
143        //! pointers to epdfs - shortcut to mpdfs()._epdf()
144        Array<epdf*> epdfs;
145        //! Indeces of rvc in common rvc
146        Array<ivec> irvcs_rvc;
147        //! Indeces of common rvc in rvcs
148        Array<ivec> irvc_rvcs;
149public:
150        /*!\brief Constructor from list of mFacs,
151        */
152        mprod ( Array<mpdf*> mFacs ) : compositepdf ( mFacs ), mpdf ( getrv ( true ),RV() ), epdfs ( n ), irvcs_rvc ( n ), irvc_rvcs ( n ) {
153                setrvc ( rv,rvc );
154                setindices ( rv );
155                for ( int i = 0;i < n;i++ ) {
156                        // establish link between rvc and rvcs
157                        rvc.dataind ( mpdfs ( i )->_rvc(), irvc_rvcs ( i ), irvcs_rvc ( i ) );
158                }
159
160                for ( int i=0;i<n;i++ ) {
161                        epdfs ( i ) =& ( mpdfs ( i )->_epdf() );
162                }
163        };
164
165        double evalcond ( const vec &val, const vec &cond ) {
166                int i;
167                double res = 0.0;
168                vec condi;
169                for ( i = n - 1;i >= 0;i-- ) {
170                        if ( ( irvcs_rvc ( i ).length() > 0 ) || ( irvcs_rv ( i ).length() > 0 ) ) {
171                                condi = zeros ( irvcs_rvc ( i ).length() +irvcs_rv ( i ).length() );
172                                //copy part of the rvc into condi
173                                set_subvector ( condi, irvcs_rvc ( i ), get_vec ( cond,irvc_rvcs ( i ) ) );
174                                //copy part of the rv into condi
175                                set_subvector ( condi, irvcs_rv ( i ), get_vec ( val,irv_rvcs ( i ) ) );
176                                mpdfs ( i )->condition ( condi );
177                        }
178                        // add logarithms
179                        res += epdfs ( i )->evalpdflog ( val ( rvsinrv ( i ) ) );
180                }
181                return exp ( res );
182        }
183        vec samplecond ( const vec &cond, double &ll ) {
184                vec smp=zeros ( rv.count() );
185                vec condi;
186                vec smpi;
187                ll = 0;
188                for ( int i = ( n - 1 );i >= 0;i-- ) {
189                        if ( ( irvcs_rvc ( i ).length() > 0 ) || ( irvcs_rv ( i ).length() > 0 ) ) {
190                                condi = zeros ( irvcs_rv ( i ).length() + irvcs_rvc ( i ).length() );
191                                // copy data in condition
192                                set_subvector ( condi,irvcs_rvc ( i ), get_vec ( cond, irvc_rvcs ( i ) ) );
193                                // copy data in already generated sample
194                                set_subvector ( condi,irvcs_rv ( i ), get_vec ( smp,irv_rvcs ( i ) ) );
195
196                                mpdfs ( i )->condition ( condi );
197                        }
198                        smpi = epdfs ( i )->sample();
199                        // copy contribution of this pdf into smp
200                        set_subvector ( smp,rvsinrv ( i ), smpi );
201                        // add ith likelihood contribution
202                        ll+=epdfs ( i )->evalpdflog ( smpi );
203                }
204                return smp;
205        }
206        mat samplecond ( const vec &cond, vec &ll, int N ) {
207                mat Smp ( rv.count(),N );
208                for ( int i=0;i<N;i++ ) {Smp.set_col ( i,samplecond ( cond,ll ( i ) ) );}
209                return Smp;
210        }
211
212        ~mprod() {};
213};
214
215//! Product of independent epdfs. For dependent pdfs, use mprod.
216class eprod: public epdf {
217protected:
218        //! Components (epdfs)
219        Array<const epdf*> epdfs;
220        //! Array of indeces
221        Array<ivec> rvinds;
222public:
223        eprod ( const Array<const epdf*> epdfs0 ) : epdf ( RV() ),epdfs ( epdfs0 ),rvinds ( epdfs.length() ) {
224                bool independent=true;
225                for ( int i=0;i<epdfs.length();i++ ) {
226                        independent=rv.add ( epdfs ( i )->_rv() );
227                        it_assert_debug ( independent==true, "eprod:: given components are not independent ." );
228                        rvinds ( i ) = ( epdfs ( i )->_rv() ).dataind ( rv );
229                }
230        }
231
232        vec mean() const {
233                vec tmp ( rv.count() );
234                for ( int i=0;i<epdfs.length();i++ ) {
235                        vec pom = epdfs ( i )->mean();
236                        set_subvector ( tmp,rvinds ( i ), pom );
237                }
238                return tmp;
239        }
240        vec sample() const {
241                vec tmp ( rv.count() );
242                for ( int i=0;i<epdfs.length();i++ ) {
243                        vec pom = epdfs ( i )->sample();
244                        set_subvector ( tmp,rvinds ( i ), pom );
245                }
246                return tmp;
247        }
248        double evalpdflog ( const vec &val ) const {
249                double tmp=0;
250                for ( int i=0;i<epdfs.length();i++ ) {
251                        tmp+=epdfs ( i )->evalpdflog ( val ( rvinds ( i ) ) );
252                }
253                return tmp;
254        }
255        //!access function
256        const epdf* operator () ( int i ) const {it_assert_debug ( i<epdfs.length(),"wrong index" );return epdfs ( i );}
257};
258
259
260/*! \brief Mixture of mpdfs with constant weights, all mpdfs are of equal type
261
262*/
263class mmix : public mpdf {
264protected:
265        //! Component (epdfs)
266        Array<mpdf*> Coms;
267        //!Internal epdf
268        emix Epdf;
269public:
270        //!Default constructor
271        mmix ( RV &rv, RV &rvc ) : mpdf ( rv, rvc ), Epdf ( rv ) {ep = &Epdf;};
272        //! Set weights \c w and components \c R
273        void set_parameters ( const vec &w, const Array<mpdf*> &Coms ) {
274                Array<epdf*> Eps ( Coms.length() );
275
276                for ( int i = 0;i < Coms.length();i++ ) {
277                        Eps ( i ) = & ( Coms ( i )->_epdf() );
278                }
279                Epdf.set_parameters ( w, Eps );
280        };
281
282        void condition ( const vec &cond ) {
283                for ( int i = 0;i < Coms.length();i++ ) {Coms ( i )->condition ( cond );}
284        };
285};
286
287#endif //MX_H
Note: See TracBrowser for help on using the browser.