root/applications/robust/robustlib.h @ 1204

Revision 1204, 18.8 kB (checked in by sindj, 14 years ago)

Rozpracovani funkci na Bayes data update. JS

Line 
1/*!
2  \file
3  \brief Robust Bayesian auto-regression model
4  \author Jan Sindelar.
5*/
6
7#ifndef ROBUST_H
8#define ROBUST_H
9
10#include <stat/exp_family.h>
11#include <limits>
12#include <vector>
13#include <algorithm>
14       
15using namespace bdm;
16using namespace std;
17using namespace itpp;
18
19const double max_range = numeric_limits<double>::max()/10e-5;
20
21class polyhedron;
22class vertex;
23
24/// A class describing a single polyhedron of the split complex. From a collection of such classes a Hasse diagram
25/// of the structure in the exponent of a Laplace-Inverse-Gamma density will be created.
26class polyhedron
27{
28        /// A property having a value of 1 usually, with higher value only if the polyhedron arises as a coincidence of
29        /// more than just the necessary number of conditions. For example if a newly created line passes through an already
30        /// existing point, the points multiplicity will rise by 1.
31        int multiplicity;       
32
33        int split_state;
34
35        int merge_state;
36
37       
38
39public:
40        /// A list of polyhedrons parents within the Hasse diagram.
41        vector<polyhedron*> parents;
42
43        /// A list of polyhedrons children withing the Hasse diagram.
44        vector<polyhedron*> children;
45
46        /// All the vertices of the given polyhedron
47        vector<vertex*> vertices;
48
49        /// A list used for storing children that lie in the positive region related to a certain condition
50        vector<polyhedron*> positivechildren;
51
52        /// A list used for storing children that lie in the negative region related to a certain condition
53        vector<polyhedron*> negativechildren;
54
55        /// Children intersecting the condition
56        vector<polyhedron*> neutralchildren;
57
58        vector<polyhedron*> mergechildren;
59
60        polyhedron* positiveparent;
61
62        polyhedron* negativeparent;
63
64        int message_counter;
65
66        /// List of triangulation polyhedrons of the polyhedron given by their relative vertices.
67        vector<vector<vertex*>> triangulations;
68
69        /// A list of relative addresses serving for Hasse diagram construction.
70        vector<int> kids_rel_addresses;
71
72        /// Default constructor
73        polyhedron()
74        {
75                multiplicity = 1;
76
77                message_counter = 0;
78        }
79       
80        /// Setter for raising multiplicity
81        void raise_multiplicity()
82        {
83                multiplicity++;
84        }
85
86        /// Setter for lowering multiplicity
87        void lower_multiplicity()
88        {
89                multiplicity--;
90        }
91       
92        /// An obligatory operator, when the class is used within a C++ STL structure like a vector
93        int operator==(polyhedron polyhedron2)
94        {
95                return true;
96        }
97
98        /// An obligatory operator, when the class is used within a C++ STL structure like a vector
99        int operator<(polyhedron polyhedron2)
100        {
101                return false;
102        }
103
104        void set_state(double state_indicator, actions action)
105        {
106                switch(action)
107                {
108                        case MERGE:
109                                merge_state = (int)sign(state_indicator);                       
110                        break;
111                        case SPLIT:
112                                split_state = (int)sign(state_indicator);
113                        break;
114                }
115        }
116
117        int get_state(actions action)
118        {
119                switch(action)
120                {
121                        case MERGE:
122                                return merge_state;                     
123                        break;
124                        case SPLIT:
125                                return split_state;
126                        break;
127                }
128        }
129
130        int number_of_children()
131        {
132                return children.size()+positivechildren.size()+negativechildren.size()+neutralchildren.size();
133        }
134
135        void send_state_message(bool shouldsplit, bool shouldmerge)
136        {
137                if(shouldsplit||shouldmerge)
138                {
139                        for(vector<polyhedron*>::iterator parent_iterator = parents.begin();parent_iterator<parents.end();parent_iterator++)
140                        {
141                                polyhedron* current_parent = *parent_iterator;
142
143                                current_parent->message_counter++;
144
145                                bool is_last = (current_parent->message_counter == current_parent->number_of_children());
146
147                                if(shouldmerge)
148                                {
149                                        int child_state  = get_state(MERGE);
150                                        int parent_state = current_parent->get_state(MERGE);
151
152                                        if(parent_state == NULL || parent_state == 0)
153                                        {
154                                                current_parent->set_state(child_state, MERGE);
155
156                                                if(child_state == 0)
157                                                {
158                                                        current_parent->mergechildren.push_back(this);
159                                                }
160                                        }
161                                        else
162                                        {
163                                                if(child_state == 0)
164                                                {
165                                                        if(parent_state > 0)
166                                                        {
167                                                                positiveparent = current_parent;
168                                                        }
169                                                        else
170                                                        {
171                                                                negativeparent = current_parent;
172                                                        }
173                                                }
174                                        }
175
176                                        if(is_last)
177                                        {
178                                                if(parent_state > 0)
179                                                {
180                                                        for(vector<polyhedron*>::iterator merge_child = current_parent->mergechildren.begin(); merge_child < current_parent->mergechildren.end();merge_child++)
181                                                        {
182                                                                (*merge_child)->positiveparent = current_parent;
183                                                        }
184                                                }
185
186                                                if(parent_state < 0)
187                                                {
188                                                        for(vector<polyhedron*>::iterator merge_child = current_parent->mergechildren.begin(); merge_child < current_parent->mergechildren.end();merge_child++)
189                                                        {
190                                                                (*merge_child)->negativeparent = current_parent;
191                                                        }
192                                                }
193
194                                                current_parent->mergechildren.clear();
195                                        }
196
197
198                                }
199                       
200                        }
201                }
202        }
203};
204
205/// A class for representing 0-dimensional polyhedron - a vertex. It will be located in the bottom row of the Hasse
206/// diagram representing a complex of polyhedrons. It has its coordinates in the parameter space.
207class vertex : public polyhedron
208{
209        /// A dynamic array representing coordinates of the vertex
210        vec coordinates;       
211
212        enum actions {MERGE, SPLIT};
213
214public:
215
216
217
218        /// Default constructor
219        vertex();
220
221        /// Constructor of a vertex from a set of coordinates
222        vertex(vec coordinates)
223        {
224                this->coordinates = coordinates;
225        }
226
227        /// A method that widens the set of coordinates of given vertex. It is used when a complex in a parameter
228        /// space of certain dimension is established, but the dimension is not known when the vertex is created.
229        void push_coordinate(double coordinate)
230        {
231                coordinates = concat(coordinates,coordinate);
232        }
233
234        /// A method obtaining the set of coordinates of a vertex. These coordinates are not obtained as a pointer
235        /// (not given by reference), but a new copy is created (they are given by value).
236        vec get_coordinates()
237        {               
238                return coordinates;
239        }
240
241               
242};
243
244/// A class representing a polyhedron in a top row of the complex. Such polyhedron has a condition that differitiates
245/// it from polyhedrons in other rows.
246class toprow : public polyhedron
247{
248       
249public:
250        /// A condition used for determining the function of a Laplace-Inverse-Gamma density resulting from Bayesian estimation
251        vec condition;
252
253        /// Default constructor
254        toprow();
255
256        /// Constructor creating a toprow from the condition
257        toprow(vec condition)
258        {
259                this->condition = condition;
260        }
261
262};
263
264class condition
265{       
266public:
267        vec value;     
268
269        int multiplicity;
270
271        condition(vec value)
272        {
273                this->value = value;
274                multiplicity = 1;
275        }
276}
277
278
279//! Conditional(e) Multicriteria-Laplace-Inverse-Gamma distribution density
280class emlig // : eEF
281{
282
283        /// A statistic in a form of a Hasse diagram representing a complex of convex polyhedrons obtained as a result
284        /// of data update from Bayesian estimation or set by the user if this emlig is a prior density
285        vector<vector<polyhedron*>> statistic;
286
287        vector<condition*> conditions;
288
289        double normalization_factor;
290
291        void alter_toprow_conditions(vec condition, bool should_be_added)
292        {
293                for(vector<polyhedron*>::iterator horiz_ref = statistic[statistic.size()-1].begin();horiz_ref<statistic[statistic.size()-1].end();horiz_ref++)
294                {
295                        double product = 0;
296
297                        vector<vertex*>::iterator vertex_ref = (*horiz_ref)->vertices.begin();
298
299                        do
300                        {
301                                product = (*vertex_ref)->coordinates*condition;
302                        }
303                        while(product == 0)
304
305                        if((product>0 && should_be_added)||(product<0 && !should_be_added))
306                        {
307                                ((toprow*) (*horiz_ref))->condition += condition;
308                        }
309                        else
310                        {
311                                ((toprow*) (*horiz_ref))->condition -= condition;
312                        }                                                       
313                }
314        }
315       
316public: 
317
318        /// A default constructor creates an emlig with predefined statistic representing only the range of the given
319        /// parametric space, where the number of parameters of the needed model is given as a parameter to the constructor.
320        emlig(int number_of_parameters)
321        {
322                create_statistic(number_of_parameters);
323        }
324
325        /// A constructor for creating an emlig when the user wants to create the statistic by himself. The creation of a
326        /// statistic is needed outside the constructor. Used for a user defined prior distribution on the parameters.
327        emlig(vector<vector<polyhedron*>> statistic)
328        {
329                this->statistic = statistic;
330        }
331
332        void add_and_remove_condition(vec toremove, vec toadd)
333        {
334                vector<condition*>::iterator toremove_ref = conditions.end();
335                bool condition_should_be_added = false;
336
337                for(vector<condition*>::iterator ref = conditions.begin();ref<conditions.end();ref++)
338                {
339                        if(toremove != NULL)
340                        {
341                                if((*ref)->value == toremove)
342                                {
343                                        if(multiplicity>1)
344                                        {
345                                                multiplicity--;
346
347                                                alter_toprow_conditions(toremove,false);
348
349                                                toremove = NULL;
350                                        }
351                                        else
352                                        {
353                                                toremove_ref = ref;                                                     
354                                        }
355                                }
356                        }
357
358                        if(toadd != NULL)
359                        {
360                                if((*iterator)->value == toadd)
361                                {
362                                        (*iterator)->multiplicity++;
363
364                                        alter_toprow_conditions(toadd,true);
365
366                                        toadd = NULL;
367                                }
368                                else
369                                {
370                                        condition_should_be_added = true;
371                                }
372                        }
373                }
374
375                if(toremove_ref!=conditions.end())
376                {
377                        conditions.erase(toremove_ref);
378                }
379
380                if(condition_should_be_added)
381                {
382                        conditions.push_back(new condition(toadd));
383                }
384
385                vector<vector<polyhedron*>> for_splitting;
386                vector<vector<polyhedron*>> for_merging;
387
388                for(vector<polyhedron*>::iterator horizontal_position = statistic[0].begin();horizontal_position<statistic[0].end();horizontal_position++)
389                {               
390                        vertex* current_vertex = (vertex*)horizontal_position;
391                       
392                        if(toadd != NULL)
393                        {
394                                current_vertex->set_state(toadd*current_vertex->coordinates,SPLIT);
395                        }
396                       
397                        if(toremove != NULL)
398                        {
399                                current_vertex->set_state(toremove*current_vertex->coordinates,MERGE);
400                        }
401
402                        current_vertex->send_state_message(toadd != NULL, toremove != NULL);
403                }
404        }
405
406protected:
407
408        /// A method for creating plain default statistic representing only the range of the parameter space.
409    void create_statistic(int number_of_parameters)
410        {
411                // An empty vector of coordinates.
412                vec origin_coord;       
413
414                // We create an origin - this point will have all the coordinates zero, but now it has an empty vector of coords.
415                vertex *origin = new vertex(origin_coord);
416
417                // It has itself as a vertex. There will be a nice use for this when the vertices of its parents are searched in
418                // the recursive creation procedure below.
419                origin->vertices.push_back(origin);
420
421                // As a statistic, we have to create a vector of vectors of polyhedron pointers. It will then represent the Hasse
422                // diagram. First we create a vector of polyhedrons..
423                vector<polyhedron*> origin_vec;
424
425                // ..we fill it with the origin..
426                origin_vec.push_back(origin);
427
428                // ..and we fill the statistic with the created vector.
429                statistic.push_back(origin_vec);
430
431                // Now we have a statistic for a zero dimensional space. Regarding to how many dimensional space we need to
432                // describe, we have to widen the descriptional default statistic. We use an iterative procedure as follows:
433                for(int i=0;i<number_of_parameters;i++)
434                {
435                        // We first will create two new vertices. These will be the borders of the parameter space in the dimension
436                        // of newly added parameter. Therefore they will have all coordinates except the last one zero. We get the
437                        // right amount of zero cooridnates by reading them from the origin
438                        vec origin_coord = origin->get_coordinates();                                           
439
440                        // And we incorporate the nonzero coordinates into the new cooordinate vectors
441                        vec origin_coord1 = concat(origin_coord,max_range);
442                        vec origin_coord2 = concat(origin_coord,-max_range);
443
444                        // Now we create the points
445                        vertex *new_point1 = new vertex(origin_coord1);
446                        vertex *new_point2 = new vertex(origin_coord2);
447                       
448                        //*********************************************************************************************************
449                        // The algorithm for recursive build of a new Hasse diagram representing the space structure from the old
450                        // diagram works so that you create two copies of the old Hasse diagram, you shift them up one level (points
451                        // will be segments, segments will be areas etc.) and you connect each one of the original copied polyhedrons
452                        // with its offspring by a parent-child relation. Also each of the segments in the first (second) copy is
453                        // connected to the first (second) newly created vertex by a parent-child relation.
454                        //*********************************************************************************************************
455
456
457                        // Create the vectors of vectors of pointers to polyhedrons to hold the copies of the old Hasse diagram
458                        vector<vector<polyhedron*>> new_statistic1;
459                        vector<vector<polyhedron*>> new_statistic2;
460
461                        // Copy the statistic by rows
462                        for(int j=0;j<statistic.size();j++)
463                        {
464                                // an element counter
465                                int element_number = 0;
466
467                                vector<polyhedron*> supportnew_1;
468                                vector<polyhedron*> supportnew_2;
469
470                                new_statistic1.push_back(supportnew_1);
471                                new_statistic2.push_back(supportnew_2);
472
473                                // for each polyhedron in the given row
474                                for(vector<polyhedron*>::iterator horiz_ref = statistic[j].begin();horiz_ref<statistic[j].end();horiz_ref++)
475                                {       
476                                        // Append an extra zero coordinate to each of the vertices for the new dimension
477                                        // If j==0 => we loop through vertices
478                                        if(j == 0)
479                                        {
480                                                // cast the polyhedron pointer to a vertex pointer and push a zero to its vector of coordinates
481                                                ((vertex*) (*horiz_ref))->push_coordinate(0);
482                                        }
483
484                                        // if it has parents
485                                        if(!(*horiz_ref)->parents.empty())
486                                        {
487                                                // save the relative address of this child in a vector kids_rel_addresses of all its parents.
488                                                // This information will later be used for copying the whole Hasse diagram with each of the
489                                                // relations contained within.
490                                                for(vector<polyhedron*>::iterator parent_ref = (*horiz_ref)->parents.begin();parent_ref < (*horiz_ref)->parents.end();parent_ref++)
491                                                {
492                                                        (*parent_ref)->kids_rel_addresses.push_back(element_number);                                                   
493                                                }                                               
494                                        }
495
496                                        // **************************************************************************************************
497                                        // Here we begin creating a new polyhedron, which will be a copy of the old one. Each such polyhedron
498                                        // will be created as a toprow, but this information will be later forgotten and only the polyhedrons
499                                        // in the top row of the Hasse diagram will be considered toprow for later use.
500                                        // **************************************************************************************************
501
502                                        // First we create vectors specifying a toprow condition. In the case of a preconstructed statistic
503                                        // this condition will be a vector of zeros. There are two vectors, because we need two copies of
504                                        // the original Hasse diagram.
505                                        vec vec1(i+2);
506                                        vec1.zeros();
507
508                                        vec vec2(i+2);
509                                        vec2.zeros();
510
511                                        // We create a new toprow with the previously specified condition.
512                                        toprow *current_copy1 = new toprow(vec1);
513                                        toprow *current_copy2 = new toprow(vec2);                                       
514
515                                        // The vertices of the copies will be inherited, because there will be a parent/child relation
516                                        // between each polyhedron and its offspring (comming from the copy) and a parent has all the
517                                        // vertices of its child plus more.
518                                        for(vector<vertex*>::iterator vert_ref = (*horiz_ref)->vertices.begin();vert_ref<(*horiz_ref)->vertices.end();vert_ref++)
519                                        {
520                                                current_copy1->vertices.push_back(*vert_ref);
521                                                current_copy2->vertices.push_back(*vert_ref);                                           
522                                        }
523                                       
524                                        // The only new vertex of the offspring should be the newly created point.
525                                        current_copy1->vertices.push_back(new_point1);
526                                        current_copy2->vertices.push_back(new_point2);
527                                       
528                                        // This method guarantees that each polyhedron is already triangulated, therefore its triangulation
529                                        // is only one set of vertices and it is the set of all its vertices.
530                                        current_copy1->triangulations.push_back(current_copy1->vertices);
531                                        current_copy2->triangulations.push_back(current_copy2->vertices);
532                                       
533                                        // Now we have copied the polyhedron and we have to copy all of its relations. Because we are copying
534                                        // in the Hasse diagram from bottom up, we always have to copy the parent/child relations to all the
535                                        // kids and when we do that and know the child, in the child we will remember the parent we came from.
536                                        // This way all the parents/children relations are saved in both the parent and the child.
537                                        if(!(*horiz_ref)->kids_rel_addresses.empty())
538                                        {
539                                                for(vector<int>::iterator kid_ref = (*horiz_ref)->kids_rel_addresses.begin();kid_ref<(*horiz_ref)->kids_rel_addresses.end();kid_ref++)
540                                                {       
541                                                        // find the child and save the relation to the parent
542                                                        current_copy1->children.push_back(new_statistic1[j-1][(*kid_ref)]);
543                                                        current_copy2->children.push_back(new_statistic2[j-1][(*kid_ref)]);
544
545                                                        // in the child save the parents' address
546                                                        new_statistic1[j-1][(*kid_ref)]->parents.push_back(current_copy1);
547                                                        new_statistic2[j-1][(*kid_ref)]->parents.push_back(current_copy2);
548                                                }                                               
549
550                                                // Here we clear the parents kids_rel_addresses vector for later use (when we need to widen the
551                                                // Hasse diagram again)
552                                                (*horiz_ref)->kids_rel_addresses.clear();
553                                        }
554                                        // If there were no children previously, we are copying a polyhedron that has been a vertex before.
555                                        // In this case it is a segment now and it will have a relation to its mother (copywise) and to the
556                                        // newly created point. Here we create the connection to the new point, again from both sides.
557                                        else
558                                        {
559                                                // Add the address of the new point in the former vertex
560                                                current_copy1->children.push_back(new_point1);
561                                                current_copy2->children.push_back(new_point2);
562
563                                                // Add the address of the former vertex in the new point
564                                                new_point1->parents.push_back(current_copy1);
565                                                new_point2->parents.push_back(current_copy2);
566                                        }
567
568                                        // Save the mother in its offspring
569                                        current_copy1->children.push_back(*horiz_ref);
570                                        current_copy2->children.push_back(*horiz_ref);
571
572                                        // Save the offspring in its mother
573                                        (*horiz_ref)->parents.push_back(current_copy1);
574                                        (*horiz_ref)->parents.push_back(current_copy2); 
575                                                               
576                                       
577                                        // Add the copies into the relevant statistic. The statistic will later be appended to the previous
578                                        // Hasse diagram
579                                        new_statistic1[j].push_back(current_copy1);
580                                        new_statistic2[j].push_back(current_copy2);
581                                       
582                                        // Raise the count in the vector of polyhedrons
583                                        element_number++;
584                                       
585                                }                               
586                        }
587
588                        statistic[0].push_back(new_point1);
589                        statistic[0].push_back(new_point2);
590
591                        // Merge the new statistics into the old one. This will either be the final statistic or we will
592                        // reenter the widening loop.
593                        for(int j=0;j<new_statistic1.size();j++)
594                        {
595                                if(j+1==statistic.size())
596                                {
597                                        vector<polyhedron*> support;
598                                        statistic.push_back(support);
599                                }
600                               
601                                statistic[j+1].insert(statistic[j+1].end(),new_statistic1[j].begin(),new_statistic1[j].end());
602                                statistic[j+1].insert(statistic[j+1].end(),new_statistic2[j].begin(),new_statistic2[j].end());
603                        }
604                }
605        }
606
607
608       
609       
610};
611
612//! Robust Bayesian AR model for Multicriteria-Laplace-Inverse-Gamma density
613class RARX : public BM
614{
615private:
616
617        emlig posterior;
618
619public:
620        RARX():BM()
621        {
622        };
623
624        void bayes(const itpp::vec &yt, const itpp::vec &cond = empty_vec)
625        {
626               
627        }
628
629};
630
631
632#endif //TRAGE_H
Note: See TracBrowser for help on using the browser.