root/library/bdm/stat/emix.h @ 750

Revision 750, 10.9 kB (checked in by sarka, 15 years ago)

dimc ze set_parameters do validate

  • 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
[394]13#ifndef EMIX_H
14#define EMIX_H
[107]15
[477]16#define LOG2  0.69314718055995
[333]17
[461]18#include "../shared_ptr.h"
[384]19#include "exp_family.h"
[107]20
[286]21namespace bdm {
[107]22
[182]23//this comes first because it is used inside emix!
24
25/*! \brief Class representing ratio of two densities
26which arise e.g. by applying the Bayes rule.
27It represents density in the form:
28\f[
29f(rv|rvc) = \frac{f(rv,rvc)}{f(rvc)}
30\f]
31where \f$ f(rvc) = \int f(rv,rvc) d\ rv \f$.
32
33In particular this type of arise by conditioning of a mixture model.
34
[211]35At present the only supported operation is evallogcond().
[182]36 */
[693]37class mratio: public pdf {
[192]38protected:
[693]39        //! Nominator in the form of pdf
[192]40        const epdf* nom;
[504]41
[182]42        //!Denominator in the form of epdf
[504]43        shared_ptr<epdf> den;
44
[192]45        //!flag for destructor
46        bool destroynom;
[193]47        //!datalink between conditional and nom
48        datalink_m2e dl;
[192]49public:
50        //!Default constructor. By default, the given epdf is not copied!
[182]51        //! It is assumed that this function will be used only temporarily.
[693]52        mratio ( const epdf* nom0, const RV &rv, bool copy = false ) : pdf ( ), dl ( ) {
[286]53                // adjust rv and rvc
[675]54
[737]55                set_rv ( rv ); // TODO co kdyby tohle samo uz nastavovalo dimension?!?!
[675]56                dim = rv._dsize();
57
[286]58                rvc = nom0->_rv().subt ( rv );
59                dimc = rvc._dsize();
[737]60
[286]61                //prepare data structures
[477]62                if ( copy ) {
[565]63                        bdm_error ( "todo" );
64                        // destroynom = true;
[477]65                } else {
66                        nom = nom0;
67                        destroynom = false;
68                }
[565]69                bdm_assert_debug ( rvc.length() > 0, "Makes no sense to use this object!" );
[477]70
[286]71                // build denominator
[192]72                den = nom->marginal ( rvc );
[477]73                dl.set_connection ( rv, rvc, nom0->_rv() );
[192]74        };
[675]75
[211]76        double evallogcond ( const vec &val, const vec &cond ) {
[214]77                double tmp;
[487]78                vec nom_val ( dimension() + dimc );
[477]79                dl.pushup_cond ( nom_val, val, cond );
[214]80                tmp = exp ( nom->evallog ( nom_val ) - den->evallog ( cond ) );
81                return tmp;
[192]82        }
[182]83        //! Object takes ownership of nom and will destroy it
[477]84        void ownnom() {
85                destroynom = true;
86        }
[182]87        //! Default destructor
[477]88        ~mratio() {
89                if ( destroynom ) {
90                        delete nom;
91                }
92        }
[550]93
94private:
95        // not implemented
96        mratio ( const mratio & );
[737]97        mratio &operator= ( const mratio & );
[182]98};
99
[107]100/*!
101* \brief Mixture of epdfs
102
103Density function:
104\f[
105f(x) = \sum_{i=1}^{n} w_{i} f_i(x), \quad \sum_{i=1}^n w_i = 1.
106\f]
107where \f$f_i(x)\f$ is any density on random variable \f$x\f$, called \a component,
108
109*/
[145]110class emix : public epdf {
[162]111protected:
112        //! weights of the components
113        vec w;
[559]114
[162]115        //! Component (epdfs)
[504]116        Array<shared_ptr<epdf> > Coms;
117
[162]118public:
[559]119        //! Default constructor
120        emix ( ) : epdf ( ) { }
121
[737]122        /*!
123          \brief Set weights \c w and components \c Coms
[559]124
[737]125          Shared pointers in Coms are kept inside this instance and
126          shouldn't be modified after being passed to this method.
127        */
[504]128        void set_parameters ( const vec &w, const Array<shared_ptr<epdf> > &Coms );
[750]129   
130        virtual void validate ();
[107]131
[162]132        vec sample() const;
[715]133
[739]134        vec mean() const;
[715]135
[739]136        vec variance() const;
137
138        double evallog ( const vec &val ) const;
139
140        vec evallog_mat ( const mat &Val ) const;
141
[214]142        //! Auxiliary function that returns pdflog for each component
[739]143        mat evallog_coms ( const mat &Val ) const;
[107]144
[504]145        shared_ptr<epdf> marginal ( const RV &rv ) const;
[536]146        //! Update already existing marginal density  \c target
[504]147        void marginal ( const RV &rv, emix &target ) const;
[693]148        shared_ptr<pdf> condition ( const RV &rv ) const;
[182]149
[713]150        //Access methods
[162]151        //! returns a pointer to the internal mean value. Use with Care!
[477]152        vec& _w() {
153                return w;
154        }
[204]155
[193]156        //!access function
[504]157        shared_ptr<epdf> _Coms ( int i ) {
[477]158                return Coms ( i );
[286]159        }
[504]160
[477]161        void set_rv ( const RV &rv ) {
162                epdf::set_rv ( rv );
163                for ( int i = 0; i < Coms.length(); i++ ) {
164                        Coms ( i )->set_rv ( rv );
165                }
166        }
[713]167
168        //! Load from structure with elements:
169        //!  \code
170        //! { class='emix';
171        //!   pdfs = (..., ...);     // list of pdfs in the mixture
172        //!   weights = ( 0.5, 0.5 ); // weights of pdfs in the mixture
173        //! }
174        //! \endcode
175        //!@}
176        void from_setting ( const Setting &set ) {
[737]177
178                vec w0;
[716]179                Array<shared_ptr<epdf> > Coms0;
[737]180
[716]181                UI::get ( Coms0, set, "pdfs", UI::compulsory );
[713]182
[737]183                if ( !UI::get ( w0, set, "weights", UI::optional ) ) {
[713]184                        int len = Coms.length();
[737]185                        w0.set_length ( len );
[716]186                        w0 = 1.0 / len;
[713]187                }
[716]188
189                // TODO asi lze nacitat primocare do w a coms, jen co bude hotovy validate()
[737]190                set_parameters ( w0, Coms0 );
[750]191                validate();
[713]192        }
[107]193};
[737]194SHAREDPTR ( emix );
[713]195UIREGISTER ( emix );
[107]196
[333]197/*!
198* \brief Mixture of egiws
199
200*/
201class egiwmix : public egiw {
202protected:
203        //! weights of the components
204        vec w;
205        //! Component (epdfs)
206        Array<egiw*> Coms;
207        //!Flag if owning Coms
208        bool destroyComs;
209public:
210        //!Default constructor
211        egiwmix ( ) : egiw ( ) {};
212
213        //! Set weights \c w and components \c Coms
214        //!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.
[477]215        void set_parameters ( const vec &w, const Array<egiw*> &Coms, bool copy = false );
[333]216
217        //!return expected value
218        vec mean() const;
219
220        //!return a sample from the density
221        vec sample() const;
222
223        //!return the expected variance
[477]224        vec variance() const;
[333]225
226        // TODO!!! Defined to follow ANSI and/or for future development
227        void mean_mat ( mat &M, mat&R ) const {};
[477]228        double evallog_nn ( const vec &val ) const {
229                return 0;
230        };
231        double lognc () const {
232                return 0;
[504]233        }
[333]234
[504]235        shared_ptr<epdf> marginal ( const RV &rv ) const;
[660]236        //! marginal density update
[504]237        void marginal ( const RV &rv, emix &target ) const;
238
[333]239//Access methods
240        //! returns a pointer to the internal mean value. Use with Care!
[477]241        vec& _w() {
242                return w;
243        }
244        virtual ~egiwmix() {
245                if ( destroyComs ) {
246                        for ( int i = 0; i < Coms.length(); i++ ) {
247                                delete Coms ( i );
248                        }
249                }
250        }
[333]251        //! Auxiliary function for taking ownership of the Coms()
[477]252        void ownComs() {
253                destroyComs = true;
254        }
[333]255
256        //!access function
[477]257        egiw* _Coms ( int i ) {
258                return Coms ( i );
259        }
[333]260
[477]261        void set_rv ( const RV &rv ) {
262                egiw::set_rv ( rv );
263                for ( int i = 0; i < Coms.length(); i++ ) {
264                        Coms ( i )->set_rv ( rv );
265                }
[333]266        }
267
268        //! Approximation of a GiW mix by a single GiW pdf
269        egiw* approx();
270};
271
[115]272/*! \brief Chain rule decomposition of epdf
273
[145]274Probability density in the form of Chain-rule decomposition:
275\[
276f(x_1,x_2,x_3) = f(x_1|x_2,x_3)f(x_2,x_3)f(x_3)
277\]
278Note that
[115]279*/
[693]280class mprod: public pdf {
[507]281private:
[693]282        Array<shared_ptr<pdf> > pdfs;
[507]283
[693]284        //! Data link for each pdfs
[546]285        Array<shared_ptr<datalink_m2m> > dls;
[461]286
[546]287protected:
[487]288        //! dummy epdf used only as storage for RV and dim
289        epdf iepdf;
[461]290
[162]291public:
[507]292        //! \brief Default constructor
293        mprod() { }
294
295        /*!\brief Constructor from list of mFacs
[165]296        */
[693]297        mprod ( const Array<shared_ptr<pdf> > &mFacs ) {
[477]298                set_elements ( mFacs );
[461]299        }
[693]300        //! Set internal \c pdfs from given values
[737]301        void set_elements ( const Array<shared_ptr<pdf> > &mFacs );
[477]302
[739]303        double evallogcond ( const vec &val, const vec &cond );
[395]304
[739]305        vec evallogcond_mat ( const mat &Dt, const vec &cond );
[395]306
[739]307        vec evallogcond_mat ( const Array<vec> &Dt, const vec &cond );
308
[270]309        //TODO smarter...
310        vec samplecond ( const vec &cond ) {
[477]311                //! Ugly hack to help to discover if mpfs are not in proper order. Correct solution = check that explicitely.
[487]312                vec smp = std::numeric_limits<double>::infinity() * ones ( dimension() );
[165]313                vec smpi;
[192]314                // Hard assumption here!!! We are going backwards, to assure that samples that are needed from smp are already generated!
[693]315                for ( int i = ( pdfs.length() - 1 ); i >= 0; i-- ) {
316                        // generate contribution of this pdf
[737]317                        smpi = pdfs ( i )->samplecond ( dls ( i )->get_cond ( smp , cond ) );
[162]318                        // copy contribution of this pdf into smp
[270]319                        dls ( i )->pushup ( smp, smpi );
[145]320                }
[162]321                return smp;
322        }
323
[395]324        //! Load from structure with elements:
325        //!  \code
326        //! { class='mprod';
[693]327        //!   pdfs = (..., ...);     // list of pdfs in the order of chain rule
[395]328        //! }
329        //! \endcode
330        //!@}
[477]331        void from_setting ( const Setting &set ) {
[693]332                Array<shared_ptr<pdf> > atmp; //temporary Array
333                UI::get ( atmp, set, "pdfs", UI::compulsory );
[527]334                set_elements ( atmp );
[395]335        }
[107]336};
[477]337UIREGISTER ( mprod );
[529]338SHAREDPTR ( mprod );
[107]339
[168]340//! Product of independent epdfs. For dependent pdfs, use mprod.
341class eprod: public epdf {
342protected:
343        //! Components (epdfs)
[170]344        Array<const epdf*> epdfs;
[168]345        //! Array of indeces
[270]346        Array<datalink*> dls;
[168]347public:
[536]348        //! Default constructor
[477]349        eprod () : epdfs ( 0 ), dls ( 0 ) {};
[737]350        //! Set internal
[477]351        void set_parameters ( const Array<const epdf*> &epdfs0, bool named = true ) {
352                epdfs = epdfs0;//.set_length ( epdfs0.length() );
[286]353                dls.set_length ( epdfs.length() );
354
[477]355                bool independent = true;
[286]356                if ( named ) {
[477]357                        for ( int i = 0; i < epdfs.length(); i++ ) {
358                                independent = rv.add ( epdfs ( i )->_rv() );
[565]359                                bdm_assert_debug ( independent, "eprod:: given components are not independent." );
[286]360                        }
[477]361                        dim = rv._dsize();
362                } else {
363                        dim = 0;
364                        for ( int i = 0; i < epdfs.length(); i++ ) {
365                                dim += epdfs ( i )->dimension();
[286]366                        }
[204]367                }
[286]368                //
[477]369                int cumdim = 0;
370                int dimi = 0;
[286]371                int i;
[477]372                for ( i = 0; i < epdfs.length(); i++ ) {
[286]373                        dls ( i ) = new datalink;
[477]374                        if ( named ) {
375                                dls ( i )->set_connection ( epdfs ( i )->_rv() , rv );
376                        } else {
[286]377                                dimi = epdfs ( i )->dimension();
[477]378                                dls ( i )->set_connection ( dimi, dim, linspace ( cumdim, cumdim + dimi - 1 ) );
379                                cumdim += dimi;
[286]380                        }
381                }
[168]382        }
383
[739]384        vec mean() const;
385
386        vec variance() const;
387
388        vec sample() const;
389
390        double evallog ( const vec &val ) const;
391
[170]392        //!access function
[477]393        const epdf* operator () ( int i ) const {
[565]394                bdm_assert_debug ( i < epdfs.length(), "wrong index" );
[477]395                return epdfs ( i );
396        }
[204]397
[193]398        //!Destructor
[477]399        ~eprod() {
400                for ( int i = 0; i < epdfs.length(); i++ ) {
401                        delete dls ( i );
402                }
403        }
[168]404};
405
406
[693]407/*! \brief Mixture of pdfs with constant weights, all pdfs are of equal RV and RVC
[124]408
409*/
[693]410class mmix : public pdf {
[488]411protected:
[693]412        //! Component (pdfs)
413        Array<shared_ptr<pdf> > Coms;
[488]414        //!weights of the components
415        vec w;
416public:
417        //!Default constructor
[737]418        mmix() : Coms ( 0 ) { }
[461]419
[488]420        //! Set weights \c w and components \c R
[693]421        void set_parameters ( const vec &w0, const Array<shared_ptr<pdf> > &Coms0 ) {
[536]422                //!\todo check if all components are OK
[488]423                Coms = Coms0;
[737]424                w = w0;
[503]425
[737]426                if ( Coms0.length() > 0 ) {
427                        set_rv ( Coms ( 0 )->_rv() );
[675]428                        dim = rv._dsize();
[737]429                        set_rvc ( Coms ( 0 )->_rvc() );
[513]430                        dimc = rvc._dsize();
431                }
[488]432        }
[737]433        double evallogcond ( const vec &dt, const vec &cond ) {
434                double ll = 0.0;
435                for ( int i = 0; i < Coms.length(); i++ ) {
436                        ll += Coms ( i )->evallogcond ( dt, cond );
[488]437                }
438                return ll;
439        }
440
[737]441        vec samplecond ( const vec &cond );
[488]442
[711]443        //! Load from structure with elements:
444        //!  \code
445        //! { class='mmix';
446        //!   pdfs = (..., ...);     // list of pdfs in the mixture
447        //!   weights = ( 0.5, 0.5 ); // weights of pdfs in the mixture
448        //! }
449        //! \endcode
450        //!@}
451        void from_setting ( const Setting &set ) {
[737]452                UI::get ( Coms, set, "pdfs", UI::compulsory );
[711]453
[716]454                // TODO ma byt zde, ci ve validate()?
[737]455                if ( Coms.length() > 0 ) {
456                        set_rv ( Coms ( 0 )->_rv() );
[716]457                        dim = rv._dsize();
[737]458                        set_rvc ( Coms ( 0 )->_rvc() );
[716]459                        dimc = rvc._dsize();
460                }
461
[737]462                if ( !UI::get ( w, set, "weights", UI::optional ) ) {
[711]463                        int len = Coms.length();
[737]464                        w.set_length ( len );
[715]465                        w = 1.0 / len;
[711]466                }
467        }
[488]468};
[737]469SHAREDPTR ( mmix );
[711]470UIREGISTER ( mmix );
[488]471
[254]472}
[107]473#endif //MX_H
Note: See TracBrowser for help on using the browser.