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

Revision 739, 10.9 kB (checked in by mido, 14 years ago)

the rest of h to cpp movements, with exception of from_setting and validate to avoid conflicts with Sarka

  • 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
132        vec mean() const;
133
134        vec variance() const;
135
136        double evallog ( const vec &val ) const;
137
138        vec evallog_mat ( const mat &Val ) const;
139
140        //! Auxiliary function that returns pdflog for each component
141        mat evallog_coms ( const mat &Val ) const;
142
143        shared_ptr<epdf> marginal ( const RV &rv ) const;
144        //! Update already existing marginal density  \c target
145        void marginal ( const RV &rv, emix &target ) const;
146        shared_ptr<pdf> condition ( const RV &rv ) const;
147
148        //Access methods
149        //! returns a pointer to the internal mean value. Use with Care!
150        vec& _w() {
151                return w;
152        }
153
154        //!access function
155        shared_ptr<epdf> _Coms ( int i ) {
156                return Coms ( i );
157        }
158
159        void set_rv ( const RV &rv ) {
160                epdf::set_rv ( rv );
161                for ( int i = 0; i < Coms.length(); i++ ) {
162                        Coms ( i )->set_rv ( rv );
163                }
164        }
165
166        //! Load from structure with elements:
167        //!  \code
168        //! { class='emix';
169        //!   pdfs = (..., ...);     // list of pdfs in the mixture
170        //!   weights = ( 0.5, 0.5 ); // weights of pdfs in the mixture
171        //! }
172        //! \endcode
173        //!@}
174        void from_setting ( const Setting &set ) {
175
176                vec w0;
177                Array<shared_ptr<epdf> > Coms0;
178
179                UI::get ( Coms0, set, "pdfs", UI::compulsory );
180
181                if ( !UI::get ( w0, set, "weights", UI::optional ) ) {
182                        int len = Coms.length();
183                        w0.set_length ( len );
184                        w0 = 1.0 / len;
185                }
186
187                // TODO asi lze nacitat primocare do w a coms, jen co bude hotovy validate()
188                set_parameters ( w0, Coms0 );
189        }
190};
191SHAREDPTR ( emix );
192UIREGISTER ( emix );
193
194/*!
195* \brief Mixture of egiws
196
197*/
198class egiwmix : public egiw {
199protected:
200        //! weights of the components
201        vec w;
202        //! Component (epdfs)
203        Array<egiw*> Coms;
204        //!Flag if owning Coms
205        bool destroyComs;
206public:
207        //!Default constructor
208        egiwmix ( ) : egiw ( ) {};
209
210        //! Set weights \c w and components \c Coms
211        //!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.
212        void set_parameters ( const vec &w, const Array<egiw*> &Coms, bool copy = false );
213
214        //!return expected value
215        vec mean() const;
216
217        //!return a sample from the density
218        vec sample() const;
219
220        //!return the expected variance
221        vec variance() const;
222
223        // TODO!!! Defined to follow ANSI and/or for future development
224        void mean_mat ( mat &M, mat&R ) const {};
225        double evallog_nn ( const vec &val ) const {
226                return 0;
227        };
228        double lognc () const {
229                return 0;
230        }
231
232        shared_ptr<epdf> marginal ( const RV &rv ) const;
233        //! marginal density update
234        void marginal ( const RV &rv, emix &target ) const;
235
236//Access methods
237        //! returns a pointer to the internal mean value. Use with Care!
238        vec& _w() {
239                return w;
240        }
241        virtual ~egiwmix() {
242                if ( destroyComs ) {
243                        for ( int i = 0; i < Coms.length(); i++ ) {
244                                delete Coms ( i );
245                        }
246                }
247        }
248        //! Auxiliary function for taking ownership of the Coms()
249        void ownComs() {
250                destroyComs = true;
251        }
252
253        //!access function
254        egiw* _Coms ( int i ) {
255                return Coms ( i );
256        }
257
258        void set_rv ( const RV &rv ) {
259                egiw::set_rv ( rv );
260                for ( int i = 0; i < Coms.length(); i++ ) {
261                        Coms ( i )->set_rv ( rv );
262                }
263        }
264
265        //! Approximation of a GiW mix by a single GiW pdf
266        egiw* approx();
267};
268
269/*! \brief Chain rule decomposition of epdf
270
271Probability density in the form of Chain-rule decomposition:
272\[
273f(x_1,x_2,x_3) = f(x_1|x_2,x_3)f(x_2,x_3)f(x_3)
274\]
275Note that
276*/
277class mprod: public pdf {
278private:
279        Array<shared_ptr<pdf> > pdfs;
280
281        //! Data link for each pdfs
282        Array<shared_ptr<datalink_m2m> > dls;
283
284protected:
285        //! dummy epdf used only as storage for RV and dim
286        epdf iepdf;
287
288public:
289        //! \brief Default constructor
290        mprod() { }
291
292        /*!\brief Constructor from list of mFacs
293        */
294        mprod ( const Array<shared_ptr<pdf> > &mFacs ) {
295                set_elements ( mFacs );
296        }
297        //! Set internal \c pdfs from given values
298        void set_elements ( const Array<shared_ptr<pdf> > &mFacs );
299
300        double evallogcond ( const vec &val, const vec &cond );
301
302        vec evallogcond_mat ( const mat &Dt, const vec &cond );
303
304        vec evallogcond_mat ( const Array<vec> &Dt, const vec &cond );
305
306        //TODO smarter...
307        vec samplecond ( const vec &cond ) {
308                //! Ugly hack to help to discover if mpfs are not in proper order. Correct solution = check that explicitely.
309                vec smp = std::numeric_limits<double>::infinity() * ones ( dimension() );
310                vec smpi;
311                // Hard assumption here!!! We are going backwards, to assure that samples that are needed from smp are already generated!
312                for ( int i = ( pdfs.length() - 1 ); i >= 0; i-- ) {
313                        // generate contribution of this pdf
314                        smpi = pdfs ( i )->samplecond ( dls ( i )->get_cond ( smp , cond ) );
315                        // copy contribution of this pdf into smp
316                        dls ( i )->pushup ( smp, smpi );
317                }
318                return smp;
319        }
320
321        //! Load from structure with elements:
322        //!  \code
323        //! { class='mprod';
324        //!   pdfs = (..., ...);     // list of pdfs in the order of chain rule
325        //! }
326        //! \endcode
327        //!@}
328        void from_setting ( const Setting &set ) {
329                Array<shared_ptr<pdf> > atmp; //temporary Array
330                UI::get ( atmp, set, "pdfs", UI::compulsory );
331                set_elements ( atmp );
332        }
333};
334UIREGISTER ( mprod );
335SHAREDPTR ( mprod );
336
337//! Product of independent epdfs. For dependent pdfs, use mprod.
338class eprod: public epdf {
339protected:
340        //! Components (epdfs)
341        Array<const epdf*> epdfs;
342        //! Array of indeces
343        Array<datalink*> dls;
344public:
345        //! Default constructor
346        eprod () : epdfs ( 0 ), dls ( 0 ) {};
347        //! Set internal
348        void set_parameters ( const Array<const epdf*> &epdfs0, bool named = true ) {
349                epdfs = epdfs0;//.set_length ( epdfs0.length() );
350                dls.set_length ( epdfs.length() );
351
352                bool independent = true;
353                if ( named ) {
354                        for ( int i = 0; i < epdfs.length(); i++ ) {
355                                independent = rv.add ( epdfs ( i )->_rv() );
356                                bdm_assert_debug ( independent, "eprod:: given components are not independent." );
357                        }
358                        dim = rv._dsize();
359                } else {
360                        dim = 0;
361                        for ( int i = 0; i < epdfs.length(); i++ ) {
362                                dim += epdfs ( i )->dimension();
363                        }
364                }
365                //
366                int cumdim = 0;
367                int dimi = 0;
368                int i;
369                for ( i = 0; i < epdfs.length(); i++ ) {
370                        dls ( i ) = new datalink;
371                        if ( named ) {
372                                dls ( i )->set_connection ( epdfs ( i )->_rv() , rv );
373                        } else {
374                                dimi = epdfs ( i )->dimension();
375                                dls ( i )->set_connection ( dimi, dim, linspace ( cumdim, cumdim + dimi - 1 ) );
376                                cumdim += dimi;
377                        }
378                }
379        }
380
381        vec mean() const;
382
383        vec variance() const;
384
385        vec sample() const;
386
387        double evallog ( const vec &val ) const;
388
389        //!access function
390        const epdf* operator () ( int i ) const {
391                bdm_assert_debug ( i < epdfs.length(), "wrong index" );
392                return epdfs ( i );
393        }
394
395        //!Destructor
396        ~eprod() {
397                for ( int i = 0; i < epdfs.length(); i++ ) {
398                        delete dls ( i );
399                }
400        }
401};
402
403
404/*! \brief Mixture of pdfs with constant weights, all pdfs are of equal RV and RVC
405
406*/
407class mmix : public pdf {
408protected:
409        //! Component (pdfs)
410        Array<shared_ptr<pdf> > Coms;
411        //!weights of the components
412        vec w;
413public:
414        //!Default constructor
415        mmix() : Coms ( 0 ) { }
416
417        //! Set weights \c w and components \c R
418        void set_parameters ( const vec &w0, const Array<shared_ptr<pdf> > &Coms0 ) {
419                //!\todo check if all components are OK
420                Coms = Coms0;
421                w = w0;
422
423                if ( Coms0.length() > 0 ) {
424                        set_rv ( Coms ( 0 )->_rv() );
425                        dim = rv._dsize();
426                        set_rvc ( Coms ( 0 )->_rvc() );
427                        dimc = rvc._dsize();
428                }
429        }
430        double evallogcond ( const vec &dt, const vec &cond ) {
431                double ll = 0.0;
432                for ( int i = 0; i < Coms.length(); i++ ) {
433                        ll += Coms ( i )->evallogcond ( dt, cond );
434                }
435                return ll;
436        }
437
438        vec samplecond ( const vec &cond );
439
440        //! Load from structure with elements:
441        //!  \code
442        //! { class='mmix';
443        //!   pdfs = (..., ...);     // list of pdfs in the mixture
444        //!   weights = ( 0.5, 0.5 ); // weights of pdfs in the mixture
445        //! }
446        //! \endcode
447        //!@}
448        void from_setting ( const Setting &set ) {
449                UI::get ( Coms, set, "pdfs", UI::compulsory );
450
451                // TODO ma byt zde, ci ve validate()?
452                if ( Coms.length() > 0 ) {
453                        set_rv ( Coms ( 0 )->_rv() );
454                        dim = rv._dsize();
455                        set_rvc ( Coms ( 0 )->_rvc() );
456                        dimc = rvc._dsize();
457                }
458
459                if ( !UI::get ( w, set, "weights", UI::optional ) ) {
460                        int len = Coms.length();
461                        w.set_length ( len );
462                        w = 1.0 / len;
463                }
464        }
465};
466SHAREDPTR ( mmix );
467UIREGISTER ( mmix );
468
469}
470#endif //MX_H
Note: See TracBrowser for help on using the browser.