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

Revision 715, 12.9 kB (checked in by mido, 15 years ago)

patch of the previous commits

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