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

Revision 713, 13.0 kB (checked in by mido, 15 years ago)

_m changed to _mat

emix.cfg prepared, but it is not yet debugged!

  • 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        vec evallog_mat ( const mat &Val ) const {
162                vec x = zeros ( Val.cols() );
163                for ( int i = 0; i < w.length(); i++ ) {
164                        x += w ( i ) * exp ( Coms ( i )->evallog_mat ( Val ) );
165                }
166                return log ( x );
167        };
168        /*
169        //! Auxiliary function that returns pdflog for each component
170        mat evallog_mat ( const mat &Val ) const {
171                mat X ( w.length(), Val.cols() );
172                for ( int i = 0; i < w.length(); i++ ) {
173                        X.set_row ( i, w ( i ) *exp ( Coms ( i )->evallog_mat ( Val ) ) );
174                }
175                return X;
176        };
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                        double default_weight = 1.0 / len;
218                        for( int i=0; i < len; i++)
219                                w(i) = default_weight;
220                }
221        }
222};
223SHAREDPTR( emix );
224UIREGISTER ( emix );
225
226/*!
227* \brief Mixture of egiws
228
229*/
230class egiwmix : public egiw {
231protected:
232        //! weights of the components
233        vec w;
234        //! Component (epdfs)
235        Array<egiw*> Coms;
236        //!Flag if owning Coms
237        bool destroyComs;
238public:
239        //!Default constructor
240        egiwmix ( ) : egiw ( ) {};
241
242        //! Set weights \c w and components \c Coms
243        //!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.
244        void set_parameters ( const vec &w, const Array<egiw*> &Coms, bool copy = false );
245
246        //!return expected value
247        vec mean() const;
248
249        //!return a sample from the density
250        vec sample() const;
251
252        //!return the expected variance
253        vec variance() const;
254
255        // TODO!!! Defined to follow ANSI and/or for future development
256        void mean_mat ( mat &M, mat&R ) const {};
257        double evallog_nn ( const vec &val ) const {
258                return 0;
259        };
260        double lognc () const {
261                return 0;
262        }
263
264        shared_ptr<epdf> marginal ( const RV &rv ) const;
265        //! marginal density update
266        void marginal ( const RV &rv, emix &target ) const;
267
268//Access methods
269        //! returns a pointer to the internal mean value. Use with Care!
270        vec& _w() {
271                return w;
272        }
273        virtual ~egiwmix() {
274                if ( destroyComs ) {
275                        for ( int i = 0; i < Coms.length(); i++ ) {
276                                delete Coms ( i );
277                        }
278                }
279        }
280        //! Auxiliary function for taking ownership of the Coms()
281        void ownComs() {
282                destroyComs = true;
283        }
284
285        //!access function
286        egiw* _Coms ( int i ) {
287                return Coms ( i );
288        }
289
290        void set_rv ( const RV &rv ) {
291                egiw::set_rv ( rv );
292                for ( int i = 0; i < Coms.length(); i++ ) {
293                        Coms ( i )->set_rv ( rv );
294                }
295        }
296
297        //! Approximation of a GiW mix by a single GiW pdf
298        egiw* approx();
299};
300
301/*! \brief Chain rule decomposition of epdf
302
303Probability density in the form of Chain-rule decomposition:
304\[
305f(x_1,x_2,x_3) = f(x_1|x_2,x_3)f(x_2,x_3)f(x_3)
306\]
307Note that
308*/
309class mprod: public pdf {
310private:
311        Array<shared_ptr<pdf> > pdfs;
312
313        //! Data link for each pdfs
314        Array<shared_ptr<datalink_m2m> > dls;
315
316protected:
317        //! dummy epdf used only as storage for RV and dim
318        epdf iepdf;
319
320public:
321        //! \brief Default constructor
322        mprod() { }
323
324        /*!\brief Constructor from list of mFacs
325        */
326        mprod ( const Array<shared_ptr<pdf> > &mFacs ) {
327                set_elements ( mFacs );
328        }
329        //! Set internal \c pdfs from given values
330        void set_elements (const Array<shared_ptr<pdf> > &mFacs );
331
332        double evallogcond ( const vec &val, const vec &cond ) {
333                int i;
334                double res = 0.0;
335                for ( i = pdfs.length() - 1; i >= 0; i-- ) {
336                        /*                      if ( pdfs(i)->_rvc().count() >0) {
337                                                        pdfs ( i )->condition ( dls ( i )->get_cond ( val,cond ) );
338                                                }
339                                                // add logarithms
340                                                res += epdfs ( i )->evallog ( dls ( i )->pushdown ( val ) );*/
341                        res += pdfs ( i )->evallogcond (
342                                   dls ( i )->pushdown ( val ),
343                                   dls ( i )->get_cond ( val, cond )
344                               );
345                }
346                return res;
347        }
348        vec evallogcond_mat ( const mat &Dt, const vec &cond ) {
349                vec tmp ( Dt.cols() );
350                for ( int i = 0; i < Dt.cols(); i++ ) {
351                        tmp ( i ) = evallogcond ( Dt.get_col ( i ), cond );
352                }
353                return tmp;
354        };
355        vec evallogcond_mat ( const Array<vec> &Dt, const vec &cond ) {
356                vec tmp ( Dt.length() );
357                for ( int i = 0; i < Dt.length(); i++ ) {
358                        tmp ( i ) = evallogcond ( Dt ( i ), cond );
359                }
360                return tmp;
361        };
362
363
364        //TODO smarter...
365        vec samplecond ( const vec &cond ) {
366                //! Ugly hack to help to discover if mpfs are not in proper order. Correct solution = check that explicitely.
367                vec smp = std::numeric_limits<double>::infinity() * ones ( dimension() );
368                vec smpi;
369                // Hard assumption here!!! We are going backwards, to assure that samples that are needed from smp are already generated!
370                for ( int i = ( pdfs.length() - 1 ); i >= 0; i-- ) {
371                        // generate contribution of this pdf
372                        smpi = pdfs(i)->samplecond(dls ( i )->get_cond ( smp , cond ));                 
373                        // copy contribution of this pdf into smp
374                        dls ( i )->pushup ( smp, smpi );
375                }
376                return smp;
377        }
378
379        //! Load from structure with elements:
380        //!  \code
381        //! { class='mprod';
382        //!   pdfs = (..., ...);     // list of pdfs in the order of chain rule
383        //! }
384        //! \endcode
385        //!@}
386        void from_setting ( const Setting &set ) {
387                Array<shared_ptr<pdf> > atmp; //temporary Array
388                UI::get ( atmp, set, "pdfs", UI::compulsory );
389                set_elements ( atmp );
390        }
391};
392UIREGISTER ( mprod );
393SHAREDPTR ( mprod );
394
395//! Product of independent epdfs. For dependent pdfs, use mprod.
396class eprod: public epdf {
397protected:
398        //! Components (epdfs)
399        Array<const epdf*> epdfs;
400        //! Array of indeces
401        Array<datalink*> dls;
402public:
403        //! Default constructor
404        eprod () : epdfs ( 0 ), dls ( 0 ) {};
405        //! Set internal
406        void set_parameters ( const Array<const epdf*> &epdfs0, bool named = true ) {
407                epdfs = epdfs0;//.set_length ( epdfs0.length() );
408                dls.set_length ( epdfs.length() );
409
410                bool independent = true;
411                if ( named ) {
412                        for ( int i = 0; i < epdfs.length(); i++ ) {
413                                independent = rv.add ( epdfs ( i )->_rv() );
414                                bdm_assert_debug ( independent, "eprod:: given components are not independent." );
415                        }
416                        dim = rv._dsize();
417                } else {
418                        dim = 0;
419                        for ( int i = 0; i < epdfs.length(); i++ ) {
420                                dim += epdfs ( i )->dimension();
421                        }
422                }
423                //
424                int cumdim = 0;
425                int dimi = 0;
426                int i;
427                for ( i = 0; i < epdfs.length(); i++ ) {
428                        dls ( i ) = new datalink;
429                        if ( named ) {
430                                dls ( i )->set_connection ( epdfs ( i )->_rv() , rv );
431                        } else {
432                                dimi = epdfs ( i )->dimension();
433                                dls ( i )->set_connection ( dimi, dim, linspace ( cumdim, cumdim + dimi - 1 ) );
434                                cumdim += dimi;
435                        }
436                }
437        }
438
439        vec mean() const {
440                vec tmp ( dim );
441                for ( int i = 0; i < epdfs.length(); i++ ) {
442                        vec pom = epdfs ( i )->mean();
443                        dls ( i )->pushup ( tmp, pom );
444                }
445                return tmp;
446        }
447        vec variance() const {
448                vec tmp ( dim ); //second moment
449                for ( int i = 0; i < epdfs.length(); i++ ) {
450                        vec pom = epdfs ( i )->mean();
451                        dls ( i )->pushup ( tmp, pow ( pom, 2 ) );
452                }
453                return tmp - pow ( mean(), 2 );
454        }
455        vec sample() const {
456                vec tmp ( dim );
457                for ( int i = 0; i < epdfs.length(); i++ ) {
458                        vec pom = epdfs ( i )->sample();
459                        dls ( i )->pushup ( tmp, pom );
460                }
461                return tmp;
462        }
463        double evallog ( const vec &val ) const {
464                double tmp = 0;
465                for ( int i = 0; i < epdfs.length(); i++ ) {
466                        tmp += epdfs ( i )->evallog ( dls ( i )->pushdown ( val ) );
467                }
468                bdm_assert_debug ( std::isfinite ( tmp ), "Infinite" );
469                return tmp;
470        }
471        //!access function
472        const epdf* operator () ( int i ) const {
473                bdm_assert_debug ( i < epdfs.length(), "wrong index" );
474                return epdfs ( i );
475        }
476
477        //!Destructor
478        ~eprod() {
479                for ( int i = 0; i < epdfs.length(); i++ ) {
480                        delete dls ( i );
481                }
482        }
483};
484
485
486/*! \brief Mixture of pdfs with constant weights, all pdfs are of equal RV and RVC
487
488*/
489class mmix : public pdf {
490protected:
491        //! Component (pdfs)
492        Array<shared_ptr<pdf> > Coms;
493        //!weights of the components
494        vec w;
495public:
496        //!Default constructor
497        mmix() : Coms(0) { }
498
499        //! Set weights \c w and components \c R
500        void set_parameters ( const vec &w0, const Array<shared_ptr<pdf> > &Coms0 ) {
501                //!\todo check if all components are OK
502                Coms = Coms0;
503                w=w0;   
504
505                if (Coms0.length()>0){
506                        set_rv(Coms(0)->_rv());
507                        dim = rv._dsize();
508                        set_rvc(Coms(0)->_rvc());
509                        dimc = rvc._dsize();
510                }
511        }
512        double evallogcond (const vec &dt, const vec &cond) {
513                double ll=0.0;
514                for (int i=0;i<Coms.length();i++){
515                        ll+=Coms(i)->evallogcond(dt,cond);
516                }
517                return ll;
518        }
519
520        vec samplecond (const vec &cond);
521
522        //! Load from structure with elements:
523        //!  \code
524        //! { class='mmix';
525        //!   pdfs = (..., ...);     // list of pdfs in the mixture
526        //!   weights = ( 0.5, 0.5 ); // weights of pdfs in the mixture
527        //! }
528        //! \endcode
529        //!@}
530        void from_setting ( const Setting &set ) {
531                UI::get ( Coms, set, "pdfs", UI::compulsory );
532
533                if( !UI::get( w, set, "weights", UI::optional ) )
534                {
535                        int len = Coms.length();
536                        w.set_length( len );
537                        double default_weight = 1.0 / len;
538                        for( int i=0; i < len; i++)
539                                w(i) = default_weight;
540                }
541        }
542};
543UIREGISTER ( mmix );
544
545}
546#endif //MX_H
Note: See TracBrowser for help on using the browser.