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

Revision 737, 13.3 kB (checked in by mido, 14 years ago)

ASTYLER RUN OVER THE WHOLE LIBRARY, JUPEE

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