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