root/bdm/stat/emix.h @ 229

Revision 229, 8.9 kB (checked in by smidl, 15 years ago)

epdf has a new function: variance()

  • 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        vec variance() const {
108                //non-central moment
109                vec mom2 = zeros(rv.count());
110                for ( int i = 0;i < w.length();i++ ) {mom2 += w ( i ) * pow(Coms ( i )->mean(),2); }
111                //central moment
112                return mom2-pow(mean(),2);
113        }
114        double evallog ( const vec &val ) const {
115                int i;
116                double sum = 0.0;
117                for ( i = 0;i < w.length();i++ ) {sum += w ( i ) * exp ( Coms ( i )->evallog ( val ) );}
118                if (sum==0.0){sum=std::numeric_limits<double>::epsilon();}
119                double tmp=log ( sum );
120                it_assert_debug(std::isfinite(tmp),"Infinite");
121                return tmp;
122        };
123        vec evallog_m ( const mat &Val ) const {
124                vec x=zeros ( Val.cols() );
125                for ( int i = 0; i < w.length(); i++ ) {
126                        x+= w ( i ) *exp ( Coms ( i )->evallog_m ( Val ) );
127                }
128                return log ( x );
129        };
130        //! Auxiliary function that returns pdflog for each component
131        mat evallog_M ( const mat &Val ) const {
132                mat X ( w.length(), Val.cols() );
133                for ( int i = 0; i < w.length(); i++ ) {
134                        X.set_row ( i, w ( i ) *exp ( Coms ( i )->evallog_m ( Val ) ) );
135                }
136                return X;
137        };
138
139        emix* marginal ( const RV &rv ) const;
140        mratio* condition ( const RV &rv ) const; //why not mratio!!
141
142//Access methods
143        //! returns a pointer to the internal mean value. Use with Care!
144        vec& _w() {return w;}
145        virtual ~emix() {if ( destroyComs ) {for ( int i=0;i<Coms.length();i++ ) {delete Coms ( i );}}}
146        //! Auxiliary function for taking ownership of the Coms()
147        void ownComs() {destroyComs=true;}
148
149        //!access function
150        epdf* _Coms ( int i ) {return Coms ( i );}
151};
152
153/*! \brief Chain rule decomposition of epdf
154
155Probability density in the form of Chain-rule decomposition:
156\[
157f(x_1,x_2,x_3) = f(x_1|x_2,x_3)f(x_2,x_3)f(x_3)
158\]
159Note that
160*/
161class mprod: public compositepdf, public mpdf {
162protected:
163        //! pointers to epdfs - shortcut to mpdfs()._epdf()
164        Array<epdf*> epdfs;
165        //! Data link for each mpdfs
166        Array<datalink_m2m*> dls;
167public:
168        /*!\brief Constructor from list of mFacs,
169        */
170        mprod ( Array<mpdf*> mFacs ) : compositepdf ( mFacs ), mpdf ( getrv ( true ),RV() ), epdfs ( n ), dls ( n ) {
171                setrvc ( rv,rvc );
172                // rv and rvc established = > we can link them with mpdfs
173                for ( int i = 0;i < n;i++ ) {
174                        dls ( i ) = new datalink_m2m ( mpdfs ( i )->_rv(), mpdfs ( i )->_rvc(), rv, rvc );
175                }
176
177                for ( int i=0;i<n;i++ ) {
178                        epdfs ( i ) =& ( mpdfs ( i )->_epdf() );
179                }
180        };
181
182        double evallogcond ( const vec &val, const vec &cond ) {
183                int i;
184                double res = 1.0;
185                for ( i = n - 1;i >= 0;i-- ) {
186                        /*                      if ( mpdfs(i)->_rvc().count() >0) {
187                                                        mpdfs ( i )->condition ( dls ( i )->get_cond ( val,cond ) );
188                                                }
189                                                // add logarithms
190                                                res += epdfs ( i )->evallog ( dls ( i )->get_val ( val ) );*/
191                        res *= mpdfs ( i )->evallogcond (
192                                   dls ( i )->get_val ( val ),
193                                   dls ( i )->get_cond ( val, cond )
194                               );
195                }
196                return res;
197        }
198        vec samplecond ( const vec &cond, double &ll ) {
199                //! Ugly hack to help to discover if mpfs are not in proper order. Correct solution = check that explicitely.
200                vec smp= std::numeric_limits<double>::infinity() * ones ( rv.count() );
201                vec smpi;
202                ll = 0;
203                // Hard assumption here!!! We are going backwards, to assure that samples that are needed from smp are already generated!
204                for ( int i = ( n - 1 );i >= 0;i-- ) {
205                        if ( mpdfs ( i )->_rvc().count() ) {
206                                mpdfs ( i )->condition ( dls ( i )->get_cond ( smp ,cond ) ); // smp is val here!!
207                        }
208                        smpi = epdfs ( i )->sample();
209                        // copy contribution of this pdf into smp
210                        dls ( i )->fill_val ( smp, smpi );
211                        // add ith likelihood contribution
212                        ll+=epdfs ( i )->evallog ( smpi );
213                }
214                return smp;
215        }
216        mat samplecond ( const vec &cond, vec &ll, int N ) {
217                mat Smp ( rv.count(),N );
218                for ( int i=0;i<N;i++ ) {Smp.set_col ( i,samplecond ( cond,ll ( i ) ) );}
219                return Smp;
220        }
221
222        ~mprod() {};
223};
224
225//! Product of independent epdfs. For dependent pdfs, use mprod.
226class eprod: public epdf {
227protected:
228        //! Components (epdfs)
229        Array<const epdf*> epdfs;
230        //! Array of indeces
231        Array<datalink_e2e*> dls;
232public:
233        eprod ( const Array<const epdf*> epdfs0 ) : epdf ( RV() ),epdfs ( epdfs0 ),dls ( epdfs.length() ) {
234                bool independent=true;
235                for ( int i=0;i<epdfs.length();i++ ) {
236                        independent=rv.add ( epdfs ( i )->_rv() );
237                        it_assert_debug ( independent==true, "eprod:: given components are not independent ." );
238                }
239                for ( int i=0;i<epdfs.length();i++ ) {
240                        dls ( i ) = new datalink_e2e ( epdfs ( i )->_rv() , rv );
241                }
242        }
243
244        vec mean() const {
245                vec tmp ( rv.count() );
246                for ( int i=0;i<epdfs.length();i++ ) {
247                        vec pom = epdfs ( i )->mean();
248                        dls ( i )->fill_val ( tmp, pom );
249                }
250                return tmp;
251        }
252        vec variance() const {
253                vec tmp ( rv.count() ); //second moment
254                for ( int i=0;i<epdfs.length();i++ ) {
255                        vec pom = epdfs ( i )->mean();
256                        dls ( i )->fill_val ( tmp, pow(pom,2) );
257                }
258                return tmp-pow(mean(),2);
259        }
260        vec sample() const {
261                vec tmp ( rv.count() );
262                for ( int i=0;i<epdfs.length();i++ ) {
263                        vec pom = epdfs ( i )->sample();
264                        dls ( i )->fill_val ( tmp, pom );
265                }
266                return tmp;
267        }
268        double evallog ( const vec &val ) const {
269                double tmp=0;
270                for ( int i=0;i<epdfs.length();i++ ) {
271                        tmp+=epdfs ( i )->evallog ( dls ( i )->get_val ( val ) );
272                }
273                it_assert_debug(std::isfinite(tmp),"Infinite");
274                return tmp;
275        }
276        //!access function
277        const epdf* operator () ( int i ) const {it_assert_debug ( i<epdfs.length(),"wrong index" );return epdfs ( i );}
278
279        //!Destructor
280        ~eprod() {for ( int i=0;i<epdfs.length();i++ ) {delete dls ( i );}}
281};
282
283
284/*! \brief Mixture of mpdfs with constant weights, all mpdfs are of equal type
285
286*/
287class mmix : public mpdf {
288protected:
289        //! Component (epdfs)
290        Array<mpdf*> Coms;
291        //!Internal epdf
292        emix Epdf;
293public:
294        //!Default constructor
295        mmix ( RV &rv, RV &rvc ) : mpdf ( rv, rvc ), Epdf ( rv ) {ep = &Epdf;};
296        //! Set weights \c w and components \c R
297        void set_parameters ( const vec &w, const Array<mpdf*> &Coms ) {
298                Array<epdf*> Eps ( Coms.length() );
299
300                for ( int i = 0;i < Coms.length();i++ ) {
301                        Eps ( i ) = & ( Coms ( i )->_epdf() );
302                }
303                Epdf.set_parameters ( w, Eps );
304        };
305
306        void condition ( const vec &cond ) {
307                for ( int i = 0;i < Coms.length();i++ ) {Coms ( i )->condition ( cond );}
308        };
309};
310
311#endif //MX_H
Note: See TracBrowser for help on using the browser.