root/bdm/stat/emix.h @ 229

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

epdf has a new function: variance()

  • Property svn:eol-style set to native
RevLine 
[107]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
[182]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
[211]34At present the only supported operation is evallogcond().
[182]35 */
36class mratio: public mpdf {
[192]37protected:
[182]38        //! Nominator in the form of mpdf
[192]39        const epdf* nom;
[182]40        //!Denominator in the form of epdf
[192]41        epdf* den;
42        //!flag for destructor
43        bool destroynom;
[193]44        //!datalink between conditional and nom
45        datalink_m2e dl;
[192]46public:
47        //!Default constructor. By default, the given epdf is not copied!
[182]48        //! It is assumed that this function will be used only temporarily.
[204]49        mratio ( const epdf* nom0, const RV &rv, bool copy=false ) :mpdf ( rv,nom0->_rv().subt ( rv ) ), dl ( rv,rvc,nom0->_rv() ) {
[192]50                if ( copy ) {
[182]51//                      nom = nom0->_copy_();
[204]52                        it_error ( "todo" );
[192]53                        destroynom=true;
[182]54                }
[192]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        };
[211]62        double evallogcond ( const vec &val, const vec &cond ) {
[214]63                double tmp;
[204]64                vec nom_val ( rv.count() +rvc.count() );
65                dl.fill_val_cond ( nom_val,val,cond );
[214]66                tmp = exp ( nom->evallog ( nom_val ) - den->evallog ( cond ) );
67                it_assert_debug(std::isfinite(tmp),"Infinite value");
68                return tmp;
[192]69        }
[182]70        //! Object takes ownership of nom and will destroy it
[192]71        void ownnom() {destroynom=true;}
[182]72        //! Default destructor
[192]73        ~mratio() {delete den; if ( destroynom ) {delete nom;}}
[182]74};
75
[107]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*/
[145]86class emix : public epdf {
[162]87protected:
88        //! weights of the components
89        vec w;
90        //! Component (epdfs)
91        Array<epdf*> Coms;
[178]92        //!Flag if owning Coms
93        bool destroyComs;
[162]94public:
95        //!Default constructor
[181]96        emix ( const RV &rv ) : epdf ( rv ) {};
[182]97        //! Set weights \c w and components \c Coms
[224]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.
[178]99        void set_parameters ( const vec &w, const Array<epdf*> &Coms, bool copy=true );
[107]100
[162]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        }
[229]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        }
[211]114        double evallog ( const vec &val ) const {
[162]115                int i;
116                double sum = 0.0;
[211]117                for ( i = 0;i < w.length();i++ ) {sum += w ( i ) * exp ( Coms ( i )->evallog ( val ) );}
[214]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;
[162]122        };
[211]123        vec evallog_m ( const mat &Val ) const {
[193]124                vec x=zeros ( Val.cols() );
[192]125                for ( int i = 0; i < w.length(); i++ ) {
[211]126                        x+= w ( i ) *exp ( Coms ( i )->evallog_m ( Val ) );
[182]127                }
[192]128                return log ( x );
[182]129        };
[214]130        //! Auxiliary function that returns pdflog for each component
[211]131        mat evallog_M ( const mat &Val ) const {
[192]132                mat X ( w.length(), Val.cols() );
133                for ( int i = 0; i < w.length(); i++ ) {
[211]134                        X.set_row ( i, w ( i ) *exp ( Coms ( i )->evallog_m ( Val ) ) );
[189]135                }
136                return X;
137        };
[107]138
[182]139        emix* marginal ( const RV &rv ) const;
140        mratio* condition ( const RV &rv ) const; //why not mratio!!
141
[107]142//Access methods
[162]143        //! returns a pointer to the internal mean value. Use with Care!
144        vec& _w() {return w;}
[181]145        virtual ~emix() {if ( destroyComs ) {for ( int i=0;i<Coms.length();i++ ) {delete Coms ( i );}}}
[178]146        //! Auxiliary function for taking ownership of the Coms()
[181]147        void ownComs() {destroyComs=true;}
[204]148
[193]149        //!access function
[204]150        epdf* _Coms ( int i ) {return Coms ( i );}
[107]151};
152
[115]153/*! \brief Chain rule decomposition of epdf
154
[145]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
[115]160*/
[175]161class mprod: public compositepdf, public mpdf {
[162]162protected:
[181]163        //! pointers to epdfs - shortcut to mpdfs()._epdf()
[162]164        Array<epdf*> epdfs;
[192]165        //! Data link for each mpdfs
166        Array<datalink_m2m*> dls;
[162]167public:
[168]168        /*!\brief Constructor from list of mFacs,
[165]169        */
[192]170        mprod ( Array<mpdf*> mFacs ) : compositepdf ( mFacs ), mpdf ( getrv ( true ),RV() ), epdfs ( n ), dls ( n ) {
[181]171                setrvc ( rv,rvc );
[192]172                // rv and rvc established = > we can link them with mpdfs
[181]173                for ( int i = 0;i < n;i++ ) {
[193]174                        dls ( i ) = new datalink_m2m ( mpdfs ( i )->_rv(), mpdfs ( i )->_rvc(), rv, rvc );
[181]175                }
176
177                for ( int i=0;i<n;i++ ) {
178                        epdfs ( i ) =& ( mpdfs ( i )->_epdf() );
179                }
[175]180        };
[124]181
[211]182        double evallogcond ( const vec &val, const vec &cond ) {
[162]183                int i;
[193]184                double res = 1.0;
[182]185                for ( i = n - 1;i >= 0;i-- ) {
[193]186                        /*                      if ( mpdfs(i)->_rvc().count() >0) {
187                                                        mpdfs ( i )->condition ( dls ( i )->get_cond ( val,cond ) );
188                                                }
189                                                // add logarithms
[211]190                                                res += epdfs ( i )->evallog ( dls ( i )->get_val ( val ) );*/
191                        res *= mpdfs ( i )->evallogcond (
[204]192                                   dls ( i )->get_val ( val ),
193                                   dls ( i )->get_cond ( val, cond )
194                               );
[145]195                }
[193]196                return res;
[162]197        }
198        vec samplecond ( const vec &cond, double &ll ) {
[192]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() );
[165]201                vec smpi;
202                ll = 0;
[192]203                // Hard assumption here!!! We are going backwards, to assure that samples that are needed from smp are already generated!
[162]204                for ( int i = ( n - 1 );i >= 0;i-- ) {
[193]205                        if ( mpdfs ( i )->_rvc().count() ) {
[192]206                                mpdfs ( i )->condition ( dls ( i )->get_cond ( smp ,cond ) ); // smp is val here!!
[145]207                        }
[165]208                        smpi = epdfs ( i )->sample();
[162]209                        // copy contribution of this pdf into smp
[193]210                        dls ( i )->fill_val ( smp, smpi );
[165]211                        // add ith likelihood contribution
[211]212                        ll+=epdfs ( i )->evallog ( smpi );
[145]213                }
[162]214                return smp;
215        }
216        mat samplecond ( const vec &cond, vec &ll, int N ) {
[168]217                mat Smp ( rv.count(),N );
218                for ( int i=0;i<N;i++ ) {Smp.set_col ( i,samplecond ( cond,ll ( i ) ) );}
[162]219                return Smp;
220        }
221
222        ~mprod() {};
[107]223};
224
[168]225//! Product of independent epdfs. For dependent pdfs, use mprod.
226class eprod: public epdf {
227protected:
228        //! Components (epdfs)
[170]229        Array<const epdf*> epdfs;
[168]230        //! Array of indeces
[193]231        Array<datalink_e2e*> dls;
[168]232public:
[193]233        eprod ( const Array<const epdf*> epdfs0 ) : epdf ( RV() ),epdfs ( epdfs0 ),dls ( epdfs.length() ) {
[168]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                }
[204]239                for ( int i=0;i<epdfs.length();i++ ) {
240                        dls ( i ) = new datalink_e2e ( epdfs ( i )->_rv() , rv );
241                }
[168]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();
[204]248                        dls ( i )->fill_val ( tmp, pom );
[168]249                }
250                return tmp;
251        }
[229]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        }
[168]260        vec sample() const {
261                vec tmp ( rv.count() );
262                for ( int i=0;i<epdfs.length();i++ ) {
263                        vec pom = epdfs ( i )->sample();
[204]264                        dls ( i )->fill_val ( tmp, pom );
[168]265                }
266                return tmp;
267        }
[211]268        double evallog ( const vec &val ) const {
[168]269                double tmp=0;
270                for ( int i=0;i<epdfs.length();i++ ) {
[211]271                        tmp+=epdfs ( i )->evallog ( dls ( i )->get_val ( val ) );
[168]272                }
[214]273                it_assert_debug(std::isfinite(tmp),"Infinite");
[168]274                return tmp;
275        }
[170]276        //!access function
[181]277        const epdf* operator () ( int i ) const {it_assert_debug ( i<epdfs.length(),"wrong index" );return epdfs ( i );}
[204]278
[193]279        //!Destructor
[204]280        ~eprod() {for ( int i=0;i<epdfs.length();i++ ) {delete dls ( i );}}
[168]281};
282
283
[145]284/*! \brief Mixture of mpdfs with constant weights, all mpdfs are of equal type
[124]285
286*/
[145]287class mmix : public mpdf {
[162]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() );
[124]299
[162]300                for ( int i = 0;i < Coms.length();i++ ) {
301                        Eps ( i ) = & ( Coms ( i )->_epdf() );
302                }
303                Epdf.set_parameters ( w, Eps );
304        };
[124]305
[162]306        void condition ( const vec &cond ) {
307                for ( int i = 0;i < Coms.length();i++ ) {Coms ( i )->condition ( cond );}
308        };
[124]309};
[182]310
[107]311#endif //MX_H
Note: See TracBrowser for help on using the browser.