root/bdm/stat/emix.h @ 224

Revision 224, 8.4 kB (checked in by smidl, 15 years ago)

doc

  • 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 evallogcond().
35 */
36class mratio: public mpdf {
37protected:
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        //!datalink between conditional and nom
45        datalink_m2e dl;
46public:
47        //!Default constructor. By default, the given epdf is not copied!
48        //! It is assumed that this function will be used only temporarily.
49        mratio ( const epdf* nom0, const RV &rv, bool copy=false ) :mpdf ( rv,nom0->_rv().subt ( rv ) ), dl ( rv,rvc,nom0->_rv() ) {
50                if ( copy ) {
51//                      nom = nom0->_copy_();
52                        it_error ( "todo" );
53                        destroynom=true;
54                }
55                else {
56                        nom = nom0;
57                        destroynom = false;
58                }
59                it_assert_debug ( rvc.length() >0,"Makes no sense to use this object!" );
60                den = nom->marginal ( rvc );
61        };
62        double evallogcond ( const vec &val, const vec &cond ) {
63                double tmp;
64                vec nom_val ( rv.count() +rvc.count() );
65                dl.fill_val_cond ( nom_val,val,cond );
66                tmp = exp ( nom->evallog ( nom_val ) - den->evallog ( cond ) );
67                it_assert_debug(std::isfinite(tmp),"Infinite value");
68                return tmp;
69        }
70        //! Object takes ownership of nom and will destroy it
71        void ownnom() {destroynom=true;}
72        //! Default destructor
73        ~mratio() {delete den; if ( destroynom ) {delete nom;}}
74};
75
76/*!
77* \brief Mixture of epdfs
78
79Density function:
80\f[
81f(x) = \sum_{i=1}^{n} w_{i} f_i(x), \quad \sum_{i=1}^n w_i = 1.
82\f]
83where \f$f_i(x)\f$ is any density on random variable \f$x\f$, called \a component,
84
85*/
86class emix : public epdf {
87protected:
88        //! weights of the components
89        vec w;
90        //! Component (epdfs)
91        Array<epdf*> Coms;
92        //!Flag if owning Coms
93        bool destroyComs;
94public:
95        //!Default constructor
96        emix ( const RV &rv ) : epdf ( rv ) {};
97        //! Set weights \c w and components \c Coms
98        //!By default Coms are copied inside. Parameter \c copy can be set to false if Coms live externally. Use method ownComs() if Coms should be destroyed by the destructor.
99        void set_parameters ( const vec &w, const Array<epdf*> &Coms, bool copy=true );
100
101        vec sample() const;
102        vec mean() const {
103                int i; vec mu = zeros ( rv.count() );
104                for ( i = 0;i < w.length();i++ ) {mu += w ( i ) * Coms ( i )->mean(); }
105                return mu;
106        }
107        double evallog ( const vec &val ) const {
108                int i;
109                double sum = 0.0;
110                for ( i = 0;i < w.length();i++ ) {sum += w ( i ) * exp ( Coms ( i )->evallog ( val ) );}
111                if (sum==0.0){sum=std::numeric_limits<double>::epsilon();}
112                double tmp=log ( sum );
113                it_assert_debug(std::isfinite(tmp),"Infinite");
114                return tmp;
115        };
116        vec evallog_m ( const mat &Val ) const {
117                vec x=zeros ( Val.cols() );
118                for ( int i = 0; i < w.length(); i++ ) {
119                        x+= w ( i ) *exp ( Coms ( i )->evallog_m ( Val ) );
120                }
121                return log ( x );
122        };
123        //! Auxiliary function that returns pdflog for each component
124        mat evallog_M ( const mat &Val ) const {
125                mat X ( w.length(), Val.cols() );
126                for ( int i = 0; i < w.length(); i++ ) {
127                        X.set_row ( i, w ( i ) *exp ( Coms ( i )->evallog_m ( Val ) ) );
128                }
129                return X;
130        };
131
132        emix* marginal ( const RV &rv ) const;
133        mratio* condition ( const RV &rv ) const; //why not mratio!!
134
135//Access methods
136        //! returns a pointer to the internal mean value. Use with Care!
137        vec& _w() {return w;}
138        virtual ~emix() {if ( destroyComs ) {for ( int i=0;i<Coms.length();i++ ) {delete Coms ( i );}}}
139        //! Auxiliary function for taking ownership of the Coms()
140        void ownComs() {destroyComs=true;}
141
142        //!access function
143        epdf* _Coms ( int i ) {return Coms ( i );}
144};
145
146/*! \brief Chain rule decomposition of epdf
147
148Probability density in the form of Chain-rule decomposition:
149\[
150f(x_1,x_2,x_3) = f(x_1|x_2,x_3)f(x_2,x_3)f(x_3)
151\]
152Note that
153*/
154class mprod: public compositepdf, public mpdf {
155protected:
156        //! pointers to epdfs - shortcut to mpdfs()._epdf()
157        Array<epdf*> epdfs;
158        //! Data link for each mpdfs
159        Array<datalink_m2m*> dls;
160public:
161        /*!\brief Constructor from list of mFacs,
162        */
163        mprod ( Array<mpdf*> mFacs ) : compositepdf ( mFacs ), mpdf ( getrv ( true ),RV() ), epdfs ( n ), dls ( n ) {
164                setrvc ( rv,rvc );
165                // rv and rvc established = > we can link them with mpdfs
166                for ( int i = 0;i < n;i++ ) {
167                        dls ( i ) = new datalink_m2m ( mpdfs ( i )->_rv(), mpdfs ( i )->_rvc(), rv, rvc );
168                }
169
170                for ( int i=0;i<n;i++ ) {
171                        epdfs ( i ) =& ( mpdfs ( i )->_epdf() );
172                }
173        };
174
175        double evallogcond ( const vec &val, const vec &cond ) {
176                int i;
177                double res = 1.0;
178                for ( i = n - 1;i >= 0;i-- ) {
179                        /*                      if ( mpdfs(i)->_rvc().count() >0) {
180                                                        mpdfs ( i )->condition ( dls ( i )->get_cond ( val,cond ) );
181                                                }
182                                                // add logarithms
183                                                res += epdfs ( i )->evallog ( dls ( i )->get_val ( val ) );*/
184                        res *= mpdfs ( i )->evallogcond (
185                                   dls ( i )->get_val ( val ),
186                                   dls ( i )->get_cond ( val, cond )
187                               );
188                }
189                return res;
190        }
191        vec samplecond ( const vec &cond, double &ll ) {
192                //! Ugly hack to help to discover if mpfs are not in proper order. Correct solution = check that explicitely.
193                vec smp= std::numeric_limits<double>::infinity() * ones ( rv.count() );
194                vec smpi;
195                ll = 0;
196                // Hard assumption here!!! We are going backwards, to assure that samples that are needed from smp are already generated!
197                for ( int i = ( n - 1 );i >= 0;i-- ) {
198                        if ( mpdfs ( i )->_rvc().count() ) {
199                                mpdfs ( i )->condition ( dls ( i )->get_cond ( smp ,cond ) ); // smp is val here!!
200                        }
201                        smpi = epdfs ( i )->sample();
202                        // copy contribution of this pdf into smp
203                        dls ( i )->fill_val ( smp, smpi );
204                        // add ith likelihood contribution
205                        ll+=epdfs ( i )->evallog ( smpi );
206                }
207                return smp;
208        }
209        mat samplecond ( const vec &cond, vec &ll, int N ) {
210                mat Smp ( rv.count(),N );
211                for ( int i=0;i<N;i++ ) {Smp.set_col ( i,samplecond ( cond,ll ( i ) ) );}
212                return Smp;
213        }
214
215        ~mprod() {};
216};
217
218//! Product of independent epdfs. For dependent pdfs, use mprod.
219class eprod: public epdf {
220protected:
221        //! Components (epdfs)
222        Array<const epdf*> epdfs;
223        //! Array of indeces
224        Array<datalink_e2e*> dls;
225public:
226        eprod ( const Array<const epdf*> epdfs0 ) : epdf ( RV() ),epdfs ( epdfs0 ),dls ( epdfs.length() ) {
227                bool independent=true;
228                for ( int i=0;i<epdfs.length();i++ ) {
229                        independent=rv.add ( epdfs ( i )->_rv() );
230                        it_assert_debug ( independent==true, "eprod:: given components are not independent ." );
231                }
232                for ( int i=0;i<epdfs.length();i++ ) {
233                        dls ( i ) = new datalink_e2e ( epdfs ( i )->_rv() , rv );
234                }
235        }
236
237        vec mean() const {
238                vec tmp ( rv.count() );
239                for ( int i=0;i<epdfs.length();i++ ) {
240                        vec pom = epdfs ( i )->mean();
241                        dls ( i )->fill_val ( tmp, pom );
242                }
243                return tmp;
244        }
245        vec sample() const {
246                vec tmp ( rv.count() );
247                for ( int i=0;i<epdfs.length();i++ ) {
248                        vec pom = epdfs ( i )->sample();
249                        dls ( i )->fill_val ( tmp, pom );
250                }
251                return tmp;
252        }
253        double evallog ( const vec &val ) const {
254                double tmp=0;
255                for ( int i=0;i<epdfs.length();i++ ) {
256                        tmp+=epdfs ( i )->evallog ( dls ( i )->get_val ( val ) );
257                }
258                it_assert_debug(std::isfinite(tmp),"Infinite");
259                return tmp;
260        }
261        //!access function
262        const epdf* operator () ( int i ) const {it_assert_debug ( i<epdfs.length(),"wrong index" );return epdfs ( i );}
263
264        //!Destructor
265        ~eprod() {for ( int i=0;i<epdfs.length();i++ ) {delete dls ( i );}}
266};
267
268
269/*! \brief Mixture of mpdfs with constant weights, all mpdfs are of equal type
270
271*/
272class mmix : public mpdf {
273protected:
274        //! Component (epdfs)
275        Array<mpdf*> Coms;
276        //!Internal epdf
277        emix Epdf;
278public:
279        //!Default constructor
280        mmix ( RV &rv, RV &rvc ) : mpdf ( rv, rvc ), Epdf ( rv ) {ep = &Epdf;};
281        //! Set weights \c w and components \c R
282        void set_parameters ( const vec &w, const Array<mpdf*> &Coms ) {
283                Array<epdf*> Eps ( Coms.length() );
284
285                for ( int i = 0;i < Coms.length();i++ ) {
286                        Eps ( i ) = & ( Coms ( i )->_epdf() );
287                }
288                Epdf.set_parameters ( w, Eps );
289        };
290
291        void condition ( const vec &cond ) {
292                for ( int i = 0;i < Coms.length();i++ ) {Coms ( i )->condition ( cond );}
293        };
294};
295
296#endif //MX_H
Note: See TracBrowser for help on using the browser.